diff options
author | Himbeer <himbeer@disroot.org> | 2024-05-13 12:23:53 +0200 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-05-13 12:23:53 +0200 |
commit | 17b4d61fb3a3692203b124926ee84fa099fe3e38 (patch) | |
tree | 2fae7bc7a215780a773d2bc5af465e86edd9a4f4 /src | |
parent | a2dde064100021085407bf47ae40425689ab13e7 (diff) |
Initial U-mode demo
Fixes #14.
Diffstat (limited to 'src')
-rw-r--r-- | src/instructions.zig | 6 | ||||
-rw-r--r-- | src/interrupts.zig | 2 | ||||
-rw-r--r-- | src/main.zig | 13 | ||||
-rw-r--r-- | src/paging.zig | 31 | ||||
-rw-r--r-- | src/process.zig | 59 | ||||
-rw-r--r-- | src/trap.zig | 2 |
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 }; |