\begin{flushright}
{\small
\begin{minipage}
コナン・ドイル 「青い紅玉」 } \end{flushright}
B-Free OS は、ユーザからはシングルユーザ・マルチタスクの OS として見え ます。
B-Free が起動すると、画面がクリアされ、{\em root ウィンドウが表示され ます}。
\begin{figure}
この状態で、ユーザはroot ウィンドウ上に表示されている仮身を操作するこ とができます。
ここでは、B-Free のファイルシステムについて説明します。
最初にシステムをインストールした時点では、B-Free システムのファイルシ ステムは、図 \ref{fig:bfree-filesystem} のようになっています。
\begin{figure}
この図のなかで、ユーザが直接見ることができるファイルは、網箱で囲んだ部 分だけです。
root ファイルシステムは、中心核や各種マネージャなどのシステムで 使用する実身を含んでいます。
\begin{lablist} \labitem {SYSTEM} この実身には {\em KERNEL} という実身がひとつあ るだけです。{\em KERNEL}という実身は、中心核の実行実身がそのまま入っ ています。
\labitem {MANAGER} この実身には、システムで使用する各種マネージャ(周 辺核および外核が含まれています。
\labitem {\$\$PROGRAM.BOX} この実身には、アプリケーション群へのリン クが含まれています。
\labitem {\$\$RELATION.BOX} この実身には、続柄の情報が入ります。
\labitem {\$\$小物入れ} この実身には、小物(アクセサリー的なアプリケ ーション群へのリンクが入ります。
\labitem {USR} ユーザ自身が使用する実身が含まれています。立ち上げ直 後、ディスプレイに表示されるウィンドウは、この {\em USR}実身の内容で す。 \end{lablist}
B-Free OS は、シングルユーザ向けの OS です。 しかし、多くのBTRONマシンがつながったネットワークを構築したような場合、 ネットワーク全体では複数のユーザが資源(実身・プリンタなど)を共有するこ とができます。 そのため、ユーザごとに特有の情報を記録する必要があります。
B-Free OS では、ユーザ情報として以下の情報を管理します。
\begin{description}
\item
特権レベルでは、レベル 0 が最も高い特権をもち、すべての実身を読み書き できます。レベル 0 のユーザに対して、実身を読み書きできないような指定 はできません。 \end{description}
\chapter{B-Free OS の構造} \label{cha:structure}
\begin{flushright}
{\small
\begin{minipage}
小松左京 「虚無回廊」 } \end{flushright}
OS は、一枚岩的 な構造をもつものが多数作られてきました。 一枚岩的な OS は、その名のとおり OS がひとつの巨大なプログラムとなって います。
すなわちコンピュータは、2つの動作モード --- カーネルモードとユーザモー ドをもち、カーネルモードで走るプログラムこそが OS という考えがその根底 にあります。
ユーザモードで走るプログラムは、あくまでもユーザが作成したプログラムで あり、OS 的な機能はありません。
一枚岩的な OS の代表は、UN*X です (図 \ref{fig:unix-structure})。
\begin{figure}
UNIX の世界では、一枚岩的な OS --- カーネルと呼びます、とユーザプログ ラムという2種類のプログラムしかありません \footnote{デーモンと呼ばれる 特殊なプログラムもありますが、これもまたユーザプログラムの一つです。}
一枚岩的な構造をもつカーネルの場合、カーネルを変更するには大変な努力が 必要となります。 それは、ある小さな変更をするだけでも他の(関係のなさそうな)部分に影響が及 ぶ可能性があるからです。
一枚岩的な構造をもつオペレーティングシステムは今でも主流です。しかし、 一枚岩的な構造には、保守性や拡張性に問題があることが徐々に分かってきま した。そのため新しく生まれた考えかたがマイクロカーネルという考えです。
マイクロカーネルという考えでは、ハードウェアに密着した部分などを小さな モジュール(マイクロカーネル)にまとめます。そして、一枚岩的なオペレーテ ィングではカーネルがやっていたほとんどの仕事をマイクロカーネルの外へ追い 出します。
マイクロカーネルの代表は Machオペレーテイングシステムです。 正確にいうと、Mach オペレーティングシステムは、マイクロカーネルアーキ テクチャをとるシステムで使用するためのマイクロカーネルにすぎません。 OS としてユーザプログラムを動かすためには、Mach の上に載る複数のプログ ラムが必要となります。
現在のところ、Mach の上にのるプログラム(Machではサーバと呼んでいます) は、UN*Xのインタフェースをもつ UN*Xサーバや MS-D*Sのインタフェースを もつサーバなどがあります。 また、最近では GNU プロジェクトでもMachを基にした Hurd という OS の作 成を行っています。
\begin{figure}
一枚岩的な OS とマイクロカーネルを比較してどちらが良いということは一言 では言えません。
さて、問題は B-Free OS でどちらのアーキテクチャを採用するかということで す。
B-Free OS を製作する目的(OS のソースを公開し、簡単に変更などをできるよ うにする)を考えると、見とおしがよい構造というのが重要になってきます。 そう考えると、一枚岩的な OS の利点はほとんど性能面においてであり、ソー スの変更や改良などを簡単に行うのは困難です。 逆にマイクロカーネル方式の OS では、よほどうまく作らないと、性能面では 一枚岩的な OS よりも劣ります。しかし、中の構造はひとつひとつの要素が分 かれており、それぞれの変更が他に与える影響が少ない分だけ見とおしがよい といえそうです。
これらのことから、B-Free OS の目的(ユーザが自由にソースを見て、OSを変 更できる)を考えると、マイクロカーネル方式を採用するのが適当だと思われ ます。
B-Free での OS の構造は、マイクロカーネル構造をとります。
OS の中心となる核として、\ITRON を採用します。 この \ITRON は、\microITRON 3.0 を基にしたものです。
\begin{figure}
B-Free OS は、次の構成要素から成り立っています。
\begin{lablist} \labitem {中心核(いわゆるマイクロカーネル)} \microITRON 3.0 に準拠した \ITRON OS です。CPU のカーネルモードで動 きます。 % \labitem {LOWLIB} アプリケーションプログラムに対してシステムコールインタフェースを提供 するための層です。
厳密にはライブラリではないため、LOWLIB (低レベルライブラリ)という名 前になっています。
LOWLIB は、システムコールインタフェースを提供する他にユーザプロセス
の初期化や各周辺核との通信なども行います。
%
\labitem {周辺核}
BTRON
OS としての API を提供します。中心核の提供するシステムコールを
使用するタスク群です。ファイル管理やプロセス管理などの機能を提供しま
す。また周辺核にあるデバイスマネージャは、デバイスドライバへのアクセ
スする手段を提供します。
周辺核に含まれる機能は次のとおりです (カッコの中はその機能を実現する マネージャの名前です)。
\begin{description}
\item
また、マネージャとは別に MMU を操作するような機能は中心核に含まれ
ています。中心核の提供する仮想記憶管理は、ある程度統一化されていま
す。
%
\item
次のようなデバイスドライバは、最低必要となります。
\begin{itemize}
\item ディスプレイ・デバイスドライバ
\item キーボード・デバイスドライバ
\item ポインティグ・デバイスドライバ
\item FD/HD デバイスドライバ
\end{itemize}
%
\labitem {外核/殻}
補助的なサービス --- かな漢字変換や仮身・実身操作など、を提供するプ
ロセス群です。
%
\labitem {ライブラリ}
アプリケーションに対して、BTRON
API を提供します。実際の処理は、外
核や周辺核と協調し、データをやりとりすることによって行います。
%
\labitem {アプリケーション}
ユーザが使用するプログラムです。
実身の内容を表示するデータランドエディタ、テキスト実身の内容を編集す
る基本文書エディタ、そして図形実身の内容を編集する基本図形エディタな
どがあります。
\end{lablist}
\chapter{中心核} \label{cha:core}
\begin{flushright}
{\small
\begin{minipage}
ドナルド・モフィット 「第二創世記」 } \end{flushright}
\vspace{1cm}
B-Free OS で最もマシン寄りの部分、それが中心核です。 中心核は、それ自体\ITRON 仕様の OS となっています。 中心核と上位の層とのインタフェースは、\ITRON システムコールとして決め られたインタフェースを使用しています(一部拡張してあります)。そのため、 異なったCPU上に B-Free OS を移植する場合でも、変更は中心核のみに留め、 上位層の変更は最小限にすることができるようになっています。
この章では、中心核の機能と構造について説明します。
中心核は、\microITRON 3.0 の基本仕様(一部拡張仕様も含む)準拠のカーネル です。
中心核は、周辺核、外核そしてアプリケーションなどの上位層に対して次の機 能を提供します。
\begin{quote} \begin{itemize} \item タスク管理 \item 同期・通信機能(IPC) \item メモリプール管理機能 \item 割り込み管理機能 \item 例外管理機能 \item 時間管理機能 \item システム管理機能 \end{itemize} \end{quote}
この他に \microITRON 3.0 では規定されていない次の機能も提供します。
\begin{quote} \begin{itemize} \item 仮想メモリ管理機能 \end{itemize} \end{quote}
中心核は、基本的な OS の機能を上位層に与えます。 なお、上位層は中心核に対してシステムコールを発行することによって、 中心核の機能を使用します。しかし、中心核より上位の層(周辺核、外核も含 む)は、すべてメッセージの送受信により要求の送受信を行います。システム コール( = CPU でのトラップ)を介して呼び出されるというのは中心核だけで す。
中心核では、次のシステムコールをサポートします (* 印は現在未サポート)。
\vspace{1cm}
\topcaption{中心核でサポートするシステムコール} \tablehead{ \hline \multicolumn{3}{l}{\small 前ページより続く} \\ \hline \multicolumn{1}{c}{分類} & \multicolumn{1}{|c}{システムコール名} & \multicolumn{1}{|c}{機能} \\ \hline\hline } \tablefirsthead{ \hline \multicolumn{1}{c}{分類} & \multicolumn{1}{|c}{システムコール名} & \multicolumn{1}{|c}{機能} \\ \hline\hline } \tabletail { \hline \multicolumn{3}{r}{\small 次ページへ続く} \\ \hline } \tablelasttail {\hline} % \begin{center} \begin{supertabular}{l@{\hspace{1cm}} | p{3cm}@{\hspace{1cm}} | p{7cm}} タスク管理関係 & cre_tsk & \\ & del_tsk & \\ & sta_tsk & \\ & ext_tsk & \\ & exd_tsk & \\ & ter_tsk & \\ & dis_dsp & \\ & ena_dsp & \\ & chg_pri & \\ & rot_rdq & \\ & rel_wai & \\ & get_tid & \\ & ref_tsk & \\ \hline タスク附属同期機能 & sus_tsk & \\ & rsm_tsk & \\ & frsm_tsk & \\ & slp_tsk & \\ & \* tslp_tsk & \\ & wup_tsk & \\ & can_wup & \\ \hline 同期・通信機能 & cre_sem & \\ & del_sem & \\ & sig_sem & \\ & wai_sem & \\ & preq_sem & \\ & twai_sem & \\ & ref_sem & \\ & cre_flg & \\ & del_flg & \\ & set_flg & \\ & clr_flg & \\ & wai_flg & \\ & pol_flg & \\ & twai_flg & \\ & ref_flg & \\ & cre_mbf & \\ & del_mbf & \\ & snd_mbf & \\ & psnd_mbf & \\ & tsnd_mbf & \\ & rcv_mbf & \\ & prcv_mbf & \\ & trcv_mbf & \\ \hline 割込み管理機能 & dis_int & \\ & ena_int & \\ \hline メモリプール管理機能 & cre_mpl & \\ & del_mpl & \\ & get_blk & \\ & pget_blk & \\ & rel_blk & \\ & ref_mpl & \\ & tget_blk & \\ \hline 時間管理機能 & \*set_tim & \\ \hline システム管理機能 & get_ver & \\ \hline \end{supertabular} \end{center}
\vspace{1cm}
ユーザアプリケーションが、BTRON
の機能を使用する場合、次のような順
序で処理を行います(図 \ref{fig:syscall-route})。
\begin{figure}
\begin{enumerate} \item ユーザプログラムは、中心核に対してメッセージを送信するシステム コールを発行して、周辺核へメッセージを送る。 % \item 周辺核は、送られてきたメッセージを受けとり、メッセージに書かれ た要求を実行する。 % \item 周辺核は要求を処理すると、結果をメッセージの形にして中心核 を介してアプリケーションへ送る。 % \item ユーザアプリケーションは、返答メッセージを受けとる。 (システムコールの終了) \end{enumerate}
なお、中心核を呼び出す処理というのは、ライブラリが行うので、アプリケー ションが中心核を意識することはありません。 ファイルの読み書きなどの処理は、周辺核のファイル管理マネージャが、メッ セージを受けとることによって処理します。
また、中心核では、\microITRON 3.0 で新たに拡張された接続機能に ついては、サポートしません。異なったホスト間での通信機能については、中 心核よりも更に上位の層でサポートします。 μITRON3.0の接続機能を使用しない理由は次のとおりです。
\begin{itemize} \item μITRON 3.0 での通信機能は組み込み機械で CPU が複数ある場合を 想定している。 \item 基本的に CPU がひとつだけ入っており、他のマシンとは比較的大域 の広いインタフェース (Ethernet など)が使えるパソコンとは相性が悪い。 \end{itemize}
つまり、μITRON 3.0 での接続機能は、パーソナルコンピュータでの通信のよ うな用途には向かないのではないかということです。
中心核の構成を図 \ref{fig:nucleas-structure} に示します。
\begin{figure}
\begin{lablist} \labitem{タスク管理部分} タスク管理では、\ITRON の意味でのタスクを管理します。タスクは実行 単位としてのプログラムを意味しています。 タスク管理部分では、タスクの生成/削除/実行などの操作の他に、タスク 同士で同期や通信などを行う機能も含んでいます。 % \labitem{メモリ管理部分} メモリ管理部分では、物理メモリの管理を行います。物理メモリは基本的 にページ単位 (80386 で 4K バイト) で管理を行います。しかし、メモリ 管理部分が提供するインタフェースでは、バイト単位での物理メモリの取 得/解放ができるようになっています。 % \labitem{割込み/例外管理部分} 割込み管理では、外部割込みおよびトラップ (例外、内部割込み)の割り込みテ ーブルへの登録を行います。また、実際に割り込みが起った場合の各関数 への処理の割り振りも行います。 % \labitem{時間管理部分} 一定時間ごとの指定された関数の実行をする機能を提供します。 % \labitem{システム管理部分} バージョン番号などを管理します。 % \labitem {仮想メモリ管理部分} CPU のもつ仮想メモリの管理機構をそのまま提供します。 更に抽象的な仮想メモリの管理については、周辺核のメモリマネージャが 行います。
この仮想メモリの管理は、μITRON 3.0 では規定していないため、B-Free 独自の仕様を定めます。 \end{lablist}
タスク管理部分は、次のモジュールからできています。
\begin{table}
各タスクには、構造体 {\tt t_tcb} の形式のデータがひとつ割り当てられます。
{\tt t_tcb} は次の情報を記録します。
\begin{quote} \begin{itemize} \item タスクリストのためのリンクリスト \item タスク ID \item タスクの状態 \item タスクのプライオリティ(優先順位) \item タスク属性 \item タスクが待ち状態のときに使用する情報 \item タスク間通信で使用する情報 \item スタック情報 \item コンテキスト情報 (80386) \item 仮想記憶のために使用する情報 \end{itemize} \end{quote}
現在動いているタスクは、{\tt run_tsk} というポインタ変数が指し示して います。
タスク ID は MIN_TASKID から MAX_TASKID までの範囲を占める整数値 (32 ビット) です。 MIN_TASKID と MAX_TASKID は、{\tt src/kernel/itron-3.0/h/config.h}で 定義しています。
デフォルトでは、次の値となります。
\vspace{5mm}
\begin{boxedminipage}
中心核のシステムコールでは、対象となるタスクを指定するためにタスク ID を使います。
タスクのプライオリティ(優先順位)は、32 ビットの整数で表現します。 この値の範囲は、マクロ MIN_PRIORITY(プライオリティの最小値) から MAX_PRIORITY(プライオリティ値の最大値) となります。
プライオリティは、値の小さい方が優先度が高くなります。そのため、 MIN_PRIORITTY が一番高くなります。
MIN_PRIORITY / MAX_PRIORITY は、 {\tt src/kernel/itron-3.0/h/config.h} で定義しています。デフォルトの値 は次のとおりです。
\vspace{5mm}
\begin{center}
\begin{boxedminipage}
タスクのレディキューの配列は、各エントリがひとつのプライオリティに対応 しています。そのため、プリオリティ値の範囲がレディキューの配列のエント リ数となります。
記述言語の指定を行います。μ ITRON 3.0 では、TA_ASM (アセンブラ) と TA_HLNG (高級言語) の 2 つの状態をもちますが、B-Free の中心核では 記述言語による区別はしていないので、TA_HLNG だけが使用できます。
タスクは、表 \ref{tab:task-status} 示した値のどれかの状態になります。
\begin{table}
タスク状態は、図 \ref{fig:task-life} に示す状態遷移図のように変化しま す。
\begin{figure}
タスクは、以下の原因によって待ち状態となります。
\begin{itemize} \item システムコールによる待ち状態。 \item タスク間同期・通信機能による待ち状態 \item 資源取得時の待ち状態 \end{itemize}
タスクの待ち状態は、表 \ref{tab:wait-status} のマクロによって表現します。
\begin{table}
タスク間通信を行うための情報を表 \ref{tab:タスク間通信のための情報} に 示すものがあります。
\begin{table}
カーネルモードで動作するときのスタック領域を指すポインタ変数です。
スタックの領域は、関数 \verb+make_task_stack()+ が作成します。 スタックのサイズは、1 ページ \footnote{80386 の場合、4K バイトです} です。
コンテキスト情報は、CPU に依存したタスクの情報です。 コンテキストスイッチが発生した時点でのレジスタの値が入ります。
コンテキスト情報は、T_I386_CONTEXT \footnote{src/kernel/itron-3.0/i386/i386.h で定義} という型で定義しています(80386 の場合)。
\begin{boxedminipage}
コンテキスト情報構造体 (T_I386_CONTEXT)
typedef struct { UW backlink; UW esp0; UW ss0; UW esp1; UW ss1; UW esp2; UW ss2;
UW cr3; UW eip; UW eflags; UW eax; UW ecx; UW edx; UW ebx; UW esp; UW ebp; UW esi; UW edi; UW es; UW cs; UW ss; UW ds; UW fs; UW gs; UW ldtr; UH t:1; UH zero:15; UH iobitmap; } T_I386_CONTEXT;
\end{verbatim} \end{boxedminipage}
コンテキストスイッチは、{\tt task_switch()} と {\tt resume()} が行い ます。
{\tt task_switch()}\footnote{ common/task.c の中で宣言しています。} は、レディタスクリストの中で、一番優先順位の高い タスクをカレントタスクにします。 実際のタスク切り換えは、{\tt resume()} によっておこないます。 そのため、この関数の中での処理は、{\tt run_tsk} 変数とレディタスクリ ストの更新だけとうことになります。
{\tt task_switch()}は、引数 {\tt save_nowtask} をもちます。 この {\tt save_nowtask} が TRUE のとき現タスクをレディタスクリスト に保存します。FALSE の時は、ready タスクキューから削除します。
レディタスクリストから削除しない場合、他のタスクのプライオリティが下が ると、コンテキストスイッチを行ったタスクは、再び実行されることになります。
逆にレディタスクリストから削除した場合、他のタスクがレディリストに追加 しない限り元のタスクが実行されることはありません。 レディタスクリストから削除するのは、タスクが待ち状態に入ったときに行い ます。
{\tt resume()} \footnote{ i386/locore.s 内で宣言しています。}は、CPU のコンテキストスイッチ機 能を使って、コンテキストスイッチを行います。
具体的には、引数で渡されたセレクタが指しているプロセスの TSS にジャン プします。
{\tt resume()} のソースは、高々 20 ステップしかないので、実際のリスト を次に示します。 タスクスイッチは、{\tt .byte 0xff, .byte 0x28} と書いた部分で行ってい ます。これは、アセンブラに「TSS にジャンプする」という動作に対応するニ モニックが定義されていないためです。
\begin{quote}
\begin{boxedminipage}
タスク管理部分では、実行可能なタスクのリストをもっています。 このリストは、{\tt common/task.c} の中で宣言しています。
\vspace{5mm}
\begin{minipage}
このレディキューを操作するために以下の関数を定義しています。 これらの関数は、引数として
\begin{itemize} \item 操作するリスト \item 追加/挿入/削除するエントリ情報 \end{itemize}
の2つをもらい、修正したリストを返り値として返します。
\subsubsection*{init_task}
TCB テーブルの内容を初期化します。 そして、カレントタスクをタスク番号 (-1) のタスクとします。
\subsubsection*{add_tcb_list}
引数 list で指定されたリストの一番最後にタスクを追加します。
\subsubsection*{ins_tcb_list}
引数 list で指定されたリストの一番最初にタスクを挿入します
\subsubsection*{del_tcb_list}
引数 list で指定されたリストから、要素 del を削除します。
メモリ管理部分では、主に 2 つの形態の\underline{物理}メモリを管理します。
\begin{itemize} \item ページ (4Kバイト) 単位での管理 \item バイト単位での管理 \end{itemize}
さらに、μITRON 3.0 で定義している可変長メモリプールに関するシステムコー ルのためのモジュールがあります。
ページ単位でのメモリ管理は、ファイル {\tt common/pmemory.c} にある関数 で管理します。
物理メモリページは、{\tt memory_map
各エントリは、次に示す値のどれかになります。
\begin{quote}
\begin{tabular}
\subsubsection*{pmem_init()}
配列 {\tt memory_map} の内容を初期化します。
\subsubsection*{palloc()}
サイズで指定したページ数分の連続した物理メモリ(ページ) をアロケートし ます。
配列{\tt memory_map} のエントリのうちアロケートする物理ページに対応す るものの値を {\tt MEM_USE} に変更します。
\subsubsection*{pfree()}
{\tt palloc()} でアロケートした物理メモリ(ページ)をフリー状態にします。
配列{\tt memory_map} の解放する物理ページに対応するエントリの値を {\tt MEM_FREE} に変更します。
ITRON では、バイト単位のメモリのアロケート/フリーを行うためのシステム コールを定義しています。
バイト単位のメモリ管理を行うための関数は、{\tt common/itron_memory.c} で定義しています。
\begin{table}
バイト単位のメモリ管理を行うために、フリーなメモリ領域をリストで管理し ています。 各フリーメモリ領域は、構造体 {\tt kmem_entry} で管理します。この構造体は、 {\tt freelist} という変数につながったリストとなります。
メモリをアロケートする時は、この {\tt freelist} を辿り、取得したいサイ ズをもつフリーメモリ領域を割り当てます。 フリーリストにアロケートできるようなサイズをもつフリー領域がない場合に は、{\tt getcore()} によって新しいフリーメモリを取り出します。このとき、 {\tt getcore()} は、ページ単位のメモリのアロケートを行う {\tt palloc()} を呼び出します。
μITRON 3.0 ではメモリ管理機能として固定長メモリプールと可変長メモリプー ルの2種類を定義しています。 中心核でサポートしているのは、このうちの可変長メモリプールに関するシス テムコールです。
可変長メモリプールの管理は、{\tt common/itron_memory.c} にある関数に よって行います。
\begin{table}
各可変長メモリプールは、構造体 {\tt memory_pool} によって管理します。 構造体 {\tt memory_pool} には、次の情報を記録します。
\begin{itemize} \item メモリプールの ID \item サイズ \item メモリブロック取得待ちのタスクのリスト \item このメモリプールが管理しているフリー領域のリスト \end{itemize}
メモリプールは、{\tt memory_pool_table
各メモリプールに属しているフリー領域は、構造体 {\tt free_mem_entry} をエントリとなるリストで管理しています。
メモリプールを生成するとき、メモリプールの管理するメモリのサイズを指定 します。 {\tt cre_mpl()} では、先に説明したバイト単位のメモリ管理を行う関数 ({\tt kalloc()}) を使ってメモリを取得します。
中心核では、タスク間の同期・通信機能として次の機能を提供しています。
\begin{itemize} \item セマフォ \item イベントフラグ \item メッセージバッファ \end{itemize}
この章では、それぞれの機能の実装内容について説明します。
セマフォは、2つ以上のタスク間で同期を取ったり、同時にアクセスすることがで きないデータを保護するための機能です。
そのために、次の機能が必要になります。
\begin{itemize} \item すでにセマフォがロックされていた場合、セマフォが解放されるまでタ スクを待たせる機能。 \item セマフォが解放されたとき、セマフォ待ちの状態にあるタスクを実行さ せる機能。 \end{itemize}
セマフォ待ちのタスクを管理するために、待ち状態にあるタスクのリストを管 理しています。
セマフォ機能は、次の関数が処理します\footnote{ すべて {\tt src/kernel/itron-3.0/common/semaphore.c} の中で定義。}。
\vspace{5mm}
\begin{tabular}
ひとつひとつのセマフォは、構造体 {\tt semaphore_t} で管理しています。
\vspace{5mm}
\begin{boxedminipage}
配列 \verb+semaphore_table
ハードウェア割り込み(外部割り込み)の処理は、{\tt i386/fault.c} の中にある {\tt interrupt()} で行います。
割り込みが発生すると、{\tt interrupt()} は次の処理を行います。
\begin{itemize} \item 大域変数 {\tt on_interrup} の値を TRUE に変更。 \item 大域変数 {\tt delayed_disatch} の値を FALSE に変更。 \item 各割り込み別に定義してある関数へ分岐。 \item {\tt delayed_dispatch} が TRUE に変更されていたら、 {\tt task_switch()} を実行。このとき、現走行タスクはレディキューから削 除しない。 \end{itemize}
{\tt interrupt()} が処理する割り込みは、表 \ref{tab:interrupt-proclist} のとおりです。
\begin{table}
トラップの処理は、\verb+trap()+ で行いますが、この関数は今のところ何も していません。
トラップの一種であるシステムコールは、{\tt int64_handler} \footnote {{\tt src/kernel/itron-3.0/i386/interrupt.s}で定義。} と {\tt syscall()} \footnote{{\tt src/kernel/itron-3.0/common/syscall.c} で定義。}で処理します。
例外は、次の要因で発生する CPU のエラーです。
\begin{itemize} \item 0 割り例外 \item プロテクトフォールト \item ページフォールト \item 不法 TSS 例外 \end{itemize}
それぞれの例外が発生した時の対応は表 \ref{tab:except-process} に示すと おりです。
\begin{table}
インテル i386 プロセッサには、ページ単位での仮想記憶を管理する機能があ ります。
B-Free での仮想記憶管理をモデル化したものを 図 \ref{fig:model} に示し ます。
\begin{figure}
仮想記憶は、リージョン (Region) という単位で管理します。 この場合の管理情報は、仮想領域のアドレス、物理メモリのマップ情報、そし て、読み書きの許可を表す permission のことです。
1つのタスクには1つ以上のリージョンを結びつけることができます。 たとえば、BTRON レベルでのユーザプロセス(の中のタスク)は、プログラムの 実行部分(コード部分)が入るテキスト・リージョン、読み書きするためのデー タが入るデータ・リージョン(実際には、データ・リージョンは、恐らく実行 前に値が決まっている変数が入るリージョンと、実行前には領域だけが決まっ ているリージョンそして、ヒープのために使われるリージョンの3つのリージ ョンに分かれます)、そしてスタック領域を表すスタック・リージョンと いう複数の Region と結びついています。
タスクが複数のリージョンを所有するのは、次のような利点があります。
\begin{enumerate} \item リージョンごとに permission が指定できる。そのことによって、テキス トは実行するだけで読み書きできないなどの指定ができる。すべてひとつ のリージョンにしてしまうと、permission は最少公倍数的なものになって しまうだろう(つまり、読み/書き/実行のすべてを許可した状態になってし まう)。
\item リージョンを仮想空間の中で離して置くことによって、リージョンの大き さを広げることができる。成長するリージョンにはヒープ、スタックなど があります。 \end{enumerate}
逆に、複数タスクが1つのリージョンを所有することもできます。この場合、複数のタ スクから所有されるリージョンは、共有メモリとなります(図 \ref{fig:share})。
\begin{figure}
B-Free OS では、デフォルトでデータを共有することはしません。しかし、プ ログラムの実行部分についてはデフォルトで共有します。これは、プログラム の実行部分は大抵の場合変更しないため、共有しても他のプロセスに影響をお よぼすことがないからです。 プログラムの実行部分を変更するような場合、リージョンを共有しないように システムに要求する必要があります。もし、共有しているプログラムの実行部 分を変更しようとした場合、メモリの保護違反となりプログラムは、強制終了 します。
複数のリージョンが、仮想空間の中で重なりあうことはできません。
リージョンは、一言でいうと任意のタスクの仮想空間の一部の領域です。
リージョンを管理するための情報には、次の種類があります。
\begin{description}
\item
リージョンが管理する仮想空間は次の3つのパラメータで表します。
\begin{itemize} \item リージョンの開始仮想アドレス \item 最少サイズ \item 最大サイズ \item 大きさが変わらないリージョンの場合には、最少サイズ、最大サイズは 同じ値となります。 \end{itemize}
\item
仮想メモリ中のページの読み書きの許可状態を表ります。
\begin{itemize} \item 実行可/実行不可 \item 書き込み可/書き込み不可 \item 読み込み可/読み込み不可 \end{itemize}
\item
リージョンの中のページのうちどれが物理メモリとマッピングしているか、 マッピングしていた場合には物理メモリ(ページ)番号を記憶します。
\item
タスクは、リージョンの情報を直接操作することはできません。 そのためリージョンの内容を変更する場合、中心核(ITRON)のシステムコール を実行する必要があります。
中心核のもつリージョン操作関数を表 \ref{tab:function-list} に示します。 もともと ITRON では、仮想記憶操作については定義していません。 そのため、リージョン操作システムールは ITRON で規定している独自システ ムコールとしてシステムコール名の最初に 'v' がつきます。
\begin{table}
これらのシステムコールは、リージョンの情報をアクセスするだけで CPU の メモリ管理機能には影響を与えないものもあります。
ユーザプログラムが物理メモリにマップしていない仮想ページにアクセスした 場合、ページフォールトが発生します。
ページフォールトが発生した場合、中心核は次の処理を行います。
\begin{itemize} \item ユーザのページフォルトハンドラを呼び出す。 \end{itemize}
\chapter{LOWLIB} \label{cha:lowlib}
%\begin{flushright}
% {\small
% \begin{minipage}
\vspace{2cm} LOWLIB (低レベルライブラリ) は、ユーザプログラムに対してシステムコール インタフェースを提供するための層です。
\begin{figure}
LOWLIB は、次の示す働きをします。
\begin{itemize} \item アプリケーションの動作環境の初期化。 \item システムコールをアプリケーションに提供。 \item マネージャ群との通信を行う。 \end{itemize}
LOWLIB は、BTRON/POSIX という環境毎に、別々にもつことになります。 そのために、LOWLIB をマッピングするための中心核のシステムコールがあり ます。
\begin{table}
中心核がサポートするタスク生成の機能だけでは、 アプリケーションプログラムを動作させることはできません。
LOWLIB は、中心核のタスク生成の機能ではサポートしていない アプリケーションプログラムが動作するための環境を初期化します。
具体的には、次の処理を行います。
\begin{itemize} \item ユーザモードで動くためのスタック領域を確保します。 \item システムコール用のトラップハンドラを登録します。 \item コードおよびデータ用の領域を仮想空間上に確保します。 \end{itemize}
これらの処理を行った後に、ユーザプログラムのエントリアドレスへジャンプ します。 このとき、カーネルモードからユーザモードへの遷移を行います。
結局のところアプリケーションにとっての環境というのは、システムコールの 機能によって決定されます。
LOWLIB は、アプリケーションプログラムにシステムコールを提供することに よって、アプリケーションの動作環境を提供します。
システムコールの処理を行うために、LOWLIB 層にシステムコールのエントリ テーブルをもっています。
また、システムコールの実行に必要な情報についても LOWLIB は各プロセス毎 にもっています。
システムコールの実行は次のように行います。
\begin{enumerate} \item ユーザプログラムがシステムコールを呼び出す(CPU のトラップ命令を 実行)。 \item LOWLIB のトラップハンドラを実行。 \item LOWLIB は、システムコール番号からシステムコール関数を選択、実行 する。 \item システムコールの実行後、ユーザプログラムへ戻る。 \end{enumerate}
BTRON 環境での LOWLIB は、次のようなソース構成になっています。
\begin{table}
これらの他にライブラリとして、{\tt src/kernlib/libkernel.a} をリンクし ます。
BTRON 環境用の LOWLIB は、{\tt lowlib_start()} という関数から実行をは じめます。
{\tt lowlib_start()}は、BTRON プロセスを動作させるために必要な、次の 初期化処理を行います。
\begin{itemize} \item ユーザプロセス用の Region を生成。
ユーザプロセスはデフォルトで、次の Region をもちます。
\begin{itemize} \item コード用 region (読み込みと実行のみ可能) \item データ用 region (読み込みと書き込みのみ可能) \item ヒープ用 region (読み込みと書き込みのみ可能:この region は大 きさが変化する) \item スタック用 region (読み込みと書き込みのみ可能) \end{itemize}
\item スタック領域の確保(物理メモリ)。 \item 非同期動作用のタスクを生成(メインに動作するタスクは、親プロセス が生成します)。実行します。 \item プロセス情報をプロセスマネージャに登録します。 \item システムコール用のトラップハンドラをプロセス毎に存在するトラップ ベクタに登録します。 \item ユーザプログラムのエントリルーチンへジャンプします。 \end{itemize}
システムコールのエントリルーチンは、次の3つの引数をもちます。
\begin{description}
\item
エントリルーチンの動作は、次のようになります。
\vspace{1cm}
\begin{boxedminipage}
entry(int sysno, void *uargp, int *errnop) { <システムコール番号のチェック>
<システムコール番号で指定しているシステムコール関数を呼び出す>
<システムコール関数は、配列 syscalls
<システムコールの実行結果を *errnop に入れる>
<return> } \end{verbatim} \end{boxedminipage}
\chapter{周辺核} \label{cha:server}
周辺核は、中心核 (ITRON)を使って、B-Free OS の中でも重要な機能 --- BTRON API を提供します。
周辺核で提供する機能には、次の種類があります。
\begin{description}
\item
B-Free OS では、次のような複数のファイル形式を使用することができます。
\begin{itemize}
\item BTRON FD ファイルシステム
\item {\it B-Free Standard File System}
\item {\tt MS-DOS ファイルシステム}
\end{itemize}
%
\item
周辺核、すなわち B-Free OS での BTRON API を処理する部分は、決して巨大 なプログラムではありません。
周辺核は、図 \ref{fig:server-struct} に見るように単機能なプログラムの 集まりです。
\begin{figure}
周辺核と上位層(外核とアプリケーション)は、中心核の IPC 機能によって通信し ます。
周辺核を構成する要素を次のリストに示します。
\begin{description}
\item
B-Free では、ファイル形式を複数取り扱うことができるので、ファイル管
理サーバでは、各ファイル形式ごとにあるファイル管理プログラムを統合し
ます。
%
\item
デバイスには各々名前が付いています。デバイス管理サーバでは、デバイス 名とデバイスドライバの持つ通信用のポートを結びつけます。 \end{description}
メモリマネージャは、仮想メモリを操作するためのマネージャです。
B-Free/OS では、仮想メモリベースの OS です。つまり、B-Free/OS は、ペー ジ単位での仮想メモリを扱うことができます。
--- B-Free/OS での仮想記憶とはどういうものなのか。
\vspace{5mm}
仮想記憶機能とは、物理メモリに依存しない仮想的なメモリを扱う機能のこと をいいます。
物理メモリのみを使用する実記憶ベースの OS の場合、実メモリのサイズを越え てメモリを使用することはできません。
例えば、実メモリが 4M バイトの大きさをもつシステムの場合、5M のメモリ を消費するアプリケーションを動かすことはできません。
仮想記憶の機能をもつ OS の場合、仮想記憶機能を使うことによって物理メモ リのサイズを越えた記憶容量をもつことができます。 仮想記憶では、物理メモリのサイズを越えた分の記憶領域を2次記憶装置にも つことにより、アプリケーションに対して物理メモリのサイズを越えたメモリ をもっているように見せます(図 \ref{fig:virtual-memory})。
\begin{figure}
仮想記憶の機能を実現するために、メモリマネージャは次の処理を行います。
\begin{quote} \begin{lablist} \labitem{ページイン処理} {二次記憶に追い出した情報を物理メモリに戻 します。このとき、物理メモリが空いていない時には、物理メモリに空 き領域を作ります。ページイン処理は、アプリケーションが物理メモリ にないページのアドレスをアクセスしたときに発生するページフォール トを契機にして実行します。}
\labitem{ページアウト処理} {物理メモリにマッピングしているが、使用 していないページの内容を二次記憶装置に追い出します。}
\labitem{仮想記憶ページ情報の管理} {仮想記憶ページの情報を管理しま す。管理する情報は次のとおりです。
\begin{itemize} \item 仮想記憶ページが物理メモリにマッピングされている場合、物理 メモリのアドレスを記憶します。 \item 仮想記憶ページが二次記憶装置にページアウトされているときに は、二次記憶装置のどこにページアウトしたかという情報を管理しま す。 \end{itemize} } \end{lablist} \end{quote}
メモリマネージャが受け付けることのできるメッセージは、次のものがありま す。
\begin{table}
\chapter{デバイス管理} \label{cha:device}
\begin{center}
\begin{minipage}
この章では、B-Free/OS で使用するデバイスドライバについての説明とデバ イスドライバ自体を管理するためのマネージャであるデバイスドライバマネーッ ジャについての説明を行います。
デバイスドライバマネージャは、BTRON 環境だけではなく、POSIX 環境でも 使用する環境に依存しないマネージャです。 } \end{minipage} \end{center}
デバイスドライバというのは、ハードウェアデバイス (FD や HD などのスト レージデバイスやキーボード、ディスプレイなどの入出力装置など) を管理す るためのソフトウェアです。
B-Free では、デバイスドライバは、個々のデバイスを管理するためのデバイ スドライバと、それらのデバイスドライバを管理するデバイスマネージャとい う2つの構成要素から成り立っています。
\begin{figure}
B-Free の個々のデバイスドライバは、固有の論理デバイス名をもっています。 論理デバイス名は、アプリケーションがデバイスを指定するときに使用します。
論理デバイス名は、3つの要素からなりたっています。
\begin{description}
\item
\item
\item
HD のパーティションなどがサブユニットにあたります。 \end{description}
論理デバイス名の例を 図 \ref{fig:device-name} に示します。
\begin{figure}
デバイスマネージャは、デバイスドライバの管理を行います。 デバイスマネージャは、ITRON レベルでのタスクとして動作します。
表 \ref{tab:device-manager-request} に示すリクエストを受け付けます。
\begin{table}
{\it dev_define ()} は、デバイスドライバの情報をデバイスドライバマネー ジャに登録します。
登録する情報は次のとおりです:
\begin{itemize} \item (ユニット名/サブユニット名を除いた)デバイスドライバの名前 \item ユニット名の最大値 \item サブユニット名の最大値 \item 要求受けつけ用のメッセージバッファ ID \item 次に示すデバイスドライバ属性 \begin{itemize} \item ドライバのタイプ (ブロック or キャラクタ) \item ドライバに使用するバッファサイズ \item 排他的使用となるか非排他的使用(複数のプロセス間で共有可)となるか \end{itemize} \end{itemize}
これらの情報は、デバイスドライバマネージャが内部に持っているデバイスド ライバの管理テーブルに記録します。
{\it dev_remove ()} は、デバイスドライバマネージャの中に記録してある デバイスドライバの情報のうち、指定したものを削除します。
削除するデバイスドライバの指定は、名前で行います。
{\it dev_find ()} は、デバイスドライバの検索を行います。
具体的には、デバイスドライバを使用するために要求を送るメッセージバッファ ID を調べるために使用します。
検索に使用するキーは、デバイスドライバの名前です。
デバイス名の中にユニット名/サブユニット名が含まれていた場合、 デバイスの種類のみを取り出して、デバイスドライバ登録テーブルを検索しま す。
たとえば、デバイスドライバ名として次の名称:
\begin{center}
\begin{minipage}
を指定した場合、ユニット名/サブユニット名を除いた次の名称に変換して検 索します。
\begin{center}
\begin{minipage}
デバイスマネージャ自身は、デバイスドライバの登録しか行いませんが、 BTRON OS 環境 あるいは POSIX OS 環境のサーバによって、動的にデバイスド ライバをロード/登録することも可能です。その場合、各 OS 環境の API によっ てファイルシステムからデバイスドライバをロードしタスクとして動作できる ようにしてから、デバイスドライバマネージャに登録するということになりま す。
指定したファイルからデバイスドライバを読み取り、メモリ上にロードします。
{\tt dev_load} によってファイルから読み込んだデバイスドライバをメモリ 上から削除します。
当然ですが、この処理を実行したあとはデバイスドライバは使用できません。
デバイスドライバが受信し、処理するパケットの種類は表 \ref{tab:driver-packet} のとおりです。
\begin{table}
B-Free では、デバイスドライバもひとつのタスクとして動作しています。
デバイスドライバの概略をリストにすると次のようになります。
\vspace{1cm} \tablehead{ \hline \multicolumn{1}{l}{\small 前ページより続く} \\ \hline } \tablefirsthead{ \hline } \tabletail { \hline \multicolumn{1}{r}{\small 次ページへ続く} \\ \hline } \tablelasttail {\hline}
\begin{supertabular}{| @{\hspace{1cm}} p{13cm} |} \verb|driver_main ()| \\ \verb|{| \\ \verb| < ドライバの初期化 >| \\ \verb| ・割り込みハンドラの登録。| \\ \verb| ・インタフェース LSI の初期化| \\ \verb| ・ドライバで使用するテーブル類の初期化| \\ \verb| ・要求受信用のメッセージバッファをドライバマネージャに登録| \\ \verb|| \\ \verb| /* 要求受けつけループの実行 */| \\ \verb| for (;;)| \\ \verb| {| \\ \verb| <要求パケットの受信>| \\ \verb| switch (パケットタイプ)| \\ \verb| {| \\ \verb| case DeviceInit: <デバイスドライバの初期化>| \\ \verb| case DeviceExit: <デバイスドライバの終了>| \\ \verb| case DeviceOpen: <デバイスのオープン処理>| \\ \verb| case DeviceClose: <デバイスのクローズ処理>| \\ \verb| case DeviceRead: <デバイスの read 処理>| \\ \verb| case DeviceWrite: <デバイスの write 処理>| \\ \verb| case DeviceControl:<デバイスの Control 処理>| \\ \verb| case DeviceProbe: <デバイスのプローヴ処理>| \\ \verb| }| \\ \verb|}| \\ \end{supertabular} \vspace{1cm}
デバイスドライバが共有する資源としては、DMA \footnote{Direct Memory Access}や割り込みなどがあります。
この章では、これらの資源をアクセスするための関数について説明します。
なお、これらの関数は、libkernel.a に入っています。
PC9801 では、DMA の制御用として μPD8237A (DMAコントローラ) を使用しています。
この LSI では、4 つの DMA 用のポートがありますが、ひとつは PC9801 のアー キテクチャ上の問題(メモリリフレッシュ用に使用)でデバイスドライバ用とし ては使用できないため、使えるのは 3 つということになります。
PC9801 では、3つのDMAをそれぞれ次のデバイスに割り当ててあります。
\begin{table}
これら以外にも、デバイス自体に DMA コントローラを塔載しているものがあ ります(SCSI ボードなど)。
B-Free では、DMA の制御を行うための次の関数を用意してあります。
dma_setup は、DMA を使用するための前準備を行います。 具体的には、DMA コントローラに以下のパラメータを設定します。
\begin{itemize} \item モード設定 \item チャネルマスク値設定 \item 転送アドレス設定 \item バンク番号指定 \item 転送カウント設定 \end{itemize}
dma_setup を実行すると、DMA コントローラは DMA 要求を受けつける状態に なります。その状態で、周辺デバイス ( FD ドライブならば FDD コントロー ラ ) が転送要求を DMA コントローラに送ると DMA 転送が発生します。
dma_setup は、次のようにして呼び出します。
{\bf dma_setup (void *addr, W mode, W length, W mask)}
\begin{quote}
\begin{description}
\item
{\tt dma_setup()} を実行すると DMA コントローラによる DMA 転送の準備 が行われます。 この後で、DMA コントローラに転送開始のイベントが上がることによって DMA 転送が行われます。 このイベントは、通常各制御 LSI (例えば FDD の場合には μPD765) が、 送ります。
PC9801 の場合、周辺機器のために表 \ref{tab:interrupt-table} に示すような割り込みエントリが用意してあります。
\begin{table}
割り込みを使用するためには、中心核のシステムコールを使って割り込みハン ドラを登録する必要があります。 割り込みハンドラを登録するための中心核のシステムコールは、 {\bf def_int ()} です。
\begin{center}
\begin{boxedminipage}
\begin{quote}
\begin{description}
\item
HD ドライバは、PC9801 版の B-Free では、SASI 版と SCSI 版 の3種類があります。
\chapter{外核} \label{cha:manager}
\chapter{ユーザインタフェース}
ユーザインタフェースについて説明する章。 (ウィンドウや仮身実身など)
\chapter{POSIXインタフェース} \label{cha:posix}
\begin{flushright}
{\small
\begin{minipage}
Don Libes \& Sandy Ressler 「Life with UNIX」} \end{flushright}
\vspace{5mm}
\begin{quote} {\small B-Free /OS の基本構造がマイクロカーネルアプローチを取っていることから、 ユーザからみたシステム環境は、複数個もたせることが可能です。
ユーザからみたシステムインタフェースのうち、メインとなっているのは、 これまで説明してきた BTRON/OS です。
BTRON とは別のシステム環境が B-Free にはひとつあります。 それが、この章で説明する POSIX インタフェースです。 } \end{quote}
POSIX \footnote{Portable Operating System Interface for Computer Environments} は、IEEE \footnote{電気電子技術者協会} が規定したオペレーティングシス テムのインタフェースです。
基本的には、これまでの UN*X と呼ばれてきた OS の最大公約数といえます。
B-Free の POSIX 環境には、以下の API があります。
\begin{multicols}{4} \begin{verbatim} access chdir chmod chown close closedir creat dup dup2 execl execle execlp execv execve execvp _exit fcntl fork fseek fstat getcwd getegid getenv geteuid getgid getgrgid getgrnam getgroups getlogin getpgrp getpid getppid getuid kill link lseek mkdir mkfifo open opendir pause pipe read readdir remove rename rewind rewinddir rmdir setgid setpgid setsid setuid sigaction sigaddset sigdelset sigemptyset sigfillset sigismember siglongjmp sigpending sigprocmask sigsetjmp sitsuspend sleep stat time times ttyname tzset umask uname unlink utime watipid write mount umount \end{verbatim} \end{multicols}
\par
POSIX 環境は、BTRON 環境と同様に POSIX マネージャ と LOWLIB そしてユー ザプログラムからできています。
この章の残りは次の構成になっています。
\begin{itemize} \item POSIX マネージャについての説明 \item POSIX システムコールをサポートした POSIX 用 LOWLIB の説明。 \item POSIX プログラム(ユーザプログラム) の構成およびライブラリについての説明。 \end{itemize}
POSIX の OS 環境では、次の 4 つの POSIX マネージャが動きます \footnote{ここでいうマネージャとは、BTRON 環境での周辺核のことです。}。
\vspace{5pt}
\begin{tabular}
\begin{figure}
ファイルマネージャが受け付けるパケットの種類を 表 \ref{tab:file-packet}に示します。
\vspace{5mm} \tablehead{ \hline \multicolumn{2}{l}{\footnotesize 前ページより続く} \\ \hline \multicolumn{1}{c}{種類} & \multicolumn{1}{c}{処理} \\ \hline\hline } \tablefirsthead{ \hline \multicolumn{1}{c}{種類} & \multicolumn{1}{c}{処理} \\ \hline\hline } \tabletail { \hline \multicolumn{2}{r}{\footnotesize 次ページへ続く} \\ \hline } \tablelasttail {\hline} \topcaption{ファイルマネージャが処理するパケットの種類} \par \begin{supertabular}{l @{\hspace{1cm}} p{8cm}} \label{tab:file-packet} FILE_NULL & 何もしない \\ FILE_TRAVERSE & パス名を辿る \\ FILE_CLOSE & ファイルをクローズする \\ FILE_SELECT & デバイスの select \\ FILE_READ & ファイルの読み取り \\ FILE_WRITE & ファイルの書き込み \\ FILE_TRANC & ファイルのサイズを変更 \\ FILE_GETATTR & ファイル属性を得る \\ FILE_SETATTR & ファイル属性を設定 \\ FILE_ACCESS & ファイルのアクセス権をチェック \\ FILE_LINK & ファイルのハードリンク \\ FILE_MKDIR & ディレクトリを作成 \\ FILE_RMDIR & ディレクトリを削除 \\ FILE_MKSPEC & スペシャルファイルの作成 \\ FILE_RMSPEC & スペシャルファイルの削除 \\ FILE_CONTROL & ファイルの制御 \\ FILE_MOVE & ファイルの移動(名前の変更) \\ FILE_MOUNT & ファイルシステムをマウントする \\ FILE_UNMOUNT & ファイルシステムをアンマウントする \\ \end{supertabular} \vspace{1cm}
要求の受けつけは、次の {\tt get_request()}\footnote{ libkernel.a で定義している関数です。 } によって行います。
受信した要求メッセージは、まず {\tt doit()} 関数に渡されます。
{\tt doit()} 関数は、次の処理を行います。
\begin{description}
\item
そのとき、分解したメッセージの内容を引数として関数に渡します。 \end{description}
ファイルを使用する時には、open システムコールによってパス名を指定し、 該当するファイルをオープンします。
パスを辿る処理は次のように行います。
\vspace{1cm} \tablehead{ \hline \multicolumn{1}{l}{\small 前ページより続く} \\ \hline } \tablefirsthead{ \hline } \tabletail { \hline \multicolumn{1}{r}{\small 次ページへ続く} \\ \hline } \tablelasttail {\hline}
\begin{supertabular}{| @{\hspace{1cm}} p{13cm} |} \verb|| \\ \verb| /*| \\ \verb| * パス名の辿り ...... 引数 path で指定したパスを順々に辿って いく。| \\ \verb| * 最後の要素まで辿ったら、その要素に対応 する| \\ \verb| * ポートを返す。| \\ \verb| */| \\ \verb| ID| \\ \verb| traverse(char *path)| \\ \verb| {| \\ \verb| ID tmp;| \\ \verb| char 残りのパス名;| \\ \verb| char 現在の要素;| \\ \verb| | \\ \verb| if (パス名が絶対パス)| \\ \verb| tmp = rootdir;| \\ \verb| else| \\ \verb| tmp = カレントプロセスのカレントディレクトリ;| \\ \verb|| \\ \verb| 残りのパス名 = path;| \\ \verb| | \\ \verb| while (<のこりのパス名が NULL ではない>)| \\ \verb| {| \\ \verb| 現在の要素 = <残りのパス名から先頭要素をひとつ取り出す >;| \\ \verb| <残りの要素は残りのパス名に入れる>;| \\ \verb|| \\ \verb| tmp = FS_LOOKUP (tmp, 現在の要素); /* パス名をひとつだけ 辿る */| \\ \verb|| \\ \verb| < 必要ならばエラー処理を行う >| \\ \verb|| \\ \verb| }| \\ \verb| return (tmp); /* 最後まで辿った */| \\ \verb| }| \\ \verb| | \\ \end{supertabular} \vspace{1cm}
ファイルマネージャ自体は、物理媒体 (HD/FD など) に対するアクセスは行い ません。 物理媒体をアクセスするのは、サブファイルシステムというモジュールによっ て行います。
サブファイルシステムは、ファイルシステムのタイプごとに存在しています。 POSIX 環境では、次のサブファイルシステムがあります。
\begin{description}
\item
各サブファイルシステムは、ファイルマネージャと同じ実行モジュールにリン クしています。 そのため、サブファイルシステムの処理を行うタスクは、ファイルシステムマ ネージャと同じタスクとなります (ファイルシステムマネージャから見ると、 サブファイルシステムを処理するのは単なる関数となります)。
ただし、サブファイルシステムとファイルマネージャとは、表 \ref{tab:sub-filesystem-if}示すインタフェースでのみやりとりを行います。 表 \ref{tab:sub-filesystem-if} に示したのはマクロ\footnote{ src/posix/usr/include/server/file.h に定義。} ですが、サブファイルシステムは、このマクロに対応する関数インタフェース をもちます。
\begin{table}
サブファイルシステムインタフェースは、ファイルマネージャのインタフェー ス (表 \ref{tab:file-packet}) と同等のインタフェースをもちます。
MS-DOS ファイルシステムは、POSIX 環境でのサブファイルシステムのひとつ です。
基本的には、MS-DOS の FAT ファイルシステムと同一ですが、次の点が拡張さ れています。
\begin{itemize} \item 長いファイル名 (最大 256 文字) のサポート \item シンボリックリンクのサポート \item スペシャルファイルのシミュレート機能のサポート \end{itemize}
これらの拡張機能は、MS-DOS ファイルシステム自体は変更しない形で拡張し ています。そのため、従来の MS-DOS システムから読み書き可能となっていま す。
\paragraph{拡張方法}
FAT ファイルシステムの拡張方法は、DOS との共有を行えるようにすることか ら、もとの FAT ファイルシステムの管理情報はそのまま使用する方式をとり ます。
拡張部分については、変換テーブルの入ったファイルを使用することにします (このファイルも通常の FAT ファイルです)。
変換テーブルのファイルは、各ディレクトリにひとつだけ存在することとしま す。ファイル名は、POSIX.TBL となります。
変換テーブルは次の情報が入ります。
\begin{itemize} \item MS-DOS のファイル名(POSIX ファイルマネージャが自動的に生成します) \item POSIX 環境から見えるファイル名 \item 属性情報(ファイルのパーミッション/ファイルの種類など) \end{itemize}
具体的には変換テーブルの内容は次のようになります。
\vspace{5mm}
\begin{minipage}
POSIX プロセスマネージャは、POSIX 環境上で動いているプロセス(以下 POSIX プロセスと略記) を管理します。
各 POSIX プロセスは、プロセスマネージャ内では 構造体 {\tt process} で表現されます。この構造体は POSIX プロセスマネージャ内で のみ使用するものです \footnote{ \tt src/posix/usr/src/sys/server/PM/pm.h で定義}。
\vspace{5mm}
\begin{boxedminipage}
struct process { struct process *prev; struct process *next;
enum proc_status status; /* プロセスの状態を示す */ pid_t pid; /* プロセス ID */
uid_t uid; /* プロセスが属する所有者 */ gid_t gid; /* プロセスが属するグループ */
ID main_task; /* ユーザプログラムのコードを実行するタスク */ ID signal_task; /* シグナルの受信処理を行うタスク */ ID fifo_task; /* パイプを使うときに使用するタスク */ ID alarm_task; /* alarm システムコール用のタスク */
ID efile; /* 実行ファイルを指しているメッセージポート * コード部のページインのときに使用する。 */ };
\end{verbatim} \end{boxedminipage} \vspace{5mm}
つまるところ、POSIX プロセスマネージャはこの構造体情報を管理するのが仕 事となります。
POSIX 環境でのプロセスマネージャは、アプリケーションに対して次の機能を 提供します。
\begin{itemize} \item 新しいプロセスの生成 \item プロセスの終了処理 \item プロセススケジューリング \item プログラムの実行 (exec) \item シグナルの処理 \item インターバルタイマ \end{itemize}
POSIX 環境上で新しいプロセスを生成するのは、{\tt fork} システムコール です。
アプリケーションが {\tt fork} システムコールを実行すると、次の処理を行 います。
\begin{quote}
\begin{description}
\item
\begin{enumerate} \item 中心核に対して、新しいタスクを生成するシステムコールを発行 ({\tt cre_tsk})。
デフォルトでは、1つのプロセスごとに以下のタスクを生成します (表 \ref{tab:posix-process-task} も参照のこと)。
\begin{itemize} \item 主タスク \item シグナル \item alarm 用タスク \end{itemize}
これら以外のタスクについては、必要なときに LOWLIB が生成する。
\item 新しく生成したタスクの仮想空間に LOWLIB (自分自身) を複製しま す。以後の処理は、複製した LOWLIB が行います。
\item 新しいタスクに対して {\tt fork} システムコールを発行した Region の内容を複製する ({\tt vdup_reg})。
複製は、以下の Region に対して行う。
\begin{itemize} \item コード領域 \item データ領域 \item スタック領域 \end{itemize}
\item 新しいタスクの実行ポイントを {\tt fork} の子プロセス実行エント リポイントへセット。
子プロセスは次に CPU の使用権が渡ってくるときに、この処理で設定し たエントリから実行する。
\item POSIX/プロセスマネージャに、新しく作成したプロセスの情報を追加。 \end{enumerate}
\item
\item
POSIX/プロセスマネージャでは、シグナルの送信/受信の処理のみを扱います。 つまり、シグナルを受信した結果 core ダンプを作成するなどの処理は、 各プロセスが自分自身で処理を行います。
POSIX/プロセスマネージャが受信するメッセージのうち、シグナルに関係する のは次のものです。
\vspace{5mm}
\begin{tabular}
これらのうち、{\tt PROC_SETUP} についてはプロセスの初期化の時に使用す るものです。
\paragraph{\tt PROC_KILL シグナルを送信する} \hfill \\
{\tt PROC_KILL} は、次の構造をもったメッセージです。
\vspace{5mm}
\begin{boxedminipage}
struct proc_kill { proc_t dest_proc; /* シグナルの送信先のプロセス ID */ unsigned int signo; /* シグナル番号 */ }; \end{verbatim}
\end{boxedminipage} \vspace{5mm}
このメッセージで明らかのように送信元のプロセスは、送り先のプロセスにつ いては、プロセス ID のみ知っていることを前提にしています。
このメッセージを受けとると、POSIX/プロセスマネージャはプロセス情報とし て登録しているシグナル情報の送信用メッセージバッファへシグナル情報を送 信します。
シグナル情報は、シグナル番号を表現する単なる 32 ビットの整数値です。
シグナル情報を受信するのは LOWLIB 層で動いているシグナル処理用タスクで す。
POSIXには、一定時間後にシグナル (SIGALRM) を送信する alarm システムコー ルがあります。
alarm システムコールの使用方法は簡単です。
\begin{quote}
\begin{minipage}
と指定することによって、引数 {\gt 待ち時間} で指定した時間が経過すると カーネルが SIGALRM シグナルを alarm システムコールを実行したプロセスへ 送ります。
alarm システムコールを実行したあとも、ユーザプロセスは他の処理を続ける ことができるため、一種のマルチタスク的な処理を行うことができます。
POSIX/プロセスマネージャは、alarm システムコールを実現するため、一定時 間ごとに、起動するタスクをもっています。
POSIX 環境で使用するメモリマネージャは、次の仕事をします。
\begin{itemize} \item POSIX プロセスのページフォールト発生時の処理 \item 仮想空間の割り当て管理 \item POSIX プロセスのもつ物理メモリのページアウト処理 \end{itemize}
POSIX プロセスの仮想空間上でのレイアウトを図 \ref{fig:posix-memory-layout} に示します。
\begin{figure}
ページフォールトの処理は、オンデマンドに行われます。
ユーザプロセスの処理中にページフォールトが発生した場合、その原因によっ て対処方法が異ります。
\begin{table}
ページアウト処理は、すでに使っていない物理メモリをマッピングしている領 域を他の役割に使用するためのものです。
ページアウト処理は、メモリマネージャの中の一タスクが行います。
POSIX 環境でのデバイスマネージャは、BTRON 環境のデバイスドライバマネー ジャができるまでのつなぎとして動作します。
インタフェースなどは、BTRON 環境のデバイスドライバマネージャと同じです ので、そちらを参照してください(Chapter \ref{cha:device})。
POSIX 環境を実現するために、POSIX 環境では独自の LOWLIB をもっています (以下、POSIX/LOWLIB と略記)。
POSIX/LOWLIB は、次の処理を行います。
\begin{description}
\item
プロセスではじめに実行する処理です。
ユーザのプログラムコードを実行するための準備を行います。 ユーザプロセスが起動された状態では、スタックの内容などは設定されてい ません。LOWLIB のこの部分によってコマンドライン引数 (argc, argv) など の設定を行います。
\item
ユーザプログラムが POSIX システムコールを発行したときに、システムコー ルの処理を実行する部分です。
システムコールの機能は、POSIX に定められた規格に準拠しています。 (一部拡張/変更あり)
\item
シグナルの受信処理を行います。 \end{description}
ユーザプロセスの初期化は、POSIX/LOWLIB とユーザプロセスがリンクする初 期化コード (pstart.o) の共同作業によって行います。
\begin{lablist} \labitem{POSIX/LOWLIB}
ユーザプロセスが動作するための環境を整えます。
具体的には、以下の処理を実行します。
\begin{itemize} \item ユーザプロセス用の仮想空間(コード/データ/ヒープ/スタック) を生成。 \item 生成した仮想空間のうちコード部分を読み込む(正確にはデマンド ページングにより、アクセスした瞬間に実行ファイルを読み込むように設 定する。 \item プロセスマネージャにプロセスを登録する。 \item ユーザスタックのボトム部に必要な引数 (argc/argv) をロードします。 \item LOWLIB 層で動くタスクを生成します。 \item ユーザプログラムのエントリ部分 (pstart.o の先頭) へジャンプし ます。 \end{itemize}
\labitem{\tt pstart.o}
{\tt pstart.o} は、ユーザスタックの内容を整え {\tt main()} をコール します。 \end{lablist}
POSIX 環境でのシステムコール番号は、65 番を使用します。
POSIX/プロセスマネージャから送られたシグナルメッセージは、 まず、POSIX/LOWLIB 層で動いているシグナル(受信)タスクが受けとります。
シグナルタスクは、受け取ったシグナルの種類によって次のどれかの処理を行 います。
\begin{quote} \begin{itemize} \item ユーザプロセスを強制終了させる(必要ならば core ダンプを出力する)。 \item シグナルを無視する。 \item ユーザプログラムのシグナルハンドラを実行する。 \item プロセスを一時停止させる。 \item プロセスを再開させる(すでにプロセスが一時停止していた場合)。 \end{itemize} \end{quote}
POSIX 環境では、ユーザプロセスは複数のタスクが協調して動作しています。
ユーザプログラムでもプロセスに従属しているタスクを生成することもできま す。ユーザプログラム中でタスクを生成していない状態では、次のタスクが動 いています (表 \ref{tab:posix-process-task})。
\begin{table}
同じプロセスに属しているタスクは、仮想記憶空間を共有します。 つまり、同じプロセス内のタスクの間では、メモリ内容が互いに読み書きでき るようになっています。
各タスクの関係を図によって示すと 図 \ref{fig:task-with-posix} のように なります。
\begin{figure}
主タスクでは、ユーザプログラムのコード部分を実行します。
プロセスに属しているタスクの中でもメインの処理を行うタスクです。
ユーザプロセスは、主タスクを複数生成することができます \footnote{現状 では、未サポート}。
シグナルの受信処理を行うタスクがこのシグナルタスクです。
POSIX ではシグナルとして表 \ref{tab:posix-signal} に示す種類を定義して います。
\vspace{1cm} \topcaption{シグナルの種類} \tablehead{ \hline \multicolumn{2}{l}{\small 前ページより続く} \\ \hline \multicolumn{1}{c}{シグナル名 (番号)} & \multicolumn{1}{c}{内 容} \\ \hline\hline } \tablefirsthead{ \hline \multicolumn{1}{c}{シグナル名 (番号)} & \multicolumn{1}{c}{内 容} \\ \hline\hline } \tabletail{ \hline \multicolumn{2}{r}{次ページへ続く} \\ \hline } \tablelasttail{ \hline } \begin{center} \begin{supertabular}{l @{\hspace{1cm}} p{10cm}} \label{tab:posix-signal} SIGHUP (1) & ハングアップシグナル。端末がハングアップしたとき に発行するシグナル \\ SIGINT (2) & キーボードの割り込みキーを入力したときにプロセ スに送るシグナル \\ SIGQUIT (3) & キーボードの割り込みキーを入力したときにプロセ スに送るシグナル \\ SIGILL (4) & illegal instruction \\ SIGABRT (5) & abort() 関数によって引き起こされるシグナル \\ SIGFPE (6) & \\ SIGTTIN (7) & \\ SIGTTOU (8) & \\ SIGKILL (9) & 強制終了シグナル。このシグナルはマスクすることが できない。 \\ SIGSEGV (10) & セグメンテーションフォールトが発生したときに送ら れるシグナル。 \\ SIGALRM (11) & アラームシグナル。alarm システムコールによって 設定した時刻に送るシグナル。 \\ SIGSTOP (12) & \\ SIGUSR1 (13) & ユーザ定義シグナル \\ SIGUSR2 (14) & ユーザ定義シグナル \\ SIGTERM (15) & \\ SIGCHLD (16) & \\ SIGTSTP (17) & プロセス中断シグナル \\ SIGCONT (18) & プロセス再開シグナル \\ SIGPIPE (19) & \\ \end{supertabular} \end{center} \vspace{1cm}
これらのシグナルを受けとるとプロセス (シグナルタスク) は、次のいずれか の処理を行います。
\begin{itemize} \item シグナルを無視する。 \item プロセスを終了する。 \item プロセスを中断する。 \item プロセスを再開する。 \item signal システムコールによって設定してあったシグナルハンドラを実 行する。 \end{itemize}
これらのうち、シグナルハンドラを実行するケース以外のケースについては、 シグナルタスク内だけで処理します。
% %
\appendix
\chapter{B-Free のブート方式} \label{cha:kernel-boot}
ブートは、いくつかの段階に分けて実行されます。
\begin{description}
\item
PC9801 での IPL が終了した時点での各種レジスタの値は、次の仕様になっ ています。
\begin{center}
\begin{boxedminipage}
AX,BX,CX,DX 不定
ロードアドレス セグメント 0x1FC0 オフセット 0x0000 ロードサイズ 1024 バイト
\end{verbatim} \end{boxedminipage} \end{center}
\item
first boot は、コンソールに立ち上げメッセージを出力し、指定されたパー ティションから second boot を読み込み実行します。このとき second boot のサイズは無条件に 64K bytes と見なします。
first boot は、8086 モードで動作し、FD などの操作は、BIOS を介して行 います。
なお、first boot は、as86 (Linux にある 8086/8088 用アセンブラ)でか かれています。
\item
second boot は、ファイルシステムの扱いかたを知っていますが、特に指定 しない限りファイルシステムは見に行きません。
カーネルに処理を渡すときに、カーネルの動作環境も整える。具体的には、 仮想メモリ環境のセットアップ、CPUモードの変更、GDT/IDT の初期化などを 行います(つまりカーネルに制御が渡った時には、32ビットモードかつ仮想ペ ージ機能つきで CPU が動いています)。
second boot は、C によって記述されています(一部はアセンブラが入って いる)。
second boot が実行されたときのコンソールのメッセージを次に示します。 (`;'の後は註釈です)
\begin{verbatim} Loading second boot...done ; first boot が出力します。 Second BOOT for BTRON/386 Version 1.0.0 ; バージョン番号は異なっている ; 場合があります。 Waiting 10 second. ; 10秒間待ちます。このときに何 ; かキーを押すと対話モードに入 Loading kernel...done ; ります。 ; 後はカーネルに制御が渡ります \end{verbatim}
second boot の対話モードでは、次のコマンドが使用できます。
\vspace{5mm}
\begin{tabular}
partition は、次のように指定します。
\vspace{5mm}
\begin{tabular}
path は、次のように指定します。
\vspace{5mm}
\begin{tabular}
パーティションの先頭にあるブートブロックは、次の構造をしています。
\vspace{5mm}
\begin{tabular}
\begin{quote}
\begin{boxedminipage}
{\gt !! 重要 !!}
現在の BTRON/386 のブートは1セクタ 512 バイトにしか対応していません。
もし、ブートを作り直した時にうまくローディングできなかった場合には、 フロッピィのフォーマットが1セクタ512バイトとなっているかを確認してみて ください。
\end{boxedminipage} \end{quote}
ファーストブートがセカンドブートをロードした後のメモリマップは次のよう になっています。
\begin{boxedminipage}
Addr 内容 0x00000000 BIOSが使用する領域 4K 0x00001000 --+ セカンドブートロード領域 60K | | 0x00001000 16bit code. | | 0x00002000 32bit code. start address: 0x9000 | | 0x0000FFFF --+ 0x00010000 GDTテーブル 2K | 0x00011FFF 0x00012000 IDTテーブル 2K | 0x00013FFF
\end{verbatim} \end{boxedminipage}
セカンドブートがカーネルをロードした後のメモリマップは、次のようになっ ています。
\begin{boxedminipage}
0x00000000 | | 0x7FFFFFFF
0x80000000 --+ セカンドブートロード領域の残骸 | | ページテーブルに使用する。 | | (0x80000000 - 0x800003FFF は、セカンドブートが | | 初期化する。 0x8000FFFF --+ 0x80010000 GDT テーブル 2K | 0x80011FFF 0x80012000 IDTテーブル 2K | 0x80013FFF 0x80020000 --+ カーネルが使用する領域 1G (Max) | | ここにカーネルのイメージが | | ロードされる。 0xBFFFFFFF --+
(2)物理アドレス
0x00000000 --+ セカンドブートロード領域の残骸 | | ページテーブルに使用する。 | | (0x80000000 - 0x800003FFF は、セカンドブートが | | 初期化する。 0x0000FFFF --+ 0x00010000 GDT テーブル 2K | 0x00011FFF 0x00012000 IDTテーブル 2K | 0x00013FFF 0x00020000 --+ カーネルが使用する領域 1G (Max) | | ここにカーネルのイメージが | | ロードされる。 0x3FFFFFFF --+ \end{verbatim} \end{boxedminipage}
\chapter{\tt libkernel.a} \label{cha:libkernel}
\begin{flushright}
{\small
\begin{minipage}
Charles Sheffield 「マッカンドルー航宙記」 } \end{flushright}
{\tt libkernel.a} は、周辺核とデバイスドライバ そして LOWLIB で使用すること ができるライブラリです。
{\tt libkernel.a} は、以下の機能を提供します。
\begin{itemize} \item 中心核の機能を使用するためのシステムコール関数 \item デバイスに対して入出力を行うための関数 \item 割り込み操作関数 \item {\tt DMA} 操作関数 \item 文字列操作などの各種ライブラリ関数 \end{itemize}
このライブラリを使用することによって、周辺核などの作成を助けることがで きます。
{\tt libkernel.a} は、ライブラリとしてリンクするだけで使用できます。
{\tt libkernel.a} を使用する方法は、直接 {\tt libkernel.a} をリンクす る方法とライブラリパスを指定する方法の 2 通りがあります。
直接 libkernel.a を指定してリンクする方法です。
リンクコマンド ld
を使う場合にはこの方法を使用します。
ld -o foo bar <libkernel.a>
cc
のコマンドラインオプションのひとつ -L
を
指定する方法です。
具体的には、次のように指定します。
cc -o foo bar -L<libkernel.a の入っているディレクトリ> -lkernel