Mais conteúdo relacionado
【学習メモ#12th】12ステップで作る組込みOS自作入門
- 5. 割込みの延長で動作
● 7thのようなサンプル・プログラムは、シリア
ル受信割込みのハンドラ内部でコマンド応答処
理を行なっている
– こういった実装を「割込みの内部で処理している」
「割込みの延長で動作する」などと呼ぶ
● 割込みの内部で処理すると、重たい処理であれ
ば割込みの遅延が発生するので良くない
● 割込みハンドラで必要な処理を行うのではな
く、処理用のスレッドで行う形が良い
– シリアル通信を例に行なってみる
- 6. シリアル送受信の場合
● シリアル・コントローラは送信と受信の割込み
ベクタが同じなので、一つの割込みハンドラで
送信と受信の処理を行う
● シリアル受信割込みはデータを受信することで
割込みが発生する
● シリアル送信割込みは1文字送信を行ったと
き、その送信処理が完了して次の文字の送信が
可能になったときに発生する
- 7. シリアル受信割込み
● シリアル受信処理の実装
– ①割込みハンドラで受信文字を取り出してメッセー
ジによりコマンド応答スレッドに送信
– ②コマンド応答スレッドは、メッセージを受信した
ら文字を組み立ててコマンドとして解釈し、該当の
処理を行う
● こうすればシリアル受信の割込みはコマンド応
答スレッドに受信文字を送信するだけで済む
- 8. シリアル送信割込み
● これまでの方法だとビジーループにより送信可
能になるまで待ち合わせる形だった
● ビジーループ中は他の処理が行えず、CPUが空
回りしている状態でCPU時間が無駄
● この問題を回避する方法として、シリアル送信
割込みを利用する
- 9. シリアル送信割込みの実装例
● 実装例
– シリアル送信の割込みハンドラとシリアル送信ス
レッド作成
– シリアル送信スレッドは送信要求を受けたら、送信
バッファに送信する文字列を書き込み、先頭の1文
字を送信。送信後に割込み待ち状態に
– 1文字の送信が完了するとシリアル送信割込みが発
生。割込みハンドラでは送信バッファを参照し、未
送信の文字列が残っているならば次の1文字を送信
– 1文字の送信が完了すると再度送信割込みが入る
● この部分は今回のプログラムでいうところの
consdrv.cにあたる
- 10. 非タスク・コンテキスト
● シリアル受信割込みが発生したとき、スレッド
に受信データを渡し、コマンド・スレッドでコ
マンド応答処理を行う
● 要は受信データは行単位でメモリに格納して
メッセージ通信により渡す流れとなる
– つまり、シリアル受信割込み発生中にメッセージ通
信とメモリ獲得の割込みが必要となり、割込み中に
割込みが発生するという結果になる。これではコン
テキスト情報が破壊されてしまい正常に動作しない
● 割込み処理中は中断も再開もできないわけで、
スレッドのようにスリープさせられない
● こういう状態を非タスク・コンテキストと呼ぶ
- 11. タスク・コンテキスト
● 割込みが非タスク・コンテキストで動作するな
ら、スレッドの状態はタスク・コンテキストと
呼ぶ
● 割込み中の割込みではコンテキスト情報の保存
先が無いため、システム・コールは呼べない
● よって、スレッドへのデータの受け渡しのため
に、割込みではないけれど同じ処理ができる
サービスをOSに実装する必要がある
- 12. サービス・コール
● そこで、システム・コールと同じ処理を割込み
でなく関数として呼び出せるサービス・コール
という機能を実装する
– 実体はシステム・コールと全く同じ。KOZOSでは呼
び名を変えているだけ
● サービス・コールは割込みハンドラでの処理中
に、システム・コールと同じようなことができ
るための関数ってわけ
● よって、サービス・コールは割込みハンドラで
のみ利用可能でスレッドからの利用は一切禁止
– スレッドの実行中に割込みが入り他スレッドに処理
が切り替わったりそのスレッドがシステム・コール
を発行すると、関数が再入される可能性もあるため
- 13. 追加するサービス・コール
● 追加するサービス・コールは以下の4つ
– kx_wakeup()
– kx_send()
– kx_kmalloc(),kx_kmfree()
● 実際はシステム・コールのkz_xxxと同じで、割
込みハンドラ内でのみ利用可能
– 処理内容はkz_wakeup()をコピペして、kx_wakeup()
にしただけのやつ
- 14. 排他
● シリアル送信割込みでは送信バッファの扱いに
注意する必要がある
● 送信バッファをスレッドと割込みという異なる
コンテキストから操作しており、再入が行われ
る可能性がある
● そこで今回は割込み禁止にして送信を行う関数
を再入させないようにする
- 15. 割込みの管理
● 今まで割込みハンドラの登録は内部のサービス
関数によって行なっていたけれど、ここでシス
テム・コールとして利用できるようにしている
● これでOSのユーザが割込みハンドラを自由に登
録できるようにはなった
- 18. プログラムの修正と追加
● 追加ファイル
– consdrv.h,consdrv.c...コンソール・ドライバ・ス
レッド
– command.c...コマンド・スレッド
● 修正ファイル
– defines.h...メッセージIDの定義
– syscall.h,syscall.c...システム・コール、サービ
ス・コールの追加
– kozos.h,kozos.c...システム・コール、サービス・
コールの追加
– main.c...起動するスレッドの修正
– Makefile
- 19. 修正と追加内容
● サービス・コール追加
– 追加した関数についてはスライドの12p参照
– サービス・コールの追加に伴い、ごちゃごちゃと細
かい部分修正
● コンソール・ドライバ・スレッド追加
– コンソールを利用するためのデバイス・スレッド
– 基本的には他スレッドからのコマンド
(CONSDRV_CMD_USEやCONSDRV_SMD_WRITE)受け付け
と、シリアル送受信の処理が行われる(割込みハン
ドラもここで登録)
● コマンド・スレッド追加
– コンソールからのコマンド処理を行う
● あとはまあいろいろだ
- 20. 構造体のパディング
● 一般的なCPUでは整数値などのデータはそのサ
イズにアライメントされている必要がある
– 2バイトのデータは2の倍数のアドレス、4バイトの
データは4の倍数のアドレスに配置されている必要
があるわけ
● アドレスをなんらかの値の倍数に合わせること
をアライメントと呼び、その倍数を境界やバウ
ンダリと言う
● 今回はconsregという構造体でアライメントが
為されており、アライメント調節用の付加領域
のことを一般にパディングと呼ぶ。パディング
はコンパイラによって自動的に付加される
- 21. シリアル送受信の処理
● consdrv.cにあるconsdrv_intrproc()が割込み
の実質的な処理にあたる
● コンソールに文字が入力されたとき(シリアル
受信割込み)と、コンソールに1文字送信して送
信処理が完了し、次の文字が送れるようになっ
たとき(シリアル送信割込み)の処理を行う
● 1つの関数で2つ役割があるので注意すること
● この割込みハンドラではsend_char()を利用し
ているが、スレッド側からもこの関数を利用し
ている(スレッド側は実際はsend_string())
● 再入の不具合がおこるのでスレッド側から呼び
出すときは割込み禁止にして呼び出されている
- 25. まとめ
● 今回のポイントはシリアル送受信の割込み部分
と、それを可能にしているタスク間通信。ス
レッドはいわずもがな
● 最終的にはCPUとメモリとI/Oをユーザから操作
できるようなシステムコールが実装されたこと
になる
● あとはタイマとかLANのドライバとか書いたり
するのが発展系なんだろう
● おつかれーつかれたー