はじめに
以前、簡易的なOSを作ってみる(未解決)でOS作りに挑戦し、失敗。
しかし、Gemini 1.5 Pro なら作れるのではないかと思い、再挑戦です。
2024年6月、 Claude 3.5 Sonnet が話題になってますが、あえて Gemini を使います。
要件
- Docker で起動する
- 画面に「Hello, World!」と表示する
準備
- ターミナル: Dockerコマンドを使います
- エディタ: VSCodeなど
- Docker: OSを起動させる仮想環境として使います
- VNCクライアント: 後ほど、Docker上で起動したOSの画面を表示するために使用
今回はRealVNC Viewer
以下、Dockerfile、ブートセクタ、その他もろもろ、Gemini 1.5 Pro に質問しながら進めました。
実装
Docker環境構築
まずは、プロジェクト用のディレクトリを作成。
mkdir my-os
cd my-os
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 ["/bin/sh"]
-
Dockerfileの内容
-
FROM alpine:latest
: OS開発の土台となる、軽量なAlpine Linuxのイメージを取得 -
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
: Alpine Linuxのミラーサイトを、より安定したものに変更 -
RUN apk update && apk add nasm qemu-system-x86_64 gcc make libc-dev
: OS開発に必要なツール(nasm, qemu-system-x86_64, gccなど)をインストール -
ENV PATH="${PATH}:/usr/bin"
: qemu-system-x86_64コマンドを実行できるように、パスを通す -
WORKDIR /root/os
: Dockerコンテナ内の/root/os
を作業ディレクトリに設定 -
CMD ["/bin/sh"]
: コンテナ起動時に/bin/sh
を実行
-
- Dockerイメージのビルド
コマンドプロンプトまたはターミナルを開き、以下のコマンドを実行
docker build -t os-dev .
エラーが無ければ、これで、OS開発用Dockerの準備が完了です。
ブートセクタ作成
次に、OSが起動した時に一番最初に読み込まれるプログラム「ブートセクタ」を作ります。
[bits 16]
[org 0x7c00]
start:
mov ah, 0x0e ; ビデオサービス(テレタイプモード)
mov bx, 0x0007 ; 文字色(白)
mov bp, msg ; メッセージのアドレス
.loop:
mov al, [bp]
cmp al, 0
je .end
int 0x10 ; ビデオサービス割り込み
inc bp
jmp .loop
.end:
jmp $ ; 無限ループ
msg:
db 'Hello, World!', 0
times 510-($-$$) db 0 ; 510バイト目まで0で埋める
dw 0xaa55 ; ブートセクタのマジックナンバー
バイナリに変換する際も、コメントはそのままで大丈夫でした。
-
コードの説明
-
[bits 16]
: 16ビットモードで動作することを指定します。 -
[org 0x7c00]
: プログラムをメモリ上の0x7c00番地に配置することを指定します。 -
start:
: プログラムの開始位置です。 -
mov ah, 0x0e
: ビデオサービス(テレタイプモード)を指定します。 -
mov bx, 0x0007
: 文字色を白に設定します。 -
mov bp, msg
: メッセージのアドレスをbp
レジスタに格納します。 -
.loop:
: 文字列の表示ループです。 -
mov al, [bp]
: 表示する文字をal
レジスタに取得します。 -
cmp al, 0
: 文字がnull(終端)かどうか判定します。 -
je .end
: nullの場合はループを終了します。 -
int 0x10
: ビデオサービス割り込みを実行します。 -
inc bp
: 次の文字へポインタを進めます。 -
jmp .loop
: ループの先頭へジャンプします。 -
.end:
: ループ終了位置です。 -
jmp $
: 無限ループです。 -
msg:
: 表示するメッセージを定義します。 -
times 510-($-$$) db 0
: 510バイト目まで0で埋めます。 -
dw 0xaa55
: ブートセクタのマジックナンバーです。
-
これで、OSの心臓部であるブートセクタの作成が完了。
ステップ3:バイナリ変換
作成した「boot.asm」を、コンピュータが理解できる言葉(機械語)に変換します。
-
バイナリ変換コマンドの実行
コマンドプロンプトまたはターミナルで、以下のコマンドを実行します。
nasm -f bin boot.asm -o boot.bin
-
コマンドの説明
nasm -f bin boot.asm -o boot.bin
:boot.asm
をバイナリファイル(boot.bin
)に変換します。
-
コマンドの説明
これで、OSを実行する準備が整いました。
ステップ4:Docker上で実行
いよいよ、作成したOSをDocker上で実行します!
-
Dockerコンテナの起動
コマンドプロンプトまたはターミナルで、以下のコマンドを実行します。
docker run -it -p 5900:5900 -v $(pwd):/root/os os-dev qemu-system-x86_64 -vnc :0 -fda boot.bin
実行結果
$ docker run -it -p 5900:5900 -v $(pwd):/root/os os-dev qemu-system-x86_64 -vnc :0 -fda boot.bin WARNING: Image format was not specified for 'boot.bin' and probing guessed raw. Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. Specify the 'raw' format explicitly to remove the restrictions.
WARNINGが出てますが、とりあえず大丈夫そうですね。
-
コマンドの説明
-
docker run -it -p 5900:5900 -v $(pwd):/root/os os-dev
: ステップ1で作成した「os-dev」イメージを使って、Dockerコンテナを起動します。-v $(pwd):/root/os
は、カレントディレクトリ(ここでは「my-os」フォルダ)を、Dockerコンテナ内の/root/os
にマウントします。-p 5900:5900
で、Dockerホストとコンテナ間でポートフォワーディングを設定します。 -
qemu-system-x86_64 -vnc :0 -fda boot.bin
: QEMUを使って、boot.bin
を実行します。-vnc :0
オプションでVNCサーバーを起動します。
-
-
コマンドの説明
-
VNCクライアントで接続
インストールしたVNCクライアントを起動し、 "127.0.0.1:5900" に接続します。
うまくいけば、VNCクライアント上の黒い画面に「Hello, World!」と表示されます。
ついに、、、OSが起動しました 🎉🎉
途中、何度かエラーがあったのですが、それも解決してもらいました。
さすがGemi兄さんですね!
まとめ
今回は、Geminiの協力を得て、簡易的なOSを起動してみました。
まだ文字列を表示させただけのものですが、これから徐々に、進化させて行こうと思います。
AIを活用することで、自分が未経験の分野にもチャレンジすることができます。
みなさんも一緒にがんばりましょう!