Embedded Linux user space and kernel space, process context and interrupt context

Preface

  • When I was learning embedded linux system before, I was always fascinated by interrupt context and process context , and I was very familiar with it. However, it was always difficult to explain the concepts forcibly, so I ran to figure out these. For the purpose of this concept, I read a lot of information on the Internet. The learning of these concepts is a cumulative process.

User space and kernel space

  • We know that the current operating system uses virtual memory , so for a 32-bit operating system, its addressing space (virtual storage space) is 4G (2 to the 32th power). The core of the worry system is the kernel , which is independent of ordinary applications and can access the protected memory space as well as all the permissions to access the underlying hardware devices. In order to ensure that user processes cannot directly manipulate the kernel and ensure the safety of the kernel, the worry system divides the virtual space into two parts, one part is the kernel space and the other is the user space. For the linux operating system , the highest 1G byte (from virtual address 0xC0000000 to 0xFFFFFFFF) is used by the kernel, which is called kernel space, and the lower 3G byte (from virtual address 0x00000000 to 0xBFFFFFFF), For each process to use, called user space. **Each process can enter the kernel through system calls. Therefore, the Linux kernel is shared by all processes in the system. Therefore, from the perspective of a specific process, each process can have 4G bytes of virtual space . The space allocation is shown in the figure below:
    Insert picture description here

  • With user space and kernel space, the entire linux internal structure can be divided into three parts , from the bottom to the top: hardware -> kernel space -> user space . As shown below:
    Insert picture description here

  • It should be noted that:
    (1) The kernel code and data are stored in the kernel space , and the code and data of the user program are stored in the user space of the process. Whether it is kernel space or user space, they are all in virtual space .
    (2) Linux uses a two-level protection mechanism: level 0 is for the kernel and level 3 is for user programs .

Kernel mode and user mode

(1) When a task (process) executes a system call and falls into execution in the kernel code, it is said that the process is in the kernel running state (kernel state) . The processor is now executing in the kernel code with the highest privilege level (level 0). When the process is in the kernel mode, the executed kernel code will use the kernel stack of the current process. Each process has its own kernel stack.

(2) When the process is executing the user's own code, it is said to be in the user running state (user state) . At this time, the processor is running in user code with the lowest privilege level (level 3). When the user program is being executed and is suddenly interrupted by the interrupt program, the user program can also be symbolically referred to as being in the kernel state of the process. Because the interrupt handler will use the kernel stack of the current process.

Process context and interrupt context

Context

  • The context is translated from the English context . Refers to an environment . Relative to the process, it is the environment when the process is executed; specifically, it is the various variables and data, including all register variables, files opened by the process, memory information, etc.

atom

  • Atom (atom) originally means "the smallest particle that cannot be further divided", and atomic operation means "an operation or a series of operations that cannot be interrupted."

And why is there such a concept of context?

  • Kernel space and user space are two working modes of modern operating systems. The kernel module runs in the kernel space , and the user mode application runs in the user space . They represent different levels and have different access rights to system resources. The kernel module runs at the highest level (kernel mode), all operations under this level are trusted by the system, and applications run at a lower level (user mode) . At this level, the processor controls direct access to hardware and unauthorized access to memory. The kernel mode and user mode have their own memory mapping, that is, their own address space.

  • The processor is always in one of the following states:
    (1) Kernel mode, running in the process context , the kernel represents the process running in the kernel space; kernel mode, running in the interrupt context, the kernel represents the hardware running in the kernel space;
    (2) User mode, running in user space .

  • The two different operating states of the system have the concept of context. If an application in the user space wants to request system services, such as operating a physical device and mapping the address of the device to the user space, it must be implemented through system calls . ( System calls are interface functions provided by the operating system to the user space ).

  • Through the system call, the user space application program will enter the kernel space, and the kernel will run in the kernel space on behalf of the process, which involves context switching. The user space and the kernel space have different address mappings, general or special register sets , And the user space process must pass many variables and parameters to the kernel, and the kernel must also save some registers, variables, etc. of the user process, so that it can return to the user space to continue execution after the system call ends.

Process context

The so-called process context refers to the values ​​in all registers of the CPU, the state of the process, and the content on the stack when a process is executing. When the kernel needs to switch to another process, it needs to save all the states of the current process, that is Save the process context of the current process so that when the process is executed again, the state at the time of switching can be restored and the execution can continue.

  • The context of a process can be divided into three parts: user-level context, register context, and system-level context .
    User context : text, data, user stack and shared memory area;
    register context : general register, program register (IP), processor status register (EFLAGS), stack pointer (ESP);
    system-level context : process control block task_struct, memory Management information (mm_struct, vm_area_struct, pgd, pte), kernel stack.
    When process scheduling occurs, the process switch is a context switch (context switch).
  • The operating system must switch all the information mentioned above before the newly scheduled process can run. The system call is a mode switch (mode switch) . Compared with process switching, mode switching is much easier and saves time, because the main task of mode switching is to switch the context of process registers.
  • The process context is mainly exception handlers and kernel threads . The reason why the kernel enters the process context is because some work of the process itself needs to be done in the kernel. For example, a system call serves the current process, and an exception is usually an error state caused by the processing process. So it makes sense to refer to current in the context of the process.

