FABRIC.md -> FABRIC-0.md FABRIC-2.md -> FABRIC-1.md FABRIC-3.md -> FABRIC-2.md (the current/living document) FABRIC-4.md unchanged (new #3 to follow separately) Every cross-reference repo-wide updated to match, including doc-comment citations inside kernel source (.c/.h) files -- done via an ordered placeholder substitution (FABRIC-3.md->placeholder2, FABRIC-2.md-> placeholder1, FABRIC.md->placeholder0, then placeholders resolved to final names) in a single pass per file to avoid double-shifting already-renamed references. One line in capsules/font.4th grew past the 64-char block-format limit as a side effect of the longer filename; shortened it and reverified with mkcapsule --lint (34/34 pass) before rebuilding. Verified 3-arch boot to ok> (amd64/aarch64/riscv64, each in the foreground) after the fix; logs and DoE CSVs from this session's verification runs included per this repo's own audit-artifact convention. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019YcT3H2PQeyujrzjqS3Var
183 lines
7.1 KiB
C
183 lines
7.1 KiB
C
/*
|
||
StarForth — Steady-State Virtual Machine Runtime
|
||
Copyright (c) 2023–2025 Robert A. James. All rights reserved.
|
||
Licensed under the StarForth License, Version 1.0.
|
||
*/
|
||
|
||
/**
|
||
* arch.c (riscv64) - Architecture abstractions for StarKernel on RISC-V 64-bit
|
||
*/
|
||
|
||
#include "arch.h"
|
||
#include "console.h"
|
||
#include <stdint.h>
|
||
|
||
extern void riscv64_install_vectors(void);
|
||
extern char __kernel_start[]; /* same pattern pmm.c:67 already uses */
|
||
|
||
/* Item 4.3.5a. Prints satp's MODE/PPN fields and a known running address
|
||
* as a permanent boot record (same diagnostic-verbosity convention as
|
||
* apic.c's "AArch64: running at EL..." on the other ISA). Confirmed live,
|
||
* 2026-08-08: firmware (EDK2 RISC-V) leaves satp.MODE=10 (Sv57) active at
|
||
* kernel entry -- not Sv39/Sv48 as this file's own arch_mmu_init() stub
|
||
* comment assumed; that comment is stale, corrected below. __kernel_start
|
||
* printing here (0xbdd56982 in the confirming boot) landed inside the
|
||
* UEFI-reported total physical RAM window (0x80000000 + 1020 MB), near the
|
||
* top past the PMM-free region -- consistent with the kernel's own running
|
||
* range being identity-mapped (VA==PA) under firmware's Sv57 table, not
|
||
* some high canonical virtual range. That is the basis for the Bare-mode
|
||
* switch below being safe. */
|
||
static void print_hex64(uint64_t val)
|
||
{
|
||
char buf[19];
|
||
buf[0] = '0'; buf[1] = 'x';
|
||
for (int i = 15; i >= 0; i--) {
|
||
int nibble = (int)(val & 0xF);
|
||
buf[2 + i] = (char)(nibble < 10 ? '0' + nibble : 'a' + nibble - 10);
|
||
val >>= 4;
|
||
}
|
||
buf[18] = '\0';
|
||
console_puts(buf);
|
||
}
|
||
|
||
/**
|
||
* @brief Perform the earliest RISC-V architecture initialisation (no-op).
|
||
*
|
||
* RISC-V has no GDT or IDT; privilege separation is handled by the
|
||
* machine/supervisor/user execution modes (M/S/U), and the trap vector
|
||
* table is installed by writing @c stvec in @c arch_interrupts_init()
|
||
* via @c riscv64_install_vectors(). This stub satisfies the common
|
||
* @c arch_early_init() call site in @c kernel_main() without any
|
||
* RISC-V-specific action.
|
||
*/
|
||
void arch_early_init(void)
|
||
{
|
||
/* No GDT/IDT on RISC-V; privilege via exception levels */
|
||
|
||
uint64_t satp;
|
||
__asm__ volatile ("csrr %0, satp" : "=r"(satp));
|
||
uint64_t mode = satp >> 60;
|
||
uint64_t ppn = satp & 0xFFFFFFFFFFFULL;
|
||
|
||
console_println("riscv64 item 4.3.5a: satp state at kernel entry (before switch)");
|
||
console_puts(" satp.MODE = "); print_hex64(mode); console_puts("\n");
|
||
console_puts(" satp.PPN = "); print_hex64(ppn); console_puts("\n");
|
||
console_puts(" __kernel_start = "); print_hex64((uint64_t)__kernel_start); console_puts("\n");
|
||
|
||
/* Explicit switch to Bare mode (satp.MODE=0): this kernel builds no
|
||
* riscv64 page table of its own (vmm.c's is x86-64-shaped and never
|
||
* activated here, per its own load_cr3() no-op outside __x86_64__) and
|
||
* has no present use for virtual memory on this ISA, so there is no
|
||
* reason to inherit firmware's Sv57 mapping -- which is confirmed to
|
||
* have at least one hole (PLIC_THRESHOLD, FABRIC-0.md item 4.3.5a).
|
||
* ExitBootServices() has already completed several checkpoints before
|
||
* this function runs (ConOut/GOP done, BootServices exited per the
|
||
* "[CKPT 008]" trace), so nothing downstream depends on firmware's
|
||
* table surviving. Single asm block: the CSR write and SFENCE.VMA
|
||
* must not be separated by a compiler-scheduled memory access (RISC-V
|
||
* Privileged Spec §4.2.1, SFENCE.VMA ordering). */
|
||
__asm__ volatile (
|
||
"csrw satp, x0\n"
|
||
"sfence.vma\n"
|
||
::: "memory"
|
||
);
|
||
|
||
console_println("riscv64: satp cleared -- Bare mode, explicit (item 4.3.5a)");
|
||
}
|
||
|
||
/**
|
||
* @brief Enable supervisor-mode interrupts (RISC-V CSRSI sstatus).
|
||
*
|
||
* Issues @c CSRSI @c sstatus, @c 0x2 which sets bit 1 (@c SIE —
|
||
* Supervisor Interrupt Enable) in the @c sstatus CSR. While @c SIE = 1,
|
||
* pending supervisor-mode interrupts are taken. The @c memory clobber
|
||
* prevents the compiler from reordering stores across the barrier.
|
||
*
|
||
* Must be called after @c arch_interrupts_init() has installed the
|
||
* @c stvec trap handler, and after the PLIC driver has been configured
|
||
* to forward the desired interrupt sources.
|
||
*/
|
||
void arch_enable_interrupts(void)
|
||
{
|
||
__asm__ volatile ("csrsi sstatus, 0x2" ::: "memory");
|
||
}
|
||
|
||
/**
|
||
* @brief Disable supervisor-mode interrupts (RISC-V CSRCI sstatus).
|
||
*
|
||
* Issues @c CSRCI @c sstatus, @c 0x2 which clears bit 1 (@c SIE) in
|
||
* @c sstatus, masking all supervisor-mode interrupts. Machine-mode
|
||
* interrupts are unaffected. Used around critical sections in the
|
||
* single-threaded kernel. The @c memory clobber acts as a compiler
|
||
* barrier; pair with a @c FENCE instruction for a hardware barrier.
|
||
*/
|
||
void arch_disable_interrupts(void)
|
||
{
|
||
__asm__ volatile ("csrci sstatus, 0x2" ::: "memory");
|
||
}
|
||
|
||
/**
|
||
* @brief Halt the core until the next interrupt (RISC-V WFI).
|
||
*
|
||
* Issues the @c WFI (Wait For Interrupt) instruction in supervisor mode.
|
||
* The core enters a low-power state and resumes when a pending interrupt
|
||
* is detected (or after a platform-specific timeout). In the kernel panic
|
||
* path this is called inside an infinite loop with @c SIE cleared to stop
|
||
* the processor permanently. In the idle path it reduces power consumption
|
||
* between heartbeat ticks.
|
||
*
|
||
* The @c memory clobber prevents store-sinking across the @c WFI.
|
||
*/
|
||
void arch_halt(void)
|
||
{
|
||
__asm__ volatile ("wfi" ::: "memory");
|
||
}
|
||
|
||
void arch_cold_reset(void)
|
||
{
|
||
arch_disable_interrupts();
|
||
/* SBI SRST extension (0x53525354): sbi_system_reset, cold reboot = type 1 */
|
||
register unsigned long a7 __asm__("a7") = 0x53525354UL;
|
||
register unsigned long a6 __asm__("a6") = 0UL;
|
||
register unsigned long a0 __asm__("a0") = 1UL; /* cold reboot */
|
||
register unsigned long a1 __asm__("a1") = 0UL; /* no reason */
|
||
__asm__ volatile ("ecall" : "+r"(a0) : "r"(a1), "r"(a6), "r"(a7) : "memory");
|
||
for (;;) __asm__ volatile ("wfi" ::: "memory");
|
||
}
|
||
|
||
/**
|
||
* @brief Read the RISC-V CPU cycle counter (@c rdcycle).
|
||
*
|
||
* Issues the @c RDCYCLE pseudo-instruction (a @c CSRRS on @c cycle, CSR
|
||
* 0xC00) to read the 64-bit hardware performance counter that counts
|
||
* elapsed clock cycles since reset. On RISC-V the cycle counter is the
|
||
* architectural equivalent of the x86-64 TSC.
|
||
*
|
||
* Unlike the AArch64 @c CNTPCT_EL0, the RISC-V @c cycle register is a
|
||
* per-hart counter and is not architecturally guaranteed to be synchronised
|
||
* across harts. For single-core LithosAnanke this is not a concern.
|
||
* Frequency is not architecturally specified; @c timer_init() assumes
|
||
* 1 GHz for QEMU @c virt board compatibility.
|
||
*
|
||
* @return Current 64-bit cycle counter value; frequency platform-dependent.
|
||
*/
|
||
uint64_t arch_read_timestamp(void)
|
||
{
|
||
uint64_t val;
|
||
__asm__ volatile ("rdcycle %0" : "=r"(val));
|
||
return val;
|
||
}
|
||
|
||
/**
|
||
* @brief Initialise the RISC-V MMU (stub — deferred to a later milestone).
|
||
*
|
||
* Full Sv39/Sv48 page-table setup (SATP, PMP, etc.) is deferred to a
|
||
* later milestone. This stub satisfies the common @c arch_mmu_init()
|
||
* call site shared across all three supported ISAs. The VMM subsystem
|
||
* (@c vmm.c) handles page-table management independently of this hook.
|
||
*/
|
||
void arch_mmu_init(void)
|
||
{
|
||
/* Stub: Sv39/Sv48 bring-up deferred */
|
||
}
|