astryon/core/src/pmm.zig
Gabriel c4bb857c4e
core: Reserve physical page 0
In the kernel's early stages we access physical memory identity-mapped, so it's not very good for us to allocate that frame and then try to use it.
2025-02-15 22:18:49 +01:00

107 lines
3.7 KiB
Zig

const std = @import("std");
const easyboot = @cImport(@cInclude("easyboot.h"));
const platform = @import("arch/platform.zig").arch;
const mmap = @import("mmap.zig");
const bmap = @import("lib/bitmap.zig");
const FrameAllocatorError = error{
InvalidMemoryMap,
MemoryAlreadyInUse,
MemoryNotInUse,
OutOfMemory,
};
pub const FrameAllocator = struct {
bitmap: bmap.Bitmap,
free_memory: u64,
used_memory: u64,
reserved_memory: u64,
start_index: usize,
};
pub const PhysFrame = struct {
address: usize,
pub fn virtualAddress(self: *const PhysFrame, base: usize) usize {
return base + self.address;
}
};
pub fn lockFrame(allocator: *FrameAllocator, address: usize) !void {
const index = address / platform.PAGE_SIZE;
if (try allocator.bitmap.get(index) == 1) return error.MemoryAlreadyInUse;
try allocator.bitmap.set(index, 1);
allocator.used_memory += platform.PAGE_SIZE;
allocator.free_memory -= platform.PAGE_SIZE;
}
pub fn lockFrames(allocator: *FrameAllocator, address: usize, pages: usize) !void {
var index: usize = 0;
while (index < pages) : (index += 1) {
try lockFrame(allocator, address + (index * platform.PAGE_SIZE));
}
}
pub fn freeFrame(allocator: *FrameAllocator, address: usize) !void {
const index = address / platform.PAGE_SIZE;
if (try allocator.bitmap.get(index) == 0) return error.MemoryNotInUse;
try allocator.bitmap.set(index, 0);
allocator.used_memory -= platform.PAGE_SIZE;
allocator.free_memory += platform.PAGE_SIZE;
if (allocator.start_index > index) allocator.start_index = index;
}
pub fn freeFrames(allocator: *FrameAllocator, address: usize, pages: usize) !void {
const index: usize = 0;
while (index < pages) : (index += 1) {
try freeFrame(allocator, address + (index * platform.PAGE_SIZE));
}
}
pub fn allocFrame(allocator: *FrameAllocator) !PhysFrame {
const index: usize = try bmap.findInBitmap(&allocator.bitmap, 0, allocator.start_index) orelse return error.OutOfMemory;
const address = index * platform.PAGE_SIZE;
try lockFrame(allocator, address);
allocator.start_index = index + 1;
return PhysFrame{ .address = address };
}
pub fn initializeFrameAllocator(tag: *easyboot.multiboot_tag_mmap_t) !FrameAllocator {
const largest_free = mmap.findLargestFreeEntry(tag) orelse return error.InvalidMemoryMap;
const physical_address_space_size = mmap.getAddressSpaceSize(tag) orelse return error.InvalidMemoryMap;
const bitmap_base_address: [*]u8 = @ptrFromInt(largest_free.base_addr);
const bitmap_bit_size = physical_address_space_size / @as(usize, platform.PAGE_SIZE);
const bitmap_size: usize = try std.math.divCeil(usize, bitmap_bit_size, 8);
var allocator: FrameAllocator = FrameAllocator{ .bitmap = bmap.createBitmap(bitmap_base_address, bitmap_size), .free_memory = 0, .used_memory = 0, .reserved_memory = 0, .start_index = 0 };
allocator.bitmap.clear(1); // Set all pages to used/reserved by default, then clear out the free ones
var iter = mmap.createMemoryMapIterator(tag);
while (iter.next()) |entry| {
const index = entry.base_addr / platform.PAGE_SIZE;
const pages = entry.length / platform.PAGE_SIZE;
if (entry.type != easyboot.MULTIBOOT_MEMORY_AVAILABLE) {
allocator.reserved_memory += entry.length;
continue;
}
allocator.free_memory += entry.length;
try bmap.updateBitmapRegion(&allocator.bitmap, index, pages, 0);
}
const frames_to_lock = try std.math.divCeil(usize, bitmap_size, platform.PAGE_SIZE);
try lockFrames(&allocator, @intFromPtr(bitmap_base_address), frames_to_lock);
// Avoid causing trouble.
try lockFrame(&allocator, 0);
return allocator;
}