Interrupt context

  • The hardware sends an interrupt signal to the CPU through the trigger signal, causing the kernel to call the interrupt handler and enter the kernel space. In this process, some hardware variables and parameters are also passed to the kernel, and the kernel performs interrupt processing through these parameters.
    Therefore, the "interrupt context" can be understood as the parameters passed by the hardware and some environments that the kernel needs to save, mainly the environment of the interrupted process.
    The kernel enters the interrupt context because of the interrupt processing or soft interrupt caused by the interrupt signal. The occurrence of interrupt signals is random, and interrupt handlers and soft interrupts cannot predict in advance which process is currently running when the interrupt occurs, so it is possible to reference current in the interrupt context, but it does not make sense.
    In fact, the interrupt signal that the A process wants to wait for may occur during the execution of the B process. For example, process A starts a disk write operation, process B is running after process A sleeps, and process B is interrupted by a disk interrupt signal after the disk is written, and process A is awakened during interrupt processing.

Process context vs interrupt context

  • The kernel can be in two contexts: process context and interrupt context .
    After the system call, the user application enters the kernel space, and then the kernel space runs in the process context for the representative of the corresponding process in the user space .
  • Asynchronous interrupts will cause the interrupt handler to be called, and the interrupt handler runs in the interrupt context .
    Interrupt context and process context cannot occur at the same time. The kernel code
    running in the process context is preemptible , but the interrupt context will run until the end and will not be preempted. Therefore, the kernel restricts the work of the interrupt context and does not allow it to perform the following operations :
  1. Enter the sleep state or actively give up the CPU.
    Because the interrupt context does not belong to any process, it has nothing to do with current (although current points to the interrupted process at this time), so once the interrupt context sleeps or gives up the CPU, it cannot be awakened. So it is also called atomic context.
  2. Occupy mutexes
    To protect the resources of the critical section of the interrupt handler, mutexes cannot be used. If the semaphore cannot be obtained, the code will sleep, and the same situation as above will occur. If a lock must be used, spinlock is used.
  3. Performing time-consuming tasks
    Interrupt processing should be as fast as possible, because the kernel has to respond to a large number of services and requests, and the interrupt context takes too long to take up the CPU time and will seriously affect system functions. When performing time-consuming tasks in an interrupt handling routine, it should be handled by the bottom half of the interrupt handling routine.
  4. Access to user space virtual memory
    Because the interrupt context is not related to a specific process, it is the kernel running in the kernel space on behalf of the hardware, so the user space virtual address cannot be accessed in the interrupt context
  5. Interrupt handling routines should not be set to reentrant (routines that can be called in parallel or recursively)
    because when an interrupt occurs, both preempt and irq are disabled until the interrupt returns. Therefore, the interrupt context is not the same as the process context, and different instances of interrupt processing routines are not allowed to run concurrently on SMP.
  6. The interrupt handling routine can be interrupted by higher-level IRQ
    If you want to disable this interrupt, the interrupt handler can be defined as the rapid processing routines, the equivalent of telling CPU, the routine runs, disable all interrupts on the local CPU request. The direct result of this is that the system performance is degraded because other interrupts are delayed in response.

Atomic context

A basic principle of the kernel is: in an interrupt or atomic context, the kernel cannot access user space, and the kernel cannot sleep . That is to say, in this case, the kernel cannot call any function that may cause sleep. Generally speaking, the atomic context refers to the interrupt or soft interrupt, and while holding a spin lock . The kernel provides four macros to determine whether it is in these situations:

  • The count accessed by these four macros is thread_info->preempt_count. This variable is actually a bit mask. The lowest 8 bits represent the preemption count, which is usually modified by spin_lock/spin_unlock, or forcibly modified by the programmer, and indicates that the maximum preemption depth allowed by the kernel is 256.
  • Bit 8-15 is the soft interrupt count, which is usually modified by local_bh_disable/local_bh_enable, and indicates that the maximum soft interrupt depth allowed by the kernel is 256.
  • Bit 16-27 is the hard interrupt count, which is usually modified by enter_irq/exit_irq, and indicates that the maximum hard interrupt depth allowed by the kernel is 4096.
  • The 28th bit is the PREEMPT_ACTIVE flag. The code means:
    PREEMPT_MASK: 0x000000ff
    SOFTIRQ_MASK: 0x0000ff00
    HARDIRQ_MASK: 0x0fff0000

All the places where the above 4 macros return 1 are atomic contexts . The kernel is not allowed to access user space, the kernel is not allowed to sleep, and any functions that may cause sleep are not allowed to be called. **And it means that thread_info->preempt_count is not 0, which tells the kernel that preemption is disabled.
However, for in_atomic(), when preemption is enabled, it works very well. It can tell the kernel whether it currently holds a spinlock, whether to disable preemption, etc. However, when preemption is not enabled, spin_lock does not modify preempt_count at all, so even if the kernel calls spin_lock and holds the spin lock, in_atomic() still returns 0, which incorrectly tells the kernel that it is currently in a non-atomic context. Therefore, any code that relies on in_atomic() to determine whether it is in the atomic context is problematic when preemption is prohibited.

Blog content reference: https://mp.weixin.qq.com/s?src=11×tamp=1563710917&ver=1742&signature=QR4lcgtbcKzOvDFLwoqFNplQTjSK7GewpVDBCvNpaXRozYEwcUOrFTqWKf5XsDAp00ySWlARSnQsnzDVXewoqWKf5XsDAp00ySWlARSnQsnzDV=1563710917

Guess you like

Origin blog.csdn.net/qq_41782149/article/details/96754633