PatchworkOS
Loading...
Searching...
No Matches
mem.c
Go to the documentation of this file.
1#include "mem.h"
2#include "efidef.h"
3
4#include <efilib.h>
5#include <kernel/defs.h>
7
8#include <boot/boot_info.h>
9#include <kernel/mem/paging.h>
10#include <sys/proc.h>
11
12// We cant use the normal memory allocator after exiting boot services so we use this basic one instead.
13struct
14{
15 EFI_PHYSICAL_ADDRESS buffer;
21
22EFI_STATUS mem_init(void)
23{
24 Print(L"Initializing basic allocator... ");
25
27 EFI_STATUS status = mem_map_init(&map);
28 if (EFI_ERROR(status))
29 {
30 Print(L"failed to initialize memory map (0x%lx)!\n", status);
31 return status;
32 }
33
34 uint64_t availPages = 0;
35 for (size_t i = 0; i < map.length; i++)
36 {
37 EFI_MEMORY_DESCRIPTOR* desc = BOOT_MEMORY_MAP_GET_DESCRIPTOR(&map, i);
38 if (desc->Type == EfiConventionalMemory)
39 {
40 availPages += desc->NumberOfPages;
41 }
42 }
43
44 basicAllocator.maxPages =
46 Print(L"basic alloc using %llu pages... ", basicAllocator.maxPages);
47
48 status = uefi_call_wrapper(BS->AllocatePages, 4, AllocateAnyPages, EfiLoaderData, basicAllocator.maxPages,
49 &basicAllocator.buffer);
50 if (EFI_ERROR(status))
51 {
52 Print(L"failed to allocate buffer (0x%lx)!\n", status);
53 return status;
54 }
55
56 basicAllocator.pagesAllocated = 0;
57 basicAllocator.gop = NULL;
58 basicAllocator.map = NULL;
59
60 Print(L"done!\n");
61 return EFI_SUCCESS;
62}
63
65{
66 EFI_STATUS status = EFI_SUCCESS;
67
68 map->descriptors = LibMemoryMap(&map->length, &map->key, &map->descSize, &map->descVersion);
69 if (map->descriptors == NULL)
70 {
71 return EFI_OUT_OF_RESOURCES;
72 }
73
74 for (size_t i = 0; i < map->length; i++)
75 {
76 EFI_MEMORY_DESCRIPTOR* desc = BOOT_MEMORY_MAP_GET_DESCRIPTOR(map, i);
77 desc->VirtualStart = (EFI_VIRTUAL_ADDRESS)PML_LOWER_TO_HIGHER(desc->PhysicalStart);
78 }
79
80 return status;
81}
82
84{
85 FreePool(map->descriptors);
87 map->length = 0;
88}
89
91{
92 // Getting here would be bad, we have exited boot services so we cant print to the screen, and are out of
93 // memory. A better solution might be to implement a very basic logging system, but for now we just fill the screen
94 // with a color and halt the CPU.
95 uint32_t color = 0xFF000000 | (red << 16) | (green << 8) | (blue);
96 for (uint64_t y = 0; y < basicAllocator.gop->height; y++)
97 {
98 for (uint64_t x = 0; x < basicAllocator.gop->width; x++)
99 {
100 basicAllocator.gop->physAddr[x + y * basicAllocator.gop->stride] = color;
101 }
102 }
103 for (;;)
104 {
105 asm("cli; hlt");
106 }
107}
108
110{
111 if (basicAllocator.pagesAllocated + amount >= basicAllocator.maxPages)
112 {
113 panic_without_boot_services(0xFF, 0x00, 0x00);
114 }
115
116 for (uint64_t i = 0; i < amount; i++)
117 {
118 *pages = (void*)(basicAllocator.buffer + basicAllocator.pagesAllocated * PAGE_SIZE);
119 basicAllocator.pagesAllocated++;
120 pages++;
121 }
122 return 0;
123}
124
126{
127 basicAllocator.gop = gop;
128 basicAllocator.map = map;
129
131 {
132 panic_without_boot_services(0x00, 0xFF, 0x00);
133 }
134
135 uintptr_t maxAddress = 0;
136 for (uint64_t i = 0; i < map->length; i++)
137 {
138 const EFI_MEMORY_DESCRIPTOR* desc = BOOT_MEMORY_MAP_GET_DESCRIPTOR(map, i);
139 maxAddress = MAX(maxAddress, desc->PhysicalStart + desc->NumberOfPages * PAGE_SIZE);
140 }
141
142 // I have no idea why its not enough to just identity map everything in the memory map, but this seems to be
143 // required for paging to work properly on all platforms.
144 if (page_table_map(table, 0, 0, BYTES_TO_PAGES(maxAddress), PML_WRITE | PML_PRESENT, PML_CALLBACK_NONE) == ERR)
145 {
146 panic_without_boot_services(0xFF, 0xFF, 0x00);
147 }
148
149 for (uint64_t i = 0; i < map->length; i++)
150 {
151 const EFI_MEMORY_DESCRIPTOR* desc = BOOT_MEMORY_MAP_GET_DESCRIPTOR(map, i);
152 if (desc->VirtualStart < PML_HIGHER_HALF_START)
153 {
154 panic_without_boot_services(0x00, 0x00, 0xFF);
155 }
156 if (desc->PhysicalStart > PML_LOWER_HALF_END)
157 {
158 panic_without_boot_services(0xFF, 0x00, 0xFF);
159 }
160
161 if (page_table_map(table, (void*)desc->VirtualStart, (void*)desc->PhysicalStart, desc->NumberOfPages,
163 {
164 panic_without_boot_services(0xFF, 0x00, 0xFF);
165 }
166 }
167
168 if (page_table_map(table, (void*)kernel->virtStart, (void*)kernel->physStart, BYTES_TO_PAGES(kernel->size),
170 {
171 panic_without_boot_services(0x00, 0xFF, 0xFF);
172 }
173
174 if (page_table_map(table, (void*)gop->virtAddr, (void*)gop->physAddr, BYTES_TO_PAGES(gop->size),
176 {
177 panic_without_boot_services(0xFF, 0xFF, 0xFF);
178 }
179}
#define BOOT_MEMORY_MAP_GET_DESCRIPTOR(map, index)
Definition boot_info.h:41
EFI_STATUS mem_map_init(boot_memory_map_t *map)
Initialize and load the memory map provided by the UEFI firmware.
Definition mem.c:64
void mem_page_table_init(page_table_t *table, boot_memory_map_t *map, boot_gop_t *gop, boot_kernel_t *kernel)
Initializes a page table for use by the kernel.
Definition mem.c:125
#define MEM_BASIC_ALLOCATOR_RESERVE_PERCENTAGE
The percentage of available memory that we will reserve for the basic allocator.
Definition mem.h:29
#define MEM_BASIC_ALLOCATOR_MIN_PAGES
The minimum amount of pages that we will reserve for the basic allocator.
Definition mem.h:22
void mem_map_deinit(boot_memory_map_t *map)
Deinitializes the memory map and frees any allocated resources.
Definition mem.c:83
EFI_STATUS mem_init(void)
Initializes the basic memory allocator.
Definition mem.c:22
#define NORETURN
GCC noreturn function attribute.
Definition defs.h:39
#define PML_CALLBACK_NONE
Special callback ID that indicates no callback is associated with the page.
static uint64_t page_table_map(page_table_t *table, void *virtAddr, void *physAddr, uint64_t pageAmount, pml_flags_t flags, pml_callback_id_t callbackId)
Maps a range of virtual addresses to physical addresses in the page table.
Definition paging.h:422
#define PML_LOWER_HALF_END
The end of the lower half of the address space.
#define PML_LOWER_TO_HIGHER(addr)
Converts an address from the lower half to the higher half.
static uint64_t page_table_init(page_table_t *table, pml_alloc_pages_t allocPages, pml_free_pages_t freePages)
Initializes a page table.
Definition paging.h:157
#define PML_HIGHER_HALF_START
The start of the higher half of the address space.
@ PML_PRESENT
@ PML_WRITE
#define MAX(x, y)
Definition math.h:15
#define PAGE_SIZE
Memory page size.
Definition proc.h:140
#define BYTES_TO_PAGES(amount)
Convert bytes to pages.
Definition proc.h:151
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
uint64_t pagesAllocated
Definition mem.c:17
boot_gop_t * gop
Definition mem.c:18
static NORETURN void panic_without_boot_services(uint8_t red, uint8_t green, uint8_t blue)
Definition mem.c:90
uint64_t maxPages
Definition mem.c:16
boot_memory_map_t * map
Definition mem.c:19
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
static uint64_t basic_allocator_alloc_pages(void **pages, uint64_t amount)
Definition mem.c:109
struct @29 basicAllocator
int64_t x
Definition main.c:152
int64_t y
Definition main.c:153
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
__UINTPTR_TYPE__ uintptr_t
Definition stdint.h:43
uint64_t size
Definition boot_info.h:35
uint32_t * virtAddr
Definition boot_info.h:34
uint32_t * physAddr
Definition boot_info.h:33
uintptr_t virtStart
Definition boot_info.h:89
uintptr_t physStart
Definition boot_info.h:88
uint64_t size
Definition boot_info.h:91
uint64_t length
Definition boot_info.h:47
EFI_MEMORY_DESCRIPTOR * descriptors
Definition boot_info.h:46
A page table structure.