読者です 読者をやめる 読者になる 読者になる

次はfind_trampoline()。

minix

調べているのはここにあるソース。
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の動作をスタートさせる処理が実行されていく。