switch_toマクロを読んでみる。
http://w.livedoor.jp/eb639000/d/%a5%d7%a5%ed%a5%bb%a5%b9%a5%c7%a5%a3%a5%b9%a5%d1%a5%c3%a5%c1
こちらにまとめていますが、経過はブログに書いた方がよいのかもしれません・・・
switch_toマクロに付いてだいぶ読めるようになってきたので、読んでみたいと思います。
ちなみにカーネルのバージョンは、2.6.35.2です。
#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 */ \ __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)
1.EFLAGSをスタックに退避。
2.EBPレジスタをスタックに退避。
3.ESPレジスタを引数prevで渡されたtask_struct構造体のthread.spへセット。
4.引数nextで渡されたtask_struct構造体のthread.spをESPレジスタへセット。
5.ラベル1のアドレスを引数prevで渡されたtask_struct構造体のthread.ipへセット。
6.引数nextで渡されたtask_struct構造体のthread.ipをスタックに退避。
7.カナリヤ値を使用する場合はカナリヤ値の処理
8.__switch_to関数へ
9.EBPレジスタへポップ
10.EFLAGSをポップ<カナリア値の処理>
1.引数nextで渡されたtask_struct構造体の中のstack_canaryの値をEBXレジスタへセット
2.EBXレジスタの値をGSレジスタへセット(CPU固有領域へ)
カナリヤ値の処理はちょっと自信がありませんが、こんな感じだと思います。
こうしてみるとLinuxカーネル解読室と違うところはカナリヤ値に対応した点と、拡張インラインアセンブラで名前指定になった点を除けば一緒ですね。