mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-18 15:42:09 -06:00
target/arm: Move pmsav8_mpu_lookup to ptw.c
This is the final user of get_phys_addr_pmsav7_default within helper.c, so make it static within ptw.c. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20220604040607.269301-10-richard.henderson@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
730d5c31d8
commit
fedbaa0503
3 changed files with 143 additions and 142 deletions
|
@ -11834,142 +11834,6 @@ void v8m_security_lookup(CPUARMState *env, uint32_t address,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
|
|
||||||
MMUAccessType access_type, ARMMMUIdx mmu_idx,
|
|
||||||
hwaddr *phys_ptr, MemTxAttrs *txattrs,
|
|
||||||
int *prot, bool *is_subpage,
|
|
||||||
ARMMMUFaultInfo *fi, uint32_t *mregion)
|
|
||||||
{
|
|
||||||
/* Perform a PMSAv8 MPU lookup (without also doing the SAU check
|
|
||||||
* that a full phys-to-virt translation does).
|
|
||||||
* mregion is (if not NULL) set to the region number which matched,
|
|
||||||
* or -1 if no region number is returned (MPU off, address did not
|
|
||||||
* hit a region, address hit in multiple regions).
|
|
||||||
* We set is_subpage to true if the region hit doesn't cover the
|
|
||||||
* entire TARGET_PAGE the address is within.
|
|
||||||
*/
|
|
||||||
ARMCPU *cpu = env_archcpu(env);
|
|
||||||
bool is_user = regime_is_user(env, mmu_idx);
|
|
||||||
uint32_t secure = regime_is_secure(env, mmu_idx);
|
|
||||||
int n;
|
|
||||||
int matchregion = -1;
|
|
||||||
bool hit = false;
|
|
||||||
uint32_t addr_page_base = address & TARGET_PAGE_MASK;
|
|
||||||
uint32_t addr_page_limit = addr_page_base + (TARGET_PAGE_SIZE - 1);
|
|
||||||
|
|
||||||
*is_subpage = false;
|
|
||||||
*phys_ptr = address;
|
|
||||||
*prot = 0;
|
|
||||||
if (mregion) {
|
|
||||||
*mregion = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unlike the ARM ARM pseudocode, we don't need to check whether this
|
|
||||||
* was an exception vector read from the vector table (which is always
|
|
||||||
* done using the default system address map), because those accesses
|
|
||||||
* are done in arm_v7m_load_vector(), which always does a direct
|
|
||||||
* read using address_space_ldl(), rather than going via this function.
|
|
||||||
*/
|
|
||||||
if (regime_translation_disabled(env, mmu_idx)) { /* MPU disabled */
|
|
||||||
hit = true;
|
|
||||||
} else if (m_is_ppb_region(env, address)) {
|
|
||||||
hit = true;
|
|
||||||
} else {
|
|
||||||
if (pmsav7_use_background_region(cpu, mmu_idx, is_user)) {
|
|
||||||
hit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) {
|
|
||||||
/* region search */
|
|
||||||
/* Note that the base address is bits [31:5] from the register
|
|
||||||
* with bits [4:0] all zeroes, but the limit address is bits
|
|
||||||
* [31:5] from the register with bits [4:0] all ones.
|
|
||||||
*/
|
|
||||||
uint32_t base = env->pmsav8.rbar[secure][n] & ~0x1f;
|
|
||||||
uint32_t limit = env->pmsav8.rlar[secure][n] | 0x1f;
|
|
||||||
|
|
||||||
if (!(env->pmsav8.rlar[secure][n] & 0x1)) {
|
|
||||||
/* Region disabled */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (address < base || address > limit) {
|
|
||||||
/*
|
|
||||||
* Address not in this region. We must check whether the
|
|
||||||
* region covers addresses in the same page as our address.
|
|
||||||
* In that case we must not report a size that covers the
|
|
||||||
* whole page for a subsequent hit against a different MPU
|
|
||||||
* region or the background region, because it would result in
|
|
||||||
* incorrect TLB hits for subsequent accesses to addresses that
|
|
||||||
* are in this MPU region.
|
|
||||||
*/
|
|
||||||
if (limit >= base &&
|
|
||||||
ranges_overlap(base, limit - base + 1,
|
|
||||||
addr_page_base,
|
|
||||||
TARGET_PAGE_SIZE)) {
|
|
||||||
*is_subpage = true;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (base > addr_page_base || limit < addr_page_limit) {
|
|
||||||
*is_subpage = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matchregion != -1) {
|
|
||||||
/* Multiple regions match -- always a failure (unlike
|
|
||||||
* PMSAv7 where highest-numbered-region wins)
|
|
||||||
*/
|
|
||||||
fi->type = ARMFault_Permission;
|
|
||||||
fi->level = 1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
matchregion = n;
|
|
||||||
hit = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hit) {
|
|
||||||
/* background fault */
|
|
||||||
fi->type = ARMFault_Background;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matchregion == -1) {
|
|
||||||
/* hit using the background region */
|
|
||||||
get_phys_addr_pmsav7_default(env, mmu_idx, address, prot);
|
|
||||||
} else {
|
|
||||||
uint32_t ap = extract32(env->pmsav8.rbar[secure][matchregion], 1, 2);
|
|
||||||
uint32_t xn = extract32(env->pmsav8.rbar[secure][matchregion], 0, 1);
|
|
||||||
bool pxn = false;
|
|
||||||
|
|
||||||
if (arm_feature(env, ARM_FEATURE_V8_1M)) {
|
|
||||||
pxn = extract32(env->pmsav8.rlar[secure][matchregion], 4, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_is_system_region(env, address)) {
|
|
||||||
/* System space is always execute never */
|
|
||||||
xn = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*prot = simple_ap_to_rw_prot(env, mmu_idx, ap);
|
|
||||||
if (*prot && !xn && !(pxn && !is_user)) {
|
|
||||||
*prot |= PAGE_EXEC;
|
|
||||||
}
|
|
||||||
/* We don't need to look the attribute up in the MAIR0/MAIR1
|
|
||||||
* registers because that only tells us about cacheability.
|
|
||||||
*/
|
|
||||||
if (mregion) {
|
|
||||||
*mregion = matchregion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fi->type = ARMFault_Permission;
|
|
||||||
fi->level = 1;
|
|
||||||
return !(*prot & (1 << access_type));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Combine either inner or outer cacheability attributes for normal
|
/* Combine either inner or outer cacheability attributes for normal
|
||||||
* memory, according to table D4-42 and pseudocode procedure
|
* memory, according to table D4-42 and pseudocode procedure
|
||||||
* CombineS1S2AttrHints() of ARM DDI 0487B.b (the ARMv8 ARM).
|
* CombineS1S2AttrHints() of ARM DDI 0487B.b (the ARMv8 ARM).
|
||||||
|
|
144
target/arm/ptw.c
144
target/arm/ptw.c
|
@ -375,8 +375,7 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_phys_addr_pmsav7_default(CPUARMState *env,
|
static void get_phys_addr_pmsav7_default(CPUARMState *env, ARMMMUIdx mmu_idx,
|
||||||
ARMMMUIdx mmu_idx,
|
|
||||||
int32_t address, int *prot)
|
int32_t address, int *prot)
|
||||||
{
|
{
|
||||||
if (!arm_feature(env, ARM_FEATURE_M)) {
|
if (!arm_feature(env, ARM_FEATURE_M)) {
|
||||||
|
@ -605,6 +604,147 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
|
||||||
return !(*prot & (1 << access_type));
|
return !(*prot & (1 << access_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
|
||||||
|
MMUAccessType access_type, ARMMMUIdx mmu_idx,
|
||||||
|
hwaddr *phys_ptr, MemTxAttrs *txattrs,
|
||||||
|
int *prot, bool *is_subpage,
|
||||||
|
ARMMMUFaultInfo *fi, uint32_t *mregion)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Perform a PMSAv8 MPU lookup (without also doing the SAU check
|
||||||
|
* that a full phys-to-virt translation does).
|
||||||
|
* mregion is (if not NULL) set to the region number which matched,
|
||||||
|
* or -1 if no region number is returned (MPU off, address did not
|
||||||
|
* hit a region, address hit in multiple regions).
|
||||||
|
* We set is_subpage to true if the region hit doesn't cover the
|
||||||
|
* entire TARGET_PAGE the address is within.
|
||||||
|
*/
|
||||||
|
ARMCPU *cpu = env_archcpu(env);
|
||||||
|
bool is_user = regime_is_user(env, mmu_idx);
|
||||||
|
uint32_t secure = regime_is_secure(env, mmu_idx);
|
||||||
|
int n;
|
||||||
|
int matchregion = -1;
|
||||||
|
bool hit = false;
|
||||||
|
uint32_t addr_page_base = address & TARGET_PAGE_MASK;
|
||||||
|
uint32_t addr_page_limit = addr_page_base + (TARGET_PAGE_SIZE - 1);
|
||||||
|
|
||||||
|
*is_subpage = false;
|
||||||
|
*phys_ptr = address;
|
||||||
|
*prot = 0;
|
||||||
|
if (mregion) {
|
||||||
|
*mregion = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unlike the ARM ARM pseudocode, we don't need to check whether this
|
||||||
|
* was an exception vector read from the vector table (which is always
|
||||||
|
* done using the default system address map), because those accesses
|
||||||
|
* are done in arm_v7m_load_vector(), which always does a direct
|
||||||
|
* read using address_space_ldl(), rather than going via this function.
|
||||||
|
*/
|
||||||
|
if (regime_translation_disabled(env, mmu_idx)) { /* MPU disabled */
|
||||||
|
hit = true;
|
||||||
|
} else if (m_is_ppb_region(env, address)) {
|
||||||
|
hit = true;
|
||||||
|
} else {
|
||||||
|
if (pmsav7_use_background_region(cpu, mmu_idx, is_user)) {
|
||||||
|
hit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) {
|
||||||
|
/* region search */
|
||||||
|
/*
|
||||||
|
* Note that the base address is bits [31:5] from the register
|
||||||
|
* with bits [4:0] all zeroes, but the limit address is bits
|
||||||
|
* [31:5] from the register with bits [4:0] all ones.
|
||||||
|
*/
|
||||||
|
uint32_t base = env->pmsav8.rbar[secure][n] & ~0x1f;
|
||||||
|
uint32_t limit = env->pmsav8.rlar[secure][n] | 0x1f;
|
||||||
|
|
||||||
|
if (!(env->pmsav8.rlar[secure][n] & 0x1)) {
|
||||||
|
/* Region disabled */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address < base || address > limit) {
|
||||||
|
/*
|
||||||
|
* Address not in this region. We must check whether the
|
||||||
|
* region covers addresses in the same page as our address.
|
||||||
|
* In that case we must not report a size that covers the
|
||||||
|
* whole page for a subsequent hit against a different MPU
|
||||||
|
* region or the background region, because it would result in
|
||||||
|
* incorrect TLB hits for subsequent accesses to addresses that
|
||||||
|
* are in this MPU region.
|
||||||
|
*/
|
||||||
|
if (limit >= base &&
|
||||||
|
ranges_overlap(base, limit - base + 1,
|
||||||
|
addr_page_base,
|
||||||
|
TARGET_PAGE_SIZE)) {
|
||||||
|
*is_subpage = true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base > addr_page_base || limit < addr_page_limit) {
|
||||||
|
*is_subpage = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchregion != -1) {
|
||||||
|
/*
|
||||||
|
* Multiple regions match -- always a failure (unlike
|
||||||
|
* PMSAv7 where highest-numbered-region wins)
|
||||||
|
*/
|
||||||
|
fi->type = ARMFault_Permission;
|
||||||
|
fi->level = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
matchregion = n;
|
||||||
|
hit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hit) {
|
||||||
|
/* background fault */
|
||||||
|
fi->type = ARMFault_Background;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchregion == -1) {
|
||||||
|
/* hit using the background region */
|
||||||
|
get_phys_addr_pmsav7_default(env, mmu_idx, address, prot);
|
||||||
|
} else {
|
||||||
|
uint32_t ap = extract32(env->pmsav8.rbar[secure][matchregion], 1, 2);
|
||||||
|
uint32_t xn = extract32(env->pmsav8.rbar[secure][matchregion], 0, 1);
|
||||||
|
bool pxn = false;
|
||||||
|
|
||||||
|
if (arm_feature(env, ARM_FEATURE_V8_1M)) {
|
||||||
|
pxn = extract32(env->pmsav8.rlar[secure][matchregion], 4, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_is_system_region(env, address)) {
|
||||||
|
/* System space is always execute never */
|
||||||
|
xn = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*prot = simple_ap_to_rw_prot(env, mmu_idx, ap);
|
||||||
|
if (*prot && !xn && !(pxn && !is_user)) {
|
||||||
|
*prot |= PAGE_EXEC;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We don't need to look the attribute up in the MAIR0/MAIR1
|
||||||
|
* registers because that only tells us about cacheability.
|
||||||
|
*/
|
||||||
|
if (mregion) {
|
||||||
|
*mregion = matchregion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fi->type = ARMFault_Permission;
|
||||||
|
fi->level = 1;
|
||||||
|
return !(*prot & (1 << access_type));
|
||||||
|
}
|
||||||
|
|
||||||
static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address,
|
static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address,
|
||||||
MMUAccessType access_type, ARMMMUIdx mmu_idx,
|
MMUAccessType access_type, ARMMMUIdx mmu_idx,
|
||||||
hwaddr *phys_ptr, MemTxAttrs *txattrs,
|
hwaddr *phys_ptr, MemTxAttrs *txattrs,
|
||||||
|
|
|
@ -36,9 +36,6 @@ simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap)
|
||||||
bool m_is_ppb_region(CPUARMState *env, uint32_t address);
|
bool m_is_ppb_region(CPUARMState *env, uint32_t address);
|
||||||
bool m_is_system_region(CPUARMState *env, uint32_t address);
|
bool m_is_system_region(CPUARMState *env, uint32_t address);
|
||||||
|
|
||||||
void get_phys_addr_pmsav7_default(CPUARMState *env,
|
|
||||||
ARMMMUIdx mmu_idx,
|
|
||||||
int32_t address, int *prot);
|
|
||||||
bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx, bool is_user);
|
bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx, bool is_user);
|
||||||
|
|
||||||
bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
|
bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue