調べているのはここにあるソース。
http://gsd.unex.es/projects/minixsmp/
u32_t find_trampoline(void) { /* Find a memory zone suitable for allocating trampoline code. It will be a 0's zone, suposing this is free. */ u32_t addr8; u32_t addr; u32_t i; u8_t c; /* size of tampoline code */ u32_t tramp_len=(u32_t)end_init_ap-(u32_t)init_ap; /* Look for a hole of free memory in each valid position of base memory */ /* For some reason 0x0000F000 is not valid!! so start form 0x10 */ for (addr8=0x11; addr8<0x100; addr8++) { if (addr8==0xA0) addr8=0xC0; /* vectors A0..BF are reserved */ addr=addr8<<12; /* aligned in 4kb boundaries */ for (i=0; i<tramp_len; i++) { phys_copy(addr+i, vir2phys(&c), 1); if (c) break; } if (i==tramp_len) { /* Prepare and copy the tampoline */ copy_registers_to_trampoline(); phys_copy(vir2phys(init_ap), addr, tramp_len); disable_operand_size(addr,tramp_len); /*dump_trampoline(addr,tramp_len);*/ return addr; /* return it */ } } return 0; }
まず、trampolineって何だ?というのを調べると、
http://wapedia.mobi/en/Trampoline_(computers)でこんな説明があったのでエキサイト翻訳したのを貼っ付けると。
「トランポリン(時々間接的なジャンプベクトルと呼ばれる)は、割り込み処理ルーチン、I/Oルーチンなどを示しながらアドレスを保持する記憶域です。 次に、実行は、すぐにトランポリンに飛びついて、飛び出るか、または弾んで、したがって、用語はトランポリンです。」
他にも、こんなところをみつけた。
http://ossmpedia.org/messages/linux/2.6.9-34.EL/59017.ja
http://www.cheesecake.org/sac/smp.html
ループに入る前にtramp_lenを設定している部分で使っている、変数は実際は変数じゃなくて、アセンブラコードのラベル。
/* size of tampoline code */
u32_t tramp_len=(u32_t)end_init_ap-(u32_t)init_ap;
アセンブラコードはxmp.sにいて、こんなデータ構造になっている。
_init_ap: C16 jmp _skip_data _data_area: ! Space for variables _gdtr_data: .data2 0x0000 ! gdt limit .data4 0x00000000 ! addr _idtr_data: .data2 0x0000 ! idt limit .data4 0x00000000 ! addr _esi_data: .data4 0x00000000 ! esi _edi_data: .data4 0x00000000 ! edi _ebp_data: .data4 0x00000000 ! ebp _skip_data: ! Mark life_flag to tell BSP we are running C16 cli ! safe from interrupts C16 mov ax, cs C16 mov ds, ax ! ds= cs (_init_ap) ! Prepare environment to jump into protected mode C16 lgdt ( [ TR_GDTR_OFFSET ] ) C16 lidt ( [ TR_IDTR_OFFSET ] ) ! Into protected mode mov eax, cr0 orb al, 1 mov cr0, eax ! Far jmp to start with 32 bit execution. ! Jump to a .text CS-addressed point C16 jmpf CS_SELECTOR:_trampoline_pm _end_init_ap:
この関数のメインループ前にあるコメントが気になる。。
/* Look for a hole of free memory in each valid position of base memory */ /* For some reason 0x0000F000 is not valid!! so start form 0x10 */
ループ先頭で行っている以下の処理は、MPの仕様書「B.4.2 USING STARTUP IPI」の説明と一致していて、
A0-BFは予約済みだから使うなよ!とか、ページ境界は4KBだからって説明が書いてあるので、それに則ってます。
if (addr8==0xA0) addr8=0xC0; /* vectors A0..BF are reserved */ addr=addr8<<12; /* aligned in 4kb boundaries */
そんで、次の処理に移っていって、copy_registers_to_trampoline()はxmp.sで実装されてて、
gdtrとidtrのデータをトランポリンコードにコピーする処理。
if (i==tramp_len) { /* Prepare and copy the tampoline */ copy_registers_to_trampoline(); phys_copy(vir2phys(init_ap), addr, tramp_len); disable_operand_size(addr,tramp_len); /*dump_trampoline(addr,tramp_len);*/ return addr; /* return it */ }
disable_operand_size()はmp.cにいるcで書かれたコードで、マシン語コードの書き変えをしている。
void disable_operand_size(u32_t trampoline_addr, u32_t trampoline_sz) { /* Change operand-size modifier codes (66h & 67h) on trampoline's machine code introduced by assembler and replace they with <nop> code (90h) */ u16_t code; u32_t code_addr=vir2phys(&code); while (trampoline_sz>1) { /* last byte not necessary to scan */ phys_copy(trampoline_addr, code_addr, 2); if ((code==0x6766)) { /* o16 a16 */ code=0x9090; /* nop nop */ phys_copy(code_addr, trampoline_addr, 2); trampoline_addr+=2; trampoline_sz-=2; } else { trampoline_addr++; trampoline_sz--; } } }
トランポリンコードが見つかれば、この後はmp_start()内でCPUの動作をスタートさせる処理が実行されていく。