[英]Linux 64 bit context switch
in the switch_to macro in 32 bit mode, there the following code is executed before the __switch_to function is called: 在32位模式的switch_to宏中,在调用__switch_to函数之前执行以下代码:
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" /* restore EIP */ \
__switch_canary \
"jmp __switch_to\n" /* regparm call */
The EIP is pushed onto the stack (restore EIP). EIP被压入堆栈(恢复EIP)。 When __switch_to finishes, there is a ret which returns to that location.
当__switch_to完成时,会有一个返回到该位置的ret。 Here is the corrsponding 64 bit code:
这是相应的64位代码:
asm volatile(SAVE_CONTEXT \
"movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */ \
"movq %P[threadrsp](%[next]),%%rsp\n\t" /* restore RSP */ \
"call __switch_to\n\t"
There, only the rsp is saved and restored. 在那里,只保存和恢复rsp。 I think that the RIP is already at the top of stack.
我认为RIP已经处于堆栈顶部。 But I cannot find the instruction where that is done.
但是我无法找到指示的地方。 How is the 64 bit context switch, especially for the RIP register, actually done?
如何实际完成64位上下文切换,特别是对于RIP寄存器?
Thanks in advance! 提前致谢!
In 32 bit kernel, the thread.ip
may be one of: 在32位内核中,
thread.ip
可能是以下之一:
1
label in switch_to
switch_to
的1
标签 ret_from_fork
ret_from_kernel_thread
The return to the proper place is ensured by simulating a call
using a push
+ jmp
pair. 通过使用
push
+ jmp
对模拟call
来确保返回正确的位置。
In 64 bit kernel, thread.ip
is not used like this. 在64位内核中,
thread.ip
不是这样使用的。 Execution always continues after the call
(which used to be the 1
label in the 32 bit case). 在
call
之后执行总是继续(以前是32位情况下的1
标签)。 As such, there is no need to emulate the call
, it can be done normally. 因此,不需要模拟
call
,它可以正常完成。 Dispatching to ret_from_fork
happens using a conditional jump after __switch_to
returns (you have omitted this part): 在
__switch_to
返回后使用条件跳转调度到ret_from_fork
(您已省略此部分):
#define switch_to(prev, next, last) \
asm volatile(SAVE_CONTEXT \
"movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */ \
"movq %P[threadrsp](%[next]),%%rsp\n\t" /* restore RSP */ \
"call __switch_to\n\t" \
"movq "__percpu_arg([current_task])",%%rsi\n\t" \
__switch_canary \
"movq %P[thread_info](%%rsi),%%r8\n\t" \
"movq %%rax,%%rdi\n\t" \
"testl %[_tif_fork],%P[ti_flags](%%r8)\n\t" \
"jnz ret_from_fork\n\t" \
RESTORE_CONTEXT \
The ret_from_kernel_thread
is incorporated into the ret_from_fork
path, using yet another conditional jump in entry_64.S
: ret_from_kernel_thread
包含在ret_from_fork
路径中,使用entry_64.S
另一个条件跳转:
ENTRY(ret_from_fork)
DEFAULT_FRAME
LOCK ; btr $TIF_FORK,TI_flags(%r8)
pushq_cfi $0x0002
popfq_cfi # reset kernel eflags
call schedule_tail # rdi: 'prev' task parameter
GET_THREAD_INFO(%rcx)
RESTORE_REST
testl $3, CS-ARGOFFSET(%rsp) # from kernel_thread?
jz 1f
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.