1 /*
2 * Software MMU support
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "qemu-timer.h"
20
21 #define DATA_SIZE (1 << SHIFT)
22
23 #if DATA_SIZE == 8
24 #define SUFFIX q
25 #define USUFFIX q
26 #define DATA_TYPE uint64_t
27 #elif DATA_SIZE == 4
28 #define SUFFIX l
29 #define USUFFIX l
30 #define DATA_TYPE uint32_t
31 #elif DATA_SIZE == 2
32 #define SUFFIX w
33 #define USUFFIX uw
34 #define DATA_TYPE uint16_t
35 #elif DATA_SIZE == 1
36 #define SUFFIX b
37 #define USUFFIX ub
38 #define DATA_TYPE uint8_t
39 #else
40 #error unsupported data size
41 #endif
42
43 #ifdef SOFTMMU_CODE_ACCESS
44 #define READ_ACCESS_TYPE 2
45 #define ADDR_READ addr_code
46 #else
47 #define READ_ACCESS_TYPE 0
48 #define ADDR_READ addr_read
49 #endif
50
51 #if defined(CONFIG_MEMCHECK) && !defined(OUTSIDE_JIT) && !defined(SOFTMMU_CODE_ACCESS)
52 /*
53 * Support for memory access checker.
54 * We need to instrument __ldx/__stx_mmu routines implemented in this file with
55 * callbacks to access validation routines implemented by the memory checker.
56 * Note that (at least for now) we don't do that instrumentation for memory
57 * addressing the code (SOFTMMU_CODE_ACCESS controls that). Also, we don't want
58 * to instrument code that is used by emulator itself (OUTSIDE_JIT controls
59 * that).
60 */
61 #define CONFIG_MEMCHECK_MMU
62 #include "memcheck/memcheck_api.h"
63 #endif // CONFIG_MEMCHECK && !OUTSIDE_JIT && !SOFTMMU_CODE_ACCESS
64
65 static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
66 int mmu_idx,
67 void *retaddr);
glue(io_read,SUFFIX)68 static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr,
69 target_ulong addr,
70 void *retaddr)
71 {
72 DATA_TYPE res;
73 int index;
74 index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
75 physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
76 env->mem_io_pc = (unsigned long)retaddr;
77 if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT)
78 && !can_do_io(env)) {
79 cpu_io_recompile(env, retaddr);
80 }
81
82 env->mem_io_vaddr = addr;
83 #if SHIFT <= 2
84 res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr);
85 #else
86 #ifdef TARGET_WORDS_BIGENDIAN
87 res = (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr) << 32;
88 res |= io_mem_read[index][2](io_mem_opaque[index], physaddr + 4);
89 #else
90 res = io_mem_read[index][2](io_mem_opaque[index], physaddr);
91 res |= (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr + 4) << 32;
92 #endif
93 #endif /* SHIFT > 2 */
94 return res;
95 }
96
97 /* handle all cases except unaligned access which span two pages */
glue(glue (__ld,SUFFIX),MMUSUFFIX)98 DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
99 int mmu_idx)
100 {
101 DATA_TYPE res;
102 int index;
103 target_ulong tlb_addr;
104 target_phys_addr_t ioaddr;
105 unsigned long addend;
106 void *retaddr;
107 #ifdef CONFIG_MEMCHECK_MMU
108 int invalidate_cache = 0;
109 #endif // CONFIG_MEMCHECK_MMU
110
111 /* test if there is match for unaligned or IO access */
112 /* XXX: could done more in memory macro in a non portable way */
113 index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
114 redo:
115 tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
116 if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
117 if (tlb_addr & ~TARGET_PAGE_MASK) {
118 /* IO access */
119 if ((addr & (DATA_SIZE - 1)) != 0)
120 goto do_unaligned_access;
121 retaddr = GETPC();
122 ioaddr = env->iotlb[mmu_idx][index];
123 res = glue(io_read, SUFFIX)(ioaddr, addr, retaddr);
124 } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
125 /* This is not I/O access: do access verification. */
126 #ifdef CONFIG_MEMCHECK_MMU
127 /* We only validate access to the guest's user space, for which
128 * mmu_idx is set to 1. */
129 if (memcheck_instrument_mmu && mmu_idx == 1 &&
130 memcheck_validate_ld(addr, DATA_SIZE, (target_ulong)(ptrdiff_t)GETPC())) {
131 /* Memory read breaks page boundary. So, if required, we
132 * must invalidate two caches in TLB. */
133 invalidate_cache = 2;
134 }
135 #endif // CONFIG_MEMCHECK_MMU
136 /* slow unaligned access (it spans two pages or IO) */
137 do_unaligned_access:
138 retaddr = GETPC();
139 #ifdef ALIGNED_ONLY
140 do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
141 #endif
142 res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr,
143 mmu_idx, retaddr);
144 } else {
145 #ifdef CONFIG_MEMCHECK_MMU
146 /* We only validate access to the guest's user space, for which
147 * mmu_idx is set to 1. */
148 if (memcheck_instrument_mmu && mmu_idx == 1) {
149 invalidate_cache = memcheck_validate_ld(addr, DATA_SIZE,
150 (target_ulong)(ptrdiff_t)GETPC());
151 }
152 #endif // CONFIG_MEMCHECK_MMU
153 /* unaligned/aligned access in the same page */
154 #ifdef ALIGNED_ONLY
155 if ((addr & (DATA_SIZE - 1)) != 0) {
156 retaddr = GETPC();
157 do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
158 }
159 #endif
160 addend = env->tlb_table[mmu_idx][index].addend;
161 res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend));
162 }
163 #ifdef CONFIG_MEMCHECK_MMU
164 if (invalidate_cache) {
165 /* Accessed memory is under memchecker control. We must invalidate
166 * containing page(s) in order to make sure that next access to them
167 * will invoke _ld/_st_mmu. */
168 env->tlb_table[mmu_idx][index].addr_read ^= TARGET_PAGE_MASK;
169 env->tlb_table[mmu_idx][index].addr_write ^= TARGET_PAGE_MASK;
170 if ((invalidate_cache == 2) && (index < CPU_TLB_SIZE)) {
171 // Read crossed page boundaris. Invalidate second cache too.
172 env->tlb_table[mmu_idx][index + 1].addr_read ^= TARGET_PAGE_MASK;
173 env->tlb_table[mmu_idx][index + 1].addr_write ^= TARGET_PAGE_MASK;
174 }
175 }
176 #endif // CONFIG_MEMCHECK_MMU
177 } else {
178 /* the page is not in the TLB : fill it */
179 retaddr = GETPC();
180 #ifdef ALIGNED_ONLY
181 if ((addr & (DATA_SIZE - 1)) != 0)
182 do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
183 #endif
184 tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
185 goto redo;
186 }
187 return res;
188 }
189
190 /* handle all unaligned cases */
glue(glue (slow_ld,SUFFIX),MMUSUFFIX)191 static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
192 int mmu_idx,
193 void *retaddr)
194 {
195 DATA_TYPE res, res1, res2;
196 int index, shift;
197 target_phys_addr_t ioaddr;
198 unsigned long addend;
199 target_ulong tlb_addr, addr1, addr2;
200
201 index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
202 redo:
203 tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
204 if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
205 if (tlb_addr & ~TARGET_PAGE_MASK) {
206 /* IO access */
207 if ((addr & (DATA_SIZE - 1)) != 0)
208 goto do_unaligned_access;
209 ioaddr = env->iotlb[mmu_idx][index];
210 res = glue(io_read, SUFFIX)(ioaddr, addr, retaddr);
211 } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
212 do_unaligned_access:
213 /* slow unaligned access (it spans two pages) */
214 addr1 = addr & ~(DATA_SIZE - 1);
215 addr2 = addr1 + DATA_SIZE;
216 res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1,
217 mmu_idx, retaddr);
218 res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2,
219 mmu_idx, retaddr);
220 shift = (addr & (DATA_SIZE - 1)) * 8;
221 #ifdef TARGET_WORDS_BIGENDIAN
222 res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift));
223 #else
224 res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift));
225 #endif
226 res = (DATA_TYPE)res;
227 } else {
228 /* unaligned/aligned access in the same page */
229 addend = env->tlb_table[mmu_idx][index].addend;
230 res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend));
231 }
232 } else {
233 /* the page is not in the TLB : fill it */
234 tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
235 goto redo;
236 }
237 return res;
238 }
239
240 #ifndef SOFTMMU_CODE_ACCESS
241
242 static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
243 DATA_TYPE val,
244 int mmu_idx,
245 void *retaddr);
246
glue(io_write,SUFFIX)247 static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr,
248 DATA_TYPE val,
249 target_ulong addr,
250 void *retaddr)
251 {
252 int index;
253 index = (physaddr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
254 physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
255 if (index > (IO_MEM_NOTDIRTY >> IO_MEM_SHIFT)
256 && !can_do_io(env)) {
257 cpu_io_recompile(env, retaddr);
258 }
259
260 env->mem_io_vaddr = addr;
261 env->mem_io_pc = (unsigned long)retaddr;
262 #if SHIFT <= 2
263 io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val);
264 #else
265 #ifdef TARGET_WORDS_BIGENDIAN
266 io_mem_write[index][2](io_mem_opaque[index], physaddr, val >> 32);
267 io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val);
268 #else
269 io_mem_write[index][2](io_mem_opaque[index], physaddr, val);
270 io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32);
271 #endif
272 #endif /* SHIFT > 2 */
273 }
274
glue(glue (__st,SUFFIX),MMUSUFFIX)275 void REGPARM glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
276 DATA_TYPE val,
277 int mmu_idx)
278 {
279 target_phys_addr_t ioaddr;
280 unsigned long addend;
281 target_ulong tlb_addr;
282 void *retaddr;
283 int index;
284 #ifdef CONFIG_MEMCHECK_MMU
285 int invalidate_cache = 0;
286 #endif // CONFIG_MEMCHECK_MMU
287
288 index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
289 redo:
290 tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
291 if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
292 if (tlb_addr & ~TARGET_PAGE_MASK) {
293 /* IO access */
294 if ((addr & (DATA_SIZE - 1)) != 0)
295 goto do_unaligned_access;
296 retaddr = GETPC();
297 ioaddr = env->iotlb[mmu_idx][index];
298 glue(io_write, SUFFIX)(ioaddr, val, addr, retaddr);
299 } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
300 /* This is not I/O access: do access verification. */
301 #ifdef CONFIG_MEMCHECK_MMU
302 /* We only validate access to the guest's user space, for which
303 * mmu_idx is set to 1. */
304 if (memcheck_instrument_mmu && mmu_idx == 1 &&
305 memcheck_validate_st(addr, DATA_SIZE, (uint64_t)val,
306 (target_ulong)(ptrdiff_t)GETPC())) {
307 /* Memory write breaks page boundary. So, if required, we
308 * must invalidate two caches in TLB. */
309 invalidate_cache = 2;
310 }
311 #endif // CONFIG_MEMCHECK_MMU
312 do_unaligned_access:
313 retaddr = GETPC();
314 #ifdef ALIGNED_ONLY
315 do_unaligned_access(addr, 1, mmu_idx, retaddr);
316 #endif
317 glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val,
318 mmu_idx, retaddr);
319 } else {
320 #ifdef CONFIG_MEMCHECK_MMU
321 /* We only validate access to the guest's user space, for which
322 * mmu_idx is set to 1. */
323 if (memcheck_instrument_mmu && mmu_idx == 1) {
324 invalidate_cache = memcheck_validate_st(addr, DATA_SIZE,
325 (uint64_t)val,
326 (target_ulong)(ptrdiff_t)GETPC());
327 }
328 #endif // CONFIG_MEMCHECK_MMU
329 /* aligned/unaligned access in the same page */
330 #ifdef ALIGNED_ONLY
331 if ((addr & (DATA_SIZE - 1)) != 0) {
332 retaddr = GETPC();
333 do_unaligned_access(addr, 1, mmu_idx, retaddr);
334 }
335 #endif
336 addend = env->tlb_table[mmu_idx][index].addend;
337 glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val);
338 }
339 #ifdef CONFIG_MEMCHECK_MMU
340 if (invalidate_cache) {
341 /* Accessed memory is under memchecker control. We must invalidate
342 * containing page(s) in order to make sure that next access to them
343 * will invoke _ld/_st_mmu. */
344 env->tlb_table[mmu_idx][index].addr_read ^= TARGET_PAGE_MASK;
345 env->tlb_table[mmu_idx][index].addr_write ^= TARGET_PAGE_MASK;
346 if ((invalidate_cache == 2) && (index < CPU_TLB_SIZE)) {
347 // Write crossed page boundaris. Invalidate second cache too.
348 env->tlb_table[mmu_idx][index + 1].addr_read ^= TARGET_PAGE_MASK;
349 env->tlb_table[mmu_idx][index + 1].addr_write ^= TARGET_PAGE_MASK;
350 }
351 }
352 #endif // CONFIG_MEMCHECK_MMU
353 } else {
354 /* the page is not in the TLB : fill it */
355 retaddr = GETPC();
356 #ifdef ALIGNED_ONLY
357 if ((addr & (DATA_SIZE - 1)) != 0)
358 do_unaligned_access(addr, 1, mmu_idx, retaddr);
359 #endif
360 tlb_fill(addr, 1, mmu_idx, retaddr);
361 goto redo;
362 }
363 }
364
365 /* handles all unaligned cases */
glue(glue (slow_st,SUFFIX),MMUSUFFIX)366 static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
367 DATA_TYPE val,
368 int mmu_idx,
369 void *retaddr)
370 {
371 target_phys_addr_t ioaddr;
372 unsigned long addend;
373 target_ulong tlb_addr;
374 int index, i;
375
376 index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
377 redo:
378 tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
379 if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
380 if (tlb_addr & ~TARGET_PAGE_MASK) {
381 /* IO access */
382 if ((addr & (DATA_SIZE - 1)) != 0)
383 goto do_unaligned_access;
384 ioaddr = env->iotlb[mmu_idx][index];
385 glue(io_write, SUFFIX)(ioaddr, val, addr, retaddr);
386 } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
387 do_unaligned_access:
388 /* XXX: not efficient, but simple */
389 /* Note: relies on the fact that tlb_fill() does not remove the
390 * previous page from the TLB cache. */
391 for(i = DATA_SIZE - 1; i >= 0; i--) {
392 #ifdef TARGET_WORDS_BIGENDIAN
393 glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)),
394 mmu_idx, retaddr);
395 #else
396 glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8),
397 mmu_idx, retaddr);
398 #endif
399 }
400 } else {
401 /* aligned/unaligned access in the same page */
402 addend = env->tlb_table[mmu_idx][index].addend;
403 glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val);
404 }
405 } else {
406 /* the page is not in the TLB : fill it */
407 tlb_fill(addr, 1, mmu_idx, retaddr);
408 goto redo;
409 }
410 }
411
412 #endif /* !defined(SOFTMMU_CODE_ACCESS) */
413
414 #undef READ_ACCESS_TYPE
415 #undef SHIFT
416 #undef DATA_TYPE
417 #undef SUFFIX
418 #undef USUFFIX
419 #undef DATA_SIZE
420 #undef ADDR_READ
421