/** * HIPPO, the HOS In-place Physical Page Organizer. */ module hulk.hippo; import hulk.header; import hulk.bootinfo; import hulk.klog; import hulk.linker_addresses; struct hippo { /** * Linked list node entry for a physical page. */ private struct PhysicalPage { PhysicalPage * next; } /** * Linked list of free physical pages. */ private static __gshared PhysicalPage * free_pages; /** * Number of free physical pages. */ private static __gshared size_t n_free_pages; /** * Initialize HIPPO. * * Ok, what we do here is iterate through all of the memory map regions in * the bootinfo memory_map array, and create a linked list of all free * physical pages that are available. Within the available memory regions, * we have to watch out for the following items: * 1) HULK binary (text + data) * - This includes the HULK header and bootinfo structures * 2) HULK bss * 3) HULK stack * 4) Framebuffer * 5) Page tables * * @param bootinfo HULK boot information structure. */ public static void initialize(HulkHeader * header) { size_t usable_memory; ulong[2][5] reserved = [ [header.bootinfo.hulk_phys, cast(ulong)header.total_size], [header.bootinfo.bss_phys, LinkerAddresses.hulk_bss_size], [header.bootinfo.stack_phys, header.stack_size], [cast(ulong)header.bootinfo.fb.buffer, header.bootinfo.fb.height * header.bootinfo.fb.stride], [header.bootinfo.pt_phys, header.bootinfo.pt_size], ]; for (size_t ri = 0u; ri < reserved.length; ri++) { reserved[ri][1] += reserved[ri][0]; } for (size_t bii = 0u; bii < header.bootinfo.memory_map_count; bii++) { if (header.bootinfo.memory_map[bii].type == BootInfo.MemoryRegion.Type.Conventional) { ulong phys = header.bootinfo.memory_map[bii].base; ulong phys_end = phys + header.bootinfo.memory_map[bii].size; usable_memory += header.bootinfo.memory_map[bii].size; while (phys < phys_end) { bool is_reserved = false; for (size_t ri = 0u; ri < reserved.length; ri++) { if ((reserved[ri][0] <= phys) && (phys < reserved[ri][1])) { is_reserved = true; break; } } if (!is_reserved) { free_page(phys); } phys += 4096u; } } } size_t usable_kb = usable_memory >> 10u; size_t usable_mb = usable_kb >> 10u; size_t frac_mb = ((1000u * (usable_kb & 0x3FFu)) + 512u) >> 10u; klog.writefln("Found %u.%03uMB of usable RAM", usable_mb, frac_mb); } /** * Free a physical page. * * @param phys Physical page address. */ private static void free_page(ulong phys) { PhysicalPage * pp = cast(PhysicalPage *)phys; pp.next = free_pages; free_pages = pp; n_free_pages++; } /** * Allocate a physical page. * * @return Page address, or null if none available. */ public static void * allocate_page() { PhysicalPage * pp; if (free_pages != null) { pp = free_pages; free_pages = free_pages.next; } return cast(void *)pp; } }