Kernel.cpp secondboot.asm → cstart.cpp → Kernel.cppのstartKernel.cppに飛ぶ。 この段階でC++コードになる。 void startKernel(void); 行っている内容は、とりあえず、カーネルが使用するメモリを設定して その次になぜか知らないがグローバルデスクリプタテーブルを再設定している。 リアルモードのときに全部やっとけよと思う。GDTの再設定が終われば 画面・その他の設定、スケジューラの起動、システムプロセスとINITプロセスの起動、 mainProcess関数に移る。 この関数が起動された段階で、コード、スタック、データセグメントはすべて 0x00000000から0xffffffffまで使用可能になっている。起動して始めは カーネルが使用するメモリ領域の割り当てとGDTの再設定である。 kmはMemoryManager型のクラスでメモリ領域を管理する。 GDTUtilはその名のとおりグローバルデスクリプタテーブルを再設定するために 使われる。 0x00200000 0x007FFFFF ------------------------------------------------------------------------- | kernel Heap Domain | | 0x00600000 = 6MB | ------------------------------------------------------------------------- void startKernel(void) { /* kernel memory range */ km.initialize(0x200000, 0x7fffff); /* set segment */ GDTUtil::setup(); VESA周辺はわからないことだらけなので後日解析する事にする。 /* VESA */ g_vesaInfo = new VesaInfo; memcpy(g_vesaInfo, (VesaInfo*)0x800, sizeof(VesaInfo)); /* console */ if (g_vesaInfo->sign[0] == 'N') { g_console = new GraphicalConsole(); g_console->printf("VESA not supported. sorry kernel stop.\n"); for (;;); } else { g_vesaDetail = new VesaInfoDetail; memcpy(g_vesaDetail, (VesaInfoDetail*)0x830, sizeof(VesaInfoDetail)); g_console = new VesaConsole(g_vesaDetail); g_console->setCHColor(GP_LIGHTGREEN); g_console->setBGColor(GP_WHITE); g_console->clearScreen(); } g_log = new LogConsole(); ここで、コンソールにバージョン情報を書き込む。 g_console->printf("%s\nCopyright (c) 2002-2004 higepon\n\n", version); pic_init()というのは割り込みの設定をしているようだが、その詳細は明らかでない。 RTC::init()もその類のようだ。わかんねー。 pic_init()は割り込み領域の設定とタイマーの設定を行っている。 pic_init(); RTC::init(); printOK("Setting PIC "); 割り込みデスクリプタテーブルを初期化する。 IDTUtil::setup(); printOK("Setting IDT "); printOK("Setting GDT "); このカーネルプログラムで使用している型の大きさを改めてチェックしている。 ・・・始めにチェックしとけよ・・・ checkTypeSize(); printOK("Checking type size "); マウスの初期化をする。 /* mouse init */ int mouse = Mouse::init(); if (!mouse) printOK("Setting Mouse "); else g_console->printf("Mouse init error=%d\n", mouse); 物理メモリの大きさを読む。 /* get total system memory */ g_total_system_memory = MemoryManager::getPhysicalMemorySize(); g_console->printf("\nSystem TotalL Memory %d[MB]. VRAM=%x Paging on \n", g_total_system_memory / 1024 / 1024, g_vesaDetail->physBasePtr); 共有メモリを初期化 /* shared memory object */ SharedMemoryObject::setup(); メッセージキューの初期化 /* messenger */ g_messenger = new Messenger(512); 第二の保護システム、仮想メモリの初期化。 0から8メガバイトとVRAM領域をページング領域に登録する。 0x00100000 0x00200000 0x007FFFFF ------------------------------------------------------------------------- | kernel code Domain | kernel Heap Domain | | | 0x00600000 = 6MB | ------------------------------------------------------------------------- を見るとわかるように物理メモリのはじめから8メガバイトはカーネルが使用することに なっている。 /* paging start */ g_page_manager = new PageManager(g_total_system_memory); g_page_manager->setup((PhysicalAddress)(g_vesaDetail->physBasePtr)); ダミースレッドの確保。何で確保するんだろう? /* dummy thread struct */ Thread* dummy1 = new Thread(); Thread* dummy2 = new Thread(); g_prevThread = dummy1->tinfo; g_currentThread = dummy2->tinfo; スケジューラの初期化。下の英語にあるとおり、タイマー割り込みが有効になるまでに このコードを実行しなければならない。スケジューラのコンストラクタは、 実行中のスレッドと休止中のスレッドのキューを初期化している。 /* this should be called, before timer enabled */ ProcessOperation::initialize(g_page_manager); g_scheduler = new Scheduler(); アイドルプロセスとINITプロセスを作成している。プロセスの作成にはProcessOperation::create を呼び出している。この呼び出しで、スレッドに独自のページディレクトリを与えている。 /* at first create idle process */ Process* idleProcess = ProcessOperation::create(ProcessOperation::KERNEL_PROCESS, "IDLE"); Thread* idleThread = ThreadOperation::create(idleProcess, (dword)monaIdle); g_scheduler->join(idleThread); /* start up Process */ Process* initProcess = ProcessOperation::create(ProcessOperation::KERNEL_PROCESS, "INIT"); Thread* initThread = ThreadOperation::create(initProcess, (dword)mainProcess); g_scheduler->join(initThread); disableTimer(); enableInterrupt(); g_info_level = MSG; /* dummy thread struct */ g_prevThread = dummy1->tinfo; g_currentThread = dummy2->tinfo; g_prevThread->archinfo->cr3 = 1; g_currentThread->archinfo->cr3 = 2; enableTimer(); #ifdef HIGE #endif アイドルプロセスとINITプロセスを起動し終えたら起動プログラムは特にすることはない。 というか,スケジューリングが始まるとこのプログラムが実行されることはなくなる。 しかし,スケジューリングが始まるまで若干のタイムラグがあるのでその間 for(;;); で時間をつぶすようにしている。そして,スケジューリングが始まると 実際の処理はmainProcess関数に移る。そう,新しい時代の始まりだ。 for (;;); }