From e392799b914521ff6405cad9087f488b0045c986 Mon Sep 17 00:00:00 2001 From: Jack Halford Date: Fri, 7 Feb 2020 15:28:22 +0100 Subject: [PATCH] wip: std.mem.allocator --- build.zig | 11 +++--- qemu.sh | 21 ++++------- src/console.zig | 2 +- src/driver/ide.zig | 5 +-- src/main.zig | 2 +- src/ring_buffer.zig | 11 +++--- src/task.zig | 22 ++++++------ src/vga.zig | 6 ++-- src/vmem.zig | 86 +++++++++++++++++++++++++++++++-------------- 9 files changed, 98 insertions(+), 68 deletions(-) diff --git a/build.zig b/build.zig index e7ecfce..5cc7d1a 100644 --- a/build.zig +++ b/build.zig @@ -15,18 +15,17 @@ pub fn build(b: *Builder) void { kernel.addAssemblyFile("src/arch/x86/switch_tasks.s"); kernel.setBuildMode(b.standardReleaseOptions()); - kernel.setTheTarget(builtin.Target{ + kernel.setTheTarget(std.Target{ .Cross = std.Target.Cross{ - .arch = builtin.Target.Arch.i386, - .os = builtin.Target.Os.freestanding, - .abi = builtin.Target.Abi.none, - .cpu_features = builtin.Target.CpuFeatures.initFromCpu( + .arch = std.Target.Arch.i386, + .os = std.Target.Os.freestanding, + .abi = std.Target.Abi.none, + .cpu_features = std.Target.CpuFeatures.initFromCpu( builtin.Arch.i386, &builtin.Target.x86.cpu._i686, ), }, }); - kernel.setLinkerScriptPath("src/arch/x86/linker.ld"); b.default_step.dependOn(&kernel.step); } diff --git a/qemu.sh b/qemu.sh index c96e696..681a46f 100755 --- a/qemu.sh +++ b/qemu.sh @@ -1,19 +1,21 @@ #!/bin/bash +# usage: ./qemu.sh start +# ./qemu.sh quit QEMU_SOCKET=/tmp/qemu.sock QEMU_MONITOR="sudo socat - UNIX-CONNECT:${QEMU_SOCKET}" QEMU_GDB_PORT=4242 KERNEL=build/kernel -start() { +qemu_start() { touch disk.img # sudo pkill -9 qemu-system-i386 sudo qemu-system-i386 \ -gdb tcp::${QEMU_GDB_PORT} \ -monitor unix:${QEMU_SOCKET},server,nowait \ -enable-kvm \ - -m 1341M \ -curses \ + -m 1341M \ -hda disk.img \ -kernel ${KERNEL} # -drive file=disk.img,if=virtio\ @@ -27,16 +29,7 @@ start() { # -serial mon:stdio \ } -monitor() { sudo ${QEMU_MONITOR}; } -monitor-exec() { echo "$1" | sudo ${QEMU_MONITOR} >/dev/null; } +qemu_quit() { echo quit | sudo ${QEMU_MONITOR} >/dev/null; } +qemu_monitor() { sudo ${QEMU_MONITOR}; } -quit() { monitor-exec quit; } - -reload() { - monitor-exec stop - # monitor "change ide1-cd0 ${KERNEL}" - monitor-exec system_reset - monitor-exec cont -} - -"$@" +qemu_"$@" diff --git a/src/console.zig b/src/console.zig index 15ce322..c2ea38b 100644 --- a/src/console.zig +++ b/src/console.zig @@ -67,7 +67,7 @@ pub fn keyboard_callback(char: u8) void { } pub fn loop() void { - input_ring.init() catch unreachable; + input_ring.init(vmem.allocator) catch unreachable; input_ring.task = task.current_task; ps2.keyboard_callback = keyboard_callback; print("> ", .{}); diff --git a/src/driver/ide.zig b/src/driver/ide.zig index ee81220..dd56ec1 100644 --- a/src/driver/ide.zig +++ b/src/driver/ide.zig @@ -91,8 +91,9 @@ const IDEDevice = struct { var err: u8 = 0; var status: u8 = 0; - var self = try kernel.vmem.create(IDEDevice); - errdefer kernel.vmem.destroy(self); + // TODO: make this nicer + var self = try kernel.vmem.allocator.create(IDEDevice); + errdefer kernel.vmem.allocator.destroy(self); self.reserved = 1; self.channel = channel; self.drive = drive; diff --git a/src/main.zig b/src/main.zig index f9cb3f3..4e0bf91 100644 --- a/src/main.zig +++ b/src/main.zig @@ -30,7 +30,7 @@ export fn kmain(magic: u32, info: *const multiboot.MultibootInfo) noreturn { _ = task.new(@ptrToInt(topbar)) catch unreachable; _ = task.new(@ptrToInt(console.loop)) catch unreachable; - var buf = vmem.create([512]u8) catch unreachable; + var buf = vmem.allocator.create([512]u8) catch unreachable; println("buf at 0x{x}", .{@ptrToInt(buf)}); driver.ide.first_ide_drive.read(2, buf); diff --git a/src/ring_buffer.zig b/src/ring_buffer.zig index ff68088..841703c 100644 --- a/src/ring_buffer.zig +++ b/src/ring_buffer.zig @@ -3,16 +3,17 @@ usingnamespace @import("index.zig"); pub fn Ring(comptime T: type) type { return struct { const Self = @This(); - const Size = u10; // 0-1024 + const Size = u10; // 0-1023 const size = @import("std").math.maxInt(Size); + allocator: std.mem.Allocator = undefined, buffer: *[size]T, task: ?*task.TaskNode = null, read_index: Size = 0, write_index: Size = 0, - //TODO: allocator argument and remove the namespace - pub fn init(ring: *Self) !void { - ring.buffer = try vmem.create(@TypeOf(ring.buffer.*)); + pub fn init(ring: *Self, alloc: std.mem.Allocator) !void { + ring.allocator = alloc; + ring.buffer = try ring.allocator.create(@TypeOf(ring.buffer.*)); } pub fn write(ring: *Self, elem: T) void { @@ -24,7 +25,7 @@ pub fn Ring(comptime T: type) type { pub fn read(ring: *Self) ?T { if (ring.write_index == ring.read_index) return null; const id = ring.read_index; - ring.read_index +%= 1; + ring.read_index +%= 1; // add with overflow to loop the ring return ring.buffer[id]; } }; diff --git a/src/task.zig b/src/task.zig index 0133307..b246aed 100644 --- a/src/task.zig +++ b/src/task.zig @@ -34,6 +34,7 @@ pub const TaskState = enum { }; pub const Task = struct { + stack: *[STACK_SIZE]u8 = undefined, esp: usize, tid: u16, time_used: u64 = 0, @@ -44,8 +45,8 @@ pub const Task = struct { pub fn create(entrypoint: usize) !*Task { // Allocate and initialize the thread structure. - var t = try vmem.create(Task); - errdefer vmem.destroy(t); + var t = try vmem.allocator.create(Task); + errdefer vmem.allocator.destroy(t); t.time_used = 0; t.state = .ReadyToRun; @@ -54,7 +55,8 @@ pub const Task = struct { assert(tid_counter != 0); //overflow // allocate a new stack - t.esp = (try vmem.malloc(STACK_SIZE)) + STACK_SIZE; + t.stack = try vmem.allocator.create([STACK_SIZE]u8); + t.esp = @ptrToInt(t.stack) + STACK_SIZE; // if the tasks rets from its main function, it will go to terminate // NOTE: if terminate is called this way it has an incorrect ebp! t.esp -= 4; @@ -70,8 +72,8 @@ pub const Task = struct { } pub fn destroy(self: *Task) void { - vmem.free(self.esp); - vmem.destroy(self); + vmem.allocator.destroy(self.stack); + vmem.allocator.destroy(self); } }; @@ -82,8 +84,8 @@ pub fn new(entrypoint: usize) !*TaskNode { task.lock_scheduler(); defer task.unlock_scheduler(); - const node = try vmem.create(TaskNode); - errdefer vmem.destroy(node); + const node = try vmem.allocator.create(TaskNode); + errdefer vmem.allocator.destroy(node); node.data = try Task.create(entrypoint); ready_tasks.prepend(node); @@ -99,7 +101,7 @@ pub fn wakeup_tick(tick: usize) bool { while (task.sleeping_tasks.popZero()) |sleepnode| { const tasknode = sleepnode.data; tasknode.data.state = .ReadyToRun; - vmem.free(@ptrToInt(sleepnode)); + vmem.allocator.destroy(sleepnode); task.ready_tasks.prepend(tasknode); popped = true; } @@ -111,7 +113,7 @@ pub fn usleep(usec: u64) !void { assert(current_task.data.state == .Running); update_time_used(); - const node = try vmem.create(SleepNode); + const node = try vmem.allocator.create(SleepNode); lock_scheduler(); defer unlock_scheduler(); @@ -177,7 +179,7 @@ pub fn cleaner_loop() noreturn { if (terminated_tasks.popFirst()) |n| { notify("DESTROYING {}", .{n.data.tid}); n.data.destroy(); - vmem.destroy(n); + vmem.allocator.destroy(n); } else { notify("NOTHING TO CLEAN", .{}); block(.Paused); diff --git a/src/vga.zig b/src/vga.zig index d371a9f..7e17dd0 100644 --- a/src/vga.zig +++ b/src/vga.zig @@ -10,7 +10,7 @@ pub var vga = VGA{ .vram = @intToPtr([*]VGAEntry, 0xb8000)[0..0x4000], .cursor = 80 * 2, .foreground = Color.Black, - .background = Color.LightGrey, + .background = Color.White, }; // Color codes. @@ -68,8 +68,8 @@ pub fn topbar() void { // println("topbar1"); while (true) { const cursor = vga.cursor; - vga.background = Color.Green; - vga.foreground = Color.LightGrey; + vga.background = Color.Black; + vga.foreground = Color.White; vga.cursor = 0; vga.cursor_enabled = false; diff --git a/src/vmem.zig b/src/vmem.zig index 75e0c57..7c88612 100644 --- a/src/vmem.zig +++ b/src/vmem.zig @@ -1,5 +1,5 @@ pub usingnamespace @import("index.zig"); -pub const allocator: std.mem.Allocator = undefined; +pub var allocator: std.mem.Allocator = undefined; // TODO: make a better memory allocator // stupid simple virtual memory allocator @@ -8,44 +8,78 @@ pub const allocator: std.mem.Allocator = undefined; // - no allocation bigger than a page const stack_size: usize = (layout.HEAP_END - layout.HEAP) / x86.PAGE_SIZE; -var stack: [stack_size]usize = undefined; // Stack of free virtual addresses var stack_index: usize = 0; // Index into the stack. +var stack: [stack_size]usize = undefined; // Stack of free virtual addresses pub fn available() usize { return stack_index * x86.PAGE_SIZE; } -pub fn malloc(size: usize) !usize { - if (available() == 0) { - return error.OutOfMemory; - } - stack_index -= 1; - var vaddr: usize = stack[stack_index]; - try x86.paging.mmap(vaddr, null); - return vaddr; -} - -pub fn create(comptime T: type) !*T { - assert(@sizeOf(T) < x86.PAGE_SIZE); // this allocator only support 1:1 mapping - return @intToPtr(*T, try malloc(@sizeOf(T))); -} - -pub fn destroy(O: var) void { - vmem.free(@ptrToInt(O)); -} - -pub fn free(address: usize) void { - x86.paging.unmap(address); - stack[stack_index] = address; +fn dealloc(addr: usize) void { + x86.paging.unmap(addr); + stack[stack_index] = addr; stack_index += 1; } +const Error = error{OutOfMemory}; + +fn realloc( + self: *std.mem.Allocator, + old_mem: []u8, + old_alignment: u29, + new_byte_count: usize, + new_alignment: u29, +) ![]u8 { + if (old_mem.len == 0) { + // new allocation + assert(new_byte_count < x86.PAGE_SIZE); // this allocator only support 1:1 mapping + if (available() == 0) return error.OutOfMemory; + stack_index -= 1; + var vaddr: usize = stack[stack_index]; + try x86.paging.mmap(vaddr, null); + return @intToPtr([*]u8, vaddr)[0..new_byte_count]; + } + // free + if (new_byte_count == 0) { + dealloc(@ptrToInt(&old_mem[0])); + return &[_]u8{}; + } + println("vmem: unsupported allocator operation", .{}); + x86.hang(); + // return undefined; +} + +fn shrink( + self: *std.mem.Allocator, + old_mem: []u8, + old_alignment: u29, + new_byte_count: usize, + new_alignment: u29, +) []u8 { + // free + if (new_byte_count == 0) { + dealloc(@ptrToInt(&old_mem[0])); + return &[_]u8{}; + } + + println("vmem doesn't support shrinking, {}, {}, {}, {}", .{ + old_mem, + old_alignment, + new_byte_count, + new_alignment, + }); + x86.hang(); + // return undefined; +} + pub fn init() void { + allocator = std.mem.Allocator{ + .reallocFn = realloc, + .shrinkFn = shrink, + }; var addr: usize = layout.HEAP; while (addr < layout.HEAP_END) : (addr += x86.PAGE_SIZE) { - // println("addr {x}", addr); stack[stack_index] = addr; stack_index += 1; - // return; } }