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_t * pml4_root_address ()
 Gets the pml4 root address for the kernel.
 
void * allocate_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.
 
void * allocate_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_t * map (virtual_address_t *virtual_address, size_t flags)
 Allocates a physical address to a virtual address.
 
virtual_address_t * map (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_t * map (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_t * get_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. (Rounds up to the next multiple of 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, given a page size to a power of 2.
 
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 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 half kernel offset.
 
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 half kernel offset.
 
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 half memory offset.
 
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 higher half direct map offset.
 
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 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 PhysicalMemoryManager * s_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 107 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 < (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}
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 unmap_lower_kernel()
Unmaps the kernel physical memory from the lower half that was set up during the kernel boot.
Definition physical.cpp:969
virtual_address_t * map(virtual_address_t *virtual_address, size_t flags)
Allocates a physical address to a virtual address.
Definition physical.cpp:535
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 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
uint64_t memory_used() const
Gets the memory currently used.
Definition physical.cpp:753
static bool check_nx()
Checks if the No Execute page flag is supported.
Definition cpu.cpp:642
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.
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
struct PACKED MaxOS::memory::PageTableEntry pte_t
Alias for PageTableEntry struct.
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
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, 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 764 of file physical.cpp.

764 {
765
766 return (size & (~(PAGE_SIZE - 1)));
767}

References MaxOS::memory::PAGE_SIZE.

Referenced by MaxOS::memory::VirtualMemoryManager::load_range_from_process(), reserve(), and MaxOS::memory::VirtualMemoryManager::unload_range_from_process().

◆ align_to_page()

size_t PhysicalMemoryManager::align_to_page ( size_t  size)
static

Aligns a size to the page size. (Rounds up to the next multiple of PAGE_SIZE)

Parameters
sizeThe size to align
Returns
The aligned size

Definition at line 155 of file physical.cpp.

155 {
156
157 return ((size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
158}

References MaxOS::memory::PAGE_SIZE.

Referenced by size_to_frames().

◆ 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, given a page size to a power of 2.

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

Definition at line 167 of file physical.cpp.

167 {
168
169 return (size + page_size - 1) & ~(page_size - 1);
170}

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

◆ allocate_area()

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

Allocate an area of physical memory (ie reserve it)

Todo:
freeing
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 270 of file physical.cpp.

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

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

◆ 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 188 of file physical.cpp.

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

References multiboot_mmap_entry::addr, MaxOS::memory::PAGE_SIZE, MaxOS::memory::ROW_BITS, and to_dm_region().

Referenced by MaxOS::memory::VirtualMemoryManager::allocate(), and 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 846 of file physical.cpp.

846 {
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}
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 178 of file physical.cpp.

178 {
179
180 return (size % PAGE_SIZE) == 0;
181}

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 636 of file physical.cpp.

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

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 341 of file physical.cpp.

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

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

Referenced by MaxOS::processes::SharedMemory::close().

◆ free_frame()

void PhysicalMemoryManager::free_frame ( void *  address)

Frees a frame in the bit map.

Parameters
addressThe address to free

Definition at line 250 of file physical.cpp.

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

References MaxOS::memory::PAGE_SIZE, and MaxOS::memory::ROW_BITS.

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

◆ 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 944 of file physical.cpp.

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

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
Todo:
make static version

Definition at line 828 of file physical.cpp.

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

Referenced by MaxOS::memory::VirtualMemoryManager::allocate(), is_mapped(), MaxOS::memory::VirtualMemoryManager::load_range_from_process(), and MaxOS::memory::VirtualMemoryManager::~VirtualMemoryManager().

◆ 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 579 of file physical.cpp.

579 {
580
581 // Map the physical address to its virtual address counter-part
582 map(physical_address, physical_address, flags);
583}

References map().

Referenced by MaxOS::system::CPU::init_cores().

◆ 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 960 of file physical.cpp.

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

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 869 of file physical.cpp.

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

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 493 of file physical.cpp.

493 {
494
495 // Map using the kernel's pml4 table
496 return map(physical_address, virtual_address, flags, m_pml4_root_address);
497}

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 508 of file physical.cpp.

508 {
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}
static bool in_higher_region(uintptr_t virtual_address)
Checks if a virtual address is in the higher region.
Definition physical.cpp:960
@ GLOBAL
The page can be shared between processes.
Definition physical.h:52
@ USER
This page is accessible from user mode.
Definition physical.h:46

References MaxOS::memory::GLOBAL, 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 535 of file physical.cpp.

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

References allocate_frame(), and map().

Referenced by MaxOS::memory::VirtualMemoryManager::allocate(), identity_map(), MaxOS::hardwarecommunication::IOAPIC::IOAPIC(), MaxOS::memory::VirtualMemoryManager::load_range_from_process(), 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 565 of file physical.cpp.

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

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 549 of file physical.cpp.

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

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

Referenced by MaxOS::console::FramebufferConsole::FramebufferConsole().

◆ 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 743 of file physical.cpp.

743 {
744
745 return m_memory_size;
746}

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

◆ memory_used()

uint64_t PhysicalMemoryManager::memory_used ( ) const

Gets the memory currently used.

Returns
The memory size in bytes

Definition at line 753 of file physical.cpp.

753 {
754
755 return m_used_frames * PAGE_SIZE;
756}

References MaxOS::memory::PAGE_SIZE.

Referenced by PhysicalMemoryManager(), and MaxOS::processes::Process::~Process().

◆ 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 733 of file physical.cpp.

733 {
734
735 return m_pml4_root_address;
736}

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

◆ reserve() [1/2]

void PhysicalMemoryManager::reserve ( uint64_t  address)

Reserves a physical address.

Parameters
addressThe address to reserve

Definition at line 774 of file physical.cpp.

774 {
775
776 reserve(address, PAGE_SIZE);
777}
void reserve(uint64_t address)
Reserves a physical address.
Definition physical.cpp:774

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

Referenced by MaxOS::console::FramebufferConsole::FramebufferConsole(), 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 786 of file physical.cpp.

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

References align_direct_to_page(), align_up_to_page(), MaxOS::Logger::DEBUG(), MaxOS::memory::PAGE_SIZE, and MaxOS::memory::ROW_BITS.

◆ 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 89 of file physical.cpp.

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

References multiboot_mmap_entry::addr, MaxOS::system::Multiboot::end_address, 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, MaxOS::system::Multiboot::start_tag(), to_higher_region(), and to_lower_region().

Referenced by PhysicalMemoryManager().

◆ size_to_frames()

size_t PhysicalMemoryManager::size_to_frames ( size_t  size)
static

Converts a size to the number of frames.

Parameters
sizeThe size to convert
Returns
The number of frames to fully cover the region (min 1 if size > 0)

Definition at line 144 of file physical.cpp.

144 {
145
146 return align_to_page(size) / PAGE_SIZE;
147}
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

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

Referenced by MaxOS::memory::VirtualMemoryManager::allocate(), allocate_area(), MaxOS::console::FramebufferConsole::FramebufferConsole(), free_area(), MaxOS::memory::VirtualMemoryManager::load_physical_into_address_space(), map_area(), map_area(), MaxOS::memory::VirtualMemoryManager::unload_range_from_process(), unmap_area(), and MaxOS::memory::VirtualMemoryManager::~VirtualMemoryManager().

◆ 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 929 of file physical.cpp.

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

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

Referenced by allocate_frame(), MaxOS::console::FramebufferConsole::FramebufferConsole(), MaxOS::processes::GlobalScheduler::load_multiboot_elfs(), MaxOS::processes::GlobalScheduler::prepare_initrd(), MaxOS::console::FramebufferConsole::print_logo(), 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 882 of file physical.cpp.

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

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 914 of file physical.cpp.

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

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 898 of file physical.cpp.

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

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 590 of file physical.cpp.

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

References unmap().

Referenced by MaxOS::memory::VirtualMemoryManager::allocate(), MaxOS::memory::VirtualMemoryManager::unload_range_from_process(), 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 602 of file physical.cpp.

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

◆ 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 624 of file physical.cpp.

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

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 969 of file physical.cpp.

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

References p4_table.

Referenced by PhysicalMemoryManager().

Member Data Documentation

◆ s_current_manager


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