自作OS（1）: ブートローダ

OSつくってみたいので、進捗を日記的にまとめていきたい

大まかな流れは[30日でできる! OS自作入門](https://www.amazon.co.jp/exec/obidos/ASIN/B00IR1HYI0/kuredev-22/ref=nosim/)に沿っていく
ただ、同じようにFAT12フロッピーだとつまらないと思ったので、いろいろ変えていきたい

# ブートローダ
NASMの説明や, セグメント方式等の説明に関しては省略
(NASMに関しては、個人的に[NASM Tutorial](http://cs.lmu.edu/~ray/notes/nasmtutorial/)がとてもよかった)

まず、FAT32 USBを目標にしたいと思ったのでFAT32のBPBを調査することから始めた（Linux系では不要？なのだが, WIndowsとかでは必要らしい）
これについては、FAT32の仕様書「[Microsoft Extensible Firmware Initiative FAT32 File System Specification](https://staff.washington.edu/dittrich/misc/fatgen103.pdf)」を参照した([FATファイル システムのしくみと操作法](http://elm-chan.org/docs/fat.html)では日本語に訳してくれている)


以下は、それらを簡単にまとめた表と手元のUSBメモリをWindowsでFAT32フォーマットして確認したバイナリ


 <table><tr><th>名前</th><th>オフセット(byte)</th><th>サイズ(bytes)</th><th>説明</th><th>実際確認した値（Little Endian）</th></tr>
<tr><td>BS_jmpBoot</td><td>0</td><td>3</td><td>ブートコードへのジャンプ命令</td><td>EB 58 90</td></tr>
<tr><td>BS_OEMName</td><td>3</td><td>8</td><td>任意の名前</td><td>4D 53 44 4F 53 35 2E 30 (MSDOS5.0)</td></tr>
<tr><td>BPB_BytsPerSec</td><td>11</td><td>2</td><td>bytes/sector, 普通512か</td><td>00 02 (512)</td></tr>
<tr><td>BPB_SecPerClus</td><td>13</td><td>1</td><td>sectors/cluster, 2冪でないといけない, 現在よく使われるのは8のようだ </td><td>08</td></tr>
<tr><td>BPB_RsvdSecCnt</td><td>14</td><td>2</td><td>予約セクタ数, FAT32の場合32が代表的</td><td>80 07</td></tr>
<tr><td>BPB_NumFATs</td><td>16</td><td>1</td><td>ボリューム中のFATデータ構造の数, FATの場合常に2とある</td><td>02</td></tr>
<tr><td>BPB_RootEntCnt</td><td>17</td><td>2</td><td>FAT12/16においてルートディレクトリ中の32byteエントリの数を示す, FAT32の場合0とある</td><td>00 00</td></tr>
<tr><td>BPB_TotSec16</td><td>19</td><td>2</td><td>ボリューム中の総セクタ数(16bit), FAT32の場合0</td><td>00 00</td></tr>
<tr><td>BPB_Media</td><td>21</td><td>1</td><td>パーティションありのノンリムーバルメディアの場合は0xF8, パーティションなしのリムーバルメディアの場合は0xF0が標準的な値</td><td>F8</td></tr>
<tr><td>BPB_FATSz16</td><td>22</td><td>2</td><td>FAT12/FAT16における1つのFATによって占有されるセクタ数(16bit), FAT32の場合0</td><td>00 00</td></tr>
<tr><td>BPB_SecPerTrk</td><td>24</td><td>2</td><td>secters/track</td><td>3F 00(63)</td></tr>
<tr><td>BPB_NumHeads</td><td>26</td><td>2</td><td>ヘッド数</td><td>FF 00 (255)</td></tr>
<tr><td>BPB_HiddSec</td><td>28</td><td>4</td><td>FATボリュームより前にある隠れセクタの数, パーティションがないメディアでは0</td><td>3F 00 00 00 (63)</td></tr>
<tr><td>BPB_TotSec32</td><td>32</td><td>4</td><td>ボリューム中の総セクタ数(32bit)</td><td>C1 7F F1 00 (15826881)</td></tr>
<tr><td>BPB_FATSz32</td><td>36</td><td>4</td><td>1つのFATに占有されるセクタ数(32bit)</td><td>40 3C 00 00 (15424)</td></tr>
<tr><td>BPB_ExtFlags</td><td>40</td><td>2</td><td>0-3: アクティイブなFAT数, 4-6: 予約, 7: 0ならミラーリング, 1なら1FAT, 8-15: 予約</td><td>00 00</td></tr>
<tr><td>BPB_FSVer</td><td>42</td><td>2</td><td>FAT32ボリュームのバージョン, Highがメジャー, Lowがマイナー</td><td>00 00</td></tr>
<tr><td>BPB_RootClus</td><td>44</td><td>4</td><td>ルートディレクトリの最初のクラスタの番号, 基本2とある</td><td>02 00 00 00</td></tr>
<tr><td>BPB_FSInfo</td><td>48</td><td>2</td><td>FAT32ボリュームの予約領域中のFATINFO構造のセクタ番号, 基本1</td><td>01 00</td></tr>
<tr><td>BPB_BkBootSec</td><td>50</td><td>2</td><td>0の場合ブートレコードのコピーボリューム中の予約領域のセクタ番号, 基本6</td><td>06 00</td></tr>
<tr><td>BPB_Reserverd</td><td>52</td><td>12</td><td>拡張のための予約領域, FAT32の場合0で埋める</td><td>0埋め</td></tr>
<tr><td>BS_DrvNum</td><td>64</td><td>1</td><td>ドライブナンバー</td><td>80</td></tr>
<tr><td>BS_Reserved1</td><td>65</td><td>1</td><td>WindowsNT用の予約領域, 0でいい</td><td>00</td></tr>
<tr><td>BS_BootSig</td><td>66</td><td>1</td><td>0x29, 以下の3フィールドがあるということを示す</td><td>29</td></tr>
<tr><td>BS_VolID</td><td>67</td><td>4</td><td>ボリュームのシリアルナンバー, BS_VolLabと共に、リムーバルメディアでのトラッキングに利用される, これによりFATファイルシステムのドライバが不正なディスクが挿入されたことを検出できる</td><td>5C A1 A6 A0</td></tr>
<tr><td>BS_VolLab</td><td>71</td><td>11</td><td>ボリュームラベル, ルートディレクトリに記録されている11byteのボリュームラベルに一致する</td><td>4E 4F 20 4E 41 4D 45 20 20 20 20 (NO NAME   )</td></tr>
<tr><td>BS_FileSysType</td><td>82</td><td>8</td><td>"FAT32"という文字列を入れる</td><td>46 41 54 33 20 20 20 (FAT32   )</td></tr></table>

## ブートコードを書く前の事前知識
### BIOSがMBRをロードするアドレス
BIOSはMBRを0000:7c00にロードする
もしくは07c0:0000と書かれる場合もあるが、
これは、
```0x0000 * 16 + 0x7c00 = 0x07c0 * 16 + 0x0000 = 0x7c00```
なので同じ場所

したがって、初期化処理として２通りのやり方がある

* ```org 0x7c00``` で0x7c00から始めて、セグメントレジスタを0x0000に初期化する
* 0x0000から始めて、セグメントレジスタを0x07c0に初期化する 

### ```int 0x10```
0x10はVideo Servicesに関連する割り込み
1. AHレジスタにファンクションコードを指定
2. ALレジスタにビデオモードを指定
3. ```int 0x10```実行
4. AHレジスタに0x0Eを指定しint 0x10を実行することでALレジスタの文字を書き込む（終端コードまでループ）
したがって、コードでは以下のような流れになる

```nasm
        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を表示するだけのブートローダを作成した。

```nasm:boot.asm
[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自作入門](https://www.amazon.co.jp/exec/obidos/ASIN/B00IR1HYI0/kuredev-22/ref=nosim/)
* [Microsoft Extensible Firmware Initiative FAT32 File System Specification](https://staff.washington.edu/dittrich/misc/fatgen103.pdf)
* [FATファイル システムのしくみと操作法](http://elm-chan.org/docs/fat.html)
* [Tips BIOSサービス割り込み ビデオサービス ビデオモード設定](http://softwaretechnique.jp/OS_Development/Tips/Bios_Services/video_services_00.html)
* [Babystep2 - OSDev Wiki](http://wiki.osdev.org/Babystep2)
* [Writing an OS: Baby Steps](http://tutorialsbynick.com/writing-an-os-baby-steps/)
* [GitHub - ishanthilina/USB-FAT32-Bootloader: A simple FAT32 bootloader written in assembly to boot from USB drives.](https://github.com/ishanthilina/USB-FAT32-Bootloader)
* [Inside My BRAIN » Blog Archive » OSの起動まで（2）-BPB（2）](http://masuto.ddo.jp/blog/?p=426)