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を設定する

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 4Intel Xeon プロセッサ用のINIT IPIを1回目に送信し、Pentium 4Intel 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 4Intel 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マイクロ秒ほど待ち時間をつくります。

ICRの下位32bit(Interrupt Command Registerのbit31-0)に書き込まれる値

bit14 Levelフラグ以外は、1回目のINIT IPI送信の時と同じです。

bit14 Levelフラグ:設定値 1
Pentium 4Intel Xeon以外のプロセッサでは、このフラグには常に0が設定されています。

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からリアルモードで処理を開始します。