LoginSignup
0
0

マイクロカーネル HinaOS にシステムコールを実装する

Last updated at Posted at 2023-06-29

はじめに

前回に引き続き、怒田晟也さん著“自作OSで学ぶマイクロカーネルの設計と実装”のIDEAS.mdより、マイクロカーネルHinaOSにシステムコールを追加します。

実装概要

割り込みの発生回数を取得するシステムコールを実装します。

あたりをつける

kernel/syscall.cがシステムコール定義場所になっています。このファイル内容を見る限り、sys_uptime関数がカーネル内の処理に関連する統計情報を返す関数になっているので、この関数まわりを踏襲することで、目的を達成できそうです。

// 起動してからの経過時間をミリ秒単位で返す。
static int sys_uptime(void) {
    return uptime_ticks / TICK_HZ;
}

実装

1. ユーザランド側の関数呼び出し定義

各システムコールは、32bitのシステムコール番号で識別され、指定のレジスタに格納されたシステムコール番号に応じてカーネルモード時に処理を行います。libs/common/types.h にその定義場所があるので、定義します。

#define SYS_INTERRUPT_COUNT    18

次に、libs/user/syscall.c に以下の関数を定義します。特に渡したい値はないので、0 ~ 4番目の引数は0にします。最後の引数はカーネルモード時に関数を実行する識別子になるので、先ほど定義した変数を入れます。

// interruptシステムコール: システムの割り込み回数の取得
int sys_interrupt_count(void) {
    return arch_syscall(0, 0, 0, 0, 0, SYS_INTERRUPT_COUNT);
}

2. 割り込み回数カウントを定義

グローバル変数uptime_ticksは、interrupt.hに定義されているので、同様に割り込み回数カウントをinterrupt.hに定義します。ちなみに、extern 修飾子は外部ファイルから参照可能な変数であることを表します。

extern unsigned uptime_ticks;
extern unsigned interrupt_count; // 割り込み回数の総数

上記に加え、interrupt.cファイル内でもinterrupt_countを宣言&初期化しないと怒られます。これは、ヘッダファイル内のexternで定義と初期化が同時にできないためです。

unsigned interrupt_count = 0;

3. 統計情報取得実装

割り込み・例外ハンドラのエントリポイントとなるkernel/riscv32/trap.criscv32_handle_trap関数の頭に先ほど定義したinterrupt_countのインクリメント処理を加えます。

void riscv32_handle_trap(struct riscv32_trap_frame *frame) {
    stack_check();  // スタックオーバーフローをチェック
    interrupt_count++;
    ...

4. システムコール定義

libs/user/にて、ユーザランド側のシステムコールのインタフェースとなるAPIを定義します。

// libs/user/syscall.h

int sys_interrupt_count(void);

// libs/user/syscall.c

static int sys_interrupt_count(void) {
    return interrupt_count;
}

5. システムコールハンドラ追記

/kernel/syscall.chandle_syscallにて、システムコール番号のパターンマッチを行う箇所があるので、そこにケースを追記します。

// システムコールハンドラ
long handle_syscall(long a0, long a1, long a2, long a3, long a4, long n) {
    long ret;
    switch (n) {
	      // ...
        case SYS_INTERRUPT_COUNT:
            ret = sys_interrupt_count();
            break;
	      // ...
    }

    return ret;
}

6. コマンドを定義する

シェルサーバに割り込み回数を取得するコマンドを定義します。interruptは文字数が長く、タイポする可能性があるので、intptというコマンドとして定義します。

static void do_interrupt_count(struct args *args) {
    printf("%d times\n", sys_interrupt_count());
}

// ...

static struct command commands[] = {
		// ...
    {.name = "intpt", .run = do_interrupt_count, .help = "get interrupt count"},
    // ...
};

7. 実行

shell> intpt
15279 times
shell> intpt
18689 times
shell> intpt
36608 times

一秒あたり2000回ほど割り込まれています。タイマ割り込みも含まれているので、このような数字になるのだと思います。

参考文献

https://www.amazon.co.jp/自作OSで学ぶマイクロカーネルの設計と実装-怒田晟也-ebook/dp/B0C52SFYDC/ref=sr_1_1?__mk_ja_JP=カタカナ&crid=17NO089IHFDL0&keywords=マイクロカーネル&qid=1687662077&s=books&sprefix=マイクロカーネル%2Cstripbooks%2C166&sr=1-1

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0