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