xref: /openbmc/qemu/target/i386/tcg/access.c (revision d76795ea)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /* Access guest memory in blocks. */
3 
4 #include "qemu/osdep.h"
5 #include "cpu.h"
6 #include "exec/cpu_ldst.h"
7 #include "exec/exec-all.h"
8 #include "access.h"
9 
10 
11 void access_prepare_mmu(X86Access *ret, CPUX86State *env,
12                         vaddr vaddr, unsigned size,
13                         MMUAccessType type, int mmu_idx, uintptr_t ra)
14 {
15     int size1, size2;
16     void *haddr1, *haddr2;
17 
18     assert(size > 0 && size <= TARGET_PAGE_SIZE);
19 
20     size1 = MIN(size, -(vaddr | TARGET_PAGE_MASK)),
21     size2 = size - size1;
22 
23     memset(ret, 0, sizeof(*ret));
24     ret->vaddr = vaddr;
25     ret->size = size;
26     ret->size1 = size1;
27     ret->mmu_idx = mmu_idx;
28     ret->env = env;
29     ret->ra = ra;
30 
31     haddr1 = probe_access(env, vaddr, size1, type, mmu_idx, ra);
32     ret->haddr1 = haddr1;
33 
34     if (unlikely(size2)) {
35         haddr2 = probe_access(env, vaddr + size1, size2, type, mmu_idx, ra);
36         if (haddr2 == haddr1 + size1) {
37             ret->size1 = size;
38         } else {
39 #ifdef CONFIG_USER_ONLY
40             g_assert_not_reached();
41 #else
42             ret->haddr2 = haddr2;
43 #endif
44         }
45     }
46 }
47 
48 void access_prepare(X86Access *ret, CPUX86State *env, vaddr vaddr,
49                     unsigned size, MMUAccessType type, uintptr_t ra)
50 {
51     int mmu_idx = cpu_mmu_index(env_cpu(env), false);
52     access_prepare_mmu(ret, env, vaddr, size, type, mmu_idx, ra);
53 }
54 
55 static void *access_ptr(X86Access *ac, vaddr addr, unsigned len)
56 {
57     vaddr offset = addr - ac->vaddr;
58 
59     assert(addr >= ac->vaddr);
60 
61 #ifdef CONFIG_USER_ONLY
62     assert(offset <= ac->size1 - len);
63     return ac->haddr1 + offset;
64 #else
65     if (likely(offset <= ac->size1 - len)) {
66         return ac->haddr1 + offset;
67     }
68     assert(offset <= ac->size - len);
69     /*
70      * If the address is not naturally aligned, it might span both pages.
71      * Only return ac->haddr2 if the area is entirely within the second page,
72      * otherwise fall back to slow accesses.
73      */
74     if (likely(offset >= ac->size1)) {
75         return ac->haddr2 + (offset - ac->size1);
76     }
77     return NULL;
78 #endif
79 }
80 
81 #ifdef CONFIG_USER_ONLY
82 # define test_ptr(p)  true
83 #else
84 # define test_ptr(p)  likely(p)
85 #endif
86 
87 uint8_t access_ldb(X86Access *ac, vaddr addr)
88 {
89     void *p = access_ptr(ac, addr, sizeof(uint8_t));
90 
91     if (test_ptr(p)) {
92         return ldub_p(p);
93     }
94     return cpu_ldub_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
95 }
96 
97 uint16_t access_ldw(X86Access *ac, vaddr addr)
98 {
99     void *p = access_ptr(ac, addr, sizeof(uint16_t));
100 
101     if (test_ptr(p)) {
102         return lduw_le_p(p);
103     }
104     return cpu_lduw_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
105 }
106 
107 uint32_t access_ldl(X86Access *ac, vaddr addr)
108 {
109     void *p = access_ptr(ac, addr, sizeof(uint32_t));
110 
111     if (test_ptr(p)) {
112         return ldl_le_p(p);
113     }
114     return cpu_ldl_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
115 }
116 
117 uint64_t access_ldq(X86Access *ac, vaddr addr)
118 {
119     void *p = access_ptr(ac, addr, sizeof(uint64_t));
120 
121     if (test_ptr(p)) {
122         return ldq_le_p(p);
123     }
124     return cpu_ldq_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
125 }
126 
127 void access_stb(X86Access *ac, vaddr addr, uint8_t val)
128 {
129     void *p = access_ptr(ac, addr, sizeof(uint8_t));
130 
131     if (test_ptr(p)) {
132         stb_p(p, val);
133     } else {
134         cpu_stb_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
135     }
136 }
137 
138 void access_stw(X86Access *ac, vaddr addr, uint16_t val)
139 {
140     void *p = access_ptr(ac, addr, sizeof(uint16_t));
141 
142     if (test_ptr(p)) {
143         stw_le_p(p, val);
144     } else {
145         cpu_stw_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
146     }
147 }
148 
149 void access_stl(X86Access *ac, vaddr addr, uint32_t val)
150 {
151     void *p = access_ptr(ac, addr, sizeof(uint32_t));
152 
153     if (test_ptr(p)) {
154         stl_le_p(p, val);
155     } else {
156         cpu_stl_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
157     }
158 }
159 
160 void access_stq(X86Access *ac, vaddr addr, uint64_t val)
161 {
162     void *p = access_ptr(ac, addr, sizeof(uint64_t));
163 
164     if (test_ptr(p)) {
165         stq_le_p(p, val);
166     } else {
167         cpu_stq_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
168     }
169 }
170