/* * Helper routines to provide target memory access for semihosting * syscalls in system emulation mode. * * Copyright (c) 2007 CodeSourcery. * * This code is licensed under the GPL */ #include "qemu/osdep.h" #include "exec/exec-all.h" #include "semihosting/uaccess.h" void *uaccess_lock_user(CPUArchState *env, target_ulong addr, target_ulong len, bool copy) { void *p = malloc(len); if (p && copy) { if (cpu_memory_rw_debug(env_cpu(env), addr, p, len, 0)) { free(p); p = NULL; } } return p; } ssize_t uaccess_strlen_user(CPUArchState *env, target_ulong addr) { int mmu_idx = cpu_mmu_index(env, false); size_t len = 0; while (1) { size_t left_in_page; int flags; void *h; /* Find the number of bytes remaining in the page. */ left_in_page = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK); flags = probe_access_flags(env, addr, 0, MMU_DATA_LOAD, mmu_idx, true, &h, 0); if (flags & TLB_INVALID_MASK) { return -1; } if (flags & TLB_MMIO) { do { uint8_t c; if (cpu_memory_rw_debug(env_cpu(env), addr, &c, 1, 0)) { return -1; } if (c == 0) { return len; } addr++; len++; if (len > INT32_MAX) { return -1; } } while (--left_in_page != 0); } else { char *p = memchr(h, 0, left_in_page); if (p) { len += p - (char *)h; return len <= INT32_MAX ? (ssize_t)len : -1; } addr += left_in_page; len += left_in_page; if (len > INT32_MAX) { return -1; } } } } char *uaccess_lock_user_string(CPUArchState *env, target_ulong addr) { ssize_t len = uaccess_strlen_user(env, addr); if (len < 0) { return NULL; } return uaccess_lock_user(env, addr, len + 1, true); } void uaccess_unlock_user(CPUArchState *env, void *p, target_ulong addr, target_ulong len) { if (len) { cpu_memory_rw_debug(env_cpu(env), addr, p, len, 1); } free(p); }