OS自作入門 -Advent31-
Step8 スレッドを実装する 最終戦
引き続き残りのスレッド管理周りを実装していくことにしよう。
OSの実装(続き)
組み込みハンドラの登録
kozos.cの続きに組込みハンドラを実装していく。KOZOSはソフトウェア・割込みベクタに対するハンドラをhandlers[]
という配列に持っており、割込み発生時にはそのハンドラを実行する。
ここで定義しているsetintr()
関数はhanders[]
にハンドラを設定するためのサービス関数となる。
softvec_setintr()
をソフトウェア・割込みベクタにOSのハンドラとしてthread_intr()
を登録している点がちょっと分からなかったな。
これにより、指定した割込みが発生した際には
thread_intr()
が呼ばれ、OSに処理が渡るようになります。
という記載があるが、、、thread_init()
の実装の方でOSとしてスレッドを実行するような処理が書かれるのだろうと推測。
システム・コールの実行
システム・コールの発行時にはgetcurrent()
によりカレントスレッドがレディーキューから取得されてから、call_functions()
が呼ばれ、システムコールの種別に応じて処理が実行される。
割込み処理
割込み処理はこの辺り。
上述の通り
これにより、指定した割込みが発生した際には
thread_intr()
が呼ばれ、OSに処理が渡るようになります。
という箇所がある。これはsoftvec_setintr
が呼ばれ、ソフトウェア・割込みベクタに割込みハンドラとしてthread_intr()
が登録される。これにより、割込み発生時にはthread_intr()
が呼ばれ、コンテキストとしてスタックポインタを保存し、handlers[]に登録された関数を呼び出しているという処理になる。(handlers[]
へのハンドラのセットはここでやっている)
また、ハンドラを呼び出した後はschedule()
を呼びスケジューリングを行う。実行するスレッドを選択することをスケジューリングと呼ぶが、優先度高いものとかの処理がある場合はここが多少複雑になるのだろうと思っている。
この後にディスパッチすることによりカレントスレッドが動き出す。ここでスタックポインタの値が格納されているアドレスを渡し、そこからスタックポインタの値を復旧し、さらに各汎用レジスタの値を復旧する動きになる。
初期スレッドの起動
kz_start
の実装。ここに置いておく。kz_start
が呼ばれることにより、一つ目のスレッドが初期化されて動作を開始する。あとは初期スレッドからkz_run
により各種サービス用スレッドを必要に応じて起動するとOSが出来上がる。また、thread_run
によってスレッドを生成し、dispatch
でスレッドに実行を移し、初期スレッドが動作を開始した後は、割込みを契機としてOSに処理が渡るようになっている。
システムコール
システムコールのヘッダーファイル。
現状kz_run
とkz_exit
の二つ。
typedef enum {
KZ_SYSCALL_TYPE_RUN = 0,
KZ_SYSCALL_TYPE_EXIT<
} kz_syscall_type_t;
という形でシステムコール番号を定義している。次にkz_syscall_param_t
という構造体を定義している。これはシステムコールのパラメータや戻り値の受け渡しの際に、構造体のポインタで渡せるようにしているためである。引数が複数ある場合があるので、構造体に一旦格納し、そのポインタを渡せるようにしておくための構造体。
システムコールの実装。
C言語からKOZOSのシステムコールを呼び出すためのサービス関数でしかない。APIと呼ぶらしい(いつも使っているAPIはかなり広義かもしれん)。
APIはアプリケーションプログラムがOSの機能を利用する際に利用するインターフェースです。
とのこと。
OSで利用する型の定義
defines.hに置いてある。
- kz_thread_id_t
スレッドIDを表す型 - kz_fund_t
スレッドのメイン関数を扱うための型 - kz_handler__t
割込みハンドラなどを扱うための型
OSを利用する
さて、ようやくOS周りの実装が終わったので利用してみよう。
main.cに置いてある。
kz_start()
を呼んで初期スレッドを起動し、あとはスレッドに動作が渡るだけ。
kz_start(start_threads, "start", 0x100, 0, NULL);
それぞれ、"start"
はスレッドの名前、0x100
はスタックサイズ、0, NULL
はメイン関数に渡すargc, argv
の引数。
でstart_threads
の中ではtest08_1_main
を実行しており、これがスレッドとして動作開始することになる。
アプリケーションプログラムはtest08_1_main
なので実装する。test08_1.cに置いてある。あまり前と変わっていない。echo
, exit
を受け付けてそれぞれ動作するようになっている。
最後にMakefileにkozos.c
, syscall.c
, test08_1.c
をコンパイル対象に含めて終わり。
実行
失敗する!!!なぜだ。
エラーログは
tools/bin/h8300-elf-gcc startup.o main.o interrupt.o lib.o serial.o kozos.o syscall.o test08_1.o -o kozos -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS -static -T ld.scr -L.
# kozos.o: In function `.L13':
# kozos.c:(.text+0x175): undefined reference to `___mulsi3'
# kozos.c:(.text+0x189): undefined reference to `___mulsi3'
# kozos.c:(.text+0x1a3): undefined reference to `___mulsi3'
# kozos.c:(.text+0x1b9): undefined reference to `___mulsi3'
# kozos.c:(.text+0x20d): undefined reference to `___mulsi3'
# kozos.o:kozos.c:(.text+0x275): more undefined references to `___mulsi3' follow
# collect2: error: ld returned 1 exit status
# make: *** [kozos] Error 1
困った。。。意味が分からん。___mulsi3
が見つからないよ。ってのは分かるがそれがなんで見つからないのかが分からん。kozos.cの
thp->next = NULL;
thp->init.func = func;
thp->init.argc = argc;
thp->init.argv = argv;
memset(thread_stack, 0, stacksize);
thread_stack += stacksize;
thp->stack = thread_stack;
この辺りをコメントアウトするとエラーが消える。多分thp
が見つからないか、ポインタ参照で見つからないか。かなぁとか思っているけど理由が分からなかった。
が、調べると神々がいるもんだ。
http://d.hatena.ne.jp/satfy/20110202/1296666655
http://kozos.jp/kozos/h8_2/h8_04/os/kozos.c
助かった。。。危うく積んだかと思った。理由はちょっと分からないけど構造体のサイズの問題みたい。
padding(何かで埋めておく、この場合char dummy[16]
で埋める)すると大丈夫みたい。
bootloadの方をmake & make image & make write
して、osの方をmake & ../../tools/bin/kz_xmodem kozos.elf /dev/tty.usbserial-XXXXXX
して、sudo cu -l /dev/tty.usbserial-FT0BTH3I -s 9600
とすると以下のような感じになる。
Connected.
unknown.
kzload> run
starting from entry point: ffc020
kozos boot succeed!
start EXIT.
test08_1 started.
> echo hogehoge
hogehoge
> abc
unknown.
> exit
test08_1 exit.
command EXIT.
system error!
これでいいはず。最後のsystem error!
は処理するスレッドがないから出る表示。
今日はこんな感じで。なんか一番難しかったような気もする。あとある程度写経しているのだが、コンパイルとか実行をこまめにやるわけではなく、最後の最後にまとめてコンパイル、リンク、write、loadとかするので書き間違えるととても探すのに時間がかかるなぁ。
この本読み終えたら一回総集編を作らないと知識の整理が追いつかない。
- 前の記事
OS自作入門 -Advent30- 2018.01.14
- 次の記事
OS自作入門 -Advent32- 2018.01.20