Getting Started with Linux Drivers - Basic Concepts


Introduction to the Linux Kernel

History of Unix

UnixMulticsIt was born out of a failed multi-user operating system at Bell Labs . MulticsAfter the project was terminated, the people at Bell Labs' scientific research center found themselves in a situation where no interactive operating system was available. In this case, in the summer of 1969, programmers at Bell Labs designed a prototype of the file system system that eventually evolved into Unix.
As a result of the initial sixteenth design and years of innovation and gradual improvement, Unixthe system has become a powerful, robust and stable operating system. The following features are Unixthe root cause of what makes it powerful:

  • Unix is ​​very simple. Unlike other systems that provide thousands of system calls and have no clear design purpose, Unix only provides a few hundred system calls and has a very clear design purpose.
  • In Unix, everything is treated as a file.
  • The Unix kernel and related system tool software are written in C language-it is this feature that makes Unix have amazing portability in front of various hardware architectures, and makes it easy for developers to adapt can accept it.
  • Unix processes are created very quickly and have a very unique fork()system call.
  • Unix provides a set of very simple but stable inter-process communication primitives. The fast and concise process creation process enables Unix programs to aim at completing a task with quality and quantity in one execution, while simple and stable inter-process communication The mechanism can ensure that these single-purpose simple programs can be easily combined to solve tasks that become more and more complex in reality.
    Today, Unix has evolved into a modern operating system that supports preemptive, multithreading, virtual memory, paging, dynamic linking, and TCP/IP networking. Different variants of Unix are used on systems ranging from clusters of hundreds of CPUs to embedded devices.

Introduction to Linux

In 1991, a Linus Torvaldsnew operating system was developed for the then- Intel 80386new computers using microprocessors, and Linuxthus was born. At that time, Linus, a student at the University of Helsinki in Finland, was troubled by the fact that he could not use the powerful and free Unix system as he wanted. For Torvalds, using Microsoft's DOS system, which was popular at the time, there was nothing else to do except play Prince of Persia. Linus is keen to use Minix, a cheap Unix for teaching, but he cannot easily modify and distribute the source code of the system (due to the Minix license), nor can he act rashly on the design made by the Minix developers, which makes him angry. Huai was disappointed with the author's design concept.
Linus was as determined to get out of this predicament as any dynamic college student was: to develop his own operating system. He started by writing a simple terminal emulation program for connecting to the university's large Unix system. His terminal emulation program has been continuously improved and perfected after a school year of research and development. Soon, Linus had an immature but complete Unix in his hands. In late 1991, he posted an early version on the Internet.
Since then, Linux has set sail, and the initial Linux release quickly won many users. In fact, an important factor for his success is that Linux quickly attracted many developers and hackers to modify and improve its code. Due to its licensing terms, Linux quickly became a collaborative development project for many people.

Introduction to Operating Systems and Kernels

The operating system refers to those parts in the entire system that are responsible for completing the most basic functions and system management. These sections should be included 内核、设备驱动程序、启动引导程序、命令行Shell或者其他种类用户界面、基本的文件管理工具和系统工具.
内核Sometimes referred to as the supervisor or operating system core. Usually a core 由负责响应中断的中断服务程序,负责管理多个进程从而分享处理器时间的调度程序、负责管理进程地址空间的内存管理程序和网络、进程间通信等系统服务程序is composed together. For modern operating systems that provide protection mechanisms, the kernel is independent of ordinary applications. He generally resides in a 系统态protected memory space and has all permissions to access hardware devices. This system state and the protected memory space are collectively referred to as 内核空间.
Reference programs running in the system 系统调用communicate with the kernel via . Applications usually call library functions (such as C library functions), and then the library functions use the system call interface to let the kernel complete various tasks on its behalf. Some library functions provide many functions that system calls do not have. In those more complex functions, the operation of calling the kernel is usually just a step in this work.
内核It is also responsible for managing the hardware devices of the system. Almost all existing architectures, including all Linux-supported architectures, provide interrupt mechanisms. When a hardware device wants to communicate with the system, it first sends an asynchronous interrupt signal to interrupt the execution of the processor, and then interrupts the execution of the kernel. An interrupt usually corresponds to an interrupt number. The kernel uses this interrupt number to find the corresponding interrupt service program, and calls this program to respond to and process the interrupt. 许多操作系统的中断服务程序,包括Linux的,都不在进程上下文执行。它们在一个与所有进程都无关的、专门的中断上下文中运行. The reason why there is such a special execution environment is to ensure that the interrupt service program can respond and process the interrupt request at the first time, and then exit quickly.
We can necessarily generalize the activity of each processor at any given point in time as one of three things:
insert image description here

  • Run in user space, execute user process
  • Runs in the kernel space, in the process context, and executes on behalf of a specific process.
  • Runs in kernel space, in interrupt context, has nothing to do with any process, and handles a specific interrupt.

