OpenBSDでのMBR

OpenBSDでのMBR処理

一般的に、HDDの全てを使ってOpenBSDをインストールしている場合、mbr.Sで定義されているプログラムおよびデータがMBRには書かれていると思います。または、Linuxなど他のOSを別パーティションにインストールしてある場合は、FIFOなど別のMBRが書かれているかもしれません。

このプログラムおよびデータは、HDDのMBR(Master Boot Record)領域に書かれていて、PCの電源を入れたときにBIOSによって、自動的に0x07c00番地にロードし、実行されます。

OpenBSDが提供しているMBRは非常に簡単で、OpenBSDのPBR[Partition Boot Record]をロードする為だけの機能しかなく、他のOSを切り替えてブートさせたりする機能は存在しない、非常にシンプルな構成になっています。

OpenBSD3.5までのMBRは、INT 13Hを使用していた為に8.4GBを超えたパーティションにあるOSをブート出来ませんでしたが、OpenBSD3.6からは拡張INT 13Hを使用するようになったので8.4GB超えの制限は無くなりました。

arch/i386/stand/mbr/mbr.S

セグメント レジスタの設定

コード セグメントの調整
プログラムが実行された当初は、Code Segment Register(CS)の値が0x0000となっているので、ロングジャンプを行ない、CS レジスタの値をBOOTSEGの値に再設定します。
スタック セグメントの設定
Stack Segment Register(SS)をCSと同じようにBOOTSEGに設定した後、Stack Pointer Register(SP)をBOOTSTACKOFFに設定します。これによりStack領域は07C0:FFFCに設定されます。

以前は、Stack Segment register(SS)を設定する前には、割り込み禁止にしていましたが、

「SSに対してmov命令を行なうときは、次の命令まで全ての割り込みが抑制される。」

との事なので、直前のcli命令と、直後のsti命令はコメントにされています。

データ セグメントの設定
Data Segment Register(DS)レジスタをBOOTSEGに設定します。
設定後のレジスタ
セグメント レジスタの設定が終わった段階での各レジスタが示す領域は下記のようになります。
設定後のレジスタ
設定後のレジスタ

MBRの再配置

MBRのリロケーション
メモリのBOOTSEGに読込まれているMBRをBOOTRELOCSEGの領域にコピーを行います。
リロケーション先にジャンプ
relocにジャンプします。
ここで注意するのは、一行下にジャンプしていますが、BOOTSEG:relocにジャンプしているのではなく、リロケーション先であるBOOTRELOCSEG:relocにジャンプしていると言うことです。 つまりジャンプ後は、コピー先アドレスであるBOOTRELOCSEG上にあるコードが実行されることになり、ジャンプ後はCS レジスタもBOOTRELOCSEG(0x7a0)に変更されます。
ES,DSレジスタの設定
ES レジスタBOOTBIOS(0x7c0)にセットし、DS レジスタをBOOTRELOC(0x7a0)にセットします。
リロケーション後のレジスタ
リロケーション後の段階での各レジスタが示す領域は下記のようになります。
リロケーション後のレジスタ
リロケーション後のレジスタ

SHIFT key押下の検出

現在のMBRは、PBR(biosboot)の読出しに拡張INT 13Hを使用するようになり、OpenBSDのパーティションが8Gを超えた場所に存在していてもブートが可能となりました。しかし従来のINT 13Hでも読出せるようにフォールバックシーケンスも持っています。フォールバックさせるにはboot中にシフトキーを押下していれば、INT 13Hで読出すようになります。ここでの処理ははSHIFT key押下の検出を行ない読出し方法の決定を行ないます。

SHIFT key押下検出

SHIFT key押下はINT 16Hを使用して検出を行います。INT 16H入出力は下記のようになります。

INT 16Hの入力パラメータ
入力
レジスタ 内容
AH 02h(GET SHIFT FLAGS)
INT 16Hの出力パラメータ
出力
レジスタ 内容
AH shift flags

出力されたshift flagsの意味は下記の意味を持ちます。bit0かbit1が1ならばshift keyが押下された事になります。

shift flagsのビットアサイン
shift flags
bit意味
0right shift key pressed
1left shift key pressed
2Ctrl key pressed (either Ctrl on 101/102-key keyboards)
3Alt key pressed (either Alt on 101/102-key keyboards)
4ScrollLock active
5NumLock active
6CapsLock active
7Insert active
検出時の処理

シフトキー押下が検出出来た場合は、ブザーを約1秒鳴らし検出出来たことをオペレータに知らせます。そして、flagsMBR_FLAGS_FORCE_CHS検出bitをセットします。

boot driveのチェック

PC/AT互換機のBIOSは、電源立上げ時に接続されているDisk drive の検索を行ないます。通常は、IDE Pri-Master → Pri-Slave → Sec-Master → Sec-Slave→ SCSI1 ID1 → ID2 → ID3 ...と言う順番で検出されますが、BIOSメニューで起動ドライブの変更を行なった場合は指定されたドライブが最初に検索されます。そしてBIOSは、見つかった順番にそれぞれ0x80,0x81...とユニークなdrive numberを振っていきます。

BIOSは最初にFDDからの起動をdrive number順に試みて(FDDのdrive numberは0x00,0x01...とIDが振られる)失敗した場合、0x80のdriveからdrive number順に起動を試みます。そして、起動されたデバイスのdrive numberはBIOSによってDL レジスタにセットされ、MBRプログラムに渡されます。

HDDからのブートかチェック
起動したドライブのIDはDL レジスタにセットされBIOSから渡されので、HDDからのbootであるか(DL レジスタのbit7目が1か)チェックを行ないます。
不正な値の場合は画面に表示
FDDまたは不正な値の場合は(古いBIOSの場合値がセットされて来ない場合があるようです)、画面上に次のようなメッセージを表示します。
MBR on floppy or old BIOS
	  
値の修正
不正な値が入っていた場合、DLレジスタに0x80を書込んで処理を続けます。DLの値を無理やり修正してしまってもdisk読出しの処理でエラーになるので問題無いのだと思います。
しかし、この処理だとセカンダリHDDからのブートは失敗してしまいますね。OpenBSDのMBRはプライマリHDDからのブートしか出来ないようです。

boot可能なパーティションを検索

Partition Tableのアドレスをセット
pt ( Partition Tableのアドレス ) をSI レジスタにセットします。
検索カウンタをセット
Partition Tableは全部で4つ存在するので、NDOSPART ( Partition Table数 )をCX レジスタにセットします。
Partition Tableの検索
Partition Tableのboot flagがDOSACTIVE ( boot可能 )であるかチェックしboot可能なPartitionが見つかった場合はループから抜けます。見つからない場合は、SI レジスタにPARTSZ(Partition Tableのサイズ)を加算して、次のPartition Tableを検索します。
boot可能なPartitionが無い場合
Partition Tableを検索しても、ブート可能なPartitionがが見つからなかった場合は、画面上にメッセージを表示し、HALTさせます。
No active partition
	  

boot deviceの表示

どのdeviceおよびPartitionからbootが行なわれたかを、画面に表示してオペレータに通知します。

boot drive numberのdecimal変換
boot drive numberが0x80の場合は'0'、0x81の場合は'1'とasciiに変換を行ないます。求めた値はdrive_numにセットします。
Partition Noのdecimal変換
boot Partition Noのasciiに変換を行なう。求めた値はpart_numにセットします
「パーティションを検索処理」で使用したCX レジスタのカウンタ値を利用し、'0' + (4-cx) ((4-cx)はループの回数)でboot Partition Noは求める事が出来きます。
画面表示
infoからpart_numまでの内容を画面に表示します。
例えば、boot driveが0x80でboot Partitionが4の場合と下記のように表示されます。
Using drive 0 , partition 4
	  
SHIFT keyが押下され、MBR_FLAGS_FORCE_CHSが1の場合(INT 13Hで読込モード)、表示が多少異なり下記のように表示されます。(最初に"!"が付加される)
!Using drive 0 , partition 4
	  

Signatureのクリア

MBRのsignatureの値をクリアします。MBRのsignatureをチェックせずにクリアして良いのか??と思ったのですが、コメントを見ると下記のように書いてありました。

我々は、以前MBRをロードした場所にPBS(biosboot)をロードするだろう。 その後、ロードされた値をチェックを行なうが、自分自身(MBR)をチェックしないようにsignatureをクリアします。

つまりMBRの場所にbiosbootを読込むのだが、これらのsignatureは値が同じであるので、仮に読込みが失敗したとしても、現在ある内容がどちらであるか判別出来ません。これを回避するために読込む前にMBRのsignatureの値をクリアしておくと言うことなのでしょう。結局MBRのsignatureをチェックしないようです。

