ppc/pnv: Introduce PnvChipClass::xscom_core_base() method
[qemu/ar7.git] / target / s390x / mem_helper.c
blob2325767f1787f7162f666b7afe1ac40f88dd2e54
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 using real address */
2333 uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr)
2335 return cpu_ldl_real_ra(env, wrap_address(env, addr), GETPC());
2338 uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr)
2340 return cpu_ldq_real_ra(env, wrap_address(env, addr), GETPC());
2343 /* store using real address */
2344 void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
2346 cpu_stl_real_ra(env, wrap_address(env, addr), (uint32_t)v1, GETPC());
2348 if ((env->psw.mask & PSW_MASK_PER) &&
2349 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
2350 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
2351 /* PSW is saved just before calling the helper. */
2352 env->per_address = env->psw.addr;
2353 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
2357 void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
2359 cpu_stq_real_ra(env, wrap_address(env, addr), v1, GETPC());
2361 if ((env->psw.mask & PSW_MASK_PER) &&
2362 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
2363 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
2364 /* PSW is saved just before calling the helper. */
2365 env->per_address = env->psw.addr;
2366 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
2370 /* load real address */
2371 uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
2373 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
2374 uint64_t ret, tec;
2375 int flags, exc, cc;
2377 /* XXX incomplete - has more corner cases */
2378 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
2379 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, GETPC());
2382 exc = mmu_translate(env, addr, 0, asc, &ret, &flags, &tec);
2383 if (exc) {
2384 cc = 3;
2385 ret = exc | 0x80000000;
2386 } else {
2387 cc = 0;
2388 ret |= addr & ~TARGET_PAGE_MASK;
2391 env->cc_op = cc;
2392 return ret;
2394 #endif
2396 /* load pair from quadword */
2397 uint64_t HELPER(lpq)(CPUS390XState *env, uint64_t addr)
2399 uintptr_t ra = GETPC();
2400 uint64_t hi, lo;
2402 check_alignment(env, addr, 16, ra);
2403 hi = cpu_ldq_data_ra(env, addr + 0, ra);
2404 lo = cpu_ldq_data_ra(env, addr + 8, ra);
2406 env->retxl = lo;
2407 return hi;
2410 uint64_t HELPER(lpq_parallel)(CPUS390XState *env, uint64_t addr)
2412 uintptr_t ra = GETPC();
2413 uint64_t hi, lo;
2414 int mem_idx;
2415 TCGMemOpIdx oi;
2416 Int128 v;
2418 assert(HAVE_ATOMIC128);
2420 mem_idx = cpu_mmu_index(env, false);
2421 oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
2422 v = helper_atomic_ldo_be_mmu(env, addr, oi, ra);
2423 hi = int128_gethi(v);
2424 lo = int128_getlo(v);
2426 env->retxl = lo;
2427 return hi;
2430 /* store pair to quadword */
2431 void HELPER(stpq)(CPUS390XState *env, uint64_t addr,
2432 uint64_t low, uint64_t high)
2434 uintptr_t ra = GETPC();
2436 check_alignment(env, addr, 16, ra);
2437 cpu_stq_data_ra(env, addr + 0, high, ra);
2438 cpu_stq_data_ra(env, addr + 8, low, ra);
2441 void HELPER(stpq_parallel)(CPUS390XState *env, uint64_t addr,
2442 uint64_t low, uint64_t high)
2444 uintptr_t ra = GETPC();
2445 int mem_idx;
2446 TCGMemOpIdx oi;
2447 Int128 v;
2449 assert(HAVE_ATOMIC128);
2451 mem_idx = cpu_mmu_index(env, false);
2452 oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
2453 v = int128_make128(low, high);
2454 helper_atomic_sto_be_mmu(env, addr, v, oi, ra);
2457 /* Execute instruction. This instruction executes an insn modified with
2458 the contents of r1. It does not change the executed instruction in memory;
2459 it does not change the program counter.
2461 Perform this by recording the modified instruction in env->ex_value.
2462 This will be noticed by cpu_get_tb_cpu_state and thus tb translation.
2464 void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
2466 uint64_t insn = cpu_lduw_code(env, addr);
2467 uint8_t opc = insn >> 8;
2469 /* Or in the contents of R1[56:63]. */
2470 insn |= r1 & 0xff;
2472 /* Load the rest of the instruction. */
2473 insn <<= 48;
2474 switch (get_ilen(opc)) {
2475 case 2:
2476 break;
2477 case 4:
2478 insn |= (uint64_t)cpu_lduw_code(env, addr + 2) << 32;
2479 break;
2480 case 6:
2481 insn |= (uint64_t)(uint32_t)cpu_ldl_code(env, addr + 2) << 16;
2482 break;
2483 default:
2484 g_assert_not_reached();
2487 /* The very most common cases can be sped up by avoiding a new TB. */
2488 if ((opc & 0xf0) == 0xd0) {
2489 typedef uint32_t (*dx_helper)(CPUS390XState *, uint32_t, uint64_t,
2490 uint64_t, uintptr_t);
2491 static const dx_helper dx[16] = {
2492 [0x0] = do_helper_trt_bkwd,
2493 [0x2] = do_helper_mvc,
2494 [0x4] = do_helper_nc,
2495 [0x5] = do_helper_clc,
2496 [0x6] = do_helper_oc,
2497 [0x7] = do_helper_xc,
2498 [0xc] = do_helper_tr,
2499 [0xd] = do_helper_trt_fwd,
2501 dx_helper helper = dx[opc & 0xf];
2503 if (helper) {
2504 uint32_t l = extract64(insn, 48, 8);
2505 uint32_t b1 = extract64(insn, 44, 4);
2506 uint32_t d1 = extract64(insn, 32, 12);
2507 uint32_t b2 = extract64(insn, 28, 4);
2508 uint32_t d2 = extract64(insn, 16, 12);
2509 uint64_t a1 = wrap_address(env, env->regs[b1] + d1);
2510 uint64_t a2 = wrap_address(env, env->regs[b2] + d2);
2512 env->cc_op = helper(env, l, a1, a2, 0);
2513 env->psw.addr += ilen;
2514 return;
2516 } else if (opc == 0x0a) {
2517 env->int_svc_code = extract64(insn, 48, 8);
2518 env->int_svc_ilen = ilen;
2519 helper_exception(env, EXCP_SVC);
2520 g_assert_not_reached();
2523 /* Record the insn we want to execute as well as the ilen to use
2524 during the execution of the target insn. This will also ensure
2525 that ex_value is non-zero, which flags that we are in a state
2526 that requires such execution. */
2527 env->ex_value = insn | ilen;
2530 uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src,
2531 uint64_t len)
2533 const uint8_t psw_key = (env->psw.mask & PSW_MASK_KEY) >> PSW_SHIFT_KEY;
2534 const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
2535 const uint64_t r0 = env->regs[0];
2536 const uintptr_t ra = GETPC();
2537 uint8_t dest_key, dest_as, dest_k, dest_a;
2538 uint8_t src_key, src_as, src_k, src_a;
2539 uint64_t val;
2540 int cc = 0;
2542 HELPER_LOG("%s dest %" PRIx64 ", src %" PRIx64 ", len %" PRIx64 "\n",
2543 __func__, dest, src, len);
2545 if (!(env->psw.mask & PSW_MASK_DAT)) {
2546 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2549 /* OAC (operand access control) for the first operand -> dest */
2550 val = (r0 & 0xffff0000ULL) >> 16;
2551 dest_key = (val >> 12) & 0xf;
2552 dest_as = (val >> 6) & 0x3;
2553 dest_k = (val >> 1) & 0x1;
2554 dest_a = val & 0x1;
2556 /* OAC (operand access control) for the second operand -> src */
2557 val = (r0 & 0x0000ffffULL);
2558 src_key = (val >> 12) & 0xf;
2559 src_as = (val >> 6) & 0x3;
2560 src_k = (val >> 1) & 0x1;
2561 src_a = val & 0x1;
2563 if (!dest_k) {
2564 dest_key = psw_key;
2566 if (!src_k) {
2567 src_key = psw_key;
2569 if (!dest_a) {
2570 dest_as = psw_as;
2572 if (!src_a) {
2573 src_as = psw_as;
2576 if (dest_a && dest_as == AS_HOME && (env->psw.mask & PSW_MASK_PSTATE)) {
2577 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2579 if (!(env->cregs[0] & CR0_SECONDARY) &&
2580 (dest_as == AS_SECONDARY || src_as == AS_SECONDARY)) {
2581 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2583 if (!psw_key_valid(env, dest_key) || !psw_key_valid(env, src_key)) {
2584 tcg_s390_program_interrupt(env, PGM_PRIVILEGED, ra);
2587 len = wrap_length32(env, len);
2588 if (len > 4096) {
2589 cc = 3;
2590 len = 4096;
2593 /* FIXME: AR-mode and proper problem state mode (using PSW keys) missing */
2594 if (src_as == AS_ACCREG || dest_as == AS_ACCREG ||
2595 (env->psw.mask & PSW_MASK_PSTATE)) {
2596 qemu_log_mask(LOG_UNIMP, "%s: AR-mode and PSTATE support missing\n",
2597 __func__);
2598 tcg_s390_program_interrupt(env, PGM_ADDRESSING, ra);
2601 /* FIXME: Access using correct keys and AR-mode */
2602 if (len) {
2603 S390Access srca = access_prepare(env, src, len, MMU_DATA_LOAD,
2604 mmu_idx_from_as(src_as), ra);
2605 S390Access desta = access_prepare(env, dest, len, MMU_DATA_STORE,
2606 mmu_idx_from_as(dest_as), ra);
2608 access_memmove(env, &desta, &srca, ra);
2611 return cc;
2614 /* Decode a Unicode character. A return value < 0 indicates success, storing
2615 the UTF-32 result into OCHAR and the input length into OLEN. A return
2616 value >= 0 indicates failure, and the CC value to be returned. */
2617 typedef int (*decode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2618 uint64_t ilen, bool enh_check, uintptr_t ra,
2619 uint32_t *ochar, uint32_t *olen);
2621 /* Encode a Unicode character. A return value < 0 indicates success, storing
2622 the bytes into ADDR and the output length into OLEN. A return value >= 0
2623 indicates failure, and the CC value to be returned. */
2624 typedef int (*encode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2625 uint64_t ilen, uintptr_t ra, uint32_t c,
2626 uint32_t *olen);
2628 static int decode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2629 bool enh_check, uintptr_t ra,
2630 uint32_t *ochar, uint32_t *olen)
2632 uint8_t s0, s1, s2, s3;
2633 uint32_t c, l;
2635 if (ilen < 1) {
2636 return 0;
2638 s0 = cpu_ldub_data_ra(env, addr, ra);
2639 if (s0 <= 0x7f) {
2640 /* one byte character */
2641 l = 1;
2642 c = s0;
2643 } else if (s0 <= (enh_check ? 0xc1 : 0xbf)) {
2644 /* invalid character */
2645 return 2;
2646 } else if (s0 <= 0xdf) {
2647 /* two byte character */
2648 l = 2;
2649 if (ilen < 2) {
2650 return 0;
2652 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2653 c = s0 & 0x1f;
2654 c = (c << 6) | (s1 & 0x3f);
2655 if (enh_check && (s1 & 0xc0) != 0x80) {
2656 return 2;
2658 } else if (s0 <= 0xef) {
2659 /* three byte character */
2660 l = 3;
2661 if (ilen < 3) {
2662 return 0;
2664 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2665 s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2666 c = s0 & 0x0f;
2667 c = (c << 6) | (s1 & 0x3f);
2668 c = (c << 6) | (s2 & 0x3f);
2669 /* Fold the byte-by-byte range descriptions in the PoO into
2670 tests against the complete value. It disallows encodings
2671 that could be smaller, and the UTF-16 surrogates. */
2672 if (enh_check
2673 && ((s1 & 0xc0) != 0x80
2674 || (s2 & 0xc0) != 0x80
2675 || c < 0x1000
2676 || (c >= 0xd800 && c <= 0xdfff))) {
2677 return 2;
2679 } else if (s0 <= (enh_check ? 0xf4 : 0xf7)) {
2680 /* four byte character */
2681 l = 4;
2682 if (ilen < 4) {
2683 return 0;
2685 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2686 s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2687 s3 = cpu_ldub_data_ra(env, addr + 3, ra);
2688 c = s0 & 0x07;
2689 c = (c << 6) | (s1 & 0x3f);
2690 c = (c << 6) | (s2 & 0x3f);
2691 c = (c << 6) | (s3 & 0x3f);
2692 /* See above. */
2693 if (enh_check
2694 && ((s1 & 0xc0) != 0x80
2695 || (s2 & 0xc0) != 0x80
2696 || (s3 & 0xc0) != 0x80
2697 || c < 0x010000
2698 || c > 0x10ffff)) {
2699 return 2;
2701 } else {
2702 /* invalid character */
2703 return 2;
2706 *ochar = c;
2707 *olen = l;
2708 return -1;
2711 static int decode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2712 bool enh_check, uintptr_t ra,
2713 uint32_t *ochar, uint32_t *olen)
2715 uint16_t s0, s1;
2716 uint32_t c, l;
2718 if (ilen < 2) {
2719 return 0;
2721 s0 = cpu_lduw_data_ra(env, addr, ra);
2722 if ((s0 & 0xfc00) != 0xd800) {
2723 /* one word character */
2724 l = 2;
2725 c = s0;
2726 } else {
2727 /* two word character */
2728 l = 4;
2729 if (ilen < 4) {
2730 return 0;
2732 s1 = cpu_lduw_data_ra(env, addr + 2, ra);
2733 c = extract32(s0, 6, 4) + 1;
2734 c = (c << 6) | (s0 & 0x3f);
2735 c = (c << 10) | (s1 & 0x3ff);
2736 if (enh_check && (s1 & 0xfc00) != 0xdc00) {
2737 /* invalid surrogate character */
2738 return 2;
2742 *ochar = c;
2743 *olen = l;
2744 return -1;
2747 static int decode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2748 bool enh_check, uintptr_t ra,
2749 uint32_t *ochar, uint32_t *olen)
2751 uint32_t c;
2753 if (ilen < 4) {
2754 return 0;
2756 c = cpu_ldl_data_ra(env, addr, ra);
2757 if ((c >= 0xd800 && c <= 0xdbff) || c > 0x10ffff) {
2758 /* invalid unicode character */
2759 return 2;
2762 *ochar = c;
2763 *olen = 4;
2764 return -1;
2767 static int encode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2768 uintptr_t ra, uint32_t c, uint32_t *olen)
2770 uint8_t d[4];
2771 uint32_t l, i;
2773 if (c <= 0x7f) {
2774 /* one byte character */
2775 l = 1;
2776 d[0] = c;
2777 } else if (c <= 0x7ff) {
2778 /* two byte character */
2779 l = 2;
2780 d[1] = 0x80 | extract32(c, 0, 6);
2781 d[0] = 0xc0 | extract32(c, 6, 5);
2782 } else if (c <= 0xffff) {
2783 /* three byte character */
2784 l = 3;
2785 d[2] = 0x80 | extract32(c, 0, 6);
2786 d[1] = 0x80 | extract32(c, 6, 6);
2787 d[0] = 0xe0 | extract32(c, 12, 4);
2788 } else {
2789 /* four byte character */
2790 l = 4;
2791 d[3] = 0x80 | extract32(c, 0, 6);
2792 d[2] = 0x80 | extract32(c, 6, 6);
2793 d[1] = 0x80 | extract32(c, 12, 6);
2794 d[0] = 0xf0 | extract32(c, 18, 3);
2797 if (ilen < l) {
2798 return 1;
2800 for (i = 0; i < l; ++i) {
2801 cpu_stb_data_ra(env, addr + i, d[i], ra);
2804 *olen = l;
2805 return -1;
2808 static int encode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2809 uintptr_t ra, uint32_t c, uint32_t *olen)
2811 uint16_t d0, d1;
2813 if (c <= 0xffff) {
2814 /* one word character */
2815 if (ilen < 2) {
2816 return 1;
2818 cpu_stw_data_ra(env, addr, c, ra);
2819 *olen = 2;
2820 } else {
2821 /* two word character */
2822 if (ilen < 4) {
2823 return 1;
2825 d1 = 0xdc00 | extract32(c, 0, 10);
2826 d0 = 0xd800 | extract32(c, 10, 6);
2827 d0 = deposit32(d0, 6, 4, extract32(c, 16, 5) - 1);
2828 cpu_stw_data_ra(env, addr + 0, d0, ra);
2829 cpu_stw_data_ra(env, addr + 2, d1, ra);
2830 *olen = 4;
2833 return -1;
2836 static int encode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2837 uintptr_t ra, uint32_t c, uint32_t *olen)
2839 if (ilen < 4) {
2840 return 1;
2842 cpu_stl_data_ra(env, addr, c, ra);
2843 *olen = 4;
2844 return -1;
2847 static inline uint32_t convert_unicode(CPUS390XState *env, uint32_t r1,
2848 uint32_t r2, uint32_t m3, uintptr_t ra,
2849 decode_unicode_fn decode,
2850 encode_unicode_fn encode)
2852 uint64_t dst = get_address(env, r1);
2853 uint64_t dlen = get_length(env, r1 + 1);
2854 uint64_t src = get_address(env, r2);
2855 uint64_t slen = get_length(env, r2 + 1);
2856 bool enh_check = m3 & 1;
2857 int cc, i;
2859 /* Lest we fail to service interrupts in a timely manner, limit the
2860 amount of work we're willing to do. For now, let's cap at 256. */
2861 for (i = 0; i < 256; ++i) {
2862 uint32_t c, ilen, olen;
2864 cc = decode(env, src, slen, enh_check, ra, &c, &ilen);
2865 if (unlikely(cc >= 0)) {
2866 break;
2868 cc = encode(env, dst, dlen, ra, c, &olen);
2869 if (unlikely(cc >= 0)) {
2870 break;
2873 src += ilen;
2874 slen -= ilen;
2875 dst += olen;
2876 dlen -= olen;
2877 cc = 3;
2880 set_address(env, r1, dst);
2881 set_length(env, r1 + 1, dlen);
2882 set_address(env, r2, src);
2883 set_length(env, r2 + 1, slen);
2885 return cc;
2888 uint32_t HELPER(cu12)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2890 return convert_unicode(env, r1, r2, m3, GETPC(),
2891 decode_utf8, encode_utf16);
2894 uint32_t HELPER(cu14)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2896 return convert_unicode(env, r1, r2, m3, GETPC(),
2897 decode_utf8, encode_utf32);
2900 uint32_t HELPER(cu21)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2902 return convert_unicode(env, r1, r2, m3, GETPC(),
2903 decode_utf16, encode_utf8);
2906 uint32_t HELPER(cu24)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2908 return convert_unicode(env, r1, r2, m3, GETPC(),
2909 decode_utf16, encode_utf32);
2912 uint32_t HELPER(cu41)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2914 return convert_unicode(env, r1, r2, m3, GETPC(),
2915 decode_utf32, encode_utf8);
2918 uint32_t HELPER(cu42)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2920 return convert_unicode(env, r1, r2, m3, GETPC(),
2921 decode_utf32, encode_utf16);
2924 void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
2925 uintptr_t ra)
2927 /* test the actual access, not just any access to the page due to LAP */
2928 while (len) {
2929 const uint64_t pagelen = -(addr | TARGET_PAGE_MASK);
2930 const uint64_t curlen = MIN(pagelen, len);
2932 probe_write(env, addr, curlen, cpu_mmu_index(env, false), ra);
2933 addr = wrap_address(env, addr + curlen);
2934 len -= curlen;
2938 void HELPER(probe_write_access)(CPUS390XState *env, uint64_t addr, uint64_t len)
2940 probe_write_access(env, addr, len, GETPC());