wip: std.mem.allocator
This commit is contained in:
parent
50ac72e24b
commit
e392799b91
9 changed files with 98 additions and 68 deletions
11
build.zig
11
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);
|
||||
}
|
||||
|
|
|
|||
21
qemu.sh
21
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_"$@"
|
||||
|
|
|
|||
|
|
@ -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("> ", .{});
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
};
|
||||
|
|
|
|||
22
src/task.zig
22
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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
76
src/vmem.zig
76
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue