ipxe: update binaries
[qemu/ar7.git] / target / s390x / mem_helper.c
bloba237dec7579e66f9ff3c3bb03d5b0d53cbc13502
1 /*
2 * S/390 memory access helper routines
4 * Copyright (c) 2009 Ulrich Hecht
5 * Copyright (c) 2009 Alexander Graf
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "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"
32 #if !defined(CONFIG_USER_ONLY)
33 #include "hw/s390x/storage-keys.h"
34 #endif
36 /*****************************************************************************/
37 /* Softmmu support */
39 /* #define DEBUG_HELPER */
40 #ifdef DEBUG_HELPER
41 #define HELPER_LOG(x...) qemu_log(x)
42 #else
43 #define HELPER_LOG(x...)
44 #endif
46 static inline bool psw_key_valid(CPUS390XState *env, uint8_t psw_key)
48 uint16_t pkm = env->cregs[3] >> 16;
50 if (env->psw.mask & PSW_MASK_PSTATE) {
51 /* PSW key has range 0..15, it is valid if the bit is 1 in the PKM */
52 return pkm & (0x80 >> psw_key);
54 return true;
57 static bool is_destructive_overlap(CPUS390XState *env, uint64_t dest,
58 uint64_t src, uint32_t len)
60 if (!len || src == dest) {
61 return false;
63 /* Take care of wrapping at the end of address space. */
64 if (unlikely(wrap_address(env, src + len - 1) < src)) {
65 return dest > src || dest <= wrap_address(env, src + len - 1);
67 return dest > src && dest <= src + len - 1;
70 /* Trigger a SPECIFICATION exception if an address or a length is not
71 naturally aligned. */
72 static inline void check_alignment(CPUS390XState *env, uint64_t v,
73 int wordsize, uintptr_t ra)
75 if (v % wordsize) {
76 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
80 /* Load a value from memory according to its size. */
81 static inline uint64_t cpu_ldusize_data_ra(CPUS390XState *env, uint64_t addr,
82 int wordsize, uintptr_t ra)
84 switch (wordsize) {
85 case 1:
86 return cpu_ldub_data_ra(env, addr, ra);
87 case 2:
88 return cpu_lduw_data_ra(env, addr, ra);
89 default:
90 abort();
94 /* Store a to memory according to its size. */
95 static inline void cpu_stsize_data_ra(CPUS390XState *env, uint64_t addr,
96 uint64_t value, int wordsize,
97 uintptr_t ra)
99 switch (wordsize) {
100 case 1:
101 cpu_stb_data_ra(env, addr, value, ra);
102 break;
103 case 2:
104 cpu_stw_data_ra(env, addr, value, ra);
105 break;
106 default:
107 abort();
111 /* An access covers at most 4096 bytes and therefore at most two pages. */
112 typedef struct S390Access {
113 target_ulong vaddr1;
114 target_ulong vaddr2;
115 char *haddr1;
116 char *haddr2;
117 uint16_t size1;
118 uint16_t size2;
120 * If we can't access the host page directly, we'll have to do I/O access
121 * via ld/st helpers. These are internal details, so we store the
122 * mmu idx to do the access here instead of passing it around in the
123 * helpers. Maybe, one day we can get rid of ld/st access - once we can
124 * handle TLB_NOTDIRTY differently. We don't expect these special accesses
125 * to trigger exceptions - only if we would have TLB_NOTDIRTY on LAP
126 * pages, we might trigger a new MMU translation - very unlikely that
127 * the mapping changes in between and we would trigger a fault.
129 int mmu_idx;
130 } S390Access;
132 static S390Access access_prepare(CPUS390XState *env, vaddr vaddr, int size,
133 MMUAccessType access_type, int mmu_idx,
134 uintptr_t ra)
136 S390Access access = {
137 .vaddr1 = vaddr,
138 .size1 = MIN(size, -(vaddr | TARGET_PAGE_MASK)),
139 .mmu_idx = mmu_idx,
142 g_assert(size > 0 && size <= 4096);
143 access.haddr1 = probe_access(env, access.vaddr1, access.size1, access_type,
144 mmu_idx, ra);
146 if (unlikely(access.size1 != size)) {
147 /* The access crosses page boundaries. */
148 access.vaddr2 = wrap_address(env, vaddr + access.size1);
149 access.size2 = size - access.size1;
150 access.haddr2 = probe_access(env, access.vaddr2, access.size2,
151 access_type, mmu_idx, ra);
153 return access;
156 /* Helper to handle memset on a single page. */
157 static void do_access_memset(CPUS390XState *env, vaddr vaddr, char *haddr,
158 uint8_t byte, uint16_t size, int mmu_idx,
159 uintptr_t ra)
161 #ifdef CONFIG_USER_ONLY
162 g_assert(haddr);
163 memset(haddr, byte, size);
164 #else
165 TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
166 int i;
168 if (likely(haddr)) {
169 memset(haddr, byte, size);
170 } else {
172 * Do a single access and test if we can then get access to the
173 * page. This is especially relevant to speed up TLB_NOTDIRTY.
175 g_assert(size > 0);
176 helper_ret_stb_mmu(env, vaddr, byte, oi, ra);
177 haddr = tlb_vaddr_to_host(env, vaddr, MMU_DATA_STORE, mmu_idx);
178 if (likely(haddr)) {
179 memset(haddr + 1, byte, size - 1);
180 } else {
181 for (i = 1; i < size; i++) {
182 helper_ret_stb_mmu(env, vaddr + i, byte, oi, ra);
186 #endif
189 static void access_memset(CPUS390XState *env, S390Access *desta,
190 uint8_t byte, uintptr_t ra)
193 do_access_memset(env, desta->vaddr1, desta->haddr1, byte, desta->size1,
194 desta->mmu_idx, ra);
195 if (likely(!desta->size2)) {
196 return;
198 do_access_memset(env, desta->vaddr2, desta->haddr2, byte, desta->size2,
199 desta->mmu_idx, ra);
202 static uint8_t do_access_get_byte(CPUS390XState *env, vaddr vaddr, char **haddr,
203 int offset, int mmu_idx, uintptr_t ra)
205 #ifdef CONFIG_USER_ONLY
206 return ldub_p(*haddr + offset);
207 #else
208 TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
209 uint8_t byte;
211 if (likely(*haddr)) {
212 return ldub_p(*haddr + offset);
215 * Do a single access and test if we can then get access to the
216 * page. This is especially relevant to speed up TLB_NOTDIRTY.
218 byte = helper_ret_ldub_mmu(env, vaddr + offset, oi, ra);
219 *haddr = tlb_vaddr_to_host(env, vaddr, MMU_DATA_LOAD, mmu_idx);
220 return byte;
221 #endif
224 static uint8_t access_get_byte(CPUS390XState *env, S390Access *access,
225 int offset, uintptr_t ra)
227 if (offset < access->size1) {
228 return do_access_get_byte(env, access->vaddr1, &access->haddr1,
229 offset, access->mmu_idx, ra);
231 return do_access_get_byte(env, access->vaddr2, &access->haddr2,
232 offset - access->size1, access->mmu_idx, ra);
235 static void do_access_set_byte(CPUS390XState *env, vaddr vaddr, char **haddr,
236 int offset, uint8_t byte, int mmu_idx,
237 uintptr_t ra)
239 #ifdef CONFIG_USER_ONLY
240 stb_p(*haddr + offset, byte);
241 #else
242 TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
244 if (likely(*haddr)) {
245 stb_p(*haddr + offset, byte);
246 return;
249 * Do a single access and test if we can then get access to the
250 * page. This is especially relevant to speed up TLB_NOTDIRTY.
252 helper_ret_stb_mmu(env, vaddr + offset, byte, oi, ra);
253 *haddr = tlb_vaddr_to_host(env, vaddr, MMU_DATA_STORE, mmu_idx);
254 #endif
257 static void access_set_byte(CPUS390XState *env, S390Access *access,
258 int offset, uint8_t byte, uintptr_t ra)
260 if (offset < access->size1) {
261 do_access_set_byte(env, access->vaddr1, &access->haddr1, offset, byte,
262 access->mmu_idx, ra);
263 } else {
264 do_access_set_byte(env, access->vaddr2, &access->haddr2,
265 offset - access->size1, byte, access->mmu_idx, ra);
270 * Move data with the same semantics as memmove() in case ranges don't overlap
271 * or src > dest. Undefined behavior on destructive overlaps.
273 static void access_memmove(CPUS390XState *env, S390Access *desta,
274 S390Access *srca, uintptr_t ra)
276 int diff;
278 g_assert(desta->size1 + desta->size2 == srca->size1 + srca->size2);
280 /* Fallback to slow access in case we don't have access to all host pages */
281 if (unlikely(!desta->haddr1 || (desta->size2 && !desta->haddr2) ||
282 !srca->haddr1 || (srca->size2 && !srca->haddr2))) {
283 int i;
285 for (i = 0; i < desta->size1 + desta->size2; i++) {
286 uint8_t byte = access_get_byte(env, srca, i, ra);
288 access_set_byte(env, desta, i, byte, ra);
290 return;
293 if (srca->size1 == desta->size1) {
294 memmove(desta->haddr1, srca->haddr1, srca->size1);
295 if (unlikely(srca->size2)) {
296 memmove(desta->haddr2, srca->haddr2, srca->size2);
298 } else if (srca->size1 < desta->size1) {
299 diff = desta->size1 - srca->size1;
300 memmove(desta->haddr1, srca->haddr1, srca->size1);
301 memmove(desta->haddr1 + srca->size1, srca->haddr2, diff);
302 if (likely(desta->size2)) {
303 memmove(desta->haddr2, srca->haddr2 + diff, desta->size2);
305 } else {
306 diff = srca->size1 - desta->size1;
307 memmove(desta->haddr1, srca->haddr1, desta->size1);
308 memmove(desta->haddr2, srca->haddr1 + desta->size1, diff);
309 if (likely(srca->size2)) {
310 memmove(desta->haddr2 + diff, srca->haddr2, srca->size2);
315 static int mmu_idx_from_as(uint8_t as)
317 switch (as) {
318 case AS_PRIMARY:
319 return MMU_PRIMARY_IDX;
320 case AS_SECONDARY:
321 return MMU_SECONDARY_IDX;
322 case AS_HOME:
323 return MMU_HOME_IDX;
324 default:
325 /* FIXME AS_ACCREG */
326 g_assert_not_reached();
330 /* and on array */
331 static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest,
332 uint64_t src, uintptr_t ra)
334 const int mmu_idx = cpu_mmu_index(env, false);
335 S390Access srca1, srca2, desta;
336 uint32_t i;
337 uint8_t c = 0;
339 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
340 __func__, l, dest, src);
342 /* NC always processes one more byte than specified - maximum is 256 */
343 l++;
345 srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
346 srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
347 desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
348 for (i = 0; i < l; i++) {
349 const uint8_t x = access_get_byte(env, &srca1, i, ra) &
350 access_get_byte(env, &srca2, i, ra);
352 c |= x;
353 access_set_byte(env, &desta, i, x, ra);
355 return c != 0;
358 uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
359 uint64_t src)
361 return do_helper_nc(env, l, dest, src, GETPC());
364 /* xor on array */
365 static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest,
366 uint64_t src, uintptr_t ra)
368 const int mmu_idx = cpu_mmu_index(env, false);
369 S390Access srca1, srca2, desta;
370 uint32_t i;
371 uint8_t c = 0;
373 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
374 __func__, l, dest, src);
376 /* XC always processes one more byte than specified - maximum is 256 */
377 l++;
379 srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
380 srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
381 desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
383 /* xor with itself is the same as memset(0) */
384 if (src == dest) {
385 access_memset(env, &desta, 0, ra);
386 return 0;
389 for (i = 0; i < l; i++) {
390 const uint8_t x = access_get_byte(env, &srca1, i, ra) ^
391 access_get_byte(env, &srca2, i, ra);
393 c |= x;
394 access_set_byte(env, &desta, i, x, ra);
396 return c != 0;
399 uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
400 uint64_t src)
402 return do_helper_xc(env, l, dest, src, GETPC());
405 /* or on array */
406 static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest,
407 uint64_t src, uintptr_t ra)
409 const int mmu_idx = cpu_mmu_index(env, false);
410 S390Access srca1, srca2, desta;
411 uint32_t i;
412 uint8_t c = 0;
414 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
415 __func__, l, dest, src);
417 /* OC always processes one more byte than specified - maximum is 256 */
418 l++;
420 srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
421 srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
422 desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
423 for (i = 0; i < l; i++) {
424 const uint8_t x = access_get_byte(env, &srca1, i, ra) |
425 access_get_byte(env, &srca2, i, ra);
427 c |= x;
428 access_set_byte(env, &desta, i, x, ra);
430 return c != 0;
433 uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
434 uint64_t src)
436 return do_helper_oc(env, l, dest, src, GETPC());
439 /* memmove */
440 static uint32_t do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest,
441 uint64_t src, uintptr_t ra)
443 const int mmu_idx = cpu_mmu_index(env, false);
444 S390Access srca, desta;
445 uint32_t i;
447 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
448 __func__, l, dest, src);
450 /* MVC always copies one more byte than specified - maximum is 256 */
451 l++;
453 srca = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
454 desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
457 * "When the operands overlap, the result is obtained as if the operands
458 * were processed one byte at a time". Only non-destructive overlaps
459 * behave like memmove().
461 if (dest == src + 1) {
462 access_memset(env, &desta, access_get_byte(env, &srca, 0, ra), ra);
463 } else if (!is_destructive_overlap(env, dest, src, l)) {
464 access_memmove(env, &desta, &srca, ra);
465 } else {
466 for (i = 0; i < l; i++) {
467 uint8_t byte = access_get_byte(env, &srca, i, ra);
469 access_set_byte(env, &desta, i, byte, ra);
473 return env->cc_op;
476 void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
478 do_helper_mvc(env, l, dest, src, GETPC());
481 /* move inverse */
482 void HELPER(mvcin)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
484 const int mmu_idx = cpu_mmu_index(env, false);
485 S390Access srca, desta;
486 uintptr_t ra = GETPC();
487 int i;
489 /* MVCIN always copies one more byte than specified - maximum is 256 */
490 l++;
492 src = wrap_address(env, src - l + 1);
493 srca = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
494 desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
495 for (i = 0; i < l; i++) {
496 const uint8_t x = access_get_byte(env, &srca, l - i - 1, ra);
498 access_set_byte(env, &desta, i, x, ra);
502 /* move numerics */
503 void HELPER(mvn)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
505 const int mmu_idx = cpu_mmu_index(env, false);
506 S390Access srca1, srca2, desta;
507 uintptr_t ra = GETPC();
508 int i;
510 /* MVN always copies one more byte than specified - maximum is 256 */
511 l++;
513 srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
514 srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
515 desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
516 for (i = 0; i < l; i++) {
517 const uint8_t x = (access_get_byte(env, &srca1, i, ra) & 0x0f) |
518 (access_get_byte(env, &srca2, i, ra) & 0xf0);
520 access_set_byte(env, &desta, i, x, ra);
524 /* move with offset */
525 void HELPER(mvo)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
527 const int mmu_idx = cpu_mmu_index(env, false);
528 /* MVO always processes one more byte than specified - maximum is 16 */
529 const int len_dest = (l >> 4) + 1;
530 const int len_src = (l & 0xf) + 1;
531 uintptr_t ra = GETPC();
532 uint8_t byte_dest, byte_src;
533 S390Access srca, desta;
534 int i, j;
536 srca = access_prepare(env, src, len_src, MMU_DATA_LOAD, mmu_idx, ra);
537 desta = access_prepare(env, dest, len_dest, MMU_DATA_STORE, mmu_idx, ra);
539 /* Handle rightmost byte */
540 byte_dest = cpu_ldub_data_ra(env, dest + len_dest - 1, ra);
541 byte_src = access_get_byte(env, &srca, len_src - 1, ra);
542 byte_dest = (byte_dest & 0x0f) | (byte_src << 4);
543 access_set_byte(env, &desta, len_dest - 1, byte_dest, ra);
545 /* Process remaining bytes from right to left */
546 for (i = len_dest - 2, j = len_src - 2; i >= 0; i--, j--) {
547 byte_dest = byte_src >> 4;
548 if (j >= 0) {
549 byte_src = access_get_byte(env, &srca, j, ra);
550 } else {
551 byte_src = 0;
553 byte_dest |= byte_src << 4;
554 access_set_byte(env, &desta, i, byte_dest, ra);
558 /* move zones */
559 void HELPER(mvz)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
561 const int mmu_idx = cpu_mmu_index(env, false);
562 S390Access srca1, srca2, desta;
563 uintptr_t ra = GETPC();
564 int i;
566 /* MVZ always copies one more byte than specified - maximum is 256 */
567 l++;
569 srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
570 srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
571 desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
572 for (i = 0; i < l; i++) {
573 const uint8_t x = (access_get_byte(env, &srca1, i, ra) & 0xf0) |
574 (access_get_byte(env, &srca2, i, ra) & 0x0f);
576 access_set_byte(env, &desta, i, x, ra);
580 /* compare unsigned byte arrays */
581 static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1,
582 uint64_t s2, uintptr_t ra)
584 uint32_t i;
585 uint32_t cc = 0;
587 HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
588 __func__, l, s1, s2);
590 for (i = 0; i <= l; i++) {
591 uint8_t x = cpu_ldub_data_ra(env, s1 + i, ra);
592 uint8_t y = cpu_ldub_data_ra(env, s2 + i, ra);
593 HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
594 if (x < y) {
595 cc = 1;
596 break;
597 } else if (x > y) {
598 cc = 2;
599 break;
603 HELPER_LOG("\n");
604 return cc;
607 uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2)
609 return do_helper_clc(env, l, s1, s2, GETPC());
612 /* compare logical under mask */
613 uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
614 uint64_t addr)
616 uintptr_t ra = GETPC();
617 uint32_t cc = 0;
619 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
620 mask, addr);
622 while (mask) {
623 if (mask & 8) {
624 uint8_t d = cpu_ldub_data_ra(env, addr, ra);
625 uint8_t r = extract32(r1, 24, 8);
626 HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
627 addr);
628 if (r < d) {
629 cc = 1;
630 break;
631 } else if (r > d) {
632 cc = 2;
633 break;
635 addr++;
637 mask = (mask << 1) & 0xf;
638 r1 <<= 8;
641 HELPER_LOG("\n");
642 return cc;
645 static inline uint64_t get_address(CPUS390XState *env, int reg)
647 return wrap_address(env, env->regs[reg]);
651 * Store the address to the given register, zeroing out unused leftmost
652 * bits in bit positions 32-63 (24-bit and 31-bit mode only).
654 static inline void set_address_zero(CPUS390XState *env, int reg,
655 uint64_t address)
657 if (env->psw.mask & PSW_MASK_64) {
658 env->regs[reg] = address;
659 } else {
660 if (!(env->psw.mask & PSW_MASK_32)) {
661 address &= 0x00ffffff;
662 } else {
663 address &= 0x7fffffff;
665 env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
669 static inline void set_address(CPUS390XState *env, int reg, uint64_t address)
671 if (env->psw.mask & PSW_MASK_64) {
672 /* 64-Bit mode */
673 env->regs[reg] = address;
674 } else {
675 if (!(env->psw.mask & PSW_MASK_32)) {
676 /* 24-Bit mode. According to the PoO it is implementation
677 dependent if bits 32-39 remain unchanged or are set to
678 zeros. Choose the former so that the function can also be
679 used for TRT. */
680 env->regs[reg] = deposit64(env->regs[reg], 0, 24, address);
681 } else {
682 /* 31-Bit mode. According to the PoO it is implementation
683 dependent if bit 32 remains unchanged or is set to zero.
684 Choose the latter so that the function can also be used for
685 TRT. */
686 address &= 0x7fffffff;
687 env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
692 static inline uint64_t wrap_length32(CPUS390XState *env, uint64_t length)
694 if (!(env->psw.mask & PSW_MASK_64)) {
695 return (uint32_t)length;
697 return length;
700 static inline uint64_t wrap_length31(CPUS390XState *env, uint64_t length)
702 if (!(env->psw.mask & PSW_MASK_64)) {
703 /* 24-Bit and 31-Bit mode */
704 length &= 0x7fffffff;
706 return length;
709 static inline uint64_t get_length(CPUS390XState *env, int reg)
711 return wrap_length31(env, env->regs[reg]);
714 static inline void set_length(CPUS390XState *env, int reg, uint64_t length)
716 if (env->psw.mask & PSW_MASK_64) {
717 /* 64-Bit mode */
718 env->regs[reg] = length;
719 } else {
720 /* 24-Bit and 31-Bit mode */
721 env->regs[reg] = deposit64(env->regs[reg], 0, 32, length);
725 /* search string (c is byte to search, r2 is string, r1 end of string) */
726 void HELPER(srst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
728 uintptr_t ra = GETPC();
729 uint64_t end, str;
730 uint32_t len;
731 uint8_t v, c = env->regs[0];
733 /* Bits 32-55 must contain all 0. */
734 if (env->regs[0] & 0xffffff00u) {
735 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
738 str = get_address(env, r2);
739 end = get_address(env, r1);
741 /* Lest we fail to service interrupts in a timely manner, limit the
742 amount of work we're willing to do. For now, let's cap at 8k. */
743 for (len = 0; len < 0x2000; ++len) {
744 if (str + len == end) {
745 /* Character not found. R1 & R2 are unmodified. */
746 env->cc_op = 2;
747 return;
749 v = cpu_ldub_data_ra(env, str + len, ra);
750 if (v == c) {
751 /* Character found. Set R1 to the location; R2 is unmodified. */
752 env->cc_op = 1;
753 set_address(env, r1, str + len);
754 return;
758 /* CPU-determined bytes processed. Advance R2 to next byte to process. */
759 env->cc_op = 3;
760 set_address(env, r2, str + len);
763 void HELPER(srstu)(CPUS390XState *env, uint32_t r1, uint32_t r2)
765 uintptr_t ra = GETPC();
766 uint32_t len;
767 uint16_t v, c = env->regs[0];
768 uint64_t end, str, adj_end;
770 /* Bits 32-47 of R0 must be zero. */
771 if (env->regs[0] & 0xffff0000u) {
772 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
775 str = get_address(env, r2);
776 end = get_address(env, r1);
778 /* If the LSB of the two addresses differ, use one extra byte. */
779 adj_end = end + ((str ^ end) & 1);
781 /* Lest we fail to service interrupts in a timely manner, limit the
782 amount of work we're willing to do. For now, let's cap at 8k. */
783 for (len = 0; len < 0x2000; len += 2) {
784 if (str + len == adj_end) {
785 /* End of input found. */
786 env->cc_op = 2;
787 return;
789 v = cpu_lduw_data_ra(env, str + len, ra);
790 if (v == c) {
791 /* Character found. Set R1 to the location; R2 is unmodified. */
792 env->cc_op = 1;
793 set_address(env, r1, str + len);
794 return;
798 /* CPU-determined bytes processed. Advance R2 to next byte to process. */
799 env->cc_op = 3;
800 set_address(env, r2, str + len);
803 /* unsigned string compare (c is string terminator) */
804 uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
806 uintptr_t ra = GETPC();
807 uint32_t len;
809 c = c & 0xff;
810 s1 = wrap_address(env, s1);
811 s2 = wrap_address(env, s2);
813 /* Lest we fail to service interrupts in a timely manner, limit the
814 amount of work we're willing to do. For now, let's cap at 8k. */
815 for (len = 0; len < 0x2000; ++len) {
816 uint8_t v1 = cpu_ldub_data_ra(env, s1 + len, ra);
817 uint8_t v2 = cpu_ldub_data_ra(env, s2 + len, ra);
818 if (v1 == v2) {
819 if (v1 == c) {
820 /* Equal. CC=0, and don't advance the registers. */
821 env->cc_op = 0;
822 env->retxl = s2;
823 return s1;
825 } else {
826 /* Unequal. CC={1,2}, and advance the registers. Note that
827 the terminator need not be zero, but the string that contains
828 the terminator is by definition "low". */
829 env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2);
830 env->retxl = s2 + len;
831 return s1 + len;
835 /* CPU-determined bytes equal; advance the registers. */
836 env->cc_op = 3;
837 env->retxl = s2 + len;
838 return s1 + len;
841 /* move page */
842 uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
844 const int mmu_idx = cpu_mmu_index(env, false);
845 const bool f = extract64(r0, 11, 1);
846 const bool s = extract64(r0, 10, 1);
847 uintptr_t ra = GETPC();
848 S390Access srca, desta;
850 if ((f && s) || extract64(r0, 12, 4)) {
851 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
854 r1 = wrap_address(env, r1 & TARGET_PAGE_MASK);
855 r2 = wrap_address(env, r2 & TARGET_PAGE_MASK);
858 * TODO:
859 * - Access key handling
860 * - CC-option with surpression of page-translation exceptions
861 * - Store r1/r2 register identifiers at real location 162
863 srca = access_prepare(env, r2, TARGET_PAGE_SIZE, MMU_DATA_LOAD, mmu_idx,
864 ra);
865 desta = access_prepare(env, r1, TARGET_PAGE_SIZE, MMU_DATA_STORE, mmu_idx,
866 ra);
867 access_memmove(env, &desta, &srca, ra);
868 return 0; /* data moved */
871 /* string copy */
872 uint32_t HELPER(mvst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
874 const int mmu_idx = cpu_mmu_index(env, false);
875 const uint64_t d = get_address(env, r1);
876 const uint64_t s = get_address(env, r2);
877 const uint8_t c = env->regs[0];
878 const int len = MIN(-(d | TARGET_PAGE_MASK), -(s | TARGET_PAGE_MASK));
879 S390Access srca, desta;
880 uintptr_t ra = GETPC();
881 int i;
883 if (env->regs[0] & 0xffffff00ull) {
884 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
888 * Our access should not exceed single pages, as we must not report access
889 * exceptions exceeding the actually copied range (which we don't know at
890 * this point). We might over-indicate watchpoints within the pages
891 * (if we ever care, we have to limit processing to a single byte).
893 srca = access_prepare(env, s, len, MMU_DATA_LOAD, mmu_idx, ra);
894 desta = access_prepare(env, d, len, MMU_DATA_STORE, mmu_idx, ra);
895 for (i = 0; i < len; i++) {
896 const uint8_t v = access_get_byte(env, &srca, i, ra);
898 access_set_byte(env, &desta, i, v, ra);
899 if (v == c) {
900 set_address_zero(env, r1, d + i);
901 return 1;
904 set_address_zero(env, r1, d + len);
905 set_address_zero(env, r2, s + len);
906 return 3;
909 /* load access registers r1 to r3 from memory at a2 */
910 void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
912 uintptr_t ra = GETPC();
913 int i;
915 if (a2 & 0x3) {
916 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
919 for (i = r1;; i = (i + 1) % 16) {
920 env->aregs[i] = cpu_ldl_data_ra(env, a2, ra);
921 a2 += 4;
923 if (i == r3) {
924 break;
929 /* store access registers r1 to r3 in memory at a2 */
930 void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
932 uintptr_t ra = GETPC();
933 int i;
935 if (a2 & 0x3) {
936 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
939 for (i = r1;; i = (i + 1) % 16) {
940 cpu_stl_data_ra(env, a2, env->aregs[i], ra);
941 a2 += 4;
943 if (i == r3) {
944 break;
949 /* move long helper */
950 static inline uint32_t do_mvcl(CPUS390XState *env,
951 uint64_t *dest, uint64_t *destlen,
952 uint64_t *src, uint64_t *srclen,
953 uint16_t pad, int wordsize, uintptr_t ra)
955 const int mmu_idx = cpu_mmu_index(env, false);
956 int len = MIN(*destlen, -(*dest | TARGET_PAGE_MASK));
957 S390Access srca, desta;
958 int i, cc;
960 if (*destlen == *srclen) {
961 cc = 0;
962 } else if (*destlen < *srclen) {
963 cc = 1;
964 } else {
965 cc = 2;
968 if (!*destlen) {
969 return cc;
973 * Only perform one type of type of operation (move/pad) at a time.
974 * Stay within single pages.
976 if (*srclen) {
977 /* Copy the src array */
978 len = MIN(MIN(*srclen, -(*src | TARGET_PAGE_MASK)), len);
979 *destlen -= len;
980 *srclen -= len;
981 srca = access_prepare(env, *src, len, MMU_DATA_LOAD, mmu_idx, ra);
982 desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
983 access_memmove(env, &desta, &srca, ra);
984 *src = wrap_address(env, *src + len);
985 *dest = wrap_address(env, *dest + len);
986 } else if (wordsize == 1) {
987 /* Pad the remaining area */
988 *destlen -= len;
989 desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
990 access_memset(env, &desta, pad, ra);
991 *dest = wrap_address(env, *dest + len);
992 } else {
993 desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
995 /* The remaining length selects the padding byte. */
996 for (i = 0; i < len; (*destlen)--, i++) {
997 if (*destlen & 1) {
998 access_set_byte(env, &desta, i, pad, ra);
999 } else {
1000 access_set_byte(env, &desta, i, pad >> 8, ra);
1003 *dest = wrap_address(env, *dest + len);
1006 return *destlen ? 3 : cc;
1009 /* move long */
1010 uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
1012 const int mmu_idx = cpu_mmu_index(env, false);
1013 uintptr_t ra = GETPC();
1014 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
1015 uint64_t dest = get_address(env, r1);
1016 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
1017 uint64_t src = get_address(env, r2);
1018 uint8_t pad = env->regs[r2 + 1] >> 24;
1019 CPUState *cs = env_cpu(env);
1020 S390Access srca, desta;
1021 uint32_t cc, cur_len;
1023 if (is_destructive_overlap(env, dest, src, MIN(srclen, destlen))) {
1024 cc = 3;
1025 } else if (srclen == destlen) {
1026 cc = 0;
1027 } else if (destlen < srclen) {
1028 cc = 1;
1029 } else {
1030 cc = 2;
1033 /* We might have to zero-out some bits even if there was no action. */
1034 if (unlikely(!destlen || cc == 3)) {
1035 set_address_zero(env, r2, src);
1036 set_address_zero(env, r1, dest);
1037 return cc;
1038 } else if (!srclen) {
1039 set_address_zero(env, r2, src);
1043 * Only perform one type of type of operation (move/pad) in one step.
1044 * Stay within single pages.
1046 while (destlen) {
1047 cur_len = MIN(destlen, -(dest | TARGET_PAGE_MASK));
1048 if (!srclen) {
1049 desta = access_prepare(env, dest, cur_len, MMU_DATA_STORE, mmu_idx,
1050 ra);
1051 access_memset(env, &desta, pad, ra);
1052 } else {
1053 cur_len = MIN(MIN(srclen, -(src | TARGET_PAGE_MASK)), cur_len);
1055 srca = access_prepare(env, src, cur_len, MMU_DATA_LOAD, mmu_idx,
1056 ra);
1057 desta = access_prepare(env, dest, cur_len, MMU_DATA_STORE, mmu_idx,
1058 ra);
1059 access_memmove(env, &desta, &srca, ra);
1060 src = wrap_address(env, src + cur_len);
1061 srclen -= cur_len;
1062 env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, srclen);
1063 set_address_zero(env, r2, src);
1065 dest = wrap_address(env, dest + cur_len);
1066 destlen -= cur_len;
1067 env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, destlen);
1068 set_address_zero(env, r1, dest);
1071 * MVCL is interruptible. Return to the main loop if requested after
1072 * writing back all state to registers. If no interrupt will get
1073 * injected, we'll end up back in this handler and continue processing
1074 * the remaining parts.
1076 if (destlen && unlikely(cpu_loop_exit_requested(cs))) {
1077 cpu_loop_exit_restore(cs, ra);
1080 return cc;
1083 /* move long extended */
1084 uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1085 uint32_t r3)
1087 uintptr_t ra = GETPC();
1088 uint64_t destlen = get_length(env, r1 + 1);
1089 uint64_t dest = get_address(env, r1);
1090 uint64_t srclen = get_length(env, r3 + 1);
1091 uint64_t src = get_address(env, r3);
1092 uint8_t pad = a2;
1093 uint32_t cc;
1095 cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra);
1097 set_length(env, r1 + 1, destlen);
1098 set_length(env, r3 + 1, srclen);
1099 set_address(env, r1, dest);
1100 set_address(env, r3, src);
1102 return cc;
1105 /* move long unicode */
1106 uint32_t HELPER(mvclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1107 uint32_t r3)
1109 uintptr_t ra = GETPC();
1110 uint64_t destlen = get_length(env, r1 + 1);
1111 uint64_t dest = get_address(env, r1);
1112 uint64_t srclen = get_length(env, r3 + 1);
1113 uint64_t src = get_address(env, r3);
1114 uint16_t pad = a2;
1115 uint32_t cc;
1117 cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 2, ra);
1119 set_length(env, r1 + 1, destlen);
1120 set_length(env, r3 + 1, srclen);
1121 set_address(env, r1, dest);
1122 set_address(env, r3, src);
1124 return cc;
1127 /* compare logical long helper */
1128 static inline uint32_t do_clcl(CPUS390XState *env,
1129 uint64_t *src1, uint64_t *src1len,
1130 uint64_t *src3, uint64_t *src3len,
1131 uint16_t pad, uint64_t limit,
1132 int wordsize, uintptr_t ra)
1134 uint64_t len = MAX(*src1len, *src3len);
1135 uint32_t cc = 0;
1137 check_alignment(env, *src1len | *src3len, wordsize, ra);
1139 if (!len) {
1140 return cc;
1143 /* Lest we fail to service interrupts in a timely manner, limit the
1144 amount of work we're willing to do. */
1145 if (len > limit) {
1146 len = limit;
1147 cc = 3;
1150 for (; len; len -= wordsize) {
1151 uint16_t v1 = pad;
1152 uint16_t v3 = pad;
1154 if (*src1len) {
1155 v1 = cpu_ldusize_data_ra(env, *src1, wordsize, ra);
1157 if (*src3len) {
1158 v3 = cpu_ldusize_data_ra(env, *src3, wordsize, ra);
1161 if (v1 != v3) {
1162 cc = (v1 < v3) ? 1 : 2;
1163 break;
1166 if (*src1len) {
1167 *src1 += wordsize;
1168 *src1len -= wordsize;
1170 if (*src3len) {
1171 *src3 += wordsize;
1172 *src3len -= wordsize;
1176 return cc;
1180 /* compare logical long */
1181 uint32_t HELPER(clcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
1183 uintptr_t ra = GETPC();
1184 uint64_t src1len = extract64(env->regs[r1 + 1], 0, 24);
1185 uint64_t src1 = get_address(env, r1);
1186 uint64_t src3len = extract64(env->regs[r2 + 1], 0, 24);
1187 uint64_t src3 = get_address(env, r2);
1188 uint8_t pad = env->regs[r2 + 1] >> 24;
1189 uint32_t cc;
1191 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, -1, 1, ra);
1193 env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, src1len);
1194 env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, src3len);
1195 set_address(env, r1, src1);
1196 set_address(env, r2, src3);
1198 return cc;
1201 /* compare logical long extended memcompare insn with padding */
1202 uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1203 uint32_t r3)
1205 uintptr_t ra = GETPC();
1206 uint64_t src1len = get_length(env, r1 + 1);
1207 uint64_t src1 = get_address(env, r1);
1208 uint64_t src3len = get_length(env, r3 + 1);
1209 uint64_t src3 = get_address(env, r3);
1210 uint8_t pad = a2;
1211 uint32_t cc;
1213 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x2000, 1, ra);
1215 set_length(env, r1 + 1, src1len);
1216 set_length(env, r3 + 1, src3len);
1217 set_address(env, r1, src1);
1218 set_address(env, r3, src3);
1220 return cc;
1223 /* compare logical long unicode memcompare insn with padding */
1224 uint32_t HELPER(clclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1225 uint32_t r3)
1227 uintptr_t ra = GETPC();
1228 uint64_t src1len = get_length(env, r1 + 1);
1229 uint64_t src1 = get_address(env, r1);
1230 uint64_t src3len = get_length(env, r3 + 1);
1231 uint64_t src3 = get_address(env, r3);
1232 uint16_t pad = a2;
1233 uint32_t cc = 0;
1235 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x1000, 2, ra);
1237 set_length(env, r1 + 1, src1len);
1238 set_length(env, r3 + 1, src3len);
1239 set_address(env, r1, src1);
1240 set_address(env, r3, src3);
1242 return cc;
1245 /* checksum */
1246 uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
1247 uint64_t src, uint64_t src_len)
1249 uintptr_t ra = GETPC();
1250 uint64_t max_len, len;
1251 uint64_t cksm = (uint32_t)r1;
1253 /* Lest we fail to service interrupts in a timely manner, limit the
1254 amount of work we're willing to do. For now, let's cap at 8k. */
1255 max_len = (src_len > 0x2000 ? 0x2000 : src_len);
1257 /* Process full words as available. */
1258 for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
1259 cksm += (uint32_t)cpu_ldl_data_ra(env, src, ra);
1262 switch (max_len - len) {
1263 case 1:
1264 cksm += cpu_ldub_data_ra(env, src, ra) << 24;
1265 len += 1;
1266 break;
1267 case 2:
1268 cksm += cpu_lduw_data_ra(env, src, ra) << 16;
1269 len += 2;
1270 break;
1271 case 3:
1272 cksm += cpu_lduw_data_ra(env, src, ra) << 16;
1273 cksm += cpu_ldub_data_ra(env, src + 2, ra) << 8;
1274 len += 3;
1275 break;
1278 /* Fold the carry from the checksum. Note that we can see carry-out
1279 during folding more than once (but probably not more than twice). */
1280 while (cksm > 0xffffffffull) {
1281 cksm = (uint32_t)cksm + (cksm >> 32);
1284 /* Indicate whether or not we've processed everything. */
1285 env->cc_op = (len == src_len ? 0 : 3);
1287 /* Return both cksm and processed length. */
1288 env->retxl = cksm;
1289 return len;
1292 void HELPER(pack)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src)
1294 uintptr_t ra = GETPC();
1295 int len_dest = len >> 4;
1296 int len_src = len & 0xf;
1297 uint8_t b;
1299 dest += len_dest;
1300 src += len_src;
1302 /* last byte is special, it only flips the nibbles */
1303 b = cpu_ldub_data_ra(env, src, ra);
1304 cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
1305 src--;
1306 len_src--;
1308 /* now pack every value */
1309 while (len_dest > 0) {
1310 b = 0;
1312 if (len_src >= 0) {
1313 b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
1314 src--;
1315 len_src--;
1317 if (len_src >= 0) {
1318 b |= cpu_ldub_data_ra(env, src, ra) << 4;
1319 src--;
1320 len_src--;
1323 len_dest--;
1324 dest--;
1325 cpu_stb_data_ra(env, dest, b, ra);
1329 static inline void do_pkau(CPUS390XState *env, uint64_t dest, uint64_t src,
1330 uint32_t srclen, int ssize, uintptr_t ra)
1332 int i;
1333 /* The destination operand is always 16 bytes long. */
1334 const int destlen = 16;
1336 /* The operands are processed from right to left. */
1337 src += srclen - 1;
1338 dest += destlen - 1;
1340 for (i = 0; i < destlen; i++) {
1341 uint8_t b = 0;
1343 /* Start with a positive sign */
1344 if (i == 0) {
1345 b = 0xc;
1346 } else if (srclen > ssize) {
1347 b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
1348 src -= ssize;
1349 srclen -= ssize;
1352 if (srclen > ssize) {
1353 b |= cpu_ldub_data_ra(env, src, ra) << 4;
1354 src -= ssize;
1355 srclen -= ssize;
1358 cpu_stb_data_ra(env, dest, b, ra);
1359 dest--;
1364 void HELPER(pka)(CPUS390XState *env, uint64_t dest, uint64_t src,
1365 uint32_t srclen)
1367 do_pkau(env, dest, src, srclen, 1, GETPC());
1370 void HELPER(pku)(CPUS390XState *env, uint64_t dest, uint64_t src,
1371 uint32_t srclen)
1373 do_pkau(env, dest, src, srclen, 2, GETPC());
1376 void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
1377 uint64_t src)
1379 uintptr_t ra = GETPC();
1380 int len_dest = len >> 4;
1381 int len_src = len & 0xf;
1382 uint8_t b;
1383 int second_nibble = 0;
1385 dest += len_dest;
1386 src += len_src;
1388 /* last byte is special, it only flips the nibbles */
1389 b = cpu_ldub_data_ra(env, src, ra);
1390 cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
1391 src--;
1392 len_src--;
1394 /* now pad every nibble with 0xf0 */
1396 while (len_dest > 0) {
1397 uint8_t cur_byte = 0;
1399 if (len_src > 0) {
1400 cur_byte = cpu_ldub_data_ra(env, src, ra);
1403 len_dest--;
1404 dest--;
1406 /* only advance one nibble at a time */
1407 if (second_nibble) {
1408 cur_byte >>= 4;
1409 len_src--;
1410 src--;
1412 second_nibble = !second_nibble;
1414 /* digit */
1415 cur_byte = (cur_byte & 0xf);
1416 /* zone bits */
1417 cur_byte |= 0xf0;
1419 cpu_stb_data_ra(env, dest, cur_byte, ra);
1423 static inline uint32_t do_unpkau(CPUS390XState *env, uint64_t dest,
1424 uint32_t destlen, int dsize, uint64_t src,
1425 uintptr_t ra)
1427 int i;
1428 uint32_t cc;
1429 uint8_t b;
1430 /* The source operand is always 16 bytes long. */
1431 const int srclen = 16;
1433 /* The operands are processed from right to left. */
1434 src += srclen - 1;
1435 dest += destlen - dsize;
1437 /* Check for the sign. */
1438 b = cpu_ldub_data_ra(env, src, ra);
1439 src--;
1440 switch (b & 0xf) {
1441 case 0xa:
1442 case 0xc:
1443 case 0xe ... 0xf:
1444 cc = 0; /* plus */
1445 break;
1446 case 0xb:
1447 case 0xd:
1448 cc = 1; /* minus */
1449 break;
1450 default:
1451 case 0x0 ... 0x9:
1452 cc = 3; /* invalid */
1453 break;
1456 /* Now pad every nibble with 0x30, advancing one nibble at a time. */
1457 for (i = 0; i < destlen; i += dsize) {
1458 if (i == (31 * dsize)) {
1459 /* If length is 32/64 bytes, the leftmost byte is 0. */
1460 b = 0;
1461 } else if (i % (2 * dsize)) {
1462 b = cpu_ldub_data_ra(env, src, ra);
1463 src--;
1464 } else {
1465 b >>= 4;
1467 cpu_stsize_data_ra(env, dest, 0x30 + (b & 0xf), dsize, ra);
1468 dest -= dsize;
1471 return cc;
1474 uint32_t HELPER(unpka)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1475 uint64_t src)
1477 return do_unpkau(env, dest, destlen, 1, src, GETPC());
1480 uint32_t HELPER(unpku)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1481 uint64_t src)
1483 return do_unpkau(env, dest, destlen, 2, src, GETPC());
1486 uint32_t HELPER(tp)(CPUS390XState *env, uint64_t dest, uint32_t destlen)
1488 uintptr_t ra = GETPC();
1489 uint32_t cc = 0;
1490 int i;
1492 for (i = 0; i < destlen; i++) {
1493 uint8_t b = cpu_ldub_data_ra(env, dest + i, ra);
1494 /* digit */
1495 cc |= (b & 0xf0) > 0x90 ? 2 : 0;
1497 if (i == (destlen - 1)) {
1498 /* sign */
1499 cc |= (b & 0xf) < 0xa ? 1 : 0;
1500 } else {
1501 /* digit */
1502 cc |= (b & 0xf) > 0x9 ? 2 : 0;
1506 return cc;
1509 static uint32_t do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array,
1510 uint64_t trans, uintptr_t ra)
1512 uint32_t i;
1514 for (i = 0; i <= len; i++) {
1515 uint8_t byte = cpu_ldub_data_ra(env, array + i, ra);
1516 uint8_t new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
1517 cpu_stb_data_ra(env, array + i, new_byte, ra);
1520 return env->cc_op;
1523 void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
1524 uint64_t trans)
1526 do_helper_tr(env, len, array, trans, GETPC());
1529 uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array,
1530 uint64_t len, uint64_t trans)
1532 uintptr_t ra = GETPC();
1533 uint8_t end = env->regs[0] & 0xff;
1534 uint64_t l = len;
1535 uint64_t i;
1536 uint32_t cc = 0;
1538 if (!(env->psw.mask & PSW_MASK_64)) {
1539 array &= 0x7fffffff;
1540 l = (uint32_t)l;
1543 /* Lest we fail to service interrupts in a timely manner, limit the
1544 amount of work we're willing to do. For now, let's cap at 8k. */
1545 if (l > 0x2000) {
1546 l = 0x2000;
1547 cc = 3;
1550 for (i = 0; i < l; i++) {
1551 uint8_t byte, new_byte;
1553 byte = cpu_ldub_data_ra(env, array + i, ra);
1555 if (byte == end) {
1556 cc = 1;
1557 break;
1560 new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
1561 cpu_stb_data_ra(env, array + i, new_byte, ra);
1564 env->cc_op = cc;
1565 env->retxl = len - i;
1566 return array + i;
1569 static inline uint32_t do_helper_trt(CPUS390XState *env, int len,
1570 uint64_t array, uint64_t trans,
1571 int inc, uintptr_t ra)
1573 int i;
1575 for (i = 0; i <= len; i++) {
1576 uint8_t byte = cpu_ldub_data_ra(env, array + i * inc, ra);
1577 uint8_t sbyte = cpu_ldub_data_ra(env, trans + byte, ra);
1579 if (sbyte != 0) {
1580 set_address(env, 1, array + i * inc);
1581 env->regs[2] = deposit64(env->regs[2], 0, 8, sbyte);
1582 return (i == len) ? 2 : 1;
1586 return 0;
1589 static uint32_t do_helper_trt_fwd(CPUS390XState *env, uint32_t len,
1590 uint64_t array, uint64_t trans,
1591 uintptr_t ra)
1593 return do_helper_trt(env, len, array, trans, 1, ra);
1596 uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
1597 uint64_t trans)
1599 return do_helper_trt(env, len, array, trans, 1, GETPC());
1602 static uint32_t do_helper_trt_bkwd(CPUS390XState *env, uint32_t len,
1603 uint64_t array, uint64_t trans,
1604 uintptr_t ra)
1606 return do_helper_trt(env, len, array, trans, -1, ra);
1609 uint32_t HELPER(trtr)(CPUS390XState *env, uint32_t len, uint64_t array,
1610 uint64_t trans)
1612 return do_helper_trt(env, len, array, trans, -1, GETPC());
1615 /* Translate one/two to one/two */
1616 uint32_t HELPER(trXX)(CPUS390XState *env, uint32_t r1, uint32_t r2,
1617 uint32_t tst, uint32_t sizes)
1619 uintptr_t ra = GETPC();
1620 int dsize = (sizes & 1) ? 1 : 2;
1621 int ssize = (sizes & 2) ? 1 : 2;
1622 uint64_t tbl = get_address(env, 1);
1623 uint64_t dst = get_address(env, r1);
1624 uint64_t len = get_length(env, r1 + 1);
1625 uint64_t src = get_address(env, r2);
1626 uint32_t cc = 3;
1627 int i;
1629 /* The lower address bits of TBL are ignored. For TROO, TROT, it's
1630 the low 3 bits (double-word aligned). For TRTO, TRTT, it's either
1631 the low 12 bits (4K, without ETF2-ENH) or 3 bits (with ETF2-ENH). */
1632 if (ssize == 2 && !s390_has_feat(S390_FEAT_ETF2_ENH)) {
1633 tbl &= -4096;
1634 } else {
1635 tbl &= -8;
1638 check_alignment(env, len, ssize, ra);
1640 /* Lest we fail to service interrupts in a timely manner, */
1641 /* limit the amount of work we're willing to do. */
1642 for (i = 0; i < 0x2000; i++) {
1643 uint16_t sval = cpu_ldusize_data_ra(env, src, ssize, ra);
1644 uint64_t tble = tbl + (sval * dsize);
1645 uint16_t dval = cpu_ldusize_data_ra(env, tble, dsize, ra);
1646 if (dval == tst) {
1647 cc = 1;
1648 break;
1650 cpu_stsize_data_ra(env, dst, dval, dsize, ra);
1652 len -= ssize;
1653 src += ssize;
1654 dst += dsize;
1656 if (len == 0) {
1657 cc = 0;
1658 break;
1662 set_address(env, r1, dst);
1663 set_length(env, r1 + 1, len);
1664 set_address(env, r2, src);
1666 return cc;
1669 void HELPER(cdsg)(CPUS390XState *env, uint64_t addr,
1670 uint32_t r1, uint32_t r3)
1672 uintptr_t ra = GETPC();
1673 Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
1674 Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1675 Int128 oldv;
1676 uint64_t oldh, oldl;
1677 bool fail;
1679 check_alignment(env, addr, 16, ra);
1681 oldh = cpu_ldq_data_ra(env, addr + 0, ra);
1682 oldl = cpu_ldq_data_ra(env, addr + 8, ra);
1684 oldv = int128_make128(oldl, oldh);
1685 fail = !int128_eq(oldv, cmpv);
1686 if (fail) {
1687 newv = oldv;
1690 cpu_stq_data_ra(env, addr + 0, int128_gethi(newv), ra);
1691 cpu_stq_data_ra(env, addr + 8, int128_getlo(newv), ra);
1693 env->cc_op = fail;
1694 env->regs[r1] = int128_gethi(oldv);
1695 env->regs[r1 + 1] = int128_getlo(oldv);
1698 void HELPER(cdsg_parallel)(CPUS390XState *env, uint64_t addr,
1699 uint32_t r1, uint32_t r3)
1701 uintptr_t ra = GETPC();
1702 Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
1703 Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1704 int mem_idx;
1705 TCGMemOpIdx oi;
1706 Int128 oldv;
1707 bool fail;
1709 assert(HAVE_CMPXCHG128);
1711 mem_idx = cpu_mmu_index(env, false);
1712 oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1713 oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
1714 fail = !int128_eq(oldv, cmpv);
1716 env->cc_op = fail;
1717 env->regs[r1] = int128_gethi(oldv);
1718 env->regs[r1 + 1] = int128_getlo(oldv);
1721 static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
1722 uint64_t a2, bool parallel)
1724 uint32_t mem_idx = cpu_mmu_index(env, false);
1725 uintptr_t ra = GETPC();
1726 uint32_t fc = extract32(env->regs[0], 0, 8);
1727 uint32_t sc = extract32(env->regs[0], 8, 8);
1728 uint64_t pl = get_address(env, 1) & -16;
1729 uint64_t svh, svl;
1730 uint32_t cc;
1732 /* Sanity check the function code and storage characteristic. */
1733 if (fc > 1 || sc > 3) {
1734 if (!s390_has_feat(S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2)) {
1735 goto spec_exception;
1737 if (fc > 2 || sc > 4 || (fc == 2 && (r3 & 1))) {
1738 goto spec_exception;
1742 /* Sanity check the alignments. */
1743 if (extract32(a1, 0, fc + 2) || extract32(a2, 0, sc)) {
1744 goto spec_exception;
1747 /* Sanity check writability of the store address. */
1748 probe_write(env, a2, 1 << sc, mem_idx, ra);
1751 * Note that the compare-and-swap is atomic, and the store is atomic,
1752 * but the complete operation is not. Therefore we do not need to
1753 * assert serial context in order to implement this. That said,
1754 * restart early if we can't support either operation that is supposed
1755 * to be atomic.
1757 if (parallel) {
1758 uint32_t max = 2;
1759 #ifdef CONFIG_ATOMIC64
1760 max = 3;
1761 #endif
1762 if ((HAVE_CMPXCHG128 ? 0 : fc + 2 > max) ||
1763 (HAVE_ATOMIC128 ? 0 : sc > max)) {
1764 cpu_loop_exit_atomic(env_cpu(env), ra);
1768 /* All loads happen before all stores. For simplicity, load the entire
1769 store value area from the parameter list. */
1770 svh = cpu_ldq_data_ra(env, pl + 16, ra);
1771 svl = cpu_ldq_data_ra(env, pl + 24, ra);
1773 switch (fc) {
1774 case 0:
1776 uint32_t nv = cpu_ldl_data_ra(env, pl, ra);
1777 uint32_t cv = env->regs[r3];
1778 uint32_t ov;
1780 if (parallel) {
1781 #ifdef CONFIG_USER_ONLY
1782 uint32_t *haddr = g2h(a1);
1783 ov = atomic_cmpxchg__nocheck(haddr, cv, nv);
1784 #else
1785 TCGMemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mem_idx);
1786 ov = helper_atomic_cmpxchgl_be_mmu(env, a1, cv, nv, oi, ra);
1787 #endif
1788 } else {
1789 ov = cpu_ldl_data_ra(env, a1, ra);
1790 cpu_stl_data_ra(env, a1, (ov == cv ? nv : ov), ra);
1792 cc = (ov != cv);
1793 env->regs[r3] = deposit64(env->regs[r3], 32, 32, ov);
1795 break;
1797 case 1:
1799 uint64_t nv = cpu_ldq_data_ra(env, pl, ra);
1800 uint64_t cv = env->regs[r3];
1801 uint64_t ov;
1803 if (parallel) {
1804 #ifdef CONFIG_ATOMIC64
1805 # ifdef CONFIG_USER_ONLY
1806 uint64_t *haddr = g2h(a1);
1807 ov = atomic_cmpxchg__nocheck(haddr, cv, nv);
1808 # else
1809 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN, mem_idx);
1810 ov = helper_atomic_cmpxchgq_be_mmu(env, a1, cv, nv, oi, ra);
1811 # endif
1812 #else
1813 /* Note that we asserted !parallel above. */
1814 g_assert_not_reached();
1815 #endif
1816 } else {
1817 ov = cpu_ldq_data_ra(env, a1, ra);
1818 cpu_stq_data_ra(env, a1, (ov == cv ? nv : ov), ra);
1820 cc = (ov != cv);
1821 env->regs[r3] = ov;
1823 break;
1825 case 2:
1827 uint64_t nvh = cpu_ldq_data_ra(env, pl, ra);
1828 uint64_t nvl = cpu_ldq_data_ra(env, pl + 8, ra);
1829 Int128 nv = int128_make128(nvl, nvh);
1830 Int128 cv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1831 Int128 ov;
1833 if (!parallel) {
1834 uint64_t oh = cpu_ldq_data_ra(env, a1 + 0, ra);
1835 uint64_t ol = cpu_ldq_data_ra(env, a1 + 8, ra);
1837 ov = int128_make128(ol, oh);
1838 cc = !int128_eq(ov, cv);
1839 if (cc) {
1840 nv = ov;
1843 cpu_stq_data_ra(env, a1 + 0, int128_gethi(nv), ra);
1844 cpu_stq_data_ra(env, a1 + 8, int128_getlo(nv), ra);
1845 } else if (HAVE_CMPXCHG128) {
1846 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1847 ov = helper_atomic_cmpxchgo_be_mmu(env, a1, cv, nv, oi, ra);
1848 cc = !int128_eq(ov, cv);
1849 } else {
1850 /* Note that we asserted !parallel above. */
1851 g_assert_not_reached();
1854 env->regs[r3 + 0] = int128_gethi(ov);
1855 env->regs[r3 + 1] = int128_getlo(ov);
1857 break;
1859 default:
1860 g_assert_not_reached();
1863 /* Store only if the comparison succeeded. Note that above we use a pair
1864 of 64-bit big-endian loads, so for sc < 3 we must extract the value
1865 from the most-significant bits of svh. */
1866 if (cc == 0) {
1867 switch (sc) {
1868 case 0:
1869 cpu_stb_data_ra(env, a2, svh >> 56, ra);
1870 break;
1871 case 1:
1872 cpu_stw_data_ra(env, a2, svh >> 48, ra);
1873 break;
1874 case 2:
1875 cpu_stl_data_ra(env, a2, svh >> 32, ra);
1876 break;
1877 case 3:
1878 cpu_stq_data_ra(env, a2, svh, ra);
1879 break;
1880 case 4:
1881 if (!parallel) {
1882 cpu_stq_data_ra(env, a2 + 0, svh, ra);
1883 cpu_stq_data_ra(env, a2 + 8, svl, ra);
1884 } else if (HAVE_ATOMIC128) {
1885 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1886 Int128 sv = int128_make128(svl, svh);
1887 helper_atomic_sto_be_mmu(env, a2, sv, oi, ra);
1888 } else {
1889 /* Note that we asserted !parallel above. */
1890 g_assert_not_reached();
1892 break;
1893 default:
1894 g_assert_not_reached();
1898 return cc;
1900 spec_exception:
1901 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
1904 uint32_t HELPER(csst)(CPUS390XState *env, uint32_t r3, uint64_t a1, uint64_t a2)
1906 return do_csst(env, r3, a1, a2, false);
1909 uint32_t HELPER(csst_parallel)(CPUS390XState *env, uint32_t r3, uint64_t a1,
1910 uint64_t a2)
1912 return do_csst(env, r3, a1, a2, true);
1915 #if !defined(CONFIG_USER_ONLY)
1916 void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1918 uintptr_t ra = GETPC();
1919 bool PERchanged = false;
1920 uint64_t src = a2;
1921 uint32_t i;
1923 if (src & 0x7) {
1924 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
1927 for (i = r1;; i = (i + 1) % 16) {
1928 uint64_t val = cpu_ldq_data_ra(env, src, ra);
1929 if (env->cregs[i] != val && i >= 9 && i <= 11) {
1930 PERchanged = true;
1932 env->cregs[i] = val;
1933 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
1934 i, src, val);
1935 src += sizeof(uint64_t);
1937 if (i == r3) {
1938 break;
1942 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
1943 s390_cpu_recompute_watchpoints(env_cpu(env));
1946 tlb_flush(env_cpu(env));
1949 void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1951 uintptr_t ra = GETPC();
1952 bool PERchanged = false;
1953 uint64_t src = a2;
1954 uint32_t i;
1956 if (src & 0x3) {
1957 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
1960 for (i = r1;; i = (i + 1) % 16) {
1961 uint32_t val = cpu_ldl_data_ra(env, src, ra);
1962 if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
1963 PERchanged = true;
1965 env->cregs[i] = deposit64(env->cregs[i], 0, 32, val);
1966 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val);
1967 src += sizeof(uint32_t);
1969 if (i == r3) {
1970 break;
1974 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
1975 s390_cpu_recompute_watchpoints(env_cpu(env));
1978 tlb_flush(env_cpu(env));
1981 void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1983 uintptr_t ra = GETPC();
1984 uint64_t dest = a2;
1985 uint32_t i;
1987 if (dest & 0x7) {
1988 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
1991 for (i = r1;; i = (i + 1) % 16) {
1992 cpu_stq_data_ra(env, dest, env->cregs[i], ra);
1993 dest += sizeof(uint64_t);
1995 if (i == r3) {
1996 break;
2001 void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
2003 uintptr_t ra = GETPC();
2004 uint64_t dest = a2;
2005 uint32_t i;
2007 if (dest & 0x3) {
2008 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
2011 for (i = r1;; i = (i + 1) % 16) {
2012 cpu_stl_data_ra(env, dest, env->cregs[i], ra);
2013 dest += sizeof(uint32_t);
2015 if (i == r3) {
2016 break;
2021 uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
2023 uintptr_t ra = GETPC();
2024 int i;
2026 real_addr = wrap_address(env, real_addr) & TARGET_PAGE_MASK;
2028 for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
2029 cpu_stq_mmuidx_ra(env, real_addr + i, 0, MMU_REAL_IDX, ra);
2032 return 0;
2035 uint32_t HELPER(tprot)(CPUS390XState *env, uint64_t a1, uint64_t a2)
2037 S390CPU *cpu = env_archcpu(env);
2038 CPUState *cs = env_cpu(env);
2041 * TODO: we currently don't handle all access protection types
2042 * (including access-list and key-controlled) as well as AR mode.
2044 if (!s390_cpu_virt_mem_check_write(cpu, a1, 0, 1)) {
2045 /* Fetching permitted; storing permitted */
2046 return 0;
2049 if (env->int_pgm_code == PGM_PROTECTION) {
2050 /* retry if reading is possible */
2051 cs->exception_index = -1;
2052 if (!s390_cpu_virt_mem_check_read(cpu, a1, 0, 1)) {
2053 /* Fetching permitted; storing not permitted */
2054 return 1;
2058 switch (env->int_pgm_code) {
2059 case PGM_PROTECTION:
2060 /* Fetching not permitted; storing not permitted */
2061 cs->exception_index = -1;
2062 return 2;
2063 case PGM_ADDRESSING:
2064 case PGM_TRANS_SPEC:
2065 /* exceptions forwarded to the guest */
2066 s390_cpu_virt_mem_handle_exc(cpu, GETPC());
2067 return 0;
2070 /* Translation not available */
2071 cs->exception_index = -1;
2072 return 3;
2075 /* insert storage key extended */
2076 uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
2078 static S390SKeysState *ss;
2079 static S390SKeysClass *skeyclass;
2080 uint64_t addr = wrap_address(env, r2);
2081 uint8_t key;
2083 if (addr > ram_size) {
2084 return 0;
2087 if (unlikely(!ss)) {
2088 ss = s390_get_skeys_device();
2089 skeyclass = S390_SKEYS_GET_CLASS(ss);
2092 if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
2093 return 0;
2095 return key;
2098 /* set storage key extended */
2099 void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
2101 static S390SKeysState *ss;
2102 static S390SKeysClass *skeyclass;
2103 uint64_t addr = wrap_address(env, r2);
2104 uint8_t key;
2106 if (addr > ram_size) {
2107 return;
2110 if (unlikely(!ss)) {
2111 ss = s390_get_skeys_device();
2112 skeyclass = S390_SKEYS_GET_CLASS(ss);
2115 key = (uint8_t) r1;
2116 skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
2118 * As we can only flush by virtual address and not all the entries
2119 * that point to a physical address we have to flush the whole TLB.
2121 tlb_flush_all_cpus_synced(env_cpu(env));
2124 /* reset reference bit extended */
2125 uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
2127 static S390SKeysState *ss;
2128 static S390SKeysClass *skeyclass;
2129 uint8_t re, key;
2131 if (r2 > ram_size) {
2132 return 0;
2135 if (unlikely(!ss)) {
2136 ss = s390_get_skeys_device();
2137 skeyclass = S390_SKEYS_GET_CLASS(ss);
2140 if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
2141 return 0;
2144 re = key & (SK_R | SK_C);
2145 key &= ~SK_R;
2147 if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
2148 return 0;
2151 * As we can only flush by virtual address and not all the entries
2152 * that point to a physical address we have to flush the whole TLB.
2154 tlb_flush_all_cpus_synced(env_cpu(env));
2157 * cc
2159 * 0 Reference bit zero; change bit zero
2160 * 1 Reference bit zero; change bit one
2161 * 2 Reference bit one; change bit zero
2162 * 3 Reference bit one; change bit one
2165 return re >> 1;
2168 uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
2170 const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
2171 S390Access srca, desta;
2172 uintptr_t ra = GETPC();
2173 int cc = 0;
2175 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
2176 __func__, l, a1, a2);
2178 if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) ||
2179 psw_as == AS_HOME || psw_as == AS_ACCREG) {
2180 s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2183 l = wrap_length32(env, l);
2184 if (l > 256) {
2185 /* max 256 */
2186 l = 256;
2187 cc = 3;
2188 } else if (!l) {
2189 return cc;
2192 /* TODO: Access key handling */
2193 srca = access_prepare(env, a2, l, MMU_DATA_LOAD, MMU_PRIMARY_IDX, ra);
2194 desta = access_prepare(env, a1, l, MMU_DATA_STORE, MMU_SECONDARY_IDX, ra);
2195 access_memmove(env, &desta, &srca, ra);
2196 return cc;
2199 uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
2201 const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
2202 S390Access srca, desta;
2203 uintptr_t ra = GETPC();
2204 int cc = 0;
2206 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
2207 __func__, l, a1, a2);
2209 if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) ||
2210 psw_as == AS_HOME || psw_as == AS_ACCREG) {
2211 s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2214 l = wrap_length32(env, l);
2215 if (l > 256) {
2216 /* max 256 */
2217 l = 256;
2218 cc = 3;
2219 } else if (!l) {
2220 return cc;
2223 /* TODO: Access key handling */
2224 srca = access_prepare(env, a2, l, MMU_DATA_LOAD, MMU_SECONDARY_IDX, ra);
2225 desta = access_prepare(env, a1, l, MMU_DATA_STORE, MMU_PRIMARY_IDX, ra);
2226 access_memmove(env, &desta, &srca, ra);
2227 return cc;
2230 void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4)
2232 CPUState *cs = env_cpu(env);
2233 const uintptr_t ra = GETPC();
2234 uint64_t table, entry, raddr;
2235 uint16_t entries, i, index = 0;
2237 if (r2 & 0xff000) {
2238 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
2241 if (!(r2 & 0x800)) {
2242 /* invalidation-and-clearing operation */
2243 table = r1 & ASCE_ORIGIN;
2244 entries = (r2 & 0x7ff) + 1;
2246 switch (r1 & ASCE_TYPE_MASK) {
2247 case ASCE_TYPE_REGION1:
2248 index = (r2 >> 53) & 0x7ff;
2249 break;
2250 case ASCE_TYPE_REGION2:
2251 index = (r2 >> 42) & 0x7ff;
2252 break;
2253 case ASCE_TYPE_REGION3:
2254 index = (r2 >> 31) & 0x7ff;
2255 break;
2256 case ASCE_TYPE_SEGMENT:
2257 index = (r2 >> 20) & 0x7ff;
2258 break;
2260 for (i = 0; i < entries; i++) {
2261 /* addresses are not wrapped in 24/31bit mode but table index is */
2262 raddr = table + ((index + i) & 0x7ff) * sizeof(entry);
2263 entry = cpu_ldq_mmuidx_ra(env, raddr, MMU_REAL_IDX, ra);
2264 if (!(entry & REGION_ENTRY_I)) {
2265 /* we are allowed to not store if already invalid */
2266 entry |= REGION_ENTRY_I;
2267 cpu_stq_mmuidx_ra(env, raddr, entry, MMU_REAL_IDX, ra);
2272 /* We simply flush the complete tlb, therefore we can ignore r3. */
2273 if (m4 & 1) {
2274 tlb_flush(cs);
2275 } else {
2276 tlb_flush_all_cpus_synced(cs);
2280 /* invalidate pte */
2281 void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr,
2282 uint32_t m4)
2284 CPUState *cs = env_cpu(env);
2285 const uintptr_t ra = GETPC();
2286 uint64_t page = vaddr & TARGET_PAGE_MASK;
2287 uint64_t pte_addr, pte;
2289 /* Compute the page table entry address */
2290 pte_addr = (pto & SEGMENT_ENTRY_ORIGIN);
2291 pte_addr += VADDR_PAGE_TX(vaddr) * 8;
2293 /* Mark the page table entry as invalid */
2294 pte = cpu_ldq_mmuidx_ra(env, pte_addr, MMU_REAL_IDX, ra);
2295 pte |= PAGE_ENTRY_I;
2296 cpu_stq_mmuidx_ra(env, pte_addr, pte, MMU_REAL_IDX, ra);
2298 /* XXX we exploit the fact that Linux passes the exact virtual
2299 address here - it's not obliged to! */
2300 if (m4 & 1) {
2301 if (vaddr & ~VADDR_PAGE_TX_MASK) {
2302 tlb_flush_page(cs, page);
2303 /* XXX 31-bit hack */
2304 tlb_flush_page(cs, page ^ 0x80000000);
2305 } else {
2306 /* looks like we don't have a valid virtual address */
2307 tlb_flush(cs);
2309 } else {
2310 if (vaddr & ~VADDR_PAGE_TX_MASK) {
2311 tlb_flush_page_all_cpus_synced(cs, page);
2312 /* XXX 31-bit hack */
2313 tlb_flush_page_all_cpus_synced(cs, page ^ 0x80000000);
2314 } else {
2315 /* looks like we don't have a valid virtual address */
2316 tlb_flush_all_cpus_synced(cs);
2321 /* flush local tlb */
2322 void HELPER(ptlb)(CPUS390XState *env)
2324 tlb_flush(env_cpu(env));
2327 /* flush global tlb */
2328 void HELPER(purge)(CPUS390XState *env)
2330 tlb_flush_all_cpus_synced(env_cpu(env));
2333 /* load real address */
2334 uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
2336 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
2337 uint64_t ret, tec;
2338 int flags, exc, cc;
2340 /* XXX incomplete - has more corner cases */
2341 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
2342 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, GETPC());
2345 exc = mmu_translate(env, addr, 0, asc, &ret, &flags, &tec);
2346 if (exc) {
2347 cc = 3;
2348 ret = exc | 0x80000000;
2349 } else {
2350 cc = 0;
2351 ret |= addr & ~TARGET_PAGE_MASK;
2354 env->cc_op = cc;
2355 return ret;
2357 #endif
2359 /* load pair from quadword */
2360 uint64_t HELPER(lpq)(CPUS390XState *env, uint64_t addr)
2362 uintptr_t ra = GETPC();
2363 uint64_t hi, lo;
2365 check_alignment(env, addr, 16, ra);
2366 hi = cpu_ldq_data_ra(env, addr + 0, ra);
2367 lo = cpu_ldq_data_ra(env, addr + 8, ra);
2369 env->retxl = lo;
2370 return hi;
2373 uint64_t HELPER(lpq_parallel)(CPUS390XState *env, uint64_t addr)
2375 uintptr_t ra = GETPC();
2376 uint64_t hi, lo;
2377 int mem_idx;
2378 TCGMemOpIdx oi;
2379 Int128 v;
2381 assert(HAVE_ATOMIC128);
2383 mem_idx = cpu_mmu_index(env, false);
2384 oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
2385 v = helper_atomic_ldo_be_mmu(env, addr, oi, ra);
2386 hi = int128_gethi(v);
2387 lo = int128_getlo(v);
2389 env->retxl = lo;
2390 return hi;
2393 /* store pair to quadword */
2394 void HELPER(stpq)(CPUS390XState *env, uint64_t addr,
2395 uint64_t low, uint64_t high)
2397 uintptr_t ra = GETPC();
2399 check_alignment(env, addr, 16, ra);
2400 cpu_stq_data_ra(env, addr + 0, high, ra);
2401 cpu_stq_data_ra(env, addr + 8, low, ra);
2404 void HELPER(stpq_parallel)(CPUS390XState *env, uint64_t addr,
2405 uint64_t low, uint64_t high)
2407 uintptr_t ra = GETPC();
2408 int mem_idx;
2409 TCGMemOpIdx oi;
2410 Int128 v;
2412 assert(HAVE_ATOMIC128);
2414 mem_idx = cpu_mmu_index(env, false);
2415 oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
2416 v = int128_make128(low, high);
2417 helper_atomic_sto_be_mmu(env, addr, v, oi, ra);
2420 /* Execute instruction. This instruction executes an insn modified with
2421 the contents of r1. It does not change the executed instruction in memory;
2422 it does not change the program counter.
2424 Perform this by recording the modified instruction in env->ex_value.
2425 This will be noticed by cpu_get_tb_cpu_state and thus tb translation.
2427 void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
2429 uint64_t insn = cpu_lduw_code(env, addr);
2430 uint8_t opc = insn >> 8;
2432 /* Or in the contents of R1[56:63]. */
2433 insn |= r1 & 0xff;
2435 /* Load the rest of the instruction. */
2436 insn <<= 48;
2437 switch (get_ilen(opc)) {
2438 case 2:
2439 break;
2440 case 4:
2441 insn |= (uint64_t)cpu_lduw_code(env, addr + 2) << 32;
2442 break;
2443 case 6:
2444 insn |= (uint64_t)(uint32_t)cpu_ldl_code(env, addr + 2) << 16;
2445 break;
2446 default:
2447 g_assert_not_reached();
2450 /* The very most common cases can be sped up by avoiding a new TB. */
2451 if ((opc & 0xf0) == 0xd0) {
2452 typedef uint32_t (*dx_helper)(CPUS390XState *, uint32_t, uint64_t,
2453 uint64_t, uintptr_t);
2454 static const dx_helper dx[16] = {
2455 [0x0] = do_helper_trt_bkwd,
2456 [0x2] = do_helper_mvc,
2457 [0x4] = do_helper_nc,
2458 [0x5] = do_helper_clc,
2459 [0x6] = do_helper_oc,
2460 [0x7] = do_helper_xc,
2461 [0xc] = do_helper_tr,
2462 [0xd] = do_helper_trt_fwd,
2464 dx_helper helper = dx[opc & 0xf];
2466 if (helper) {
2467 uint32_t l = extract64(insn, 48, 8);
2468 uint32_t b1 = extract64(insn, 44, 4);
2469 uint32_t d1 = extract64(insn, 32, 12);
2470 uint32_t b2 = extract64(insn, 28, 4);
2471 uint32_t d2 = extract64(insn, 16, 12);
2472 uint64_t a1 = wrap_address(env, env->regs[b1] + d1);
2473 uint64_t a2 = wrap_address(env, env->regs[b2] + d2);
2475 env->cc_op = helper(env, l, a1, a2, 0);
2476 env->psw.addr += ilen;
2477 return;
2479 } else if (opc == 0x0a) {
2480 env->int_svc_code = extract64(insn, 48, 8);
2481 env->int_svc_ilen = ilen;
2482 helper_exception(env, EXCP_SVC);
2483 g_assert_not_reached();
2486 /* Record the insn we want to execute as well as the ilen to use
2487 during the execution of the target insn. This will also ensure
2488 that ex_value is non-zero, which flags that we are in a state
2489 that requires such execution. */
2490 env->ex_value = insn | ilen;
2493 uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src,
2494 uint64_t len)
2496 const uint8_t psw_key = (env->psw.mask & PSW_MASK_KEY) >> PSW_SHIFT_KEY;
2497 const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
2498 const uint64_t r0 = env->regs[0];
2499 const uintptr_t ra = GETPC();
2500 uint8_t dest_key, dest_as, dest_k, dest_a;
2501 uint8_t src_key, src_as, src_k, src_a;
2502 uint64_t val;
2503 int cc = 0;
2505 HELPER_LOG("%s dest %" PRIx64 ", src %" PRIx64 ", len %" PRIx64 "\n",
2506 __func__, dest, src, len);
2508 if (!(env->psw.mask & PSW_MASK_DAT)) {
2509 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2512 /* OAC (operand access control) for the first operand -> dest */
2513 val = (r0 & 0xffff0000ULL) >> 16;
2514 dest_key = (val >> 12) & 0xf;
2515 dest_as = (val >> 6) & 0x3;
2516 dest_k = (val >> 1) & 0x1;
2517 dest_a = val & 0x1;
2519 /* OAC (operand access control) for the second operand -> src */
2520 val = (r0 & 0x0000ffffULL);
2521 src_key = (val >> 12) & 0xf;
2522 src_as = (val >> 6) & 0x3;
2523 src_k = (val >> 1) & 0x1;
2524 src_a = val & 0x1;
2526 if (!dest_k) {
2527 dest_key = psw_key;
2529 if (!src_k) {
2530 src_key = psw_key;
2532 if (!dest_a) {
2533 dest_as = psw_as;
2535 if (!src_a) {
2536 src_as = psw_as;
2539 if (dest_a && dest_as == AS_HOME && (env->psw.mask & PSW_MASK_PSTATE)) {
2540 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2542 if (!(env->cregs[0] & CR0_SECONDARY) &&
2543 (dest_as == AS_SECONDARY || src_as == AS_SECONDARY)) {
2544 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2546 if (!psw_key_valid(env, dest_key) || !psw_key_valid(env, src_key)) {
2547 tcg_s390_program_interrupt(env, PGM_PRIVILEGED, ra);
2550 len = wrap_length32(env, len);
2551 if (len > 4096) {
2552 cc = 3;
2553 len = 4096;
2556 /* FIXME: AR-mode and proper problem state mode (using PSW keys) missing */
2557 if (src_as == AS_ACCREG || dest_as == AS_ACCREG ||
2558 (env->psw.mask & PSW_MASK_PSTATE)) {
2559 qemu_log_mask(LOG_UNIMP, "%s: AR-mode and PSTATE support missing\n",
2560 __func__);
2561 tcg_s390_program_interrupt(env, PGM_ADDRESSING, ra);
2564 /* FIXME: Access using correct keys and AR-mode */
2565 if (len) {
2566 S390Access srca = access_prepare(env, src, len, MMU_DATA_LOAD,
2567 mmu_idx_from_as(src_as), ra);
2568 S390Access desta = access_prepare(env, dest, len, MMU_DATA_STORE,
2569 mmu_idx_from_as(dest_as), ra);
2571 access_memmove(env, &desta, &srca, ra);
2574 return cc;
2577 /* Decode a Unicode character. A return value < 0 indicates success, storing
2578 the UTF-32 result into OCHAR and the input length into OLEN. A return
2579 value >= 0 indicates failure, and the CC value to be returned. */
2580 typedef int (*decode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2581 uint64_t ilen, bool enh_check, uintptr_t ra,
2582 uint32_t *ochar, uint32_t *olen);
2584 /* Encode a Unicode character. A return value < 0 indicates success, storing
2585 the bytes into ADDR and the output length into OLEN. A return value >= 0
2586 indicates failure, and the CC value to be returned. */
2587 typedef int (*encode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2588 uint64_t ilen, uintptr_t ra, uint32_t c,
2589 uint32_t *olen);
2591 static int decode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2592 bool enh_check, uintptr_t ra,
2593 uint32_t *ochar, uint32_t *olen)
2595 uint8_t s0, s1, s2, s3;
2596 uint32_t c, l;
2598 if (ilen < 1) {
2599 return 0;
2601 s0 = cpu_ldub_data_ra(env, addr, ra);
2602 if (s0 <= 0x7f) {
2603 /* one byte character */
2604 l = 1;
2605 c = s0;
2606 } else if (s0 <= (enh_check ? 0xc1 : 0xbf)) {
2607 /* invalid character */
2608 return 2;
2609 } else if (s0 <= 0xdf) {
2610 /* two byte character */
2611 l = 2;
2612 if (ilen < 2) {
2613 return 0;
2615 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2616 c = s0 & 0x1f;
2617 c = (c << 6) | (s1 & 0x3f);
2618 if (enh_check && (s1 & 0xc0) != 0x80) {
2619 return 2;
2621 } else if (s0 <= 0xef) {
2622 /* three byte character */
2623 l = 3;
2624 if (ilen < 3) {
2625 return 0;
2627 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2628 s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2629 c = s0 & 0x0f;
2630 c = (c << 6) | (s1 & 0x3f);
2631 c = (c << 6) | (s2 & 0x3f);
2632 /* Fold the byte-by-byte range descriptions in the PoO into
2633 tests against the complete value. It disallows encodings
2634 that could be smaller, and the UTF-16 surrogates. */
2635 if (enh_check
2636 && ((s1 & 0xc0) != 0x80
2637 || (s2 & 0xc0) != 0x80
2638 || c < 0x1000
2639 || (c >= 0xd800 && c <= 0xdfff))) {
2640 return 2;
2642 } else if (s0 <= (enh_check ? 0xf4 : 0xf7)) {
2643 /* four byte character */
2644 l = 4;
2645 if (ilen < 4) {
2646 return 0;
2648 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2649 s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2650 s3 = cpu_ldub_data_ra(env, addr + 3, ra);
2651 c = s0 & 0x07;
2652 c = (c << 6) | (s1 & 0x3f);
2653 c = (c << 6) | (s2 & 0x3f);
2654 c = (c << 6) | (s3 & 0x3f);
2655 /* See above. */
2656 if (enh_check
2657 && ((s1 & 0xc0) != 0x80
2658 || (s2 & 0xc0) != 0x80
2659 || (s3 & 0xc0) != 0x80
2660 || c < 0x010000
2661 || c > 0x10ffff)) {
2662 return 2;
2664 } else {
2665 /* invalid character */
2666 return 2;
2669 *ochar = c;
2670 *olen = l;
2671 return -1;
2674 static int decode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2675 bool enh_check, uintptr_t ra,
2676 uint32_t *ochar, uint32_t *olen)
2678 uint16_t s0, s1;
2679 uint32_t c, l;
2681 if (ilen < 2) {
2682 return 0;
2684 s0 = cpu_lduw_data_ra(env, addr, ra);
2685 if ((s0 & 0xfc00) != 0xd800) {
2686 /* one word character */
2687 l = 2;
2688 c = s0;
2689 } else {
2690 /* two word character */
2691 l = 4;
2692 if (ilen < 4) {
2693 return 0;
2695 s1 = cpu_lduw_data_ra(env, addr + 2, ra);
2696 c = extract32(s0, 6, 4) + 1;
2697 c = (c << 6) | (s0 & 0x3f);
2698 c = (c << 10) | (s1 & 0x3ff);
2699 if (enh_check && (s1 & 0xfc00) != 0xdc00) {
2700 /* invalid surrogate character */
2701 return 2;
2705 *ochar = c;
2706 *olen = l;
2707 return -1;
2710 static int decode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2711 bool enh_check, uintptr_t ra,
2712 uint32_t *ochar, uint32_t *olen)
2714 uint32_t c;
2716 if (ilen < 4) {
2717 return 0;
2719 c = cpu_ldl_data_ra(env, addr, ra);
2720 if ((c >= 0xd800 && c <= 0xdbff) || c > 0x10ffff) {
2721 /* invalid unicode character */
2722 return 2;
2725 *ochar = c;
2726 *olen = 4;
2727 return -1;
2730 static int encode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2731 uintptr_t ra, uint32_t c, uint32_t *olen)
2733 uint8_t d[4];
2734 uint32_t l, i;
2736 if (c <= 0x7f) {
2737 /* one byte character */
2738 l = 1;
2739 d[0] = c;
2740 } else if (c <= 0x7ff) {
2741 /* two byte character */
2742 l = 2;
2743 d[1] = 0x80 | extract32(c, 0, 6);
2744 d[0] = 0xc0 | extract32(c, 6, 5);
2745 } else if (c <= 0xffff) {
2746 /* three byte character */
2747 l = 3;
2748 d[2] = 0x80 | extract32(c, 0, 6);
2749 d[1] = 0x80 | extract32(c, 6, 6);
2750 d[0] = 0xe0 | extract32(c, 12, 4);
2751 } else {
2752 /* four byte character */
2753 l = 4;
2754 d[3] = 0x80 | extract32(c, 0, 6);
2755 d[2] = 0x80 | extract32(c, 6, 6);
2756 d[1] = 0x80 | extract32(c, 12, 6);
2757 d[0] = 0xf0 | extract32(c, 18, 3);
2760 if (ilen < l) {
2761 return 1;
2763 for (i = 0; i < l; ++i) {
2764 cpu_stb_data_ra(env, addr + i, d[i], ra);
2767 *olen = l;
2768 return -1;
2771 static int encode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2772 uintptr_t ra, uint32_t c, uint32_t *olen)
2774 uint16_t d0, d1;
2776 if (c <= 0xffff) {
2777 /* one word character */
2778 if (ilen < 2) {
2779 return 1;
2781 cpu_stw_data_ra(env, addr, c, ra);
2782 *olen = 2;
2783 } else {
2784 /* two word character */
2785 if (ilen < 4) {
2786 return 1;
2788 d1 = 0xdc00 | extract32(c, 0, 10);
2789 d0 = 0xd800 | extract32(c, 10, 6);
2790 d0 = deposit32(d0, 6, 4, extract32(c, 16, 5) - 1);
2791 cpu_stw_data_ra(env, addr + 0, d0, ra);
2792 cpu_stw_data_ra(env, addr + 2, d1, ra);
2793 *olen = 4;
2796 return -1;
2799 static int encode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2800 uintptr_t ra, uint32_t c, uint32_t *olen)
2802 if (ilen < 4) {
2803 return 1;
2805 cpu_stl_data_ra(env, addr, c, ra);
2806 *olen = 4;
2807 return -1;
2810 static inline uint32_t convert_unicode(CPUS390XState *env, uint32_t r1,
2811 uint32_t r2, uint32_t m3, uintptr_t ra,
2812 decode_unicode_fn decode,
2813 encode_unicode_fn encode)
2815 uint64_t dst = get_address(env, r1);
2816 uint64_t dlen = get_length(env, r1 + 1);
2817 uint64_t src = get_address(env, r2);
2818 uint64_t slen = get_length(env, r2 + 1);
2819 bool enh_check = m3 & 1;
2820 int cc, i;
2822 /* Lest we fail to service interrupts in a timely manner, limit the
2823 amount of work we're willing to do. For now, let's cap at 256. */
2824 for (i = 0; i < 256; ++i) {
2825 uint32_t c, ilen, olen;
2827 cc = decode(env, src, slen, enh_check, ra, &c, &ilen);
2828 if (unlikely(cc >= 0)) {
2829 break;
2831 cc = encode(env, dst, dlen, ra, c, &olen);
2832 if (unlikely(cc >= 0)) {
2833 break;
2836 src += ilen;
2837 slen -= ilen;
2838 dst += olen;
2839 dlen -= olen;
2840 cc = 3;
2843 set_address(env, r1, dst);
2844 set_length(env, r1 + 1, dlen);
2845 set_address(env, r2, src);
2846 set_length(env, r2 + 1, slen);
2848 return cc;
2851 uint32_t HELPER(cu12)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2853 return convert_unicode(env, r1, r2, m3, GETPC(),
2854 decode_utf8, encode_utf16);
2857 uint32_t HELPER(cu14)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2859 return convert_unicode(env, r1, r2, m3, GETPC(),
2860 decode_utf8, encode_utf32);
2863 uint32_t HELPER(cu21)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2865 return convert_unicode(env, r1, r2, m3, GETPC(),
2866 decode_utf16, encode_utf8);
2869 uint32_t HELPER(cu24)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2871 return convert_unicode(env, r1, r2, m3, GETPC(),
2872 decode_utf16, encode_utf32);
2875 uint32_t HELPER(cu41)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2877 return convert_unicode(env, r1, r2, m3, GETPC(),
2878 decode_utf32, encode_utf8);
2881 uint32_t HELPER(cu42)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2883 return convert_unicode(env, r1, r2, m3, GETPC(),
2884 decode_utf32, encode_utf16);
2887 void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
2888 uintptr_t ra)
2890 /* test the actual access, not just any access to the page due to LAP */
2891 while (len) {
2892 const uint64_t pagelen = -(addr | TARGET_PAGE_MASK);
2893 const uint64_t curlen = MIN(pagelen, len);
2895 probe_write(env, addr, curlen, cpu_mmu_index(env, false), ra);
2896 addr = wrap_address(env, addr + curlen);
2897 len -= curlen;
2901 void HELPER(probe_write_access)(CPUS390XState *env, uint64_t addr, uint64_t len)
2903 probe_write_access(env, addr, len, GETPC());