1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include "qemu/osdep.h"
21#include "cpu.h"
22#include "exec/exec-all.h"
23#include "qemu/host-utils.h"
24#include "qemu/main-loop.h"
25#include "exec/helper-proto.h"
26#include "helper_regs.h"
27#include "exec/cpu_ldst.h"
28#include "tcg/tcg.h"
29#include "internal.h"
30#include "qemu/atomic128.h"
31
32
33
34static inline bool needs_byteswap(const CPUPPCState *env)
35{
36#if defined(TARGET_WORDS_BIGENDIAN)
37 return msr_le;
38#else
39 return !msr_le;
40#endif
41}
42
43
44
45
46static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr,
47 target_long arg)
48{
49#if defined(TARGET_PPC64)
50 if (!msr_is_64bit(env, env->msr)) {
51 return (uint32_t)(addr + arg);
52 } else
53#endif
54 {
55 return addr + arg;
56 }
57}
58
59static void *probe_contiguous(CPUPPCState *env, target_ulong addr, uint32_t nb,
60 MMUAccessType access_type, int mmu_idx,
61 uintptr_t raddr)
62{
63 void *host1, *host2;
64 uint32_t nb_pg1, nb_pg2;
65
66 nb_pg1 = -(addr | TARGET_PAGE_MASK);
67 if (likely(nb <= nb_pg1)) {
68
69 return probe_access(env, addr, nb, access_type, mmu_idx, raddr);
70 }
71
72
73 nb_pg2 = nb - nb_pg1;
74 host1 = probe_access(env, addr, nb_pg1, access_type, mmu_idx, raddr);
75 addr = addr_add(env, addr, nb_pg1);
76 host2 = probe_access(env, addr, nb_pg2, access_type, mmu_idx, raddr);
77
78
79 if (host2 == host1 + nb_pg1) {
80 return host1;
81 }
82 return NULL;
83}
84
85void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
86{
87 uintptr_t raddr = GETPC();
88 int mmu_idx = cpu_mmu_index(env, false);
89 void *host = probe_contiguous(env, addr, (32 - reg) * 4,
90 MMU_DATA_LOAD, mmu_idx, raddr);
91
92 if (likely(host)) {
93
94 for (; reg < 32; reg++) {
95 env->gpr[reg] = (uint32_t)ldl_be_p(host);
96 host += 4;
97 }
98 } else {
99
100 for (; reg < 32; reg++) {
101 env->gpr[reg] = cpu_ldl_mmuidx_ra(env, addr, mmu_idx, raddr);
102 addr = addr_add(env, addr, 4);
103 }
104 }
105}
106
107void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
108{
109 uintptr_t raddr = GETPC();
110 int mmu_idx = cpu_mmu_index(env, false);
111 void *host = probe_contiguous(env, addr, (32 - reg) * 4,
112 MMU_DATA_STORE, mmu_idx, raddr);
113
114 if (likely(host)) {
115
116 for (; reg < 32; reg++) {
117 stl_be_p(host, env->gpr[reg]);
118 host += 4;
119 }
120 } else {
121
122 for (; reg < 32; reg++) {
123 cpu_stl_mmuidx_ra(env, addr, env->gpr[reg], mmu_idx, raddr);
124 addr = addr_add(env, addr, 4);
125 }
126 }
127}
128
129static void do_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
130 uint32_t reg, uintptr_t raddr)
131{
132 int mmu_idx;
133 void *host;
134 uint32_t val;
135
136 if (unlikely(nb == 0)) {
137 return;
138 }
139
140 mmu_idx = cpu_mmu_index(env, false);
141 host = probe_contiguous(env, addr, nb, MMU_DATA_LOAD, mmu_idx, raddr);
142
143 if (likely(host)) {
144
145 for (; nb > 3; nb -= 4) {
146 env->gpr[reg] = (uint32_t)ldl_be_p(host);
147 reg = (reg + 1) % 32;
148 host += 4;
149 }
150 switch (nb) {
151 default:
152 return;
153 case 1:
154 val = ldub_p(host) << 24;
155 break;
156 case 2:
157 val = lduw_be_p(host) << 16;
158 break;
159 case 3:
160 val = (lduw_be_p(host) << 16) | (ldub_p(host + 2) << 8);
161 break;
162 }
163 } else {
164
165 for (; nb > 3; nb -= 4) {
166 env->gpr[reg] = cpu_ldl_mmuidx_ra(env, addr, mmu_idx, 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 val = cpu_lduw_mmuidx_ra(env, addr, mmu_idx, raddr) << 16;
178 break;
179 case 3:
180 val = cpu_lduw_mmuidx_ra(env, addr, mmu_idx, raddr) << 16;
181 addr = addr_add(env, addr, 2);
182 val |= cpu_ldub_mmuidx_ra(env, addr, mmu_idx, raddr) << 8;
183 break;
184 }
185 }
186 env->gpr[reg] = val;
187}
188
189void helper_lsw(CPUPPCState *env, target_ulong addr,
190 uint32_t nb, uint32_t reg)
191{
192 do_lsw(env, addr, nb, reg, GETPC());
193}
194
195
196
197
198
199
200
201void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg,
202 uint32_t ra, uint32_t rb)
203{
204 if (likely(xer_bc != 0)) {
205 int num_used_regs = DIV_ROUND_UP(xer_bc, 4);
206 if (unlikely((ra != 0 && lsw_reg_in_range(reg, num_used_regs, ra)) ||
207 lsw_reg_in_range(reg, num_used_regs, rb))) {
208 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
209 POWERPC_EXCP_INVAL |
210 POWERPC_EXCP_INVAL_LSWX, GETPC());
211 } else {
212 do_lsw(env, addr, xer_bc, reg, GETPC());
213 }
214 }
215}
216
217void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
218 uint32_t reg)
219{
220 uintptr_t raddr = GETPC();
221 int mmu_idx;
222 void *host;
223 uint32_t val;
224
225 if (unlikely(nb == 0)) {
226 return;
227 }
228
229 mmu_idx = cpu_mmu_index(env, false);
230 host = probe_contiguous(env, addr, nb, MMU_DATA_STORE, mmu_idx, raddr);
231
232 if (likely(host)) {
233
234 for (; nb > 3; nb -= 4) {
235 stl_be_p(host, env->gpr[reg]);
236 reg = (reg + 1) % 32;
237 host += 4;
238 }
239 val = env->gpr[reg];
240 switch (nb) {
241 case 1:
242 stb_p(host, val >> 24);
243 break;
244 case 2:
245 stw_be_p(host, val >> 16);
246 break;
247 case 3:
248 stw_be_p(host, val >> 16);
249 stb_p(host + 2, val >> 8);
250 break;
251 }
252 } else {
253 for (; nb > 3; nb -= 4) {
254 cpu_stl_mmuidx_ra(env, addr, env->gpr[reg], mmu_idx, raddr);
255 reg = (reg + 1) % 32;
256 addr = addr_add(env, addr, 4);
257 }
258 val = env->gpr[reg];
259 switch (nb) {
260 case 1:
261 cpu_stb_mmuidx_ra(env, addr, val >> 24, mmu_idx, raddr);
262 break;
263 case 2:
264 cpu_stw_mmuidx_ra(env, addr, val >> 16, mmu_idx, raddr);
265 break;
266 case 3:
267 cpu_stw_mmuidx_ra(env, addr, val >> 16, mmu_idx, raddr);
268 addr = addr_add(env, addr, 2);
269 cpu_stb_mmuidx_ra(env, addr, val >> 8, mmu_idx, raddr);
270 break;
271 }
272 }
273}
274
275static void dcbz_common(CPUPPCState *env, target_ulong addr,
276 uint32_t opcode, bool epid, uintptr_t retaddr)
277{
278 target_ulong mask, dcbz_size = env->dcache_line_size;
279 uint32_t i;
280 void *haddr;
281 int mmu_idx = epid ? PPC_TLB_EPID_STORE : env->dmmu_idx;
282
283#if defined(TARGET_PPC64)
284
285 if (env->excp_model == POWERPC_EXCP_970 &&
286 !(opcode & 0x00200000) && ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
287 dcbz_size = 32;
288 }
289#endif
290
291
292 mask = ~(dcbz_size - 1);
293 addr &= mask;
294
295
296 if ((env->reserve_addr & mask) == addr) {
297 env->reserve_addr = (target_ulong)-1ULL;
298 }
299
300
301 haddr = probe_write(env, addr, dcbz_size, mmu_idx, retaddr);
302 if (haddr) {
303 memset(haddr, 0, dcbz_size);
304 } else {
305
306 for (i = 0; i < dcbz_size; i += 8) {
307 cpu_stq_mmuidx_ra(env, addr + i, 0, mmu_idx, retaddr);
308 }
309 }
310}
311
312void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode)
313{
314 dcbz_common(env, addr, opcode, false, GETPC());
315}
316
317void helper_dcbzep(CPUPPCState *env, target_ulong addr, uint32_t opcode)
318{
319 dcbz_common(env, addr, opcode, true, GETPC());
320}
321
322void helper_icbi(CPUPPCState *env, target_ulong addr)
323{
324 addr &= ~(env->dcache_line_size - 1);
325
326
327
328
329
330
331 cpu_ldl_data_ra(env, addr, GETPC());
332}
333
334void helper_icbiep(CPUPPCState *env, target_ulong addr)
335{
336#if !defined(CONFIG_USER_ONLY)
337
338 addr &= ~(env->dcache_line_size - 1);
339 cpu_ldl_mmuidx_ra(env, addr, PPC_TLB_EPID_LOAD, GETPC());
340#endif
341}
342
343
344target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
345 uint32_t ra, uint32_t rb)
346{
347 int i, c, d;
348
349 d = 24;
350 for (i = 0; i < xer_bc; i++) {
351 c = cpu_ldub_data_ra(env, addr, GETPC());
352 addr = addr_add(env, addr, 1);
353
354 if (likely(reg != rb && (ra == 0 || reg != ra))) {
355 env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
356 }
357 if (unlikely(c == xer_cmp)) {
358 break;
359 }
360 if (likely(d != 0)) {
361 d -= 8;
362 } else {
363 d = 24;
364 reg++;
365 reg = reg & 0x1F;
366 }
367 }
368 return i;
369}
370
371#ifdef TARGET_PPC64
372uint64_t helper_lq_le_parallel(CPUPPCState *env, target_ulong addr,
373 uint32_t opidx)
374{
375 Int128 ret;
376
377
378 assert(HAVE_ATOMIC128);
379 ret = helper_atomic_ldo_le_mmu(env, addr, opidx, GETPC());
380 env->retxh = int128_gethi(ret);
381 return int128_getlo(ret);
382}
383
384uint64_t helper_lq_be_parallel(CPUPPCState *env, target_ulong addr,
385 uint32_t opidx)
386{
387 Int128 ret;
388
389
390 assert(HAVE_ATOMIC128);
391 ret = helper_atomic_ldo_be_mmu(env, addr, opidx, GETPC());
392 env->retxh = int128_gethi(ret);
393 return int128_getlo(ret);
394}
395
396void helper_stq_le_parallel(CPUPPCState *env, target_ulong addr,
397 uint64_t lo, uint64_t hi, uint32_t opidx)
398{
399 Int128 val;
400
401
402 assert(HAVE_ATOMIC128);
403 val = int128_make128(lo, hi);
404 helper_atomic_sto_le_mmu(env, addr, val, opidx, GETPC());
405}
406
407void helper_stq_be_parallel(CPUPPCState *env, target_ulong addr,
408 uint64_t lo, uint64_t hi, uint32_t opidx)
409{
410 Int128 val;
411
412
413 assert(HAVE_ATOMIC128);
414 val = int128_make128(lo, hi);
415 helper_atomic_sto_be_mmu(env, addr, val, opidx, GETPC());
416}
417
418uint32_t helper_stqcx_le_parallel(CPUPPCState *env, target_ulong addr,
419 uint64_t new_lo, uint64_t new_hi,
420 uint32_t opidx)
421{
422 bool success = false;
423
424
425 assert(HAVE_CMPXCHG128);
426
427 if (likely(addr == env->reserve_addr)) {
428 Int128 oldv, cmpv, newv;
429
430 cmpv = int128_make128(env->reserve_val2, env->reserve_val);
431 newv = int128_make128(new_lo, new_hi);
432 oldv = helper_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv,
433 opidx, GETPC());
434 success = int128_eq(oldv, cmpv);
435 }
436 env->reserve_addr = -1;
437 return env->so + success * CRF_EQ_BIT;
438}
439
440uint32_t helper_stqcx_be_parallel(CPUPPCState *env, target_ulong addr,
441 uint64_t new_lo, uint64_t new_hi,
442 uint32_t opidx)
443{
444 bool success = false;
445
446
447 assert(HAVE_CMPXCHG128);
448
449 if (likely(addr == env->reserve_addr)) {
450 Int128 oldv, cmpv, newv;
451
452 cmpv = int128_make128(env->reserve_val2, env->reserve_val);
453 newv = int128_make128(new_lo, new_hi);
454 oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv,
455 opidx, GETPC());
456 success = int128_eq(oldv, cmpv);
457 }
458 env->reserve_addr = -1;
459 return env->so + success * CRF_EQ_BIT;
460}
461#endif
462
463
464
465#if defined(HOST_WORDS_BIGENDIAN)
466#define HI_IDX 0
467#define LO_IDX 1
468#else
469#define HI_IDX 1
470#define LO_IDX 0
471#endif
472
473
474
475
476
477
478
479
480#define LVE(name, access, swap, element) \
481 void helper_##name(CPUPPCState *env, ppc_avr_t *r, \
482 target_ulong addr) \
483 { \
484 size_t n_elems = ARRAY_SIZE(r->element); \
485 int adjust = HI_IDX * (n_elems - 1); \
486 int sh = sizeof(r->element[0]) >> 1; \
487 int index = (addr & 0xf) >> sh; \
488 if (msr_le) { \
489 index = n_elems - index - 1; \
490 } \
491 \
492 if (needs_byteswap(env)) { \
493 r->element[LO_IDX ? index : (adjust - index)] = \
494 swap(access(env, addr, GETPC())); \
495 } else { \
496 r->element[LO_IDX ? index : (adjust - index)] = \
497 access(env, addr, GETPC()); \
498 } \
499 }
500#define I(x) (x)
501LVE(lvebx, cpu_ldub_data_ra, I, u8)
502LVE(lvehx, cpu_lduw_data_ra, bswap16, u16)
503LVE(lvewx, cpu_ldl_data_ra, bswap32, u32)
504#undef I
505#undef LVE
506
507#define STVE(name, access, swap, element) \
508 void helper_##name(CPUPPCState *env, ppc_avr_t *r, \
509 target_ulong addr) \
510 { \
511 size_t n_elems = ARRAY_SIZE(r->element); \
512 int adjust = HI_IDX * (n_elems - 1); \
513 int sh = sizeof(r->element[0]) >> 1; \
514 int index = (addr & 0xf) >> sh; \
515 if (msr_le) { \
516 index = n_elems - index - 1; \
517 } \
518 \
519 if (needs_byteswap(env)) { \
520 access(env, addr, swap(r->element[LO_IDX ? index : \
521 (adjust - index)]), \
522 GETPC()); \
523 } else { \
524 access(env, addr, r->element[LO_IDX ? index : \
525 (adjust - index)], GETPC()); \
526 } \
527 }
528#define I(x) (x)
529STVE(stvebx, cpu_stb_data_ra, I, u8)
530STVE(stvehx, cpu_stw_data_ra, bswap16, u16)
531STVE(stvewx, cpu_stl_data_ra, bswap32, u32)
532#undef I
533#undef LVE
534
535#ifdef TARGET_PPC64
536#define GET_NB(rb) ((rb >> 56) & 0xFF)
537
538#define VSX_LXVL(name, lj) \
539void helper_##name(CPUPPCState *env, target_ulong addr, \
540 ppc_vsr_t *xt, target_ulong rb) \
541{ \
542 ppc_vsr_t t; \
543 uint64_t nb = GET_NB(rb); \
544 int i; \
545 \
546 t.s128 = int128_zero(); \
547 if (nb) { \
548 nb = (nb >= 16) ? 16 : nb; \
549 if (msr_le && !lj) { \
550 for (i = 16; i > 16 - nb; i--) { \
551 t.VsrB(i - 1) = cpu_ldub_data_ra(env, addr, GETPC()); \
552 addr = addr_add(env, addr, 1); \
553 } \
554 } else { \
555 for (i = 0; i < nb; i++) { \
556 t.VsrB(i) = cpu_ldub_data_ra(env, addr, GETPC()); \
557 addr = addr_add(env, addr, 1); \
558 } \
559 } \
560 } \
561 *xt = t; \
562}
563
564VSX_LXVL(lxvl, 0)
565VSX_LXVL(lxvll, 1)
566#undef VSX_LXVL
567
568#define VSX_STXVL(name, lj) \
569void helper_##name(CPUPPCState *env, target_ulong addr, \
570 ppc_vsr_t *xt, target_ulong rb) \
571{ \
572 target_ulong nb = GET_NB(rb); \
573 int i; \
574 \
575 if (!nb) { \
576 return; \
577 } \
578 \
579 nb = (nb >= 16) ? 16 : nb; \
580 if (msr_le && !lj) { \
581 for (i = 16; i > 16 - nb; i--) { \
582 cpu_stb_data_ra(env, addr, xt->VsrB(i - 1), GETPC()); \
583 addr = addr_add(env, addr, 1); \
584 } \
585 } else { \
586 for (i = 0; i < nb; i++) { \
587 cpu_stb_data_ra(env, addr, xt->VsrB(i), GETPC()); \
588 addr = addr_add(env, addr, 1); \
589 } \
590 } \
591}
592
593VSX_STXVL(stxvl, 0)
594VSX_STXVL(stxvll, 1)
595#undef VSX_STXVL
596#undef GET_NB
597#endif
598
599#undef HI_IDX
600#undef LO_IDX
601
602void helper_tbegin(CPUPPCState *env)
603{
604
605
606
607
608
609
610
611
612
613 env->spr[SPR_TEXASR] =
614 (1ULL << TEXASR_FAILURE_PERSISTENT) |
615 (1ULL << TEXASR_NESTING_OVERFLOW) |
616 (msr_hv << TEXASR_PRIVILEGE_HV) |
617 (msr_pr << TEXASR_PRIVILEGE_PR) |
618 (1ULL << TEXASR_FAILURE_SUMMARY) |
619 (1ULL << TEXASR_TFIAR_EXACT);
620 env->spr[SPR_TFIAR] = env->nip | (msr_hv << 1) | msr_pr;
621 env->spr[SPR_TFHAR] = env->nip + 4;
622 env->crf[0] = 0xB;
623}
624