125 lines
3.4 KiB
C
125 lines
3.4 KiB
C
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include "vmm.h"
|
|
#include "hal/hal.h"
|
|
#include "bootinfo/bootinfo.h"
|
|
#include "pmm/pmm.h"
|
|
#include "paging.h"
|
|
#include "proc/proc.h"
|
|
#include "kprintf.h"
|
|
#include "spinlock/spinlock.h"
|
|
|
|
PgTable *KERNEL_CR3 = NULL;
|
|
SpinLock spinlock;
|
|
|
|
PgTable *hal_vmm_current_cr3(void) {
|
|
PgTable *cr3;
|
|
asm volatile("mov %%cr3, %0" : "=r"(cr3));
|
|
return cr3;
|
|
}
|
|
|
|
PgIndex hal_vmm_pageindex(uint64_t vaddr) {
|
|
PgIndex ret;
|
|
|
|
ret.pml4 = (vaddr >> 39) & 0x1ff;
|
|
ret.pml3 = (vaddr >> 30) & 0x1ff;
|
|
ret.pml2 = (vaddr >> 21) & 0x1ff;
|
|
ret.pml1 = (vaddr >> 12) & 0x1ff;
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint64_t *hal_vmm_nexttable(uint64_t *table, uint64_t ent) {
|
|
uint8_t *addr;
|
|
|
|
if (table[ent] & HAL_PG_PRESENT) {
|
|
addr = (uint8_t *)(table[ent] & ~((uint64_t)0xfff));
|
|
} else {
|
|
addr = pmm_alloc(1);
|
|
hal_memset(BOOT_INFO.hhdm_off + addr, 0, HAL_PAGE_SIZE);
|
|
table[ent] = (uint64_t)addr | HAL_PG_USER | HAL_PG_RW | HAL_PG_PRESENT;
|
|
}
|
|
|
|
return (uint64_t *)(BOOT_INFO.hhdm_off + addr);
|
|
}
|
|
|
|
void hal_vmm_map_page(PgTable *pml4, uint64_t virtaddr, uint64_t physaddr, uint32_t flags) {
|
|
PgIndex pi = hal_vmm_pageindex(virtaddr);
|
|
|
|
uint64_t *pml3 = hal_vmm_nexttable((uint64_t *)pml4, pi.pml4);
|
|
uint64_t *pml2 = hal_vmm_nexttable((uint64_t *)pml3, pi.pml3);
|
|
uint64_t *pml1 = hal_vmm_nexttable((uint64_t *)pml2, pi.pml2);
|
|
uint64_t *pte = &pml1[pi.pml1];
|
|
|
|
*pte = (physaddr & ~0xFFF) | (flags & 0x7);
|
|
}
|
|
|
|
void hal_vmm_unmap_page(PgTable *pml4, uint64_t virtaddr, uint64_t physaddr) {
|
|
PgIndex pi = hal_vmm_pageindex(virtaddr);
|
|
|
|
uint64_t *pml3 = hal_vmm_nexttable((uint64_t *)pml4, pi.pml4);
|
|
uint64_t *pml2 = hal_vmm_nexttable((uint64_t *)pml3, pi.pml3);
|
|
uint64_t *pml1 = hal_vmm_nexttable((uint64_t *)pml2, pi.pml2);
|
|
uint64_t *pte = &pml1[pi.pml1];
|
|
|
|
*pte &= ~HAL_PG_PRESENT;
|
|
}
|
|
|
|
void hal_vmm_map_range(PgTable *cr3, void *virtstart, void *physstart, size_t size, uint32_t flags) {
|
|
if (size % HAL_PAGE_SIZE != 0 || (uint64_t)virtstart % HAL_PAGE_SIZE != 0 || (uint64_t)physstart % HAL_PG_PRESENT != 0) {
|
|
return;
|
|
}
|
|
|
|
spinlock_acquire(&spinlock);
|
|
uint8_t *vaddr = virtstart, *paddr = physstart;
|
|
|
|
for (; vaddr <= ((uint8_t *)virtstart + size); vaddr += HAL_PAGE_SIZE, paddr += HAL_PAGE_SIZE) {
|
|
hal_vmm_map_page(cr3, (uint64_t)vaddr, (uint64_t)paddr, flags);
|
|
}
|
|
spinlock_release(&spinlock);
|
|
}
|
|
|
|
void hal_vmm_unmap_range(PgTable *cr3, void *virtstart, void *physstart, size_t size) {
|
|
if (size % HAL_PAGE_SIZE != 0 || (uint64_t)virtstart % HAL_PAGE_SIZE != 0 || (uint64_t)physstart % HAL_PG_PRESENT != 0) {
|
|
return;
|
|
}
|
|
|
|
spinlock_acquire(&spinlock);
|
|
uint8_t *vaddr = virtstart, *paddr = physstart;
|
|
|
|
for (; vaddr <= ((uint8_t *)virtstart + size); vaddr += HAL_PAGE_SIZE, paddr += HAL_PAGE_SIZE) {
|
|
hal_vmm_unmap_page(cr3, (uint64_t)vaddr, (uint64_t)paddr);
|
|
}
|
|
spinlock_release(&spinlock);
|
|
}
|
|
|
|
void hal_vmm_map_kern(PgTable *cr3) {
|
|
PgTable *kcr3 = BOOT_INFO.hhdm_off + KERNEL_CR3;
|
|
for (size_t i = 256; i < 512; i++) {
|
|
cr3->ents[i] = kcr3->ents[i];
|
|
}
|
|
}
|
|
|
|
void hal_vmm_switch_pd(PgTable *cr3) {
|
|
hal_loadpd(cr3);
|
|
}
|
|
|
|
PgTable *hal_vmm_userproc_pml4(Proc *proc) {
|
|
uint8_t *cr3 = pmm_alloc(1);
|
|
PgTable *pml4 = (PgTable *)VIRT(cr3);
|
|
hal_memset(pml4, 0, HAL_PAGE_SIZE);
|
|
|
|
PgTable *kcr3 = VIRT(KERNEL_CR3);
|
|
|
|
for (size_t i = 256; i < 512; i++) {
|
|
pml4->ents[i] = kcr3->ents[i];
|
|
}
|
|
|
|
return (PgTable *)cr3;
|
|
}
|
|
|
|
void hal_vmm_init(void) {
|
|
spinlock_init(&spinlock);
|
|
KERNEL_CR3 = hal_vmm_current_cr3();
|
|
}
|