Chapters 6 and 7 Embedded Linux Development

Chapters 6 and 7 Embedded Linux Development

The BIOS reads the first 512 bytes of the hard disk (MBR). Only one OS boot record can be stored in the MBR. If there are multiple systems, there will be problems.

MBR contains part or all of Bootloader and partition table

Bootloader generally contains two stages of code

Bootloader mode:

Self-starting mode: load the OS into RAM from a solid-state storage device such as Flash to run without intervention.

Interactive mode: Download the OS from the Host through the serial port or network interface and run it in RAM, with functions such as programming.

Bootloader function

The first stage:

  • Initialize basic hardware
  • Automatically move the Bootloader to memory
  • Set the stack pointer and zero out the bss segment. Prepare for subsequent code execution.

second stage:

  • Initialize the hardware to be used in this stage
  • read environment variables
  • start up
  • Self-starting mode, load the kernel from Flash or through the network and execute
  • Interactive download mode, perform related operations after receiving user commands

Embedded Linux development environment

NFS service: file directory sharing

TFTP service: download with TFTP protocol

Minicom software: serial port communication, implement ioctl() method

.config file

CONFIG_RAMDISK = y(yes) m(module) *(default?)

make configConfigure parameters line by line

make menuconfigRead Kconfig by interface

make xconfigIn the form of a three-dimensional gui

Linux kernel boot

cp arch/arm/boot/zImage /tftpboot

Start the development board and enter the Bootloader

Configure kernel parameters, configure Host/Target ip address

tftp to get the kernel image file

bootz boots the kernel

FrameBuffer Driver

Low-level base console driverdrivers/char/console.c

middle layer driverdrivers/video/fbcon.c fbmem.c

Drivers for top-level specific hardwareradeonfb.c

Device file /dev/fb0, major device number 29

ioctl() can get screen parameters

mmap maps the screen buffer to user space (passes the mapped space size)

Read and write operation user space address

Linux file system

In embedded Linux applications, the main storage devices are RAM (DRAM, SDRAM) and ROM (often using Flash memory).

Linux file systems are divided into three categories:

  • Flash-based file system (entity)
  • ARM based file system (memory)
  • Network File System NFS

Flash file system

Features of flash memory reading and writing and erasing: the writing operation changes 1 to 0, and the erasing operation restores 0 to 1, and the unit of erasing is block (block)

NOR flash memory: fast reading speed, high price, supports XIP, and reads and writes in words.

NAND flash memory: fast writing speed, high storage density, requires a special system interface, and reads and writes in units of pages.

On top of Flash, MTD (Memory Technology Drivers) device driver support is required. Specific file systems such as jffs2, yaffs, etc. are built on top of MTD, and on top of that is VFS.

The main advantage of using the MTD driver is that it is specially designed for various non-volatile memories (mainly flash memory), so it has better support, management and sector-based erasing and reading of Flash. / Write operation interface.

RAM file system

RamdiskUse a part of fixed-size memory as a partition, and put some files that are frequently accessed but will not change (such as a read-only root file system) in memory, which Ramdiskcan significantly improve system performance. In the boot phase of Linux, initrda set of mechanisms is provided to load the kernel image and the root file system into memory together.

Network file system

NFS is a technology for sharing files over the network between different machines and different operating systems.

NFS service, pay attention to mountthe command usage method

Linux device drivers

When there is an operating system, the hardware/driver/application relationship

The operating system achieves the purpose of providing convenience for upper-layer applications by making troubles for the driver . When the drivers are all designed according to the device-independent interface provided by the operating system, then the application program will use a unified system call interface to access various devices.

Device driver: As the name implies, it drives the hardware device to work. The device driver directly deals with the underlying hardware, reads and writes device registers according to the specific working mode of the hardware device, completes device polling, interrupt processing, DMA communication, and maps physical memory to virtual memory. , and ultimately enable communication devices to send and receive data, display devices to display text and images, and storage devices to record files and data.

Linux kernel architecture

image-20220105183032828

The Linux kernel is divided into 5 modules:

  • Process Scheduler: Responsible for managing CPU resources so that each process can access the CPU as fairly as possible
  • Memory Management: Responsible for managing memory resources so that each process can safely share the memory resources of the machine. In addition, memory management will provide a mechanism for virtual memory, which allows a process to use more memory than is available to the system. The unused memory will be stored in the external non-volatile memory through the file system, and then retrieved to the memory when needed. middle.
  • Virtual File System (Virtual File System, VFS): The kernel abstracts external devices with different functions into a unified file operation interface
  • Network (Network): Responsible for managing the network equipment of the system and implementing various network standards
  • Device Control : Almost every system operation is ultimately mapped to a physical device. Except for the processor, memory, and very few other entities, any device control operation in the entirety is controlled by a device specific to the addressable Device-related code to carry out. These codes are called device drivers.

Each piece of code that can be added to the kernel at runtime is called a module. The Linux kernel provides support for many module types, including but not limited to, device drivers. Each module consists of object code (not linked into a complete executable file), can be dynamically linked into the running kernel, through insmodthe program , and through rmmodthe program to link.

Most character devices only provide the ability to access data sequentially, unlike ordinary file access, which can move the access pointer back and forth to access data at different locations.

"crw-rw-r–" the first letter indicates a character device, b stands for block device (block device)

Block devices are generally large-capacity storage devices, and a file system needs to be established for data storage. The block interface must support mounting filesystems.

The smallest unit of a network interface device is a packet .

Build modules

The kernel and user address spaces are isolated, and the kernel can only call its own code.

There is no function in the kernel module main, there is maina function in the kernel

Based on kbuild mechanism, write Makefile

KSRC = /lib/modules/$(shell uname -r)/build
PWD = $(shell pwd)
obj-m = hello.o

default:
$(MAKE) -C $(KSRC) M=$(PWD) modules
clean:
S(MAKE) -C $(KSRC) SUBDIRS=$(PWD) clean

insmodrun, load

rmmoduninstall

lsmodView the list of runtime modules

modinfoView kernel module information

depmod -aupdate kernel module index

modprobeAutomatically resolve kernel module dependencies

Classification of devices and modules

Treating devices in the Linux way can be divided into three basic device types: character devices, block devices, and network interfaces . Among them, character devices and block devices /devcan find corresponding files in the directory.

  • Character Device

A character device refers to a device that can only read and write one byte at a time, and cannot randomly read a certain data in the device memory, and reads data in sequence. Character devices are stream-oriented devices . Common character devices include mouse, keyboard, serial port, console, and LED devices. Text console ( /dev/console) and serial port ( /dev/ttyS0) are examples of character devices because they represent the stream abstraction well. Character devices are accessed through filesystem nodes , such as /dev/tty1and /dev/lp0. A character driver usually implements at least openthe , close, read, writeand system calls. The only relevant difference between a character device and an ordinary file is that ordinary files can be moved freely, but most character devices are only data channels, which can only be accessed sequentially . The device file has no file size and is replaced by two numbers: major device number + this device number.

  • Block Devices

A block device refers to a device that can read a certain length of data from any location on the device. Block devices include hard disks, disks, U disks, and SD cards. Like character devices, block devices are accessed through filesystem nodes located in /devthe directory . A block device (such as a disk) should be able to host a file system. **Block and character devices differ only in the way the kernel manages data internally, and therefore in the kernel/driver software interface. **In most Unix-like systems, a block device can only handle several whole blocks whose size is an integer multiple of 2. But in the Linux system, applications are allowed to read and write a block device like a character device, which allows any number of bytes to be transferred at a time.

  • Network Interface

Any network transaction is carried out through an interface, that is to say, a network interface is a device capable of exchanging data with other hosts. A network interface can be a hardware device or a pure software device such as a loopback interface. A network interface is responsible for sending and receiving datagrams. Although a network like TCP is stream-oriented, network devices are often designed to handle the sending and receiving of packets, that is to say, they know nothing about individual connections, they only process packets, so the network interface is not a flow- oriented For streaming devices , a network interface is not /dev/tty1as easily mapped to a node in the file system. The way Unix provides access to interfaces is still by assigning them a name (for example eth0), but this name has no corresponding entry in the file system, network interfaces appear in the form of configuration files .

  • You can call dmesg"Hello, world" to see the printout, or you can usecat /proc/devices

The difference between kernel modules and applications

  • Applications are executed sequentially from start to finish, while functions in kernel modules are called passively.
  • ** Kernel modules cannot call C libraries. **Because kernel modules are only linked to the kernel, the only functions a module can call are those exported by the kernel.
  • Kernel modules have to do some cleanup. When the application exits, it is not necessary to release the resources it applied for before it is called, but when the module exits, it must confirm all the resources it applied for when it was loaded, otherwise, the resources it applied for will remain in the system until the system is restarted. middle.
  • **Applications run in user space, while kernel modules run in kernel space. **Under Unix, the kernel runs at the highest level, at which everything is allowed, and applications run at the lowest level , where the processor controls direct access to hardware and illegal access to memory.

The process of compiling and loading modules

obj-mThe module to be declared is defined, that is, the .o file, the operating system kernel compilation directoryKSRC is defined , and the location of the source file is specified . The Linux kernel compilation uses the Kbuild system. This Makefile will be called twice. The first time is to construct the kernel directory tree, and the second time is to call after the kernel source tree is found to run and call the kernel to build the actual module building work . After success, the file will be generated under the current path .Mdefault$(MAKE)make.ko

The following two header files are required for loadable modules

#include <linux/module.h>
#include <linux/init.h>

The former contains definitions of functions and symbols required by a large number of loaded modules. The latter specifies initialization and cleanup functions. Note that at the end of the module we use MODULE_AUTHOR("Sheng LYU")two MODULE_LICENSE("GPL")macros, the former defines the author and the latter defines the code license.

Generally speaking, the main number is used to identify the driver connected to the device, such as /dev/nulland /dev/zeroare managed by driver 1, while the virtual console and serial port terminal are both managed by driver 4. The minor number is used by the kernel to decide which device to refer to.

  • Device numbers can be created or removed using:
sudo mknod /dev/test001 c 240 0
rm /dev/test001

important file structure

Most basic drivers include three important kernel data structures called file_operations, file, and inode. file_operationThe structure description structure is a character driver to establish the connection between the device and the number. The scull device driver implements only the most important device methods. Its file_operations structure is initialized as follows:

struct file_operations scull_fops = {
    
    
 .owner =  THIS_MODULE, 
 .llseek =  scull_llseek, 
    /* loff_t (*llseek) (struct file *, loff_t, int);
llseek 方法用作改变文件中的当前读/写位置, 并且新位置作为(正的)返回值. loff_t 参数是一个"long offset", 并且就算在 32位平台上也至少 64 位宽. 错误由一个负返回值指示. 如果这个函数指针是 NULL, seek 调用会以潜在地无法预知的方式修改 file 结构中的位置计数器( 在"file 结构" 一节中描述).*/
    
 .read =  scull_read, 
    /*ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
用来从设备中获取数据. 在这个位置的一个空指针导致 read 系统调用以 -EINVAL("Invalid argument") 失败. 一个非负返回值代表了成功读取的字节数( 返回值是一个 "signed size" 类型, 常常是目标平台本地的整数类型).*/
    
