From: Peter Maydell <[email protected]> In cpu_memory_rw_debug() we need to do a virtual-to-physical address translation for debug access. Currently we assume that the translation is valid for an entire guest page, but this may not be true if the target implements some protection regions that have sub-page granularity. (Currently the only such target is the Arm CPUs when using an MPU, as in R-profile and M-profile.)
For TCG's emulated accesses, we handle sub-page granularity by the CPU filling in the lg_page_size field of the CPUTLBEntryFull struct to tell us how large the region covered by the result is. But we didn't extend this to the debug-access code path, with the result that debug accesses might incorrectly fail because they are looking at the mapping for the address rounded down to a page boundary. Provide a cpu_translate_for_debug() function which reports to the caller not just the physical address and attributes of the translation but also the lg_page_size for which it is valid. The fallback implementation calls cpu_get_phys_addr_attrs_debug() and assumes target-page-sized validity. NB: the "return true on valid access, false on failure" follows the same convention as TCGCPUOps::tlb_fill_align() (though it is the opposite of what we use in some other places, e.g. in target/arm's get_phys_addr_* functions). Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Philippe Mathieu-Daudé <[email protected]> Message-id: [email protected] Reviewed-by: Richard Henderson <[email protected]> Message-ID: <[email protected]> Signed-off-by: Philippe Mathieu-Daudé <[email protected]> --- include/hw/core/cpu.h | 32 ++++++++++++++++++++++++++++++++ include/hw/core/sysemu-cpu-ops.h | 27 +++++++++++++++++++++++++-- hw/core/cpu-system.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index e3436a1766f..a7256aeb9dc 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -772,6 +772,38 @@ hwaddr cpu_get_phys_addr_attrs_debug(CPUState *cpu, vaddr addr, */ hwaddr cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr); +/** + * TranslateForDebugResult: gives result of cpu_translate_for_debug() + * + * @physaddr: the physical address corresponding to the virtual address + * @attrs: the transaction attributes for this access + * @lg_page_size: log2 of the size of the aligned block of memory + * that this physaddr and attrs are valid for. + */ +typedef struct TranslateForDebugResult { + hwaddr physaddr; + MemTxAttrs attrs; + uint8_t lg_page_size; +} TranslateForDebugResult; + +/** + * cpu_translate_for_debug: + * @cpu: The CPU use for the virtual-to-physical translation + * @addr: The virtual address + * @result: Struct filled in with results of translation + * + * Perform a virtual-to-physical address translation for debug accesses. + * Use it only for debugging because no protection checks are done. + * + * The address need not be page-aligned; the returned address in @result + * will be the physical address corresponding to that virtual address. + * + * Returns: false on translation failure; true on successful translation + * and fills in the fields of @result. + */ +bool cpu_translate_for_debug(CPUState *cpu, vaddr addr, + TranslateForDebugResult *result); + /** cpu_asidx_from_attrs: * @cpu: CPU * @attrs: memory transaction attributes diff --git a/include/hw/core/sysemu-cpu-ops.h b/include/hw/core/sysemu-cpu-ops.h index c0e9e726708..441901fae8e 100644 --- a/include/hw/core/sysemu-cpu-ops.h +++ b/include/hw/core/sysemu-cpu-ops.h @@ -33,19 +33,42 @@ typedef struct SysemuCPUOps { * @get_phys_addr_debug: Callback for obtaining a physical address. * This must be able to handle a non-page-aligned address, and will * return the physical address corresponding to that address. + * + * CPUs should prefer to implement translate_for_debug instead of + * this (and must do so if their translations are not always valid + * for a complete target page or they use memory attributes). */ hwaddr (*get_phys_addr_debug)(CPUState *cpu, vaddr addr); /** * @get_phys_addr_attrs_debug: Callback for obtaining a physical address * and the associated memory transaction attributes to use for the * access. - * CPUs which use memory transaction attributes should implement this - * instead of get_phys_addr_debug. + * * This must be able to handle a non-page-aligned address, and will * return the physical address corresponding to that address. + * + * CPUs should prefer to implement translate_for_debug instead of + * this (and must do so if their translations are not always valid + * for a complete target page). */ hwaddr (*get_phys_addr_attrs_debug)(CPUState *cpu, vaddr addr, MemTxAttrs *attrs); + /** + * @translate_for_debug: Callback for translating a virtual address into + * a physical address for debug purposes. + * The implementation should fill in @result with the physical address, + * transaction attributes, and log2 of the size of the aligned block of + * memory that the translation is valid for. + * This must be able to handle a non-page-aligned address, and will + * return the physical address corresponding to that address. + * The attributes must include the debug flag being set. + * Returns false on translation failure; on success returns true and + * fills in @result. + * + * This is the preferred method to implement for new CPUs. + */ + bool (*translate_for_debug)(CPUState *cpu, vaddr addr, + TranslateForDebugResult *result); /** * @asidx_from_attrs: Callback to return the CPU AddressSpace to use for * a memory access with the specified memory transaction attributes. diff --git a/hw/core/cpu-system.c b/hw/core/cpu-system.c index 05c126ecb6b..252e90c8fdf 100644 --- a/hw/core/cpu-system.c +++ b/hw/core/cpu-system.c @@ -22,6 +22,7 @@ #include "qapi/error.h" #include "system/address-spaces.h" #include "exec/cputlb.h" +#include "exec/target_page.h" #include "system/memory.h" #include "qemu/target-info.h" #include "hw/core/qdev.h" @@ -55,6 +56,37 @@ bool cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, return false; } +bool cpu_translate_for_debug(CPUState *cpu, vaddr addr, + TranslateForDebugResult *result) +{ + if (cpu->cc->sysemu_ops->translate_for_debug) { + return cpu->cc->sysemu_ops->translate_for_debug(cpu, addr, result); + } else { + /* Fallbacks for CPUs which don't implement translate_for_debug */ + if (cpu->cc->sysemu_ops->get_phys_addr_attrs_debug) { + result->physaddr = + cpu->cc->sysemu_ops->get_phys_addr_attrs_debug(cpu, addr, + &result->attrs); + } else { + result->physaddr + = cpu->cc->sysemu_ops->get_phys_addr_debug(cpu, addr); + result->attrs = MEMTXATTRS_UNSPECIFIED; + } + if (result->physaddr == -1) { + return false; + } + /* Indicate that this is a debug access. */ + result->attrs.debug = 1; + /* + * Assume memory access permissions are valid for the whole page. + * Targets where this isn't true should implement the + * translate_for_debug method. + */ + result->lg_page_size = TARGET_PAGE_BITS; + return true; + } +} + hwaddr cpu_get_phys_addr_attrs_debug(CPUState *cpu, vaddr addr, MemTxAttrs *attrs) { -- 2.53.0
