SlideShare uma empresa Scribd logo
1 de 77
Baixar para ler offline
MinixとSMP
〜Minix SMPを読んでみる〜
     @masami256
Agenda

• Minix SMP?
• Minix SMP初期化の流れ
• トランポリンコード
Minix SMP?

• Minix SMPはMinix2.0.0でSMPを実装
  o 作者はJesús M. Álvarez Llorenteさん
  o プロジェクトのページはこちら
      http://gsd.unex.es/projects/minixsmp/
      ソースや論文(スペイン語)がダウンロード可能
• 対象アーキテクチャはx86
基本用語

• MP:Multi Processor
• BSP:Boot Strap Processor
   o コンピュータが起動したときに動いたCPU
• AP:Application Processor
   o 2〜n個目のCPU
• APIC(Advanced Programmable Interrupt Controller)
   o x86における割り込みコントローラ
• Local APIC
   o CPU内部に実装されていて、外部からの割り込みをコントロールする
• IO APIC
   o I/Oデバイスから受け取った割り込みをCPUにリダイレクトする
• IPI(Interprocessor Interrupt)
   o プロセッサ間の割り込み
Agenda

• Minix SMP?
• Minix SMP初期化の流れ
• トランポリンコード
SMPのセットアップ手順
SMPのセットアップ手順(続き)
実際の流れを追いかけよう

電源ON〜main()の間はSMPに関する処理はない
ので飛ばします
SMPのセットアップ手順
enable_cpu()の処理概要

• main()から呼ばれた場合は、BSPの有効化をする
• 今動いているCPU(this_cpu)が有効化済みかチェック
• 有効化しようとしているCPUがthis_cpuかチェック
• 同じ場合
  o enable_apic_ints()を呼んでAPCI・割り込みの有効化
  o 次に動くプロセスの選択
• 違う場合
  o CPUに割り込みメッセージを送信
enable_cpu()の処理
PUBLIC void enable_cpu(int cpu, int echo) {
 ・・・・
  if (cpu_available[cpu]==CPU_ENABLED) return;

    /* A CPU only can only enable its own APIC */
    if (cpu==this_cpu) {
       enable_apic_ints();
       cpu_available[cpu]=CPU_ENABLED;
       lock_pick_proc();
       if (echo) printk("CPU%d enabledn",cpu);
    }
    else {
       interrupt_cpu(cpu,MP_CM_ENABLE,echo);
    }
}
this_cpu
#define this_cpu   f_this_cpu()
 f_this_cpuはTHIS_CPU_SHORTマクロを呼び出すのがメインの処理。
 #define THIS_CPU_SHORT(reg)                 ;
          mov edx, (_local_apic_base)     ;
          add edx, 0x20             ;
          mov reg, FLAT_DS_SELECTOR           ;
          mov ds, reg             ;
          mov reg, (edx)            ;
          and reg, 0x0F000000          ;
          shr reg, 6*4

local_apic_baseは以下のようにmp.cにて定義。
u32_t local_apic_base=0x0FEE00000;
MPの仕様書によると、APICのデフォルトベースアドレス0FEC0_0000hと
0FEE0_0000hと記述されている。Minix SMPでは_local_apic_baseの値は
0x0FEE00000としています。
enable_apic_ints()の処理

reg = LOCAL_APIC_READ(LOCAL_APIC_SPIV);
reg |= (1<<ENABLE_APIC_SHIFT);   /* Enable APIC */
LOCAL_APIC_WRITE(LOCAL_APIC_SPIV, reg);

reg = LOCAL_APIC_READ(LOCAL_APIC_LVTL0);
reg &= ~(7<<LVT_DM_SHIFT);       /* clear delivery mode */
reg &= ~(1<<LVT_MASKED_SHIFT);       /* unmask LINTIN0 */
reg |= (LVT_DM_EXTINT<<LVT_DM_SHIFT);      /* ExtINT at LINTINT0 */
LOCAL_APIC_WRITE(LOCAL_APIC_LVTL0, reg);

reg = LOCAL_APIC_READ(LOCAL_APIC_LVTL1);
reg &= ~(7<<LVT_DM_SHIFT);        /* clear delivery mode */
reg &= ~(1<<LVT_MASKED_SHIFT);        /* ummask LINTIN1 */
reg |= (LVT_DM_NMI<<LVT_DM_SHIFT);       /* NMI at LINTINT1 */
LOCAL_APIC_WRITE(LOCAL_APIC_LVTL1, reg);
LOCAL APICへの読み書き

void LOCAL_APIC_WRITE(u32_t reg, u32_t val) {
  phys_copy_dword( vir2phys(&val), local_apic_base+reg );
}

u32_t LOCAL_APIC_READ(u32_t reg) {
  u32_t val;
  phys_copy_dword( local_apic_base+reg, vir2phys(&val) );
  return val;
}
SMPのセットアップ手順
mp_start()の処理概要

