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