Comparing single-kernel and microkernel designs

The operating system kernel can be divided into two camps: single kernel and microkernel (the third camp is the exkernel, which is mainly used in scientific research systems).
单内核It is the simpler design of the two camps. The so-called single kernel is to implement it as a single large process as a whole, and also run on a separate address space. Therefore, such kernels usually live on disk as a single static binary. All kernel services run on such a large kernel address space. Communication between kernels is trivial, since everyone is running in kernel mode and in the same address space: the kernel calls functions directly, which is no different from user-space applications. Proponents of this pattern believe that a single module has the characteristics of simplicity and high performance.
微内核Rather than being implemented as a single large process, the functionality of the microkernel is divided into multiple independent processes, each of which is called a server. Ideally, only servers that strongly request privileged services run in privileged mode, and all other servers run in user space. However, all servers remain separate and run on their own address spaces. Therefore, it is impossible to directly call functions like a single-module kernel, but to handle microkernel communication through message passing: the system uses an inter-process communication (IPC) mechanism, so each server communicates with each other through the IPC mechanism to exchange "services". ". The independence of the servers effectively prevents the failure of one server from harming another server.
Linux is a single kernel, that is, the Linux kernel runs on a separate kernel address space. However, Linux has absorbed the essence of the microkernel: it is proud of its modular design, preemptive kernel, support for kernel threads, and the ability to dynamically load kernel modules. Not only that, Linux also avoids the defect of performance loss in its microkernel design, allowing everything to run in the kernel mode, calling functions directly without message passing. So far, Linux is a modular, multi-threaded and schedulable operating system with the kernel itself, and edibleism has once again gained the upper hand.

summary

This part is mainly used to introduce the basic concepts related to Linux. For detailed reference materials, you can add the group to download the original book for viewing
qq:602877925

Introduction to Device Drivers

driver's role

As a programmer, you can make your own choices about your drivers and choose an acceptable balance between desired programming practices and resulting flexibility. Although it may sound strange to say that a driver is "flexible," we like the word because it emphasizes one 驱动程序的角色是提供机制,而不是策略.
The distinction between mechanism and strategy is one of the best ideas behind Unix design. Most programming problems can actually be divided into two parts: "what capabilities are provided" ( 机制) and "how to use these capabilities" ( 策略). If these two aspects are expressed by different parts of the program, or even jointly expressed by different programs, software packages are very easy to develop and adapt to special needs.
You can also look at your driver from different angles: 它是一个存在于应用程序和实际设备间的软件层. This privileged role of the driver allows the driver programmer to choose closely how the device should behave: different drivers may provide different capabilities, even the same device. The actual drive design should be a balance among many different considerations. For example, a single device may be used concurrently by different programs, and the driver programmer has complete freedom to decide how to handle concurrency. You can implement memory mapping on a device independent of its hardware capabilities, or you can provide users with a user library to moderate application programmers to implement new strategies on top of available primitives, etc. A major consideration is the balance between exposing the user as many options as possible, and the time you have to spend writing the driver, and the need to keep things simple to avoid bugs creeping in.

