locore

locoreの主な処理

locoreはkernelが立ち上がって最初に動く処理です。この処理では主にCPU関するローレベルな設定等を行います。
  1. run_loadfile関数から引き渡された引数をセーブ。
  2. EFLAGS registerを初期化。
  3. CPUの種類の特定とCPU性能情報の取得。
  4. 現在のstackは、boot lorderプログラムで使用していたstackなので、kernelエリアのstack(と言っても一時的な)に変更。
  5. bss[非初期化変数]領域のzeroクリア。
  6. ページングの設定。
  7. init386関数をcallして、i386に依存する初期設定を行う。

Kernel Imageのメモリ配置とリロケーション

Kernelが本格的に動き出すためには、ページングの機能を有効にして、仮想記憶などの設定を行う必要があります。ページングが有効になるとkernelはリニアアドレスのd01000000H番地にマッピングされ、kernelはこのアドレス上で動作するようになります。(もちろん、自動的にd01000000H番地にマッピングされる訳でなく、そのように設定を行う)。Kernelは論理アドレスで動作する事を前提としているので、Kernel内で使用されるStatic変数などのアドレスは論理アドレス上の番地に配置されています。

Kernelのメモリ配置
Kernelのメモリ配置

しかし、この時点ではまだページングが無効であり、セグメント機構しか働いていないので、kernelは物理アドレス上で動作しています。この場合、ページングの設定を行うまで、あるラベルにデータをストアする時は、そのラベルのアドレスを 論理アドレス -> 物理アドレス変換してからストアする必要があります。

objdump -d /bsd | less

bsd:     file format elf32-i386

Disassembly of section .text:

d0100120 <start>:<- 論理メモリ上のマッピングはd0100120H番地だが実際には物理メモリ上の100120H番地に存在する。
d0100120:       66 c7 05 72 04 00 00    movw   $0x1234,0x472
d0100127:       34 12 
d0100129:       8b 44 24 04             mov    0x4(%esp,1),%eax
d010012d:       a3 bc 95 52 00          mov    %eax,0x5295bc
d0100132:       8b 44 24 08             mov    0x8(%esp,1),%eax
d0100136:       a3 20 48 53 00          mov    %eax,0x534820
d010013b:       8b 44 24 10             mov    0x10(%esp,1),%eax
d010013f:       85 c0                   test   %eax,%eax	

RELOCマクロ

上記の問題を吸収するためlocoreのソース中には、RELOCマクロが存在します。RELOCマクロの中身は次のように定義されています。

#define RELOC(x)        ((x) - KERNBASE)

このマクロは現在のアドレスからKERNBASEを減算しています。KERNBASEはページング有効時に、kernelがマップされる領域の先頭アドレスが定義されていて、これを減算する事により「論理アドレス→物理アドレス」の変換を行ないます。

start:  movw    $0x1234,0x472                   # warm boot
        movl    4(%esp),%eax
        movl    %eax,RELOC(_C_LABEL(boothowto))

は、次のように変換される。
	
d0100020  start:
d0100020:       66 c7 05 72 04 00 00  movw   $0x1234,0x472
d0100027:       34 12 
d0100029:       8b 44 24 04           mov    0x4(%esp,1),%eax
d010002d:       a3 38 80 3a 00        mov    %eax,0x5295bc <- 物理アドレスに変換されている

実際のboothowtoは次のアドレス
d05295bc g     O .data  00000004 boothowto
	

arch/i386/i386/locore.s

boot設定

BIOSに対して"warm boot"の設定を行います。これにより、リブートした時にシステム診断が省略され、マシンの立上げが多少早くなります。

BISOのアドレス0x472に値を書込む事により、ブート時の動作を変更出来る。

引数の保存

boot関数から渡された引数を変数に保存する。

レジスタの初期化

EFLAGS registerPSL_MBOで初期化。FS・GSレジスタをゼロクリア。

CPU判定

80486以降のCPUではcpuid命令により、CPUの詳しい情報が取得できるようになっていますが、80386 CPUや80486互換であってもcpuid命令をサポートしていないCPUに対しては、フラグの動作でCPUの種別を判別します。

cpuid命令が使えないCPUの判定

cpuid命令が使えないCPUの判定は、EFLAGSレジスタ上のフラグの有無と演算結果でのフラグの動作状態で行います。具体的には次のようなアルゴリズムになります。

if(EFLAGS の ac[Alignment Check]が無効){
    if( 符合無し除算 (0x5555/2)の結果 ZF[Zero Flag]が変化しない){
        NexGen 586 CPU
    }
    else{
        Intel 386 CPU
    }
}
else if(EFLAGS の ID[ID flag]が無効){
    if( 符合無し除算 (0x5555/2)の結果 CF[Carry Flag]が変化する){
        Intel 486 CPU
    }
    else if(符合無し除算 (0xffffffff/4)の結果 C,PF,AF,Z,N,Vが変化する ){
        Cyrix 6x86 CPU
    }
    else{
        Cyrix 486DLC CPU
        CACHE動作の設定(config時のパラメータにより、無効/有効を選択)
    }
}
else{
   cpuidを実行
}
	
cpuid命令を使ったCPUの判定

cpuid命令を使った検出は次のようになります。

Vendor IDを取得 cpuid(ax=0)
CPUの種類と性能で取得 cpuid(ax=1)
if(CPUにCache有り){
    Cache情報を取得 cpuid(ax=2)
}
	  

上記で取得した情報は、下記の変数に格納されます。

CPU情報が格納される変数一覧
変数内容
cpuarch/i386/include/cputypes.hに定義された値が入る
cpuid_levelCPUIDの入力(AX Register)出来るMax値
cpu_vendorVendor ID
cpu_idType,Model,Family...
cpu_featureCPUの拡張機能
cpu_cache_eaxCache,TLB
cpu_cache_ebxCache,TLB
cpu_cache_ecxCache,TLB
cpu_cache_edxCache,TLB

スタックの設定

boot時に使用していたのスタックから、ページングを設定するまでの一時的なスタックtmpstk(512byteの大きさ)に変更する。

ページングの設定

長くなりそうなので、locoreでのページング設定とページを分けました。

Last modified: Tue Jan 22 18:29:45 2008 JST