Implement S-mode exceptions
This commit is contained in:
@@ -6,6 +6,7 @@ const regs = @import("regs.zig");
|
|||||||
const dtb = @import("../../util/dtb.zig");
|
const dtb = @import("../../util/dtb.zig");
|
||||||
const physMemory = @import("../../mem/phys.zig");
|
const physMemory = @import("../../mem/phys.zig");
|
||||||
const arena = @import("../../arena.zig");
|
const arena = @import("../../arena.zig");
|
||||||
|
const exception = @import("exception.zig");
|
||||||
|
|
||||||
const log = debug.log;
|
const log = debug.log;
|
||||||
const arch = kernel.arch;
|
const arch = kernel.arch;
|
||||||
@@ -83,6 +84,9 @@ fn bspUpperEntry(realAddress: usize, unused: usize) callconv(.C) noreturn {
|
|||||||
rv64RelocateKernel(relOffset, relaStart, relaEnd);
|
rv64RelocateKernel(relOffset, relaStart, relaEnd);
|
||||||
vmm.unmapEarly();
|
vmm.unmapEarly();
|
||||||
|
|
||||||
|
// Setup exception handling
|
||||||
|
exception.init();
|
||||||
|
|
||||||
debug.log.setWriteFn(&sbi.debugPrintByte);
|
debug.log.setWriteFn(&sbi.debugPrintByte);
|
||||||
kernel.mem.PhysicalAddress.gVirtualizeBase = 0;
|
kernel.mem.PhysicalAddress.gVirtualizeBase = 0;
|
||||||
kernel.mem.PhysicalAddress.gVirtualizeSize = vmm.virtualizeRange();
|
kernel.mem.PhysicalAddress.gVirtualizeSize = vmm.virtualizeRange();
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
const regs = @import("regs.zig");
|
||||||
|
const debug = @import("../../debug.zig");
|
||||||
|
const arch = @import("../../kernel.zig").arch;
|
||||||
|
|
||||||
|
const log = debug.log;
|
||||||
|
|
||||||
|
extern fn __rv64_exception_vectors() void;
|
||||||
|
|
||||||
|
pub const ExceptionCause = enum(u64) {
|
||||||
|
misaligned_instruction = 0,
|
||||||
|
instruction_access_fault = 1,
|
||||||
|
illegal_instruction = 2,
|
||||||
|
breakpoint = 3,
|
||||||
|
load_address_misaligned = 4,
|
||||||
|
load_access_fault = 5,
|
||||||
|
store_address_misaligned = 6,
|
||||||
|
store_access_fault = 7,
|
||||||
|
ecall_umode = 8,
|
||||||
|
ecall_smode = 9,
|
||||||
|
ecall_mmode = 11,
|
||||||
|
instruction_page_fault = 12,
|
||||||
|
load_page_fault = 13,
|
||||||
|
store_page_fault = 15,
|
||||||
|
_,
|
||||||
|
|
||||||
|
pub fn name(self: @This()) []const u8 {
|
||||||
|
return switch (self) {
|
||||||
|
.misaligned_instruction => "misaligned instruction",
|
||||||
|
.instruction_access_fault => "instruction access fault",
|
||||||
|
.illegal_instruction => "illegal instruction",
|
||||||
|
.breakpoint => "breakpoint",
|
||||||
|
.load_address_misaligned => "load address misaligned",
|
||||||
|
.load_access_fault => "load access fault",
|
||||||
|
.store_address_misaligned => "store address misaligned",
|
||||||
|
.store_access_fault => "store access fault",
|
||||||
|
.ecall_umode => "ecall umode",
|
||||||
|
.ecall_smode => "ecall smode",
|
||||||
|
.ecall_mmode => "ecall mmode",
|
||||||
|
.instruction_page_fault => "instruction page fault",
|
||||||
|
.load_page_fault => "load page fault",
|
||||||
|
.store_page_fault => "store page fault",
|
||||||
|
else => "<unknown>",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ExceptionFrame = extern struct {
|
||||||
|
ra: usize,
|
||||||
|
gp: usize,
|
||||||
|
tN: [7]usize,
|
||||||
|
sN: [12]usize,
|
||||||
|
aN: [8]usize,
|
||||||
|
|
||||||
|
pub fn dump(self: *const @This(), comptime level: log.Level) void {
|
||||||
|
log.writeln(level, " ra = 0x{x:016} gp = 0x{x:016}", .{ self.ra, self.gp });
|
||||||
|
log.writeln(level, " t0 = 0x{x:016} t1 = 0x{x:016}", .{ self.tN[0], self.tN[1] });
|
||||||
|
log.writeln(level, " t2 = 0x{x:016} t3 = 0x{x:016}", .{ self.tN[2], self.tN[3] });
|
||||||
|
log.writeln(level, " t4 = 0x{x:016} t5 = 0x{x:016}", .{ self.tN[4], self.tN[5] });
|
||||||
|
log.writeln(level, " t6 = 0x{x:016}", .{ self.tN[6] });
|
||||||
|
log.writeln(level, " s0 = 0x{x:016} s1 = 0x{x:016}", .{ self.sN[0], self.sN[1] });
|
||||||
|
log.writeln(level, " s2 = 0x{x:016} s1 = 0x{x:016}", .{ self.sN[2], self.sN[3] });
|
||||||
|
log.writeln(level, " s4 = 0x{x:016} s6 = 0x{x:016}", .{ self.sN[4], self.sN[5] });
|
||||||
|
log.writeln(level, " s6 = 0x{x:016} s7 = 0x{x:016}", .{ self.sN[6], self.sN[7] });
|
||||||
|
log.writeln(level, " s8 = 0x{x:016} s9 = 0x{x:016}", .{ self.sN[8], self.sN[9] });
|
||||||
|
log.writeln(level, "s10 = 0x{x:016} s11 = 0x{x:016}", .{ self.sN[10], self.sN[11] });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init() void {
|
||||||
|
const base = @intFromPtr(&__rv64_exception_vectors);
|
||||||
|
|
||||||
|
regs.STVEC.write(.{
|
||||||
|
.MODE = .vectored,
|
||||||
|
.BASE = @intCast(base >> 2),
|
||||||
|
});
|
||||||
|
|
||||||
|
asm volatile ("":::"memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn rv64SmodeTrapGeneral(frame: *ExceptionFrame) callconv(.C) void {
|
||||||
|
const scause = regs.SCAUSE.read();
|
||||||
|
if (scause.INTERRUPT) {
|
||||||
|
return rv64SmodeTrapInterrupt(frame);
|
||||||
|
}
|
||||||
|
const cause = @as(ExceptionCause, @enumFromInt(scause.CODE));
|
||||||
|
const epc = regs.SEPC.get();
|
||||||
|
const tval = regs.STVAL.get();
|
||||||
|
|
||||||
|
log.err("S-mode exception:", .{});
|
||||||
|
log.err(" Cause: {s} (0x{x})", .{ cause.name(), scause.CODE });
|
||||||
|
log.err(" stval = 0x{x:016} sepc = 0x{x:016}", .{ tval, epc });
|
||||||
|
frame.dump(.err);
|
||||||
|
|
||||||
|
@panic("Unhandled exception in S-mode");
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn rv64SmodeTrapInterrupt(frame: *ExceptionFrame) callconv(.C) void {
|
||||||
|
_ = frame;
|
||||||
|
log.todo("rv64SmodeTrapInterrupt", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
comptime {
|
||||||
|
asm (@embedFile("vectors.S"));
|
||||||
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
fn makeRegister(comptime name: []const u8, comptime bits: type) type {
|
fn makeRegister(comptime name: []const u8, comptime bits: type) type {
|
||||||
const repr = @typeInfo(bits).@"struct".backing_integer.?;
|
const repr = switch (@typeInfo(bits)) {
|
||||||
|
.@"struct" => |s| s.backing_integer.?,
|
||||||
|
else => bits,
|
||||||
|
};
|
||||||
return enum(repr) {
|
return enum(repr) {
|
||||||
pub fn set(value: repr) void {
|
pub fn set(value: repr) void {
|
||||||
asm volatile ("csrw " ++ name ++ ", %[value]"::[value]"r"(value));
|
asm volatile ("csrw " ++ name ++ ", %[value]"::[value]"r"(value));
|
||||||
@@ -21,8 +24,6 @@ fn makeRegister(comptime name: []const u8, comptime bits: type) type {
|
|||||||
pub fn read() bits {
|
pub fn read() bits {
|
||||||
return @bitCast(get());
|
return @bitCast(get());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub usingnamespace bits;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,3 +56,19 @@ pub const SSTATUS = makeRegister("sstatus", packed struct(u64) {
|
|||||||
// 19..64
|
// 19..64
|
||||||
_3: u45 = 0,
|
_3: u45 = 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pub const STVEC = makeRegister("stvec", packed struct(u64) {
|
||||||
|
MODE: enum(u2) {
|
||||||
|
direct = 0,
|
||||||
|
vectored = 1,
|
||||||
|
} = .direct,
|
||||||
|
BASE: u62 = 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
pub const SCAUSE = makeRegister("scause", packed struct(u64) {
|
||||||
|
CODE: u63 = 0,
|
||||||
|
INTERRUPT: bool = false
|
||||||
|
});
|
||||||
|
|
||||||
|
pub const STVAL = makeRegister("stval", u64);
|
||||||
|
pub const SEPC = makeRegister("sepc", u64);
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
.global __rv64_exception_vectors
|
||||||
|
.extern rv64SmodeTrapGeneral
|
||||||
|
.extern rv64SmodeTrapInterrupt
|
||||||
|
|
||||||
|
// ra, gp, 7×tN, 12×sN, 8×aN
|
||||||
|
.set GP_REGS_SIZE, (2 + 7 + 12 + 8) * 8
|
||||||
|
.set TRAP_CONTEXT_SIZE, (GP_REGS_SIZE)
|
||||||
|
|
||||||
|
.macro SAVE_GP_REGS
|
||||||
|
sd ra, 0 * 8(sp)
|
||||||
|
sd gp, 1 * 8(sp)
|
||||||
|
|
||||||
|
sd t0, 2 * 8(sp)
|
||||||
|
sd t1, 3 * 8(sp)
|
||||||
|
sd t2, 4 * 8(sp)
|
||||||
|
sd t3, 5 * 8(sp)
|
||||||
|
sd t4, 6 * 8(sp)
|
||||||
|
sd t5, 7 * 8(sp)
|
||||||
|
sd t6, 8 * 8(sp)
|
||||||
|
|
||||||
|
sd s0, 9 * 8(sp)
|
||||||
|
sd s1, 10 * 8(sp)
|
||||||
|
sd s2, 11 * 8(sp)
|
||||||
|
sd s3, 12 * 8(sp)
|
||||||
|
sd s4, 13 * 8(sp)
|
||||||
|
sd s5, 14 * 8(sp)
|
||||||
|
sd s6, 15 * 8(sp)
|
||||||
|
sd s7, 16 * 8(sp)
|
||||||
|
sd s8, 17 * 8(sp)
|
||||||
|
sd s9, 18 * 8(sp)
|
||||||
|
sd s10, 19 * 8(sp)
|
||||||
|
sd s11, 20 * 8(sp)
|
||||||
|
|
||||||
|
sd a0, 21 * 8(sp)
|
||||||
|
sd a1, 22 * 8(sp)
|
||||||
|
sd a2, 23 * 8(sp)
|
||||||
|
sd a3, 24 * 8(sp)
|
||||||
|
sd a4, 25 * 8(sp)
|
||||||
|
sd a5, 26 * 8(sp)
|
||||||
|
sd a6, 27 * 8(sp)
|
||||||
|
sd a7, 28 * 8(sp)
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro SMODE_TRAP n, handler
|
||||||
|
.type __rv64_smode_trap_\n, @function
|
||||||
|
__rv64_smode_trap_\n:
|
||||||
|
// TODO properly handle traps coming from U-mode
|
||||||
|
// TODO save CSRs
|
||||||
|
addi sp, sp, -(TRAP_CONTEXT_SIZE)
|
||||||
|
SAVE_GP_REGS
|
||||||
|
mv a0, sp
|
||||||
|
|
||||||
|
call \handler
|
||||||
|
|
||||||
|
// TODO return from exception
|
||||||
|
j .
|
||||||
|
.size __rv64_smode_trap_\n, . - __rv64_smode_trap_\n
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.pushsection .text
|
||||||
|
.option push
|
||||||
|
.option norvc
|
||||||
|
|
||||||
|
.p2align 4
|
||||||
|
.type __rv64_exception_vectors, %function
|
||||||
|
__rv64_exception_vectors:
|
||||||
|
j __rv64_smode_trap_0
|
||||||
|
j __rv64_smode_trap_1
|
||||||
|
j __rv64_smode_trap_2
|
||||||
|
j __rv64_smode_trap_3
|
||||||
|
j __rv64_smode_trap_4
|
||||||
|
j __rv64_smode_trap_5
|
||||||
|
j __rv64_smode_trap_6
|
||||||
|
j __rv64_smode_trap_7
|
||||||
|
j __rv64_smode_trap_8
|
||||||
|
j __rv64_smode_trap_9
|
||||||
|
j __rv64_smode_trap_10
|
||||||
|
j __rv64_smode_trap_11
|
||||||
|
j __rv64_smode_trap_12
|
||||||
|
j __rv64_smode_trap_13
|
||||||
|
j __rv64_smode_trap_14
|
||||||
|
j __rv64_smode_trap_15
|
||||||
|
.size __rv64_exception_vectors, . - __rv64_exception_vectors
|
||||||
|
|
||||||
|
SMODE_TRAP 0, rv64SmodeTrapGeneral
|
||||||
|
SMODE_TRAP 1, rv64SmodeTrapInterrupt
|
||||||
|
SMODE_TRAP 2, rv64SmodeTrapInterrupt
|
||||||
|
SMODE_TRAP 3, rv64SmodeTrapInterrupt
|
||||||
|
SMODE_TRAP 4, rv64SmodeTrapInterrupt
|
||||||
|
SMODE_TRAP 5, rv64SmodeTrapInterrupt
|
||||||
|
SMODE_TRAP 6, rv64SmodeTrapInterrupt
|
||||||
|
SMODE_TRAP 7, rv64SmodeTrapInterrupt
|
||||||
|
SMODE_TRAP 8, rv64SmodeTrapInterrupt
|
||||||
|
SMODE_TRAP 9, rv64SmodeTrapInterrupt
|
||||||
|
SMODE_TRAP 10, rv64SmodeTrapInterrupt
|
||||||
|
SMODE_TRAP 11, rv64SmodeTrapInterrupt
|
||||||
|
SMODE_TRAP 12, rv64SmodeTrapInterrupt
|
||||||
|
SMODE_TRAP 13, rv64SmodeTrapInterrupt
|
||||||
|
SMODE_TRAP 14, rv64SmodeTrapInterrupt
|
||||||
|
SMODE_TRAP 15, rv64SmodeTrapInterrupt
|
||||||
|
|
||||||
|
.option pop // norvc
|
||||||
|
.popsection // .text
|
||||||
@@ -34,6 +34,12 @@ pub export fn kernel_main() callconv(.C) noreturn {
|
|||||||
thread.addThread(t);
|
thread.addThread(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ptr: *const u32 = @ptrFromInt(0x1111111111111114);
|
||||||
|
const z = ptr.*;
|
||||||
|
_ = z;
|
||||||
|
while (true) {}
|
||||||
|
|
||||||
thread.enter();
|
thread.enter();
|
||||||
|
|
||||||
arch.halt();
|
arch.halt();
|
||||||
|
|||||||
Reference in New Issue
Block a user