はじめに
こんにちは!
前回、以下の記事で、OSの起動と文字列の表示ができました。
GeminiならOSを作れるはず - その1-
今回は、キーボード入力ができるようにしてみます。
要件
- Docker で起動する
- プロンプトを表示する
- キーボード入力を受け付ける
完成イメージ
とりあえず文字を入力できればOK
準備
前回の続きになるので、
GeminiならOSを作れるはず - その1-
をご確認ください。
実装
前回の続きですが、必要ファイルは全て記載しておきます。
Dockerfile
Dockerfile
FROM alpine:latest
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
RUN apk update && apk add nasm qemu-system-x86_64 gcc make libc-dev
ENV PATH="${PATH}:/usr/bin"
WORKDIR /root/os
CMD ["qemu-system-x86_64", "-vga", "cirrus", "-vnc", ":0", "-k", "ja", "-drive", "format=raw,file=boot.bin", "-drive", "format=raw,file=floppy.img"]
boot.asm
boot.asm
[bits 16]
[org 0x7c00]
; --- グローバル変数 ---
cursor_x dw 0 ; カーソルX座標
cursor_y dw 0 ; カーソルY座標
input_buffer db 256 dup(0) ; 入力バッファ
input_buffer_len dw 0 ; 入力バッファの文字数
start:
; レジスタの初期化
xor ax, ax
mov es, ax
; 画面モードの設定 (80x25 テキストモード)
mov ah, 0x00
mov al, 0x03
int 0x10
; プロンプトの表示
call print_prompt
.loop:
; キーボード入力処理
call handle_keyboard
jmp .loop
; --- プロンプト表示 ---
print_prompt:
mov ah, 0x0e ; ビデオサービス(テレタイプモード)
mov bx, 0x0007 ; 文字色(白)
mov bp, prompt_msg ; メッセージのアドレス
.print_prompt_loop:
mov al, [bp] ; 文字を取得
cmp al, 0 ; 文字列の終端であれば終了
je .print_prompt_end
int 0x10 ; 文字を表示
inc bp ; 次の文字へ
jmp .print_prompt_loop
.print_prompt_end:
ret
; --- キーボード入力処理 ---
handle_keyboard:
mov ah, 0x00 ; キーボード入力待ち
int 0x16 ; キーボードBIOS割り込み
; スキャンコードをASCIIコードに変換
mov bl, al ; スキャンコードを bl に保存
call scancode_to_ascii
; --- キー入力処理 ---
cmp al, 0x0D ; Enterキー?
je .handle_enter
cmp al, 0x08 ; Backspaceキー?
je .handle_backspace
jmp .handle_char
.handle_enter:
; コマンド実行処理 (ここではプロンプトを再表示するだけ)
mov word [cursor_x], 0 ; カーソル位置を先頭に
inc word [cursor_y] ; 次の行へ
mov word [input_buffer_len], 0 ; 入力バッファをクリア
; カーソル位置を更新
mov ah, 0x02 ; カーソル位置設定
mov bh, 0 ; ページ番号 (通常は0)
mov dh, [cursor_y] ; 行番号
mov dl, [cursor_x] ; 列番号
int 0x10
call print_prompt
jmp .end_input
.handle_backspace:
; バッファから最後の文字を削除
cmp word [input_buffer_len], 0 ; バッファが空なら何もしない
je .end_input
dec word [input_buffer_len]
mov di, input_buffer
add di, [input_buffer_len]
mov byte [di], 0 ; バッファの最後を0でクリア
; カーソルを左に移動して文字を削除
mov al, 0x08 ; Backspace
int 0x10
mov al, ' ' ; 空白文字
int 0x10
mov al, 0x08 ; Backspace
int 0x10
jmp .end_input
.handle_char:
; 入力バッファに文字を追加
mov di, input_buffer
add di, [input_buffer_len]
mov byte [di], al
inc word [input_buffer_len]
; 画面に文字を表示
mov ah, 0x0e ; テレタイプ出力
mov bx, 0x0007 ; 属性 (白文字、黒背景)
int 0x10
.end_input:
ret
; --- スキャンコード - ASCIIコード 変換テーブル ---
scancode_to_ascii:
; 一旦そのまま返す
mov al, bl
ret
; --- プロンプトメッセージ ---
prompt_msg:
db 'user@os> ', 0
; --- 残り部分を0で埋める ---
times 510-($-$$) db 0
dw 0xaa55
起動してみる
まずはDockerfileをビルド
docker build -t os-dev .
続いてバイナリ変換コマンドの実行
nasm -f bin boot.asm -o boot.bin
コンテナを起動
docker run -it -p 5900:5900 -v $(pwd):/root/os os-dev
RealVNC Viewer でlocalhost:5900にアクセス
OSが起動し、プロンプトが表示されました!
文字を入力して、Enterを押してみます。
入力できました!
まだ、シェルやファイルシステムが入ってないのでコマンドは反応しません。
次のステップをどうするか、Geminiに相談しながら考えます。
まとめ
今回は、OSを起動し、キーボードからの入力ができるようにしてみました。
私はOS開発の知識が皆無なので、AIの助けが無いと、何もできません。
しかし、AIを活用することで、まずはここまで来れたのです、、そう考えると、凄いですね。
まだまだ準備運動のスタートラインレベルです。
これから少しずつ進めて、OSに軽量なAIを組み込むところまでは行きたいと思います!
みなさんも一緒に頑張りましょう😀