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 "accel/tcg/cpu-mmu-index.h" 13 #include "exec/exec-all.h" 14 #include "exec/target_page.h" 15 #include "exec/tlb-flags.h" 16 #include "semihosting/uaccess.h" 17 18 void *uaccess_lock_user(CPUArchState *env, target_ulong addr, 19 target_ulong len, bool copy) 20 { 21 void *p = malloc(len); 22 if (p && copy) { 23 if (cpu_memory_rw_debug(env_cpu(env), addr, p, len, 0)) { 24 free(p); 25 p = NULL; 26 } 27 } 28 return p; 29 } 30 31 ssize_t uaccess_strlen_user(CPUArchState *env, target_ulong addr) 32 { 33 int mmu_idx = cpu_mmu_index(env_cpu(env), false); 34 size_t len = 0; 35 36 while (1) { 37 size_t left_in_page; 38 int flags; 39 void *h; 40 41 /* Find the number of bytes remaining in the page. */ 42 left_in_page = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK); 43 44 flags = probe_access_flags(env, addr, 0, MMU_DATA_LOAD, 45 mmu_idx, true, &h, 0); 46 if (flags & TLB_INVALID_MASK) { 47 return -1; 48 } 49 if (flags & TLB_MMIO) { 50 do { 51 uint8_t c; 52 if (cpu_memory_rw_debug(env_cpu(env), addr, &c, 1, 0)) { 53 return -1; 54 } 55 if (c == 0) { 56 return len; 57 } 58 addr++; 59 len++; 60 if (len > INT32_MAX) { 61 return -1; 62 } 63 } while (--left_in_page != 0); 64 } else { 65 char *p = memchr(h, 0, left_in_page); 66 if (p) { 67 len += p - (char *)h; 68 return len <= INT32_MAX ? (ssize_t)len : -1; 69 } 70 addr += left_in_page; 71 len += left_in_page; 72 if (len > INT32_MAX) { 73 return -1; 74 } 75 } 76 } 77 } 78 79 char *uaccess_lock_user_string(CPUArchState *env, target_ulong addr) 80 { 81 ssize_t len = uaccess_strlen_user(env, addr); 82 if (len < 0) { 83 return NULL; 84 } 85 return uaccess_lock_user(env, addr, len + 1, true); 86 } 87 88 void uaccess_unlock_user(CPUArchState *env, void *p, 89 target_ulong addr, target_ulong len) 90 { 91 if (len) { 92 cpu_memory_rw_debug(env_cpu(env), addr, p, len, 1); 93 } 94 free(p); 95 } 96