aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-05-13 12:23:53 +0200
committerHimbeer <himbeer@disroot.org>2024-05-13 12:23:53 +0200
commit17b4d61fb3a3692203b124926ee84fa099fe3e38 (patch)
tree2fae7bc7a215780a773d2bc5af465e86edd9a4f4 /src
parenta2dde064100021085407bf47ae40425689ab13e7 (diff)
Initial U-mode demo
Fixes #14.
Diffstat (limited to 'src')
-rw-r--r--src/instructions.zig6
-rw-r--r--src/interrupts.zig2
-rw-r--r--src/main.zig13
-rw-r--r--src/paging.zig31
-rw-r--r--src/process.zig59
-rw-r--r--src/trap.zig2
6 files changed, 71 insertions, 42 deletions
diff --git a/src/instructions.zig b/src/instructions.zig
index d286f0b..818a35f 100644
--- a/src/instructions.zig
+++ b/src/instructions.zig
@@ -45,15 +45,17 @@ pub fn stackPointer() usize {
}
pub const setSatp = setCsrFn(paging.Satp, "satp").?;
+pub const setSscratch = setCsrFn(usize, "sscratch").?;
+pub const setSepc = setCsrFn(usize, "sepc").?;
pub fn setCsrFn(comptime T: type, csr: []const u8) ?fn (T) void {
- if (csr.len > 5) return null;
+ if (csr.len > 8) return null;
return struct {
fn setCsr(value: T) void {
const bits: usize = @bitCast(value);
- comptime var buf = [_]u8{0} ** 20;
+ comptime var buf = [_]u8{0} ** 23;
asm volatile (std.fmt.bufPrint(buf[0..], "csrw {s}, %[bits]", .{csr}) catch unreachable
:
diff --git a/src/interrupts.zig b/src/interrupts.zig
index 9b030bc..a2233aa 100644
--- a/src/interrupts.zig
+++ b/src/interrupts.zig
@@ -223,7 +223,7 @@ export fn supervisorTrapVector() align(4) callconv(.Naked) noreturn {
\\ mv a3, zero
\\ csrr a4, sstatus
\\ mv a5, t5
- \\ la sp, _stack_end
+ \\ la sp, _stvec_stack_end
\\ call handleTrap
\\
\\ csrw sepc, a0
diff --git a/src/main.zig b/src/main.zig
index 8c61156..058fe36 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -12,6 +12,7 @@ const mem = @import("mem.zig");
const paging = @import("paging.zig");
const pci = @import("pci.zig");
const plic = @import("plic.zig");
+const process = @import("process.zig");
const time = @import("sbi/time.zig");
const Error = error{
@@ -63,6 +64,7 @@ fn run(hart_id: usize, fdt_blob: *fdt.RawHeader, w: debug_console.Writer) !noret
try w.print(".data: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (rw-)\r\n", .{ @intFromPtr(paging.data_start), @intFromPtr(paging.data_end) });
try w.print(".bss: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (rw-)\r\n", .{ @intFromPtr(paging.bss_start), @intFromPtr(paging.bss_end) });
try w.print("Stack: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (rw-)\r\n", .{ @intFromPtr(paging.stack_start), @intFromPtr(paging.stack_end) });
+ try w.print("Trap Stack: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (rw-)\r\n", .{ @intFromPtr(paging.stvec_stack_start), @intFromPtr(paging.stvec_stack_end) });
try w.print("\r\n", .{});
try w.print("Heap: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (rw-)\r\n", .{ @intFromPtr(paging.heap_start), @intFromPtr(paging.heap_end) });
try w.print("\r\n", .{});
@@ -70,13 +72,7 @@ fn run(hart_id: usize, fdt_blob: *fdt.RawHeader, w: debug_console.Writer) !noret
try w.print("=============================================================\r\n", .{});
try w.print("\r\n", .{});
- try kmem.identityMapRange(paging.mmio_start, paging.mmio_end, paging.EntryFlags.readWrite);
- try kmem.identityMapRange(@intFromPtr(paging.text_start), @intFromPtr(paging.text_end), paging.EntryFlags.readExec);
- try kmem.identityMapRange(@intFromPtr(paging.rodata_start), @intFromPtr(paging.rodata_end), paging.EntryFlags.readOnly);
- try kmem.identityMapRange(@intFromPtr(paging.data_start), @intFromPtr(paging.data_end), paging.EntryFlags.readWrite);
- try kmem.identityMapRange(@intFromPtr(paging.bss_start), @intFromPtr(paging.bss_end), paging.EntryFlags.readWrite);
- try kmem.identityMapRange(@intFromPtr(paging.stack_start), @intFromPtr(paging.stack_end), paging.EntryFlags.readWrite);
- try kmem.identityMapRange(@intFromPtr(paging.heap_start), @intFromPtr(paging.heap_end), paging.EntryFlags.readWrite);
+ try kmem.mapKernel();
try kmem.identityMapRange(@intFromPtr(fdt_blob), @intFromPtr(fdt_blob) + dt_header.total_size, paging.EntryFlags.readOnly);
instructions.setSatp(kmem.satp(0));
@@ -131,6 +127,9 @@ fn run(hart_id: usize, fdt_blob: *fdt.RawHeader, w: debug_console.Writer) !noret
@as(*volatile u8, @ptrFromInt(0x1)).* = 0;
try w.print("Segfault successful\r\n", .{});
+ try w.print("Enter process demo\r\n", .{});
+ try process.demo();
+
while (true) {
asm volatile ("wfi");
}
diff --git a/src/paging.zig b/src/paging.zig
index 95ed048..b77ea96 100644
--- a/src/paging.zig
+++ b/src/paging.zig
@@ -19,6 +19,8 @@ pub const bss_start = @extern(*anyopaque, .{ .name = "_bss_start" });
pub const bss_end = @extern(*anyopaque, .{ .name = "_bss_end" });
pub const stack_start = @extern(*anyopaque, .{ .name = "_stack_start" });
pub const stack_end = @extern(*anyopaque, .{ .name = "_stack_end" });
+pub const stvec_stack_start = @extern(*anyopaque, .{ .name = "_stvec_stack_start" });
+pub const stvec_stack_end = @extern(*anyopaque, .{ .name = "_stvec_stack_end" });
pub const heap_start = @extern(*anyopaque, .{ .name = "_heap_start" });
pub const heap_end = @extern(*anyopaque, .{ .name = "_heap_end" });
@@ -420,6 +422,17 @@ pub const Table = struct {
.mode = .sv39,
};
}
+
+ pub fn mapKernel(root: *Table) !void {
+ try root.identityMapRange(mmio_start, mmio_end, EntryFlags.readWrite);
+ try root.identityMapRange(@intFromPtr(text_start), @intFromPtr(text_end), EntryFlags.readExec);
+ try root.identityMapRange(@intFromPtr(rodata_start), @intFromPtr(rodata_end), EntryFlags.readOnly);
+ try root.identityMapRange(@intFromPtr(data_start), @intFromPtr(data_end), EntryFlags.readWrite);
+ try root.identityMapRange(@intFromPtr(bss_start), @intFromPtr(bss_end), EntryFlags.readWrite);
+ try root.identityMapRange(@intFromPtr(stack_start), @intFromPtr(stack_end), EntryFlags.readWrite);
+ try root.identityMapRange(@intFromPtr(stvec_stack_start), @intFromPtr(stvec_stack_end), EntryFlags.readWrite);
+ try root.identityMapRange(@intFromPtr(heap_start), @intFromPtr(heap_end), EntryFlags.readWrite);
+ }
};
pub fn init() void {
@@ -477,32 +490,32 @@ pub fn alloc(n: usize) !*void {
// Free (contiguous) memory page(s). Provides limited protection against double-frees.
pub fn free(ptr: *void) !void {
- const num_pages = @intFromPtr(heapSize()) / page_size;
+ const num_pages = heapSize() / page_size;
// Start allocating beyond page descriptors.
- const alloc_start: *void = @ptrFromInt(pageAlign(@intFromPtr(heap_start) + num_pages * @sizeOf(Page)));
+ const alloc_start = pageAlign(@intFromPtr(heap_start) + num_pages * @sizeOf(Page));
// Restore the address to the page descriptor flags from the address of its contents
// by restoring the descriptor number and indexing the descriptor table
// at the start of the heap using it.
- const addr = @intFromPtr(heap_start) + (ptr - alloc_start) / page_size;
+ const addr = @intFromPtr(heap_start) + (@intFromPtr(ptr) - alloc_start) / page_size;
// Ensure basic address sanity.
// Does not check descriptor table bounds.
- if (addr < @intFromPtr(heap_start) or addr >= @intFromPtr(heap_start) + @intFromPtr(heapSize())) return AllocError.OutOfRange;
+ if (addr < @intFromPtr(heap_start) or addr >= @intFromPtr(heap_start) + heapSize()) return AllocError.OutOfRange;
- const page: [*]Page = @ptrCast(addr);
+ var page: [*]Page = @ptrFromInt(addr);
// Mark all but the last page as free.
// A double-free check is performed on the last page before it is freed.
- while (@bitCast(page.flags.active) and !@bitCast(page.flags.last)) : (page += 1) {
- page.flags = .clear;
+ while (@bitCast(page[0].flags.active) and !@bitCast(page[0].flags.last)) : (page += 1) {
+ page[0].flags = Page.Flags.clear;
}
// Free page encountered, but it isn't marked as the last. Potential double-free.
- if (!page.isLast()) return AllocError.DoubleFree;
+ if (!@bitCast(page[0].flags.last)) return AllocError.DoubleFree;
// Mark the last page as free.
- page.clear();
+ page[0].flags = Page.Flags.clear;
}
// Allocate memory pages and overwrite their contents with zeroes for added security.
diff --git a/src/process.zig b/src/process.zig
index 61103bf..9577bc3 100644
--- a/src/process.zig
+++ b/src/process.zig
@@ -6,16 +6,15 @@ const std = @import("std");
const instructions = @import("instructions.zig");
const interrupts = @import("interrupts.zig");
-const mem = @import("mem.zig");
const paging = @import("paging.zig");
+const trap = @import("trap.zig");
const num_stack_pages = 2;
-var next_pid = 1;
-var previous_scheduled = 1;
+var next_pid: u16 = 1;
var list = std.mem.zeroInit(std.DoublyLinkedList(*Info));
-pub const State = enum {
+pub const State = enum(u8) {
waiting,
active,
sleeping,
@@ -24,7 +23,7 @@ pub const State = enum {
pub const Info = extern struct {
id: u16,
- trap_frame: interrupts.TrapFrame,
+ trap_frame: trap.Frame,
stack: [*]u8,
pc: usize,
page_table: *paging.Table,
@@ -37,34 +36,35 @@ pub const Info = extern struct {
}
pub fn satp(self: *const Info) paging.Satp {
- return mem.satp(self.page_table, self.pid);
+ return self.page_table.satp(self.id);
}
};
-fn new(entry: *fn () void) !Info {
+fn new(entry: usize) !Info {
const stack = try paging.alloc(num_stack_pages);
- errdefer paging.free(stack);
+ errdefer paging.free(stack) catch {};
- const procmem = try paging.zeroedAlloc(1);
- errdefer paging.free(procmem);
+ const procmem: *paging.Table = @alignCast(@ptrCast(try paging.zeroedAlloc(1)));
+ errdefer paging.free(@ptrCast(procmem)) catch {};
- const proc = .{
+ var proc = Info{
.id = next_pid,
- .trap_frame = std.mem.zeroInit(interrupts.TrapFrame),
- .stack = stack,
- .pc = @ptrCast(entry),
+ .trap_frame = std.mem.zeroInit(trap.Frame, .{}),
+ .stack = @alignCast(@ptrCast(stack)),
+ .pc = entry,
.page_table = procmem,
.state = .waiting,
};
- const stack_top = proc.stack + num_stack_pages * paging.page_size;
+ const stack_top = @intFromPtr(proc.stack) + num_stack_pages * paging.page_size;
proc.trap_frame.general_purpose_registers[2] = stack_top;
- try procmem.map(@intFromPtr(entry), @intFromPtr(entry), paging.EntryFlags.userReadExec, 0);
+ try procmem.mapKernel();
+ try procmem.map(entry, entry, paging.EntryFlags.userReadExec, 0);
// Not using identityMapRange because this is going to be expanded for non-relocatable binaries.
for (0..num_stack_pages) |page| {
- const vaddr = page * paging.page_size;
- const paddr = page * paging.page_size;
+ const vaddr = @intFromPtr(proc.stack) + page * paging.page_size;
+ const paddr = @intFromPtr(proc.stack) + page * paging.page_size;
try procmem.map(vaddr, paddr, paging.EntryFlags.userReadWrite, 0);
}
@@ -88,13 +88,13 @@ fn switchTo(proc: *const Info) noreturn {
asm volatile (
\\ csrr t0, sstatus
\\ li t1, 0x100
- \\ noti t1, t1
- \\ andi t0, t0, t1
+ \\ not t1, t1
+ \\ and t0, t0, t1
\\ csrw sstatus, t0
::: "t0", "t1");
instructions.setSepc(proc.pc);
- instructions.setSatp(proc.buildSatp());
+ instructions.setSatp(proc.satp());
// Probably not always needed. Let's not take the risk for now.
asm volatile (
@@ -138,6 +138,21 @@ fn switchTo(proc: *const Info) noreturn {
\\
\\ sret
);
+
+ unreachable;
}
-pub fn demo() void {}
+pub fn demo() !void {
+ const entry: [*]u8 = @alignCast(@ptrCast(try paging.zeroedAlloc(1)));
+ defer paging.free(@ptrCast(entry)) catch {};
+
+ entry[0] = 0x73;
+ entry[1] = 0x00;
+ entry[2] = 0x00;
+ entry[3] = 0x00;
+
+ var proc = try new(@intFromPtr(entry));
+ switchTo(&proc);
+
+ while (true) asm volatile ("wfi");
+}
diff --git a/src/trap.zig b/src/trap.zig
index 8435072..4460cfd 100644
--- a/src/trap.zig
+++ b/src/trap.zig
@@ -6,6 +6,6 @@ pub const Frame = extern struct {
general_purpose_registers: [32]usize, // Offset: 0
floating_point_registers: [32]usize, // Offset: 256
satp: usize, // Offset: 512
- stack_pointer: *u8, // Offset: 520
+ stack_pointer: *allowzero u8, // Offset: 520
hart_id: usize, // Offset: 528
};