phys: use a bitmap to track pages
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
//! Simple bump allocator arena.
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const phys_memory = @import("mem/phys.zig");
|
||||
const log = @import("debug.zig").log;
|
||||
const mem = @import("mem.zig");
|
||||
|
||||
+53
-14
@@ -43,21 +43,22 @@ const PhysicalMemoryManager = struct {
|
||||
page_array: []Page,
|
||||
offset: u64 = 0,
|
||||
last_free: usize = 0,
|
||||
bitmap: []u64, // Each bit represents a page
|
||||
|
||||
const RECORDS_PER_PAGE: usize = vmm.PAGE_SIZE / @sizeOf(Page);
|
||||
|
||||
fn alloc_page(self: *@This()) ?mem.PhysicalAddress {
|
||||
for (self.last_free..self.page_array.len) |i| {
|
||||
if (self.page_array[i].refcount == 0) {
|
||||
self.page_array[i].refcount += 1;
|
||||
self.last_free = (i + 1) % self.page_array.len;
|
||||
for (self.last_free..self.bitmap.len * 64) |i| {
|
||||
if (!self.is_page_used(i)) {
|
||||
self.set_page_used(i);
|
||||
self.last_free = (i + 1) % (self.bitmap.len * 64);
|
||||
return .{ .raw = self.offset + i * vmm.PAGE_SIZE };
|
||||
}
|
||||
}
|
||||
for (0..self.last_free) |i| {
|
||||
if (self.page_array[i].refcount == 0) {
|
||||
self.page_array[i].refcount += 1;
|
||||
self.last_free = (i + 1) % self.page_array.len;
|
||||
if (!self.is_page_used(i)) {
|
||||
self.set_page_used(i);
|
||||
self.last_free = (i + 1) % (self.bitmap.len * 64);
|
||||
return .{ .raw = self.offset + i * vmm.PAGE_SIZE };
|
||||
}
|
||||
}
|
||||
@@ -107,25 +108,44 @@ const PhysicalMemoryManager = struct {
|
||||
|
||||
fn free_page(self: *@This(), page: mem.PhysicalAddress) void {
|
||||
const index = self.valid_index(page);
|
||||
if (self.page_array[index].refcount == 0) {
|
||||
if (!self.is_page_used(index)) {
|
||||
log.panic("free_page: double free of page 0x{x} detected", .{page.raw});
|
||||
}
|
||||
self.page_array[index].refcount -= 1;
|
||||
if (self.page_array[index].refcount == 0) {
|
||||
self.last_free = index;
|
||||
}
|
||||
self.clear_page_used(index);
|
||||
self.last_free = index;
|
||||
}
|
||||
|
||||
fn get_page(self: *@This(), page: mem.PhysicalAddress) *Page {
|
||||
const index = self.valid_index(page);
|
||||
return &self.page_array[index];
|
||||
}
|
||||
|
||||
fn is_page_used(self: *@This(), index: usize) bool {
|
||||
const word_index = index / 64;
|
||||
const bit_index = index % 64;
|
||||
return (self.bitmap[word_index] & (@as(u64, 1) << @intCast(bit_index))) != 0;
|
||||
}
|
||||
|
||||
fn set_page_used(self: *@This(), index: usize) void {
|
||||
const word_index = index / 64;
|
||||
const bit_index = index % 64;
|
||||
self.bitmap[word_index] |= (@as(u64, 1) << @intCast(bit_index));
|
||||
}
|
||||
|
||||
fn clear_page_used(self: *@This(), index: usize) void {
|
||||
const word_index = index / 64;
|
||||
const bit_index = index % 64;
|
||||
self.bitmap[word_index] &= ~(@as(u64, 1) << @intCast(bit_index));
|
||||
}
|
||||
};
|
||||
|
||||
var g_memory_regions: std.BoundedArray(MemoryRegion, 16) = .{};
|
||||
var g_reserved_regions: std.BoundedArray(MemoryRegion, 16) = .{};
|
||||
var g_physical_memory_lock = Spinlock{};
|
||||
var g_physical_memory = PhysicalMemoryManager{ .page_array = undefined };
|
||||
var g_physical_memory = PhysicalMemoryManager{
|
||||
.page_array = undefined,
|
||||
.bitmap = undefined,
|
||||
};
|
||||
|
||||
/// Adds an available memory region to the list.
|
||||
///
|
||||
@@ -198,6 +218,21 @@ fn alloc_page_array(page_count: usize) []Page {
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
fn alloc_bitmap(pages: usize) []u64 {
|
||||
// Round up to the upper u64 that has at least `pages` bits
|
||||
const bitmap_entries = (pages + 63) / 64;
|
||||
for (g_memory_regions.constSlice()) |region| {
|
||||
if (alloc_from_region(®ion, "bitmap", bitmap_entries * @sizeOf(u64))) |phys_address| {
|
||||
const vaddr = (mem.PhysicalAddress{ .raw = phys_address }).virtualize();
|
||||
const ptr: [*]u64 = @ptrFromInt(vaddr);
|
||||
const slice: []u64 = ptr[0..bitmap_entries];
|
||||
@memset(slice, 0); // Clear the bitmap
|
||||
return slice;
|
||||
}
|
||||
}
|
||||
@panic("Failed to allocate bitmap");
|
||||
}
|
||||
|
||||
/// Initializes the physical memory management.
|
||||
///
|
||||
/// # Notes
|
||||
@@ -218,10 +253,13 @@ pub fn init() void {
|
||||
}
|
||||
|
||||
const memory_pages = (memory_end - memory_start) / vmm.PAGE_SIZE; // == bitmap bits required
|
||||
const bitmap = alloc_bitmap(memory_pages);
|
||||
|
||||
const page_array_pages = (memory_pages + PhysicalMemoryManager.RECORDS_PER_PAGE - 1) //
|
||||
/ PhysicalMemoryManager.RECORDS_PER_PAGE;
|
||||
/ PhysicalMemoryManager.RECORDS_PER_PAGE;
|
||||
|
||||
const page_array = alloc_page_array(page_array_pages);
|
||||
|
||||
var available_pages: usize = 0;
|
||||
|
||||
for (g_memory_regions.constSlice()) |region| {
|
||||
@@ -248,6 +286,7 @@ pub fn init() void {
|
||||
|
||||
g_physical_memory.page_array = page_array;
|
||||
g_physical_memory.offset = memory_start;
|
||||
g_physical_memory.bitmap = bitmap;
|
||||
}
|
||||
|
||||
fn trace_allocation(count: usize, page: ?mem.PhysicalAddress) void {
|
||||
|
||||
Reference in New Issue
Block a user