mcpField
R
riscv-privileged

riscv-privileged

github.com/mohitmishra786開発269284 回インストール18 週間前に更新
リポジトリ

riscv-privileged について

riscv-privilegedは、RISC-V特権アーキテクチャを扱うエージェント向けのスキルです。特権モード、CSR、トラップ、割り込み、OpenSBI、仮想メモリ、QEMUでのテストを網羅し、カーネルやハイパーバイザーの開発に役立ちます。

主な機能

  1. 01M/S/U特権モードとCSR
  2. 02トラップ処理とベクター設定
  3. 03PLICとCLINTの割り込み
  4. 04OpenSBIファームウェアとSBI呼び出し
  5. 05Sv39/Sv48ページテーブルとQEMUテスト

活用シーン

  1. 01RISC-V OSカーネルまたはハイパーバイザーの作成
  2. 02トラップハンドラーとコンテキスト切り替えの実装
  3. 03QEMU virtでの割り込み設定
  4. 04Sv39またはSv48仮想メモリの構築

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill riscv-privileged

インストール後、Claude Code で/riscv-privilegedを入力して読み込まれたか確認します。

詳細

RISC-V 特権アーキテクチャ

目的

RISC-V 特権仕様について、M/S/U 特権モード、CSR レジスタ、トラップ処理、PLIC および CLINT 割り込みコントローラー、OpenSBI ファームウェアとの統合、Sv39/Sv48 ページテーブル、QEMU virt マシンでのテストをエージェントに案内します。

使用する場面

  • RISC-V 向けの OS カーネルやハイパーバイザーを作成するとき
  • トラップハンドラーやコンテキストスイッチを実装するとき
  • S モードのファームウェアサービスに OpenSBI を統合するとき
  • QEMU virt またはハードウェアで割り込みコントローラーを設定するとき
  • Sv39 または Sv48 で仮想メモリを設定するとき
  • xv6-RISC-V またはベアメタルファームウェアを移植するとき

ワークフロー

1. 特権レベル
RISC-V privilege stack
├── M-mode (Machine) — firmware, OpenSBI, most privileged
├── S-mode (Supervisor) — OS kernel
└── U-mode (User) — applications

Embedded (no S-mode): M + U only
2. 主な CSR
CSRモード目的
mstatus / sstatusM/S割り込みの有効化、特権状態
mtvec / stvecM/Sトラップベクターのベースアドレス
mepc / sepcM/S例外 PC
mcause / scauseM/Sトラップ原因コード
mtval / stvalM/Sフォールトが発生したアドレス/命令
satpSページテーブルルート(モード + PPN)
mie / sieM/S割り込み有効化ビット
mip / sipM/S割り込み保留ビット
// Read CSR (GCC extended asm)
static inline uint64_t read_csr_satp(void) {
    uint64_t val;
    asm volatile("csrr %0, satp" : "=r"(val));
    return val;
}

// Write CSR
static inline void write_csr_stvec(void *handler) {
    asm volatile("csrw stvec, %0" :: "r"(handler));
}
3. トラップ処理
Trap types
├── Synchronous exceptions — ecall, page fault, illegal insn
└── Asynchronous interrupts — timer, external, software
// scause encoding (top bit: 1=interrupt, 0=exception)
void handle_trap(uint64_t scause, uint64_t sepc, uint64_t stval) {
    if (scause & (1UL << 63)) {
        // Interrupt
        switch (scause & 0xff) {
        case 5:  // Supervisor timer interrupt
            timer_interrupt();
            break;
        case 9:  // Supervisor external interrupt
            external_interrupt();
            break;
        }
    } else {
        // Exception
        switch (scause) {
        case 8:   // ecall from U-mode
            handle_syscall();
            break;
        case 12:  // Instruction page fault
        case 13:  // Load page fault
        case 15:  // Store page fault
            handle_page_fault(stval, scause);
            break;
        }
    }
}
4. トラップベクターの設定
# trapvec.S — direct mode (all traps to one handler)
.section .text.trap
.globl trap_entry
.align 4
trap_entry:
    # Save registers to trap frame
    csrrw sp, sscratch, sp   # switch to kernel stack
    # ... save caller-saved ...
    csrr a0, scause
    csrr a1, sepc
    csrr a2, stval
    call handle_trap
    # ... restore ...
    sret
