memory_region_access_valid() returns true and false and nothing else, but it makes distintions between error types that we can see via each error_log message: if mr->ops->valid.accepts fails the reason is set to "rejected", reason is set to "unaligned" if addr is unaligned and reason is set to "invalid size" if size is less that min_access_size or greater than max_access_size.
We're particularly interested in the "reason: rejected" result. In RISC-V this is thrown when the mem_op tries to access a protected page, and we need to throw a special exception for this case. memory_region_dispatch_read() (and write()) will default to MEMTX_DECODE_ERROR because memory_region_access_valid() does not give additional info when it fails, and back in the RISC-V side we're having to make assumptions to determine that this MEMTX_DECODE_ERROR is in fact a "rejected" error type. Add a new MemTxResult arg in memory_region_access_valid() that the funcion will use to set the reason why it failed. Based on the error reasons (described above) and the definition of each MemTxResult, we're setting the following results: - result ok: MEMTX_OK - rejected: MEMTX_ACCESS_ERROR - all other errors: MEMTX_DECODE_ERROR Existing callers are unchanged. No behavioral change is intended for now. Signed-off-by: Daniel Henrique Barboza <[email protected]> --- hw/s390x/s390-pci-inst.c | 2 +- include/system/memory.h | 2 +- system/memory.c | 20 +++++++++++++++++--- system/physmem.c | 3 ++- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 10066ca618..877ed84b94 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -904,7 +904,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, for (i = 0; i < len; i += 8) { if (!memory_region_access_valid(mr, offset + i, 8, true, - MEMTXATTRS_UNSPECIFIED)) { + MEMTXATTRS_UNSPECIFIED, NULL)) { s390_program_interrupt(env, PGM_OPERAND, ra); return 0; } diff --git a/include/system/memory.h b/include/system/memory.h index 1417132f6d..d74fae52e3 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -2602,7 +2602,7 @@ void mtree_info(bool flatview, bool dispatch_tree, bool owner, bool disabled); bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr, unsigned size, bool is_write, - MemTxAttrs attrs); + MemTxAttrs attrs, MemTxResult *result); /** * memory_region_dispatch_read: perform a read directly to the specified diff --git a/system/memory.c b/system/memory.c index 739ba11da6..48348edb96 100644 --- a/system/memory.c +++ b/system/memory.c @@ -1403,14 +1403,22 @@ bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr, unsigned size, bool is_write, - MemTxAttrs attrs) + MemTxAttrs attrs, + MemTxResult *result) { + if (result) { + *result = MEMTX_OK; + } + if (mr->ops->valid.accepts && !mr->ops->valid.accepts(mr->opaque, addr, size, is_write, attrs)) { qemu_log_mask(LOG_INVALID_MEM, "Invalid %s at addr 0x%" HWADDR_PRIX ", size %u, region '%s', reason: rejected\n", is_write ? "write" : "read", addr, size, memory_region_name(mr)); + if (result) { + *result = MEMTX_ACCESS_ERROR; + } return false; } @@ -1419,6 +1427,9 @@ bool memory_region_access_valid(MemoryRegion *mr, ", size %u, region '%s', reason: unaligned\n", is_write ? "write" : "read", addr, size, memory_region_name(mr)); + if (result) { + *result = MEMTX_DECODE_ERROR; + } return false; } @@ -1436,6 +1447,9 @@ bool memory_region_access_valid(MemoryRegion *mr, addr, size, memory_region_name(mr), mr->ops->valid.min_access_size, mr->ops->valid.max_access_size); + if (result) { + *result = MEMTX_DECODE_ERROR; + } return false; } return true; @@ -1478,7 +1492,7 @@ MemTxResult memory_region_dispatch_read(MemoryRegion *mr, mr->alias_offset + addr, pval, op, attrs); } - if (!memory_region_access_valid(mr, addr, size, false, attrs)) { + if (!memory_region_access_valid(mr, addr, size, false, attrs, NULL)) { *pval = unassigned_mem_read(mr, addr, size); return MEMTX_DECODE_ERROR; } @@ -1527,7 +1541,7 @@ MemTxResult memory_region_dispatch_write(MemoryRegion *mr, mr->alias_offset + addr, data, op, attrs); } - if (!memory_region_access_valid(mr, addr, size, true, attrs)) { + if (!memory_region_access_valid(mr, addr, size, true, attrs, NULL)) { unassigned_mem_write(mr, addr, data, size); return MEMTX_DECODE_ERROR; } diff --git a/system/physmem.c b/system/physmem.c index 7bcbf87573..a0f77aae66 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -3635,7 +3635,8 @@ static bool flatview_access_valid(FlatView *fv, hwaddr addr, hwaddr len, mr = flatview_translate(fv, addr, &xlat, &l, is_write, attrs); if (!memory_access_is_direct(mr, is_write, attrs)) { l = memory_access_size(mr, l, addr); - if (!memory_region_access_valid(mr, xlat, l, is_write, attrs)) { + if (!memory_region_access_valid(mr, xlat, l, is_write, attrs, + NULL)) { return false; } } -- 2.43.0
