LoginSignup
6
2

More than 5 years have passed since last update.

BIOSを使用しないでテキストを表示させる

Posted at

VRAMに直書きする

自分の前回の投稿(自作OS(1): ブートローダ)では、BIOSの割り込み0x10のテレタイプモードでテキストを表示したが今回はBIOSを使用せずにVRAMに直接書き込むことでテキストを表示させる
※とりあえず今回はリアルモードでの話

NASMを使用します

VRAMの領域は0xb800:0x0000

2byteが色を含めた1文字分に相当する
具体的には、

  • 1byte目: キャラクタコード
  • 2byte目: 0-3bit 文字色, 4-8bit 背景色

といった具合
また、80文字x25行なので、1行は160byteとなる

基本的に知っておくことはこれだけで、適切なオフセットを計算して2byteを書き込むということを繰り返す操作となる

コード

各種初期化

まず、stosw命令はアキュムレータレジスタ(AX)をエクストラセグメント(ES)のディスティネーションインデックス(DI)に書き込むので、ESにはVRAMのセグメントアドレス0xb800を入れておく

ソースインデックス(SI)には目的のテキストのアドレスを入れておく

[bits 16]
[org 0x7c00]

start:
        ;; initialize segment registers                                                                                                      
        xor     ax, ax
        mov     ds, ax
        mov     ss, ax
        ;; initialize stack                                                                                                                  
        mov     sp, 0x7c00

        mov     ax, 0xb800      ; VRAM segment                                                                                               
        mov     es, ax          ; segment reg for stosw  
        mov     si, msg

        jmp     println

メインの処理

汎用レジスタの使い方は以下のような感じ

  • アキュムレータレジスタ(AX): ALは文字、AHは色情報
  • カウンターレジスタ(CX): 行内オフセット
  • ベースレジスタ(BX): 行オフセット (160 byte/line), 25行あるので2byte使いました

大まかな処理の流れ

  1. SIレジスタからlodsbでALに次の文字を格納
  2. 終端なら1行分インクリメントして、とりあえずhang
  3. AHに文字色と背景色の情報を格納
  4. BXにオフセット値を乗せる
  5. オフセットアドレス DI = CX + BX
  6. ES:DIにAXの内容を書き込む
  7. CXを1文字分(2byte)インクリメントして次の文字へ
println:
        xor     cx, cx          ; cx = 0                                                                                                     
print_char:
        lodsb                   ; load a char to AL                                                                                          
        or      al, al          ; if \0                                                                                                      

        jnz     print
        add     word [line], 160 ; 1 line = 80 chars x 2 bytes                                                                               
        jmp     hang
print:
        mov     ah, 0x0f        ; char:white, back:black                                                                                     

        ;; set offset                                                                                                                        
        mov     bx, word [line]
        xor     di, di          ; di = 0 (beginning of VRAM)                                                                                 
        add     di, cx          ; x-offset                                                                                                   
        add     di, bx          ; y-offset                                                                                                   
        ;; write                                                                                                                             
        stosw                   ; stor ax to ES:DI, and di -= 2                                                                              

        add     cx, 2           ; char/attr = 2byte                                                                                          
        jmp     print_char

hang:
        hlt
        jmp     hang

line    dw      0               ; = line num x ( 80 x 2 )                                                                                    
msg     db      "Hello World", 0
        times   510-($-$$) db 0
        dw      0xaa55

参考

OSDev
OS Wiki

6
2
0

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
6
2