Partition Boot Record (biosboot)の読込み

read方法の分岐
MBR_FLAGS_FORCE_CHSが0ならば、Disk Read時に拡張INT 13Hを使用する。1ならばINT 13Hを使用する。
拡張INT 13Hがサポートされているかチェック
最初にBIOSが拡張INT 13Hがサポートされているかチェックを行ないます。それぞれのレジスタに次の値を代入してINT 13Hをcallします。
INT 13H(Installation Check)のパラメータ
レジスタ 意味
AH 41h ( INSTALLATION CHECK ) 処理
BX 0x55AA 固定値
DL BIOSから渡される起動ドライブのID ドライブ番号

戻値をチェックし、次の場合は拡張INT 13Hによるdisk accessがサポートされていないので、INT 13Hでdisk readを行ないます。

  1. キャリアフラグがセットされている。(extensions not supported)
  2. BX レジスタが0x55AAでない場合
  3. CL レジスタが0x1でない場合 (extended disk access functions not supported)
拡張 INT 13HによるPBRの読込み (LAB mode)
disk readする前に、readしていることを示すインジケータ(LAB modeの場合 ' . ' )を画面に表示します。
Using drive 0 , partition 4 .
	  
拡張 INT 13Hは、Disk Address Packetと呼ばれるデーター構造を使いread情報を受け渡します。この構造体は、ラベルlba_commandに定義されていて、このラベルのアドレスをDS,SI レジスタにセットしBIOS側に情報を渡します。
Disk Address Packetの内容
lba_command :
10H パケットのサイズ
00H reserved (0固定)
0001H Readするsector数
0000H Read Dataを書出す、メモリ上のOffset Address
BOOTSEG Read Dataを書出す、メモリ上のSegment Address
lba_sectorm :
Partition Tableの
開始位置(LAB)の値
Disk上のRead開始位置(LAB)

lba_sectormに検索したPartition Tableのパーティション開始位置(LAB)をセットし、レジスタに次の値を代入して拡張 INT 13Hをcallします。

拡張INT 13H(Disk Read)のパラメータ
Register 意味
AH 42h ( EXTENDED READ ) 処理
DL BIOSから渡される起動ドライブのID ドライブ番号
DS : SI DS : lba_command Disk Address Packetのアドレス

拡張INT 13Hでの読込みが失敗した場合は、INT 13Hでの読込みを試みます。

INT 13HによるPBRの読込み (CHS mode [shift key押下検出時])
INT 13HでのReadが指定されている場合、または拡張INT 13Hがサポートされてい無い場合は、INT 13Hによるdisk readを試みます。disk readする前に、readしていることを示すインジケータを画面(CHS modeの場合 ' ; ' )に表示します
!Using drive 0 , partition 4 ;
	  
レジスタに次の値を代入して INT 13Hをcallします。
INT 13H(Disk Read)のパラメータ
Register 意味
AH 02h ( Read ) 処理
AL 01h (書込み/読込み)するセクタ数
CH Partition Tableの3byte目 シリンダの下位 8bit 分
CL Partition Tableの2byte目 b5-b0: セクタ番号
b7-b6: シリンダの上位 2bit 分
DH Partition Tableの1byte目 ヘッド番号
DL BIOSから渡される起動ドライブのID ドライブ番号
ES : BX ES : 07C0H BX : 0000H Read Dataを書出すメモリのアドレス

Readに失敗した場合は、画面にRead errorを表示してHALTさせます。

Using drive 0 , partition 4 ;
Read error
	  

biosbootのSignatureをチェック

PBR[Partition Boot Record] (biosboot)読込み後は、次のような配置になります。

partition boot sector (biosboot)読込み後
partition boot sector (biosboot)読込み後

読込んだbiosbootが正しいものか、または正しくLoadされているかチェックするために、biosbootのSignatureDOSMBR_SIGNATUREと等しいかチェックします。Signatureが不正な値の場合は、画面に"No O/S"を表示してHALTさせます。

Using drive 0 , partition 4 ;
No O/S

biosbootに処理を移す

bisobootの先頭番地 ( 0000:(BOOTSEG << 4))番地にジャンプし、biosbootに処理を移行する。

Last modified: Wed Jan 23 17:45:05 2008 JST