PatchworkOS  c9fea19
A non-POSIX operating system.
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>
5#include <kernel/log/log.h>
6#include <kernel/log/panic.h>
9#include <kernel/sync/lock.h>
10
11#include <boot/boot_info.h>
12
13#include <errno.h>
14#include <string.h>
15#include <sys/math.h>
16#include <sys/proc.h>
17
18static const char* efiMemTypeToString[] = {
19 "reserved",
20 "loader code",
21 "loader data",
22 "boot services code",
23 "boot services data",
24 "runtime services code",
25 "runtime services data",
26 "conventional",
27 "unusable",
28 "acpi reclaim",
29 "acpi memory nvs",
30 "io",
31 "io port space",
32 "pal code",
33 "persistent",
34};
35
36#define PMM_BITMAP_SIZE (CONFIG_PMM_BITMAP_MAX_ADDR / PAGE_SIZE)
37
40
41// Stores the bitmap data
43
45
47
48static bool pmm_is_efi_mem_available(EFI_MEMORY_TYPE type)
49{
50 if (!boot_is_mem_ram(type))
51 {
52 return false;
53 }
54
55 switch (type)
56 {
57 case EfiConventionalMemory:
58 case EfiLoaderCode:
59 // EfiLoaderData is intentionally not included here as it's freed later in `init()`.
60 case EfiBootServicesCode:
61 case EfiBootServicesData:
62 return true;
63 default:
64 return false;
65 }
66}
67
68static void pmm_free_unlocked(void* address)
69{
71 {
73 }
74 else if (address >= (void*)PML_LOWER_TO_HIGHER(0))
75 {
77 }
78 else
79 {
80 panic(NULL, "pmm: attempt to free lower half address %p", address);
81 }
82}
83
85{
87
89 uintptr_t physEnd = physStart + count * PAGE_SIZE;
90
91 if (physEnd <= CONFIG_PMM_BITMAP_MAX_ADDR)
92 {
94 }
95 else if (physStart < CONFIG_PMM_BITMAP_MAX_ADDR)
96 {
97 uint64_t bitmapPageCount = (CONFIG_PMM_BITMAP_MAX_ADDR - physStart) / PAGE_SIZE;
98 pmm_bitmap_free(&bitmap, address, bitmapPageCount);
99
101 for (uint64_t i = 0; i < count - bitmapPageCount; i++)
102 {
103 pmm_stack_free(&stack, (void*)(stackAddr + i * PAGE_SIZE));
104 }
105 }
106 else
107 {
108 for (uint64_t i = 0; i < count; i++)
109 {
111 }
112 }
113}
114
116{
117 LOG_INFO("UEFI-provided memory map\n");
118
119 for (uint64_t i = 0; i < map->length; i++)
120 {
121 const EFI_MEMORY_DESCRIPTOR* desc = BOOT_MEMORY_MAP_GET_DESCRIPTOR(map, i);
122
123 if (boot_is_mem_ram(desc->Type))
124 {
125 pageAmount += desc->NumberOfPages;
126 }
127 }
128
129 LOG_INFO("page amount %llu\n", pageAmount);
130}
131
133{
134 for (uint64_t i = 0; i < map->length; i++)
135 {
136 const EFI_MEMORY_DESCRIPTOR* desc = BOOT_MEMORY_MAP_GET_DESCRIPTOR(map, i);
137
138 if (pmm_is_efi_mem_available(desc->Type))
139 {
140#ifndef NDEBUG
141 // Clear the memory to deliberatly cause corruption if the memory is actually being used.
142 memset((void*)desc->VirtualStart, 0xCC, desc->NumberOfPages * PAGE_SIZE);
143#endif
144 pmm_free_pages_unlocked((void*)desc->VirtualStart, desc->NumberOfPages);
145 }
146 else
147 {
148 LOG_INFO("reserve [0x%016lx-0x%016lx] pages=%d type=%s\n", desc->VirtualStart,
149 (uint64_t)desc->VirtualStart + desc->NumberOfPages * PAGE_SIZE, desc->NumberOfPages,
150 efiMemTypeToString[desc->Type]);
151 }
152 }
153
154 LOG_INFO("memory %llu MB (usable %llu MB reserved %llu MB)\n", (pageAmount * PAGE_SIZE) / 1000000,
155 (pmm_free_amount() * PAGE_SIZE) / 1000000, ((pageAmount - pmm_free_amount()) * PAGE_SIZE) / 1000000);
156}
157
170
171void* pmm_alloc(void)
172{
174 void* address = pmm_stack_alloc(&stack);
175 if (address == NULL)
176 {
177 LOG_WARN("failed to allocate single page, there are %llu pages left\n", stack.free);
178 errno = ENOMEM;
179 return NULL;
180 }
181 return address;
182}
183
185{
187 for (uint64_t i = 0; i < count; i++)
188 {
189 void* address = pmm_stack_alloc(&stack);
190 if (address == NULL)
191 {
192 LOG_WARN("failed to allocate page %llu of %llu, there are %llu pages left\n", i, count, stack.free);
193 // Free previously allocated pages.
194 for (uint64_t j = 0; j < i; j++)
195 {
196 pmm_stack_free(&stack, addresses[j]);
197 addresses[j] = NULL;
198 }
199 errno = ENOMEM;
200 return ERR;
201 }
202 addresses[i] = address;
203 }
204 return 0;
205}
206
208{
210 void* address = pmm_bitmap_alloc(&bitmap, count, maxAddr, alignment);
211 if (address == NULL)
212 {
213 LOG_WARN("failed to allocate %llu pages from bitmap, there are %llu bitmap pages left\n", count, bitmap.free);
214 errno = ENOMEM;
215 return NULL;
216 }
217 return address;
218}
219
220void pmm_free(void* address)
221{
224}
225
226void pmm_free_pages(void** addresses, uint64_t count)
227{
229 for (uint64_t i = 0; i < count; i++)
230 {
231 pmm_free_unlocked(addresses[i]);
232 }
233}
234
240
242{
244 return pageAmount;
245}
246
248{
250 return stack.free + bitmap.free;
251}
252
254{
256 return pageAmount - (stack.free + bitmap.free);
257}
boot_info_t * bootInfo
Definition boot_info.c:14
static bool boot_is_mem_ram(EFI_MEMORY_TYPE type)
Definition boot_info.h:24
#define BOOT_MEMORY_MAP_GET_DESCRIPTOR(map, index)
Definition boot_info.h:52
boot_info_t * boot_info_get(void)
Gets the boot info structure.
Definition boot_info.c:16
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:266
#define LOG_WARN(format,...)
Definition log.h:107
#define LOG_INFO(format,...)
Definition log.h:106
#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
uint64_t pmm_alloc_pages(void **addresses, uint64_t count)
Allocates multiple physical pages.
Definition pmm.c:184
void pmm_free(void *address)
Frees a single physical page.
Definition pmm.c:220
void pmm_free_pages(void **addresses, uint64_t count)
Frees multiple physical pages.
Definition pmm.c:226
void pmm_free_region(void *address, uint64_t count)
Frees a contiguous region of physical pages.
Definition pmm.c:235
uint64_t pmm_free_amount(void)
Retrieves the amount of free physical memory.
Definition pmm.c:247
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:207
void * pmm_alloc(void)
Allocates a single physical page.
Definition pmm.c:171
uint64_t pmm_used_amount(void)
Retrieves the amount of reserved physical memory.
Definition pmm.c:253
uint64_t pmm_total_amount(void)
Retrieves the total amount of physical memory managed by the PMM.
Definition pmm.c:241
void pmm_init(void)
Initializes the Physical Memory Manager.
Definition pmm.c:158
#define LOCK_CREATE()
Create a lock initializer.
Definition lock.h:68
#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:141
#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
The size of a memory page in bytes.
Definition proc.h:106
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
static uintptr_t address
Mapped virtual address of the HPET registers.
Definition hpet.c:95
boot_memory_map_t * map
Definition mem.c:19
static void pmm_free_unlocked(void *address)
Definition pmm.c:68
static uint64_t pageAmount
Definition pmm.c:44
static pmm_stack_t stack
Definition pmm.c:38
static lock_t lock
Definition pmm.c:46
static pmm_bitmap_t bitmap
Definition pmm.c:39
static void pmm_load_memory(const boot_memory_map_t *map)
Definition pmm.c:132
static uint64_t bitmapBuffer[BITMAP_BITS_TO_QWORDS(PMM_BITMAP_SIZE)]
Definition pmm.c:42
static void pmm_free_pages_unlocked(void *address, uint64_t count)
Definition pmm.c:84
#define PMM_BITMAP_SIZE
Definition pmm.c:36
static bool pmm_is_efi_mem_available(EFI_MEMORY_TYPE type)
Definition pmm.c:48
static const char * efiMemTypeToString[]
Definition pmm.c:18
static void pmm_detect_memory(const boot_memory_map_t *map)
Definition pmm.c:115
static atomic_long count
Definition main.c:10
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINTPTR_TYPE__ uintptr_t
Definition stdint.h:43
_PUBLIC void * memset(void *s, int c, size_t n)
Definition memset.c:4
boot_memory_t memory
Definition boot_info.h:106
uint64_t length
Definition boot_info.h:58
boot_memory_map_t map
Definition boot_info.h:95
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