minix smp

77
MinixSMP Minix SMPを読んでみる〜 @masami256

Upload: masami-ichikawa

Post on 28-Jun-2015

2.737 views

Category:

Technology


4 download

DESCRIPTION

第2回カーネル/VM探検隊の資料

TRANSCRIPT

Page 1: Minix smp

MinixとSMP〜Minix SMPを読んでみる〜

@masami256

Page 2: Minix smp

Agenda

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

Page 3: Minix smp

Minix SMP?

• Minix SMPはMinix2.0.0でSMPを実装o 作者はJesús M. Álvarez Llorenteさん o プロジェクトのページはこちら

http://gsd.unex.es/projects/minixsmp/ ソースや論文(スペイン語)がダウンロード可能

• 対象アーキテクチャはx86

Page 4: Minix smp

基本用語

• 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 プロセッサ間の割り込み

Page 5: Minix smp

Agenda

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

Page 6: Minix smp

SMPのセットアップ手順

Page 7: Minix smp

SMPのセットアップ手順(続き)

Page 8: Minix smp

実際の流れを追いかけよう

電源ON〜main()の間はSMPに関する処理はないので飛ばします

Page 9: Minix smp

SMPのセットアップ手順

Page 10: Minix smp

enable_cpu()の処理概要

• main()から呼ばれた場合は、BSPの有効化をする• 今動いているCPU(this_cpu)が有効化済みかチェック• 有効化しようとしているCPUがthis_cpuかチェック• 同じ場合

o enable_apic_ints()を呼んでAPCI・割り込みの有効化o 次に動くプロセスの選択

• 違う場合o CPUに割り込みメッセージを送信

Page 11: Minix smp

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); }}

Page 12: Minix smp

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としています。

Page 13: Minix smp

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);

Page 14: Minix smp

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;}

Page 15: Minix smp

SMPのセットアップ手順

Page 16: Minix smp

mp_start()の処理概要

• load_fps()〜free_trampoline()までの処理を順番に呼び出し• 関数の終了時点でAPが起動するようになる

Page 17: Minix smp

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); }

Page 18: Minix smp

SMPのセットアップ手順

Page 19: Minix 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内)

Page 20: Minix smp

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 */};

Page 21: Minix smp

fps構造体

• fpsの先頭4バイトはシグネチャですo シグネチャは"_MP_"であることと規定されてます

• OSがfpsを探すときはfpsが置かれているべきアドレスを起点としますo そこから16バイトおきにメモリの内容を読み込みます

• 読み込んだ16バイトの領域がfpsかは、シグネチャとチェックサムで確認します

• チェックサムの確認はfpsの領域(16バイト)を1バイトずつ読み込んで数値として足し算していき、結果が0ならOKとなります

Page 22: Minix smp

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 */

Page 23: Minix smp

SMPのセットアップ手順

Page 24: Minix 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と同じく、シグネチャとチェックサム

Page 25: Minix smp

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

Page 26: Minix smp

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 */};

Page 27: Minix smp

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 */

Page 28: Minix smp

SMPのセットアップ手順

Page 29: Minix 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実装では特に使用せずに読み飛ばしています

Page 30: 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 : ・・・ }}

Page 31: Minix smp

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 */};

Page 32: Minix smp

Processor Entriesの処理概要

• CPUが有効かチェックする • CPU FLAGSフィールド(ce_flags)を調べる

o 大きさは1バイトで2種類(各1bit)のビットがありますo ENビットが0なら、このCPUは無効

無効の場合、このCPUは使用禁止o BPビットが1なら、このCPUはBSP

• CPUが有効かどうかのチェックは必須です

Page 33: Minix smp

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;

Page 34: Minix smp

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 */};

Page 35: Minix smp

I/O APIC Entriesの処理概要

• I/O APIC Entriesで見なければいけないところo ENビット(1bit)

CPU EntriesのENビットと同じく、有効なら1 になるo I/O APIC ADDRESS

APICへ読み書きするときに使うアドレス

Page 36: Minix smp

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;

Page 37: Minix smp

SMPのセットアップ手順

Page 38: Minix smp

find_trampoline()の処理概要

• メモリ上でトランポリンコードを置く場所を探します• トランポリンコード?

o トランポリン(時々間接的なジャンプベクトルと呼ばれる)は、割り込み処理ルーチン、I/Oルーチンなどを示しながらアドレスを保持する記憶域です。 次に、実行は、すぐにトランポリンに飛びついて、飛び出るか、または弾んで、したがって、用語はトランポリンです。 http://wapedia.mobi/en/Trampoline_(computers)

