カーネル
**スケジューラは 1 つだけ。同じコードが、5 つのターゲットすべてで動きます。**固定優先度でプリエンプティブ、コアごとに走ります。各タスクは 1 つのコアに固定され、そこから動きません(BMP)。
レジスタフレームを見ないコンテキストスイッチ
スケジューラは、レジスタフレームを見ません。トラップの境界を、たった 1 つの関数に絞ってあるからです。
onTrap(sp: usize) usize
アーキごとのスタブが、全レジスタを中断中のスタックに積みます。そして中断した時点のスタックポインタだけを渡して onTrap を呼ぶ。スケジューラはその値をいまのタスクに保存し、次のタスクの値を返すだけです。あとはスタブが pop して戻ります(復帰命令は x86 が iretq、riscv が sret、aarch64 が eret、Cortex-M は例外リターン)。
レジスタの並びは、アーキ非依存のコードへ一切漏れません。だから、同じスケジューラが 5 つのターゲットで動きます。
コアごとの状態と、固定されたタスク
実行状態——いまのタスク、ラウンドロビンの位置、tick の数——は、詰めた論理コア番号で引きます。実機は APIC 番号を飛び飛びに振ることがあるので、対応表で物理と論理をつなぎます。各タスクは自分のコアを覚えていて、コア間を移りません。
マルチコア起動
5 つのターゲットは、すべて 2 コア目以降を起こします。
| アーキ | コアの起動 | その後 |
|---|---|---|
| x86_64 | INIT-SIPI-SIPI で物理 0x8000 のトランポリンへ | real → protected → long mode。ACPI MADT から最大 4 コア |
| ARMv6-M(RP2040) | コア間 SIO FIFO の起動ハンドシェイク | 2 つ目の Cortex-M0+。コア ID レジスタでコアごとの状態を引く |
| RV32(RP2350) | SIO FIFO の起動ハンドシェイク | 2 つ目の Hazard3 コアがスケジューラに参加。実機で確認済み |
| riscv64 | SBI HSM の hart_start を M-mode ファームウェアへ | 2 つ目以降のハートが S-mode に入り、スケジューラに参加 |
| aarch64 | PSCI の CPU_ON をファームウェアへ | 2 つ目以降のコアが EL1 に入り、スケジューラに参加 |
x86 では、コア数を決め打ちせず、実際に数えます。応答しないコアは失敗として扱い、そのコアに固定していたタスクは、スケジューラを起こす前に、生きているコアへ移します。
実行時に spawn される新しいアクターは、いちばん空いているコアに置かれます——x86_64・riscv64・aarch64 で。MCU の飛行ビルドは、タスクをコアに明示的に固定します。
メモリモデル
カーネルは、自分のページテーブルを持ちます。中身はアーキごとに違います。
- x86 —
[0, 4 GiB)を 2 MiB の大ページで恒等マップし、NX と書き込み保護をかけます。 - riscv64 — 39bit 空間を 1 GiB のメガページで恒等マップします。
- aarch64 — 1 GiB ブロックで恒等マップします。
**物理フレームの割り当ては、x86 だけにあります。**ファームウェアのメモリマップが報告する、いちばん大きい空き RAM を管理します。
- 確保は O(1)。ポインタを進めるだけの割り当てと、空きフレーム自身をつないだ空きリストの組み合わせです。解放したフレームは、次の空きの位置を自分の先頭ワードに書きます。だから、管理用の領域が要りません。
- **細かくマップするのは、必要になったときだけ。**大きなページを 4 KiB に割り、対象の末端エントリにユーザビットと非キャッシュビットを立てます。MMIO 領域(NIC の BAR、I/O APIC)は非キャッシュでマップします。
riscv64 と aarch64 は、中間のページテーブルを小さな固定プールから取ります。
MMU 無し MCU プロファイルには、MMU がそもそもありません。アドレス空間はフラットで物理(VA == PA)、MMU モジュールは何もしないスタブで、隔離はページテーブルでなく PMP / MPU 領域でかけます。
カーネルのペイロードとしての VM
このカーネルは、そもそも Lambda C VM インスタンスをホストするために在ります——スケジュールされる、隔離されたアクターとして。
各タスクは、自分のスタック・グローバル領域・ヒープを持つ、独立した VM です。スケジューラは、コンテキストスイッチのたびに、VM のプロセス全体の実行状態を退避・復元します。だから VM のフレームは、まわりに割り込み禁止区間を持たず、完全にプリエンプトできます。
契約の詳しくは アクター、各アクターを自分のメモリに閉じ込める仕組みは 隔離、スケジューラのハードリアルタイム・プリミティブは リアルタイム にあります。