Kernel version: 2.6.33.4
The switch_to macro is defined in system. H (ARCH \ x86 \ include \ ASM). The full text is as follows:
/*
* Saving eflags is important. It switches not only iopl between tasks,
* It also protects other tasks from NT leaking through sysenter etc.
*/
# Define switch_to (prev, next, last )\
Do {\
/*\
* Context-switching clobbers all registers, So we clobber
\
* Them explicitly, via unused output variables.
\
* (Eax and EBP is not listed because EBP is saved/restored
\
* Explicitly for wchan access and eax is the return value
\
* _ Switch_to ())
\
*/\
Unsigned long EBX, ECx, EDX, ESI, EDI;
\
\
ASM volatile ("pushfl \ n \ t"
/* Save flags */\
"Pushl % EBP \ n \ t"
/* Save EBP */\
"Movl % ESP, % [prev_sp] \ n \ t"
/* Save ESP */\
"Movl % [next_sp], % ESP \ n \ t"
/* Restore ESP */\
"Movl $ 1f, % [prev_ip] \ n \ t"
/* Save EIP */\
"Pushl % [next_ip] \ n \ t"
/* In this command, the restore EIP pushes the return address of line 66 to the stack, that is, the address of line 67, and the last command ret of the _ switch_to function pops up to the EIP, when this process is switched out, another process will enter */when executing 63 lines of commands */
\
_ Switch_canary
\
"JMP _ switch_to \ n"
/* Regparm call */\
"1: \ t"
\
"Popl % EBP \ n \ t"
/* Restore EBP */\
"Popfl \ n"
/* Restore flags */\
\
/* Output parameters */
\
: [Prev_sp] "= m" (prev-> thread. SP ),
\
[Prev_ip] "= m" (prev-> thread. IP ),
\
"= A" (last ),
\
\
/* Clobbered output registers :*/
\
"= B" (EBX), "= C" (ECx), "= D" (EDX ),
\
"= S" (Esi), "= D" (EDI)
\
\
_ Switch_canary_oparam
\
\
/* Input parameters :*/
\
: [Next_sp] "M" (next-> thread. SP ),
\
[Next_ip] "M" (next-> thread. IP ),
\
\
/* Regparm parameters for _ switch_to ():*/
\
[Prev] "a" (prev ),
\
[Next] "D" (next)
\
\
_ Switch_canary_iparam
\
\
:/* Reloaded segment REGISTERS */
\
"Memory ");
\
} While (0)
The macro has three variables: Prev, next, and last, which respectively refer to the previous process descriptor, the next process descriptor to be switched, and the previous process descriptor.
First, five unsigned Long Integer Variables EBX, ECx, EDX, ESI, and EDI are defined.
"= B" (EBX), "= C" (ECx), "= D" (EDX ),
\
"= S" (Esi), "= D" (EDI)
The five variables correspond to the General registers EBX, ECx, EDX, ESI, and EDI respectively.
Input variable
[Prev] "a" (prev ),
\
[Next] "D" (next)
\
We can see that the prev and next variables exist in the registers eax and EDX respectively.
Variables in the output part
"= A" (last)
We can see that the last variable exists in the register eax, that is, the last and Prev are actually a value.
The Assembly section below
"Pushfl \ n \ t"
/* Save flags */\
"Pushl % EBP \ n \ t"
/* Save EBP */
Push the values of the eflags and EBP registers into the stack, that is, the prev process stack. The current ESP should be directed to the prev process stack.
Through the definition of the output parameter, we can know that [prev_sp] and [prev_ip] correspond to (prev-> thread) respectively. SP) and (prev-> thread. IP) memory address. The definitions of [next_sp] and [next_ip] are similar.
The "movl % ESP, % [prev_sp] \ n \ t" command stores the ESP register value in the prev-> thread. SP variable;
Similarly, "movl % [next_sp], % ESP \ n \ t" sets next-> thread. when the SP variable value is moved into the ESP register, this command completes the process stack switching, because ESP points to the stack of different processes, meaning that different processes are currently running.
The "movl $ 1f, % [prev_ip] \ n \ t" command stores the address marked as 1 in the prev-> thread. IP variable memory.
"Pushl % [next_ip] \ n \ t" indicates the next-> thread of the next process. the value of the IP variable is pushed into the stack by the previous command. In general, next-> thread. the IP value is the address marked as 1 (next-> thread. the value of the IP address is the address marked as 1 below, because the next process was the prev process when it was first switched out, % [prev_ip] command is used to store the address marked as 1 into Prev-> thread. IP variable memory), this value is pushed into the stack mainly for the following "JMP
After the _ switch_to \ n "command jumps to the _ switch_to function, the __switch_to function will finally run the RET command, which will move the top value of the current stack into the EIP register, then run the command again. The address of the next command we want to run after the _ switch_to function is the address marked as 1, so we need to do this here.
The role of _ switch_canary is not very clear yet, but the command is still very simple.
The two commands run at the address marked as 1 are
"Popl % EBP \ n \ t"
/* Restore EBP */\
"Popfl \ n"
/* Restore flags */\
Corresponds to the top
"Pushfl \ n \ t"
/* Save flags */\
"Pushl % EBP \ n \ t"
/* Save EBP */\