Max OS 0.3
Loading...
Searching...
No Matches
physical.cpp
Go to the documentation of this file.
1
9#include <common/logger.h>
10#include <memory/physical.h>
11#include <system/cpu.h>
12
13using namespace MaxOS::memory;
14using namespace MaxOS::system;
15using namespace MaxOS::common;
16
17volatile extern PAGE_ALIGNED unsigned char p4_table[];
18volatile extern PAGE_ALIGNED unsigned char p3_table[];
19volatile extern PAGE_ALIGNED unsigned char p3_table_hh[];
20volatile extern PAGE_ALIGNED unsigned char p2_table[];
21volatile extern PAGE_ALIGNED unsigned char p1_table[];
22
23extern uint64_t _kernel_end;
24extern uint64_t _kernel_size;
25extern uint64_t _kernel_physical_end;
26
32: m_kernel_end((uint64_t) &_kernel_physical_end),
33m_multiboot(multiboot),
34m_pml4_root_address((uint64_t*) p4_table),
35m_pml4_root((pte_t*) p4_table) {
36
37 Logger::INFO() << "Setting up Physical Memory Manager\n";
38 Logger::DEBUG() << "Kernel Memory: kernel_end = 0x" << (uint64_t) &_kernel_end << ", kernel_size = 0x"
39 << (uint64_t) &_kernel_size << ", kernel_physical_end = 0x" << (uint64_t) &_kernel_physical_end
40 << "\n";
41 m_kernel_start_page = align_up_to_page((size_t) &_kernel_physical_end + PAGE_SIZE, PAGE_SIZE);
42
43 // Set up the current manager
45 m_lock.unlock();
46 s_current_manager = this;
47 m_nx_allowed = CPU::check_nx();
48
49 // Find a region of memory available to be used
50 m_mmap_tag = m_multiboot->mmap();
51 for(multiboot_mmap_entry* entry = m_mmap_tag->entries; (multiboot_uint8_t*) entry < (multiboot_uint8_t*) m_mmap_tag + m_mmap_tag->size; entry = (multiboot_mmap_entry*) ( (unsigned long) entry + m_mmap_tag->entry_size)) {
52
53 // Skip if the region is not free or there is not enough space
54 if(entry->type != MULTIBOOT_MEMORY_AVAILABLE)
55 continue;
56
57 // Store the entry. (note: don't break here as it is desired to find the last usable entry as that is normally biggest)
58 m_mmap = entry;
59 }
60
61 // Store the information about the bitmap
62 m_memory_size = (m_mmap->addr + m_mmap->len);
63 m_bitmap_size = m_memory_size / PAGE_SIZE + 1;
64 m_total_entries = m_bitmap_size / ROW_BITS + 1;
65 Logger::DEBUG() << "Memory Info: size = " << (int) (m_memory_size / 1024 / 1024) << "mb, bitmap size = 0x" << (uint64_t) m_bitmap_size << ", total entries = " << (int) m_total_entries << ", page size = 0x"<< (uint64_t) PAGE_SIZE << "\n";
66
67 // Map the physical memory into the virtual memory
68 Logger::DEBUG() << "Mapping from 0x0 to 0x" << (uint64_t) (m_mmap->addr + m_mmap->len) << " to higher half direct map at offset 0x" << HIGHER_HALF_DIRECT_MAP << "\n";
69 for(uint64_t physical_address = 0; physical_address < (m_mmap->addr + m_mmap->len); physical_address += PAGE_SIZE)
70 map((physical_address_t*) physical_address, (virtual_address_t*) (HIGHER_HALF_DIRECT_MAP + physical_address),PRESENT | WRITE);
71
72 // Kernel Setup
73 initialise_bit_map();
74 reserve_kernel_regions(multiboot);
75
76 // Initialisation Done
77 m_initialised = true;
78 Logger::DEBUG() << "Memory used at start: " << (int) (memory_used() / 1024 / 1024) << "mb \n";
79}
80
81PhysicalMemoryManager::~PhysicalMemoryManager() = default;
82
90
91 // Reserve the pages used by the higher half mapping
92 reserve((uint64_t) m_mmap->addr, m_setup_frames * PAGE_SIZE, "HHDM");
93
94 // Reserve the area for the bitmap
95 reserve((uint64_t) from_dm_region((uint64_t) m_bit_map), m_bitmap_size / 8, "Bitmap");
96
97 // Calculate how much space the kernel takes up
98 uint32_t kernel_entries = (m_kernel_start_page / PAGE_SIZE) + 1;
99 if((((uint32_t) (m_kernel_start_page)) % PAGE_SIZE) != 0)
100 kernel_entries += 1;
101
102 // Reserve the kernel entries
103 reserve(0, kernel_entries * PAGE_SIZE, "Kernel");
104
105 // Reserve the area for the mmap
106 uint64_t mem_end = m_mmap->addr + m_mmap->len;
107 for(multiboot_mmap_entry* entry = m_mmap_tag->entries; (multiboot_uint8_t*) entry < (multiboot_uint8_t*) m_mmap_tag + m_mmap_tag->size; entry = (multiboot_mmap_entry*) ( (unsigned long) entry + m_mmap_tag->entry_size)) {
108
109 // Dont reserve free regions
110 if(entry->type <= MULTIBOOT_MEMORY_AVAILABLE)
111 continue;
112
113 // Don't reserve the memory being managed by pmm
114 if(entry->addr >= mem_end)
115 continue;
116
117 reserve(entry->addr, entry->len, "MMap");
118 }
119
120 // Reserve the area for each multiboot module
121 for(multiboot_tag* tag = multiboot->start_tag(); tag->type != MULTIBOOT_TAG_TYPE_END; tag = (struct multiboot_tag*) ((multiboot_uint8_t*) tag + ((tag->size + 7) & ~7))) {
122
123 if(tag->type != MULTIBOOT_TAG_TYPE_MODULE)
124 continue;
125
126 // Reserve the module's address
127 auto* module = (struct multiboot_tag_module*) tag;
128 reserve(module->mod_start, module->mod_end - module->mod_start, "Module");
129 }
130
131 // Reserve all the tags
132 auto end_tag = (multiboot_tag*) to_higher_region(multiboot->end_address);
133 auto start_tag = (uint64_t) to_lower_region((uintptr_t) multiboot->start_tag());
134 size_t tags_size = multiboot->end_address - start_tag + ((end_tag->size + 7) & ~7);
135 reserve(start_tag, tags_size, "Tags");
136}
137
145
146 return align_to_page(size) / PAGE_SIZE;
147}
148
156
157 return ((size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
158}
159
167size_t PhysicalMemoryManager::align_up_to_page(size_t size, size_t page_size) {
168
169 return (size + page_size - 1) & ~(page_size - 1);
170}
171
179
180 return (size % PAGE_SIZE) == 0;
181}
182
189
190 // Wait for the lock
191 m_lock.lock();
192
193 // If not initialised, cant use the bitmap or higher half mapped physical memory so use leftover kernel memory already
194 // mapped in loader.s
195 if(!m_initialised) {
196
197 // Use frames at the start of the mmap free
198 void* address = (void*) ((uintptr_t) m_mmap->addr + (m_setup_frames * PAGE_SIZE));
199 m_setup_frames++;
200
201 m_lock.unlock();
202 return address;
203 }
204
205 // Check if there are enough frames
206 ASSERT(m_used_frames < m_bitmap_size, "No more frames available\n");
207
208 for(uint32_t row = 0; row < m_total_entries; ++row) {
209
210 // If the row is full continue
211 if(m_bit_map[row] == 0xFFFFFFFFFFFFFFFF)
212 continue;
213
214 for(uint32_t column = 0; column < ROW_BITS; ++column) {
215
216 // Entry isn't free
217 if(m_bit_map[row] & (1ULL << column))
218 continue;
219
220 // Mark the frame as used
221 m_bit_map[row] |= (1ULL << column);
222 m_used_frames++;
223
224 // Thread safe
225 m_lock.unlock();
226
227 // Calculate the address
228 uint64_t frame_address = (row * ROW_BITS) + column;
229 frame_address *= PAGE_SIZE;
230
231 // Zero the page
232 void* virt = to_dm_region(frame_address);
233 memset(virt, 0, PAGE_SIZE);
234
235 return (void*)frame_address;
236 }
237 }
238
239 // Error frame not found
240 ASSERT(false, "Frame not found\n");
241 m_lock.unlock();
242 return nullptr;
243}
244
251
252 m_lock.lock();
253
254 // Mark the frame as not used
255 m_used_frames--;
256 uint64_t frame_address = (uint64_t) address / PAGE_SIZE;
257 m_bit_map[frame_address / ROW_BITS] &= ~(1ULL << (frame_address % ROW_BITS));
258
259 m_lock.unlock();
260}
261
270void* PhysicalMemoryManager::allocate_area(uint64_t start_address, size_t size) {
271
272 m_lock.lock();
273
274 // Store the information about the frames needed to be allocated for this size
275 size_t frame_count = size_to_frames(size);
276 uint32_t start_row = 0;
277 uint32_t start_column = 0;
278 size_t adjacent_frames = 0;
279
280 for(uint32_t row = 0; row < m_total_entries; ++row) {
281
282 // Skip full rows
283 if(m_bit_map[row] == 0xFFFFFFFFFFFFFFFF) {
284 adjacent_frames = 0;
285 continue;
286 }
287
288 for(uint32_t column = 0; column < ROW_BITS; ++column) {
289
290 // Not enough adjacent frames
291 if(m_bit_map[row] & (1ULL << column)) {
292 adjacent_frames = 0;
293 continue;
294 }
295
296 // Store the address of the first frame in set of adjacent ones
297 if(adjacent_frames == 0) {
298 start_row = row;
299 start_column = column;
300 }
301
302 // Make sure there are enough frames in a row found
303 adjacent_frames++;
304 if(adjacent_frames != frame_count)
305 continue;
306
307 // Mark the frames as used
308 m_used_frames += frame_count;
309 for(uint32_t i = 0; i < frame_count; ++i) {
310
311 // Get the location of the bit
312 uint32_t index = start_row + (start_column + i) / ROW_BITS;
313 uint32_t bit = (start_column + i) % ROW_BITS;
314
315 // Check bounds
316 ASSERT(index < m_total_entries && bit < ROW_BITS, "Index out of bounds\n");
317
318 // Mark the bit as used
319 m_bit_map[index] |= (1ULL << bit);
320 }
321
322 // Return start of the block of adjacent frames
323 m_lock.unlock();
324 return (void*) (start_address + (start_row * ROW_BITS + start_column) * PAGE_SIZE);
325
326 }
327 }
328
329 // Not enough free frames adjacent to each other
330 m_lock.unlock();
331 ASSERT(false, "Cannot allocate that much memory\n");
332 return nullptr;
333}
334
341void PhysicalMemoryManager::free_area(uint64_t start_address, size_t size) {
342
343 // Convert address into frames
344 size_t frame_count = size_to_frames(size);
345 uint64_t frame_address = start_address / PAGE_SIZE;
346
347 // Check bounds
348 if(frame_address >= m_bitmap_size)
349 return;
350
351 // Wait until other threads have finished other memory operations
352 m_lock.lock();
353
354 // Mark the frames as not used
355 m_used_frames -= frame_count;
356 for(uint32_t i = 0; i < frame_count; ++i)
357 m_bit_map[(frame_address + i) / ROW_BITS] &= ~(1ULL << ((frame_address + i) % ROW_BITS));
358
359 m_lock.unlock();
360}
361
370pml_t* PhysicalMemoryManager::get_higher_half_table(uint64_t index, uint64_t index2, uint64_t index3) {
371
372 return (pml_t*) (0xFFFF000000000000 | ((510UL << 39) | (index3 << 30) | (index2 << 21) | (index << 12)));
373}
374
375
384pml_t* PhysicalMemoryManager::get_or_create_table(pml_t* table, size_t index, size_t flags) {
385
386 // Table is already created so just find the entry
387 if(table->entries[index].present)
388 return (pml_t*) to_dm_region(physical_address_of_entry(&table->entries[index]));
389
390 // Create the table
391 auto* new_table = (uint64_t*) allocate_frame();
392 table->entries[index] = create_page_table_entry((uint64_t) new_table, flags);
393
394 // Move the table to the higher half
395 new_table = (uint64_t*) to_dm_region((uintptr_t) new_table);
396
397 // Reset the memory contents at the address
398 clean_page_table(new_table);
399
400 return (pml_t*) new_table;
401}
402
412pml_t* PhysicalMemoryManager::get_and_create_table(pml_t* parent_table, uint64_t table_index, pml_t* table) {
413
414 // Table already created so don't need to do anything
417 if(parent_table->entries[table_index].present)
418 return table;
419
420 // Create the table
421 auto* new_table = (uint64_t*) allocate_frame();
422 parent_table->entries[table_index] = create_page_table_entry((uint64_t) new_table, PRESENT | WRITE);
423
424 // Move the table to higher half
425 // Except this doesn't need to be done because using anom memory
426
427 // Reset the memory contents at the address
428 clean_page_table((uint64_t*) table);
429
430 return table;
431}
432
433
440pte_t* PhysicalMemoryManager::get_entry(virtual_address_t* virtual_address, pml_t* pml4_table) {
441
442 // Kernel memory must be in the higher half
443 size_t flags = PRESENT | WRITE;
444 if(!in_higher_region((uint64_t) virtual_address))
445 flags |= (USER | GLOBAL);
446
447 uint16_t pml4_index = PML4_GET_INDEX((uint64_t) virtual_address);
448 uint16_t pdpr_index = PML3_GET_INDEX((uint64_t) virtual_address);
449 uint16_t pd_index = PML2_GET_INDEX((uint64_t) virtual_address);
450 uint16_t pt_index = PML1_GET_INDEX((uint64_t) virtual_address);
451
452 pml_t* pdpr_table = nullptr;
453 pml_t* pd_table = nullptr;
454 pml_t* pt_table = nullptr;
455
456 // If it is before initialization then cant rely on the direct map
457 if(!m_initialised) {
458 pdpr_table = get_and_create_table(pml4_table, pml4_index, get_higher_half_table(pml4_index));
459 pd_table = get_and_create_table(pdpr_table, pdpr_index, get_higher_half_table(pdpr_index, pml4_index));
460 pt_table = get_and_create_table(pd_table, pd_index, get_higher_half_table(pd_index, pdpr_index, pml4_index));
461
462 } else {
463 pdpr_table = get_or_create_table(pml4_table, pml4_index, flags);
464 pd_table = get_or_create_table(pdpr_table, pdpr_index, flags);
465 pt_table = get_or_create_table(pd_table, pd_index, flags);
466 }
467
468 // Get the entry
469 return &pt_table->entries[pt_index];
470}
471
472
479uint64_t PhysicalMemoryManager::physical_address_of_entry(pte_t* entry) {
480
481 return entry->physical_address << 12;
482}
483
484
493virtual_address_t* PhysicalMemoryManager::map(physical_address_t* physical_address, virtual_address_t* virtual_address, size_t flags) {
494
495 // Map using the kernel's pml4 table
496 return map(physical_address, virtual_address, flags, m_pml4_root_address);
497}
498
508virtual_address_t* PhysicalMemoryManager::map(physical_address_t* physical_address, virtual_address_t* virtual_address, size_t flags, uint64_t* pml4_table) {
509
510 // If it is in a lower region then assume it is the user space
511 if(!in_higher_region((uint64_t) virtual_address))
512 flags |= (USER | GLOBAL);
513
514 // If the entry already exists then the mapping is already done
515 pte_t* pte = get_entry(virtual_address, (pml_t*) pml4_table);
516 if(pte->present)
517 return virtual_address;
518
519 // Map the physical address to the virtual address
520 *pte = create_page_table_entry((uint64_t) physical_address, flags);
521
522 // Flush the TLB (cache)
523 asm volatile("invlpg (%0)"::"r" (virtual_address) : "memory");
524
525 return virtual_address;
526}
527
536
537 // Map a new physical address to the requested virtual address
538 return map(allocate_frame(), virtual_address, flags);
539
540}
541
549void PhysicalMemoryManager::map_area(virtual_address_t* virtual_address_start, size_t length, size_t flags) {
550
551 // Map the required frames
552 for(size_t i = 0; i < size_to_frames(length); ++i)
553 map((virtual_address_t*) ((uintptr_t) virtual_address_start + (i * PAGE_SIZE)), flags);
554
555}
556
565void PhysicalMemoryManager::map_area(physical_address_t* physical_address_start, virtual_address_t* virtual_address_start, size_t length, size_t flags) {
566
567 // Map the required frames
568 for(size_t i = 0; i < size_to_frames(length); ++i)
569 map((virtual_address_t*) ((uintptr_t) physical_address_start + (i * PAGE_SIZE)),
570 (virtual_address_t*) ((uintptr_t) virtual_address_start + (i * PAGE_SIZE)), flags);
571}
572
579void PhysicalMemoryManager::identity_map(physical_address_t* physical_address, size_t flags) {
580
581 // Map the physical address to its virtual address counter-part
582 map(physical_address, physical_address, flags);
583}
584
591
592 // Pass the kernel's pml4 table
593 unmap(virtual_address, m_pml4_root_address);
594}
595
602void PhysicalMemoryManager::unmap(virtual_address_t* virtual_address, uint64_t* pml4_root) {
603
604 // Get the entry
605 pte_t* pte = get_entry(virtual_address, (pml_t*) pml4_root);
606
607 // Make sure the address is actually mapped
608 if(!pte->present)
609 return;
610
611 // Unmap the entry
612 pte->present = false;
613
614 // Flush the TLB (cache)
615 asm volatile("invlpg (%0)"::"r" (virtual_address) : "memory");
616}
617
624void PhysicalMemoryManager::unmap_area(virtual_address_t* virtual_address_start, size_t length) {
625
626 // Unmap the required frames
627 for(size_t i = 0; i < size_to_frames(length); ++i)
628 unmap((virtual_address_t*) ((uintptr_t) virtual_address_start + (i * PAGE_SIZE)));
629}
630
637
638 // Null the table (prevents false mappings when re-using frames)
639 for(int i = 0; i < 512; i++)
640 table[i] = 0x00l;
641}
642
652pte_t PhysicalMemoryManager::create_page_table_entry(uintptr_t address, size_t flags) const {
653
654 pte_t page = (pte_t) {
655 .present = (flags & PRESENT) != 0,
656 .write = (flags & WRITE) != 0,
657 .user = (flags & USER) != 0,
658 .write_through = (flags & WRITE_THROUGH) != 0,
659 .cache_disabled = (flags & CACHE_DISABLED) != 0,
660 .accessed = (flags & ACCESSED) != 0,
661 .dirty = (flags & DIRTY) != 0,
662 .huge_page = (flags & HUGE_PAGE) != 0,
663 .global = (flags & GLOBAL) != 0,
664 .available = 0,
665 .physical_address = address >> 12,
666 };
667
668 // Set the NX bit if it is allowed
669 if(m_nx_allowed && (flags & NO_EXECUTE)) {
670 auto page_raw = (uint64_t) &page;
671 page_raw |= NO_EXECUTE;
672 page = *(pte_t*) page_raw;
673 }
674
675 return page;
676}
677
683void PhysicalMemoryManager::initialise_bit_map() {
684
685 // Earliest address to place the bitmap (after the kernel and hh direct map)
686 uint64_t limit = m_kernel_start_page;
687
688 // Find a region for the bitmap to handle
689 for(multiboot_mmap_entry* entry = m_mmap_tag->entries; (multiboot_uint8_t*) entry <
690 (multiboot_uint8_t*) m_mmap_tag +
691 m_mmap_tag->size; entry = (multiboot_mmap_entry*) (
692 (unsigned long) entry + m_mmap_tag->entry_size)) {
693
694 // Cant use a non-free entry or an entry past limit (ie don't user higher addresses that will be overridden later)
695 if(entry->type != MULTIBOOT_MEMORY_AVAILABLE || entry->len > limit)
696 continue;
697
698 size_t space = entry->len;
699 size_t offset = 0;
700
701 // Determine how much of the region is below the limit and adjust the starting point to there
702 if(entry->addr < limit) {
703 offset = limit - entry->addr;
704 space -= offset;
705 }
706
707 // Make sure there is enough space
708 ASSERT(space >= (m_bitmap_size / 8 + 1), "Not enough space for the bitmap (too big)\n");
709
710 // Return the address (ensuring that it is in the safe region)
711 m_bit_map = (uint64_t*) to_dm_region(entry->addr + offset);
712 break;
713 }
714
715 // Error no suitable space for the bitmap found
716 ASSERT(m_bit_map != nullptr, "No space for the bitmap (no region)\n");
717
718 // Clear the bitmap (mark all as free)
719 for(uint32_t i = 0; i < m_total_entries; ++i)
720 m_bit_map[i] = 0;
721
722 Logger::DEBUG() << "Bitmap: location: 0x" << (uint64_t) m_bit_map << " - 0x"
723 << (uint64_t) (m_bit_map + m_bitmap_size / 8) << " (range of 0x" << (uint64_t) m_bitmap_size / 8
724 << ")\n";
725
726}
727
734
735 return m_pml4_root_address;
736}
737
744
745 return m_memory_size;
746}
747
754
755 return m_used_frames * PAGE_SIZE;
756}
757
765
766 return (size & (~(PAGE_SIZE - 1)));
767}
768
774void PhysicalMemoryManager::reserve(uint64_t address) {
775
776 reserve(address, PAGE_SIZE);
777}
778
786void PhysicalMemoryManager::reserve(uint64_t address, size_t size, const char* type) {
787
788 // Cant reserve virtual addresses (ensure the address is physical)
789 ASSERT(address < m_memory_size, "Attempt to reserve address bigger then the memory can contain: 0x%x\n", address);
790 ASSERT(address + size < m_memory_size, "Attempt to reserve region bigger then the memory can contain: 0x%x-0x%x\n",
791 address, address + size);
792
793 // Wait to be able to reserve
794 m_lock.lock();
795
796 // Align to a page, if rounding down need to correct the range
797 size_t aligned_address = align_direct_to_page(address);
798 if(aligned_address < address)
799 size += address - aligned_address;
800
801 // Convert in to amount of pages
802 size = align_up_to_page(size, PAGE_SIZE);
803 size_t page_count = size / PAGE_SIZE;
804 uint64_t frame_index = aligned_address / PAGE_SIZE;
805
806 // Mark all as used
807 for(size_t i = 0; i < page_count; ++i)
808 m_bit_map[(frame_index + i) / ROW_BITS] |= (1ULL << ((frame_index + i) % ROW_BITS));
809
810 // Update the used frames
811 m_used_frames += page_count;
812
813 // Clear the lock
814 m_lock.unlock();
815 Logger::DEBUG() << "Reserved Address for " << type << ": 0x" << aligned_address << " - 0x" << aligned_address + size
816 << " (length of 0x" << size << ")\n";
817}
818
829
830 pte_t* entry = get_entry(virtual_address, (pml_t*) pml4_root);
831
832 // Cant get a physical address if its inst free
833 if(!entry->present)
834 return nullptr;
835
836 return (physical_address_t*) physical_address_of_entry(entry);
837}
838
846void PhysicalMemoryManager::change_page_flags(virtual_address_t* virtual_address, size_t flags, uint64_t* pml4_root) {
847
848 pte_t* entry = get_entry(virtual_address, (pml_t*) pml4_root);
849
850 // Cant edit a non-present entry (will page fault)
851 if(!entry->present)
852 return;
853
854 *entry = create_page_table_entry(physical_address_of_entry(entry), flags);
855
856 // Flush the TLB (cache)
857 asm volatile("invlpg (%0)"::"r" (virtual_address) : "memory");
858
859}
860
869bool PhysicalMemoryManager::is_mapped(uintptr_t physical_address, uintptr_t virtual_address, uint64_t* pml4_root) {
870
871 return get_physical_address((virtual_address_t*) virtual_address, pml4_root) ==
872 (physical_address_t*) physical_address;
873
874}
875
882void* PhysicalMemoryManager::to_higher_region(uintptr_t physical_address) {
883
884 // If it's in the lower half then add the offset
885 if(physical_address < HIGHER_HALF_KERNEL_OFFSET)
886 return (void*) (physical_address + HIGHER_HALF_KERNEL_OFFSET);
887
888 // Must be in the higher half
889 return (void*) physical_address;
890}
891
898void* PhysicalMemoryManager::to_lower_region(uintptr_t virtual_address) {
899
900 // If it's in the lower half then add the offset
901 if(virtual_address > HIGHER_HALF_KERNEL_OFFSET)
902 return (void*) (virtual_address - HIGHER_HALF_KERNEL_OFFSET);
903
904 // Must be in the lower half
905 return (void*) virtual_address;
906}
907
914void* PhysicalMemoryManager::to_io_region(uintptr_t physical_address) {
915
916 if(physical_address < HIGHER_HALF_MEM_OFFSET)
917 return (void*) (physical_address + HIGHER_HALF_MEM_OFFSET);
918
919 // Must be in the higher half
920 return (void*) physical_address;
921}
922
929void* PhysicalMemoryManager::to_dm_region(uintptr_t physical_address) {
930
931 if(physical_address < HIGHER_HALF_OFFSET)
932 return (void*) (physical_address + HIGHER_HALF_DIRECT_MAP);
933
934 // Must be in the higher half
935 return (void*) physical_address;
936}
937
944void* PhysicalMemoryManager::from_dm_region(uintptr_t virtual_address) {
945
946 if(virtual_address > HIGHER_HALF_DIRECT_MAP)
947 return (void*) (virtual_address - HIGHER_HALF_DIRECT_MAP);
948
949 // Must be in the lower half
950 return (void*) virtual_address;
951}
952
953
960bool PhysicalMemoryManager::in_higher_region(uintptr_t virtual_address) {
961
962 return virtual_address & (1l << 62);
963}
964
965
static LogRecord DEBUG()
Gets the active logger for debug logs.
Definition logger.cpp:204
static LogRecord INFO()
Gets the active logger for info logs.
Definition logger.cpp:195
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:929
static void unmap_lower_kernel()
Unmaps the kernel physical memory from the lower half that was set up during the kernel boot.
Definition physical.cpp:969
void unmap_area(virtual_address_t *virtual_address_start, size_t length)
Unmaps an area of virtual memory.
Definition physical.cpp:624
static size_t align_direct_to_page(size_t size)
Aligns a address to the page size.
Definition physical.cpp:764
static void * to_io_region(uintptr_t physical_address)
Converts a physical address to an IO region address if it is in the lower region using the higher hal...
Definition physical.cpp:914
void reserve(uint64_t address)
Reserves a physical address.
Definition physical.cpp:774
void map_area(virtual_address_t *virtual_address_start, size_t length, size_t flags)
Allocates a new area physical memory to a area virtual address.
Definition physical.cpp:549
void unmap(virtual_address_t *virtual_address)
Unmaps a virtual address using the kernel's pml4 table.
Definition physical.cpp:590
static size_t align_to_page(size_t size)
Aligns a size to the page size. (Rounds up to the next multiple of PAGE_SIZE)
Definition physical.cpp:155
PhysicalMemoryManager(system::Multiboot *multiboot)
Constructs a PhysicalMemoryManager. Unmaps the lower kernel and sets up the bitmap for physical memor...
Definition physical.cpp:31
uint64_t memory_size() const
Gets total the memory size available for use (allocated or not)
Definition physical.cpp:743
static void clean_page_table(uint64_t *table)
Cleans a page table (fills it with 0 or null entries)
Definition physical.cpp:636
virtual_address_t * map(virtual_address_t *virtual_address, size_t flags)
Allocates a physical address to a virtual address.
Definition physical.cpp:535
uint64_t * pml4_root_address()
Gets the pml4 root address for the kernel.
Definition physical.cpp:733
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:898
static void * to_higher_region(uintptr_t physical_address)
Converts a physical address to a higher region address if it is in the lower region using the higher ...
Definition physical.cpp:882
bool is_mapped(uintptr_t physical_address, uintptr_t virtual_address, uint64_t *pml4_root)
Checks if a physical address is mapped to a virtual address.
Definition physical.cpp:869
static void * from_dm_region(uintptr_t physical_address)
Converts a direct map region address to a physical address if it is in the higher region using the hi...
Definition physical.cpp:944
void change_page_flags(virtual_address_t *virtual_address, size_t flags, uint64_t *pml4_root)
Changes the flags of a page.
Definition physical.cpp:846
static bool check_aligned(size_t size)
Checks if an address is aligned.
Definition physical.cpp:178
static PhysicalMemoryManager * s_current_manager
The current physical memory manager in use.
Definition physical.h:183
static size_t align_up_to_page(size_t size, size_t s_page_size)
Aligns a size up to the page size, given a page size to a power of 2.
Definition physical.cpp:167
void identity_map(physical_address_t *physical_address, size_t flags)
Maps a physical address to its virtual address counter-part.
Definition physical.cpp:579
static size_t size_to_frames(size_t size)
Converts a size to the number of frames.
Definition physical.cpp:144
void free_area(uint64_t start_address, size_t size)
Frees an area of physical memory.
Definition physical.cpp:341
void reserve_kernel_regions(system::Multiboot *multiboot)
Reserves the kernel, multiboot modules, mmap regions and higher half mapping regions in the physical ...
Definition physical.cpp:89
static bool in_higher_region(uintptr_t virtual_address)
Checks if a virtual address is in the higher region.
Definition physical.cpp:960
uint64_t memory_used() const
Gets the memory currently used.
Definition physical.cpp:753
void free_frame(void *address)
Frees a frame in the bit map.
Definition physical.cpp:250
physical_address_t * get_physical_address(virtual_address_t *virtual_address, uint64_t *pml4_root)
Gets the physical address from a virtual address (if it exists)
Definition physical.cpp:828
void * allocate_area(uint64_t start_address, size_t size)
Allocate an area of physical memory (ie reserve it)
Definition physical.cpp:270
void * allocate_frame()
Allocates a physical page of memory, if the PMM is not initalise it will use the anon memory instead ...
Definition physical.cpp:188
static bool check_nx()
Checks if the No Execute page flag is supported.
Definition cpu.cpp:642
Parses and provides access to Multiboot 2 information.
Definition multiboot.h:518
unsigned long end_address
The end address of the multiboot info struct.
Definition multiboot.h:540
multiboot_tag * start_tag() const
multiboot_tag_mmap * mmap()
Get the module tag.
Defines Central Processing Unit (CPU) structures and functions for managing CPU state and features.
Defines a Logger class for logging messages with different severity levels to multiple output streams...
volatile PAGE_ALIGNED unsigned char p3_table_hh[]
The PDPT table for higher half direct map setup in loader.s.
volatile PAGE_ALIGNED unsigned char p3_table[]
The PDPT table setup in loader.s.
volatile PAGE_ALIGNED unsigned char p4_table[]
The PML4 table setup in loader.s.
volatile PAGE_ALIGNED unsigned char p2_table[]
The PD table setup in loader.s.
volatile PAGE_ALIGNED unsigned char p1_table[]
The PT table setup in loader.s.
uint64_t _kernel_physical_end
The physical address where the kernel ends.
uint64_t _kernel_end
The virtual address of where the kernel ends.
uint64_t _kernel_size
The length of the memory region used by the kernel code.
Defines a PhysicalMemoryManager class for managing physical memory allocation and deallocation of pag...
constexpr uint64_t HIGHER_HALF_OFFSET
Where higher half memory usable space starts.
Definition physical.h:98
struct PACKED MaxOS::memory::PageMapLevel pml_t
Alias for PageMapLevel struct.
void virtual_address_t
A type representing a virtual address (used for readability)
Definition physical.h:30
constexpr uint64_t HIGHER_HALF_DIRECT_MAP
Where the map of physical memory to higher half starts.
Definition physical.h:99
#define PML4_GET_INDEX(ADDR)
Get the PML4 index from a virtual address.
Definition physical.h:23
struct PACKED MaxOS::memory::PageTableEntry pte_t
Alias for PageTableEntry struct.
#define PML3_GET_INDEX(ADDR)
Get the PDPT index from a virtual address.
Definition physical.h:24
#define PML1_GET_INDEX(ADDR)
Get the PT index from a virtual address.
Definition physical.h:26
constexpr uint64_t HIGHER_HALF_KERNEL_OFFSET
Where the kernel is mapped in higher half memory.
Definition physical.h:95
constexpr uint64_t HIGHER_HALF_MEM_OFFSET
Where higher half memory starts.
Definition physical.h:96
void physical_address_t
A type representing a physical address (used for readability)
Definition physical.h:31
constexpr uint8_t ROW_BITS
The number of bits in the bitmap row.
Definition physical.h:93
constexpr uint64_t PAGE_SIZE
The size of a page (4KB)
Definition physical.h:92
@ PRESENT
The page is present in memory.
Definition physical.h:44
@ WRITE
Memory in this page is writable.
Definition physical.h:45
@ GLOBAL
The page can be shared between processes.
Definition physical.h:52
@ DIRTY
This page has been written to.
Definition physical.h:50
@ USER
This page is accessible from user mode.
Definition physical.h:46
@ CACHE_DISABLED
Dont let the CPU cache this page.
Definition physical.h:48
@ NO_EXECUTE
Dont let the CPU execute code on this page.
Definition physical.h:53
#define PML2_GET_INDEX(ADDR)
Get the PDP index from a virtual address.
Definition physical.h:25
An entry in the memory map containing information about a region of memory.
Definition multiboot.h:222
multiboot_uint64_t addr
The starting address of the memory region.
Definition multiboot.h:223
multiboot_uint64_t len
The length of the memory region.
Definition multiboot.h:224
multiboot_uint32_t size
*copydoc multiboot_tag::size
Definition multiboot.h:290
struct multiboot_mmap_entry entries[0]
The memory map entries.
Definition multiboot.h:293
multiboot_uint32_t entry_size
The size of each entry.
Definition multiboot.h:291
Common header for all multiboot info tags.
Definition multiboot.h:234