「手探りでCUI OS作成に挑む」連載
この記事は「手探りでCUI OS作成に挑む」連載の一部です。
全体の目次は「手探りでCUI OS作成に挑む」連載目次を御覧下さい。
MBR VBRとは
通常、HDDなどの記憶媒体では先頭の512バイトに**MBR(Master Boot Record)が存在します。FATファイルシステムで初期化されたパーティションの先頭にはVBR(Volume Boot Record)**が置かれます。
MBR中でパーティションが4つまで登録でき、それにより一つのHDDをCドライブ、Dドライブと分割できます。
そしてそれぞれのパーティションの先頭の512バイトにはVBRと呼ばれるデータが置かれ、ここにはFATに関する情報が記録されます。
OSが起動可能なHDDの場合は初めにMBRを実行し、その後VBRを実行し、その後カーネルと順を追って実行されます。
ファイルシステムを実装していないOS自作本ではいきなりMBRからOSのコードを立ち上げていることもありますが、FAT16でファイルシステムを実装する場合は以下の用に実装できます。
MBRのコード
[BITS 16]
[ORG 0x7C00]
start:
; 1. MBRを安全な領域(0x0600)へ退避
xor ax, ax
mov ds, ax
mov si, 0x7C00
mov di, 0x0600
mov cx, 512
rep movsb
; 2. セグメントレジスタの初期化
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
; 0x0600にジャンプして処理を続行
jmp 0x0000:(continue - start + 0x0600)
continue:
mov si, msg_loading
call print_string
; 4. VBRを0x7C00に読み込む(このコードを上書き)
mov ah, 0x02
mov al, 1 ; 読み込むセクタ数
mov ch, 0 ; シリンダ番号
mov cl, 1 ; セクタ番号(1〜63)
mov dh, 1 ; ヘッド番号
mov dl, 0x80 ; 一台目のHDDを読み込む
mov bx, 0x7C00
int 0x13
jc disk_error
; 5. 0x7C00に読み込んだVBRへ跳ぶ
jmp 0x0000:0x7C00
print_string:
lodsb
or al, al
jz .done
mov ah, 0x0E
int 0x10
jmp print_string
.done:
ret
disk_error:
mov si, msg_disk_error
call print_string
jmp $
msg_loading db "Loading VBR...", 0
msg_disk_error db "Disk read error!", 0
; MBRの残りを埋める
times 446-($-$$) db 0
; パーティションテーブル(FAT16のパーティション)
db 0x80 ; アクティブパーティション
db 0x01, 0x01, 0x00 ; CHS開始位置(0,1,1)
db 0x04 ; パーティションタイプ(FAT16)
db 0xFF, 0xFF, 0xFF ; CHS終了位置(最大値)
dd 63 ; 開始LBA(63セクタ目)
dd 4096 ; セクタ数(約2MB)
; 残りの3つの空パーティションを埋める
times 16 * 3 db 0
dw 0xAA55
VBRのコード
[BITS 16]
[ORG 0x7C00] ; VBRはアドレス0x7C00に読み込まれる
; FAT16のBPB
jmp start
nop
db "MSWIN4.1" ; OEM名
dw 512 ; セクタあたりのバイト数
db 1 ; クラスタあたりのセクタ数
dw 1 ; 予約セクタ数
db 2 ; FATテーブルの数
dw 512 ; ルートディレクトリ項目数
dw 4096 ; 総セクタ数(16ビット)
db 0xF8 ; 媒体種別(HDD等)
dw 8 ; 各FATのセクタ数
dw 63 ; トラックあたりのセクタ数
dw 255 ; ヘッド数
dd 63 ; 隠しセクタ数
dd 0 ; 総セクタ数(32ビット、16ビットが0の場合に使用)
db 0x80 ; BIOSドライブ番号(0x80=HDD)
db 0 ; 予約(使用されない)
db 0x29 ; 拡張ブート用
dd 0x12345678 ; ボリューム番号
db "FAT16DISK " ; ボリュームラベル
db "FAT16 " ; ファイルシステムの種類
start:
mov si, msg_loaded
call print_string
; FAT16ファイルシステムのマウント(今後の拡張用)
jmp $ ; 無限ループ(実際にはファイルシステムを読み込む)
print_string:
lodsb
or al, al
jz .done
mov ah, 0x0E
int 0x10
jmp print_string
.done:
ret
msg_loaded db "FAT16 VBR Loaded!", 0
; 残りの領域を512バイトまで埋める
times 510-($-$$) db 0
dw 0xAA55
起動
OSはまだ実装していませんがMBRからVBRを起動することに成功しました。
# コンパイル
nasm -f bin mbr.asm -o mbr.bin
nasm -f bin vbr.asm -o vbr.bin
dd if=/dev/zero of=virtual_disk.img bs=1M count=1024 # 1GBの仮想HDD生成
# MBRを先頭512バイトへ書き込み
dd if=mbr.bin of=virtual_disk.img bs=512 count=1 conv=notrunc
# VBRを63セクタ目へ書き込み「第1パーティションの先頭512バイト」
dd if=vbr.bin of=virtual_disk.img bs=512 seek=63 conv=notrunc
# 起動する
qemu-system-i386 -hda virtual_disk.img
仮想HDDが本当にFATとして識別されるかをXPで検証
先ほど作った仮想HDDをWindowsXPでEドライブとして読み込ませるとFATとして認識されました。
qemu-system-i386 \
-m 1024 \
-hda xp.img \
-hdb virtual_disk.img \
-boot c \
-cpu host \
-smp 2 \
-net nic -net user \
-vga std \
-rtc base=localtime \
-enable-kvm \
-usbdevice tablet
次回
次はNASMを用いて実際に簡単なファイルを書き込み、XP上で読み込まれるかを確認します。
又、今回はOSを起動するHDDのMBRとVBRを自分で研究してコードを書きました。
OSの入っていないただのHDDの場合にもMBRとVBRは生成されるようなので、実際にXPで初期化をしてどんなデータが生成されるのかを見てみます。
恐らく実行できる命令はないのではないかと思います。