 .write =  scull_write, 
    /*ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
发送数据给设备. 如果 NULL, -EINVAL 返回给调用 write 系统调用的程序. 如果非负, 返回值代表成功写的字节数.*/
 .ioctl =  scull_ioctl, 
    /*int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
ioctl 系统调用提供了发出设备特定命令的方法(例如格式化软盘的一个磁道, 这不是读也不是写). 另外, 几个 ioctl 命令被内核识别而不必引用 fops 表. 如果设备不提供 ioctl 方法, 对于任何未事先定义的请求(-ENOTTY, "设备无这样的 ioctl"), 系统调用返回一个错误.*/
 .open =  scull_open, 
    /*int (*open) (struct inode *, struct file *);
尽管这常常是对设备文件进行的第一个操作, 不要求驱动声明一个对应的方法. 如果这个项是 NULL, 设备打开一直成功, 但是你的驱动不会得到通知.*/
 .release =  scull_release,  
    /*int (*release) (struct inode *, struct file *);
在文件结构被释放时引用这个操作. 如同 open, release 可以为 NULL.*/
};  

Registration and removal of character devices

int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
/*major 是需要使用的主编号, name 是驱动的名子(出现在 /proc/devices), fops 是缺省的 file_operations 结构. 一个对 register_chrdev 的调用为给定的主编号注册 0 - 255 的次编号, 并且为每一个建立一个缺省的 cdev 结构. 使用这个接口的驱动必须准备好处理对所有 256 个次编号的 open 调用( 不管它们是否对应真实设备 ), 它们不能使用大于 255 的主或次编号.*/

int unregister_chrdev(unsigned int major, const char *name);
/*major 和 name 必须和传递给 register_chrdev 的相同, 否则调用会失败.*/

open and release methods

openmethod provided to the driver to do any initialization in preparation for subsequent operations. In most drivers, open should do the following:

  • Check for device-specific errors (e.g. device not ready, or similar hardware errors)
  • If it is turned on for the first time, initialize the device
  • Update the f_op pointer if necessary.
  • Allocate and populate any data structures to be put filp->private_datainto

Function prototype:

int (*open)(struct inode *inode, struct file *filp);

releaseThe role of methods is the opposite openof . Sometimes you'll find implementations of methods called device_closeinstead of device_release. Anyway, device methods should perform the following tasks:

  • openfrees filp->private_dataanything allocated in
  • At the end closeclose the device

read and write methods

Both the read and write methods perform similar tasks, that is, copying data from and to application code. Therefore, their prototypes are quite similar, and they can be introduced together:

ssize_t read(struct file *filp, char __user *buff, size_t count, loff_t *offp);
ssize_t write(struct file *filp, const char __user *buff, size_t count, loff_t *offp);

For the two methods, filpit is a file pointer, countwhich is the size of the requested transfer data. buffThe parameter points to the buffer holding the written data, or the empty buffer to put the new data. Finally, offp is a pointer to a "long offset type" object , which indicates the file location the user is accessing.

Note that the buff parameter of readthe and writemethod is a user-space pointer . Therefore, it cannot be directly dereferenced by kernel code.

Obviously, your driver must be able to access user-space caches to do its job. However, for security reasons this access must use special, kernel-provided functions. We introduce a few such functions (defined in ), and the <asm/uaccess.h>rest in the "Using ioctl Parameters" section of Chapter 1. They use some special, architecture-dependent tricks to ensure safe and correct data transfers between the kernel and userspace.

The read and write code in scull needs to copy entire segments of data to and from user address space. This capability is provided by the following kernel functions, which copy an arbitrary byte array, and lie at the heart of most read and write implementations.

unsigned long copy_to_user(void __user *to,const void *from,unsigned long count); 
//将数据从内核拷贝至用户空间,用于read操作
unsigned long copy_from_user(void *to,const void __user *from,unsigned long count); 
//将数据从用户空间拷贝到内核中,用于write操作

ioctl interface

