]> git.proxmox.com Git - mirror_qemu.git/blame - target/s390x/mem_helper.c
Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2019-10-22-v3' into staging
[mirror_qemu.git] / target / s390x / mem_helper.c
CommitLineData
8ef7f78e
BS
1/*
2 * S/390 memory access helper routines
3 *
4 * Copyright (c) 2009 Ulrich Hecht
5 * Copyright (c) 2009 Alexander Graf
6 *
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
41c6a6dd 10 * version 2.1 of the License, or (at your option) any later version.
8ef7f78e
BS
11 *
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.
16 *
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/>.
19 */
20
9615495a 21#include "qemu/osdep.h"
8ef7f78e 22#include "cpu.h"
4e58b838 23#include "internal.h"
1e36aee6 24#include "tcg_s390x.h"
2ef6175a 25#include "exec/helper-proto.h"
63c91552 26#include "exec/exec-all.h"
f08b6170 27#include "exec/cpu_ldst.h"
303a9ab8 28#include "qemu/int128.h"
5e95612e 29#include "qemu/atomic128.h"
741da0d3
PB
30
31#if !defined(CONFIG_USER_ONLY)
0f5f6691 32#include "hw/s390x/storage-keys.h"
741da0d3 33#endif
8ef7f78e
BS
34
35/*****************************************************************************/
36/* Softmmu support */
8ef7f78e
BS
37
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
44
c07a1009
DH
45static inline bool psw_key_valid(CPUS390XState *env, uint8_t psw_key)
46{
47 uint16_t pkm = env->cregs[3] >> 16;
48
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);
52 }
53 return true;
54}
55
fbc17598
DH
56static bool is_destructive_overlap(CPUS390XState *env, uint64_t dest,
57 uint64_t src, uint32_t len)
58{
59 if (!len || src == dest) {
60 return false;
61 }
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);
65 }
66 return dest > src && dest <= src + len - 1;
67}
68
31006af3
AJ
69/* Trigger a SPECIFICATION exception if an address or a length is not
70 naturally aligned. */
71static inline void check_alignment(CPUS390XState *env, uint64_t v,
72 int wordsize, uintptr_t ra)
73{
74 if (v % wordsize) {
1e36aee6 75 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
31006af3
AJ
76 }
77}
78
79/* Load a value from memory according to its size. */
80static inline uint64_t cpu_ldusize_data_ra(CPUS390XState *env, uint64_t addr,
81 int wordsize, uintptr_t ra)
82{
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();
90 }
91}
92
15417787
AJ
93/* Store a to memory according to its size. */
94static inline void cpu_stsize_data_ra(CPUS390XState *env, uint64_t addr,
95 uint64_t value, int wordsize,
96 uintptr_t ra)
97{
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();
107 }
108}
109
70ebd9ce
DH
110/* An access covers at most 4096 bytes and therefore at most two pages. */
111typedef struct S390Access {
112 target_ulong vaddr1;
113 target_ulong vaddr2;
114 char *haddr1;
115 char *haddr2;
116 uint16_t size1;
117 uint16_t size2;
118 /*
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.
127 */
128 int mmu_idx;
129} S390Access;
130
131static S390Access access_prepare(CPUS390XState *env, vaddr vaddr, int size,
132 MMUAccessType access_type, int mmu_idx,
133 uintptr_t ra)
8ef7f78e 134{
70ebd9ce
DH
135 S390Access access = {
136 .vaddr1 = vaddr,
137 .size1 = MIN(size, -(vaddr | TARGET_PAGE_MASK)),
138 .mmu_idx = mmu_idx,
139 };
fc89efe6 140
70ebd9ce
DH
141 g_assert(size > 0 && size <= 4096);
142 access.haddr1 = probe_access(env, access.vaddr1, access.size1, access_type,
143 mmu_idx, ra);
144
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);
151 }
152 return access;
153}
154
155/* Helper to handle memset on a single page. */
156static void do_access_memset(CPUS390XState *env, vaddr vaddr, char *haddr,
157 uint8_t byte, uint16_t size, int mmu_idx,
158 uintptr_t ra)
159{
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;
166
167 if (likely(haddr)) {
168 memset(haddr, byte, size);
169 } else {
170 /*
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.
173 */
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);
fc89efe6 179 } else {
70ebd9ce
DH
180 for (i = 1; i < size; i++) {
181 helper_ret_stb_mmu(env, vaddr + i, byte, oi, ra);
182 }
fc89efe6 183 }
8ef7f78e 184 }
70ebd9ce
DH
185#endif
186}
187
188static void access_memset(CPUS390XState *env, S390Access *desta,
189 uint8_t byte, uintptr_t ra)
190{
191
192 do_access_memset(env, desta->vaddr1, desta->haddr1, byte, desta->size1,
193 desta->mmu_idx, ra);
194 if (likely(!desta->size2)) {
195 return;
196 }
197 do_access_memset(env, desta->vaddr2, desta->haddr2, byte, desta->size2,
198 desta->mmu_idx, ra);
8ef7f78e
BS
199}
200
b6c636f2
DH
201static uint8_t do_access_get_byte(CPUS390XState *env, vaddr vaddr, char **haddr,
202 int offset, int mmu_idx, uintptr_t ra)
3e7e5e0b 203{
b6c636f2
DH
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;
209
210 if (likely(*haddr)) {
211 return ldub_p(*haddr + offset);
212 }
213 /*
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.
216 */
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
221}
222
223static uint8_t access_get_byte(CPUS390XState *env, S390Access *access,
224 int offset, uintptr_t ra)
225{
226 if (offset < access->size1) {
227 return do_access_get_byte(env, access->vaddr1, &access->haddr1,
228 offset, access->mmu_idx, ra);
229 }
230 return do_access_get_byte(env, access->vaddr2, &access->haddr2,
231 offset - access->size1, access->mmu_idx, ra);
232}
233
234static void do_access_set_byte(CPUS390XState *env, vaddr vaddr, char **haddr,
235 int offset, uint8_t byte, int mmu_idx,
236 uintptr_t ra)
237{
238#ifdef CONFIG_USER_ONLY
239 stb_p(*haddr + offset, byte);
240#else
241 TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
242
243 if (likely(*haddr)) {
244 stb_p(*haddr + offset, byte);
245 return;
246 }
247 /*
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.
250 */
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
254}
255
256static void access_set_byte(CPUS390XState *env, S390Access *access,
257 int offset, uint8_t byte, uintptr_t ra)
258{
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);
265 }
266}
267
268/*
269 * Move data with the same semantics as memmove() in case ranges don't overlap
270 * or src > dest. Undefined behavior on destructive overlaps.
271 */
272static void access_memmove(CPUS390XState *env, S390Access *desta,
273 S390Access *srca, uintptr_t ra)
274{
275 int diff;
276
277 g_assert(desta->size1 + desta->size2 == srca->size1 + srca->size2);
278
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;
283
284 for (i = 0; i < desta->size1 + desta->size2; i++) {
285 uint8_t byte = access_get_byte(env, srca, i, ra);
286
287 access_set_byte(env, desta, i, byte, ra);
288 }
289 return;
290 }
291
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);
296 }
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);
303 }
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);
3e7e5e0b 310 }
3e7e5e0b
DH
311 }
312}
313
314static int mmu_idx_from_as(uint8_t as)
315{
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();
326 }
327}
328
8ef7f78e 329/* and on array */
349d078a
RH
330static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest,
331 uint64_t src, uintptr_t ra)
8ef7f78e 332{
4d78c68b
DH
333 const int mmu_idx = cpu_mmu_index(env, false);
334 S390Access srca1, srca2, desta;
349d078a
RH
335 uint32_t i;
336 uint8_t c = 0;
8ef7f78e
BS
337
338 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
339 __func__, l, dest, src);
349d078a 340
4d78c68b
DH
341 /* NC always processes one more byte than specified - maximum is 256 */
342 l++;
343
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);
350
349d078a 351 c |= x;
4d78c68b 352 access_set_byte(env, &desta, i, x, ra);
8ef7f78e 353 }
349d078a
RH
354 return c != 0;
355}
356
357uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
358 uint64_t src)
359{
360 return do_helper_nc(env, l, dest, src, GETPC());
8ef7f78e
BS
361}
362
363/* xor on array */
9c009e88
RH
364static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest,
365 uint64_t src, uintptr_t ra)
8ef7f78e 366{
70ebd9ce 367 const int mmu_idx = cpu_mmu_index(env, false);
a8821dd5 368 S390Access srca1, srca2, desta;
9c009e88
RH
369 uint32_t i;
370 uint8_t c = 0;
8ef7f78e
BS
371
372 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
373 __func__, l, dest, src);
374
a8821dd5
DH
375 /* XC always processes one more byte than specified - maximum is 256 */
376 l++;
377
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);
70ebd9ce 381
8ef7f78e 382 /* xor with itself is the same as memset(0) */
8ef7f78e 383 if (src == dest) {
70ebd9ce 384 access_memset(env, &desta, 0, ra);
8ef7f78e
BS
385 return 0;
386 }
8ef7f78e 387
a8821dd5
DH
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);
391
9c009e88 392 c |= x;
a8821dd5 393 access_set_byte(env, &desta, i, x, ra);
8ef7f78e 394 }
9c009e88
RH
395 return c != 0;
396}
397
398uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
399 uint64_t src)
400{
401 return do_helper_xc(env, l, dest, src, GETPC());
8ef7f78e
BS
402}
403
404/* or on array */
6fc2606e
RH
405static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest,
406 uint64_t src, uintptr_t ra)
8ef7f78e 407{
8c4a7320
DH
408 const int mmu_idx = cpu_mmu_index(env, false);
409 S390Access srca1, srca2, desta;
6fc2606e
RH
410 uint32_t i;
411 uint8_t c = 0;
8ef7f78e
BS
412
413 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
414 __func__, l, dest, src);
6fc2606e 415
8c4a7320
DH
416 /* OC always processes one more byte than specified - maximum is 256 */
417 l++;
418
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);
425
6fc2606e 426 c |= x;
8c4a7320 427 access_set_byte(env, &desta, i, x, ra);
8ef7f78e 428 }
6fc2606e
RH
429 return c != 0;
430}
431
432uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
433 uint64_t src)
434{
435 return do_helper_oc(env, l, dest, src, GETPC());
8ef7f78e
BS
436}
437
438/* memmove */
d376f123
RH
439static uint32_t do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest,
440 uint64_t src, uintptr_t ra)
8ef7f78e 441{
70ebd9ce 442 const int mmu_idx = cpu_mmu_index(env, false);
b6c636f2 443 S390Access srca, desta;
d3696812 444 uint32_t i;
8ef7f78e
BS
445
446 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
447 __func__, l, dest, src);
448
d573ffde
DH
449 /* MVC always copies one more byte than specified - maximum is 256 */
450 l++;
451
b6c636f2 452 srca = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
70ebd9ce
DH
453 desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
454
d573ffde
DH
455 /*
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().
459 */
d3696812 460 if (dest == src + 1) {
b6c636f2 461 access_memset(env, &desta, access_get_byte(env, &srca, 0, ra), ra);
b7dd1f7f 462 } else if (!is_destructive_overlap(env, dest, src, l)) {
b6c636f2 463 access_memmove(env, &desta, &srca, ra);
d376f123 464 } else {
d573ffde 465 for (i = 0; i < l; i++) {
b7809f36
DH
466 uint8_t byte = access_get_byte(env, &srca, i, ra);
467
468 access_set_byte(env, &desta, i, byte, ra);
d376f123 469 }
8ef7f78e 470 }
8ef7f78e 471
d376f123 472 return env->cc_op;
8ef7f78e
BS
473}
474
d3696812
RH
475void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
476{
477 do_helper_mvc(env, l, dest, src, GETPC());
478}
479
6c9deca8
AJ
480/* move inverse */
481void HELPER(mvcin)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
482{
65a27df9
DH
483 const int mmu_idx = cpu_mmu_index(env, false);
484 S390Access srca, desta;
6c9deca8
AJ
485 uintptr_t ra = GETPC();
486 int i;
487
65a27df9
DH
488 /* MVCIN always copies one more byte than specified - maximum is 256 */
489 l++;
490
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);
496
497 access_set_byte(env, &desta, i, x, ra);
6c9deca8
AJ
498 }
499}
500
256dab6f
AJ
501/* move numerics */
502void HELPER(mvn)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
503{
ab8bab68
DH
504 const int mmu_idx = cpu_mmu_index(env, false);
505 S390Access srca1, srca2, desta;
256dab6f
AJ
506 uintptr_t ra = GETPC();
507 int i;
508
ab8bab68
DH
509 /* MVN always copies one more byte than specified - maximum is 256 */
510 l++;
511
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);
518
519 access_set_byte(env, &desta, i, x, ra);
256dab6f
AJ
520 }
521}
522
fdc0a747
AJ
523/* move with offset */
524void HELPER(mvo)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
525{
ab89acd0
DH
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;
fdc0a747 530 uintptr_t ra = GETPC();
fdc0a747 531 uint8_t byte_dest, byte_src;
ab89acd0
DH
532 S390Access srca, desta;
533 int i, j;
fdc0a747 534
ab89acd0
DH
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);
fdc0a747
AJ
537
538 /* Handle rightmost byte */
ab89acd0
DH
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);
fdc0a747 541 byte_dest = (byte_dest & 0x0f) | (byte_src << 4);
ab89acd0 542 access_set_byte(env, &desta, len_dest - 1, byte_dest, ra);
fdc0a747
AJ
543
544 /* Process remaining bytes from right to left */
ab89acd0 545 for (i = len_dest - 2, j = len_src - 2; i >= 0; i--, j--) {
fdc0a747 546 byte_dest = byte_src >> 4;
ab89acd0
DH
547 if (j >= 0) {
548 byte_src = access_get_byte(env, &srca, j, ra);
fdc0a747
AJ
549 } else {
550 byte_src = 0;
551 }
552 byte_dest |= byte_src << 4;
ab89acd0 553 access_set_byte(env, &desta, i, byte_dest, ra);
fdc0a747
AJ
554 }
555}
556
01f8db88
AJ
557/* move zones */
558void HELPER(mvz)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
559{
6514f42b
DH
560 const int mmu_idx = cpu_mmu_index(env, false);
561 S390Access srca1, srca2, desta;
01f8db88
AJ
562 uintptr_t ra = GETPC();
563 int i;
564
6514f42b
DH
565 /* MVZ always copies one more byte than specified - maximum is 256 */
566 l++;
567
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);
574
575 access_set_byte(env, &desta, i, x, ra);
01f8db88
AJ
576 }
577}
578
8ef7f78e 579/* compare unsigned byte arrays */
e79f56f4
RH
580static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1,
581 uint64_t s2, uintptr_t ra)
8ef7f78e 582{
e79f56f4
RH
583 uint32_t i;
584 uint32_t cc = 0;
8ef7f78e
BS
585
586 HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
587 __func__, l, s1, s2);
e79f56f4 588
8ef7f78e 589 for (i = 0; i <= l; i++) {
e79f56f4
RH
590 uint8_t x = cpu_ldub_data_ra(env, s1 + i, ra);
591 uint8_t y = cpu_ldub_data_ra(env, s2 + i, ra);
8ef7f78e
BS
592 HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
593 if (x < y) {
594 cc = 1;
e79f56f4 595 break;
8ef7f78e
BS
596 } else if (x > y) {
597 cc = 2;
e79f56f4 598 break;
8ef7f78e
BS
599 }
600 }
e79f56f4 601
8ef7f78e
BS
602 HELPER_LOG("\n");
603 return cc;
604}
605
e79f56f4
RH
606uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2)
607{
608 return do_helper_clc(env, l, s1, s2, GETPC());
609}
610
8ef7f78e 611/* compare logical under mask */
19b0516f
BS
612uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
613 uint64_t addr)
8ef7f78e 614{
868b5cbd
RH
615 uintptr_t ra = GETPC();
616 uint32_t cc = 0;
8ef7f78e
BS
617
618 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
619 mask, addr);
868b5cbd 620
8ef7f78e
BS
621 while (mask) {
622 if (mask & 8) {
868b5cbd
RH
623 uint8_t d = cpu_ldub_data_ra(env, addr, ra);
624 uint8_t r = extract32(r1, 24, 8);
8ef7f78e
BS
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;
633 }
634 addr++;
635 }
636 mask = (mask << 1) & 0xf;
637 r1 <<= 8;
638 }
868b5cbd 639
8ef7f78e
BS
640 HELPER_LOG("\n");
641 return cc;
642}
643
a5c3cedd 644static inline uint64_t get_address(CPUS390XState *env, int reg)
8ef7f78e 645{
a5c3cedd 646 return wrap_address(env, env->regs[reg]);
8ef7f78e
BS
647}
648
d292671a
DH
649/*
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).
652 */
653static inline void set_address_zero(CPUS390XState *env, int reg,
654 uint64_t address)
655{
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;
663 }
664 env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
665 }
666}
667
a65047af
AJ
668static inline void set_address(CPUS390XState *env, int reg, uint64_t address)
669{
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);
687 }
688 }
689}
690
a7627565
DH
691static inline uint64_t wrap_length32(CPUS390XState *env, uint64_t length)
692{
693 if (!(env->psw.mask & PSW_MASK_64)) {
694 return (uint32_t)length;
695 }
696 return length;
697}
698
699static inline uint64_t wrap_length31(CPUS390XState *env, uint64_t length)
29a58fd8
AJ
700{
701 if (!(env->psw.mask & PSW_MASK_64)) {
702 /* 24-Bit and 31-Bit mode */
703 length &= 0x7fffffff;
704 }
705 return length;
706}
707
708static inline uint64_t get_length(CPUS390XState *env, int reg)
709{
a7627565 710 return wrap_length31(env, env->regs[reg]);
29a58fd8
AJ
711}
712
713static inline void set_length(CPUS390XState *env, int reg, uint64_t length)
714{
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);
721 }
722}
723
8ef7f78e 724/* search string (c is byte to search, r2 is string, r1 end of string) */
7591db78 725void HELPER(srst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
8ef7f78e 726{
4663e822 727 uintptr_t ra = GETPC();
7591db78 728 uint64_t end, str;
4600c994 729 uint32_t len;
7591db78 730 uint8_t v, c = env->regs[0];
8ef7f78e 731
7591db78
RH
732 /* Bits 32-55 must contain all 0. */
733 if (env->regs[0] & 0xffffff00u) {
1e36aee6 734 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
7591db78 735 }
8ef7f78e 736
7591db78
RH
737 str = get_address(env, r2);
738 end = get_address(env, r1);
4600c994
RH
739
740 /* Lest we fail to service interrupts in a timely manner, limit the
e03ba136 741 amount of work we're willing to do. For now, let's cap at 8k. */
4600c994
RH
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;
7591db78 746 return;
4600c994 747 }
4663e822 748 v = cpu_ldub_data_ra(env, str + len, ra);
4600c994
RH
749 if (v == c) {
750 /* Character found. Set R1 to the location; R2 is unmodified. */
751 env->cc_op = 1;
7591db78
RH
752 set_address(env, r1, str + len);
753 return;
8ef7f78e
BS
754 }
755 }
756
be7acb58
RH
757 /* CPU-determined bytes processed. Advance R2 to next byte to process. */
758 env->cc_op = 3;
759 set_address(env, r2, str + len);
760}
761
762void HELPER(srstu)(CPUS390XState *env, uint32_t r1, uint32_t r2)
763{
764 uintptr_t ra = GETPC();
765 uint32_t len;
766 uint16_t v, c = env->regs[0];
767 uint64_t end, str, adj_end;
768
769 /* Bits 32-47 of R0 must be zero. */
770 if (env->regs[0] & 0xffff0000u) {
1e36aee6 771 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
be7acb58
RH
772 }
773
774 str = get_address(env, r2);
775 end = get_address(env, r1);
776
777 /* If the LSB of the two addresses differ, use one extra byte. */
778 adj_end = end + ((str ^ end) & 1);
779
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;
787 }
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;
794 }
795 }
796
4600c994 797 /* CPU-determined bytes processed. Advance R2 to next byte to process. */
4600c994 798 env->cc_op = 3;
7591db78 799 set_address(env, r2, str + len);
8ef7f78e
BS
800}
801
802/* unsigned string compare (c is string terminator) */
aa31bf60 803uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
8ef7f78e 804{
3cc8ca3d 805 uintptr_t ra = GETPC();
aa31bf60 806 uint32_t len;
8ef7f78e
BS
807
808 c = c & 0xff;
a5c3cedd
AJ
809 s1 = wrap_address(env, s1);
810 s2 = wrap_address(env, s2);
aa31bf60
RH
811
812 /* Lest we fail to service interrupts in a timely manner, limit the
e03ba136 813 amount of work we're willing to do. For now, let's cap at 8k. */
aa31bf60 814 for (len = 0; len < 0x2000; ++len) {
3cc8ca3d
RH
815 uint8_t v1 = cpu_ldub_data_ra(env, s1 + len, ra);
816 uint8_t v2 = cpu_ldub_data_ra(env, s2 + len, ra);
aa31bf60
RH
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;
823 }
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;
8ef7f78e 831 }
8ef7f78e
BS
832 }
833
aa31bf60
RH
834 /* CPU-determined bytes equal; advance the registers. */
835 env->cc_op = 3;
836 env->retxl = s2 + len;
837 return s1 + len;
8ef7f78e
BS
838}
839
840/* move page */
7cf96fca 841uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
8ef7f78e 842{
b6c636f2 843 const int mmu_idx = cpu_mmu_index(env, false);
bf349f1a
DH
844 const bool f = extract64(r0, 11, 1);
845 const bool s = extract64(r0, 10, 1);
b6c636f2
DH
846 uintptr_t ra = GETPC();
847 S390Access srca, desta;
bf349f1a
DH
848
849 if ((f && s) || extract64(r0, 12, 4)) {
1e36aee6 850 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
bf349f1a
DH
851 }
852
a3910396
DH
853 r1 = wrap_address(env, r1 & TARGET_PAGE_MASK);
854 r2 = wrap_address(env, r2 & TARGET_PAGE_MASK);
855
856 /*
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
861 */
b6c636f2
DH
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);
7cf96fca 867 return 0; /* data moved */
8ef7f78e
BS
868}
869
2bb525e2
DH
870/* string copy */
871uint32_t HELPER(mvst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
8ef7f78e 872{
bb36ed88 873 const int mmu_idx = cpu_mmu_index(env, false);
2bb525e2
DH
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];
bb36ed88
DH
877 const int len = MIN(-(d | TARGET_PAGE_MASK), -(s | TARGET_PAGE_MASK));
878 S390Access srca, desta;
08a4cb79 879 uintptr_t ra = GETPC();
bb36ed88 880 int i;
8ef7f78e 881
2bb525e2 882 if (env->regs[0] & 0xffffff00ull) {
1e36aee6 883 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
087b8193 884 }
aa31bf60 885
bb36ed88
DH
886 /*
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).
891 */
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);
896
897 access_set_byte(env, &desta, i, v, ra);
8ef7f78e 898 if (v == c) {
bb36ed88 899 set_address_zero(env, r1, d + i);
2bb525e2 900 return 1;
8ef7f78e 901 }
8ef7f78e 902 }
2bb525e2
DH
903 set_address_zero(env, r1, d + len);
904 set_address_zero(env, r2, s + len);
905 return 3;
8ef7f78e
BS
906}
907
8ef7f78e 908/* load access registers r1 to r3 from memory at a2 */
19b0516f 909void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
8ef7f78e 910{
9393c020 911 uintptr_t ra = GETPC();
8ef7f78e
BS
912 int i;
913
21fc97c5 914 if (a2 & 0x3) {
1e36aee6 915 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
21fc97c5
DH
916 }
917
8ef7f78e 918 for (i = r1;; i = (i + 1) % 16) {
9393c020 919 env->aregs[i] = cpu_ldl_data_ra(env, a2, ra);
8ef7f78e
BS
920 a2 += 4;
921
922 if (i == r3) {
923 break;
924 }
925 }
926}
927
928/* store access registers r1 to r3 in memory at a2 */
19b0516f 929void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
8ef7f78e 930{
44cf6c2e 931 uintptr_t ra = GETPC();
8ef7f78e
BS
932 int i;
933
21fc97c5 934 if (a2 & 0x3) {
1e36aee6 935 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
21fc97c5
DH
936 }
937
8ef7f78e 938 for (i = r1;; i = (i + 1) % 16) {
44cf6c2e 939 cpu_stl_data_ra(env, a2, env->aregs[i], ra);
8ef7f78e
BS
940 a2 += 4;
941
942 if (i == r3) {
943 break;
944 }
945 }
946}
947
d3327121
AJ
948/* move long helper */
949static inline uint32_t do_mvcl(CPUS390XState *env,
950 uint64_t *dest, uint64_t *destlen,
951 uint64_t *src, uint64_t *srclen,
16f2e4b8 952 uint16_t pad, int wordsize, uintptr_t ra)
8ef7f78e 953{
70ebd9ce 954 const int mmu_idx = cpu_mmu_index(env, false);
86678418 955 int len = MIN(*destlen, -(*dest | TARGET_PAGE_MASK));
b6c636f2 956 S390Access srca, desta;
86678418 957 int i, cc;
8ef7f78e 958
d3327121 959 if (*destlen == *srclen) {
8ef7f78e 960 cc = 0;
d3327121 961 } else if (*destlen < *srclen) {
8ef7f78e
BS
962 cc = 1;
963 } else {
964 cc = 2;
965 }
966
86678418
DH
967 if (!*destlen) {
968 return cc;
969 }
8ef7f78e 970
86678418
DH
971 /*
972 * Only perform one type of type of operation (move/pad) at a time.
973 * Stay within single pages.
974 */
975 if (*srclen) {
976 /* Copy the src array */
977 len = MIN(MIN(*srclen, -(*src | TARGET_PAGE_MASK)), len);
978 *destlen -= len;
979 *srclen -= len;
b6c636f2
DH
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);
86678418
DH
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;
70ebd9ce
DH
988 desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
989 access_memset(env, &desta, pad, ra);
86678418 990 *dest = wrap_address(env, *dest + len);
16f2e4b8 991 } else {
b8e7b2fe
DH
992 desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
993
86678418
DH
994 /* The remaining length selects the padding byte. */
995 for (i = 0; i < len; (*destlen)--, i++) {
996 if (*destlen & 1) {
b8e7b2fe 997 access_set_byte(env, &desta, i, pad, ra);
86678418 998 } else {
b8e7b2fe 999 access_set_byte(env, &desta, i, pad >> 8, ra);
86678418 1000 }
16f2e4b8 1001 }
b8e7b2fe 1002 *dest = wrap_address(env, *dest + len);
16f2e4b8 1003 }
8ef7f78e 1004
86678418 1005 return *destlen ? 3 : cc;
d3327121
AJ
1006}
1007
1008/* move long */
1009uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
1010{
70ebd9ce 1011 const int mmu_idx = cpu_mmu_index(env, false);
d3327121
AJ
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;
1f6493be 1018 CPUState *cs = env_cpu(env);
b6c636f2 1019 S390Access srca, desta;
f1c2e27c 1020 uint32_t cc, cur_len;
d3327121 1021
fbc17598
DH
1022 if (is_destructive_overlap(env, dest, src, MIN(srclen, destlen))) {
1023 cc = 3;
f1c2e27c
DH
1024 } else if (srclen == destlen) {
1025 cc = 0;
1026 } else if (destlen < srclen) {
1027 cc = 1;
fbc17598 1028 } else {
f1c2e27c
DH
1029 cc = 2;
1030 }
1031
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);
fbc17598 1039 }
8ef7f78e 1040
f1c2e27c
DH
1041 /*
1042 * Only perform one type of type of operation (move/pad) in one step.
1043 * Stay within single pages.
1044 */
1045 while (destlen) {
1046 cur_len = MIN(destlen, -(dest | TARGET_PAGE_MASK));
1047 if (!srclen) {
70ebd9ce
DH
1048 desta = access_prepare(env, dest, cur_len, MMU_DATA_STORE, mmu_idx,
1049 ra);
1050 access_memset(env, &desta, pad, ra);
f1c2e27c
DH
1051 } else {
1052 cur_len = MIN(MIN(srclen, -(src | TARGET_PAGE_MASK)), cur_len);
8ef7f78e 1053
b6c636f2
DH
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);
f1c2e27c
DH
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);
1063 }
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);
1068
1f6493be
DH
1069 /*
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.
1074 */
1075 if (destlen && unlikely(cpu_loop_exit_requested(cs))) {
1076 cpu_loop_exit_restore(cs, ra);
1077 }
f1c2e27c 1078 }
8ef7f78e
BS
1079 return cc;
1080}
1081
d3327121 1082/* move long extended */
19b0516f
BS
1083uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1084 uint32_t r3)
8ef7f78e 1085{
453e4c07 1086 uintptr_t ra = GETPC();
29a58fd8 1087 uint64_t destlen = get_length(env, r1 + 1);
a5c3cedd 1088 uint64_t dest = get_address(env, r1);
29a58fd8 1089 uint64_t srclen = get_length(env, r3 + 1);
a5c3cedd 1090 uint64_t src = get_address(env, r3);
d3327121 1091 uint8_t pad = a2;
8ef7f78e
BS
1092 uint32_t cc;
1093
16f2e4b8
AJ
1094 cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra);
1095
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);
1100
1101 return cc;
1102}
1103
1104/* move long unicode */
1105uint32_t HELPER(mvclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1106 uint32_t r3)
1107{
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;
1115
1116 cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 2, ra);
8ef7f78e 1117
d3327121
AJ
1118 set_length(env, r1 + 1, destlen);
1119 set_length(env, r3 + 1, srclen);
a65047af
AJ
1120 set_address(env, r1, dest);
1121 set_address(env, r3, src);
8ef7f78e
BS
1122
1123 return cc;
1124}
1125
5c2b48a8
AJ
1126/* compare logical long helper */
1127static inline uint32_t do_clcl(CPUS390XState *env,
1128 uint64_t *src1, uint64_t *src1len,
1129 uint64_t *src3, uint64_t *src3len,
31006af3
AJ
1130 uint16_t pad, uint64_t limit,
1131 int wordsize, uintptr_t ra)
5c2b48a8
AJ
1132{
1133 uint64_t len = MAX(*src1len, *src3len);
8ef7f78e
BS
1134 uint32_t cc = 0;
1135
31006af3
AJ
1136 check_alignment(env, *src1len | *src3len, wordsize, ra);
1137
84aa07f1 1138 if (!len) {
8ef7f78e
BS
1139 return cc;
1140 }
1141
84aa07f1 1142 /* Lest we fail to service interrupts in a timely manner, limit the
5c2b48a8
AJ
1143 amount of work we're willing to do. */
1144 if (len > limit) {
1145 len = limit;
84aa07f1 1146 cc = 3;
8ef7f78e
BS
1147 }
1148
31006af3
AJ
1149 for (; len; len -= wordsize) {
1150 uint16_t v1 = pad;
1151 uint16_t v3 = pad;
84aa07f1 1152
5c2b48a8 1153 if (*src1len) {
31006af3 1154 v1 = cpu_ldusize_data_ra(env, *src1, wordsize, ra);
84aa07f1 1155 }
5c2b48a8 1156 if (*src3len) {
31006af3 1157 v3 = cpu_ldusize_data_ra(env, *src3, wordsize, ra);
84aa07f1
AJ
1158 }
1159
1160 if (v1 != v3) {
1161 cc = (v1 < v3) ? 1 : 2;
8ef7f78e
BS
1162 break;
1163 }
84aa07f1 1164
5c2b48a8 1165 if (*src1len) {
31006af3
AJ
1166 *src1 += wordsize;
1167 *src1len -= wordsize;
84aa07f1 1168 }
5c2b48a8 1169 if (*src3len) {
31006af3
AJ
1170 *src3 += wordsize;
1171 *src3len -= wordsize;
84aa07f1 1172 }
8ef7f78e
BS
1173 }
1174
5c2b48a8
AJ
1175 return cc;
1176}
1177
1178
1179/* compare logical long */
1180uint32_t HELPER(clcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
1181{
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;
1189
31006af3 1190 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, -1, 1, ra);
5c2b48a8
AJ
1191
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);
1196
1197 return cc;
1198}
1199
1200/* compare logical long extended memcompare insn with padding */
1201uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1202 uint32_t r3)
1203{
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;
1211
31006af3
AJ
1212 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x2000, 1, ra);
1213
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);
1218
1219 return cc;
1220}
1221
1222/* compare logical long unicode memcompare insn with padding */
1223uint32_t HELPER(clclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1224 uint32_t r3)
1225{
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;
1233
1234 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x1000, 2, ra);
5c2b48a8 1235
84aa07f1
AJ
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);
8ef7f78e
BS
1240
1241 return cc;
1242}
1243
1244/* checksum */
374724f9
RH
1245uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
1246 uint64_t src, uint64_t src_len)
8ef7f78e 1247{
498644e9 1248 uintptr_t ra = GETPC();
374724f9
RH
1249 uint64_t max_len, len;
1250 uint64_t cksm = (uint32_t)r1;
8ef7f78e 1251
374724f9 1252 /* Lest we fail to service interrupts in a timely manner, limit the
e03ba136 1253 amount of work we're willing to do. For now, let's cap at 8k. */
374724f9 1254 max_len = (src_len > 0x2000 ? 0x2000 : src_len);
8ef7f78e 1255
374724f9
RH
1256 /* Process full words as available. */
1257 for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
498644e9 1258 cksm += (uint32_t)cpu_ldl_data_ra(env, src, ra);
8ef7f78e
BS
1259 }
1260
374724f9 1261 switch (max_len - len) {
8ef7f78e 1262 case 1:
498644e9 1263 cksm += cpu_ldub_data_ra(env, src, ra) << 24;
374724f9 1264 len += 1;
8ef7f78e
BS
1265 break;
1266 case 2:
498644e9 1267 cksm += cpu_lduw_data_ra(env, src, ra) << 16;
374724f9 1268 len += 2;
8ef7f78e
BS
1269 break;
1270 case 3:
498644e9
RH
1271 cksm += cpu_lduw_data_ra(env, src, ra) << 16;
1272 cksm += cpu_ldub_data_ra(env, src + 2, ra) << 8;
374724f9 1273 len += 3;
8ef7f78e
BS
1274 break;
1275 }
1276
374724f9
RH
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);
1281 }
1282
1283 /* Indicate whether or not we've processed everything. */
1284 env->cc_op = (len == src_len ? 0 : 3);
8ef7f78e 1285
374724f9
RH
1286 /* Return both cksm and processed length. */
1287 env->retxl = cksm;
1288 return len;
8ef7f78e
BS
1289}
1290
76c57490
AJ
1291void HELPER(pack)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src)
1292{
1293 uintptr_t ra = GETPC();
1294 int len_dest = len >> 4;
1295 int len_src = len & 0xf;
1296 uint8_t b;
1297
1298 dest += len_dest;
1299 src += len_src;
1300
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--;
1306
1307 /* now pack every value */
3cea0927 1308 while (len_dest > 0) {
76c57490
AJ
1309 b = 0;
1310
3cea0927 1311 if (len_src >= 0) {
76c57490
AJ
1312 b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
1313 src--;
1314 len_src--;
1315 }
3cea0927 1316 if (len_src >= 0) {
76c57490
AJ
1317 b |= cpu_ldub_data_ra(env, src, ra) << 4;
1318 src--;
1319 len_src--;
1320 }
1321
1322 len_dest--;
1323 dest--;
1324 cpu_stb_data_ra(env, dest, b, ra);
1325 }
1326}
1327
4e256bef
AJ
1328static inline void do_pkau(CPUS390XState *env, uint64_t dest, uint64_t src,
1329 uint32_t srclen, int ssize, uintptr_t ra)
3bd3d6d3 1330{
3bd3d6d3
AJ
1331 int i;
1332 /* The destination operand is always 16 bytes long. */
1333 const int destlen = 16;
1334
1335 /* The operands are processed from right to left. */
1336 src += srclen - 1;
1337 dest += destlen - 1;
1338
1339 for (i = 0; i < destlen; i++) {
1340 uint8_t b = 0;
1341
1342 /* Start with a positive sign */
1343 if (i == 0) {
1344 b = 0xc;
4e256bef 1345 } else if (srclen > ssize) {
3bd3d6d3 1346 b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
4e256bef
AJ
1347 src -= ssize;
1348 srclen -= ssize;
3bd3d6d3
AJ
1349 }
1350
4e256bef 1351 if (srclen > ssize) {
3bd3d6d3 1352 b |= cpu_ldub_data_ra(env, src, ra) << 4;
4e256bef
AJ
1353 src -= ssize;
1354 srclen -= ssize;
3bd3d6d3
AJ
1355 }
1356
1357 cpu_stb_data_ra(env, dest, b, ra);
1358 dest--;
1359 }
1360}
1361
4e256bef
AJ
1362
1363void HELPER(pka)(CPUS390XState *env, uint64_t dest, uint64_t src,
1364 uint32_t srclen)
1365{
1366 do_pkau(env, dest, src, srclen, 1, GETPC());
1367}
1368
1369void HELPER(pku)(CPUS390XState *env, uint64_t dest, uint64_t src,
1370 uint32_t srclen)
1371{
1372 do_pkau(env, dest, src, srclen, 2, GETPC());
1373}
1374
19b0516f
BS
1375void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
1376 uint64_t src)
8ef7f78e 1377{
84e1b98b 1378 uintptr_t ra = GETPC();
8ef7f78e
BS
1379 int len_dest = len >> 4;
1380 int len_src = len & 0xf;
1381 uint8_t b;
1382 int second_nibble = 0;
1383
1384 dest += len_dest;
1385 src += len_src;
1386
1387 /* last byte is special, it only flips the nibbles */
84e1b98b
RH
1388 b = cpu_ldub_data_ra(env, src, ra);
1389 cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
8ef7f78e
BS
1390 src--;
1391 len_src--;
1392
1393 /* now pad every nibble with 0xf0 */
1394
1395 while (len_dest > 0) {
1396 uint8_t cur_byte = 0;
1397
1398 if (len_src > 0) {
84e1b98b 1399 cur_byte = cpu_ldub_data_ra(env, src, ra);
8ef7f78e
BS
1400 }
1401
1402 len_dest--;
1403 dest--;
1404
1405 /* only advance one nibble at a time */
1406 if (second_nibble) {
1407 cur_byte >>= 4;
1408 len_src--;
1409 src--;
1410 }
1411 second_nibble = !second_nibble;
1412
1413 /* digit */
1414 cur_byte = (cur_byte & 0xf);
1415 /* zone bits */
1416 cur_byte |= 0xf0;
1417
84e1b98b 1418 cpu_stb_data_ra(env, dest, cur_byte, ra);
8ef7f78e
BS
1419 }
1420}
1421
15417787
AJ
1422static inline uint32_t do_unpkau(CPUS390XState *env, uint64_t dest,
1423 uint32_t destlen, int dsize, uint64_t src,
1424 uintptr_t ra)
1a35f08a 1425{
1a35f08a
AJ
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;
1431
1432 /* The operands are processed from right to left. */
1433 src += srclen - 1;
15417787 1434 dest += destlen - dsize;
1a35f08a
AJ
1435
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;
1453 }
1454
1455 /* Now pad every nibble with 0x30, advancing one nibble at a time. */
15417787
AJ
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. */
1a35f08a 1459 b = 0;
15417787 1460 } else if (i % (2 * dsize)) {
1a35f08a
AJ
1461 b = cpu_ldub_data_ra(env, src, ra);
1462 src--;
1463 } else {
1464 b >>= 4;
1465 }
15417787
AJ
1466 cpu_stsize_data_ra(env, dest, 0x30 + (b & 0xf), dsize, ra);
1467 dest -= dsize;
1a35f08a
AJ
1468 }
1469
1470 return cc;
1471}
1472
15417787
AJ
1473uint32_t HELPER(unpka)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1474 uint64_t src)
1475{
1476 return do_unpkau(env, dest, destlen, 1, src, GETPC());
1477}
1478
1479uint32_t HELPER(unpku)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1480 uint64_t src)
1481{
1482 return do_unpkau(env, dest, destlen, 2, src, GETPC());
1483}
1484
5d4a655a
AJ
1485uint32_t HELPER(tp)(CPUS390XState *env, uint64_t dest, uint32_t destlen)
1486{
1487 uintptr_t ra = GETPC();
1488 uint32_t cc = 0;
1489 int i;
1490
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;
1495
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;
1502 }
1503 }
1504
1505 return cc;
1506}
1507
d376f123
RH
1508static uint32_t do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array,
1509 uint64_t trans, uintptr_t ra)
8ef7f78e 1510{
981a8ea0 1511 uint32_t i;
8ef7f78e
BS
1512
1513 for (i = 0; i <= len; i++) {
981a8ea0
RH
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);
8ef7f78e 1517 }
d376f123
RH
1518
1519 return env->cc_op;
8ef7f78e
BS
1520}
1521
981a8ea0
RH
1522void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
1523 uint64_t trans)
1524{
d376f123 1525 do_helper_tr(env, len, array, trans, GETPC());
981a8ea0
RH
1526}
1527
3f4de675
AJ
1528uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array,
1529 uint64_t len, uint64_t trans)
1530{
d46cd62f 1531 uintptr_t ra = GETPC();
3f4de675
AJ
1532 uint8_t end = env->regs[0] & 0xff;
1533 uint64_t l = len;
1534 uint64_t i;
d46cd62f 1535 uint32_t cc = 0;
3f4de675
AJ
1536
1537 if (!(env->psw.mask & PSW_MASK_64)) {
1538 array &= 0x7fffffff;
1539 l = (uint32_t)l;
1540 }
1541
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;
d46cd62f 1546 cc = 3;
3f4de675
AJ
1547 }
1548
1549 for (i = 0; i < l; i++) {
1550 uint8_t byte, new_byte;
1551
d46cd62f 1552 byte = cpu_ldub_data_ra(env, array + i, ra);
3f4de675
AJ
1553
1554 if (byte == end) {
d46cd62f 1555 cc = 1;
3f4de675
AJ
1556 break;
1557 }
1558
d46cd62f
RH
1559 new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
1560 cpu_stb_data_ra(env, array + i, new_byte, ra);
3f4de675
AJ
1561 }
1562
d46cd62f 1563 env->cc_op = cc;
3f4de675
AJ
1564 env->retxl = len - i;
1565 return array + i;
1566}
1567
b213c9f5
RH
1568static inline uint32_t do_helper_trt(CPUS390XState *env, int len,
1569 uint64_t array, uint64_t trans,
1570 int inc, uintptr_t ra)
54f00775 1571{
b213c9f5 1572 int i;
54f00775
AJ
1573
1574 for (i = 0; i <= len; i++) {
b213c9f5 1575 uint8_t byte = cpu_ldub_data_ra(env, array + i * inc, ra);
2c7e5f8c 1576 uint8_t sbyte = cpu_ldub_data_ra(env, trans + byte, ra);
54f00775
AJ
1577
1578 if (sbyte != 0) {
b213c9f5 1579 set_address(env, 1, array + i * inc);
2c7e5f8c
RH
1580 env->regs[2] = deposit64(env->regs[2], 0, 8, sbyte);
1581 return (i == len) ? 2 : 1;
54f00775
AJ
1582 }
1583 }
1584
2c7e5f8c
RH
1585 return 0;
1586}
1587
ad8c851d
PZ
1588static uint32_t do_helper_trt_fwd(CPUS390XState *env, uint32_t len,
1589 uint64_t array, uint64_t trans,
1590 uintptr_t ra)
1591{
1592 return do_helper_trt(env, len, array, trans, 1, ra);
1593}
1594
2c7e5f8c
RH
1595uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
1596 uint64_t trans)
1597{
b213c9f5
RH
1598 return do_helper_trt(env, len, array, trans, 1, GETPC());
1599}
1600
ad8c851d
PZ
1601static uint32_t do_helper_trt_bkwd(CPUS390XState *env, uint32_t len,
1602 uint64_t array, uint64_t trans,
1603 uintptr_t ra)
1604{
1605 return do_helper_trt(env, len, array, trans, -1, ra);
1606}
1607
b213c9f5
RH
1608uint32_t HELPER(trtr)(CPUS390XState *env, uint32_t len, uint64_t array,
1609 uint64_t trans)
1610{
1611 return do_helper_trt(env, len, array, trans, -1, GETPC());
54f00775
AJ
1612}
1613
4065ae76
AJ
1614/* Translate one/two to one/two */
1615uint32_t HELPER(trXX)(CPUS390XState *env, uint32_t r1, uint32_t r2,
1616 uint32_t tst, uint32_t sizes)
1617{
1618 uintptr_t ra = GETPC();
1619 int dsize = (sizes & 1) ? 1 : 2;
1620 int ssize = (sizes & 2) ? 1 : 2;
3c39c800 1621 uint64_t tbl = get_address(env, 1);
4065ae76
AJ
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;
1627
3c39c800
RH
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;
1635 }
1636
4065ae76
AJ
1637 check_alignment(env, len, ssize, ra);
1638
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;
1648 }
1649 cpu_stsize_data_ra(env, dst, dval, dsize, ra);
1650
1651 len -= ssize;
1652 src += ssize;
1653 dst += dsize;
1654
1655 if (len == 0) {
1656 cc = 0;
1657 break;
1658 }
1659 }
1660
1661 set_address(env, r1, dst);
1662 set_length(env, r1 + 1, len);
1663 set_address(env, r2, src);
1664
1665 return cc;
1666}
1667
0c9fa168
RH
1668void HELPER(cdsg)(CPUS390XState *env, uint64_t addr,
1669 uint32_t r1, uint32_t r3)
303a9ab8
RH
1670{
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;
0c9fa168 1675 uint64_t oldh, oldl;
303a9ab8
RH
1676 bool fail;
1677
0c9fa168 1678 check_alignment(env, addr, 16, ra);
c0080f1b 1679
0c9fa168
RH
1680 oldh = cpu_ldq_data_ra(env, addr + 0, ra);
1681 oldl = cpu_ldq_data_ra(env, addr + 8, ra);
303a9ab8 1682
0c9fa168
RH
1683 oldv = int128_make128(oldl, oldh);
1684 fail = !int128_eq(oldv, cmpv);
1685 if (fail) {
1686 newv = oldv;
303a9ab8
RH
1687 }
1688
0c9fa168
RH
1689 cpu_stq_data_ra(env, addr + 0, int128_gethi(newv), ra);
1690 cpu_stq_data_ra(env, addr + 8, int128_getlo(newv), ra);
1691
303a9ab8
RH
1692 env->cc_op = fail;
1693 env->regs[r1] = int128_gethi(oldv);
1694 env->regs[r1 + 1] = int128_getlo(oldv);
1695}
1696
6476615d
EC
1697void HELPER(cdsg_parallel)(CPUS390XState *env, uint64_t addr,
1698 uint32_t r1, uint32_t r3)
1699{
0c9fa168
RH
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;
1707
830bf10c 1708 assert(HAVE_CMPXCHG128);
0c9fa168
RH
1709
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);
1714
1715 env->cc_op = fail;
1716 env->regs[r1] = int128_gethi(oldv);
1717 env->regs[r1 + 1] = int128_getlo(oldv);
6476615d
EC
1718}
1719
1720static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
1721 uint64_t a2, bool parallel)
c67ba303 1722{
c67ba303 1723 uint32_t mem_idx = cpu_mmu_index(env, false);
c67ba303
RH
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;
1730
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;
1735 }
1736 if (fc > 2 || sc > 4 || (fc == 2 && (r3 & 1))) {
1737 goto spec_exception;
1738 }
1739 }
1740
1741 /* Sanity check the alignments. */
dc95b31d 1742 if (extract32(a1, 0, fc + 2) || extract32(a2, 0, sc)) {
c67ba303
RH
1743 goto spec_exception;
1744 }
1745
1746 /* Sanity check writability of the store address. */
9cd9cdae 1747 probe_write(env, a2, 1 << sc, mem_idx, ra);
c67ba303 1748
5e95612e
RH
1749 /*
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.
1755 */
6476615d 1756 if (parallel) {
5e95612e
RH
1757 uint32_t max = 2;
1758#ifdef CONFIG_ATOMIC64
1759 max = 3;
c67ba303 1760#endif
5e95612e
RH
1761 if ((HAVE_CMPXCHG128 ? 0 : fc + 2 > max) ||
1762 (HAVE_ATOMIC128 ? 0 : sc > max)) {
29a0af61 1763 cpu_loop_exit_atomic(env_cpu(env), ra);
c67ba303
RH
1764 }
1765 }
1766
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);
1771
1772 switch (fc) {
1773 case 0:
1774 {
1775 uint32_t nv = cpu_ldl_data_ra(env, pl, ra);
1776 uint32_t cv = env->regs[r3];
1777 uint32_t ov;
1778
6476615d 1779 if (parallel) {
c67ba303
RH
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);
1790 }
1791 cc = (ov != cv);
1792 env->regs[r3] = deposit64(env->regs[r3], 32, 32, ov);
1793 }
1794 break;
1795
1796 case 1:
1797 {
1798 uint64_t nv = cpu_ldq_data_ra(env, pl, ra);
1799 uint64_t cv = env->regs[r3];
1800 uint64_t ov;
1801
6476615d 1802 if (parallel) {
c67ba303
RH
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
6476615d 1812 /* Note that we asserted !parallel above. */
c67ba303
RH
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);
1818 }
1819 cc = (ov != cv);
1820 env->regs[r3] = ov;
1821 }
1822 break;
1823
1824 case 2:
1825 {
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;
1831
5e95612e 1832 if (!parallel) {
c67ba303
RH
1833 uint64_t oh = cpu_ldq_data_ra(env, a1 + 0, ra);
1834 uint64_t ol = cpu_ldq_data_ra(env, a1 + 8, ra);
1835
1836 ov = int128_make128(ol, oh);
1837 cc = !int128_eq(ov, cv);
1838 if (cc) {
1839 nv = ov;
1840 }
1841
1842 cpu_stq_data_ra(env, a1 + 0, int128_gethi(nv), ra);
1843 cpu_stq_data_ra(env, a1 + 8, int128_getlo(nv), ra);
5e95612e
RH
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();
c67ba303
RH
1851 }
1852
1853 env->regs[r3 + 0] = int128_gethi(ov);
1854 env->regs[r3 + 1] = int128_getlo(ov);
1855 }
1856 break;
1857
1858 default:
1859 g_assert_not_reached();
1860 }
1861
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:
5e95612e
RH
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) {
c67ba303
RH
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);
5e95612e 1887 } else {
6476615d 1888 /* Note that we asserted !parallel above. */
c67ba303 1889 g_assert_not_reached();
c67ba303 1890 }
de4e05d1 1891 break;
c67ba303
RH
1892 default:
1893 g_assert_not_reached();
1894 }
1895 }
1896
1897 return cc;
1898
1899 spec_exception:
1e36aee6 1900 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
c67ba303
RH
1901}
1902
6476615d
EC
1903uint32_t HELPER(csst)(CPUS390XState *env, uint32_t r3, uint64_t a1, uint64_t a2)
1904{
1905 return do_csst(env, r3, a1, a2, false);
1906}
1907
1908uint32_t HELPER(csst_parallel)(CPUS390XState *env, uint32_t r3, uint64_t a1,
1909 uint64_t a2)
1910{
1911 return do_csst(env, r3, a1, a2, true);
1912}
1913
8ef7f78e 1914#if !defined(CONFIG_USER_ONLY)
19b0516f 1915void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
8ef7f78e 1916{
97ae2149 1917 uintptr_t ra = GETPC();
311918b9 1918 bool PERchanged = false;
8ef7f78e 1919 uint64_t src = a2;
97ae2149 1920 uint32_t i;
8ef7f78e 1921
21fc97c5 1922 if (src & 0x7) {
1e36aee6 1923 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
21fc97c5
DH
1924 }
1925
8ef7f78e 1926 for (i = r1;; i = (i + 1) % 16) {
97ae2149 1927 uint64_t val = cpu_ldq_data_ra(env, src, ra);
311918b9
AJ
1928 if (env->cregs[i] != val && i >= 9 && i <= 11) {
1929 PERchanged = true;
1930 }
1931 env->cregs[i] = val;
8ef7f78e 1932 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
97ae2149 1933 i, src, val);
8ef7f78e
BS
1934 src += sizeof(uint64_t);
1935
1936 if (i == r3) {
1937 break;
1938 }
1939 }
1940
311918b9 1941 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
dc79e928 1942 s390_cpu_recompute_watchpoints(env_cpu(env));
311918b9
AJ
1943 }
1944
dc79e928 1945 tlb_flush(env_cpu(env));
8ef7f78e
BS
1946}
1947
19b0516f 1948void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
8ef7f78e 1949{
1b642a73 1950 uintptr_t ra = GETPC();
311918b9 1951 bool PERchanged = false;
8ef7f78e 1952 uint64_t src = a2;
1b642a73 1953 uint32_t i;
8ef7f78e 1954
21fc97c5 1955 if (src & 0x3) {
1e36aee6 1956 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
21fc97c5
DH
1957 }
1958
8ef7f78e 1959 for (i = r1;; i = (i + 1) % 16) {
1b642a73 1960 uint32_t val = cpu_ldl_data_ra(env, src, ra);
311918b9
AJ
1961 if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
1962 PERchanged = true;
1963 }
1b642a73
RH
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);
8ef7f78e
BS
1966 src += sizeof(uint32_t);
1967
1968 if (i == r3) {
1969 break;
1970 }
1971 }
1972
311918b9 1973 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
dc79e928 1974 s390_cpu_recompute_watchpoints(env_cpu(env));
311918b9
AJ
1975 }
1976
dc79e928 1977 tlb_flush(env_cpu(env));
8ef7f78e
BS
1978}
1979
19b0516f 1980void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
8ef7f78e 1981{
75d6240c 1982 uintptr_t ra = GETPC();
8ef7f78e 1983 uint64_t dest = a2;
75d6240c 1984 uint32_t i;
8ef7f78e 1985
21fc97c5 1986 if (dest & 0x7) {
1e36aee6 1987 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
21fc97c5
DH
1988 }
1989
8ef7f78e 1990 for (i = r1;; i = (i + 1) % 16) {
75d6240c 1991 cpu_stq_data_ra(env, dest, env->cregs[i], ra);
8ef7f78e
BS
1992 dest += sizeof(uint64_t);
1993
1994 if (i == r3) {
1995 break;
1996 }
1997 }
1998}
1999
19b0516f 2000void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
8ef7f78e 2001{
75d6240c 2002 uintptr_t ra = GETPC();
8ef7f78e 2003 uint64_t dest = a2;
75d6240c 2004 uint32_t i;
8ef7f78e 2005
21fc97c5 2006 if (dest & 0x3) {
1e36aee6 2007 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
21fc97c5
DH
2008 }
2009
8ef7f78e 2010 for (i = r1;; i = (i + 1) % 16) {
75d6240c 2011 cpu_stl_data_ra(env, dest, env->cregs[i], ra);
8ef7f78e
BS
2012 dest += sizeof(uint32_t);
2013
2014 if (i == r3) {
2015 break;
2016 }
2017 }
2018}
2019
f79f1ca4
TH
2020uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
2021{
aef2b01a 2022 uintptr_t ra = GETPC();
f79f1ca4
TH
2023 int i;
2024
e26131c9 2025 real_addr = wrap_address(env, real_addr) & TARGET_PAGE_MASK;
f79f1ca4 2026
f79f1ca4 2027 for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
e26131c9 2028 cpu_stq_real_ra(env, real_addr + i, 0, ra);
f79f1ca4
TH
2029 }
2030
2031 return 0;
2032}
2033
bb879430 2034uint32_t HELPER(tprot)(CPUS390XState *env, uint64_t a1, uint64_t a2)
8ef7f78e 2035{
dc79e928
RH
2036 S390CPU *cpu = env_archcpu(env);
2037 CPUState *cs = env_cpu(env);
bb879430
DH
2038
2039 /*
2040 * TODO: we currently don't handle all access protection types
2041 * (including access-list and key-controlled) as well as AR mode.
2042 */
2043 if (!s390_cpu_virt_mem_check_write(cpu, a1, 0, 1)) {
2044 /* Fetching permitted; storing permitted */
2045 return 0;
2046 }
b5e85329
DH
2047
2048 if (env->int_pgm_code == PGM_PROTECTION) {
2049 /* retry if reading is possible */
bed04a2b 2050 cs->exception_index = -1;
b5e85329
DH
2051 if (!s390_cpu_virt_mem_check_read(cpu, a1, 0, 1)) {
2052 /* Fetching permitted; storing not permitted */
2053 return 1;
2054 }
2055 }
2056
bb879430
DH
2057 switch (env->int_pgm_code) {
2058 case PGM_PROTECTION:
bb879430 2059 /* Fetching not permitted; storing not permitted */
bed04a2b 2060 cs->exception_index = -1;
bb879430 2061 return 2;
b5e85329
DH
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;
bb879430 2067 }
b5e85329
DH
2068
2069 /* Translation not available */
bed04a2b 2070 cs->exception_index = -1;
b5e85329 2071 return 3;
8ef7f78e
BS
2072}
2073
2074/* insert storage key extended */
19b0516f 2075uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
8ef7f78e 2076{
0f5f6691
JH
2077 static S390SKeysState *ss;
2078 static S390SKeysClass *skeyclass;
a5c3cedd 2079 uint64_t addr = wrap_address(env, r2);
0f5f6691 2080 uint8_t key;
8ef7f78e
BS
2081
2082 if (addr > ram_size) {
2083 return 0;
2084 }
2085
0f5f6691
JH
2086 if (unlikely(!ss)) {
2087 ss = s390_get_skeys_device();
2088 skeyclass = S390_SKEYS_GET_CLASS(ss);
2089 }
2090
2091 if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
2092 return 0;
2093 }
2094 return key;
8ef7f78e
BS
2095}
2096
2097/* set storage key extended */
2bbde27f 2098void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
8ef7f78e 2099{
0f5f6691
JH
2100 static S390SKeysState *ss;
2101 static S390SKeysClass *skeyclass;
a5c3cedd 2102 uint64_t addr = wrap_address(env, r2);
0f5f6691 2103 uint8_t key;
8ef7f78e
BS
2104
2105 if (addr > ram_size) {
2106 return;
2107 }
2108
0f5f6691
JH
2109 if (unlikely(!ss)) {
2110 ss = s390_get_skeys_device();
2111 skeyclass = S390_SKEYS_GET_CLASS(ss);
2112 }
2113
2114 key = (uint8_t) r1;
2115 skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
5b773a11
DH
2116 /*
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.
2119 */
2120 tlb_flush_all_cpus_synced(env_cpu(env));
8ef7f78e
BS
2121}
2122
2123/* reset reference bit extended */
5cc69c54 2124uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
8ef7f78e 2125{
0f5f6691
JH
2126 static S390SKeysState *ss;
2127 static S390SKeysClass *skeyclass;
2128 uint8_t re, key;
8ef7f78e
BS
2129
2130 if (r2 > ram_size) {
2131 return 0;
2132 }
2133
0f5f6691
JH
2134 if (unlikely(!ss)) {
2135 ss = s390_get_skeys_device();
2136 skeyclass = S390_SKEYS_GET_CLASS(ss);
2137 }
2138
2139 if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
2140 return 0;
2141 }
2142
8ef7f78e 2143 re = key & (SK_R | SK_C);
0f5f6691
JH
2144 key &= ~SK_R;
2145
2146 if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
2147 return 0;
2148 }
5b773a11
DH
2149 /*
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.
2152 */
2153 tlb_flush_all_cpus_synced(env_cpu(env));
8ef7f78e
BS
2154
2155 /*
2156 * cc
2157 *
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
2162 */
2163
2164 return re >> 1;
2165}
2166
a3084e80 2167uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
8ef7f78e 2168{
43df3e71 2169 const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
efb1a76e 2170 S390Access srca, desta;
b90fb26b 2171 uintptr_t ra = GETPC();
efb1a76e 2172 int cc = 0;
8ef7f78e 2173
a3084e80
AJ
2174 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
2175 __func__, l, a1, a2);
2176
43df3e71
DH
2177 if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) ||
2178 psw_as == AS_HOME || psw_as == AS_ACCREG) {
77b703f8 2179 s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
43df3e71
DH
2180 }
2181
373290d8 2182 l = wrap_length32(env, l);
a3084e80 2183 if (l > 256) {
8ef7f78e
BS
2184 /* max 256 */
2185 l = 256;
2186 cc = 3;
373290d8
DH
2187 } else if (!l) {
2188 return cc;
8ef7f78e
BS
2189 }
2190
efb1a76e
DH
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);
8ef7f78e
BS
2195 return cc;
2196}
2197
a3084e80 2198uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
8ef7f78e 2199{
43df3e71 2200 const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
efb1a76e 2201 S390Access srca, desta;
b90fb26b 2202 uintptr_t ra = GETPC();
efb1a76e 2203 int cc = 0;
a3084e80 2204
8ef7f78e
BS
2205 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
2206 __func__, l, a1, a2);
2207
43df3e71
DH
2208 if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) ||
2209 psw_as == AS_HOME || psw_as == AS_ACCREG) {
77b703f8 2210 s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
43df3e71
DH
2211 }
2212
373290d8 2213 l = wrap_length32(env, l);
a3084e80
AJ
2214 if (l > 256) {
2215 /* max 256 */
2216 l = 256;
2217 cc = 3;
373290d8
DH
2218 } else if (!l) {
2219 return cc;
a3084e80 2220 }
8ef7f78e 2221
efb1a76e
DH
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);
a3084e80 2226 return cc;
8ef7f78e
BS
2227}
2228
be7f28de
DH
2229void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4)
2230{
dc79e928 2231 CPUState *cs = env_cpu(env);
be7f28de
DH
2232 const uintptr_t ra = GETPC();
2233 uint64_t table, entry, raddr;
2234 uint16_t entries, i, index = 0;
2235
2236 if (r2 & 0xff000) {
1e36aee6 2237 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
be7f28de
DH
2238 }
2239
2240 if (!(r2 & 0x800)) {
2241 /* invalidation-and-clearing operation */
adab99be 2242 table = r1 & ASCE_ORIGIN;
be7f28de
DH
2243 entries = (r2 & 0x7ff) + 1;
2244
adab99be
TH
2245 switch (r1 & ASCE_TYPE_MASK) {
2246 case ASCE_TYPE_REGION1:
be7f28de
DH
2247 index = (r2 >> 53) & 0x7ff;
2248 break;
adab99be 2249 case ASCE_TYPE_REGION2:
be7f28de
DH
2250 index = (r2 >> 42) & 0x7ff;
2251 break;
adab99be 2252 case ASCE_TYPE_REGION3:
be7f28de
DH
2253 index = (r2 >> 31) & 0x7ff;
2254 break;
adab99be 2255 case ASCE_TYPE_SEGMENT:
be7f28de
DH
2256 index = (r2 >> 20) & 0x7ff;
2257 break;
2258 }
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);
8eb82de9 2262 entry = cpu_ldq_real_ra(env, raddr, ra);
3fd0e85f 2263 if (!(entry & REGION_ENTRY_I)) {
be7f28de 2264 /* we are allowed to not store if already invalid */
3fd0e85f 2265 entry |= REGION_ENTRY_I;
8eb82de9 2266 cpu_stq_real_ra(env, raddr, entry, ra);
be7f28de
DH
2267 }
2268 }
2269 }
2270
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);
2276 }
2277}
2278
8ef7f78e 2279/* invalidate pte */
1f58720c
AJ
2280void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr,
2281 uint32_t m4)
8ef7f78e 2282{
dc79e928 2283 CPUState *cs = env_cpu(env);
8eb82de9 2284 const uintptr_t ra = GETPC();
8ef7f78e 2285 uint64_t page = vaddr & TARGET_PAGE_MASK;
8a4719f5 2286 uint64_t pte_addr, pte;
8ef7f78e 2287
8a4719f5 2288 /* Compute the page table entry address */
adab99be 2289 pte_addr = (pto & SEGMENT_ENTRY_ORIGIN);
3fd0e85f 2290 pte_addr += VADDR_PAGE_TX(vaddr) * 8;
8a4719f5
AJ
2291
2292 /* Mark the page table entry as invalid */
8eb82de9 2293 pte = cpu_ldq_real_ra(env, pte_addr, ra);
3fd0e85f 2294 pte |= PAGE_ENTRY_I;
8eb82de9 2295 cpu_stq_real_ra(env, pte_addr, pte, ra);
8ef7f78e
BS
2296
2297 /* XXX we exploit the fact that Linux passes the exact virtual
2298 address here - it's not obliged to! */
1f58720c 2299 if (m4 & 1) {
3fd0e85f 2300 if (vaddr & ~VADDR_PAGE_TX_MASK) {
97b95aae
DH
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);
2307 }
8ef7f78e 2308 } else {
3fd0e85f 2309 if (vaddr & ~VADDR_PAGE_TX_MASK) {
97b95aae
DH
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);
2316 }
8ef7f78e
BS
2317 }
2318}
2319
2320/* flush local tlb */
19b0516f 2321void HELPER(ptlb)(CPUS390XState *env)
8ef7f78e 2322{
dc79e928 2323 tlb_flush(env_cpu(env));
8ef7f78e
BS
2324}
2325
31a18b45
RH
2326/* flush global tlb */
2327void HELPER(purge)(CPUS390XState *env)
2328{
dc79e928 2329 tlb_flush_all_cpus_synced(env_cpu(env));
31a18b45
RH
2330}
2331
9c3fd85b
RH
2332/* load using real address */
2333uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr)
2334{
34499dad 2335 return cpu_ldl_real_ra(env, wrap_address(env, addr), GETPC());
9c3fd85b
RH
2336}
2337
2338uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr)
2339{
34499dad 2340 return cpu_ldq_real_ra(env, wrap_address(env, addr), GETPC());
9c3fd85b
RH
2341}
2342
8ef7f78e 2343/* store using real address */
204504e2 2344void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
8ef7f78e 2345{
4ae43341 2346 cpu_stl_real_ra(env, wrap_address(env, addr), (uint32_t)v1, GETPC());
2f543949
AJ
2347
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);
2354 }
8ef7f78e
BS
2355}
2356
9c3fd85b
RH
2357void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
2358{
4ae43341 2359 cpu_stq_real_ra(env, wrap_address(env, addr), v1, GETPC());
2f543949
AJ
2360
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);
2367 }
9c3fd85b
RH
2368}
2369
8ef7f78e 2370/* load real address */
d8fe4a9c 2371uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
8ef7f78e 2372{
8ef7f78e 2373 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
ce7ac79d 2374 uint64_t ret, tec;
9accc852 2375 int flags, exc, cc;
8ef7f78e
BS
2376
2377 /* XXX incomplete - has more corner cases */
2378 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1e36aee6 2379 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, GETPC());
8ef7f78e
BS
2380 }
2381
ce7ac79d
RH
2382 exc = mmu_translate(env, addr, 0, asc, &ret, &flags, &tec);
2383 if (exc) {
8ef7f78e 2384 cc = 3;
9accc852 2385 ret = exc | 0x80000000;
8ef7f78e 2386 } else {
9accc852 2387 cc = 0;
8ef7f78e
BS
2388 ret |= addr & ~TARGET_PAGE_MASK;
2389 }
8ef7f78e 2390
d8fe4a9c
RH
2391 env->cc_op = cc;
2392 return ret;
8ef7f78e 2393}
8ef7f78e 2394#endif
a5cfc223 2395
e22dfdb2 2396/* load pair from quadword */
0c9fa168 2397uint64_t HELPER(lpq)(CPUS390XState *env, uint64_t addr)
e22dfdb2
AJ
2398{
2399 uintptr_t ra = GETPC();
2400 uint64_t hi, lo;
2401
0c9fa168
RH
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);
2405
2406 env->retxl = lo;
2407 return hi;
2408}
2409
2410uint64_t HELPER(lpq_parallel)(CPUS390XState *env, uint64_t addr)
2411{
2412 uintptr_t ra = GETPC();
2413 uint64_t hi, lo;
830bf10c
RH
2414 int mem_idx;
2415 TCGMemOpIdx oi;
2416 Int128 v;
0c9fa168 2417
830bf10c
RH
2418 assert(HAVE_ATOMIC128);
2419
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);
e22dfdb2
AJ
2425
2426 env->retxl = lo;
2427 return hi;
2428}
2429
0c9fa168
RH
2430/* store pair to quadword */
2431void HELPER(stpq)(CPUS390XState *env, uint64_t addr,
2432 uint64_t low, uint64_t high)
6476615d 2433{
0c9fa168 2434 uintptr_t ra = GETPC();
6476615d 2435
0c9fa168
RH
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);
6476615d
EC
2439}
2440
0c9fa168
RH
2441void HELPER(stpq_parallel)(CPUS390XState *env, uint64_t addr,
2442 uint64_t low, uint64_t high)
c21b610f
AJ
2443{
2444 uintptr_t ra = GETPC();
830bf10c
RH
2445 int mem_idx;
2446 TCGMemOpIdx oi;
2447 Int128 v;
c21b610f 2448
830bf10c
RH
2449 assert(HAVE_ATOMIC128);
2450
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);
c21b610f
AJ
2455}
2456
303c681a
RH
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.
2460
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.
a5cfc223 2463*/
83500793 2464void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
a5cfc223 2465{
83500793
RH
2466 uint64_t insn = cpu_lduw_code(env, addr);
2467 uint8_t opc = insn >> 8;
2468
2469 /* Or in the contents of R1[56:63]. */
2470 insn |= r1 & 0xff;
2471
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();
2485 }
2486
d376f123
RH
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] = {
ad8c851d 2492 [0x0] = do_helper_trt_bkwd,
d376f123
RH
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,
ad8c851d 2499 [0xd] = do_helper_trt_fwd,
d376f123
RH
2500 };
2501 dx_helper helper = dx[opc & 0xf];
2502
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);
a5c3cedd
AJ
2509 uint64_t a1 = wrap_address(env, env->regs[b1] + d1);
2510 uint64_t a2 = wrap_address(env, env->regs[b2] + d2);
d376f123
RH
2511
2512 env->cc_op = helper(env, l, a1, a2, 0);
2513 env->psw.addr += ilen;
2514 return;
2515 }
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();
2521 }
2522
303c681a
RH
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;
a5cfc223 2528}
3e7e5e0b
DH
2529
2530uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src,
2531 uint64_t len)
2532{
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();
3e7e5e0b
DH
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;
2541
2542 HELPER_LOG("%s dest %" PRIx64 ", src %" PRIx64 ", len %" PRIx64 "\n",
2543 __func__, dest, src, len);
2544
2545 if (!(env->psw.mask & PSW_MASK_DAT)) {
1e36aee6 2546 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
3e7e5e0b
DH
2547 }
2548
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;
2555
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;
2562
2563 if (!dest_k) {
2564 dest_key = psw_key;
2565 }
2566 if (!src_k) {
2567 src_key = psw_key;
2568 }
2569 if (!dest_a) {
2570 dest_as = psw_as;
2571 }
2572 if (!src_a) {
2573 src_as = psw_as;
2574 }
2575
2576 if (dest_a && dest_as == AS_HOME && (env->psw.mask & PSW_MASK_PSTATE)) {
1e36aee6 2577 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
3e7e5e0b
DH
2578 }
2579 if (!(env->cregs[0] & CR0_SECONDARY) &&
2580 (dest_as == AS_SECONDARY || src_as == AS_SECONDARY)) {
1e36aee6 2581 tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
3e7e5e0b
DH
2582 }
2583 if (!psw_key_valid(env, dest_key) || !psw_key_valid(env, src_key)) {
1e36aee6 2584 tcg_s390_program_interrupt(env, PGM_PRIVILEGED, ra);
3e7e5e0b
DH
2585 }
2586
a7627565 2587 len = wrap_length32(env, len);
3e7e5e0b
DH
2588 if (len > 4096) {
2589 cc = 3;
2590 len = 4096;
2591 }
2592
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__);
1e36aee6 2598 tcg_s390_program_interrupt(env, PGM_ADDRESSING, ra);
3e7e5e0b
DH
2599 }
2600
b6c636f2
DH
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);
2607
2608 access_memmove(env, &desta, &srca, ra);
2609 }
3e7e5e0b
DH
2610
2611 return cc;
2612}
941ef3db
RH
2613
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. */
2617typedef 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);
2620
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. */
2624typedef int (*encode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2625 uint64_t ilen, uintptr_t ra, uint32_t c,
2626 uint32_t *olen);
2627
2628static 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)
2631{
2632 uint8_t s0, s1, s2, s3;
2633 uint32_t c, l;
2634
2635 if (ilen < 1) {
2636 return 0;
2637 }
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;
2651 }
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;
2657 }
2658 } else if (s0 <= 0xef) {
2659 /* three byte character */
2660 l = 3;
2661 if (ilen < 3) {
2662 return 0;
2663 }
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;
2678 }
2679 } else if (s0 <= (enh_check ? 0xf4 : 0xf7)) {
2680 /* four byte character */
2681 l = 4;
2682 if (ilen < 4) {
2683 return 0;
2684 }
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;
2700 }
2701 } else {
2702 /* invalid character */
2703 return 2;
2704 }
2705
2706 *ochar = c;
2707 *olen = l;
2708 return -1;
2709}
2710
2711static 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)
2714{
2715 uint16_t s0, s1;
2716 uint32_t c, l;
2717
2718 if (ilen < 2) {
2719 return 0;
2720 }
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;
2731 }
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;
2739 }
2740 }
2741
2742 *ochar = c;
2743 *olen = l;
2744 return -1;
2745}
2746
2747static 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)
2750{
2751 uint32_t c;
2752
2753 if (ilen < 4) {
2754 return 0;
2755 }
2756 c = cpu_ldl_data_ra(env, addr, ra);
2757 if ((c >= 0xd800 && c <= 0xdbff) || c > 0x10ffff) {
2758 /* invalid unicode character */
2759 return 2;
2760 }
2761
2762 *ochar = c;
2763 *olen = 4;
2764 return -1;
2765}
2766
2767static int encode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2768 uintptr_t ra, uint32_t c, uint32_t *olen)
2769{
2770 uint8_t d[4];
2771 uint32_t l, i;
2772
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);
2795 }
2796
2797 if (ilen < l) {
2798 return 1;
2799 }
2800 for (i = 0; i < l; ++i) {
2801 cpu_stb_data_ra(env, addr + i, d[i], ra);
2802 }
2803
2804 *olen = l;
2805 return -1;
2806}
2807
2808static int encode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2809 uintptr_t ra, uint32_t c, uint32_t *olen)
2810{
2811 uint16_t d0, d1;
2812
2813 if (c <= 0xffff) {
2814 /* one word character */
2815 if (ilen < 2) {
2816 return 1;
2817 }
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;
2824 }
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;
2831 }
2832
2833 return -1;
2834}
2835
2836static int encode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2837 uintptr_t ra, uint32_t c, uint32_t *olen)
2838{
2839 if (ilen < 4) {
2840 return 1;
2841 }
2842 cpu_stl_data_ra(env, addr, c, ra);
2843 *olen = 4;
2844 return -1;
2845}
2846
2847static 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)
2851{
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;
2858
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;
2863
2864 cc = decode(env, src, slen, enh_check, ra, &c, &ilen);
2865 if (unlikely(cc >= 0)) {
2866 break;
2867 }
2868 cc = encode(env, dst, dlen, ra, c, &olen);
2869 if (unlikely(cc >= 0)) {
2870 break;
2871 }
2872
2873 src += ilen;
2874 slen -= ilen;
2875 dst += olen;
2876 dlen -= olen;
2877 cc = 3;
2878 }
2879
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);
2884
2885 return cc;
2886}
2887
2888uint32_t HELPER(cu12)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2889{
2890 return convert_unicode(env, r1, r2, m3, GETPC(),
2891 decode_utf8, encode_utf16);
2892}
2893
2894uint32_t HELPER(cu14)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2895{
2896 return convert_unicode(env, r1, r2, m3, GETPC(),
2897 decode_utf8, encode_utf32);
2898}
2899
2900uint32_t HELPER(cu21)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2901{
2902 return convert_unicode(env, r1, r2, m3, GETPC(),
2903 decode_utf16, encode_utf8);
2904}
2905
2906uint32_t HELPER(cu24)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2907{
2908 return convert_unicode(env, r1, r2, m3, GETPC(),
2909 decode_utf16, encode_utf32);
2910}
2911
2912uint32_t HELPER(cu41)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2913{
2914 return convert_unicode(env, r1, r2, m3, GETPC(),
2915 decode_utf32, encode_utf8);
2916}
2917
2918uint32_t HELPER(cu42)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2919{
2920 return convert_unicode(env, r1, r2, m3, GETPC(),
2921 decode_utf32, encode_utf16);
2922}
c5a7392c
DH
2923
2924void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
2925 uintptr_t ra)
2926{
c5a7392c
DH
2927 /* test the actual access, not just any access to the page due to LAP */
2928 while (len) {
46750128 2929 const uint64_t pagelen = -(addr | TARGET_PAGE_MASK);
c5a7392c
DH
2930 const uint64_t curlen = MIN(pagelen, len);
2931
2932 probe_write(env, addr, curlen, cpu_mmu_index(env, false), ra);
2933 addr = wrap_address(env, addr + curlen);
2934 len -= curlen;
2935 }
c5a7392c
DH
2936}
2937
2938void HELPER(probe_write_access)(CPUS390XState *env, uint64_t addr, uint64_t len)
2939{
2940 probe_write_access(env, addr, len, GETPC());
2941}