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/address-spaces.h"
25#include "exec/helper-proto.h"
26#include "exec/exec-all.h"
27#include "exec/cpu_ldst.h"
28#include "qemu/int128.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
1303uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
1304 uint64_t trans)
1305{
1306 return do_helper_trt(env, len, array, trans, 1, GETPC());
1307}
1308
1309uint32_t HELPER(trtr)(CPUS390XState *env, uint32_t len, uint64_t array,
1310 uint64_t trans)
1311{
1312 return do_helper_trt(env, len, array, trans, -1, GETPC());
1313}
1314
1315
1316uint32_t HELPER(trXX)(CPUS390XState *env, uint32_t r1, uint32_t r2,
1317 uint32_t tst, uint32_t sizes)
1318{
1319 uintptr_t ra = GETPC();
1320 int dsize = (sizes & 1) ? 1 : 2;
1321 int ssize = (sizes & 2) ? 1 : 2;
1322 uint64_t tbl = get_address(env, 1);
1323 uint64_t dst = get_address(env, r1);
1324 uint64_t len = get_length(env, r1 + 1);
1325 uint64_t src = get_address(env, r2);
1326 uint32_t cc = 3;
1327 int i;
1328
1329
1330
1331
1332 if (ssize == 2 && !s390_has_feat(S390_FEAT_ETF2_ENH)) {
1333 tbl &= -4096;
1334 } else {
1335 tbl &= -8;
1336 }
1337
1338 check_alignment(env, len, ssize, ra);
1339
1340
1341
1342 for (i = 0; i < 0x2000; i++) {
1343 uint16_t sval = cpu_ldusize_data_ra(env, src, ssize, ra);
1344 uint64_t tble = tbl + (sval * dsize);
1345 uint16_t dval = cpu_ldusize_data_ra(env, tble, dsize, ra);
1346 if (dval == tst) {
1347 cc = 1;
1348 break;
1349 }
1350 cpu_stsize_data_ra(env, dst, dval, dsize, ra);
1351
1352 len -= ssize;
1353 src += ssize;
1354 dst += dsize;
1355
1356 if (len == 0) {
1357 cc = 0;
1358 break;
1359 }
1360 }
1361
1362 set_address(env, r1, dst);
1363 set_length(env, r1 + 1, len);
1364 set_address(env, r2, src);
1365
1366 return cc;
1367}
1368
1369static void do_cdsg(CPUS390XState *env, uint64_t addr,
1370 uint32_t r1, uint32_t r3, bool parallel)
1371{
1372 uintptr_t ra = GETPC();
1373 Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
1374 Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1375 Int128 oldv;
1376 bool fail;
1377
1378 if (parallel) {
1379#ifndef CONFIG_ATOMIC128
1380 cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
1381#else
1382 int mem_idx = cpu_mmu_index(env, false);
1383 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1384 oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
1385 fail = !int128_eq(oldv, cmpv);
1386#endif
1387 } else {
1388 uint64_t oldh, oldl;
1389
1390 check_alignment(env, addr, 16, ra);
1391
1392 oldh = cpu_ldq_data_ra(env, addr + 0, ra);
1393 oldl = cpu_ldq_data_ra(env, addr + 8, ra);
1394
1395 oldv = int128_make128(oldl, oldh);
1396 fail = !int128_eq(oldv, cmpv);
1397 if (fail) {
1398 newv = oldv;
1399 }
1400
1401 cpu_stq_data_ra(env, addr + 0, int128_gethi(newv), ra);
1402 cpu_stq_data_ra(env, addr + 8, int128_getlo(newv), ra);
1403 }
1404
1405 env->cc_op = fail;
1406 env->regs[r1] = int128_gethi(oldv);
1407 env->regs[r1 + 1] = int128_getlo(oldv);
1408}
1409
1410void HELPER(cdsg)(CPUS390XState *env, uint64_t addr,
1411 uint32_t r1, uint32_t r3)
1412{
1413 do_cdsg(env, addr, r1, r3, false);
1414}
1415
1416void HELPER(cdsg_parallel)(CPUS390XState *env, uint64_t addr,
1417 uint32_t r1, uint32_t r3)
1418{
1419 do_cdsg(env, addr, r1, r3, true);
1420}
1421
1422static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
1423 uint64_t a2, bool parallel)
1424{
1425#if !defined(CONFIG_USER_ONLY) || defined(CONFIG_ATOMIC128)
1426 uint32_t mem_idx = cpu_mmu_index(env, false);
1427#endif
1428 uintptr_t ra = GETPC();
1429 uint32_t fc = extract32(env->regs[0], 0, 8);
1430 uint32_t sc = extract32(env->regs[0], 8, 8);
1431 uint64_t pl = get_address(env, 1) & -16;
1432 uint64_t svh, svl;
1433 uint32_t cc;
1434
1435
1436 if (fc > 1 || sc > 3) {
1437 if (!s390_has_feat(S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2)) {
1438 goto spec_exception;
1439 }
1440 if (fc > 2 || sc > 4 || (fc == 2 && (r3 & 1))) {
1441 goto spec_exception;
1442 }
1443 }
1444
1445
1446 if (extract32(a1, 0, 4 << fc) || extract32(a2, 0, 1 << sc)) {
1447 goto spec_exception;
1448 }
1449
1450
1451#ifndef CONFIG_USER_ONLY
1452 probe_write(env, a2, 0, mem_idx, ra);
1453#endif
1454
1455
1456
1457
1458
1459 if (parallel) {
1460 int mask = 0;
1461#if !defined(CONFIG_ATOMIC64)
1462 mask = -8;
1463#elif !defined(CONFIG_ATOMIC128)
1464 mask = -16;
1465#endif
1466 if (((4 << fc) | (1 << sc)) & mask) {
1467 cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
1468 }
1469 }
1470
1471
1472
1473 svh = cpu_ldq_data_ra(env, pl + 16, ra);
1474 svl = cpu_ldq_data_ra(env, pl + 24, ra);
1475
1476 switch (fc) {
1477 case 0:
1478 {
1479 uint32_t nv = cpu_ldl_data_ra(env, pl, ra);
1480 uint32_t cv = env->regs[r3];
1481 uint32_t ov;
1482
1483 if (parallel) {
1484#ifdef CONFIG_USER_ONLY
1485 uint32_t *haddr = g2h(a1);
1486 ov = atomic_cmpxchg__nocheck(haddr, cv, nv);
1487#else
1488 TCGMemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mem_idx);
1489 ov = helper_atomic_cmpxchgl_be_mmu(env, a1, cv, nv, oi, ra);
1490#endif
1491 } else {
1492 ov = cpu_ldl_data_ra(env, a1, ra);
1493 cpu_stl_data_ra(env, a1, (ov == cv ? nv : ov), ra);
1494 }
1495 cc = (ov != cv);
1496 env->regs[r3] = deposit64(env->regs[r3], 32, 32, ov);
1497 }
1498 break;
1499
1500 case 1:
1501 {
1502 uint64_t nv = cpu_ldq_data_ra(env, pl, ra);
1503 uint64_t cv = env->regs[r3];
1504 uint64_t ov;
1505
1506 if (parallel) {
1507#ifdef CONFIG_ATOMIC64
1508# ifdef CONFIG_USER_ONLY
1509 uint64_t *haddr = g2h(a1);
1510 ov = atomic_cmpxchg__nocheck(haddr, cv, nv);
1511# else
1512 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN, mem_idx);
1513 ov = helper_atomic_cmpxchgq_be_mmu(env, a1, cv, nv, oi, ra);
1514# endif
1515#else
1516
1517 g_assert_not_reached();
1518#endif
1519 } else {
1520 ov = cpu_ldq_data_ra(env, a1, ra);
1521 cpu_stq_data_ra(env, a1, (ov == cv ? nv : ov), ra);
1522 }
1523 cc = (ov != cv);
1524 env->regs[r3] = ov;
1525 }
1526 break;
1527
1528 case 2:
1529 {
1530 uint64_t nvh = cpu_ldq_data_ra(env, pl, ra);
1531 uint64_t nvl = cpu_ldq_data_ra(env, pl + 8, ra);
1532 Int128 nv = int128_make128(nvl, nvh);
1533 Int128 cv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1534 Int128 ov;
1535
1536 if (parallel) {
1537#ifdef CONFIG_ATOMIC128
1538 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1539 ov = helper_atomic_cmpxchgo_be_mmu(env, a1, cv, nv, oi, ra);
1540 cc = !int128_eq(ov, cv);
1541#else
1542
1543 g_assert_not_reached();
1544#endif
1545 } else {
1546 uint64_t oh = cpu_ldq_data_ra(env, a1 + 0, ra);
1547 uint64_t ol = cpu_ldq_data_ra(env, a1 + 8, ra);
1548
1549 ov = int128_make128(ol, oh);
1550 cc = !int128_eq(ov, cv);
1551 if (cc) {
1552 nv = ov;
1553 }
1554
1555 cpu_stq_data_ra(env, a1 + 0, int128_gethi(nv), ra);
1556 cpu_stq_data_ra(env, a1 + 8, int128_getlo(nv), ra);
1557 }
1558
1559 env->regs[r3 + 0] = int128_gethi(ov);
1560 env->regs[r3 + 1] = int128_getlo(ov);
1561 }
1562 break;
1563
1564 default:
1565 g_assert_not_reached();
1566 }
1567
1568
1569
1570
1571 if (cc == 0) {
1572 switch (sc) {
1573 case 0:
1574 cpu_stb_data_ra(env, a2, svh >> 56, ra);
1575 break;
1576 case 1:
1577 cpu_stw_data_ra(env, a2, svh >> 48, ra);
1578 break;
1579 case 2:
1580 cpu_stl_data_ra(env, a2, svh >> 32, ra);
1581 break;
1582 case 3:
1583 cpu_stq_data_ra(env, a2, svh, ra);
1584 break;
1585 case 4:
1586 if (parallel) {
1587#ifdef CONFIG_ATOMIC128
1588 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1589 Int128 sv = int128_make128(svl, svh);
1590 helper_atomic_sto_be_mmu(env, a2, sv, oi, ra);
1591#else
1592
1593 g_assert_not_reached();
1594#endif
1595 } else {
1596 cpu_stq_data_ra(env, a2 + 0, svh, ra);
1597 cpu_stq_data_ra(env, a2 + 8, svl, ra);
1598 }
1599 break;
1600 default:
1601 g_assert_not_reached();
1602 }
1603 }
1604
1605 return cc;
1606
1607 spec_exception:
1608 s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
1609 g_assert_not_reached();
1610}
1611
1612uint32_t HELPER(csst)(CPUS390XState *env, uint32_t r3, uint64_t a1, uint64_t a2)
1613{
1614 return do_csst(env, r3, a1, a2, false);
1615}
1616
1617uint32_t HELPER(csst_parallel)(CPUS390XState *env, uint32_t r3, uint64_t a1,
1618 uint64_t a2)
1619{
1620 return do_csst(env, r3, a1, a2, true);
1621}
1622
1623#if !defined(CONFIG_USER_ONLY)
1624void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1625{
1626 uintptr_t ra = GETPC();
1627 S390CPU *cpu = s390_env_get_cpu(env);
1628 bool PERchanged = false;
1629 uint64_t src = a2;
1630 uint32_t i;
1631
1632 if (src & 0x7) {
1633 s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
1634 }
1635
1636 for (i = r1;; i = (i + 1) % 16) {
1637 uint64_t val = cpu_ldq_data_ra(env, src, ra);
1638 if (env->cregs[i] != val && i >= 9 && i <= 11) {
1639 PERchanged = true;
1640 }
1641 env->cregs[i] = val;
1642 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
1643 i, src, val);
1644 src += sizeof(uint64_t);
1645
1646 if (i == r3) {
1647 break;
1648 }
1649 }
1650
1651 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
1652 s390_cpu_recompute_watchpoints(CPU(cpu));
1653 }
1654
1655 tlb_flush(CPU(cpu));
1656}
1657
1658void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1659{
1660 uintptr_t ra = GETPC();
1661 S390CPU *cpu = s390_env_get_cpu(env);
1662 bool PERchanged = false;
1663 uint64_t src = a2;
1664 uint32_t i;
1665
1666 if (src & 0x3) {
1667 s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
1668 }
1669
1670 for (i = r1;; i = (i + 1) % 16) {
1671 uint32_t val = cpu_ldl_data_ra(env, src, ra);
1672 if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
1673 PERchanged = true;
1674 }
1675 env->cregs[i] = deposit64(env->cregs[i], 0, 32, val);
1676 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val);
1677 src += sizeof(uint32_t);
1678
1679 if (i == r3) {
1680 break;
1681 }
1682 }
1683
1684 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
1685 s390_cpu_recompute_watchpoints(CPU(cpu));
1686 }
1687
1688 tlb_flush(CPU(cpu));
1689}
1690
1691void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1692{
1693 uintptr_t ra = GETPC();
1694 uint64_t dest = a2;
1695 uint32_t i;
1696
1697 if (dest & 0x7) {
1698 s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
1699 }
1700
1701 for (i = r1;; i = (i + 1) % 16) {
1702 cpu_stq_data_ra(env, dest, env->cregs[i], ra);
1703 dest += sizeof(uint64_t);
1704
1705 if (i == r3) {
1706 break;
1707 }
1708 }
1709}
1710
1711void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1712{
1713 uintptr_t ra = GETPC();
1714 uint64_t dest = a2;
1715 uint32_t i;
1716
1717 if (dest & 0x3) {
1718 s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
1719 }
1720
1721 for (i = r1;; i = (i + 1) % 16) {
1722 cpu_stl_data_ra(env, dest, env->cregs[i], ra);
1723 dest += sizeof(uint32_t);
1724
1725 if (i == r3) {
1726 break;
1727 }
1728 }
1729}
1730
1731uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
1732{
1733 uintptr_t ra = GETPC();
1734 int i;
1735
1736 real_addr = wrap_address(env, real_addr) & TARGET_PAGE_MASK;
1737
1738 for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
1739 cpu_stq_real_ra(env, real_addr + i, 0, ra);
1740 }
1741
1742 return 0;
1743}
1744
1745uint32_t HELPER(tprot)(CPUS390XState *env, uint64_t a1, uint64_t a2)
1746{
1747 S390CPU *cpu = s390_env_get_cpu(env);
1748 CPUState *cs = CPU(cpu);
1749
1750
1751
1752
1753
1754 if (!s390_cpu_virt_mem_check_write(cpu, a1, 0, 1)) {
1755
1756 return 0;
1757 }
1758
1759 if (env->int_pgm_code == PGM_PROTECTION) {
1760
1761 cs->exception_index = 0;
1762 if (!s390_cpu_virt_mem_check_read(cpu, a1, 0, 1)) {
1763
1764 return 1;
1765 }
1766 }
1767
1768 switch (env->int_pgm_code) {
1769 case PGM_PROTECTION:
1770
1771 cs->exception_index = 0;
1772 return 2;
1773 case PGM_ADDRESSING:
1774 case PGM_TRANS_SPEC:
1775
1776 s390_cpu_virt_mem_handle_exc(cpu, GETPC());
1777 return 0;
1778 }
1779
1780
1781 cs->exception_index = 0;
1782 return 3;
1783}
1784
1785
1786uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
1787{
1788 static S390SKeysState *ss;
1789 static S390SKeysClass *skeyclass;
1790 uint64_t addr = wrap_address(env, r2);
1791 uint8_t key;
1792
1793 if (addr > ram_size) {
1794 return 0;
1795 }
1796
1797 if (unlikely(!ss)) {
1798 ss = s390_get_skeys_device();
1799 skeyclass = S390_SKEYS_GET_CLASS(ss);
1800 }
1801
1802 if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
1803 return 0;
1804 }
1805 return key;
1806}
1807
1808
1809void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
1810{
1811 static S390SKeysState *ss;
1812 static S390SKeysClass *skeyclass;
1813 uint64_t addr = wrap_address(env, r2);
1814 uint8_t key;
1815
1816 if (addr > ram_size) {
1817 return;
1818 }
1819
1820 if (unlikely(!ss)) {
1821 ss = s390_get_skeys_device();
1822 skeyclass = S390_SKEYS_GET_CLASS(ss);
1823 }
1824
1825 key = (uint8_t) r1;
1826 skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
1827}
1828
1829
1830uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
1831{
1832 static S390SKeysState *ss;
1833 static S390SKeysClass *skeyclass;
1834 uint8_t re, key;
1835
1836 if (r2 > ram_size) {
1837 return 0;
1838 }
1839
1840 if (unlikely(!ss)) {
1841 ss = s390_get_skeys_device();
1842 skeyclass = S390_SKEYS_GET_CLASS(ss);
1843 }
1844
1845 if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1846 return 0;
1847 }
1848
1849 re = key & (SK_R | SK_C);
1850 key &= ~SK_R;
1851
1852 if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1853 return 0;
1854 }
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865 return re >> 1;
1866}
1867
1868uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1869{
1870 uintptr_t ra = GETPC();
1871 int cc = 0, i;
1872
1873 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1874 __func__, l, a1, a2);
1875
1876 if (l > 256) {
1877
1878 l = 256;
1879 cc = 3;
1880 }
1881
1882
1883 for (i = 0; i < l; i++) {
1884 uint8_t x = cpu_ldub_primary_ra(env, a2 + i, ra);
1885 cpu_stb_secondary_ra(env, a1 + i, x, ra);
1886 }
1887
1888 return cc;
1889}
1890
1891uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1892{
1893 uintptr_t ra = GETPC();
1894 int cc = 0, i;
1895
1896 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1897 __func__, l, a1, a2);
1898
1899 if (l > 256) {
1900
1901 l = 256;
1902 cc = 3;
1903 }
1904
1905
1906 for (i = 0; i < l; i++) {
1907 uint8_t x = cpu_ldub_secondary_ra(env, a2 + i, ra);
1908 cpu_stb_primary_ra(env, a1 + i, x, ra);
1909 }
1910
1911 return cc;
1912}
1913
1914void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4)
1915{
1916 CPUState *cs = CPU(s390_env_get_cpu(env));
1917 const uintptr_t ra = GETPC();
1918 uint64_t table, entry, raddr;
1919 uint16_t entries, i, index = 0;
1920
1921 if (r2 & 0xff000) {
1922 s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
1923 }
1924
1925 if (!(r2 & 0x800)) {
1926
1927 table = r1 & ASCE_ORIGIN;
1928 entries = (r2 & 0x7ff) + 1;
1929
1930 switch (r1 & ASCE_TYPE_MASK) {
1931 case ASCE_TYPE_REGION1:
1932 index = (r2 >> 53) & 0x7ff;
1933 break;
1934 case ASCE_TYPE_REGION2:
1935 index = (r2 >> 42) & 0x7ff;
1936 break;
1937 case ASCE_TYPE_REGION3:
1938 index = (r2 >> 31) & 0x7ff;
1939 break;
1940 case ASCE_TYPE_SEGMENT:
1941 index = (r2 >> 20) & 0x7ff;
1942 break;
1943 }
1944 for (i = 0; i < entries; i++) {
1945
1946 raddr = table + ((index + i) & 0x7ff) * sizeof(entry);
1947 entry = cpu_ldq_real_ra(env, raddr, ra);
1948 if (!(entry & REGION_ENTRY_INV)) {
1949
1950 entry |= REGION_ENTRY_INV;
1951 cpu_stq_real_ra(env, raddr, entry, ra);
1952 }
1953 }
1954 }
1955
1956
1957 if (m4 & 1) {
1958 tlb_flush(cs);
1959 } else {
1960 tlb_flush_all_cpus_synced(cs);
1961 }
1962}
1963
1964
1965void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr,
1966 uint32_t m4)
1967{
1968 CPUState *cs = CPU(s390_env_get_cpu(env));
1969 const uintptr_t ra = GETPC();
1970 uint64_t page = vaddr & TARGET_PAGE_MASK;
1971 uint64_t pte_addr, pte;
1972
1973
1974 pte_addr = (pto & SEGMENT_ENTRY_ORIGIN);
1975 pte_addr += (vaddr & VADDR_PX) >> 9;
1976
1977
1978 pte = cpu_ldq_real_ra(env, pte_addr, ra);
1979 pte |= PAGE_INVALID;
1980 cpu_stq_real_ra(env, pte_addr, pte, ra);
1981
1982
1983
1984 if (m4 & 1) {
1985 if (vaddr & ~VADDR_PX) {
1986 tlb_flush_page(cs, page);
1987
1988 tlb_flush_page(cs, page ^ 0x80000000);
1989 } else {
1990
1991 tlb_flush(cs);
1992 }
1993 } else {
1994 if (vaddr & ~VADDR_PX) {
1995 tlb_flush_page_all_cpus_synced(cs, page);
1996
1997 tlb_flush_page_all_cpus_synced(cs, page ^ 0x80000000);
1998 } else {
1999
2000 tlb_flush_all_cpus_synced(cs);
2001 }
2002 }
2003}
2004
2005
2006void HELPER(ptlb)(CPUS390XState *env)
2007{
2008 S390CPU *cpu = s390_env_get_cpu(env);
2009
2010 tlb_flush(CPU(cpu));
2011}
2012
2013
2014void HELPER(purge)(CPUS390XState *env)
2015{
2016 S390CPU *cpu = s390_env_get_cpu(env);
2017
2018 tlb_flush_all_cpus_synced(CPU(cpu));
2019}
2020
2021
2022uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr)
2023{
2024 return cpu_ldl_real_ra(env, wrap_address(env, addr), GETPC());
2025}
2026
2027uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr)
2028{
2029 return cpu_ldq_real_ra(env, wrap_address(env, addr), GETPC());
2030}
2031
2032
2033void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
2034{
2035 cpu_stl_real_ra(env, wrap_address(env, addr), (uint32_t)v1, GETPC());
2036
2037 if ((env->psw.mask & PSW_MASK_PER) &&
2038 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
2039 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
2040
2041 env->per_address = env->psw.addr;
2042 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
2043 }
2044}
2045
2046void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
2047{
2048 cpu_stq_real_ra(env, wrap_address(env, addr), v1, GETPC());
2049
2050 if ((env->psw.mask & PSW_MASK_PER) &&
2051 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
2052 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
2053
2054 env->per_address = env->psw.addr;
2055 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
2056 }
2057}
2058
2059
2060uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
2061{
2062 CPUState *cs = CPU(s390_env_get_cpu(env));
2063 uint32_t cc = 0;
2064 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
2065 uint64_t ret;
2066 int old_exc, flags;
2067
2068
2069 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
2070 s390_program_interrupt(env, PGM_SPECIAL_OP, 2, GETPC());
2071 }
2072
2073 old_exc = cs->exception_index;
2074 if (mmu_translate(env, addr, 0, asc, &ret, &flags, true)) {
2075 cc = 3;
2076 }
2077 if (cs->exception_index == EXCP_PGM) {
2078 ret = env->int_pgm_code | 0x80000000;
2079 } else {
2080 ret |= addr & ~TARGET_PAGE_MASK;
2081 }
2082 cs->exception_index = old_exc;
2083
2084 env->cc_op = cc;
2085 return ret;
2086}
2087#endif
2088
2089
2090static uint64_t do_lpq(CPUS390XState *env, uint64_t addr, bool parallel)
2091{
2092 uintptr_t ra = GETPC();
2093 uint64_t hi, lo;
2094
2095 if (parallel) {
2096#ifndef CONFIG_ATOMIC128
2097 cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
2098#else
2099 int mem_idx = cpu_mmu_index(env, false);
2100 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
2101 Int128 v = helper_atomic_ldo_be_mmu(env, addr, oi, ra);
2102 hi = int128_gethi(v);
2103 lo = int128_getlo(v);
2104#endif
2105 } else {
2106 check_alignment(env, addr, 16, ra);
2107
2108 hi = cpu_ldq_data_ra(env, addr + 0, ra);
2109 lo = cpu_ldq_data_ra(env, addr + 8, ra);
2110 }
2111
2112 env->retxl = lo;
2113 return hi;
2114}
2115
2116uint64_t HELPER(lpq)(CPUS390XState *env, uint64_t addr)
2117{
2118 return do_lpq(env, addr, false);
2119}
2120
2121uint64_t HELPER(lpq_parallel)(CPUS390XState *env, uint64_t addr)
2122{
2123 return do_lpq(env, addr, true);
2124}
2125
2126
2127static void do_stpq(CPUS390XState *env, uint64_t addr,
2128 uint64_t low, uint64_t high, bool parallel)
2129{
2130 uintptr_t ra = GETPC();
2131
2132 if (parallel) {
2133#ifndef CONFIG_ATOMIC128
2134 cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
2135#else
2136 int mem_idx = cpu_mmu_index(env, false);
2137 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
2138
2139 Int128 v = int128_make128(low, high);
2140 helper_atomic_sto_be_mmu(env, addr, v, oi, ra);
2141#endif
2142 } else {
2143 check_alignment(env, addr, 16, ra);
2144
2145 cpu_stq_data_ra(env, addr + 0, high, ra);
2146 cpu_stq_data_ra(env, addr + 8, low, ra);
2147 }
2148}
2149
2150void HELPER(stpq)(CPUS390XState *env, uint64_t addr,
2151 uint64_t low, uint64_t high)
2152{
2153 do_stpq(env, addr, low, high, false);
2154}
2155
2156void HELPER(stpq_parallel)(CPUS390XState *env, uint64_t addr,
2157 uint64_t low, uint64_t high)
2158{
2159 do_stpq(env, addr, low, high, true);
2160}
2161
2162
2163
2164
2165
2166
2167
2168
2169void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
2170{
2171 uint64_t insn = cpu_lduw_code(env, addr);
2172 uint8_t opc = insn >> 8;
2173
2174
2175 insn |= r1 & 0xff;
2176
2177
2178 insn <<= 48;
2179 switch (get_ilen(opc)) {
2180 case 2:
2181 break;
2182 case 4:
2183 insn |= (uint64_t)cpu_lduw_code(env, addr + 2) << 32;
2184 break;
2185 case 6:
2186 insn |= (uint64_t)(uint32_t)cpu_ldl_code(env, addr + 2) << 16;
2187 break;
2188 default:
2189 g_assert_not_reached();
2190 }
2191
2192
2193 if ((opc & 0xf0) == 0xd0) {
2194 typedef uint32_t (*dx_helper)(CPUS390XState *, uint32_t, uint64_t,
2195 uint64_t, uintptr_t);
2196 static const dx_helper dx[16] = {
2197 [0x2] = do_helper_mvc,
2198 [0x4] = do_helper_nc,
2199 [0x5] = do_helper_clc,
2200 [0x6] = do_helper_oc,
2201 [0x7] = do_helper_xc,
2202 [0xc] = do_helper_tr,
2203 };
2204 dx_helper helper = dx[opc & 0xf];
2205
2206 if (helper) {
2207 uint32_t l = extract64(insn, 48, 8);
2208 uint32_t b1 = extract64(insn, 44, 4);
2209 uint32_t d1 = extract64(insn, 32, 12);
2210 uint32_t b2 = extract64(insn, 28, 4);
2211 uint32_t d2 = extract64(insn, 16, 12);
2212 uint64_t a1 = wrap_address(env, env->regs[b1] + d1);
2213 uint64_t a2 = wrap_address(env, env->regs[b2] + d2);
2214
2215 env->cc_op = helper(env, l, a1, a2, 0);
2216 env->psw.addr += ilen;
2217 return;
2218 }
2219 } else if (opc == 0x0a) {
2220 env->int_svc_code = extract64(insn, 48, 8);
2221 env->int_svc_ilen = ilen;
2222 helper_exception(env, EXCP_SVC);
2223 g_assert_not_reached();
2224 }
2225
2226
2227
2228
2229
2230 env->ex_value = insn | ilen;
2231}
2232
2233uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src,
2234 uint64_t len)
2235{
2236 const uint8_t psw_key = (env->psw.mask & PSW_MASK_KEY) >> PSW_SHIFT_KEY;
2237 const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
2238 const uint64_t r0 = env->regs[0];
2239 const uintptr_t ra = GETPC();
2240 uint8_t dest_key, dest_as, dest_k, dest_a;
2241 uint8_t src_key, src_as, src_k, src_a;
2242 uint64_t val;
2243 int cc = 0;
2244
2245 HELPER_LOG("%s dest %" PRIx64 ", src %" PRIx64 ", len %" PRIx64 "\n",
2246 __func__, dest, src, len);
2247
2248 if (!(env->psw.mask & PSW_MASK_DAT)) {
2249 s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra);
2250 }
2251
2252
2253 val = (r0 & 0xffff0000ULL) >> 16;
2254 dest_key = (val >> 12) & 0xf;
2255 dest_as = (val >> 6) & 0x3;
2256 dest_k = (val >> 1) & 0x1;
2257 dest_a = val & 0x1;
2258
2259
2260 val = (r0 & 0x0000ffffULL);
2261 src_key = (val >> 12) & 0xf;
2262 src_as = (val >> 6) & 0x3;
2263 src_k = (val >> 1) & 0x1;
2264 src_a = val & 0x1;
2265
2266 if (!dest_k) {
2267 dest_key = psw_key;
2268 }
2269 if (!src_k) {
2270 src_key = psw_key;
2271 }
2272 if (!dest_a) {
2273 dest_as = psw_as;
2274 }
2275 if (!src_a) {
2276 src_as = psw_as;
2277 }
2278
2279 if (dest_a && dest_as == AS_HOME && (env->psw.mask & PSW_MASK_PSTATE)) {
2280 s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra);
2281 }
2282 if (!(env->cregs[0] & CR0_SECONDARY) &&
2283 (dest_as == AS_SECONDARY || src_as == AS_SECONDARY)) {
2284 s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra);
2285 }
2286 if (!psw_key_valid(env, dest_key) || !psw_key_valid(env, src_key)) {
2287 s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra);
2288 }
2289
2290 len = wrap_length(env, len);
2291 if (len > 4096) {
2292 cc = 3;
2293 len = 4096;
2294 }
2295
2296
2297 if (src_as == AS_ACCREG || dest_as == AS_ACCREG ||
2298 (env->psw.mask & PSW_MASK_PSTATE)) {
2299 qemu_log_mask(LOG_UNIMP, "%s: AR-mode and PSTATE support missing\n",
2300 __func__);
2301 s390_program_interrupt(env, PGM_ADDRESSING, 6, ra);
2302 }
2303
2304
2305
2306
2307
2308#ifdef CONFIG_USER_ONLY
2309
2310 g_assert_not_reached();
2311#else
2312 fast_memmove_as(env, dest, src, len, dest_as, src_as, ra);
2313#endif
2314
2315 return cc;
2316}
2317
2318
2319
2320
2321typedef int (*decode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2322 uint64_t ilen, bool enh_check, uintptr_t ra,
2323 uint32_t *ochar, uint32_t *olen);
2324
2325
2326
2327
2328typedef int (*encode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2329 uint64_t ilen, uintptr_t ra, uint32_t c,
2330 uint32_t *olen);
2331
2332static int decode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2333 bool enh_check, uintptr_t ra,
2334 uint32_t *ochar, uint32_t *olen)
2335{
2336 uint8_t s0, s1, s2, s3;
2337 uint32_t c, l;
2338
2339 if (ilen < 1) {
2340 return 0;
2341 }
2342 s0 = cpu_ldub_data_ra(env, addr, ra);
2343 if (s0 <= 0x7f) {
2344
2345 l = 1;
2346 c = s0;
2347 } else if (s0 <= (enh_check ? 0xc1 : 0xbf)) {
2348
2349 return 2;
2350 } else if (s0 <= 0xdf) {
2351
2352 l = 2;
2353 if (ilen < 2) {
2354 return 0;
2355 }
2356 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2357 c = s0 & 0x1f;
2358 c = (c << 6) | (s1 & 0x3f);
2359 if (enh_check && (s1 & 0xc0) != 0x80) {
2360 return 2;
2361 }
2362 } else if (s0 <= 0xef) {
2363
2364 l = 3;
2365 if (ilen < 3) {
2366 return 0;
2367 }
2368 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2369 s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2370 c = s0 & 0x0f;
2371 c = (c << 6) | (s1 & 0x3f);
2372 c = (c << 6) | (s2 & 0x3f);
2373
2374
2375
2376 if (enh_check
2377 && ((s1 & 0xc0) != 0x80
2378 || (s2 & 0xc0) != 0x80
2379 || c < 0x1000
2380 || (c >= 0xd800 && c <= 0xdfff))) {
2381 return 2;
2382 }
2383 } else if (s0 <= (enh_check ? 0xf4 : 0xf7)) {
2384
2385 l = 4;
2386 if (ilen < 4) {
2387 return 0;
2388 }
2389 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2390 s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2391 s3 = cpu_ldub_data_ra(env, addr + 3, ra);
2392 c = s0 & 0x07;
2393 c = (c << 6) | (s1 & 0x3f);
2394 c = (c << 6) | (s2 & 0x3f);
2395 c = (c << 6) | (s3 & 0x3f);
2396
2397 if (enh_check
2398 && ((s1 & 0xc0) != 0x80
2399 || (s2 & 0xc0) != 0x80
2400 || (s3 & 0xc0) != 0x80
2401 || c < 0x010000
2402 || c > 0x10ffff)) {
2403 return 2;
2404 }
2405 } else {
2406
2407 return 2;
2408 }
2409
2410 *ochar = c;
2411 *olen = l;
2412 return -1;
2413}
2414
2415static int decode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2416 bool enh_check, uintptr_t ra,
2417 uint32_t *ochar, uint32_t *olen)
2418{
2419 uint16_t s0, s1;
2420 uint32_t c, l;
2421
2422 if (ilen < 2) {
2423 return 0;
2424 }
2425 s0 = cpu_lduw_data_ra(env, addr, ra);
2426 if ((s0 & 0xfc00) != 0xd800) {
2427
2428 l = 2;
2429 c = s0;
2430 } else {
2431
2432 l = 4;
2433 if (ilen < 4) {
2434 return 0;
2435 }
2436 s1 = cpu_lduw_data_ra(env, addr + 2, ra);
2437 c = extract32(s0, 6, 4) + 1;
2438 c = (c << 6) | (s0 & 0x3f);
2439 c = (c << 10) | (s1 & 0x3ff);
2440 if (enh_check && (s1 & 0xfc00) != 0xdc00) {
2441
2442 return 2;
2443 }
2444 }
2445
2446 *ochar = c;
2447 *olen = l;
2448 return -1;
2449}
2450
2451static int decode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2452 bool enh_check, uintptr_t ra,
2453 uint32_t *ochar, uint32_t *olen)
2454{
2455 uint32_t c;
2456
2457 if (ilen < 4) {
2458 return 0;
2459 }
2460 c = cpu_ldl_data_ra(env, addr, ra);
2461 if ((c >= 0xd800 && c <= 0xdbff) || c > 0x10ffff) {
2462
2463 return 2;
2464 }
2465
2466 *ochar = c;
2467 *olen = 4;
2468 return -1;
2469}
2470
2471static int encode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2472 uintptr_t ra, uint32_t c, uint32_t *olen)
2473{
2474 uint8_t d[4];
2475 uint32_t l, i;
2476
2477 if (c <= 0x7f) {
2478
2479 l = 1;
2480 d[0] = c;
2481 } else if (c <= 0x7ff) {
2482
2483 l = 2;
2484 d[1] = 0x80 | extract32(c, 0, 6);
2485 d[0] = 0xc0 | extract32(c, 6, 5);
2486 } else if (c <= 0xffff) {
2487
2488 l = 3;
2489 d[2] = 0x80 | extract32(c, 0, 6);
2490 d[1] = 0x80 | extract32(c, 6, 6);
2491 d[0] = 0xe0 | extract32(c, 12, 4);
2492 } else {
2493
2494 l = 4;
2495 d[3] = 0x80 | extract32(c, 0, 6);
2496 d[2] = 0x80 | extract32(c, 6, 6);
2497 d[1] = 0x80 | extract32(c, 12, 6);
2498 d[0] = 0xf0 | extract32(c, 18, 3);
2499 }
2500
2501 if (ilen < l) {
2502 return 1;
2503 }
2504 for (i = 0; i < l; ++i) {
2505 cpu_stb_data_ra(env, addr + i, d[i], ra);
2506 }
2507
2508 *olen = l;
2509 return -1;
2510}
2511
2512static int encode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2513 uintptr_t ra, uint32_t c, uint32_t *olen)
2514{
2515 uint16_t d0, d1;
2516
2517 if (c <= 0xffff) {
2518
2519 if (ilen < 2) {
2520 return 1;
2521 }
2522 cpu_stw_data_ra(env, addr, c, ra);
2523 *olen = 2;
2524 } else {
2525
2526 if (ilen < 4) {
2527 return 1;
2528 }
2529 d1 = 0xdc00 | extract32(c, 0, 10);
2530 d0 = 0xd800 | extract32(c, 10, 6);
2531 d0 = deposit32(d0, 6, 4, extract32(c, 16, 5) - 1);
2532 cpu_stw_data_ra(env, addr + 0, d0, ra);
2533 cpu_stw_data_ra(env, addr + 2, d1, ra);
2534 *olen = 4;
2535 }
2536
2537 return -1;
2538}
2539
2540static int encode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2541 uintptr_t ra, uint32_t c, uint32_t *olen)
2542{
2543 if (ilen < 4) {
2544 return 1;
2545 }
2546 cpu_stl_data_ra(env, addr, c, ra);
2547 *olen = 4;
2548 return -1;
2549}
2550
2551static inline uint32_t convert_unicode(CPUS390XState *env, uint32_t r1,
2552 uint32_t r2, uint32_t m3, uintptr_t ra,
2553 decode_unicode_fn decode,
2554 encode_unicode_fn encode)
2555{
2556 uint64_t dst = get_address(env, r1);
2557 uint64_t dlen = get_length(env, r1 + 1);
2558 uint64_t src = get_address(env, r2);
2559 uint64_t slen = get_length(env, r2 + 1);
2560 bool enh_check = m3 & 1;
2561 int cc, i;
2562
2563
2564
2565 for (i = 0; i < 256; ++i) {
2566 uint32_t c, ilen, olen;
2567
2568 cc = decode(env, src, slen, enh_check, ra, &c, &ilen);
2569 if (unlikely(cc >= 0)) {
2570 break;
2571 }
2572 cc = encode(env, dst, dlen, ra, c, &olen);
2573 if (unlikely(cc >= 0)) {
2574 break;
2575 }
2576
2577 src += ilen;
2578 slen -= ilen;
2579 dst += olen;
2580 dlen -= olen;
2581 cc = 3;
2582 }
2583
2584 set_address(env, r1, dst);
2585 set_length(env, r1 + 1, dlen);
2586 set_address(env, r2, src);
2587 set_length(env, r2 + 1, slen);
2588
2589 return cc;
2590}
2591
2592uint32_t HELPER(cu12)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2593{
2594 return convert_unicode(env, r1, r2, m3, GETPC(),
2595 decode_utf8, encode_utf16);
2596}
2597
2598uint32_t HELPER(cu14)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2599{
2600 return convert_unicode(env, r1, r2, m3, GETPC(),
2601 decode_utf8, encode_utf32);
2602}
2603
2604uint32_t HELPER(cu21)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2605{
2606 return convert_unicode(env, r1, r2, m3, GETPC(),
2607 decode_utf16, encode_utf8);
2608}
2609
2610uint32_t HELPER(cu24)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2611{
2612 return convert_unicode(env, r1, r2, m3, GETPC(),
2613 decode_utf16, encode_utf32);
2614}
2615
2616uint32_t HELPER(cu41)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2617{
2618 return convert_unicode(env, r1, r2, m3, GETPC(),
2619 decode_utf32, encode_utf8);
2620}
2621
2622uint32_t HELPER(cu42)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2623{
2624 return convert_unicode(env, r1, r2, m3, GETPC(),
2625 decode_utf32, encode_utf16);
2626}
2627