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