VOOZH about

URL: https://qiita.com/pollenjp/items/8fcb9573cdf2dc6e2668

⇱ 30日でできる!OS自作入門(3日目)[Ubuntu16.04/NASM] #Ubuntu16.04LTS - Qiita


👁 Image
37

Go to list of users who liked

15

Share on X(Twitter)

Share on Facebook

Add to Hatena Bookmark

More than 5 years have passed since last update.

@pollenjp(pollenjp)in👁 Image
UT-virtual

30日でできる!OS自作入門(3日目)[Ubuntu16.04/NASM]

37
Last updated at Posted at 2018-04-07

30日でできる!OS自作入門(記事一覧)[Ubuntu16.04/NASM]

目的

"30日でできる!OS自作入門"の内容をUbuntu(Linux)で実行するには本の内容だけでは厳しいので調べた結果をメモ。(リンクと動作確認済みコード・コメント)

👁 image.png

このテキストを読む上でUbuntuとnasmを使う方の参考になればと思っております。
(テキストが無いと厳しいです)
Ubuntu 16.04 LTS

※Githubにコード上げると思いますので待ってちょ。

追記:2019/01/27 リンク載せ忘れていました。
ソースコードは以下のGitHubにあげています。
https://github.com/pollenjp/myHariboteOS

1-2. harib00a

追記(p.49)したコードを以下に表示

harib00a/ipl.asm
; 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オプションでフロッピーディスクであることを明示

terminal(入力)
$ qemu-system-i386 -fda helloos.img

このために修正したMakefileが以下のとおり

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)

追加したコードは以下

ipl.asm
; 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
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 helloos.img	# "-fda" for floppy disk

実行してみましょう

$ make run

実行結果
👁 image.png

4. 10シリンダ分を読む(p.56)

追加したコードは以下

ipl.asm
; 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はおそらく変更ナシ(一応載せる)

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からです。

haribote.asm
fin:
 HLT
 JMP fin

次にこれをディスクイメージharibote.imgに保存するのですが、ここでedimg.exeが必要なようです。しかし、Linux/Ubuntu上で実行したい自分はいろんな記事を探したり、edimg.cの内容を読んで理解しょうとしたりしましたが、以下の記事を見つけて解決しました!

では、動くファイルを作成していきましょう!

Makefile
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を実行しましょう。

terminal(入力)
$ make img

次にharibote.sysの機械語との対応を見ましょう。

haribote.lst
 1 fin:
 2 00000000 F4 HLT
 3 00000001 EBFD JMP fin

F4EBFDが確認できますね。

では次にghexを立ち上げてどの箇所に書き込まれているのかをチェックします。

terminal(入力)
$ ghex haribote.img

ファイルを開いた状態でctrl+fを押すとファイル内文字列検索できるので、その箇所にテキストに乗っているように48 41 52 ...(最初の3つくらいで十分)と入力してEnter(find next)を押しましょう。(逆説的な説明ではありますが、確認することが目的なのでHARIBOTESYS
の文字を探す必要は無いでしょう。)

2回くらい押すと以下のように0x2600にHARIBOTESYSの文字が見つかります。
👁 image.png

F4 EB FDと入力した場合も同様です。offset:0x4200(写真左下)が確認できると思います。
👁 image.png

これらのことからテキストにかかれていた以下のことが言えます。

空の状態のディスクに対してファイルを普通に保存すると、

  • (1)ファイル名波0x002600以降に入るらしい
  • (2)ファイルの中身は0x004200以降に入るらしい

良かった。確認できた!
※これ確認するために1周間くらいかけました(0_0)

6. ブートセクタからOS本体を実行(p.59) - harib00f

haribote.asmipl.asmに変更を加える。

haribote.asm
 ORG 0xc200 ; 0xc200 <- 0x8000 + 0x4200
fin:
 HLT
 JMP fin
ipl.asm
; 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

実行

terminal(入力)
$ make run

実行結果
👁 image.png

これでは上手く読み込まれたのかどうかがわからないので次で確認しましょう。

7. OS本体の動作を確認(p.59) - harib00g

説明はテキストで十分かと思うのでここではコードだけ。

haribote.asm
; 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デバッグ体験記」)

ipl10.asm
; 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も名前変更

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

では実行

terminal(入力)
$ make run

実行結果
👁 image.png

やったー!真っ黒な画面を出力できた〜!
これで正常にharibote.asmが読み込めていることがわかりましたね。んではつぎー。

8. 32ビットモードへ(p.61) - harib00h

キーボードの状態をBIOSから教えてもらうためのコード
変更部分はharibote.asmのみ

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

ここにきてまた著者のオリジナル実行ファイルですか。。。
調べるのに結構苦労しましたね。
以下のbootpack.cとリンカスクリプトのhar.ldMakefileを作成していただければ解決!

bootpack.c
void HariMain(void)
{
fin:
 goto fin;
}
har.ld
/* 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) }

}
Makefile
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
har.ld
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386)

SECTIONS {
. = 0x7c00;
.text : { *(.text) }
}

debugcleanはおまけとして追加しました。
debugは「gdbデバッグ体験記」にて!
cleanはバイナリファイルで溢れかえったディレクトリを最小サイズにするために削除するコマンドです。

とりあえず実装することが目的なので詳しい説明はナシです(^o^)
私も完全に理解していないのでもう少し理解したら追記します。

10. HTLしたい(p.66) - harib00j

HLT処理はC言語で生成できないのでアセンブルの方で関数を定義してやります。

nasmfunc.asm
; nasmfunc.asm
; TAB=4

section .text
 GLOBAL io_hlt

io_hlt: ; void io_hlt(void);
 HLT
 RET

そして、アセンブラで定義された関数をC言語側で使用

bootpack.c
// bootpack.c
extern void io_hlt(void);

void HariMain(void)
{
fin:
 io_hlt();
 goto fin;
}

Makefileはリンク処理に書き足せばとりあえずOKです。

Makefile
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と入力してリソースをクリックすると見れます。)

harib00i(無限ループ)
👁 image.png

harib00j(HLT)
👁 image.png

今回の分ここまでです。
(つかれたあああああ)

参考

37

Go to list of users who liked

15
5

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
37

Go to list of users who liked

15