/* * Copyright (C) 2018 Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /** * @file mmu.h * * @brief APIs for Memory Management module */ #ifndef MMU_H #define MMU_H /** * @brief Memory Management * * @defgroup acrn_mem ACRN Memory Management * @{ */ /** The flag that indicates that the page fault was caused by a non present * page. */ #define PAGE_FAULT_P_FLAG 0x00000001U /** The flag that indicates that the page fault was caused by a write access. */ #define PAGE_FAULT_WR_FLAG 0x00000002U /** The flag that indicates that the page fault was caused in user mode. */ #define PAGE_FAULT_US_FLAG 0x00000004U /** The flag that indicates that the page fault was caused by a reserved bit * violation. */ #define PAGE_FAULT_RSVD_FLAG 0x00000008U /** The flag that indicates that the page fault was caused by an instruction * fetch. */ #define PAGE_FAULT_ID_FLAG 0x00000010U /* Defines used for common memory sizes */ #define MEM_1K 1024U #define MEM_2K (MEM_1K * 2U) #define MEM_4K (MEM_1K * 4U) #define MEM_1M (MEM_1K * 1024U) #define MEM_2M (MEM_1M * 2U) #define MEM_1G (MEM_1M * 1024U) #ifndef ASSEMBLER #include #include #include /* Define cache line size (in bytes) */ #define CACHE_LINE_SIZE 64U /* IA32E Paging constants */ #define IA32E_REF_MASK ((get_cpu_info())->physical_address_mask) extern uint8_t ld_text_end; static inline uint64_t round_page_up(uint64_t addr) { return (((addr + (uint64_t)PAGE_SIZE) - 1UL) & PAGE_MASK); } static inline uint64_t round_page_down(uint64_t addr) { return (addr & PAGE_MASK); } static inline uint64_t round_pde_up(uint64_t val) { return (((val + (uint64_t)PDE_SIZE) - 1UL) & PDE_MASK); } static inline uint64_t round_pde_down(uint64_t val) { return (val & PDE_MASK); } /** * @brief Page tables level in IA32 paging mode */ enum _page_table_level { /** * @brief The PML4 level in the page tables */ IA32E_PML4 = 0, /** * @brief The Page-Directory-Pointer-Table level in the page tables */ IA32E_PDPT = 1, /** * @brief The Page-Directory level in the page tables */ IA32E_PD = 2, /** * @brief The Page-Table level in the page tables */ IA32E_PT = 3, }; /* Page size */ #define PAGE_SIZE_4K MEM_4K #define PAGE_SIZE_2M MEM_2M #define PAGE_SIZE_1G MEM_1G void sanitize_pte_entry(uint64_t *ptep); void sanitize_pte(uint64_t *pt_page); /** * @brief MMU paging enable * * @return None */ void enable_paging(void); /** * @brief Supervisor-mode execution prevention (SMEP) enable * * @return None */ void enable_smep(void); /** * @brief Supervisor-mode Access Prevention (SMAP) enable * * @return None */ void enable_smap(void); /** * @brief MMU page tables initialization * * @return None */ void init_paging(void); void mmu_add(uint64_t *pml4_page, uint64_t paddr_base, uint64_t vaddr_base, uint64_t size, uint64_t prot, const struct memory_ops *mem_ops); void mmu_modify_or_del(uint64_t *pml4_page, uint64_t vaddr_base, uint64_t size, uint64_t prot_set, uint64_t prot_clr, const struct memory_ops *mem_ops, uint32_t type); void hv_access_memory_region_update(uint64_t base, uint64_t size); /** * @brief VPID allocation * * @retval 0 VPID overflow * @retval >0 the valid VPID */ uint16_t allocate_vpid(void); /** * @brief Specified signle VPID flush * * @param[in] vpid the specified VPID * * @return None */ void flush_vpid_single(uint16_t vpid); /** * @brief All VPID flush * * @return None */ void flush_vpid_global(void); /** * @brief Guest-physical mappings and combined mappings invalidation * * @param[in] vcpu the pointer that points the vcpu data structure * * @return None */ void invept(const struct acrn_vcpu *vcpu); /** *@pre (pml4_page != NULL) && (pg_size != NULL) */ const uint64_t *lookup_address(uint64_t *pml4_page, uint64_t addr, uint64_t *pg_size, const struct memory_ops *mem_ops); /** Defines a single entry in an E820 memory map. */ struct e820_entry { /** The base address of the memory range. */ uint64_t baseaddr; /** The length of the memory range. */ uint64_t length; /** The type of memory region. */ uint32_t type; } __packed; /* E820 memory types */ #define E820_TYPE_RAM 1U /* EFI 1, 2, 3, 4, 5, 6, 7 */ #define E820_TYPE_RESERVED 2U /* EFI 0, 11, 12, 13 (everything not used elsewhere) */ #define E820_TYPE_ACPI_RECLAIM 3U /* EFI 9 */ #define E820_TYPE_ACPI_NVS 4U /* EFI 10 */ #define E820_TYPE_UNUSABLE 5U /* EFI 8 */ static inline void cache_flush_invalidate_all(void) { asm volatile (" wbinvd\n" : : : "memory"); } static inline void clflush(volatile void *p) { asm volatile ("clflush (%0)" :: "r"(p)); } /** * Invalid HPA is defined for error checking, * according to SDM vol.3A 4.1.4, the maximum * host physical address width is 52 */ #define INVALID_HPA (0x1UL << 52U) #define INVALID_GPA (0x1UL << 52U) /* External Interfaces */ /** * @brief EPT page tables destroy * * @param[inout] vm the pointer that points to VM data structure * * @return None */ void destroy_ept(struct acrn_vm *vm); /** * @brief Translating from guest-physical address to host-physcial address * * @param[in] vm the pointer that points to VM data structure * @param[in] gpa the specified guest-physical address * * @retval hpa the host physical address mapping to the \p gpa * @retval INVALID_HPA the HPA of parameter gpa is unmapping */ uint64_t gpa2hpa(struct acrn_vm *vm, uint64_t gpa); /** * @brief Translating from guest-physical address to host-physcial address * * @param[in] vm the pointer that points to VM data structure * @param[in] gpa the specified guest-physical address * @param[out] size the pointer that returns the page size of * the page in which the gpa is * * @retval hpa the host physical address mapping to the \p gpa * @retval INVALID_HPA the HPA of parameter gpa is unmapping */ uint64_t local_gpa2hpa(struct acrn_vm *vm, uint64_t gpa, uint32_t *size); /** * @brief Translating from host-physical address to guest-physical address for SOS_VM * * @param[in] hpa the specified host-physical address * * @pre: the gpa and hpa are identical mapping in SOS. */ uint64_t sos_vm_hpa2gpa(uint64_t hpa); /** * @brief Guest-physical memory region mapping * * @param[in] vm the pointer that points to VM data structure * @param[in] pml4_page The physical address of The EPTP * @param[in] hpa The specified start host physical address of host * physical memory region that GPA will be mapped * @param[in] gpa The specified start guest physical address of guest * physical memory region that needs to be mapped * @param[in] size The size of guest physical memory region that needs * to be mapped * @param[in] prot_orig The specified memory access right and memory type * * @return None */ void ept_mr_add(struct acrn_vm *vm, uint64_t *pml4_page, uint64_t hpa, uint64_t gpa, uint64_t size, uint64_t prot_orig); /** * @brief Guest-physical memory page access right or memory type updating * * @param[in] vm the pointer that points to VM data structure * @param[in] pml4_page The physical address of The EPTP * @param[in] gpa The specified start guest physical address of guest * physical memory region whoes mapping needs to be updated * @param[in] size The size of guest physical memory region * @param[in] prot_set The specified memory access right and memory type * that will be set * @param[in] prot_clr The specified memory access right and memory type * that will be cleared * * @return None */ void ept_mr_modify(struct acrn_vm *vm, uint64_t *pml4_page, uint64_t gpa, uint64_t size, uint64_t prot_set, uint64_t prot_clr); /** * @brief Guest-physical memory region unmapping * * @param[in] vm the pointer that points to VM data structure * @param[in] pml4_page The physical address of The EPTP * @param[in] gpa The specified start guest physical address of guest * physical memory region whoes mapping needs to be deleted * @param[in] size The size of guest physical memory region * * @return None * * @pre [gpa,gpa+size) has been mapped into host physical memory region */ void ept_mr_del(struct acrn_vm *vm, uint64_t *pml4_page, uint64_t gpa, uint64_t size); /** * @brief EPT misconfiguration handling * * @param[in] vcpu the pointer that points to vcpu data structure * * @retval -EINVAL fail to handle the EPT misconfig * @retval 0 Success to handle the EPT misconfig */ int32_t ept_misconfig_vmexit_handler(__unused struct acrn_vcpu *vcpu); /** * @} */ #endif /* ASSEMBLER not defined */ #endif /* MMU_H */