mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-18 19:57:31 +00:00
hv: mmu: replace dynamic memory allocation in memory
Replace dynamic memory allocation in memory management with static memory allocation. Since the static memory allocation can guarantee the allocation never failed, so split_large_page and construct_pgentry don't need to return a errno any more. Besides, the destroy_ept don't need to free page any more. Instead, it would memset the eptp to 0 to make sure we can't walk this paging table again. Tracked-On: #861 Signed-off-by: Li, Fei1 <fei1.li@intel.com>
This commit is contained in:
parent
9c7c0de08f
commit
0391f84c83
@ -222,7 +222,7 @@ config HV_RAM_START
|
|||||||
|
|
||||||
config HV_RAM_SIZE
|
config HV_RAM_SIZE
|
||||||
hex "Size of the RAM region used by the hypervisor"
|
hex "Size of the RAM region used by the hypervisor"
|
||||||
default 0x04000000
|
default 0x06000000
|
||||||
help
|
help
|
||||||
A 64-bit integer indicating the size of RAM used by the hypervisor.
|
A 64-bit integer indicating the size of RAM used by the hypervisor.
|
||||||
It is ensured at link time that the footprint of the hypervisor
|
It is ensured at link time that the footprint of the hypervisor
|
||||||
|
@ -10,55 +10,18 @@
|
|||||||
|
|
||||||
#define ACRN_DBG_EPT 6U
|
#define ACRN_DBG_EPT 6U
|
||||||
|
|
||||||
/**
|
|
||||||
* @pre pml4_addr != NULL
|
|
||||||
*/
|
|
||||||
void free_ept_mem(uint64_t *pml4_page)
|
|
||||||
{
|
|
||||||
uint64_t *pdpt_page, *pd_page, *pt_page;
|
|
||||||
uint64_t *pml4e, *pdpte, *pde;
|
|
||||||
uint64_t pml4e_idx, pdpte_idx, pde_idx;
|
|
||||||
|
|
||||||
for (pml4e_idx = 0U; pml4e_idx < PTRS_PER_PML4E; pml4e_idx++) {
|
|
||||||
pml4e = pml4_page + pml4e_idx;
|
|
||||||
if (pgentry_present(PTT_EPT, *pml4e) == 0UL) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pdpt_page = pml4e_page_vaddr(*pml4e);
|
|
||||||
|
|
||||||
for (pdpte_idx = 0U; pdpte_idx < PTRS_PER_PDPTE; pdpte_idx++) {
|
|
||||||
pdpte = pdpt_page + pdpte_idx;
|
|
||||||
if ((pgentry_present(PTT_EPT, *pdpte) == 0UL) ||
|
|
||||||
pdpte_large(*pdpte) != 0UL) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pd_page = pdpte_page_vaddr(*pdpte);
|
|
||||||
|
|
||||||
for (pde_idx = 0U; pde_idx < PTRS_PER_PDE; pde_idx++) {
|
|
||||||
pde = pd_page + pde_idx;
|
|
||||||
if ((pgentry_present(PTT_EPT, *pde) == 0UL) ||
|
|
||||||
pde_large(*pde) != 0UL) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pt_page = pde_page_vaddr(*pde);
|
|
||||||
|
|
||||||
/* Free page table entry table */
|
|
||||||
free_paging_struct((void *)pt_page);
|
|
||||||
}
|
|
||||||
/* Free page directory entry table */
|
|
||||||
free_paging_struct((void *)pd_page);
|
|
||||||
}
|
|
||||||
free_paging_struct((void *)pdpt_page);
|
|
||||||
}
|
|
||||||
free_paging_struct((void *)pml4_page);
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy_ept(struct vm *vm)
|
void destroy_ept(struct vm *vm)
|
||||||
{
|
{
|
||||||
|
/* Destroy secure world */
|
||||||
|
if (vm->sworld_control.flag.active != 0UL) {
|
||||||
|
destroy_secure_world(vm, true);
|
||||||
|
}
|
||||||
|
|
||||||
if (vm->arch_vm.nworld_eptp != NULL) {
|
if (vm->arch_vm.nworld_eptp != NULL) {
|
||||||
free_ept_mem((uint64_t *)vm->arch_vm.nworld_eptp);
|
(void)memset(vm->arch_vm.nworld_eptp, 0U, CPU_PAGE_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* using return value INVALID_HPA as error code */
|
/* using return value INVALID_HPA as error code */
|
||||||
uint64_t local_gpa2hpa(struct vm *vm, uint64_t gpa, uint32_t *size)
|
uint64_t local_gpa2hpa(struct vm *vm, uint64_t gpa, uint32_t *size)
|
||||||
{
|
{
|
||||||
@ -73,7 +36,7 @@ uint64_t local_gpa2hpa(struct vm *vm, uint64_t gpa, uint32_t *size)
|
|||||||
eptp = vm->arch_vm.nworld_eptp;
|
eptp = vm->arch_vm.nworld_eptp;
|
||||||
}
|
}
|
||||||
|
|
||||||
pgentry = lookup_address((uint64_t *)eptp, gpa, &pg_size, PTT_EPT);
|
pgentry = lookup_address((uint64_t *)eptp, gpa, &pg_size, &vm->arch_vm.ept_mem_ops);
|
||||||
if (pgentry != NULL) {
|
if (pgentry != NULL) {
|
||||||
hpa = ((*pgentry & (~(pg_size - 1UL)))
|
hpa = ((*pgentry & (~(pg_size - 1UL)))
|
||||||
| (gpa & (pg_size - 1UL)));
|
| (gpa & (pg_size - 1UL)));
|
||||||
@ -222,9 +185,8 @@ void ept_mr_add(struct vm *vm, uint64_t *pml4_page,
|
|||||||
struct vcpu *vcpu;
|
struct vcpu *vcpu;
|
||||||
uint64_t prot = prot_orig;
|
uint64_t prot = prot_orig;
|
||||||
|
|
||||||
dev_dbg(ACRN_DBG_EPT, "%s, vm[%d] hpa: 0x%016llx gpa: 0x%016llx ",
|
dev_dbg(ACRN_DBG_EPT, "%s, vm[%d] hpa: 0x%016llx gpa: 0x%016llx size: 0x%016llx prot: 0x%016x\n",
|
||||||
__func__, vm->vm_id, hpa, gpa);
|
__func__, vm->vm_id, hpa, gpa, size, prot);
|
||||||
dev_dbg(ACRN_DBG_EPT, "size: 0x%016llx prot: 0x%016x\n", size, prot);
|
|
||||||
|
|
||||||
/* EPT & VT-d share the same page tables, set SNP bit
|
/* EPT & VT-d share the same page tables, set SNP bit
|
||||||
* to force snooping of PCIe devices if the page
|
* to force snooping of PCIe devices if the page
|
||||||
@ -234,7 +196,7 @@ void ept_mr_add(struct vm *vm, uint64_t *pml4_page,
|
|||||||
prot |= EPT_SNOOP_CTRL;
|
prot |= EPT_SNOOP_CTRL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mmu_add(pml4_page, hpa, gpa, size, prot, PTT_EPT);
|
mmu_add(pml4_page, hpa, gpa, size, prot, &vm->arch_vm.ept_mem_ops);
|
||||||
|
|
||||||
foreach_vcpu(i, vm, vcpu) {
|
foreach_vcpu(i, vm, vcpu) {
|
||||||
vcpu_make_request(vcpu, ACRN_REQUEST_EPT_FLUSH);
|
vcpu_make_request(vcpu, ACRN_REQUEST_EPT_FLUSH);
|
||||||
@ -248,8 +210,9 @@ void ept_mr_modify(struct vm *vm, uint64_t *pml4_page,
|
|||||||
struct vcpu *vcpu;
|
struct vcpu *vcpu;
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
|
|
||||||
mmu_modify_or_del(pml4_page, gpa, size,
|
dev_dbg(ACRN_DBG_EPT, "%s,vm[%d] gpa 0x%llx size 0x%llx\n", __func__, vm->vm_id, gpa, size);
|
||||||
prot_set, prot_clr, PTT_EPT, MR_MODIFY);
|
|
||||||
|
mmu_modify_or_del(pml4_page, gpa, size, prot_set, prot_clr, &vm->arch_vm.ept_mem_ops, MR_MODIFY);
|
||||||
|
|
||||||
foreach_vcpu(i, vm, vcpu) {
|
foreach_vcpu(i, vm, vcpu) {
|
||||||
vcpu_make_request(vcpu, ACRN_REQUEST_EPT_FLUSH);
|
vcpu_make_request(vcpu, ACRN_REQUEST_EPT_FLUSH);
|
||||||
@ -258,17 +221,14 @@ void ept_mr_modify(struct vm *vm, uint64_t *pml4_page,
|
|||||||
/**
|
/**
|
||||||
* @pre [gpa,gpa+size) has been mapped into host physical memory region
|
* @pre [gpa,gpa+size) has been mapped into host physical memory region
|
||||||
*/
|
*/
|
||||||
void ept_mr_del(struct vm *vm, uint64_t *pml4_page,
|
void ept_mr_del(struct vm *vm, uint64_t *pml4_page, uint64_t gpa, uint64_t size)
|
||||||
uint64_t gpa, uint64_t size)
|
|
||||||
{
|
{
|
||||||
struct vcpu *vcpu;
|
struct vcpu *vcpu;
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
|
|
||||||
dev_dbg(ACRN_DBG_EPT, "%s,vm[%d] gpa 0x%llx size 0x%llx\n",
|
dev_dbg(ACRN_DBG_EPT, "%s,vm[%d] gpa 0x%llx size 0x%llx\n", __func__, vm->vm_id, gpa, size);
|
||||||
__func__, vm->vm_id, gpa, size);
|
|
||||||
|
|
||||||
mmu_modify_or_del(pml4_page, gpa, size,
|
mmu_modify_or_del(pml4_page, gpa, size, 0UL, 0UL, &vm->arch_vm.ept_mem_ops, MR_DEL);
|
||||||
0UL, 0UL, PTT_EPT, MR_DEL);
|
|
||||||
|
|
||||||
foreach_vcpu(i, vm, vcpu) {
|
foreach_vcpu(i, vm, vcpu) {
|
||||||
vcpu_make_request(vcpu, ACRN_REQUEST_EPT_FLUSH);
|
vcpu_make_request(vcpu, ACRN_REQUEST_EPT_FLUSH);
|
||||||
|
@ -619,6 +619,10 @@ int prepare_vm0_memmap_and_e820(struct vm *vm)
|
|||||||
"vm0: bottom memory - 0x%llx, top memory - 0x%llx\n",
|
"vm0: bottom memory - 0x%llx, top memory - 0x%llx\n",
|
||||||
e820_mem.mem_bottom, e820_mem.mem_top);
|
e820_mem.mem_bottom, e820_mem.mem_top);
|
||||||
|
|
||||||
|
if (e820_mem.mem_top > EPT_ADDRESS_SPACE(CONFIG_SOS_RAM_SIZE)) {
|
||||||
|
panic("Please configure VM0_ADDRESS_SPACE correctly!\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* create real ept map for all ranges with UC */
|
/* create real ept map for all ranges with UC */
|
||||||
ept_mr_add(vm, pml4_page,
|
ept_mr_add(vm, pml4_page,
|
||||||
e820_mem.mem_bottom, e820_mem.mem_bottom,
|
e820_mem.mem_bottom, e820_mem.mem_bottom,
|
||||||
|
@ -87,12 +87,8 @@ int create_vm(struct vm_description *vm_desc, struct vm **rtn_vm)
|
|||||||
/* gpa_lowtop are used for system start up */
|
/* gpa_lowtop are used for system start up */
|
||||||
vm->hw.gpa_lowtop = 0UL;
|
vm->hw.gpa_lowtop = 0UL;
|
||||||
|
|
||||||
vm->arch_vm.nworld_eptp = alloc_paging_struct();
|
init_ept_mem_ops(vm);
|
||||||
if (vm->arch_vm.nworld_eptp == NULL) {
|
vm->arch_vm.nworld_eptp = vm->arch_vm.ept_mem_ops.get_pml4_page(vm->arch_vm.ept_mem_ops.info, 0UL);
|
||||||
pr_fatal("%s, alloc memory for EPTP failed\n", __func__);
|
|
||||||
status = -ENOMEM;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
sanitize_pte((uint64_t *)vm->arch_vm.nworld_eptp);
|
sanitize_pte((uint64_t *)vm->arch_vm.nworld_eptp);
|
||||||
|
|
||||||
/* Only for SOS: Configure VM software information */
|
/* Only for SOS: Configure VM software information */
|
||||||
@ -180,7 +176,7 @@ err:
|
|||||||
vioapic_cleanup(vm_ioapic(vm));
|
vioapic_cleanup(vm_ioapic(vm));
|
||||||
|
|
||||||
if (vm->arch_vm.nworld_eptp != NULL) {
|
if (vm->arch_vm.nworld_eptp != NULL) {
|
||||||
free(vm->arch_vm.nworld_eptp);
|
(void)memset(vm->arch_vm.nworld_eptp, 0U, CPU_PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -212,10 +208,6 @@ int shutdown_vm(struct vm *vm)
|
|||||||
/* cleanup vioapic */
|
/* cleanup vioapic */
|
||||||
vioapic_cleanup(vm_ioapic(vm));
|
vioapic_cleanup(vm_ioapic(vm));
|
||||||
|
|
||||||
/* Destroy secure world */
|
|
||||||
if (vm->sworld_control.flag.active != 0UL) {
|
|
||||||
destroy_secure_world(vm, true);
|
|
||||||
}
|
|
||||||
/* Free EPT allocated resources assigned to VM */
|
/* Free EPT allocated resources assigned to VM */
|
||||||
destroy_ept(vm);
|
destroy_ept(vm);
|
||||||
|
|
||||||
|
@ -238,39 +238,57 @@ void init_paging(void)
|
|||||||
struct e820_entry *entry;
|
struct e820_entry *entry;
|
||||||
uint64_t hv_hpa;
|
uint64_t hv_hpa;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
uint64_t low32_max_ram = 0UL;
|
||||||
|
uint64_t high64_max_ram;
|
||||||
uint64_t attr_uc = (PAGE_TABLE | PAGE_CACHE_UC);
|
uint64_t attr_uc = (PAGE_TABLE | PAGE_CACHE_UC);
|
||||||
|
|
||||||
pr_dbg("HV MMU Initialization");
|
pr_dbg("HV MMU Initialization");
|
||||||
|
|
||||||
/* Allocate memory for Hypervisor PML4 table */
|
/* Allocate memory for Hypervisor PML4 table */
|
||||||
mmu_pml4_addr = alloc_paging_struct();
|
mmu_pml4_addr = ppt_mem_ops.get_pml4_page(ppt_mem_ops.info, 0UL);
|
||||||
|
|
||||||
init_e820();
|
init_e820();
|
||||||
obtain_e820_mem_info();
|
obtain_e820_mem_info();
|
||||||
|
|
||||||
|
/* align to 2MB */
|
||||||
|
high64_max_ram = (e820_mem.mem_top + PDE_SIZE - 1UL) & PDE_MASK;
|
||||||
|
|
||||||
|
if (high64_max_ram > (CONFIG_PLATFORM_RAM_SIZE + PLATFORM_LO_MMIO_SIZE) ||
|
||||||
|
high64_max_ram < (1UL << 32U)) {
|
||||||
|
panic("Please configure HV_ADDRESS_SPACE correctly!\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* Map all memory regions to UC attribute */
|
/* Map all memory regions to UC attribute */
|
||||||
mmu_add((uint64_t *)mmu_pml4_addr, e820_mem.mem_bottom,
|
mmu_add((uint64_t *)mmu_pml4_addr, e820_mem.mem_bottom, e820_mem.mem_bottom,
|
||||||
e820_mem.mem_bottom, e820_mem.mem_top - e820_mem.mem_bottom,
|
high64_max_ram - e820_mem.mem_bottom, attr_uc, &ppt_mem_ops);
|
||||||
attr_uc, PTT_PRIMARY);
|
|
||||||
|
|
||||||
/* Modify WB attribute for E820_TYPE_RAM */
|
/* Modify WB attribute for E820_TYPE_RAM */
|
||||||
for (i = 0U; i < e820_entries; i++) {
|
for (i = 0U; i < e820_entries; i++) {
|
||||||
entry = &e820[i];
|
entry = &e820[i];
|
||||||
if (entry->type == E820_TYPE_RAM) {
|
if (entry->type == E820_TYPE_RAM) {
|
||||||
mmu_modify_or_del((uint64_t *)mmu_pml4_addr,
|
if (entry->baseaddr < (1UL << 32U)) {
|
||||||
entry->baseaddr, entry->length,
|
uint64_t end = entry->baseaddr + entry->length;
|
||||||
PAGE_CACHE_WB, PAGE_CACHE_MASK,
|
if (end < (1UL << 32U) && (end > low32_max_ram)) {
|
||||||
PTT_PRIMARY, MR_MODIFY);
|
low32_max_ram = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mmu_modify_or_del((uint64_t *)mmu_pml4_addr, 0UL, (low32_max_ram + PDE_SIZE - 1UL) & PDE_MASK,
|
||||||
|
PAGE_CACHE_WB, PAGE_CACHE_MASK, &ppt_mem_ops, MR_MODIFY);
|
||||||
|
|
||||||
|
mmu_modify_or_del((uint64_t *)mmu_pml4_addr, (1UL << 32U), high64_max_ram - (1UL << 32U),
|
||||||
|
PAGE_CACHE_WB, PAGE_CACHE_MASK, &ppt_mem_ops, MR_MODIFY);
|
||||||
|
|
||||||
/* set the paging-structure entries' U/S flag
|
/* set the paging-structure entries' U/S flag
|
||||||
* to supervisor-mode for hypervisor owned memroy.
|
* to supervisor-mode for hypervisor owned memroy.
|
||||||
*/
|
*/
|
||||||
hv_hpa = get_hv_image_base();
|
hv_hpa = get_hv_image_base();
|
||||||
mmu_modify_or_del((uint64_t *)mmu_pml4_addr, hv_hpa, CONFIG_HV_RAM_SIZE,
|
mmu_modify_or_del((uint64_t *)mmu_pml4_addr, hv_hpa & PDE_MASK,
|
||||||
|
CONFIG_HV_RAM_SIZE + ((hv_hpa & (PDE_SIZE - 1UL)) != 0UL) ? PDE_SIZE : 0UL,
|
||||||
PAGE_CACHE_WB, PAGE_CACHE_MASK | PAGE_USER,
|
PAGE_CACHE_WB, PAGE_CACHE_MASK | PAGE_USER,
|
||||||
PTT_PRIMARY, MR_MODIFY);
|
&ppt_mem_ops, MR_MODIFY);
|
||||||
|
|
||||||
/* Enable paging */
|
/* Enable paging */
|
||||||
enable_paging(hva2hpa(mmu_pml4_addr));
|
enable_paging(hva2hpa(mmu_pml4_addr));
|
||||||
|
@ -5,11 +5,6 @@
|
|||||||
*/
|
*/
|
||||||
#include <hypervisor.h>
|
#include <hypervisor.h>
|
||||||
|
|
||||||
#define PML4_PAGE_NUM(size) 1UL
|
|
||||||
#define PDPT_PAGE_NUM(size) (((size) + PML4E_SIZE - 1UL) >> PML4E_SHIFT)
|
|
||||||
#define PD_PAGE_NUM(size) (((size) + PDPTE_SIZE - 1UL) >> PDPTE_SHIFT)
|
|
||||||
#define PT_PAGE_NUM(size) (((size) + PDE_SIZE - 1UL) >> PDE_SHIFT)
|
|
||||||
|
|
||||||
#define DEFINE_PGTABLE_PAGE(prefix, lvl, LVL, size) \
|
#define DEFINE_PGTABLE_PAGE(prefix, lvl, LVL, size) \
|
||||||
static struct page prefix ## lvl ## _pages[LVL ## _PAGE_NUM(size)]
|
static struct page prefix ## lvl ## _pages[LVL ## _PAGE_NUM(size)]
|
||||||
|
|
||||||
@ -66,8 +61,6 @@ const struct memory_ops ppt_mem_ops = {
|
|||||||
.get_pd_page = ppt_get_pd_page,
|
.get_pd_page = ppt_get_pd_page,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The size of the guest physical address space, covered by the EPT page table of a VM */
|
|
||||||
#define EPT_ADDRESS_SPACE(size) ((size != 0UL) ? (size + PLATFORM_LO_MMIO_SIZE) : 0UL)
|
|
||||||
DEFINE_PGTABLE_PAGE(vm0_, pml4, PML4, EPT_ADDRESS_SPACE(CONFIG_SOS_RAM_SIZE));
|
DEFINE_PGTABLE_PAGE(vm0_, pml4, PML4, EPT_ADDRESS_SPACE(CONFIG_SOS_RAM_SIZE));
|
||||||
DEFINE_PGTABLE_PAGE(vm0_, pdpt, PDPT, EPT_ADDRESS_SPACE(CONFIG_SOS_RAM_SIZE));
|
DEFINE_PGTABLE_PAGE(vm0_, pdpt, PDPT, EPT_ADDRESS_SPACE(CONFIG_SOS_RAM_SIZE));
|
||||||
DEFINE_PGTABLE_PAGE(vm0_, pd, PD, EPT_ADDRESS_SPACE(CONFIG_SOS_RAM_SIZE));
|
DEFINE_PGTABLE_PAGE(vm0_, pd, PD, EPT_ADDRESS_SPACE(CONFIG_SOS_RAM_SIZE));
|
||||||
@ -79,13 +72,6 @@ static struct page uos_nworld_pdpt_pages[CONFIG_MAX_VM_NUM - 1U][PDPT_PAGE_NUM(E
|
|||||||
static struct page uos_nworld_pd_pages[CONFIG_MAX_VM_NUM - 1U][PD_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))];
|
static struct page uos_nworld_pd_pages[CONFIG_MAX_VM_NUM - 1U][PD_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))];
|
||||||
static struct page uos_nworld_pt_pages[CONFIG_MAX_VM_NUM - 1U][PT_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))];
|
static struct page uos_nworld_pt_pages[CONFIG_MAX_VM_NUM - 1U][PT_PAGE_NUM(EPT_ADDRESS_SPACE(CONFIG_UOS_RAM_SIZE))];
|
||||||
|
|
||||||
#define TRUSTY_PML4_PAGE_NUM(size) (1UL)
|
|
||||||
#define TRUSTY_PDPT_PAGE_NUM(size) (1UL)
|
|
||||||
#define TRUSTY_PD_PAGE_NUM(size) (PD_PAGE_NUM(size))
|
|
||||||
#define TRUSTY_PT_PAGE_NUM(size) (PT_PAGE_NUM(size))
|
|
||||||
#define TRUSTY_PGTABLE_PAGE_NUM(size) \
|
|
||||||
(TRUSTY_PML4_PAGE_NUM(size) + TRUSTY_PDPT_PAGE_NUM(size) + TRUSTY_PD_PAGE_NUM(size) + TRUSTY_PT_PAGE_NUM(size))
|
|
||||||
|
|
||||||
static struct page uos_sworld_pgtable_pages[CONFIG_MAX_VM_NUM - 1U][TRUSTY_PGTABLE_PAGE_NUM(TRUSTY_RAM_SIZE)];
|
static struct page uos_sworld_pgtable_pages[CONFIG_MAX_VM_NUM - 1U][TRUSTY_PGTABLE_PAGE_NUM(TRUSTY_RAM_SIZE)];
|
||||||
|
|
||||||
/* ept: extended page table*/
|
/* ept: extended page table*/
|
||||||
|
@ -10,11 +10,9 @@
|
|||||||
/*
|
/*
|
||||||
* Split a large page table into next level page table.
|
* Split a large page table into next level page table.
|
||||||
*/
|
*/
|
||||||
static int split_large_page(uint64_t *pte,
|
static void split_large_page(uint64_t *pte, enum _page_table_level level,
|
||||||
enum _page_table_level level,
|
uint64_t vaddr, const struct memory_ops *mem_ops)
|
||||||
enum _page_table_type ptt)
|
|
||||||
{
|
{
|
||||||
int ret = -EINVAL;
|
|
||||||
uint64_t *pbase;
|
uint64_t *pbase;
|
||||||
uint64_t ref_paddr, paddr, paddrinc;
|
uint64_t ref_paddr, paddr, paddrinc;
|
||||||
uint64_t i, ref_prot;
|
uint64_t i, ref_prot;
|
||||||
@ -24,23 +22,20 @@ static int split_large_page(uint64_t *pte,
|
|||||||
ref_paddr = (*pte) & PDPTE_PFN_MASK;
|
ref_paddr = (*pte) & PDPTE_PFN_MASK;
|
||||||
paddrinc = PDE_SIZE;
|
paddrinc = PDE_SIZE;
|
||||||
ref_prot = (*pte) & ~PDPTE_PFN_MASK;
|
ref_prot = (*pte) & ~PDPTE_PFN_MASK;
|
||||||
|
pbase = (uint64_t *)mem_ops->get_pd_page(mem_ops->info, vaddr);
|
||||||
break;
|
break;
|
||||||
case IA32E_PD:
|
case IA32E_PD:
|
||||||
ref_paddr = (*pte) & PDE_PFN_MASK;
|
ref_paddr = (*pte) & PDE_PFN_MASK;
|
||||||
paddrinc = PTE_SIZE;
|
paddrinc = PTE_SIZE;
|
||||||
ref_prot = (*pte) & ~PDE_PFN_MASK;
|
ref_prot = (*pte) & ~PDE_PFN_MASK;
|
||||||
ref_prot &= ~PAGE_PSE;
|
ref_prot &= ~PAGE_PSE;
|
||||||
|
pbase = (uint64_t *)mem_ops->get_pt_page(mem_ops->info, vaddr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return ret;
|
panic("invalid paging table level: %d", level);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(ACRN_DBG_MMU, "%s, paddr: 0x%llx\n", __func__, ref_paddr);
|
dev_dbg(ACRN_DBG_MMU, "%s, paddr: 0x%llx, pbase: 0x%llx\n", __func__, ref_paddr, pbase);
|
||||||
|
|
||||||
pbase = (uint64_t *)alloc_paging_struct();
|
|
||||||
if (pbase == NULL) {
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
paddr = ref_paddr;
|
paddr = ref_paddr;
|
||||||
for (i = 0UL; i < PTRS_PER_PTE; i++) {
|
for (i = 0UL; i < PTRS_PER_PTE; i++) {
|
||||||
@ -48,12 +43,10 @@ static int split_large_page(uint64_t *pte,
|
|||||||
paddr += paddrinc;
|
paddr += paddrinc;
|
||||||
}
|
}
|
||||||
|
|
||||||
ref_prot = (ptt == PTT_PRIMARY) ? PAGE_TABLE : EPT_RWX;
|
ref_prot = mem_ops->get_default_access_right();
|
||||||
set_pgentry(pte, hva2hpa((void *)pbase) | ref_prot);
|
set_pgentry(pte, hva2hpa((void *)pbase) | ref_prot);
|
||||||
|
|
||||||
/* TODO: flush the TLB */
|
/* TODO: flush the TLB */
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void local_modify_or_del_pte(uint64_t *pte,
|
static inline void local_modify_or_del_pte(uint64_t *pte,
|
||||||
@ -72,19 +65,11 @@ static inline void local_modify_or_del_pte(uint64_t *pte,
|
|||||||
/*
|
/*
|
||||||
* pgentry may means pml4e/pdpte/pde
|
* pgentry may means pml4e/pdpte/pde
|
||||||
*/
|
*/
|
||||||
static inline int construct_pgentry(enum _page_table_type ptt, uint64_t *pde)
|
static inline void construct_pgentry(uint64_t *pde, void *pd_page, uint64_t prot)
|
||||||
{
|
{
|
||||||
uint64_t prot;
|
|
||||||
void *pd_page = alloc_paging_struct();
|
|
||||||
if (pd_page == NULL) {
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
sanitize_pte((uint64_t *)pd_page);
|
sanitize_pte((uint64_t *)pd_page);
|
||||||
|
|
||||||
prot = (ptt == PTT_PRIMARY) ? PAGE_TABLE: EPT_RWX;
|
|
||||||
set_pgentry(pde, hva2hpa(pd_page) | prot);
|
set_pgentry(pde, hva2hpa(pd_page) | prot);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -94,21 +79,18 @@ static inline int construct_pgentry(enum _page_table_type ptt, uint64_t *pde)
|
|||||||
* type: MR_DEL
|
* type: MR_DEL
|
||||||
* delete [vaddr_start, vaddr_end) MT PT mapping
|
* delete [vaddr_start, vaddr_end) MT PT mapping
|
||||||
*/
|
*/
|
||||||
static void modify_or_del_pte(const uint64_t *pde,
|
static void modify_or_del_pte(const uint64_t *pde, uint64_t vaddr_start, uint64_t vaddr_end,
|
||||||
uint64_t vaddr_start, uint64_t vaddr_end,
|
uint64_t prot_set, uint64_t prot_clr, const struct memory_ops *mem_ops, uint32_t type)
|
||||||
uint64_t prot_set, uint64_t prot_clr,
|
|
||||||
enum _page_table_type ptt, uint32_t type)
|
|
||||||
{
|
{
|
||||||
uint64_t *pt_page = pde_page_vaddr(*pde);
|
uint64_t *pt_page = pde_page_vaddr(*pde);
|
||||||
uint64_t vaddr = vaddr_start;
|
uint64_t vaddr = vaddr_start;
|
||||||
uint64_t index = pte_index(vaddr);
|
uint64_t index = pte_index(vaddr);
|
||||||
|
|
||||||
dev_dbg(ACRN_DBG_MMU, "%s, vaddr: [0x%llx - 0x%llx]\n",
|
dev_dbg(ACRN_DBG_MMU, "%s, vaddr: [0x%llx - 0x%llx]\n", __func__, vaddr, vaddr_end);
|
||||||
__func__, vaddr, vaddr_end);
|
|
||||||
for (; index < PTRS_PER_PTE; index++) {
|
for (; index < PTRS_PER_PTE; index++) {
|
||||||
uint64_t *pte = pt_page + index;
|
uint64_t *pte = pt_page + index;
|
||||||
|
|
||||||
if (pgentry_present(ptt, *pte) == 0UL) {
|
if (mem_ops->pgentry_present(*pte) == 0UL) {
|
||||||
panic("invalid op, pte not present");
|
panic("invalid op, pte not present");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,34 +109,26 @@ static void modify_or_del_pte(const uint64_t *pde,
|
|||||||
* type: MR_DEL
|
* type: MR_DEL
|
||||||
* delete [vaddr_start, vaddr_end) MT PT mapping
|
* delete [vaddr_start, vaddr_end) MT PT mapping
|
||||||
*/
|
*/
|
||||||
static void modify_or_del_pde(const uint64_t *pdpte,
|
static void modify_or_del_pde(const uint64_t *pdpte, uint64_t vaddr_start, uint64_t vaddr_end,
|
||||||
uint64_t vaddr_start, uint64_t vaddr_end,
|
uint64_t prot_set, uint64_t prot_clr, const struct memory_ops *mem_ops, uint32_t type)
|
||||||
uint64_t prot_set, uint64_t prot_clr,
|
|
||||||
enum _page_table_type ptt, uint32_t type)
|
|
||||||
{
|
{
|
||||||
uint64_t *pd_page = pdpte_page_vaddr(*pdpte);
|
uint64_t *pd_page = pdpte_page_vaddr(*pdpte);
|
||||||
uint64_t vaddr = vaddr_start;
|
uint64_t vaddr = vaddr_start;
|
||||||
uint64_t index = pde_index(vaddr);
|
uint64_t index = pde_index(vaddr);
|
||||||
|
|
||||||
dev_dbg(ACRN_DBG_MMU, "%s, vaddr: [0x%llx - 0x%llx]\n",
|
dev_dbg(ACRN_DBG_MMU, "%s, vaddr: [0x%llx - 0x%llx]\n", __func__, vaddr, vaddr_end);
|
||||||
__func__, vaddr, vaddr_end);
|
|
||||||
for (; index < PTRS_PER_PDE; index++) {
|
for (; index < PTRS_PER_PDE; index++) {
|
||||||
uint64_t *pde = pd_page + index;
|
uint64_t *pde = pd_page + index;
|
||||||
uint64_t vaddr_next = (vaddr & PDE_MASK) + PDE_SIZE;
|
uint64_t vaddr_next = (vaddr & PDE_MASK) + PDE_SIZE;
|
||||||
|
|
||||||
if (pgentry_present(ptt, *pde) == 0UL) {
|
if (mem_ops->pgentry_present(*pde) == 0UL) {
|
||||||
panic("invalid op, pde not present");
|
panic("invalid op, pde not present");
|
||||||
}
|
}
|
||||||
if (pde_large(*pde) != 0UL) {
|
if (pde_large(*pde) != 0UL) {
|
||||||
if (vaddr_next > vaddr_end ||
|
if (vaddr_next > vaddr_end || !mem_aligned_check(vaddr, PDE_SIZE)) {
|
||||||
!mem_aligned_check(vaddr, PDE_SIZE)) {
|
split_large_page(pde, IA32E_PD, vaddr, mem_ops);
|
||||||
int ret = split_large_page(pde, IA32E_PD, ptt);
|
|
||||||
if (ret != 0) {
|
|
||||||
panic("split large PDE failed");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
local_modify_or_del_pte(pde,
|
local_modify_or_del_pte(pde, prot_set, prot_clr, type);
|
||||||
prot_set, prot_clr, type);
|
|
||||||
if (vaddr_next < vaddr_end) {
|
if (vaddr_next < vaddr_end) {
|
||||||
vaddr = vaddr_next;
|
vaddr = vaddr_next;
|
||||||
continue;
|
continue;
|
||||||
@ -162,8 +136,7 @@ static void modify_or_del_pde(const uint64_t *pdpte,
|
|||||||
break; /* done */
|
break; /* done */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
modify_or_del_pte(pde, vaddr, vaddr_end,
|
modify_or_del_pte(pde, vaddr, vaddr_end, prot_set, prot_clr, mem_ops, type);
|
||||||
prot_set, prot_clr, ptt, type);
|
|
||||||
if (vaddr_next >= vaddr_end) {
|
if (vaddr_next >= vaddr_end) {
|
||||||
break; /* done */
|
break; /* done */
|
||||||
}
|
}
|
||||||
@ -178,34 +151,27 @@ static void modify_or_del_pde(const uint64_t *pdpte,
|
|||||||
* type: MR_DEL
|
* type: MR_DEL
|
||||||
* delete [vaddr_start, vaddr_end) MT PT mapping
|
* delete [vaddr_start, vaddr_end) MT PT mapping
|
||||||
*/
|
*/
|
||||||
static void modify_or_del_pdpte(const uint64_t *pml4e,
|
static void modify_or_del_pdpte(const uint64_t *pml4e, uint64_t vaddr_start, uint64_t vaddr_end,
|
||||||
uint64_t vaddr_start, uint64_t vaddr_end,
|
uint64_t prot_set, uint64_t prot_clr, const struct memory_ops *mem_ops, uint32_t type)
|
||||||
uint64_t prot_set, uint64_t prot_clr,
|
|
||||||
enum _page_table_type ptt, uint32_t type)
|
|
||||||
{
|
{
|
||||||
uint64_t *pdpt_page = pml4e_page_vaddr(*pml4e);
|
uint64_t *pdpt_page = pml4e_page_vaddr(*pml4e);
|
||||||
uint64_t vaddr = vaddr_start;
|
uint64_t vaddr = vaddr_start;
|
||||||
uint64_t index = pdpte_index(vaddr);
|
uint64_t index = pdpte_index(vaddr);
|
||||||
|
|
||||||
dev_dbg(ACRN_DBG_MMU, "%s, vaddr: [0x%llx - 0x%llx]\n",
|
dev_dbg(ACRN_DBG_MMU, "%s, vaddr: [0x%llx - 0x%llx]\n", __func__, vaddr, vaddr_end);
|
||||||
__func__, vaddr, vaddr_end);
|
|
||||||
for (; index < PTRS_PER_PDPTE; index++) {
|
for (; index < PTRS_PER_PDPTE; index++) {
|
||||||
uint64_t *pdpte = pdpt_page + index;
|
uint64_t *pdpte = pdpt_page + index;
|
||||||
uint64_t vaddr_next = (vaddr & PDPTE_MASK) + PDPTE_SIZE;
|
uint64_t vaddr_next = (vaddr & PDPTE_MASK) + PDPTE_SIZE;
|
||||||
|
|
||||||
if (pgentry_present(ptt, *pdpte) == 0UL) {
|
if (mem_ops->pgentry_present(*pdpte) == 0UL) {
|
||||||
panic("invalid op, pdpte not present");
|
panic("invalid op, pdpte not present");
|
||||||
}
|
}
|
||||||
if (pdpte_large(*pdpte) != 0UL) {
|
if (pdpte_large(*pdpte) != 0UL) {
|
||||||
if (vaddr_next > vaddr_end ||
|
if (vaddr_next > vaddr_end ||
|
||||||
!mem_aligned_check(vaddr, PDPTE_SIZE)) {
|
!mem_aligned_check(vaddr, PDPTE_SIZE)) {
|
||||||
int ret = split_large_page(pdpte, IA32E_PDPT, ptt);
|
split_large_page(pdpte, IA32E_PDPT, vaddr, mem_ops);
|
||||||
if (ret != 0) {
|
|
||||||
panic("split large PDPTE failed");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
local_modify_or_del_pte(pdpte,
|
local_modify_or_del_pte(pdpte, prot_set, prot_clr, type);
|
||||||
prot_set, prot_clr, type);
|
|
||||||
if (vaddr_next < vaddr_end) {
|
if (vaddr_next < vaddr_end) {
|
||||||
vaddr = vaddr_next;
|
vaddr = vaddr_next;
|
||||||
continue;
|
continue;
|
||||||
@ -213,8 +179,7 @@ static void modify_or_del_pdpte(const uint64_t *pml4e,
|
|||||||
break; /* done */
|
break; /* done */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
modify_or_del_pde(pdpte, vaddr, vaddr_end,
|
modify_or_del_pde(pdpte, vaddr, vaddr_end, prot_set, prot_clr, mem_ops, type);
|
||||||
prot_set, prot_clr, ptt, type);
|
|
||||||
if (vaddr_next >= vaddr_end) {
|
if (vaddr_next >= vaddr_end) {
|
||||||
break; /* done */
|
break; /* done */
|
||||||
}
|
}
|
||||||
@ -235,10 +200,8 @@ static void modify_or_del_pdpte(const uint64_t *pml4e,
|
|||||||
* type: MR_DEL
|
* type: MR_DEL
|
||||||
* delete [vaddr_base, vaddr_base + size ) memory region page table mapping.
|
* delete [vaddr_base, vaddr_base + size ) memory region page table mapping.
|
||||||
*/
|
*/
|
||||||
void mmu_modify_or_del(uint64_t *pml4_page,
|
void mmu_modify_or_del(uint64_t *pml4_page, uint64_t vaddr_base, uint64_t size,
|
||||||
uint64_t vaddr_base, uint64_t size,
|
uint64_t prot_set, uint64_t prot_clr, const struct memory_ops *mem_ops, uint32_t type)
|
||||||
uint64_t prot_set, uint64_t prot_clr,
|
|
||||||
enum _page_table_type ptt, uint32_t type)
|
|
||||||
{
|
{
|
||||||
uint64_t vaddr = round_page_up(vaddr_base);
|
uint64_t vaddr = round_page_up(vaddr_base);
|
||||||
uint64_t vaddr_next, vaddr_end;
|
uint64_t vaddr_next, vaddr_end;
|
||||||
@ -251,11 +214,10 @@ void mmu_modify_or_del(uint64_t *pml4_page,
|
|||||||
while (vaddr < vaddr_end) {
|
while (vaddr < vaddr_end) {
|
||||||
vaddr_next = (vaddr & PML4E_MASK) + PML4E_SIZE;
|
vaddr_next = (vaddr & PML4E_MASK) + PML4E_SIZE;
|
||||||
pml4e = pml4e_offset(pml4_page, vaddr);
|
pml4e = pml4e_offset(pml4_page, vaddr);
|
||||||
if (pgentry_present(ptt, *pml4e) == 0UL) {
|
if (mem_ops->pgentry_present(*pml4e) == 0UL) {
|
||||||
panic("invalid op, pml4e not present");
|
panic("invalid op, pml4e not present");
|
||||||
}
|
}
|
||||||
modify_or_del_pdpte(pml4e, vaddr, vaddr_end,
|
modify_or_del_pdpte(pml4e, vaddr, vaddr_end, prot_set, prot_clr, mem_ops, type);
|
||||||
prot_set, prot_clr, ptt, type);
|
|
||||||
vaddr = vaddr_next;
|
vaddr = vaddr_next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -264,9 +226,8 @@ void mmu_modify_or_del(uint64_t *pml4_page,
|
|||||||
* In PT level,
|
* In PT level,
|
||||||
* add [vaddr_start, vaddr_end) to [paddr_base, ...) MT PT mapping
|
* add [vaddr_start, vaddr_end) to [paddr_base, ...) MT PT mapping
|
||||||
*/
|
*/
|
||||||
static void add_pte(const uint64_t *pde, uint64_t paddr_start,
|
static void add_pte(const uint64_t *pde, uint64_t paddr_start, uint64_t vaddr_start, uint64_t vaddr_end,
|
||||||
uint64_t vaddr_start, uint64_t vaddr_end,
|
uint64_t prot, const struct memory_ops *mem_ops)
|
||||||
uint64_t prot, enum _page_table_type ptt)
|
|
||||||
{
|
{
|
||||||
uint64_t *pt_page = pde_page_vaddr(*pde);
|
uint64_t *pt_page = pde_page_vaddr(*pde);
|
||||||
uint64_t vaddr = vaddr_start;
|
uint64_t vaddr = vaddr_start;
|
||||||
@ -278,7 +239,7 @@ static void add_pte(const uint64_t *pde, uint64_t paddr_start,
|
|||||||
for (; index < PTRS_PER_PTE; index++) {
|
for (; index < PTRS_PER_PTE; index++) {
|
||||||
uint64_t *pte = pt_page + index;
|
uint64_t *pte = pt_page + index;
|
||||||
|
|
||||||
if (pgentry_present(ptt, *pte) != 0UL) {
|
if (mem_ops->pgentry_present(*pte) != 0UL) {
|
||||||
panic("invalid op, pte present");
|
panic("invalid op, pte present");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,9 +257,8 @@ static void add_pte(const uint64_t *pde, uint64_t paddr_start,
|
|||||||
* In PD level,
|
* In PD level,
|
||||||
* add [vaddr_start, vaddr_end) to [paddr_base, ...) MT PT mapping
|
* add [vaddr_start, vaddr_end) to [paddr_base, ...) MT PT mapping
|
||||||
*/
|
*/
|
||||||
static void add_pde(const uint64_t *pdpte, uint64_t paddr_start,
|
static void add_pde(const uint64_t *pdpte, uint64_t paddr_start, uint64_t vaddr_start, uint64_t vaddr_end,
|
||||||
uint64_t vaddr_start, uint64_t vaddr_end,
|
uint64_t prot, const struct memory_ops *mem_ops)
|
||||||
uint64_t prot, enum _page_table_type ptt)
|
|
||||||
{
|
{
|
||||||
uint64_t *pd_page = pdpte_page_vaddr(*pdpte);
|
uint64_t *pd_page = pdpte_page_vaddr(*pdpte);
|
||||||
uint64_t vaddr = vaddr_start;
|
uint64_t vaddr = vaddr_start;
|
||||||
@ -311,7 +271,7 @@ static void add_pde(const uint64_t *pdpte, uint64_t paddr_start,
|
|||||||
uint64_t *pde = pd_page + index;
|
uint64_t *pde = pd_page + index;
|
||||||
uint64_t vaddr_next = (vaddr & PDE_MASK) + PDE_SIZE;
|
uint64_t vaddr_next = (vaddr & PDE_MASK) + PDE_SIZE;
|
||||||
|
|
||||||
if (pgentry_present(ptt, *pde) == 0UL) {
|
if (mem_ops->pgentry_present(*pde) == 0UL) {
|
||||||
if (mem_aligned_check(paddr, PDE_SIZE) &&
|
if (mem_aligned_check(paddr, PDE_SIZE) &&
|
||||||
mem_aligned_check(vaddr, PDE_SIZE) &&
|
mem_aligned_check(vaddr, PDE_SIZE) &&
|
||||||
(vaddr_next <= vaddr_end)) {
|
(vaddr_next <= vaddr_end)) {
|
||||||
@ -323,13 +283,11 @@ static void add_pde(const uint64_t *pdpte, uint64_t paddr_start,
|
|||||||
}
|
}
|
||||||
break; /* done */
|
break; /* done */
|
||||||
} else {
|
} else {
|
||||||
int ret = construct_pgentry(ptt, pde);
|
void *pt_page = mem_ops->get_pt_page(mem_ops->info, vaddr);
|
||||||
if (ret != 0) {
|
construct_pgentry(pde, pt_page, mem_ops->get_default_access_right());
|
||||||
panic("construct pde page table fail");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
add_pte(pde, paddr, vaddr, vaddr_end, prot, ptt);
|
add_pte(pde, paddr, vaddr, vaddr_end, prot, mem_ops);
|
||||||
if (vaddr_next >= vaddr_end) {
|
if (vaddr_next >= vaddr_end) {
|
||||||
break; /* done */
|
break; /* done */
|
||||||
}
|
}
|
||||||
@ -342,22 +300,20 @@ static void add_pde(const uint64_t *pdpte, uint64_t paddr_start,
|
|||||||
* In PDPT level,
|
* In PDPT level,
|
||||||
* add [vaddr_start, vaddr_end) to [paddr_base, ...) MT PT mapping
|
* add [vaddr_start, vaddr_end) to [paddr_base, ...) MT PT mapping
|
||||||
*/
|
*/
|
||||||
static void add_pdpte(const uint64_t *pml4e, uint64_t paddr_start,
|
static void add_pdpte(const uint64_t *pml4e, uint64_t paddr_start, uint64_t vaddr_start, uint64_t vaddr_end,
|
||||||
uint64_t vaddr_start, uint64_t vaddr_end,
|
uint64_t prot, const struct memory_ops *mem_ops)
|
||||||
uint64_t prot, enum _page_table_type ptt)
|
|
||||||
{
|
{
|
||||||
uint64_t *pdpt_page = pml4e_page_vaddr(*pml4e);
|
uint64_t *pdpt_page = pml4e_page_vaddr(*pml4e);
|
||||||
uint64_t vaddr = vaddr_start;
|
uint64_t vaddr = vaddr_start;
|
||||||
uint64_t paddr = paddr_start;
|
uint64_t paddr = paddr_start;
|
||||||
uint64_t index = pdpte_index(vaddr);
|
uint64_t index = pdpte_index(vaddr);
|
||||||
|
|
||||||
dev_dbg(ACRN_DBG_MMU, "%s, paddr: 0x%llx, vaddr: [0x%llx - 0x%llx]\n",
|
dev_dbg(ACRN_DBG_MMU, "%s, paddr: 0x%llx, vaddr: [0x%llx - 0x%llx]\n", __func__, paddr, vaddr, vaddr_end);
|
||||||
__func__, paddr, vaddr, vaddr_end);
|
|
||||||
for (; index < PTRS_PER_PDPTE; index++) {
|
for (; index < PTRS_PER_PDPTE; index++) {
|
||||||
uint64_t *pdpte = pdpt_page + index;
|
uint64_t *pdpte = pdpt_page + index;
|
||||||
uint64_t vaddr_next = (vaddr & PDPTE_MASK) + PDPTE_SIZE;
|
uint64_t vaddr_next = (vaddr & PDPTE_MASK) + PDPTE_SIZE;
|
||||||
|
|
||||||
if (pgentry_present(ptt, *pdpte) == 0UL) {
|
if (mem_ops->pgentry_present(*pdpte) == 0UL) {
|
||||||
if (mem_aligned_check(paddr, PDPTE_SIZE) &&
|
if (mem_aligned_check(paddr, PDPTE_SIZE) &&
|
||||||
mem_aligned_check(vaddr, PDPTE_SIZE) &&
|
mem_aligned_check(vaddr, PDPTE_SIZE) &&
|
||||||
(vaddr_next <= vaddr_end)) {
|
(vaddr_next <= vaddr_end)) {
|
||||||
@ -369,13 +325,11 @@ static void add_pdpte(const uint64_t *pml4e, uint64_t paddr_start,
|
|||||||
}
|
}
|
||||||
break; /* done */
|
break; /* done */
|
||||||
} else {
|
} else {
|
||||||
int ret = construct_pgentry(ptt, pdpte);
|
void *pd_page = mem_ops->get_pd_page(mem_ops->info, vaddr);
|
||||||
if (ret != 0) {
|
construct_pgentry(pdpte, pd_page, mem_ops->get_default_access_right());
|
||||||
panic("construct pdpte page table fail");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
add_pde(pdpte, paddr, vaddr, vaddr_end, prot, ptt);
|
add_pde(pdpte, paddr, vaddr, vaddr_end, prot, mem_ops);
|
||||||
if (vaddr_next >= vaddr_end) {
|
if (vaddr_next >= vaddr_end) {
|
||||||
break; /* done */
|
break; /* done */
|
||||||
}
|
}
|
||||||
@ -389,16 +343,14 @@ static void add_pdpte(const uint64_t *pml4e, uint64_t paddr_start,
|
|||||||
* add [vaddr_base, vaddr_base + size ) memory region page table mapping.
|
* add [vaddr_base, vaddr_base + size ) memory region page table mapping.
|
||||||
* @pre: the prot should set before call this function.
|
* @pre: the prot should set before call this function.
|
||||||
*/
|
*/
|
||||||
void mmu_add(uint64_t *pml4_page, uint64_t paddr_base,
|
void mmu_add(uint64_t *pml4_page, uint64_t paddr_base, uint64_t vaddr_base, uint64_t size, uint64_t prot,
|
||||||
uint64_t vaddr_base, uint64_t size,
|
const struct memory_ops *mem_ops)
|
||||||
uint64_t prot, enum _page_table_type ptt)
|
|
||||||
{
|
{
|
||||||
uint64_t vaddr, vaddr_next, vaddr_end;
|
uint64_t vaddr, vaddr_next, vaddr_end;
|
||||||
uint64_t paddr;
|
uint64_t paddr;
|
||||||
uint64_t *pml4e;
|
uint64_t *pml4e;
|
||||||
|
|
||||||
dev_dbg(ACRN_DBG_MMU, "%s, paddr 0x%llx, vaddr 0x%llx, size 0x%llx\n",
|
dev_dbg(ACRN_DBG_MMU, "%s, paddr 0x%llx, vaddr 0x%llx, size 0x%llx\n", __func__, paddr_base, vaddr_base, size);
|
||||||
__func__, paddr_base, vaddr_base, size);
|
|
||||||
|
|
||||||
/* align address to page size*/
|
/* align address to page size*/
|
||||||
vaddr = round_page_up(vaddr_base);
|
vaddr = round_page_up(vaddr_base);
|
||||||
@ -408,13 +360,11 @@ void mmu_add(uint64_t *pml4_page, uint64_t paddr_base,
|
|||||||
while (vaddr < vaddr_end) {
|
while (vaddr < vaddr_end) {
|
||||||
vaddr_next = (vaddr & PML4E_MASK) + PML4E_SIZE;
|
vaddr_next = (vaddr & PML4E_MASK) + PML4E_SIZE;
|
||||||
pml4e = pml4e_offset(pml4_page, vaddr);
|
pml4e = pml4e_offset(pml4_page, vaddr);
|
||||||
if (pgentry_present(ptt, *pml4e) == 0UL) {
|
if (mem_ops->pgentry_present(*pml4e) == 0UL) {
|
||||||
int ret = construct_pgentry(ptt, pml4e);
|
void *pdpt_page = mem_ops->get_pdpt_page(mem_ops->info, vaddr);
|
||||||
if (ret != 0) {
|
construct_pgentry(pml4e, pdpt_page, mem_ops->get_default_access_right());
|
||||||
panic("construct pml4e page table fail");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
add_pdpte(pml4e, paddr, vaddr, vaddr_end, prot, ptt);
|
add_pdpte(pml4e, paddr, vaddr, vaddr_end, prot, mem_ops);
|
||||||
|
|
||||||
paddr += (vaddr_next - vaddr);
|
paddr += (vaddr_next - vaddr);
|
||||||
vaddr = vaddr_next;
|
vaddr = vaddr_next;
|
||||||
@ -424,18 +374,17 @@ void mmu_add(uint64_t *pml4_page, uint64_t paddr_base,
|
|||||||
/**
|
/**
|
||||||
* @pre (pml4_page != NULL) && (pg_size != NULL)
|
* @pre (pml4_page != NULL) && (pg_size != NULL)
|
||||||
*/
|
*/
|
||||||
uint64_t *lookup_address(uint64_t *pml4_page,
|
uint64_t *lookup_address(uint64_t *pml4_page, uint64_t addr, uint64_t *pg_size, const struct memory_ops *mem_ops)
|
||||||
uint64_t addr, uint64_t *pg_size, enum _page_table_type ptt)
|
|
||||||
{
|
{
|
||||||
uint64_t *pml4e, *pdpte, *pde, *pte;
|
uint64_t *pml4e, *pdpte, *pde, *pte;
|
||||||
|
|
||||||
pml4e = pml4e_offset(pml4_page, addr);
|
pml4e = pml4e_offset(pml4_page, addr);
|
||||||
if (pgentry_present(ptt, *pml4e) == 0UL) {
|
if (mem_ops->pgentry_present(*pml4e) == 0UL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pdpte = pdpte_offset(pml4e, addr);
|
pdpte = pdpte_offset(pml4e, addr);
|
||||||
if (pgentry_present(ptt, *pdpte) == 0UL) {
|
if (mem_ops->pgentry_present(*pdpte) == 0UL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (pdpte_large(*pdpte) != 0UL) {
|
} else if (pdpte_large(*pdpte) != 0UL) {
|
||||||
*pg_size = PDPTE_SIZE;
|
*pg_size = PDPTE_SIZE;
|
||||||
@ -443,7 +392,7 @@ uint64_t *lookup_address(uint64_t *pml4_page,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pde = pde_offset(pdpte, addr);
|
pde = pde_offset(pdpte, addr);
|
||||||
if (pgentry_present(ptt, *pde) == 0UL) {
|
if (mem_ops->pgentry_present(*pde) == 0UL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (pde_large(*pde) != 0UL) {
|
} else if (pde_large(*pde) != 0UL) {
|
||||||
*pg_size = PDE_SIZE;
|
*pg_size = PDE_SIZE;
|
||||||
@ -451,7 +400,7 @@ uint64_t *lookup_address(uint64_t *pml4_page,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pte = pte_offset(pde, addr);
|
pte = pte_offset(pde, addr);
|
||||||
if (pgentry_present(ptt, *pte) == 0UL) {
|
if (mem_ops->pgentry_present(*pte) == 0UL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
*pg_size = PTE_SIZE;
|
*pg_size = PTE_SIZE;
|
||||||
|
@ -97,14 +97,14 @@ static void create_secure_world_ept(struct vm *vm, uint64_t gpa_orig,
|
|||||||
* Normal World.PD/PT are shared in both Secure world's EPT
|
* Normal World.PD/PT are shared in both Secure world's EPT
|
||||||
* and Normal World's EPT
|
* and Normal World's EPT
|
||||||
*/
|
*/
|
||||||
pml4_base = alloc_paging_struct();
|
pml4_base = vm->arch_vm.ept_mem_ops.get_pml4_page(vm->arch_vm.ept_mem_ops.info, TRUSTY_EPT_REBASE_GPA);
|
||||||
vm->arch_vm.sworld_eptp = pml4_base;
|
vm->arch_vm.sworld_eptp = pml4_base;
|
||||||
sanitize_pte((uint64_t *)vm->arch_vm.sworld_eptp);
|
sanitize_pte((uint64_t *)vm->arch_vm.sworld_eptp);
|
||||||
|
|
||||||
/* The trusty memory is remapped to guest physical address
|
/* The trusty memory is remapped to guest physical address
|
||||||
* of gpa_rebased to gpa_rebased + size
|
* of gpa_rebased to gpa_rebased + size
|
||||||
*/
|
*/
|
||||||
sub_table_addr = alloc_paging_struct();
|
sub_table_addr = vm->arch_vm.ept_mem_ops.get_pdpt_page(vm->arch_vm.ept_mem_ops.info, TRUSTY_EPT_REBASE_GPA);
|
||||||
sworld_pml4e = hva2hpa(sub_table_addr) | table_present;
|
sworld_pml4e = hva2hpa(sub_table_addr) | table_present;
|
||||||
set_pgentry((uint64_t *)pml4_base, sworld_pml4e);
|
set_pgentry((uint64_t *)pml4_base, sworld_pml4e);
|
||||||
|
|
||||||
@ -148,8 +148,6 @@ static void create_secure_world_ept(struct vm *vm, uint64_t gpa_orig,
|
|||||||
|
|
||||||
void destroy_secure_world(struct vm *vm, bool need_clr_mem)
|
void destroy_secure_world(struct vm *vm, bool need_clr_mem)
|
||||||
{
|
{
|
||||||
uint64_t j;
|
|
||||||
void *pdpt_addr;
|
|
||||||
struct vm *vm0 = get_vm_from_vmid(0U);
|
struct vm *vm0 = get_vm_from_vmid(0U);
|
||||||
uint64_t hpa = vm->sworld_control.sworld_memory.base_hpa;
|
uint64_t hpa = vm->sworld_control.sworld_memory.base_hpa;
|
||||||
uint64_t gpa_sos = vm->sworld_control.sworld_memory.base_gpa_in_sos;
|
uint64_t gpa_sos = vm->sworld_control.sworld_memory.base_gpa_in_sos;
|
||||||
@ -174,14 +172,8 @@ void destroy_secure_world(struct vm *vm, bool need_clr_mem)
|
|||||||
ept_mr_add(vm, vm->arch_vm.nworld_eptp,
|
ept_mr_add(vm, vm->arch_vm.nworld_eptp,
|
||||||
hpa, gpa_uos, size, EPT_RWX | EPT_WB);
|
hpa, gpa_uos, size, EPT_RWX | EPT_WB);
|
||||||
|
|
||||||
/* Free trusty ept page-structures */
|
/* sanitize trusty ept page-structures */
|
||||||
pdpt_addr =
|
sanitize_pte((uint64_t *)vm->arch_vm.sworld_eptp);
|
||||||
(void *)pml4e_page_vaddr(*(uint64_t *)vm->arch_vm.sworld_eptp);
|
|
||||||
/* identical PDPTEs except trusty memory */
|
|
||||||
for (j = 0UL; j < NON_TRUSTY_PDPT_ENTRIES; j++) {
|
|
||||||
sanitize_pte_entry((uint64_t *)pdpt_addr + j);
|
|
||||||
}
|
|
||||||
free_ept_mem((uint64_t *)vm->arch_vm.sworld_eptp);
|
|
||||||
vm->arch_vm.sworld_eptp = NULL;
|
vm->arch_vm.sworld_eptp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +356,7 @@ int32_t hcall_notify_ioreq_finish(uint16_t vmid, uint16_t vcpu_id)
|
|||||||
static int32_t local_set_vm_memory_region(struct vm *vm,
|
static int32_t local_set_vm_memory_region(struct vm *vm,
|
||||||
struct vm *target_vm, const struct vm_memory_region *region)
|
struct vm *target_vm, const struct vm_memory_region *region)
|
||||||
{
|
{
|
||||||
uint64_t hpa, base_paddr;
|
uint64_t hpa, base_paddr, gpa_end;
|
||||||
uint64_t prot;
|
uint64_t prot;
|
||||||
uint64_t *pml4_page;
|
uint64_t *pml4_page;
|
||||||
|
|
||||||
@ -366,6 +366,14 @@ static int32_t local_set_vm_memory_region(struct vm *vm,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpa_end = region->gpa + region->size;
|
||||||
|
if ((gpa_end > vm->arch_vm.ept_mem_ops.info->ept.top_address_space) &&
|
||||||
|
(region->gpa < TRUSTY_EPT_REBASE_GPA)) {
|
||||||
|
pr_err("%s, invalid gpa: 0x%llx, size: 0x%llx, top_address_space: 0x%llx", __func__,
|
||||||
|
region->gpa, region->size, vm->arch_vm.ept_mem_ops.info->ept.top_address_space);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
dev_dbg(ACRN_DBG_HYCALL,
|
dev_dbg(ACRN_DBG_HYCALL,
|
||||||
"[vm%d] type=%d gpa=0x%x vm0_gpa=0x%x size=0x%x",
|
"[vm%d] type=%d gpa=0x%x vm0_gpa=0x%x size=0x%x",
|
||||||
target_vm->vm_id, region->type, region->gpa,
|
target_vm->vm_id, region->type, region->gpa,
|
||||||
|
@ -68,7 +68,7 @@ static int vdev_pt_init(struct pci_vdev *vdev)
|
|||||||
/* Create an iommu domain for target VM if not created */
|
/* Create an iommu domain for target VM if not created */
|
||||||
if (vm->iommu == NULL) {
|
if (vm->iommu == NULL) {
|
||||||
if (vm->arch_vm.nworld_eptp == 0UL) {
|
if (vm->arch_vm.nworld_eptp == 0UL) {
|
||||||
vm->arch_vm.nworld_eptp = alloc_paging_struct();
|
vm->arch_vm.nworld_eptp = vm->arch_vm.ept_mem_ops.get_pml4_page(vm->arch_vm.ept_mem_ops.info, 0UL);
|
||||||
sanitize_pte((uint64_t *)vm->arch_vm.nworld_eptp);
|
sanitize_pte((uint64_t *)vm->arch_vm.nworld_eptp);
|
||||||
}
|
}
|
||||||
vm->iommu = create_iommu_domain(vm->vm_id,
|
vm->iommu = create_iommu_domain(vm->vm_id,
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#ifndef ASSEMBLER
|
#ifndef ASSEMBLER
|
||||||
|
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
|
#include <page.h>
|
||||||
|
|
||||||
/* Define cache line size (in bytes) */
|
/* Define cache line size (in bytes) */
|
||||||
#define CACHE_LINE_SIZE 64U
|
#define CACHE_LINE_SIZE 64U
|
||||||
@ -53,11 +54,6 @@ static inline uint64_t round_page_down(uint64_t addr)
|
|||||||
return (addr & CPU_PAGE_MASK);
|
return (addr & CPU_PAGE_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum _page_table_type {
|
|
||||||
PTT_PRIMARY = 0, /* Mapping for hypervisor */
|
|
||||||
PTT_EPT = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Represent the 4 levels of translation tables in IA-32e paging mode */
|
/* Represent the 4 levels of translation tables in IA-32e paging mode */
|
||||||
enum _page_table_level {
|
enum _page_table_level {
|
||||||
IA32E_PML4 = 0,
|
IA32E_PML4 = 0,
|
||||||
@ -83,13 +79,10 @@ void free_paging_struct(void *ptr);
|
|||||||
void enable_paging(uint64_t pml4_base_addr);
|
void enable_paging(uint64_t pml4_base_addr);
|
||||||
void enable_smep(void);
|
void enable_smep(void);
|
||||||
void init_paging(void);
|
void init_paging(void);
|
||||||
void mmu_add(uint64_t *pml4_page, uint64_t paddr_base,
|
void mmu_add(uint64_t *pml4_page, uint64_t paddr_base, uint64_t vaddr_base,
|
||||||
uint64_t vaddr_base, uint64_t size,
|
uint64_t size, uint64_t prot, const struct memory_ops *mem_ops);
|
||||||
uint64_t prot, enum _page_table_type ptt);
|
void mmu_modify_or_del(uint64_t *pml4_page, uint64_t vaddr_base, uint64_t size,
|
||||||
void mmu_modify_or_del(uint64_t *pml4_page,
|
uint64_t prot_set, uint64_t prot_clr, const struct memory_ops *mem_ops, uint32_t type);
|
||||||
uint64_t vaddr_base, uint64_t size,
|
|
||||||
uint64_t prot_set, uint64_t prot_clr,
|
|
||||||
enum _page_table_type ptt, uint32_t type);
|
|
||||||
int check_vmx_mmu_cap(void);
|
int check_vmx_mmu_cap(void);
|
||||||
uint16_t allocate_vpid(void);
|
uint16_t allocate_vpid(void);
|
||||||
void flush_vpid_single(uint16_t vpid);
|
void flush_vpid_single(uint16_t vpid);
|
||||||
@ -100,7 +93,7 @@ bool check_continuous_hpa(struct vm *vm, uint64_t gpa_arg, uint64_t size_arg);
|
|||||||
*@pre (pml4_page != NULL) && (pg_size != NULL)
|
*@pre (pml4_page != NULL) && (pg_size != NULL)
|
||||||
*/
|
*/
|
||||||
uint64_t *lookup_address(uint64_t *pml4_page, uint64_t addr,
|
uint64_t *lookup_address(uint64_t *pml4_page, uint64_t addr,
|
||||||
uint64_t *pg_size, enum _page_table_type ptt);
|
uint64_t *pg_size, const struct memory_ops *mem_ops);
|
||||||
|
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
|
|
||||||
@ -166,7 +159,6 @@ void ept_mr_modify(struct vm *vm, uint64_t *pml4_page, uint64_t gpa,
|
|||||||
*/
|
*/
|
||||||
void ept_mr_del(struct vm *vm, uint64_t *pml4_page, uint64_t gpa,
|
void ept_mr_del(struct vm *vm, uint64_t *pml4_page, uint64_t gpa,
|
||||||
uint64_t size);
|
uint64_t size);
|
||||||
void free_ept_mem(uint64_t *pml4_page);
|
|
||||||
int ept_violation_vmexit_handler(struct vcpu *vcpu);
|
int ept_violation_vmexit_handler(struct vcpu *vcpu);
|
||||||
int ept_misconfig_vmexit_handler(__unused struct vcpu *vcpu);
|
int ept_misconfig_vmexit_handler(__unused struct vcpu *vcpu);
|
||||||
|
|
||||||
|
@ -13,6 +13,21 @@
|
|||||||
/* size of the low MMIO address space: 2GB */
|
/* size of the low MMIO address space: 2GB */
|
||||||
#define PLATFORM_LO_MMIO_SIZE 0x80000000UL
|
#define PLATFORM_LO_MMIO_SIZE 0x80000000UL
|
||||||
|
|
||||||
|
#define PML4_PAGE_NUM(size) 1UL
|
||||||
|
#define PDPT_PAGE_NUM(size) (((size) + PML4E_SIZE - 1UL) >> PML4E_SHIFT)
|
||||||
|
#define PD_PAGE_NUM(size) (((size) + PDPTE_SIZE - 1UL) >> PDPTE_SHIFT)
|
||||||
|
#define PT_PAGE_NUM(size) (((size) + PDE_SIZE - 1UL) >> PDE_SHIFT)
|
||||||
|
|
||||||
|
/* The size of the guest physical address space, covered by the EPT page table of a VM */
|
||||||
|
#define EPT_ADDRESS_SPACE(size) ((size != 0UL) ? (size + PLATFORM_LO_MMIO_SIZE) : 0UL)
|
||||||
|
|
||||||
|
#define TRUSTY_PML4_PAGE_NUM(size) (1UL)
|
||||||
|
#define TRUSTY_PDPT_PAGE_NUM(size) (1UL)
|
||||||
|
#define TRUSTY_PD_PAGE_NUM(size) (PD_PAGE_NUM(size))
|
||||||
|
#define TRUSTY_PT_PAGE_NUM(size) (PT_PAGE_NUM(size))
|
||||||
|
#define TRUSTY_PGTABLE_PAGE_NUM(size) \
|
||||||
|
(TRUSTY_PML4_PAGE_NUM(size) + TRUSTY_PDPT_PAGE_NUM(size) + TRUSTY_PD_PAGE_NUM(size) + TRUSTY_PT_PAGE_NUM(size))
|
||||||
|
|
||||||
struct page {
|
struct page {
|
||||||
uint8_t contents[PAGE_SIZE];
|
uint8_t contents[PAGE_SIZE];
|
||||||
} __aligned(PAGE_SIZE);
|
} __aligned(PAGE_SIZE);
|
||||||
|
@ -162,9 +162,4 @@ static inline uint64_t pdpte_large(uint64_t pdpte)
|
|||||||
return pdpte & PAGE_PSE;
|
return pdpte & PAGE_PSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t pgentry_present(enum _page_table_type ptt, uint64_t pte)
|
|
||||||
{
|
|
||||||
return (ptt == PTT_PRIMARY) ? (pte & PAGE_PRESENT) : (pte & EPT_RWX);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* PGTABLE_H */
|
#endif /* PGTABLE_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user