0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

XPで初期化したFAT16に自分のカーネルを入れる(失敗)

Last updated at Posted at 2025-07-03

「手探りでCUI OS作成に挑む」連載

この記事は「手探りでCUI OS作成に挑む」連載の一部です。
全体の目次は「手探りでCUI OS作成に挑む」連載目次を御覧下さい。

HDD

# 128MBの仮想HDD生成
dd if=/dev/zero of=virtual_disk.img bs=1M count=128

图片.png
图片.png

FAT16初期化

FAT16形式、1クラスタ=4kb(8セクタ)でHDDを初期化する。

  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

图片.png

图片.png

图片.png

图片.png

64kb分のファイルを初期化したHDDへ保存する
图片.png

BPBの情報

VBRのダンプ
test@test-ThinkPad-X280:~$ xxd -s $((512*63)) -l 512 virtual_disk.img
00007e00: eb3c 904d 5344 4f53 352e 3000 0208 0200  .<.MSDOS5.0.....
00007e10: 0200 0200 00f8 7f00 3f00 1000 3f00 0000  ........?...?...
00007e20: b1f3 0300 8000 2926 74bf 5c4e 4f20 4e41  ......)&t.\NO NA
00007e30: 4d45 2020 2020 4641 5431 3620 2020 33c9  ME    FAT16   3.
00007e40: 8ed1 bcf0 7b8e d9b8 0020 8ec0 fcbd 007c  ....{.... .....|
00007e50: 384e 247d 248b c199 e83c 0172 1c83 eb3a  8N$}$....<.r...:
00007e60: 66a1 1c7c 2666 3b07 268a 57fc 7506 80ca  f..|&f;.&.W.u...
00007e70: 0288 5602 80c3 1073 eb33 c98a 4610 98f7  ..V....s.3..F...
00007e80: 6616 0346 1c13 561e 0346 0e13 d18b 7611  f..F..V..F....v.
00007e90: 6089 46fc 8956 feb8 2000 f7e6 8b5e 0b03  `.F..V.. ....^..
00007ea0: c348 f7f3 0146 fc11 4efe 61bf 0000 e8e6  .H...F..N.a.....
00007eb0: 0072 3926 382d 7417 60b1 0bbe a17d f3a6  .r9&8-t.`....}..
00007ec0: 6174 324e 7409 83c7 203b fb72 e6eb dca0  at2Nt... ;.r....
00007ed0: fb7d b47d 8bf0 ac98 4074 0c48 7413 b40e  .}.}....@t.Ht...
00007ee0: bb07 00cd 10eb efa0 fd7d ebe6 a0fc 7deb  .........}....}.
00007ef0: e1cd 16cd 1926 8b55 1a52 b001 bb00 00e8  .....&.U.R......
00007f00: 3b00 72e8 5b8a 5624 be0b 7c8b fcc7 46f0  ;.r.[.V$..|...F.
00007f10: 3d7d c746 f429 7d8c d989 4ef2 894e f6c6  =}.F.)}...N..N..
00007f20: 0696 7dcb ea03 0000 200f b6c8 668b 46f8  ..}..... ...f.F.
00007f30: 6603 461c 668b d066 c1ea 10eb 5e0f b6c8  f.F.f..f....^...
00007f40: 4a4a 8a46 0d32 e4f7 e203 46fc 1356 feeb  JJ.F.2....F..V..
00007f50: 4a52 5006 536a 016a 1091 8b46 1896 9233  JRP.Sj.j...F...3
00007f60: d2f7 f691 f7f6 4287 caf7 761a 8af2 8ae8  ......B...v.....
00007f70: c0cc 020a ccb8 0102 807e 020e 7504 b442  .........~..u..B
00007f80: 8bf4 8a56 24cd 1361 6172 0b40 7501 4203  ...V$..aar.@u.B.
00007f90: 5e0b 4975 06f8 c341 bb00 0060 666a 00eb  ^.Iu...A...`fj..
00007fa0: b04e 544c 4452 2020 2020 2020 0d0a 5265  .NTLDR      ..Re
00007fb0: 6d6f 7665 2064 6973 6b73 206f 7220 6f74  move disks or ot
00007fc0: 6865 7220 6d65 6469 612e ff0d 0a44 6973  her media....Dis
00007fd0: 6b20 6572 726f 72ff 0d0a 5072 6573 7320  k error...Press 
00007fe0: 616e 7920 6b65 7920 746f 2072 6573 7461  any key to resta
00007ff0: 7274 0d0a 0000 0000 0000 00ac cbd8 55aa  rt............U.

BPBから取り出した今欲しい情報
​1クラスタ​​:8セクタ
FAT表​:127セクタ
予約セクタ:2セクタ

FAT表1

開始位置:63(パーティション開始位置) + 2(予約セクタ)=65

test@test-ThinkPad-X280:~$ xxd -s $((512*65)) -l 512 virtual_disk.img
00008200: f8ff ffff 0300 0400 0500 0600 0700 0800  ................
00008210: 0900 0a00 0b00 0c00 0d00 0e00 0f00 1000  ................
00008220: 1100 ffff 0000 0000 0000 0000 0000 0000  ................
00008230: 0000 0000 0000 0000 0000 0000 0000 0000  ................

断片化せず綺麗に連続して並んでいる。

ルートディレクトリ

開始位置:63(パーティション開始位置) + 2(予約セクタ) + 127×2(FAT1+FAT2)=319

test@test-ThinkPad-X280:~$ xxd -s $((512*319)) -l 512 virtual_disk.img
00027e00: d0c2 bcd3 beed 2020 2020 2008 0000 0000  ......     .....
00027e10: 0000 0000 0000 0399 e35a 0000 0000 0000  .........Z......
00027e20: 5445 5354 2020 2020 5458 5420 186a 7699  TEST    TXT .jv.
00027e30: e35a e35a 0000 6a99 e35a 0200 92f4 0000  .Z.Z..j..Z......
00027e40: 0000 0000 0000 0000 0000 0000 0000 0000  ................

ファイル

ルートディレクトリの大きさ=32(1ファイルあたり)×512 / 512=32クラスタ
開始位置:63(パーティション開始位置) + 2(予約セクタ) + 127×2(FAT1+FAT2) + 32

test@test-ThinkPad-X280:~$ xxd -s $((512*351)) -l 512 virtual_disk.img
0002be00: 3031 3233 3435 3637 3839 3031 3233 3435  0123456789012345
0002be10: 3637 3839 3031 3233 3435 3637 3839 3031  6789012345678901
0002be20: 3233 3435 3637 3839 3031 3233 3435 3637  2345678901234567
0002be30: 3839 3031 3233 3435 3637 3839 3031 3233  8901234567890123
0002be40: 3435 3637 3839 3031 3233 3435 3637 3839  4567890123456789
0002be50: 3031 3233 3435 3637 3839 3031 3233 3435  0123456789012345

XPで入れたファイルの内容と一致する。
图片.png

自前MBR中のBPBをXPに合わせる

先ほどダンプを取ったMBRから解析したBPBは以下の通り

オフセット 大きさ 16進値 (リトルエンディアン) 10進値 説明
0x00 3 EB 3C 90 - ジャンプ命令 (JMP 3C NOP)
0x03 8 "MSDOS5.0" - OEM名
0x0B 2 0x0200 512 バイト/セクタ
0x0D 1 0x08 8 セクタ/クラスタ
0x0E 2 0x0002 2 予約セクタ数
0x10 1 0x02 2 FAT数
0x11 2 0x0000 0 ルートエントリ数 (FAT16では0)
0x13 2 0x0000 0 総セクタ数16 (0 = FAT32または64KB以上)
0x15 1 0xF8 248 メディアタイプ (固定ディスク)
0x16 2 0x007F 127 セクタ/FAT
0x18 2 0x003F 63 セクタ/トラック
0x1A 2 0x0010 16 ヘッド数
0x1C 4 0x000003F3 1011 非表示セクタ数
0x20 4 0x00008000 32768 総セクタ数32
0x24 1 0x00 0 物理ドライブ番号
0x25 1 0x00 0 予約
0x26 1 0x29 41 拡張ブート署名
0x27 4 0x2674BF5C 644,829,020 ボリュームシリアル番号
0x2B 11 "NO NAME " - ボリュームラベル
0x36 8 "FAT16 " - ファイルシステムタイプ

このMBRをこのまま使うと自作OSが起動できないため、BPBの部分をまるまる自分のMBRへ入れる

書き直したMBR
[BITS 16]
[ORG 0x7C00]  ; VBRはアドレス0x7C00に読み込まれる

; FAT16のBPB
jmp start
nop
db "MSDOS5.0"     ; OEM名(8bitに満たない場合は空白埋め)
dw 512              ; バイト/セクタ(0x0200)
db 8                ; セクタ/クラスタ(4KBクラスタ)
dw 2                ; 予約セクタ数
db 2                ; FAT数
dw 0                ; ルートディレクトリエントリ数
dw 0                ; 総セクタ数(16bit領域、0で代わりにTotSec32を使用)
db 0xF8             ; メディアタイプ(固定ディスク)
dw 127              ; FATサイズ(セクタ数、後述計算)
dw 63               ; セクタ/トラック(LBA互換)
dw 16               ; ヘッド数(LBA互換)
dd 1011             ; 隠しセクタ数
dd 32768            ; 総セクタ数
; 拡張BPB (FAT16用)
db 0                ; BIOSドライブ番号(0x80=HDD)
db 0                ; 予約
db 0x29             ; 拡張ブート署名
dd 0x2674BF5C       ; ボリュームID(任意)
db 'NO NAME    '    ; ボリュームラベル
db 'FAT16   '       ; ファイルシステム名

start:

    mov si, msg_loaded
    call print_string

    ; kernelは128セクタ分(65536バイト=64KB),LBA=351
    ; KERNEL.BIN は LBA 351 セクタ目から始まる
    mov ah, 0x02
    mov al, 128         ; 128セクタ読み込む
    mov ch, 0           ; Cylinder 0
    mov cl, 36          ; Sector 36
    mov dh, 5           ; Head 5
    mov dl, 0x80        ; HDD
    mov bx, 0x8000      ; 読み込み先アドレス
    int 0x13
    jc load_error

    jmp 0x0000:0x8000 ; kernelの開始アドレスへ跳ぶ

print_string:
    lodsb
    or al, al
    jz .done
    mov ah, 0x0E
    int 0x10
    jmp print_string
.done:
    ret
    
load_error:
    mov si, error_msg
    call print_string

msg_loaded db "[VBR] Execution started at 0x0000:0x7C00", 0x0D, 0x0A, 0
error_msg db "Failed to load KERNEL.BIN", 0x0D, 0x0A, 0

; 残りの領域を512バイトまで埋める
times 510-($-$$) db 0

dw 0xAA55

FAT表及びルートディレクトリを自前で作る

fat16_init.asm
; FAT表及びルートディレクトリを初期化する。
; DDで65セクタ目からの位置に書き込む。(63+予約セクタ2)
; 固定でKERNEL.BINを一つ登録しておく。
; 前提:
;   - MBRは0セクタ目に設置
;   - VBRは63セクタ目に設置(パーティションはMBR中で63セクタ目から始まるように設定してある)
;   - FATの情報は65から始まる

bits 16

; ------------------------------
; FAT1表LBA 64〜始まる (DDでこの場所に置く) 
; ------------------------------
fat1:
    dw 0xFFF8          ; クラスタ0:予約
    dw 0xFFFF          ; クラスタ1:予約

    ; KERNEL.BIN
    ; 64kb / 4kb = 16クラスタ
    dw 0x0300
    dw 0x0400
    dw 0x0500
    dw 0x0600
    dw 0x0700
    dw 0x0800
    dw 0x0900
    dw 0x0a00
    dw 0x0b00
    dw 0x0c00
    dw 0x0d00
    dw 0x0e00
    dw 0x0f00
    dw 0x1000
    dw 0x1100
    dw 0xFFFF
    ;KERNEL.BIN終端

    ; FAT表の剰余分を0で埋める (127セクタ×512バイト-既に書き込んだ分のバイト数)
    times 65024 - ($ - fat1) db 0

; ------------------------------
; FAT2表(FAT表1の予備 FAT1の直後)簡略化の為に0埋め
; ------------------------------
fat2:
    dw 0xFFF8          ; クラスタ0:予約
    dw 0xFFFF          ; クラスタ1:予約

    ; KERNEL.BIN
    ; 64kb / 4kb = 16クラスタ
    dw 0x0300
    dw 0x0400
    dw 0x0500
    dw 0x0600
    dw 0x0700
    dw 0x0800
    dw 0x0900
    dw 0x0a00
    dw 0x0b00
    dw 0x0c00
    dw 0x0d00
    dw 0x0e00
    dw 0x0f00
    dw 0x1000
    dw 0x1100
    dw 0xFFFF
    ;KERNEL.BIN終端

    times 65024 - ($ - fat2) db 0

; ------------------------------
; ルートディレクトリ(FAT2の直後,LBA 319)
; ------------------------------
root_dir:
    ; KERNEL.BINの登録(32字节)
    db 'KERNEL  BIN'          ; ファイル名(8.3形式)
    db 0x20                   ; 属性(0X20は通常のファイルを意味する)
    db 0                      ; 保留
    db 0                      ; 作成時間(ミリ秒)
    dw 0x0000                 ; 作成時間(16:00:00)
    dw 0x2100                 ; 作成日時(2023-01-01)
    dw 0x2100                 ; 最終変更日時
    dw 0                      ; EA索引
    dw 0x0000                 ; 最終変更時間
    dw 0x2100                 ; 最終変更日時
    dw 2   ; 開始クラスタ
    dd 65536                  ; ファイルの大きさ(バイト)

    ; ルートディレクトリが32セクタとなるように0で埋める。
    times 512 * 32 - ($ - root_dir) db 0

以下の手順で書き込む

cd boot # nasm -f bin ​boot/fat16_init.asm -o fat16_init.binがなぜか実行できない為苦肉の策
nasm -f bin mbr.asm -o mbr.bin
nasm -f bin vbr.asm -o vbr.bin
nasm -f bin ​fat16_init.asm -o fat16_init.bin
cd ..
nasm -f bin kernel.asm -o kernel.bin

# 128MBの仮想HDD生成
dd if=/dev/zero of=virtual_disk.img bs=1M count=128

# MBRを先頭512バイトへ書き込み
dd if=boot/mbr.bin of=virtual_disk.img bs=512 count=1 conv=notrunc

# VBRを63セクタ目へ書き込み「第1パーティションの先頭512バイト」
dd if=boot/vbr.bin of=virtual_disk.img bs=512 seek=63 conv=notrunc

# ルートディレクトリ及びFAT表を65バイト目〜に書き込み
dd if=boot/fat16_init.bin of=virtual_disk.img bs=512 seek=65 conv=notrunc

# カーネル部分
dd if=kernel.bin of=virtual_disk.img bs=512 seek=351 conv=notrunc

图片.png

XPで読み込むと初期化されていないと表示される。
自分で作った時はHファイル名が表示され、ファイルが開けないだけだった。
XPで初期化したHDDに合わせるとHDDそのものが開けなくなった。
全く原因が分からない。
既に10時間以上ファイルシステムに費やしていて気が狂いそうなので今日はやめる。

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?