| /* |
| * 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_cpu(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); |
| } |