KOZOS (22)

スデに酒が注入されてますが、明日くらいまでは集中してこっちな方向。

とは言え

継続なソレが分からなくなってたりして。とりあえず syscall_proc で掘削してみるか。
重複しますが syscall_proc 手続きを呼び出しているのは kozos.c で定義されている syscall_intr 手続き。

static void syscall_intr(void)
{
  syscall_proc(current->syscall.type, current->syscall.param);
}

逆に syscall_intr 手続きを呼び出しているのはどれかな。

find . -type f -print0 | xargs -0 -e grep -nH -e 'syscall_intr'
./kozos.c:232:static void syscall_intr(void)
./kozos.c:254:   * syscall_intr(), softerr_intr() がハンドラに登録されているので,
./kozos.c:284:  setintr(SOFTVEC_TYPE_SYSCALL, syscall_intr); /* システム・コール */

Grep finished (matches found) at Tue May  3 19:46:54

setintr 手続きは kozos.c の kz_start 手続きから呼ばれている模様。割り込みハンドラの登録、とコメントに記述されている。これはちょい前に掘ってる部分だな。
ちょっと整理する意味でも kozos.c の中の call graph てきなソレを確認した方が良さげ。

とゆーことで

以下。

thread_intr  -+- syscall_intr -+-syscall_proc -+- getcurrent
              |                                |
              |                                +- call_functions
              |
              +- schedule -+- kz_sysdown
              |
              +- dispatch

call_functions -+- thread_run   -+- putcurrent
                |                |
                |                +- thread_init -+- thread_end
                |
                +- thread_exit


kz_start    -+- thread_run   -+- putcurrent
             |                |
             |                +- thread_init -+- thread_end
             |
             +- setintr
             |
             +- dispatch

kz_syscall
syscall_intr
softerr_intr
  • kz_start は main.c の main 手続きから呼び出されてます
  • kz_syscall 手続きは syscall.c の kz_run 手続きおよび kz_exit 手続きから呼び出されます
  • thread_intr は setintr で softvec_setintr 手続きに渡されてます
    • setintr は kz_start から呼び出されてます
  • syscall_intr および softerr_intr は kz_start 手続きにおいて setintr 手続きに渡されます

微妙な部分を掘ってみる

ええと、thread_run 手続きの定義あたりの記述が以下。

/* システム・コールの処理(kz_run():スレッドの起動) */
static kz_thread_id_t thread_run(kz_func_t func, char *name,
				 int stacksize, int argc, char *argv[])

thread_run が kickoff されてるのは、というと

  • call_functions 手続き (kozos.c:197)
  • kz_start 手続き (kozos.c:288)

なんですが、kz_run って何だっけorz
ええと、syscall.c で手続き定義されとるな。main.c で以下な記述になってます。

static int start_threads(int argc, char *argv[])
{
  kz_run(test08_1_main, "command", 0x100, 0, NULL);
  return 0;
}

int main(void)
{
  INTR_DISABLE; /* 割込み無効にする */

  puts("kozos boot succeed!\n");

  /* OSの動作開始 */
  kz_start(start_threads, "start", 0x100, 0, NULL);
  /* ここには戻ってこない */

  return 0;
}

ええと、kz_start に kz_run を呼び出す start_threads 手続きが渡されてます。kz_start はいっちゃん最初の kickoff なので

void kz_start(kz_func_t func, char *name, int stacksize,
	      int argc, char *argv[])

な引数を

  /* システム・コール発行不可なので直接関数を呼び出してスレッド作成する */
  current = (kz_thread *)thread_run(func, name, stacksize, argc, argv);

で、うん、ってカンジで kickoff してるのか。kz_start 手続きは main 手続きからのみの呼び出しか。このあたりは最近のエントリでもごもごしてないのかなぁ。

してました

が、掘削具合が微妙。冗長かもしれませんがここから掘削。kz_start 手続きは適当にしか掘ってない模様。体力の続く限り (?) 頑張ってみます。とりあえず以下から。

void kz_start(kz_func_t func, char *name, int stacksize,
	      int argc, char *argv[])
{
  /*
   * 以降で呼び出すスレッド関連のライブラリ関数の内部で current を
   * 見ている場合があるので,current を NULL に初期化しておく.
   */
  current = NULL;

ヤッてるのはコメントの通りなんですが、current という変数は kozos.c の先頭部分あたりで定義 (宣言?) されてます。

static kz_thread *current; /* カレント・スレッド */

普通に考えると外部変数で static で (static はこの際関係ないですが) なので 0 初期化されるんでないの? というのはアマ。
このあたりは OS がヤッてくれるナニであって今はその OS 的なソレが bootstrap してる箇所ですので自分で NULL 初期化しないと駄目です。ちなみに NULL も自分で定義してないと駄目で defines.h にて以下。

#define NULL ((void *)0)

次の三行なナニは

  readyque.head = readyque.tail = NULL;
  memset(threads,  0, sizeof(threads));
  memset(handlers, 0, sizeof(handlers));

kozos.c の先頭部分で定義されてるソレの初期化ですね。

/* スレッドのレディー・キュー */
static struct {
  kz_thread *head;
  kz_thread *tail;
} readyque;

static kz_thread *current; /* カレント・スレッド */
static kz_thread threads[THREAD_NUM]; /* タスク・コントロール・ブロック */
static kz_handler_t handlers[SOFTVEC_TYPE_NUM]; /* 割込みハンドラ */

ちなみに THREAD_NUM は 6 で SOFTVEC_TYPE_NUM は intr.h で定義されてて以下。

#define SOFTVEC_TYPE_NUM     3

あるいは kz_thread とか kz_handler_t の定義は何かというと

kz_thread 型

_kz_thread 構造体で定義は kozos.c です。

kz_handler_t 型
typedef void (*kz_handler_t)(void);
ということは
  • threads は要素は 6 で TCB な配列なのか
  • handlers は関数ポインタな配列で要素の数は 3

ちなみにこの handlers という名前の配列の添字は intr.h で定義されてます。

#define SOFTVEC_TYPE_SOFTERR 0
#define SOFTVEC_TYPE_SYSCALL 1
#define SOFTVEC_TYPE_SERINTR 2

ちょい find-grep してみてやれ。

  • ./kozos.c:285: setintr(SOFTVEC_TYPE_SOFTERR, softerr_intr); /* ダウン要因発生 */
  • ./kozos.c:284: setintr(SOFTVEC_TYPE_SYSCALL, syscall_intr); /* システム・コール */

SOFTVEC_TYPE_SERINTR は未使用な模様。setintr 掘るべきなのかどうか。なんとゆーかソース見てるとコンテキストを見失いがちですよね。
って、変数初期化してる直後で setintr 呼びだしてるしorz

  /* 割込みハンドラの登録 */
  setintr(SOFTVEC_TYPE_SYSCALL, syscall_intr); /* システム・コール */
  setintr(SOFTVEC_TYPE_SOFTERR, softerr_intr); /* ダウン要因発生 */

ええと setintr 手続きの定義が以下ですね。

/* 割込みハンドラの登録 */
static int setintr(softvec_type_t type, kz_handler_t handler)
{
  static void thread_intr(softvec_type_t type, unsigned long sp);

  /*
   * 割込みを受け付けるために,ソフトウエア・割込みベクタに
   * OSの割込み処理の入口となる関数を登録する.
   */
  softvec_setintr(type, thread_intr);

  handlers[type] = handler; /* OS側から呼び出す割込みハンドラを登録 */

  return 0;
}

softvec_setintr 手続きの定義は interrupt.c な模様です。

/* ソフトウエア・割込みベクタの設定 */
int softvec_setintr(softvec_type_t type, softvec_handler_t handler)
{
  SOFTVECS[type] = handler;
  return 0;
}

SOFTVECS は interrupt.h で以下な定義。

#define SOFTVECS ((softvec_handler_t *)SOFTVEC_ADDR)

SOFTVEC_ADDR って何、って思ったら直上で以下な定義。

/* 以下はリンカ・スクリプトで定義してあるシンボル */
extern char softvec;
#define SOFTVEC_ADDR (&softvec)

えーと、リンカスクリプトが久々に出てきましたな。

MEMORY
{
	ramall(rwx)	: o = 0xffbf20, l = 0x004000 /* 16KB */
	softvec(rw)	: o = 0xffbf20, l = 0x000040 /* top of RAM */

わを、これって RAM の先頭の割り込みベクタテーブルじゃん。という事は softvec_setintr 手続きはこの領域に引数なナニを設定してるのか。

  SOFTVECS[type] = handler;

0x40 って 64 bytes で 4 で割ったら 16 個ってことで良いのかな。
で、その直後で再度配列に云々してるんですがちょっとマテ。
softvec_setintr に渡されてるのは thread_intr 手続きだな。その後、handlers という配列に設定されてるのは引数で渡されるソレなので

  /* 割込みハンドラの登録 */
  setintr(SOFTVEC_TYPE_SYSCALL, syscall_intr); /* システム・コール */
  setintr(SOFTVEC_TYPE_SOFTERR, softerr_intr); /* ダウン要因発生 */

の syscall_intr とか softerr_intr などになる。ここでポイント高いのは setintr 手続きの中で softvec_setintr 手続きに渡されている thread_intr 手続き

/* 割込み処理の入口関数 */
static void thread_intr(softvec_type_t type, unsigned long sp)

ということになるんですが、そろそろ限界。明日はここ起点でがっつり掘削予定。