0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CUIOS開発 COM実行実装 第2段階 INT21Hの実装

Posted at

「手探りでCUI OS作成に挑む」連載

この記事は「手探りでCUI OS作成に挑む」連載の一部です。
全体の目次は「手探りでCUI OS作成に挑む」連載目次を御覧下さい。

やりたいこと

現在CUIのOSを開発中です。以下は開発中のソースです。
https://github.com/ooe1220/sourouOS/tree/20250628

COMファイルを実行する雛形を作ります。
まだFAT表を解析してファイルを読み込む部分を実装していないので一旦4セクタ目に固定でCOMファイルを設置して、実行します。

実装するCOMファイル

先にこのCOMファイルがMS-DOS上で動くことを確認します。

图片.png

hello.asm
org 0x100          ; COMは必ず0x100から開始(セグメントは自由)

mov ah, 0009h
mov dx, msg
int 21h

mov ax, 4C00h
int 21h

msg db 'Hello, World!$'

times 512 - ($ - $$) db 0  ; 1セクタ分埋める
# コンパイル
nasm -f bin hello.asm -o hello.com

# 空のフロッピーイメージ作成 FAT12で初期化
dd if=/dev/zero of=floppy.img bs=512 count=2880
mkfs.fat -F 12 floppy.img

# フロッピーにhello.comを入れる
sudo mkdir /mnt/floppy
sudo mount -o loop floppy.img /mnt/floppy

sudo cp hello.com /mnt/floppy

sudo umount /mnt/floppy

## QEMUで起動
qemu-system-i386 -fda floppy.img -hda msdos_hdd.img -boot c

実装

ブートローダ(今回の重点ではない)

boot.asm
boot.asm
; 第2セクタを読み込み、実行するブートローダー
[bits 16]
org 0x7C00

start:
    ; セグメント初期化
    xor ax, ax
    mov ds, ax
    mov es, ax

    ; スタック設定
    mov ss, ax
    mov sp, 0x7C00
    
    mov si, msg1
    call print_string

    ; ディスクから第2セクタを 0x7E00 に読み込む
    mov ah, 0x02        ; INT 13h サービス 2: 読み込み
    mov al, 3           ; 読み込むセクタ数 = 3
    mov ch, 0           ; シリンダ = 0
    mov cl, 2           ; セクタ番号 = 2(1始まり)
    mov dh, 0           ; ヘッド = 0
    mov dl, 0x80        ; ドライブ番号
    mov bx, 0x7E00      ; 読み込み先アドレス
    int 0x13
    jc disk_error       ; エラー時に無限ループ

    ; 読み込んだコードへ跳ぶ(第2セクタ)
    jmp 0x0000:0x7E00

disk_error:
    mov si, msg2
    call print_string
    jmp $
    
print_string:
    pusha
    mov ah, 0x0E     ;1文字出力
    mov bh, 0
.print_loop:
    lodsb            ;SIの示すアドレスから1バイトをALに読み込み、SIを+1(次の文字へ)
    test al, al      ;alが0かどうかを確認する
    jz .done         ;文字が 0 か(=終端記号か)を確認。※'hello',0 文字列の最後に目印の0を入れている
    int 0x10         ;BIOS割り込みで AL の文字を表示
    jmp .print_loop
.done:
    popa
    ret

msg1 db 'boot loader', 0x0D, 0x0A,0
msg2 db 'disk_error', 0x0D, 0x0A,0

times 510-($-$$) db 0
dw 0xAA55

検証用のコード

INT21Hを割り込み表(IVT)へ登録
COMファイルを0x0200:0x0100へ読み込む
0x0200:0x0100へ跳ぶ

testcode.asm
testcode.asm
[bits 16]
[org 0x7E00]

start:
    ; レジスタ初期化
    xor ax, ax
    mov ds, ax
    mov es, ax
    
    ; スタック設定
    mov ss, ax
    mov sp, 0x7C00

    ; INT21Hを割り込み表へ登録
    mov word [0x21 * 4], int21_handler
    mov word [0x21 * 4 + 2], cs
    
    ; COMファイルは4セクタ目に保存されている
    mov bl, 0x03           ; LBA 0-7 4セクタ目〜
    mov bh, 0x00           ; LBA 8-15
    mov cl, 0x00           ; LBA 16-23
    mov si, 0x01              ; 読み込みセクタ数 1
    mov ax, 0x0200
    mov es, ax
    mov di, 0x0100   ;転送先 0x0200:0x0100
    
    call read_multi_sector
    
    jmp 0x0200:0x0100

    cli
    hlt
        
%include "int21.asm"
%include "driver/disk.asm"
%include "driver/vga.asm"

times 1024-($-$$) db 0

MS-DOSシステムコールの再現

今回の重点は9番の文字列表示機能

int21.asm
int21.asm
; int 21h ハンドラ
int21_handler:
    pusha
    
    ; DSを呼び出し元のCSに合わせる
    push ax
    mov ax, 0x0200
    mov ds, ax
    pop ax

    cmp ah, 1
    je get_key

    cmp ah, 2
    je put_char
    
    cmp ah, 9
    je printstring
    
    cmp ah, 4Ch
    je int21_exit

    jmp unknown_function

; AH=01h キーボード入力 (結果ALに)
get_key:
    mov ah, 0
    int 16h
    popa
    iret

; AH=02h 文字表示 (DLに文字)
put_char:
    mov ah, 0x0E
    mov al, dl
    int 10h
    popa
    iret
    
; AH=09h $終端文字列表示
printstring:
    push ds           ; DSを退避
    push si           ; SIを退避
         
     mov si, dx        ; DXが文字列のオフセットと想定(DSセグメント)
 print_loop:
     lodsb             ; AL = [DS:SI], SI++
     cmp al, '$'       ; '$' で終わり?
     je print_done
     mov ah, 0x0E
     mov bh, 0x00
     mov bl, 0x07      ; 文字属性(標準)
     int 0x10          ; 文字表示
     jmp print_loop
    
print_done:
    pop si
    pop ds
    popa
    iret
    
; AH=4Ch 終了処理(カーネルに戻る等)
int21_exit:
    popa  
    ; ここで終了処理。例: 無限ループで停止
    cli
    hlt

unknown_function:
    popa
    iret

動作確認

COMを実行できた。
图片.png

# コンパイル
nasm boot.asm -o boot.bin             # 1セクタ
nasm testcode.asm -o testcode.bin     # 2セクタ
nasm -f bin hello.asm -o hello.com    # 1セクタ

# 結合
cat boot.bin testcode.bin hello.com > os.img   

qemu-system-i386 -hda os.img  -monitor stdio 

今後

今回はCOMファイルを固定の場所に設置して読み込みましたが、今後はFAT表及びルートディレクトリにファイルとして書き込み、そこから起動できるようにします。
具体的には以下の用に起動できるようにするつもりです。

C:\>DIR
hello.com
C:\>hello.com
Hello,World!

又現在はint10hを用いて文字列を表示しているが、現在開発中のOSではVRAMへ直書きして文字を表示しているため、この部分も書き直す。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?