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.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);
}

21
qemu.sh
View file

@ -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_"$@"

View file

@ -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("> ", .{});

View file

@ -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;

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(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);

View file

@ -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];
}
};

View file

@ -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);

View file

@ -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;

View file

@ -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;
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 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 {
assert(@sizeOf(T) < x86.PAGE_SIZE); // this allocator only support 1:1 mapping
return @intToPtr(*T, try malloc(@sizeOf(T)));
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{};
}
pub fn destroy(O: var) void {
vmem.free(@ptrToInt(O));
}
pub fn free(address: usize) void {
x86.paging.unmap(address);
stack[stack_index] = address;
stack_index += 1;
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;
}
}