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