target/s390x: Implement LOAD/STORE TO REAL ADDRESS inline
[qemu/ar7.git] / target / s390x / mem_helper.c
blob2921419c27cd721f0520f5885e89d6b57b8167c2
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"
31 #if !defined(CONFIG_USER_ONLY)
32 #include "hw/s390x/storage-keys.h"
33 #endif
35 /*****************************************************************************/
36 /* Softmmu support */
38 /* #define DEBUG_HELPER */
39 #ifdef DEBUG_HELPER
40 #define HELPER_LOG(x...) qemu_log(x)
41 #else
42 #define HELPER_LOG(x...)
43 #endif
45 static inline bool psw_key_valid(CPUS390XState *env, uint8_t psw_key)
47 uint16_t pkm = env->cregs[3] >> 16;
49 if (env->psw.mask & PSW_MASK_PSTATE) {
50 /* PSW key has range 0..15, it is valid if the bit is 1 in the PKM */
51 return pkm & (0x80 >> psw_key);
53 return true;
56 static bool is_destructive_overlap(CPUS390XState *env, uint64_t dest,
57 uint64_t src, uint32_t len)
59 if (!len || src == dest) {
60 return false;
62 /* Take care of wrapping at the end of address space. */
63 if (unlikely(wrap_address(env, src + len - 1) < src)) {
64 return dest > src || dest <= wrap_address(env, src + len - 1);
66 return dest > src && dest <= src + len - 1;
69 /* Trigger a SPECIFICATION exception if an address or a length is not
70 naturally aligned. */
71 static inline void check_alignment(CPUS390XState *env, uint64_t v,
72 int wordsize, uintptr_t ra)
74 if (v % wordsize) {
75 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
79 /* Load a value from memory according to its size. */
80 static inline uint64_t cpu_ldusize_data_ra(CPUS390XState *env, uint64_t addr,
81 int wordsize, uintptr_t ra)
83 switch (wordsize) {
84 case 1:
85 return cpu_ldub_data_ra(env, addr, ra);
86 case 2:
87 return cpu_lduw_data_ra(env, addr, ra);
88 default:
89 abort();
93 /* Store a to memory according to its size. */
94 static inline void cpu_stsize_data_ra(CPUS390XState *env, uint64_t addr,
95 uint64_t value, int wordsize,
96 uintptr_t ra)
98 switch (wordsize) {
99 case 1:
100 cpu_stb_data_ra(env, addr, value, ra);
101 break;
102 case 2:
103 cpu_stw_data_ra(env, addr, value, ra);
104 break;
105 default:
106 abort();
110 /* An access covers at most 4096 bytes and therefore at most two pages. */
111 typedef struct S390Access {
112 target_ulong vaddr1;
113 target_ulong vaddr2;
114 char *haddr1;
115 char *haddr2;
116 uint16_t size1;
117 uint16_t size2;
119 * If we can't access the host page directly, we'll have to do I/O access
120 * via ld/st helpers. These are internal details, so we store the
121 * mmu idx to do the access here instead of passing it around in the
122 * helpers. Maybe, one day we can get rid of ld/st access - once we can
123 * handle TLB_NOTDIRTY differently. We don't expect these special accesses
124 * to trigger exceptions - only if we would have TLB_NOTDIRTY on LAP
125 * pages, we might trigger a new MMU translation - very unlikely that
126 * the mapping changes in between and we would trigger a fault.
128 int mmu_idx;
129 } S390Access;
131 static S390Access access_prepare(CPUS390XState *env, vaddr vaddr, int size,
132 MMUAccessType access_type, int mmu_idx,
133 uintptr_t ra)
135 S390Access access = {
136 .vaddr1 = vaddr,
137 .size1 = MIN(size, -(vaddr | TARGET_PAGE_MASK)),
138 .mmu_idx = mmu_idx,
141 g_assert(size > 0 && size <= 4096);
142 access.haddr1 = probe_access(env, access.vaddr1, access.size1, access_type,
143 mmu_idx, ra);
145 if (unlikely(access.size1 != size)) {
146 /* The access crosses page boundaries. */
147 access.vaddr2 = wrap_address(env, vaddr + access.size1);
148 access.size2 = size - access.size1;
149 access.haddr2 = probe_access(env, access.vaddr2, access.size2,
150 access_type, mmu_idx, ra);
152 return access;
155 /* Helper to handle memset on a single page. */
156 static void do_access_memset(CPUS390XState *env, vaddr vaddr, char *haddr,
157 uint8_t byte, uint16_t size, int mmu_idx,
158 uintptr_t ra)
160 #ifdef CONFIG_USER_ONLY
161 g_assert(haddr);
162 memset(haddr, byte, size);
163 #else
164 TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
165 int i;
167 if (likely(haddr)) {
168 memset(haddr, byte, size);
169 } else {
171 * Do a single access and test if we can then get access to the
172 * page. This is especially relevant to speed up TLB_NOTDIRTY.
174 g_assert(size > 0);
175 helper_ret_stb_mmu(env, vaddr, byte, oi, ra);
176 haddr = tlb_vaddr_to_host(env, vaddr, MMU_DATA_STORE, mmu_idx);
177 if (likely(haddr)) {
178 memset(haddr + 1, byte, size - 1);
179 } else {
180 for (i = 1; i < size; i++) {
181 helper_ret_stb_mmu(env, vaddr + i, byte, oi, ra);
185 #endif
188 static void access_memset(CPUS390XState *env, S390Access *desta,
189 uint8_t byte, uintptr_t ra)
192 do_access_memset(env, desta->vaddr1, desta->haddr1, byte, desta->size1,
193 desta->mmu_idx, ra);
194 if (likely(!desta->size2)) {
195 return;
197 do_access_memset(env, desta->vaddr2, desta->haddr2, byte, desta->size2,
198 desta->mmu_idx, ra);
201 static uint8_t do_access_get_byte(CPUS390XState *env, vaddr vaddr, char **haddr,
202 int offset, int mmu_idx, uintptr_t ra)
204 #ifdef CONFIG_USER_ONLY
205 return ldub_p(*haddr + offset);
206 #else
207 TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
208 uint8_t byte;
210 if (likely(*haddr)) {
211 return ldub_p(*haddr + offset);
214 * Do a single access and test if we can then get access to the
215 * page. This is especially relevant to speed up TLB_NOTDIRTY.
217 byte = helper_ret_ldub_mmu(env, vaddr + offset, oi, ra);
218 *haddr = tlb_vaddr_to_host(env, vaddr, MMU_DATA_LOAD, mmu_idx);
219 return byte;
220 #endif
223 static uint8_t access_get_byte(CPUS390XState *env, S390Access *access,
224 int offset, uintptr_t ra)
226 if (offset < access->size1) {
227 return do_access_get_byte(env, access->vaddr1, &access->haddr1,
228 offset, access->mmu_idx, ra);
230 return do_access_get_byte(env, access->vaddr2, &access->haddr2,
231 offset - access->size1, access->mmu_idx, ra);
234 static void do_access_set_byte(CPUS390XState *env, vaddr vaddr, char **haddr,
235 int offset, uint8_t byte, int mmu_idx,
236 uintptr_t ra)
238 #ifdef CONFIG_USER_ONLY
239 stb_p(*haddr + offset, byte);
240 #else
241 TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
243 if (likely(*haddr)) {
244 stb_p(*haddr + offset, byte);
245 return;
248 * Do a single access and test if we can then get access to the
249 * page. This is especially relevant to speed up TLB_NOTDIRTY.
251 helper_ret_stb_mmu(env, vaddr + offset, byte, oi, ra);
252 *haddr = tlb_vaddr_to_host(env, vaddr, MMU_DATA_STORE, mmu_idx);
253 #endif
256 static void access_set_byte(CPUS390XState *env, S390Access *access,
257 int offset, uint8_t byte, uintptr_t ra)
259 if (offset < access->size1) {
260 do_access_set_byte(env, access->vaddr1, &access->haddr1, offset, byte,
261 access->mmu_idx, ra);
262 } else {
263 do_access_set_byte(env, access->vaddr2, &access->haddr2,
264 offset - access->size1, byte, access->mmu_idx, ra);
269 * Move data with the same semantics as memmove() in case ranges don't overlap
270 * or src > dest. Undefined behavior on destructive overlaps.
272 static void access_memmove(CPUS390XState *env, S390Access *desta,
273 S390Access *srca, uintptr_t ra)
275 int diff;
277 g_assert(desta->size1 + desta->size2 == srca->size1 + srca->size2);
279 /* Fallback to slow access in case we don't have access to all host pages */
280 if (unlikely(!desta->haddr1 || (desta->size2 && !desta->haddr2) ||
281 !srca->haddr1 || (srca->size2 && !srca->haddr2))) {
282 int i;
284 for (i = 0; i < desta->size1 + desta->size2; i++) {
285 uint8_t byte = access_get_byte(env, srca, i, ra);
287 access_set_byte(env, desta, i, byte, ra);
289 return;
292 if (srca->size1 == desta->size1) {
293 memmove(desta->haddr1, srca->haddr1, srca->size1);
294 if (unlikely(srca->size2)) {
295 memmove(desta->haddr2, srca->haddr2, srca->size2);
297 } else if (srca->size1 < desta->size1) {
298 diff = desta->size1 - srca->size1;
299 memmove(desta->haddr1, srca->haddr1, srca->size1);
300 memmove(desta->haddr1 + srca->size1, srca->haddr2, diff);
301 if (likely(desta->size2)) {
302 memmove(desta->haddr2, srca->haddr2 + diff, desta->size2);
304 } else {
305 diff = srca->size1 - desta->size1;
306 memmove(desta->haddr1, srca->haddr1, desta->size1);
307 memmove(desta->haddr2, srca->haddr1 + desta->size1, diff);
308 if (likely(srca->size2)) {
309 memmove(desta->haddr2 + diff, srca->haddr2, srca->size2);
314 static int mmu_idx_from_as(uint8_t as)
316 switch (as) {
317 case AS_PRIMARY:
318 return MMU_PRIMARY_IDX;
319 case AS_SECONDARY:
320 return MMU_SECONDARY_IDX;
321 case AS_HOME:
322 return MMU_HOME_IDX;
323 default:
324 /* FIXME AS_ACCREG */
325 g_assert_not_reached();
329 /* and on array */
330 static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest,
331 uint64_t src, uintptr_t ra)
333 const int mmu_idx = cpu_mmu_index(env, false);
334 S390Access srca1, srca2, desta;
335 uint32_t i;
336 uint8_t c = 0;
338 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
339 __func__, l, dest, src);
341 /* NC always processes one more byte than specified - maximum is 256 */
342 l++;
344 srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
345 srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
346 desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
347 for (i = 0; i < l; i++) {
348 const uint8_t x = access_get_byte(env, &srca1, i, ra) &
349 access_get_byte(env, &srca2, i, ra);
351 c |= x;
352 access_set_byte(env, &desta, i, x, ra);
354 return c != 0;
357 uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
358 uint64_t src)
360 return do_helper_nc(env, l, dest, src, GETPC());
363 /* xor on array */
364 static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest,
365 uint64_t src, uintptr_t ra)
367 const int mmu_idx = cpu_mmu_index(env, false);
368 S390Access srca1, srca2, desta;
369 uint32_t i;
370 uint8_t c = 0;
372 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
373 __func__, l, dest, src);
375 /* XC always processes one more byte than specified - maximum is 256 */
376 l++;
378 srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
379 srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
380 desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
382 /* xor with itself is the same as memset(0) */
383 if (src == dest) {
384 access_memset(env, &desta, 0, ra);
385 return 0;
388 for (i = 0; i < l; i++) {
389 const uint8_t x = access_get_byte(env, &srca1, i, ra) ^
390 access_get_byte(env, &srca2, i, ra);
392 c |= x;
393 access_set_byte(env, &desta, i, x, ra);
395 return c != 0;
398 uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
399 uint64_t src)
401 return do_helper_xc(env, l, dest, src, GETPC());
404 /* or on array */
405 static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest,
406 uint64_t src, uintptr_t ra)
408 const int mmu_idx = cpu_mmu_index(env, false);
409 S390Access srca1, srca2, desta;
410 uint32_t i;
411 uint8_t c = 0;
413 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
414 __func__, l, dest, src);
416 /* OC always processes one more byte than specified - maximum is 256 */
417 l++;
419 srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
420 srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
421 desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
422 for (i = 0; i < l; i++) {
423 const uint8_t x = access_get_byte(env, &srca1, i, ra) |
424 access_get_byte(env, &srca2, i, ra);
426 c |= x;
427 access_set_byte(env, &desta, i, x, ra);
429 return c != 0;
432 uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
433 uint64_t src)
435 return do_helper_oc(env, l, dest, src, GETPC());
438 /* memmove */
439 static uint32_t do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest,
440 uint64_t src, uintptr_t ra)
442 const int mmu_idx = cpu_mmu_index(env, false);
443 S390Access srca, desta;
444 uint32_t i;
446 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
447 __func__, l, dest, src);
449 /* MVC always copies one more byte than specified - maximum is 256 */
450 l++;
452 srca = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
453 desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
456 * "When the operands overlap, the result is obtained as if the operands
457 * were processed one byte at a time". Only non-destructive overlaps
458 * behave like memmove().
460 if (dest == src + 1) {
461 access_memset(env, &desta, access_get_byte(env, &srca, 0, ra), ra);
462 } else if (!is_destructive_overlap(env, dest, src, l)) {
463 access_memmove(env, &desta, &srca, ra);
464 } else {
465 for (i = 0; i < l; i++) {
466 uint8_t byte = access_get_byte(env, &srca, i, ra);
468 access_set_byte(env, &desta, i, byte, ra);
472 return env->cc_op;
475 void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
477 do_helper_mvc(env, l, dest, src, GETPC());
480 /* move inverse */
481 void HELPER(mvcin)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
483 const int mmu_idx = cpu_mmu_index(env, false);
484 S390Access srca, desta;
485 uintptr_t ra = GETPC();
486 int i;
488 /* MVCIN always copies one more byte than specified - maximum is 256 */
489 l++;
491 src = wrap_address(env, src - l + 1);
492 srca = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
493 desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
494 for (i = 0; i < l; i++) {
495 const uint8_t x = access_get_byte(env, &srca, l - i - 1, ra);
497 access_set_byte(env, &desta, i, x, ra);
501 /* move numerics */
502 void HELPER(mvn)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
504 const int mmu_idx = cpu_mmu_index(env, false);
505 S390Access srca1, srca2, desta;
506 uintptr_t ra = GETPC();
507 int i;
509 /* MVN always copies one more byte than specified - maximum is 256 */
510 l++;
512 srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
513 srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
514 desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
515 for (i = 0; i < l; i++) {
516 const uint8_t x = (access_get_byte(env, &srca1, i, ra) & 0x0f) |
517 (access_get_byte(env, &srca2, i, ra) & 0xf0);
519 access_set_byte(env, &desta, i, x, ra);
523 /* move with offset */
524 void HELPER(mvo)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
526 const int mmu_idx = cpu_mmu_index(env, false);
527 /* MVO always processes one more byte than specified - maximum is 16 */
528 const int len_dest = (l >> 4) + 1;
529 const int len_src = (l & 0xf) + 1;
530 uintptr_t ra = GETPC();
531 uint8_t byte_dest, byte_src;
532 S390Access srca, desta;
533 int i, j;
535 srca = access_prepare(env, src, len_src, MMU_DATA_LOAD, mmu_idx, ra);
536 desta = access_prepare(env, dest, len_dest, MMU_DATA_STORE, mmu_idx, ra);
538 /* Handle rightmost byte */
539 byte_dest = cpu_ldub_data_ra(env, dest + len_dest - 1, ra);
540 byte_src = access_get_byte(env, &srca, len_src - 1, ra);
541 byte_dest = (byte_dest & 0x0f) | (byte_src << 4);
542 access_set_byte(env, &desta, len_dest - 1, byte_dest, ra);
544 /* Process remaining bytes from right to left */
545 for (i = len_dest - 2, j = len_src - 2; i >= 0; i--, j--) {
546 byte_dest = byte_src >> 4;
547 if (j >= 0) {
548 byte_src = access_get_byte(env, &srca, j, ra);
549 } else {
550 byte_src = 0;
552 byte_dest |= byte_src << 4;
553 access_set_byte(env, &desta, i, byte_dest, ra);
557 /* move zones */
558 void HELPER(mvz)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
560 const int mmu_idx = cpu_mmu_index(env, false);
561 S390Access srca1, srca2, desta;
562 uintptr_t ra = GETPC();
563 int i;
565 /* MVZ always copies one more byte than specified - maximum is 256 */
566 l++;
568 srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
569 srca2 = access_prepare(env, dest, 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, &srca1, i, ra) & 0xf0) |
573 (access_get_byte(env, &srca2, i, ra) & 0x0f);
575 access_set_byte(env, &desta, i, x, ra);
579 /* compare unsigned byte arrays */
580 static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1,
581 uint64_t s2, uintptr_t ra)
583 uint32_t i;
584 uint32_t cc = 0;
586 HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
587 __func__, l, s1, s2);
589 for (i = 0; i <= l; i++) {
590 uint8_t x = cpu_ldub_data_ra(env, s1 + i, ra);
591 uint8_t y = cpu_ldub_data_ra(env, s2 + i, ra);
592 HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
593 if (x < y) {
594 cc = 1;
595 break;
596 } else if (x > y) {
597 cc = 2;
598 break;
602 HELPER_LOG("\n");
603 return cc;
606 uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2)
608 return do_helper_clc(env, l, s1, s2, GETPC());
611 /* compare logical under mask */
612 uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
613 uint64_t addr)
615 uintptr_t ra = GETPC();
616 uint32_t cc = 0;
618 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
619 mask, addr);
621 while (mask) {
622 if (mask & 8) {
623 uint8_t d = cpu_ldub_data_ra(env, addr, ra);
624 uint8_t r = extract32(r1, 24, 8);
625 HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
626 addr);
627 if (r < d) {
628 cc = 1;
629 break;
630 } else if (r > d) {
631 cc = 2;
632 break;
634 addr++;
636 mask = (mask << 1) & 0xf;
637 r1 <<= 8;
640 HELPER_LOG("\n");
641 return cc;
644 static inline uint64_t get_address(CPUS390XState *env, int reg)
646 return wrap_address(env, env->regs[reg]);
650 * Store the address to the given register, zeroing out unused leftmost
651 * bits in bit positions 32-63 (24-bit and 31-bit mode only).
653 static inline void set_address_zero(CPUS390XState *env, int reg,
654 uint64_t address)
656 if (env->psw.mask & PSW_MASK_64) {
657 env->regs[reg] = address;
658 } else {
659 if (!(env->psw.mask & PSW_MASK_32)) {
660 address &= 0x00ffffff;
661 } else {
662 address &= 0x7fffffff;
664 env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
668 static inline void set_address(CPUS390XState *env, int reg, uint64_t address)
670 if (env->psw.mask & PSW_MASK_64) {
671 /* 64-Bit mode */
672 env->regs[reg] = address;
673 } else {
674 if (!(env->psw.mask & PSW_MASK_32)) {
675 /* 24-Bit mode. According to the PoO it is implementation
676 dependent if bits 32-39 remain unchanged or are set to
677 zeros. Choose the former so that the function can also be
678 used for TRT. */
679 env->regs[reg] = deposit64(env->regs[reg], 0, 24, address);
680 } else {
681 /* 31-Bit mode. According to the PoO it is implementation
682 dependent if bit 32 remains unchanged or is set to zero.
683 Choose the latter so that the function can also be used for
684 TRT. */
685 address &= 0x7fffffff;
686 env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
691 static inline uint64_t wrap_length32(CPUS390XState *env, uint64_t length)
693 if (!(env->psw.mask & PSW_MASK_64)) {
694 return (uint32_t)length;
696 return length;
699 static inline uint64_t wrap_length31(CPUS390XState *env, uint64_t length)
701 if (!(env->psw.mask & PSW_MASK_64)) {
702 /* 24-Bit and 31-Bit mode */
703 length &= 0x7fffffff;
705 return length;
708 static inline uint64_t get_length(CPUS390XState *env, int reg)
710 return wrap_length31(env, env->regs[reg]);
713 static inline void set_length(CPUS390XState *env, int reg, uint64_t length)
715 if (env->psw.mask & PSW_MASK_64) {
716 /* 64-Bit mode */
717 env->regs[reg] = length;
718 } else {
719 /* 24-Bit and 31-Bit mode */
720 env->regs[reg] = deposit64(env->regs[reg], 0, 32, length);
724 /* search string (c is byte to search, r2 is string, r1 end of string) */
725 void HELPER(srst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
727 uintptr_t ra = GETPC();
728 uint64_t end, str;
729 uint32_t len;
730 uint8_t v, c = env->regs[0];
732 /* Bits 32-55 must contain all 0. */
733 if (env->regs[0] & 0xffffff00u) {
734 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
737 str = get_address(env, r2);
738 end = get_address(env, r1);
740 /* Lest we fail to service interrupts in a timely manner, limit the
741 amount of work we're willing to do. For now, let's cap at 8k. */
742 for (len = 0; len < 0x2000; ++len) {
743 if (str + len == end) {
744 /* Character not found. R1 & R2 are unmodified. */
745 env->cc_op = 2;
746 return;
748 v = cpu_ldub_data_ra(env, str + len, ra);
749 if (v == c) {
750 /* Character found. Set R1 to the location; R2 is unmodified. */
751 env->cc_op = 1;
752 set_address(env, r1, str + len);
753 return;
757 /* CPU-determined bytes processed. Advance R2 to next byte to process. */
758 env->cc_op = 3;
759 set_address(env, r2, str + len);
762 void HELPER(srstu)(CPUS390XState *env, uint32_t r1, uint32_t r2)
764 uintptr_t ra = GETPC();
765 uint32_t len;
766 uint16_t v, c = env->regs[0];
767 uint64_t end, str, adj_end;
769 /* Bits 32-47 of R0 must be zero. */
770 if (env->regs[0] & 0xffff0000u) {
771 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
774 str = get_address(env, r2);
775 end = get_address(env, r1);
777 /* If the LSB of the two addresses differ, use one extra byte. */
778 adj_end = end + ((str ^ end) & 1);
780 /* Lest we fail to service interrupts in a timely manner, limit the
781 amount of work we're willing to do. For now, let's cap at 8k. */
782 for (len = 0; len < 0x2000; len += 2) {
783 if (str + len == adj_end) {
784 /* End of input found. */
785 env->cc_op = 2;
786 return;
788 v = cpu_lduw_data_ra(env, str + len, ra);
789 if (v == c) {
790 /* Character found. Set R1 to the location; R2 is unmodified. */
791 env->cc_op = 1;
792 set_address(env, r1, str + len);
793 return;
797 /* CPU-determined bytes processed. Advance R2 to next byte to process. */
798 env->cc_op = 3;
799 set_address(env, r2, str + len);
802 /* unsigned string compare (c is string terminator) */
803 uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
805 uintptr_t ra = GETPC();
806 uint32_t len;
808 c = c & 0xff;
809 s1 = wrap_address(env, s1);
810 s2 = wrap_address(env, s2);
812 /* Lest we fail to service interrupts in a timely manner, limit the
813 amount of work we're willing to do. For now, let's cap at 8k. */
814 for (len = 0; len < 0x2000; ++len) {
815 uint8_t v1 = cpu_ldub_data_ra(env, s1 + len, ra);
816 uint8_t v2 = cpu_ldub_data_ra(env, s2 + len, ra);
817 if (v1 == v2) {
818 if (v1 == c) {
819 /* Equal. CC=0, and don't advance the registers. */
820 env->cc_op = 0;
821 env->retxl = s2;
822 return s1;
824 } else {
825 /* Unequal. CC={1,2}, and advance the registers. Note that
826 the terminator need not be zero, but the string that contains
827 the terminator is by definition "low". */
828 env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2);
829 env->retxl = s2 + len;
830 return s1 + len;
834 /* CPU-determined bytes equal; advance the registers. */
835 env->cc_op = 3;
836 env->retxl = s2 + len;
837 return s1 + len;
840 /* move page */
841 uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
843 const int mmu_idx = cpu_mmu_index(env, false);
844 const bool f = extract64(r0, 11, 1);
845 const bool s = extract64(r0, 10, 1);
846 uintptr_t ra = GETPC();
847 S390Access srca, desta;
849 if ((f && s) || extract64(r0, 12, 4)) {
850 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
853 r1 = wrap_address(env, r1 & TARGET_PAGE_MASK);
854 r2 = wrap_address(env, r2 & TARGET_PAGE_MASK);
857 * TODO:
858 * - Access key handling
859 * - CC-option with surpression of page-translation exceptions
860 * - Store r1/r2 register identifiers at real location 162
862 srca = access_prepare(env, r2, TARGET_PAGE_SIZE, MMU_DATA_LOAD, mmu_idx,
863 ra);
864 desta = access_prepare(env, r1, TARGET_PAGE_SIZE, MMU_DATA_STORE, mmu_idx,
865 ra);
866 access_memmove(env, &desta, &srca, ra);
867 return 0; /* data moved */
870 /* string copy */
871 uint32_t HELPER(mvst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
873 const int mmu_idx = cpu_mmu_index(env, false);
874 const uint64_t d = get_address(env, r1);
875 const uint64_t s = get_address(env, r2);
876 const uint8_t c = env->regs[0];
877 const int len = MIN(-(d | TARGET_PAGE_MASK), -(s | TARGET_PAGE_MASK));
878 S390Access srca, desta;
879 uintptr_t ra = GETPC();
880 int i;
882 if (env->regs[0] & 0xffffff00ull) {
883 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
887 * Our access should not exceed single pages, as we must not report access
888 * exceptions exceeding the actually copied range (which we don't know at
889 * this point). We might over-indicate watchpoints within the pages
890 * (if we ever care, we have to limit processing to a single byte).
892 srca = access_prepare(env, s, len, MMU_DATA_LOAD, mmu_idx, ra);
893 desta = access_prepare(env, d, len, MMU_DATA_STORE, mmu_idx, ra);
894 for (i = 0; i < len; i++) {
895 const uint8_t v = access_get_byte(env, &srca, i, ra);
897 access_set_byte(env, &desta, i, v, ra);
898 if (v == c) {
899 set_address_zero(env, r1, d + i);
900 return 1;
903 set_address_zero(env, r1, d + len);
904 set_address_zero(env, r2, s + len);
905 return 3;
908 /* load access registers r1 to r3 from memory at a2 */
909 void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
911 uintptr_t ra = GETPC();
912 int i;
914 if (a2 & 0x3) {
915 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
918 for (i = r1;; i = (i + 1) % 16) {
919 env->aregs[i] = cpu_ldl_data_ra(env, a2, ra);
920 a2 += 4;
922 if (i == r3) {
923 break;
928 /* store access registers r1 to r3 in memory at a2 */
929 void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
931 uintptr_t ra = GETPC();
932 int i;
934 if (a2 & 0x3) {
935 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
938 for (i = r1;; i = (i + 1) % 16) {
939 cpu_stl_data_ra(env, a2, env->aregs[i], ra);
940 a2 += 4;
942 if (i == r3) {
943 break;
948 /* move long helper */
949 static inline uint32_t do_mvcl(CPUS390XState *env,
950 uint64_t *dest, uint64_t *destlen,
951 uint64_t *src, uint64_t *srclen,
952 uint16_t pad, int wordsize, uintptr_t ra)
954 const int mmu_idx = cpu_mmu_index(env, false);
955 int len = MIN(*destlen, -(*dest | TARGET_PAGE_MASK));
956 S390Access srca, desta;
957 int i, cc;
959 if (*destlen == *srclen) {
960 cc = 0;
961 } else if (*destlen < *srclen) {
962 cc = 1;
963 } else {
964 cc = 2;
967 if (!*destlen) {
968 return cc;
972 * Only perform one type of type of operation (move/pad) at a time.
973 * Stay within single pages.
975 if (*srclen) {
976 /* Copy the src array */
977 len = MIN(MIN(*srclen, -(*src | TARGET_PAGE_MASK)), len);
978 *destlen -= len;
979 *srclen -= len;
980 srca = access_prepare(env, *src, len, MMU_DATA_LOAD, mmu_idx, ra);
981 desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
982 access_memmove(env, &desta, &srca, ra);
983 *src = wrap_address(env, *src + len);
984 *dest = wrap_address(env, *dest + len);
985 } else if (wordsize == 1) {
986 /* Pad the remaining area */
987 *destlen -= len;
988 desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
989 access_memset(env, &desta, pad, ra);
990 *dest = wrap_address(env, *dest + len);
991 } else {
992 desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
994 /* The remaining length selects the padding byte. */
995 for (i = 0; i < len; (*destlen)--, i++) {
996 if (*destlen & 1) {
997 access_set_byte(env, &desta, i, pad, ra);
998 } else {
999 access_set_byte(env, &desta, i, pad >> 8, ra);
1002 *dest = wrap_address(env, *dest + len);
1005 return *destlen ? 3 : cc;
1008 /* move long */
1009 uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
1011 const int mmu_idx = cpu_mmu_index(env, false);
1012 uintptr_t ra = GETPC();
1013 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
1014 uint64_t dest = get_address(env, r1);
1015 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
1016 uint64_t src = get_address(env, r2);
1017 uint8_t pad = env->regs[r2 + 1] >> 24;
1018 CPUState *cs = env_cpu(env);
1019 S390Access srca, desta;
1020 uint32_t cc, cur_len;
1022 if (is_destructive_overlap(env, dest, src, MIN(srclen, destlen))) {
1023 cc = 3;
1024 } else if (srclen == destlen) {
1025 cc = 0;
1026 } else if (destlen < srclen) {
1027 cc = 1;
1028 } else {
1029 cc = 2;
1032 /* We might have to zero-out some bits even if there was no action. */
1033 if (unlikely(!destlen || cc == 3)) {
1034 set_address_zero(env, r2, src);
1035 set_address_zero(env, r1, dest);
1036 return cc;
1037 } else if (!srclen) {
1038 set_address_zero(env, r2, src);
1042 * Only perform one type of type of operation (move/pad) in one step.
1043 * Stay within single pages.
1045 while (destlen) {
1046 cur_len = MIN(destlen, -(dest | TARGET_PAGE_MASK));
1047 if (!srclen) {
1048 desta = access_prepare(env, dest, cur_len, MMU_DATA_STORE, mmu_idx,
1049 ra);
1050 access_memset(env, &desta, pad, ra);
1051 } else {
1052 cur_len = MIN(MIN(srclen, -(src | TARGET_PAGE_MASK)), cur_len);
1054 srca = access_prepare(env, src, cur_len, MMU_DATA_LOAD, mmu_idx,
1055 ra);
1056 desta = access_prepare(env, dest, cur_len, MMU_DATA_STORE, mmu_idx,
1057 ra);
1058 access_memmove(env, &desta, &srca, ra);
1059 src = wrap_address(env, src + cur_len);
1060 srclen -= cur_len;
1061 env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, srclen);
1062 set_address_zero(env, r2, src);
1064 dest = wrap_address(env, dest + cur_len);
1065 destlen -= cur_len;
1066 env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, destlen);
1067 set_address_zero(env, r1, dest);
1070 * MVCL is interruptible. Return to the main loop if requested after
1071 * writing back all state to registers. If no interrupt will get
1072 * injected, we'll end up back in this handler and continue processing
1073 * the remaining parts.
1075 if (destlen && unlikely(cpu_loop_exit_requested(cs))) {
1076 cpu_loop_exit_restore(cs, ra);
1079 return cc;
1082 /* move long extended */
1083 uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1084 uint32_t r3)
1086 uintptr_t ra = GETPC();
1087 uint64_t destlen = get_length(env, r1 + 1);
1088 uint64_t dest = get_address(env, r1);
1089 uint64_t srclen = get_length(env, r3 + 1);
1090 uint64_t src = get_address(env, r3);
1091 uint8_t pad = a2;
1092 uint32_t cc;
1094 cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra);
1096 set_length(env, r1 + 1, destlen);
1097 set_length(env, r3 + 1, srclen);
1098 set_address(env, r1, dest);
1099 set_address(env, r3, src);
1101 return cc;
1104 /* move long unicode */
1105 uint32_t HELPER(mvclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1106 uint32_t r3)
1108 uintptr_t ra = GETPC();
1109 uint64_t destlen = get_length(env, r1 + 1);
1110 uint64_t dest = get_address(env, r1);
1111 uint64_t srclen = get_length(env, r3 + 1);
1112 uint64_t src = get_address(env, r3);
1113 uint16_t pad = a2;
1114 uint32_t cc;
1116 cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 2, ra);
1118 set_length(env, r1 + 1, destlen);
1119 set_length(env, r3 + 1, srclen);
1120 set_address(env, r1, dest);
1121 set_address(env, r3, src);
1123 return cc;
1126 /* compare logical long helper */
1127 static inline uint32_t do_clcl(CPUS390XState *env,
1128 uint64_t *src1, uint64_t *src1len,
1129 uint64_t *src3, uint64_t *src3len,
1130 uint16_t pad, uint64_t limit,
1131 int wordsize, uintptr_t ra)
1133 uint64_t len = MAX(*src1len, *src3len);
1134 uint32_t cc = 0;
1136 check_alignment(env, *src1len | *src3len, wordsize, ra);
1138 if (!len) {
1139 return cc;
1142 /* Lest we fail to service interrupts in a timely manner, limit the
1143 amount of work we're willing to do. */
1144 if (len > limit) {
1145 len = limit;
1146 cc = 3;
1149 for (; len; len -= wordsize) {
1150 uint16_t v1 = pad;
1151 uint16_t v3 = pad;
1153 if (*src1len) {
1154 v1 = cpu_ldusize_data_ra(env, *src1, wordsize, ra);
1156 if (*src3len) {
1157 v3 = cpu_ldusize_data_ra(env, *src3, wordsize, ra);
1160 if (v1 != v3) {
1161 cc = (v1 < v3) ? 1 : 2;
1162 break;
1165 if (*src1len) {
1166 *src1 += wordsize;
1167 *src1len -= wordsize;
1169 if (*src3len) {
1170 *src3 += wordsize;
1171 *src3len -= wordsize;
1175 return cc;
1179 /* compare logical long */
1180 uint32_t HELPER(clcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
1182 uintptr_t ra = GETPC();
1183 uint64_t src1len = extract64(env->regs[r1 + 1], 0, 24);
1184 uint64_t src1 = get_address(env, r1);
1185 uint64_t src3len = extract64(env->regs[r2 + 1], 0, 24);
1186 uint64_t src3 = get_address(env, r2);
1187 uint8_t pad = env->regs[r2 + 1] >> 24;
1188 uint32_t cc;
1190 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, -1, 1, ra);
1192 env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, src1len);
1193 env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, src3len);
1194 set_address(env, r1, src1);
1195 set_address(env, r2, src3);
1197 return cc;
1200 /* compare logical long extended memcompare insn with padding */
1201 uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1202 uint32_t r3)
1204 uintptr_t ra = GETPC();
1205 uint64_t src1len = get_length(env, r1 + 1);
1206 uint64_t src1 = get_address(env, r1);
1207 uint64_t src3len = get_length(env, r3 + 1);
1208 uint64_t src3 = get_address(env, r3);
1209 uint8_t pad = a2;
1210 uint32_t cc;
1212 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x2000, 1, ra);
1214 set_length(env, r1 + 1, src1len);
1215 set_length(env, r3 + 1, src3len);
1216 set_address(env, r1, src1);
1217 set_address(env, r3, src3);
1219 return cc;
1222 /* compare logical long unicode memcompare insn with padding */
1223 uint32_t HELPER(clclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1224 uint32_t r3)
1226 uintptr_t ra = GETPC();
1227 uint64_t src1len = get_length(env, r1 + 1);
1228 uint64_t src1 = get_address(env, r1);
1229 uint64_t src3len = get_length(env, r3 + 1);
1230 uint64_t src3 = get_address(env, r3);
1231 uint16_t pad = a2;
1232 uint32_t cc = 0;
1234 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x1000, 2, ra);
1236 set_length(env, r1 + 1, src1len);
1237 set_length(env, r3 + 1, src3len);
1238 set_address(env, r1, src1);
1239 set_address(env, r3, src3);
1241 return cc;
1244 /* checksum */
1245 uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
1246 uint64_t src, uint64_t src_len)
1248 uintptr_t ra = GETPC();
1249 uint64_t max_len, len;
1250 uint64_t cksm = (uint32_t)r1;
1252 /* Lest we fail to service interrupts in a timely manner, limit the
1253 amount of work we're willing to do. For now, let's cap at 8k. */
1254 max_len = (src_len > 0x2000 ? 0x2000 : src_len);
1256 /* Process full words as available. */
1257 for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
1258 cksm += (uint32_t)cpu_ldl_data_ra(env, src, ra);
1261 switch (max_len - len) {
1262 case 1:
1263 cksm += cpu_ldub_data_ra(env, src, ra) << 24;
1264 len += 1;
1265 break;
1266 case 2:
1267 cksm += cpu_lduw_data_ra(env, src, ra) << 16;
1268 len += 2;
1269 break;
1270 case 3:
1271 cksm += cpu_lduw_data_ra(env, src, ra) << 16;
1272 cksm += cpu_ldub_data_ra(env, src + 2, ra) << 8;
1273 len += 3;
1274 break;
1277 /* Fold the carry from the checksum. Note that we can see carry-out
1278 during folding more than once (but probably not more than twice). */
1279 while (cksm > 0xffffffffull) {
1280 cksm = (uint32_t)cksm + (cksm >> 32);
1283 /* Indicate whether or not we've processed everything. */
1284 env->cc_op = (len == src_len ? 0 : 3);
1286 /* Return both cksm and processed length. */
1287 env->retxl = cksm;
1288 return len;
1291 void HELPER(pack)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src)
1293 uintptr_t ra = GETPC();
1294 int len_dest = len >> 4;
1295 int len_src = len & 0xf;
1296 uint8_t b;
1298 dest += len_dest;
1299 src += len_src;
1301 /* last byte is special, it only flips the nibbles */
1302 b = cpu_ldub_data_ra(env, src, ra);
1303 cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
1304 src--;
1305 len_src--;
1307 /* now pack every value */
1308 while (len_dest > 0) {
1309 b = 0;
1311 if (len_src >= 0) {
1312 b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
1313 src--;
1314 len_src--;
1316 if (len_src >= 0) {
1317 b |= cpu_ldub_data_ra(env, src, ra) << 4;
1318 src--;
1319 len_src--;
1322 len_dest--;
1323 dest--;
1324 cpu_stb_data_ra(env, dest, b, ra);
1328 static inline void do_pkau(CPUS390XState *env, uint64_t dest, uint64_t src,
1329 uint32_t srclen, int ssize, uintptr_t ra)
1331 int i;
1332 /* The destination operand is always 16 bytes long. */
1333 const int destlen = 16;
1335 /* The operands are processed from right to left. */
1336 src += srclen - 1;
1337 dest += destlen - 1;
1339 for (i = 0; i < destlen; i++) {
1340 uint8_t b = 0;
1342 /* Start with a positive sign */
1343 if (i == 0) {
1344 b = 0xc;
1345 } else if (srclen > ssize) {
1346 b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
1347 src -= ssize;
1348 srclen -= ssize;
1351 if (srclen > ssize) {
1352 b |= cpu_ldub_data_ra(env, src, ra) << 4;
1353 src -= ssize;
1354 srclen -= ssize;
1357 cpu_stb_data_ra(env, dest, b, ra);
1358 dest--;
1363 void HELPER(pka)(CPUS390XState *env, uint64_t dest, uint64_t src,
1364 uint32_t srclen)
1366 do_pkau(env, dest, src, srclen, 1, GETPC());
1369 void HELPER(pku)(CPUS390XState *env, uint64_t dest, uint64_t src,
1370 uint32_t srclen)
1372 do_pkau(env, dest, src, srclen, 2, GETPC());
1375 void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
1376 uint64_t src)
1378 uintptr_t ra = GETPC();
1379 int len_dest = len >> 4;
1380 int len_src = len & 0xf;
1381 uint8_t b;
1382 int second_nibble = 0;
1384 dest += len_dest;
1385 src += len_src;
1387 /* last byte is special, it only flips the nibbles */
1388 b = cpu_ldub_data_ra(env, src, ra);
1389 cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
1390 src--;
1391 len_src--;
1393 /* now pad every nibble with 0xf0 */
1395 while (len_dest > 0) {
1396 uint8_t cur_byte = 0;
1398 if (len_src > 0) {
1399 cur_byte = cpu_ldub_data_ra(env, src, ra);
1402 len_dest--;
1403 dest--;
1405 /* only advance one nibble at a time */
1406 if (second_nibble) {
1407 cur_byte >>= 4;
1408 len_src--;
1409 src--;
1411 second_nibble = !second_nibble;
1413 /* digit */
1414 cur_byte = (cur_byte & 0xf);
1415 /* zone bits */
1416 cur_byte |= 0xf0;
1418 cpu_stb_data_ra(env, dest, cur_byte, ra);
1422 static inline uint32_t do_unpkau(CPUS390XState *env, uint64_t dest,
1423 uint32_t destlen, int dsize, uint64_t src,
1424 uintptr_t ra)
1426 int i;
1427 uint32_t cc;
1428 uint8_t b;
1429 /* The source operand is always 16 bytes long. */
1430 const int srclen = 16;
1432 /* The operands are processed from right to left. */
1433 src += srclen - 1;
1434 dest += destlen - dsize;
1436 /* Check for the sign. */
1437 b = cpu_ldub_data_ra(env, src, ra);
1438 src--;
1439 switch (b & 0xf) {
1440 case 0xa:
1441 case 0xc:
1442 case 0xe ... 0xf:
1443 cc = 0; /* plus */
1444 break;
1445 case 0xb:
1446 case 0xd:
1447 cc = 1; /* minus */
1448 break;
1449 default:
1450 case 0x0 ... 0x9:
1451 cc = 3; /* invalid */
1452 break;
1455 /* Now pad every nibble with 0x30, advancing one nibble at a time. */
1456 for (i = 0; i < destlen; i += dsize) {
1457 if (i == (31 * dsize)) {
1458 /* If length is 32/64 bytes, the leftmost byte is 0. */
1459 b = 0;
1460 } else if (i % (2 * dsize)) {
1461 b = cpu_ldub_data_ra(env, src, ra);
1462 src--;
1463 } else {
1464 b >>= 4;
1466 cpu_stsize_data_ra(env, dest, 0x30 + (b & 0xf), dsize, ra);
1467 dest -= dsize;
1470 return cc;
1473 uint32_t HELPER(unpka)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1474 uint64_t src)
1476 return do_unpkau(env, dest, destlen, 1, src, GETPC());
1479 uint32_t HELPER(unpku)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1480 uint64_t src)
1482 return do_unpkau(env, dest, destlen, 2, src, GETPC());
1485 uint32_t HELPER(tp)(CPUS390XState *env, uint64_t dest, uint32_t destlen)
1487 uintptr_t ra = GETPC();
1488 uint32_t cc = 0;
1489 int i;
1491 for (i = 0; i < destlen; i++) {
1492 uint8_t b = cpu_ldub_data_ra(env, dest + i, ra);
1493 /* digit */
1494 cc |= (b & 0xf0) > 0x90 ? 2 : 0;
1496 if (i == (destlen - 1)) {
1497 /* sign */
1498 cc |= (b & 0xf) < 0xa ? 1 : 0;
1499 } else {
1500 /* digit */
1501 cc |= (b & 0xf) > 0x9 ? 2 : 0;
1505 return cc;
1508 static uint32_t do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array,
1509 uint64_t trans, uintptr_t ra)
1511 uint32_t i;
1513 for (i = 0; i <= len; i++) {
1514 uint8_t byte = cpu_ldub_data_ra(env, array + i, ra);
1515 uint8_t new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
1516 cpu_stb_data_ra(env, array + i, new_byte, ra);
1519 return env->cc_op;
1522 void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
1523 uint64_t trans)
1525 do_helper_tr(env, len, array, trans, GETPC());
1528 uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array,
1529 uint64_t len, uint64_t trans)
1531 uintptr_t ra = GETPC();
1532 uint8_t end = env->regs[0] & 0xff;
1533 uint64_t l = len;
1534 uint64_t i;
1535 uint32_t cc = 0;
1537 if (!(env->psw.mask & PSW_MASK_64)) {
1538 array &= 0x7fffffff;
1539 l = (uint32_t)l;
1542 /* Lest we fail to service interrupts in a timely manner, limit the
1543 amount of work we're willing to do. For now, let's cap at 8k. */
1544 if (l > 0x2000) {
1545 l = 0x2000;
1546 cc = 3;
1549 for (i = 0; i < l; i++) {
1550 uint8_t byte, new_byte;
1552 byte = cpu_ldub_data_ra(env, array + i, ra);
1554 if (byte == end) {
1555 cc = 1;
1556 break;
1559 new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
1560 cpu_stb_data_ra(env, array + i, new_byte, ra);
1563 env->cc_op = cc;
1564 env->retxl = len - i;
1565 return array + i;
1568 static inline uint32_t do_helper_trt(CPUS390XState *env, int len,
1569 uint64_t array, uint64_t trans,
1570 int inc, uintptr_t ra)
1572 int i;
1574 for (i = 0; i <= len; i++) {
1575 uint8_t byte = cpu_ldub_data_ra(env, array + i * inc, ra);
1576 uint8_t sbyte = cpu_ldub_data_ra(env, trans + byte, ra);
1578 if (sbyte != 0) {
1579 set_address(env, 1, array + i * inc);
1580 env->regs[2] = deposit64(env->regs[2], 0, 8, sbyte);
1581 return (i == len) ? 2 : 1;
1585 return 0;
1588 static uint32_t do_helper_trt_fwd(CPUS390XState *env, uint32_t len,
1589 uint64_t array, uint64_t trans,
1590 uintptr_t ra)
1592 return do_helper_trt(env, len, array, trans, 1, ra);
1595 uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
1596 uint64_t trans)
1598 return do_helper_trt(env, len, array, trans, 1, GETPC());
1601 static uint32_t do_helper_trt_bkwd(CPUS390XState *env, uint32_t len,
1602 uint64_t array, uint64_t trans,
1603 uintptr_t ra)
1605 return do_helper_trt(env, len, array, trans, -1, ra);
1608 uint32_t HELPER(trtr)(CPUS390XState *env, uint32_t len, uint64_t array,
1609 uint64_t trans)
1611 return do_helper_trt(env, len, array, trans, -1, GETPC());
1614 /* Translate one/two to one/two */
1615 uint32_t HELPER(trXX)(CPUS390XState *env, uint32_t r1, uint32_t r2,
1616 uint32_t tst, uint32_t sizes)
1618 uintptr_t ra = GETPC();
1619 int dsize = (sizes & 1) ? 1 : 2;
1620 int ssize = (sizes & 2) ? 1 : 2;
1621 uint64_t tbl = get_address(env, 1);
1622 uint64_t dst = get_address(env, r1);
1623 uint64_t len = get_length(env, r1 + 1);
1624 uint64_t src = get_address(env, r2);
1625 uint32_t cc = 3;
1626 int i;
1628 /* The lower address bits of TBL are ignored. For TROO, TROT, it's
1629 the low 3 bits (double-word aligned). For TRTO, TRTT, it's either
1630 the low 12 bits (4K, without ETF2-ENH) or 3 bits (with ETF2-ENH). */
1631 if (ssize == 2 && !s390_has_feat(S390_FEAT_ETF2_ENH)) {
1632 tbl &= -4096;
1633 } else {
1634 tbl &= -8;
1637 check_alignment(env, len, ssize, ra);
1639 /* Lest we fail to service interrupts in a timely manner, */
1640 /* limit the amount of work we're willing to do. */
1641 for (i = 0; i < 0x2000; i++) {
1642 uint16_t sval = cpu_ldusize_data_ra(env, src, ssize, ra);
1643 uint64_t tble = tbl + (sval * dsize);
1644 uint16_t dval = cpu_ldusize_data_ra(env, tble, dsize, ra);
1645 if (dval == tst) {
1646 cc = 1;
1647 break;
1649 cpu_stsize_data_ra(env, dst, dval, dsize, ra);
1651 len -= ssize;
1652 src += ssize;
1653 dst += dsize;
1655 if (len == 0) {
1656 cc = 0;
1657 break;
1661 set_address(env, r1, dst);
1662 set_length(env, r1 + 1, len);
1663 set_address(env, r2, src);
1665 return cc;
1668 void HELPER(cdsg)(CPUS390XState *env, uint64_t addr,
1669 uint32_t r1, uint32_t r3)
1671 uintptr_t ra = GETPC();
1672 Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
1673 Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1674 Int128 oldv;
1675 uint64_t oldh, oldl;
1676 bool fail;
1678 check_alignment(env, addr, 16, ra);
1680 oldh = cpu_ldq_data_ra(env, addr + 0, ra);
1681 oldl = cpu_ldq_data_ra(env, addr + 8, ra);
1683 oldv = int128_make128(oldl, oldh);
1684 fail = !int128_eq(oldv, cmpv);
1685 if (fail) {
1686 newv = oldv;
1689 cpu_stq_data_ra(env, addr + 0, int128_gethi(newv), ra);
1690 cpu_stq_data_ra(env, addr + 8, int128_getlo(newv), ra);
1692 env->cc_op = fail;
1693 env->regs[r1] = int128_gethi(oldv);
1694 env->regs[r1 + 1] = int128_getlo(oldv);
1697 void HELPER(cdsg_parallel)(CPUS390XState *env, uint64_t addr,
1698 uint32_t r1, uint32_t r3)
1700 uintptr_t ra = GETPC();
1701 Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
1702 Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1703 int mem_idx;
1704 TCGMemOpIdx oi;
1705 Int128 oldv;
1706 bool fail;
1708 assert(HAVE_CMPXCHG128);
1710 mem_idx = cpu_mmu_index(env, false);
1711 oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1712 oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
1713 fail = !int128_eq(oldv, cmpv);
1715 env->cc_op = fail;
1716 env->regs[r1] = int128_gethi(oldv);
1717 env->regs[r1 + 1] = int128_getlo(oldv);
1720 static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
1721 uint64_t a2, bool parallel)
1723 uint32_t mem_idx = cpu_mmu_index(env, false);
1724 uintptr_t ra = GETPC();
1725 uint32_t fc = extract32(env->regs[0], 0, 8);
1726 uint32_t sc = extract32(env->regs[0], 8, 8);
1727 uint64_t pl = get_address(env, 1) & -16;
1728 uint64_t svh, svl;
1729 uint32_t cc;
1731 /* Sanity check the function code and storage characteristic. */
1732 if (fc > 1 || sc > 3) {
1733 if (!s390_has_feat(S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2)) {
1734 goto spec_exception;
1736 if (fc > 2 || sc > 4 || (fc == 2 && (r3 & 1))) {
1737 goto spec_exception;
1741 /* Sanity check the alignments. */
1742 if (extract32(a1, 0, fc + 2) || extract32(a2, 0, sc)) {
1743 goto spec_exception;
1746 /* Sanity check writability of the store address. */
1747 probe_write(env, a2, 1 << sc, mem_idx, ra);
1750 * Note that the compare-and-swap is atomic, and the store is atomic,
1751 * but the complete operation is not. Therefore we do not need to
1752 * assert serial context in order to implement this. That said,
1753 * restart early if we can't support either operation that is supposed
1754 * to be atomic.
1756 if (parallel) {
1757 uint32_t max = 2;
1758 #ifdef CONFIG_ATOMIC64
1759 max = 3;
1760 #endif
1761 if ((HAVE_CMPXCHG128 ? 0 : fc + 2 > max) ||
1762 (HAVE_ATOMIC128 ? 0 : sc > max)) {
1763 cpu_loop_exit_atomic(env_cpu(env), ra);
1767 /* All loads happen before all stores. For simplicity, load the entire
1768 store value area from the parameter list. */
1769 svh = cpu_ldq_data_ra(env, pl + 16, ra);
1770 svl = cpu_ldq_data_ra(env, pl + 24, ra);
1772 switch (fc) {
1773 case 0:
1775 uint32_t nv = cpu_ldl_data_ra(env, pl, ra);
1776 uint32_t cv = env->regs[r3];
1777 uint32_t ov;
1779 if (parallel) {
1780 #ifdef CONFIG_USER_ONLY
1781 uint32_t *haddr = g2h(a1);
1782 ov = atomic_cmpxchg__nocheck(haddr, cv, nv);
1783 #else
1784 TCGMemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mem_idx);
1785 ov = helper_atomic_cmpxchgl_be_mmu(env, a1, cv, nv, oi, ra);
1786 #endif
1787 } else {
1788 ov = cpu_ldl_data_ra(env, a1, ra);
1789 cpu_stl_data_ra(env, a1, (ov == cv ? nv : ov), ra);
1791 cc = (ov != cv);
1792 env->regs[r3] = deposit64(env->regs[r3], 32, 32, ov);
1794 break;
1796 case 1:
1798 uint64_t nv = cpu_ldq_data_ra(env, pl, ra);
1799 uint64_t cv = env->regs[r3];
1800 uint64_t ov;
1802 if (parallel) {
1803 #ifdef CONFIG_ATOMIC64
1804 # ifdef CONFIG_USER_ONLY
1805 uint64_t *haddr = g2h(a1);
1806 ov = atomic_cmpxchg__nocheck(haddr, cv, nv);
1807 # else
1808 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN, mem_idx);
1809 ov = helper_atomic_cmpxchgq_be_mmu(env, a1, cv, nv, oi, ra);
1810 # endif
1811 #else
1812 /* Note that we asserted !parallel above. */
1813 g_assert_not_reached();
1814 #endif
1815 } else {
1816 ov = cpu_ldq_data_ra(env, a1, ra);
1817 cpu_stq_data_ra(env, a1, (ov == cv ? nv : ov), ra);
1819 cc = (ov != cv);
1820 env->regs[r3] = ov;
1822 break;
1824 case 2:
1826 uint64_t nvh = cpu_ldq_data_ra(env, pl, ra);
1827 uint64_t nvl = cpu_ldq_data_ra(env, pl + 8, ra);
1828 Int128 nv = int128_make128(nvl, nvh);
1829 Int128 cv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1830 Int128 ov;
1832 if (!parallel) {
1833 uint64_t oh = cpu_ldq_data_ra(env, a1 + 0, ra);
1834 uint64_t ol = cpu_ldq_data_ra(env, a1 + 8, ra);
1836 ov = int128_make128(ol, oh);
1837 cc = !int128_eq(ov, cv);
1838 if (cc) {
1839 nv = ov;
1842 cpu_stq_data_ra(env, a1 + 0, int128_gethi(nv), ra);
1843 cpu_stq_data_ra(env, a1 + 8, int128_getlo(nv), ra);
1844 } else if (HAVE_CMPXCHG128) {
1845 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1846 ov = helper_atomic_cmpxchgo_be_mmu(env, a1, cv, nv, oi, ra);
1847 cc = !int128_eq(ov, cv);
1848 } else {
1849 /* Note that we asserted !parallel above. */
1850 g_assert_not_reached();
1853 env->regs[r3 + 0] = int128_gethi(ov);
1854 env->regs[r3 + 1] = int128_getlo(ov);
1856 break;
1858 default:
1859 g_assert_not_reached();
1862 /* Store only if the comparison succeeded. Note that above we use a pair
1863 of 64-bit big-endian loads, so for sc < 3 we must extract the value
1864 from the most-significant bits of svh. */
1865 if (cc == 0) {
1866 switch (sc) {
1867 case 0:
1868 cpu_stb_data_ra(env, a2, svh >> 56, ra);
1869 break;
1870 case 1:
1871 cpu_stw_data_ra(env, a2, svh >> 48, ra);
1872 break;
1873 case 2:
1874 cpu_stl_data_ra(env, a2, svh >> 32, ra);
1875 break;
1876 case 3:
1877 cpu_stq_data_ra(env, a2, svh, ra);
1878 break;
1879 case 4:
1880 if (!parallel) {
1881 cpu_stq_data_ra(env, a2 + 0, svh, ra);
1882 cpu_stq_data_ra(env, a2 + 8, svl, ra);
1883 } else if (HAVE_ATOMIC128) {
1884 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1885 Int128 sv = int128_make128(svl, svh);
1886 helper_atomic_sto_be_mmu(env, a2, sv, oi, ra);
1887 } else {
1888 /* Note that we asserted !parallel above. */
1889 g_assert_not_reached();
1891 break;
1892 default:
1893 g_assert_not_reached();
1897 return cc;
1899 spec_exception:
1900 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
1903 uint32_t HELPER(csst)(CPUS390XState *env, uint32_t r3, uint64_t a1, uint64_t a2)
1905 return do_csst(env, r3, a1, a2, false);
1908 uint32_t HELPER(csst_parallel)(CPUS390XState *env, uint32_t r3, uint64_t a1,
1909 uint64_t a2)
1911 return do_csst(env, r3, a1, a2, true);
1914 #if !defined(CONFIG_USER_ONLY)
1915 void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1917 uintptr_t ra = GETPC();
1918 bool PERchanged = false;
1919 uint64_t src = a2;
1920 uint32_t i;
1922 if (src & 0x7) {
1923 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
1926 for (i = r1;; i = (i + 1) % 16) {
1927 uint64_t val = cpu_ldq_data_ra(env, src, ra);
1928 if (env->cregs[i] != val && i >= 9 && i <= 11) {
1929 PERchanged = true;
1931 env->cregs[i] = val;
1932 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
1933 i, src, val);
1934 src += sizeof(uint64_t);
1936 if (i == r3) {
1937 break;
1941 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
1942 s390_cpu_recompute_watchpoints(env_cpu(env));
1945 tlb_flush(env_cpu(env));
1948 void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1950 uintptr_t ra = GETPC();
1951 bool PERchanged = false;
1952 uint64_t src = a2;
1953 uint32_t i;
1955 if (src & 0x3) {
1956 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
1959 for (i = r1;; i = (i + 1) % 16) {
1960 uint32_t val = cpu_ldl_data_ra(env, src, ra);
1961 if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
1962 PERchanged = true;
1964 env->cregs[i] = deposit64(env->cregs[i], 0, 32, val);
1965 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val);
1966 src += sizeof(uint32_t);
1968 if (i == r3) {
1969 break;
1973 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
1974 s390_cpu_recompute_watchpoints(env_cpu(env));
1977 tlb_flush(env_cpu(env));
1980 void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1982 uintptr_t ra = GETPC();
1983 uint64_t dest = a2;
1984 uint32_t i;
1986 if (dest & 0x7) {
1987 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
1990 for (i = r1;; i = (i + 1) % 16) {
1991 cpu_stq_data_ra(env, dest, env->cregs[i], ra);
1992 dest += sizeof(uint64_t);
1994 if (i == r3) {
1995 break;
2000 void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
2002 uintptr_t ra = GETPC();
2003 uint64_t dest = a2;
2004 uint32_t i;
2006 if (dest & 0x3) {
2007 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
2010 for (i = r1;; i = (i + 1) % 16) {
2011 cpu_stl_data_ra(env, dest, env->cregs[i], ra);
2012 dest += sizeof(uint32_t);
2014 if (i == r3) {
2015 break;
2020 uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
2022 uintptr_t ra = GETPC();
2023 int i;
2025 real_addr = wrap_address(env, real_addr) & TARGET_PAGE_MASK;
2027 for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
2028 cpu_stq_real_ra(env, real_addr + i, 0, ra);
2031 return 0;
2034 uint32_t HELPER(tprot)(CPUS390XState *env, uint64_t a1, uint64_t a2)
2036 S390CPU *cpu = env_archcpu(env);
2037 CPUState *cs = env_cpu(env);
2040 * TODO: we currently don't handle all access protection types
2041 * (including access-list and key-controlled) as well as AR mode.
2043 if (!s390_cpu_virt_mem_check_write(cpu, a1, 0, 1)) {
2044 /* Fetching permitted; storing permitted */
2045 return 0;
2048 if (env->int_pgm_code == PGM_PROTECTION) {
2049 /* retry if reading is possible */
2050 cs->exception_index = -1;
2051 if (!s390_cpu_virt_mem_check_read(cpu, a1, 0, 1)) {
2052 /* Fetching permitted; storing not permitted */
2053 return 1;
2057 switch (env->int_pgm_code) {
2058 case PGM_PROTECTION:
2059 /* Fetching not permitted; storing not permitted */
2060 cs->exception_index = -1;
2061 return 2;
2062 case PGM_ADDRESSING:
2063 case PGM_TRANS_SPEC:
2064 /* exceptions forwarded to the guest */
2065 s390_cpu_virt_mem_handle_exc(cpu, GETPC());
2066 return 0;
2069 /* Translation not available */
2070 cs->exception_index = -1;
2071 return 3;
2074 /* insert storage key extended */
2075 uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
2077 static S390SKeysState *ss;
2078 static S390SKeysClass *skeyclass;
2079 uint64_t addr = wrap_address(env, r2);
2080 uint8_t key;
2082 if (addr > ram_size) {
2083 return 0;
2086 if (unlikely(!ss)) {
2087 ss = s390_get_skeys_device();
2088 skeyclass = S390_SKEYS_GET_CLASS(ss);
2091 if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
2092 return 0;
2094 return key;
2097 /* set storage key extended */
2098 void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
2100 static S390SKeysState *ss;
2101 static S390SKeysClass *skeyclass;
2102 uint64_t addr = wrap_address(env, r2);
2103 uint8_t key;
2105 if (addr > ram_size) {
2106 return;
2109 if (unlikely(!ss)) {
2110 ss = s390_get_skeys_device();
2111 skeyclass = S390_SKEYS_GET_CLASS(ss);
2114 key = (uint8_t) r1;
2115 skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
2117 * As we can only flush by virtual address and not all the entries
2118 * that point to a physical address we have to flush the whole TLB.
2120 tlb_flush_all_cpus_synced(env_cpu(env));
2123 /* reset reference bit extended */
2124 uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
2126 static S390SKeysState *ss;
2127 static S390SKeysClass *skeyclass;
2128 uint8_t re, key;
2130 if (r2 > ram_size) {
2131 return 0;
2134 if (unlikely(!ss)) {
2135 ss = s390_get_skeys_device();
2136 skeyclass = S390_SKEYS_GET_CLASS(ss);
2139 if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
2140 return 0;
2143 re = key & (SK_R | SK_C);
2144 key &= ~SK_R;
2146 if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
2147 return 0;
2150 * As we can only flush by virtual address and not all the entries
2151 * that point to a physical address we have to flush the whole TLB.
2153 tlb_flush_all_cpus_synced(env_cpu(env));
2156 * cc
2158 * 0 Reference bit zero; change bit zero
2159 * 1 Reference bit zero; change bit one
2160 * 2 Reference bit one; change bit zero
2161 * 3 Reference bit one; change bit one
2164 return re >> 1;
2167 uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
2169 const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
2170 S390Access srca, desta;
2171 uintptr_t ra = GETPC();
2172 int cc = 0;
2174 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
2175 __func__, l, a1, a2);
2177 if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) ||
2178 psw_as == AS_HOME || psw_as == AS_ACCREG) {
2179 s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2182 l = wrap_length32(env, l);
2183 if (l > 256) {
2184 /* max 256 */
2185 l = 256;
2186 cc = 3;
2187 } else if (!l) {
2188 return cc;
2191 /* TODO: Access key handling */
2192 srca = access_prepare(env, a2, l, MMU_DATA_LOAD, MMU_PRIMARY_IDX, ra);
2193 desta = access_prepare(env, a1, l, MMU_DATA_STORE, MMU_SECONDARY_IDX, ra);
2194 access_memmove(env, &desta, &srca, ra);
2195 return cc;
2198 uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
2200 const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
2201 S390Access srca, desta;
2202 uintptr_t ra = GETPC();
2203 int cc = 0;
2205 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
2206 __func__, l, a1, a2);
2208 if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) ||
2209 psw_as == AS_HOME || psw_as == AS_ACCREG) {
2210 s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2213 l = wrap_length32(env, l);
2214 if (l > 256) {
2215 /* max 256 */
2216 l = 256;
2217 cc = 3;
2218 } else if (!l) {
2219 return cc;
2222 /* TODO: Access key handling */
2223 srca = access_prepare(env, a2, l, MMU_DATA_LOAD, MMU_SECONDARY_IDX, ra);
2224 desta = access_prepare(env, a1, l, MMU_DATA_STORE, MMU_PRIMARY_IDX, ra);
2225 access_memmove(env, &desta, &srca, ra);
2226 return cc;
2229 void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4)
2231 CPUState *cs = env_cpu(env);
2232 const uintptr_t ra = GETPC();
2233 uint64_t table, entry, raddr;
2234 uint16_t entries, i, index = 0;
2236 if (r2 & 0xff000) {
2237 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
2240 if (!(r2 & 0x800)) {
2241 /* invalidation-and-clearing operation */
2242 table = r1 & ASCE_ORIGIN;
2243 entries = (r2 & 0x7ff) + 1;
2245 switch (r1 & ASCE_TYPE_MASK) {
2246 case ASCE_TYPE_REGION1:
2247 index = (r2 >> 53) & 0x7ff;
2248 break;
2249 case ASCE_TYPE_REGION2:
2250 index = (r2 >> 42) & 0x7ff;
2251 break;
2252 case ASCE_TYPE_REGION3:
2253 index = (r2 >> 31) & 0x7ff;
2254 break;
2255 case ASCE_TYPE_SEGMENT:
2256 index = (r2 >> 20) & 0x7ff;
2257 break;
2259 for (i = 0; i < entries; i++) {
2260 /* addresses are not wrapped in 24/31bit mode but table index is */
2261 raddr = table + ((index + i) & 0x7ff) * sizeof(entry);
2262 entry = cpu_ldq_real_ra(env, raddr, ra);
2263 if (!(entry & REGION_ENTRY_I)) {
2264 /* we are allowed to not store if already invalid */
2265 entry |= REGION_ENTRY_I;
2266 cpu_stq_real_ra(env, raddr, entry, ra);
2271 /* We simply flush the complete tlb, therefore we can ignore r3. */
2272 if (m4 & 1) {
2273 tlb_flush(cs);
2274 } else {
2275 tlb_flush_all_cpus_synced(cs);
2279 /* invalidate pte */
2280 void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr,
2281 uint32_t m4)
2283 CPUState *cs = env_cpu(env);
2284 const uintptr_t ra = GETPC();
2285 uint64_t page = vaddr & TARGET_PAGE_MASK;
2286 uint64_t pte_addr, pte;
2288 /* Compute the page table entry address */
2289 pte_addr = (pto & SEGMENT_ENTRY_ORIGIN);
2290 pte_addr += VADDR_PAGE_TX(vaddr) * 8;
2292 /* Mark the page table entry as invalid */
2293 pte = cpu_ldq_real_ra(env, pte_addr, ra);
2294 pte |= PAGE_ENTRY_I;
2295 cpu_stq_real_ra(env, pte_addr, pte, ra);
2297 /* XXX we exploit the fact that Linux passes the exact virtual
2298 address here - it's not obliged to! */
2299 if (m4 & 1) {
2300 if (vaddr & ~VADDR_PAGE_TX_MASK) {
2301 tlb_flush_page(cs, page);
2302 /* XXX 31-bit hack */
2303 tlb_flush_page(cs, page ^ 0x80000000);
2304 } else {
2305 /* looks like we don't have a valid virtual address */
2306 tlb_flush(cs);
2308 } else {
2309 if (vaddr & ~VADDR_PAGE_TX_MASK) {
2310 tlb_flush_page_all_cpus_synced(cs, page);
2311 /* XXX 31-bit hack */
2312 tlb_flush_page_all_cpus_synced(cs, page ^ 0x80000000);
2313 } else {
2314 /* looks like we don't have a valid virtual address */
2315 tlb_flush_all_cpus_synced(cs);
2320 /* flush local tlb */
2321 void HELPER(ptlb)(CPUS390XState *env)
2323 tlb_flush(env_cpu(env));
2326 /* flush global tlb */
2327 void HELPER(purge)(CPUS390XState *env)
2329 tlb_flush_all_cpus_synced(env_cpu(env));
2332 /* load real address */
2333 uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
2335 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
2336 uint64_t ret, tec;
2337 int flags, exc, cc;
2339 /* XXX incomplete - has more corner cases */
2340 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
2341 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, GETPC());
2344 exc = mmu_translate(env, addr, 0, asc, &ret, &flags, &tec);
2345 if (exc) {
2346 cc = 3;
2347 ret = exc | 0x80000000;
2348 } else {
2349 cc = 0;
2350 ret |= addr & ~TARGET_PAGE_MASK;
2353 env->cc_op = cc;
2354 return ret;
2356 #endif
2358 /* load pair from quadword */
2359 uint64_t HELPER(lpq)(CPUS390XState *env, uint64_t addr)
2361 uintptr_t ra = GETPC();
2362 uint64_t hi, lo;
2364 check_alignment(env, addr, 16, ra);
2365 hi = cpu_ldq_data_ra(env, addr + 0, ra);
2366 lo = cpu_ldq_data_ra(env, addr + 8, ra);
2368 env->retxl = lo;
2369 return hi;
2372 uint64_t HELPER(lpq_parallel)(CPUS390XState *env, uint64_t addr)
2374 uintptr_t ra = GETPC();
2375 uint64_t hi, lo;
2376 int mem_idx;
2377 TCGMemOpIdx oi;
2378 Int128 v;
2380 assert(HAVE_ATOMIC128);
2382 mem_idx = cpu_mmu_index(env, false);
2383 oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
2384 v = helper_atomic_ldo_be_mmu(env, addr, oi, ra);
2385 hi = int128_gethi(v);
2386 lo = int128_getlo(v);
2388 env->retxl = lo;
2389 return hi;
2392 /* store pair to quadword */
2393 void HELPER(stpq)(CPUS390XState *env, uint64_t addr,
2394 uint64_t low, uint64_t high)
2396 uintptr_t ra = GETPC();
2398 check_alignment(env, addr, 16, ra);
2399 cpu_stq_data_ra(env, addr + 0, high, ra);
2400 cpu_stq_data_ra(env, addr + 8, low, ra);
2403 void HELPER(stpq_parallel)(CPUS390XState *env, uint64_t addr,
2404 uint64_t low, uint64_t high)
2406 uintptr_t ra = GETPC();
2407 int mem_idx;
2408 TCGMemOpIdx oi;
2409 Int128 v;
2411 assert(HAVE_ATOMIC128);
2413 mem_idx = cpu_mmu_index(env, false);
2414 oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
2415 v = int128_make128(low, high);
2416 helper_atomic_sto_be_mmu(env, addr, v, oi, ra);
2419 /* Execute instruction. This instruction executes an insn modified with
2420 the contents of r1. It does not change the executed instruction in memory;
2421 it does not change the program counter.
2423 Perform this by recording the modified instruction in env->ex_value.
2424 This will be noticed by cpu_get_tb_cpu_state and thus tb translation.
2426 void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
2428 uint64_t insn = cpu_lduw_code(env, addr);
2429 uint8_t opc = insn >> 8;
2431 /* Or in the contents of R1[56:63]. */
2432 insn |= r1 & 0xff;
2434 /* Load the rest of the instruction. */
2435 insn <<= 48;
2436 switch (get_ilen(opc)) {
2437 case 2:
2438 break;
2439 case 4:
2440 insn |= (uint64_t)cpu_lduw_code(env, addr + 2) << 32;
2441 break;
2442 case 6:
2443 insn |= (uint64_t)(uint32_t)cpu_ldl_code(env, addr + 2) << 16;
2444 break;
2445 default:
2446 g_assert_not_reached();
2449 /* The very most common cases can be sped up by avoiding a new TB. */
2450 if ((opc & 0xf0) == 0xd0) {
2451 typedef uint32_t (*dx_helper)(CPUS390XState *, uint32_t, uint64_t,
2452 uint64_t, uintptr_t);
2453 static const dx_helper dx[16] = {
2454 [0x0] = do_helper_trt_bkwd,
2455 [0x2] = do_helper_mvc,
2456 [0x4] = do_helper_nc,
2457 [0x5] = do_helper_clc,
2458 [0x6] = do_helper_oc,
2459 [0x7] = do_helper_xc,
2460 [0xc] = do_helper_tr,
2461 [0xd] = do_helper_trt_fwd,
2463 dx_helper helper = dx[opc & 0xf];
2465 if (helper) {
2466 uint32_t l = extract64(insn, 48, 8);
2467 uint32_t b1 = extract64(insn, 44, 4);
2468 uint32_t d1 = extract64(insn, 32, 12);
2469 uint32_t b2 = extract64(insn, 28, 4);
2470 uint32_t d2 = extract64(insn, 16, 12);
2471 uint64_t a1 = wrap_address(env, env->regs[b1] + d1);
2472 uint64_t a2 = wrap_address(env, env->regs[b2] + d2);
2474 env->cc_op = helper(env, l, a1, a2, 0);
2475 env->psw.addr += ilen;
2476 return;
2478 } else if (opc == 0x0a) {
2479 env->int_svc_code = extract64(insn, 48, 8);
2480 env->int_svc_ilen = ilen;
2481 helper_exception(env, EXCP_SVC);
2482 g_assert_not_reached();
2485 /* Record the insn we want to execute as well as the ilen to use
2486 during the execution of the target insn. This will also ensure
2487 that ex_value is non-zero, which flags that we are in a state
2488 that requires such execution. */
2489 env->ex_value = insn | ilen;
2492 uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src,
2493 uint64_t len)
2495 const uint8_t psw_key = (env->psw.mask & PSW_MASK_KEY) >> PSW_SHIFT_KEY;
2496 const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
2497 const uint64_t r0 = env->regs[0];
2498 const uintptr_t ra = GETPC();
2499 uint8_t dest_key, dest_as, dest_k, dest_a;
2500 uint8_t src_key, src_as, src_k, src_a;
2501 uint64_t val;
2502 int cc = 0;
2504 HELPER_LOG("%s dest %" PRIx64 ", src %" PRIx64 ", len %" PRIx64 "\n",
2505 __func__, dest, src, len);
2507 if (!(env->psw.mask & PSW_MASK_DAT)) {
2508 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2511 /* OAC (operand access control) for the first operand -> dest */
2512 val = (r0 & 0xffff0000ULL) >> 16;
2513 dest_key = (val >> 12) & 0xf;
2514 dest_as = (val >> 6) & 0x3;
2515 dest_k = (val >> 1) & 0x1;
2516 dest_a = val & 0x1;
2518 /* OAC (operand access control) for the second operand -> src */
2519 val = (r0 & 0x0000ffffULL);
2520 src_key = (val >> 12) & 0xf;
2521 src_as = (val >> 6) & 0x3;
2522 src_k = (val >> 1) & 0x1;
2523 src_a = val & 0x1;
2525 if (!dest_k) {
2526 dest_key = psw_key;
2528 if (!src_k) {
2529 src_key = psw_key;
2531 if (!dest_a) {
2532 dest_as = psw_as;
2534 if (!src_a) {
2535 src_as = psw_as;
2538 if (dest_a && dest_as == AS_HOME && (env->psw.mask & PSW_MASK_PSTATE)) {
2539 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2541 if (!(env->cregs[0] & CR0_SECONDARY) &&
2542 (dest_as == AS_SECONDARY || src_as == AS_SECONDARY)) {
2543 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2545 if (!psw_key_valid(env, dest_key) || !psw_key_valid(env, src_key)) {
2546 tcg_s390_program_interrupt(env, PGM_PRIVILEGED, ra);
2549 len = wrap_length32(env, len);
2550 if (len > 4096) {
2551 cc = 3;
2552 len = 4096;
2555 /* FIXME: AR-mode and proper problem state mode (using PSW keys) missing */
2556 if (src_as == AS_ACCREG || dest_as == AS_ACCREG ||
2557 (env->psw.mask & PSW_MASK_PSTATE)) {
2558 qemu_log_mask(LOG_UNIMP, "%s: AR-mode and PSTATE support missing\n",
2559 __func__);
2560 tcg_s390_program_interrupt(env, PGM_ADDRESSING, ra);
2563 /* FIXME: Access using correct keys and AR-mode */
2564 if (len) {
2565 S390Access srca = access_prepare(env, src, len, MMU_DATA_LOAD,
2566 mmu_idx_from_as(src_as), ra);
2567 S390Access desta = access_prepare(env, dest, len, MMU_DATA_STORE,
2568 mmu_idx_from_as(dest_as), ra);
2570 access_memmove(env, &desta, &srca, ra);
2573 return cc;
2576 /* Decode a Unicode character. A return value < 0 indicates success, storing
2577 the UTF-32 result into OCHAR and the input length into OLEN. A return
2578 value >= 0 indicates failure, and the CC value to be returned. */
2579 typedef int (*decode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2580 uint64_t ilen, bool enh_check, uintptr_t ra,
2581 uint32_t *ochar, uint32_t *olen);
2583 /* Encode a Unicode character. A return value < 0 indicates success, storing
2584 the bytes into ADDR and the output length into OLEN. A return value >= 0
2585 indicates failure, and the CC value to be returned. */
2586 typedef int (*encode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2587 uint64_t ilen, uintptr_t ra, uint32_t c,
2588 uint32_t *olen);
2590 static int decode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2591 bool enh_check, uintptr_t ra,
2592 uint32_t *ochar, uint32_t *olen)
2594 uint8_t s0, s1, s2, s3;
2595 uint32_t c, l;
2597 if (ilen < 1) {
2598 return 0;
2600 s0 = cpu_ldub_data_ra(env, addr, ra);
2601 if (s0 <= 0x7f) {
2602 /* one byte character */
2603 l = 1;
2604 c = s0;
2605 } else if (s0 <= (enh_check ? 0xc1 : 0xbf)) {
2606 /* invalid character */
2607 return 2;
2608 } else if (s0 <= 0xdf) {
2609 /* two byte character */
2610 l = 2;
2611 if (ilen < 2) {
2612 return 0;
2614 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2615 c = s0 & 0x1f;
2616 c = (c << 6) | (s1 & 0x3f);
2617 if (enh_check && (s1 & 0xc0) != 0x80) {
2618 return 2;
2620 } else if (s0 <= 0xef) {
2621 /* three byte character */
2622 l = 3;
2623 if (ilen < 3) {
2624 return 0;
2626 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2627 s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2628 c = s0 & 0x0f;
2629 c = (c << 6) | (s1 & 0x3f);
2630 c = (c << 6) | (s2 & 0x3f);
2631 /* Fold the byte-by-byte range descriptions in the PoO into
2632 tests against the complete value. It disallows encodings
2633 that could be smaller, and the UTF-16 surrogates. */
2634 if (enh_check
2635 && ((s1 & 0xc0) != 0x80
2636 || (s2 & 0xc0) != 0x80
2637 || c < 0x1000
2638 || (c >= 0xd800 && c <= 0xdfff))) {
2639 return 2;
2641 } else if (s0 <= (enh_check ? 0xf4 : 0xf7)) {
2642 /* four byte character */
2643 l = 4;
2644 if (ilen < 4) {
2645 return 0;
2647 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2648 s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2649 s3 = cpu_ldub_data_ra(env, addr + 3, ra);
2650 c = s0 & 0x07;
2651 c = (c << 6) | (s1 & 0x3f);
2652 c = (c << 6) | (s2 & 0x3f);
2653 c = (c << 6) | (s3 & 0x3f);
2654 /* See above. */
2655 if (enh_check
2656 && ((s1 & 0xc0) != 0x80
2657 || (s2 & 0xc0) != 0x80
2658 || (s3 & 0xc0) != 0x80
2659 || c < 0x010000
2660 || c > 0x10ffff)) {
2661 return 2;
2663 } else {
2664 /* invalid character */
2665 return 2;
2668 *ochar = c;
2669 *olen = l;
2670 return -1;
2673 static int decode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2674 bool enh_check, uintptr_t ra,
2675 uint32_t *ochar, uint32_t *olen)
2677 uint16_t s0, s1;
2678 uint32_t c, l;
2680 if (ilen < 2) {
2681 return 0;
2683 s0 = cpu_lduw_data_ra(env, addr, ra);
2684 if ((s0 & 0xfc00) != 0xd800) {
2685 /* one word character */
2686 l = 2;
2687 c = s0;
2688 } else {
2689 /* two word character */
2690 l = 4;
2691 if (ilen < 4) {
2692 return 0;
2694 s1 = cpu_lduw_data_ra(env, addr + 2, ra);
2695 c = extract32(s0, 6, 4) + 1;
2696 c = (c << 6) | (s0 & 0x3f);
2697 c = (c << 10) | (s1 & 0x3ff);
2698 if (enh_check && (s1 & 0xfc00) != 0xdc00) {
2699 /* invalid surrogate character */
2700 return 2;
2704 *ochar = c;
2705 *olen = l;
2706 return -1;
2709 static int decode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2710 bool enh_check, uintptr_t ra,
2711 uint32_t *ochar, uint32_t *olen)
2713 uint32_t c;
2715 if (ilen < 4) {
2716 return 0;
2718 c = cpu_ldl_data_ra(env, addr, ra);
2719 if ((c >= 0xd800 && c <= 0xdbff) || c > 0x10ffff) {
2720 /* invalid unicode character */
2721 return 2;
2724 *ochar = c;
2725 *olen = 4;
2726 return -1;
2729 static int encode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2730 uintptr_t ra, uint32_t c, uint32_t *olen)
2732 uint8_t d[4];
2733 uint32_t l, i;
2735 if (c <= 0x7f) {
2736 /* one byte character */
2737 l = 1;
2738 d[0] = c;
2739 } else if (c <= 0x7ff) {
2740 /* two byte character */
2741 l = 2;
2742 d[1] = 0x80 | extract32(c, 0, 6);
2743 d[0] = 0xc0 | extract32(c, 6, 5);
2744 } else if (c <= 0xffff) {
2745 /* three byte character */
2746 l = 3;
2747 d[2] = 0x80 | extract32(c, 0, 6);
2748 d[1] = 0x80 | extract32(c, 6, 6);
2749 d[0] = 0xe0 | extract32(c, 12, 4);
2750 } else {
2751 /* four byte character */
2752 l = 4;
2753 d[3] = 0x80 | extract32(c, 0, 6);
2754 d[2] = 0x80 | extract32(c, 6, 6);
2755 d[1] = 0x80 | extract32(c, 12, 6);
2756 d[0] = 0xf0 | extract32(c, 18, 3);
2759 if (ilen < l) {
2760 return 1;
2762 for (i = 0; i < l; ++i) {
2763 cpu_stb_data_ra(env, addr + i, d[i], ra);
2766 *olen = l;
2767 return -1;
2770 static int encode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2771 uintptr_t ra, uint32_t c, uint32_t *olen)
2773 uint16_t d0, d1;
2775 if (c <= 0xffff) {
2776 /* one word character */
2777 if (ilen < 2) {
2778 return 1;
2780 cpu_stw_data_ra(env, addr, c, ra);
2781 *olen = 2;
2782 } else {
2783 /* two word character */
2784 if (ilen < 4) {
2785 return 1;
2787 d1 = 0xdc00 | extract32(c, 0, 10);
2788 d0 = 0xd800 | extract32(c, 10, 6);
2789 d0 = deposit32(d0, 6, 4, extract32(c, 16, 5) - 1);
2790 cpu_stw_data_ra(env, addr + 0, d0, ra);
2791 cpu_stw_data_ra(env, addr + 2, d1, ra);
2792 *olen = 4;
2795 return -1;
2798 static int encode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2799 uintptr_t ra, uint32_t c, uint32_t *olen)
2801 if (ilen < 4) {
2802 return 1;
2804 cpu_stl_data_ra(env, addr, c, ra);
2805 *olen = 4;
2806 return -1;
2809 static inline uint32_t convert_unicode(CPUS390XState *env, uint32_t r1,
2810 uint32_t r2, uint32_t m3, uintptr_t ra,
2811 decode_unicode_fn decode,
2812 encode_unicode_fn encode)
2814 uint64_t dst = get_address(env, r1);
2815 uint64_t dlen = get_length(env, r1 + 1);
2816 uint64_t src = get_address(env, r2);
2817 uint64_t slen = get_length(env, r2 + 1);
2818 bool enh_check = m3 & 1;
2819 int cc, i;
2821 /* Lest we fail to service interrupts in a timely manner, limit the
2822 amount of work we're willing to do. For now, let's cap at 256. */
2823 for (i = 0; i < 256; ++i) {
2824 uint32_t c, ilen, olen;
2826 cc = decode(env, src, slen, enh_check, ra, &c, &ilen);
2827 if (unlikely(cc >= 0)) {
2828 break;
2830 cc = encode(env, dst, dlen, ra, c, &olen);
2831 if (unlikely(cc >= 0)) {
2832 break;
2835 src += ilen;
2836 slen -= ilen;
2837 dst += olen;
2838 dlen -= olen;
2839 cc = 3;
2842 set_address(env, r1, dst);
2843 set_length(env, r1 + 1, dlen);
2844 set_address(env, r2, src);
2845 set_length(env, r2 + 1, slen);
2847 return cc;
2850 uint32_t HELPER(cu12)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2852 return convert_unicode(env, r1, r2, m3, GETPC(),
2853 decode_utf8, encode_utf16);
2856 uint32_t HELPER(cu14)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2858 return convert_unicode(env, r1, r2, m3, GETPC(),
2859 decode_utf8, encode_utf32);
2862 uint32_t HELPER(cu21)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2864 return convert_unicode(env, r1, r2, m3, GETPC(),
2865 decode_utf16, encode_utf8);
2868 uint32_t HELPER(cu24)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2870 return convert_unicode(env, r1, r2, m3, GETPC(),
2871 decode_utf16, encode_utf32);
2874 uint32_t HELPER(cu41)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2876 return convert_unicode(env, r1, r2, m3, GETPC(),
2877 decode_utf32, encode_utf8);
2880 uint32_t HELPER(cu42)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2882 return convert_unicode(env, r1, r2, m3, GETPC(),
2883 decode_utf32, encode_utf16);
2886 void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
2887 uintptr_t ra)
2889 /* test the actual access, not just any access to the page due to LAP */
2890 while (len) {
2891 const uint64_t pagelen = -(addr | TARGET_PAGE_MASK);
2892 const uint64_t curlen = MIN(pagelen, len);
2894 probe_write(env, addr, curlen, cpu_mmu_index(env, false), ra);
2895 addr = wrap_address(env, addr + curlen);
2896 len -= curlen;
2900 void HELPER(probe_write_access)(CPUS390XState *env, uint64_t addr, uint64_t len)
2902 probe_write_access(env, addr, len, GETPC());