mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-11-16 13:55:04 +00:00
add pgtable callbacks set_pgentry to implement arch specific set generic page table entry for any paging level, and remove x86 specific tweak_exe_right/recover_exe_right callbacks, move the logic in set_pgentry callback. remove common set_pgentry function to avoid confusing. Tracked-On: #8831 Signed-off-by: hangliu1 <hang1.liu@intel.com> Reviewed-by: Fei Li <fei1.li@intel.com> Acked-by: Wang, Yu1 <yu1.wang@intel.com>
118 lines
4.1 KiB
C
118 lines
4.1 KiB
C
/*
|
|
* Copyright (C) 2018-2025 Intel Corporation.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <types.h>
|
|
#include <util.h>
|
|
#include <acrn_hv_defs.h>
|
|
#include <asm/page.h>
|
|
#include <pgtable.h>
|
|
#include <mmu.h>
|
|
#include <logmsg.h>
|
|
|
|
#if CONFIG_SERIAL_8250_PCI
|
|
static uint8_t uart_pde_page[PAGE_SIZE]__aligned(PAGE_SIZE);
|
|
static uint8_t uart_pdpte_page[PAGE_SIZE]__aligned(PAGE_SIZE);
|
|
|
|
void early_pgtable_map_uart(uint64_t addr)
|
|
{
|
|
uint64_t *pml4e, *pdpte, *pde;
|
|
uint64_t value;
|
|
|
|
CPU_CR_READ(cr3, &value);
|
|
/*assumpiton for map high mmio in early pagetable is that it is only used for
|
|
2MB page since 1G page may not available when memory width is 39bit */
|
|
pml4e = pgtl3e_offset((uint64_t *)value, addr);
|
|
/* address is above 512G */
|
|
if(!(*pml4e & PAGE_PRESENT)) {
|
|
*pml4e = hva2hpa_early(uart_pdpte_page) + (PAGE_PRESENT|PAGE_RW);
|
|
}
|
|
pdpte = pgtl2e_offset(pml4e, addr);
|
|
if(!(*pdpte & PAGE_PRESENT)) {
|
|
*(pdpte) = hva2hpa_early(uart_pde_page) + (PAGE_PRESENT|PAGE_RW);
|
|
pde = pgtl1e_offset(pdpte, addr);
|
|
*pde = (addr & PGTL1_MASK) + (PAGE_PRESENT|PAGE_RW|PAGE_PSE);
|
|
} else if(!(*pdpte & PAGE_PSE)) {
|
|
pde = pgtl1e_offset(pdpte, addr);
|
|
if(!(*pde & PAGE_PRESENT)) {
|
|
*pde = (addr & PGTL1_MASK) + (PAGE_PRESENT|PAGE_RW|PAGE_PSE);
|
|
}
|
|
} else {
|
|
/* no process */
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @brief Create a root page table for Secure World.
|
|
*
|
|
* This function initializes a new root page table for Secure World. It is intended to be used during the initialization
|
|
* phase of Trusty, setting up isolated memory regions for secure execution. Secure world can access Normal World's
|
|
* memory, but Normal World cannot access Secure World's memory. The PML4T/PDPT for Secure World are separated from
|
|
* Normal World. PDT/PT are shared in both Secure World's EPT and Normal World's EPT. So this function copies the PDPTEs
|
|
* from the Normal World to the Secure World.
|
|
*
|
|
* - It creates a new root page table and every entries are initialized to point to the sanitized page by default.
|
|
* - The access right specified by prot_clr is cleared for Secure World PDPTEs.
|
|
* - Finally, the function returns the new root page table pointer.
|
|
*
|
|
* @param[in] table A pointer to the struct pgtable containing the information of the specified memory operations.
|
|
* @param[in] nworld_pml4_page A pointer to pml4 table hierarchy in Normal World.
|
|
* @param[in] prot_table_present Mask indicating the page referenced is present.
|
|
* @param[in] prot_clr Bit positions representing the specified properties which need to be cleared.
|
|
*
|
|
* @return A pointer to the newly created root page table for Secure World.
|
|
*
|
|
* @pre table != NULL
|
|
* @pre nworld_pml4_page != NULL
|
|
*
|
|
* @post N/A
|
|
*/
|
|
void *pgtable_create_trusty_root(const struct pgtable *table,
|
|
void *nworld_pml4_page, uint64_t prot_table_present, uint64_t prot_clr)
|
|
{
|
|
uint16_t i;
|
|
uint64_t pdpte, *dest_pdpte_p, *src_pdpte_p;
|
|
uint64_t nworld_pml4e, sworld_pml4e;
|
|
void *sub_table_addr, *pml4_base;
|
|
|
|
/* Copy PDPT entries from Normal world to Secure world
|
|
* Secure world can access Normal World's memory,
|
|
* but Normal World can not access Secure World's memory.
|
|
* The PML4/PDPT for Secure world are separated from
|
|
* Normal World. PD/PT are shared in both Secure world's EPT
|
|
* and Normal World's EPT
|
|
*/
|
|
pml4_base = pgtable_create_root(table);
|
|
|
|
/* The trusty memory is remapped to guest physical address
|
|
* of gpa_rebased to gpa_rebased + size
|
|
*/
|
|
sub_table_addr = alloc_page(table->pool);
|
|
sworld_pml4e = hva2hpa(sub_table_addr) | prot_table_present;
|
|
*(uint64_t *)pml4_base = sworld_pml4e;
|
|
table->flush_cache_pagewalk(pml4_base);
|
|
nworld_pml4e = get_pgentry((uint64_t *)nworld_pml4_page);
|
|
|
|
/*
|
|
* copy PTPDEs from normal world EPT to secure world EPT,
|
|
* and remove execute access attribute in these entries
|
|
*/
|
|
dest_pdpte_p = page_addr(sworld_pml4e);
|
|
src_pdpte_p = page_addr(nworld_pml4e);
|
|
for (i = 0U; i < (uint16_t)(PTRS_PER_PGTL2E - 1UL); i++) {
|
|
pdpte = get_pgentry(src_pdpte_p);
|
|
if ((pdpte & prot_table_present) != 0UL) {
|
|
pdpte &= ~prot_clr;
|
|
*dest_pdpte_p = pdpte;
|
|
table->flush_cache_pagewalk(dest_pdpte_p);
|
|
}
|
|
src_pdpte_p++;
|
|
dest_pdpte_p++;
|
|
}
|
|
|
|
return pml4_base;
|
|
}
|