1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include "qemu/osdep.h"
22#include "cpu.h"
23#include "internal.h"
24#include "exec/helper-proto.h"
25#include "exec/exec-all.h"
26#include "exec/cpu_ldst.h"
27#include "qemu/int128.h"
28
29#if !defined(CONFIG_USER_ONLY)
30#include "hw/s390x/storage-keys.h"
31#endif
32
33
34
35#if !defined(CONFIG_USER_ONLY)
36
37
38
39
40
41void tlb_fill(CPUState *cs, target_ulong addr, int size,
42 MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
43{
44 int ret = s390_cpu_handle_mmu_fault(cs, addr, size, access_type, mmu_idx);
45 if (unlikely(ret != 0)) {
46 cpu_loop_exit_restore(cs, retaddr);
47 }
48}
49
50#endif
51
52
53#ifdef DEBUG_HELPER
54#define HELPER_LOG(x...) qemu_log(x)
55#else
56#define HELPER_LOG(x...)
57#endif
58
59static inline bool psw_key_valid(CPUS390XState *env, uint8_t psw_key)
60{
61 uint16_t pkm = env->cregs[3] >> 16;
62
63 if (env->psw.mask & PSW_MASK_PSTATE) {
64
65 return pkm & (0x80 >> psw_key);
66 }
67 return true;
68}
69
70
71static inline uint32_t adj_len_to_page(uint32_t len, uint64_t addr)
72{
73#ifndef CONFIG_USER_ONLY
74 if ((addr & ~TARGET_PAGE_MASK) + len - 1 >= TARGET_PAGE_SIZE) {
75 return -(addr | TARGET_PAGE_MASK);
76 }
77#endif
78 return len;
79}
80
81
82
83static inline void check_alignment(CPUS390XState *env, uint64_t v,
84 int wordsize, uintptr_t ra)
85{
86 if (v % wordsize) {
87 s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
88 }
89}
90
91
92static inline uint64_t cpu_ldusize_data_ra(CPUS390XState *env, uint64_t addr,
93 int wordsize, uintptr_t ra)
94{
95 switch (wordsize) {
96 case 1:
97 return cpu_ldub_data_ra(env, addr, ra);
98 case 2:
99 return cpu_lduw_data_ra(env, addr, ra);
100 default:
101 abort();
102 }
103}
104
105
106static inline void cpu_stsize_data_ra(CPUS390XState *env, uint64_t addr,
107 uint64_t value, int wordsize,
108 uintptr_t ra)
109{
110 switch (wordsize) {
111 case 1:
112 cpu_stb_data_ra(env, addr, value, ra);
113 break;
114 case 2:
115 cpu_stw_data_ra(env, addr, value, ra);
116 break;
117 default:
118 abort();
119 }
120}
121
122static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte,
123 uint32_t l, uintptr_t ra)
124{
125 int mmu_idx = cpu_mmu_index(env, false);
126
127 while (l > 0) {
128 void *p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
129 if (p) {
130
131 uint32_t l_adj = adj_len_to_page(l, dest);
132 memset(p, byte, l_adj);
133 dest += l_adj;
134 l -= l_adj;
135 } else {
136
137
138 cpu_stb_data_ra(env, dest, byte, ra);
139 dest++;
140 l--;
141 }
142 }
143}
144
145#ifndef CONFIG_USER_ONLY
146static void fast_memmove_idx(CPUS390XState *env, uint64_t dest, uint64_t src,
147 uint32_t len, int dest_idx, int src_idx,
148 uintptr_t ra)
149{
150 TCGMemOpIdx oi_dest = make_memop_idx(MO_UB, dest_idx);
151 TCGMemOpIdx oi_src = make_memop_idx(MO_UB, src_idx);
152 uint32_t len_adj;
153 void *src_p;
154 void *dest_p;
155 uint8_t x;
156
157 while (len > 0) {
158 src = wrap_address(env, src);
159 dest = wrap_address(env, dest);
160 src_p = tlb_vaddr_to_host(env, src, MMU_DATA_LOAD, src_idx);
161 dest_p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, dest_idx);
162
163 if (src_p && dest_p) {
164
165 len_adj = adj_len_to_page(adj_len_to_page(len, src), dest);
166 memmove(dest_p, src_p, len_adj);
167 } else {
168
169
170
171 len_adj = 1;
172 x = helper_ret_ldub_mmu(env, src, oi_src, ra);
173 helper_ret_stb_mmu(env, dest, x, oi_dest, ra);
174 }
175 src += len_adj;
176 dest += len_adj;
177 len -= len_adj;
178 }
179}
180
181static int mmu_idx_from_as(uint8_t as)
182{
183 switch (as) {
184 case AS_PRIMARY:
185 return MMU_PRIMARY_IDX;
186 case AS_SECONDARY:
187 return MMU_SECONDARY_IDX;
188 case AS_HOME:
189 return MMU_HOME_IDX;
190 default:
191
192 g_assert_not_reached();
193 }
194}
195
196static void fast_memmove_as(CPUS390XState *env, uint64_t dest, uint64_t src,
197 uint32_t len, uint8_t dest_as, uint8_t src_as,
198 uintptr_t ra)
199{
200 int src_idx = mmu_idx_from_as(src_as);
201 int dest_idx = mmu_idx_from_as(dest_as);
202
203 fast_memmove_idx(env, dest, src, len, dest_idx, src_idx, ra);
204}
205#endif
206
207static void fast_memmove(CPUS390XState *env, uint64_t dest, uint64_t src,
208 uint32_t l, uintptr_t ra)
209{
210 int mmu_idx = cpu_mmu_index(env, false);
211
212 while (l > 0) {
213 void *src_p = tlb_vaddr_to_host(env, src, MMU_DATA_LOAD, mmu_idx);
214 void *dest_p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
215 if (src_p && dest_p) {
216
217 uint32_t l_adj = adj_len_to_page(l, src);
218 l_adj = adj_len_to_page(l_adj, dest);
219 memmove(dest_p, src_p, l_adj);
220 src += l_adj;
221 dest += l_adj;
222 l -= l_adj;
223 } else {
224
225
226
227 cpu_stb_data_ra(env, dest, cpu_ldub_data_ra(env, src, ra), ra);
228 src++;
229 dest++;
230 l--;
231 }
232 }
233}
234
235
236static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest,
237 uint64_t src, uintptr_t ra)
238{
239 uint32_t i;
240 uint8_t c = 0;
241
242 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
243 __func__, l, dest, src);
244
245 for (i = 0; i <= l; i++) {
246 uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
247 x &= cpu_ldub_data_ra(env, dest + i, ra);
248 c |= x;
249 cpu_stb_data_ra(env, dest + i, x, ra);
250 }
251 return c != 0;
252}
253
254uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
255 uint64_t src)
256{
257 return do_helper_nc(env, l, dest, src, GETPC());
258}
259
260
261static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest,
262 uint64_t src, uintptr_t ra)
263{
264 uint32_t i;
265 uint8_t c = 0;
266
267 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
268 __func__, l, dest, src);
269
270
271 if (src == dest) {
272 fast_memset(env, dest, 0, l + 1, ra);
273 return 0;
274 }
275
276 for (i = 0; i <= l; i++) {
277 uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
278 x ^= cpu_ldub_data_ra(env, dest + i, ra);
279 c |= x;
280 cpu_stb_data_ra(env, dest + i, x, ra);
281 }
282 return c != 0;
283}
284
285uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
286 uint64_t src)
287{
288 return do_helper_xc(env, l, dest, src, GETPC());
289}
290
291
292static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest,
293 uint64_t src, uintptr_t ra)
294{
295 uint32_t i;
296 uint8_t c = 0;
297
298 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
299 __func__, l, dest, src);
300
301 for (i = 0; i <= l; i++) {
302 uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
303 x |= cpu_ldub_data_ra(env, dest + i, ra);
304 c |= x;
305 cpu_stb_data_ra(env, dest + i, x, ra);
306 }
307 return c != 0;
308}
309
310uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
311 uint64_t src)
312{
313 return do_helper_oc(env, l, dest, src, GETPC());
314}
315
316
317static uint32_t do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest,
318 uint64_t src, uintptr_t ra)
319{
320 uint32_t i;
321
322 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
323 __func__, l, dest, src);
324
325
326
327
328 if (dest == src + 1) {
329 fast_memset(env, dest, cpu_ldub_data_ra(env, src, ra), l + 1, ra);
330 } else if (dest < src || src + l < dest) {
331 fast_memmove(env, dest, src, l + 1, ra);
332 } else {
333
334 for (i = 0; i <= l; i++) {
335 uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
336 cpu_stb_data_ra(env, dest + i, x, ra);
337 }
338 }
339
340 return env->cc_op;
341}
342
343void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
344{
345 do_helper_mvc(env, l, dest, src, GETPC());
346}
347
348
349void HELPER(mvcin)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
350{
351 uintptr_t ra = GETPC();
352 int i;
353
354 for (i = 0; i <= l; i++) {
355 uint8_t v = cpu_ldub_data_ra(env, src - i, ra);
356 cpu_stb_data_ra(env, dest + i, v, ra);
357 }
358}
359
360
361void HELPER(mvn)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
362{
363 uintptr_t ra = GETPC();
364 int i;
365
366 for (i = 0; i <= l; i++) {
367 uint8_t v = cpu_ldub_data_ra(env, dest + i, ra) & 0xf0;
368 v |= cpu_ldub_data_ra(env, src + i, ra) & 0x0f;
369 cpu_stb_data_ra(env, dest + i, v, ra);
370 }
371}
372
373
374void HELPER(mvo)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
375{
376 uintptr_t ra = GETPC();
377 int len_dest = l >> 4;
378 int len_src = l & 0xf;
379 uint8_t byte_dest, byte_src;
380 int i;
381
382 src += len_src;
383 dest += len_dest;
384
385
386 byte_src = cpu_ldub_data_ra(env, src, ra);
387 byte_dest = cpu_ldub_data_ra(env, dest, ra);
388 byte_dest = (byte_dest & 0x0f) | (byte_src << 4);
389 cpu_stb_data_ra(env, dest, byte_dest, ra);
390
391
392 for (i = 1; i <= len_dest; i++) {
393 byte_dest = byte_src >> 4;
394 if (len_src - i >= 0) {
395 byte_src = cpu_ldub_data_ra(env, src - i, ra);
396 } else {
397 byte_src = 0;
398 }
399 byte_dest |= byte_src << 4;
400 cpu_stb_data_ra(env, dest - i, byte_dest, ra);
401 }
402}
403
404
405void HELPER(mvz)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
406{
407 uintptr_t ra = GETPC();
408 int i;
409
410 for (i = 0; i <= l; i++) {
411 uint8_t b = cpu_ldub_data_ra(env, dest + i, ra) & 0x0f;
412 b |= cpu_ldub_data_ra(env, src + i, ra) & 0xf0;
413 cpu_stb_data_ra(env, dest + i, b, ra);
414 }
415}
416
417
418static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1,
419 uint64_t s2, uintptr_t ra)
420{
421 uint32_t i;
422 uint32_t cc = 0;
423
424 HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
425 __func__, l, s1, s2);
426
427 for (i = 0; i <= l; i++) {
428 uint8_t x = cpu_ldub_data_ra(env, s1 + i, ra);
429 uint8_t y = cpu_ldub_data_ra(env, s2 + i, ra);
430 HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
431 if (x < y) {
432 cc = 1;
433 break;
434 } else if (x > y) {
435 cc = 2;
436 break;
437 }
438 }
439
440 HELPER_LOG("\n");
441 return cc;
442}
443
444uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2)
445{
446 return do_helper_clc(env, l, s1, s2, GETPC());
447}
448
449
450uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
451 uint64_t addr)
452{
453 uintptr_t ra = GETPC();
454 uint32_t cc = 0;
455
456 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
457 mask, addr);
458
459 while (mask) {
460 if (mask & 8) {
461 uint8_t d = cpu_ldub_data_ra(env, addr, ra);
462 uint8_t r = extract32(r1, 24, 8);
463 HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
464 addr);
465 if (r < d) {
466 cc = 1;
467 break;
468 } else if (r > d) {
469 cc = 2;
470 break;
471 }
472 addr++;
473 }
474 mask = (mask << 1) & 0xf;
475 r1 <<= 8;
476 }
477
478 HELPER_LOG("\n");
479 return cc;
480}
481
482static inline uint64_t get_address(CPUS390XState *env, int reg)
483{
484 return wrap_address(env, env->regs[reg]);
485}
486
487static inline void set_address(CPUS390XState *env, int reg, uint64_t address)
488{
489 if (env->psw.mask & PSW_MASK_64) {
490
491 env->regs[reg] = address;
492 } else {
493 if (!(env->psw.mask & PSW_MASK_32)) {
494
495
496
497
498 env->regs[reg] = deposit64(env->regs[reg], 0, 24, address);
499 } else {
500
501
502
503
504 address &= 0x7fffffff;
505 env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
506 }
507 }
508}
509
510static inline uint64_t wrap_length(CPUS390XState *env, uint64_t length)
511{
512 if (!(env->psw.mask & PSW_MASK_64)) {
513
514 length &= 0x7fffffff;
515 }
516 return length;
517}
518
519static inline uint64_t get_length(CPUS390XState *env, int reg)
520{
521 return wrap_length(env, env->regs[reg]);
522}
523
524static inline void set_length(CPUS390XState *env, int reg, uint64_t length)
525{
526 if (env->psw.mask & PSW_MASK_64) {
527
528 env->regs[reg] = length;
529 } else {
530
531 env->regs[reg] = deposit64(env->regs[reg], 0, 32, length);
532 }
533}
534
535
536void HELPER(srst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
537{
538 uintptr_t ra = GETPC();
539 uint64_t end, str;
540 uint32_t len;
541 uint8_t v, c = env->regs[0];
542
543
544 if (env->regs[0] & 0xffffff00u) {
545 s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
546 }
547
548 str = get_address(env, r2);
549 end = get_address(env, r1);
550
551
552
553 for (len = 0; len < 0x2000; ++len) {
554 if (str + len == end) {
555
556 env->cc_op = 2;
557 return;
558 }
559 v = cpu_ldub_data_ra(env, str + len, ra);
560 if (v == c) {
561
562 env->cc_op = 1;
563 set_address(env, r1, str + len);
564 return;
565 }
566 }
567
568
569 env->cc_op = 3;
570 set_address(env, r2, str + len);
571}
572
573void HELPER(srstu)(CPUS390XState *env, uint32_t r1, uint32_t r2)
574{
575 uintptr_t ra = GETPC();
576 uint32_t len;
577 uint16_t v, c = env->regs[0];
578 uint64_t end, str, adj_end;
579
580
581 if (env->regs[0] & 0xffff0000u) {
582 s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
583 }
584
585 str = get_address(env, r2);
586 end = get_address(env, r1);
587
588
589 adj_end = end + ((str ^ end) & 1);
590
591
592
593 for (len = 0; len < 0x2000; len += 2) {
594 if (str + len == adj_end) {
595
596 env->cc_op = 2;
597 return;
598 }
599 v = cpu_lduw_data_ra(env, str + len, ra);
600 if (v == c) {
601
602 env->cc_op = 1;
603 set_address(env, r1, str + len);
604 return;
605 }
606 }
607
608
609 env->cc_op = 3;
610 set_address(env, r2, str + len);
611}
612
613
614uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
615{
616 uintptr_t ra = GETPC();
617 uint32_t len;
618
619 c = c & 0xff;
620 s1 = wrap_address(env, s1);
621 s2 = wrap_address(env, s2);
622
623
624
625 for (len = 0; len < 0x2000; ++len) {
626 uint8_t v1 = cpu_ldub_data_ra(env, s1 + len, ra);
627 uint8_t v2 = cpu_ldub_data_ra(env, s2 + len, ra);
628 if (v1 == v2) {
629 if (v1 == c) {
630
631 env->cc_op = 0;
632 env->retxl = s2;
633 return s1;
634 }
635 } else {
636
637
638
639 env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2);
640 env->retxl = s2 + len;
641 return s1 + len;
642 }
643 }
644
645
646 env->cc_op = 3;
647 env->retxl = s2 + len;
648 return s1 + len;
649}
650
651
652uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
653{
654
655
656 fast_memmove(env, r1, r2, TARGET_PAGE_SIZE, GETPC());
657 return 0;
658}
659
660
661uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s)
662{
663 uintptr_t ra = GETPC();
664 uint32_t len;
665
666 c = c & 0xff;
667 d = wrap_address(env, d);
668 s = wrap_address(env, s);
669
670
671
672 for (len = 0; len < 0x2000; ++len) {
673 uint8_t v = cpu_ldub_data_ra(env, s + len, ra);
674 cpu_stb_data_ra(env, d + len, v, ra);
675 if (v == c) {
676
677 env->cc_op = 1;
678 env->retxl = s;
679 return d + len;
680 }
681 }
682
683
684 env->cc_op = 3;
685 env->retxl = s + len;
686 return d + len;
687}
688
689
690void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
691{
692 uintptr_t ra = GETPC();
693 int i;
694
695 if (a2 & 0x3) {
696
697 s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra);
698 }
699
700 for (i = r1;; i = (i + 1) % 16) {
701 env->aregs[i] = cpu_ldl_data_ra(env, a2, ra);
702 a2 += 4;
703
704 if (i == r3) {
705 break;
706 }
707 }
708}
709
710
711void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
712{
713 uintptr_t ra = GETPC();
714 int i;
715
716 if (a2 & 0x3) {
717 s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
718 }
719
720 for (i = r1;; i = (i + 1) % 16) {
721 cpu_stl_data_ra(env, a2, env->aregs[i], ra);
722 a2 += 4;
723
724 if (i == r3) {
725 break;
726 }
727 }
728}
729
730
731static inline uint32_t do_mvcl(CPUS390XState *env,
732 uint64_t *dest, uint64_t *destlen,
733 uint64_t *src, uint64_t *srclen,
734 uint16_t pad, int wordsize, uintptr_t ra)
735{
736 uint64_t len = MIN(*srclen, *destlen);
737 uint32_t cc;
738
739 if (*destlen == *srclen) {
740 cc = 0;
741 } else if (*destlen < *srclen) {
742 cc = 1;
743 } else {
744 cc = 2;
745 }
746
747
748 fast_memmove(env, *dest, *src, len, ra);
749 *src += len;
750 *srclen -= len;
751 *dest += len;
752 *destlen -= len;
753
754
755 if (wordsize == 1) {
756 fast_memset(env, *dest, pad, *destlen, ra);
757 *dest += *destlen;
758 *destlen = 0;
759 } else {
760
761 if (*destlen & 1) {
762 cpu_stb_data_ra(env, *dest, pad & 0xff, ra);
763 *dest += 1;
764 *destlen -= 1;
765 }
766
767 for (; *destlen; *dest += 2, *destlen -= 2) {
768 cpu_stw_data_ra(env, *dest, pad, ra);
769 }
770 }
771
772 return cc;
773}
774
775
776uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
777{
778 uintptr_t ra = GETPC();
779 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
780 uint64_t dest = get_address(env, r1);
781 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
782 uint64_t src = get_address(env, r2);
783 uint8_t pad = env->regs[r2 + 1] >> 24;
784 uint32_t cc;
785
786 cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra);
787
788 env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, destlen);
789 env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, srclen);
790 set_address(env, r1, dest);
791 set_address(env, r2, src);
792
793 return cc;
794}
795
796
797uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
798 uint32_t r3)
799{
800 uintptr_t ra = GETPC();
801 uint64_t destlen = get_length(env, r1 + 1);
802 uint64_t dest = get_address(env, r1);
803 uint64_t srclen = get_length(env, r3 + 1);
804 uint64_t src = get_address(env, r3);
805 uint8_t pad = a2;
806 uint32_t cc;
807
808 cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra);
809
810 set_length(env, r1 + 1, destlen);
811 set_length(env, r3 + 1, srclen);
812 set_address(env, r1, dest);
813 set_address(env, r3, src);
814
815 return cc;
816}
817
818
819uint32_t HELPER(mvclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
820 uint32_t r3)
821{
822 uintptr_t ra = GETPC();
823 uint64_t destlen = get_length(env, r1 + 1);
824 uint64_t dest = get_address(env, r1);
825 uint64_t srclen = get_length(env, r3 + 1);
826 uint64_t src = get_address(env, r3);
827 uint16_t pad = a2;
828 uint32_t cc;
829
830 cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 2, ra);
831
832 set_length(env, r1 + 1, destlen);
833 set_length(env, r3 + 1, srclen);
834 set_address(env, r1, dest);
835 set_address(env, r3, src);
836
837 return cc;
838}
839
840
841static inline uint32_t do_clcl(CPUS390XState *env,
842 uint64_t *src1, uint64_t *src1len,
843 uint64_t *src3, uint64_t *src3len,
844 uint16_t pad, uint64_t limit,
845 int wordsize, uintptr_t ra)
846{
847 uint64_t len = MAX(*src1len, *src3len);
848 uint32_t cc = 0;
849
850 check_alignment(env, *src1len | *src3len, wordsize, ra);
851
852 if (!len) {
853 return cc;
854 }
855
856
857
858 if (len > limit) {
859 len = limit;
860 cc = 3;
861 }
862
863 for (; len; len -= wordsize) {
864 uint16_t v1 = pad;
865 uint16_t v3 = pad;
866
867 if (*src1len) {
868 v1 = cpu_ldusize_data_ra(env, *src1, wordsize, ra);
869 }
870 if (*src3len) {
871 v3 = cpu_ldusize_data_ra(env, *src3, wordsize, ra);
872 }
873
874 if (v1 != v3) {
875 cc = (v1 < v3) ? 1 : 2;
876 break;
877 }
878
879 if (*src1len) {
880 *src1 += wordsize;
881 *src1len -= wordsize;
882 }
883 if (*src3len) {
884 *src3 += wordsize;
885 *src3len -= wordsize;
886 }
887 }
888
889 return cc;
890}
891
892
893
894uint32_t HELPER(clcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
895{
896 uintptr_t ra = GETPC();
897 uint64_t src1len = extract64(env->regs[r1 + 1], 0, 24);
898 uint64_t src1 = get_address(env, r1);
899 uint64_t src3len = extract64(env->regs[r2 + 1], 0, 24);
900 uint64_t src3 = get_address(env, r2);
901 uint8_t pad = env->regs[r2 + 1] >> 24;
902 uint32_t cc;
903
904 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, -1, 1, ra);
905
906 env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, src1len);
907 env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, src3len);
908 set_address(env, r1, src1);
909 set_address(env, r2, src3);
910
911 return cc;
912}
913
914
915uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
916 uint32_t r3)
917{
918 uintptr_t ra = GETPC();
919 uint64_t src1len = get_length(env, r1 + 1);
920 uint64_t src1 = get_address(env, r1);
921 uint64_t src3len = get_length(env, r3 + 1);
922 uint64_t src3 = get_address(env, r3);
923 uint8_t pad = a2;
924 uint32_t cc;
925
926 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x2000, 1, ra);
927
928 set_length(env, r1 + 1, src1len);
929 set_length(env, r3 + 1, src3len);
930 set_address(env, r1, src1);
931 set_address(env, r3, src3);
932
933 return cc;
934}
935
936
937uint32_t HELPER(clclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
938 uint32_t r3)
939{
940 uintptr_t ra = GETPC();
941 uint64_t src1len = get_length(env, r1 + 1);
942 uint64_t src1 = get_address(env, r1);
943 uint64_t src3len = get_length(env, r3 + 1);
944 uint64_t src3 = get_address(env, r3);
945 uint16_t pad = a2;
946 uint32_t cc = 0;
947
948 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x1000, 2, ra);
949
950 set_length(env, r1 + 1, src1len);
951 set_length(env, r3 + 1, src3len);
952 set_address(env, r1, src1);
953 set_address(env, r3, src3);
954
955 return cc;
956}
957
958
959uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
960 uint64_t src, uint64_t src_len)
961{
962 uintptr_t ra = GETPC();
963 uint64_t max_len, len;
964 uint64_t cksm = (uint32_t)r1;
965
966
967
968 max_len = (src_len > 0x2000 ? 0x2000 : src_len);
969
970
971 for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
972 cksm += (uint32_t)cpu_ldl_data_ra(env, src, ra);
973 }
974
975 switch (max_len - len) {
976 case 1:
977 cksm += cpu_ldub_data_ra(env, src, ra) << 24;
978 len += 1;
979 break;
980 case 2:
981 cksm += cpu_lduw_data_ra(env, src, ra) << 16;
982 len += 2;
983 break;
984 case 3:
985 cksm += cpu_lduw_data_ra(env, src, ra) << 16;
986 cksm += cpu_ldub_data_ra(env, src + 2, ra) << 8;
987 len += 3;
988 break;
989 }
990
991
992
993 while (cksm > 0xffffffffull) {
994 cksm = (uint32_t)cksm + (cksm >> 32);
995 }
996
997
998 env->cc_op = (len == src_len ? 0 : 3);
999
1000
1001 env->retxl = cksm;
1002 return len;
1003}
1004
1005void HELPER(pack)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src)
1006{
1007 uintptr_t ra = GETPC();
1008 int len_dest = len >> 4;
1009 int len_src = len & 0xf;
1010 uint8_t b;
1011
1012 dest += len_dest;
1013 src += len_src;
1014
1015
1016 b = cpu_ldub_data_ra(env, src, ra);
1017 cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
1018 src--;
1019 len_src--;
1020
1021
1022 while (len_dest >= 0) {
1023 b = 0;
1024
1025 if (len_src > 0) {
1026 b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
1027 src--;
1028 len_src--;
1029 }
1030 if (len_src > 0) {
1031 b |= cpu_ldub_data_ra(env, src, ra) << 4;
1032 src--;
1033 len_src--;
1034 }
1035
1036 len_dest--;
1037 dest--;
1038 cpu_stb_data_ra(env, dest, b, ra);
1039 }
1040}
1041
1042static inline void do_pkau(CPUS390XState *env, uint64_t dest, uint64_t src,
1043 uint32_t srclen, int ssize, uintptr_t ra)
1044{
1045 int i;
1046
1047 const int destlen = 16;
1048
1049
1050 src += srclen - 1;
1051 dest += destlen - 1;
1052
1053 for (i = 0; i < destlen; i++) {
1054 uint8_t b = 0;
1055
1056
1057 if (i == 0) {
1058 b = 0xc;
1059 } else if (srclen > ssize) {
1060 b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
1061 src -= ssize;
1062 srclen -= ssize;
1063 }
1064
1065 if (srclen > ssize) {
1066 b |= cpu_ldub_data_ra(env, src, ra) << 4;
1067 src -= ssize;
1068 srclen -= ssize;
1069 }
1070
1071 cpu_stb_data_ra(env, dest, b, ra);
1072 dest--;
1073 }
1074}
1075
1076
1077void HELPER(pka)(CPUS390XState *env, uint64_t dest, uint64_t src,
1078 uint32_t srclen)
1079{
1080 do_pkau(env, dest, src, srclen, 1, GETPC());
1081}
1082
1083void HELPER(pku)(CPUS390XState *env, uint64_t dest, uint64_t src,
1084 uint32_t srclen)
1085{
1086 do_pkau(env, dest, src, srclen, 2, GETPC());
1087}
1088
1089void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
1090 uint64_t src)
1091{
1092 uintptr_t ra = GETPC();
1093 int len_dest = len >> 4;
1094 int len_src = len & 0xf;
1095 uint8_t b;
1096 int second_nibble = 0;
1097
1098 dest += len_dest;
1099 src += len_src;
1100
1101
1102 b = cpu_ldub_data_ra(env, src, ra);
1103 cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
1104 src--;
1105 len_src--;
1106
1107
1108
1109 while (len_dest > 0) {
1110 uint8_t cur_byte = 0;
1111
1112 if (len_src > 0) {
1113 cur_byte = cpu_ldub_data_ra(env, src, ra);
1114 }
1115
1116 len_dest--;
1117 dest--;
1118
1119
1120 if (second_nibble) {
1121 cur_byte >>= 4;
1122 len_src--;
1123 src--;
1124 }
1125 second_nibble = !second_nibble;
1126
1127
1128 cur_byte = (cur_byte & 0xf);
1129
1130 cur_byte |= 0xf0;
1131
1132 cpu_stb_data_ra(env, dest, cur_byte, ra);
1133 }
1134}
1135
1136static inline uint32_t do_unpkau(CPUS390XState *env, uint64_t dest,
1137 uint32_t destlen, int dsize, uint64_t src,
1138 uintptr_t ra)
1139{
1140 int i;
1141 uint32_t cc;
1142 uint8_t b;
1143
1144 const int srclen = 16;
1145
1146
1147 src += srclen - 1;
1148 dest += destlen - dsize;
1149
1150
1151 b = cpu_ldub_data_ra(env, src, ra);
1152 src--;
1153 switch (b & 0xf) {
1154 case 0xa:
1155 case 0xc:
1156 case 0xe ... 0xf:
1157 cc = 0;
1158 break;
1159 case 0xb:
1160 case 0xd:
1161 cc = 1;
1162 break;
1163 default:
1164 case 0x0 ... 0x9:
1165 cc = 3;
1166 break;
1167 }
1168
1169
1170 for (i = 0; i < destlen; i += dsize) {
1171 if (i == (31 * dsize)) {
1172
1173 b = 0;
1174 } else if (i % (2 * dsize)) {
1175 b = cpu_ldub_data_ra(env, src, ra);
1176 src--;
1177 } else {
1178 b >>= 4;
1179 }
1180 cpu_stsize_data_ra(env, dest, 0x30 + (b & 0xf), dsize, ra);
1181 dest -= dsize;
1182 }
1183
1184 return cc;
1185}
1186
1187uint32_t HELPER(unpka)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1188 uint64_t src)
1189{
1190 return do_unpkau(env, dest, destlen, 1, src, GETPC());
1191}
1192
1193uint32_t HELPER(unpku)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1194 uint64_t src)
1195{
1196 return do_unpkau(env, dest, destlen, 2, src, GETPC());
1197}
1198
1199uint32_t HELPER(tp)(CPUS390XState *env, uint64_t dest, uint32_t destlen)
1200{
1201 uintptr_t ra = GETPC();
1202 uint32_t cc = 0;
1203 int i;
1204
1205 for (i = 0; i < destlen; i++) {
1206 uint8_t b = cpu_ldub_data_ra(env, dest + i, ra);
1207
1208 cc |= (b & 0xf0) > 0x90 ? 2 : 0;
1209
1210 if (i == (destlen - 1)) {
1211
1212 cc |= (b & 0xf) < 0xa ? 1 : 0;
1213 } else {
1214
1215 cc |= (b & 0xf) > 0x9 ? 2 : 0;
1216 }
1217 }
1218
1219 return cc;
1220}
1221
1222static uint32_t do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array,
1223 uint64_t trans, uintptr_t ra)
1224{
1225 uint32_t i;
1226
1227 for (i = 0; i <= len; i++) {
1228 uint8_t byte = cpu_ldub_data_ra(env, array + i, ra);
1229 uint8_t new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
1230 cpu_stb_data_ra(env, array + i, new_byte, ra);
1231 }
1232
1233 return env->cc_op;
1234}
1235
1236void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
1237 uint64_t trans)
1238{
1239 do_helper_tr(env, len, array, trans, GETPC());
1240}
1241
1242uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array,
1243 uint64_t len, uint64_t trans)
1244{
1245 uintptr_t ra = GETPC();
1246 uint8_t end = env->regs[0] & 0xff;
1247 uint64_t l = len;
1248 uint64_t i;
1249 uint32_t cc = 0;
1250
1251 if (!(env->psw.mask & PSW_MASK_64)) {
1252 array &= 0x7fffffff;
1253 l = (uint32_t)l;
1254 }
1255
1256
1257
1258 if (l > 0x2000) {
1259 l = 0x2000;
1260 cc = 3;
1261 }
1262
1263 for (i = 0; i < l; i++) {
1264 uint8_t byte, new_byte;
1265
1266 byte = cpu_ldub_data_ra(env, array + i, ra);
1267
1268 if (byte == end) {
1269 cc = 1;
1270 break;
1271 }
1272
1273 new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
1274 cpu_stb_data_ra(env, array + i, new_byte, ra);
1275 }
1276
1277 env->cc_op = cc;
1278 env->retxl = len - i;
1279 return array + i;
1280}
1281
1282static inline uint32_t do_helper_trt(CPUS390XState *env, int len,
1283 uint64_t array, uint64_t trans,
1284 int inc, uintptr_t ra)
1285{
1286 int i;
1287
1288 for (i = 0; i <= len; i++) {
1289 uint8_t byte = cpu_ldub_data_ra(env, array + i * inc, ra);
1290 uint8_t sbyte = cpu_ldub_data_ra(env, trans + byte, ra);
1291
1292 if (sbyte != 0) {
1293 set_address(env, 1, array + i * inc);
1294 env->regs[2] = deposit64(env->regs[2], 0, 8, sbyte);
1295 return (i == len) ? 2 : 1;
1296 }
1297 }
1298
1299 return 0;
1300}
1301
1302uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
1303 uint64_t trans)
1304{
1305 return do_helper_trt(env, len, array, trans, 1, GETPC());
1306}
1307
1308uint32_t HELPER(trtr)(CPUS390XState *env, uint32_t len, uint64_t array,
1309 uint64_t trans)
1310{
1311 return do_helper_trt(env, len, array, trans, -1, GETPC());
1312}
1313
1314
1315uint32_t HELPER(trXX)(CPUS390XState *env, uint32_t r1, uint32_t r2,
1316 uint32_t tst, uint32_t sizes)
1317{
1318 uintptr_t ra = GETPC();
1319 int dsize = (sizes & 1) ? 1 : 2;
1320 int ssize = (sizes & 2) ? 1 : 2;
1321 uint64_t tbl = get_address(env, 1);
1322 uint64_t dst = get_address(env, r1);
1323 uint64_t len = get_length(env, r1 + 1);
1324 uint64_t src = get_address(env, r2);
1325 uint32_t cc = 3;
1326 int i;
1327
1328
1329
1330
1331 if (ssize == 2 && !s390_has_feat(S390_FEAT_ETF2_ENH)) {
1332 tbl &= -4096;
1333 } else {
1334 tbl &= -8;
1335 }
1336
1337 check_alignment(env, len, ssize, ra);
1338
1339
1340
1341 for (i = 0; i < 0x2000; i++) {
1342 uint16_t sval = cpu_ldusize_data_ra(env, src, ssize, ra);
1343 uint64_t tble = tbl + (sval * dsize);
1344 uint16_t dval = cpu_ldusize_data_ra(env, tble, dsize, ra);
1345 if (dval == tst) {
1346 cc = 1;
1347 break;
1348 }
1349 cpu_stsize_data_ra(env, dst, dval, dsize, ra);
1350
1351 len -= ssize;
1352 src += ssize;
1353 dst += dsize;
1354
1355 if (len == 0) {
1356 cc = 0;
1357 break;
1358 }
1359 }
1360
1361 set_address(env, r1, dst);
1362 set_length(env, r1 + 1, len);
1363 set_address(env, r2, src);
1364
1365 return cc;
1366}
1367
1368static void do_cdsg(CPUS390XState *env, uint64_t addr,
1369 uint32_t r1, uint32_t r3, bool parallel)
1370{
1371 uintptr_t ra = GETPC();
1372 Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
1373 Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1374 Int128 oldv;
1375 bool fail;
1376
1377 if (parallel) {
1378#ifndef CONFIG_ATOMIC128
1379 cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
1380#else
1381 int mem_idx = cpu_mmu_index(env, false);
1382 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1383 oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
1384 fail = !int128_eq(oldv, cmpv);
1385#endif
1386 } else {
1387 uint64_t oldh, oldl;
1388
1389 check_alignment(env, addr, 16, ra);
1390
1391 oldh = cpu_ldq_data_ra(env, addr + 0, ra);
1392 oldl = cpu_ldq_data_ra(env, addr + 8, ra);
1393
1394 oldv = int128_make128(oldl, oldh);
1395 fail = !int128_eq(oldv, cmpv);
1396 if (fail) {
1397 newv = oldv;
1398 }
1399
1400 cpu_stq_data_ra(env, addr + 0, int128_gethi(newv), ra);
1401 cpu_stq_data_ra(env, addr + 8, int128_getlo(newv), ra);
1402 }
1403
1404 env->cc_op = fail;
1405 env->regs[r1] = int128_gethi(oldv);
1406 env->regs[r1 + 1] = int128_getlo(oldv);
1407}
1408
1409void HELPER(cdsg)(CPUS390XState *env, uint64_t addr,
1410 uint32_t r1, uint32_t r3)
1411{
1412 do_cdsg(env, addr, r1, r3, false);
1413}
1414
1415void HELPER(cdsg_parallel)(CPUS390XState *env, uint64_t addr,
1416 uint32_t r1, uint32_t r3)
1417{
1418 do_cdsg(env, addr, r1, r3, true);
1419}
1420
1421static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
1422 uint64_t a2, bool parallel)
1423{
1424#if !defined(CONFIG_USER_ONLY) || defined(CONFIG_ATOMIC128)
1425 uint32_t mem_idx = cpu_mmu_index(env, false);
1426#endif
1427 uintptr_t ra = GETPC();
1428 uint32_t fc = extract32(env->regs[0], 0, 8);
1429 uint32_t sc = extract32(env->regs[0], 8, 8);
1430 uint64_t pl = get_address(env, 1) & -16;
1431 uint64_t svh, svl;
1432 uint32_t cc;
1433
1434
1435 if (fc > 1 || sc > 3) {
1436 if (!s390_has_feat(S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2)) {
1437 goto spec_exception;
1438 }
1439 if (fc > 2 || sc > 4 || (fc == 2 && (r3 & 1))) {
1440 goto spec_exception;
1441 }
1442 }
1443
1444
1445 if (extract32(a1, 0, 4 << fc) || extract32(a2, 0, 1 << sc)) {
1446 goto spec_exception;
1447 }
1448
1449
1450#ifndef CONFIG_USER_ONLY
1451 probe_write(env, a2, 0, mem_idx, ra);
1452#endif
1453
1454
1455
1456
1457
1458 if (parallel) {
1459 int mask = 0;
1460#if !defined(CONFIG_ATOMIC64)
1461 mask = -8;
1462#elif !defined(CONFIG_ATOMIC128)
1463 mask = -16;
1464#endif
1465 if (((4 << fc) | (1 << sc)) & mask) {
1466 cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
1467 }
1468 }
1469
1470
1471
1472 svh = cpu_ldq_data_ra(env, pl + 16, ra);
1473 svl = cpu_ldq_data_ra(env, pl + 24, ra);
1474
1475 switch (fc) {
1476 case 0:
1477 {
1478 uint32_t nv = cpu_ldl_data_ra(env, pl, ra);
1479 uint32_t cv = env->regs[r3];
1480 uint32_t ov;
1481
1482 if (parallel) {
1483#ifdef CONFIG_USER_ONLY
1484 uint32_t *haddr = g2h(a1);
1485 ov = atomic_cmpxchg__nocheck(haddr, cv, nv);
1486#else
1487 TCGMemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mem_idx);
1488 ov = helper_atomic_cmpxchgl_be_mmu(env, a1, cv, nv, oi, ra);
1489#endif
1490 } else {
1491 ov = cpu_ldl_data_ra(env, a1, ra);
1492 cpu_stl_data_ra(env, a1, (ov == cv ? nv : ov), ra);
1493 }
1494 cc = (ov != cv);
1495 env->regs[r3] = deposit64(env->regs[r3], 32, 32, ov);
1496 }
1497 break;
1498
1499 case 1:
1500 {
1501 uint64_t nv = cpu_ldq_data_ra(env, pl, ra);
1502 uint64_t cv = env->regs[r3];
1503 uint64_t ov;
1504
1505 if (parallel) {
1506#ifdef CONFIG_ATOMIC64
1507# ifdef CONFIG_USER_ONLY
1508 uint64_t *haddr = g2h(a1);
1509 ov = atomic_cmpxchg__nocheck(haddr, cv, nv);
1510# else
1511 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN, mem_idx);
1512 ov = helper_atomic_cmpxchgq_be_mmu(env, a1, cv, nv, oi, ra);
1513# endif
1514#else
1515
1516 g_assert_not_reached();
1517#endif
1518 } else {
1519 ov = cpu_ldq_data_ra(env, a1, ra);
1520 cpu_stq_data_ra(env, a1, (ov == cv ? nv : ov), ra);
1521 }
1522 cc = (ov != cv);
1523 env->regs[r3] = ov;
1524 }
1525 break;
1526
1527 case 2:
1528 {
1529 uint64_t nvh = cpu_ldq_data_ra(env, pl, ra);
1530 uint64_t nvl = cpu_ldq_data_ra(env, pl + 8, ra);
1531 Int128 nv = int128_make128(nvl, nvh);
1532 Int128 cv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1533 Int128 ov;
1534
1535 if (parallel) {
1536#ifdef CONFIG_ATOMIC128
1537 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1538 ov = helper_atomic_cmpxchgo_be_mmu(env, a1, cv, nv, oi, ra);
1539 cc = !int128_eq(ov, cv);
1540#else
1541
1542 g_assert_not_reached();
1543#endif
1544 } else {
1545 uint64_t oh = cpu_ldq_data_ra(env, a1 + 0, ra);
1546 uint64_t ol = cpu_ldq_data_ra(env, a1 + 8, ra);
1547
1548 ov = int128_make128(ol, oh);
1549 cc = !int128_eq(ov, cv);
1550 if (cc) {
1551 nv = ov;
1552 }
1553
1554 cpu_stq_data_ra(env, a1 + 0, int128_gethi(nv), ra);
1555 cpu_stq_data_ra(env, a1 + 8, int128_getlo(nv), ra);
1556 }
1557
1558 env->regs[r3 + 0] = int128_gethi(ov);
1559 env->regs[r3 + 1] = int128_getlo(ov);
1560 }
1561 break;
1562
1563 default:
1564 g_assert_not_reached();
1565 }
1566
1567
1568
1569
1570 if (cc == 0) {
1571 switch (sc) {
1572 case 0:
1573 cpu_stb_data_ra(env, a2, svh >> 56, ra);
1574 break;
1575 case 1:
1576 cpu_stw_data_ra(env, a2, svh >> 48, ra);
1577 break;
1578 case 2:
1579 cpu_stl_data_ra(env, a2, svh >> 32, ra);
1580 break;
1581 case 3:
1582 cpu_stq_data_ra(env, a2, svh, ra);
1583 break;
1584 case 4:
1585 if (parallel) {
1586#ifdef CONFIG_ATOMIC128
1587 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1588 Int128 sv = int128_make128(svl, svh);
1589 helper_atomic_sto_be_mmu(env, a2, sv, oi, ra);
1590#else
1591
1592 g_assert_not_reached();
1593#endif
1594 } else {
1595 cpu_stq_data_ra(env, a2 + 0, svh, ra);
1596 cpu_stq_data_ra(env, a2 + 8, svl, ra);
1597 }
1598 break;
1599 default:
1600 g_assert_not_reached();
1601 }
1602 }
1603
1604 return cc;
1605
1606 spec_exception:
1607 s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
1608 g_assert_not_reached();
1609}
1610
1611uint32_t HELPER(csst)(CPUS390XState *env, uint32_t r3, uint64_t a1, uint64_t a2)
1612{
1613 return do_csst(env, r3, a1, a2, false);
1614}
1615
1616uint32_t HELPER(csst_parallel)(CPUS390XState *env, uint32_t r3, uint64_t a1,
1617 uint64_t a2)
1618{
1619 return do_csst(env, r3, a1, a2, true);
1620}
1621
1622#if !defined(CONFIG_USER_ONLY)
1623void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1624{
1625 uintptr_t ra = GETPC();
1626 S390CPU *cpu = s390_env_get_cpu(env);
1627 bool PERchanged = false;
1628 uint64_t src = a2;
1629 uint32_t i;
1630
1631 if (src & 0x7) {
1632 s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
1633 }
1634
1635 for (i = r1;; i = (i + 1) % 16) {
1636 uint64_t val = cpu_ldq_data_ra(env, src, ra);
1637 if (env->cregs[i] != val && i >= 9 && i <= 11) {
1638 PERchanged = true;
1639 }
1640 env->cregs[i] = val;
1641 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
1642 i, src, val);
1643 src += sizeof(uint64_t);
1644
1645 if (i == r3) {
1646 break;
1647 }
1648 }
1649
1650 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
1651 s390_cpu_recompute_watchpoints(CPU(cpu));
1652 }
1653
1654 tlb_flush(CPU(cpu));
1655}
1656
1657void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1658{
1659 uintptr_t ra = GETPC();
1660 S390CPU *cpu = s390_env_get_cpu(env);
1661 bool PERchanged = false;
1662 uint64_t src = a2;
1663 uint32_t i;
1664
1665 if (src & 0x3) {
1666 s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
1667 }
1668
1669 for (i = r1;; i = (i + 1) % 16) {
1670 uint32_t val = cpu_ldl_data_ra(env, src, ra);
1671 if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
1672 PERchanged = true;
1673 }
1674 env->cregs[i] = deposit64(env->cregs[i], 0, 32, val);
1675 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val);
1676 src += sizeof(uint32_t);
1677
1678 if (i == r3) {
1679 break;
1680 }
1681 }
1682
1683 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
1684 s390_cpu_recompute_watchpoints(CPU(cpu));
1685 }
1686
1687 tlb_flush(CPU(cpu));
1688}
1689
1690void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1691{
1692 uintptr_t ra = GETPC();
1693 uint64_t dest = a2;
1694 uint32_t i;
1695
1696 if (dest & 0x7) {
1697 s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
1698 }
1699
1700 for (i = r1;; i = (i + 1) % 16) {
1701 cpu_stq_data_ra(env, dest, env->cregs[i], ra);
1702 dest += sizeof(uint64_t);
1703
1704 if (i == r3) {
1705 break;
1706 }
1707 }
1708}
1709
1710void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1711{
1712 uintptr_t ra = GETPC();
1713 uint64_t dest = a2;
1714 uint32_t i;
1715
1716 if (dest & 0x3) {
1717 s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
1718 }
1719
1720 for (i = r1;; i = (i + 1) % 16) {
1721 cpu_stl_data_ra(env, dest, env->cregs[i], ra);
1722 dest += sizeof(uint32_t);
1723
1724 if (i == r3) {
1725 break;
1726 }
1727 }
1728}
1729
1730uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
1731{
1732 uintptr_t ra = GETPC();
1733 int i;
1734
1735 real_addr = wrap_address(env, real_addr) & TARGET_PAGE_MASK;
1736
1737 for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
1738 cpu_stq_real_ra(env, real_addr + i, 0, ra);
1739 }
1740
1741 return 0;
1742}
1743
1744uint32_t HELPER(tprot)(CPUS390XState *env, uint64_t a1, uint64_t a2)
1745{
1746 S390CPU *cpu = s390_env_get_cpu(env);
1747 CPUState *cs = CPU(cpu);
1748
1749
1750
1751
1752
1753 if (!s390_cpu_virt_mem_check_write(cpu, a1, 0, 1)) {
1754
1755 return 0;
1756 }
1757
1758 if (env->int_pgm_code == PGM_PROTECTION) {
1759
1760 cs->exception_index = 0;
1761 if (!s390_cpu_virt_mem_check_read(cpu, a1, 0, 1)) {
1762
1763 return 1;
1764 }
1765 }
1766
1767 switch (env->int_pgm_code) {
1768 case PGM_PROTECTION:
1769
1770 cs->exception_index = 0;
1771 return 2;
1772 case PGM_ADDRESSING:
1773 case PGM_TRANS_SPEC:
1774
1775 s390_cpu_virt_mem_handle_exc(cpu, GETPC());
1776 return 0;
1777 }
1778
1779
1780 cs->exception_index = 0;
1781 return 3;
1782}
1783
1784
1785uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
1786{
1787 static S390SKeysState *ss;
1788 static S390SKeysClass *skeyclass;
1789 uint64_t addr = wrap_address(env, r2);
1790 uint8_t key;
1791
1792 if (addr > ram_size) {
1793 return 0;
1794 }
1795
1796 if (unlikely(!ss)) {
1797 ss = s390_get_skeys_device();
1798 skeyclass = S390_SKEYS_GET_CLASS(ss);
1799 }
1800
1801 if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
1802 return 0;
1803 }
1804 return key;
1805}
1806
1807
1808void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
1809{
1810 static S390SKeysState *ss;
1811 static S390SKeysClass *skeyclass;
1812 uint64_t addr = wrap_address(env, r2);
1813 uint8_t key;
1814
1815 if (addr > ram_size) {
1816 return;
1817 }
1818
1819 if (unlikely(!ss)) {
1820 ss = s390_get_skeys_device();
1821 skeyclass = S390_SKEYS_GET_CLASS(ss);
1822 }
1823
1824 key = (uint8_t) r1;
1825 skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
1826}
1827
1828
1829uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
1830{
1831 static S390SKeysState *ss;
1832 static S390SKeysClass *skeyclass;
1833 uint8_t re, key;
1834
1835 if (r2 > ram_size) {
1836 return 0;
1837 }
1838
1839 if (unlikely(!ss)) {
1840 ss = s390_get_skeys_device();
1841 skeyclass = S390_SKEYS_GET_CLASS(ss);
1842 }
1843
1844 if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1845 return 0;
1846 }
1847
1848 re = key & (SK_R | SK_C);
1849 key &= ~SK_R;
1850
1851 if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1852 return 0;
1853 }
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864 return re >> 1;
1865}
1866
1867uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1868{
1869 uintptr_t ra = GETPC();
1870 int cc = 0, i;
1871
1872 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1873 __func__, l, a1, a2);
1874
1875 if (l > 256) {
1876
1877 l = 256;
1878 cc = 3;
1879 }
1880
1881
1882 for (i = 0; i < l; i++) {
1883 uint8_t x = cpu_ldub_primary_ra(env, a2 + i, ra);
1884 cpu_stb_secondary_ra(env, a1 + i, x, ra);
1885 }
1886
1887 return cc;
1888}
1889
1890uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1891{
1892 uintptr_t ra = GETPC();
1893 int cc = 0, i;
1894
1895 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1896 __func__, l, a1, a2);
1897
1898 if (l > 256) {
1899
1900 l = 256;
1901 cc = 3;
1902 }
1903
1904
1905 for (i = 0; i < l; i++) {
1906 uint8_t x = cpu_ldub_secondary_ra(env, a2 + i, ra);
1907 cpu_stb_primary_ra(env, a1 + i, x, ra);
1908 }
1909
1910 return cc;
1911}
1912
1913void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4)
1914{
1915 CPUState *cs = CPU(s390_env_get_cpu(env));
1916 const uintptr_t ra = GETPC();
1917 uint64_t table, entry, raddr;
1918 uint16_t entries, i, index = 0;
1919
1920 if (r2 & 0xff000) {
1921 s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
1922 }
1923
1924 if (!(r2 & 0x800)) {
1925
1926 table = r1 & ASCE_ORIGIN;
1927 entries = (r2 & 0x7ff) + 1;
1928
1929 switch (r1 & ASCE_TYPE_MASK) {
1930 case ASCE_TYPE_REGION1:
1931 index = (r2 >> 53) & 0x7ff;
1932 break;
1933 case ASCE_TYPE_REGION2:
1934 index = (r2 >> 42) & 0x7ff;
1935 break;
1936 case ASCE_TYPE_REGION3:
1937 index = (r2 >> 31) & 0x7ff;
1938 break;
1939 case ASCE_TYPE_SEGMENT:
1940 index = (r2 >> 20) & 0x7ff;
1941 break;
1942 }
1943 for (i = 0; i < entries; i++) {
1944
1945 raddr = table + ((index + i) & 0x7ff) * sizeof(entry);
1946 entry = cpu_ldq_real_ra(env, raddr, ra);
1947 if (!(entry & REGION_ENTRY_INV)) {
1948
1949 entry |= REGION_ENTRY_INV;
1950 cpu_stq_real_ra(env, raddr, entry, ra);
1951 }
1952 }
1953 }
1954
1955
1956 if (m4 & 1) {
1957 tlb_flush(cs);
1958 } else {
1959 tlb_flush_all_cpus_synced(cs);
1960 }
1961}
1962
1963
1964void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr,
1965 uint32_t m4)
1966{
1967 CPUState *cs = CPU(s390_env_get_cpu(env));
1968 const uintptr_t ra = GETPC();
1969 uint64_t page = vaddr & TARGET_PAGE_MASK;
1970 uint64_t pte_addr, pte;
1971
1972
1973 pte_addr = (pto & SEGMENT_ENTRY_ORIGIN);
1974 pte_addr += (vaddr & VADDR_PX) >> 9;
1975
1976
1977 pte = cpu_ldq_real_ra(env, pte_addr, ra);
1978 pte |= PAGE_INVALID;
1979 cpu_stq_real_ra(env, pte_addr, pte, ra);
1980
1981
1982
1983 if (m4 & 1) {
1984 if (vaddr & ~VADDR_PX) {
1985 tlb_flush_page(cs, page);
1986
1987 tlb_flush_page(cs, page ^ 0x80000000);
1988 } else {
1989
1990 tlb_flush(cs);
1991 }
1992 } else {
1993 if (vaddr & ~VADDR_PX) {
1994 tlb_flush_page_all_cpus_synced(cs, page);
1995
1996 tlb_flush_page_all_cpus_synced(cs, page ^ 0x80000000);
1997 } else {
1998
1999 tlb_flush_all_cpus_synced(cs);
2000 }
2001 }
2002}
2003
2004
2005void HELPER(ptlb)(CPUS390XState *env)
2006{
2007 S390CPU *cpu = s390_env_get_cpu(env);
2008
2009 tlb_flush(CPU(cpu));
2010}
2011
2012
2013void HELPER(purge)(CPUS390XState *env)
2014{
2015 S390CPU *cpu = s390_env_get_cpu(env);
2016
2017 tlb_flush_all_cpus_synced(CPU(cpu));
2018}
2019
2020
2021uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr)
2022{
2023 return cpu_ldl_real_ra(env, wrap_address(env, addr), GETPC());
2024}
2025
2026uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr)
2027{
2028 return cpu_ldq_real_ra(env, wrap_address(env, addr), GETPC());
2029}
2030
2031
2032void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
2033{
2034 cpu_stl_real_ra(env, wrap_address(env, addr), (uint32_t)v1, GETPC());
2035
2036 if ((env->psw.mask & PSW_MASK_PER) &&
2037 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
2038 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
2039
2040 env->per_address = env->psw.addr;
2041 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
2042 }
2043}
2044
2045void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
2046{
2047 cpu_stq_real_ra(env, wrap_address(env, addr), v1, GETPC());
2048
2049 if ((env->psw.mask & PSW_MASK_PER) &&
2050 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
2051 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
2052
2053 env->per_address = env->psw.addr;
2054 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
2055 }
2056}
2057
2058
2059uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
2060{
2061 CPUState *cs = CPU(s390_env_get_cpu(env));
2062 uint32_t cc = 0;
2063 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
2064 uint64_t ret;
2065 int old_exc, flags;
2066
2067
2068 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
2069 s390_program_interrupt(env, PGM_SPECIAL_OP, 2, GETPC());
2070 }
2071
2072 old_exc = cs->exception_index;
2073 if (mmu_translate(env, addr, 0, asc, &ret, &flags, true)) {
2074 cc = 3;
2075 }
2076 if (cs->exception_index == EXCP_PGM) {
2077 ret = env->int_pgm_code | 0x80000000;
2078 } else {
2079 ret |= addr & ~TARGET_PAGE_MASK;
2080 }
2081 cs->exception_index = old_exc;
2082
2083 env->cc_op = cc;
2084 return ret;
2085}
2086#endif
2087
2088
2089static uint64_t do_lpq(CPUS390XState *env, uint64_t addr, bool parallel)
2090{
2091 uintptr_t ra = GETPC();
2092 uint64_t hi, lo;
2093
2094 if (parallel) {
2095#ifndef CONFIG_ATOMIC128
2096 cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
2097#else
2098 int mem_idx = cpu_mmu_index(env, false);
2099 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
2100 Int128 v = helper_atomic_ldo_be_mmu(env, addr, oi, ra);
2101 hi = int128_gethi(v);
2102 lo = int128_getlo(v);
2103#endif
2104 } else {
2105 check_alignment(env, addr, 16, ra);
2106
2107 hi = cpu_ldq_data_ra(env, addr + 0, ra);
2108 lo = cpu_ldq_data_ra(env, addr + 8, ra);
2109 }
2110
2111 env->retxl = lo;
2112 return hi;
2113}
2114
2115uint64_t HELPER(lpq)(CPUS390XState *env, uint64_t addr)
2116{
2117 return do_lpq(env, addr, false);
2118}
2119
2120uint64_t HELPER(lpq_parallel)(CPUS390XState *env, uint64_t addr)
2121{
2122 return do_lpq(env, addr, true);
2123}
2124
2125
2126static void do_stpq(CPUS390XState *env, uint64_t addr,
2127 uint64_t low, uint64_t high, bool parallel)
2128{
2129 uintptr_t ra = GETPC();
2130
2131 if (parallel) {
2132#ifndef CONFIG_ATOMIC128
2133 cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
2134#else
2135 int mem_idx = cpu_mmu_index(env, false);
2136 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
2137
2138 Int128 v = int128_make128(low, high);
2139 helper_atomic_sto_be_mmu(env, addr, v, oi, ra);
2140#endif
2141 } else {
2142 check_alignment(env, addr, 16, ra);
2143
2144 cpu_stq_data_ra(env, addr + 0, high, ra);
2145 cpu_stq_data_ra(env, addr + 8, low, ra);
2146 }
2147}
2148
2149void HELPER(stpq)(CPUS390XState *env, uint64_t addr,
2150 uint64_t low, uint64_t high)
2151{
2152 do_stpq(env, addr, low, high, false);
2153}
2154
2155void HELPER(stpq_parallel)(CPUS390XState *env, uint64_t addr,
2156 uint64_t low, uint64_t high)
2157{
2158 do_stpq(env, addr, low, high, true);
2159}
2160
2161
2162
2163
2164
2165
2166
2167
2168void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
2169{
2170 uint64_t insn = cpu_lduw_code(env, addr);
2171 uint8_t opc = insn >> 8;
2172
2173
2174 insn |= r1 & 0xff;
2175
2176
2177 insn <<= 48;
2178 switch (get_ilen(opc)) {
2179 case 2:
2180 break;
2181 case 4:
2182 insn |= (uint64_t)cpu_lduw_code(env, addr + 2) << 32;
2183 break;
2184 case 6:
2185 insn |= (uint64_t)(uint32_t)cpu_ldl_code(env, addr + 2) << 16;
2186 break;
2187 default:
2188 g_assert_not_reached();
2189 }
2190
2191
2192 if ((opc & 0xf0) == 0xd0) {
2193 typedef uint32_t (*dx_helper)(CPUS390XState *, uint32_t, uint64_t,
2194 uint64_t, uintptr_t);
2195 static const dx_helper dx[16] = {
2196 [0x2] = do_helper_mvc,
2197 [0x4] = do_helper_nc,
2198 [0x5] = do_helper_clc,
2199 [0x6] = do_helper_oc,
2200 [0x7] = do_helper_xc,
2201 [0xc] = do_helper_tr,
2202 };
2203 dx_helper helper = dx[opc & 0xf];
2204
2205 if (helper) {
2206 uint32_t l = extract64(insn, 48, 8);
2207 uint32_t b1 = extract64(insn, 44, 4);
2208 uint32_t d1 = extract64(insn, 32, 12);
2209 uint32_t b2 = extract64(insn, 28, 4);
2210 uint32_t d2 = extract64(insn, 16, 12);
2211 uint64_t a1 = wrap_address(env, env->regs[b1] + d1);
2212 uint64_t a2 = wrap_address(env, env->regs[b2] + d2);
2213
2214 env->cc_op = helper(env, l, a1, a2, 0);
2215 env->psw.addr += ilen;
2216 return;
2217 }
2218 } else if (opc == 0x0a) {
2219 env->int_svc_code = extract64(insn, 48, 8);
2220 env->int_svc_ilen = ilen;
2221 helper_exception(env, EXCP_SVC);
2222 g_assert_not_reached();
2223 }
2224
2225
2226
2227
2228
2229 env->ex_value = insn | ilen;
2230}
2231
2232uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src,
2233 uint64_t len)
2234{
2235 const uint8_t psw_key = (env->psw.mask & PSW_MASK_KEY) >> PSW_SHIFT_KEY;
2236 const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
2237 const uint64_t r0 = env->regs[0];
2238 const uintptr_t ra = GETPC();
2239 uint8_t dest_key, dest_as, dest_k, dest_a;
2240 uint8_t src_key, src_as, src_k, src_a;
2241 uint64_t val;
2242 int cc = 0;
2243
2244 HELPER_LOG("%s dest %" PRIx64 ", src %" PRIx64 ", len %" PRIx64 "\n",
2245 __func__, dest, src, len);
2246
2247 if (!(env->psw.mask & PSW_MASK_DAT)) {
2248 s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra);
2249 }
2250
2251
2252 val = (r0 & 0xffff0000ULL) >> 16;
2253 dest_key = (val >> 12) & 0xf;
2254 dest_as = (val >> 6) & 0x3;
2255 dest_k = (val >> 1) & 0x1;
2256 dest_a = val & 0x1;
2257
2258
2259 val = (r0 & 0x0000ffffULL);
2260 src_key = (val >> 12) & 0xf;
2261 src_as = (val >> 6) & 0x3;
2262 src_k = (val >> 1) & 0x1;
2263 src_a = val & 0x1;
2264
2265 if (!dest_k) {
2266 dest_key = psw_key;
2267 }
2268 if (!src_k) {
2269 src_key = psw_key;
2270 }
2271 if (!dest_a) {
2272 dest_as = psw_as;
2273 }
2274 if (!src_a) {
2275 src_as = psw_as;
2276 }
2277
2278 if (dest_a && dest_as == AS_HOME && (env->psw.mask & PSW_MASK_PSTATE)) {
2279 s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra);
2280 }
2281 if (!(env->cregs[0] & CR0_SECONDARY) &&
2282 (dest_as == AS_SECONDARY || src_as == AS_SECONDARY)) {
2283 s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra);
2284 }
2285 if (!psw_key_valid(env, dest_key) || !psw_key_valid(env, src_key)) {
2286 s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra);
2287 }
2288
2289 len = wrap_length(env, len);
2290 if (len > 4096) {
2291 cc = 3;
2292 len = 4096;
2293 }
2294
2295
2296 if (src_as == AS_ACCREG || dest_as == AS_ACCREG ||
2297 (env->psw.mask & PSW_MASK_PSTATE)) {
2298 qemu_log_mask(LOG_UNIMP, "%s: AR-mode and PSTATE support missing\n",
2299 __func__);
2300 s390_program_interrupt(env, PGM_ADDRESSING, 6, ra);
2301 }
2302
2303
2304
2305
2306
2307#ifdef CONFIG_USER_ONLY
2308
2309 g_assert_not_reached();
2310#else
2311 fast_memmove_as(env, dest, src, len, dest_as, src_as, ra);
2312#endif
2313
2314 return cc;
2315}
2316
2317
2318
2319
2320typedef int (*decode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2321 uint64_t ilen, bool enh_check, uintptr_t ra,
2322 uint32_t *ochar, uint32_t *olen);
2323
2324
2325
2326
2327typedef int (*encode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2328 uint64_t ilen, uintptr_t ra, uint32_t c,
2329 uint32_t *olen);
2330
2331static int decode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2332 bool enh_check, uintptr_t ra,
2333 uint32_t *ochar, uint32_t *olen)
2334{
2335 uint8_t s0, s1, s2, s3;
2336 uint32_t c, l;
2337
2338 if (ilen < 1) {
2339 return 0;
2340 }
2341 s0 = cpu_ldub_data_ra(env, addr, ra);
2342 if (s0 <= 0x7f) {
2343
2344 l = 1;
2345 c = s0;
2346 } else if (s0 <= (enh_check ? 0xc1 : 0xbf)) {
2347
2348 return 2;
2349 } else if (s0 <= 0xdf) {
2350
2351 l = 2;
2352 if (ilen < 2) {
2353 return 0;
2354 }
2355 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2356 c = s0 & 0x1f;
2357 c = (c << 6) | (s1 & 0x3f);
2358 if (enh_check && (s1 & 0xc0) != 0x80) {
2359 return 2;
2360 }
2361 } else if (s0 <= 0xef) {
2362
2363 l = 3;
2364 if (ilen < 3) {
2365 return 0;
2366 }
2367 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2368 s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2369 c = s0 & 0x0f;
2370 c = (c << 6) | (s1 & 0x3f);
2371 c = (c << 6) | (s2 & 0x3f);
2372
2373
2374
2375 if (enh_check
2376 && ((s1 & 0xc0) != 0x80
2377 || (s2 & 0xc0) != 0x80
2378 || c < 0x1000
2379 || (c >= 0xd800 && c <= 0xdfff))) {
2380 return 2;
2381 }
2382 } else if (s0 <= (enh_check ? 0xf4 : 0xf7)) {
2383
2384 l = 4;
2385 if (ilen < 4) {
2386 return 0;
2387 }
2388 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2389 s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2390 s3 = cpu_ldub_data_ra(env, addr + 3, ra);
2391 c = s0 & 0x07;
2392 c = (c << 6) | (s1 & 0x3f);
2393 c = (c << 6) | (s2 & 0x3f);
2394 c = (c << 6) | (s3 & 0x3f);
2395
2396 if (enh_check
2397 && ((s1 & 0xc0) != 0x80
2398 || (s2 & 0xc0) != 0x80
2399 || (s3 & 0xc0) != 0x80
2400 || c < 0x010000
2401 || c > 0x10ffff)) {
2402 return 2;
2403 }
2404 } else {
2405
2406 return 2;
2407 }
2408
2409 *ochar = c;
2410 *olen = l;
2411 return -1;
2412}
2413
2414static int decode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2415 bool enh_check, uintptr_t ra,
2416 uint32_t *ochar, uint32_t *olen)
2417{
2418 uint16_t s0, s1;
2419 uint32_t c, l;
2420
2421 if (ilen < 2) {
2422 return 0;
2423 }
2424 s0 = cpu_lduw_data_ra(env, addr, ra);
2425 if ((s0 & 0xfc00) != 0xd800) {
2426
2427 l = 2;
2428 c = s0;
2429 } else {
2430
2431 l = 4;
2432 if (ilen < 4) {
2433 return 0;
2434 }
2435 s1 = cpu_lduw_data_ra(env, addr + 2, ra);
2436 c = extract32(s0, 6, 4) + 1;
2437 c = (c << 6) | (s0 & 0x3f);
2438 c = (c << 10) | (s1 & 0x3ff);
2439 if (enh_check && (s1 & 0xfc00) != 0xdc00) {
2440
2441 return 2;
2442 }
2443 }
2444
2445 *ochar = c;
2446 *olen = l;
2447 return -1;
2448}
2449
2450static int decode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2451 bool enh_check, uintptr_t ra,
2452 uint32_t *ochar, uint32_t *olen)
2453{
2454 uint32_t c;
2455
2456 if (ilen < 4) {
2457 return 0;
2458 }
2459 c = cpu_ldl_data_ra(env, addr, ra);
2460 if ((c >= 0xd800 && c <= 0xdbff) || c > 0x10ffff) {
2461
2462 return 2;
2463 }
2464
2465 *ochar = c;
2466 *olen = 4;
2467 return -1;
2468}
2469
2470static int encode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2471 uintptr_t ra, uint32_t c, uint32_t *olen)
2472{
2473 uint8_t d[4];
2474 uint32_t l, i;
2475
2476 if (c <= 0x7f) {
2477
2478 l = 1;
2479 d[0] = c;
2480 } else if (c <= 0x7ff) {
2481
2482 l = 2;
2483 d[1] = 0x80 | extract32(c, 0, 6);
2484 d[0] = 0xc0 | extract32(c, 6, 5);
2485 } else if (c <= 0xffff) {
2486
2487 l = 3;
2488 d[2] = 0x80 | extract32(c, 0, 6);
2489 d[1] = 0x80 | extract32(c, 6, 6);
2490 d[0] = 0xe0 | extract32(c, 12, 4);
2491 } else {
2492
2493 l = 4;
2494 d[3] = 0x80 | extract32(c, 0, 6);
2495 d[2] = 0x80 | extract32(c, 6, 6);
2496 d[1] = 0x80 | extract32(c, 12, 6);
2497 d[0] = 0xf0 | extract32(c, 18, 3);
2498 }
2499
2500 if (ilen < l) {
2501 return 1;
2502 }
2503 for (i = 0; i < l; ++i) {
2504 cpu_stb_data_ra(env, addr + i, d[i], ra);
2505 }
2506
2507 *olen = l;
2508 return -1;
2509}
2510
2511static int encode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2512 uintptr_t ra, uint32_t c, uint32_t *olen)
2513{
2514 uint16_t d0, d1;
2515
2516 if (c <= 0xffff) {
2517
2518 if (ilen < 2) {
2519 return 1;
2520 }
2521 cpu_stw_data_ra(env, addr, c, ra);
2522 *olen = 2;
2523 } else {
2524
2525 if (ilen < 4) {
2526 return 1;
2527 }
2528 d1 = 0xdc00 | extract32(c, 0, 10);
2529 d0 = 0xd800 | extract32(c, 10, 6);
2530 d0 = deposit32(d0, 6, 4, extract32(c, 16, 5) - 1);
2531 cpu_stw_data_ra(env, addr + 0, d0, ra);
2532 cpu_stw_data_ra(env, addr + 2, d1, ra);
2533 *olen = 4;
2534 }
2535
2536 return -1;
2537}
2538
2539static int encode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2540 uintptr_t ra, uint32_t c, uint32_t *olen)
2541{
2542 if (ilen < 4) {
2543 return 1;
2544 }
2545 cpu_stl_data_ra(env, addr, c, ra);
2546 *olen = 4;
2547 return -1;
2548}
2549
2550static inline uint32_t convert_unicode(CPUS390XState *env, uint32_t r1,
2551 uint32_t r2, uint32_t m3, uintptr_t ra,
2552 decode_unicode_fn decode,
2553 encode_unicode_fn encode)
2554{
2555 uint64_t dst = get_address(env, r1);
2556 uint64_t dlen = get_length(env, r1 + 1);
2557 uint64_t src = get_address(env, r2);
2558 uint64_t slen = get_length(env, r2 + 1);
2559 bool enh_check = m3 & 1;
2560 int cc, i;
2561
2562
2563
2564 for (i = 0; i < 256; ++i) {
2565 uint32_t c, ilen, olen;
2566
2567 cc = decode(env, src, slen, enh_check, ra, &c, &ilen);
2568 if (unlikely(cc >= 0)) {
2569 break;
2570 }
2571 cc = encode(env, dst, dlen, ra, c, &olen);
2572 if (unlikely(cc >= 0)) {
2573 break;
2574 }
2575
2576 src += ilen;
2577 slen -= ilen;
2578 dst += olen;
2579 dlen -= olen;
2580 cc = 3;
2581 }
2582
2583 set_address(env, r1, dst);
2584 set_length(env, r1 + 1, dlen);
2585 set_address(env, r2, src);
2586 set_length(env, r2 + 1, slen);
2587
2588 return cc;
2589}
2590
2591uint32_t HELPER(cu12)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2592{
2593 return convert_unicode(env, r1, r2, m3, GETPC(),
2594 decode_utf8, encode_utf16);
2595}
2596
2597uint32_t HELPER(cu14)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2598{
2599 return convert_unicode(env, r1, r2, m3, GETPC(),
2600 decode_utf8, encode_utf32);
2601}
2602
2603uint32_t HELPER(cu21)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2604{
2605 return convert_unicode(env, r1, r2, m3, GETPC(),
2606 decode_utf16, encode_utf8);
2607}
2608
2609uint32_t HELPER(cu24)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2610{
2611 return convert_unicode(env, r1, r2, m3, GETPC(),
2612 decode_utf16, encode_utf32);
2613}
2614
2615uint32_t HELPER(cu41)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2616{
2617 return convert_unicode(env, r1, r2, m3, GETPC(),
2618 decode_utf32, encode_utf8);
2619}
2620
2621uint32_t HELPER(cu42)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2622{
2623 return convert_unicode(env, r1, r2, m3, GETPC(),
2624 decode_utf32, encode_utf16);
2625}
2626