とりあえず使ってみる

OpenDOS については、ソースを追い掛けるのを止めて、とりあえず、使ってみる事にした。
この場合、正確には、DR-DOSって事になるのかもしれないが、Ver 7.03 を選択。
QEMU 0.13.0 上に、20M のHDDイメージを用意して、DR-DOS をインストール。
割り当てメモリは、4M。(でも十分過ぎる。笑)
試行錯誤の末、なんとか、インストール終了。


さて、ここから、HDD イメージ上の MBR を覗いてみる。

80 01 01 00 04 0F 3F 26 3F 00 00 00 51 99 00 00

いきなり、パーティションテーブル。
それも、1〜3は、空で、4番目のパーティションの中身。
順番に、
80: ブート可
01 01 00:パーティションの最初のセクタ C=0,H=1,S=1
04: パーティション識別子 → FAT16(32MB以下)
0F 3F 26:パーティションの最後のセクタ C=26,H=0F,S=3F
3F 00 00 00:パーティションの最初のセクタ LBA=3F(本当?)
51 99 00 00:パーティションの全セクタ数 39249 → 19MiBくらい?
=27h*10h*3Fh - 3F(1トラック分)

seg000:0000                 cli
seg000:0001                 sub     ax, ax
seg000:0003                 mov     ss, ax
seg000:0005                 mov     ax, 7C00h
seg000:0008                 mov     sp, ax
seg000:000A                 sti
seg000:000B                 cld
seg000:000C                 sub     ax, ax
seg000:000E                 mov     ds, ax
seg000:0010                 mov     si, 7C00h
seg000:0013                 mov     ax, 60h ; '`'
seg000:0016                 mov     es, ax
seg000:0018                 assume es:nothing
seg000:0018                 sub     di, di
seg000:001A                 mov     cx, 100h
seg000:001D                 rep movsw
seg000:001F                 jmp     far ptr 60h:24h

こっちは、MBR の ブートストラップローダの先頭部分。
自分自身を、0060:0000にコピーしてから、次の命令があるアドレスへ far ジャンプしています。

seg000:0024                 mov     ax, cs
seg000:0026                 mov     ds, ax
seg000:0028                 assume ds:nothing
seg000:0028                 mov     cx, 4
seg000:002B                 mov     di, 1BEh
seg000:002E
seg000:002E loc_7C02E:                              ; CODE XREF: seg000:003D^Yj
seg000:002E                 mov     dx, [di]
seg000:0030                 cmp     dl, 80h ; '€'
seg000:0033                 jz      short loc_7C041
seg000:0035                 cmp     dl, 0
seg000:0038                 jnz     short loc_7C08A
seg000:003A                 add     di, 10h
seg000:003D                 loop    loc_7C02E
seg000:003F                 int     18h             ; TRANSFER TO ROM BASIC
seg000:003F                                         ; causes transfer to ROM-based BASIC (IBM-PC)
seg000:003F                                         ; often reboots a compatible; often has no effect at all

DSレジスタをジャンプ先の0060に設定。
CXレジスタをカウンタとして以降の処理を4回繰り返す。DIレジスタの初期値は1BEh。
 DIレジスタがポイントするアドレスの内容をDXレジスタに転送。
 DLレジスタと即値:80hとを比較。
 一致すれば、loc_7C041へジャンプ
 DLレジスタと即値:00hとを比較。
 一致しなければ、loc_7C08Aへジャンプ
 DIレジスタに即値:10hを加算
 繰り返し
ここでは、パーティションテーブルのフラグをチェックしています。
80はブート可、00はブート不可、それ以外は不正なコードとみなしているようです。
int 18h は、ROM-BASIC 呼び出しですが、最近のPCでは、何も無しですかね?

seg000:008A loc_7C08A:                              ; CODE XREF: seg000:0038^Xj
seg000:008A                                         ; seg000:004C^Xj ...
seg000:008A                 mov     si, 9Dh ; '・
seg000:008D
seg000:008D loc_7C08D:                              ; CODE XREF: seg000:0075^Xj
seg000:008D                                         ; seg000:0088^Xj ...
seg000:008D                 lodsb
seg000:008E                 cmp     al, 24h ; '$'
seg000:0090
seg000:0090 loc_7C090:                              ; CODE XREF: seg000:loc_7C090^Yj
seg000:0090                 jz      short loc_7C090
seg000:0092                 push    si
seg000:0093                 mov     bx, 7
seg000:0096                 mov     ah, 0Eh
seg000:0098                 int     10h             ; - VIDEO - WRITE CHARACTER AND ADVANCE CURSOR (TTY WRITE)
seg000:0098                                         ; AL = character, BH = display page (alpha modes)
seg000:0098                                         ; BL = foreground color (graphics modes)
seg000:009A                 pop     si
seg000:009B                 jmp     short loc_7C08D

とりあえず、不正なコードに遭遇した時の処理。
SIレジスタに、即値:9Dhを転送。
9Dhには、エラーメッセージが配置されています。
seg000:009D aInvalidPartiti db 'Invalid partition table$'
lodsb は、

    MOV     AL, [SI]
    INC     SI        ; DF=0の場合

