自作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

  • 847f5db 2015-12-01 syscall: システムコール割り込みでもpusha/popaと同等のコンテキスト退避/復帰追加
  • 03bdad2 2015-12-12 timer: global_counterを10ミリ秒単位から1ミリ秒単位のカウントへ変更
  • c4d76ea 2015-12-15 kernel: sched: タイマ要因外のscheduleでもタイムスライスを保証するよう修正

メモリ管理: ページングに関する機能設定

  • 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をヒープ領域から確保し、
確保した領域の先頭のアドレス(物理アドレスであり、仮想アドレスでもある)を返します。

ファイルシステム: ファイルシステムシステムコール追加

ここでは、ファイルシステムと、ファイルを扱うための「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ですね。
「既存のものに合わせる」という気持ちで作っているわけではありませんが、
システムコールの粒度がまちまち」なのはかねてからの問題点なので、
システムコールについては、いずれ設計し直そうかと考えています。

リリース前コード整理

以前はリリース前に作業ブランチ内でコードを整えてからmasterブランチへマージしていたのですが、
最近は面倒さを感じてしまい、あまりツリーを整形せずにmasterへマージしてしまっています。。。

この記事の変更履歴

02/11 23時 実行している様子(GIFアニメ)追加、コミット一覧を分類分けし、コメントを追加