VOOZH about

URL: https://qiita.com/Wanwannodao/items/19830459606eedc46812

⇱ 自作OS(1): ブートローダ #USB - Qiita


👁 Image
28

Go to list of users who liked

19

Share on X(Twitter)

Share on Facebook

Add to Hatena Bookmark

More than 5 years have passed since last update.

@Wanwannodao

自作OS(1): ブートローダ

28
Last updated at Posted at 2016-08-12

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に関連する割り込み

  1. AHレジスタにファンクションコードを指定
  2. ALレジスタにビデオモードを指定
  3. int 0x10実行
  4. 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を表示するだけのブートローダを作成した。

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での動作確認はできた

参考

28

Go to list of users who liked

19
0

Go to list of comments

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28

Go to list of users who liked

19