1#include <console/printf.h>
2#include <limine.h>
3#include <math/align.h>
4#include <math/units.h>
5#include <mem/alloc.h>
6#include <mem/bitmap.h>
7#include <mem/buddy.h>
8#include <mem/domain.h>
9#include <mem/pmm.h>
10#include <smp/domain.h>
11#include <stdbool.h>
12#include <stdint.h>
13#include <string.h>
14
15struct limine_memmap_response *memmap;
16typedef paddr_t (*alloc_fn)(size_t pages, enum alloc_flags f);
17
18typedef void (*free_fn)(paddr_t addr, size_t pages);
19
20static alloc_fn current_alloc_fn = bitmap_alloc_pages;
21static free_fn current_free_fn = bitmap_free_pages;
22
23void pmm_early_init(struct limine_memmap_request m) {
24 bitmap = boot_bitmap;
25 memmap = m.response;
26
27 if (memmap == NULL || memmap->entries == NULL) {
28 panic(INIT_FAILED, "Limine memory map unavailable");
29 return;
30 }
31
32 uint64_t total_phys = 0;
33 for (uint64_t i = 0; i < memmap->entry_count; i++) {
34 struct limine_memmap_entry *entry = memmap->entries[i];
35
36 if (entry->type == LIMINE_MEMMAP_USABLE) {
37 total_phys += entry->length;
38 uint64_t start = ALIGN_DOWN(entry->base, PAGE_SIZE);
39 uint64_t end = ALIGN_UP(entry->base + entry->length, PAGE_SIZE);
40
41 for (uint64_t addr = start; addr < end; addr += PAGE_SIZE) {
42 uint64_t index = addr / PAGE_SIZE;
43 if (index < to_bits(BOOT_BITMAP_SIZE)) {
44 clear_bit(index);
45 }
46 }
47 }
48 }
49
50 uint64_t last_usable_pfn = 0;
51
52 for (uint64_t i = 0; i < memmap->entry_count; i++) {
53 struct limine_memmap_entry *entry = memmap->entries[i];
54 if (entry->type != LIMINE_MEMMAP_USABLE)
55 continue;
56
57 uint64_t end =
58 ALIGN_UP(entry->base + entry->length, PAGE_SIZE) / PAGE_SIZE;
59
60 if (end > last_usable_pfn)
61 last_usable_pfn = end;
62 }
63
64 global.last_pfn = last_usable_pfn;
65 global.total_pages = total_phys / PAGE_SIZE;
66}
67
68void pmm_mid_init(void) {
69 buddy_init();
70 current_alloc_fn = buddy_alloc_pages_global;
71 current_free_fn = buddy_free_pages_global;
72}
73
74void pmm_late_init(void) {
75 domain_buddies_init();
76 current_alloc_fn = domain_alloc;
77 current_free_fn = domain_free;
78}
79
80paddr_t pmm_alloc_page_full(enum alloc_flags f) {
81 return pmm_alloc_pages_full(count: 1, flags: f);
82}
83
84void pmm_free_page(paddr_t addr) {
85 pmm_free_pages(addr, count: 1);
86}
87
88paddr_t pmm_alloc_pages_full(uint64_t count, enum alloc_flags f) {
89 return current_alloc_fn(count, f);
90}
91
92void pmm_free_pages(paddr_t addr, uint64_t count) {
93 if (!addr)
94 return;
95
96 current_free_fn(addr, count);
97}
98
99uint64_t pmm_get_usable_ram(void) {
100 return global.total_pages * PAGE_SIZE;
101}
102