自分でOSを1から作ってみる Advent Calendar 2024の5日目です。
今日の目標
この前作成したブートセクタはテキストを表示させましたが、BIOSを使って表示させました。なので今回はとりあえずBIOSを使用せずVRAMを使って「Hello,World!」を表示させようと思います。
VRAMについて
VRAMは通常のRAMと似ているのですが、映像データの処理に特化しており、CPUとGPUのどちらからでもアクセスできるようになっています。詳しいことは調べてください。
制作
まずVRAMを使って「Hello,World!」を表示させるコードを載せてしまいます。解説も後に載っています。
[BITS 16]
[ORG 0x7C00]
start:
; ビデオメモリの先頭アドレスを設定 (0xB8000)
mov ax, 0xB800
mov es, ax ; ESをビデオメモリのセグメントアドレスに設定
mov di, 0 ; DIを0に初期化(ビデオメモリのオフセット)
; 表示する文字列のアドレスをSIに設定
mov si, message
print_string:
mov al, [si] ; SIが指す文字をALに読み込む
cmp al, 0 ; 文字がnull(0)かチェック
je done ; nullなら終了
mov [es:di], al ; ビデオメモリに文字を書き込み
mov byte [es:di+1], 0x0F ; 属性(白文字、黒背景)を設定
add di, 2 ; 次の文字位置に移動
inc si ; 次の文字へ
jmp print_string ; 繰り返す
done:
; 無限ループで終了
cli ; 割り込み禁止
hang:
hlt
jmp hang
; 表示するメッセージ
message db "Hello, World!", 0
times 510-($-$$) db 0 ; パディングを加えて512バイトに調整
dw 0xAA55 ; ブートセクタシグネチャ
実行方法は前の記事を参照してください。
コードの解説
今回新出のコードのみ説明しておこうと思います
ビデオメモリの設定
mov ax, 0xB800
mov es, ax
mov di, 0
mov ax, 0xB800
は、テキストモードのビデオメモリのセグメントアドレス(0xB800)をAXレジスタに設定します。
mov es, ax
により、ビデオメモリのセグメントアドレスを ES レジスタにロードします。
mov di, 0
により、ビデオメモリのオフセットが0に初期化されます。
メッセージの表示
print_string:
mov al, [si]
cmp al, 0
je done
mov [es:di], al
mov byte [es:di+1], 0x0F
add di, 2
inc si
jmp print_string
print_string
ラベルから始まるループで、メッセージを1文字ずつVRAMに書き込みます。
mov al, [si]
で SI レジスタが指す文字を AL レジスタにロードします。(mov si, message
で設定した値)
cmp al, 0
と je done
により、文字がNULL文字(終了文字)であれば done にジャンプし、処理を終了します。
mov [es:di], al
により、ビデオメモリの ES:DI アドレスに文字を表示します。
mov byte [es:di+1], 0x0F
で、文字の属性(白文字、黒背景)を設定します。
add di, 2
で次の文字位置に移動します(VRAMは1文字2バイト幅)。
inc si
で次の文字に進みます。
jmp print_string
でループを続けます。
終わりに
今回のブートセクタはカーネルをロードしたりはしていないのでまだOSという感じはしません。なのでそろそろカーネルのロードとかをしたいと思うのですが、自分でブートローダを作っても大変だし不便だしでメリットがないのでブートローダに関しては既成のものを使用しようと思います。もしかしたら最後の方で自分でブートローダを作ってみるかもしれません。