• トランポリンコードはAPの初期化時に必要ですo x86系CPUはリアルモードで起動するので、プロテクト

モードに移行したりといった処理がAPも必要です

Page 39: Minix smp

find_trampoline()の処理概要

• トランポリンコードのサイズを計算• トランポリンコードを置ける場所の探索• GDT、IDTをレジスタにコピー• トランポリンコードを見つかった場所にコピー• トランポリンコード中のマシン語コードの書き換え

Page 40: Minix smp

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:

Page 41: Minix smp

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だ!と説明が書いてあるので、それに則ってます。

Page 42: Minix smp

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 */ }

Page 43: Minix smp

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

Page 44: Minix smp

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--; } } }

Page 45: Minix smp

SMPのセットアップ手順

Page 46: Minix smp

send_init_ipi()の処理概要

• APを起動させる前にipiを初期化します • MPの仕様書「Appendix A System BIOS Programming

Guidelines」と「Appendix B Operating System Programming Guidelines」あたりに詳しく書かれています

Page 47: Minix smp

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」と説明があります

Page 48: Minix smp

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に書き込みます

Page 49: Minix smp

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();

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

Page 50: Minix smp

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の初期化が終りです

Page 51: Minix smp

SMPのセットアップ手順

Page 52: Minix smp

send_startup_ipi()の処理概要

• この関数は引数を2個受け取りますo trampoline_addrはトランポリンのアドレスo which_cpuは起動させたいcpu番号

this_cpuマクロで取得したcpu番号です • この関数でipiを有効にすることで、APが起動するようにな

ります

Page 53: Minix smp

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 */

Page 54: Minix smp

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が起動します

Page 55: Minix smp

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");}

Page 56: Minix smp

SMPのセットアップ手順

Page 57: Minix 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);}

Page 58: Minix smp

Agenda

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

Page 59: 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の関数を呼び出すまでが一連の処理です

Page 60: Minix smp

トランポリンコードの処理

Page 61: Minix smp

トランポリンコードの処理概要

• リアルモードからプロテクトモードに移行し、次の処理に進むo cs・dsレジスタの設定o gdtr、idtrの設定o プロテクトモード移行o _trampolin_pmへセグメントジャンプ

Page 62: Minix smp

トランポリンコード(データ定義).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

Page 63: Minix smp

トランポリンコード(処理部)_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

Page 64: Minix smp

トランポリンコードの処理

Page 65: Minix smp

trampoline_pm()の処理概要

• 各種レジスタの設定• TSSの設定

o Task State Segmentの略o タスク状態の保存・復元に使用するデータ領域o x86ではTSSを使ってタスクを切り替えることができる

• スタックの設定• キャッシュの有効化• ap_main()のコール

Page 66: Minix smp

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

Page 67: Minix smp

トランポリンコードの処理

Page 68: Minix smp

enable_cache()の概要

• CPUのキャッシュを有効にします• CR0レジスタのCDとNWビットを0にします

o CDビット:0にすることでキャッシュを有効化o NWビット:0ならキャッシュヒット時にライトバックす

る 486の場合はライトスルー

PE

NW

CD

PG

031

Page 69: Minix smp

enable_cache()の処理

_enable_cache: mov ax, cr0 and ax, 0x9FFFFFFF ! 100111111111...111 mov cr0, ax wbinv

Page 70: Minix smp

トランポリンコードの処理

Page 71: Minix smp

ap_main()の処理概要

• enable_cpu()を呼んでAPを有効にする• 次に動くプロセスを選ぶ

o lock_pick_proc()o pick_proc()のロックを使う版

• そのプロセスを動かすo restart()o restart()はminixに元々ある関数で、kernel/main..cのmain()

最後の処理でも使っている

Page 72: Minix smp

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 */

Page 73: Minix smp

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... */

Page 74: Minix smp

トランポリンコードの処理

Page 75: Minix smp

enable_cpu()の処理概要

• ap_main()から呼ばれた場合は、APの有効化をする• 今動いているCPUが有効化済みかチェック• 有効化しようとしているCPUがthis_cpuかチェック• 同じ場合

o enable_apic_ints()を呼んでAPCI・割り込みの有効化o 次に動くプロセスの選択

• 違う場合o CPUに割り込みメッセージを送信

Page 76: Minix smp

At last

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

Page 77: Minix 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