Files
zing/src/arch/riscv64.zig
T

127 lines
3.3 KiB
Zig

//! RISC-V 64-bit platform-specific implementations.
const boot = @import("riscv64/boot.zig");
const regs = @import("riscv64/regs.zig");
const thread = @import("../thread.zig");
const std = @import("std");
const builtin = @import("builtin");
const Arena = @import("../arena.zig").Arena;
export const _ = boot.rv64_bsp_lower_entry;
extern fn __rv64_enter_task(cx: *Context) callconv(.C) noreturn;
extern fn __rv64_switch_task(dcx: *Context, scx: *Context) callconv(.C) void;
extern fn __rv64_task_enter_kernel() callconv(.C) noreturn;
fn idle_function() callconv(.naked) noreturn {
asm volatile ("j .");
}
/// This CPU's HART (HARdware Thread) ID.
pub threadlocal var t_hart_id: u32 = 0;
/// RISC-V task context
pub const Context = extern struct {
const STACK_SIZE: usize = 8192;
// Has to be exactly at offset 0x00, used in assembly.
kstack: thread.KStack(STACK_SIZE),
/// Constructs an idle context struct.
pub fn idle() @This() {
const entry = @intFromPtr(&idle_function);
return Context.kernel(entry, 0);
}
/// Constructs a kernel task context with entry point in `pc` and an `arg`ument.
pub fn kernel(pc: usize, arg: usize) @This() {
var ks = thread.KStack(STACK_SIZE).create();
const entry = @intFromPtr(&__rv64_task_enter_kernel);
ks.push(pc);
ks.push(arg);
ks.push(0); // x8/s0/fp
ks.push(0); // x9/s1
ks.push(0); // x18/s2
ks.push(0); // x19/s3
ks.push(0); // x20/s4
ks.push(0); // x21/s5
ks.push(0); // x22/s6
ks.push(0); // x23/s7
ks.push(0); // x24/s8
ks.push(0); // x25/s9
ks.push(0); // x26/s10
ks.push(0); // x27/s11
ks.push(0); // x4/gp
ks.push(entry); // x1/ra return address
return .{ .kstack = ks };
}
/// Low-level task context entry function.
pub fn enter(self: *@This()) noreturn {
__rv64_enter_task(self);
}
/// Low-level task context switch function.
pub fn switch_from(self: *@This(), from: *@This()) void {
__rv64_switch_task(self, from);
}
};
pub inline fn halt() noreturn {
while (true) {
_ = set_interrupt_mask(true);
wait_for_interrupt();
}
}
pub inline fn set_interrupt_mask(mask: bool) bool {
const old = interrupt_mask();
if (mask) {
regs.SSTATUS.modify(.{}, .{ .SIE = true });
} else {
regs.SSTATUS.modify(.{ .SIE = true }, .{});
}
return old;
}
pub fn interrupt_mask() bool {
return regs.SSTATUS.read().SIE;
}
pub inline fn wait_for_interrupt() void {
asm volatile ("wfi");
}
pub inline fn spin_hint() void {
// Don't want to explicitly enable Zihintpause ext, so just paste this as raw opcode
asm volatile (".word 0x0100000f");
}
pub inline fn barrier(comptime ordering: std.builtin.AtomicOrder) void {
switch (ordering) {
.acquire => {
asm volatile ("fence rw, w");
},
.release => {
asm volatile ("fence w, rw");
},
.acq_rel, .seq_cst => {
asm volatile ("fence rw, rw");
},
.unordered, .monotonic => {},
}
asm volatile ("" ::: "memory");
}
pub inline fn set_thread_pointer(tp: usize) void {
asm volatile ("mv tp, %[tp]"
:
: [tp] "r" (tp),
: "memory"
);
}