简体   繁体   English

Linux 64位上下文切换

[英]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可能是以下之一:

  • the 1 label in switch_to switch_to1标签
  • 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM