wip: std.mem.allocator

This commit is contained in:
Jack Halford 2020-02-07 15:28:22 +01:00
parent 50ac72e24b
commit e392799b91
9 changed files with 98 additions and 68 deletions

View file

@ -15,18 +15,17 @@ pub fn build(b: *Builder) void {
kernel.addAssemblyFile("src/arch/x86/switch_tasks.s"); kernel.addAssemblyFile("src/arch/x86/switch_tasks.s");
kernel.setBuildMode(b.standardReleaseOptions()); kernel.setBuildMode(b.standardReleaseOptions());
kernel.setTheTarget(builtin.Target{ kernel.setTheTarget(std.Target{
.Cross = std.Target.Cross{ .Cross = std.Target.Cross{
.arch = builtin.Target.Arch.i386, .arch = std.Target.Arch.i386,
.os = builtin.Target.Os.freestanding, .os = std.Target.Os.freestanding,
.abi = builtin.Target.Abi.none, .abi = std.Target.Abi.none,
.cpu_features = builtin.Target.CpuFeatures.initFromCpu( .cpu_features = std.Target.CpuFeatures.initFromCpu(
builtin.Arch.i386, builtin.Arch.i386,
&builtin.Target.x86.cpu._i686, &builtin.Target.x86.cpu._i686,
), ),
}, },
}); });
kernel.setLinkerScriptPath("src/arch/x86/linker.ld"); kernel.setLinkerScriptPath("src/arch/x86/linker.ld");
b.default_step.dependOn(&kernel.step); b.default_step.dependOn(&kernel.step);
} }

21
qemu.sh
View file

@ -1,19 +1,21 @@
#!/bin/bash #!/bin/bash
# usage: ./qemu.sh start
# ./qemu.sh quit
QEMU_SOCKET=/tmp/qemu.sock QEMU_SOCKET=/tmp/qemu.sock
QEMU_MONITOR="sudo socat - UNIX-CONNECT:${QEMU_SOCKET}" QEMU_MONITOR="sudo socat - UNIX-CONNECT:${QEMU_SOCKET}"
QEMU_GDB_PORT=4242 QEMU_GDB_PORT=4242
KERNEL=build/kernel KERNEL=build/kernel
start() { qemu_start() {
touch disk.img touch disk.img
# sudo pkill -9 qemu-system-i386 # sudo pkill -9 qemu-system-i386
sudo qemu-system-i386 \ sudo qemu-system-i386 \
-gdb tcp::${QEMU_GDB_PORT} \ -gdb tcp::${QEMU_GDB_PORT} \
-monitor unix:${QEMU_SOCKET},server,nowait \ -monitor unix:${QEMU_SOCKET},server,nowait \
-enable-kvm \ -enable-kvm \
-m 1341M \
-curses \ -curses \
-m 1341M \
-hda disk.img \ -hda disk.img \
-kernel ${KERNEL} -kernel ${KERNEL}
# -drive file=disk.img,if=virtio\ # -drive file=disk.img,if=virtio\
@ -27,16 +29,7 @@ start() {
# -serial mon:stdio \ # -serial mon:stdio \
} }
monitor() { sudo ${QEMU_MONITOR}; } qemu_quit() { echo quit | sudo ${QEMU_MONITOR} >/dev/null; }
monitor-exec() { echo "$1" | sudo ${QEMU_MONITOR} >/dev/null; } qemu_monitor() { sudo ${QEMU_MONITOR}; }
quit() { monitor-exec quit; } qemu_"$@"
reload() {
monitor-exec stop
# monitor "change ide1-cd0 ${KERNEL}"
monitor-exec system_reset
monitor-exec cont
}
"$@"

View file

@ -67,7 +67,7 @@ pub fn keyboard_callback(char: u8) void {
} }
pub fn loop() void { pub fn loop() void {
input_ring.init() catch unreachable; input_ring.init(vmem.allocator) catch unreachable;
input_ring.task = task.current_task; input_ring.task = task.current_task;
ps2.keyboard_callback = keyboard_callback; ps2.keyboard_callback = keyboard_callback;
print("> ", .{}); print("> ", .{});

View file

@ -91,8 +91,9 @@ const IDEDevice = struct {
var err: u8 = 0; var err: u8 = 0;
var status: u8 = 0; var status: u8 = 0;
var self = try kernel.vmem.create(IDEDevice); // TODO: make this nicer
errdefer kernel.vmem.destroy(self); var self = try kernel.vmem.allocator.create(IDEDevice);
errdefer kernel.vmem.allocator.destroy(self);
self.reserved = 1; self.reserved = 1;
self.channel = channel; self.channel = channel;
self.drive = drive; self.drive = drive;

View file

@ -30,7 +30,7 @@ export fn kmain(magic: u32, info: *const multiboot.MultibootInfo) noreturn {
_ = task.new(@ptrToInt(topbar)) catch unreachable; _ = task.new(@ptrToInt(topbar)) catch unreachable;
_ = task.new(@ptrToInt(console.loop)) 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)}); println("buf at 0x{x}", .{@ptrToInt(buf)});
driver.ide.first_ide_drive.read(2, buf); driver.ide.first_ide_drive.read(2, buf);

View file

@ -3,16 +3,17 @@ usingnamespace @import("index.zig");
pub fn Ring(comptime T: type) type { pub fn Ring(comptime T: type) type {
return struct { return struct {
const Self = @This(); const Self = @This();
const Size = u10; // 0-1024 const Size = u10; // 0-1023
const size = @import("std").math.maxInt(Size); const size = @import("std").math.maxInt(Size);
allocator: std.mem.Allocator = undefined,
buffer: *[size]T, buffer: *[size]T,
task: ?*task.TaskNode = null, task: ?*task.TaskNode = null,
read_index: Size = 0, read_index: Size = 0,
write_index: Size = 0, write_index: Size = 0,
//TODO: allocator argument and remove the namespace pub fn init(ring: *Self, alloc: std.mem.Allocator) !void {
pub fn init(ring: *Self) !void { ring.allocator = alloc;
ring.buffer = try vmem.create(@TypeOf(ring.buffer.*)); ring.buffer = try ring.allocator.create(@TypeOf(ring.buffer.*));
} }
pub fn write(ring: *Self, elem: T) void { 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 { pub fn read(ring: *Self) ?T {
if (ring.write_index == ring.read_index) return null; if (ring.write_index == ring.read_index) return null;
const id = ring.read_index; const id = ring.read_index;
ring.read_index +%= 1; ring.read_index +%= 1; // add with overflow to loop the ring
return ring.buffer[id]; return ring.buffer[id];
} }
}; };

View file

@ -34,6 +34,7 @@ pub const TaskState = enum {
}; };
pub const Task = struct { pub const Task = struct {
stack: *[STACK_SIZE]u8 = undefined,
esp: usize, esp: usize,
tid: u16, tid: u16,
time_used: u64 = 0, time_used: u64 = 0,
@ -44,8 +45,8 @@ pub const Task = struct {
pub fn create(entrypoint: usize) !*Task { pub fn create(entrypoint: usize) !*Task {
// Allocate and initialize the thread structure. // Allocate and initialize the thread structure.
var t = try vmem.create(Task); var t = try vmem.allocator.create(Task);
errdefer vmem.destroy(t); errdefer vmem.allocator.destroy(t);
t.time_used = 0; t.time_used = 0;
t.state = .ReadyToRun; t.state = .ReadyToRun;
@ -54,7 +55,8 @@ pub const Task = struct {
assert(tid_counter != 0); //overflow assert(tid_counter != 0); //overflow
// allocate a new stack // 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 // 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! // NOTE: if terminate is called this way it has an incorrect ebp!
t.esp -= 4; t.esp -= 4;
@ -70,8 +72,8 @@ pub const Task = struct {
} }
pub fn destroy(self: *Task) void { pub fn destroy(self: *Task) void {
vmem.free(self.esp); vmem.allocator.destroy(self.stack);
vmem.destroy(self); vmem.allocator.destroy(self);
} }
}; };
@ -82,8 +84,8 @@ pub fn new(entrypoint: usize) !*TaskNode {
task.lock_scheduler(); task.lock_scheduler();
defer task.unlock_scheduler(); defer task.unlock_scheduler();
const node = try vmem.create(TaskNode); const node = try vmem.allocator.create(TaskNode);
errdefer vmem.destroy(node); errdefer vmem.allocator.destroy(node);
node.data = try Task.create(entrypoint); node.data = try Task.create(entrypoint);
ready_tasks.prepend(node); ready_tasks.prepend(node);
@ -99,7 +101,7 @@ pub fn wakeup_tick(tick: usize) bool {
while (task.sleeping_tasks.popZero()) |sleepnode| { while (task.sleeping_tasks.popZero()) |sleepnode| {
const tasknode = sleepnode.data; const tasknode = sleepnode.data;
tasknode.data.state = .ReadyToRun; tasknode.data.state = .ReadyToRun;
vmem.free(@ptrToInt(sleepnode)); vmem.allocator.destroy(sleepnode);
task.ready_tasks.prepend(tasknode); task.ready_tasks.prepend(tasknode);
popped = true; popped = true;
} }
@ -111,7 +113,7 @@ pub fn usleep(usec: u64) !void {
assert(current_task.data.state == .Running); assert(current_task.data.state == .Running);
update_time_used(); update_time_used();
const node = try vmem.create(SleepNode); const node = try vmem.allocator.create(SleepNode);
lock_scheduler(); lock_scheduler();
defer unlock_scheduler(); defer unlock_scheduler();
@ -177,7 +179,7 @@ pub fn cleaner_loop() noreturn {
if (terminated_tasks.popFirst()) |n| { if (terminated_tasks.popFirst()) |n| {
notify("DESTROYING {}", .{n.data.tid}); notify("DESTROYING {}", .{n.data.tid});
n.data.destroy(); n.data.destroy();
vmem.destroy(n); vmem.allocator.destroy(n);
} else { } else {
notify("NOTHING TO CLEAN", .{}); notify("NOTHING TO CLEAN", .{});
block(.Paused); block(.Paused);

View file

@ -10,7 +10,7 @@ pub var vga = VGA{
.vram = @intToPtr([*]VGAEntry, 0xb8000)[0..0x4000], .vram = @intToPtr([*]VGAEntry, 0xb8000)[0..0x4000],
.cursor = 80 * 2, .cursor = 80 * 2,
.foreground = Color.Black, .foreground = Color.Black,
.background = Color.LightGrey, .background = Color.White,
}; };
// Color codes. // Color codes.
@ -68,8 +68,8 @@ pub fn topbar() void {
// println("topbar1"); // println("topbar1");
while (true) { while (true) {
const cursor = vga.cursor; const cursor = vga.cursor;
vga.background = Color.Green; vga.background = Color.Black;
vga.foreground = Color.LightGrey; vga.foreground = Color.White;
vga.cursor = 0; vga.cursor = 0;
vga.cursor_enabled = false; vga.cursor_enabled = false;

View file

@ -1,5 +1,5 @@
pub usingnamespace @import("index.zig"); 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 // TODO: make a better memory allocator
// stupid simple virtual memory allocator // stupid simple virtual memory allocator
@ -8,44 +8,78 @@ pub const allocator: std.mem.Allocator = undefined;
// - no allocation bigger than a page // - no allocation bigger than a page
const stack_size: usize = (layout.HEAP_END - layout.HEAP) / x86.PAGE_SIZE; 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_index: usize = 0; // Index into the stack.
var stack: [stack_size]usize = undefined; // Stack of free virtual addresses
pub fn available() usize { pub fn available() usize {
return stack_index * x86.PAGE_SIZE; return stack_index * x86.PAGE_SIZE;
} }
pub fn malloc(size: usize) !usize { fn dealloc(addr: usize) void {
if (available() == 0) { x86.paging.unmap(addr);
return error.OutOfMemory; 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; stack_index -= 1;
var vaddr: usize = stack[stack_index]; var vaddr: usize = stack[stack_index];
try x86.paging.mmap(vaddr, null); try x86.paging.mmap(vaddr, null);
return vaddr; 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;
} }
pub fn create(comptime T: type) !*T { fn shrink(
assert(@sizeOf(T) < x86.PAGE_SIZE); // this allocator only support 1:1 mapping self: *std.mem.Allocator,
return @intToPtr(*T, try malloc(@sizeOf(T))); 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{};
} }
pub fn destroy(O: var) void { println("vmem doesn't support shrinking, {}, {}, {}, {}", .{
vmem.free(@ptrToInt(O)); old_mem,
} old_alignment,
new_byte_count,
pub fn free(address: usize) void { new_alignment,
x86.paging.unmap(address); });
stack[stack_index] = address; x86.hang();
stack_index += 1; // return undefined;
} }
pub fn init() void { pub fn init() void {
allocator = std.mem.Allocator{
.reallocFn = realloc,
.shrinkFn = shrink,
};
var addr: usize = layout.HEAP; var addr: usize = layout.HEAP;
while (addr < layout.HEAP_END) : (addr += x86.PAGE_SIZE) { while (addr < layout.HEAP_END) : (addr += x86.PAGE_SIZE) {
// println("addr {x}", addr);
stack[stack_index] = addr; stack[stack_index] = addr;
stack_index += 1; stack_index += 1;
// return;
} }
} }