linux核心switch_to函數

來源:互聯網
上載者:User

核心版本:2.6.33.4
switch_to宏定義在System.h (arch\x86\include\asm)中,全文如下:
/*
 * 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 of
\
* __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"
/* restore EIP   在這條指令把66行跳轉的返回地址即67行的地址壓入棧中,_switch_to函數的最後一條指令ret即可將其彈出到eip中,當這個進程在被切換出去的時候由另外一個進程在執行63行的指令時填入*/
\
    __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)

宏有三個變數:prev, next, last,分別指前一個進程描述符,下一個要切換的進程描述符,上一個進程描述符
首先定義了五個無符號長整形變數ebx, ecx, edx, esi, edi; 通過下面的輸出變數部分
      "=b" (ebx), "=c" (ecx), "=d" (edx),
\
      "=S" (esi), "=D" (edi)

可以看出這五個變數分別對應通用寄存器ebx, ecx, edx, esi, edi。
由輸入部分的變數
      [prev]     "a" (prev),
\
      [next]     "d" (next)
\
我們可以看到prev和next變數分別存在寄存器eax和edx中的
由輸出部分的變數
"=a" (last)
我們可以看到last變數分別存在寄存器eax中的,即last和prev其實是一個值

下面的彙編部分
    "pushfl\n\t"
/* save    flags */ \
    "pushl %%ebp\n\t"
/* save    EBP   */
把Eflags寄存器和ebp寄存器的值壓入棧中,即prev進程的棧中,當前的esp應該是指向prev的進程棧中
通過輸出參數部分的定義我們可以得知[prev_sp]和[prev_ip]分別對應 (prev->thread.sp)和(prev->thread.ip)的記憶體位址,[next_sp]和[next_ip]的定義也是類似的。

 "movl %%esp,%[prev_sp]\n\t"指令的作用是把esp寄存器的值存入prev->thread.sp變數中;
同理,"movl %[next_sp],%%esp\n\t"是把next->thread.sp變數的值移入esp寄存器中,這條指令即完成了進程堆棧的切換,因為esp指向不同進程的堆棧意味著當前在運行不同的進程。
"movl $1f,%[prev_ip]\n\t"指令的作用是把下面的標誌為1的地址存入prev->thread.ip變數的記憶體中

"pushl %[next_ip]\n\t"表示把next進程的next->thread.ip變數的值壓入棧中由上一條指令我們可以得知,在一般的情況下,next->thread.ip的值即為下面標誌為1的地址(next->thread.ip的值為何是下面標誌為1的地址,因為next進程在前一次被切換出去的時候是prev進程,由movl $1f,%[prev_ip]指令的作用是把標誌為1的地址存入prev->thread.ip變數的記憶體中),將此值壓入棧中主要是為了在下面"jmp
__switch_to\n"指令跳到__switch_to函數後,__switch_to函數最後會運行ret指令,此指令會把當時的棧頂值移入eip寄存器中,然後再運行;而我們希望在__switch_to函數後啟動並執行下一條指令的地址就是標誌為1的地址,故在這裡需要這麼做。
__switch_canary的作用現在還不是很明白,不過指令還是很簡單的

標誌為1的地址處啟動並執行兩條指令為
    "popl %%ebp\n\t"
/* restore EBP   */ \
    "popfl\n"
/* restore flags */ \

即對應最上面的
    "pushfl\n\t"
/* save    flags */ \
    "pushl %%ebp\n\t"
/* save    EBP   */ \

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.