Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
target/riscv: Reorg access check in get_physical_address
We were effectively computing the protection bits twice,
once while performing access checks and once while returning
the valid bits to the caller.  Reorg so we do this once.

Move the computation of mxr close to its single use.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Weiwei Li <liweiwei@iscas.ac.cn>
Tested-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Message-Id: <20230325105429.1142530-25-richard.henderson@linaro.org>
Message-Id: <20230412114333.118895-25-richard.henderson@linaro.org>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
  • Loading branch information
rth7680 authored and alistair23 committed May 5, 2023
1 parent a9d2e3e commit e1dd150
Showing 1 changed file with 36 additions and 33 deletions.
69 changes: 36 additions & 33 deletions target/riscv/cpu_helper.c
Expand Up @@ -747,7 +747,7 @@ static int get_physical_address_pmp(CPURISCVState *env, int *prot,
* @is_debug: Is this access from a debugger or the monitor?
*/
static int get_physical_address(CPURISCVState *env, hwaddr *physical,
int *prot, vaddr addr,
int *ret_prot, vaddr addr,
target_ulong *fault_pte_addr,
int access_type, int mmu_idx,
bool first_stage, bool two_stage,
Expand Down Expand Up @@ -779,20 +779,14 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,

if (mode == PRV_M || !riscv_cpu_cfg(env)->mmu) {
*physical = addr;
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
*ret_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
return TRANSLATE_SUCCESS;
}

*prot = 0;
*ret_prot = 0;

hwaddr base;
int levels, ptidxbits, ptesize, vm, sum, mxr, widened;

if (first_stage == true) {
mxr = get_field(env->mstatus, MSTATUS_MXR);
} else {
mxr = get_field(env->vsstatus, MSTATUS_MXR);
}
int levels, ptidxbits, ptesize, vm, sum, widened;

if (first_stage == true) {
if (use_background) {
Expand Down Expand Up @@ -835,7 +829,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
levels = 5; ptidxbits = 9; ptesize = 8; break;
case VM_1_10_MBARE:
*physical = addr;
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
*ret_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
return TRANSLATE_SUCCESS;
default:
g_assert_not_reached();
Expand Down Expand Up @@ -970,6 +964,27 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
return TRANSLATE_FAIL;
}

int prot = 0;
if (pte & PTE_R) {
prot |= PAGE_READ;
}
if (pte & PTE_W) {
prot |= PAGE_WRITE;
}
if (pte & PTE_X) {
bool mxr;

if (first_stage == true) {
mxr = get_field(env->mstatus, MSTATUS_MXR);
} else {
mxr = get_field(env->vsstatus, MSTATUS_MXR);
}
if (mxr) {
prot |= PAGE_READ;
}
prot |= PAGE_EXEC;
}

if ((pte & PTE_U) &&
((mode != PRV_U) && (!sum || access_type == MMU_INST_FETCH))) {
/*
Expand All @@ -982,17 +997,9 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
/* Supervisor PTE flags when not S mode */
return TRANSLATE_FAIL;
}
if (access_type == MMU_DATA_LOAD &&
!((pte & PTE_R) || ((pte & PTE_X) && mxr))) {
/* Read access check failed */
return TRANSLATE_FAIL;
}
if (access_type == MMU_DATA_STORE && !(pte & PTE_W)) {
/* Write access check failed */
return TRANSLATE_FAIL;
}
if (access_type == MMU_INST_FETCH && !(pte & PTE_X)) {
/* Fetch access check failed */

if (!((prot >> access_type) & 1)) {
/* Access check failed */
return TRANSLATE_FAIL;
}

Expand Down Expand Up @@ -1057,20 +1064,16 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
(vpn & (((target_ulong)1 << ptshift) - 1))
) << PGSHIFT) | (addr & ~TARGET_PAGE_MASK);

/* set permissions on the TLB entry */
if ((pte & PTE_R) || ((pte & PTE_X) && mxr)) {
*prot |= PAGE_READ;
}
if (pte & PTE_X) {
*prot |= PAGE_EXEC;
}
/*
* Add write permission on stores or if the page is already dirty,
* so that we TLB miss on later writes to update the dirty bit.
* Remove write permission unless this is a store, or the page is
* already dirty, so that we TLB miss on later writes to update
* the dirty bit.
*/
if ((pte & PTE_W) && (access_type == MMU_DATA_STORE || (pte & PTE_D))) {
*prot |= PAGE_WRITE;
if (access_type != MMU_DATA_STORE && !(pte & PTE_D)) {
prot &= ~PAGE_WRITE;
}
*ret_prot = prot;

return TRANSLATE_SUCCESS;
}

Expand Down

0 comments on commit e1dd150

Please sign in to comment.