0から作るソフトウェア開発
日々勉強中。。。 |
Follow @Nina_Petipa |
Tips マルチブート仕様 |
マルチブート仕様で使用する変数の型式 | |
---|---|
型式 | 説明 |
u8 | 符号なし(unsigned)の8ビットデータです |
u16 | 符号なし(unsigned)の16ビットデータです |
u32 | 符号なし(unsigned)の32ビットデータです |
u64 | 符号なし(unsigned)の64ビットデータです |
マルチブートヘッダー | |||
---|---|---|---|
マジックフィールド | |||
オフセット | 型式 | フィールド名 | 説明 |
0 | u32 | magic | マルチブートヘッダーを特定するためのマジックナンバーです。 マジックナンバーとして”必ず0x1BADB002を設定します”。 |
4 | u32 | flags |
このフィールドにはOSが必要な機能とブートローダーが必要な情報を
ヘッダーに格納しているかどうかを示すフラグです。
ブートローダーは、予約ビットに値がセットされている場合や、有効なビットが セットされていてもOSが起動できない(フラグの条件を満たせない)場合には ユーザーに通知して、OSの起動を中止する必要があります。 ビット16からビット31はオプション機能ビットとなります。 ブートローダーはビット16-31がセットされているが、 ビット16-31の機能について対応していない場合には、 このビットを無視してOSを起動させても問題ありません。 ビット0:1に設定している場合には、ブートローダーは、 OSと一緒にロードするモジュールをページ境界(4KB境界)に配置する 必要があります。(OSのなかには起動時に用意しているページに、 モジュールがロードされることを前提としているものがあるためです。) ビット1:1に設定している場合には、ブートローダーは OSに引数として渡す ブート情報構造体 のmem_*フィールドに、システムで利用可能なメモリー情報を セットする必要があります。また、メモリーマップ情報がある場合にも、 構造体のmmap_*フィールドにメモリーマップ情報をセットする 必要があります。 ビット2:1に設定している場合、OSは ブート情報構造体 のビデオモードテーブルを使用しますので、ブートローダーは テーブル値をセットする必要があります。 ビット16:1に設定している場合には、 マルチブートヘッダーのオフセット12から28が有効となります。 セットされている場合には、ブートローダーは実行フォーマットの ヘッダー(ELFヘッダーなど)ではなく、マルチブートヘッダーの 情報からOSをロードするアドレスを計算”するべき”です。 ”するべき”ですが、OSイメージがa.outフォーマットの場合には、 ”する必要がある”になります。 この仕様に準拠するブートローダーは、ELFフォーマットの OSイメージと、マルチブートヘッダーにロードするアドレスが 設定されているOSイメージ両方をロードできる必要があります。 また、必須ではありませんが、ELFフォーマット以外の実行形式に対応するのもありです。 |
8 | u32 | checksum |
チェックサムを設定します。
magicフィールドの値とflagsフィールドの値の合計と
checksumフィールドの値を足すと0になるような32ビットのチェックサムの値を設定する
必要があります。
|
アドレスフィールド | |||
flagsのビット16が1の場合に、アドレスフィールドの全部のフィールドが 有効となります。アドレスは物理アドレスです。 | |||
12 | u32 | header_addr | マルチブートヘッダーの先頭が配置される物理アドレスを設定します。 (magicフィールドの値が配置されるメモリーの物理アドレスです)。 OSの実行バイナリが使用するオフセットアドレスにあわせるために 使用します。 |
16 | u32 | load_addr | OSイメージのテキストセグメント(.text)の開始物理アドレスを 設定します。OSの実行バイナリだけをロードするために、 OSイメージファイルの先頭から何バイト目に実行バイナリが あるのかを計算するために使用します。 (header_addr - load_addrの値がマルチブートヘッダーから 数えた実行バイナリのオフセット値となります)。 このため、load_addrはheader_addr以下の値に設定する必要があります。 |
20 | u32 | load_end_addr | OSイメージの初期値付きデータセグメント(.data)の最終物理アドレスを 設定します。(load_end_addr - load_addr)は ロードする初期値有りデータのバイト数となります。 初期値有りデータセグメントとテキストセグメントは連続しているものとして ブートローダーは処理します。このように想定するのは、a.out実行形式にそのような 形式があるからです。このフィールドが0の場合、ブートローダーは OSイメージがテキストセグメントとデータセグメントだけであると判断します。 |
24 | u32 | bss_end_addr | 初期値無し変数のデータセグメント(.bss)の最終物理アドレス を設定します。ブートローダーはこのエリアをゼロで初期化します。 (ANSI C規格に準拠するためなど)。 また、ブートローダーはこのエリアにはモジュールをロードしたり、 OSに渡す情報を格納しないようにします。 このフィールドが0に設定されている場合には、ブートローダーは 初期値無し変数のデータセグメント(.bss)が無いものとして (初期化しません)処理します。 |
28 | u32 | entry_addr | OSをロードした後にジャンプする物理アドレスを設定します。 (カーネルのメイン関数のアドレスを設定します)。 |
グラフィックフィールド | |||
flagsのビット2が1の場合に、グラフィックフィールドの全部のフィールドが 有効となります。OS起動時にカーネルが要求するグラフィックモードを設定します。 グラフィックモードは”推奨”モードなだけで、要求されたグラフィックモードが あれば、ブートローダーはそのモードに設定”するべき”です。 特に指定が無い場合や要求モードが無い場合は、ブートローダーは 要求モードに似たモードに設定”するべき”です。 | |||
32 | u32 | entry_addr |
0:ブートローダーはグラフィックモードに設定します 1:ブートローダーはEGA標準のテキストモードに設定します その他の値:将来仕様のため予約されています (値が0の場合でもブートローダーはOS起動時にテキストモードに 設定してもよいです。) |
36 | u32 | width |
グラフィックの列数を設定します。 グラフィックモード:ピクセル単位で設定します。 テキストモード:文字数単位で設定します。 (値を0に設定した場合、OSはどのように設定されるかは気にしません) |
40 | u32 | height |
グラフィックの行数を設定します。 グラフィックモード:ピクセル単位で設定します。 テキストモード:文字数単位で設定します。 (値を0に設定した場合、OSはどのように設定されるかは気にしません) |
44 | u32 | depth |
0以外:グラフィックモードの1ピクセル毎のビット数を設定します 0:ビット数をどのように設定されてもOSには問題ありません |
マシン状態 | ||
---|---|---|
レジスター | 設定値 | 説明 |
EAXレジスター | 0x2BADB002 | ブートローダーはEAXレジスターに0x2BADB002を設定する必要があります。 OSでこの値を確認することでマルチブート仕様に準拠したブートローダーから ブートされたことが確認できます。(例えば、マルチブート仕様に準拠していない ブートローダーからブートされたことを判断する場合にも使用できます)。 |
EBXレジスター | ブート情報構造体の格納アドレス | ブートローダーはブート情報構造体の格納アドレスが設定されている必要があります。 |
CSレジスター | コードセグメントセレクター値 | ブートローダーが構築したGDTのコードセグメントディスクリプターを指す セレクター値が格納されています。 リミットが0xFFFFFFFでオフセットが0の読み込み/実行可能な 32ビットコードセグメント値が設定されている必要があります。 実際に設定される値は未定義となります。 |
DS、ES、FS、GS、SSレジスター | データセグメントセレクター値 | ブートローダーが構築したGDTのデータセグメントディスクリプターを指す セレクター値が格納されています。 リミットが0xFFFFFFFでオフセットが0の読み込み/書き込み可能な 32ビットデータセグメント値が設定されている必要があります。 実際に設定される値は未定義となります。 |
A20 | A20ゲート有効 | OS起動時にはA20が有効となっている必要があります。 |
CR0制御レジスター | ビット31(PGビット) = 0 | OS起動時にはCR0制御レジスターのビット31(PGビット)が0にクリアー されている必要があります。CR0の他のビットは未定義となります。 |
EFLAGS |
ビット9(IFビット) = 0 ビット17(VMビット) = 0 |
OS起動時にはEFLAGSレジスターのビット17(VMビット)と ビット9(IFビット)が0にクリアー されている必要があります。EFLAGSの他のビットは未定義となります。 |
その他のレジスター | 未定義 | その他のCPUのレジスターとフラグは未定義となります。 |
CR0レジスタ | ||
---|---|---|
ビット | ビット名称 | 説明 |
0 | PE | Protection Enableビット。このビットをONにするとプロテクティッドモードへ移行します |
1 | MP |
Monitor Co-Processorビット。モニタ・コプロセッサビット WAIT命令を実行したときの動作を変更することができます 0:TSビットが0でも1でも関係なく無視する 1:TSビットが1であればコプロセッサ使用不可能例外を発生させる |
2 | EM |
Emulationビット。エミュレーションビット 浮動小数点演算(x87 FPU)命令を実行したときの動作を変更することができます 0:x87 FPUを持っているので命令実行可能 1:命令実行時x87 FPUを持っていないのでコプロセッサ使用不可例外が発生する ソフトウェアによってエミュレーションを行う ※細かい条件はIntelのCPU仕様書をご確認ください |
3 | TS |
Task Switchビット。タスクスイッチビット CPUはタスクスイッチする時にこのビットを1にします ※EM、MPビットの設定によっては影響があります |
4 | ET |
Extended Typeビット。拡張タイプビット 0:80287以前のCPU 1:80387以後のCPU |
5 | NE |
数値演算エラービット 0:x87 FPUエラーレポート無効 1:x87 FPUエラーレポート有効 |
16 | WP |
Write Protectビット。書き込み保護ビット 0:リング0のプログラムが読み取り専用のユーザ空間に書き込むことができる 1:リング0のプログラムが読み取り専用のユーザ空間に書き込むことを禁止 |
18 | AM |
Alignment Maskビット。アライメントマスクビット 0:自動アライメントチェック無効 1:自動アライメントチェック有効 |
29 | NW |
Not Write throughビット。ノットライトスルービット 0:CDビットが0の場合キャッシュをライトバックまたはライトスルーが有効 1:CDビットとNWビットの組み合わせはCPUのマニュアル10-17ページを参照ください |
30 | CD |
Cache Disableビット。キャッシュ無効ビット 0:NWビットが0の場合キャッシュ操作が有効 1:CDビットとNWビットの組み合わせはCPUのマニュアル10-17ページを参照ください |
31 | PG |
PaGingビット。ページングビット 0:ページング無効 1:ページング有効 |
EFLAGSレジスタ | ||
---|---|---|
ビット |
ステータス フラグ |
説明 |
0 | CF |
Carry Flag キャリーフラグ 1:足し算なので最上位ビットが繰り上げた場合。(例:0xFFFF+1や0x0000-1をした場合) 0:繰り上げが発生しなかった場合。(例:x0FFFE+1をした場合) |
2 | PF |
Parity Flag パリティフラグ 1:演算した結果の最下位バイトに値1のビットが偶数個ある場合(例:0xFF03など) 0:逆に奇数個の場合(例:0x0F10など) |
4 | AF |
Adjust Flag 調整フラグ 1:演算した結果のビット3(最下位バイトの最上位ビット)に繰り上げが発生した場合(例:0x0080+0x08など) 0:逆に繰り上げが発生しなかった場合 |
6 | ZF |
Zero Flag ゼロフラグ 1:演算した結果が0の場合 0:逆に0位外の場合 |
7 | SF |
Sign Flag 符号フラグ 1:演算した結果が負の場合 0:逆に正の場合 |
8 | TF |
Trap Flag トラップフラグ 1:デバッグのシングルステップモードが有効 0:逆にシングルステップモードが無効 |
9 | IF |
Interrupt Enable Flag 割り込み可能フラグ 1:割り込みが有効。STI命令を実行するとこのフラグが1になります 0:割り込みが無効。CLI命令を実行するとこのフラグが0になります 割り込みを有効にするか無効にするかするフラグです。 |
10 | DF |
Direction Flag 方向フラグ 1:文字列関係の命令(LODSBなど)で実行した後例えばSIレジスタの値がインクリメントされる 0:逆にデクリメントされる |
11 | OF |
Overflow Flag オバーフローフラグ 1:演算結果が格納するレジスタより大きい数字になった場合(例:0xFF+0x01をALレジスタに格納) 0:逆に格納するレジスタより小さい場合 |
12-13 | IOPL |
I/O privilege level field I/O特権レベルフィールド このフィールドには特権レベルの値を入れます(通常0から3) 0以外:ユーザモードとして動作します 0 :特権モードとして動作します このフィールドの値は特にCPL(Current Privilege Level)と言います。後々出てきます。 |
14 | NT |
Nested Task Flag ネストタスクフラグ 1:現在のタスクが直前に実行されたタスクにリンクされている場合 0:逆にリンクされていない場合 |
16 | RF |
Resume Flag 再開フラグ デバッグ例外に対するプロセッサの応答を制御する |
17 | VM |
Virtual-8086 mode Flag 仮想8086モードフラグ 1:仮想8086モードが有効 0:仮想8086モードが無効(プロテクティッドモード) |
18 | AC |
Alignment check Flag アライメントチェックフラグ 1:アライメントチェックが有効(CR0レジスタのAMビットもセットしておく必要があります) 0:アライメントチェックが無効 |
19 | VIF |
Virtual interrupt Flag 仮想割り込みフラグ 1:仮想割り込みが有効(CR4レジスタのVMEビットもセットしておく必要があります) 0:仮想割り込みが無効 |
20 | VIP |
Virtual interrupt pending Flag 仮想割り込み保留フラグ 1:仮想割り込みが保留状態(CR4レジスタのVMEビットもセットしておく必要があります) 0:仮想割り込みに保留無し |
21 | ID |
Identification Flag 識別フラグ プログラムから値0か1を書き込むことができると、CPUID命令が使えることを意味します |
ESPレジスター、GDTR、IDTR | |
---|---|
レジスター | 説明 |
ESPレジスター | OS起動後、カーネルは直ぐにスタックポインターを設定する必要があります |
GDTR | セグメントレジスターはブートローダーが設定しますが、 GDTRが有効でない”可能性があります”ので、 OSはそのカーネル専用のGDTを構築するまでは、 セグメントレジスターの値を変更してはいけません。 |
IDTR | OSはそのカーネル専用のIDTを構築するまでは、 割り込みを禁止しておく必要があります。 |
マルチブート情報 | |||
---|---|---|---|
ラベル名 |
オフセット (バイト) |
サイズ (バイト) |
説明 |
flags | 0 | 4 |
ブート情報の各フィールドが有効/無効(有り/無し)となっているか示すフラグです 各ビットが1になっていれば有効(有り)で、0であれば無効(無し)となります ビット0:1であればmem_*フィールドが有効になります ビット1:1であればboot_deviceフィールドが有効になります ビット2:1であればcmdlineフィールドが有効になります ビット3:1であればmods_*フィールドが有効になります ビット4:1であればsymフィールドがa.outカーネルイメージ用の フォーマットになります ビット5:1であればsymフィールドがELFカーネルイメージ用の フォーマットになります ビット6:1であればmmap_*フィールドが有効になります ビット7:1であればdrives_*フィールドが有効になります ビット8:1であればconfig_tableフィールドが有効になります ビット9:1であればboot_loader_nameフィールドが有効になります ビット10:1であればapm_tableフィールドが有効になります ビット11:1であればvbe_*フィールドが有効になります |
mem_lower | 4 | 4 | ローメモリーのメモリーサイズが格納されています。 メモリーサイズはキロバイト単位で格納されます。 ローメモリーの最小アドレスは0から始まります。 最大アドレスは640KBとなります。 |
mem_upper | 8 | 4 | 拡張メモリー(1MB以降のメモリー領域)のメモリーサイズが格納されています。 メモリーサイズはキロバイト単位で格納されます。 拡張メモリの最小アドレスは1MBから始まります。 最大アドレスは、拡張メモリー以降にある最初の予約メモリー領域の アドレスから1MBを引いたアドレスとなります。(このアドレス値 の保証はありません。) |
boot_device | 12 | 4 |
ブートローダーが、OSをロードしたBIOSのディスクデバイス情報が格納されます。
OSがBIOSディスク以外からロードされた場合には、このフィールドは
無効(存在しない)となっている必要があります。
このフィールドを見て、OSはルートデバイスを判断できます(必要時)。
boot_deviceフィールドは次のように4バイトに分かれています。 drive:BIOSディスクサービス(INT 0x13)で使用される、BIOSドライブ番号が 格納されます。(0x00はフロッピーディスク、0x80ならHDDなど)。 part1:トップのパーディション番号が格納されます。 part2:サブパーティション番号が格納されます。 part3:サブパーティション番号が格納されます。 パーティション番号のは0から始まる数字となります。 使用されていないパーティションは0xFFに設定されている必要があります。 例えば、1つのDOSパーティションを使用している場合には、 part1はDOSパーティション番号が格納され、 part2とpart3は0xFFが格納されます。 また、最初のパーティションがDOSで、次のパーティションがBSDパーティション (DOSパーティションのサブパーティション)の 場合にはpart1にはDOSパーティション番号が格納され、 part2にはBSDのサブパーティション番号が格納され、 part3には0xFFが格納されます。 |
cmdline | 16 | 4 | カーネルに渡すコマンドラインの物理アドレスが格納されます。 コマンドラインはC言語のNullで終わる文字列となります。 |
mods_count | 20 | 4 |
カーネルと一緒にロードされるモジュールの情報がモジュール構造体として
メモリーに格納されます。そのモジュール構造体の数と格納されている
物理アドレスが格納されます。
mods_count:ロードされたモジュール数が格納されます。 モジュールが1つもロードされていない場合は0となります。 mods_addr:最初のモジュール構造体がロードされた物理アドレスが格納 されます。 各モジュール構造体は次のような構造となっています。 mod_start:ロードされたモジュールの開始アドレスが格納されます。 mode_end:ロードされたモジュールの最終アドレスが格納されます。 string:ロードされたモジュールに関する任意の文字列が格納されます。 文字列はASCIIで0x00が文字列の終端となります。通常文字列として、 コマンドラインや(OSがモジュールを実行ファイルとして 実行する場合など)、パス(モジュールをファイルとして扱う場合など)が 格納されますが、実際はどのように利用するかは各OSによって異なります。 reserved:0固定にする必要があります。OSはこのフィールドを 無視する必要があります。 |
mods_addr | 24 | 4 | |
syms | 28-40 | 12 |
flagsのビット4とビット5はどちらか一方だけ1が設定されます(排他関係)。 ビット4が1の場合(ビット5は0) symsフィールドは次のような構造となります。 a.outフォーマットのカーネルイメージのヘッダーにあるシンボルテーブルの情報が 格納されます。 addr:a.outフォーマットにはnlist構造体の配列(テーブル)の 直ぐ次にそのテーブル自体のサイズが配置されています。 そのテーブルのサイズが格納されている物理アドレスが 格納されます。格納されているサイズ自体はunsigned longの 整数値でASCII文字で0終端の文字列で格納されています。 tabsize:a.outフォーマットの シンボルセクションの最初に配置されている サイズパラメーターが格納されています。シンボルが無い場合は 0が格納されます。 strsize:a.outフォーマットの ストリングクションの最初に配置されている サイズパラメーターが格納されています。 |
flagsのビット4とビット5はどちらか一方だけ1が設定されます(排他関係)。 ビット5が1の場合(ビット4は0) symsフィールドは次のような構造となります。 ELFフォーマットのカーネルイメージにあるshdr_*の情報が格納されます。 (ELFフォーマットのプログラムヘッダーにあるshdr_num、shdr_size、shdr_addr、shdr_shndxが それぞれ、num、size、addr、shndxにあたります)。 カーネルイメージのセクションが全てロードされて、各セクションが物理アドレスの どこにロードされているのかをELFセクションヘッダーの物理アドレスフィールドで 取得することができます。シンボルが無い場合には、shdr_numが0になります。 |
|||
mmap_length | 44 | 4 | メモリマップ情報のデータ長が格納されています |
mmap_addr | 48 | 4 |
メモリーマップ情報が格納されているアドレスが格納されています。
メモリーマップ情報の各エントリーは次のようなフォーマットで格納されています。 メモリーマップ情報の1つのエントリーはbase_addr、length、typeの3つの フィールドとなります。このエントリーがメモリー領域数分の配列となって格納されています。 sizeフィールドは先頭のみとなります。 size:メモリーマップ情報のサイズが格納されます。 20(バイト)より大きい値が入ります。 base_addr:そのメモリー領域の開始アドレスとなります。 length:そのメモリー領域のサイズが格納されます type:そのメモリー領域の種類が格納されます。値が1ならばRAMでその他の値であれば 予約領域となります。 メモリーマップ情報にあるRAMメモリー領域の情報は全てOSで利用可能な領域となります。 |
drive_length | 52 | 4 |
ドライブ構造体の格納情報が格納されます。 drive_addr:ドライブ構造体が格納されている物理アドレスが 格納されます。 drive_length:ドライブ構造体のサイズが格納されます。 情報が無い場合は0が格納されます。 ドライブ構造体は次のようなフォーマットとなります。 size:この構造体のサイズが格納されています。サイズはdrive_portsの数 で変わります。メモリー上のアライメントのため、サイズは必ずしも(10 + 2 * ポート数)と はなりません。 drive_number:BIOSドライブ番号が格納されます。 drive_mode:ブートローダーがドライブにアクセスするモードが格納されます。 値が0の場合、CHSモード(シリンダー/ヘッド/セクターを指定してアクセス)。値が1の 場合、LBA(Logical Block Addressing)モードとなります。 drive_cylinders、drive_head、drive_sectors: BIOSが検出したそのドライブが持っているシリンダー数、ヘッド数、セクター数が格納されます。 drive_ports:BIOSで使用されるI/Oポート番号が配列で格納されます。値は unsignedの2バイト整数か0となります。値が0であれば配列の終端となります。 (配列にはドライブと関係ないI/Oポート番号が格納されている可能性があります)。 |
drive_addr | 56 | 4 | |
config_table | 60 | 4 | BIOSのシステム設定情報取得 サービスコールで取得したテーブルが格納されている物理アドレスが格納されます。 |
boot_loader_name | 64 | 4 | OSを起動したブートローダーの名前が格納された物理アドレスが格納されます。 メモリーに格納される名前の文字列はC言語のNullで終わる文字列となります。 |
apm_table | 68 | 4 |
APMテーブルが格納されている物理アドレスが格納されます。 APMテーブルのフォーマットは次のようになります。 version:バージョン番号 cseg:プロテクティッドモード32ビットコードセグメント offset:エントリーポイントのオフセット cseg_16:プロテクティッドモード16ビットコードセグメント dseg:プロテクティッドモード16ビットデータセグメント flags:フラグ cseg_len:プロテクティッドモード32ビットコードセグメントのサイズ cseg_16_len:プロテクティッドモード16ビットコードセグメントのサイズ dseg_len:データセグメントのサイズ 詳細はAdvanced Power Management (APM) BIOS Interface Specification (APM BIOSインターフェース仕様)を参照してください。 |
vbe_control_info | 72 | 4 |
OS起動時にグラフィックモードが必要な場合で、マルチブートヘッダーに
グラフィックモードの指定があるときのみ値が格納されます。
vbe_control_info:VBE(VESA BIOS Extension:VESA BIOS拡張)で規定されている VBE機能0x00の返り値として得られるVBE制御情報が格納されている物理アドレスが格納されます。 vbe_mode_info:VBE機能0x01の返り値として得られるVBEモード情報が格納されている物理アドレスが格納されます。 vbe_interface_seg:VBE 2.0+で規定されているプロテクティッドモードインターフェースのテーブル値が格納されます。 vbe_interface_off:VBE 2.0+で規定されているプロテクティッドモードインターフェースのテーブル値が格納されます。 vbe_interface_len:VBE 2.0+で規定されているプロテクティッドモードインターフェースのテーブル値が格納されます。 テーブル値の情報が利用できない場合には、vbe_interface_*の値は0となります。 VBE 3.0では旧バージョンのVBEと互換性の無いプロテクティッドモードインターフェースが定義されいますので、 注意してください。VBE 3.0以降のテーブルを使用する場合はカーネル自身でテーブル値を取得する 必要があります。VBE用に、グラフィックテーブル用のフィールドを定義していますが、マルチブートローダーは 非VBEモードでもVBEモードをシミュレートしてフィールドに値を設定することもできます。 |
vbe_mode_info | 76 | 4 | |
vbe_mode | 80 | 2 | |
vbe_interface_seg | 82 | 2 | |
vbe_interface_off | 84 | 2 | |
vbe_interface_len | 86 | 2 |
/* multiboot.h - Multiboot header file. */ /* Copyright (C) 1999,2003,2007,2008,2009 Free Software Foundation, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef MULTIBOOT_HEADER #define MULTIBOOT_HEADER 1
/* How many bytes from the start of the file we search for the header. */
#define MULTIBOOT_SEARCH 8192
/* The magic field should contain this. */
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
/* This should be in %eax. */
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
/* The bits in the required part of flags field we don't support. */
#define MULTIBOOT_UNSUPPORTED 0x0000fffc
/* Alignment of multiboot modules. */
#define MULTIBOOT_MOD_ALIGN 0x00001000
/* Alignment of the multiboot info structure. */
#define MULTIBOOT_INFO_ALIGN 0x00000004
/* Flags set in the 'flags' member of the multiboot header. */ /* Align all boot modules on i386 page (4KB) boundaries. */
#define MULTIBOOT_PAGE_ALIGN 0x00000001
/* Must pass memory information to OS. */
#define MULTIBOOT_MEMORY_INFO 0x00000002
/* Must pass video information to OS. */
#define MULTIBOOT_VIDEO_MODE 0x00000004
/* This flag indicates the use of the address fields in the header. */
#define MULTIBOOT_AOUT_KLUDGE 0x00010000
/* Flags to be set in the 'flags' member of the multiboot info structure. */ /* is there basic lower/upper memory information? */
#define MULTIBOOT_INFO_MEMORY 0x00000001
/* is there a boot device set? */
#define MULTIBOOT_INFO_BOOTDEV 0x00000002
/* is the command-line defined? */
#define MULTIBOOT_INFO_CMDLINE 0x00000004
/* are there modules to do something with? */
#define MULTIBOOT_INFO_MODS 0x00000008
/* These next two are mutually exclusive */ /* is there a symbol table loaded? */
#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010
/* is there an ELF section header table? */
#define MULTIBOOT_INFO_ELF_SHDR 0X00000020
/* is there a full memory map? */
#define MULTIBOOT_INFO_MEM_MAP 0x00000040
/* Is there drive info? */
#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080
/* Is there a config table? */
#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100
/* Is there a boot loader name? */
#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200
/* Is there a APM table? */
#define MULTIBOOT_INFO_APM_TABLE 0x00000400
/* Is there video information? */
#define MULTIBOOT_INFO_VIDEO_INFO 0x00000800 #ifndef ASM_FILE typedef unsigned short multiboot_uint16_t; typedef unsigned int multiboot_uint32_t; typedef unsigned long long multiboot_uint64_t; struct multiboot_header {
/* Must be MULTIBOOT_MAGIC - see above. */
multiboot_uint32_t magic;
/* Feature flags. */
multiboot_uint32_t flags;
/* The above fields plus this one must equal 0 mod 2^32. */
multiboot_uint32_t checksum;
/* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */
multiboot_uint32_t header_addr; multiboot_uint32_t load_addr; multiboot_uint32_t load_end_addr; multiboot_uint32_t bss_end_addr; multiboot_uint32_t entry_addr;
/* These are only valid if MULTIBOOT_VIDEO_MODE is set. */
multiboot_uint32_t mode_type; multiboot_uint32_t width; multiboot_uint32_t height; multiboot_uint32_t depth; };
/* The symbol table for a.out. */
struct multiboot_aout_symbol_table { multiboot_uint32_t tabsize; multiboot_uint32_t strsize; multiboot_uint32_t addr; multiboot_uint32_t reserved; }; typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
/* The section header table for ELF. */
struct multiboot_elf_section_header_table { multiboot_uint32_t num; multiboot_uint32_t size; multiboot_uint32_t addr; multiboot_uint32_t shndx; }; typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; struct multiboot_info {
/* Multiboot info version number */
multiboot_uint32_t flags;
/* Available memory from BIOS */
multiboot_uint32_t mem_lower; multiboot_uint32_t mem_upper;
/* "root" partition */
multiboot_uint32_t boot_device;
/* Kernel command line */
multiboot_uint32_t cmdline;
/* Boot-Module list */
multiboot_uint32_t mods_count; multiboot_uint32_t mods_addr; union { multiboot_aout_symbol_table_t aout_sym; multiboot_elf_section_header_table_t elf_sec; } u;
/* Memory Mapping buffer */
multiboot_uint32_t mmap_length; multiboot_uint32_t mmap_addr;
/* Drive Info buffer */
multiboot_uint32_t drives_length; multiboot_uint32_t drives_addr;
/* ROM configuration table */
multiboot_uint32_t config_table;
/* Boot Loader Name */
multiboot_uint32_t boot_loader_name;
/* APM table */
multiboot_uint32_t apm_table;
/* Video */
multiboot_uint32_t vbe_control_info; multiboot_uint32_t vbe_mode_info; multiboot_uint16_t vbe_mode; multiboot_uint16_t vbe_interface_seg; multiboot_uint16_t vbe_interface_off; multiboot_uint16_t vbe_interface_len; }; typedef struct multiboot_info multiboot_info_t; struct multiboot_mmap_entry { multiboot_uint32_t size; multiboot_uint64_t addr; multiboot_uint64_t len; #define MULTIBOOT_MEMORY_AVAILABLE 1 #define MULTIBOOT_MEMORY_RESERVED 2 multiboot_uint32_t type; } __attribute__((packed)); typedef struct multiboot_mmap_entry multiboot_memory_map_t; struct multiboot_mod_list {
/* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
multiboot_uint32_t mod_start; multiboot_uint32_t mod_end;
/* Module command line */
multiboot_uint32_t cmdline;
/* padding to take it to 16 bytes (must be zero) */
multiboot_uint32_t pad; }; typedef struct multiboot_mod_list multiboot_module_t; #endif
/* ! ASM_FILE */
#endif
/* ! MULTIBOOT_HEADER */
/* boot.S - bootstrap the kernel */ /* Copyright (C) 1999, 2001 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#define ASM_FILE 1 #include <multiboot.h>
/* C symbol format. HAVE_ASM_USCORE is defined by configure. */
#ifdef HAVE_ASM_USCORE # define EXT_C(sym) _ ## sym #else # define EXT_C(sym) sym #endif
/* The size of our stack (16KB). */
#define STACK_SIZE 0x4000
/* The flags for the Multiboot header. */
#ifdef __ELF__ # define MULTIBOOT_HEADER_FLAGS 0x00000003 #else # define MULTIBOOT_HEADER_FLAGS 0x00010003 #endif .text .globl start, _start start: _start: jmp multiboot_entry
/* Align 32 bits boundary. */
.align 4
/* Multiboot header. */
multiboot_header:
/* magic */
.long MULTIBOOT_HEADER_MAGIC
/* flags */
.long MULTIBOOT_HEADER_FLAGS
/* checksum */
.long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) #ifndef __ELF__
/* header_addr */
.long multiboot_header
/* load_addr */
.long _start
/* load_end_addr */
.long _edata
/* bss_end_addr */
.long _end
/* entry_addr */
.long multiboot_entry #endif
/* ! __ELF__ */
multiboot_entry:
/* Initialize the stack pointer. */
movl $(stack + STACK_SIZE), %esp
/* Reset EFLAGS. */
pushl $0 popf
/* Push the pointer to the Multiboot information structure. */
pushl %ebx
/* Push the magic value. */
pushl %eax
/* Now enter the C main function... */
call EXT_C(cmain)
/* Halt. */
pushl $halt_message call EXT_C(printf) loop: hlt jmp loop halt_message: .asciz "Halted."
/* Our stack area. */
.comm stack, STACK_SIZE
/* kernel.c - the C part of the kernel */ /* Copyright (C) 1999 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <multiboot.h>
/* Macros. */ /* Check if the bit BIT in FLAGS is set. */
#define CHECK_FLAG(flags,bit) ((flags) & (1 << (bit)))
/* Some screen stuff. */ /* The number of columns. */
#define COLUMNS 80
/* The number of lines. */
#define LINES 24
/* The attribute of an character. */
#define ATTRIBUTE 7
/* The video memory address. */
#define VIDEO 0xB8000
/* Variables. */ /* Save the X position. */
static int xpos;
/* Save the Y position. */
static int ypos;
/* Point to the video memory. */
static volatile unsigned char *video;
/* Forward declarations. */
void cmain (unsigned long magic, unsigned long addr); static void cls (void); static void itoa (char *buf, int base, int d); static void putchar (int c); void printf (const char *format, ...);
/* Check if MAGIC is valid and print the Multiboot information structure pointed by ADDR. */
void cmain (unsigned long magic, unsigned long addr) { multiboot_info_t *mbi;
/* Clear the screen. */
cls ();
/* Am I booted by a Multiboot-compliant boot loader? */
if (magic != MULTIBOOT_BOOTLOADER_MAGIC) { printf ("Invalid magic number: 0x%x\n", (unsigned) magic); return; }
/* Set MBI to the address of the Multiboot information structure. */
mbi = (multiboot_info_t *) addr;
/* Print out the flags. */
printf ("flags = 0x%x\n", (unsigned) mbi->flags);
/* Are mem_* valid? */
if (CHECK_FLAG (mbi->flags, 0)) printf ("mem_lower = %uKB, mem_upper = %uKB\n", (unsigned) mbi->mem_lower, (unsigned) mbi->mem_upper);
/* Is boot_device valid? */
if (CHECK_FLAG (mbi->flags, 1)) printf ("boot_device = 0x%x\n", (unsigned) mbi->boot_device);
/* Is the command line passed? */
if (CHECK_FLAG (mbi->flags, 2)) printf ("cmdline = %s\n", (char *) mbi->cmdline);
/* Are mods_* valid? */
if (CHECK_FLAG (mbi->flags, 3)) { multiboot_module_t *mod; int i; printf ("mods_count = %d, mods_addr = 0x%x\n", (int) mbi->mods_count, (int) mbi->mods_addr); for (i = 0, mod = (multiboot_module_t *) mbi->mods_addr; i < mbi->mods_count; i++, mod++) printf (" mod_start = 0x%x, mod_end = 0x%x, cmdline = %s\n", (unsigned) mod->mod_start, (unsigned) mod->mod_end, (char *) mod->cmdline); }
/* Bits 4 and 5 are mutually exclusive! */
if (CHECK_FLAG (mbi->flags, 4) && CHECK_FLAG (mbi->flags, 5)) { printf ("Both bits 4 and 5 are set.\n"); return; }
/* Is the symbol table of a.out valid? */
if (CHECK_FLAG (mbi->flags, 4)) { multiboot_aout_symbol_table_t *multiboot_aout_sym = &(mbi->u.aout_sym); printf ("multiboot_aout_symbol_table: tabsize = 0x%0x, " "strsize = 0x%x, addr = 0x%x\n", (unsigned) multiboot_aout_sym->tabsize, (unsigned) multiboot_aout_sym->strsize, (unsigned) multiboot_aout_sym->addr); }
/* Is the section header table of ELF valid? */
if (CHECK_FLAG (mbi->flags, 5)) { multiboot_elf_section_header_table_t *multiboot_elf_sec = &(mbi->u.elf_sec); printf ("multiboot_elf_sec: num = %u, size = 0x%x," " addr = 0x%x, shndx = 0x%x\n", (unsigned) multiboot_elf_sec->num, (unsigned) multiboot_elf_sec->size, (unsigned) multiboot_elf_sec->addr, (unsigned) multiboot_elf_sec->shndx); }
/* Are mmap_* valid? */
if (CHECK_FLAG (mbi->flags, 6)) { multiboot_memory_map_t *mmap; printf ("mmap_addr = 0x%x, mmap_length = 0x%x\n", (unsigned) mbi->mmap_addr, (unsigned) mbi->mmap_length); for (mmap = (multiboot_memory_map_t *) mbi->mmap_addr; (unsigned long) mmap < mbi->mmap_addr + mbi->mmap_length; mmap = (multiboot_memory_map_t *) ((unsigned long) mmap + mmap->size + sizeof (mmap->size))) printf (" size = 0x%x, base_addr = 0x%x%x," " length = 0x%x%x, type = 0x%x\n", (unsigned) mmap->size, mmap->addr >> 32, mmap->addr & 0xffffffff, mmap->len >> 32, mmap->len & 0xffffffff, (unsigned) mmap->type); } }
/* Clear the screen and initialize VIDEO, XPOS and YPOS. */
static void cls (void) { int i; video = (unsigned char *) VIDEO; for (i = 0; i < COLUMNS * LINES * 2; i++) *(video + i) = 0; xpos = 0; ypos = 0; }
/* Convert the integer D to a string and save the string in BUF. If BASE is equal to 'd', interpret that D is decimal, and if BASE is equal to 'x', interpret that D is hexadecimal. */
static void itoa (char *buf, int base, int d) { char *p = buf; char *p1, *p2; unsigned long ud = d; int divisor = 10;
/* If %d is specified and D is minus, put `-' in the head. */
if (base == 'd' && d < 0) { *p++ = '-'; buf++; ud = -d; } else if (base == 'x') divisor = 16;
/* Divide UD by DIVISOR until UD == 0. */
do { int remainder = ud % divisor; *p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10; } while (ud /= divisor);
/* Terminate BUF. */
*p = 0;
/* Reverse BUF. */
p1 = buf; p2 = p - 1; while (p1 < p2) { char tmp = *p1; *p1 = *p2; *p2 = tmp; p1++; p2--; } }
/* Put the character C on the screen. */
static void putchar (int c) { if (c == '\n' || c == '\r') { newline: xpos = 0; ypos++; if (ypos >= LINES) ypos = 0; return; } *(video + (xpos + ypos * COLUMNS) * 2) = c & 0xFF; *(video + (xpos + ypos * COLUMNS) * 2 + 1) = ATTRIBUTE; xpos++; if (xpos >= COLUMNS) goto newline; }
/* Format a string and print it on the screen, just like the libc function printf. */
void printf (const char *format, ...) { char **arg = (char **) &format; int c; char buf[20]; arg++; while ((c = *format++) != 0) { if (c != '%') putchar (c); else { char *p; c = *format++; switch (c) { case 'd': case 'u': case 'x': itoa (buf, c, *((int *) arg++)); p = buf; goto string; break; case 's': p = *arg++; if (! p) p = "(null)"; string: while (*p) putchar (*p++); break; default: putchar (*((int *) arg++)); break; } } } }
$ i686-pc-linux-gnu-gcc -c -o kernel.o kernel.c -I./
$ i686-pc-linux-gnu-gcc -c -o boot.o boot.S -I./
$ i686-pc-linux-gnu-ld -Ttext=0x100000 --oformat=elf32-i386 boot.o kernel.o -o KImage