Microkernel thing OS experiment (Zig ⚡)
at dev 5.4 kB view raw
1/// Simple Multi Bump Allocator, because the old buddy system wasn't 2/// suitable to pass memory down to the root task, and we never 3/// have to free memory 4const std = @import("std"); 5const common = @import("../root.zig"); 6const arch = @import("arch"); 7const log = std.log.scoped(.bootmem); 8 9/// This is meant for pageframe allocation, does bump allocation with 10/// a first fit from the end. Ideally we do as little memory allocation 11/// as possible in the microkernel anyways. 12pub const BootPmm = struct { 13 // Store this in a chunk of ram which you remove from the region 14 regions: []Region = undefined, 15 //top_region: usize = undefined, 16 17 const Self = @This(); 18 pub const Region = struct { 19 base: usize, 20 length: usize, 21 type: RegionType, 22 }; 23 pub const RegionType = enum(usize) { 24 usable = 0, 25 acpi_reclaimable = 1, 26 bootloader_reclaimable = 2, 27 executable_and_modules = 3, 28 framebuffer = 4, 29 // Just forget about reserved regions for now 30 reserved = 5, 31 }; 32 33 // Calculate the needed size to allocate the []Region slice 34 pub fn calculateMetadataSize(entries: usize) usize { 35 return entries * @sizeOf(Region); 36 } 37 38 /// For the love of god len(regions) must be > 0 39 /// Only call this function once 40 pub fn initialize(self: *Self, regions: []Region) void { 41 self.regions = regions; 42 //self.top_region = regions.len - 1; 43 } 44 45 /// Allocates physical memory, aligned to page size 46 pub fn allocPhys(self: *Self, size: usize) !usize { 47 if (self.regions.len == 0) { 48 @branchHint(.cold); 49 return error.NoMemory; 50 } 51 const true_alloc_size = std.mem.alignForward(usize, size, std.heap.pageSize()); 52 53 var i: usize = self.regions.len; 54 while (i > 0) : (i -= 1) { 55 const region = &self.regions[i - 1]; 56 if (region.type != .usable) continue; 57 if (true_alloc_size > region.length) continue; 58 region.length -= true_alloc_size; 59 return region.base + region.length; 60 } 61 return error.OutOfMemory; 62 } 63 64 pub fn allocMem(self: *Self, size: usize) !usize { 65 return try self.allocPhys(size) + common.init_data.hhdm_slide; 66 } 67 68 pub fn debugInfo(self: *Self) void { 69 var total: usize = 0; 70 var usable: usize = 0; 71 72 for (self.regions) |region| { 73 total += region.length; 74 if (region.type == .usable) usable += region.length; 75 } 76 77 const total_gib = total / (1 << 30); 78 total -= total_gib * (1 << 30); 79 const total_mib = total / (1 << 20); 80 total -= total_mib * (1 << 20); 81 const total_kib = total / (1 << 10); 82 log.debug("Total Memory: {} GiB + {} MiB + {} KiB", .{ total_gib, total_mib, total_kib }); 83 84 const usable_gib = usable / (1 << 30); 85 usable -= usable_gib * (1 << 30); 86 const usable_mib = usable / (1 << 20); 87 usable -= usable_mib * (1 << 20); 88 const usable_kib = usable / (1 << 10); 89 log.debug("Usable: {} GiB + {} MiB + {} KiB", .{ usable_gib, usable_mib, usable_kib }); 90 } 91}; 92 93pub fn init() void { 94 const memmap = arch.boot.limine_requests.memmap.response.?.getEntries(); 95 96 const bootmem_structure_size, const region_count = blk: { 97 var region_count: usize = 0; 98 for (memmap) |region| { 99 switch (region.type) { 100 .usable, .acpi_reclaimable, .bootloader_reclaimable, .executable_and_modules, .framebuffer => region_count += 1, 101 else => {}, 102 } 103 } 104 105 break :blk .{ BootPmm.calculateMetadataSize(region_count), region_count }; 106 }; 107 const bootmem_pages = std.mem.alignForward(usize, bootmem_structure_size, std.heap.pageSize()); 108 109 // Given the bootmem structure size, find a page to hold it 110 const bootmem_struct: []BootPmm.Region = blk: { 111 var i: usize = memmap.len; 112 while (i > 0) : (i -= 1) { 113 const region = memmap[i - 1]; 114 if (bootmem_pages > region.length) continue; 115 switch (region.type) { 116 .usable => {}, 117 else => continue, 118 } 119 // Unfortunately, we can't modify the limine memory map itself 120 // So, remember the region we ate from instead 121 region.length -= bootmem_pages; 122 const bootmem_struct_ptr = common.mm.physToHHDM([*]BootPmm.Region, region.base + region.length); 123 break :blk bootmem_struct_ptr[0..region_count]; 124 } 125 @panic("Couldn't allocate bootmem structure!"); 126 }; 127 // Now, fill the bootmem structure out from the limine memmap 128 var i: usize = 0; 129 for (memmap) |region| { 130 switch (region.type) { 131 .usable => bootmem_struct[i].type = .usable, 132 .acpi_reclaimable => bootmem_struct[i].type = .acpi_reclaimable, 133 .bootloader_reclaimable => bootmem_struct[i].type = .bootloader_reclaimable, 134 .executable_and_modules => bootmem_struct[i].type = .executable_and_modules, 135 .framebuffer => bootmem_struct[i].type = .framebuffer, 136 else => continue, 137 } 138 bootmem_struct[i].base = region.base; 139 bootmem_struct[i].length = region.length; 140 i += 1; 141 } 142 143 // Finally, initialize the global bootmem 144 common.init_data.bootmem.initialize(bootmem_struct); 145}