implemented page allocator
This commit is contained in:
parent
48421fc0ef
commit
4341e1dce2
6 changed files with 195 additions and 10 deletions
|
|
@ -30,4 +30,6 @@ SECTIONS
|
||||||
|
|
||||||
. = ALIGN(16);
|
. = ALIGN(16);
|
||||||
__stack_top = . + 0x10000;
|
__stack_top = . + 0x10000;
|
||||||
|
. = ALIGN(0x1000);
|
||||||
|
PROVIDE(__memory_start = .);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
19
src/Fdt.zig
19
src/Fdt.zig
|
|
@ -28,7 +28,7 @@ pub const ReserveEntry = extern struct {
|
||||||
address: u64,
|
address: u64,
|
||||||
size: u64,
|
size: u64,
|
||||||
|
|
||||||
pub fn toNative(self: *const ReserveEntry) struct { address: u64, size: u64 } {
|
pub fn toNative(self: *const ReserveEntry) packed struct { address: u64, size: u64 } {
|
||||||
return .{
|
return .{
|
||||||
.address = std.mem.bigToNative(u64, self.address),
|
.address = std.mem.bigToNative(u64, self.address),
|
||||||
.size = std.mem.bigToNative(u64, self.size),
|
.size = std.mem.bigToNative(u64, self.size),
|
||||||
|
|
@ -580,7 +580,16 @@ pub fn chosen(self: *const Fdt) ?Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn memory(self: *const Fdt) ?Node {
|
pub fn memory(self: *const Fdt) ?Node {
|
||||||
return self.findNode("/memory") orelse self.findFirstCompatible("memory");
|
var n = self.nodes();
|
||||||
|
while (n.next()) |node| {
|
||||||
|
if (node.getProperty("device_type")) |dev_type| {
|
||||||
|
if (std.mem.eql(u8, dev_type.asString().?, "memory")) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cpus(self: *const Fdt) ?Node {
|
pub fn cpus(self: *const Fdt) ?Node {
|
||||||
|
|
@ -626,7 +635,7 @@ pub const MemoryReservationIterator = struct {
|
||||||
data: []const u8,
|
data: []const u8,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
|
|
||||||
pub fn next(self: *MemoryReservationIterator) ?struct { address: u64, size: u64 } {
|
pub fn next(self: *MemoryReservationIterator) ?packed struct { address: u64, size: u64 } {
|
||||||
if (self.pos + 16 > self.data.len) return null;
|
if (self.pos + 16 > self.data.len) return null;
|
||||||
|
|
||||||
const entry: *const ReserveEntry = @alignCast(@ptrCast(self.data.ptr + self.pos));
|
const entry: *const ReserveEntry = @alignCast(@ptrCast(self.data.ptr + self.pos));
|
||||||
|
|
@ -636,7 +645,7 @@ pub const MemoryReservationIterator = struct {
|
||||||
// End marker is all zeros
|
// End marker is all zeros
|
||||||
if (result.address == 0 and result.size == 0) return null;
|
if (result.address == 0 and result.size == 0) return null;
|
||||||
|
|
||||||
return result;
|
return @bitCast(result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -652,5 +661,3 @@ pub fn parseReg(data: []const u8, address_cells: u32, size_cells: u32) RegIterat
|
||||||
.pos = 0,
|
.pos = 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
11
src/debug.zig
Normal file
11
src/debug.zig
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
const Console = @import("drivers/Console.zig");
|
||||||
|
|
||||||
|
var console: Console = undefined;
|
||||||
|
|
||||||
|
pub fn init(c: Console) void {
|
||||||
|
console = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print(comptime s: []const u8, args: anytype) void {
|
||||||
|
console.print(s, args);
|
||||||
|
}
|
||||||
29
src/main.zig
29
src/main.zig
|
|
@ -2,10 +2,11 @@ const std = @import("std");
|
||||||
const isa = @import("riscv/isa.zig");
|
const isa = @import("riscv/isa.zig");
|
||||||
const Fdt = @import("Fdt.zig");
|
const Fdt = @import("Fdt.zig");
|
||||||
const Console = @import("drivers/Console.zig");
|
const Console = @import("drivers/Console.zig");
|
||||||
|
const debug = @import("debug.zig");
|
||||||
|
const mem = @import("mem.zig");
|
||||||
|
|
||||||
const UART_BASE: usize = 0x10000000;
|
const UART_BASE: usize = 0x10000000;
|
||||||
|
const MEMORY_START = @extern([*]u8, .{.name = "__memory_start"});
|
||||||
var console: Console = undefined;
|
|
||||||
|
|
||||||
fn uart_put(c: u8) void {
|
fn uart_put(c: u8) void {
|
||||||
const uart: *volatile u8 = @ptrFromInt(UART_BASE);
|
const uart: *volatile u8 = @ptrFromInt(UART_BASE);
|
||||||
|
|
@ -32,9 +33,29 @@ export fn kmain(hartid: u64, fdt_ptr: *const anyopaque) callconv(.c) noreturn {
|
||||||
while (true) asm volatile ("wfi");
|
while (true) asm volatile ("wfi");
|
||||||
};
|
};
|
||||||
|
|
||||||
console = Console.init(fdt).?;
|
const root = fdt.root().?;
|
||||||
|
|
||||||
console.print("booting hydra...\n", .{});
|
const console = Console.init(fdt).?;
|
||||||
|
debug.init(console);
|
||||||
|
|
||||||
|
debug.print("booting hydra...\n", .{});
|
||||||
|
|
||||||
|
var reservations = fdt.memoryReservations();
|
||||||
|
|
||||||
|
while (reservations.next()) |reservation| {
|
||||||
|
debug.print("0x{x}:0x{x}\n", .{reservation.address, reservation.size});
|
||||||
|
}
|
||||||
|
const memory = fdt.memory().?;
|
||||||
|
var reg_iter = Fdt.parseReg(memory.getProperty("reg").?.data, root.addressCells(), root.sizeCells());
|
||||||
|
const reg = reg_iter.next().?;
|
||||||
|
const memory_end = reg.address + reg.size;
|
||||||
|
|
||||||
|
var buddy: mem.BuddyAllocator = .{};
|
||||||
|
buddy.init(MEMORY_START[0..memory_end - @intFromPtr(MEMORY_START)]);
|
||||||
|
debug.print("memory allocator initialized.\n", .{});
|
||||||
|
|
||||||
|
const allocator = buddy.allocator();
|
||||||
|
_ = allocator;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
asm volatile ("wfi");
|
asm volatile ("wfi");
|
||||||
|
|
|
||||||
3
src/mem.zig
Normal file
3
src/mem.zig
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub const BuddyAllocator = @import("mem/BuddyAllocator.zig");
|
||||||
|
|
||||||
|
pub const PAGE_SIZE = 0x1000;
|
||||||
141
src/mem/BuddyAllocator.zig
Normal file
141
src/mem/BuddyAllocator.zig
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const BuddyAllocator = @This();
|
||||||
|
const mem = @import("../mem.zig");
|
||||||
|
const math = std.math;
|
||||||
|
|
||||||
|
const MIN_BLOCK_SIZE = mem.PAGE_SIZE;
|
||||||
|
const MAX_LEVEL = 16;
|
||||||
|
|
||||||
|
const Block = struct {
|
||||||
|
next: ?*Block,
|
||||||
|
level: u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
freelist: [MAX_LEVEL + 1]?*Block = .{null} ** (MAX_LEVEL + 1),
|
||||||
|
|
||||||
|
pub fn init(self: *BuddyAllocator, range: []u8) void {
|
||||||
|
self.freeRange(range.ptr, range.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getLevelSize(level: u8) usize {
|
||||||
|
return @as(usize, MIN_BLOCK_SIZE) << @intCast(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn freeRange(self: *BuddyAllocator, start: [*]u8, size: usize) void {
|
||||||
|
var current_addr = @intFromPtr(start);
|
||||||
|
const end_addr = current_addr + size;
|
||||||
|
|
||||||
|
current_addr = std.mem.alignForward(usize, current_addr, MIN_BLOCK_SIZE);
|
||||||
|
|
||||||
|
while (current_addr + getLevelSize(0) <= end_addr) {
|
||||||
|
var level: u8 = MAX_LEVEL;
|
||||||
|
while (level > 0) : (level -= 1) {
|
||||||
|
const blk_size = getLevelSize(level);
|
||||||
|
if (current_addr + blk_size <= end_addr and current_addr % blk_size == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const b = @as(*Block, @ptrFromInt(current_addr));
|
||||||
|
b.* = .{ .next = self.freelist[level], .level = level };
|
||||||
|
self.freelist[level] = b;
|
||||||
|
|
||||||
|
current_addr += getLevelSize(level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getBuddy(block: *Block) *Block {
|
||||||
|
const addr = @intFromPtr(block);
|
||||||
|
const size = getLevelSize(block.level);
|
||||||
|
return @ptrFromInt(addr ^ size);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isFree(self: *BuddyAllocator, buddy: *Block, level: u8) bool {
|
||||||
|
var curr = self.freelist[level];
|
||||||
|
while (curr) |node| : (curr = node.next) {
|
||||||
|
if (node == buddy) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocBlock(self: *BuddyAllocator, level: u8) ?[*]u8 {
|
||||||
|
if (level > MAX_LEVEL) return null;
|
||||||
|
|
||||||
|
var target_level = level;
|
||||||
|
while (target_level <= MAX_LEVEL) : (target_level += 1) {
|
||||||
|
if (self.freelist[target_level]) |block| {
|
||||||
|
self.freelist[target_level] = block.next;
|
||||||
|
|
||||||
|
var b = block;
|
||||||
|
while (b.level > level) {
|
||||||
|
b.level -= 1;
|
||||||
|
const buddy = getBuddy(b);
|
||||||
|
buddy.* = .{ .next = self.freelist[b.level], .level = b.level };
|
||||||
|
self.freelist[b.level] = buddy;
|
||||||
|
}
|
||||||
|
return @ptrCast(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn freeBlock(self: *BuddyAllocator, addr: [*]u8, level: u8) void {
|
||||||
|
var b = @as(*Block, @alignCast(@ptrCast(addr)));
|
||||||
|
b.level = level;
|
||||||
|
|
||||||
|
while (b.level < MAX_LEVEL) {
|
||||||
|
const buddy = getBuddy(b);
|
||||||
|
if (!self.isFree(buddy, b.level)) break;
|
||||||
|
|
||||||
|
var prev: ?*Block = null;
|
||||||
|
var curr = self.freelist[b.level];
|
||||||
|
while (curr) |node| : (curr = node.next) {
|
||||||
|
if (node == buddy) {
|
||||||
|
if (prev) |p| p.next = node.next else self.freelist[b.level] = node.next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (@intFromPtr(buddy) < @intFromPtr(b)) b = buddy;
|
||||||
|
b.level += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
b.next = self.freelist[b.level];
|
||||||
|
self.freelist[b.level] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocator(self: *BuddyAllocator) Allocator {
|
||||||
|
return .{
|
||||||
|
.ptr = self,
|
||||||
|
.vtable = &.{
|
||||||
|
.alloc = alloc,
|
||||||
|
.resize = Allocator.noResize,
|
||||||
|
.remap = Allocator.noRemap,
|
||||||
|
.free = free,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc(ctx: *anyopaque, len: usize, ptr_align: std.mem.Alignment, ret_addr: usize) ?[*]u8 {
|
||||||
|
_ = ptr_align;
|
||||||
|
_ = ret_addr;
|
||||||
|
const self: *BuddyAllocator = @ptrCast(@alignCast(ctx));
|
||||||
|
|
||||||
|
const actual_size = @max(len, MIN_BLOCK_SIZE);
|
||||||
|
const level = math.log2_int_ceil(usize, (actual_size + MIN_BLOCK_SIZE - 1) / MIN_BLOCK_SIZE);
|
||||||
|
|
||||||
|
return self.allocBlock(@intCast(level));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free(ctx: *anyopaque, buf: []u8, buf_align: std.mem.Alignment, ret_addr: usize) void {
|
||||||
|
_ = buf_align;
|
||||||
|
_ = ret_addr;
|
||||||
|
const self: *BuddyAllocator = @ptrCast(@alignCast(ctx));
|
||||||
|
|
||||||
|
const actual_size = @max(buf.len, MIN_BLOCK_SIZE);
|
||||||
|
const level = math.log2_int_ceil(usize, (actual_size + MIN_BLOCK_SIZE - 1) / MIN_BLOCK_SIZE);
|
||||||
|
|
||||||
|
self.freeBlock(buf.ptr, @intCast(level));
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue