アセンブリ言語

命令
ORG プログラムの読み込み先メモリを指定(このプログラム中のメモリ位置の原点)
JE CMPの結果が等しかったらジャンプ(jump if equal)
INT 割り込み。BIOS内の関数を呼ぶ
HLT CPUを待機状態にさせる。入力装置の操作で解除する
1
2
3
4
5
6
7
8
9
MOV BYTE [123] 456
MOV WORD [123] 456
; (BYTE|WORD) [\d+]でメモリ番地を表す
; BYTE = 1バイトを使う
; WORD = 2バイトを使う
; 456(10) = 0000 0001 1100 1000 (2)
; メモリの123番地に11001000
; 124番地に00000001
; 下位桁が先に格納されるのはリトルエンディアンだから?

レジスタ

レジスタ名
AX アキュムレータ
CX カウンタ
DX データ
BX ベース
SP スタックポインタ
BP ベースポインタ
SI ソースインデックス
DI デスティネーションインデックス
ES エクストラセグメント
CS コードセグメント
SS スタックセグメント
DS データセグメント
FS おまけ
GS おまけ

アセンブリを使って書き直す(02_day/helloos3)

1
2
3
4
5
DB		0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
DB 0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
DB 0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
DB 0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
DB 0xee, 0xf4, 0xeb, 0xfd

これを人間が読めるようにすると・・・

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
entry:
MOV AX,0 ; レジスタ初期化
MOV SS,AX
MOV SP,0x7c00 ; スタックポインタにORGの値を入れておく
MOV DS,AX
MOV ES,AX

MOV SI,msg
putloop:
MOV AL,[SI]
ADD SI,1
CMP AL,0 ; このへんでループしてる
JE fin
MOV AH,0x0e ; 一文字表示ファンクション
MOV BX,15 ; カラーコード
INT 0x10 ; ビデオBIOS呼び出し
JMP putloop
fin:
HLT ; 何かあるまでCPUを停止させる
JMP fin ; 無限ループ

C言語でなんとなく書いてみるとこんな感じ。レジスタや関数呼び出しはテキトウなので動かない。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
char* msg = "hello, world";
int* SI = NULL;
int AX,SS,SP,DS,ES;

void entry(){
AX = 0,
SS = AX,
SP = 0x7c00,
DS = AX,
ES = AX;
int* SI = msg;
}

void putloop(){
while(*SI--) //ポインタを進めてる
write(*SI); //BIOS呼び出し
fin();
}

void fin(){
hlt(); // CPUを待機状態にする。解除されると関数を抜ける。
fin();
}

int main(){
entry();
putloop();
}

HLTの効果(02_day/helloos3)

あれっ!no bootable device!?

58行目を編集して

1
2
;RESB	0x7dfe-$
RESB 0x7dfe-($-$$)

とりあえずいつもどおりアセンブルして起動しようとすると、プードデバイスがないと言われた。

プーとセクタのバグっぽい。その原因は

1
ORG		0x7c00

プログラム全体の基準を決めてしまっているので58行目を相対アドレスにしなければならない。著者作のnaskだとなぜ動くのか不明だが、修正しておく。0x7dfe - 0x7c00 = 0x01feより、

1
RESB	0x01fe-($-$$)

これで正常に動いた。

HLTなし

タスクマネージャを見るとCPUの第14スレッドが使用率100%になっていた。

HLTあり

HLTの効果はたしかにあるようだ。

ブートセクタだけを作るようにする

今後の拡張のために、ブートセクタとOS本体のコードを切り分けて、あとからまとめるようにするらしい。
本書では著者作のedimg.exeを使用しているが、甘えずに一般的なやり方を探す。

やっていることは本章では空のディスクイメージを作成し、そこにアセンブルしたブートセクタを書き込んでいるようだ。

どうやらmtoolsにあるmformatコマンドでイメージファイルを作成できるらしい。

https://www.gnu.org/software/mtools/manual/mtools.html

4.13 Mformat  

mformat [-t cylinders|-T tot_sectors] [-h heads] [-s sectors]
    [-f size] [-1] [-4] [-8]
    [-v volume_label]
    [-F] [-S sizecode]
    [-M software_sector_size]
    [-N serial_number] [-a]
    [-C] [-H hidden_sectors] [-I fsVersion]
    [-r root_sectors] [-L fat_len] 
    [-B boot_sector] [-k]
    [-m media_descriptor]
    [-K backup_boot]
    [-R nb_reserved_sectors]
    [-c clusters_per_sector]
    [-d fat_copies]
    [-X] [-2 sectors_on_track_0] [-3]
    [-0 rate_on_track_0] [-A rate_on_other_tracks]
    drive:

The following options are supported:  

f  
Specifies the size of the DOS file system to format. Only a certain number of predefined sizes are supported by this flag; for others use the -h/-t/-s flags. The following sizes are supported:  
    1440  
        1440K, double-sided, 18 sectors per track, 80 cylinders (for 3 1/2 HD)  

C  
creates the disk image file to install the MS-DOS file system on it. Obviously, this is useless on physical devices such as floppies and hard disk partitions, but is interesting for image files.

B  
Use the boot sector stored in the given file or device, instead of using its own. Only the geometry fields are updated to match the target disks parameters.

また、フォーマット対象のドライブを指定するには-iオプションを使用すれば良いと書いてある。

2.2 Drive letters

The drive letter : (colon) has a special meaning. It is used to access image files which are directly specified on the command line using the -i options.

よくわからなかったので、mtoolsのソースコードを見てみると、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// config.c
static void maintain_default_drive(char drive)
{
if(default_drive == ':')
return; /* we have an image */
if(default_drive == '\0' ||
default_drive > drive)
default_drive = drive;
}

char get_default_drive(void)
{
if(default_drive != '\0')
return default_drive;
else
return 'A';
}

のようになっている。デフォルトのドライブレターが:なので、-iオプションのオプションは::

1
-i <image-file> <drive>

よって、

1
mformat -f 1440 -C -B ipl.bin -i helloos.img ::

よって、これらをMakefileにすると、

1
2
3
4
5
ipl:
nasm ipl.nas -o ipl.bin

img: ipl
mformat -f 1440 -C -B ipl.bin -i os.img ::

参考文献