Most drivers require - in addition to the ability to read and write to the device - the ability to perform various hardware controls through the device driver. Most devices can perform operations beyond simple data transfers; userspace must often be able to request, for example, that the device be locked Its door, eject its media, report an error message, change the baud rate, or self-destruct. These operations are often supported by the ioctl method, which is implemented through the system call of the same name.

int ioctl(int fd, unsigned long cmd, ...); //应用层
long (*unlocked_ioctl)(struct file* file,
                      unsigned int cmd,
                      unsigned long arg);//内核层

exercise

  • mknod cannot create ordinary files . c character file, p pipe file
  • The function copy_to_userusually appears in the read method function of the device driver (the read here can be regarded as reading the kernel, and copy the content from the kernel to the user space after reading the kernel)
  • The role of GNU make in the software development process is to reduce the compilation and linking process according to the dependency relationship in the program compilation stage, and improve the compilation efficiency
  • When a process starts, three files are opened by default: standard input, standard output, and standard error handling (stdin, stdout, stderr)
  • Inode nodes and files are not in one-to-one correspondence, the inode numbers of soft links are different, and the inodes of hard links are the same.

img

img

img

  • The device driver is the interface between the upper application and the underlying hardware, providing a mechanism for accessing the hardware.
  • The upper-layer application accesses the device through the device node file under the file system/dev, and triggers the corresponding device driver in the kernel to work
  • The Linux kernel finds the corresponding device driver module through the major device number of the device
  • The device driver module distinguishes subdivided devices in a large class of devices through the minor device number
struct file_operations device_fops = {
    
    
    llseek: device_llseek,
    read: device_read,
    write: device_write,
    unlocked_ioctl: device_ioctl,
    open: device_open,
    release: device_release
};

or

struct file_operations device_fops = {
    
    
    .owner = THIS_MODULE,
    .llseek = device_llseek,
    .read = device_read,
    .write = device_write,
    .unlocked_ioctl = device_ioctl,
    .open = device_open,
    .release = device_release,
};
  • The llseek() method is the specific implementation of the lseek() system call, which is used to complete the positioning operation of the device
  • The ioctl() method, in addition to reading and writing the device, the device driver also needs to provide a variety of hardware control capabilities, such as configuring the device, entering or exiting a certain operating mode, generally not through read/write and other file operations. , such as the setting of the serial communication protocol (baud rate, data format, etc.). In the Linux kernel, the unlocked_ioctl() method is used to implement the ioctl() system call.
  • int ioctl(int fd, int cmd, ...) fd device file number, cmd command, the third parameter can point to various data types.
  • Large-capacity data transmission must use read, writethe function
  • If a process calls read, but has no data to read, the process must block. As soon as the data arrives, the process wakes up and returns the data to the caller.
  • If the data is not ready, simply return -EAGAIN, so non-blocking operations return immediately.
  • The device driver provides the mechanism (mechanism), and the application provides the policy (strategy)
  • /proc is a special pseudo-file system that the kernel uses to output information to the outside world. Each file under /proc is bound to a kernel function that dynamically generates the "content" of the file when the file is read. In the ux kernel, the unlocked_ioctl() method is used to implement the ioctl() system call
    .
  • int ioctl(int fd, int cmd, ...) fd device file number, cmd command, the third parameter can point to various data types.
  • Large-capacity data transmission must use read, writethe function
  • If a process calls read, but has no data to read, the process must block. As soon as the data arrives, the process wakes up and returns the data to the caller.
  • If the data is not ready, simply return -EAGAIN, so non-blocking operations return immediately.
  • The device driver provides the mechanism (mechanism), and the application provides the policy (strategy)
  • /proc is a special pseudo-file system that the kernel uses to output information to the outside world. Each file under /proc is bound to a kernel function that dynamically generates the "content" of the file when the file is read
  • Incorrect use of pointers in user space usually leads to 'Segment Fault', illegal use of memory addresses in kernel space usually leads to "oops"

Guess you like

Origin blog.csdn.net/wjrzm2001/article/details/127459256