Max OS 0.3
Loading...
Searching...
No Matches
virtual.cpp
Go to the documentation of this file.
1
9#include <memory/virtual.h>
10#include <common/logger.h>
11#include <processes/scheduler.h>
12
13using namespace MaxOS::memory;
14using namespace MaxOS::common;
15using namespace MaxOS::processes;
16
23
24 // Set the kernel flag
25 bool is_kernel = MemoryManager::s_kernel_memory_manager == nullptr;
26 if (!is_kernel) {
27
28 // Get a new pml4 table
29 m_pml4_root_physical_address = (uint64_t*) PhysicalMemoryManager::s_current_manager->allocate_frame();
30 m_pml4_root_address = (uint64_t*) PhysicalMemoryManager::to_dm_region((uint64_t) m_pml4_root_physical_address);
31
32 // Clear the table
33 PhysicalMemoryManager::clean_page_table(m_pml4_root_address);
34
35 // Map the higher half of the kernel (p4 256 - 511)
36 for (size_t i = 256; i < 512; i++) {
37
38 // Recursive Map the pml4 table (so that we can access the new pml4 table later on)
39 if (i == 510) {
40 m_pml4_root_address[i] = (uint64_t) m_pml4_root_physical_address | PRESENT | WRITE;
41 continue;
42 }
43
44 // Set the new pml4 table to the old (kernel) pml4 table
45 m_pml4_root_address[i] = PhysicalMemoryManager::s_current_manager->pml4_root_address()[i];
46
47 }
48 Logger::DEBUG() << "Mapped higher half of kernel\n";
49
50
51 } else {
52 m_pml4_root_address = PhysicalMemoryManager::s_current_manager->pml4_root_address();
53 m_pml4_root_physical_address = (uint64_t*) PhysicalMemoryManager::to_lower_region((uint64_t) m_pml4_root_address);
54 }
55
56 // Allocate space for the vmm
60 Logger::DEBUG() << "VMM space: physical - 0x" << (uint64_t) vmm_space_physical << ", virtual - 0x" << (uint64_t) vmm_space << "\n";
61
62 // Make sure everything is mapped correctly
63 if (!is_kernel)
64 ASSERT(vmm_space_physical != PhysicalMemoryManager::s_current_manager->get_physical_address((virtual_address_t*) vmm_space, m_pml4_root_address), "Physical address does not match mapped address: 0x%x != 0x%x\n", vmm_space_physical,
65 PhysicalMemoryManager::s_current_manager->get_physical_address((virtual_address_t*) vmm_space, m_pml4_root_address));
66
67 // Set the first region
68 m_first_region = (virtual_memory_region_t*) vmm_space;
69 m_current_region = m_first_region;
70 m_first_region->next = nullptr;
71
72 // Calculate the next available address (kernel needs to reserve space for the higher half)
73 m_next_available_address = is_kernel ? vmm_space + VMM_RESERVED : PAGE_SIZE;
74 Logger::DEBUG() << "Next available address: 0x" << m_next_available_address << "\n";
75
76}
77
82
83 // Free all the frames used by the VMM
84 virtual_memory_region_t* region = m_first_region;
85
86 // Loop through the regions
87 while (region != nullptr) {
88
89 // Loop through the chunks
90 for (size_t i = 0; i < CHUNKS_PER_PAGE; i++) {
91
92 // Have reached the end?
93 if (i == m_current_chunk && region == m_current_region)
94 break;
95
96 // Free each page in the chunk
97 size_t pages = PhysicalMemoryManager::size_to_frames(region->chunks[i].size);
98 for (size_t j = 0; j < pages; j++) {
99
100 // Convert the virtual address to a physical address and free it
101 physical_address_t* frame = PhysicalMemoryManager::s_current_manager->get_physical_address((virtual_address_t*) region->chunks[i].start_address + (j * PAGE_SIZE), m_pml4_root_address);
103
104 }
105 }
106
107 region = region->next;
108 }
109}
110
111
119void* VirtualMemoryManager::allocate(size_t size, size_t flags) {
120
121 return allocate(0, size, flags);
122}
123
124
133void* VirtualMemoryManager::allocate(uint64_t address, size_t size, size_t flags) {
134
135 // Make sure allocating something
136 if (size == 0)
137 return nullptr;
138
139 // If specific address is given
140 if (address != 0) {
141
142 // Make sure isn't already allocated
143 if (address < m_next_available_address)
144 return nullptr;
145
146 // Make sure its aligned
148 return nullptr;
149
150 }
151
152 // Make sure the size is aligned
154
155 // Check the free list for a chunk (if not asking for a specific address)
156 free_chunk_t* reusable_chunk = address == 0 ? find_and_remove_free_chunk(size) : nullptr;
157 if (reusable_chunk != nullptr) {
158
159 // If the chunk is not being reserved then the old memory needs to be unmapped
160 if (flags & VirtualFlags::RESERVE) {
161
162 // Unmap the memory
164 for (size_t i = 0; i < pages; i++) {
165
166 // Get the frame
167 physical_address_t* frame = PhysicalMemoryManager::s_current_manager->get_physical_address((virtual_address_t*) reusable_chunk->start_address + (i * PAGE_SIZE), m_pml4_root_address);
168
169 // Free the frame
171
172 }
173 }
174
175 // Return the address
176 return (void*) reusable_chunk->start_address;
177 }
178
179
180 // Is there space in the current region
181 if (m_current_chunk >= CHUNKS_PER_PAGE)
182 new_region();
183
184 // If needed to allocate at a specific address, fill with free memory up to that address to prevent fragmentation
185 if (address != 0)
186 fill_up_to_address(address, flags, false);
187
188 // Allocate the memory
189 virtual_memory_chunk_t* chunk = &m_current_region->chunks[m_current_chunk];
190 chunk->size = size;
191 chunk->flags = flags;
192 chunk->start_address = m_next_available_address;
193
194 // Update the next available address
195 m_next_available_address += size;
196 m_current_chunk++;
197
198 // If just reserving the space don't map it
199 if (flags & RESERVE)
200 return (void*) chunk->start_address;
201
202 // Map the memory
204 for (size_t i = 0; i < pages; i++) {
205
206 // Allocate a new frame
208 ASSERT(frame != nullptr, "Failed to allocate frame (from current region)\n");
209
210 // Map the frame
211 PhysicalMemoryManager::s_current_manager->map(frame, (virtual_address_t*) chunk->start_address + (i * PAGE_SIZE), PRESENT | WRITE, m_pml4_root_address);
212
213 }
214
215 // Return the address
216 return (void*) chunk->start_address;
217}
218
222void VirtualMemoryManager::new_region() {
223
224 // Space for the new region
226 ASSERT(new_region_physical != nullptr, "Failed to allocate new VMM region\n");
227
228 // Align the new region
229 auto* new_region = (virtual_memory_region_t*) PhysicalMemoryManager::align_to_page((uint64_t) m_current_region + PAGE_SIZE);
230
231 // Map the new region
233 new_region->next = nullptr;
234
235 // Clear the new region
236 for (size_t i = 0; i < CHUNKS_PER_PAGE; i++) {
237 new_region->chunks[i].size = 0;
238 new_region->chunks[i].flags = 0;
239 new_region->chunks[i].start_address = 0;
240 }
241
242 // Set the current region
243 m_current_region->next = new_region;
244 m_current_chunk = 0;
245 m_current_region = new_region;
246}
247
253void VirtualMemoryManager::free(void* address) {
254
255 // Make sure freeing something
256 if (address == nullptr)
257 return;
258
259 // Find the chunk
260 virtual_memory_region_t* region = m_first_region;
261 virtual_memory_chunk_t* chunk = nullptr;
262 while (region != nullptr) {
263
264 // Loop through the chunks
265 for (size_t i = 0; i < CHUNKS_PER_PAGE; i++) {
266
267 // Check if the address is in the chunk
268 if (region->chunks[i].start_address == (uintptr_t) address) {
269 chunk = &region->chunks[i];
270 break;
271 }
272 }
273
274 // If the chunk was found
275 if (chunk != nullptr)
276 break;
277
278 // Move to the next region
279 region = region->next;
280 }
281
282 // Make sure the chunk was found
283 if (chunk == nullptr)
284 return;
285
286 // If the chunk is shared, don't unmap it incase other processes are using it
287 if (chunk->flags & VirtualFlags::SHARED) {
288
289 // Find the resource
290 for(const auto& resource : GlobalScheduler::current_process()->resource_manager.resources()){
291
292 // Skip non-shared memory resources
293 if(resource.second->type() != resource_type_t::SHARED_MEMORY)
294 continue;
295
296 // Skip shared memory that points elsewhere
297 auto shared = (SharedMemory*)resource.second;
298 if((void*)shared->physical_address() != address)
299 continue;
300
301 // Close the resource
302 GlobalScheduler::current_process()->resource_manager.close_resource(resource.first, 0);
303 }
304 }
305
306 // Add the chunk to the free list
307 add_free_chunk(chunk->start_address, chunk->size);
308
309 // Clear the chunk
310 chunk->size = 0;
311 chunk->flags = 0;
312 chunk->start_address = 0;
313}
314
321
322 // Loop through all the regions and add up the size of the allocated chunks
323 size_t result = 0;
324
325 // Iterate through the regions
326 virtual_memory_region_t* region = m_first_region;
327 while (region != nullptr) {
328
329 // Loop through the chunks
330 for (size_t i = 0; i < CHUNKS_PER_PAGE; i++) {
331
332 // Check if the address is in the chunk
333 if (region->chunks[i].size != 0)
334 result += region->chunks[i].size;
335 }
336
337 // Move to the next region
338 region = region->next;
339 }
340
341 return result;
342}
343
350void VirtualMemoryManager::add_free_chunk(uintptr_t start_address, size_t size) {
351
352 // Create the new chunk
353 auto* new_chunk = (free_chunk_t*) start_address;
354 new_chunk->start_address = start_address;
355 new_chunk->size = size;
356 new_chunk->next = m_free_chunks;
357
358 // Set the new chunk
359 m_free_chunks = new_chunk;
360}
361
370free_chunk_t* VirtualMemoryManager::find_and_remove_free_chunk(size_t size) {
371
372 // Find the chunk
373 free_chunk_t* current = m_free_chunks;
374 free_chunk_t* previous = nullptr;
375 while (current != nullptr) {
376
377 // Check if the chunk is big enough
378 if (current->size >= size) {
379
380 // Remove the chunk
381 if (previous != nullptr) {
382 previous->next = current->next;
383 } else {
384 m_free_chunks = current->next;
385 }
386
387 // Return the chunk
388 return current;
389
390 }
391
392 // Move to the next chunk
394 current = current->next;
395 }
396
397 // No chunk found
398 return nullptr;
399
400}
401
408
409 return m_pml4_root_physical_address;
410}
411
419
420 // Get the shared memory block
421 auto block = (SharedMemory*)GlobalScheduler::current_process()->resource_manager.get_resource(name);
422
423 // Load the shared memory
424 if (block != nullptr)
425 return load_shared_memory(block->physical_address(), block->size());
426
427 return nullptr;
428}
429
437void* VirtualMemoryManager::load_shared_memory(uintptr_t physical_address, size_t size) {
438
439 // Make sure there is somthing to map
440 if (size == 0 || physical_address == 0)
441 return nullptr;
442
443 // Load it into physical memory
444 return load_physical_into_address_space(physical_address, size, SHARED);
445}
446
455void* VirtualMemoryManager::load_physical_into_address_space(uintptr_t physical_address, size_t size, size_t flags) {
456
457 // Reserve some space
458 void* address = allocate(size, flags | RESERVE);
459
460 // Map the shared memory
462 for (size_t i = 0; i < pages; i++)
463 PhysicalMemoryManager::s_current_manager->map((physical_address_t*) (physical_address + (i * PAGE_SIZE)), (virtual_address_t*) ((uintptr_t) address + (i * PAGE_SIZE)), PRESENT | WRITE, m_pml4_root_address);
464
465
466 // All done
467 return address;
468}
469
477void VirtualMemoryManager::fill_up_to_address(uintptr_t address, size_t flags, bool mark_used) {
478
479 // Make sure the address is aligned
480 address = PhysicalMemoryManager::align_to_page(address);
481
482 // Make sure the address is not before the next available address
483 ASSERT(address >= m_next_available_address, "FAILED TO FILL: Address is before the next available address - 0x%x < 0x%x\n", address, m_next_available_address);
484
485 // Calculate the size
486 size_t size = address - m_next_available_address;
487
488 // Allocate the memory
489 virtual_memory_chunk_t* chunk = &m_current_region->chunks[m_current_chunk];
490 chunk->size = size;
491 chunk->flags = flags;
492 chunk->start_address = m_next_available_address;
493
494 // Update the next available address
495 m_next_available_address += size;
496 m_current_chunk++;
497
498 // Map the memory
500 for (size_t i = 0; i < pages; i++) {
501
502 // Allocate a new frame
504 ASSERT(frame != nullptr, "Failed to allocate frame (from fill up)\n");
505
506 // Map the frame
507 PhysicalMemoryManager::s_current_manager->map(frame, (virtual_address_t*) chunk->start_address + (i * PAGE_SIZE), PRESENT | WRITE, m_pml4_root_address);
508
509 }
510
511 // Mark as free if needed
512 if (!mark_used)
513 free((void*) chunk->start_address);
514}
515
522
523 // Make sure the address is valid
524 if (m_pml4_root_address == nullptr)
525 return nullptr;
526
527 // Return the address
528 return m_pml4_root_address;
529}
static Logger DEBUG()
Gets active logger set to DEBUG level.
Definition logger.cpp:193
Stores the left, top, width and height of a rectangle.
Definition rectangle.h:22
static MemoryManager * s_kernel_memory_manager
The memory manager for any kernel processes and all kernel allocations.
static void * to_dm_region(uintptr_t physical_address)
Converts a physical address to a direct map region address if it is in the lower region using the hig...
Definition physical.cpp:930
static size_t align_to_page(size_t size)
Aligns a size to the page size.
Definition physical.cpp:167
static void clean_page_table(uint64_t *table)
Cleans a page table (fills it with 0 or null entries)
Definition physical.cpp:639
static void * to_lower_region(uintptr_t virtual_address)
Converts a virtual address to a lower region address if it is in the higher region using the higher h...
Definition physical.cpp:899
static bool check_aligned(size_t size)
Checks if an address is aligned.
Definition physical.cpp:190
static PhysicalMemoryManager * s_current_manager
The current physical memory manager in use.
Definition physical.h:185
static size_t align_up_to_page(size_t size, size_t s_page_size)
Aligns a size up to the page size.
Definition physical.cpp:179
static size_t size_to_frames(size_t size)
Converts a size to the number of frames.
Definition physical.cpp:156
VirtualMemoryManager()
Construct a new Virtual Memory Manager object and set up the initial page tables (kernel mapped into ...
Definition virtual.cpp:22
void * load_physical_into_address_space(uintptr_t physical_address, size_t size, size_t flags)
Load physical memory into the VMM's address space.
Definition virtual.cpp:455
void * allocate(size_t size, size_t flags)
Allocate a new chunk of virtual memory.
Definition virtual.cpp:119
size_t memory_used()
Returns the amount of memory used.
Definition virtual.cpp:320
uint64_t * pml4_root_address_physical()
Get the physical address of the PML4 root.
Definition virtual.cpp:407
~VirtualMemoryManager()
Destroy the Virtual Memory Manager object and free all used pages.
Definition virtual.cpp:81
uint64_t * pml4_root_address()
Get the virtual address of the PML4 root.
Definition virtual.cpp:521
void free(void *address)
Free a chunk of virtual memory.
Definition virtual.cpp:253
void * load_shared_memory(const string &name)
Load shared memory into the VMM's address space.
Definition virtual.cpp:418
static Process * current_process()
Gets the process on the currently executing core.
A block memory that is mapped into multiple processes.
Definition ipc.h:29
Defines a Logger class for logging messages with different severity levels to multiple output streams...
#define ASSERT(condition, format,...)
If the specified condition is not met then the kernel will crash with the specified message.
Definition logger.h:100
constexpr uint64_t HIGHER_HALF_DIRECT_MAP
Where the map of physical memory to higher half starts.
Definition physical.h:99
constexpr uint64_t PAGE_SIZE
The size of a page (4KB)
Definition physical.h:91
@ PRESENT
The page is present in memory.
Definition physical.h:43
@ WRITE
Memory in this page is writable.
Definition physical.h:44
Defines a GlobalScheduler and Scheduler for managing processes and threads.
A chunk of memory that has been freed and is available for allocation. A node in a linked list.
Definition virtual.h:62
A container for a region of virtual memory that has been allocated by the Virtual Memory Manager.
Definition virtual.h:47
Defines a VirtualMemoryManager class for managing virtual memory allocation and mapping to physical m...
struct PACKED MaxOS::memory::VirtualMemoryRegion virtual_memory_region_t
Alias for VirtualMemoryRegion struct.
@ SHARED
The memory is shared between multiple processes.
Definition virtual.h:34
@ RESERVE
Reserve the memory but do not map any physical memory to it.
Definition virtual.h:33