From 2d6c75408e4d0b98ae9af9ca3f8747f87fef18d8 Mon Sep 17 00:00:00 2001 From: Jason Chen CJ Date: Wed, 11 Apr 2018 11:00:53 +0800 Subject: [PATCH] mmu: refine the checking of entry present - change the input param of check_page_table_present from struct map_params to page_table_type - check EPT present bits misconfiguration in check_page_table_present - change var "table_present" to more suitable name "entry_present" Signed-off-by: Jason Chen CJ Acked-by: Tian, Kevin --- hypervisor/arch/x86/mmu.c | 83 ++++++++++++++++++++----------- hypervisor/include/arch/x86/mmu.h | 1 + 2 files changed, 56 insertions(+), 28 deletions(-) diff --git a/hypervisor/arch/x86/mmu.c b/hypervisor/arch/x86/mmu.c index a9001df60..f45b13a87 100644 --- a/hypervisor/arch/x86/mmu.c +++ b/hypervisor/arch/x86/mmu.c @@ -171,6 +171,30 @@ static bool check_mmu_1gb_support(struct map_params *map_params) return status; } +static inline uint32_t check_page_table_present(int page_table_type, + uint64_t table_entry) +{ + if (page_table_type == PTT_EPT) { + table_entry &= (IA32E_EPT_R_BIT | IA32E_EPT_W_BIT | + IA32E_EPT_X_BIT); + /* RWX misconfiguration for: + * - write-only + * - write-execute + * - execute-only (if cap not support) + * no check for reserved bits + */ + if ((table_entry == IA32E_EPT_W_BIT) || + (table_entry == (IA32E_EPT_W_BIT | IA32E_EPT_X_BIT)) || + ((table_entry == IA32E_EPT_X_BIT) && + !check_ept_x_only_support())) + return PT_MISCFG_PRESENT; + } else { + table_entry &= (IA32E_COMM_P_BIT); + } + + return (table_entry) ? PT_PRESENT : PT_NOT_PRESENT; +} + static uint32_t map_mem_region(void *vaddr, void *paddr, void *table_base, uint64_t attr, uint32_t table_level, int table_type, enum mem_map_request_type request_type) @@ -345,19 +369,6 @@ static uint32_t fetch_page_table_offset(void *addr, uint32_t table_level) return table_offset; } -static inline uint32_t check_page_table_present(struct map_params *map_params, - uint64_t table_entry) -{ - if (map_params->page_table_type == PTT_EPT) { - table_entry &= (IA32E_EPT_R_BIT | IA32E_EPT_W_BIT | - IA32E_EPT_X_BIT); - } else { - table_entry &= (IA32E_COMM_P_BIT); - } - - return (table_entry) ? PT_PRESENT : PT_NOT_PRESENT; -} - static int get_table_entry(void *addr, void *table_base, uint32_t table_level, uint64_t *table_entry) { @@ -381,7 +392,7 @@ static void *walk_paging_struct(void *addr, void *table_base, { uint32_t table_offset; uint64_t table_entry; - uint64_t table_present; + uint64_t entry_present; /* if table_level == IA32E_PT Just return the same address * can't walk down any further */ @@ -405,15 +416,15 @@ static void *walk_paging_struct(void *addr, void *table_base, /* Set table present bits to any of the * read/write/execute bits */ - table_present = (IA32E_EPT_R_BIT | IA32E_EPT_W_BIT | + entry_present = (IA32E_EPT_R_BIT | IA32E_EPT_W_BIT | IA32E_EPT_X_BIT); } else { /* Set table preset bits to P bit or r/w bit */ - table_present = (IA32E_COMM_P_BIT | IA32E_COMM_RW_BIT); + entry_present = (IA32E_COMM_P_BIT | IA32E_COMM_RW_BIT); } /* Determine if a valid entry exists */ - if ((table_entry & table_present) == 0) { + if ((table_entry & entry_present) == 0) { /* No entry present - need to allocate a new table */ sub_table_addr = alloc_paging_struct(); /* Check to ensure memory available for this structure*/ @@ -431,7 +442,7 @@ static void *walk_paging_struct(void *addr, void *table_base, * sub-table */ MEM_WRITE64(table_base + table_offset, - HVA2HPA(sub_table_addr) | table_present); + HVA2HPA(sub_table_addr) | entry_present); } else { /* Get address of the sub-table */ sub_table_addr = HPA2HVA(table_entry & IA32E_REF_MASK); @@ -610,7 +621,7 @@ int obtain_last_page_table_entry(struct map_params *map_params, struct entry_params *entry, void *addr, bool direct) { uint64_t table_entry; - uint32_t table_present = 0; + uint32_t entry_present = 0; int ret = 0; /* Obtain the PML4 address */ void *table_addr = direct ? (map_params->pml4_base) @@ -620,8 +631,12 @@ int obtain_last_page_table_entry(struct map_params *map_params, ret = get_table_entry(addr, table_addr, IA32E_PML4, &table_entry); if (ret < 0) return ret; - table_present = check_page_table_present(map_params, table_entry); - if (table_present == PT_NOT_PRESENT) { + entry_present = check_page_table_present(map_params->page_table_type, + table_entry); + if (entry_present == PT_MISCFG_PRESENT) { + pr_err("Present bits misconfigurated"); + return -EINVAL; + } else if (entry_present == PT_NOT_PRESENT) { /* PML4E not present, return PML4 base address */ entry->entry_level = IA32E_PML4; entry->entry_base = table_addr; @@ -638,8 +653,12 @@ int obtain_last_page_table_entry(struct map_params *map_params, ret = get_table_entry(addr, table_addr, IA32E_PDPT, &table_entry); if (ret < 0) return ret; - table_present = check_page_table_present(map_params, table_entry); - if (table_present == PT_NOT_PRESENT) { + entry_present = check_page_table_present(map_params->page_table_type, + table_entry); + if (entry_present == PT_MISCFG_PRESENT) { + pr_err("Present bits misconfigurated"); + return -EINVAL; + } else if (entry_present == PT_NOT_PRESENT) { /* PDPTE not present, return PDPT base address */ entry->entry_level = IA32E_PDPT; entry->entry_base = table_addr; @@ -667,8 +686,12 @@ int obtain_last_page_table_entry(struct map_params *map_params, ret = get_table_entry(addr, table_addr, IA32E_PD, &table_entry); if (ret < 0) return ret; - table_present = check_page_table_present(map_params, table_entry); - if (table_present == PT_NOT_PRESENT) { + entry_present = check_page_table_present(map_params->page_table_type, + table_entry); + if (entry_present == PT_MISCFG_PRESENT) { + pr_err("Present bits misconfigurated"); + return -EINVAL; + } else if (entry_present == PT_NOT_PRESENT) { /* PDE not present, return PDE base address */ entry->entry_level = IA32E_PD; entry->entry_base = table_addr; @@ -677,7 +700,6 @@ int obtain_last_page_table_entry(struct map_params *map_params, entry->entry_off = fetch_page_table_offset(addr, IA32E_PD); entry->entry_val = table_entry; return 0; - } if (table_entry & IA32E_PDE_PS_BIT) { /* 2MB page size, return the base addr of the pg entry*/ @@ -695,8 +717,13 @@ int obtain_last_page_table_entry(struct map_params *map_params, ret = get_table_entry(addr, table_addr, IA32E_PT, &table_entry); if (ret < 0) return ret; - table_present = check_page_table_present(map_params, table_entry); - entry->entry_present = ((table_present == PT_PRESENT) + entry_present = check_page_table_present(map_params->page_table_type, + table_entry); + if (entry_present == PT_MISCFG_PRESENT) { + pr_err("Present bits misconfigurated"); + return -EINVAL; + } + entry->entry_present = ((entry_present == PT_PRESENT) ? (PT_PRESENT):(PT_NOT_PRESENT)); entry->entry_level = IA32E_PT; entry->entry_base = table_addr; diff --git a/hypervisor/include/arch/x86/mmu.h b/hypervisor/include/arch/x86/mmu.h index 4b4a63e28..3e62177f8 100644 --- a/hypervisor/include/arch/x86/mmu.h +++ b/hypervisor/include/arch/x86/mmu.h @@ -280,6 +280,7 @@ enum _page_table_level { enum _page_table_present { PT_NOT_PRESENT = 0, PT_PRESENT = 1, + PT_MISCFG_PRESENT = 2, }; /* Page size */