1 /* 2 * Helper routines to provide target memory access for semihosting 3 * syscalls in system emulation mode. 4 * 5 * Copyright (c) 2007 CodeSourcery. 6 * 7 * This code is licensed under the GPL 8 */ 9 10 #include "qemu/osdep.h" 11 #include "exec/cpu-all.h" 12 #include "exec/exec-all.h" 13 #include "semihosting/uaccess.h" 14 15 void *uaccess_lock_user(CPUArchState *env, target_ulong addr, 16 target_ulong len, bool copy) 17 { 18 void *p = malloc(len); 19 if (p && copy) { 20 if (cpu_memory_rw_debug(env_cpu(env), addr, p, len, 0)) { 21 free(p); 22 p = NULL; 23 } 24 } 25 return p; 26 } 27 28 ssize_t uaccess_strlen_user(CPUArchState *env, target_ulong addr) 29 { 30 int mmu_idx = cpu_mmu_index(env_cpu(env), false); 31 size_t len = 0; 32 33 while (1) { 34 size_t left_in_page; 35 int flags; 36 void *h; 37 38 /* Find the number of bytes remaining in the page. */ 39 left_in_page = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK); 40 41 flags = probe_access_flags(env, addr, 0, MMU_DATA_LOAD, 42 mmu_idx, true, &h, 0); 43 if (flags & TLB_INVALID_MASK) { 44 return -1; 45 } 46 if (flags & TLB_MMIO) { 47 do { 48 uint8_t c; 49 if (cpu_memory_rw_debug(env_cpu(env), addr, &c, 1, 0)) { 50 return -1; 51 } 52 if (c == 0) { 53 return len; 54 } 55 addr++; 56 len++; 57 if (len > INT32_MAX) { 58 return -1; 59 } 60 } while (--left_in_page != 0); 61 } else { 62 char *p = memchr(h, 0, left_in_page); 63 if (p) { 64 len += p - (char *)h; 65 return len <= INT32_MAX ? (ssize_t)len : -1; 66 } 67 addr += left_in_page; 68 len += left_in_page; 69 if (len > INT32_MAX) { 70 return -1; 71 } 72 } 73 } 74 } 75 76 char *uaccess_lock_user_string(CPUArchState *env, target_ulong addr) 77 { 78 ssize_t len = uaccess_strlen_user(env, addr); 79 if (len < 0) { 80 return NULL; 81 } 82 return uaccess_lock_user(env, addr, len + 1, true); 83 } 84 85 void uaccess_unlock_user(CPUArchState *env, void *p, 86 target_ulong addr, target_ulong len) 87 { 88 if (len) { 89 cpu_memory_rw_debug(env_cpu(env), addr, p, len, 1); 90 } 91 free(p); 92 } 93