127 lines
3.3 KiB
Zig
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"
|
|
);
|
|
}
|