OSがあまりにわからなかったからとり
あえず自分でOSつくっちゃった話
動機
・もう6学期だし真面目に勉強しようと思った ・真面目に授業聞いてみたけどよくわからなかった ・Amazonみてたら「OS自作」という文字列を発見 ・話し聞いてもよくわからないしもはや自分で作っちゃえばいいんじゃない? ・駒場祭付近暇だしそこで、一気に作っちゃおう0 step 本選び
・OS自作についての本はいくつかあった
・リアルタイム性など、何かに特化したものを除くと有名なものは以下の2つ 候補1:「30日でできる!OS自作入門」 小林秀実著
0 step 本選び
候補1:「30日でできる!OS自作入門」 小林秀実著 プログラミングの基礎からはじめて、30日後にはウィンドウシス テムを有する32bitマルチタスクOSをフルスクラッチで作り上げ るという入門書。ビギナーでも無理なく作成できるようPCの仕組 み・アセンブラ・Cの解説から始まり、試行錯誤を繰り返しながら アルゴリズムを学びつつ、たのしく自由な雰囲気でOSをゼロか ら構築していくという、他に類を見ない手法による、趣味と実用 と学習を兼ね備えたOS作成の入門書。0 step 本選び
候補2:「12ステップで作る組み込みOS自作入門」 坂井弘亮 著 手軽に購入できるマイコンボード上で動作する独自の組込 みOSをフルスクラッチで自作する。ブートローダーも自作し ますので、電源ONの一番最初の動作からの理解/学習 が可能です。また内容は12ステップに分かれているため、 講義や輪講、実習などでの教材利用にも向いている0 step 本選び
・授業でやる内容に関して理解が深まるか ・駒場祭による休講、祝日(実質4日)で実装できるか ・難しすぎないか などを基準に選定 →「12ステップで作る組み込みOS自作入門」 に決定!
はじめに
組込みOSとは? →ある特定の機器に搭載して制御するためのOS →ここではマイコンボード上で動くOSを実装 このOSでなにができるか? →I/Oはシリアル通信だけ →PCからの文字入力に応答したり、文字を出力したりするはじめに
それだけの機能でOSといえるか? →OSの基本機能は資源管理 →スレッドによるCPU時間の管理の実装 →固定サイズのメモリ管理の実装 →シリアル通信でI/Oの管理の実装 →よってOSと言っても良いのではないかはじめに
このOSには実用性がないのではないか? →「使う」ではなく「作る」ことが目的
はじめに
マイコンボードH8/3069Fの組み込みOSを実装 ・PCとシリアルケーブルでつなぐ
・端末エミュレータでPCからマイコンを操作 ・PC側でマイコンの動作の様子を見る
開発の流れ
第1部 ブート・ローダーの作成 第2部 OSの作成 1st step 開発環境の作成 7th step 割込み処理を実装する 2nd step シリアル通信 8th step スレッドを実装する 3rd step 静的変数の読み書き 9th step 優先度スケジューリング 4th step シリアル経由でファイルを転送する 10th step OSのメモリ管理 5th step ELFフォーマットの展開 11th step タスク間通信を実装する 6th step もう一度、Hello World 12th step 外部割込みを実装する1st step 開発環境の構築
H8/3069Fネット対応マイコンLANボード(完成品) 通販コード K-01271 発売日 2006/01/23 1台 ¥3,750(税込) →秋月電子通商で購入可1st step 開発環境の構築
やること
・開発のための環境構築
1st step 開発環境の構築
割込みベクタによって実行開始するアドレスを定義 →スタートアップのstartという関数から始まるように定義 スタートアップをアセンブラで実装 →startという関数はスタックポインタの設定を行ったあとmain()を呼び出す メイン関数ではputs()という関数で「Hello World!」という文字列を出力 ライブラリ関数として1文字送信関数putc()とそれを複数回用いた文字列送信関数puts() を実装1st step 開発環境の構築
その他 ・ライブラリ関数のヘッダファイル ・シリアル・デバイス・ドライバ ・メモリをあつかうリンカスクリプト なども実装した。1st step 開発環境の構築
2nd step シリアル通信
やること
・必要なC言語の標準ライブラリの関数の実装 ・数字を表示する関数の実装
2nd step シリアル通信
memset() : メモリを特定の倍てデータで埋める memcpy() : メモリのコピー memcmp() : メモリの比較 strlen() : 文字列の長さ strcpy() : 文字列のコピー strcmp() : 文字列の比較 strncpy() : 長さ指定での文字列の比較 などのおなじみのライブラリ関数を実装2nd step シリアル通信
putxval() : 整数値を16進数で出力するライブラリ関数を実装
当然、それに伴って
2nd step シリアル通信
3rd step 静的変数の読み書き
やること
3rd step 静的変数の読み書き
メモリをあつかうリンカスクリプトを修正 →いままでROMだけを扱っていたがRAMも扱えるようにメモリ領域を定義 →各セクションをどこに配置するか定義 →静的関数が配置されるdataセクション、bssセクションはRAMとROMの両方に配置さ れるように定義 →スタックの定義の追加3rd step 静的変数の読み書き
4th step シリアル経由でファイルを転送する
やること
4th step シリアル経由でファイルを転送する
XMODEMとは
4th step シリアル経由でファイルを転送する
XMODEMのプロトコルに従ってXMODEMを実装 ファイルの受信処理の開始などをコマンドで操作できるようにmain関数がコマンド入力を 受け付けるように変更 →”load”で受信処理開始 →”dump”でメモリを16進で出力 →それ以外の入力には”unknown”とかえす4th step シリアル経由でファイルを転送する
リンカスクリプトで受信バッファのための領域を定義 デバイスドライバにデータ受信のための関数を追加
コンソールでの1文字受信関数getc(),文字列受信関数gets()をライブラリに追加 →マイコンボードの動作が確認できるようにエコーバックも実装している
4th step シリアル経由でファイルを転送する
5th step ELFフォーマットの展開
やること
・OSを起動させるための「実行形式ファイル」を転送する ・それを解析して、メモリ上に展開できるようにする
5th step ELFフォーマットの展開
5th step ELFフォーマットの展開
6th step もう一度、Hello World
やること
6th step もう一度、Hello World
ブートローダー側
5th step で表示できるようにした部分をmemcpy()によって実際に動作させるメモリ上に コピー
6th step もう一度、Hello World
OS側 基本的にはここまで書いてきたコードが使える コンソールからの入力を受付け、echo,exitコマンドに対して処理を行うようなmain関数を 実装 OSようにリンカスクリプトのメモリ定義を書き直す6th step もう一度、Hello World
7th step 割込み処理を実装する
やること
7th step 割込み処理を実装する
ブートローダー側 割込み処理の前と後におこなう処理(メモリの退避、復帰など)をアセンブラで実装 割込みベクタを変更し割込みが起こった時に実行すべきアドレスを指定 その他 ・割込みベクタ関連の定義や初期化などを実装7th step 割込み処理を実装する
OS側
シリアル受信割込みを受け付けるように、シリアルデバイスドライバに割込み機能を追加 main関数を割込みによって動作するように変更
7th step 割込み処理を実装する
8th step スレッドを実装する
やること
・スレッド動作を実装する
8th step スレッドを実装する
ブートローダー側 リンカスクリプトの書き換え →スタックを用途別に明示的に分離 それに伴い、割込み処理やスタートアップで用途にあったスタックを使うように変更 ブートローダー側はこれで完成!8th step スレッドを実装する
OS側 リンカスクリプトの書き換え(同様) スレッドのディスパッチ処理を追加 スレッドの生成、終了、システムコールの呼び出しを行う関数などを実装 リンクリスト構造でスレッドを管理8th step スレッドを実装する
9th step 優先度スケジューリング
やること
・スレッドに優先度を導入する ・システム・コールを追加する
9th step 優先度スケジューリング
優先度を追加 レディ−キューの配列を優先順位の高い順に検索し、動作可能なスレッドを探す →優先順位の高い方から実行 スレッドの切り替えを行う関数や、スレッドをスリープ状態にする/起こす関数、優先度を変 更する関数、スレッドIDを取得する関数を実装9th step 優先度スケジューリング
10th step OSのメモリ管理
やること
10th step OSのメモリ管理
あらかじめ16バイト×8個、32バイト×8個、64バイト×4個の領域を用意する それらをリンクリストでつなぐ
メモリが要求されたら収まる最小サイズの領域をリンクリストから切り離して与える 開放されたらまたリンクリストに繋ぎ直す
10th step OSのメモリ管理
11th step タスク間通信を実装する
やること
11th step タスク間通信を実装する
11th step タスク間通信を実装する
12th step 外部割込みを実装する
やること
・1文字受信割込みを受け付ける「割込み処理」を実装する ・コマンド応答スレッドを作成する
12th step 外部割込みを実装する
やること
割込みハンドラからシステムコールを呼び出せるようにトラップ命令を発行せずにシステ ムコールの処理を関数呼び出しするサービス関数を実装