1バイトのコードで、上記と同等の処理を行ってくれるのは便利なんですが、
これが、Intelマジックと言うか、混乱の元になっているような気もするなぁ...
'$'は、DOS形式の文字列終端子です。
もし、ALにセットされた文字が、'$'であれば、ここで無限ループします。
表示すべき文字であれば、BIOSサービスを利用して、一文字ずつ表示すると。
BIOSサービスをコールする前に、SIレジスタを退避しているけど、
int 10h って、SI レジスタの内容を破壊しちゃうのかな?

seg000:0041 loc_7C041:                              ; CODE XREF: seg000:0033^Xj
seg000:0041                 mov     si, di
seg000:0043                 jmp     short loc_7C052
seg000:0045 ; トトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトト
seg000:0045
seg000:0045 loc_7C045:                              ; CODE XREF: seg000:loc_7C052^Yj
seg000:0045                 add     di, 10h
seg000:0048                 mov     ax, [di]
seg000:004A                 cmp     al, 80h ; '€'
seg000:004C                 jz      short loc_7C08A
seg000:004E                 cmp     al, 0
seg000:0050                 jnz     short loc_7C08A
seg000:0052
seg000:0052 loc_7C052:                              ; CODE XREF: seg000:0043^Xj
seg000:0052                 loop    loc_7C045

最初にブート可のパーティションに遭遇した後の処理。
DIレジスタの内容をSIレジスタに保存してloc_7C052へジャンプ。
まだ、繰り返し処理は続いている。(アセンブラ的な流れやな〜)
こっちの繰り返しでは、80hのパーティションが見付かったら不正とするようですね。
ブート可のパーティションが複数あったらダメって事ですな。
ブート可のパーティションが見付かったら、さっさと起動すれば良いように思うのですが、
世の中、そんなに、甘いもんじゃない... ってわけでもないだろうに。

seg000:0054                 mov     cx, 5
seg000:0057
seg000:0057 loc_7C057:                              ; CODE XREF: seg000:0070^Yj
seg000:0057                 mov     ax, 0
seg000:005A                 mov     es, ax
seg000:005C                 assume es:nothing
seg000:005C                 mov     bx, 7C00h
seg000:005F                 mov     ah, 2
seg000:0061                 mov     al, 1
seg000:0063                 push    cx
seg000:0064                 mov     cx, [si+2]
seg000:0067                 int     13h             ; DISK - READ SECTORS INTO MEMORY
seg000:0067                                         ; AL = number of sectors to read, CH = track, CL = sector
seg000:0067                                         ; DH = head, DL = drive, ES:BX -> buffer to fill
seg000:0067                                         ; Return: CF set on error, AH = status, AL = number of sectors read
seg000:0069                 pop     cx
seg000:006A                 jnb     short loc_7C077
seg000:006C                 mov     ah, 0
seg000:006E                 int     13h             ; DISK - RESET DISK SYSTEM
seg000:006E                                         ; DL = drive (if bit 7 is set both hard disks and floppy disks reset)
seg000:0070                 loop    loc_7C057
seg000:0072                 mov     si, 0C9h ; 'ノ'
seg000:0075                 jmp     short loc_7C08D

こちらは、正常系の処理。
CXレジスタに5を設定しているのは、リトライ回数だと思う。
ES:BXは、0000:7C00に設定。
DXは、既に設定済み、CXの内容は、SI+2から転送。
なるほど...
パーティションテーブルの先頭4バイトは、そのまま、BIOSサービスのDX,CXの内容になるわけですな。
カウンタとして使用しているCXレジスタの内容は、当然、
BIOSサービスの呼び出し前後で、PUSH,POP されると。
BIOSサービスの呼び出し後、JNBとなっているけど、これは、JNCだと思う。
OPコードは同じなので、逆アセンブラには、どっちだか分からないわけですね。
キャリーフラグがONの場合は、何かしらエラーが発生したので、
ディスクをリセットして、再度、読み込みを行うと。
リトライ回数分繰り返したら、SIレジスタに即値:C9hを転送。
seg000:00C9 aOperatingSyste db 'Operating System load error$'

seg000:0077 loc_7C077:                              ; CODE XREF: seg000:006A^Xj
seg000:0077                 cmp     word ptr es:[bx+1FEh], 0AA55h
seg000:007E                 jnz     short loc_7C085
seg000:0080                 jmp     far ptr 0:7C00h

読み込みが正常終了したら、読み込んだ内容のブートシグネチャをチェック。
一致しなければ、loc_7C085へジャンプ。
一致した場合は、読み込んだ内容(PBR)の先頭へ、far ジャンプする。

seg000:0085 loc_7C085:                              ; CODE XREF: seg000:007E^Xj
seg000:0085                 mov     si, 0B5h ; 'オ'
seg000:0088                 jmp     short loc_7C08D

seg000:00B5 aNoOperatingSys db 'No Operating System$'を表示。


MBRについては、多少の差はあっても、同じような処理になるはず。