Max OS 0.3
Loading...
Searching...
No Matches
MaxOS::memory::VirtualMemoryManager Class Reference

Manages the virtual memory of the system and provides functions to allocate and free memory in the virtual address space. More...

#include <virtual.h>

Public Member Functions

 VirtualMemoryManager ()
 Construct a new Virtual Memory Manager object and set up the initial page tables (kernel mapped into the hh)
 
 ~VirtualMemoryManager ()
 Destroy the Virtual Memory Manager object and free all used pages.
 
voidallocate (size_t size, size_t flags)
 Allocate a new chunk of virtual memory.
 
voidallocate (uint64_t address, size_t size, size_t flags)
 Allocate a new chunk of virtual memory at a specific address (ie for mmap io devices)
 
void free (void *address)
 Free a chunk of virtual memory.
 
voidload_physical_into_address_space (uintptr_t physical_address, size_t size, size_t flags)
 Load physical memory into the VMM's address space.
 
voidload_shared_memory (const string &name)
 Load shared memory into the VMM's address space.
 
voidload_shared_memory (uintptr_t physical_address, size_t size)
 Load shared memory into the VMM's address space.
 
uint64_tpml4_root_address ()
 Get the virtual address of the PML4 root.
 
uint64_tpml4_root_address_physical ()
 Get the physical address of the PML4 root.
 
size_t memory_used ()
 Returns the amount of memory used.
 

Detailed Description

Manages the virtual memory of the system and provides functions to allocate and free memory in the virtual address space.

Note
Have to use a linked list as vector class depends on dynamic memory allocation (which depends on this)

Definition at line 96 of file virtual.h.

Constructor & Destructor Documentation

◆ VirtualMemoryManager()

VirtualMemoryManager::VirtualMemoryManager ( )

Construct a new Virtual Memory Manager object and set up the initial page tables (kernel mapped into the hh)

Note
Should only be called once per memory manager (kernel and each process)

Definition at line 22 of file virtual.cpp.

22 {
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
57 uint64_t vmm_space = PhysicalMemoryManager::align_to_page(HIGHER_HALF_DIRECT_MAP + PhysicalMemoryManager::s_current_manager->memory_size() + PAGE_SIZE);
59 PhysicalMemoryManager::s_current_manager->map(vmm_space_physical, (virtual_address_t*) vmm_space, PRESENT | WRITE, m_pml4_root_address);
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}
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 PhysicalMemoryManager * s_current_manager
The current physical memory manager in use.
Definition physical.h:185
#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 PAGE_SIZE
The size of a page (4KB)
Definition physical.h:91
struct PACKED MaxOS::memory::VirtualMemoryRegion virtual_memory_region_t
Alias for VirtualMemoryRegion struct.

References MaxOS::memory::PhysicalMemoryManager::align_to_page(), ASSERT, MaxOS::memory::PhysicalMemoryManager::clean_page_table(), MaxOS::Logger::DEBUG(), MaxOS::memory::HIGHER_HALF_DIRECT_MAP, MaxOS::memory::PAGE_SIZE, MaxOS::memory::PRESENT, MaxOS::memory::PhysicalMemoryManager::s_current_manager, MaxOS::memory::MemoryManager::s_kernel_memory_manager, MaxOS::memory::PhysicalMemoryManager::to_dm_region(), MaxOS::memory::PhysicalMemoryManager::to_lower_region(), and MaxOS::memory::WRITE.

◆ ~VirtualMemoryManager()

VirtualMemoryManager::~VirtualMemoryManager ( )

Destroy the Virtual Memory Manager object and free all used pages.

Definition at line 81 of file virtual.cpp.

81 {
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}
static size_t size_to_frames(size_t size)
Converts a size to the number of frames.
Definition physical.cpp:156

References MaxOS::memory::PAGE_SIZE, MaxOS::memory::PhysicalMemoryManager::s_current_manager, and MaxOS::memory::PhysicalMemoryManager::size_to_frames().

Member Function Documentation

◆ allocate() [1/2]

void * VirtualMemoryManager::allocate ( size_t  size,
size_t  flags 
)

Allocate a new chunk of virtual memory.

Parameters
sizeThe size of the memory to allocate
flagsThe flags to set on the memory
Returns
The address of the allocated memory

Definition at line 119 of file virtual.cpp.

