30日でできる!OS自作入門(記事一覧)[Ubuntu16.04/NASM]
目的
"30日でできる!OS自作入門"の内容をUbuntu(Linux)で実行するには本の内容だけでは厳しいので調べた結果をメモ。(リンクと動作確認済みコード・コメント)
このテキストを読む上でUbuntuとnasmを使う方の参考になればと思っております。
(テキストが無いと厳しいです)
Ubuntu 16.04 LTS
※Githubにコード上げると思いますので待ってちょ。
追記:2019/01/27 リンク載せ忘れていました。
ソースコードは以下のGitHubにあげています。
https://github.com/pollenjp/myHariboteOS
1-2. harib00a
追記(p.49)したコードを以下に表示
; haribote-ipl
; TAB=4
ORG 0x7c00 ; read start
; description for floppy disk
JMP entry ; BS_JmpBoot
DB 0x90 ; BS_JmpBoot
DB "HARIBOTE" ; BS_OEMName 8B
DW 512 ; BPB_BytsPerSec
DB 1 ; BPB_SecPerClu
DW 1 ; BPB_RevdSecCnt : このBPBを含むブートセクタのみ
DB 2 ; BPB_NumFATs : FATの個数 (このフィールドの値は常に2に設定すべきである)
DW 224 ; BPB_RootEntCnt
DW 2880 ; BPB_TotSec16
DB 0xf0 ; BPB_Media
DW 9 ; BPB_FATSz16
DW 18 ; BPB_SecPerTrk
DW 2 ; BPB_NumHeads
DD 0 ; BPB_HiddSec
DD 2880 ; BPB_TotSec32
; FAT12/16におけるオフセット36以降のフィールド
DB 0x00 ; BS_DrvNum
DB 0x00 ; BS_Reserved1
DB 0x29 ; BS_BootSig
DD 0xffffffff ; BS_VolID
DB "HARIBOTEOS " ; BS_VolLab 11B
DB "FAT12 " ; BS_FilSysType 8B
RESB 18 ; とりあえず18バイト開けておく
; START BS_BootCode 64(0x14) 448(0x1C0)
entry:
MOV AX, 0 ; initialize Accumulator(resister)
MOV SS, AX ; Stack Segment
MOV SP, 0x7c00 ; Stack Pointer
MOV DS, AX ; Data Segment : 番地指定のとき重要
;MOV ES, AX ; Extra Segment
;MOV SI, msg ; Source Index
; load disk
MOV AX, 0x0820
MOV ES, AX ; extra segment : buffer address 0x0820
MOV CH, 0 ; counter high : cylinder 0
MOV DH, 0 ; data high : head 0
MOV CL, 2 ; counter low : sector 2
MOV AH, 0x02 ; acumulator high : read disk
MOV AL, 1 ; acumulator low : sector 1
MOV BX, 0 ; base : buffer address 0x0000
MOV DL, 0x00 ; data low : drive number
INT 0x13 ; BIOS call
JC error ; CARRY FLAG
fin:
HLT
JMP fin ; 無限ループ
error:
MOV SI, msg
putloop:
MOV AL, [SI] ; BYTE (accumulator low)
ADD SI, 1 ; increment
CMP AL, 0 ; 終了条件
JE fin ; jump to fin if equal to 0
MOV AH, 0x0e
MOV BX, 15
INT 0x10 ; interrupt BIOS
JMP putloop
msg:
DB 0x0a, 0x0a
DB "load error"
DB 0x0a
DB 0 ; end msg
RESB 0x7dfe-0x7c00-($-$$) ; 現在の場所から0x1fdまで(残りの未使用領域)を0で埋める。
; END BS_BootCode
DB 0x55, 0xaa ; BS_BootSign
実行
-fda
オプションでフロッピーディスクであることを明示
$ qemu-system-i386 -fda helloos.img
このために修正したMakefileが以下のとおり
ipl.bin : ipl.asm Makefile
nasm ipl.asm -o ipl.bin -l ipl.lst
helloos.img : ipl.bin Makefile
cat ipl.bin > helloos.img
asm :
make -r ipl.bin
img :
make -r helloos.img
run :
make img
qemu-system-i386 -fda helloos.img
3. 18セクタまで読む(p.55)
追加したコードは以下
; haribote-ipl
; TAB=4
ORG 0x7c00 ; read start
; description for floppy disk
JMP entry ; BS_JmpBoot
DB 0x90 ; BS_JmpBoot
DB "HARIBOTE" ; BS_OEMName 8B
DW 512 ; BPB_BytsPerSec
DB 1 ; BPB_SecPerClu
DW 1 ; BPB_RevdSecCnt : このBPBを含むブートセクタのみ
DB 2 ; BPB_NumFATs : FATの個数 (このフィールドの値は常に2に設定すべきである)
DW 224 ; BPB_RootEntCnt
DW 2880 ; BPB_TotSec16
DB 0xf0 ; BPB_Media
DW 9 ; BPB_FATSz16
DW 18 ; BPB_SecPerTrk
DW 2 ; BPB_NumHeads
DD 0 ; BPB_HiddSec
DD 2880 ; BPB_TotSec32
; FAT12/16におけるオフセット36以降のフィールド
DB 0x00 ; BS_DrvNum
DB 0x00 ; BS_Reserved1
DB 0x29 ; BS_BootSig
DD 0xffffffff ; BS_VolID
DB "HARIBOTEOS " ; BS_VolLab 11B
DB "FAT12 " ; BS_FilSysType 8B
RESB 18 ; とりあえず18バイト開けておく
; START BS_BootCode 64(0x14) 448(0x1C0)
entry:
MOV AX, 0 ; initialize Accumulator(resister)
MOV SS, AX ; Stack Segment
MOV SP, 0x7c00 ; Stack Pointer
MOV DS, AX ; Data Segment : 番地指定のとき重要
;MOV SI, msg ; Source Index
; load disk
MOV AX, 0x0820
MOV ES, AX ; extra segment : buffer address 0x0820
MOV CH, 0 ; counter high : cylinder 0
MOV DH, 0 ; data high : head 0
MOV CL, 2 ; counter low : sector 2
readloop:
MOV SI, 0 ; 失敗回数を数えるレジスタ
retry:
MOV AH, 0x02 ; acumulator high : 0x02 - read disk
MOV AL, 1 ; acumulator low : sector 1
MOV BX, 0 ; buffer address 0x0000
; ES:BX, ESは代入済み
MOV DL, 0x00 ; data low : drive number
INT 0x13 ; BIOS call
JNC next ; jump if not carry
ADD SI, 1 ; increment SI
CMP SI, 5
JAE error ; SI >= 5 then jump to error
MOV AH, 0x00 ; 0x00 - reset
MOV DL, 0x00 ; A drive
INT 0x13 ; reset drive
JMP retry
next:
; add 0x20 to ES
; 代わりにBXに512を足してもよい
MOV AX, ES ; 0x20だけアドレスを進める
ADD AX, 0x0020 ; 512 / 16 = 0x20
MOV ES, AX
; increment CL (sector number)
ADD CL, 1
CMP CL, 18
JBE readloop
fin:
HLT
JMP fin ; 無限ループ
error:
MOV SI, msg
putloop:
MOV AL, [SI] ; BYTE (accumulator low)
ADD SI, 1 ; increment
CMP AL, 0 ; 終了条件
JE fin ; jump to fin if equal to 0
MOV AH, 0x0e ; 1 char-function
MOV BX, 15 ; color code
INT 0x10 ; interrupt, call BIOS
JMP putloop
msg:
DB 0x0a, 0x0a
DB "load error"
DB 0x0a
DB 0 ; end point
RESB 0x7dfe-0x7c00-($-$$) ; 現在の場所から0x1fdまで(残りの未使用領域)を0で埋める。
; 0x7c00スタートなのでその分を引いている
; END BS_BootCode
DB 0x55, 0xaa ; BS_BootSign, boot signature
# ファイル生成規則
ipl.bin : ipl.asm Makefile
nasm ipl.asm -o ipl.bin -l ipl.lst
#helloos.img : ipl.bin tail.bin Makefile
helloos.img : ipl.bin Makefile
#cat ipl.bin tail.bin > helloos.img
cat ipl.bin > helloos.img
asm :
make -r ipl.bin
img :
make -r helloos.img
run :
make img
qemu-system-i386 -fda helloos.img # "-fda" for floppy disk
実行してみましょう
$ make run
4. 10シリンダ分を読む(p.56)
追加したコードは以下
; haribote-ipl
; TAB=4
CYLS EQU 10 ; どこまで読み込むか (CYLinderS)
ORG 0x7c00 ; このプログラムがメモリ上のどこに読み込まれるか
; description for floppy disk
JMP entry ; BS_JmpBoot
DB 0x90 ; BS_JmpBoot
DB "HARIBOTE" ; BS_OEMName 8B
DW 512 ; BPB_BytsPerSec
DB 1 ; BPB_SecPerClu
DW 1 ; BPB_RevdSecCnt : このBPBを含むブートセクタのみ
DB 2 ; BPB_NumFATs : FATの個数 (このフィールドの値は常に2に設定すべきである)
DW 224 ; BPB_RootEntCnt
DW 2880 ; BPB_TotSec16
DB 0xf0 ; BPB_Media
DW 9 ; BPB_FATSz16
DW 18 ; BPB_SecPerTrk
DW 2 ; BPB_NumHeads
DD 0 ; BPB_HiddSec
DD 2880 ; BPB_TotSec32
; FAT12/16におけるオフセット36以降のフィールド
DB 0x00 ; BS_DrvNum
DB 0x00 ; BS_Reserved1
DB 0x29 ; BS_BootSig
DD 0xffffffff ; BS_VolID
DB "HARIBOTEOS " ; BS_VolLab 11B
DB "FAT12 " ; BS_FilSysType 8B
RESB 18 ; とりあえず18バイト開けておく
; START BS_BootCode 64(0x14) 448(0x1C0)
entry:
MOV AX, 0 ; initialize Accumulator(resister)
MOV SS, AX ; Stack Segment
MOV SP, 0x7c00 ; Stack Pointer
MOV DS, AX ; Data Segment : 番地指定のとき重要
;MOV SI, msg ; Source Index
; load disk
MOV AX, 0x0820
MOV ES, AX ; extra segment : buffer address 0x0820
MOV CH, 0 ; cylinder 0
MOV DH, 0 ; head 0
MOV CL, 2 ; sector 2
readloop:
MOV SI, 0 ; 失敗回数を数えるレジスタ
retry:
MOV AH, 0x02 ; acumulator high : 0x02 - read disk
MOV AL, 1 ; acumulator low : sector 1
MOV BX, 0 ; buffer address 0x0000
; ES:BX, ESは代入済み
MOV DL, 0x00 ; data low : drive number
INT 0x13 ; BIOS call
JNC next ; jump if not carry
ADD SI, 1 ; increment SI
CMP SI, 5
JAE error ; SI >= 5 then jump to error
MOV AH, 0x00 ; 0x00 - reset
MOV DL, 0x00 ; A drive
INT 0x13 ; reset drive
JMP retry
next:
; add 0x20 to ES
; 代わりにBXに512を足してもよい
MOV AX, ES ; 0x20だけアドレスを進める
ADD AX, 0x0020 ; 512 / 16 = 0x20
MOV ES, AX
; increment CL (sector number)
ADD CL, 1
CMP CL, 18
JBE readloop
; ディスクのウラ面
MOV CL, 1 ; reset sector
ADD DH, 1 ; reverse HEAD
CMP DH, 2
JB readloop
; next Cylinder
mov DH, 0 ; reset HEAd
ADD CH, 1 ; cylinder += 1
CMP CH, CYLS
JB readloop
fin:
HLT
JMP fin ; 無限ループ
error:
MOV SI, msg
putloop:
MOV AL, [SI] ; BYTE (accumulator low)
ADD SI, 1 ; increment
CMP AL, 0 ; 終了条件
JE fin ; jump to fin if equal to 0
MOV AH, 0x0e ; 1 char-function
MOV BX, 15 ; color code
INT 0x10 ; interrupt, call BIOS
JMP putloop
msg:
DB 0x0a, 0x0a
DB "load error"
DB 0x0a
DB 0 ; end point
RESB 0x7dfe - 0x7c00 - ($ - $$) ; 現在の場所から0x1fdまで(残りの未使用領域)を0で埋める。
; 0x7c00スタートなのでその分を引いている
; END BS_BootCode
DB 0x55, 0xaa ; BS_BootSign, boot signature
Makefileはおそらく変更ナシ(一応載せる)
# ファイル生成規則
ipl.bin : ipl.asm Makefile
nasm ipl.asm -o ipl.bin -l ipl.lst
#helloos.img : ipl.bin tail.bin Makefile
helloos.img : ipl.bin Makefile
#cat ipl.bin tail.bin > helloos.img
cat ipl.bin > helloos.img
asm :
make -r ipl.bin
img :
make -r helloos.img
run :
make img
qemu-system-i386 -fda haribote.img # "-da" for floppy disk
5. OS本体を書き始める(p.57)
ここでLinux/Ubuntu上でedimg.exeをどのように動かせば良いのかわからなかったのでかなり苦戦しました。
まずはharibote.sys
からです。
fin:
HLT
JMP fin
次にこれをディスクイメージharibote.img
に保存するのですが、ここでedimg.exe
が必要なようです。しかし、Linux/Ubuntu上で実行したい自分はいろんな記事を探したり、edimg.c
の内容を読んで理解しょうとしたりしましたが、以下の記事を見つけて解決しました!
では、動くファイルを作成していきましょう!
default:
make img
ipl.bin : ipl.asm Makefile
nasm ipl.asm -o ipl.bin -l ipl.lst
haribote.sys : haribote.asm Makefile
nasm haribote.asm -o haribote.sys -l haribote.lst
haribote.img : ipl.bin haribote.sys Makefile
mformat -f 1440 -C -B ipl.bin -i haribote.img ::
mcopy haribote.sys -i haribote.img ::
asm :
make -r ipl.bin
img :
make -r haribote.img
run :
make img
qemu-system-i386 -fda haribote.img # "-fda" for floppy disk
何をやっているのかは自分にもまだよくわかっていませんが
mformat -f 1440 -C -B ipl.bin -i haribote.img ::
mcopy haribote.sys -i haribote.img ::
この2行によって保存しているようです。
では、make img
を実行しましょう。
$ make img
次にharibote.sys
の機械語との対応を見ましょう。
1 fin:
2 00000000 F4 HLT
3 00000001 EBFD JMP fin
F4
とEBFD
が確認できますね。
では次にghexを立ち上げてどの箇所に書き込まれているのかをチェックします。
$ ghex haribote.img
ファイルを開いた状態でctrl+f
を押すとファイル内文字列検索できるので、その箇所にテキストに乗っているように48 41 52 ...
(最初の3つくらいで十分)と入力してEnter
(find next)を押しましょう。(逆説的な説明ではありますが、確認することが目的なのでHARIBOTESYS
の文字を探す必要は無いでしょう。)
2回くらい押すと以下のように0x2600
にHARIBOTESYSの文字が見つかります。
F4 EB FD
と入力した場合も同様です。offset:0x4200(写真左下)が確認できると思います。
これらのことからテキストにかかれていた以下のことが言えます。
空の状態のディスクに対してファイルを普通に保存すると、
- (1)ファイル名波0x002600以降に入るらしい
- (2)ファイルの中身は0x004200以降に入るらしい
良かった。確認できた!
※これ確認するために1周間くらいかけました(0_0)
6. ブートセクタからOS本体を実行(p.59) - harib00f
haribote.asm
とipl.asm
に変更を加える。
ORG 0xc200 ; 0xc200 <- 0x8000 + 0x4200
fin:
HLT
JMP fin
; haribote-ipl
; TAB=4
CYLS EQU 10 ; どこまで読み込むか (CYLinderS)
ORG 0x7c00 ; このプログラムがメモリ上のどこに読み込まれるか
; description for floppy disk
JMP entry ; BS_JmpBoot
DB 0x90 ; BS_JmpBoot
DB "HARIBOTE" ; BS_OEMName 8B
DW 512 ; BPB_BytsPerSec
DB 1 ; BPB_SecPerClu
DW 1 ; BPB_RevdSecCnt : このBPBを含むブートセクタのみ
DB 2 ; BPB_NumFATs : FATの個数 (このフィールドの値は常に2に設定すべきである)
DW 224 ; BPB_RootEntCnt
DW 2880 ; BPB_TotSec16
DB 0xf0 ; BPB_Media
DW 9 ; BPB_FATSz16
DW 18 ; BPB_SecPerTrk
DW 2 ; BPB_NumHeads
DD 0 ; BPB_HiddSec
DD 2880 ; BPB_TotSec32
; FAT12/16におけるオフセット36以降のフィールド
DB 0x00 ; BS_DrvNum
DB 0x00 ; BS_Reserved1
DB 0x29 ; BS_BootSig
DD 0xffffffff ; BS_VolID
DB "HARIBOTEOS " ; BS_VolLab 11B
DB "FAT12 " ; BS_FilSysType 8B
RESB 18 ; とりあえず18バイト開けておく
; START BS_BootCode 64(0x14) 448(0x1C0)
entry:
MOV AX, 0 ; initialize Accumulator(resister)
MOV SS, AX ; Stack Segment
MOV SP, 0x7c00 ; Stack Pointer
MOV DS, AX ; Data Segment : 番地指定のとき重要
; load disk
MOV AX, 0x0820
MOV ES, AX ; buffer address 0x0820
MOV CH, 0 ; cylinder 0
MOV DH, 0 ; head 0
MOV CL, 2 ; sector 2
readloop:
MOV SI, 0 ; 失敗回数を数えるレジスタ
retry:
MOV AH, 0x02 ; acumulator high : 0x02 - read disk
MOV AL, 1 ; acumulator low : sector 1
MOV BX, 0 ; buffer address 0x0000
; ES:BX, ESは代入済み
MOV DL, 0x00 ; data low : drive number
INT 0x13 ; BIOS call
JNC next ; jump if not carry
ADD SI, 1 ; increment SI
CMP SI, 5
JAE error ; SI >= 5 then jump to error
MOV AH, 0x00 ; 0x00 - reset
MOV DL, 0x00 ; A drive
INT 0x13 ; reset drive
JMP retry
next:
; add 0x20 to ES
; 代わりにBXに512を足してもよい
MOV AX, ES ; 0x20だけアドレスを進める
ADD AX, 0x0020 ; 512 / 16 = 0x20
MOV ES, AX
; increment CL (sector number)
ADD CL, 1
CMP CL, 18
JBE readloop
; ディスクのウラ面
MOV CL, 1 ; reset sector
ADD DH, 1 ; reverse HEAD
CMP DH, 2
JB readloop
; next Cylinder
mov DH, 0 ; reset HEAd
ADD CH, 1 ; cylinder += 1
CMP CH, CYLS
JB readloop
; ブートセクタの読み込みが終わったのでOS本体を実行
JMP 0xc200
error:
MOV SI, msg
putloop:
MOV AL, [SI] ; BYTE (accumulator low)
ADD SI, 1 ; increment
CMP AL, 0 ; 終了条件
JE fin ; jump to fin if equal to 0
MOV AH, 0x0e ; 1 char-function
MOV BX, 15 ; color code
INT 0x10 ; interrupt, call BIOS
JMP putloop
fin:
HLT ; 何かあるまでCPUを停止させる
JMP fin ; 無限ループ
msg:
DB 0x0a, 0x0a
DB "load error"
DB 0x0a
DB 0 ; end point
RESB 0x7dfe - 0x7c00 - ($ - $$) ; 現在の場所から0x1fdまで(残りの未使用領域)を0で埋める。
; 0x7c00スタートなのでその分を引いている
; END BS_BootCode
DB 0x55, 0xaa ; BS_BootSign, boot signature
実行
$ make run
これでは上手く読み込まれたのかどうかがわからないので次で確認しましょう。
7. OS本体の動作を確認(p.59) - harib00g
説明はテキストで十分かと思うのでここではコードだけ。
; haribote-os
; TAB=4
ORG 0xc200 ; 0xc200 <- 0x8000 + 0x4200
; Where on memory this program will be loaded
MOV AL, 0x13 ; VGA graphics, 320x200x8bit
MOV AH, 0x00
INT 0x10
fin:
HLT
JMP fin
ipl.asm
は10セクタだけ読み込むコードであることを明示するためにipl10.asm
に名前変更(内容に変更はないが一応載せておく)
MOV [0x0ff0], CH ; IPLがどこまで読んだのかをメモ
の行の追加し忘れに注意(自分は抜けててそれに気づくのに数十時間要しました。--> 「gdbデバッグ体験記」)
; haribote-ipl
; TAB=4
CYLS EQU 10 ; どこまで読み込むか (CYLinderS)
ORG 0x7c00 ; このプログラムがメモリ上のどこに読み込まれるか
; discription for floppy disk
JMP entry ; BS_JmpBoot
DB 0x90 ; BS_JmpBoot
DB "HARIBOTE" ; BS_OEMName 8B
DW 512 ; BPB_BytsPerSec
DB 1 ; BPB_SecPerClu
DW 1 ; BPB_RevdSecCnt : このBPBを含むブートセクタのみ
DB 2 ; BPB_NumFATs : FATの個数 (このフィールドの値は常に2に設定すべきである)
DW 224 ; BPB_RootEntCnt
DW 2880 ; BPB_TotSec16
DB 0xf0 ; BPB_Media
DW 9 ; BPB_FATSz16
DW 18 ; BPB_SecPerTrk
DW 2 ; BPB_NumHeads
DD 0 ; BPB_HiddSec
DD 2880 ; BPB_TotSec32
; FAT12/16におけるオフセット36以降のフィールド
DB 0x00 ; BS_DrvNum
DB 0x00 ; BS_Reserved1
DB 0x29 ; BS_BootSig
DD 0xffffffff ; BS_VolID
DB "HARIBOTEOS " ; BS_VolLab 11B
DB "FAT12 " ; BS_FilSysType 8B
RESB 18 ; とりあえず18バイト開けておく
; START BS_BootCode 64(0x14) 448(0x1C0)
entry:
MOV AX, 0 ; initialize Accumulator(resister)
MOV SS, AX ; Stack Segment
MOV SP, 0x7c00 ; Stack Pointer
MOV DS, AX ; Data Segment : 番地指定のとき重要
; load disk
MOV AX, 0x0820
MOV ES, AX ; buffer address 0x0820
MOV CH, 0 ; cylinder 0
MOV DH, 0 ; head 0
MOV CL, 2 ; sector 2
readloop:
MOV SI, 0 ; 失敗回数を数えるレジスタ
retry:
MOV AH, 0x02 ; acumulator high : 0x02 - read disk
MOV AL, 1 ; acumulator low : sector 1
MOV BX, 0 ; buffer address 0x0000
; ES:BX, ESは代入済み
MOV DL, 0x00 ; data low : drive number
INT 0x13 ; BIOS call
JNC next ; jump if not carry
ADD SI, 1 ; increment SI
CMP SI, 5
JAE error ; SI >= 5 then jump to error
MOV AH, 0x00 ; 0x00 - reset
MOV DL, 0x00 ; A drive
INT 0x13 ; reset drive
JMP retry
next:
; add 0x20 to ES
; 代わりにBXに512を足してもよい
MOV AX, ES ; 0x20だけアドレスを進める
ADD AX, 0x0020 ; 512 / 16 = 0x20
MOV ES, AX
; increment CL (sector number)
ADD CL, 1
CMP CL, 18
JBE readloop
; ディスクのウラ面
MOV CL, 1 ; reset sector
ADD DH, 1 ; reverse HEAD
CMP DH, 2
JB readloop
; next Cylinder
mov DH, 0 ; reset HEAd
ADD CH, 1 ; cylinder += 1
CMP CH, CYLS
JB readloop
; ブートセクタの読み込みが終わったのでOS本体を実行
MOV [0x0ff0], CH ; IPLがどこまで読んだのかをメモ
JMP 0xc200
error:
MOV SI, msg
putloop:
MOV AL, [SI] ; BYTE (accumulator low)
ADD SI, 1 ; increment
CMP AL, 0 ; 終了条件
JE fin ; jump to fin if equal to 0
MOV AH, 0x0e ; 1 char-function
MOV BX, 15 ; color code
INT 0x10 ; interrupt, call BIOS
JMP putloop
fin:
HLT ; 何かあるまでCPUを停止させる
JMP fin ; 無限ループ
msg:
DB 0x0a, 0x0a
DB "load error"
DB 0x0a
DB 0 ; end point
RESB 0x7dfe - 0x7c00 - ($ - $$) ; 現在の場所から0x1fdまで(残りの未使用領域)を0で埋める。
; 0x7c00スタートなのでその分を引いている
; END BS_BootCode
DB 0x55, 0xaa ; BS_BootSign, boot signature
ipl10.asm
に名前を変更したのでMakefile
も名前変更
default:
make img
ipl10.bin : ipl10.asm Makefile
nasm ipl10.asm -o ipl10.bin -l ipl10.lst
haribote.sys : haribote.asm Makefile
nasm haribote.asm -o haribote.sys -l haribote.lst
haribote.img : ipl10.bin haribote.sys Makefile
mformat -f 1440 -C -B ipl10.bin -i haribote.img ::
mcopy haribote.sys -i haribote.img ::
asm :
make -r ipl10.bin
img :
make -r haribote.img
run :
make img
qemu-system-i386 -fda haribote.img # "-fda" for floppy disk
では実行
$ make run
やったー!真っ黒な画面を出力できた〜!
これで正常にharibote.asm
が読み込めていることがわかりましたね。んではつぎー。
8. 32ビットモードへ(p.61) - harib00h
キーボードの状態をBIOSから教えてもらうためのコード
変更部分はharibote.asm
のみ
; haribote-os
; TAB=4
; BOOT_INFO関係
CYLS EQU 0x0ff0 ; ブートセクタが設定する
LEDS EQU 0x0ff1
VMODE EQU 0x0ff2 ; 色数に関する情報(何ビットカラーか)
SCRNX EQU 0x0ff4 ; 解像度X (screen x)
SCRNY EQU 0x0ff6 ; 解像度Y (screen y)
VRAM EQU 0x0ff8 ; グラフィックバッファの開始番地
ORG 0xc200 ; 0xc200 <- 0x8000 + 0x4200
; Where on memory this program will be loaded
MOV AL, 0x13 ; VGA graphics, 320x200x8bit
MOV AH, 0x00
INT 0x10
MOV BYTE [VMODE], 8 ; 画面モードをメモする
MOV WORD [SCRNX], 320
MOV WORD [SCRNY], 200
MOV DWORD [VRAM], 0x000a0000
; LED state on keyboardをBIOSから教えてもらう
MOV AH, 0x02
INT 0x16 ; keyboard BIOS
MOV [LEDS], AL
fin:
HLT
JMP fin
実行結果は先ほどのものと変わらず真っ暗な画面のはずです。
9. C言語導入(p.63) - harib00i
- 『30日でできる!OS自作入門』をLinuxでやってみる 3.2日目
- .hrb実行形式 - 『30日でできる!OS自作入門』のメモ
- 0から作るOS開発 カーネルことはじめ - 0から作るソフトウェア開発
ここにきてまた著者のオリジナル実行ファイルですか。。。
調べるのに結構苦労しましたね。
以下のbootpack.c
とリンカスクリプトのhar.ld
、Makefile
を作成していただければ解決!
void HariMain(void)
{
fin:
goto fin;
}
/* https://vanya.jp.net/os/haribote.html#hrb */
OUTPUT_FORMAT("binary");
SECTIONS
{
.head 0x0 : {
LONG(64 * 1024) /* 0 : stack+.data+heap の大きさ(4KBの倍数) */
LONG(0x69726148) /* 4 : シグネチャ "Hari" */
LONG(0) /* 8 : mmarea の大きさ(4KBの倍数) */
LONG(0x310000) /* 12 : スタック初期値&.data転送先 */
LONG(SIZEOF(.data)) /* 16 : .dataサイズ */
LONG(LOADADDR(.data)) /* 20 : .dataの初期値列のファイル位置 */
LONG(0xE9000000) /* 24 : 0xE9000000 */
LONG(HariMain - 0x20) /* 28 : エントリアドレス - 0x20 */
LONG(0) /* 32 : heap領域(malloc領域)開始アドレス */
}
.text : { *(.text) }
.data 0x310000 : AT ( ADDR(.text) + SIZEOF(.text) ) {
*(.data)
*(.rodata*)
*(.bss)
}
/DISCARD/ : { *(.eh_frame) }
}
default:
make img
ipl10.bin : ipl10.asm Makefile
nasm ipl10.asm -o ipl10.bin -l ipl10.lst
asmhead.bin : asmhead.asm Makefile
nasm asmhead.asm -o asmhead.bin -l asmhead.lst
bootpack.hrb : bootpack.c har.ld Makefile # Cファイルをリンカスクリプトを用いてコンパイル
gcc -march=i486 -m32 -nostdlib -T har.ld bootpack.c -o bootpack.hrb
haribote.sys : asmhead.bin bootpack.hrb Makefile
cat asmhead.bin bootpack.hrb > haribote.sys
haribote.img : ipl10.bin haribote.sys Makefile
mformat -f 1440 -C -B ipl10.bin -i haribote.img ::
mcopy haribote.sys -i haribote.img ::
asm :
make -r ipl10.bin
img :
make -r haribote.img
run :
make img
qemu-system-i386 -fda haribote.img # "-fda" for floppy disk
debug :
make img
qemu-system-i386 -fda haribote.img -gdb tcp::10000 -S
clean :
rm *.lst *.bin *.sys *.img *.hrb
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386)
SECTIONS {
. = 0x7c00;
.text : { *(.text) }
}
debug
とclean
はおまけとして追加しました。
debug
は「gdbデバッグ体験記」にて!
clean
はバイナリファイルで溢れかえったディレクトリを最小サイズにするために削除するコマンドです。
とりあえず実装することが目的なので詳しい説明はナシです(^o^)
私も完全に理解していないのでもう少し理解したら追記します。
10. HTLしたい(p.66) - harib00j
HLT処理はC言語で生成できないのでアセンブルの方で関数を定義してやります。
; nasmfunc.asm
; TAB=4
section .text
GLOBAL io_hlt
io_hlt: ; void io_hlt(void);
HLT
RET
そして、アセンブラで定義された関数をC言語側で使用
// bootpack.c
extern void io_hlt(void);
void HariMain(void)
{
fin:
io_hlt();
goto fin;
}
Makefile
はリンク処理に書き足せばとりあえずOKです。
default:
make img
ipl10.bin : ipl10.asm Makefile
nasm ipl10.asm -o ipl10.bin -l ipl10.lst
asmhead.bin : asmhead.asm Makefile
nasm asmhead.asm -o asmhead.bin -l asmhead.lst
nasmfunc.o : nasmfunc.asm Makefile ; nasmfunc.asmのバイナリファイル作成
nasm -g -f elf nasmfunc.asm -o nasmfunc.o
bootpack.hrb : bootpack.c har.ld nasmfunc.o Makefile ; コンパイル/リンク
gcc -march=i486 -m32 -nostdlib -T har.ld -g bootpack.c nasmfunc.o -o bootpack.hrb
haribote.sys : asmhead.bin bootpack.hrb Makefile
cat asmhead.bin bootpack.hrb > haribote.sys
haribote.img : ipl10.bin haribote.sys Makefile
mformat -f 1440 -C -B ipl10.bin -i haribote.img ::
mcopy haribote.sys -i haribote.img ::
asm :
make -r ipl10.bin
img :
make -r haribote.img
run :
make img
qemu-system-i386 -fda haribote.img # "-fda" for floppy disk
debug:
make img
qemu-system-i386 -fda haribote.img -gdb tcp::10000 -S
clean :
rm *.lst *.bin *.sys *.img *.hrb *.o
CPUの使用率の変化が伺えます。(大雑把ですけど、コマンドでgnome-system-monitor
と入力してリソースをクリックすると見れます。)
今回の分ここまでです。
(つかれたあああああ)
参考
- BIOS_functions - BIOS - OSDev Wiki
- INT(0x13); ディスク関係 - (AT)BIOS - os-wiki
- Linuxで書くOS自作入門 3日目(前半) - Tsurugidake's diary
- 『30日でできる!OS自作入門』をLinuxでやってみる 3日目
- 『30日でできる!OS自作入門』をLinuxでやってみる 3.1日目
- 『30日でできる!OS自作入門』をLinuxでやってみる 3.2日目
- OS自作入門 3日目-1 【Linux】| 64bit環境での苦悩 - サラリーマンがハッカーを真剣に目指す
- OS自作入門 3日目-2 【Linux】| デバッグして実行順序を追ってみる - サラリーマンがハッカーを真剣に目指す
- [OS作成]30日でできる!OS自作入門 3日目 (4) - takeisa memo
- OS自作入門 onLinux 3日目 - Handwriting
- 30日でできる!OS自作入門 〜3日目-その2〜 - プログラムの森
- OS自作入門3日目 - K'zlog いろいろ
- [OS作成]30日でできる!OS自作入門 3日目 (1) - takeisa memo
- [OS作成]30日でできる!OS自作入門 3日目 (2) - takeisa memo
- [OS作成]30日でできる!OS自作入門 3日目 (3) - takeisa memo
- [OS作成]30日でできる!OS自作入門 3日目 (4) - takeisa memo
- [OS作成]30日でできる!OS自作入門 3日目 (5) - takeisa memo
- [OS作成]30日でできる!OS自作入門 3日目 (6) - takeisa memo
- [OS作成]30日でできる!OS自作入門 3日目 (7) - takeisa memo
- [OS作成]30日でできる!OS自作入門 3日目 (8) - takeisa memo
- [OS作成]30日でできる!OS自作入門 3日目 (8) 2 - takeisa memo
- QEMU上のLinuxカーネルをGDBでデバッグする - Narrow Escape