lapic.c void lapicstartap(uchar apicid, uint addr)
トップページ
jupiteroak.hatenablog.com
lapic.c
https://github.com/mit-pdos/xv6-public/blob/master/lapic.c#L128
void lapicstartap(uchar apicid, uint addr) { int i; ushort *wrv; // "The BSP must initialize CMOS shutdown code to 0AH // and the warm reset vector (DWORD based at 40:67) to point at // the AP startup code prior to the [universal startup algorithm]." outb(CMOS_PORT, 0xF); // offset 0xF is shutdown code outb(CMOS_PORT+1, 0x0A); wrv = (ushort*)P2V((0x40<<4 | 0x67)); // Warm reset vector wrv[0] = 0; wrv[1] = addr >> 4; // "Universal startup algorithm." // Send INIT (level-triggered) interrupt to reset other CPU. lapicw(ICRHI, apicid<<24); lapicw(ICRLO, INIT | LEVEL | ASSERT); microdelay(200); lapicw(ICRLO, INIT | LEVEL); microdelay(100); // should be 10ms, but too slow in Bochs! // Send startup IPI (twice!) to enter code. // Regular hardware is supposed to only accept a STARTUP // when it is in the halted state due to an INIT. So the second // should be ignored, but it is part of the official Intel algorithm. // Bochs complains about the second one. Too bad for Bochs. for(i = 0; i < 2; i++){ lapicw(ICRHI, apicid<<24); lapicw(ICRLO, STARTUP | (addr>>12)); microdelay(200); } }
lapicstartap関数は、Local APIC IDの値apicidによって指定されたAP(Application Processor)を起動させ、引数addrで指定されたアドレスから処理を開始させるために、universal startup algorithmと呼ばれる手続きを行います。
引数 uchar apicid
起動対象となるAP(Application Processor)を指定するLocal APIC IDです。
引数 uint addr
起動したAP(Application Processor)が処理を開始するアドレスです。
処理の内容
- 前処理①CMOSのShutdown Statusフィールドに0xA0を設定する
- 前処理②warm reset vectorに起動したAP(Application Processor)が処理を開始するアドレスを設定する
- universal startup algorithm①BSPからINIT IPIを送信する
- universal startup algorithm②BSPからSTARTUP IPIを2回送信する
前処理①CMOSのShutdown Statusフィールドに0xA0を設定する
universal startup algorithmの手続きをとる前に、CMOS(BIOSに関する情報が保存されているメモリ領域)のShutdown Statusフィールドに、0xA0の値を設定します。
CMOSのShutdown Statusフィールドにアクセスできるようにする
outb(CMOS_PORT, 0xF);
out命令(ポート出力命令)でI/OポートアドレスCMOS_PORT(#define CMOS_PORT 0x70)を指定することにより、CMOSのindex registerへの書き込みを行なっています。
index registerは、アクセス対象となるCMOSのフィールドを指定するために使用されるレジスタです。
index registerにオフセット0xFを設定することで、Shutdown Statusフィールドにアクセスできるようになります。
CMOSのShutdown Statusフィールドに0x0Aを設定する
outb(CMOS_PORT+1, 0x0A);
out命令(ポート出力命令)でI/OポートアドレスCMOS_PORT(#define CMOS_PORT 0x70)+1を指定することにより、CMOSのdata registerへの書き込みを行なっています。
前の命令でindex registerに0xFを設定しているので、data registerへの書き込みはShutdown Statusフィールドへの書き込みとなります。
Shutdown Statusフィールドに0x0Aを設定することで、AP(Application Processor)が起動後に処理を開始するアドレスがwarm reset vectorに設定されたアドレスになります。
前処理②warm reset vectorに起動したAP(Application Processor)が処理を開始するアドレスを設定する
universal startup algorithmの手続きをとる前に、起動したAP(Application Processor)が処理を開始するアドレスをwarm reset vectorに設定します。
warm reset vectorのアドレスを仮想アドレスに変換する
wrv = (ushort*)P2V((0x40<<4 | 0x67));
ushort型(2バイト)へのポインタwrvに、warm reset vectorのアドレスを設定します。
warm reset vectorの論理アドレスは0x0040:0x0067なので、物理アドレスは0x40<<4 | 0x67→0x0400 + 0x0067→x467となります。
ページング回路を有効化している状態を想定しているので、P2Vマクロを使って物理アドレス(0x40<<4 | 0x67)を仮想アドレスに変換します。
warm reset vectorに起動したAP(Application Processor)が処理を開始するアドレスを設定する
wrv[0] = 0; wrv[1] = addr >> 4;
warm reset vectorに、起動したAP(Application Processor)が処理を開始するアドレスを設定します。
warm reset vector下位16bit(wrv[0])に、0x0000を設定します。
warm reset vector上位16bit(wrv[1])に、アドレスaddrを4bit右シフトした値(16進数のアドレス値を1桁減らした値)を設定します。
AP(Application Processor)の起動後はリアルモードで動作するので、warm reset vector下位16bitにオフセットアドレス(16bit値)を、warm reset vector上位16bitにセグメントアドレス(16bit値)を設定してます。
universal startup algorithm①BSPからINIT IPIを送信する
universal startup algorithmの手続きとして、BSP(BootStrap Processor)からINIT IPIを1回送信し、送信先のAP(Application Processor)をリセットします。
MultiProcessor Specificatonのuniversal startup algorithmではINIT IPIの送信は1回のみですが、lapicstartap関数ではPentium 4とIntel Xeon プロセッサ用のINIT IPIを1回目に送信し、Pentium 4とIntel Xeon以外のプロセッサ用のINIT IPIを2回目に送信していると思われます。
ICR(Interrupt Command Register)の上位32bitへの書き込み
lapicw(ICRHI, apicid<<24);
lapicw関数を呼び出して、ICRの上位32bit(#define ICRHI (0x0310/4))に書き込みを行なっています。
apicidを24bit左シフト演算することにより、ICRのDestinationフィールド(Interrupt Command Registerのbit63-56)にLocal APIC IDを設定しています。
ICRのDestinationフィールド(Interrupt Command Registerのbit63-56)は、送信先となるプロセッサのLocal APIC IDを指定するフィールドです。
INIT IPIの送信は、ICRの下位32bit(#define ICRLO (0x0300/4))へ書き込みを行った際に、行われます。そのため、ICRへ書き込みを行う際は、ICRの上位32bit(#define ICRHI (0x0310/4))、ICRの下位32bit(#define ICRLO (0x0300/4))の順で書き込みを行ないます。
ICR(Interrupt Command Register)の下位32bitへの書き込み(1回目のINIT IPI送信)
lapicw(ICRLO, INIT | LEVEL | ASSERT); microdelay(200);
lapicw関数を呼び出して、ICRの下位32bit(#define ICRLO (0x0300/4))への書き込みを行ない、ICRのDestinationフィールドで指定されたLocal APIC IDを持つプロセッサへINIT IPIを送信します。その後、IPIの送信が完了するのを待つために、microdelay関数を呼び出して、200マイクロ秒ほど待ち時間をつくります。
ICRの下位32bit(Interrupt Command Registerのbit31-0)に書き込まれる値
ICRの下位32bit(Interrupt Command Registerのbit31-0)に書き込まれる値は、INIT(#define INIT 0x0000 0500)、LEVEL(#define LEVEL 0x0000 8000)、ASSERT(#define ASSERT 0x0000 4000)の論理和INIT | LEVEL | ASSERT(0x0000 c500)です。
論理和INIT | LEVEL | ASSERT(0x0000 c500)をICRの下位32bitへ書き込むことにより、ICRの下位32bitのフィールド・フラグには以下のように値が設定されます。
bit31-20
予約済みです。
bit19-18 Destination Shorthandフィールド:設定値 0b 00
IPIの送信先を簡略表現で指定するフィールドです。このフィールドが0b 00の時は、簡略表現を使用しないことを示しています。
bit17-16
予約済みです。
bit15 Trigger Modeフラグ:設定値 1
Trigger Mode(割り込み信号を検出する方式)を選択するフラグです。LEVEL(#define LEVEL 0x0000 8000)を使って、Trigger Modeフラグに1を設定しています。このフラグが1の時は、level sensitiveが選択されていることを示しています。
bit14 Levelフラグ:設定値 1
Pentium 4 と Intel Xeon プロセッサでは、このフラグには常に1が設定されています。ASSERT(#define ASSERT 0x0000 4000)を使って、Levelフラグに1を設定しています。
bit13
予約済みです。
bit12 Delivery Statusフラグ:Read Only
IPIの伝達状態を示すフラグです。
bit11 Destination Modeフラグ:設定値 0
Destinationフィールド(bit 63-56)がプロセッサを指定する方式を選択するフラグです。このフラグが0の時は、physical desitination mode(Local APIC IDを用いてプロセッサを指定する方式)が選択されていることを示しています。
bit10-8 Delivery Modeフィールド:設定値 0b 101
プロセッサに送信されるIPIのDelivery Mode(タイプ)を指定するフィールドです。INIT(#define INIT 0x0000 0500)を使って、Delivery Modeフィールドに0b 101を設定しています。このフィールドが101の時は、IPIのDelivery ModeがINIT(プロセッサにINITを実行させる場合のDelivery Mode)であることを示しています。
bit 7-0 Vectorフィールド:設定値 00h
送信されるIPIのベクタ番号を設定するフィールドです。
Delivery Modeフィールドに101(INIT)を設定しているので、Vectorフィールドは00hに設定されていなければなりません。
ICR(Interrupt Command Register)の下位32bitへの書き込み(2回目のINIT IPI送信)
lapicw(ICRLO, INIT | LEVEL); microdelay(100);
lapicw関数を呼び出して、ICRLO(ICRの下位32ビット)へ書き込みを行い、2回目のINIT IPIを送信しています。
その後、IPIの送信が完了するのを待つために、microdelay関数を呼び出して、200マイクロ秒ほど待ち時間をつくります。
universal startup algorithm②BSPからSTARTUP IPIを2回送信する
universal startup algorithmの手続きとして、BSP(BootStrap Processor)からSTARTUP IPIを2回送信し、送信先のAP(Application Processor)をリアルモードで起動させます。起動したAP(Application Processor)が処理を開始するアドレスは、STARTUP IPIのフィールドを用いて指定することができます。
ICR(Interrupt Command Register)の上位32bitへの書き込み
lapicw(ICRHI, apicid<<24);
lapicw関数を呼び出して、ICRの上位32bit(#define ICRHI (0x0310/4))に書き込みを行なっています。
apicidを24bit左シフト演算することにより、ICRのDestinationフィールド(Interrupt Command Registerのbit63-56)にLocal APIC IDを設定しています。
ICRのDestinationフィールド(Interrupt Command Registerのbit63-56)は、送信先となるプロセッサのLocal APIC IDを指定するフィールドです。
STARTUP IPIの送信は、ICRの下位32bit(#define ICRLO (0x0300/4))へ書き込みを行った時に、行われます。そのため、ICRへ書き込みを行う際は、ICRの上位32bit(#define ICRHI (0x0310/4))、ICRの下位32bit(#define ICRLO (0x0300/4))の順で書き込みを行ないます。
ICR(Interrupt Command Register)の下位32bitへの書き込み(STARTUP IPI送信)
lapicw(ICRLO, STARTUP | (addr>>12)); microdelay(200);
lapicw関数を呼び出して、ICRの下位32bit(#define ICRLO (0x0300/4))への書き込みを行ない、ICRのDestinationフィールドで指定されたLocal APIC IDを持つプロセッサへSTARTUP IPIを送信します。その後、IPIの送信が完了するのを待つために、microdelay関数を呼び出して、200マイクロ秒ほど待ち時間をつくります。
ICRの下位32bit(Interrupt Command Registerのbit31-0)に書き込まれる値
ICRの下位32bit(Interrupt Command Registerのbit31-0)に書き込まれる値は、STARTUP(#define STARTUP 0x0000 0600)と addr>>12 の論理和STARTUP | (addr>>12)です。この値をICRの下位32bitへ書き込むことにより、ICRの下位32bitのフィールド・フラグには以下のように値が設定されます。
bit31-20
予約済みです。
bit19-18 Destination Shorthandフィールド:設定値 0b 00
IPIの送信先を簡略表現で指定するフィールドです。このフィールドが0b 00の時は、簡略表現を使用しないことを示しています。
bit17-16
予約済みです。
bit15 Trigger Modeフラグ:設定値 0
Trigger Mode(割り込み信号を検出する方式)を選択するフラグです。このフラグが0の時は、edge sensitiveが選択されていることを示しています。
bit14 Levelフラグ:設定値 0
STARTUP IPIでは、常に0が設定されます。
bit13
予約済みです。
bit12 Delivery Statusフラグ:Read Only
IPIの伝達状態を示すフラグです。
bit11 Destination Modeフラグ:設定値 0
Destinationフィールド(bit 63-56)がプロセッサを指定する方式を選択するフラグです。このフラグが0の時は、physical desitination mode(Local APIC IDを用いてプロセッサを指定する方式)が選択されていることを示しています。
bit10-8 Delivery Modeフィールド:設定値 0b 110
プロセッサに送信されるIPIのDelivery Mode(タイプ)を指定するフィールドです。STARTUP(#define STARTUP 0x0000 0600)を使って、Delivery Modeフィールドに0b 110を設定しています。このフィールドが110の時は、IPIのDelivery ModeがSTARTUP(プロセッサを起動させる場合のDelivery Mode)であることを示しています。
bit 7-0 Vectorフィールド:設定値 addのbit19-12(addr>>12)
送信されるIPIのベクタ番号を設定するフィールドですが、Delivery Modeフィールドに110(STARTUP IPI)を設定している場合は、Vectorフィールドに起動したAP(Application Processor)が処理を開始するアドレスの一部を設定しなければなりません。
vectorフィールドにVVh(8bit値)が設定されていると、AP(Application Processor)はアドレス値0x000V V000からリアルモードで処理を開始します。
引数addrの値が0x0000 7000の場合、vectorフィールドに07h(8bit値)が設定されるので、AP(Application Processor)はアドレス0x0000 7000からリアルモードで処理を開始します。