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;
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 <
52 (multiboot_uint8_t*) m_mmap_tag +
53 m_mmap_tag->size; entry = (multiboot_mmap_entry*) (
54 (unsigned long) entry + m_mmap_tag->entry_size)) {
55
56 // Skip if the region is not free or there is not enough space
57 if(entry->type != MULTIBOOT_MEMORY_AVAILABLE)
58 continue;
59
60 // Store the entry. (note: don't break here as it is desired to find the last usable entry as that is normally biggest)
61 m_mmap = entry;
62 }
63
64 // Store the information about the bitmap
65 m_memory_size = (m_mmap->addr + m_mmap->len);
66 m_bitmap_size = m_memory_size / PAGE_SIZE + 1;
67 m_total_entries = m_bitmap_size / ROW_BITS + 1;
68 Logger::DEBUG() << "Memory Info: size = " << (int) (m_memory_size / 1024 / 1024) << "mb, bitmap size = 0x"
69 << (uint64_t) m_bitmap_size << ", total entries = " << (int) m_total_entries << ", page size = 0x"
70 << (uint64_t) PAGE_SIZE << "\n";
71
72 // Map the physical memory into the virtual memory
73 Logger::DEBUG() << "Mapping from 0x0 to 0x" << (uint64_t) (m_mmap->addr + m_mmap->len)
74 << " to higher half direct map at offset 0x" << HIGHER_HALF_DIRECT_MAP << "\n";
75 for(uint64_t physical_address = 0; physical_address < (m_mmap->addr + m_mmap->len); physical_address += PAGE_SIZE)
76 map((physical_address_t*) physical_address, (virtual_address_t*) (HIGHER_HALF_DIRECT_MAP + physical_address),
77 PRESENT | WRITE);
78
79 // Kernel Setup
80 initialise_bit_map();
82
83 // Initialisation Done
84 m_initialised = true;
85 Logger::DEBUG() << "Memory used at start: " << (int) (memory_used() / 1024 / 1024) << "mb \n";
86}
87
88PhysicalMemoryManager::~PhysicalMemoryManager() = default;
89
97
98 // Reserve the pages used by the higher half mapping
99 reserve((uint64_t) m_mmap->addr, m_setup_frames * PAGE_SIZE, "HHDM");
100
101 // Reserve the area for the bitmap
102 reserve((uint64_t) from_dm_region((uint64_t) m_bit_map), m_bitmap_size / 8, "Bitmap");
103
104 // Calculate how much space the kernel takes up
105 uint32_t kernel_entries = (m_kernel_start_page / PAGE_SIZE) + 1;
106 if((((uint32_t) (m_kernel_start_page)) % PAGE_SIZE) != 0)
107 kernel_entries += 1;
108
109 // Reserve the kernel entries
110 reserve(0, kernel_entries * PAGE_SIZE, "Kernel");
111
112 // Reserve the area for the mmap
113 uint64_t mem_end = m_mmap->addr + m_mmap->len;
114 for(multiboot_mmap_entry* entry = m_mmap_tag->entries; (multiboot_uint8_t*) entry <
115 (multiboot_uint8_t*) m_mmap_tag +
116 m_mmap_tag->size; entry = (multiboot_mmap_entry*) (
117 (unsigned long) entry + m_mmap_tag->entry_size)) {
118
119 // Dont reserve free regions
120 if(entry->type <= MULTIBOOT_MEMORY_AVAILABLE)
121 continue;
122
123 // Don't reserve the memory being managed by pmm
124 if(entry->addr >= mem_end)
125 continue;
126
127 reserve(entry->addr, entry->len, "MMap");
128 }
129
130 // Reserve the area for each multiboot module
131 for(multiboot_tag* tag = multiboot->start_tag();
132 tag->type != MULTIBOOT_TAG_TYPE_END; tag = (struct multiboot_tag*) ((multiboot_uint8_t*) tag +
133 ((tag->size + 7) & ~7))) {
134
135 if(tag->type != MULTIBOOT_TAG_TYPE_MODULE)
136 continue;
137
138 // Reserve the module's address
139 auto* module = (struct multiboot_tag_module*) tag;
140 reserve(module->mod_start, module->mod_end - module->mod_start, "Module");
141 }
142
143 // Reserve all the tags
144 auto end_tag = (multiboot_tag*) to_higher_region(multiboot->end_address);
145 auto start_tag = (uint64_t) to_lower_region((uintptr_t) multiboot->start_tag());
146 size_t tags_size = multiboot->end_address - start_tag + ((end_tag->size + 7) & ~7);
147 reserve(start_tag, tags_size, "Tags");
148}
149
157
158 return align_to_page(size) / PAGE_SIZE;
159}
160
168
169 return ((size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
170}
171
180
181 return (size + page_size - 1) & ~(page_size - 1);
182}
183
191
192 return (size % PAGE_SIZE) == 0;
193}
194
201
202 // Wait for the lock
203 m_lock.lock();
204
205 // If not initialised, cant use the bitmap or higher half mapped physical memory so use leftover kernel memory already
206 // mapped in loader.s
207 if(!m_initialised) {
208
209 // Use frames at the start of the mmap free
210 void* address = (void*) ((uintptr_t) m_mmap->addr + (m_setup_frames * PAGE_SIZE));
211 m_setup_frames++;
212
213 m_lock.unlock();
214 return address;
215 }
216
217 // Check if there are enough frames
218 ASSERT(m_used_frames < m_bitmap_size, "No more frames available\n");
219
220 for(uint32_t row = 0; row < m_total_entries; ++row) {
221
222 // If the row is full continue
223 if(m_bit_map[row] == 0xFFFFFFFFFFFFFFF)
224 continue;
225
226 for(uint32_t column = 0; column < ROW_BITS; ++column) {
227
228 // Entry isn't free
229 if(m_bit_map[row] & (1ULL << column))
230 continue;
231
232 // Mark the frame as used
233 m_bit_map[row] |= (1ULL << column);
234 m_used_frames++;
235
236 // Thread safe
237 m_lock.unlock();
238
239 // Return the address
240 uint64_t frame_address = (row * ROW_BITS) + column;
241 return (void*) (frame_address * PAGE_SIZE);
242 }
243 }
244
245 // Error frame not found
246 ASSERT(false, "Frame not found\n");
247 m_lock.unlock();
248 return nullptr;
249}
250
257
258 m_lock.lock();
259
260 // Mark the frame as not used
261 m_used_frames--;
263 m_bit_map[frame_address / ROW_BITS] &= ~(1 << (frame_address % ROW_BITS));
264
265 m_lock.unlock();
266}
267
275void* PhysicalMemoryManager::allocate_area(uint64_t start_address, size_t size) {
276
277 m_lock.lock();
278
279 // Store the information about the frames needed to be allocated for this size
280 size_t frame_count = size_to_frames(size);
283 size_t adjacent_frames = 0;
284
285 for(uint32_t row = 0; row < m_total_entries; ++row) {
286
287 // Skip full rows
288 if(m_bit_map[row] == 0xFFFFFFFFFFFFFFF)
289 continue;
290
291 for(uint32_t column = 0; column < ROW_BITS; ++column) {
292
293 // Not enough adjacent frames
294 if(m_bit_map[row] & (1ULL << column)) {
295 adjacent_frames = 0;
296 continue;
297 }
298
299 // Store the address of the first frame in set of adjacent ones
300 if(adjacent_frames == 0) {
301 start_row = row;
302 start_column = column;
303 }
304
305 // Make sure there are enough frames in a row found
308 continue;
309
310 // Mark the frames as used
311 m_used_frames += frame_count;
312 for(uint32_t i = 0; i < frame_count; ++i) {
313
314 // Get the location of the bit
315 uint32_t index = start_row + (start_column + i) / ROW_BITS;
317
318 // Check bounds
319 ASSERT(index >= m_total_entries || bit >= ROW_BITS, "Index out of bounds\n");
320
321 // Mark the bit as used
322 m_bit_map[index] |= (1ULL << bit);
323 }
324
325 // Return start of the block of adjacent frames
326 m_lock.unlock();
327 return (void*) (start_address + (start_row * ROW_BITS + start_column) * PAGE_SIZE);
328
329 }
330 }
331
332 // Not enough free frames adjacent to each other
333 m_lock.unlock();
334 ASSERT(false, "Cannot allocate that much memory\n");
335 return nullptr;
336}
337
344void PhysicalMemoryManager::free_area(uint64_t start_address, size_t size) {
345
346 // Convert address into frames
347 size_t frame_count = size_to_frames(size);
348 uint64_t frame_address = start_address / PAGE_SIZE;
349
350 // Check bounds
351 if(frame_address >= m_bitmap_size)
352 return;
353
354 // Wait until other threads have finished other memory operations
355 m_lock.lock();
356
357 // Mark the frames as not used
358 m_used_frames -= frame_count;
359 for(uint32_t i = 0; i < frame_count; ++i)
360 m_bit_map[(frame_address + i) / ROW_BITS] &= ~(1 << ((frame_address + i) % ROW_BITS));
361
362 m_lock.unlock();
363}
364
373pml_t* PhysicalMemoryManager::get_higher_half_table(uint64_t index, uint64_t index2, uint64_t index3) {
374
375 return (pml_t*) (0xFFFF000000000000 | ((510UL << 39) | (index3 << 30) | (index2 << 21) | (index << 12)));
376}
377
378
387pml_t* PhysicalMemoryManager::get_or_create_table(pml_t* table, size_t index, size_t flags) {
388
389 // Table is already created so just find the entry
390 if(table->entries[index].present)
391 return (pml_t*) to_dm_region(physical_address_of_entry(&table->entries[index]));
392
393 // Create the table
394 auto* new_table = (uint64_t*) allocate_frame();
395 table->entries[index] = create_page_table_entry((uint64_t) new_table, flags);
396
397 // Move the table to the higher half
399
400 // Reset the memory contents at the address
402
403 return (pml_t*) new_table;
404}
405
415pml_t* PhysicalMemoryManager::get_and_create_table(pml_t* parent_table, uint64_t table_index, pml_t* table) {
416
417 // Table already created so don't need to do anything
420 if(parent_table->entries[table_index].present)
421 return table;
422
423 // Create the table
424 auto* new_table = (uint64_t*) allocate_frame();
425 parent_table->entries[table_index] = create_page_table_entry((uint64_t) new_table, PRESENT | WRITE);
426
427 // Move the table to higher half
428 // Except this doesn't need to be done because using anom memory
429
430 // Reset the memory contents at the address
431 clean_page_table((uint64_t*) table);
432
433 return table;
434}
435
436
443pte_t* PhysicalMemoryManager::get_entry(virtual_address_t* virtual_address, pml_t* pml4_table) {
444
445 // Kernel memory must be in the higher half
446 size_t flags = PRESENT | WRITE;
447 if(!in_higher_region((uint64_t) virtual_address))
448 flags |= USER;
449
450 uint16_t pml4_index = PML4_GET_INDEX((uint64_t) virtual_address);
451 uint16_t pdpr_index = PML3_GET_INDEX((uint64_t) virtual_address);
452 uint16_t pd_index = PML2_GET_INDEX((uint64_t) virtual_address);
453 uint16_t pt_index = PML1_GET_INDEX((uint64_t) virtual_address);
454
455 pml_t* pdpr_table = nullptr;
456 pml_t* pd_table = nullptr;
457 pml_t* pt_table = nullptr;
458
459 // If it is before initialization then cant rely on the direct map
460 if(!m_initialised) {
461 pdpr_table = get_and_create_table(pml4_table, pml4_index, get_higher_half_table(pml4_index));
462 pd_table = get_and_create_table(pdpr_table, pdpr_index, get_higher_half_table(pdpr_index, pml4_index));
463 pt_table = get_and_create_table(pd_table, pd_index, get_higher_half_table(pd_index, pdpr_index, pml4_index));
464
465 } else {
466 pdpr_table = get_or_create_table(pml4_table, pml4_index, flags);
467 pd_table = get_or_create_table(pdpr_table, pdpr_index, flags);
468 pt_table = get_or_create_table(pd_table, pd_index, flags);
469 }
470
471 // Get the entry
472 return &pt_table->entries[pt_index];
473}
474
475
482uint64_t PhysicalMemoryManager::physical_address_of_entry(pte_t* entry) {
483
484 return entry->physical_address << 12;
485}
486
487
496virtual_address_t* PhysicalMemoryManager::map(physical_address_t* physical_address, virtual_address_t* virtual_address, size_t flags) {
497
498 // Map using the kernel's pml4 table
499 return map(physical_address, virtual_address, flags, m_pml4_root_address);
500}
501
512
513 // If it is in a lower region then assume it is the user space
514 if(!in_higher_region((uint64_t) virtual_address))
515 flags |= USER;
516
517 // If the entry already exists then the mapping is already done
518 pte_t* pte = get_entry(virtual_address, (pml_t*) pml4_table);
519 if(pte->present)
520 return virtual_address;
521
522 // Map the physical address to the virtual address
523 *pte = create_page_table_entry((uint64_t) physical_address, flags);
524
525 // Flush the TLB (cache)
526 asm volatile("invlpg (%0)"::"r" (virtual_address) : "memory");
527
528 return virtual_address;
529}
530
539
540 // Map a new physical address to the requested virtual address
541 return map(allocate_frame(), virtual_address, flags);
542
543}
544
553
554 // Map the required frames
555 for(size_t i = 0; i < size_to_frames(length); ++i)
557
558}
559
569
570 // Map the required frames
571 for(size_t i = 0; i < size_to_frames(length); ++i)
574}
575
582void PhysicalMemoryManager::identity_map(physical_address_t* physical_address, size_t flags) {
583
584 // Map the physical address to its virtual address counter-part
585 map(physical_address, physical_address, flags);
586}
587
594
595 // Pass the kernel's pml4 table
596 unmap(virtual_address, m_pml4_root_address);
597}
598
606
607 // Get the entry
608 pte_t* pte = get_entry(virtual_address, (pml_t*) pml4_root);
609
610 // Make sure the address is actually mapped
611 if(!pte->present)
612 return;
613
614 // Unmap the entry
615 pte->present = false;
616
617 // Flush the TLB (cache)
618 asm volatile("invlpg (%0)"::"r" (virtual_address) : "memory");
619}
620
628
629 // Unmap the required frames
630 for(size_t i = 0; i < size_to_frames(length); ++i)
632}
633
640
641 // Null the table (prevents false mappings when re-using frames)
642 for(int i = 0; i < 512; i++)
643 table[i] = 0x00l;
644}
645
655pte_t PhysicalMemoryManager::create_page_table_entry(uintptr_t address, size_t flags) const {
656
657 pte_t page = (pte_t) {
658 .present = (flags & PRESENT) != 0,
659 .write = (flags & WRITE) != 0,
660 .user = (flags & USER) != 0,
661 .write_through = (flags & WRITE_THROUGH) != 0,
662 .cache_disabled = (flags & CACHE_DISABLED) != 0,
663 .accessed = (flags & ACCESSED) != 0,
664 .dirty = (flags & DIRTY) != 0,
665 .huge_page = (flags & HUGE_PAGE) != 0,
666 .global = (flags & GLOBAL) != 0,
667 .available = 0,
668 .physical_address = address >> 12,
669 };
670
671 // Set the NX bit if it is allowed
672 if(m_nx_allowed && (flags & NO_EXECUTE)) {
673 auto page_raw = (uint64_t) &page;
675 page = *(pte_t*) page_raw;
676 }
677
678 return page;
679}
680
686void PhysicalMemoryManager::initialise_bit_map() {
687
688 // Earliest address to place the bitmap (after the kernel and hh direct map)
689 uint64_t limit = m_kernel_start_page;
690
691 // Find a region for the bitmap to handle
692 for(multiboot_mmap_entry* entry = m_mmap_tag->entries; (multiboot_uint8_t*) entry <
693 (multiboot_uint8_t*) m_mmap_tag +
694 m_mmap_tag->size; entry = (multiboot_mmap_entry*) (
695 (unsigned long) entry + m_mmap_tag->entry_size)) {
696
697 // Cant use a non-free entry or an entry past limit (ie don't user higher addresses that will be overridden later)
698 if(entry->type != MULTIBOOT_MEMORY_AVAILABLE || entry->len > limit)
699 continue;
700
701 size_t space = entry->len;
702 size_t offset = 0;
703
704 // Determine how much of the region is below the limit and adjust the starting point to there
705 if(entry->addr < limit) {
706 offset = limit - entry->addr;
707 space -= offset;
708 }
709
710 // Make sure there is enough space
711 ASSERT(space >= (m_bitmap_size / 8 + 1), "Not enough space for the bitmap (too big)\n");
712
713 // Return the address (ensuring that it is in the safe region)
714 m_bit_map = (uint64_t*) to_dm_region(entry->addr + offset);
715 break;
716 }
717
718 // Error no suitable space for the bitmap found
719 ASSERT(m_bit_map != nullptr, "No space for the bitmap (no region)\n");
720
721 // Clear the bitmap (mark all as free)
722 for(uint32_t i = 0; i < m_total_entries; ++i)
723 m_bit_map[i] = 0;
724
725 Logger::DEBUG() << "Bitmap: location: 0x" << (uint64_t) m_bit_map << " - 0x"
726 << (uint64_t) (m_bit_map + m_bitmap_size / 8) << " (range of 0x" << (uint64_t) m_bitmap_size / 8
727 << ")\n";
728
729}
730
737
738 return m_pml4_root_address;
739}
740
747
748 return m_memory_size;
749}
750
757
758 return m_used_frames * PAGE_SIZE;
759}
760
768
769 return (size & (~(PAGE_SIZE - 1)));
770}
771
778
779 reserve(address, PAGE_SIZE);
780}
781
789void PhysicalMemoryManager::reserve(uint64_t address, size_t size, const char* type) {
790
791 // Cant reserve virtual addresses (ensure the address is physical)
792 ASSERT(address < m_memory_size, "Attempt to reserve address bigger then the memory can contain: 0x%x\n", address);
793 ASSERT(address + size < m_memory_size, "Attempt to reserve region bigger then the memory can contain: 0x%x-0x%x\n",
794 address, address + size);
795
796 // Wait to be able to reserve
797 m_lock.lock();
798
799 // Align to a page, if rounding down need to correct the range
800 size_t aligned_address = align_direct_to_page(address);
801 if(aligned_address < address)
802 size += address - aligned_address;
803
804 // Convert in to amount of pages
805 size = align_up_to_page(size, PAGE_SIZE);
806 size_t page_count = size / PAGE_SIZE;
808
809 // Mark all as used
810 for(size_t i = 0; i < page_count; ++i)
811 m_bit_map[(frame_index + i) / ROW_BITS] |= (1ULL << ((frame_index + i) % ROW_BITS));
812
813 // Update the used frames
814 m_used_frames += page_count;
815
816 // Clear the lock
817 m_lock.unlock();
818 Logger::DEBUG() << "Reserved Address for " << type << ": 0x" << aligned_address << " - 0x" << aligned_address + size
819 << " (length of 0x" << size << ")\n";
820}
821
830
831 pte_t* entry = get_entry(virtual_address, (pml_t*) pml4_root);
832
833 // Cant get a physical address if its inst free
834 if(!entry->present)
835 return nullptr;
836
837 return (physical_address_t*) physical_address_of_entry(entry);
838}
839
848
849 pte_t* entry = get_entry(virtual_address, (pml_t*) pml4_root);
850
851 // Cant edit a non-present entry (will page fault)
852 if(!entry->present)
853 return;
854
855 *entry = create_page_table_entry(physical_address_of_entry(entry), flags);
856
857 // Flush the TLB (cache)
858 asm volatile("invlpg (%0)"::"r" (virtual_address) : "memory");
859
860}
861
870bool PhysicalMemoryManager::is_mapped(uintptr_t physical_address, uintptr_t virtual_address, uint64_t* pml4_root) {
871
872 return get_physical_address((virtual_address_t*) virtual_address, pml4_root) ==
873 (physical_address_t*) physical_address;
874
875}
876
884
885 // If it's in the lower half then add the offset
886 if(physical_address < HIGHER_HALF_KERNEL_OFFSET)
887 return (void*) (physical_address + HIGHER_HALF_KERNEL_OFFSET);
888
889 // Must be in the higher half
890 return (void*) physical_address;
891}
892
900
901 // If it's in the lower half then add the offset
902 if(virtual_address > HIGHER_HALF_KERNEL_OFFSET)
903 return (void*) (virtual_address - HIGHER_HALF_KERNEL_OFFSET);
904
905 // Must be in the lower half
906 return (void*) virtual_address;
907}
908
916
917 if(physical_address < HIGHER_HALF_MEM_OFFSET)
918 return (void*) (physical_address + HIGHER_HALF_MEM_OFFSET);
919
920 // Must be in the higher half
921 return (void*) physical_address;
922}
923
931
932 if(physical_address < HIGHER_HALF_OFFSET)
933 return (void*) (physical_address + HIGHER_HALF_DIRECT_MAP);
934
935 // Must be in the higher half
936 return (void*) physical_address;
937}
938
946
947 if(virtual_address > HIGHER_HALF_DIRECT_MAP)
948 return (void*) (virtual_address - HIGHER_HALF_DIRECT_MAP);
949
950 // Must be in the lower half
951 return (void*) virtual_address;
952}
953
954
962
963 return virtual_address & (1l << 62);
964}
965
966
static Logger DEBUG()
Gets active logger set to DEBUG level.
Definition logger.cpp:193
static Logger INFO()
Gets active logger set to info level.
Definition logger.cpp:171
Stores the left, top, width and height of a rectangle.
Definition rectangle.h:22
void lock()
Lock the spinlock once it is available.
Definition spinlock.cpp:24
void unlock()
Unlock the spinlock.
Definition spinlock.cpp:32
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 void unmap_lower_kernel()
Unmaps the kernel physical memory from the lower half that was set up during the kernel boot.
Definition physical.cpp:970
void unmap_area(virtual_address_t *virtual_address_start, size_t length)
Unmaps an area of virtual memory.
Definition physical.cpp:627
static size_t align_direct_to_page(size_t size)
Aligns a address to the page size.
Definition physical.cpp:767
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:915
void reserve(uint64_t address)
Reserves a physical address.
Definition physical.cpp:777
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:552
void unmap(virtual_address_t *virtual_address)
Unmaps a virtual address using the kernel's pml4 table.
Definition physical.cpp:593
static size_t align_to_page(size_t size)
Aligns a size to the page size.
Definition physical.cpp:167
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:746
static void clean_page_table(uint64_t *table)
Cleans a page table (fills it with 0 or null entries)
Definition physical.cpp:639
virtual_address_t * map(virtual_address_t *virtual_address, size_t flags)
Allocates a physical address to a virtual address.
Definition physical.cpp:538
uint64_t * pml4_root_address()
Gets the pml4 root address for the kernel.
Definition physical.cpp:736
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 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:883
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:870
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:945
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:847
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
void identity_map(physical_address_t *physical_address, size_t flags)
Maps a physical address to its virtual address counter-part.
Definition physical.cpp:582
static size_t size_to_frames(size_t size)
Converts a size to the number of frames.
Definition physical.cpp:156
void free_area(uint64_t start_address, size_t size)
Frees an area of physical memory.
Definition physical.cpp:344
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:96
static bool in_higher_region(uintptr_t virtual_address)
Checks if a virtual address is in the higher region.
Definition physical.cpp:961
uint64_t memory_used() const
Gets the memory currently used.
Definition physical.cpp:756
void free_frame(void *address)
Frees a frame in the bit map.
Definition physical.cpp:256
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:829
void * allocate_area(uint64_t start_address, size_t size)
Allocate an area of physical memory (ie reserve it)
Definition physical.cpp:275
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:200
static bool check_nx()
Checks if the No Execute page flag is supported.
Definition cpu.cpp:605
Parses and provides access to Multiboot 2 information.
Definition multiboot.h:518
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...
#define ASSERT(condition, format,...)
If the specified condition is not met then the kernel will crash with the specified message.
Definition logger.h:100
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:97
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:29
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:22
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:23
#define PML1_GET_INDEX(ADDR)
Get the PT index from a virtual address.
Definition physical.h:25
constexpr uint64_t HIGHER_HALF_KERNEL_OFFSET
Where the kernel is mapped in higher half memory.
Definition physical.h:94
constexpr uint64_t HIGHER_HALF_MEM_OFFSET
Where higher half memory starts.
Definition physical.h:95
void physical_address_t
A type representing a physical address (used for readability)
Definition physical.h:30
constexpr uint8_t ROW_BITS
The number of bits in the bitmap row.
Definition physical.h:92
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
@ GLOBAL
The page can be shared between processes.
Definition physical.h:51
@ DIRTY
This page has been written to.
Definition physical.h:49
@ USER
This page is accessible from user mode.
Definition physical.h:45
@ CACHE_DISABLED
Dont let the CPU cache this page.
Definition physical.h:47
@ NO_EXECUTE
Dont let the CPU execute code on this page.
Definition physical.h:52
#define PML2_GET_INDEX(ADDR)
Get the PDP index from a virtual address.
Definition physical.h:24
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