119 {
120
121 return allocate(0, size, flags);
122}
void * allocate(size_t size, size_t flags)
Allocate a new chunk of virtual memory.
Definition virtual.cpp:119

References allocate().

Referenced by allocate(), load_physical_into_address_space(), and MaxOS::memory::MemoryManager::MemoryManager().

◆ allocate() [2/2]

void * VirtualMemoryManager::allocate ( uint64_t  address,
size_t  size,
size_t  flags 
)

Allocate a new chunk of virtual memory at a specific address (ie for mmap io devices)

Parameters
addressThe address to allocate at
sizeThe size of the memory to allocate
flagsThe flags to set on the memory
Returns
The address of the allocated memory or nullptr if failed

Definition at line 133 of file virtual.cpp.

133 {
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
153 size = PhysicalMemoryManager::align_up_to_page(size, PAGE_SIZE);
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}
static bool check_aligned(size_t size)
Checks if an address is aligned.
Definition physical.cpp:190
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
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

References MaxOS::memory::PhysicalMemoryManager::align_up_to_page(), ASSERT, MaxOS::memory::PhysicalMemoryManager::check_aligned(), MaxOS::memory::PAGE_SIZE, MaxOS::memory::PRESENT, MaxOS::memory::RESERVE, MaxOS::memory::PhysicalMemoryManager::s_current_manager, MaxOS::memory::PhysicalMemoryManager::size_to_frames(), and MaxOS::memory::WRITE.

◆ free()

void VirtualMemoryManager::free ( void address)

Free a chunk of virtual memory.

Parameters
addressThe address of the memory to free

Definition at line 253 of file virtual.cpp.

253 {
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}
The global scheduler that manages all processes and threads across all cores.
Definition scheduler.h:26
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

References MaxOS::processes::GlobalScheduler::current_process().

◆ load_physical_into_address_space()

void * VirtualMemoryManager::load_physical_into_address_space ( uintptr_t  physical_address,
size_t  size,
size_t  flags 
)

Load physical memory into the VMM's address space.

Parameters
physical_addressThe physical address of the memory
sizeThe size of the memory
flagsThe flags to set on the memory
Returns
The address of the memory in the VMM's address space

Definition at line 455 of file virtual.cpp.

455 {
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}

References allocate(), MaxOS::memory::PAGE_SIZE, MaxOS::memory::PRESENT, MaxOS::memory::RESERVE, MaxOS::memory::PhysicalMemoryManager::s_current_manager, MaxOS::memory::PhysicalMemoryManager::size_to_frames(), and MaxOS::memory::WRITE.

Referenced by load_shared_memory().

◆ load_shared_memory() [1/2]

void * VirtualMemoryManager::load_shared_memory ( const string name)

Load shared memory into the VMM's address space.

Parameters
nameThe name of the shared memory
Returns
The address of the shared memory in the VMM's address space

Definition at line 418 of file virtual.cpp.

418 {
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}
void * load_shared_memory(const string &name)
Load shared memory into the VMM's address space.
Definition virtual.cpp:418

References MaxOS::processes::GlobalScheduler::current_process(), and load_shared_memory().

Referenced by load_shared_memory().

◆ load_shared_memory() [2/2]

void * VirtualMemoryManager::load_shared_memory ( uintptr_t  physical_address,
size_t  size 
)

Load shared memory into the VMM's address space.

Parameters
physical_addressThe physical address of the shared memory
sizeThe size of the shared memory
Returns
The address of the shared memory in the VMM's address space

Definition at line 437 of file virtual.cpp.

437 {
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}
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

References load_physical_into_address_space(), and MaxOS::memory::SHARED.

◆ memory_used()

size_t VirtualMemoryManager::memory_used ( )

Returns the amount of memory used.

Returns
The amount of memory used

Definition at line 320 of file virtual.cpp.

320 {
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}

◆ pml4_root_address()

uint64_t * VirtualMemoryManager::pml4_root_address ( )

Get the virtual address of the PML4 root.

Returns
The virtual address or nullptr if not found

Definition at line 521 of file virtual.cpp.

521 {
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}

◆ pml4_root_address_physical()

uint64_t * VirtualMemoryManager::pml4_root_address_physical ( )

Get the physical address of the PML4 root.

Returns
The physical address of the PML4 root

Definition at line 407 of file virtual.cpp.

407 {
408
409 return m_pml4_root_physical_address;
410}

The documentation for this class was generated from the following files: