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.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
21
qemu.sh
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
"$@"
|
|
||||||
|
|
|
||||||
|
|
@ -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("> ", .{});
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
22
src/task.zig
22
src/task.zig
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
72
src/vmem.zig
72
src/vmem.zig
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue