Linux kernel stacks using methods process 0 and Process 1 "go"

Source: Internet
Author: User

Transferred from: http://blog.csdn.net/yihaolovem/article/details/37119971

Directory (?) [-]

    1. 8 How stacks are used in Linux systems
      1. 81 initialization phase
      2. 82 Stack of tasks
      3. 83 switching between the task kernel stack and the user-state stack

Chatting with a friend today, my friend said he had a weird problem writing a driver. He used a deep function call in the kernel (multiple nested functions), but did not achieve the intended effect, but if the nesting is removed, the function is no problem. I didn't think much of it at the time, so I could answer the question of the compiler. Back in the mind again emerging this problem, suddenly think of the kernel stack, think that the cause of this problem should be on the kernel stack. The following is a brief introduction to the core knowledge.

User-space-running programs can allocate a large amount of space from the stack of user space to hold variables or arrays, large structures. This can be done because the user space stack itself is relatively large, but also dynamic growth. The kernel stack of the process is not as large as it can grow dynamically; it has a kernel stack of 8KB on a 32-bit machine and a 64-bit machine is 16KB.

Each process has its own kernel stack. Each call chain of a process during kernel execution must be placed on its own kernel stack. Interrupt handlers also use the process stack with which they are interrupted. This means that in the worst case, the 8KB kernel stack may be shared by multiple function nested call chains and several interrupt programs. Oh, obviously the depth of nesting will lead to overflow.

The kernel stacks are saved by reducing local variables, large arrays and structs, and nested call chains.


How to use stacks in 5.8 Linux Systems This section outlines how the Linux kernel uses the stack from boot to system uptime. The description of this section is closely related to the kernel code and can be skipped first. Come back and study carefully when you start reading the corresponding code. The Linux 0.12 system uses 4 different stacks. The 1th type is the stack that is used temporarily when the system boots, and the 2nd is the stack that is used to initialize the kernel program after entering protected mode, which is located at the fixed location of the kernel code address space. The stack is also the user-state stack that was later used by task 0, and the 3rd is the stack that each task uses when executing kernel programs, which we call a kernel-state stack of tasks. Each task has its own independent kernel-state stack, and the 4th is the stack that the task executes in the user state, located near the end of the task (process) logical address space. There are two main reasons for using multiple stacks or using different stacks in different situations. First of all, because the actual mode into the protection mode, so that the CPU to the memory address access mode has changed, so need to readjust the set stack area. In addition, in order to solve the protection problem caused by different CPU privilege level sharing using stack, it is necessary to use different stacks to execute level 0 kernel code and to execute Level 3 user code. When a task enters the kernel state, it uses the TSS.SS0, TSS.ESP0, or kernel stack, of the privilege level 0 given in its TSS segment. The original user stack pointer is saved in the kernel stack. When the user state is returned from the kernel state, the stack using the user's state is restored. They are described separately below. 5.8.1  initialization phase (1) When power-on initialization (bootsect. S,SETUP.S) When the Bootsect code is loaded into the physical memory 0x7c00 by the ROM BIOS boot, there is no stack segment set and of course the program does not use the stack. Until Bootsect is moved to 0x9000:0, the stack segment register SS is set to 0x9000, and the stack pointer ESP register is set to 0XFF00, that is, at the top of the stack at 0X9000:0XFF00, see Boot/bootsect.s 61st, 62 rows. The stack segments set in Bootsect are also used in the SETUP.S program. This is the stack that is temporarily used when the system initializes. (2) When entering the protection mode (HEAD.S)esp set exponentially to the top of the User_stack array (see user_stack array defined in SCHED.C 67~23. At this point the stack is the stack that the kernel program uses itself. The addresses given are approximate values, which are related to the actual setup parameters at compile time. These address locations are found in the System.map file that was generated when the kernel was compiled. Figure 5-23   The stack used by the kernel when it enters protection mode (3) initialization (MAIN.C) is used in the INIT/MAIN.C program until the execution Move_to_user_mode () Code transfers control to task 0. After executing Move_to_user_mode (), MAIN.C's code is "switched" into task 0 execution. By executing the fork () system call, Init () in MAIN.C is executed in Task 1 and uses the stack of task 1. The main () itself, after being "toggled" into task 0, continues to use the kernel program's own stack as the user-state stack for task 0. A detailed description of the stack used in task 0 is described later. The 5.8.2  task stack has two stacks per task, each for user-state and kernel-state execution, and is called the user-state stack and the kernel-state stack, respectively. In addition to being at different CPU privilege levels, the main difference between the two stacks is that the kernel stack of the task is small and the amount of data saved cannot exceed the 4096– task data structure block byte, about 3KB. The user-state stack of the task can be extended within the user's 64MB space. (1) Each task (except task 0 and Task 1) has its own 64MB address space when the user state is running. When a task (process) has just been created, its user-state stack pointer is set near the end of its address space (the 64MB top) section. In fact, the end part also includes the parameters of the executing program and the environment variables, then the user stack space, which is shown in 5-24. This stack is used by the application while it is running in the user state. The actual physical memory used by the stack is determined by the CPU paging mechanism. Since Linux implements the write-time copy function (copy on write), when the process is created, if neither the process nor its parent process uses the stack, the two share the physical memory page for the same stack. The kernel memory manager allocates a new memory page for the write process only if one of the processes performs a stack write, such as a push operation. And the user stack for process 0 and Process 1 is special, see the following description. Figure 5-24   The user-state stack in the logical space (2) each task has its own kernel-state stack when the kernel is running, which is used during the execution of the task in kernel code. The position in its linear address is specified by the SS0 and Esp0 two fields in the TSS segment of the task. SS0 is the segment selector for the task kernel stack, and esp0 is the stack stack bottom pointer. Therefore, the kernel stack of the task is always empty whenever the task executes from the user code transfer into the kernel code. The task kernel stack is set at the end of the page where its task data structure is located, which is placed on the same page as the task's data structure (TASK_STRUCT). This is a new mission., the fork () program is set in the kernel-level stack fields (TSS.ESP0 and TSS.SS0) of the task TSS segment, see kernel/fork.c,92 line:    p->tss.esp0 = page_size + (long) p;    p->tss.ss0 = 0x10, where p is the task data structure pointer for the new task, and TSS is the task state segment structure. The kernel requests memory for new tasks to hold its task_struct structure data, while the TSS structure (segment) is a field in task_struct. The kernel stack segment value of the task Tss.ss0 is also set to 0x10 (that is, the kernel data segment selector), while tss.esp0 points to the end of the Save Task_struct structure page. As shown in 5-25. The tss.esp0 is actually set exponentially to a byte above the page (outside) (at the bottom of the stack in the diagram). This is because the Intel CPU performs a stack operation by decreasing the stack pointer esp value First, and then saving the stack contents at the ESP pointer. Figure 5-25   Process Kernel stack Why is a page of memory that is requested from the main memory area to hold the task data structure can also be set to the data in the kernel data segment, that is, why TSS.SS0 can be set to 0x10? This is because the user kernel stack still belongs to the kernel data space. We can illustrate this from the length range of the kernel code snippet. At the end of the HEAD.S program, the kernel code snippet and the data segment descriptor are set separately, and the length is set to 16MB. This length value is the maximum amount of physical memory that the Linux 0.12 kernel can support (see comments at the beginning of the head.s,110 line). Therefore, the kernel code can be addressed to any location in the entire physical memory range, including, of course, the main memory area. Whenever a task executes a kernel program and needs to use its kernel stack, the CPU uses the TSS structure to set its kernel stack to consist of two values, Tss.ss0 and tss.esp0. When the task is switched on, the old task's kernel stack pointer esp0 will not be saved. For the CPU, these two values are read-only. So whenever a task enters the kernel state, its kernel stack is always empty. (3) Task 0 and Task 1 stack task 0 (Idle Process idle) and Task 1 (initialization process init) stack is special, need to be specifically explained. The code snippet for task 0 and Task 1 is the same as the data segment, and the limit length is also 640KB, but they are mapped to different linear address ranges. The Subgrade address for task 0 starts with the linear address 0, and the Subgrade address for Task 1 starts at 64MB. However, they all map to the physical address 0~640kb range. This address range is the kernel code and basic dataPlace to store. After Move_to_user_mode () is executed, the kernel stacks of task 0 and Task 1 are located at the end of the page where the respective task data structures reside, and the user-state stack for task 0 is the stack used before entering protected mode, which is SCHED.C's user_stack[] The position of the array. Because task 1 replicates the user stack for task 0 when it was created, Task 0 and Task 1 share use the same user stack space at the beginning. However, when Task 1 starts running, the page table entries that are mapped to user_stack[] at task 1 are set to read-only, making task 1 cause a write-page exception when the stack operation is performed. The kernel uses a copy-on-write mechanism (see Chapter 13th, for a description of copy-on-write techniques) to assign a separate main memory area page for Task 1 as a stack space. Only then, Task 1 starts using its own separate user stack memory page. Therefore, the stack of task 0 needs to remain "clean" until task 1 actually starts to use, i.e., task 0 cannot use the stack at this time to ensure that the copied stack page does not contain the data for task 0. The kernel stack of task 0 is specified in its manual initialization task data structure, and its user-state stack is set in the stack before the analog iret returns when executing Move_to_user_mode (), as shown in Figure 5-22. We know that when the privilege-level change of control shifts, the destination code uses the new privileged-level stack, and the original privileged-level code stack pointer remains in the new stack. So here the task 0 user stack pointer is pressed into the stack that is currently in the privileged level 0, and the code pointer is pressed onto the stack, and then the iret instruction is executed to transfer control from privileged level 0 to the task 0 Code of Privilege Level 3. In this manual content stack, the original ESP value is set to still be the original position value in User_stack, and the original SS segment selector is set to 0x17, which is set as the data segment selector in the user-State local table LDT. Then the task 0 code segment Selector 0x0f pressed into the stack as a selector for the CS segment of the stack, and the next instruction pointer is pressed into the stack as the original EIP. This allows you to "return" to the code in task 0 to continue execution by executing the iret instruction. 5.8.3  the switch between the kernel-state stack and the user-state stack in <span times= "" new= "" roman ", =" "' serif '" = "lang=" en-US "style=" padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px; margin-top:0px; margin-right:0px;margin-bottom:0px; margin-left:0px; In the >linux 0.12 system, all interrupt service programs are kernel code. If a task is executing in user code when an interrupt occurs, the interrupt causes the CPU privilege level to change from level 3 to 0, when the CPU switches the user-state stack to the kernel-state stack. The CPU gets the segment selector and offset value of the new stack from the task state segment of the current task, TSS. Because the interrupt service program is in the kernel, it belongs to level 0 privileged code, so the 48-bit kernel stack pointer is obtained from the SS0 and Esp0 fields of the TSS. After locating the new stack (kernel-state stack), the CPU first presses the original user-state stack pointer SS and ESP into the kernel-state stack, then presses the contents of the flag register eflags and the return position CS, EIP into the kernel-state stack. The kernel's system call is a software interrupt, so the task calls the system into the kernel and executes the interrupt service code in the kernel. The kernel code then uses the task's kernel-state stack for the operation. Similarly, when a kernel program is entered, the stack segment and stack pointer and eflags of the user-state stack are stored in the kernel-state stack of the task as the privilege level changes (from the user state to the kernel state). The user-state stack and eflags are restored when the execution Iret exits the kernel program and returns to the user program. This procedure is shown in 5-26. Figure 5-26   the kernel state and the user-state stack if a task is running in the kernel state, a stack switch is no longer required if the CPU response is interrupted because the kernel code that the task runs on is already using the kernel stack and does not involve a change in the priority level. So the CPU only puts eflags and interrupts back to the pointer cs, EIP presses into the current kernel stack, and then executes the interrupt service process.

Linux kernel stacks using method process 0 and Process 1 "go"

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.