write_csr_stvec(trap_entry);
// vectored mode: mtvec[1:0] = 01, base aligned to 4×entries
5. CLINT と PLIC
QEMU virt interrupt map
├── CLINT — timer and software interrupts (per-hart)
│   ├── mtime / mtimecmp — machine timer
│   └── msip — machine software interrupt
└── PLIC — external device interrupts (UART, virtio, etc.)
    ├── priority, pending, enable per source
    └── claim/complete per hart context
// Timer via SBI (preferred in S-mode) or direct CLINT in M-mode
// PLIC claim
uint32_t irq = plic_claim(hart_id);
handle_device_irq(irq);
plic_complete(hart_id, irq);
6. OpenSBI
# Build OpenSBI with payload (your kernel)
git clone https://github.com/riscv-software-src/opensbi
cd opensbi
make PLATFORM=generic FW_PAYLOAD_PATH=../kernel.elf FW_PAYLOAD_OFFSET=0x80200000
# Output: build/platform/generic/firmware/fw_payload.elf

ecall を介した S モードからの SBI 呼び出し:

struct sbiret sbi_set_timer(uint64_t stime) {
    return sbi_ecall(0x54494D45, 0, stime, 0, 0, 0, 0, 0);
    // Extension ID 0x54494D45 = TIME
}

一般的な SBI 拡張機能:Base、Timer、IPI、RFENCE、HSM。

7. ページテーブル — Sv39
Sv39: 39-bit virtual addresses, 3 levels
VPN[2] → L2 PTE → L1 PTE → L0 PTE → physical page

satp: MODE(4) | ASID(9) | PPN(44)
MODE = 8 for Sv39, 9 for Sv48
// PTE flags
#define PTE_V  (1L << 0)  // Valid
#define PTE_R  (1L << 1)  // Read
#define PTE_W  (1L << 2)  // Write
#define PTE_X  (1L << 3)  // Execute
#define PTE_U  (1L << 4)  // User accessible

uint64_t *walk_create(uint64_t *root, uint64_t va, int alloc);
void map_page(uint64_t *root, uint64_t va, uint64_t pa, int perm);

Sv48:4 レベル、48 ビットの仮想アドレス(RV64 の QEMU virt でのデフォルト)。

8. QEMU virt でのテスト
qemu-system-riscv64 \
  -machine virt \
  -cpu rv64 \
  -m 128M \
  -kernel kernel.elf \
  -bios default \
  -serial mon:stdio \
  -display none \
  -no-reboot

# With OpenSBI payload
qemu-system-riscv64 \
  -machine virt -m 128M \
  -kernel opensbi/build/.../fw_payload.elf \
  -serial stdio -nographic
# GDB debug
qemu-system-riscv64 -s -S ...  # port 1234, wait
riscv64-unknown-elf-gdb kernel.elf
(gdb) target remote :1234
9. 参考資料:xv6-RISC-V
git clone https://github.com/mit-pdos/xv6-riscv
make qemu
# Study: kernel/trap.c, kernel/vm.c, kernel/start.c, kernel/plic.c

よくある問題

症状原因解決策
起動時にトラップループが発生するstvec のアラインメントが不適切4 バイト境界に揃え、ハンドラーを確認します
エントリー時にページフォールトが発生するマッピング前に satp が有効化されているまずカーネルを ID マッピングします
タイマーが作動しないSBI と CLINT の不一致S モードでは sbi_set_timer を使用します
PLIC で割り込みが発生しない有効化ビットが設定されていない優先度、有効化、しきい値を設定します
OpenSBI がハングするペイロードオフセットが間違っているFW_PAYLOAD_OFFSET をリンクアドレスに合わせます
不正な命令圧縮命令がサポートされていないCPU 設定で C 拡張を有効にします

関連スキル

  • skills/low-level-programming/assembly-riscv — RV32/RV64 ISA と psABI
  • skills/kernel/os-dev-scratch — OS 開発の概念(x86 の並行例)
  • skills/virtualization/qemu-kvm — QEMU の使用パターン
  • skills/embedded/zephyr — RISC-V 上の Zephyr
  • skills/kernel/kernel-internals — Linux VM とスケジューラーの類似概念
  • skills/platform/arm-sve — その他のアーキテクチャプラットフォームスキル

コメント