diff options
Diffstat (limited to 'hw/semihosting/arm-compat-semi.c')
-rw-r--r-- | hw/semihosting/arm-compat-semi.c | 43 |
1 files changed, 42 insertions, 1 deletions
diff --git a/hw/semihosting/arm-compat-semi.c b/hw/semihosting/arm-compat-semi.c index ac1271545e..293791f721 100644 --- a/hw/semihosting/arm-compat-semi.c +++ b/hw/semihosting/arm-compat-semi.c @@ -137,6 +137,36 @@ typedef struct GuestFD { static GArray *guestfd_array; +#ifndef CONFIG_USER_ONLY +#include "exec/address-spaces.h" +/* + * Find the base of a RAM region containing the specified address + */ +static inline hwaddr +common_semi_find_region_base(hwaddr addr) +{ + MemoryRegion *subregion; + + /* + * Find the chunk of R/W memory containing the address. This is + * used for the SYS_HEAPINFO semihosting call, which should + * probably be using information from the loaded application. + */ + QTAILQ_FOREACH(subregion, &get_system_memory()->subregions, + subregions_link) { + if (subregion->ram && !subregion->readonly) { + Int128 top128 = int128_add(int128_make64(subregion->addr), + subregion->size); + Int128 addr128 = int128_make64(addr); + if (subregion->addr <= addr && int128_lt(addr128, top128)) { + return subregion->addr; + } + } + } + return 0; +} +#endif + #ifdef TARGET_ARM static inline target_ulong common_semi_arg(CPUState *cs, int argno) @@ -175,7 +205,18 @@ common_semi_rambase(CPUState *cs) { CPUArchState *env = cs->env_ptr; const struct arm_boot_info *info = env->boot_info; - return info->loader_start; + target_ulong sp; + + if (info) { + return info->loader_start; + } + + if (is_a64(env)) { + sp = env->xregs[31]; + } else { + sp = env->regs[13]; + } + return common_semi_find_region_base(sp); } #endif |