PatchworkOS
Loading...
Searching...
No Matches
pmm.c
Go to the documentation of this file.
1#include <kernel/mem/pmm.h>
2
3#include <kernel/config.h>
4#include <kernel/log/log.h>
5#include <kernel/log/panic.h>
8#include <kernel/sync/lock.h>
9
10#include <boot/boot_info.h>
11
12#include <errno.h>
13#include <sys/math.h>
14#include <sys/proc.h>
15
16static const char* efiMemTypeToString[] = {
17 "reserved",
18 "loader code",
19 "loader data",
20 "boot services code",
21 "boot services data",
22 "runtime services code",
23 "runtime services data",
24 "conventional",
25 "unusable",
26 "acpi reclaim",
27 "acpi memory nvs",
28 "io",
29 "io port space",
30 "pal code",
31 "persistent",
32};
33
34#define PMM_BITMAP_SIZE (CONFIG_PMM_BITMAP_MAX_ADDR / PAGE_SIZE)
35
38
39// Stores the bitmap data
41
43
45
46static bool pmm_is_efi_mem_available(EFI_MEMORY_TYPE type)
47{
48 if (!boot_is_mem_ram(type))
49 {
50 return false;
51 }
52
53 switch (type)
54 {
55 case EfiConventionalMemory:
56 case EfiLoaderCode:
57 // EfiLoaderData is intentionally not included here as it's freed later in `init()`.
58 case EfiBootServicesCode:
59 case EfiBootServicesData:
60 return true;
61 default:
62 return false;
63 }
64}
65
66static void pmm_free_unlocked(void* address)
67{
69 {
71 }
72 else if (address >= (void*)PML_LOWER_TO_HIGHER(0))
73 {
75 }
76 else
77 {
78 panic(NULL, "pmm: attempt to free lower half address %p", address);
79 }
80}
81
83{
85
87 uintptr_t physEnd = physStart + count * PAGE_SIZE;
88
89 if (physEnd <= CONFIG_PMM_BITMAP_MAX_ADDR)
90 {
92 }
93 else if (physStart < CONFIG_PMM_BITMAP_MAX_ADDR)
94 {
95 uint64_t bitmapPageCount = (CONFIG_PMM_BITMAP_MAX_ADDR - physStart) / PAGE_SIZE;
96 pmm_bitmap_free(&bitmap, address, bitmapPageCount);
97
99 for (uint64_t i = 0; i < count - bitmapPageCount; i++)
100 {
101 pmm_stack_free(&stack, (void*)(stackAddr + i * PAGE_SIZE));
102 }
103 }
104 else
105 {
106 for (uint64_t i = 0; i < count; i++)
107 {
109 }
110 }
111}
112
114{
115 LOG_INFO("UEFI-provided memory map\n");
116
117 for (uint64_t i = 0; i < map->length; i++)
118 {
119 const EFI_MEMORY_DESCRIPTOR* desc = BOOT_MEMORY_MAP_GET_DESCRIPTOR(map, i);
120
121 if (boot_is_mem_ram(desc->Type))
122 {
123 pageAmount += desc->NumberOfPages;
124 }
125 }
126
127 LOG_INFO("page amount %llu\n", pageAmount);
128}
129
131{
132 for (uint64_t i = 0; i < map->length; i++)
133 {
134 const EFI_MEMORY_DESCRIPTOR* desc = BOOT_MEMORY_MAP_GET_DESCRIPTOR(map, i);
135
136 if (pmm_is_efi_mem_available(desc->Type))
137 {
138 pmm_free_pages_unlocked((void*)desc->VirtualStart, desc->NumberOfPages);
139 }
140 else
141 {
142 LOG_INFO("reserve [0x%016lx-0x%016lx] pages=%d type=%s\n", desc->VirtualStart,
143 (uint64_t)desc->VirtualStart + desc->NumberOfPages * PAGE_SIZE, desc->NumberOfPages,
144 efiMemTypeToString[desc->Type]);
145 }
146 }
147
148 LOG_INFO("memory %llu MB (usable %llu MB reserved %llu MB)\n", (pageAmount * PAGE_SIZE) / 1000000,
149 (pmm_free_amount() * PAGE_SIZE) / 1000000, ((pageAmount - pmm_free_amount()) * PAGE_SIZE) / 1000000);
150}
151
161
162void* pmm_alloc(void)
163{
165 void* address = pmm_stack_alloc(&stack);
166 if (address == NULL)
167 {
168 LOG_WARN("failed to allocate single page, there are %llu pages left\n", stack.free);
169 errno = ENOMEM;
170 return NULL;
171 }
172 return address;
173}
174
176{
178 for (uint64_t i = 0; i < count; i++)
179 {
180 void* address = pmm_stack_alloc(&stack);
181 if (address == NULL)
182 {
183 LOG_WARN("failed to allocate page %llu of %llu, there are %llu pages left\n", i, count, stack.free);
184 // Free previously allocated pages.
185 for (uint64_t j = 0; j < i; j++)
186 {
187 pmm_stack_free(&stack, addresses[j]);
188 addresses[j] = NULL;
189 }
190 errno = ENOMEM;
191 return ERR;
192 }
193 addresses[i] = address;
194 }
195 return 0;
196}
197
199{
201 void* address = pmm_bitmap_alloc(&bitmap, count, maxAddr, alignment);
202 if (address == NULL)
203 {
204 LOG_WARN("failed to allocate %llu pages from bitmap, there are %llu bitmap pages left\n", count, bitmap.free);
205 errno = ENOMEM;
206 return NULL;
207 }
208 return address;
209}
210
211void pmm_free(void* address)
212{
215}
216
217void pmm_free_pages(void** addresses, uint64_t count)
218{
220 for (uint64_t i = 0; i < count; i++)
221 {
222 pmm_free_unlocked(addresses[i]);
223 }
224}
225
231
233{
235 return pageAmount;
236}
237
239{
241 return stack.free + bitmap.free;
242}
243
245{
247 return pageAmount - (stack.free + bitmap.free);
248}
static bool boot_is_mem_ram(EFI_MEMORY_TYPE type)
Definition boot_info.h:13
#define BOOT_MEMORY_MAP_GET_DESCRIPTOR(map, index)
Definition boot_info.h:41
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:362
#define LOG_WARN(format,...)
Definition log.h:88
#define LOG_INFO(format,...)
Definition log.h:87
#define PML_HIGHER_TO_LOWER(addr)
Converts an address from the higher half to the lower half.
#define PML_LOWER_TO_HIGHER(addr)
Converts an address from the lower half to the higher half.
void * pmm_bitmap_alloc(pmm_bitmap_t *bitmap, uint64_t count, uintptr_t maxAddr, uint64_t alignment)
Allocates a contiguous region of pages from the bitmap.
Definition pmm_bitmap.c:16
void pmm_bitmap_init(pmm_bitmap_t *bitmap, void *buffer, uint64_t size, uintptr_t maxAddr)
Initializes a PMM bitmap.
Definition pmm_bitmap.c:7
void pmm_bitmap_free(pmm_bitmap_t *bitmap, void *address, uint64_t count)
Frees a region of pages, returning them to the bitmap.
Definition pmm_bitmap.c:32
void * pmm_stack_alloc(pmm_stack_t *stack)
Allocates a single page from the stack.
Definition pmm_stack.c:12
void pmm_stack_init(pmm_stack_t *stack)
Initializes a PMM stack.
Definition pmm_stack.c:5
void pmm_stack_free(pmm_stack_t *stack, void *address)
Frees a single page, returning it to the stack.
Definition pmm_stack.c:36
void pmm_init(const boot_memory_map_t *map)
Initializes the Physical Memory Manager.
Definition pmm.c:152
uint64_t pmm_alloc_pages(void **addresses, uint64_t count)
Allocates multiple physical pages.
Definition pmm.c:175
void pmm_free(void *address)
Frees a single physical page.
Definition pmm.c:211
void pmm_free_pages(void **addresses, uint64_t count)
Frees multiple physical pages.
Definition pmm.c:217
void pmm_free_region(void *address, uint64_t count)
Frees a contiguous region of physical pages.
Definition pmm.c:226
uint64_t pmm_free_amount(void)
Retrieves the amount of free physical memory.
Definition pmm.c:238
uint64_t pmm_reserved_amount(void)
Retrieves the amount of reserved physical memory.
Definition pmm.c:244
void * pmm_alloc_bitmap(uint64_t count, uintptr_t maxAddr, uint64_t alignment)
Allocates a contiguous region of physical pages managed by the bitmap.
Definition pmm.c:198
void * pmm_alloc(void)
Allocates a single physical page.
Definition pmm.c:162
uint64_t pmm_total_amount(void)
Retrieves the total amount of physical memory managed by the PMM.
Definition pmm.c:232
#define LOCK_CREATE
Create a lock initializer. @macro LOCK_CREATE.
Definition lock.h:66
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:57
#define CONFIG_PMM_BITMAP_MAX_ADDR
Maximum bitmap allocator address.
Definition config.h:175
#define ENOMEM
Out of memory.
Definition errno.h:92
#define errno
Error number variable.
Definition errno.h:27
#define BITMAP_BITS_TO_QWORDS(bits)
Convert number of bits to number of qwords.
Definition bitmap.h:34
#define ROUND_DOWN(number, multiple)
Definition math.h:21
#define PAGE_SIZE
Memory page size.
Definition proc.h:140
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
static uintptr_t address
Definition hpet.c:12
boot_memory_map_t * map
Definition mem.c:19
static void pmm_free_unlocked(void *address)
Definition pmm.c:66
static uint64_t pageAmount
Definition pmm.c:42
static pmm_stack_t stack
Definition pmm.c:36
static lock_t lock
Definition pmm.c:44
static pmm_bitmap_t bitmap
Definition pmm.c:37
static void pmm_load_memory(const boot_memory_map_t *map)
Definition pmm.c:130
static uint64_t mapBuffer[BITMAP_BITS_TO_QWORDS(PMM_BITMAP_SIZE)]
Definition pmm.c:40
static void pmm_free_pages_unlocked(void *address, uint64_t count)
Definition pmm.c:82
#define PMM_BITMAP_SIZE
Definition pmm.c:34
static bool pmm_is_efi_mem_available(EFI_MEMORY_TYPE type)
Definition pmm.c:46
static const char * efiMemTypeToString[]
Definition pmm.c:16
static void pmm_detect_memory(const boot_memory_map_t *map)
Definition pmm.c:113
static atomic_long count
Definition main.c:9
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINTPTR_TYPE__ uintptr_t
Definition stdint.h:43
uint64_t length
Definition boot_info.h:47
A simple ticket lock implementation.
Definition lock.h:43
Represents a bitmap allocator's state.
Definition pmm_bitmap.h:22
uint64_t free
The number of free pages in the bitmap.
Definition pmm_bitmap.h:30
PMM stack structure for managing higher physical memory.
Definition pmm_stack.h:42
uint64_t free
The number of free pages in the stack.
Definition pmm_stack.h:54