めのん@ひとりプログラミング同好会

このブログはすべてフィクションであり、実在の人物、団体とは一切関係ありません

Zig版ASP3カーネルのsta_ker

おはようございます、めのんです!

平日はPHPの話題にしようと思っていたのですが、昨日に引き続き今日もZigの話題です。

前回予告した通り今回はsta_kerを見ていくのですが、その前に例外ベクタテーブルを見ておくことにします。 例外ベクタテーブルはスタートアップルーチンと同じcore_kernel_impl.zigで定義されています。

pub fn vector_table() linksection(".vector") callconv(.Naked) void {
    asm volatile(
     \\  ldr pc, reset_vector       // リセット
     \\  ldr pc, undef_vector       // 未定義命令
     \\  ldr pc, svc_vector         // ソフトウェア割込み
     \\  ldr pc, pabort_vector      // プリフェッチアボート
     \\  ldr pc, dabort_vector      // データアボート
     \\  ldr pc, reset_vector       // 未使用
     \\  ldr pc, irq_vector         // IRQ
     \\  ldr pc, fiq_vector         // FIQ

     (以下略)

ここで新しく登場したのはlinksectionです。 linksectionについてはドキュメントでもほとんど触れられていませんが、括弧の中の文字列リテラルで指定したセクションにその関数を配置するということなんだと思います。 関数とは言いましたが、実際には単なる配列ですよね。

前振りが長くなってしまいましたが、いよいよここからが本題のsta_kerです。 sta_kerはkernel/startup.zigで定義されています。

pub fn sta_ker() noreturn {
    // TECSの初期化
    if (!option.TOPPERS_OMIT_TECS) {
        initialize_tecs();
    }

    // ターゲット依存の初期化
    target_impl.initialize();

    // 各モジュールの初期化
    initialize_tmevt();                             //[ASPD1061]
    cfg._kernel_initialize_object();

    // 初期化ルーチンの実行
    for (cfg._kernel_inirtnb_table) |inirtnb| {
        inirtnb.inirtn(inirtnb.exinf);
    }

    // 高分解能タイマの設定
    current_hrtcnt = target_timer.hrt.get_current();    //[ASPD1063]
    set_hrt_event();                                    //[ASPD1064]

    // カーネル動作の開始
    kerflg = true;
    traceLog("kernelEnter", .{});
    target_impl.startDispatch();
}

一応、sta_kerというサービスコールについても簡単に話しておきます。 このサービスコールはμITRONにもなくて、確かTOPPERS/ASPカーネルから導入されたはずです。

簡単にいえば、このサービスコールを呼び出したところからカーネルが動き始めます。 それまではまだカーネルが起動していないので、その段階ではタスクコンテキストも非タスクコンテキストもありません。

sta_kerで何をやっているかはコメントの通りなので、取り立ててどうこういうことはありません。 Zig版ASP3カーネルを読んでいるのは、ASP3カーネルの動きを理解することではなくZigを学習することなので、言語仕様的に見どころがなければこんな感じであっさり済ませることにします。

少しだけ触れておくと、初期化ルーチンの実行というのは静的APIのATT_INIで登録した初期化ルーチンを実行するということです。 この時点ではまだカーネルは起動しきっていませんので、タスクコンテキストでも非タスクコンテキストでもありません。 最後に呼び出しているtarget_impl.startDispatch関数を呼び出すことでやっとカーネルが動き始めます。

ここで現れるtarget_implですが、kernel_impl.zigで定義されています。

pub const target_impl = @import("../target/" ++ option.TARGET
                                    ++ "/target_kernel_impl.zig");

Zigでは+ +で文字列を連結できるので(Cに比べれば)便利ですね。

で、target_implはターゲット依存部のtarget_kernel_impl.zigをインポートしたものです。 こういうインポートはZigの決まり文句なので、あちこちに登場しています。

さて、今回はずいぶん長くなってしまいました。 次回はsta_kerと対になるext_ker、それと関連するサービスコールのsns_kerについて読んでいきたいと思います。

それでは!!