5.1. main関数

ここからは各関数でAPICの設定やAPの起動等を行い、最終的にスケジューラを起動する。

main.c

extern char end[]; // first address after kernel loaded from ELF file

/* 略 */

int
main(void)
{
  kinit1(end, P2V(4*1024*1024)); // phys page allocator
  kvmalloc();      // kernel page table
  mpinit();        // detect other processors
  lapicinit();     // interrupt controller
  seginit();       // segment descriptors
  picinit();       // disable pic
  ioapicinit();    // another interrupt controller
  consoleinit();   // console hardware
  uartinit();      // serial port
  pinit();         // process table
  tvinit();        // trap vectors
  binit();         // buffer cache
  fileinit();      // file table
  ideinit();       // disk 
  startothers();   // start other processors
  kinit2(P2V(4*1024*1024), P2V(PHYSTOP)); // must come after startothers()
  userinit();      // first user process
  mpmain();        // finish this processor's setup
}

先に各関数の概要をまとめておく。

関数名概要
kinit1大域変数kmemのfreelistに、kernelの終わりから物理アドレス4MBまでを追加する。
kvmallocカーネル用のページディレクトリとPDE、PTEを作成して切り替える。
mpinit大域変数lapicにLAPICへのアクセスアドレスを設定、各cpu構造体にLAPIC IDを設定、大域変数ioapicidにIOAPIC IDを設定する。
lapicinitLAPICを有効にし、スプリアス割り込みを無効化。APICタイマが10000000からバスクロックが進むごとにカウントダウンされ、0になるとIRQ32で割り込みをかけ、再度カウントダウンを始めるよう設定。LINT0とLINT1ピン、パフォーマンスモニタリングカウンタを無効化。割り込みエラーの際にIRQ51で割り込みかけるように設定。ESR、EOIレジスタをリセット。ICRでAPにINIT IPIを送信し、Arb IDをLAPIC IDと同じ値に設定。TPRをリセット。
seginitGDTを作成し、ロードする。
picinitMPに対応していない古いPICでの割り込みを無効化する。
ioapicinit大域変数ioapicにIOAPICへのアクセスアドレスを設定し、IOリダイレクションテーブルの設定を行う。IRQ0~23番がBSPにIRQ32~55番でリダイレクトされるよう設定を行い、それら全てを無効化する。
consoleinitdevsw配列の1番にコンソール読み書き用の関数を設定し、IOAPICのキーボードコントローラからの割込みのリダイレクトを有効化する(IRQ1からIRQ33へのリダイレクト)。
uartinitUARTのFIFOを無効化し、ボーレートを9600、ワードサイズを8bitに初期化。シリアルポートが使用できるか否かを確認し、使用できる場合は「xv6...」という文字列を送信する。
pinitロセステーブルのロックを初期化する。
tvinit大域変数idtに256個のゲートディスクリプタを作成する。
binit大域変数bcache(バッファキャッシュ)を初期化する。
fileinit大域変数ftable(ファイルテーブル)のロックを初期化する。
ideinitディスク1の存在確認をする。ide.cの静的変数havedisk1に値を設定(0ならディスク1は無し、1なら有り)。
startothers各APを起動し、GDT、ページング、IDT等の設定を行い、スケジューラを実行する。mpmain関数もここで見る。
kinit2大域変数kmemのfreelistに物理アドレス4MB(0x400000)から終わり(0xe000000)までを加え、use_lockフィールドの値を1にする。
userinitinitcode.Sのプロセスを作成し、プロセステーブルに追加する。
mpmainAPのときと同様にBSPでも「cpu0: starting 0」をコンソールに出力し、IDTを読み込み、スケジューラを実行する。