Max OS 0.3
Loading...
Searching...
No Matches
memorymanagement.cpp
Go to the documentation of this file.
1
10#include <common/logger.h>
11
12using namespace MaxOS;
13using namespace MaxOS::memory;
14using namespace MaxOS::common;
15using namespace MaxOS::system;
16
23: m_virtual_memory_manager(vmm) {
24
25 // Create the VMM if not provided
26 if(m_virtual_memory_manager == nullptr)
27 m_virtual_memory_manager = new VirtualMemoryManager();
28
29 // Enable the memory manager
31
32 // Set up the first chunk of memory
33 this->m_first_memory_chunk = (MemoryChunk*) m_virtual_memory_manager->allocate(PAGE_SIZE + sizeof(MemoryChunk), 0);
34 m_first_memory_chunk->allocated = false;
35 m_first_memory_chunk->prev = nullptr;
36 m_first_memory_chunk->next = nullptr;
37 m_first_memory_chunk->size = PAGE_SIZE - sizeof(MemoryChunk);
38 m_last_memory_chunk = m_first_memory_chunk;
39
40 // First memory manager is the kernel memory manager
41 if(s_kernel_memory_manager == nullptr)
43
44}
45
50
51 // Free the VMM (if this is not the kernel memory manager)
52 if(m_virtual_memory_manager != nullptr && s_current_memory_manager != s_kernel_memory_manager)
53 delete m_virtual_memory_manager;
54
55 // Remove the kernel reference to this
56 if(s_kernel_memory_manager == this)
58
59 // Remove the active reference to this
60 if(s_current_memory_manager == this)
62}
63
70void* MemoryManager::malloc(size_t size) {
71
72 // Make sure there is somthing to do the allocation
73 if(s_current_memory_manager == nullptr)
74 return nullptr;
75
76 return s_current_memory_manager->handle_malloc(size);
77}
78
85void* MemoryManager::kmalloc(size_t size) {
86
87 // Make sure there is a kernel memory manager
88 if(s_kernel_memory_manager == nullptr)
89 return nullptr;
90
91 return s_kernel_memory_manager->handle_malloc(size);
92}
93
101
102 MemoryChunk* result = nullptr;
103
104 // Nothing to allocate
105 if(size == 0)
106 return nullptr;
107
108 // Add room to store the chunk information
109 size = align(size + sizeof(MemoryChunk));
110
111 // Find the next free chunk that is big enough
112 for(MemoryChunk* chunk = m_first_memory_chunk; chunk != nullptr && result == nullptr; chunk = chunk->next) {
113 if(chunk->size > size && !chunk->allocated)
114 result = chunk;
115 }
116
117 // If there is no free chunk then make more room
118 if(result == nullptr)
119 result = expand_heap(size);
120
121 // If there is not left over space to store extra chunks there is no need to split the chunk
122 if(result->size < size + sizeof(MemoryChunk) + 1) {
123 result->allocated = true;
124 void* p = (void*) (((size_t) result) + sizeof(MemoryChunk));
125 return p;
126 }
127
128 // Split the chunk into: what was requested + free overflow space for future allocates
129 // - This prevents waste in the event that a big free chunk was found but the requested size would only use a portion of that
130 auto* extra = (MemoryChunk*) ((size_t) result + sizeof(MemoryChunk) + size);
131 extra->allocated = false;
132 extra->size = result->size - size - sizeof(MemoryChunk);
133 extra->prev = result;
134
135 // Add to the linked list
136 extra->next = result->next;
137 if(extra->next != nullptr)
138 extra->next->prev = extra;
139
140 // Requested chunk is now allocated exactly to the size requested and points to the free (split) block of memory that
141 // it did not use
142 result->size = size;
143 result->allocated = true;
144 result->next = extra;
145
146 // Update the last memory chunk if necessary
147 if(result == m_last_memory_chunk)
148 m_last_memory_chunk = extra;
149
150 return (void*) (((size_t) result) + sizeof(MemoryChunk));
151}
152
158void MemoryManager::free(void* pointer) {
159
160 // Make sure there is a memory manager
161 if(s_current_memory_manager == nullptr)
162 return;
163
164 s_current_memory_manager->handle_free(pointer);
165}
166
172void MemoryManager::kfree(void* pointer) {
173
174 // Make sure there is a kernel memory manager
175 if(s_kernel_memory_manager == nullptr)
176 return;
177
178 s_kernel_memory_manager->handle_free(pointer);
179}
180
186void MemoryManager::handle_free(void* pointer) {
187
188 // Cant free unallocated memory
189 if(pointer == nullptr)
190 return;
191
192 // Check bounds
193 if((uint64_t) pointer < (uint64_t) m_first_memory_chunk || (uint64_t) pointer > (uint64_t) m_last_memory_chunk)
194 return;
195
196 // Get the chunk information from the pointer
197 auto* chunk = (MemoryChunk*) ((size_t) pointer - sizeof(MemoryChunk));
198 chunk->allocated = false;
199
200 // If there is a free chunk before this chunk then merge them
201 if(chunk->prev != nullptr && !chunk->prev->allocated) {
202
203 // Grow the chunk behind this one so that it now contains the freed one
204 chunk->prev->size += chunk->size + sizeof(MemoryChunk);
205 chunk->prev->next = chunk->next;
206
207 // The chunk in front of the freed one now needs to point to the merged chunk
208 if(chunk->next != nullptr)
209 chunk->next->prev = chunk->prev;
210
211 // Freed chunk doesn't exist anymore so now working with the merged chunk
212 chunk = chunk->prev;
213
214 }
215
216 // If there is a free chunk after this chunk then merge them
217 if(chunk->next != nullptr && !chunk->next->allocated) {
218
219 // Grow this chunk so that it now contains the free chunk in front of the old (now freed) one
220 chunk->size += chunk->next->size + sizeof(MemoryChunk);
221
222 // Now that this chunk contains the next one, it has to point to the one in front of what has just been merged
223 // and that has to point to this
224 chunk->next = chunk->next->next;
225 if(chunk->next != nullptr)
226 chunk->next->prev = chunk;
227
228 }
229}
230
237MemoryChunk* MemoryManager::expand_heap(size_t size) {
238
239 // Create a new chunk of memory
240 auto* chunk = (MemoryChunk*) m_virtual_memory_manager->allocate(size, PRESENT | WRITE | NO_EXECUTE);
241 ASSERT(chunk != nullptr, "Out of memory - kernel cannot allocate any more memory");
242
243 // Handled by assert, but just in case
244 if(chunk == nullptr)
245 return nullptr;
246
247 // Set the chunk's properties
248 chunk->allocated = false;
249 chunk->size = size;
250 chunk->next = nullptr;
251
252 // Insert the chunk into the linked list
253 m_last_memory_chunk->next = chunk;
254 chunk->prev = m_last_memory_chunk;
255 m_last_memory_chunk = chunk;
256
257 // If it is possible to merge the new chunk with the previous chunk then do so (note: this happens if the
258 // previous chunk is free but cant contain the size required)
259 if(!chunk->prev->allocated)
260 free((void*) ((size_t) chunk + sizeof(MemoryChunk)));
261
262 return chunk;
263}
264
271
272 size_t result = 0;
273
274 // Loop through all the chunks and add up the size of the allocated chunks
275 for(MemoryChunk* chunk = m_first_memory_chunk; chunk != nullptr; chunk = chunk->next)
276 if(chunk->allocated)
277 result += chunk->size;
278
279 return result;
280}
281
288size_t MemoryManager::align(size_t size) {
289
290 return (size / CHUNK_ALIGNMENT + 1) * CHUNK_ALIGNMENT;
291}
292
293
300
301 // Make sure there is a manager
302 if(manager == nullptr)
303 return;
304
305 // Switch the address space
306 asm volatile("mov %0, %%cr3"::"r"((uint64_t) manager->m_virtual_memory_manager->pml4_root_address_physical()) : "memory");
307
308 // Set the active memory manager
310}
311
318
319 return m_virtual_memory_manager;
320}
321
322//Redefine the default object functions with memory orientated ones (defaults disabled in makefile)
323
324
331void* operator new(size_t size) throw() {
332
333 // Handle the memory allocation
335}
336
343void* operator new[](size_t size) throw() {
344
345 // Handle the memory allocation
347}
348
356void* operator new(size_t size, void* pointer) {
357
358 return pointer;
359}
360
368void* operator new[](size_t size, void* pointer) {
369
370
371 return pointer;
372}
373
379void operator delete(void* pointer) {
380
381 // Handle the memory freeing
383}
384
390void operator delete[](void* pointer) {
391
392 // Handle the memory freeing
394}
395
402void operator delete(void* pointer, size_t) {
403
404 // Handle the memory freeing
406}
407
414void operator delete[](void* pointer, size_t size) {
415
416 // Handle the memory freeing
418}
Stores the left, top, width and height of a rectangle.
Definition rectangle.h:22
Handles memory allocation and deallocation.
void * handle_malloc(size_t size)
Allocates a block of memory.
static MemoryManager * s_current_memory_manager
The memory manager for the current process.
static size_t align(size_t size)
Aligns the size to the chunk alignment.
void handle_free(void *pointer)
Frees a block of memory.
static void free(void *pointer)
Frees a block of memory using the current memory manager.
static MemoryManager * s_kernel_memory_manager
The memory manager for any kernel processes and all kernel allocations.
static void * malloc(size_t size)
Allocates a block of memory in the current USERSPACE heap.
static void * kmalloc(size_t size)
Allocates a block of memory in the KERNEL space.
size_t memory_used()
Returns the amount of memory used.
static void kfree(void *pointer)
Frees a block of memory using the kernel memory manager.
~MemoryManager()
Destroy the Memory Manager object, frees the VMM if not the kernel memory manager.
MemoryManager(VirtualMemoryManager *virtual_memory_manager=nullptr)
Construct a new Memory Manager object. Will switch the pml4 to use the calling process's page tables.
static void switch_active_memory_manager(MemoryManager *manager)
Switches the active memory manager.
VirtualMemoryManager * vmm()
Manages the virtual memory of the system and provides functions to allocate and free memory in the vi...
Definition virtual.h:96
void * allocate(size_t size, size_t flags)
Allocate a new chunk of virtual memory.
Definition virtual.cpp:119
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
Defines a MemoryManager class for handling memory allocation and deallocation.
constexpr size_t CHUNK_ALIGNMENT
How many bytes the chunks should be a multiple of (round up to this)
constexpr uint64_t PAGE_SIZE
The size of a page (4KB)
Definition physical.h:91
A span of memory in the heap, can be allocated or free. Used as a node in a doubly linked list.
MemoryChunk * prev
Pointer to the chunk before this one in the list.
MemoryChunk * next
Pointer to the chunk after this one in the list.
size_t size
The size of this span of memory (not including the MemoryChunk struct itself)
bool allocated
Whether this chunk is in use or can be allocated.