VOOZH about

URL: https://qiita.com/pollenjp/items/d15fce401bccd37e8059

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


👁 Image
17

Go to list of users who liked

9

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自作入門(2日目)[Ubuntu16.04/NASM]

17
Last updated at Posted at 2018-03-23

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

目的

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

👁 image.png

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

(追記:2018/05/29)
ソースコードは以下のGitHubにあげています。
https://github.com/pollenjp/myHariboteOS

helloos3

0x00007c00 - 0x00007dff : ブートセクタが読み込まれるアドレス

ブートセクタ説明用のコードはもう少し下で掲載

ipl.asm
; hello-os
; TAB=4

 ORG 0x7c00 ; メモリ上の開始位置

; ディスクのための記述

 JMP entry
 DB 0x90
 DB "HELLOIPL" ; ブートセレクタの名前を自由にかいていよい (8Byte)
 DW 512 ; 1セクタの大きさ (512にしなければならない)
 DB 1 ; クラスタの大きさ (1セクタにしなければならない)
 DW 1 ; FATがどこから始まるか (普通は1セクタ目からにする)
 DB 2 ; FATの個数 (2にしなければならない)
 DW 224 ; ルートディレクトリ領域の大きさ (普通は224エントリにする)
 DW 2880 ; このドライブの大きさ (2880セクタにしなければならない)
 DB 0xf0 ; メディアタイプ (0xf0にしなければならない)
 DW 9 ; FAT領域の長さ (9セクタにしなければならない)
 DW 18 ; 1トラックにいくつのセクタがあるか (18にしなければならない)
 DW 2 ; ヘッドの数 (2にしなければならない)
 DD 0 ; パーティションを使っていないのでここは必ず0
 DD 2880 ; このドライブの大きさをもう一度書く
 DB 0, 0, 0x29 ; よくわからないけどこの値にしておくといいらしい
 DD 0xffffffff ; たぶんボリュームシリアル番号
 DB "HELLO-OS " ; ディスクの名前 (11Byte)
 DB "FAT12 " ; フォーマットの名前 (8Byte)
 RESB 18 ; とりあえず18バイト開けておく

; Program Main Body
entry:
 MOV AX, 0 ; レジスタの初期化
 MOV SS, AX
 MOV SP, 0x7c00
 MOV DS, AX
 MOV ES, AX

 MOV SI, msg
putloop:
 MOV AL, [SI] ; BYTE (accumulator low)
 ADD SI, 1 ; increment
 CMP AL, 0 ; compare (<end msg>)
 JE fin ; jump to fin if equal to 0
 MOV AH, 0x0e ; AH = 0x0e
 MOV BX, 15 ; BH = 0, BL = <color code>
 INT 0x10 ; interrupt BIOS
 JMP putloop
fin:
 HLT
 JMP fin

msg:
 DB 0x0a, 0x0a
 DB "hello, world"
 DB 0x0a
 DB 0 ; end msg

 ;RESB 0x7dfe-($-$$) ; これだとエラーが出た。。。
 RESB 0x7dfe-0x7c00-($-$$)

 DB 0x55, 0xaa

; ブート以外の記述

 DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
 RESB 4600
 DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
 RESB 1469432

helloos3で詰まったところ

 ;RESB 0x7dfe-($-$$) ; これだとエラーが出た。。。

サンプルコードではRESB 0x7dfe-$と記述されていたが、そのまま(上のように)qemuで実行したところ以下のような挙動が起きた。
👁 image.png

👁 image.png

値からさらに0x7c00を引いたら治った。
👁 image.png

ブートセクタ

ブートセクタについて少し詳しく見ていこうと思います。面倒な方は次の節に飛んでください。

今まで記述してきたhelloos.asmの中で

helloos3.img
 ......
; ディスクのための記述

 JMP entry
 DB 0x90
 ......

という箇所についての解説ですが、ブート セクタとBPBの中に出てくる表にまとまっています。
以下のコードのコメントに名前を書いて置きます。

helloos3.asm
; hello-os
; TAB=4

 ORG 0x7c00 ; このプログラムがメモリ上のどこによみこまれるのか

; ディスクのための記述
; offset byte
 JMP entry ; BS_JmpBoot 0
 DB 0x90 ; BS_JmpBoot 1
 DB "HELLOIPL" ; BS_OEMName 3 8
 DW 512 ; BPB_BytsPerSec 11 2 : バイト単位のセクタ サイズ
 DB 1 ; BPB_SecPerClus 13 1 : アロケーション ユニット(<-クラスタ)(割り当て単位)当たりのセクタ数
 DW 1 ; BPB_RsvdSecCnt 14 2 : 予約領域のセクタ数 (少なくともこのBPBを含むブートセクタそれ自身が存在するため、0であってはならない)
 DB 2 ; BPB_NumFATs 16 1 : FATの個数 (このフィールドの値は常に2に設定すべきである)
 DW 224 ; BPB_RootEntCnt 17 2 : ルートディレクトリに含まれるディレクトリエントリの数を示す
 DW 2880 ; BPB_TotSec16 19 2 : ボリュームの総セクタ数(古い16ビット フィールド)
 DB 0xf0 ; BPB_Media 21 1 : メディアタイプ(区画分けされた固定ディスク ドライブでは0xF8が標準値である。区画分けされないリムーバブル メディアでは0xF0がしばしば使われる)
 DW 9 ; BPB_FATSz16 22 2 : 1個のFATが占めるセクタ数
 DW 18 ; BPB_SecPerTrk 24 2 : トラック当たりのセクタ数
 DW 2 ; BPB_NumHeads 26 2 : ヘッドの数
 DD 0 ; BPB_HiddSec 28 4 : ストレージ上でこのボリュームの手前に存在する隠れた物理セクタの数(ボリュームがストレージの先頭から始まる場合(つまりフロッピー ディスクなど区画分けされていないもの)では常に0であるべきである。)
 DD 2880 ; BPB_TotSec32 32 4 : ボリュームの総セクタ数(新しい32ビット フィールド)


; FAT12/16におけるオフセット36以降のフィールド
 ;DB 0, 0, 0x29 ; 以下の3行に分けて記述
 DB 0x00 ; BS_DrvNum 36 1
 DB 0x00 ; BS_Reserved1 37 1
 DB 0x29 ; BS_BootSig 38 1

 DD 0xffffffff ; BS_VolID 39 4 : ボリュームシリアル番号
 DB "HELLO-OS " ; BS_VolLab 43 11 : ディスクの名前(ルート ディレクトリに記録される11バイトのボリューム ラベルに一致する)
 DB "FAT12 " ; BS_FilSysType 54 8 : フォーマットの名前
 RESB 18 ; とりあえず18バイト開けておく

; START BS_BootCode 64 448
; (ブートストラップ プログラム。システム依存フィールドで、未使用時はゼロで埋める。)
entry:
 MOV AX, 0 ; レジスタの初期化
 MOV SS, AX
 MOV SP, 0x7c00
 MOV DS, AX
 MOV ES, AX

 MOV SI, msg
putloop:
 MOV AL, [SI] ; BYTE (accumulator low)
 ADD SI, 1 ; increment
 CMP AL, 0 ; compare (<end msg>)
 JE fin ; jump to fin if equal to 0
 MOV AH, 0x0e ; AH = 0x0e
 MOV BX, 15 ; BH = 0, BL = <color code>
 INT 0x10 ; interrupt BIOS
 JMP putloop
fin:
 HLT
 JMP fin

msg:
 DB 0x0a, 0x0a
 DB "hello, world"
 DB 0x0a
 DB 0 ; end msg

 ;RESB 0x7dfe-($-$$) ; これだとエラーが出た。。。
 RESB 0x7dfe-0x7c00-($-$$) ; 現在の場所から0x1fdまで(残りの未使用領域)を0で埋める。
; END BS_BootCode

 DB 0x55, 0xaa ; BS_BootSign 510 2 : 以下の記述と同様
 ;DW 0xAA55

このMakefile作成して以下のコマンド実行でエミュレータでいつものHello, Worldが出力される。

terminal(入力)
$ make run

※makeコマンドはUbuntuの中にデフォルトで入っている。

Makefile

説明はおおよそ本に書いてあるとおり、一応Ubuntuで最低限動作するコードを載せときます。

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 helloos.img

【追記】helloos4

あほみたいにコメント追加してMakefileでGNU Makeらしく書いた。

ipl.asm
; hello-os
; FAT12 format

; - [Tips IA32(x86)命令一覧](http://softwaretechnique.jp/OS_Development/Tips/IA32_instructions.html)
; - [Add命令](http://softwaretechnique.jp/OS_Development/Tips/IA32_Instructions/ADD.html)
; - [MOV命令](http://softwaretechnique.jp/OS_Development/Tips/IA32_Instructions/MOV.html)

;=======================================================================================================================
; ブートセクタ (512バイト)
; > 0x00007c00 - 0x00007dff : ブートセクタが読み込まれるアドレス
; > [ソフトウェア的用途区分 - (AT)memorymap - os-wiki](http://oswiki.osask.jp/?%28AT%29memorymap#qd4cd666)
; リトルエンディアン

 ;=======================================================================
 ; このプログラムがメモリ上のどこによみこまれるのか
 ; > [7.1.1 ORG: Binary File Program Origin - NASM - The Netwide Assembler](https://www.nasm.us/doc/nasmdoc7.html#section-7.1.1)
 ORG 0x7c00

 ;=======================================================================
 ; ディスクのための記述
 ; http://elm-chan.org/docs/fat.html#notes
 ; BPB(BIOS Parameter Block)
 ; Name | Offset | Byte | Description
 ; | 
 ; FAT12/16/32共通フィールド(オフセット0~35)
 JMP entry ; BS_JmpBoot | 0x0000-0x0002 0-2 | 3 | Jump to Bootstrap
 DB 0x90 ; | ブートストラッププログラムへのジャンプ命令(x86命令)。
 ; | 0xEB, 0x??, 0x90 (ショート ジャンプ+NOP)
 DB "HELLOIPL" ; BS_OEMName | 0x0003-0x000a 3-10 | 8 | これは単なる名前である
 DW 512 ; BPB_BytsPerSec | 0x000b-0x000c 11-12 | 2 | セクタあたりのバイト数.
 ; | 512, 1024, 2048, 4096
 ; | Bytes Per Cluster
 DB 1 ; BPB_SecPerClus | 0x000d 13 | 1 | アロケーションユニット(割り当て単位)当たりのセクタ数
 ; | アロケーションユニットはクラスタと呼ばれている
 ; | Secters Per Cluster
 DW 1 ; BPB_RsvdSecCnt | 0x000e-0x000f 14-15 | 2 | 予約領域のセクタ数 (少なくとも
 ; | このBPB(BIOS Parameter Block)を含むブート
 ; | セクタそれ自身が存在するため0であってはならない)
 DB 2 ; BPB_NumFATs | 0x0010 16 | 1 | FATの個数 
 ; | (このフィールドの値は常に2に設定すべきである)
 DW 224 ; BPB_RootEntCnt | 0x0011-0x0012 17-18 | 2 | FAT12/16ボリュームではルートディレクトリに
 ; | 含まれるディレクトリエントリの数を示す.
 ; | このフィールドにはディレクトリテーブルのサイズが
 ; | 2セクタ境界にアライメントする値,つまり,
 ; | BPB_RootEntCnt*32がBPB_BytsPerSecの偶数倍になる値
 ; | を設定すべきである. (32というのはディレクトリエントリ1個のサイズ)
 ; | 最大の互換性のためにはFAT16では512に設定すべき.
 ; | FAT32ボリュームではこのフィールドは使われず,
 ; | 常に0でなければならない.
 ; | 224x32=4x16x32=4x512
 ; | 512=32x16
 ; | | | 
 DW 2880 ; BPB_TotSec16 | 0x0013-0x0014 19-20 | 2 | ボリュームの総セクタ数(古い16ビットフィールド).
 ; | ボリュームの4つの領域全てを含んだセクタ数.
 ; | FAT12/16でボリュームのセクタ数が0x10000以上になる
 ; | ときは,このフィールドには無効値(0)が設定され,真の
 ; | 値がBPB_TotSec32に設定される.
 ; | FAT32ボリュームでは,このフィールドは必ず無効値で
 ; | なければならない.
 ; | 0x10000=(2^4)^4=65536 > 2880
 ; | | | 
 DB 0xf0 ; BPB_Media | 0x0015 21 | 1 | 区画分けされた固定ディスクドライブでは0xF8が標準
 ; | 値である. 区画分けされないリムーバブルメディアで
 ; | は0xF0がしばしば使われる. このフィールドに有効な
 ; | 値は,0xF0,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
 ; | で,ほかに重要な点はこれと同じ値をFAT[0]の下位8
 ; | ビットに置かなければならないということだけである.
 ; | これはMS-DOS 1.xでメディアタイプの設定に遡り,
 ; | 既に使われていない。
 ; | | | 
 DW 9 ; BPB_FATSz16 | 0x0016-0x0017 22-23 | 2 | 1個のFATが占めるセクタ数.
 ; | このフィールドはFAT12/FAT16ボリュームでのみ使われる.
 ; | FAT32ボリュームでは必ず無効値(0)でなければならず,
 ; | 代わりにBPB_FATSz32が使われる. FAT領域のサイズは,
 ; | この値 * BPB_NumFATsセクタとなる。
 ; | | | 
 DW 18 ; BPB_SecPerTrk | 0x0018-0x0019 24-25 | 2 | トラック当たりのセクタ数
 DW 2 ; BPB_NumHeads | 0x001a-0x001b 26-27 | 2 | ヘッドの数
 DD 0 ; BPB_HiddSec | 0x001c-0x001f 28-31 | 4 | ストレージ上でこのボリュームの手前に存在する隠れ
 ; | た物理セクタの数. 一般的にIBM PCのディスクBIOSで
 ; | アクセスされるストレージに関するものであり,どの
 ; | ような値が入るかはシステム依存. ボリュームがスト
 ; | レージの先頭から始まる場合(つまりフロッピーディ
 ; | スクなど区画分けされていないもの)では常に0である
 ; | べきである.
 ; | | | 
 DD 2880 ; BPB_TotSec32 | 0x0020-0x0023 32-35 | 4 | ボリュームの総セクタ数(新しい32ビットフィールド).
 ; | この値はボリュームの4つの領域全てを含んだセクタ数
 ; | である.
 ; | FAT12/16ボリュームで総セクタ数が0x10000未満のとき,
 ; | このフィールドは無効値(0)でなければならなず,真の
 ; | 値はBPB_TotSec16に設定される.
 ; | FAT32ボリュームでは常に有効値が入る.

 ;=======================================================================
 ; FAT12/16におけるオフセット36以降のフィールド
 ; Name | Offset | Byte | Description
 ; | | | 
 DB 0x00 ; BS_DrvNum | 0x0024 36 | 1 |
 DB 0x00 ; BS_Reserved1 | 0x0025 37 | 1 |
 DB 0x29 ; BS_BootSig | 0x0026 38 | 1 |

 DD 0xffffffff ; BS_VolID | 0x0027-0x002a 39-42 | 4 | ボリュームシリアル番号
 DB "HELLO-OS " ; BS_VolLab | 0x002a-0x0036 43-54 | 11 | ディスクの名前(ルートディレクトリに記録される11バイトのボリュームラベルに一致する)
 DB "FAT12 " ; BS_FilSysType | 0x0036-0x003d 54-61 | 8 | フォーマットの名前
 RESB 18 ; | 0x003e-0x004f 62-79 | 8 | Reserve Bytes : [3.2.2 RESB and Friends: Declaring Uninitialized Data](https://www.nasm.us/doc/nasmdoc3.html#section-3.2.2)
 ; | 18バイト空けて 0x7c50 の直前まで埋める
 ; | naskでは0で初期化するみたいだがnasmだ
 ; | と初期化しない


 ;=======================================================================
 ; START BS_BootCode | 64 448
 ; (ブートストラッププログラム. システム依存フィールドで、未使用時はゼロで埋める。)
 ; 0x7c50
 ;
 ; rb (register byte), rw (register word), rd (register double-word) 等の表記は
 ; https://www.intel.co.jp/content/dam/www/public/ijkk/jp/ja/documents/developer/IA32_Arh_Dev_Man_Vol2A_i.pdf
 ; によっている.
 ; > | rb | rw | rd |
 ; > 0 | AL | AX | EAX |
 ; > 1 | CL | CX | ECX |
 ; > 2 | DL | DX | EDX |
 ; > 3 | BL | BX | EBX |
 ; > 4 | AL | SP | ESP |
 ; > 5 | CL | BP | EBP |
 ; > 6 | DL | SI | ESI |
 ; > 7 | BL | DI | EDI |
 ; > imm8 - 即値バイト値。記号 imm8 は -128 から +127 までの符号付き数値である
 ; == 16 bit register ==
 ; AX : acumulator
 ; CX : Counter
 ; DX : Data
 ; BX : Base
 ; SP : Stack Pointer
 ; BP : Base Pointer
 ; SI : Source Index
 ; DI : Destination Index
 ; ES : Extra Segment
 ; CS : Code Segment
 ; SS : Stack Segmengt
 ; DS : Data Segmengt
 ; FS : no-name
 ; GS : no-name

entry:
 MOV AX, 0 ; AX (rw1) に0(imm8)代入
 MOV SS, AX
 MOV SP, 0x7c00
 MOV DS, AX
 MOV ES, AX

 MOV SI, msg
putloop:
 MOV AL, BYTE [SI] ; BYTE (accumulator low)
 ADD SI, 1 ; increment stack index
 CMP AL, 0 ; compare (<end msg>)
 JE fin ; jump to fin if equal to 0

																; 一文字表示
 MOV AH, 0x0e ; AH = 0x0e
 MOV BX, 15 ; BH = 0, BL = <color code>
 INT 0x10 ; interrupt BIOS
																; [INT(0x10); ビデオ関係 - (AT)BIOS - os-wiki](http://oswiki.osask.jp/?%28AT%29BIOS#n5884802)
 JMP putloop
fin:
 HLT
 JMP fin

msg:
 DB 0x0a, 0x0a
 DB "hello, world"
 DB 0x0a
 DB 0 ; end msg

 ;RESB 0x7dfe-($-$$) ; これだとエラーが出た。。。
																	 ; セクタサイズ 512 Byte なので 510 Byte目までを埋めたいときは
																	 ; 0x1fe - ($-$$) としてやればいい
 ; > you can tell how far into the section you are by using ($-$$)
 ; > [3.5 Expressions - NASM - The Netwide Assembler](https://www.nasm.us/doc/nasmdoc3.html#section-3.5)
 RESB 0x1fe-($-$$)			 ; 現在の場所から 0x1fd (0x1fe の直前)
 ; まで(残りの未使用領域)を0で埋める
 ; (naskでは0で初期化するみたいだがnasm
 ; だと初期化しない) 
 ; 0x7dfe-0x7c00 = 32254−31744 = 510

 ;=======================================================================
 ; END BS_BootCode ; Name | Offset | Byte | Description
 DB 0x55, 0xaa ; BS_BootSign | 0x7dfe-0x7dff | 510 |
Makefile
.DEFAULT_GOAL : all
.PHONY : all
all : img

ipl.bin : ipl.asm

%.bin : %.asm
	nasm $^ -o $@ -l $*.lst

helloos.img : ipl.bin
	cat $^ > $@


.PHONY : asm
asm :
# -r, --no-builtin-rules
# Eliminate use of the built-in implicit rules.
# Also clear out the default list of suffixes for suffix rules.
#	make --no-builtin-rules ipl.bin
	make ipl.bin

.PHONY : img
img :
	make helloos.img

.PHONY : run
run :
	make img
	qemu-system-i386 helloos.img

.PHONY : clean
clean :
# lstは残しておいてもいいと思うのでcleanに入れていない
	@rm *.img *.bin

実行

$ cd helloos4
($ make)
$ make run

参考

17

Go to list of users who liked

9
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
17

Go to list of users who liked

9