Divide the kernel

The role of the kernel can be divided into the following parts (as shown below):
insert image description here

  • 进程管理- The kernel is responsible for creating and destroying processes, and handling their contact with the outside world (input and output). Communication between different processes (via signals, pipes, or IPC primitives) is fundamental to overall system functionality and is also handled by the kernel. Also, the scheduler, which controls how processes share the CPU, is part of process management. More generally, the kernel's process management activities implement the abstraction of multiple processes on a single or several CPUs.
  • 内存管理- A computer's memory is a major resource, and the strategy used to handle it is critical to system performance. The kernel creates a virtual address space for each of all processes within limited available resources. Different parts of the kernel interact with the memory management subsystem through a set of function calls, ranging from simple ones malloc/freeto more complex functions.
  • 文件系统- Unix is ​​heavily based on the concept of a file system; almost anything in Unix can be thought of as a file. The kernel builds a structured file system on top of unstructured hardware, with the result that the file abstraction is heavily applied throughout the system. In addition, Linux supports multiple file system types, that is, different ways of organizing data on physical media. For example, the disk can be formatted with a standard Linux ext3file system, a commonly used FATfile system, or several other file systems.
  • 设备控制- Almost every system operation is ultimately mapped to a physical device. With the exception of the processor, memory, and very few other entities, any device control operations at all are performed by code specific to the device being addressed. These codes are called device drivers. Embedded in the kernel are drivers for every peripheral present in the system, from hard disk drives to keyboards and tape drives.
  • 网络- The network must be managed by the operating system, since most network operations are not specific to a single process: packets entering the system are asynchronous events. Messages must be collected, identified, and distributed before a process takes over. The system is responsible for delivering datagrams between the program and the network interface, and it must control the program's execution based on the program's network activity. Additionally, all routing and address resolution concerns are implemented in the kernel.

LinuxOne of the many nice features of is the ability to extend the features provided by the kernel at runtime. This means that you can add functionality to the kernel (and remove it) while the system is running.
Each piece of code that can be added to the kernel at runtime is called a 模块. 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), which can be dynamically linked into the running kernel, insmodloaded by a program, and rmmodunloaded by a program.

Classification of devices and modules

Looking at devices the Linux way, three basic device types can be distinguished. Each module usually implements one of three types, and thus can be classified as a character module, a block module, or a network module.

  • 字符设备- A character ( char) device is a device that can be accessed as a stream of bytes (like a file); a character driver is responsible for implementing this behavior. Such drivers usually implement at least open、close、read和writea system call. Text console ( /dev/console) and serial port ( /dev/ttyS0及其友) are examples of character devices because they represent nice abstractions. Character devices are accessed through file system nodes, such as /dev/tty1and /dev/lp0. The only relevant difference between a character device and a normal file is that you can often move around in normal files, but most character devices are just data channels, and you can only access them sequentially. However, there are character devices that look like data areas, and you can move around in them. For example, a frame grabber is often such that an application can use mmapor lseekaccess the entire requested image.
  • 块设备- Like character devices, block devices are /devaccessed through file system nodes located in directories. A block device (such as a disk) should be able to host a file system. On most Unix systems, a block device can only handle I/O operations that transfer one or more entire blocks that are usually 512bytes (or a larger number of 2) in length. Linux, in contrast, allows the referencing program to read and write to a block device like a character device, allowing an arbitrary number of bytes to be transferred at a time. As a result, block and character devices differ only in the way the kernel manages data internally, and thus in the kernel/driver software interface. Like a character device, each block device is accessed through a file system node, and the distinction between them is transparent to the user. Compared with the character driver, the block driver has a completely different interface with the kernel.
  • 网络接口- Any network transaction is conducted through an interface, that is, a device capable of exchanging data with other hosts. Usually, an interface is a hardware device, but it may also be a pure software device, such as a loopback interface. A network interface is responsible for sending and receiving data packets. Driven by the kernel network subsystem, it is not necessary to know how individual transactions are mapped to the actual packets being sent. Many network connections (especially those using TCP) are stream-oriented, but network devices are often designed to handle the sending and receiving of packets. A network driver knows nothing about individual connections; it only handles packets. Since it is not a stream-oriented device, it is not as /dev/tty1easy to map a network interface to a node of the file system. Unix still provides access to interfaces by assigning them a name (for example eth0), but this name has no corresponding storage in the file system. The communication between the kernel and network device drivers is quite different from that used by char and block device drivers. No read和write, but the kernel calls functions related to message delivery.

There are other ways of dividing driver modules, which are orthogonal to the device types above. Typically, certain types of drivers work with other layers of kernel support functions for a given type of device. Such as USB module, serial port module, SCSI module and so on. Each USB device is driven by a USB module and works with the USB subsystem, but the device itself appears in the system as a character device (such as a USB serial port), a block device (a USB memory card reader), or a network device (a USB Ethernet interface).
In addition to device drivers, other functions, both hardware and software, are modular in the kernel. A common example is the file system. 一个文件系统类型决定了在块设备上信息是如何组织的,以便能表示一棵目录与文件的树. Such an entity is not a device driver because there is no explicit device associated with how information is placed; a filesystem type is a software driver because it maps low-level data structures to high-level data structures. The file system determines how long a filename is and what information about each file is stored in a directory entry. A filesystem module must implement the lowest-level system calls to access directories and files by mapping filenames and paths (and other information, such as access modes) to data structures stored in data blocks. Such an interface is completely independent of the data being transferred to and from disk (or other media), which is traditionally done by a block device driver.

Security Question

Security is a concern of growing importance today. Any security checks in the system are imposed by the kernel code. If the kernel has security holes, the system as a whole has holes. In official kernel distributions, only an authorized user can load modules; the system call checks init_modulewhether the calling process has permission to load modules into the kernel. Therefore, only a superuser or an intruder who has successfully gained privileges can exploit the capabilities of privileged code when running an official kernel.

