88 lines
2.6 KiB
Zig
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);
|
|
}
|