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