「30日でできる!OS自作入門」という本に沿ってOSを作った.
とりあえずキリのいいところまで作ったのでまとめておく.
本書の内容をそのまま載せるのはアレなので自分なりに改造した点,追加で実装した点のみをまとめる.
まず一点目に,本書はOSとしてFDイメージ(フロッピーディスクイメージ)を作成しているが,FDが無くて実機での動作確認が出来ないため,CD/DVDに書き込めるディスクイメージ (isoファイル) を作成するように改造した.
二点目に,本書で実装しているコマンド (ls や cat )に加えて moreコマンドを実装した.
isoファイル作成
isoファイルは,EI-Torito という規格に従って作成する.これはISO 9660を拡張した規格らしい.
今回作成したisoファイルの中身は以下のようになっている.
FDをエミュレートするように設定したため,20セクタ目以降は本書のFDイメージの内容をそのまま書き込んでいる.
ちなみに,1セクタ = 0x800 [byte] = 2048 [byte] である.
EI-Toritoという規格では,
- Primary Volume Descriptor
- Boot Record
の2つの Volume Descriptor をイメージファイルに書き込んでおく必要がある.
When preparing to mount a CD, your first action will be reading the volume descriptors (specifically, you will be looking for the Primary Volume Descriptor).
https://wiki.osdev.org/ISO_9660#Volume_Descriptors
Volume Descriptor というのはCDのマウント時に読まれるもので,ISO 9660では16セクタ目にあるPrimary Volume Descriptor を最初に探すようだ.
Volume Descriptorのフォーマットを以下に示す.
最初の0バイト目はタイプコードというもので,以下の表のように定義されている.
1〜5バイト目は常に’CD001’という文字列と決まっている.
6バイト目は Volume Descriptor のバージョンのようだが,これも0x01で決まっている.
7バイト目以降は Volume Descriptor それぞれで異なる.
Primary Volume Descriptor はフィールドの数が多いので説明は省略する.
Boot Record で書き込むべきフィールドと,それに対応したアセンブラのソースコード(言語はNASK)を以下に示す.
; Boot Record Volume Descriptor DB 0 ; ボリューム記述子タイプ:0 DB "CD001" ; 文字列"CD001" DB 1 ; このディスクリプターのVersion 必ず1 DB "EL TORITO SPECIFICATION"; 文字列"EL TORITO SPECIFICATION" RESB 0x8827-$ ; 残りは0で埋める RESB 0x8847-$ ; 予約:0 DB 0x012 ; Boot catalogのセクタ RESB 0x9000-$ ; 予約:0
6バイト目までは先ほど説明した通りである.
7〜38バイト目はブートシステムの識別子で,”EL TORITO SPECIFICATION”という文字列を書き込む.余った部分は0で埋めておく.
DB命令 (Data Byte) は1バイト分データを書き込む命令だが,文字列を渡すと自動的に1文字(1バイト)ずつ全て書き込んでくれる.
RESB命令は指定した数だけ0を書き込む命令である.本プログラムでは目的の番地と現在の番地の引き算によりその数を算出している.
39〜70バイト目はブートの識別子とあるが,0で埋める.
71〜74バイト目は Boot Catalog のアドレスをセクタ番号で書き込んでおく(以下参照).
今回は72バイト目以降を0で埋めているため 12 00 00 00 と書き込まれ,Boot Catalog が 18 (0x00000012) セクタ目にあることを示している.
It records at bytes 71 to 74 as little-endian 32-bit number the block address of the El Torito Boot Catalog. This catalog lists the available boot images, which serve as starting points of booting systems.
https://wiki.osdev.org/ISO_9660#The_Boot_Record
Boot Catalog ではエミュレーションの設定やブートイメージの番地指定など重要な設定を書き込む.
Boot Catalogで書き込むべきフィールドとそれに対応したアセンブラのソースコードを示す.
; Boot catalog DB 1 ; ヘッダID:1 DB 0 ; 0:80x86, 1:powerPC, 2:Mac RESB 0x9004-$ ; 予約:0 RESB 0x901c-$ ; DB 0xaa, 0x55 ; チェックサム DB 0x55 ; シグネチャ:0x55 DB 0xaa ; シグネチャ:0xaa DB 0x88 ; 0x88:Bootable, 0x00:Not Bootable DB 0x02 ; エミュレーション DB 0x00, 0x00 ; 読み込み先セグメント DB 0x00 ; ? DB 0x00 ; 予約:0 DB 0x01, 0x00 ; 読み込みセクタ数 DB 0x20, 0x00, 0x00, 0x00 ; ブートセクタの読み込み元セクタ:0x10000byte目 RESB 0x9800-$ ; 予約:0 RESB 0x10000-$ ; ブートセクタの記述まで0で埋める
Boot Media Typeで0x02を書き込むことにより,1.44Mのフロッピーディスク(容量は本書に合わせた)をエミュレートするように設定している.
また,Boot Load RBAで 20 00 00 00 と書き込むことでブートセクタ(OS本体の先頭部分)が 20 (0x00000020) セクタ目にあることを示している.
以上がisoファイルを作成するにあたって追加した部分である.
Primary Volume Descriptor に関しては,よければ参考サイトとGithubを参照してほしい.
本書で作成されたFDイメージ(OS本体)はそのまま流用していて,20セクタ目以降に書き込んでいるため,本書と同じOSがCD/DVDよりブートできる.
moreコマンド実装
isoファイルを作成できるようにしてからは,本書をそのまま読み進めて様々なOSの機能を実装していった.
大まかには,
- 割り込み処理
- FIFO (キー入力等のデータ受け取りに使う)
- メモリ管理
- マウス,キーボード制御
- ウインドウ管理
- タイマ
- タスク管理
- コンソール
である.
基本的にはC言語で実装しているが,アセンブラに頼らざるを得ない部分もあった.
本書ではコンソール実装時に,mem(使用,空きメモリ容量表示),ls,cat,clear コマンドを叩けるようにしている.
これらに加えて more コマンドを追加したので処理の流れを簡単に説明する.
more コマンドはファイルを一画面単位で閲覧するコマンドで,cat コマンドを改良することで実装した.Enterキーを押すことでファイルを一行ずつ読み進める.
コマンド実行中はキー入力を受け付ける必要があるため,割り込み処理やFIFOの機能を使っている.
cat コマンド (比較用) と more コマンドの簡易なフローチャートを以下に示す.
more コマンドは,cat コマンドの処理に加え,一画面分出力のための行数カウント用の変数と改行フラグを用意して,if文とEnter入力待ち(while文)を付け足したものとなっている.
こうすることで
- ファイルの内容を一画面分出力する
- Enterキー押下まで待つ
- Enterキーが押下されると一行出力して 2 に戻る
のループができる.ファイルの内容を全て出力したらループから抜ける.
moreコマンド実行結果の図を示す.
OSはVirtualBox上で実行している.
OS内にはharibote.sysファイルとxv6のREADMEファイルを入れてある.
実行画面(1)が > more README を叩く前の画面で,(2)が叩いた直後の画面,(3)はEnterキーを押下して少し進めた画面である.
画面が見にくいがうまく実行できた.
今後はとりあえず本書を最後まで読み進めて,ファイルシステムをもう少し理解してからcpコマンドやmvコマンドを実装したい.
参考にしたサイト
[1] Bootable CDの作り方
[2] ブータブル CD や DVD