Bochs BIOS の動作などのまとめ
このページはBochsのBIOS(rombios.c)についてまとめたページです。
参考にしたバージョンは以下の通りです。
$Id: rombios.c,v 1.160 2006/01/25 17:51:49 vruppert Exp $
もくじ
ただし、リンクは使用できません。URLに「#」がつくだけです。
EBDA (Extended BIOS Data Area)
BIOSが使用するデータバッファです。
最大でどのくらい使われるのか分かりませんが、大きくても40KB~63KBくらいでしょう。
640KBの低位メモリの高位(0x000A6000~0x000AFFFFなど)が使われます。
- Bochs BIOSでは、1KBを確保しているようです。
- Bochs BIOSを見ると、40:0Eh(0x0000040E)にセグメントが書き込まれているようです。
- CD-ROMブート時に使用しているみたい?
- int 74hのルーチンから使用しているみたい?
- 自由に使えるメモリの最大値はint 12hで確認する必要がある。
CMOS RAM の意味 (Bochs用)
RAMアドレス | 用途/意味 | 備考 |
0x10 | フロッピーディスクドライブのタイプ(high4bits:#0,low4bits:#1) | |
0x12 | ハードディスクタイプ(high4bits:#0,low4bits:#1) | |
0x19 | ハードディスク#0の拡張タイプ | 2Fh(47)固定? |
0x1A | ハードディスク#1の拡張タイプ | |
0x1B~23 | ハードディスクパラメータ#0 | |
0x24~2C | ハードディスクパラメータ#1 | |
0x2D | b5(0x20):CDブート非対応コンパイル時のブートシーケンス(=0:C,A/=1:A,C) | |
0x38 | 3rd(high4bits) boot device | 値の意味はこちら |
0x38 | FDブート時のboot signature disableの値(bit0) | =0:enable,=1:disable |
0x39~3A | ATA driver: the translation policy is defined | |
0x3D | 1st(high4bits)/2nd(low4bits) boot device | 値の意味はこちら |
1st/2nd/3rd boot device
値 | 意味 |
0 | デバイス未定義(終了?) |
1 | フロッピーディスクドライブ #0 |
2 | ハードディスクドライブ #0 |
3 | CD-ROMドライブ |
Power On Boot時の一連の動作
- F000:E05BhへFAR JMP
- DMACの初期化
- CMOSのシャットダウンステータスによって分岐
- (==0なら:) 割り込みに禁止し
- スタックの設定,BIOSコミュニケーションエリア(seg:0040h)の初期化
- biosメッセージの表示
- 割り込みベクタテーブルのゼロ初期化
- BIOSコミュニケーションエリアの初期値設定とベクタの設定
- int 17,18,19,1C,12,11,15hベクタの設定
- EBDA の初期化処理
- byte [9fc0:0h] = 1; // size(1KB)
- word [40:0eh] = 9fc0h;
- PITの初期値設定(18.2Hz)とint 08hベクタの設定(1chは初期化済)
- Keyboard(int 09,16hベクタの設定)
- Keyboard関連のコミュニケーションエリアへの書き込み
- byte [40:17~19,71,97h], 0h;
- byte [40:96h], 10h;
- word [40:1a,1c,80h], 1eh;
- word [40:82h], 3eh;
- キーボードの初期化処理
- ;; mov CMOS Equipment Byte to BDA Equipment Word
- ax = [40:10h]; al = 14h; outpb(70h, al); al = inp(71h); [40:10h] = ax;
- パラレルポートのスキャン&設定(0378,0278h)
- シリアルポートのスキャン&設定(03F8,02F8,03E8,02E8h)
- CMOS/RTCのint 1A,4A,70hベクタを設定
- timer_tick_postの呼び出し
- PS/2マウス,FPU,VIDEOBIOSのint 74,75,10hベクタを設定
- PICの初期化
- マスクレジスタはマスタ:B8h,スレーブ:8Fhのようだ。
- PCIBIOSによるIOMEM/IRQSの初期化?
- 外部ROMのスキャン&CRC検査&実行
- VGABIOS.BINも実行されint 10hベクタが変更されビデオモード番号が03hに設定される?
- ROMBIOS.Cのバナー表示
- フロッピーディスクの設定(CMOSから読み込んでコミュニケーションエリアに設定するだけ)
- byte [40:3e,3f,40,41,42,43,44,45,46,47,48,8bh], 0;
- CMOS(10h)の上位,下位4bitをチェックしてドライブが存在すれば[40:8f]の相当のビットを7に変更して書き込み
- byte [40:90,91,92,93,94,95], 0;
- al = 2h; outp (0ah, al);
- int 1e,40(int13_diskette?),0ehベクタの設定
- ret
- ハードディスクドライブの設定(CMOSから読み込んでパラメータをコピー?)
- outp(3f6h, 0ah);
- byte [40:74,77,8c,8d,8eh], 0;
- byte [40:75h], 1; byte [40:76h], c0h;
- int 13,76,41,46hベクタの設定
- ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
- CMOS(12h)の状態に従って分岐
- 拡張タイプの時はCMOS(19,1ah)に従う(=47(user definable?)でないとHALT?)
- CMOS(1b~23,24~2ch)にユーザーパラメータ?
- ATA/ATAPIドライバの初期化と存在チェック
- CDエミュレーションの初期化?
- boot試行(int 19hの発行)
int 19hの動作
- int19_relocated: がint 19h;で呼ばれる
- ds = 0;
- 1st-3rd boot device をチェック(push 1~3;call _int19_fucntion;add sp,2;test ax,ax; jnz boot_setup;)
- 戻り値:bl = boot drive; ax = error (="0") or boot segment (exp:07C0h)
- すべてのdeviceでbootが失敗するとint18_handlerがnear jmpで呼ばれる(int 18hをフックしても…無効?orz)
- どれかのboot deviceが認識されるとboot_setup:に実行が移行する(dl=device,ax=segment)
- dl = bl(boot device); eax = eax(segment)<<4; [ret_ip], ax; eax = eax>>4; ax &= f000h; [ret_cs], ax; ax = 0; es = 0; bp = 0; ax = aa55h; iret(to IPL code);
_int19_functionの動作
- 結局、やっていることは指定されたブート順番の時のデバイスから、ブートできる場合はブートセグメントに読み込んで、ドライブ番号とブートセグメントを返すだけ(cd-romブート時はまた別のfunctionを呼んでいる)。 -- nika 2006/08/10 (木) 21:04:34
- あれ、FDブート/HDブートの時はint 13hされるように見えるが、なぜかシングルステップ例外での監視時には検出されていないなぁ。int 19hの中でTFをクリアしているわけでも無いのになぁ。ってことはここがカギかな?。 -- nika 2006/08/10 (木) 21:19:22
- int 13hをフックしてみたが、もろに無視されてbootできてしまった。メッセージ表示するためだけにフックしてチェインしていたつもりだったが表示されなかったので、int 13hを実行したら即(もちろんcliで)hltを実行させるようにしても普通に起動され…。何故だろう…。何かが干渉でもしているのか・・・? -- nika 2006/08/11 (金) 00:19:11
- 念のため、ソースじゃなくて逆アセンブルしてみよう…としてもこんなBIOSみたいなものに対応した逆アセンブラってあるのか・・・。 -- nika 2006/08/12 (土) 20:59:39
static int int19_function(char bseqhr);
// リターン値: ax = BOOTセグメント, bl = ドライブ番号
Bit32u
int19_function(bseqnr)
Bit8u bseqnr;
{
Bit16u ebda_seg=read_word(0x0040,0x000E);
Bit16u bootseq;
Bit8u bootdrv;
Bit8u bootcd;
Bit8u bootchk;
Bit16u bootseg;
Bit16u status;
Bit8u lastdrive=0;
// BX_ELTORITO_BOOTをdefineしないでコンパイルした場合(古い方法)
// CMOS(0x2D)のbit5をDLのbit7にロードする.
// これはINT 13hの呼び出し時にセットされる(?)
// (0=フロッピーディスク A:, 0x80=HDD C:)
// 0: ブートする順番はC:が最初でその後にA:
// 1: ブートする順番はA:が最初でその後にC:
// BX_ELTORITO_BOOTをdefineしてコンパイルした場合
// CMOS(0x3Dと0x38)の内容で以下のように指定する
// CMOS(0x3D)の下位4bit : 1st boot device
// CMOS(0x3D)の上位4bit : 2nd boot device
// CMOS(0x38)の上位4bit : 3rd boot device
// boot device の割り当て:
// 0x00 : 未定義
// 0x01 : フロッピーディスク(A:)
// 0x02 : ハードディスク(C:)
// 0x03 : CD-ROM(D:)
// その他 : ブート中断
// ブートデバイスの順番を取得
bootseq=inb_cmos(0x3d);
bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
// bseqhrはboot device の順番(1st/2nd/3rd)
if (bseqnr==2) bootseq >>= 4;
if (bseqnr==3) bootseq >>= 8;
if (bootseq<0x10) lastdrive = 1;
bootdrv=0x00; bootcd=0;
switch(bootseq & 0x0f) {
case 0x01: bootdrv=0x00; bootcd=0; break;
case 0x02: bootdrv=0x80; bootcd=0; break;
case 0x03: bootdrv=0x00; bootcd=1; break;
default: return 0x00000000;
}
// CDからブートすることができる場合
if (bootcd != 0) {
status = cdrom_boot();
// 失敗した場合
if ( (status & 0x00ff) !=0 ) {
print_cdromboot_failure(status);
print_boot_failure(bootcd, bootdrv, 1, lastdrive);
return 0x00000000;
}
// 成功した場合はセグメントとドライブ値を設定
bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
bootdrv = (Bit8u)(status>>8);
}
// ハードディスクかフロッピーディスクから起動する場合
if (bootcd == 0) {
bootseg=0x07c0;
ASM_START
push bp
mov bp, sp
mov ax, #0x0000
mov _int19_function.status + 2[bp], ax
mov dl, _int19_function.bootdrv + 2[bp]
mov ax, _int19_function.bootseg + 2[bp]
mov es, ax ;; segment ;; BootSegment:0x07c0
mov bx, #0x0000 ;; offset
mov ah, #0x02 ;; function 2, read diskette sector
mov al, #0x01 ;; read 1 sector
mov ch, #0x00 ;; track 0
mov cl, #0x01 ;; sector 1
mov dh, #0x00 ;; head 0
int #0x13 ;; read sector
jnc int19_load_done
mov ax, #0x0001
mov _int19_function.status + 2[bp], ax
int19_load_done:
pop bp
ASM_END
// 失敗した場合
if (status != 0) {
print_boot_failure(bootcd, bootdrv, 1, lastdrive);
return 0x00000000;
}
}
// CMOS(0x38)でフロッピーディスクブートが指定
// された場合のみ、signuatureをチェックする
// bootchk = 1 : signature check disabled
// bootchk = 0 : signature check enabled
if (bootdrv != 0) bootchk = 0;
else bootchk = inb_cmos(0x38) & 0x01;
// CDブート時はsignatureチェックをしない
if (bootcd != 0)
bootchk = 1;
if (bootchk == 0) {
if (read_word(bootseg,0x1fe) != 0xaa55) {
print_boot_failure(bootcd, bootdrv, 0, lastdrive);
return 0x00000000;
}
}
// 起動メッセージの表示
print_boot_device(bootcd, bootdrv);
// リターン値としてブートセグメントを返す
return (((Bit32u)bootdrv) << 16) + bootseg;
}
(書きかけ)
FDCのレジスタ
I/Oレジスタ周りの配置
IOアドレス(FDC#1/#2) | レジスタ名 | 読み書き | 意味 | 備考 |
3F0/370h | ステータスレジスタA | R | | 本家ATには無い |
3F1/371h | ステータスレジスタB | R | | 本家ATには無い |
3F2/372h | ディジタルアウトプットレジスタ | W | | |
3F3/373h | テープドライブレジスタ | RW | | テープサポートが無ければ関係ない |
3F4/374h | メインステータスレジスタ | R | | |
3F4/374h | データレートセレクトレジスタ | W | | 本家ATには無い |
3F5/375h | データレジスタ(FIFO) | RW | | |
3F7/377h | ディジタルインプットレジスタ | R | | |
3F7/377h | コンフィグレーションコントロールレジスタ | W | | |
I/Oレジスタの意味とビット配置
- ステータスレジスタA(03F0h) Read Only (本家ATには無い)
- bit7:IRQ6
- FDCからの割り込みライン(IRQ6)の状態が読める
- bit6:DRV#2(セカンドドライブコントロール)
- '1':2台目のFDDはない
- '0':2台目のFDDはある
- bit5:STEP
- FDCのSTEP信号出力(ヘッド移動パルス)が読める
- bit4:TRACK0#
- FDCのTRK0信号入力(ヘッドの0トラック検出信号)が読める
- '0':ヘッドはトラック0の位置にある
- bit3:HDSEL
- FDCのHDSEL信号出力(ヘッド表裏選択)が読める
- '0':ドライブ#0/#2を選択中
- bit2:INDEX#
- FDCのINDEX信号入力(FDが1回転するごとに1パルスが出る)が読める
- bit1:WP#
- FDCのWP#信号入力(FDが書き込み禁止信号)が読める
- '0':FDは書き込み禁止
- bit0:DIR
- FDCのDIR信号出力(ヘッドをどちらに動かすかを決める信号)が読める
- '0':0トラック方向(外周方向)
- ステータルレジスタB(03F1h) Read Only (本家ATには無い)
- bit7~6:未使用(常に'1')
- bit5:DR0
- bit4:WDATA
- FDCへのデータ書き込み信号(WDATA)の立ち下がりがあると変化
- bit3:RDATA
- FDCからデータ信号(RDATA)の立ち下がりがあると変化
- bit2:WGATE
- bit1:MTR1
- MTR1出力(ドライブ#1モータON信号)の状態が読み出される
- '1':モータON
- '0':モータOFF
- bit0:MTR0
- デジタルアウトプットレジスタ(03F2h) Write Only (PS/2以降はReadも可能)
- bit7:MTR3(ドライブ#3モータON/OFF)
- '1':モータON(回転開始)
- '0':モータOFF(回転停止)
- bit6:MTR2
- bit5:MTR1
- bit4:MTR0
- bit3:DMAEN(DMA/割り込み動作イネーブル)(PS/2では常時'0'でイネーブル)
- '1':DMA/割り込み信号イネーブル
- '0':DMA/割り込み信号ディセーブル
- bit2:RESET#
- bit1~0:DRVSEL(ドライブセレクト)
- '11':ドライブ#3選択
- '10':ドライブ#2選択
- '01':ドライブ#1選択
- '00':ドライブ#0選択
- テープドライブレジスタ(03F3h) Read Write
- bit7~2:未使用
- bit1~0:テープ.ドライブ選択
- '11':テープ#3
- '10':テープ#2
- '01':テープ#1
- '00':無効
- メインステータスレジスタ(03F4h) Read Only
- bit7:RQM(Request for Master)
- '1':FDCがデータ/コマンドを受け付け可
- '0':FDCはデータ/コマンド処理中(BUSY?)
- bit6:DIO(Data-I/O:転送方向)
- '1':リード方向(FDC→CPU)
- '0':ライト方向(CPU→FDC)
- bit5:NDM(Non-DMAモード)
- '1':実行フェーズにDMAを使わない
- '0':実行フェーズでDMAを使う
- bit4:CB(FDCビジー)
- '1':FDCがビジー状態(次のコマンド受け付け不可)
- '0':FDCはレディー状態
- bit3:D3B(FD3ビジー)
- '1':FD#3がシーク中/シーク完了割り込み保留中
- '0':通常動作
- bit2:D2B(FD#2ビジー)
- bit1:D1B(FD#1ビジー)
- bit0:D0B(FD#0ビジー)
- データレートセレクトレジスタ(03F4h) Write Only (本家ATには無い)
- bit7:S/W RESET (PS/2ではリザーブ)(こちらは自動でリセット解除される)
- bit6:LOW POWER (PS/2ではリザーブ)
- '1':低消費電力モードになり、動作停止
- '0':通常動作
- bit5:未使用
- bit4~2:プレコンベンセーション(書き込み補償)
- '111':0.0ns
- '110':250ns
- '101':208ns
- '100':167ns
- '011':125ns
- '010':83.3ns
- '001':41.7ns
- '000':デフォルト(データレートに応じて決まる)
・1Mbps時 :41.7ns
・500/300/250kbps時:125ns
- bit1~0:データレート
・MFMモード(倍密)時
- '11':1Mbps
- '10':500kbps
- '01':300kbps
- '00':250kbps
・FMモード(単密)時
- '11':---
- '10':250kbps
- '01':150kbps
- '00':125kbps
- データレジスタ(03F5h) Read Write
- デジタルインプットレジスタ(03F7h) Read Only
- bit7:DSKCHG
- bit6-3:未使用(PS/2)
- bit2-1:データレート(PS/2)
- bit0:HIGHDEN#(PS/2)
- コンフィギュレーションコントロールレジスタ(03F7h) Write Only
FDCの制御手順
FDCの動作は以下の3つのフェーズを経て行われます。
コマンド(C)フェーズ
FDCがアイドル状態(MSR=80h)にあるとき, CPUはFDCへのコマンドの書き込みを開始できます.
コマンドは1~2バイトで, さらにパラメータが付いて最大9バイトを書き込みます.
パラメータの省略はできないので, 必ず必要なバイト分すべてを書き込みます.
コマンドの書き込みはMSRのRQM = "1", DIO = "0"を確認しながら行います.
もしFDCがコマンド異常を検出すると, 最後のリザルトフェーズに移行しますが, このときにはDIO = "1" となるので, 異常発生がわかります.
コマンドフェーズが終了すると, FDCはエグゼキューションフェーズに移行します. 例外は,
・SENSE INTERRUPT STATUS(直接リザルトフェーズに移行)
・SENSE DEVICE STATUS(直接リザルトフェーズに移行)
・SPECIFY(コマンドフェーズだけで終了)
などのFDDへのアクセスが不要なコマンド群です.
エグゼキューション(E)フェーズ
コマンドを受け取ると, FDCはエグザキューションフェーズに移行します.
FDのリード/ライトや, ヘッドシーク(ヘッドの移動)などが行われます.
DMAモードに設定していれば, FDのリード/ライト系コマンドのエグゼキューションフェーズでDMA転送要求が行われます.
PCの場合, FDCとのデータ転送は, DMAを用いて行うのがふつうの使い方です.
エグゼキューションフェーズが完了すると, 通常FDCはリザルトフェーズに移行するとともにホストに割り込みをかけます.
例外はSEEKやRECALIBRATE(0トラックへのシーク), RELATIVE SEEKです.
これらはRフェーズがないので, 動作完了後に割り込みが発生した後, SENSE INTERRUPT STATUSコマンドを発行して結果を引き取ります.
リザルト(R)フェーズ
コマンドの実行結果ステータスを通知するのがこのフェーズです.
コマンドの種類に応じて1~7バイトのステータスを引き取ります.
リザルトフェーズでは1バイトの転送ごとにMSRのRQMが "1" になり, またDIOビットは "1" になっています.
ステータスはすべて引き取らないと, 次のコマンドが発行できません.
ステータスが残っているときはDIO = "1", すべて引き取るとDIOビット="0"となるので, ステータスの引き取りが完了したかを判断することができます.
FDCコマンド/パラメータ
READ DATA (MT/MF/SK/0/0/1/1/0)(ビット配置)
- Cフェーズ(Write)
- MT,MF,SK,0,0,1,1,0
- X,X,X,X,X,HD,US1,US0
- C
- H
- R
- N
- EOT
- GSL
- DTL
- Eフェーズ(Read)
- Rフェーズ(Read)
- ST0
- ST1
- ST2
- C
- H
- R
- N
- C/H/R/Nについて
正常終了:実行終了セクタの次のセクタID
異常終了:実行終了セクタのID
備考
こめんとらん