minix smp
DESCRIPTION
第2回カーネル/VM探検隊の資料TRANSCRIPT
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 enabled\n",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 supported\n"); 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("\n\n*** WARNING! AP#"); ADDN_MP_STATUS(cpu,10,1); ADDS_MP_STATUS(" is not running ***\n\n");}
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 modeo Read values of many registers to prepare environment to jump
into protected mode in same conditions as BSPo Change to protected modeo 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の場合はライトスルー
PE
NW
CD
PG
031
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 Specificationo http://www.intel.com/design/pentium/datashts/242016.HTM
• Minix3o http://www.minix3.org/
• はてダo http://d.hatena.ne.jp/masami256