target/riscv: Fix PMP propagation for tlb
Only the pmp index that be checked by pmp_hart_has_privs can be used by pmp_get_tlb_size to avoid an error pmp index. Before modification, we may use an error pmp index. For example, we check address 0x4fc, and the size 0x4 in pmp_hart_has_privs. If there is an pmp rule, valid range is [0x4fc, 0x500), then pmp_hart_has_privs will return true; However, this checked pmp index is discarded as pmp_hart_has_privs return bool value. In pmp_is_range_in_tlb, it will traverse all pmp rules. The tlb_sa will be 0x0, and tlb_ea will be 0xfff. If there is a pmp rule [0x10, 0x14), it will be misused as it is legal in pmp_get_tlb_size. As we have already known the correct pmp index, just remove the remove the pmp_is_range_in_tlb and get tlb size directly from pmp_get_tlb_size. Signed-off-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-Id: <20221012060016.30856-1-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
parent
d1852caab1
commit
824cac681c
@ -706,24 +706,26 @@ static int get_physical_address_pmp(CPURISCVState *env, int *prot,
|
|||||||
int mode)
|
int mode)
|
||||||
{
|
{
|
||||||
pmp_priv_t pmp_priv;
|
pmp_priv_t pmp_priv;
|
||||||
target_ulong tlb_size_pmp = 0;
|
int pmp_index = -1;
|
||||||
|
|
||||||
if (!riscv_feature(env, RISCV_FEATURE_PMP)) {
|
if (!riscv_feature(env, RISCV_FEATURE_PMP)) {
|
||||||
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||||
return TRANSLATE_SUCCESS;
|
return TRANSLATE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pmp_hart_has_privs(env, addr, size, 1 << access_type, &pmp_priv,
|
pmp_index = pmp_hart_has_privs(env, addr, size, 1 << access_type,
|
||||||
mode)) {
|
&pmp_priv, mode);
|
||||||
|
if (pmp_index < 0) {
|
||||||
*prot = 0;
|
*prot = 0;
|
||||||
return TRANSLATE_PMP_FAIL;
|
return TRANSLATE_PMP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*prot = pmp_priv_to_page_prot(pmp_priv);
|
*prot = pmp_priv_to_page_prot(pmp_priv);
|
||||||
if (tlb_size != NULL) {
|
if ((tlb_size != NULL) && pmp_index != MAX_RISCV_PMPS) {
|
||||||
if (pmp_is_range_in_tlb(env, addr & ~(*tlb_size - 1), &tlb_size_pmp)) {
|
target_ulong tlb_sa = addr & ~(TARGET_PAGE_SIZE - 1);
|
||||||
*tlb_size = tlb_size_pmp;
|
target_ulong tlb_ea = tlb_sa + TARGET_PAGE_SIZE - 1;
|
||||||
}
|
|
||||||
|
*tlb_size = pmp_get_tlb_size(env, pmp_index, tlb_sa, tlb_ea);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRANSLATE_SUCCESS;
|
return TRANSLATE_SUCCESS;
|
||||||
|
@ -292,8 +292,11 @@ static bool pmp_hart_has_privs_default(CPURISCVState *env, target_ulong addr,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the address has required RWX privs to complete desired operation
|
* Check if the address has required RWX privs to complete desired operation
|
||||||
|
* Return PMP rule index if a pmp rule match
|
||||||
|
* Return MAX_RISCV_PMPS if default match
|
||||||
|
* Return negtive value if no match
|
||||||
*/
|
*/
|
||||||
bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
|
int pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
|
||||||
target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs,
|
target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs,
|
||||||
target_ulong mode)
|
target_ulong mode)
|
||||||
{
|
{
|
||||||
@ -305,8 +308,10 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
|
|||||||
|
|
||||||
/* Short cut if no rules */
|
/* Short cut if no rules */
|
||||||
if (0 == pmp_get_num_rules(env)) {
|
if (0 == pmp_get_num_rules(env)) {
|
||||||
return pmp_hart_has_privs_default(env, addr, size, privs,
|
if (pmp_hart_has_privs_default(env, addr, size, privs,
|
||||||
allowed_privs, mode);
|
allowed_privs, mode)) {
|
||||||
|
ret = MAX_RISCV_PMPS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
@ -333,7 +338,7 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
|
|||||||
if ((s + e) == 1) {
|
if ((s + e) == 1) {
|
||||||
qemu_log_mask(LOG_GUEST_ERROR,
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
"pmp violation - access is partially inside\n");
|
"pmp violation - access is partially inside\n");
|
||||||
ret = 0;
|
ret = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,18 +441,22 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ((privs & *allowed_privs) == privs);
|
if ((privs & *allowed_privs) == privs) {
|
||||||
|
ret = i;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No rule matched */
|
/* No rule matched */
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
return pmp_hart_has_privs_default(env, addr, size, privs,
|
if (pmp_hart_has_privs_default(env, addr, size, privs,
|
||||||
allowed_privs, mode);
|
allowed_privs, mode)) {
|
||||||
|
ret = MAX_RISCV_PMPS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret == 1 ? true : false;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -586,64 +595,25 @@ target_ulong mseccfg_csr_read(CPURISCVState *env)
|
|||||||
* Calculate the TLB size if the start address or the end address of
|
* Calculate the TLB size if the start address or the end address of
|
||||||
* PMP entry is presented in the TLB page.
|
* PMP entry is presented in the TLB page.
|
||||||
*/
|
*/
|
||||||
static target_ulong pmp_get_tlb_size(CPURISCVState *env, int pmp_index,
|
target_ulong pmp_get_tlb_size(CPURISCVState *env, int pmp_index,
|
||||||
target_ulong tlb_sa, target_ulong tlb_ea)
|
target_ulong tlb_sa, target_ulong tlb_ea)
|
||||||
{
|
{
|
||||||
target_ulong pmp_sa = env->pmp_state.addr[pmp_index].sa;
|
target_ulong pmp_sa = env->pmp_state.addr[pmp_index].sa;
|
||||||
target_ulong pmp_ea = env->pmp_state.addr[pmp_index].ea;
|
target_ulong pmp_ea = env->pmp_state.addr[pmp_index].ea;
|
||||||
|
|
||||||
if (pmp_sa >= tlb_sa && pmp_ea <= tlb_ea) {
|
if (pmp_sa <= tlb_sa && pmp_ea >= tlb_ea) {
|
||||||
return pmp_ea - pmp_sa + 1;
|
return TARGET_PAGE_SIZE;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
if (pmp_sa >= tlb_sa && pmp_sa <= tlb_ea && pmp_ea >= tlb_ea) {
|
|
||||||
return tlb_ea - pmp_sa + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pmp_ea <= tlb_ea && pmp_ea >= tlb_sa && pmp_sa <= tlb_sa) {
|
|
||||||
return pmp_ea - tlb_sa + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check is there a PMP entry which range covers this page. If so,
|
|
||||||
* try to find the minimum granularity for the TLB size.
|
|
||||||
*/
|
|
||||||
bool pmp_is_range_in_tlb(CPURISCVState *env, hwaddr tlb_sa,
|
|
||||||
target_ulong *tlb_size)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
target_ulong val;
|
|
||||||
target_ulong tlb_ea = (tlb_sa + TARGET_PAGE_SIZE - 1);
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_RISCV_PMPS; i++) {
|
|
||||||
val = pmp_get_tlb_size(env, i, tlb_sa, tlb_ea);
|
|
||||||
if (val) {
|
|
||||||
if (*tlb_size == 0 || *tlb_size > val) {
|
|
||||||
*tlb_size = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*tlb_size != 0) {
|
|
||||||
/*
|
/*
|
||||||
* At this point we have a tlb_size that is the smallest possible size
|
* At this point we have a tlb_size that is the smallest possible size
|
||||||
* That fits within a TARGET_PAGE_SIZE and the PMP region.
|
* That fits within a TARGET_PAGE_SIZE and the PMP region.
|
||||||
*
|
*
|
||||||
* If the size is less then TARGET_PAGE_SIZE we drop the size to 1.
|
* If the size is less then TARGET_PAGE_SIZE we drop the size to 1.
|
||||||
* This means the result isn't cached in the TLB and is only used for
|
* This means the result isn't cached in the TLB and is only used for
|
||||||
* a single translation.
|
* a single translation.
|
||||||
*/
|
*/
|
||||||
if (*tlb_size < TARGET_PAGE_SIZE) {
|
return 1;
|
||||||
*tlb_size = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -72,11 +72,11 @@ target_ulong mseccfg_csr_read(CPURISCVState *env);
|
|||||||
void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
|
void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
|
||||||
target_ulong val);
|
target_ulong val);
|
||||||
target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index);
|
target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index);
|
||||||
bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
|
int pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
|
||||||
target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs,
|
target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs,
|
||||||
target_ulong mode);
|
target_ulong mode);
|
||||||
bool pmp_is_range_in_tlb(CPURISCVState *env, hwaddr tlb_sa,
|
target_ulong pmp_get_tlb_size(CPURISCVState *env, int pmp_index,
|
||||||
target_ulong *tlb_size);
|
target_ulong tlb_sa, target_ulong tlb_ea);
|
||||||
void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index);
|
void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index);
|
||||||
void pmp_update_rule_nums(CPURISCVState *env);
|
void pmp_update_rule_nums(CPURISCVState *env);
|
||||||
uint32_t pmp_get_num_rules(CPURISCVState *env);
|
uint32_t pmp_get_num_rules(CPURISCVState *env);
|
||||||
|
Loading…
Reference in New Issue
Block a user