• load_fps()〜free_trampoline()までの処理を順番に呼び出し
• 関数の終了時点でAPが起動するようになる
mp_start()の処理
void mp_start() {
 ・・・・
  if (load_fps()) {
    if (load_mph()) {
       process_mp_configuration();
       if ((trampoline_addr=find_trampoline())) {
          FOR_EACH_AP(cpu) {
 ・・・・
               send_init_ipi(trampoline_addr, cpu);
            send_startup_ipi(trampoline_addr, cpu);
           }
          free_trampoline(trampoline_addr);
       }
SMPのセットアップ手順
load_fps()概要
• MP floating structure pointer(fps)を読み込みます
• MP floating structure pointer?
  o 16バイトの大きさのテーブル
  o MP機能に関する情報を保持しています
      特に「MP Configuration table」のアドレスを保持し
       ているのが重要なポイントです
  o 規程のアドレス内に存在(MPの仕様書で定義)
      Extended BIOS Data Area(EBDA)の最初の1KB以内
      EBDAが定義されていない場合は、ベースメモリ
       領域の最後の1KB(ベースメモリ領域が640KBな
       ら639-640KBの範囲)以内
      0F0000h〜0FFFFFの範囲(BIOSのROM内)
fps構造体

struct floating_pointer {
 char fp_signature[4];     /* must be _MP_ */
 u32_t fp_mp_table;       /* address to MP table */
 u8_t fp_length;           /* FPS size in 16-byte parragraphs */
 u8_t fp_version;         /* version number: 04h for 1.4 */
 u8_t fp_cheksum;          /* bytes in FPS must sum 0 */
 u8_t fp_sd_config_num; /* standar config number (0 for none) */
 u8_t fp_imcrp;           /* bit 7 is IMCR present and PIC mode */
 char unused[3];          /* last 3 bytes are reserved */
};
fps構造体

• fpsの先頭4バイトはシグネチャです
   o シグネチャは"_MP_"であることと規定されてます
• OSがfpsを探すときはfpsが置かれているべきアドレスを起点
  とします
   o そこから16バイトおきにメモリの内容を読み込みます
• 読み込んだ16バイトの領域がfpsかは、シグネチャとチェッ
  クサムで確認します
• チェックサムの確認はfpsの領域(16バイト)を1バイトずつ読
  み込んで数値として足し算していき、結果が0ならOKとなり
  ます
load_fps()処理内容
最初にシグネチャのチェックを実行
/* fisrt look for signature */
for (i=0; i<4; i++)
  if (fps->fp_signature[i] != SIGN_FPS[i]) return 0;

シグネチャが正しければチェックサムを計算
 /* then calculate checksum*/
 data=(unsigned char *)fps;
 checksum=0;
 for (i=0; i<sizeof (struct floating_pointer); i++)
   checksum+= data[i];
 return (!checksum); /* checksum ok if sums 0 */
SMPのセットアップ手順
load_mph()概要

• fpsを読み込めたら次はMP Configuration table
    Header(mpch)を読み込みます
•   mpchが置かれているアドレスは fps構造体のfp_mp_table
    から取得します
•    MP Configuration table Header?
     o 「MP Configuration table」のヘッダです(キリッ
     o 5種類あり、サイズも各テーブルで違います
•    MP Configuration tableを読み込むために必要な情報をこ
    こから取得します
•   load_mph()で使用するのは、2個のフィールドだけです
     o fpsと同じく、シグネチャとチェックサム
MP Configuration table

•   テーブルの種類はENTRY TYPEにより識別
•   ENTRY TYPEは5種類
•    各テーブルはメモリ上で連続
•   各項目はオプショナル(必須ではない)
      Entry Description            Entry Type Code
      Processor                                      0
      Bus                                            1
      I/O APIC                                       2
      I/O Interrupt Assignment                       3
      Local Interrupt Assignment                     4
mp_config_headerの構造体
/* Describes the estruct of MP configuration table header */
struct mp_config_header {
  char mpch_signature[4];              /* must be "PCMP" */
  u16_t mpch_length;                 /* base table size including header */
  u8_t mpch_version;                 /* MP specification version number*/
  u8_t mpch_checksum;                /* base table + checksum must sum 0 */
  char mpch_oem_id[8];                /* manufacturer id (space filled) */
  char mpch_product_id[12];           /* product id (space filled) */
  u32_t mpch_oem_table;              /* optional manufacturer table address */
  u16_t mpch_oem_table_size;          /* manufacturer table size */
  u16_t mpch_entry_count;            /* entry count in MP table */
  u32_t mpch_apic_addr;              /* IO address for local APIC */
  u16_t mpch_extended_length;         /* extended table length */
  u8_t mpch_extended_checksum; /* extended table checksum */
  char mpch_reserved;               /* unused */
};
load_mph()処理内容
シグネチャのチェック
 /* first match the signature */
 for (i=0; i<4; i++)
   if (mph.mpch_signature[i] != SIGN_MP_C_HEADER[i] )
      return 0;

チェックサムのチェック
 /* then calculate checksum */
 checksum=0;
 for (i=0; i<mph.mpch_length; i++) {
   /* the complete table is in another segment, so we need copy
     each byte into kernel address space (mph is only the header) */
   phys_copy(fps.fp_mp_table+i, vir2phys(&data), 1);
   checksum +=data;
 }
 return (!checksum); /* checksum ok if sums 0 */
SMPのセットアップ手順
process_mp_configuration()概要

• MP Configuration table数分(mph.mpch_entry_count)データ
  の読み込みを行います
• 1個目のMP Configuration tableのアドレスは以下のように求
  めます
   o next=fps.fp_mp_table+sizeof (struct mp_config_header);
• アドレスが分かってもENTRY TYPEが分からないので最初に
  1バイトだけ読みこんでENTRY TYPEの判別をします
• ENTRY TYPEが分かったら、そのENTRY TYPEに応じた
  データの読み込みをします
• ENTRY TYPEは5種類ですが、そのうち3種類はMinix SMP実
  装では特に使用せずに読み飛ばしています
process_mp_configuration()処理内容
while (i-- > 0) {
   phys_copy(next, vir2phys(&this_entry), 1);
   switch (this_entry) {
      case CPU_ENTRY_ID : // Processor
     ・・・
        case BUS_ENTRY_ID : // Bus
       ・・・
        case IO_APIC_ENTRY_ID : // I/O APIC
     ・・・
        case IO_INT_ENTRY_ID : // I/O Interrupt Assignment
     ・・・
        case LOCAL_INT_ENTRY_ID : // Local Interrupt Assignment
     ・・・
        default :
     ・・・
     }
}
Processor Entriesの構造体

struct cpu_entry {
  u8_t ce_type;              /* 0 for this type */
  u8_t ce_local_apic_id;    /* local APIC id number */
  u8_t ce_local_apic_ver;   /* local APIC version */
  u8_t ce_flags;             /* CPU enabled and CPU is bootstrap */
  u32_t ce_signature;       /* CPU type */
  u32_t ce_features;        /* features of this CPU */
  char reserved[8];         /* reserved */
};
Processor Entriesの処理概要

• CPUが有効かチェックする
• CPU FLAGSフィールド(ce_flags)を調べる
  o 大きさは1バイトで2種類(各1bit)のビットがあります
  o ENビットが0なら、このCPUは無効
      無効の場合、このCPUは使用禁止
  o BPビットが1なら、このCPUはBSP
• CPUが有効かどうかのチェックは必須です
Processor Entriesの処理

     case CPU_ENTRY_ID :
        if (++cpu_count > 2)
          ADDS_MP_STATUS("MP PANIC: only 2 cpus currently
supported!n");
        phys_copy(next,vir2phys(&ce),sizeof(struct cpu_entry));
        next+=sizeof(struct cpu_entry);
        PRINT_CPU_ENTRY(cpu);
        if ((ce.ce_flags & CE_EN_FLAG_MASK)==0)
          ADDS_MP_STATUS("MP PANIC: disabled apics not
currently supportedn");
        break;
I/O APIC Entriesの構造体

struct io_apic_entry {
  u8_t ae_type;         /* 2 for this type */
  u8_t ae_id;          /* IO APIC identification */
  u8_t ae_version;     /* IO APIC version number */
  u8_t ae_flags;        /* bit 0 means enabled */
  u32_t ae_address;     /* IO APIC memory address */
};
I/O APIC Entriesの処理概要

• I/O APIC Entriesで見なければいけないところ
   o ENビット(1bit)
       CPU EntriesのENビットと同じく、有効なら1 になる
   o I/O APIC ADDRESS
       APICへ読み書きするときに使うアドレス
I/O APIC Entriesの処理

     case IO_APIC_ENTRY_ID :
        if (++apic_count > 1)
          ADDS_MP_STATUS("MP PANIC: only 1 I/O APIC
currently supported!n");
        phys_copy(next,vir2phys(&ae),sizeof(struct io_apic_entry));
        next+=sizeof(struct io_apic_entry);
        /*PRINT_IO_APIC_ENTRY(ae);*/
        if ((ae.ae_flags & AE_EN_FLAG_MASK)==0)
          ADDS_MP_STATUS("MP PANIC: disabled apic not
currently supported!");
        io_apic_base=ae.ae_address;
        break;
SMPのセットアップ手順
find_trampoline()の処理概要

• メモリ上でトランポリンコードを置く場所を探します
• トランポリンコード?
  o トランポリン(時々間接的なジャンプベクトルと呼ばれ
    る)は、割り込み処理ルーチン、I/Oルーチンなどを示しな
    がらアドレスを保持する記憶域です。 次に、実行は、す
    ぐにトランポリンに飛びついて、飛び出るか、または弾
    んで、したがって、用語はトランポリンです。
      http://wapedia.mobi/en/Trampoline_(computers)
• トランポリンコードはAPの初期化時に必要です
  o x86系CPUはリアルモードで起動するので、プロテクト
    モードに移行したりといった処理がAPも必要です
find_trampoline()の処理概要

•   トランポリンコードのサイズを計算
•   トランポリンコードを置ける場所の探索
•   GDT、IDTをレジスタにコピー
•   トランポリンコードを見つかった場所にコピー
•   トランポリンコード中のマシン語コードの書き換え
find_trampoline()の処理1
 /* size of tampoline code */
 u32_t tramp_len=(u32_t)end_init_ap-(u32_t)init_ap;

 • tramp_lenを設定している部分で使っている、名前は変数
   じゃなくて、アセンブラコードのラベルです
    o トランポリンコードをラベルで囲ってます
 _init_ap:
     C16 jmp _skip_data
       ・・・
       C16 jmpf CS_SELECTOR:_trampoline_pm
_end_init_ap:
find_trampoline()の処理2
  /* 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文は、MPの仕様書「B.4.2 USING STARTUP
  IPI」の説明と一致していて、A0-BFは予約済みだから使うな
  よ!とか、ページ境界は4KBだ!と説明が書いてあるので、
  それに則ってます。
find_trampoline()の処理3

 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 */
 }
copy_registers_to_trampoline()の処理

_copy_registers_to_trampoline:
    ! Copy gdt and idt
         sgdt (_gdtr_data)
         sidt (_idtr_data)
    ! Copy 32-bit regsiters
         mov eax, esi
         mov (_esi_data), eax
         mov eax, edi
         mov (_edi_data), eax
         mov eax, ebp
         mov (_ebp_data), eax
         ret
disable_operand_size()の処理
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) *//
  ・・・・
   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--;
    }
  }
}
SMPのセットアップ手順
send_init_ipi()の処理概要

• APを起動させる前にipiを初期化します
• MPの仕様書「Appendix A System BIOS Programming
  Guidelines」と「Appendix B Operating System Programming
  Guidelines」あたりに詳しく書かれています
send_init_ipi()の処理1

/* Reprogram warm reset: write code 0A at CMOS addr 0F */
old_cmos=cmos_read(0x0F);
cmos_write(0x0F, 0x0A);

/* save old reset vector at 40:67 (dw) */
phys_copy(0x467,vir2phys(&old_vector), sizeof(u32_t));

• まず、CMOSに0Aを書き込んでPCをwarm resetします
  o PCの電源をOFFにしないで再起動
• reset vectorのバックアップを取ります
  o 0x467の意味は「warm-reset vector, which is a doubleword
    pointer in system RAM location 40:67h」と説明があります
send_init_ipi()の処理2

/* program reset vector to point at trampoline */
value=(trampoline_addr >> 4);          /* trampoline segment */
phys_copy(vir2phys(&value), 0x469, sizeof(u16_t));
value=(trampoline_addr & 0xF);          /* trampoline offset */
phys_copy(vir2phys(&value), 0x467, sizeof(u16_t));

• トランポリンコードのアドレスをアドレス0x467、0x469に
  書き込みます
send_init_ipi()の処理3
/* send the IPI (assert) */
apic_error_status();        /* first, clear previous errors */
LOCAL_APIC_WRITE(LOCAL_APIC_ICR_HIGH, icr_h);
LOCAL_APIC_WRITE(LOCAL_APIC_ICR_LOW, icr_l);
wait_for_ipi_completion();

/* send the IPI (deassert) */
apic_error_status();       /* first, clear previous errors */
icr_l ^= (1<<LEVEL_SHIFT); /* switch to deassert */
LOCAL_APIC_WRITE(LOCAL_APIC_ICR_HIGH, icr_h);
LOCAL_APIC_WRITE(LOCAL_APIC_ICR_LOW, icr_l);
wait_for_ipi_completion();

• しばらくデータの設定が続いてから、実際にデータを書き込
  んでいきます
send_init_ipi()の処理4

/* restore old reset vector and cmos shutdown code */
phys_copy(vir2phys(&old_vector), 0x467, sizeof(u32_t));
cmos_write(0x0F, old_cmos);

• 最後に、バックアップしたreset verctorを書き戻します
• これでIPIの初期化が終りです
SMPのセットアップ手順
send_startup_ipi()の処理概要

• この関数は引数を2個受け取ります
  o trampoline_addrはトランポリンのアドレス
  o which_cpuは起動させたいcpu番号
       this_cpuマクロで取得したcpu番号です
• この関数でipiを有効にすることで、APが起動するようにな
  ります
send_startup_ipi()の処理1
 /* put addr in 8 bit lower */
 trampoline_addr = (trampoline_addr >> 12) & 0xFF;

 /* prepare to send STARTUP IPI */
 icr_h = LOCAL_APIC_READ(LOCAL_APIC_ICR_HIGH);
 icr_l = LOCAL_APIC_READ(LOCAL_APIC_ICR_LOW);
  ・・・・
  icr_l |= (DELIVERY_STARTUP<<DELIVERY_SHIFT); /* stablish STARTUP */
 icr_l |= (1 << LEVEL_SHIFT);      /* level = assert */
 icr_l &= ~(1 << TRIGGER_SHIFT);       /* trigger = edge */
 icr_l |= (PHYSICAL_DEST << DEST_MODE_SHIFT); /* destination = physical */
 icr_l |= (DEST_FIELD << DEST_SHORT_SHIFT); /* destination by field */

 icr_l |= trampoline_addr;       /* vector field */
 icr_h |= (which_cpu << DEST_FIELD_SHIFT); /* cpu to interrupt */
send_startup_ipi()の処理2

/* send the IPI */
apic_error_status();
LOCAL_APIC_WRITE(LOCAL_APIC_ICR_HIGH, icr_h);
LOCAL_APIC_WRITE(LOCAL_APIC_ICR_LOW, icr_l);
wait_for_ipi_completion();

• 書き込み方法はsend_init_ipi()と同じです
• これで、APが起動します
APが起動したかの確認

• send_startup_ipi()でAPを起動させたら、mp_start()で 本当に
  APが起動したか確認をします。

 if (! AP_running()) {
       ADDS_MP_STATUS("nn*** WARNING! AP#");
       ADDN_MP_STATUS(cpu,10,1);
       ADDS_MP_STATUS(" is not running ***nn");
}
SMPのセットアップ手順
free_trampoline()の処理

• トランポリンコードを置く場所を探したときに使用したア
  ドレスに0を書き込んで置きます

void free_trampoline(u32_t addr) {
/* Restore with 0's the memory zone used for trampoline */

    char dummy=0;
    u32_t tramp_len=(u32_t)end_init_ap-(u32_t)init_ap;
    while (tramp_len--) phys_copy((u32_t)&dummy,addr++,1);
}
Agenda

• Minix SMP?
• Minix SMP初期化の流れ
• トランポリンコード
トランポリンコードの処理

• トランポリンコードでは実際にどんなことをするのか?
  o Mark data area to tell the BSP we are running in real mode
  o Read values of many registers to prepare environment to jump
    into protected mode in same conditions as BSP
  o Change to protected mode
  o Jump to protected mode trampoline section
• トランポリンコードはアセンブラのコードですが、最終的
  にap_main()というCの関数を呼び出すまでが一連の処理です
トランポリンコードの処理
トランポリンコードの処理概要

• リアルモードからプロテクトモードに移行し、次の処理に
  進む
  o cs・dsレジスタの設定
  o gdtr、idtrの設定
  o プロテクトモード移行
  o _trampolin_pmへセグメントジャンプ
トランポリンコード(データ定義)
.sect .data
.align 16

#define C16        o16 a16

_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:
    hlt
トランポリンコードの処理
trampoline_pm()の処理概要

• 各種レジスタの設定
• TSSの設定
   o Task State Segmentの略
   o タスク状態の保存・復元に使用するデータ領域
   o x86ではTSSを使ってタスクを切り替えることができる
• スタックの設定
• キャッシュの有効化
• ap_main()のコール
trampoline_pm()の処理
_trampoline_pm:
     ! We are in protected mode. Load AP registers as in BSP
           ・・・・・
! Load TSS of this ap
          ・・・・・
              ltr ax              ! load TSS
     ! Now we are ready to address as usual and execute normal
     ! kernel code, so, lets go
     ! Each CPU needs its own stack space inside kernel stack
     ! Make esp point to cpus stack top
          THIS_CPU(eax)
          SET_CPU_STK(eax)
     ! Enable AP cache
          call _enable_cache
     ! Continue in C code
          call _ap_main
トランポリンコードの処理
enable_cache()の概要

• CPUのキャッシュを有効にします
• CR0レジスタのCDとNWビットを0にします
  o CDビット:0にすることでキャッシュを有効化
  o NWビット:0ならキャッシュヒット時にライトバックす
    る
      486の場合はライトスルー

   31                         0
    P C N                 P
    G D W                 E
enable_cache()の処理

_enable_cache:
         mov ax, cr0
         and ax, 0x9FFFFFFF   ! 100111111111...111
         mov cr0, ax
         wbinv
トランポリンコードの処理
ap_main()の処理概要

• enable_cpu()を呼んでAPを有効にする
• 次に動くプロセスを選ぶ
   o lock_pick_proc()
   o pick_proc()のロックを使う版
• そのプロセスを動かす
   o restart()
   o restart()はminixに元々ある関数で、kernel/main..cのmain()
     最後の処理でも使っている
ap_main()の処理

/* This is the main routine for AP's. This is the entry point before
  the CPU has been started and jumped to protected mode */

 /* Tell BSP we are running */
 ap_running_flag=AP_LIFE_FLAG_MARK;

 /* Now we're ready to take some work. We find any task and call
   restart() to execute it (or to idle), but we must synchonize
   other cpus before enter kernel code */
 lock_mp_kernel(); /* restart() will unlock later */
ap_main()の処理

/* Enable APIC interrupt aceptance */
enable_cpu(this_cpu,WITHOUT_ECHO);

/* Now, kernel is our! */
lock_pick_proc(); /* Is there any work? */
restart();     /* Let's go... */
トランポリンコードの処理
enable_cpu()の処理概要

• ap_main()から呼ばれた場合は、APの有効化をする
• 今動いているCPUが有効化済みかチェック
• 有効化しようとしているCPUがthis_cpuかチェック
• 同じ場合
   o enable_apic_ints()を呼んでAPCI・割り込みの有効化
   o 次に動くプロセスの選択
• 違う場合
   o CPUに割り込みメッセージを送信
At last

• これでSMPが完全に有効になりましたヽ(*´∀`)ノ キャッ
  ホーイ!!
Link

• MultiProcessor Specification
  o http://www.intel.com/design/pentium/datashts/242016.HTM
• Minix3
  o http://www.minix3.org/
• はてダ
  o http://d.hatena.ne.jp/masami256

Mais conteúdo relacionado

Mais procurados

PHPとシグナル、その裏側
PHPとシグナル、その裏側PHPとシグナル、その裏側
PHPとシグナル、その裏側do_aki
 
signal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何かsignal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何かdo_aki
 
Ylug 110th kpatch code reading
Ylug 110th kpatch code readingYlug 110th kpatch code reading
Ylug 110th kpatch code readingMasami Hiramatsu
 
あるコンテキストスイッチの話
あるコンテキストスイッチの話あるコンテキストスイッチの話
あるコンテキストスイッチの話nullnilaki
 
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)Hiraku Toyooka
 
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。Kazuki Onishi
 
PHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 とPHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 とdo_aki
 
OPcache の最適化器の今
OPcache の最適化器の今OPcache の最適化器の今
OPcache の最適化器の今y-uti
 
きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回Tomoya Kawanishi
 
Deep Dive async/await in Unity with UniTask(UniRx.Async)
Deep Dive async/await in Unity with UniTask(UniRx.Async)Deep Dive async/await in Unity with UniTask(UniRx.Async)
Deep Dive async/await in Unity with UniTask(UniRx.Async)Yoshifumi Kawai
 
Node-v0.12の新機能について
Node-v0.12の新機能についてNode-v0.12の新機能について
Node-v0.12の新機能についてshigeki_ohtsu
 
2011.06.11 v7から始めるunix まとめ
2011.06.11 v7から始めるunix まとめ2011.06.11 v7から始めるunix まとめ
2011.06.11 v7から始めるunix まとめMakiko Konoshima
 
GoogleのSHA-1のはなし
GoogleのSHA-1のはなしGoogleのSHA-1のはなし
GoogleのSHA-1のはなしMITSUNARI Shigeo
 
4章 Linuxカーネル - 割り込み・例外 2
4章 Linuxカーネル - 割り込み・例外 24章 Linuxカーネル - 割り込み・例外 2
4章 Linuxカーネル - 割り込み・例外 2mao999
 
関東GPGPU勉強会 LLVM meets GPU
関東GPGPU勉強会 LLVM meets GPU関東GPGPU勉強会 LLVM meets GPU
関東GPGPU勉強会 LLVM meets GPUTakuro Iizuka
 
仮想記憶入門 BSD-4.3を例題に
仮想記憶入門 BSD-4.3を例題に仮想記憶入門 BSD-4.3を例題に
仮想記憶入門 BSD-4.3を例題にmagoroku Yamamoto
 
Task Spooler を試した
Task Spooler を試したTask Spooler を試した
Task Spooler を試したy-uti
 

Mais procurados (20)

PHPとシグナル、その裏側
PHPとシグナル、その裏側PHPとシグナル、その裏側
PHPとシグナル、その裏側
 
signal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何かsignal の話 或いは Zend Signals とは何か
signal の話 或いは Zend Signals とは何か
 
Ylug 110th kpatch code reading
Ylug 110th kpatch code readingYlug 110th kpatch code reading
Ylug 110th kpatch code reading
 
あるコンテキストスイッチの話
あるコンテキストスイッチの話あるコンテキストスイッチの話
あるコンテキストスイッチの話
 
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
 
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。
 
PHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 とPHP と SAPI と ZendEngine3 と
PHP と SAPI と ZendEngine3 と
 
OPcache の最適化器の今
OPcache の最適化器の今OPcache の最適化器の今
OPcache の最適化器の今
 
Mincs 日本語版
Mincs 日本語版Mincs 日本語版
Mincs 日本語版
 
きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回
 
Deep Dive async/await in Unity with UniTask(UniRx.Async)
Deep Dive async/await in Unity with UniTask(UniRx.Async)Deep Dive async/await in Unity with UniTask(UniRx.Async)
Deep Dive async/await in Unity with UniTask(UniRx.Async)
 
Node-v0.12の新機能について
Node-v0.12の新機能についてNode-v0.12の新機能について
Node-v0.12の新機能について
 
2011.06.11 v7から始めるunix まとめ
2011.06.11 v7から始めるunix まとめ2011.06.11 v7から始めるunix まとめ
2011.06.11 v7から始めるunix まとめ
 
ゆるバグ
ゆるバグゆるバグ
ゆるバグ
 
V6 unix in okinawa
V6 unix in okinawaV6 unix in okinawa
V6 unix in okinawa
 
GoogleのSHA-1のはなし
GoogleのSHA-1のはなしGoogleのSHA-1のはなし
GoogleのSHA-1のはなし
 
4章 Linuxカーネル - 割り込み・例外 2
4章 Linuxカーネル - 割り込み・例外 24章 Linuxカーネル - 割り込み・例外 2
4章 Linuxカーネル - 割り込み・例外 2
 
関東GPGPU勉強会 LLVM meets GPU
関東GPGPU勉強会 LLVM meets GPU関東GPGPU勉強会 LLVM meets GPU
関東GPGPU勉強会 LLVM meets GPU
 
仮想記憶入門 BSD-4.3を例題に
仮想記憶入門 BSD-4.3を例題に仮想記憶入門 BSD-4.3を例題に
仮想記憶入門 BSD-4.3を例題に
 
Task Spooler を試した
Task Spooler を試したTask Spooler を試した
Task Spooler を試した
 

Destaque

Minix3 fosdem2014
Minix3 fosdem2014Minix3 fosdem2014
Minix3 fosdem2014keesj
 
‘fsck’ for Openstack
‘fsck’ for Openstack‘fsck’ for Openstack
‘fsck’ for OpenstackWei Tian
 
Educational operating system-Minix&Weenix
Educational operating system-Minix&WeenixEducational operating system-Minix&Weenix
Educational operating system-Minix&WeenixStudent
 
Do journaling filesystems guarantee against corruption after a power failure (1)
Do journaling filesystems guarantee against corruption after a power failure (1)Do journaling filesystems guarantee against corruption after a power failure (1)
Do journaling filesystems guarantee against corruption after a power failure (1)Rudhramoorthi Andiappan
 
Scrubbing and gowning
Scrubbing and gowningScrubbing and gowning
Scrubbing and gowningAhmad Sulong
 
Open suse
Open suseOpen suse
Open suseixxxan
 
Solaris OS
Solaris OSSolaris OS
Solaris OSSSA KPI
 
HP Unix administration
HP Unix administrationHP Unix administration
HP Unix administrationHemnath R.
 
Solaris Operating System - Oracle
 Solaris Operating System - Oracle Solaris Operating System - Oracle
Solaris Operating System - OracleMalan Amarasinghe
 
Solaris Operating System
Solaris Operating SystemSolaris Operating System
Solaris Operating SystemJoshua Guillano
 
Presentation1 linux os
Presentation1 linux osPresentation1 linux os
Presentation1 linux osjoycoronado
 

Destaque (20)

STUDY EDUCATIONAL OPERATING SYSTEM MINIX OPERATING SYSTEM AND DEVELOP REASO...
STUDY  EDUCATIONAL OPERATING  SYSTEM MINIX OPERATING SYSTEM AND DEVELOP REASO...STUDY  EDUCATIONAL OPERATING  SYSTEM MINIX OPERATING SYSTEM AND DEVELOP REASO...
STUDY EDUCATIONAL OPERATING SYSTEM MINIX OPERATING SYSTEM AND DEVELOP REASO...
 
Minix3 fosdem2014
Minix3 fosdem2014Minix3 fosdem2014
Minix3 fosdem2014
 
‘fsck’ for Openstack
‘fsck’ for Openstack‘fsck’ for Openstack
‘fsck’ for Openstack
 
Educational operating system-Minix&Weenix
Educational operating system-Minix&WeenixEducational operating system-Minix&Weenix
Educational operating system-Minix&Weenix
 
Do journaling filesystems guarantee against corruption after a power failure (1)
Do journaling filesystems guarantee against corruption after a power failure (1)Do journaling filesystems guarantee against corruption after a power failure (1)
Do journaling filesystems guarantee against corruption after a power failure (1)
 
Debian os
Debian osDebian os
Debian os
 
Scrubbing and gowning
Scrubbing and gowningScrubbing and gowning
Scrubbing and gowning
 
Open suse
Open suseOpen suse
Open suse
 
Solaris OS
Solaris OSSolaris OS
Solaris OS
 
Open suse
Open suseOpen suse
Open suse
 
HP Unix administration
HP Unix administrationHP Unix administration
HP Unix administration
 
OpenSUSE
OpenSUSEOpenSUSE
OpenSUSE
 
Disk scheduling
Disk schedulingDisk scheduling
Disk scheduling
 
openSUSE
openSUSEopenSUSE
openSUSE
 
Solaris Operating System - Oracle
 Solaris Operating System - Oracle Solaris Operating System - Oracle
Solaris Operating System - Oracle
 
Solaris basics
Solaris basicsSolaris basics
Solaris basics
 
Symbian OS
Symbian OSSymbian OS
Symbian OS
 
Solaris Operating System
Solaris Operating SystemSolaris Operating System
Solaris Operating System
 
Kali Linux
Kali LinuxKali Linux
Kali Linux
 
Presentation1 linux os
Presentation1 linux osPresentation1 linux os
Presentation1 linux os
 

Semelhante a Minix smp

Stellaris を使った組み込みアプリ開発ガイド
Stellaris を使った組み込みアプリ開発ガイドStellaris を使った組み込みアプリ開発ガイド
Stellaris を使った組み込みアプリ開発ガイドryos36
 
JIT のコードを読んでみた
JIT のコードを読んでみたJIT のコードを読んでみた
JIT のコードを読んでみたy-uti
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputingNoboru Irieda
 
ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)
ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)
ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)Mr. Vengineer
 
C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml ssuser3a4b8c
 
Telemetryについて
TelemetryについてTelemetryについて
Telemetryについてtetsusat
 
PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門Yosuke Onoue
 
FPGAでゲーム機を作ろう! 第6回
FPGAでゲーム機を作ろう! 第6回FPGAでゲーム機を作ろう! 第6回
FPGAでゲーム機を作ろう! 第6回yoshimitsusudoh
 
リアルタイムOsのカスタマイズ
リアルタイムOsのカスタマイズリアルタイムOsのカスタマイズ
リアルタイムOsのカスタマイズKazuhiro Takahashi
 
OpenJDK HotSpot C1Compiler Overview
OpenJDK HotSpot C1Compiler OverviewOpenJDK HotSpot C1Compiler Overview
OpenJDK HotSpot C1Compiler Overviewnothingcosmos
 
RouterBOARD with OpenFlow
RouterBOARD with OpenFlowRouterBOARD with OpenFlow
RouterBOARD with OpenFlowToshiki Tsuboi
 
ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)Shinichi Awamoto
 
mod_auth_ticket - Bringing Single-Sign-On to lighttpd
mod_auth_ticket - Bringing Single-Sign-On to lighttpdmod_auth_ticket - Bringing Single-Sign-On to lighttpd
mod_auth_ticket - Bringing Single-Sign-On to lighttpdTaisuke Yamada
 
PEZY-SC programming overview
PEZY-SC programming overviewPEZY-SC programming overview
PEZY-SC programming overviewRyo Sakamoto
 
FPGAアクセラレータの作り方 (IBM POWER+CAPI編)
FPGAアクセラレータの作り方 (IBM POWER+CAPI編)FPGAアクセラレータの作り方 (IBM POWER+CAPI編)
FPGAアクセラレータの作り方 (IBM POWER+CAPI編)Mr. Vengineer
 
Android デバッグ小ネタ
Android デバッグ小ネタAndroid デバッグ小ネタ
Android デバッグ小ネタl_b__
 

Semelhante a Minix smp (20)

Stellaris を使った組み込みアプリ開発ガイド
Stellaris を使った組み込みアプリ開発ガイドStellaris を使った組み込みアプリ開発ガイド
Stellaris を使った組み込みアプリ開発ガイド
 
JIT のコードを読んでみた
JIT のコードを読んでみたJIT のコードを読んでみた
JIT のコードを読んでみた
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputing
 
ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)
ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)
ZynqMPのブートとパワーマネージメント : (ZynqMP Boot and Power Management)
 
C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml
 
Telemetryについて
TelemetryについてTelemetryについて
Telemetryについて
 
PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門
 
Inside winnyp
Inside winnypInside winnyp
Inside winnyp
 
Interrupts on xv6
Interrupts on xv6Interrupts on xv6
Interrupts on xv6
 
d-kami x86-1
d-kami x86-1d-kami x86-1
d-kami x86-1
 
FPGAでゲーム機を作ろう! 第6回
FPGAでゲーム機を作ろう! 第6回FPGAでゲーム機を作ろう! 第6回
FPGAでゲーム機を作ろう! 第6回
 
リアルタイムOsのカスタマイズ
リアルタイムOsのカスタマイズリアルタイムOsのカスタマイズ
リアルタイムOsのカスタマイズ
 
OpenJDK HotSpot C1Compiler Overview
OpenJDK HotSpot C1Compiler OverviewOpenJDK HotSpot C1Compiler Overview
OpenJDK HotSpot C1Compiler Overview
 
d-kami x86-2
d-kami x86-2d-kami x86-2
d-kami x86-2
 
RouterBOARD with OpenFlow
RouterBOARD with OpenFlowRouterBOARD with OpenFlow
RouterBOARD with OpenFlow
 
ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)
 
mod_auth_ticket - Bringing Single-Sign-On to lighttpd
mod_auth_ticket - Bringing Single-Sign-On to lighttpdmod_auth_ticket - Bringing Single-Sign-On to lighttpd
mod_auth_ticket - Bringing Single-Sign-On to lighttpd
 
PEZY-SC programming overview
PEZY-SC programming overviewPEZY-SC programming overview
PEZY-SC programming overview
 
FPGAアクセラレータの作り方 (IBM POWER+CAPI編)
FPGAアクセラレータの作り方 (IBM POWER+CAPI編)FPGAアクセラレータの作り方 (IBM POWER+CAPI編)
FPGAアクセラレータの作り方 (IBM POWER+CAPI編)
 
Android デバッグ小ネタ
Android デバッグ小ネタAndroid デバッグ小ネタ
Android デバッグ小ネタ
 

Mais de Masami Ichikawa

Mais de Masami Ichikawa (6)

Linux debug
Linux debugLinux debug
Linux debug
 
Linux Namespaces
Linux NamespacesLinux Namespaces
Linux Namespaces
 
Slub alloc and free
Slub alloc and freeSlub alloc and free
Slub alloc and free
 
Linux Namespace
Linux NamespaceLinux Namespace
Linux Namespace
 
とある帽子の大蛇料理Ⅱ
とある帽子の大蛇料理Ⅱとある帽子の大蛇料理Ⅱ
とある帽子の大蛇料理Ⅱ
 
Gnomeとdogtai
GnomeとdogtaiGnomeとdogtai
Gnomeとdogtai
 

Último

TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdftaisei2219
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものですiPride Co., Ltd.
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...Toru Tamaki
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略Ryo Sasaki
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNetToru Tamaki
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A surveyToru Tamaki
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Yuma Ohgami
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムsugiuralab
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)Hiroki Ichikura
 

Último (9)

TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システム
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
 

Minix smp

  • 2. Agenda • Minix SMP? • Minix SMP初期化の流れ • トランポリンコード
  • 3. Minix SMP? • Minix SMPはMinix2.0.0でSMPを実装 o 作者はJesús M. Álvarez Llorenteさん o プロジェクトのページはこちら  http://gsd.unex.es/projects/minixsmp/  ソースや論文(スペイン語)がダウンロード可能 • 対象アーキテクチャはx86
  • 4. 基本用語 • MP:Multi Processor • BSP:Boot Strap Processor o コンピュータが起動したときに動いたCPU • AP:Application Processor o 2〜n個目のCPU • APIC(Advanced Programmable Interrupt Controller) o x86における割り込みコントローラ • Local APIC o CPU内部に実装されていて、外部からの割り込みをコントロールする • IO APIC o I/Oデバイスから受け取った割り込みをCPUにリダイレクトする • IPI(Interprocessor Interrupt) o プロセッサ間の割り込み
  • 5. Agenda • Minix SMP? • Minix SMP初期化の流れ • トランポリンコード
  • 10. enable_cpu()の処理概要 • main()から呼ばれた場合は、BSPの有効化をする • 今動いているCPU(this_cpu)が有効化済みかチェック • 有効化しようとしているCPUがthis_cpuかチェック • 同じ場合 o enable_apic_ints()を呼んでAPCI・割り込みの有効化 o 次に動くプロセスの選択 • 違う場合 o CPUに割り込みメッセージを送信
  • 11. enable_cpu()の処理 PUBLIC void enable_cpu(int cpu, int echo) {  ・・・・ if (cpu_available[cpu]==CPU_ENABLED) return; /* A CPU only can only enable its own APIC */ if (cpu==this_cpu) { enable_apic_ints(); cpu_available[cpu]=CPU_ENABLED; lock_pick_proc(); if (echo) printk("CPU%d enabledn",cpu); } else { interrupt_cpu(cpu,MP_CM_ENABLE,echo); } }
  • 12. this_cpu #define this_cpu f_this_cpu() f_this_cpuはTHIS_CPU_SHORTマクロを呼び出すのがメインの処理。 #define THIS_CPU_SHORT(reg) ; mov edx, (_local_apic_base) ; add edx, 0x20 ; mov reg, FLAT_DS_SELECTOR ; mov ds, reg ; mov reg, (edx) ; and reg, 0x0F000000 ; shr reg, 6*4 local_apic_baseは以下のようにmp.cにて定義。 u32_t local_apic_base=0x0FEE00000; MPの仕様書によると、APICのデフォルトベースアドレス0FEC0_0000hと 0FEE0_0000hと記述されている。Minix SMPでは_local_apic_baseの値は 0x0FEE00000としています。
  • 13. enable_apic_ints()の処理 reg = LOCAL_APIC_READ(LOCAL_APIC_SPIV); reg |= (1<<ENABLE_APIC_SHIFT); /* Enable APIC */ LOCAL_APIC_WRITE(LOCAL_APIC_SPIV, reg); reg = LOCAL_APIC_READ(LOCAL_APIC_LVTL0); reg &= ~(7<<LVT_DM_SHIFT); /* clear delivery mode */ reg &= ~(1<<LVT_MASKED_SHIFT); /* unmask LINTIN0 */ reg |= (LVT_DM_EXTINT<<LVT_DM_SHIFT); /* ExtINT at LINTINT0 */ LOCAL_APIC_WRITE(LOCAL_APIC_LVTL0, reg); reg = LOCAL_APIC_READ(LOCAL_APIC_LVTL1); reg &= ~(7<<LVT_DM_SHIFT); /* clear delivery mode */ reg &= ~(1<<LVT_MASKED_SHIFT); /* ummask LINTIN1 */ reg |= (LVT_DM_NMI<<LVT_DM_SHIFT); /* NMI at LINTINT1 */ LOCAL_APIC_WRITE(LOCAL_APIC_LVTL1, reg);
  • 14. LOCAL APICへの読み書き void LOCAL_APIC_WRITE(u32_t reg, u32_t val) { phys_copy_dword( vir2phys(&val), local_apic_base+reg ); } u32_t LOCAL_APIC_READ(u32_t reg) { u32_t val; phys_copy_dword( local_apic_base+reg, vir2phys(&val) ); return val; }
  • 17. mp_start()の処理 void mp_start() {  ・・・・ if (load_fps()) { if (load_mph()) { process_mp_configuration(); if ((trampoline_addr=find_trampoline())) { FOR_EACH_AP(cpu) {  ・・・・ send_init_ipi(trampoline_addr, cpu); send_startup_ipi(trampoline_addr, cpu); } free_trampoline(trampoline_addr); }
  • 19. load_fps()概要 • MP floating structure pointer(fps)を読み込みます • MP floating structure pointer? o 16バイトの大きさのテーブル o MP機能に関する情報を保持しています  特に「MP Configuration table」のアドレスを保持し ているのが重要なポイントです o 規程のアドレス内に存在(MPの仕様書で定義)  Extended BIOS Data Area(EBDA)の最初の1KB以内  EBDAが定義されていない場合は、ベースメモリ 領域の最後の1KB(ベースメモリ領域が640KBな ら639-640KBの範囲)以内  0F0000h〜0FFFFFの範囲(BIOSのROM内)
  • 20. fps構造体 struct floating_pointer { char fp_signature[4]; /* must be _MP_ */ u32_t fp_mp_table; /* address to MP table */ u8_t fp_length; /* FPS size in 16-byte parragraphs */ u8_t fp_version; /* version number: 04h for 1.4 */ u8_t fp_cheksum; /* bytes in FPS must sum 0 */ u8_t fp_sd_config_num; /* standar config number (0 for none) */ u8_t fp_imcrp; /* bit 7 is IMCR present and PIC mode */ char unused[3]; /* last 3 bytes are reserved */ };
  • 21. fps構造体 • fpsの先頭4バイトはシグネチャです o シグネチャは"_MP_"であることと規定されてます • OSがfpsを探すときはfpsが置かれているべきアドレスを起点 とします o そこから16バイトおきにメモリの内容を読み込みます • 読み込んだ16バイトの領域がfpsかは、シグネチャとチェッ クサムで確認します • チェックサムの確認はfpsの領域(16バイト)を1バイトずつ読 み込んで数値として足し算していき、結果が0ならOKとなり ます
  • 22. load_fps()処理内容 最初にシグネチャのチェックを実行 /* fisrt look for signature */ for (i=0; i<4; i++) if (fps->fp_signature[i] != SIGN_FPS[i]) return 0; シグネチャが正しければチェックサムを計算 /* then calculate checksum*/ data=(unsigned char *)fps; checksum=0; for (i=0; i<sizeof (struct floating_pointer); i++) checksum+= data[i]; return (!checksum); /* checksum ok if sums 0 */
  • 24. load_mph()概要 • fpsを読み込めたら次はMP Configuration table Header(mpch)を読み込みます • mpchが置かれているアドレスは fps構造体のfp_mp_table から取得します • MP Configuration table Header? o 「MP Configuration table」のヘッダです(キリッ o 5種類あり、サイズも各テーブルで違います •  MP Configuration tableを読み込むために必要な情報をこ こから取得します • load_mph()で使用するのは、2個のフィールドだけです o fpsと同じく、シグネチャとチェックサム
  • 25. MP Configuration table • テーブルの種類はENTRY TYPEにより識別 • ENTRY TYPEは5種類 • 各テーブルはメモリ上で連続 • 各項目はオプショナル(必須ではない) Entry Description Entry Type Code Processor 0 Bus 1 I/O APIC 2 I/O Interrupt Assignment 3 Local Interrupt Assignment 4
  • 26. mp_config_headerの構造体 /* Describes the estruct of MP configuration table header */ struct mp_config_header { char mpch_signature[4]; /* must be "PCMP" */ u16_t mpch_length; /* base table size including header */ u8_t mpch_version; /* MP specification version number*/ u8_t mpch_checksum; /* base table + checksum must sum 0 */ char mpch_oem_id[8]; /* manufacturer id (space filled) */ char mpch_product_id[12]; /* product id (space filled) */ u32_t mpch_oem_table; /* optional manufacturer table address */ u16_t mpch_oem_table_size; /* manufacturer table size */ u16_t mpch_entry_count; /* entry count in MP table */ u32_t mpch_apic_addr; /* IO address for local APIC */ u16_t mpch_extended_length; /* extended table length */ u8_t mpch_extended_checksum; /* extended table checksum */ char mpch_reserved; /* unused */ };
  • 27. load_mph()処理内容 シグネチャのチェック  /* first match the signature */ for (i=0; i<4; i++) if (mph.mpch_signature[i] != SIGN_MP_C_HEADER[i] ) return 0; チェックサムのチェック /* then calculate checksum */ checksum=0; for (i=0; i<mph.mpch_length; i++) { /* the complete table is in another segment, so we need copy each byte into kernel address space (mph is only the header) */ phys_copy(fps.fp_mp_table+i, vir2phys(&data), 1); checksum +=data; } return (!checksum); /* checksum ok if sums 0 */
  • 29. process_mp_configuration()概要 • MP Configuration table数分(mph.mpch_entry_count)データ の読み込みを行います • 1個目のMP Configuration tableのアドレスは以下のように求 めます o next=fps.fp_mp_table+sizeof (struct mp_config_header); • アドレスが分かってもENTRY TYPEが分からないので最初に 1バイトだけ読みこんでENTRY TYPEの判別をします • ENTRY TYPEが分かったら、そのENTRY TYPEに応じた データの読み込みをします • ENTRY TYPEは5種類ですが、そのうち3種類はMinix SMP実 装では特に使用せずに読み飛ばしています
  • 30. process_mp_configuration()処理内容 while (i-- > 0) { phys_copy(next, vir2phys(&this_entry), 1); switch (this_entry) { case CPU_ENTRY_ID : // Processor ・・・ case BUS_ENTRY_ID : // Bus ・・・ case IO_APIC_ENTRY_ID : // I/O APIC ・・・ case IO_INT_ENTRY_ID : // I/O Interrupt Assignment ・・・ case LOCAL_INT_ENTRY_ID : // Local Interrupt Assignment ・・・ default : ・・・ } }
  • 31. Processor Entriesの構造体 struct cpu_entry { u8_t ce_type; /* 0 for this type */ u8_t ce_local_apic_id; /* local APIC id number */ u8_t ce_local_apic_ver; /* local APIC version */ u8_t ce_flags; /* CPU enabled and CPU is bootstrap */ u32_t ce_signature; /* CPU type */ u32_t ce_features; /* features of this CPU */ char reserved[8]; /* reserved */ };
  • 32. Processor Entriesの処理概要 • CPUが有効かチェックする • CPU FLAGSフィールド(ce_flags)を調べる o 大きさは1バイトで2種類(各1bit)のビットがあります o ENビットが0なら、このCPUは無効  無効の場合、このCPUは使用禁止 o BPビットが1なら、このCPUはBSP • CPUが有効かどうかのチェックは必須です
  • 33. Processor Entriesの処理 case CPU_ENTRY_ID : if (++cpu_count > 2) ADDS_MP_STATUS("MP PANIC: only 2 cpus currently supported!n"); phys_copy(next,vir2phys(&ce),sizeof(struct cpu_entry)); next+=sizeof(struct cpu_entry); PRINT_CPU_ENTRY(cpu); if ((ce.ce_flags & CE_EN_FLAG_MASK)==0) ADDS_MP_STATUS("MP PANIC: disabled apics not currently supportedn"); break;
  • 34. I/O APIC Entriesの構造体 struct io_apic_entry { u8_t ae_type; /* 2 for this type */ u8_t ae_id; /* IO APIC identification */ u8_t ae_version; /* IO APIC version number */ u8_t ae_flags; /* bit 0 means enabled */ u32_t ae_address; /* IO APIC memory address */ };
  • 35. I/O APIC Entriesの処理概要 • I/O APIC Entriesで見なければいけないところ o ENビット(1bit)  CPU EntriesのENビットと同じく、有効なら1 になる o I/O APIC ADDRESS  APICへ読み書きするときに使うアドレス
  • 36. I/O APIC Entriesの処理 case IO_APIC_ENTRY_ID : if (++apic_count > 1) ADDS_MP_STATUS("MP PANIC: only 1 I/O APIC currently supported!n"); phys_copy(next,vir2phys(&ae),sizeof(struct io_apic_entry)); next+=sizeof(struct io_apic_entry); /*PRINT_IO_APIC_ENTRY(ae);*/ if ((ae.ae_flags & AE_EN_FLAG_MASK)==0) ADDS_MP_STATUS("MP PANIC: disabled apic not currently supported!"); io_apic_base=ae.ae_address; break;
  • 38. find_trampoline()の処理概要 • メモリ上でトランポリンコードを置く場所を探します • トランポリンコード? o トランポリン(時々間接的なジャンプベクトルと呼ばれ る)は、割り込み処理ルーチン、I/Oルーチンなどを示しな がらアドレスを保持する記憶域です。 次に、実行は、す ぐにトランポリンに飛びついて、飛び出るか、または弾 んで、したがって、用語はトランポリンです。  http://wapedia.mobi/en/Trampoline_(computers) • トランポリンコードはAPの初期化時に必要です o x86系CPUはリアルモードで起動するので、プロテクト モードに移行したりといった処理がAPも必要です
  • 39. find_trampoline()の処理概要 • トランポリンコードのサイズを計算 • トランポリンコードを置ける場所の探索 • GDT、IDTをレジスタにコピー • トランポリンコードを見つかった場所にコピー • トランポリンコード中のマシン語コードの書き換え
  • 40. find_trampoline()の処理1 /* size of tampoline code */ u32_t tramp_len=(u32_t)end_init_ap-(u32_t)init_ap; • tramp_lenを設定している部分で使っている、名前は変数 じゃなくて、アセンブラコードのラベルです o トランポリンコードをラベルで囲ってます _init_ap: C16 jmp _skip_data ・・・ C16 jmpf CS_SELECTOR:_trampoline_pm _end_init_ap:
  • 41. find_trampoline()の処理2 /* 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文は、MPの仕様書「B.4.2 USING STARTUP IPI」の説明と一致していて、A0-BFは予約済みだから使うな よ!とか、ページ境界は4KBだ!と説明が書いてあるので、 それに則ってます。
  • 42. find_trampoline()の処理3 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 */ }
  • 43. copy_registers_to_trampoline()の処理 _copy_registers_to_trampoline: ! Copy gdt and idt sgdt (_gdtr_data) sidt (_idtr_data) ! Copy 32-bit regsiters mov eax, esi mov (_esi_data), eax mov eax, edi mov (_edi_data), eax mov eax, ebp mov (_ebp_data), eax ret
  • 44. disable_operand_size()の処理 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) *// ・・・・ 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--; } } }
  • 46. send_init_ipi()の処理概要 • APを起動させる前にipiを初期化します • MPの仕様書「Appendix A System BIOS Programming Guidelines」と「Appendix B Operating System Programming Guidelines」あたりに詳しく書かれています
  • 47. send_init_ipi()の処理1 /* Reprogram warm reset: write code 0A at CMOS addr 0F */ old_cmos=cmos_read(0x0F); cmos_write(0x0F, 0x0A); /* save old reset vector at 40:67 (dw) */ phys_copy(0x467,vir2phys(&old_vector), sizeof(u32_t)); • まず、CMOSに0Aを書き込んでPCをwarm resetします o PCの電源をOFFにしないで再起動 • reset vectorのバックアップを取ります o 0x467の意味は「warm-reset vector, which is a doubleword pointer in system RAM location 40:67h」と説明があります
  • 48. send_init_ipi()の処理2 /* program reset vector to point at trampoline */ value=(trampoline_addr >> 4); /* trampoline segment */ phys_copy(vir2phys(&value), 0x469, sizeof(u16_t)); value=(trampoline_addr & 0xF); /* trampoline offset */ phys_copy(vir2phys(&value), 0x467, sizeof(u16_t)); • トランポリンコードのアドレスをアドレス0x467、0x469に 書き込みます
  • 49. send_init_ipi()の処理3 /* send the IPI (assert) */ apic_error_status(); /* first, clear previous errors */ LOCAL_APIC_WRITE(LOCAL_APIC_ICR_HIGH, icr_h); LOCAL_APIC_WRITE(LOCAL_APIC_ICR_LOW, icr_l); wait_for_ipi_completion(); /* send the IPI (deassert) */ apic_error_status(); /* first, clear previous errors */ icr_l ^= (1<<LEVEL_SHIFT); /* switch to deassert */ LOCAL_APIC_WRITE(LOCAL_APIC_ICR_HIGH, icr_h); LOCAL_APIC_WRITE(LOCAL_APIC_ICR_LOW, icr_l); wait_for_ipi_completion(); • しばらくデータの設定が続いてから、実際にデータを書き込 んでいきます
  • 50. send_init_ipi()の処理4 /* restore old reset vector and cmos shutdown code */ phys_copy(vir2phys(&old_vector), 0x467, sizeof(u32_t)); cmos_write(0x0F, old_cmos); • 最後に、バックアップしたreset verctorを書き戻します • これでIPIの初期化が終りです
  • 52. send_startup_ipi()の処理概要 • この関数は引数を2個受け取ります o trampoline_addrはトランポリンのアドレス o which_cpuは起動させたいcpu番号  this_cpuマクロで取得したcpu番号です • この関数でipiを有効にすることで、APが起動するようにな ります
  • 53. send_startup_ipi()の処理1 /* put addr in 8 bit lower */ trampoline_addr = (trampoline_addr >> 12) & 0xFF; /* prepare to send STARTUP IPI */ icr_h = LOCAL_APIC_READ(LOCAL_APIC_ICR_HIGH); icr_l = LOCAL_APIC_READ(LOCAL_APIC_ICR_LOW);   ・・・・ icr_l |= (DELIVERY_STARTUP<<DELIVERY_SHIFT); /* stablish STARTUP */ icr_l |= (1 << LEVEL_SHIFT); /* level = assert */ icr_l &= ~(1 << TRIGGER_SHIFT); /* trigger = edge */ icr_l |= (PHYSICAL_DEST << DEST_MODE_SHIFT); /* destination = physical */ icr_l |= (DEST_FIELD << DEST_SHORT_SHIFT); /* destination by field */ icr_l |= trampoline_addr; /* vector field */ icr_h |= (which_cpu << DEST_FIELD_SHIFT); /* cpu to interrupt */
  • 54. send_startup_ipi()の処理2 /* send the IPI */ apic_error_status(); LOCAL_APIC_WRITE(LOCAL_APIC_ICR_HIGH, icr_h); LOCAL_APIC_WRITE(LOCAL_APIC_ICR_LOW, icr_l); wait_for_ipi_completion(); • 書き込み方法はsend_init_ipi()と同じです • これで、APが起動します
  • 55. APが起動したかの確認 • send_startup_ipi()でAPを起動させたら、mp_start()で 本当に APが起動したか確認をします。 if (! AP_running()) { ADDS_MP_STATUS("nn*** WARNING! AP#"); ADDN_MP_STATUS(cpu,10,1); ADDS_MP_STATUS(" is not running ***nn"); }
  • 57. free_trampoline()の処理 • トランポリンコードを置く場所を探したときに使用したア ドレスに0を書き込んで置きます void free_trampoline(u32_t addr) { /* Restore with 0's the memory zone used for trampoline */ char dummy=0; u32_t tramp_len=(u32_t)end_init_ap-(u32_t)init_ap; while (tramp_len--) phys_copy((u32_t)&dummy,addr++,1); }
  • 58. Agenda • Minix SMP? • Minix SMP初期化の流れ • トランポリンコード
  • 59. トランポリンコードの処理 • トランポリンコードでは実際にどんなことをするのか? o Mark data area to tell the BSP we are running in real mode o Read values of many registers to prepare environment to jump into protected mode in same conditions as BSP o Change to protected mode o Jump to protected mode trampoline section • トランポリンコードはアセンブラのコードですが、最終的 にap_main()というCの関数を呼び出すまでが一連の処理です
  • 61. トランポリンコードの処理概要 • リアルモードからプロテクトモードに移行し、次の処理に 進む o cs・dsレジスタの設定 o gdtr、idtrの設定 o プロテクトモード移行 o _trampolin_pmへセグメントジャンプ
  • 62. トランポリンコード(データ定義) .sect .data .align 16 #define C16 o16 a16 _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
  • 63. トランポリンコード(処理部) _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: hlt
  • 65. trampoline_pm()の処理概要 • 各種レジスタの設定 • TSSの設定 o Task State Segmentの略 o タスク状態の保存・復元に使用するデータ領域 o x86ではTSSを使ってタスクを切り替えることができる • スタックの設定 • キャッシュの有効化 • ap_main()のコール
  • 66. trampoline_pm()の処理 _trampoline_pm: ! We are in protected mode. Load AP registers as in BSP ・・・・・ ! Load TSS of this ap ・・・・・ ltr ax ! load TSS ! Now we are ready to address as usual and execute normal ! kernel code, so, lets go ! Each CPU needs its own stack space inside kernel stack ! Make esp point to cpus stack top THIS_CPU(eax) SET_CPU_STK(eax) ! Enable AP cache call _enable_cache ! Continue in C code call _ap_main
  • 68. enable_cache()の概要 • CPUのキャッシュを有効にします • CR0レジスタのCDとNWビットを0にします o CDビット:0にすることでキャッシュを有効化 o NWビット:0ならキャッシュヒット時にライトバックす る  486の場合はライトスルー 31 0 P C N P G D W E
  • 69. enable_cache()の処理 _enable_cache: mov ax, cr0 and ax, 0x9FFFFFFF ! 100111111111...111 mov cr0, ax wbinv
  • 71. ap_main()の処理概要 • enable_cpu()を呼んでAPを有効にする • 次に動くプロセスを選ぶ o lock_pick_proc() o pick_proc()のロックを使う版 • そのプロセスを動かす o restart() o restart()はminixに元々ある関数で、kernel/main..cのmain() 最後の処理でも使っている
  • 72. ap_main()の処理 /* This is the main routine for AP's. This is the entry point before the CPU has been started and jumped to protected mode */ /* Tell BSP we are running */ ap_running_flag=AP_LIFE_FLAG_MARK; /* Now we're ready to take some work. We find any task and call restart() to execute it (or to idle), but we must synchonize other cpus before enter kernel code */ lock_mp_kernel(); /* restart() will unlock later */
  • 73. ap_main()の処理 /* Enable APIC interrupt aceptance */ enable_cpu(this_cpu,WITHOUT_ECHO); /* Now, kernel is our! */ lock_pick_proc(); /* Is there any work? */ restart(); /* Let's go... */
  • 75. enable_cpu()の処理概要 • ap_main()から呼ばれた場合は、APの有効化をする • 今動いているCPUが有効化済みかチェック • 有効化しようとしているCPUがthis_cpuかチェック • 同じ場合 o enable_apic_ints()を呼んでAPCI・割り込みの有効化 o 次に動くプロセスの選択 • 違う場合 o CPUに割り込みメッセージを送信
  • 77. Link • MultiProcessor Specification o http://www.intel.com/design/pentium/datashts/242016.HTM • Minix3 o http://www.minix3.org/ • はてダ o http://d.hatena.ne.jp/masami256