1 /* User memory access */ 2 #include "qemu/osdep.h" 3 #include "qemu/cutils.h" 4 5 #include "qemu.h" 6 7 void *lock_user(int type, abi_ulong guest_addr, size_t len, bool copy) 8 { 9 void *host_addr; 10 11 guest_addr = cpu_untagged_addr(thread_cpu, guest_addr); 12 if (!access_ok_untagged(type, guest_addr, len)) { 13 return NULL; 14 } 15 host_addr = g2h_untagged(guest_addr); 16 #ifdef DEBUG_REMAP 17 if (copy) { 18 host_addr = g_memdup(host_addr, len); 19 } else { 20 host_addr = g_malloc0(len); 21 } 22 #endif 23 return host_addr; 24 } 25 26 #ifdef DEBUG_REMAP 27 void unlock_user(void *host_ptr, abi_ulong guest_addr, size_t len); 28 { 29 void *host_ptr_conv; 30 31 if (!host_ptr) { 32 return; 33 } 34 host_ptr_conv = g2h(thread_cpu, guest_addr); 35 if (host_ptr == host_ptr_conv) { 36 return; 37 } 38 if (len != 0) { 39 memcpy(host_ptr_conv, host_ptr, len); 40 } 41 g_free(host_ptr); 42 } 43 #endif 44 45 void *lock_user_string(abi_ulong guest_addr) 46 { 47 ssize_t len = target_strlen(guest_addr); 48 if (len < 0) { 49 return NULL; 50 } 51 return lock_user(VERIFY_READ, guest_addr, (size_t)len + 1, 1); 52 } 53 54 /* copy_from_user() and copy_to_user() are usually used to copy data 55 * buffers between the target and host. These internally perform 56 * locking/unlocking of the memory. 57 */ 58 int copy_from_user(void *hptr, abi_ulong gaddr, size_t len) 59 { 60 int ret = 0; 61 void *ghptr = lock_user(VERIFY_READ, gaddr, len, 1); 62 63 if (ghptr) { 64 memcpy(hptr, ghptr, len); 65 unlock_user(ghptr, gaddr, 0); 66 } else { 67 ret = -TARGET_EFAULT; 68 } 69 return ret; 70 } 71 72 int copy_to_user(abi_ulong gaddr, void *hptr, size_t len) 73 { 74 int ret = 0; 75 void *ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0); 76 77 if (ghptr) { 78 memcpy(ghptr, hptr, len); 79 unlock_user(ghptr, gaddr, len); 80 } else { 81 ret = -TARGET_EFAULT; 82 } 83 84 return ret; 85 } 86 87 /* Return the length of a string in target memory or -TARGET_EFAULT if 88 access error */ 89 ssize_t target_strlen(abi_ulong guest_addr1) 90 { 91 uint8_t *ptr; 92 abi_ulong guest_addr; 93 size_t max_len, len; 94 95 guest_addr = guest_addr1; 96 for(;;) { 97 max_len = TARGET_PAGE_SIZE - (guest_addr & ~TARGET_PAGE_MASK); 98 ptr = lock_user(VERIFY_READ, guest_addr, max_len, 1); 99 if (!ptr) 100 return -TARGET_EFAULT; 101 len = qemu_strnlen((const char *)ptr, max_len); 102 unlock_user(ptr, guest_addr, 0); 103 guest_addr += len; 104 /* we don't allow wrapping or integer overflow */ 105 if (guest_addr == 0 || (guest_addr - guest_addr1) > 0x7fffffff) { 106 return -TARGET_EFAULT; 107 } 108 if (len != max_len) { 109 break; 110 } 111 } 112 return guest_addr - guest_addr1; 113 } 114