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 <jason.cj.chen@intel.com>
Acked-by: Tian, Kevin <kevin.tian@intel.com>
This commit is contained in:
Jason Chen CJ 2018-04-11 11:00:53 +08:00 committed by Jack Ren
parent 60425f91b4
commit 2d6c75408e
2 changed files with 56 additions and 28 deletions

View File

@ -171,6 +171,30 @@ static bool check_mmu_1gb_support(struct map_params *map_params)
return status; 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, static uint32_t map_mem_region(void *vaddr, void *paddr,
void *table_base, uint64_t attr, uint32_t table_level, void *table_base, uint64_t attr, uint32_t table_level,
int table_type, enum mem_map_request_type request_type) 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; 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, static int get_table_entry(void *addr, void *table_base,
uint32_t table_level, uint64_t *table_entry) 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; uint32_t table_offset;
uint64_t table_entry; uint64_t table_entry;
uint64_t table_present; uint64_t entry_present;
/* if table_level == IA32E_PT Just return the same address /* if table_level == IA32E_PT Just return the same address
* can't walk down any further * 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 /* Set table present bits to any of the
* read/write/execute bits * 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); IA32E_EPT_X_BIT);
} else { } else {
/* Set table preset bits to P bit or r/w bit */ /* 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 */ /* 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 */ /* No entry present - need to allocate a new table */
sub_table_addr = alloc_paging_struct(); sub_table_addr = alloc_paging_struct();
/* Check to ensure memory available for this structure*/ /* Check to ensure memory available for this structure*/
@ -431,7 +442,7 @@ static void *walk_paging_struct(void *addr, void *table_base,
* sub-table * sub-table
*/ */
MEM_WRITE64(table_base + table_offset, MEM_WRITE64(table_base + table_offset,
HVA2HPA(sub_table_addr) | table_present); HVA2HPA(sub_table_addr) | entry_present);
} else { } else {
/* Get address of the sub-table */ /* Get address of the sub-table */
sub_table_addr = HPA2HVA(table_entry & IA32E_REF_MASK); 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) struct entry_params *entry, void *addr, bool direct)
{ {
uint64_t table_entry; uint64_t table_entry;
uint32_t table_present = 0; uint32_t entry_present = 0;
int ret = 0; int ret = 0;
/* Obtain the PML4 address */ /* Obtain the PML4 address */
void *table_addr = direct ? (map_params->pml4_base) 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); ret = get_table_entry(addr, table_addr, IA32E_PML4, &table_entry);
if (ret < 0) if (ret < 0)
return ret; return ret;
table_present = check_page_table_present(map_params, table_entry); entry_present = check_page_table_present(map_params->page_table_type,
if (table_present == PT_NOT_PRESENT) { 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 */ /* PML4E not present, return PML4 base address */
entry->entry_level = IA32E_PML4; entry->entry_level = IA32E_PML4;
entry->entry_base = table_addr; 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); ret = get_table_entry(addr, table_addr, IA32E_PDPT, &table_entry);
if (ret < 0) if (ret < 0)
return ret; return ret;
table_present = check_page_table_present(map_params, table_entry); entry_present = check_page_table_present(map_params->page_table_type,
if (table_present == PT_NOT_PRESENT) { 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 */ /* PDPTE not present, return PDPT base address */
entry->entry_level = IA32E_PDPT; entry->entry_level = IA32E_PDPT;
entry->entry_base = table_addr; 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); ret = get_table_entry(addr, table_addr, IA32E_PD, &table_entry);
if (ret < 0) if (ret < 0)
return ret; return ret;
table_present = check_page_table_present(map_params, table_entry); entry_present = check_page_table_present(map_params->page_table_type,
if (table_present == PT_NOT_PRESENT) { 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 */ /* PDE not present, return PDE base address */
entry->entry_level = IA32E_PD; entry->entry_level = IA32E_PD;
entry->entry_base = table_addr; 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_off = fetch_page_table_offset(addr, IA32E_PD);
entry->entry_val = table_entry; entry->entry_val = table_entry;
return 0; return 0;
} }
if (table_entry & IA32E_PDE_PS_BIT) { if (table_entry & IA32E_PDE_PS_BIT) {
/* 2MB page size, return the base addr of the pg entry*/ /* 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); ret = get_table_entry(addr, table_addr, IA32E_PT, &table_entry);
if (ret < 0) if (ret < 0)
return ret; return ret;
table_present = check_page_table_present(map_params, table_entry); entry_present = check_page_table_present(map_params->page_table_type,
entry->entry_present = ((table_present == PT_PRESENT) 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)); ? (PT_PRESENT):(PT_NOT_PRESENT));
entry->entry_level = IA32E_PT; entry->entry_level = IA32E_PT;
entry->entry_base = table_addr; entry->entry_base = table_addr;

View File

@ -280,6 +280,7 @@ enum _page_table_level {
enum _page_table_present { enum _page_table_present {
PT_NOT_PRESENT = 0, PT_NOT_PRESENT = 0,
PT_PRESENT = 1, PT_PRESENT = 1,
PT_MISCFG_PRESENT = 2,
}; };
/* Page size */ /* Page size */