Without KVM, qemu inserts an invalid 12-GiB reserved entry at the end of the physical address space, making the kernel reserve way more space than necessary for the page bitmap (and overwriting the page directory pages).
73 lines
2.5 KiB
Zig
73 lines
2.5 KiB
Zig
const easyboot = @cImport(@cInclude("easyboot.h"));
|
|
const target = @import("builtin").target;
|
|
|
|
const MemoryMapIterator = struct {
|
|
tag: *easyboot.multiboot_tag_mmap_t,
|
|
entry: ?*easyboot.multiboot_mmap_entry_t,
|
|
end: usize,
|
|
|
|
pub fn next(self: *MemoryMapIterator) ?*easyboot.multiboot_mmap_entry_t {
|
|
if (self.entry) |e| {
|
|
const current_entry = self.entry;
|
|
|
|
var new_entry: [*c]u8 = @ptrCast(e);
|
|
new_entry += self.tag.entry_size;
|
|
self.entry = @alignCast(@ptrCast(new_entry));
|
|
|
|
if (@intFromPtr(self.entry) >= self.end) self.entry = null;
|
|
|
|
if (target.cpu.arch == .x86_64) {
|
|
// Workaround for https://gitlab.com/qemu-project/qemu/-/commit/8504f129450b909c88e199ca44facd35d38ba4de
|
|
// This invalid 12GiB reserved entry is made up by QEMU (doesn't appear on any real hardware), so we can simply
|
|
// ignore it and move on to the next entry.
|
|
if (current_entry) |entry| {
|
|
if (entry.base_addr == 0x000000fd00000000 and entry.length == (0x000000ffffffffff - 0x000000fd00000000) + 1)
|
|
return self.next();
|
|
}
|
|
}
|
|
|
|
return current_entry;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
};
|
|
|
|
pub fn createMemoryMapIterator(tag: *easyboot.multiboot_tag_mmap_t) MemoryMapIterator {
|
|
return MemoryMapIterator{ .tag = tag, .entry = @alignCast(@ptrCast(tag.entries())), .end = @intFromPtr(tag) + tag.size };
|
|
}
|
|
|
|
pub fn findLargestFreeEntry(tag: *easyboot.multiboot_tag_mmap_t) ?*easyboot.multiboot_mmap_entry_t {
|
|
var max_length: u64 = 0;
|
|
var biggest_entry: ?*easyboot.multiboot_mmap_entry_t = null;
|
|
|
|
var iter = createMemoryMapIterator(tag);
|
|
|
|
while (iter.next()) |entry| {
|
|
if (entry.type == easyboot.MULTIBOOT_MEMORY_AVAILABLE and entry.length > max_length) {
|
|
max_length = entry.length;
|
|
biggest_entry = entry;
|
|
}
|
|
}
|
|
|
|
return biggest_entry;
|
|
}
|
|
|
|
pub fn findHighestEntry(tag: *easyboot.multiboot_tag_mmap_t) ?*easyboot.multiboot_mmap_entry_t {
|
|
var highest_entry: ?*easyboot.multiboot_mmap_entry_t = null;
|
|
|
|
var iter = createMemoryMapIterator(tag);
|
|
|
|
while (iter.next()) |entry| {
|
|
highest_entry = entry;
|
|
}
|
|
|
|
return highest_entry;
|
|
}
|
|
|
|
pub fn getAddressSpaceSize(tag: *easyboot.multiboot_tag_mmap_t) ?usize {
|
|
const highest_entry = findHighestEntry(tag) orelse return null;
|
|
|
|
return highest_entry.base_addr + highest_entry.length;
|
|
}
|