About the Idle process
that is the process of pid=0. It is the first process created after the kernel has completed initialization and executes when the system is idle. Its code is simple:
for (;;) pause ();
Emphasize that the idle process is a user-state process. So the problem is that the kernel is always in the kernel state from boot to initialization, so how does the kernel create idle and switch to user state?
A straightforward idea is that the kernel directly invokes user-space code to transform the kernel-to-user-state, but this is not possible because the rules
You can't do this. What about that? This is the question to be told in this article.
process-related structures
process is a dynamic concept, to manage processes first we need to abstract this dynamic concept with some static data structures. This structure is often said to be task_struct. It contains information about the process in protected mode (such as LDT and TSS). Refer to the first few chapters of the linux0.11 kernel full comment for protection mode related knowledge. So we have to create the idle, first of all to prepare the corresponding task_struct. is directly initialized in the linux0.11:
Static Union Task_union Init_task = {init_task,};
#define INIT_TASK \
/* State etc */ {0,15,15, \
/* Signals */ 0,{{},},0, \
/* EC,BRK ... */ 0,0,0,0,0,0, \
/* pid etc.. */ 0,-1,0,0,0, \
/* UID ETC */ 0,0,0,0,0,0, \
/* Alarm */ 0,0,0,0,0,0, \
/* Math */ 0, \
/* FS Info */ -1,0022,null,null,null,0, \
/* FILP */ {NULL,}, \
{ \
{0,0}, \
/ * LDT */{0x9f,0xc0fa00}, \
{0x9f,0xc0f200}, \
}, \
/*tss*/ {0,page_size+ (long) &init_task,0x10,0,0,0,0, (long) &pg_dir,\
0,0,0,0,0,0,0,0, \
0,0,0x17,0x17,0x17,0x17,0x17,0x17, \
_ldt (0), 0x80000000, \
{} \
}, \
}
The LDT and TSS of the idle task are then placed in the global descriptor Descriptor GDT:
Set_tss_desc (gdt+first_tss_entry,& (INIT_TASK.TASK.TSS));
Set_ldt_desc (gdt+first_ldt_entry,& (Init_task.task.ldt));
kernel state---> User Configuration
The process-related information is ready, then the state is switched.
Direct invocation Obviously cannot change the privilege level, but we know that interrupt processing can be switched between different privilege levels. So the kernel uses a "simulated interrupt return" approach.
Let's take a look at what happens when CPU processing breaks:
The upper part of the coloring of the "original SS, the original ESP, the original flags, original CS, the original EIP", refers to the interrupted program SS, ESP, flags, CS, EIP, these registers into the stack and out of the stack (by the iret instruction completed) are automatically completed by the CPU, And all the other registers are handled by the programmer himself. As a reminder, CS and EIP here are used in protected mode, so CS is addressing the corresponding code snippet in the GDT (the idle code snippet and data segment are already in the previous section ready to be placed in the GDT.) )
next look at how linux0.11 is modeled as an interrupt return:
#define MOVE_TO_USER_MODE () \Switch to User state
__asm__ ("Movl%%esp,%%eax\n\t" \
"PUSHL $0x17\n\t" \ //press into the original SS (point to Idle code snippet, low two bits for cpl= 3, on behalf of user state)
"PUSHL%%eax\n\t" \ //press into the original Esp
pushfl\n\t "\ //press into the original flags
" PUSHL $0x0f\n\t "\ //< Span style= "White-space:pre" > pressed into the original CS (point to Idle code snippet, low two-bit represents cpl= 3, on behalf of the user
"PUSHL $1f\n\t" \ //press into the original EIP, point to the code following the iret instruction
/* Above the stack operation should be in the program is interrupted by the CPU auto-completion, here is manual press, manufacturing was interrupted the illusion. In order to call Iret immediately, the CPU automatically completes the stack operation of these registers, completes the kernel state to the user state switch * *
"iret\n" \ //interrupt returned by the CPU to restore the previously pressed registers.
"1:\tmovl $0x17,%%eax\n\t" \
"MOVW%%ax,%%ds\n\t" \
"MOVW%%ax,%%es\n\t" \
"MOVW%%ax,%%fs\n\t" \
"MOVW%%ax,%%gs" \
::: "Ax")
How Linux creates an idle process