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