自作OSにファイルシステム・アプリローダを追加しました
システムコールと特権管理などを追加しました - へにゃぺんて@日々勉強のまとめ
こちらの記事の続きで、自作OS(仮称:OS5)の記事です。
自作OSについては、以下のページにこれまでの記事や成果物のまとめを載せています。
http://funlinux.org/os5/
今回は以下の機能を追加しました。
- メモリアロケータ
- ファイルシステム
- アプリケーションローダ
これらの機能追加により、シェルに
「シェル組み込みコマンドではない文字列を受け付けた時、
その文字列をファイル名とするファイルを開き(システムコール:open)、
実行する(システムコール:exec)」
という挙動を取らせることができるようになりました。
(上のGIFアニメでuptimeを実行することで、右上にシステム起動時間が表示されるようになりました。)
例によって、本日時点のソースコードを以下からダウンロードできます。
https://github.com/cupnes/os5/releases/tag/blog-20160208
(masterブランチにタグをつけてpushしたもの)
また、今回から自作OSを構成する
現在、それぞれのソースコード行数(アセンブラとCの行数の総和)は以下のとおりです。
ブートローダー | 253 行 |
カーネル | 1966 行 |
アプリケーション | 437 行 |
前回のブログ記事(2015/11/30)から今回の記事までの間の
コミット数は58件でした。
58件のコミットをざっくりと分けると、以下のとおりです。
なお、時系列の並びをなるべく崩さないようにしたかったので、
「メモリ管理」については「ページングに関する機能設定」と「メモリアロケータ追加」の2つのまとまりがあります。
ソースディレクトリ分離
細かな機能変更、バグfix
メモリ管理: ページングに関する機能設定
- 927ce50 2015-12-20 mem: グローバルページ機能を有効化
- bb018c1 2015-12-20 mem: カーネルページにグローバルページ設定を追加
- 3e8b196 2015-12-20 mem: VRAM領域以外すべてのページでキャッシュ有効化・ライトバック有効化
- a2b3585 2015-12-21 mem: PDE/PTEの構造体宣言をヘッダーファイルへ移動
- b8b2d62 2015-12-21 mem: uptime: PD/PTの初期化をタスクの初期化関数へ移動
- fab2ef0 2015-12-21 mem: shell: PD/PTの初期化をタスクの初期化関数へ移動
- faa5c3c 2015-12-29 mem: uptime: スタック領域のマッピングの間違いを修正
タスク管理: タスク初期化処理を汎用化
- 9905538 2015-12-26 task: task_init()を追加
- 6d32c41 2015-12-27 task: uptime: task_init()に対応
- 09c0f15 2015-12-29 task: shell: task_init()に対応
- 6df7ada 2015-12-29 task: 共通化により不要になった関数を削除
- 8c58f9f 2015-12-29 task: コンテキストスイッチ関数の先頭アドレス指定方法を修正
- 5cbfff3 2015-12-29 sched: uptime: コンテキストスイッチ関数をバイナリ値へ変更
- 7381d85 2015-12-29 sched: shell: コンテキストスイッチ関数をバイナリ値へ変更
- a73edae 2015-12-29 task: task構造体にtssを含めた
- bcfb754 2015-12-29 task: tssはtask構造体の中のメンバを使用するよう修正
- fa49c7c 2015-12-29 task: 未使用のtss定義を削除
- 2ae144d 2015-12-29 sched: context_switch関数をtask構造体に含めるよう修正
- 017a0f1 2015-12-29 未使用の変数・関数宣言を削除
- 988ed78 2015-12-29 未使用ファイル・includeを削除
- 9b1cece 2015-12-29 cpu: init_gdt()のDPL初期化箇所をタスク依存しないように修正
- 7fcb254 2015-12-29 task: task_init()にtask_idの初期化処理追加
- cb24d63 2015-12-30 sched: task_listをtask_instance_tableへ改名
- d38e790 2016-01-02 queue: カーネルに汎用キュー構造追加
- dcf4c65 2016-01-03 queue: キューダンプに各エントリのアドレスのダンプを追加
- d4c7212 2016-01-05 sched: task構造体の運用についてのコメントを追加
「タスク管理: タスク初期化処理を汎用化」から「ファイルシステム: ファイルシステム・システムコール追加」までが
「アプリケーションローダ」機能追加のための一連のコミットです。
ここでは、タスクの初期化と実行を行う汎用的な関数task_init()を追加し、
shellとuptimeの初期化にはこの関数を使用するよう修正しています。
なお、x86の「タスク管理機能」を使用しているので、カーネルに近い場所では「タスク」という表現をしていますが、
現状としては、「アプリ」・「タスク」に違いはありません。
また、task_init()という関数名の割りにはタスクの実行(ランキューへの追加)まで行っているので、
この箇所については、関数名と機能が一致していないですね。。。
メモリ管理: メモリアロケータ追加
- 5253ab4 2016-01-19 doc: memory_map: ヒープ領域を追加
- 8dd4cee 2016-01-19 mem: mem_alloc()、mem_free()を追加
- 7bffee3 2016-01-19 mem: ヒープ領域のPTE追加
- a716255 2016-01-24 task: task_init()をmem_alloc()に対応
- 06d0e0c 2016-01-24 doc: アプリのPD/PTを動的に確保するようにしたのでドキュメント修正
- 72079e2 2016-01-24 doc: メモリマップのVAのタスクスタック領域の説明を修正
ここでは、ヒープ領域の作成と、メモリアロケータの追加を行っています。
ヒープ領域は、現状、物理アドレスで
0x0009 5000 〜 0x0009 ffff
の(たった)44KBです。
なお、この空間はカーネル空間内であり、物理アドレス=仮想アドレスでマッピングしています。
また、現状のメモリアロケータmem_alloc()は、固定長4KBをヒープ領域から確保し、
確保した領域の先頭のアドレス(物理アドレスであり、仮想アドレスでもある)を返します。
ファイルシステム: ファイルシステム・システムコール追加
- 1dec9ca 2016-01-25 fs: ユーザーランドのファイルシステム作成用シェルスクリプト追加
- 4a11d61 2016-01-29 fs: コントロールブロック無し、ファイル数固定で作成
- df1fbfe 2016-01-31 apps: ユーザーランド自動ビルドされるよう修正
- 5bb54f4 2016-01-31 fs: コントロールブロック仮対応
- aab20ae 2016-01-31 doc: memory_map: 現状に合わせて修正
- 9d39ff1 2016-01-31 fs: fs_init追加
- b1ac2a8 2016-01-31 uptime: shell動作開始後にtask_init()で起動されても動作することを確認
- 79ada22 2016-02-01 syscall: openの追加と動作確認
- 56dbc6f 2016-02-01 fs: openの仕様変更後の動作確認版
- cb668f6 2016-02-01 syscall: open, execの動作確認版
- a03bd84 2016-02-01 デバッグ用出力を削除
- d7d2670 2016-02-04 shell: execシステムコール対応
ここでは、ファイルシステムと、ファイルを扱うための「open」と「exec」のシステムコールを追加しています。
「ファイルシステム」といっても、現状でファイルを定義しているバイナリ的ルールは以下の簡単なものです。
- ファイルサイズは固定長4KB
- ファイルの先頭32バイトがヘッダ、それ以降がデータ
- ヘッダの内容はファイル名のみ
- ファイルシステムとしては、「コントロールブロック(4KB)、ファイル、ファイル...」というバイナリの並び
- コントロールブロックに設定する内容は、現状は「ファイル数」のみ
追加したシステムコールについては以下のとおりです。
open | 引数でファイル名(文字列)を受け取り、struct fileのポインタを返す |
exec | 引数でstruct fileのポインタを受け取り、受け取ったファイルを実行ファイルとして実行する |
struct fileは、現状は以下のような簡単な定義です。
struct list { struct list *next; struct list *prev; }; struct file { struct list lst; char *name; void *data_base_addr; };
struct fileはファイルシステム上のファイルについて、
以下の2つのアドレスを管理しています。
- char *name: ファイル名の先頭アドレス
- void *data_base_addr: データの先頭アドレス
execでは、task_init()にstruct fileのdata_base_addrを渡すことで、
タスクの初期化と実行を行っています。
なお、LinuxではexecはGNU Cライブラリが提供するAPIですね。
「既存のものに合わせる」という気持ちで作っているわけではありませんが、
「システムコールの粒度がまちまち」なのはかねてからの問題点なので、
システムコールについては、いずれ設計し直そうかと考えています。
リリース前コード整理
- f575d38 2016-02-04 shell: デバッグ用の処理を削除
- 7a3956c 2016-02-06 fs,common: ソースコードを分割
- ac15351 2016-02-06 task: ソースコードを分割
- 276d588 2016-02-06 syscall: ソースコードを分割
- 1e4908d 2016-02-06 lock: ソースコードを分割
- 4ab7ceb 2016-02-06 init: mainからinitへリネーム
- c10998e 2016-02-06 Makefile: 余分な空行を削除
以前はリリース前に作業ブランチ内でコードを整えてからmasterブランチへマージしていたのですが、
最近は面倒さを感じてしまい、あまりツリーを整形せずにmasterへマージしてしまっています。。。
この記事の変更履歴
02/11 23時 | 実行している様子(GIFアニメ)追加、コミット一覧を分類分けし、コメントを追加 |