As a device driver writer, you should know under what circumstances certain types of device access may adversely affect the system as a whole, and should provide adequate control. For example, a device operation that affects global resources (such as setting an interrupt line), may damage hardware (such as loading firmware), or it may affect other users (such as setting a tape drive's default block size), Often only for users with sufficient authorization, and this check must be done by the driver itself.
Driver writers must also be careful, of course, to avoid introducing security bugs. The C programming language makes it easy to make several types of mistakes. For example, many of today's security problems are caused by buffer overwrites, which are caused by programmers forgetting to check how much data is written to a buffer, the data ends beyond the end of the buffer, and thus overwrites irrelevant data. Such errors can compromise the security of the entire system and must be avoided. Fortunately, avoiding such errors is often relatively easy in the context of a device driver, where the interface to the user is finely defined and highly controlled.

Copyright Terms

Linux is licensed under version 2 of the GNU General Public License (GPL), from the GNU Project of the Free Software Foundation. The GPL allows anyone to redistribute, or even sell, products covered by the GPL, as long as the recipient has access to the source code and can exercise the same rights. In addition, any software product derived from a GPL product must be placed under the GPL if it is a complete redistribution.

Overview of Linux driver development

Driver overview

Device driver ( Device Driver), referred to as driver ( Driver). It is a program that allows computer software ( ) to interact Computer Softwarewith hardware ( ). HardwareThis program establishes a hardware-to-hardware, or hardware-to-software interface. The CPU forms a connection with the hardware via the bus ( ) on the motherboard Busor other communication subsystems ( Subsystem), which makes data interaction between hardware devices possible.

The role of device drivers

A device driver is a special program that enables a computer to communicate with a device, and can be said to be equivalent to a hardware interface. Only through this interface can the operating system control the work of the hardware device.
The device driver is used to tell the operating system the function of the hardware itself, and complete the mutual translation between the electronic signal of the hardware device and the high-level programming language of the operating system and software. When the operating system needs to use some hardware, such as to let the sound card play music, it will first send instructions to the sound card driver. After the sound card driver receives it, it immediately translates it into an electronic signal command that the sound card can only understand, so that the sound card can play music. So to put it simply, the driver is an interface that provides the hardware to the operating system and coordinates the relationship between the two. And because the driver has such an important role, people say that "the driver is the soul of the hardware" and "the master of the hardware", and the driver is also vividly called "the bridge between the hardware and the system".

Classification of Device Drivers

computer system 主要硬件由CPU、存储器和外部设备组成. The objects of the driver are generally memory and external devices. With the improvement of the chip manufacturing process, in order to save costs, many controllers that originally belonged to external devices are usually embedded in the CPU. So now the driver should support the embedded controller in the CPU. Linux divides these devices into three categories, namely character devices, block devices, and network devices.
字符设备
Character devices refer to those devices that can read data byte by byte, such as LED, keyboard, mouse, etc. Character devices generally require underlying driver implementation open()、close()、wirte()、ioctl()and other functions. These functions will eventually be called by related functions in the file system. The kernel corresponds to a file for a character device, such as a character device file /dev/console. Operations on character devices can be /dev/consoleperformed through character device files. These character device files are not much different from ordinary files. The difference is that character devices generally do not support addressing, but there are many character devices that support addressing under special circumstances.
块设备
Block devices are similar to character devices and are generally disk-like devices. File systems can also be accommodated in block devices and store large amounts of information. In the Linux system, when reading and writing a block device, only one or more blocks can be transferred at a time. Linux allows applications to access block devices like character devices, reading only one byte at a time. So a block device is essentially more like an extension of a character device, and a block device can do more work, such as transferring a piece of data.
In general, block devices require more complex data structures to describe than character devices, and their internal implementations are also different. Therefore, in the Linux kernel, compared with the character driver, the block device driver has a completely different API interface.
网络设备
A computer needs a network device to connect to the Internet, and the network device is mainly responsible for data exchange between hosts. Completely different from character devices and block devices, network devices are mainly designed for receiving and sending data packets. A network device is a very special device in the Linux operating system, which does not implement read()、write()、ioctl()functions such as block devices and character devices. Network devices implement a socket interface, and any network data transmission can be done through sockets.

The relationship between the Linux operating system and the driver

Refer to the following figure for the relationship between the Linux operating system and the device driver:
insert image description here

User space includes two layers of application programs and system calls. Applications generally depend on function libraries, and function libraries are written by system calls, so applications indirectly depend on system calls.
系统调用是内核空间和用户空间的接口层. Through this system call, the application program does not need to directly access the program in the kernel space, which increases the security of the kernel. At the same time, the application program cannot access the hardware device, and can only access the hardware device through the system call layer. If the application program needs to access the hardware device, the application program first accesses the system call layer, and the system call layer accesses the device driver of the kernel. This design ensures the functional independence of each module and also ensures the security of the system.
The system call layer relies on various modules in the kernel space to implement. In the Linux kernel, there are many modules that implement specific functions. These modules include file systems, network protocol stacks, device drivers, kernel scheduling, memory management, process management, etc., all of which belong to the kernel space.
The bottom layer is the hardware layer, which is an abstraction of actual hardware devices. The function of the device driver is to drive this layer of hardware. Device drivers can work with or without an operating system. If you only need to implement some simple operations to control the device, you don't need to use the operating system. If the functions completed by the embedded system are more complicated, the operating system is often needed to help. Most operating systems have the characteristics of multitasking, so for device drivers, issues such as concurrency and blocking should be fully considered.

Linux driver development

The Linux operating system is divided into user mode and kernel mode. 用户态处理上层的软件工作。内核态用来管理用户态程序 ,完成用户态请求的工作. The driver interacts with the underlying hardware, so it works in kernel mode.
The reason why the Linux operating system is divided into two states is mainly to provide a unified computer hardware abstraction for applications. The application program working in the user mode can completely ignore the underlying hardware operations, and these operations are completed by the kernel mode program. Most of these kernel-mode programs are device drivers. A good operating system driver should be transparent to user-mode applications, that is, applications can operate hardware devices well without making the hardware enter an illegal state without knowing the working principle of the hardware. . The Linux operating system does this very well.
模块It is code that can be added to the kernel at runtime, which is a very good feature of Linux. This feature allows the kernel to be easily enlarged or reduced. On the one hand, expanding the kernel can increase the function of the kernel, and on the other hand, shrinking the kernel can reduce the size of the kernel.
The Linux kernel supports many kinds of modules, and the driver is one of the most important ones. Even the file system can be written as a module and then added to the kernel. Each module is composed of compiled object code. You can use insmodcommands to add modules to the running kernel, and you can also use rmmodcommands to delete an unused module from the kernel. Attempts to delete a module that is in use will not be allowed.
Module loading when the kernel starts is called static loading, and loading when the kernel is already running is called dynamic loading. Modules can extend any functionality expected by the kernel, but are typically used to implement device drivers. The most basic skeleton code of a module is as follows:

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

int __init xxx_init(void)
{
    
    
	/*模块加载时的初始化工作*/
	return 0;
}

void __exit xxx_exit(void)
{
    
    
	/*模块卸载时的销毁工作*/
}
module_init(xxx_init); /*指定模块的初始化函数的宏*/
module_exit(xxx_exit); /*指定模块的卸载函数的宏*/

The Linux operating system has three to four million lines of code, of which about three quarters are the driver code. So for driver developers, learning and writing device drivers is a long process. Therefore, the following knowledge is required:

  • Good C language foundation, and can flexibly use basic language structures such as C language structures, pointers, and macros. In addition, the C compiler used by the Linux system is the GNU C compiler, so you should also have some understanding of the C language of the GNU C standard.
  • Driver developers should have a good hardware foundation. Although driver developers are not required to have the principles of circuit design, they should also have a clear understanding of the interface devices described in the chip manual. Commonly used devices include SRAM, Flash, UART, IIC, USB, etc.
  • Driver developers should have a preliminary understanding of the Linux kernel source code. For example, some important data structures and functions, etc.
  • Driver developers should be capable of multitasking programming, and a large number of spin locks, mutexes, signals, etc. will also be used in the driver.

Considerations for Writing Device Drivers

Program development on Linux is generally divided into two types, one is kernel and driver development, and the other is application development. These two types of development correspond to two states of Linux, which are kernel state and user state. The kernel mode is used to manage the programs in the user mode and complete the work requested by the user mode; the user mode handles the upper-layer software work. The driver interacts with the underlying hardware, so it works in kernel mode. Kernel and driver development is very different from application development. The most important differences include the following:

  • The C library cannot be accessed during kernel and driver development, because the C library is implemented using system calls in the kernel and implemented in user space.
  • It must be used during kernel and driver development GNU C, because the Linux operating system uses GNU C from the beginning, although other compilation tools can also be used, but a lot of modifications to the previous codes are required.
  • The kernel supports asynchronous interrupts, preemption and SMP, so you must always pay attention to synchronization and concurrency when developing the kernel and drivers.
  • The kernel has only a small fixed-length stack
  • Lack of memory protection mechanism like user space during kernel and driver development
  • Floating-point numbers are difficult to use during kernel and driver development, and integer numbers should be used.
  • Kernel and driver development should consider portability, because the driver is not compatible for different platforms.

GNU C Development Driver

The GNU C language originated from a GNU project, and GNU means "GNU is not Unix". The GNU project started in 1984. The purpose of this project is to develop a complete operating system similar to UNIX and free software. This plan has been going on until Linus developed the Linux operating system. The GNU project has developed a lot of high-quality free software, and the most famous GCCcompiler, the GCC compiler, can compile the GNU C language. Linus considered the freedom and free of the GNU project, so he chose the GCC compiler to write the kernel code. Later, many developers also used this compiler, so until now, driver developers also use GNU C language to develop drivers.

Cannot use C library to develop driver

Unlike user-space applications, the kernel cannot call standard C library functions, mainly because the full C library is too large for the kernel. A compiled kernel can be around 1MB in size, while a standard C library might be 5MB in size. This is impractical for embedded devices with small storage capacity.
The header files included in the kernel program refer to the kernel header files of the kernel code tree, not the external header files when developing applications. The printing function in the library function implemented in the kernel printk(), which is printf()the kernel version of the C library function. Have basically the same usage and function.

no memory protection mechanism

When an application program attempts to access an illegal memory space due to a programming error, the operating system kernel will terminate the process and return an error code. The application program can be recovered with the help of the operating system kernel, and the application program does not have much impact on the operating system kernel. But if the operating system kernel accesses an illegal memory, it may destroy the code or data of the kernel. This will cause the kernel to be in an unknown state, and the kernel will oopsgive the user some hints through errors, but these hints are not supported and difficult to analyze.
In kernel programming, you should not access illegal memory, especially null pointers, otherwise, the kernel will suddenly die without any chance to prompt the user. It is very common for bad drivers to cause system crashes, so for driver developers, the correct access to memory should be very important.一个好的建议是,当申请内存后应该对返回的地址进行检测。

small kernel stack

Programs in user space can allocate a large amount of space to store variables from the stack, and even use the stack to store huge data structures or arrays. The reason why this is possible is that applications are non-resident memory space, they can dynamically apply for the core to release the available memory space used. The kernel requires the use of fixed resident memory space, so it is required to occupy as little resident memory as possible, and reserve as much memory as possible for user programs. Therefore, the length of the kernel stack is fixed. The kernel stack of the 32-bit machine that cannot be dynamically increased is 8KB, and the kernel stack of the 64-bit machine is 16KB.
Since the kernel stack is relatively small, the problem of small kernel stacks should be fully considered when writing programs. Try not to use recursive calls. In the application program, if the recursive calls are made more than 4,000 times, there may be overflow. In the kernel, the number of recursive calls is very small, and the functions of the program can hardly be completed. In addition, after using the memory space, the memory should be released as soon as possible to prevent resource leaks and cause a kernel crash.

focus on portability

Portability has always been an important issue for user-space programs. General portability is achieved in two ways. One way is to define a set of portability APIs, and then implement this set of APIs on the two platforms that need to be ported. Application developers can write portable programs as long as they use this set of portable APIs. In the embedded field, the more common API suite is QT. Another way is to use a language like Java, ActionScript, etc. that can be ported to many operating systems. These languages ​​are generally executed by virtual machines, so they can be ported to many platforms.
For drivers, portability requires attention to the following issues:

  • Consider byte order, some devices use big endian and some devices use little endian. The Linux kernel provides a function for big and small endian conversion
#define cpu_to_le16(v16) (v16)
#define cpu_to_le32(v32) (v32)
#define cpu_to_le64(v64) (v64)
#define le16_to_cpu(v16) (v16)
#define le16_to_cpu(v32) (v32)
#define le16_to_cpu(v64) (v64)
  • Even if the driver program of the same device uses different chips, different driver programs should be read and written, but a unified programming interface should be provided to the user.
  • Try to use macros instead of physical addresses of device ports, and you can use ifdefinemacros to determine information such as version
  • For different processors, the functions of the relevant processors should be used.

summary

With the rapid development of embedded devices, learning driver development is very helpful for personal progress.

Summarize

Welcome friends who love Linux drivers to learn together, make progress together, communicate and discuss ( _ )
qq:602877925

Guess you like

Origin blog.csdn.net/m0_56145255/article/details/130814785