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

Manages the physical memory of the system such as what pages are allocated/free and mapping of virtual to physical addresses. More...

#include <physical.h>

Public Member Functions

 PhysicalMemoryManager (system::Multiboot *multiboot)
 Constructs a PhysicalMemoryManager. Unmaps the lower kernel and sets up the bitmap for physical memory management. Reserves the kernel and the multiboot regions.
 
uint64_t memory_size () const
 Gets total the memory size available for use (allocated or not)
 
uint64_t memory_used () const
 Gets the memory currently used.
 
uint64_tpml4_root_address ()
 Gets the pml4 root address for the kernel.
 
voidallocate_frame ()
 Allocates a physical page of memory, if the PMM is not initalise it will use the anon memory instead of the bitmap.
 
void free_frame (void *address)
 Frees a frame in the bit map.
 
voidallocate_area (uint64_t start_address, size_t size)
 Allocate an area of physical memory (ie reserve it)
 
void free_area (uint64_t start_address, size_t size)
 Frees an area of physical memory.
 
virtual_address_tmap (virtual_address_t *virtual_address, size_t flags)
 Allocates a physical address to a virtual address.
 
virtual_address_tmap (physical_address_t *physical, virtual_address_t *virtual_address, size_t flags)
 Maps a physical address to a virtual address, using the kernel's pml4 table.
 
virtual_address_tmap (physical_address_t *physical, virtual_address_t *virtual_address, size_t flags, uint64_t *pml4_root)
 Maps a physical address to a virtual address.
 
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.
 
void map_area (physical_address_t *physical_address_start, virtual_address_t *virtual_address_start, size_t length, size_t flags)
 Maps an area of physical memory to a virtual address.
 
void identity_map (physical_address_t *physical_address, size_t flags)
 Maps a physical address to its virtual address counter-part.
 
void unmap (virtual_address_t *virtual_address)
 Unmaps a virtual address using the kernel's pml4 table.
 
void unmap (virtual_address_t *virtual_address, uint64_t *pml4_root)
 Unmaps a virtual address.
 
void unmap_area (virtual_address_t *virtual_address_start, size_t length)
 Unmaps an area of virtual memory.
 
void reserve (uint64_t address)
 Reserves a physical address.
 
void reserve (uint64_t address, size_t size, const char *="Unknown")
 Reserves an area of physical memory.
 
void reserve_kernel_regions (system::Multiboot *multiboot)
 Reserves the kernel, multiboot modules, mmap regions and higher half mapping regions in the physical memory manager so that those pages arent overwritten later.
 
physical_address_tget_physical_address (virtual_address_t *virtual_address, uint64_t *pml4_root)
 Gets the physical address from a virtual address (if it exists)
 
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.
 
void change_page_flags (virtual_address_t *virtual_address, size_t flags, uint64_t *pml4_root)
 Changes the flags of a page.
 

Static Public Member Functions

static void unmap_lower_kernel ()
 Unmaps the kernel physical memory from the lower half that was set up during the kernel boot.
 
static size_t size_to_frames (size_t size)
 Converts a size to the number of frames.
 
static size_t align_to_page (size_t size)
 Aligns a size to the page size.
 
static size_t align_direct_to_page (size_t size)
 Aligns a address to the page size.
 
static size_t align_up_to_page (size_t size, size_t s_page_size)
 Aligns a size up to the page size.
 
static bool check_aligned (size_t size)
 Checks if an address is aligned.
 
static void clean_page_table (uint64_t *table)
 Cleans a page table (fills it with 0 or null entries)
 
static voidto_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 half kernel offset.
 
static voidto_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 half kernel offset.
 
static voidto_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 half memory offset.
 
static voidto_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 higher half direct map offset.
 
static voidfrom_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 higher half direct map offset.
 
static bool in_higher_region (uintptr_t virtual_address)
 Checks if a virtual address is in the higher region.
 

Static Public Attributes

static PhysicalMemoryManagers_current_manager = nullptr
 The current physical memory manager in use.
 

Detailed Description

Manages the physical memory of the system such as what pages are allocated/free and mapping of virtual to physical addresses.

Todo:
Global paging so dont have map in every process

Definition at line 108 of file physical.h.

Constructor & Destructor Documentation

◆ PhysicalMemoryManager()

PhysicalMemoryManager::PhysicalMemoryManager ( system::Multiboot multiboot)
explicit

Constructs a PhysicalMemoryManager. Unmaps the lower kernel and sets up the bitmap for physical memory management. Reserves the kernel and the multiboot regions.

Parameters
multibootThe multiboot information structure to use for memory information such as the memory map.

Definition at line 31 of file physical.cpp.

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}
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 unlock()
Unlock the spinlock.
Definition spinlock.cpp:32
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
virtual_address_t * map(virtual_address_t *virtual_address, size_t flags)
Allocates a physical address to a virtual address.
Definition physical.cpp:538
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 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
uint64_t memory_used() const
Gets the memory currently used.
Definition physical.cpp:756
static bool check_nx()
Checks if the No Execute page flag is supported.
Definition cpu.cpp:605
multiboot_tag_mmap * mmap()
Get the module tag.
volatile PAGE_ALIGNED unsigned char p4_table[]
The PML4 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.
constexpr uint64_t HIGHER_HALF_DIRECT_MAP
Where the map of physical memory to higher half starts.
Definition physical.h:99
struct PACKED MaxOS::memory::PageTableEntry pte_t
Alias for PageTableEntry struct.
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
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

References _kernel_end, _kernel_physical_end, _kernel_size, multiboot_mmap_entry::addr, align_up_to_page(), MaxOS::system::CPU::check_nx(), MaxOS::Logger::DEBUG(), multiboot_tag_mmap::entries, multiboot_tag_mmap::entry_size, MaxOS::memory::HIGHER_HALF_DIRECT_MAP, MaxOS::Logger::INFO(), multiboot_mmap_entry::len, map(), memory_used(), MaxOS::system::Multiboot::mmap(), MaxOS::memory::PAGE_SIZE, MaxOS::memory::PRESENT, reserve_kernel_regions(), MaxOS::memory::ROW_BITS, s_current_manager, multiboot_tag_mmap::size, MaxOS::common::Spinlock::unlock(), unmap_lower_kernel(), and MaxOS::memory::WRITE.

Member Function Documentation

◆ align_direct_to_page()

size_t PhysicalMemoryManager::align_direct_to_page ( size_t  size)
static

Aligns a address to the page size.

Parameters
sizeThe address to align
Returns
The aligned address

Definition at line 767 of file physical.cpp.

767 {
768
769 return (size & (~(PAGE_SIZE - 1)));
770}

References MaxOS::memory::PAGE_SIZE.

Referenced by reserve().

◆ align_to_page()

size_t PhysicalMemoryManager::align_to_page ( size_t  size)
static

Aligns a size to the page size.

Parameters
sizeThe size to align
Returns
The aligned size

Definition at line 167 of file physical.cpp.

167 {
168
169 return ((size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
170}

References MaxOS::memory::PAGE_SIZE.

Referenced by size_to_frames(), and MaxOS::memory::VirtualMemoryManager::VirtualMemoryManager().

◆ align_up_to_page()

size_t PhysicalMemoryManager::align_up_to_page ( size_t  size,
size_t  page_size 
)
static

Aligns a size up to the page size.

Parameters
sizeThe size to align
page_sizeThe page size to align to
Returns
The aligned size

Definition at line 179 of file physical.cpp.

179 {
180
181 return (size + page_size - 1) & ~(page_size - 1);
182}

Referenced by MaxOS::memory::VirtualMemoryManager::allocate(), PhysicalMemoryManager(), and reserve().

◆ allocate_area()

void * PhysicalMemoryManager::allocate_area ( uint64_t  start_address,
size_t  size 
)

Allocate an area of physical memory (ie reserve it)

Parameters
start_addressThe start of the block
sizeThe size to allocate
Returns
A pointer to the start of the block (physical address)

Definition at line 275 of file physical.cpp.

275 {
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;
316 uint32_t bit = (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}
void lock()
Lock the spinlock once it is available.
Definition spinlock.cpp:24
static size_t size_to_frames(size_t size)
Converts a size to the number of frames.
Definition physical.cpp:156
#define ASSERT(condition, format,...)
If the specified condition is not met then the kernel will crash with the specified message.
Definition logger.h:100

References ASSERT, MaxOS::common::Spinlock::lock(), MaxOS::memory::PAGE_SIZE, MaxOS::memory::ROW_BITS, size_to_frames(), and MaxOS::common::Spinlock::unlock().

◆ allocate_frame()

void * PhysicalMemoryManager::allocate_frame ( )

Allocates a physical page of memory, if the PMM is not initalise it will use the anon memory instead of the bitmap.

Returns
The physical address of the page

Definition at line 200 of file physical.cpp.

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

References multiboot_mmap_entry::addr, ASSERT, MaxOS::common::Spinlock::lock(), MaxOS::memory::PAGE_SIZE, MaxOS::memory::ROW_BITS, and MaxOS::common::Spinlock::unlock().

Referenced by map().

◆ change_page_flags()

void PhysicalMemoryManager::change_page_flags ( virtual_address_t virtual_address,
size_t  flags,
uint64_t pml4_root 
)

Changes the flags of a page.

Parameters
virtual_addressThe virtual address of the page
flagsThe flags to set the page to
pml4_rootThe address of the root pml to use

Definition at line 847 of file physical.cpp.

847 {
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}
struct PACKED MaxOS::memory::PageMapLevel pml_t
Alias for PageMapLevel struct.

◆ check_aligned()

bool PhysicalMemoryManager::check_aligned ( size_t  size)
static

Checks if an address is aligned.

Parameters
sizeThe address to check
Returns
True if the address is aligned

Definition at line 190 of file physical.cpp.

190 {
191
192 return (size % PAGE_SIZE) == 0;
193}

References MaxOS::memory::PAGE_SIZE.

Referenced by MaxOS::memory::VirtualMemoryManager::allocate().

◆ clean_page_table()

void PhysicalMemoryManager::clean_page_table ( uint64_t table)
static

Cleans a page table (fills it with 0 or null entries)

Parameters
tableThe table to clean

Definition at line 639 of file physical.cpp.

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

Referenced by MaxOS::memory::VirtualMemoryManager::VirtualMemoryManager().

◆ free_area()

void PhysicalMemoryManager::free_area ( uint64_t  start_address,
size_t  size 
)

Frees an area of physical memory.

Parameters
start_addressThe start of the block
sizeThe size to free

Definition at line 344 of file physical.cpp.

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

References MaxOS::common::Spinlock::lock(), MaxOS::memory::PAGE_SIZE, MaxOS::memory::ROW_BITS, size_to_frames(), and MaxOS::common::Spinlock::unlock().

◆ free_frame()

void PhysicalMemoryManager::free_frame ( void address)

Frees a frame in the bit map.

Parameters
addressThe address to free

Definition at line 256 of file physical.cpp.

256 {
257
258 m_lock.lock();
259
260 // Mark the frame as not used
261 m_used_frames--;
262 uint64_t frame_address = (uint64_t) address / PAGE_SIZE;
263 m_bit_map[frame_address / ROW_BITS] &= ~(1 << (frame_address % ROW_BITS));
264
265 m_lock.unlock();
266}

References MaxOS::common::Spinlock::lock(), MaxOS::memory::PAGE_SIZE, MaxOS::memory::ROW_BITS, and MaxOS::common::Spinlock::unlock().

◆ from_dm_region()

void * PhysicalMemoryManager::from_dm_region ( uintptr_t  virtual_address)
static

Converts a direct map region address to a physical address if it is in the higher region using the higher half direct map offset.

Parameters
virtual_addressThe physical address in the direct map region
Returns
The physical address

Definition at line 945 of file physical.cpp.

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

References MaxOS::memory::HIGHER_HALF_DIRECT_MAP.

Referenced by reserve_kernel_regions().

◆ get_physical_address()

physical_address_t * PhysicalMemoryManager::get_physical_address ( virtual_address_t virtual_address,
uint64_t pml4_root 
)

Gets the physical address from a virtual address (if it exists)

Parameters
virtual_addressThe virtual address to get the physical address from
pml4_rootThe address of the root pml to use
Returns
The physical address or nullptr if it does not exist

Definition at line 829 of file physical.cpp.

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

Referenced by is_mapped().

◆ identity_map()

void PhysicalMemoryManager::identity_map ( physical_address_t physical_address,
size_t  flags 
)

Maps a physical address to its virtual address counter-part.

Parameters
physical_addressThe physical address to map
flagsThe flags to set the mapping to

Definition at line 582 of file physical.cpp.

582 {
583
584 // Map the physical address to its virtual address counter-part
585 map(physical_address, physical_address, flags);
586}

References map().

◆ in_higher_region()

bool PhysicalMemoryManager::in_higher_region ( uintptr_t  virtual_address)
static

Checks if a virtual address is in the higher region.

Parameters
virtual_addressThe virtual address
Returns
True if the address is in the higher region, false otherwise

Definition at line 961 of file physical.cpp.

961 {
962
963 return virtual_address & (1l << 62);
964}

Referenced by map(), and MaxOS::system::CPU::prepare_for_panic().

◆ is_mapped()

bool PhysicalMemoryManager::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.

Parameters
physical_addressThe physical address to check
virtual_addressThe virtual address to check
pml4_rootThe pml4 table to use
Returns
True if the physical address is mapped to the virtual address

Definition at line 870 of file physical.cpp.

870 {
871
872 return get_physical_address((virtual_address_t*) virtual_address, pml4_root) ==
873 (physical_address_t*) physical_address;
874
875}
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

References get_physical_address().

◆ map() [1/3]

virtual_address_t * PhysicalMemoryManager::map ( physical_address_t physical_address,
virtual_address_t virtual_address,
size_t  flags 
)

Maps a physical address to a virtual address, using the kernel's pml4 table.

Parameters
physical_addressThe physical address to map
virtual_addressThe virtual address to map to
flagsThe flags to set the mapping to
Returns
The virtual address

Definition at line 496 of file physical.cpp.

496 {
497
498 // Map using the kernel's pml4 table
499 return map(physical_address, virtual_address, flags, m_pml4_root_address);
500}

References map().

◆ map() [2/3]

virtual_address_t * PhysicalMemoryManager::map ( physical_address_t physical_address,
virtual_address_t virtual_address,
size_t  flags,
uint64_t pml4_table 
)

Maps a physical address to a virtual address.

Parameters
physical_addressThe physical address
virtual_addressThe virtual address
flagsThe flags to set the mapping to
pml4_tableThe pml4 table to use
Returns
The virtual address

Definition at line 511 of file physical.cpp.

511 {
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}
static bool in_higher_region(uintptr_t virtual_address)
Checks if a virtual address is in the higher region.
Definition physical.cpp:961
@ USER
This page is accessible from user mode.
Definition physical.h:45

References in_higher_region(), and MaxOS::memory::USER.

◆ map() [3/3]

virtual_address_t * PhysicalMemoryManager::map ( virtual_address_t virtual_address,
size_t  flags 
)

Allocates a physical address to a virtual address.

Parameters
virtual_addressThe virtual address
flagsThe flags to set the mapping to
Returns
The virtual address

Definition at line 538 of file physical.cpp.

538 {
539
540 // Map a new physical address to the requested virtual address
541 return map(allocate_frame(), virtual_address, flags);
542
543}
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

References allocate_frame(), and map().

Referenced by identity_map(), MaxOS::hardwarecommunication::IOAPIC::IOAPIC(), MaxOS::hardwarecommunication::LocalAPIC::LocalAPIC(), map(), map(), map_area(), map_area(), and PhysicalMemoryManager().

◆ map_area() [1/2]

void PhysicalMemoryManager::map_area ( physical_address_t physical_address_start,
virtual_address_t virtual_address_start,
size_t  length,
size_t  flags 
)

Maps an area of physical memory to a virtual address.

Parameters
physical_address_startThe start of the physical address
virtual_address_startThe start of the virtual address
lengthThe length of the area
flagsThe flags to set the mapping to

Definition at line 568 of file physical.cpp.

568 {
569
570 // Map the required frames
571 for(size_t i = 0; i < size_to_frames(length); ++i)
572 map((virtual_address_t*) ((uintptr_t) physical_address_start + (i * PAGE_SIZE)),
573 (virtual_address_t*) ((uintptr_t) virtual_address_start + (i * PAGE_SIZE)), flags);
574}

References map(), MaxOS::memory::PAGE_SIZE, and size_to_frames().

◆ map_area() [2/2]

void PhysicalMemoryManager::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.

Parameters
virtual_address_startThe start of the virtual address
lengthThe length of the area
flagsThe flags to set the mapping to

Definition at line 552 of file physical.cpp.

552 {
553
554 // Map the required frames
555 for(size_t i = 0; i < size_to_frames(length); ++i)
556 map((virtual_address_t*) ((uintptr_t) virtual_address_start + (i * PAGE_SIZE)), flags);
557
558}

References map(), MaxOS::memory::PAGE_SIZE, and size_to_frames().

◆ memory_size()

uint64_t PhysicalMemoryManager::memory_size ( ) const

Gets total the memory size available for use (allocated or not)

Returns
The memory size in bytes

Definition at line 746 of file physical.cpp.

746 {
747
748 return m_memory_size;
749}

◆ memory_used()

uint64_t PhysicalMemoryManager::memory_used ( ) const

Gets the memory currently used.

Returns
The memory size in bytes

Definition at line 756 of file physical.cpp.

756 {
757
758 return m_used_frames * PAGE_SIZE;
759}

References MaxOS::memory::PAGE_SIZE.

Referenced by PhysicalMemoryManager().

◆ pml4_root_address()

uint64_t * PhysicalMemoryManager::pml4_root_address ( )

Gets the pml4 root address for the kernel.

Returns
The pml4 root address

Definition at line 736 of file physical.cpp.

736 {
737
738 return m_pml4_root_address;
739}

◆ reserve() [1/2]

void PhysicalMemoryManager::reserve ( uint64_t  address)

Reserves a physical address.

Parameters
addressThe address to reserve

Definition at line 777 of file physical.cpp.

777 {
778
779 reserve(address, PAGE_SIZE);
780}
void reserve(uint64_t address)
Reserves a physical address.
Definition physical.cpp:777

References MaxOS::memory::PAGE_SIZE, and reserve().

Referenced by MaxOS::hardwarecommunication::LocalAPIC::LocalAPIC(), reserve(), and reserve_kernel_regions().

◆ reserve() [2/2]

void PhysicalMemoryManager::reserve ( uint64_t  address,
size_t  size,
const char type = "Unknown" 
)

Reserves an area of physical memory.

Parameters
addressThe start of the area
sizeThe size of the area
typeThe name for the region being reserved (not required, logging purposes only, defaults to unkown)

Definition at line 789 of file physical.cpp.

789 {
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}
static size_t align_direct_to_page(size_t size)
Aligns a address to the page size.
Definition physical.cpp:767

References align_direct_to_page(), align_up_to_page(), ASSERT, MaxOS::Logger::DEBUG(), MaxOS::common::Spinlock::lock(), MaxOS::memory::PAGE_SIZE, MaxOS::memory::ROW_BITS, and MaxOS::common::Spinlock::unlock().

◆ reserve_kernel_regions()

void PhysicalMemoryManager::reserve_kernel_regions ( system::Multiboot multiboot)

Reserves the kernel, multiboot modules, mmap regions and higher half mapping regions in the physical memory manager so that those pages arent overwritten later.

Parameters
multibootThe multiboot information structure to use for memory information such as the memory map.

Definition at line 96 of file physical.cpp.

96 {
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}
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
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
Common header for all multiboot info tags.
Definition multiboot.h:234

References multiboot_mmap_entry::addr, multiboot_tag_mmap::entries, multiboot_tag_mmap::entry_size, from_dm_region(), multiboot_mmap_entry::len, MaxOS::memory::PAGE_SIZE, reserve(), multiboot_tag_mmap::size, to_higher_region(), and to_lower_region().

Referenced by PhysicalMemoryManager().

◆ size_to_frames()

size_t PhysicalMemoryManager::size_to_frames ( size_t  size)
static

◆ to_dm_region()

void * PhysicalMemoryManager::to_dm_region ( uintptr_t  physical_address)
static

Converts a physical address to a direct map region address if it is in the lower region using the higher half direct map offset.

Parameters
physical_addressThe physical address
Returns
The direct map region address

Definition at line 930 of file physical.cpp.

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

References MaxOS::memory::HIGHER_HALF_DIRECT_MAP, and MaxOS::memory::HIGHER_HALF_OFFSET.

Referenced by MaxOS::processes::GlobalScheduler::load_multiboot_elfs(), MaxOS::drivers::video::VideoElectronicsStandardsAssociation::VideoElectronicsStandardsAssociation(), and MaxOS::memory::VirtualMemoryManager::VirtualMemoryManager().

◆ to_higher_region()

void * PhysicalMemoryManager::to_higher_region ( uintptr_t  physical_address)
static

Converts a physical address to a higher region address if it is in the lower region using the higher half kernel offset.

Parameters
physical_addressThe physical address
Returns
The higher region address

Definition at line 883 of file physical.cpp.

883 {
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}
constexpr uint64_t HIGHER_HALF_KERNEL_OFFSET
Where the kernel is mapped in higher half memory.
Definition physical.h:94

References MaxOS::memory::HIGHER_HALF_KERNEL_OFFSET.

Referenced by reserve_kernel_regions().

◆ to_io_region()

void * PhysicalMemoryManager::to_io_region ( uintptr_t  physical_address)
static

Converts a physical address to an IO region address if it is in the lower region using the higher half memory offset.

Parameters
physical_addressThe physical address
Returns
The IO region address

Definition at line 915 of file physical.cpp.

915 {
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}
constexpr uint64_t HIGHER_HALF_MEM_OFFSET
Where higher half memory starts.
Definition physical.h:95

References MaxOS::memory::HIGHER_HALF_MEM_OFFSET.

Referenced by MaxOS::hardwarecommunication::AdvancedConfigurationAndPowerInterface::find(), MaxOS::hardwarecommunication::IOAPIC::IOAPIC(), and MaxOS::hardwarecommunication::LocalAPIC::LocalAPIC().

◆ to_lower_region()

void * PhysicalMemoryManager::to_lower_region ( uintptr_t  virtual_address)
static

Converts a virtual address to a lower region address if it is in the higher region using the higher half kernel offset.

Parameters
virtual_addressThe virtual address
Returns
The lower region address

Definition at line 899 of file physical.cpp.

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

References MaxOS::memory::HIGHER_HALF_KERNEL_OFFSET.

Referenced by MaxOS::system::CPU::init_cores(), MaxOS::system::Multiboot::Multiboot(), reserve_kernel_regions(), and MaxOS::memory::VirtualMemoryManager::VirtualMemoryManager().

◆ unmap() [1/2]

void PhysicalMemoryManager::unmap ( virtual_address_t virtual_address)

Unmaps a virtual address using the kernel's pml4 table.

Parameters
virtual_addressThe virtual address to unmap

Definition at line 593 of file physical.cpp.

593 {
594
595 // Pass the kernel's pml4 table
596 unmap(virtual_address, m_pml4_root_address);
597}
void unmap(virtual_address_t *virtual_address)
Unmaps a virtual address using the kernel's pml4 table.
Definition physical.cpp:593

References unmap().

Referenced by unmap(), and unmap_area().

◆ unmap() [2/2]

void PhysicalMemoryManager::unmap ( virtual_address_t virtual_address,
uint64_t pml4_root 
)

Unmaps a virtual address.

Parameters
virtual_addressThe virtual address to unmap
pml4_rootThe pml4 table to use

Definition at line 605 of file physical.cpp.

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

◆ unmap_area()

void PhysicalMemoryManager::unmap_area ( virtual_address_t virtual_address_start,
size_t  length 
)

Unmaps an area of virtual memory.

Parameters
virtual_address_startThe start of the area
lengthThe length of the area

Definition at line 627 of file physical.cpp.

627 {
628
629 // Unmap the required frames
630 for(size_t i = 0; i < size_to_frames(length); ++i)
631 unmap((virtual_address_t*) ((uintptr_t) virtual_address_start + (i * PAGE_SIZE)));
632}

References MaxOS::memory::PAGE_SIZE, size_to_frames(), and unmap().

◆ unmap_lower_kernel()

void PhysicalMemoryManager::unmap_lower_kernel ( )
static

Unmaps the kernel physical memory from the lower half that was set up during the kernel boot.

Definition at line 970 of file physical.cpp.

970 {
971
972 p4_table[0] = 0;
973}

References p4_table.

Referenced by PhysicalMemoryManager().

Member Data Documentation

◆ s_current_manager


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