master
c 529 lines 18.9 KB
Raw
1 /*
2 * PowerPC memory access emulation helpers for QEMU.
3 *
4 * Copyright (c) 2003-2007 Jocelyn Mayer
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.1 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
20 #include "qemu/osdep.h"
21 #include "cpu.h"
22 #include "exec/target_page.h"
23 #include "qemu/host-utils.h"
24 #include "exec/helper-proto.h"
25 #include "helper_regs.h"
26 #include "accel/tcg/cpu-ldst.h"
27 #include "accel/tcg/helper-retaddr.h"
28 #include "accel/tcg/probe.h"
29 #include "internal.h"
30 #include "qemu/atomic128.h"
31
32 /* #define DEBUG_OP */
33
34 /*****************************************************************************/
35 /* Memory load and stores */
36
37 static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr,
38 target_long arg)
39 {
40 #if defined(TARGET_PPC64)
41 if (!msr_is_64bit(env, env->msr)) {
42 return (uint32_t)(addr + arg);
43 } else
44 #endif
45 {
46 return addr + arg;
47 }
48 }
49
50 static void *probe_contiguous(CPUPPCState *env, target_ulong addr, uint32_t nb,
51 MMUAccessType access_type, int mmu_idx,
52 uintptr_t raddr)
53 {
54 void *host1, *host2;
55 uint32_t nb_pg1, nb_pg2;
56
57 nb_pg1 = -(addr | TARGET_PAGE_MASK);
58 if (likely(nb <= nb_pg1)) {
59 /* The entire operation is on a single page. */
60 return probe_access(env, addr, nb, access_type, mmu_idx, raddr);
61 }
62
63 /* The operation spans two pages. */
64 nb_pg2 = nb - nb_pg1;
65 host1 = probe_access(env, addr, nb_pg1, access_type, mmu_idx, raddr);
66 addr = addr_add(env, addr, nb_pg1);
67 host2 = probe_access(env, addr, nb_pg2, access_type, mmu_idx, raddr);
68
69 /* If the two host pages are contiguous, optimize. */
70 if (host2 == host1 + nb_pg1) {
71 return host1;
72 }
73 return NULL;
74 }
75
76 void helper_LMW(CPUPPCState *env, target_ulong addr, uint32_t reg)
77 {
78 uintptr_t raddr = GETPC();
79 int mmu_idx = ppc_env_mmu_index(env, false);
80 void *host = probe_contiguous(env, addr, (32 - reg) * 4,
81 MMU_DATA_LOAD, mmu_idx, raddr);
82
83 if (likely(host)) {
84 /* Fast path -- the entire operation is in RAM at host. */
85 for (; reg < 32; reg++) {
86 env->gpr[reg] = (uint32_t)ldl_be_p(host);
87 host += 4;
88 }
89 } else {
90 /* Slow path -- at least some of the operation requires i/o. */
91 MemOp op = ppc_data_endian_env(env) | MO_UL | MO_UNALN;
92 MemOpIdx oi = make_memop_idx(op, mmu_idx);
93
94 for (; reg < 32; reg++) {
95 env->gpr[reg] = cpu_ldl_mmu(env, addr, oi, raddr);
96 addr = addr_add(env, addr, 4);
97 }
98 }
99 }
100
101 void helper_STMW(CPUPPCState *env, target_ulong addr, uint32_t reg)
102 {
103 uintptr_t raddr = GETPC();
104 int mmu_idx = ppc_env_mmu_index(env, false);
105 void *host = probe_contiguous(env, addr, (32 - reg) * 4,
106 MMU_DATA_STORE, mmu_idx, raddr);
107
108 if (likely(host)) {
109 /* Fast path -- the entire operation is in RAM at host. */
110 for (; reg < 32; reg++) {
111 stl_be_p(host, env->gpr[reg]);
112 host += 4;
113 }
114 } else {
115 /* Slow path -- at least some of the operation requires i/o. */
116 for (; reg < 32; reg++) {
117 MemOp op = ppc_data_endian_env(env) | MO_UL | MO_UNALN;
118 MemOpIdx oi = make_memop_idx(op, mmu_idx);
119
120 cpu_stl_mmu(env, addr, env->gpr[reg], oi, raddr);
121 addr = addr_add(env, addr, 4);
122 }
123 }
124 }
125
126 static void do_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
127 uint32_t reg, uintptr_t raddr)
128 {
129 int mmu_idx;
130 void *host;
131 uint32_t val;
132
133 if (unlikely(nb == 0)) {
134 return;
135 }
136
137 mmu_idx = ppc_env_mmu_index(env, false);
138 host = probe_contiguous(env, addr, nb, MMU_DATA_LOAD, mmu_idx, raddr);
139
140 if (likely(host)) {
141 /* Fast path -- the entire operation is in RAM at host. */
142 for (; nb > 3; nb -= 4) {
143 env->gpr[reg] = (uint32_t)ldl_be_p(host);
144 reg = (reg + 1) % 32;
145 host += 4;
146 }
147 switch (nb) {
148 default:
149 return;
150 case 1:
151 val = ldub_p(host) << 24;
152 break;
153 case 2:
154 val = lduw_be_p(host) << 16;
155 break;
156 case 3:
157 val = (lduw_be_p(host) << 16) | (ldub_p(host + 2) << 8);
158 break;
159 }
160 } else {
161 MemOp op = ppc_data_endian_env(env) | MO_UL | MO_UNALN;
162 MemOpIdx oi = make_memop_idx(op, mmu_idx);
163
164 /* Slow path -- at least some of the operation requires i/o. */
165 for (; nb > 3; nb -= 4) {
166 env->gpr[reg] = cpu_ldl_mmu(env, addr, oi, raddr);
167 reg = (reg + 1) % 32;
168 addr = addr_add(env, addr, 4);
169 }
170 switch (nb) {
171 default:
172 return;
173 case 1:
174 val = cpu_ldub_mmuidx_ra(env, addr, mmu_idx, raddr) << 24;
175 break;
176 case 2:
177 op = ppc_data_endian_env(env) | MO_UW | MO_UNALN;
178 oi = make_memop_idx(op, mmu_idx);
179 val = cpu_ldw_mmu(env, addr, oi, raddr) << 16;
180 break;
181 case 3:
182 op = ppc_data_endian_env(env) | MO_UW | MO_UNALN;
183 oi = make_memop_idx(op, mmu_idx);
184 val = cpu_ldw_mmu(env, addr, oi, raddr) << 16;
185 addr = addr_add(env, addr, 2);
186 val |= cpu_ldub_mmuidx_ra(env, addr, mmu_idx, raddr) << 8;
187 break;
188 }
189 }
190 env->gpr[reg] = val;
191 }
192
193 void helper_LSW(CPUPPCState *env, target_ulong addr,
194 uint32_t nb, uint32_t reg)
195 {
196 do_lsw(env, addr, nb, reg, GETPC());
197 }
198
199 /*
200 * PPC32 specification says we must generate an exception if rA is in
201 * the range of registers to be loaded. In an other hand, IBM says
202 * this is valid, but rA won't be loaded. For now, I'll follow the
203 * spec...
204 */
205 void helper_LSWX(CPUPPCState *env, target_ulong addr, uint32_t reg,
206 uint32_t ra, uint32_t rb)
207 {
208 if (likely(xer_bc != 0)) {
209 int num_used_regs = DIV_ROUND_UP(xer_bc, 4);
210 if (unlikely((ra != 0 && lsw_reg_in_range(reg, num_used_regs, ra)) ||
211 lsw_reg_in_range(reg, num_used_regs, rb))) {
212 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
213 POWERPC_EXCP_INVAL |
214 POWERPC_EXCP_INVAL_LSWX, GETPC());
215 } else {
216 do_lsw(env, addr, xer_bc, reg, GETPC());
217 }
218 }
219 }
220
221 void helper_STSW(CPUPPCState *env, target_ulong addr, uint32_t nb,
222 uint32_t reg)
223 {
224 uintptr_t raddr = GETPC();
225 int mmu_idx;
226 void *host;
227 uint32_t val;
228
229 if (unlikely(nb == 0)) {
230 return;
231 }
232
233 mmu_idx = ppc_env_mmu_index(env, false);
234 host = probe_contiguous(env, addr, nb, MMU_DATA_STORE, mmu_idx, raddr);
235
236 if (likely(host)) {
237 /* Fast path -- the entire operation is in RAM at host. */
238 for (; nb > 3; nb -= 4) {
239 stl_be_p(host, env->gpr[reg]);
240 reg = (reg + 1) % 32;
241 host += 4;
242 }
243 val = env->gpr[reg];
244 switch (nb) {
245 case 1:
246 stb_p(host, val >> 24);
247 break;
248 case 2:
249 stw_be_p(host, val >> 16);
250 break;
251 case 3:
252 stw_be_p(host, val >> 16);
253 stb_p(host + 2, val >> 8);
254 break;
255 }
256 } else {
257 MemOp op = ppc_data_endian_env(env) | MO_UL | MO_UNALN;
258 MemOpIdx oi = make_memop_idx(op, mmu_idx);
259
260 for (; nb > 3; nb -= 4) {
261 cpu_stl_mmu(env, addr, env->gpr[reg], oi, raddr);
262 reg = (reg + 1) % 32;
263 addr = addr_add(env, addr, 4);
264 }
265 val = env->gpr[reg];
266 switch (nb) {
267 case 1:
268 cpu_stb_mmuidx_ra(env, addr, val >> 24, mmu_idx, raddr);
269 break;
270 case 2:
271 op = ppc_data_endian_env(env) | MO_UW | MO_UNALN;
272 oi = make_memop_idx(op, mmu_idx);
273 cpu_stw_mmu(env, addr, val >> 16, oi, raddr);
274 break;
275 case 3:
276 op = ppc_data_endian_env(env) | MO_UW | MO_UNALN;
277 oi = make_memop_idx(op, mmu_idx);
278 cpu_stw_mmu(env, addr, val >> 16, oi, raddr);
279 addr = addr_add(env, addr, 2);
280 cpu_stb_mmuidx_ra(env, addr, val >> 8, mmu_idx, raddr);
281 break;
282 }
283 }
284 }
285
286 static void dcbz_common(CPUPPCState *env, target_ulong addr,
287 int mmu_idx, int dcbz_size, uintptr_t retaddr)
288 {
289 target_ulong mask = ~(target_ulong)(dcbz_size - 1);
290 void *haddr;
291
292 /* Align address */
293 addr &= mask;
294
295 /* Check reservation */
296 if (unlikely((env->reserve_addr & mask) == addr)) {
297 env->reserve_addr = (target_ulong)-1ULL;
298 }
299
300 /* Try fast path translate */
301 #ifdef CONFIG_USER_ONLY
302 haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, mmu_idx);
303 #else
304 haddr = probe_write(env, addr, dcbz_size, mmu_idx, retaddr);
305 if (unlikely(!haddr)) {
306 /* Slow path */
307 MemOp op = ppc_data_endian_env(env) | MO_UQ | MO_UNALN;
308 MemOpIdx oi = make_memop_idx(op, mmu_idx);
309
310 for (int i = 0; i < dcbz_size; i += 8) {
311 cpu_stq_mmu(env, addr + i, 0, oi, retaddr);
312 }
313 return;
314 }
315 #endif
316
317 set_helper_retaddr(retaddr);
318 memset(haddr, 0, dcbz_size);
319 clear_helper_retaddr();
320 }
321
322 void helper_dcbz(CPUPPCState *env, target_ulong addr, int mmu_idx)
323 {
324 dcbz_common(env, addr, mmu_idx, env->dcache_line_size, GETPC());
325 }
326
327 #ifdef TARGET_PPC64
328 void helper_dcbzl(CPUPPCState *env, target_ulong addr)
329 {
330 int dcbz_size = env->dcache_line_size;
331
332 /*
333 * The translator checked for POWERPC_EXCP_970.
334 * All that's left is to check HID5.
335 */
336 if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
337 dcbz_size = 32;
338 }
339
340 dcbz_common(env, addr, ppc_env_mmu_index(env, false), dcbz_size, GETPC());
341 }
342 #endif
343
344 void helper_ICBI(CPUPPCState *env, target_ulong addr)
345 {
346 unsigned mmu_idx = cpu_mmu_index(env_cpu(env), false);
347 MemOpIdx oi = make_memop_idx(MO_UL | MO_UNALN, mmu_idx);
348
349 addr &= ~(env->dcache_line_size - 1);
350 /*
351 * Invalidate one cache line :
352 * PowerPC specification says this is to be treated like a load
353 * (not a fetch) by the MMU. To be sure it will be so,
354 * do the load "by hand". As the returned data is not consumed,
355 * endianness is irrelevant.
356 */
357 cpu_ldl_mmu(env, addr, oi, GETPC());
358 }
359
360 void helper_ICBIEP(CPUPPCState *env, target_ulong addr)
361 {
362 #if !defined(CONFIG_USER_ONLY)
363 MemOpIdx oi = make_memop_idx(MO_UL | MO_UNALN, PPC_TLB_EPID_LOAD);
364 /* See comments above */
365 addr &= ~(env->dcache_line_size - 1);
366 cpu_ldl_mmu(env, addr, oi, GETPC());
367 #endif
368 }
369
370 /*****************************************************************************/
371 /* Altivec extension helpers */
372 #if HOST_BIG_ENDIAN
373 #define HI_IDX 0
374 #define LO_IDX 1
375 #else
376 #define HI_IDX 1
377 #define LO_IDX 0
378 #endif
379
380 /*
381 * We use MSR_LE to determine index ordering in a vector. However,
382 * byteswapping is not simply controlled by MSR_LE. We also need to
383 * take into account endianness of the target. This is done for the
384 * little-endian PPC64 user-mode target.
385 */
386
387 #define LVE(name, access, swap, element) \
388 void helper_##name(CPUPPCState *env, ppc_avr_t *r, \
389 target_ulong addr) \
390 { \
391 size_t n_elems = ARRAY_SIZE(r->element); \
392 int adjust = HI_IDX * (n_elems - 1); \
393 int sh = sizeof(r->element[0]) >> 1; \
394 int index = (addr & 0xf) >> sh; \
395 bool byteswap = ppc_env_is_little_endian(env); \
396 \
397 if (byteswap) { \
398 index = n_elems - index - 1; \
399 r->element[LO_IDX ? index : (adjust - index)] = \
400 swap(access(env, addr, GETPC())); \
401 } else { \
402 r->element[LO_IDX ? index : (adjust - index)] = \
403 access(env, addr, GETPC()); \
404 } \
405 }
406 #define I(x) (x)
407 LVE(LVEBX, cpu_ldub_data_ra, I, u8)
408 LVE(LVEHX, cpu_lduw_be_data_ra, bswap16, u16)
409 LVE(LVEWX, cpu_ldl_be_data_ra, bswap32, u32)
410 #undef I
411 #undef LVE
412
413 #define STVE(name, access, swap, element) \
414 void helper_##name(CPUPPCState *env, ppc_avr_t *r, \
415 target_ulong addr) \
416 { \
417 size_t n_elems = ARRAY_SIZE(r->element); \
418 int adjust = HI_IDX * (n_elems - 1); \
419 int sh = sizeof(r->element[0]) >> 1; \
420 int index = (addr & 0xf) >> sh; \
421 bool byteswap = ppc_env_is_little_endian(env); \
422 \
423 if (byteswap) { \
424 index = n_elems - index - 1; \
425 access(env, addr, swap(r->element[LO_IDX ? index : \
426 (adjust - index)]), \
427 GETPC()); \
428 } else { \
429 access(env, addr, r->element[LO_IDX ? index : \
430 (adjust - index)], GETPC()); \
431 } \
432 }
433 #define I(x) (x)
434 STVE(STVEBX, cpu_stb_data_ra, I, u8)
435 STVE(STVEHX, cpu_stw_be_data_ra, bswap16, u16)
436 STVE(STVEWX, cpu_stl_be_data_ra, bswap32, u32)
437 #undef I
438 #undef LVE
439
440 #ifdef TARGET_PPC64
441 #define GET_NB(rb) ((rb >> 56) & 0xFF)
442
443 #define VSX_LXVL(name, lj) \
444 void helper_##name(CPUPPCState *env, target_ulong addr, \
445 ppc_vsr_t *xt, target_ulong rb) \
446 { \
447 ppc_vsr_t t; \
448 uint64_t nb = GET_NB(rb); \
449 int i; \
450 \
451 t.s128 = int128_zero(); \
452 if (nb) { \
453 nb = (nb >= 16) ? 16 : nb; \
454 if (ppc_env_is_little_endian(env) && !lj) { \
455 for (i = 16; i > 16 - nb; i--) { \
456 t.VsrB(i - 1) = cpu_ldub_data_ra(env, addr, GETPC()); \
457 addr = addr_add(env, addr, 1); \
458 } \
459 } else { \
460 for (i = 0; i < nb; i++) { \
461 t.VsrB(i) = cpu_ldub_data_ra(env, addr, GETPC()); \
462 addr = addr_add(env, addr, 1); \
463 } \
464 } \
465 } \
466 *xt = t; \
467 }
468
469 VSX_LXVL(LXVL, 0)
470 VSX_LXVL(LXVLL, 1)
471 #undef VSX_LXVL
472
473 #define VSX_STXVL(name, lj) \
474 void helper_##name(CPUPPCState *env, target_ulong addr, \
475 ppc_vsr_t *xt, target_ulong rb) \
476 { \
477 target_ulong nb = GET_NB(rb); \
478 int i; \
479 \
480 if (!nb) { \
481 return; \
482 } \
483 \
484 nb = (nb >= 16) ? 16 : nb; \
485 if (ppc_env_is_little_endian(env) && !lj) { \
486 for (i = 16; i > 16 - nb; i--) { \
487 cpu_stb_data_ra(env, addr, xt->VsrB(i - 1), GETPC()); \
488 addr = addr_add(env, addr, 1); \
489 } \
490 } else { \
491 for (i = 0; i < nb; i++) { \
492 cpu_stb_data_ra(env, addr, xt->VsrB(i), GETPC()); \
493 addr = addr_add(env, addr, 1); \
494 } \
495 } \
496 }
497
498 VSX_STXVL(STXVL, 0)
499 VSX_STXVL(STXVLL, 1)
500 #undef VSX_STXVL
501 #undef GET_NB
502 #endif /* TARGET_PPC64 */
503
504 #undef HI_IDX
505 #undef LO_IDX
506
507 void helper_tbegin(CPUPPCState *env)
508 {
509 /*
510 * As a degenerate implementation, always fail tbegin. The reason
511 * given is "Nesting overflow". The "persistent" bit is set,
512 * providing a hint to the error handler to not retry. The TFIAR
513 * captures the address of the failure, which is this tbegin
514 * instruction. Instruction execution will continue with the next
515 * instruction in memory, which is precisely what we want.
516 */
517
518 env->spr[SPR_TEXASR] =
519 (1ULL << TEXASR_FAILURE_PERSISTENT) |
520 (1ULL << TEXASR_NESTING_OVERFLOW) |
521 (FIELD_EX64_HV(env->msr) << TEXASR_PRIVILEGE_HV) |
522 (FIELD_EX64(env->msr, MSR, PR) << TEXASR_PRIVILEGE_PR) |
523 (1ULL << TEXASR_FAILURE_SUMMARY) |
524 (1ULL << TEXASR_TFIAR_EXACT);
525 env->spr[SPR_TFIAR] = env->nip | (FIELD_EX64_HV(env->msr) << 1) |
526 FIELD_EX64(env->msr, MSR, PR);
527 env->spr[SPR_TFHAR] = env->nip + 4;
528 env->crf[0] = 0xB; /* 0b1010 = transaction failure */
529 }