Files
LithosAnanake/src/starkernel/arch/riscv64/arch.c
T
Robert Allan JamesandClaude Sonnet 5 b031b802e3 Rename FABRIC series: FABRIC.md->0, FABRIC-2.md->1, FABRIC-3.md->2, FABRIC-4.md unchanged
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
2026-09-04 11:22:51 -04:00

183 lines
7.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 20232025 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 */
}