xref: /qemu/semihosting/uaccess.c (revision 7cef6d686309e2792186504ae17cf4f3eb57ef68)
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 
uaccess_lock_user(CPUArchState * env,target_ulong addr,target_ulong len,bool copy)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 
uaccess_strlen_user(CPUArchState * env,target_ulong addr)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 
uaccess_lock_user_string(CPUArchState * env,target_ulong addr)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 
uaccess_unlock_user(CPUArchState * env,void * p,target_ulong addr,target_ulong len)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