kernel-zig/src/arch/x86/memory.zig
2019-08-15 21:15:10 +02:00

88 lines
2.6 KiB
Zig

usingnamespace @import("kernel").multiboot;
usingnamespace @import("kernel").vga;
const assert = @import("std").debug.assert;
var stack: [*]usize = undefined; // Stack of free physical page.
var stack_index: usize = 0; // Index into the stack.
// Boundaries of the frame stack.
pub var stack_size: usize = undefined;
pub var stack_end: usize = undefined;
pub const PAGE_SIZE: usize = 4096;
// 4095 -> 4096
// 4096 -> 4096
// 4097 -> 8192
pub fn pageAlign(address: u32) u32 {
return (address + PAGE_SIZE - 1) & (~PAGE_SIZE +% 1);
}
////
// Return the amount of variable elements (in bytes).
//
pub fn available() usize {
return stack_index * PAGE_SIZE;
}
////
// Request a free physical page and return its address.
//
pub fn allocate() ?usize {
if (available() == 0) {
println("out of memory");
return null;
}
stack_index -= 1;
return stack[stack_index];
}
////
// Free a previously allocated physical page.
//
// Arguments:
// address: Address of the page to be freed.
//
pub fn free(address: usize) void {
stack[stack_index] = address;
stack_index += 1;
}
////
// Scan the memory map to index all available memory.
//
// Arguments:
// info: Information structure from bootloader.
//
pub fn initialize(info: *const MultibootInfo) void {
// Ensure the bootloader has given us the memory map.
assert((info.flags & MULTIBOOT_INFO_MEMORY) != 0);
assert((info.flags & MULTIBOOT_INFO_MEM_MAP) != 0);
// Place the stack of free pages after the last Multiboot module.
stack = @intToPtr([*]usize, 0x200000);
// stack = @intToPtr([*]usize, pageAlign(info.mods_addr));
// Calculate the approximate size of the stack based on the amount of total upper memory.
stack_size = ((info.mem_upper * 1024) / PAGE_SIZE) * @sizeOf(usize);
stack_end = pageAlign(@ptrToInt(stack) + stack_size);
var map: usize = info.mmap_addr;
while (map < info.mmap_addr + info.mmap_length) {
var entry = @intToPtr(*MultibootMMapEntry, map);
// Calculate the start and end of this memory area.
var start = @truncate(usize, entry.addr);
var end = @truncate(usize, start + entry.len);
// Anything that comes before the end of the stack of free pages is reserved.
start = if (start >= stack_end) start else stack_end;
// Flag all the pages in this memory area as free.
if (entry.type == MULTIBOOT_MEMORY_AVAILABLE) while (start < end) : (start += PAGE_SIZE)
free(start);
// Go to the next entry in the memory map.
map += entry.size + @sizeOf(@typeOf(entry.size));
}
println("available memory: {d} MiB ", available() / 1024 / 1024);
}