OSつくってみたいので、進捗を日記的にまとめていきたい
大まかな流れは30日でできる! OS自作入門に沿っていく
ただ、同じようにFAT12フロッピーだとつまらないと思ったので、いろいろ変えていきたい
ブートローダ
NASMの説明や, セグメント方式等の説明に関しては省略
(NASMに関しては、個人的にNASM Tutorialがとてもよかった)
まず、FAT32 USBを目標にしたいと思ったのでFAT32のBPBを調査することから始めた(Linux系では不要?なのだが, WIndowsとかでは必要らしい)
これについては、FAT32の仕様書「Microsoft Extensible Firmware Initiative FAT32 File System Specification」を参照した(FATファイル システムのしくみと操作法では日本語に訳してくれている)
以下は、それらを簡単にまとめた表と手元のUSBメモリをWindowsでFAT32フォーマットして確認したバイナリ
名前 | オフセット(byte) | サイズ(bytes) | 説明 | 実際確認した値(Little Endian) |
---|---|---|---|---|
BS_jmpBoot | 0 | 3 | ブートコードへのジャンプ命令 | EB 58 90 |
BS_OEMName | 3 | 8 | 任意の名前 | 4D 53 44 4F 53 35 2E 30 (MSDOS5.0) |
BPB_BytsPerSec | 11 | 2 | bytes/sector, 普通512か | 00 02 (512) |
BPB_SecPerClus | 13 | 1 | sectors/cluster, 2冪でないといけない, 現在よく使われるのは8のようだ | 08 |
BPB_RsvdSecCnt | 14 | 2 | 予約セクタ数, FAT32の場合32が代表的 | 80 07 |
BPB_NumFATs | 16 | 1 | ボリューム中のFATデータ構造の数, FATの場合常に2とある | 02 |
BPB_RootEntCnt | 17 | 2 | FAT12/16においてルートディレクトリ中の32byteエントリの数を示す, FAT32の場合0とある | 00 00 |
BPB_TotSec16 | 19 | 2 | ボリューム中の総セクタ数(16bit), FAT32の場合0 | 00 00 |
BPB_Media | 21 | 1 | パーティションありのノンリムーバルメディアの場合は0xF8, パーティションなしのリムーバルメディアの場合は0xF0が標準的な値 | F8 |
BPB_FATSz16 | 22 | 2 | FAT12/FAT16における1つのFATによって占有されるセクタ数(16bit), FAT32の場合0 | 00 00 |
BPB_SecPerTrk | 24 | 2 | secters/track | 3F 00(63) |
BPB_NumHeads | 26 | 2 | ヘッド数 | FF 00 (255) |
BPB_HiddSec | 28 | 4 | FATボリュームより前にある隠れセクタの数, パーティションがないメディアでは0 | 3F 00 00 00 (63) |
BPB_TotSec32 | 32 | 4 | ボリューム中の総セクタ数(32bit) | C1 7F F1 00 (15826881) |
BPB_FATSz32 | 36 | 4 | 1つのFATに占有されるセクタ数(32bit) | 40 3C 00 00 (15424) |
BPB_ExtFlags | 40 | 2 | 0-3: アクティイブなFAT数, 4-6: 予約, 7: 0ならミラーリング, 1なら1FAT, 8-15: 予約 | 00 00 |
BPB_FSVer | 42 | 2 | FAT32ボリュームのバージョン, Highがメジャー, Lowがマイナー | 00 00 |
BPB_RootClus | 44 | 4 | ルートディレクトリの最初のクラスタの番号, 基本2とある | 02 00 00 00 |
BPB_FSInfo | 48 | 2 | FAT32ボリュームの予約領域中のFATINFO構造のセクタ番号, 基本1 | 01 00 |
BPB_BkBootSec | 50 | 2 | 0の場合ブートレコードのコピーボリューム中の予約領域のセクタ番号, 基本6 | 06 00 |
BPB_Reserverd | 52 | 12 | 拡張のための予約領域, FAT32の場合0で埋める | 0埋め |
BS_DrvNum | 64 | 1 | ドライブナンバー | 80 |
BS_Reserved1 | 65 | 1 | WindowsNT用の予約領域, 0でいい | 00 |
BS_BootSig | 66 | 1 | 0x29, 以下の3フィールドがあるということを示す | 29 |
BS_VolID | 67 | 4 | ボリュームのシリアルナンバー, BS_VolLabと共に、リムーバルメディアでのトラッキングに利用される, これによりFATファイルシステムのドライバが不正なディスクが挿入されたことを検出できる | 5C A1 A6 A0 |
BS_VolLab | 71 | 11 | ボリュームラベル, ルートディレクトリに記録されている11byteのボリュームラベルに一致する | 4E 4F 20 4E 41 4D 45 20 20 20 20 (NO NAME ) |
BS_FileSysType | 82 | 8 | "FAT32"という文字列を入れる | 46 41 54 33 20 20 20 (FAT32 ) |
ブートコードを書く前の事前知識
BIOSがMBRをロードするアドレス
BIOSはMBRを0000:7c00にロードする
もしくは07c0:0000と書かれる場合もあるが、
これは、
0x0000 * 16 + 0x7c00 = 0x07c0 * 16 + 0x0000 = 0x7c00
なので同じ場所
したがって、初期化処理として2通りのやり方がある
-
org 0x7c00
で0x7c00から始めて、セグメントレジスタを0x0000に初期化する - 0x0000から始めて、セグメントレジスタを0x07c0に初期化する
int 0x10
0x10はVideo Servicesに関連する割り込み
- AHレジスタにファンクションコードを指定
- ALレジスタにビデオモードを指定
-
int 0x10
実行 - AHレジスタに0x0Eを指定しint 0x10を実行することでALレジスタの文字を書き込む(終端コードまでループ)
したがって、コードでは以下のような流れになる
mov al, 0x00
mov ah, 0x03
int 0x10
mov si, msg
mov ah, 0x0e
println:
lodsb
or al, al ; if \0
jz hang ; jump to hang
int 0x10
jmp println
ASCIIコード
とりあえず知っておくべきもの
- キャリッジリターン 13
- ラインフィード 10
- 終端 0
MBRの最後
MBRの511バイト目と512バイト目は0xaa 0x55という決まり
HelloWorld
前述のことをまとめて、最初のステップとしてHelloWorldを表示するだけのブートローダを作成した。
[bits 16]
[org 0x7c00]
;; BPB Structure
jmp start ;BS_jmpBoot
BS_OEMName db "MYTESTOS"
BPB_BytsPerSec dw 0x0200
BPB_SecPerClus db 0x08
BPB_RsvdSecCnt dw 0x0020
BPB_NumFATs db 0x02
BPB_RootEntCnt dw 0x0000
BPB_TotSec16 dw 0x0000
BPB_Media db 0xf8
BPB_FATSz16 dw 0x0000
BPB_SecPerTrk dw 0x003f
BPB_NumHeads dw 0x00ff
BPB_HiddSec dd 0x0000003f
BPB_TotSec32 dd 0x00f17fc1
BPB_FATSz32 dd 0x00003c40
BPB_ExtFlags dw 0x0000
BPB_FSVer dw 0x0000
BPB_RootClus dd 0x00000002
BPB_FSInfo dw 0x0001
BPB_BkBootSec dw 0x0006
times 12 db 0 ;BPB_Reserverd
BS_DrvNum db 0x80
BS_Reserved1 db 0x00
BS_BootSig db 0x29
BS_VolID dd 0xa0a615c
BS_VolLab db "TESTOS BOOT"
BS_FileSysType db "FAT32 "
;; boot code
start:
;; initialize segment registers
xor ax, ax
mov ds, ax ; Data Segment
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax ; Stack Segment
mov sp, 0x7c00 ; Stack Pointer
mov al, 0x00
mov ah, 0x03
int 0x10
mov si, msg
mov ah, 0x0e
println:
lodsb
or al, al ; if \0
jz hang ; jump to hang
int 0x10
jmp println
hang:
hlt
jmp hang
msg:
db "Hello, World", 13, 10, 0
times 510-($-$$) db 0
dw 0xaa55
とりあえずQEMUでの動作確認はできた
参考
- 30日でできる! OS自作入門
- Microsoft Extensible Firmware Initiative FAT32 File System Specification
- FATファイル システムのしくみと操作法
- Tips BIOSサービス割り込み ビデオサービス ビデオモード設定
- Babystep2 - OSDev Wiki
- Writing an OS: Baby Steps
- GitHub - ishanthilina/USB-FAT32-Bootloader: A simple FAT32 bootloader written in assembly to boot from USB drives.
- Inside My BRAIN » Blog Archive » OSの起動まで(2)-BPB(2)