root / linux-user / uaccess.c @ 6a24a778
History | View | Annotate | Download (1.8 kB)
1 | 579a97f7 | bellard | /* User memory access */
|
---|---|---|---|
2 | 579a97f7 | bellard | #include <stdio.h> |
3 | 579a97f7 | bellard | #include <string.h> |
4 | 579a97f7 | bellard | |
5 | 579a97f7 | bellard | #include "qemu.h" |
6 | 579a97f7 | bellard | |
7 | 579a97f7 | bellard | /* copy_from_user() and copy_to_user() are usually used to copy data
|
8 | 579a97f7 | bellard | * buffers between the target and host. These internally perform
|
9 | 579a97f7 | bellard | * locking/unlocking of the memory.
|
10 | 579a97f7 | bellard | */
|
11 | 579a97f7 | bellard | abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len)
|
12 | 579a97f7 | bellard | { |
13 | 579a97f7 | bellard | abi_long ret = 0;
|
14 | 579a97f7 | bellard | void *ghptr;
|
15 | 579a97f7 | bellard | |
16 | 579a97f7 | bellard | if ((ghptr = lock_user(VERIFY_READ, gaddr, len, 1))) { |
17 | 579a97f7 | bellard | memcpy(hptr, ghptr, len); |
18 | 579a97f7 | bellard | unlock_user(ghptr, gaddr, 0);
|
19 | 579a97f7 | bellard | } else
|
20 | 579a97f7 | bellard | ret = -TARGET_EFAULT; |
21 | 579a97f7 | bellard | |
22 | 579a97f7 | bellard | return ret;
|
23 | 579a97f7 | bellard | } |
24 | 579a97f7 | bellard | |
25 | 579a97f7 | bellard | |
26 | 579a97f7 | bellard | abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len)
|
27 | 579a97f7 | bellard | { |
28 | 579a97f7 | bellard | abi_long ret = 0;
|
29 | 579a97f7 | bellard | void *ghptr;
|
30 | 579a97f7 | bellard | |
31 | 579a97f7 | bellard | if ((ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0))) { |
32 | 579a97f7 | bellard | memcpy(ghptr, hptr, len); |
33 | 579a97f7 | bellard | unlock_user(ghptr, gaddr, len); |
34 | 579a97f7 | bellard | } else
|
35 | 579a97f7 | bellard | ret = -TARGET_EFAULT; |
36 | 579a97f7 | bellard | |
37 | 579a97f7 | bellard | return ret;
|
38 | 579a97f7 | bellard | } |
39 | 579a97f7 | bellard | |
40 | 3dd98412 | bellard | /* XXX: use host strnlen if available ? */
|
41 | 3dd98412 | bellard | static int qemu_strnlen(const char *s, int max_len) |
42 | 3dd98412 | bellard | { |
43 | 3dd98412 | bellard | int i;
|
44 | 3dd98412 | bellard | for(i = 0; i < max_len; i++) { |
45 | 3dd98412 | bellard | if (s[i] == '\0') |
46 | 3dd98412 | bellard | break;
|
47 | 3dd98412 | bellard | } |
48 | 3dd98412 | bellard | return i;
|
49 | 3dd98412 | bellard | } |
50 | 579a97f7 | bellard | |
51 | 3dd98412 | bellard | /* Return the length of a string in target memory or -TARGET_EFAULT if
|
52 | 3dd98412 | bellard | access error */
|
53 | 3dd98412 | bellard | abi_long target_strlen(abi_ulong guest_addr1) |
54 | 579a97f7 | bellard | { |
55 | 3dd98412 | bellard | uint8_t *ptr; |
56 | 3dd98412 | bellard | abi_ulong guest_addr; |
57 | 3dd98412 | bellard | int max_len, len;
|
58 | 3dd98412 | bellard | |
59 | 3dd98412 | bellard | guest_addr = guest_addr1; |
60 | 3dd98412 | bellard | for(;;) {
|
61 | 3dd98412 | bellard | max_len = TARGET_PAGE_SIZE - (guest_addr & ~TARGET_PAGE_MASK); |
62 | 3dd98412 | bellard | ptr = lock_user(VERIFY_READ, guest_addr, max_len, 1);
|
63 | 3dd98412 | bellard | if (!ptr)
|
64 | 3dd98412 | bellard | return -TARGET_EFAULT;
|
65 | 3dd98412 | bellard | len = qemu_strnlen(ptr, max_len); |
66 | 3dd98412 | bellard | unlock_user(ptr, guest_addr, 0);
|
67 | 3dd98412 | bellard | guest_addr += len; |
68 | 3dd98412 | bellard | /* we don't allow wrapping or integer overflow */
|
69 | 3dd98412 | bellard | if (guest_addr == 0 || |
70 | 3dd98412 | bellard | (guest_addr - guest_addr1) > 0x7fffffff)
|
71 | 3dd98412 | bellard | return -TARGET_EFAULT;
|
72 | 3dd98412 | bellard | if (len != max_len)
|
73 | 3dd98412 | bellard | break;
|
74 | 3dd98412 | bellard | } |
75 | 3dd98412 | bellard | return guest_addr - guest_addr1;
|
76 | 579a97f7 | bellard | } |