target/sparc: Correctly handle bus errors in page table walks

Currently we use the ldl_phys() function to read page table entries.
With the unassigned_access hook in place, if these hit an unassigned
area of memory then the hook will cause us to wrongly generate
an exception with a fault address matching the address of the
page table entry.

Change to using address_space_ldl() so we can detect and correctly
handle bus errors and give them their correct behaviour of
causing a translation error with a suitable fault status register.

Note that this won't actually take effect until we switch the
over to using the do_translation_failed hook.

Backports commit 3c818dfcc271f5ba298b06f33466ab30f9a28349 from qemu
This commit is contained in:
Peter Maydell 2019-11-20 13:28:27 -05:00 committed by Lioncash
parent 13ed49dd35
commit 0d6cada970
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -96,6 +96,7 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
int error_code = 0, is_dirty, is_user; int error_code = 0, is_dirty, is_user;
unsigned long page_offset; unsigned long page_offset;
CPUState *cs = env_cpu(env); CPUState *cs = env_cpu(env);
MemTxResult result;
is_user = mmu_idx == MMU_USER_IDX; is_user = mmu_idx == MMU_USER_IDX;
@ -118,7 +119,10 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
/* SPARC reference MMU table walk: Context table->L1->L2->PTE */ /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
/* Context base + context number */ /* Context base + context number */
pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
pde = ldl_phys(cs->as, pde_ptr); pde = address_space_ldl(cs->as, pde_ptr, MEMTXATTRS_UNSPECIFIED, &result);
if (result != MEMTX_OK) {
return 4 << 2; /* Translation fault, L = 0 */
}
/* Ctx pde */ /* Ctx pde */
switch (pde & PTE_ENTRYTYPE_MASK) { switch (pde & PTE_ENTRYTYPE_MASK) {
@ -130,7 +134,11 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
return 4 << 2; return 4 << 2;
case 1: /* L0 PDE */ case 1: /* L0 PDE */
pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
pde = ldl_phys(cs->as, pde_ptr); pde = address_space_ldl(cs->as, pde_ptr,
MEMTXATTRS_UNSPECIFIED, &result);
if (result != MEMTX_OK) {
return (1 << 8) | (4 << 2); /* Translation fault, L = 1 */
}
switch (pde & PTE_ENTRYTYPE_MASK) { switch (pde & PTE_ENTRYTYPE_MASK) {
default: default:
@ -140,7 +148,11 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
return (1 << 8) | (4 << 2); return (1 << 8) | (4 << 2);
case 1: /* L1 PDE */ case 1: /* L1 PDE */
pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
pde = ldl_phys(cs->as, pde_ptr); pde = address_space_ldl(cs->as, pde_ptr,
MEMTXATTRS_UNSPECIFIED, &result);
if (result != MEMTX_OK) {
return (2 << 8) | (4 << 2); /* Translation fault, L = 2 */
}
switch (pde & PTE_ENTRYTYPE_MASK) { switch (pde & PTE_ENTRYTYPE_MASK) {
default: default:
@ -150,7 +162,11 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
return (2 << 8) | (4 << 2); return (2 << 8) | (4 << 2);
case 1: /* L2 PDE */ case 1: /* L2 PDE */
pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
pde = ldl_phys(cs->as, pde_ptr); pde = address_space_ldl(cs->as, pde_ptr,
MEMTXATTRS_UNSPECIFIED, &result);
if (result != MEMTX_OK) {
return (3 << 8) | (4 << 2); /* Translation fault, L = 3 */
}
switch (pde & PTE_ENTRYTYPE_MASK) { switch (pde & PTE_ENTRYTYPE_MASK) {
default: default: