19 #include <boot/multiboot.h> 22 #define PAGE_SIZE (ENTRIES * sizeof(page_directory_entry_t)) 24 #define MEMORY_SIZE 0x100000000 25 #define PAGE_NUMBER (MEMORY_SIZE / PAGE_SIZE) 37 uint16_t page_offset : 12;
39 uint16_t page_table : 10;
40 } __attribute__((packed)) bits;
50 .end = (
void*) 0x3FFFFFFF};
74 logln(
"VMM",
"Creating page directory at %08x", dir_phys);
76 memset(dir, 0, PAGE_SIZE);
91 logln(
"VMM",
"Destroying page directory at %08x", dir_phys);
117 memcpy((
void*) ((uintptr_t) dir + offset),
131 logln(
"VMM",
"Loading page directory at %08x", new_directory);
151 println(
"VMM: Already modifying a page directory at %08x",
old_directory);
166 println(
"VMM: Not yet modifying a page directory");
217 return (uintptr_t) vaddr >= (uintptr_t) domain->
start &&
218 (uintptr_t) vaddr <= (uintptr_t) domain->
end;
238 if (domain_check_enabled &&
240 println(
"%4aVMM: Domain mismatch%a");
258 if (!dir_entry->
pr) {
261 dir_entry->
pr = dir_entry->
rw = dir_entry->
user = 1;
264 memset(tab, 0, PAGE_SIZE);
268 println(
"%4aVMM: %08x is already mapped%a", vaddr);
272 tab_entry->
rw = !!(flags & VMM_WRITABLE);
273 tab_entry->
user = flags & VMM_USER;
298 if (page_table[i].pr)
300 if (i == ENTRIES - 1)
319 pages =
pmm_get_page(vaddr, len - 1) - virtual_page + 1;
320 logln(
"VMM", map ?
"Map virtual %08x-%08x (page %05x-%05x) " 321 "to physical %08x-%08x (page %05x-%05x)" :
322 "Unmap virtual %08x-%08x (page %05x-%05x)",
323 vaddr, vaddr + len - 1, virtual_page, virtual_page + pages - 1,
324 paddr, paddr + len - 1, physical_page, physical_page + pages - 1);
326 for (
int i = 0; i < pages; i++)
330 for (
int i = 0; i < pages; i++)
342 if (len == 0)
return;
353 if (len == 0)
return;
379 log(
"VMM",
"Page directory at %08x (physical %08x):",
382 for (
int i = 0; i <
ENTRIES; i++) {
387 for (
int j = 0; j <
ENTRIES; j++)
388 if (page_table[j].pr) {
389 uint32_t vpage = i * ENTRIES + j, ppage = page_table[j].
page;
391 logln(0,
""), log(
"VMM",
"");
392 log(0, vpage == ppage ?
"%s%05x to itself" :
"%s%05x to %05x",
393 logged % 8 ?
", " :
"", vpage, ppage);
408 if (len == 0)
return 0;
409 uint32_t pages = len / PAGE_SIZE + (len % PAGE_SIZE ? 1 : 0),
417 if (free_pages >= pages)
420 println(
"%4aVMM: Not enough memory%a");
430 return flags & VMM_USER ? PMM_USER : PMM_KERNEL;
485 vmm_use(vaddr, paddr, len, flags);
516 if (!paddr || !vaddr)
529 if (len == 0)
return;
540 domain_check_enabled = enable;
545 print(
"VMM init ... ");
554 vmm_map(addr, addr, VMM_KERNEL);
570 io_use_video_memory();
static uint32_t highest_kernel_page
remember the highest kernel page
page_directory_t * vmm_create_page_directory()
Creates an empty page directory.
void mmu_load_page_directory(page_directory_t *page_directory)
Loads a page directory into the CR3 register.
uint8_t isr_enable_interrupts(uint8_t enable)
Enables or disables interrupts.
static uint8_t domain_check_enabled
whether domain checking is performed
void * vmm_use_virtual_memory(void *vaddr, size_t len, vmm_flags_t flags)
Marks some page(s) as used and maps them into memory.
void vmm_enable_domain_check(uint8_t enable)
Enables or disables domain checking.
#define PAGE_SIZE
The number of bytes per page directory "happens" to equal the size of a page.
void pmm_free(void *ptr, size_t len)
Frees page frames.
uint8_t user
whether user space may access this page
#define ENTRIES
number of entries in page directories and tables
void vmm_unmap_range(void *vaddr, size_t len)
Unmaps the given page(s) from memory.
uint8_t rw
whether these pages should be writable
void mmu_flush_tlb(void *vaddr)
Flushes the Translation Lookaside Buffer for the given page.
static page_directory_t * page_directory
the current page directory
static uint8_t vmm_is_in_domain(void *vaddr, vmm_domain_t *domain)
Returns whether a virtual address belongs to a given domain.
void vmm_modified_page_directory()
Ends a page directory modification.
static uint8_t vmm_domain_check(void *vaddr, vmm_flags_t flags)
Checks whether a virtual address might be accessed with the given flags.
#define VMM_PAGETAB(i)
the address of a page table from the active page directory
void * end
end address of the domain
static page_table_entry_t * vmm_get_page_table(page_directory_entry_t *dir_entry, vmm_virtual_address_t vaddr)
Returns a virtual or physical address to a page table in memory.
void * vmm_alloc(size_t len, vmm_flags_t flags)
Marks some page(s) as used and maps them somewhere into memory.
uint8_t mmu_get_paging()
Returns whether paging is enabled or disabled.
static page_directory_t * old_directory
for temporary modifications
uint16_t page_table
index in the page directory
void vmm_map_range(void *vaddr, void *paddr, size_t len, vmm_flags_t flags)
Maps the given page(s) into memory.
An entry in a page table.
uint32_t page
where this page is located (4KiB aligned!)
uint32_t pmm_get_page(void *ptr, uint32_t offset)
Returns to which page a given memory address belongs.
static page_table_entry_t * vmm_get_page_table_entry(page_directory_entry_t *dir_entry, vmm_virtual_address_t vaddr)
Returns a virtual or physical address to a page table entry in memory.
void * vmm_map_physical_memory(void *paddr, size_t len, vmm_flags_t flags)
If necessary, maps the given page(s) somewhere into memory.
static vmm_domain_t * vmm_get_domain_from_address(void *vaddr)
Returns the domain a virtual address belongs to.
struct vmm_virtual_address_t::@11 bits
bit field
static void * vmm_find_free(size_t len, vmm_domain_t *domain)
Finds unmapped pages.
pmm_flags_t pmm_check(void *ptr)
Returns whether a page frame is used or unused.
static uint8_t old_interrupts
for temporary modifications
page_directory_t * vmm_load_page_directory(page_directory_t *new_directory)
Loads a new page directory.
void vmm_unmap(void *_vaddr)
Unmaps the given page from memory.
void * start
start address of the domain
pmm_flags_t
information on who uses a page frame (needs to fit in TYPE_BITS)
void vmm_init()
Initializes the VMM.
void pmm_use(void *ptr, size_t len, pmm_flags_t flags, char *tag)
Marks page frames for a given memory range as used or unused.
vmm_flags_t
Whether we are working with kernel or user memory.
void vmm_free(void *vaddr, size_t len)
Frees the given page(s) and unmaps them from memory.
void vmm_use(void *vaddr, void *paddr, size_t len, vmm_flags_t flags)
Marks the given page(s) as used and maps them into memory.
static void vmm_refresh_page_directory(page_directory_t *dir_phys)
Refreshes the page directory entries that are shared across page directories.
uint8_t user
whether user space may access these pages
static vmm_domain_t * vmm_get_domain(vmm_flags_t flags)
Extracts a domain from the given flags.
void vmm_destroy_page_directory(page_directory_t *dir_phys)
Destroys a page directory.
uint16_t page_offset
location in the page
static vmm_domain_t kernel_domain
We use 0-1GiB as kernel memory.
An entry in a page directory.
void * vmm_get_physical_address(void *_vaddr)
Translates a virtual address into a physical address.
void vmm_unmap_physical_memory(void *vaddr, size_t len)
If necessary, unmaps the given page(s) from memory.
void * pmm_alloc(size_t len, pmm_flags_t flags)
Allocates page frames.
uint8_t rw
whether this page should be writable
static void vmm_destroy_page_table(uint16_t page_table)
Destroys a page table in the current page directory.
uint8_t vmm_map(void *_vaddr, void *paddr, vmm_flags_t flags)
Maps the given page into memory.
uint8_t pr
whether this page is present in virtual memory
static vmm_domain_t user_domain
The memory 1GiB-4GiB is process-specific.
void vmm_modify_page_directory(page_directory_t *new_directory)
Loads a page directory for temporary modification.
uint8_t pr
whether this page table is present in virtual memory
uint32_t pmm_get_highest_kernel_page()
Returns the highest page used by the kernel.
uint16_t page
index in the page table
void vmm_dump()
Dumps the current page directory.
static pmm_flags_t vmm_get_pmm_flags(vmm_flags_t flags)
Translates VMM into PMM flags.
uint32_t pt
where this page table is located (4KiB aligned!)
void * pmm_get_address(uint32_t page, uint32_t offset)
Returns a memory address belonging to a given page.
void * vmm_use_physical_memory(void *paddr, size_t len, vmm_flags_t flags)
Marks the given page(s) as used and maps them somewhere into memory.
static void vmm_map_range_detailed(void *vaddr, void *paddr, size_t len, vmm_flags_t flags, uint8_t map)
Maps or unmaps the given page(s) into memory.
void mmu_init()
Initializes the MMU.
We use two domains, kernel and user memory.
#define VMM_PAGEDIR
the active page directory's address
void mmu_enable_paging(page_directory_t *page_directory)
Loads a page directory and enables paging.