]> git.proxmox.com Git - mirror_qemu.git/blame - target/s390x/mem_helper.c
tcg: Factor out CONFIG_USER_ONLY probe_write() from s390x code
[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"
2ef6175a 24#include "exec/helper-proto.h"
63c91552 25#include "exec/exec-all.h"
f08b6170 26#include "exec/cpu_ldst.h"
303a9ab8 27#include "qemu/int128.h"
5e95612e 28#include "qemu/atomic128.h"
741da0d3
PB
29
30#if !defined(CONFIG_USER_ONLY)
0f5f6691 31#include "hw/s390x/storage-keys.h"
741da0d3 32#endif
8ef7f78e
BS
33
34/*****************************************************************************/
35/* Softmmu support */
8ef7f78e
BS
36
37/* #define DEBUG_HELPER */
38#ifdef DEBUG_HELPER
39#define HELPER_LOG(x...) qemu_log(x)
40#else
41#define HELPER_LOG(x...)
42#endif
43
c07a1009
DH
44static inline bool psw_key_valid(CPUS390XState *env, uint8_t psw_key)
45{
46 uint16_t pkm = env->cregs[3] >> 16;
47
48 if (env->psw.mask & PSW_MASK_PSTATE) {
49 /* PSW key has range 0..15, it is valid if the bit is 1 in the PKM */
50 return pkm & (0x80 >> psw_key);
51 }
52 return true;
53}
54
d7ce6b7a 55/* Reduce the length so that addr + len doesn't cross a page boundary. */
9c009e88 56static inline uint32_t adj_len_to_page(uint32_t len, uint64_t addr)
d7ce6b7a
AJ
57{
58#ifndef CONFIG_USER_ONLY
59 if ((addr & ~TARGET_PAGE_MASK) + len - 1 >= TARGET_PAGE_SIZE) {
22f04c31 60 return -(addr | TARGET_PAGE_MASK);
d7ce6b7a
AJ
61 }
62#endif
63 return len;
64}
65
31006af3
AJ
66/* Trigger a SPECIFICATION exception if an address or a length is not
67 naturally aligned. */
68static inline void check_alignment(CPUS390XState *env, uint64_t v,
69 int wordsize, uintptr_t ra)
70{
71 if (v % wordsize) {
8d2f850a 72 s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
31006af3
AJ
73 }
74}
75
76/* Load a value from memory according to its size. */
77static inline uint64_t cpu_ldusize_data_ra(CPUS390XState *env, uint64_t addr,
78 int wordsize, uintptr_t ra)
79{
80 switch (wordsize) {
81 case 1:
82 return cpu_ldub_data_ra(env, addr, ra);
83 case 2:
84 return cpu_lduw_data_ra(env, addr, ra);
85 default:
86 abort();
87 }
88}
89
15417787
AJ
90/* Store a to memory according to its size. */
91static inline void cpu_stsize_data_ra(CPUS390XState *env, uint64_t addr,
92 uint64_t value, int wordsize,
93 uintptr_t ra)
94{
95 switch (wordsize) {
96 case 1:
97 cpu_stb_data_ra(env, addr, value, ra);
98 break;
99 case 2:
100 cpu_stw_data_ra(env, addr, value, ra);
101 break;
102 default:
103 abort();
104 }
105}
106
fc89efe6 107static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte,
9c009e88 108 uint32_t l, uintptr_t ra)
8ef7f78e 109{
97ed5ccd 110 int mmu_idx = cpu_mmu_index(env, false);
fc89efe6
AJ
111
112 while (l > 0) {
113 void *p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
114 if (p) {
115 /* Access to the whole page in write mode granted. */
9c009e88 116 uint32_t l_adj = adj_len_to_page(l, dest);
fc89efe6
AJ
117 memset(p, byte, l_adj);
118 dest += l_adj;
119 l -= l_adj;
120 } else {
121 /* We failed to get access to the whole page. The next write
122 access will likely fill the QEMU TLB for the next iteration. */
9c009e88 123 cpu_stb_data_ra(env, dest, byte, ra);
fc89efe6
AJ
124 dest++;
125 l--;
126 }
8ef7f78e 127 }
8ef7f78e
BS
128}
129
3e7e5e0b
DH
130#ifndef CONFIG_USER_ONLY
131static void fast_memmove_idx(CPUS390XState *env, uint64_t dest, uint64_t src,
132 uint32_t len, int dest_idx, int src_idx,
133 uintptr_t ra)
134{
135 TCGMemOpIdx oi_dest = make_memop_idx(MO_UB, dest_idx);
136 TCGMemOpIdx oi_src = make_memop_idx(MO_UB, src_idx);
137 uint32_t len_adj;
138 void *src_p;
139 void *dest_p;
140 uint8_t x;
141
142 while (len > 0) {
143 src = wrap_address(env, src);
144 dest = wrap_address(env, dest);
145 src_p = tlb_vaddr_to_host(env, src, MMU_DATA_LOAD, src_idx);
146 dest_p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, dest_idx);
147
148 if (src_p && dest_p) {
149 /* Access to both whole pages granted. */
150 len_adj = adj_len_to_page(adj_len_to_page(len, src), dest);
151 memmove(dest_p, src_p, len_adj);
152 } else {
153 /* We failed to get access to one or both whole pages. The next
154 read or write access will likely fill the QEMU TLB for the
155 next iteration. */
156 len_adj = 1;
157 x = helper_ret_ldub_mmu(env, src, oi_src, ra);
158 helper_ret_stb_mmu(env, dest, x, oi_dest, ra);
159 }
160 src += len_adj;
161 dest += len_adj;
162 len -= len_adj;
163 }
164}
165
166static int mmu_idx_from_as(uint8_t as)
167{
168 switch (as) {
169 case AS_PRIMARY:
170 return MMU_PRIMARY_IDX;
171 case AS_SECONDARY:
172 return MMU_SECONDARY_IDX;
173 case AS_HOME:
174 return MMU_HOME_IDX;
175 default:
176 /* FIXME AS_ACCREG */
177 g_assert_not_reached();
178 }
179}
180
181static void fast_memmove_as(CPUS390XState *env, uint64_t dest, uint64_t src,
182 uint32_t len, uint8_t dest_as, uint8_t src_as,
183 uintptr_t ra)
184{
185 int src_idx = mmu_idx_from_as(src_as);
186 int dest_idx = mmu_idx_from_as(dest_as);
187
188 fast_memmove_idx(env, dest, src, len, dest_idx, src_idx, ra);
189}
190#endif
191
6da528d1 192static void fast_memmove(CPUS390XState *env, uint64_t dest, uint64_t src,
d3696812 193 uint32_t l, uintptr_t ra)
8ef7f78e 194{
97ed5ccd 195 int mmu_idx = cpu_mmu_index(env, false);
8ef7f78e 196
6da528d1
AJ
197 while (l > 0) {
198 void *src_p = tlb_vaddr_to_host(env, src, MMU_DATA_LOAD, mmu_idx);
199 void *dest_p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
200 if (src_p && dest_p) {
201 /* Access to both whole pages granted. */
9c009e88 202 uint32_t l_adj = adj_len_to_page(l, src);
6da528d1
AJ
203 l_adj = adj_len_to_page(l_adj, dest);
204 memmove(dest_p, src_p, l_adj);
205 src += l_adj;
206 dest += l_adj;
207 l -= l_adj;
208 } else {
209 /* We failed to get access to one or both whole pages. The next
210 read or write access will likely fill the QEMU TLB for the
211 next iteration. */
d3696812 212 cpu_stb_data_ra(env, dest, cpu_ldub_data_ra(env, src, ra), ra);
6da528d1
AJ
213 src++;
214 dest++;
215 l--;
216 }
8ef7f78e 217 }
8ef7f78e 218}
8ef7f78e
BS
219
220/* and on array */
349d078a
RH
221static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest,
222 uint64_t src, uintptr_t ra)
8ef7f78e 223{
349d078a
RH
224 uint32_t i;
225 uint8_t c = 0;
8ef7f78e
BS
226
227 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
228 __func__, l, dest, src);
349d078a 229
8ef7f78e 230 for (i = 0; i <= l; i++) {
349d078a
RH
231 uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
232 x &= cpu_ldub_data_ra(env, dest + i, ra);
233 c |= x;
234 cpu_stb_data_ra(env, dest + i, x, ra);
8ef7f78e 235 }
349d078a
RH
236 return c != 0;
237}
238
239uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
240 uint64_t src)
241{
242 return do_helper_nc(env, l, dest, src, GETPC());
8ef7f78e
BS
243}
244
245/* xor on array */
9c009e88
RH
246static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest,
247 uint64_t src, uintptr_t ra)
8ef7f78e 248{
9c009e88
RH
249 uint32_t i;
250 uint8_t c = 0;
8ef7f78e
BS
251
252 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
253 __func__, l, dest, src);
254
8ef7f78e 255 /* xor with itself is the same as memset(0) */
8ef7f78e 256 if (src == dest) {
9c009e88 257 fast_memset(env, dest, 0, l + 1, ra);
8ef7f78e
BS
258 return 0;
259 }
8ef7f78e
BS
260
261 for (i = 0; i <= l; i++) {
9c009e88
RH
262 uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
263 x ^= cpu_ldub_data_ra(env, dest + i, ra);
264 c |= x;
265 cpu_stb_data_ra(env, dest + i, x, ra);
8ef7f78e 266 }
9c009e88
RH
267 return c != 0;
268}
269
270uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
271 uint64_t src)
272{
273 return do_helper_xc(env, l, dest, src, GETPC());
8ef7f78e
BS
274}
275
276/* or on array */
6fc2606e
RH
277static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest,
278 uint64_t src, uintptr_t ra)
8ef7f78e 279{
6fc2606e
RH
280 uint32_t i;
281 uint8_t c = 0;
8ef7f78e
BS
282
283 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
284 __func__, l, dest, src);
6fc2606e 285
8ef7f78e 286 for (i = 0; i <= l; i++) {
6fc2606e
RH
287 uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
288 x |= cpu_ldub_data_ra(env, dest + i, ra);
289 c |= x;
290 cpu_stb_data_ra(env, dest + i, x, ra);
8ef7f78e 291 }
6fc2606e
RH
292 return c != 0;
293}
294
295uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
296 uint64_t src)
297{
298 return do_helper_oc(env, l, dest, src, GETPC());
8ef7f78e
BS
299}
300
301/* memmove */
d376f123
RH
302static uint32_t do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest,
303 uint64_t src, uintptr_t ra)
8ef7f78e 304{
d3696812 305 uint32_t i;
8ef7f78e
BS
306
307 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
308 __func__, l, dest, src);
309
d376f123 310 /* mvc and memmove do not behave the same when areas overlap! */
fc89efe6
AJ
311 /* mvc with source pointing to the byte after the destination is the
312 same as memset with the first source byte */
d3696812
RH
313 if (dest == src + 1) {
314 fast_memset(env, dest, cpu_ldub_data_ra(env, src, ra), l + 1, ra);
d376f123 315 } else if (dest < src || src + l < dest) {
d3696812 316 fast_memmove(env, dest, src, l + 1, ra);
d376f123
RH
317 } else {
318 /* slow version with byte accesses which always work */
319 for (i = 0; i <= l; i++) {
320 uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
321 cpu_stb_data_ra(env, dest + i, x, ra);
322 }
8ef7f78e 323 }
8ef7f78e 324
d376f123 325 return env->cc_op;
8ef7f78e
BS
326}
327
d3696812
RH
328void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
329{
330 do_helper_mvc(env, l, dest, src, GETPC());
331}
332
6c9deca8
AJ
333/* move inverse */
334void HELPER(mvcin)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
335{
336 uintptr_t ra = GETPC();
337 int i;
338
339 for (i = 0; i <= l; i++) {
340 uint8_t v = cpu_ldub_data_ra(env, src - i, ra);
341 cpu_stb_data_ra(env, dest + i, v, ra);
342 }
343}
344
256dab6f
AJ
345/* move numerics */
346void HELPER(mvn)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
347{
348 uintptr_t ra = GETPC();
349 int i;
350
351 for (i = 0; i <= l; i++) {
352 uint8_t v = cpu_ldub_data_ra(env, dest + i, ra) & 0xf0;
353 v |= cpu_ldub_data_ra(env, src + i, ra) & 0x0f;
354 cpu_stb_data_ra(env, dest + i, v, ra);
355 }
356}
357
fdc0a747
AJ
358/* move with offset */
359void HELPER(mvo)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
360{
361 uintptr_t ra = GETPC();
362 int len_dest = l >> 4;
363 int len_src = l & 0xf;
364 uint8_t byte_dest, byte_src;
365 int i;
366
367 src += len_src;
368 dest += len_dest;
369
370 /* Handle rightmost byte */
371 byte_src = cpu_ldub_data_ra(env, src, ra);
372 byte_dest = cpu_ldub_data_ra(env, dest, ra);
373 byte_dest = (byte_dest & 0x0f) | (byte_src << 4);
374 cpu_stb_data_ra(env, dest, byte_dest, ra);
375
376 /* Process remaining bytes from right to left */
377 for (i = 1; i <= len_dest; i++) {
378 byte_dest = byte_src >> 4;
379 if (len_src - i >= 0) {
380 byte_src = cpu_ldub_data_ra(env, src - i, ra);
381 } else {
382 byte_src = 0;
383 }
384 byte_dest |= byte_src << 4;
385 cpu_stb_data_ra(env, dest - i, byte_dest, ra);
386 }
387}
388
01f8db88
AJ
389/* move zones */
390void HELPER(mvz)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
391{
392 uintptr_t ra = GETPC();
393 int i;
394
395 for (i = 0; i <= l; i++) {
396 uint8_t b = cpu_ldub_data_ra(env, dest + i, ra) & 0x0f;
397 b |= cpu_ldub_data_ra(env, src + i, ra) & 0xf0;
398 cpu_stb_data_ra(env, dest + i, b, ra);
399 }
400}
401
8ef7f78e 402/* compare unsigned byte arrays */
e79f56f4
RH
403static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1,
404 uint64_t s2, uintptr_t ra)
8ef7f78e 405{
e79f56f4
RH
406 uint32_t i;
407 uint32_t cc = 0;
8ef7f78e
BS
408
409 HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
410 __func__, l, s1, s2);
e79f56f4 411
8ef7f78e 412 for (i = 0; i <= l; i++) {
e79f56f4
RH
413 uint8_t x = cpu_ldub_data_ra(env, s1 + i, ra);
414 uint8_t y = cpu_ldub_data_ra(env, s2 + i, ra);
8ef7f78e
BS
415 HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
416 if (x < y) {
417 cc = 1;
e79f56f4 418 break;
8ef7f78e
BS
419 } else if (x > y) {
420 cc = 2;
e79f56f4 421 break;
8ef7f78e
BS
422 }
423 }
e79f56f4 424
8ef7f78e
BS
425 HELPER_LOG("\n");
426 return cc;
427}
428
e79f56f4
RH
429uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2)
430{
431 return do_helper_clc(env, l, s1, s2, GETPC());
432}
433
8ef7f78e 434/* compare logical under mask */
19b0516f
BS
435uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
436 uint64_t addr)
8ef7f78e 437{
868b5cbd
RH
438 uintptr_t ra = GETPC();
439 uint32_t cc = 0;
8ef7f78e
BS
440
441 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
442 mask, addr);
868b5cbd 443
8ef7f78e
BS
444 while (mask) {
445 if (mask & 8) {
868b5cbd
RH
446 uint8_t d = cpu_ldub_data_ra(env, addr, ra);
447 uint8_t r = extract32(r1, 24, 8);
8ef7f78e
BS
448 HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
449 addr);
450 if (r < d) {
451 cc = 1;
452 break;
453 } else if (r > d) {
454 cc = 2;
455 break;
456 }
457 addr++;
458 }
459 mask = (mask << 1) & 0xf;
460 r1 <<= 8;
461 }
868b5cbd 462
8ef7f78e
BS
463 HELPER_LOG("\n");
464 return cc;
465}
466
a5c3cedd 467static inline uint64_t get_address(CPUS390XState *env, int reg)
8ef7f78e 468{
a5c3cedd 469 return wrap_address(env, env->regs[reg]);
8ef7f78e
BS
470}
471
a65047af
AJ
472static inline void set_address(CPUS390XState *env, int reg, uint64_t address)
473{
474 if (env->psw.mask & PSW_MASK_64) {
475 /* 64-Bit mode */
476 env->regs[reg] = address;
477 } else {
478 if (!(env->psw.mask & PSW_MASK_32)) {
479 /* 24-Bit mode. According to the PoO it is implementation
480 dependent if bits 32-39 remain unchanged or are set to
481 zeros. Choose the former so that the function can also be
482 used for TRT. */
483 env->regs[reg] = deposit64(env->regs[reg], 0, 24, address);
484 } else {
485 /* 31-Bit mode. According to the PoO it is implementation
486 dependent if bit 32 remains unchanged or is set to zero.
487 Choose the latter so that the function can also be used for
488 TRT. */
489 address &= 0x7fffffff;
490 env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
491 }
492 }
493}
494
29a58fd8
AJ
495static inline uint64_t wrap_length(CPUS390XState *env, uint64_t length)
496{
497 if (!(env->psw.mask & PSW_MASK_64)) {
498 /* 24-Bit and 31-Bit mode */
499 length &= 0x7fffffff;
500 }
501 return length;
502}
503
504static inline uint64_t get_length(CPUS390XState *env, int reg)
505{
506 return wrap_length(env, env->regs[reg]);
507}
508
509static inline void set_length(CPUS390XState *env, int reg, uint64_t length)
510{
511 if (env->psw.mask & PSW_MASK_64) {
512 /* 64-Bit mode */
513 env->regs[reg] = length;
514 } else {
515 /* 24-Bit and 31-Bit mode */
516 env->regs[reg] = deposit64(env->regs[reg], 0, 32, length);
517 }
518}
519
8ef7f78e 520/* search string (c is byte to search, r2 is string, r1 end of string) */
7591db78 521void HELPER(srst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
8ef7f78e 522{
4663e822 523 uintptr_t ra = GETPC();
7591db78 524 uint64_t end, str;
4600c994 525 uint32_t len;
7591db78 526 uint8_t v, c = env->regs[0];
8ef7f78e 527
7591db78
RH
528 /* Bits 32-55 must contain all 0. */
529 if (env->regs[0] & 0xffffff00u) {
8d2f850a 530 s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
7591db78 531 }
8ef7f78e 532
7591db78
RH
533 str = get_address(env, r2);
534 end = get_address(env, r1);
4600c994
RH
535
536 /* Lest we fail to service interrupts in a timely manner, limit the
e03ba136 537 amount of work we're willing to do. For now, let's cap at 8k. */
4600c994
RH
538 for (len = 0; len < 0x2000; ++len) {
539 if (str + len == end) {
540 /* Character not found. R1 & R2 are unmodified. */
541 env->cc_op = 2;
7591db78 542 return;
4600c994 543 }
4663e822 544 v = cpu_ldub_data_ra(env, str + len, ra);
4600c994
RH
545 if (v == c) {
546 /* Character found. Set R1 to the location; R2 is unmodified. */
547 env->cc_op = 1;
7591db78
RH
548 set_address(env, r1, str + len);
549 return;
8ef7f78e
BS
550 }
551 }
552
be7acb58
RH
553 /* CPU-determined bytes processed. Advance R2 to next byte to process. */
554 env->cc_op = 3;
555 set_address(env, r2, str + len);
556}
557
558void HELPER(srstu)(CPUS390XState *env, uint32_t r1, uint32_t r2)
559{
560 uintptr_t ra = GETPC();
561 uint32_t len;
562 uint16_t v, c = env->regs[0];
563 uint64_t end, str, adj_end;
564
565 /* Bits 32-47 of R0 must be zero. */
566 if (env->regs[0] & 0xffff0000u) {
8d2f850a 567 s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
be7acb58
RH
568 }
569
570 str = get_address(env, r2);
571 end = get_address(env, r1);
572
573 /* If the LSB of the two addresses differ, use one extra byte. */
574 adj_end = end + ((str ^ end) & 1);
575
576 /* Lest we fail to service interrupts in a timely manner, limit the
577 amount of work we're willing to do. For now, let's cap at 8k. */
578 for (len = 0; len < 0x2000; len += 2) {
579 if (str + len == adj_end) {
580 /* End of input found. */
581 env->cc_op = 2;
582 return;
583 }
584 v = cpu_lduw_data_ra(env, str + len, ra);
585 if (v == c) {
586 /* Character found. Set R1 to the location; R2 is unmodified. */
587 env->cc_op = 1;
588 set_address(env, r1, str + len);
589 return;
590 }
591 }
592
4600c994 593 /* CPU-determined bytes processed. Advance R2 to next byte to process. */
4600c994 594 env->cc_op = 3;
7591db78 595 set_address(env, r2, str + len);
8ef7f78e
BS
596}
597
598/* unsigned string compare (c is string terminator) */
aa31bf60 599uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
8ef7f78e 600{
3cc8ca3d 601 uintptr_t ra = GETPC();
aa31bf60 602 uint32_t len;
8ef7f78e
BS
603
604 c = c & 0xff;
a5c3cedd
AJ
605 s1 = wrap_address(env, s1);
606 s2 = wrap_address(env, s2);
aa31bf60
RH
607
608 /* Lest we fail to service interrupts in a timely manner, limit the
e03ba136 609 amount of work we're willing to do. For now, let's cap at 8k. */
aa31bf60 610 for (len = 0; len < 0x2000; ++len) {
3cc8ca3d
RH
611 uint8_t v1 = cpu_ldub_data_ra(env, s1 + len, ra);
612 uint8_t v2 = cpu_ldub_data_ra(env, s2 + len, ra);
aa31bf60
RH
613 if (v1 == v2) {
614 if (v1 == c) {
615 /* Equal. CC=0, and don't advance the registers. */
616 env->cc_op = 0;
617 env->retxl = s2;
618 return s1;
619 }
620 } else {
621 /* Unequal. CC={1,2}, and advance the registers. Note that
622 the terminator need not be zero, but the string that contains
623 the terminator is by definition "low". */
624 env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2);
625 env->retxl = s2 + len;
626 return s1 + len;
8ef7f78e 627 }
8ef7f78e
BS
628 }
629
aa31bf60
RH
630 /* CPU-determined bytes equal; advance the registers. */
631 env->cc_op = 3;
632 env->retxl = s2 + len;
633 return s1 + len;
8ef7f78e
BS
634}
635
636/* move page */
7cf96fca 637uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
8ef7f78e 638{
7cf96fca
RH
639 /* ??? missing r0 handling, which includes access keys, but more
640 importantly optional suppression of the exception! */
641 fast_memmove(env, r1, r2, TARGET_PAGE_SIZE, GETPC());
642 return 0; /* data moved */
8ef7f78e
BS
643}
644
645/* string copy (c is string terminator) */
aa31bf60 646uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s)
8ef7f78e 647{
08a4cb79 648 uintptr_t ra = GETPC();
aa31bf60 649 uint32_t len;
8ef7f78e
BS
650
651 c = c & 0xff;
a5c3cedd
AJ
652 d = wrap_address(env, d);
653 s = wrap_address(env, s);
aa31bf60
RH
654
655 /* Lest we fail to service interrupts in a timely manner, limit the
e03ba136 656 amount of work we're willing to do. For now, let's cap at 8k. */
aa31bf60 657 for (len = 0; len < 0x2000; ++len) {
08a4cb79
RH
658 uint8_t v = cpu_ldub_data_ra(env, s + len, ra);
659 cpu_stb_data_ra(env, d + len, v, ra);
8ef7f78e 660 if (v == c) {
aa31bf60
RH
661 /* Complete. Set CC=1 and advance R1. */
662 env->cc_op = 1;
663 env->retxl = s;
664 return d + len;
8ef7f78e 665 }
8ef7f78e 666 }
aa31bf60
RH
667
668 /* Incomplete. Set CC=3 and signal to advance R1 and R2. */
669 env->cc_op = 3;
670 env->retxl = s + len;
671 return d + len;
8ef7f78e
BS
672}
673
8ef7f78e 674/* load access registers r1 to r3 from memory at a2 */
19b0516f 675void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
8ef7f78e 676{
9393c020 677 uintptr_t ra = GETPC();
8ef7f78e
BS
678 int i;
679
21fc97c5
DH
680 if (a2 & 0x3) {
681 /* we either came here by lam or lamy, which have different lengths */
682 s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra);
683 }
684
8ef7f78e 685 for (i = r1;; i = (i + 1) % 16) {
9393c020 686 env->aregs[i] = cpu_ldl_data_ra(env, a2, ra);
8ef7f78e
BS
687 a2 += 4;
688
689 if (i == r3) {
690 break;
691 }
692 }
693}
694
695/* store access registers r1 to r3 in memory at a2 */
19b0516f 696void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
8ef7f78e 697{
44cf6c2e 698 uintptr_t ra = GETPC();
8ef7f78e
BS
699 int i;
700
21fc97c5
DH
701 if (a2 & 0x3) {
702 s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
703 }
704
8ef7f78e 705 for (i = r1;; i = (i + 1) % 16) {
44cf6c2e 706 cpu_stl_data_ra(env, a2, env->aregs[i], ra);
8ef7f78e
BS
707 a2 += 4;
708
709 if (i == r3) {
710 break;
711 }
712 }
713}
714
d3327121
AJ
715/* move long helper */
716static inline uint32_t do_mvcl(CPUS390XState *env,
717 uint64_t *dest, uint64_t *destlen,
718 uint64_t *src, uint64_t *srclen,
16f2e4b8 719 uint16_t pad, int wordsize, uintptr_t ra)
8ef7f78e 720{
d3327121 721 uint64_t len = MIN(*srclen, *destlen);
8ef7f78e
BS
722 uint32_t cc;
723
d3327121 724 if (*destlen == *srclen) {
8ef7f78e 725 cc = 0;
d3327121 726 } else if (*destlen < *srclen) {
8ef7f78e
BS
727 cc = 1;
728 } else {
729 cc = 2;
730 }
731
d3327121
AJ
732 /* Copy the src array */
733 fast_memmove(env, *dest, *src, len, ra);
734 *src += len;
735 *srclen -= len;
736 *dest += len;
737 *destlen -= len;
8ef7f78e 738
d3327121 739 /* Pad the remaining area */
16f2e4b8
AJ
740 if (wordsize == 1) {
741 fast_memset(env, *dest, pad, *destlen, ra);
742 *dest += *destlen;
743 *destlen = 0;
744 } else {
745 /* If remaining length is odd, pad with odd byte first. */
746 if (*destlen & 1) {
747 cpu_stb_data_ra(env, *dest, pad & 0xff, ra);
748 *dest += 1;
749 *destlen -= 1;
750 }
751 /* The remaining length is even, pad using words. */
752 for (; *destlen; *dest += 2, *destlen -= 2) {
753 cpu_stw_data_ra(env, *dest, pad, ra);
754 }
755 }
8ef7f78e 756
d3327121
AJ
757 return cc;
758}
759
760/* move long */
761uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
762{
763 uintptr_t ra = GETPC();
764 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
765 uint64_t dest = get_address(env, r1);
766 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
767 uint64_t src = get_address(env, r2);
768 uint8_t pad = env->regs[r2 + 1] >> 24;
769 uint32_t cc;
770
16f2e4b8 771 cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra);
8ef7f78e 772
d3327121
AJ
773 env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, destlen);
774 env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, srclen);
a65047af
AJ
775 set_address(env, r1, dest);
776 set_address(env, r2, src);
8ef7f78e
BS
777
778 return cc;
779}
780
d3327121 781/* move long extended */
19b0516f
BS
782uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
783 uint32_t r3)
8ef7f78e 784{
453e4c07 785 uintptr_t ra = GETPC();
29a58fd8 786 uint64_t destlen = get_length(env, r1 + 1);
a5c3cedd 787 uint64_t dest = get_address(env, r1);
29a58fd8 788 uint64_t srclen = get_length(env, r3 + 1);
a5c3cedd 789 uint64_t src = get_address(env, r3);
d3327121 790 uint8_t pad = a2;
8ef7f78e
BS
791 uint32_t cc;
792
16f2e4b8
AJ
793 cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra);
794
795 set_length(env, r1 + 1, destlen);
796 set_length(env, r3 + 1, srclen);
797 set_address(env, r1, dest);
798 set_address(env, r3, src);
799
800 return cc;
801}
802
803/* move long unicode */
804uint32_t HELPER(mvclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
805 uint32_t r3)
806{
807 uintptr_t ra = GETPC();
808 uint64_t destlen = get_length(env, r1 + 1);
809 uint64_t dest = get_address(env, r1);
810 uint64_t srclen = get_length(env, r3 + 1);
811 uint64_t src = get_address(env, r3);
812 uint16_t pad = a2;
813 uint32_t cc;
814
815 cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 2, ra);
8ef7f78e 816
d3327121
AJ
817 set_length(env, r1 + 1, destlen);
818 set_length(env, r3 + 1, srclen);
a65047af
AJ
819 set_address(env, r1, dest);
820 set_address(env, r3, src);
8ef7f78e
BS
821
822 return cc;
823}
824
5c2b48a8
AJ
825/* compare logical long helper */
826static inline uint32_t do_clcl(CPUS390XState *env,
827 uint64_t *src1, uint64_t *src1len,
828 uint64_t *src3, uint64_t *src3len,
31006af3
AJ
829 uint16_t pad, uint64_t limit,
830 int wordsize, uintptr_t ra)
5c2b48a8
AJ
831{
832 uint64_t len = MAX(*src1len, *src3len);
8ef7f78e
BS
833 uint32_t cc = 0;
834
31006af3
AJ
835 check_alignment(env, *src1len | *src3len, wordsize, ra);
836
84aa07f1 837 if (!len) {
8ef7f78e
BS
838 return cc;
839 }
840
84aa07f1 841 /* Lest we fail to service interrupts in a timely manner, limit the
5c2b48a8
AJ
842 amount of work we're willing to do. */
843 if (len > limit) {
844 len = limit;
84aa07f1 845 cc = 3;
8ef7f78e
BS
846 }
847
31006af3
AJ
848 for (; len; len -= wordsize) {
849 uint16_t v1 = pad;
850 uint16_t v3 = pad;
84aa07f1 851
5c2b48a8 852 if (*src1len) {
31006af3 853 v1 = cpu_ldusize_data_ra(env, *src1, wordsize, ra);
84aa07f1 854 }
5c2b48a8 855 if (*src3len) {
31006af3 856 v3 = cpu_ldusize_data_ra(env, *src3, wordsize, ra);
84aa07f1
AJ
857 }
858
859 if (v1 != v3) {
860 cc = (v1 < v3) ? 1 : 2;
8ef7f78e
BS
861 break;
862 }
84aa07f1 863
5c2b48a8 864 if (*src1len) {
31006af3
AJ
865 *src1 += wordsize;
866 *src1len -= wordsize;
84aa07f1 867 }
5c2b48a8 868 if (*src3len) {
31006af3
AJ
869 *src3 += wordsize;
870 *src3len -= wordsize;
84aa07f1 871 }
8ef7f78e
BS
872 }
873
5c2b48a8
AJ
874 return cc;
875}
876
877
878/* compare logical long */
879uint32_t HELPER(clcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
880{
881 uintptr_t ra = GETPC();
882 uint64_t src1len = extract64(env->regs[r1 + 1], 0, 24);
883 uint64_t src1 = get_address(env, r1);
884 uint64_t src3len = extract64(env->regs[r2 + 1], 0, 24);
885 uint64_t src3 = get_address(env, r2);
886 uint8_t pad = env->regs[r2 + 1] >> 24;
887 uint32_t cc;
888
31006af3 889 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, -1, 1, ra);
5c2b48a8
AJ
890
891 env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, src1len);
892 env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, src3len);
893 set_address(env, r1, src1);
894 set_address(env, r2, src3);
895
896 return cc;
897}
898
899/* compare logical long extended memcompare insn with padding */
900uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
901 uint32_t r3)
902{
903 uintptr_t ra = GETPC();
904 uint64_t src1len = get_length(env, r1 + 1);
905 uint64_t src1 = get_address(env, r1);
906 uint64_t src3len = get_length(env, r3 + 1);
907 uint64_t src3 = get_address(env, r3);
908 uint8_t pad = a2;
909 uint32_t cc;
910
31006af3
AJ
911 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x2000, 1, ra);
912
913 set_length(env, r1 + 1, src1len);
914 set_length(env, r3 + 1, src3len);
915 set_address(env, r1, src1);
916 set_address(env, r3, src3);
917
918 return cc;
919}
920
921/* compare logical long unicode memcompare insn with padding */
922uint32_t HELPER(clclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
923 uint32_t r3)
924{
925 uintptr_t ra = GETPC();
926 uint64_t src1len = get_length(env, r1 + 1);
927 uint64_t src1 = get_address(env, r1);
928 uint64_t src3len = get_length(env, r3 + 1);
929 uint64_t src3 = get_address(env, r3);
930 uint16_t pad = a2;
931 uint32_t cc = 0;
932
933 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x1000, 2, ra);
5c2b48a8 934
84aa07f1
AJ
935 set_length(env, r1 + 1, src1len);
936 set_length(env, r3 + 1, src3len);
937 set_address(env, r1, src1);
938 set_address(env, r3, src3);
8ef7f78e
BS
939
940 return cc;
941}
942
943/* checksum */
374724f9
RH
944uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
945 uint64_t src, uint64_t src_len)
8ef7f78e 946{
498644e9 947 uintptr_t ra = GETPC();
374724f9
RH
948 uint64_t max_len, len;
949 uint64_t cksm = (uint32_t)r1;
8ef7f78e 950
374724f9 951 /* Lest we fail to service interrupts in a timely manner, limit the
e03ba136 952 amount of work we're willing to do. For now, let's cap at 8k. */
374724f9 953 max_len = (src_len > 0x2000 ? 0x2000 : src_len);
8ef7f78e 954
374724f9
RH
955 /* Process full words as available. */
956 for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
498644e9 957 cksm += (uint32_t)cpu_ldl_data_ra(env, src, ra);
8ef7f78e
BS
958 }
959
374724f9 960 switch (max_len - len) {
8ef7f78e 961 case 1:
498644e9 962 cksm += cpu_ldub_data_ra(env, src, ra) << 24;
374724f9 963 len += 1;
8ef7f78e
BS
964 break;
965 case 2:
498644e9 966 cksm += cpu_lduw_data_ra(env, src, ra) << 16;
374724f9 967 len += 2;
8ef7f78e
BS
968 break;
969 case 3:
498644e9
RH
970 cksm += cpu_lduw_data_ra(env, src, ra) << 16;
971 cksm += cpu_ldub_data_ra(env, src + 2, ra) << 8;
374724f9 972 len += 3;
8ef7f78e
BS
973 break;
974 }
975
374724f9
RH
976 /* Fold the carry from the checksum. Note that we can see carry-out
977 during folding more than once (but probably not more than twice). */
978 while (cksm > 0xffffffffull) {
979 cksm = (uint32_t)cksm + (cksm >> 32);
980 }
981
982 /* Indicate whether or not we've processed everything. */
983 env->cc_op = (len == src_len ? 0 : 3);
8ef7f78e 984
374724f9
RH
985 /* Return both cksm and processed length. */
986 env->retxl = cksm;
987 return len;
8ef7f78e
BS
988}
989
76c57490
AJ
990void HELPER(pack)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src)
991{
992 uintptr_t ra = GETPC();
993 int len_dest = len >> 4;
994 int len_src = len & 0xf;
995 uint8_t b;
996
997 dest += len_dest;
998 src += len_src;
999
1000 /* last byte is special, it only flips the nibbles */
1001 b = cpu_ldub_data_ra(env, src, ra);
1002 cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
1003 src--;
1004 len_src--;
1005
1006 /* now pack every value */
3cea0927 1007 while (len_dest > 0) {
76c57490
AJ
1008 b = 0;
1009
3cea0927 1010 if (len_src >= 0) {
76c57490
AJ
1011 b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
1012 src--;
1013 len_src--;
1014 }
3cea0927 1015 if (len_src >= 0) {
76c57490
AJ
1016 b |= cpu_ldub_data_ra(env, src, ra) << 4;
1017 src--;
1018 len_src--;
1019 }
1020
1021 len_dest--;
1022 dest--;
1023 cpu_stb_data_ra(env, dest, b, ra);
1024 }
1025}
1026
4e256bef
AJ
1027static inline void do_pkau(CPUS390XState *env, uint64_t dest, uint64_t src,
1028 uint32_t srclen, int ssize, uintptr_t ra)
3bd3d6d3 1029{
3bd3d6d3
AJ
1030 int i;
1031 /* The destination operand is always 16 bytes long. */
1032 const int destlen = 16;
1033
1034 /* The operands are processed from right to left. */
1035 src += srclen - 1;
1036 dest += destlen - 1;
1037
1038 for (i = 0; i < destlen; i++) {
1039 uint8_t b = 0;
1040
1041 /* Start with a positive sign */
1042 if (i == 0) {
1043 b = 0xc;
4e256bef 1044 } else if (srclen > ssize) {
3bd3d6d3 1045 b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
4e256bef
AJ
1046 src -= ssize;
1047 srclen -= ssize;
3bd3d6d3
AJ
1048 }
1049
4e256bef 1050 if (srclen > ssize) {
3bd3d6d3 1051 b |= cpu_ldub_data_ra(env, src, ra) << 4;
4e256bef
AJ
1052 src -= ssize;
1053 srclen -= ssize;
3bd3d6d3
AJ
1054 }
1055
1056 cpu_stb_data_ra(env, dest, b, ra);
1057 dest--;
1058 }
1059}
1060
4e256bef
AJ
1061
1062void HELPER(pka)(CPUS390XState *env, uint64_t dest, uint64_t src,
1063 uint32_t srclen)
1064{
1065 do_pkau(env, dest, src, srclen, 1, GETPC());
1066}
1067
1068void HELPER(pku)(CPUS390XState *env, uint64_t dest, uint64_t src,
1069 uint32_t srclen)
1070{
1071 do_pkau(env, dest, src, srclen, 2, GETPC());
1072}
1073
19b0516f
BS
1074void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
1075 uint64_t src)
8ef7f78e 1076{
84e1b98b 1077 uintptr_t ra = GETPC();
8ef7f78e
BS
1078 int len_dest = len >> 4;
1079 int len_src = len & 0xf;
1080 uint8_t b;
1081 int second_nibble = 0;
1082
1083 dest += len_dest;
1084 src += len_src;
1085
1086 /* last byte is special, it only flips the nibbles */
84e1b98b
RH
1087 b = cpu_ldub_data_ra(env, src, ra);
1088 cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
8ef7f78e
BS
1089 src--;
1090 len_src--;
1091
1092 /* now pad every nibble with 0xf0 */
1093
1094 while (len_dest > 0) {
1095 uint8_t cur_byte = 0;
1096
1097 if (len_src > 0) {
84e1b98b 1098 cur_byte = cpu_ldub_data_ra(env, src, ra);
8ef7f78e
BS
1099 }
1100
1101 len_dest--;
1102 dest--;
1103
1104 /* only advance one nibble at a time */
1105 if (second_nibble) {
1106 cur_byte >>= 4;
1107 len_src--;
1108 src--;
1109 }
1110 second_nibble = !second_nibble;
1111
1112 /* digit */
1113 cur_byte = (cur_byte & 0xf);
1114 /* zone bits */
1115 cur_byte |= 0xf0;
1116
84e1b98b 1117 cpu_stb_data_ra(env, dest, cur_byte, ra);
8ef7f78e
BS
1118 }
1119}
1120
15417787
AJ
1121static inline uint32_t do_unpkau(CPUS390XState *env, uint64_t dest,
1122 uint32_t destlen, int dsize, uint64_t src,
1123 uintptr_t ra)
1a35f08a 1124{
1a35f08a
AJ
1125 int i;
1126 uint32_t cc;
1127 uint8_t b;
1128 /* The source operand is always 16 bytes long. */
1129 const int srclen = 16;
1130
1131 /* The operands are processed from right to left. */
1132 src += srclen - 1;
15417787 1133 dest += destlen - dsize;
1a35f08a
AJ
1134
1135 /* Check for the sign. */
1136 b = cpu_ldub_data_ra(env, src, ra);
1137 src--;
1138 switch (b & 0xf) {
1139 case 0xa:
1140 case 0xc:
1141 case 0xe ... 0xf:
1142 cc = 0; /* plus */
1143 break;
1144 case 0xb:
1145 case 0xd:
1146 cc = 1; /* minus */
1147 break;
1148 default:
1149 case 0x0 ... 0x9:
1150 cc = 3; /* invalid */
1151 break;
1152 }
1153
1154 /* Now pad every nibble with 0x30, advancing one nibble at a time. */
15417787
AJ
1155 for (i = 0; i < destlen; i += dsize) {
1156 if (i == (31 * dsize)) {
1157 /* If length is 32/64 bytes, the leftmost byte is 0. */
1a35f08a 1158 b = 0;
15417787 1159 } else if (i % (2 * dsize)) {
1a35f08a
AJ
1160 b = cpu_ldub_data_ra(env, src, ra);
1161 src--;
1162 } else {
1163 b >>= 4;
1164 }
15417787
AJ
1165 cpu_stsize_data_ra(env, dest, 0x30 + (b & 0xf), dsize, ra);
1166 dest -= dsize;
1a35f08a
AJ
1167 }
1168
1169 return cc;
1170}
1171
15417787
AJ
1172uint32_t HELPER(unpka)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1173 uint64_t src)
1174{
1175 return do_unpkau(env, dest, destlen, 1, src, GETPC());
1176}
1177
1178uint32_t HELPER(unpku)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1179 uint64_t src)
1180{
1181 return do_unpkau(env, dest, destlen, 2, src, GETPC());
1182}
1183
5d4a655a
AJ
1184uint32_t HELPER(tp)(CPUS390XState *env, uint64_t dest, uint32_t destlen)
1185{
1186 uintptr_t ra = GETPC();
1187 uint32_t cc = 0;
1188 int i;
1189
1190 for (i = 0; i < destlen; i++) {
1191 uint8_t b = cpu_ldub_data_ra(env, dest + i, ra);
1192 /* digit */
1193 cc |= (b & 0xf0) > 0x90 ? 2 : 0;
1194
1195 if (i == (destlen - 1)) {
1196 /* sign */
1197 cc |= (b & 0xf) < 0xa ? 1 : 0;
1198 } else {
1199 /* digit */
1200 cc |= (b & 0xf) > 0x9 ? 2 : 0;
1201 }
1202 }
1203
1204 return cc;
1205}
1206
d376f123
RH
1207static uint32_t do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array,
1208 uint64_t trans, uintptr_t ra)
8ef7f78e 1209{
981a8ea0 1210 uint32_t i;
8ef7f78e
BS
1211
1212 for (i = 0; i <= len; i++) {
981a8ea0
RH
1213 uint8_t byte = cpu_ldub_data_ra(env, array + i, ra);
1214 uint8_t new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
1215 cpu_stb_data_ra(env, array + i, new_byte, ra);
8ef7f78e 1216 }
d376f123
RH
1217
1218 return env->cc_op;
8ef7f78e
BS
1219}
1220
981a8ea0
RH
1221void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
1222 uint64_t trans)
1223{
d376f123 1224 do_helper_tr(env, len, array, trans, GETPC());
981a8ea0
RH
1225}
1226
3f4de675
AJ
1227uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array,
1228 uint64_t len, uint64_t trans)
1229{
d46cd62f 1230 uintptr_t ra = GETPC();
3f4de675
AJ
1231 uint8_t end = env->regs[0] & 0xff;
1232 uint64_t l = len;
1233 uint64_t i;
d46cd62f 1234 uint32_t cc = 0;
3f4de675
AJ
1235
1236 if (!(env->psw.mask & PSW_MASK_64)) {
1237 array &= 0x7fffffff;
1238 l = (uint32_t)l;
1239 }
1240
1241 /* Lest we fail to service interrupts in a timely manner, limit the
1242 amount of work we're willing to do. For now, let's cap at 8k. */
1243 if (l > 0x2000) {
1244 l = 0x2000;
d46cd62f 1245 cc = 3;
3f4de675
AJ
1246 }
1247
1248 for (i = 0; i < l; i++) {
1249 uint8_t byte, new_byte;
1250
d46cd62f 1251 byte = cpu_ldub_data_ra(env, array + i, ra);
3f4de675
AJ
1252
1253 if (byte == end) {
d46cd62f 1254 cc = 1;
3f4de675
AJ
1255 break;
1256 }
1257
d46cd62f
RH
1258 new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
1259 cpu_stb_data_ra(env, array + i, new_byte, ra);
3f4de675
AJ
1260 }
1261
d46cd62f 1262 env->cc_op = cc;
3f4de675
AJ
1263 env->retxl = len - i;
1264 return array + i;
1265}
1266
b213c9f5
RH
1267static inline uint32_t do_helper_trt(CPUS390XState *env, int len,
1268 uint64_t array, uint64_t trans,
1269 int inc, uintptr_t ra)
54f00775 1270{
b213c9f5 1271 int i;
54f00775
AJ
1272
1273 for (i = 0; i <= len; i++) {
b213c9f5 1274 uint8_t byte = cpu_ldub_data_ra(env, array + i * inc, ra);
2c7e5f8c 1275 uint8_t sbyte = cpu_ldub_data_ra(env, trans + byte, ra);
54f00775
AJ
1276
1277 if (sbyte != 0) {
b213c9f5 1278 set_address(env, 1, array + i * inc);
2c7e5f8c
RH
1279 env->regs[2] = deposit64(env->regs[2], 0, 8, sbyte);
1280 return (i == len) ? 2 : 1;
54f00775
AJ
1281 }
1282 }
1283
2c7e5f8c
RH
1284 return 0;
1285}
1286
ad8c851d
PZ
1287static uint32_t do_helper_trt_fwd(CPUS390XState *env, uint32_t len,
1288 uint64_t array, uint64_t trans,
1289 uintptr_t ra)
1290{
1291 return do_helper_trt(env, len, array, trans, 1, ra);
1292}
1293
2c7e5f8c
RH
1294uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
1295 uint64_t trans)
1296{
b213c9f5
RH
1297 return do_helper_trt(env, len, array, trans, 1, GETPC());
1298}
1299
ad8c851d
PZ
1300static uint32_t do_helper_trt_bkwd(CPUS390XState *env, uint32_t len,
1301 uint64_t array, uint64_t trans,
1302 uintptr_t ra)
1303{
1304 return do_helper_trt(env, len, array, trans, -1, ra);
1305}
1306
b213c9f5
RH
1307uint32_t HELPER(trtr)(CPUS390XState *env, uint32_t len, uint64_t array,
1308 uint64_t trans)
1309{
1310 return do_helper_trt(env, len, array, trans, -1, GETPC());
54f00775
AJ
1311}
1312
4065ae76
AJ
1313/* Translate one/two to one/two */
1314uint32_t HELPER(trXX)(CPUS390XState *env, uint32_t r1, uint32_t r2,
1315 uint32_t tst, uint32_t sizes)
1316{
1317 uintptr_t ra = GETPC();
1318 int dsize = (sizes & 1) ? 1 : 2;
1319 int ssize = (sizes & 2) ? 1 : 2;
3c39c800 1320 uint64_t tbl = get_address(env, 1);
4065ae76
AJ
1321 uint64_t dst = get_address(env, r1);
1322 uint64_t len = get_length(env, r1 + 1);
1323 uint64_t src = get_address(env, r2);
1324 uint32_t cc = 3;
1325 int i;
1326
3c39c800
RH
1327 /* The lower address bits of TBL are ignored. For TROO, TROT, it's
1328 the low 3 bits (double-word aligned). For TRTO, TRTT, it's either
1329 the low 12 bits (4K, without ETF2-ENH) or 3 bits (with ETF2-ENH). */
1330 if (ssize == 2 && !s390_has_feat(S390_FEAT_ETF2_ENH)) {
1331 tbl &= -4096;
1332 } else {
1333 tbl &= -8;
1334 }
1335
4065ae76
AJ
1336 check_alignment(env, len, ssize, ra);
1337
1338 /* Lest we fail to service interrupts in a timely manner, */
1339 /* limit the amount of work we're willing to do. */
1340 for (i = 0; i < 0x2000; i++) {
1341 uint16_t sval = cpu_ldusize_data_ra(env, src, ssize, ra);
1342 uint64_t tble = tbl + (sval * dsize);
1343 uint16_t dval = cpu_ldusize_data_ra(env, tble, dsize, ra);
1344 if (dval == tst) {
1345 cc = 1;
1346 break;
1347 }
1348 cpu_stsize_data_ra(env, dst, dval, dsize, ra);
1349
1350 len -= ssize;
1351 src += ssize;
1352 dst += dsize;
1353
1354 if (len == 0) {
1355 cc = 0;
1356 break;
1357 }
1358 }
1359
1360 set_address(env, r1, dst);
1361 set_length(env, r1 + 1, len);
1362 set_address(env, r2, src);
1363
1364 return cc;
1365}
1366
0c9fa168
RH
1367void HELPER(cdsg)(CPUS390XState *env, uint64_t addr,
1368 uint32_t r1, uint32_t r3)
303a9ab8
RH
1369{
1370 uintptr_t ra = GETPC();
1371 Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
1372 Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1373 Int128 oldv;
0c9fa168 1374 uint64_t oldh, oldl;
303a9ab8
RH
1375 bool fail;
1376
0c9fa168 1377 check_alignment(env, addr, 16, ra);
c0080f1b 1378
0c9fa168
RH
1379 oldh = cpu_ldq_data_ra(env, addr + 0, ra);
1380 oldl = cpu_ldq_data_ra(env, addr + 8, ra);
303a9ab8 1381
0c9fa168
RH
1382 oldv = int128_make128(oldl, oldh);
1383 fail = !int128_eq(oldv, cmpv);
1384 if (fail) {
1385 newv = oldv;
303a9ab8
RH
1386 }
1387
0c9fa168
RH
1388 cpu_stq_data_ra(env, addr + 0, int128_gethi(newv), ra);
1389 cpu_stq_data_ra(env, addr + 8, int128_getlo(newv), ra);
1390
303a9ab8
RH
1391 env->cc_op = fail;
1392 env->regs[r1] = int128_gethi(oldv);
1393 env->regs[r1 + 1] = int128_getlo(oldv);
1394}
1395
6476615d
EC
1396void HELPER(cdsg_parallel)(CPUS390XState *env, uint64_t addr,
1397 uint32_t r1, uint32_t r3)
1398{
0c9fa168
RH
1399 uintptr_t ra = GETPC();
1400 Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
1401 Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1402 int mem_idx;
1403 TCGMemOpIdx oi;
1404 Int128 oldv;
1405 bool fail;
1406
830bf10c 1407 assert(HAVE_CMPXCHG128);
0c9fa168
RH
1408
1409 mem_idx = cpu_mmu_index(env, false);
1410 oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1411 oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
1412 fail = !int128_eq(oldv, cmpv);
1413
1414 env->cc_op = fail;
1415 env->regs[r1] = int128_gethi(oldv);
1416 env->regs[r1 + 1] = int128_getlo(oldv);
6476615d
EC
1417}
1418
1419static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
1420 uint64_t a2, bool parallel)
c67ba303 1421{
c67ba303 1422 uint32_t mem_idx = cpu_mmu_index(env, false);
c67ba303
RH
1423 uintptr_t ra = GETPC();
1424 uint32_t fc = extract32(env->regs[0], 0, 8);
1425 uint32_t sc = extract32(env->regs[0], 8, 8);
1426 uint64_t pl = get_address(env, 1) & -16;
1427 uint64_t svh, svl;
1428 uint32_t cc;
1429
1430 /* Sanity check the function code and storage characteristic. */
1431 if (fc > 1 || sc > 3) {
1432 if (!s390_has_feat(S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2)) {
1433 goto spec_exception;
1434 }
1435 if (fc > 2 || sc > 4 || (fc == 2 && (r3 & 1))) {
1436 goto spec_exception;
1437 }
1438 }
1439
1440 /* Sanity check the alignments. */
dc95b31d 1441 if (extract32(a1, 0, fc + 2) || extract32(a2, 0, sc)) {
c67ba303
RH
1442 goto spec_exception;
1443 }
1444
1445 /* Sanity check writability of the store address. */
1446#ifndef CONFIG_USER_ONLY
98670d47 1447 probe_write(env, a2, 0, mem_idx, ra);
c67ba303
RH
1448#endif
1449
5e95612e
RH
1450 /*
1451 * Note that the compare-and-swap is atomic, and the store is atomic,
1452 * but the complete operation is not. Therefore we do not need to
1453 * assert serial context in order to implement this. That said,
1454 * restart early if we can't support either operation that is supposed
1455 * to be atomic.
1456 */
6476615d 1457 if (parallel) {
5e95612e
RH
1458 uint32_t max = 2;
1459#ifdef CONFIG_ATOMIC64
1460 max = 3;
c67ba303 1461#endif
5e95612e
RH
1462 if ((HAVE_CMPXCHG128 ? 0 : fc + 2 > max) ||
1463 (HAVE_ATOMIC128 ? 0 : sc > max)) {
29a0af61 1464 cpu_loop_exit_atomic(env_cpu(env), ra);
c67ba303
RH
1465 }
1466 }
1467
1468 /* All loads happen before all stores. For simplicity, load the entire
1469 store value area from the parameter list. */
1470 svh = cpu_ldq_data_ra(env, pl + 16, ra);
1471 svl = cpu_ldq_data_ra(env, pl + 24, ra);
1472
1473 switch (fc) {
1474 case 0:
1475 {
1476 uint32_t nv = cpu_ldl_data_ra(env, pl, ra);
1477 uint32_t cv = env->regs[r3];
1478 uint32_t ov;
1479
6476615d 1480 if (parallel) {
c67ba303
RH
1481#ifdef CONFIG_USER_ONLY
1482 uint32_t *haddr = g2h(a1);
1483 ov = atomic_cmpxchg__nocheck(haddr, cv, nv);
1484#else
1485 TCGMemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mem_idx);
1486 ov = helper_atomic_cmpxchgl_be_mmu(env, a1, cv, nv, oi, ra);
1487#endif
1488 } else {
1489 ov = cpu_ldl_data_ra(env, a1, ra);
1490 cpu_stl_data_ra(env, a1, (ov == cv ? nv : ov), ra);
1491 }
1492 cc = (ov != cv);
1493 env->regs[r3] = deposit64(env->regs[r3], 32, 32, ov);
1494 }
1495 break;
1496
1497 case 1:
1498 {
1499 uint64_t nv = cpu_ldq_data_ra(env, pl, ra);
1500 uint64_t cv = env->regs[r3];
1501 uint64_t ov;
1502
6476615d 1503 if (parallel) {
c67ba303
RH
1504#ifdef CONFIG_ATOMIC64
1505# ifdef CONFIG_USER_ONLY
1506 uint64_t *haddr = g2h(a1);
1507 ov = atomic_cmpxchg__nocheck(haddr, cv, nv);
1508# else
1509 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN, mem_idx);
1510 ov = helper_atomic_cmpxchgq_be_mmu(env, a1, cv, nv, oi, ra);
1511# endif
1512#else
6476615d 1513 /* Note that we asserted !parallel above. */
c67ba303
RH
1514 g_assert_not_reached();
1515#endif
1516 } else {
1517 ov = cpu_ldq_data_ra(env, a1, ra);
1518 cpu_stq_data_ra(env, a1, (ov == cv ? nv : ov), ra);
1519 }
1520 cc = (ov != cv);
1521 env->regs[r3] = ov;
1522 }
1523 break;
1524
1525 case 2:
1526 {
1527 uint64_t nvh = cpu_ldq_data_ra(env, pl, ra);
1528 uint64_t nvl = cpu_ldq_data_ra(env, pl + 8, ra);
1529 Int128 nv = int128_make128(nvl, nvh);
1530 Int128 cv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1531 Int128 ov;
1532
5e95612e 1533 if (!parallel) {
c67ba303
RH
1534 uint64_t oh = cpu_ldq_data_ra(env, a1 + 0, ra);
1535 uint64_t ol = cpu_ldq_data_ra(env, a1 + 8, ra);
1536
1537 ov = int128_make128(ol, oh);
1538 cc = !int128_eq(ov, cv);
1539 if (cc) {
1540 nv = ov;
1541 }
1542
1543 cpu_stq_data_ra(env, a1 + 0, int128_gethi(nv), ra);
1544 cpu_stq_data_ra(env, a1 + 8, int128_getlo(nv), ra);
5e95612e
RH
1545 } else if (HAVE_CMPXCHG128) {
1546 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1547 ov = helper_atomic_cmpxchgo_be_mmu(env, a1, cv, nv, oi, ra);
1548 cc = !int128_eq(ov, cv);
1549 } else {
1550 /* Note that we asserted !parallel above. */
1551 g_assert_not_reached();
c67ba303
RH
1552 }
1553
1554 env->regs[r3 + 0] = int128_gethi(ov);
1555 env->regs[r3 + 1] = int128_getlo(ov);
1556 }
1557 break;
1558
1559 default:
1560 g_assert_not_reached();
1561 }
1562
1563 /* Store only if the comparison succeeded. Note that above we use a pair
1564 of 64-bit big-endian loads, so for sc < 3 we must extract the value
1565 from the most-significant bits of svh. */
1566 if (cc == 0) {
1567 switch (sc) {
1568 case 0:
1569 cpu_stb_data_ra(env, a2, svh >> 56, ra);
1570 break;
1571 case 1:
1572 cpu_stw_data_ra(env, a2, svh >> 48, ra);
1573 break;
1574 case 2:
1575 cpu_stl_data_ra(env, a2, svh >> 32, ra);
1576 break;
1577 case 3:
1578 cpu_stq_data_ra(env, a2, svh, ra);
1579 break;
1580 case 4:
5e95612e
RH
1581 if (!parallel) {
1582 cpu_stq_data_ra(env, a2 + 0, svh, ra);
1583 cpu_stq_data_ra(env, a2 + 8, svl, ra);
1584 } else if (HAVE_ATOMIC128) {
c67ba303
RH
1585 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1586 Int128 sv = int128_make128(svl, svh);
1587 helper_atomic_sto_be_mmu(env, a2, sv, oi, ra);
5e95612e 1588 } else {
6476615d 1589 /* Note that we asserted !parallel above. */
c67ba303 1590 g_assert_not_reached();
c67ba303 1591 }
de4e05d1 1592 break;
c67ba303
RH
1593 default:
1594 g_assert_not_reached();
1595 }
1596 }
1597
1598 return cc;
1599
1600 spec_exception:
8d2f850a 1601 s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
c67ba303
RH
1602 g_assert_not_reached();
1603}
1604
6476615d
EC
1605uint32_t HELPER(csst)(CPUS390XState *env, uint32_t r3, uint64_t a1, uint64_t a2)
1606{
1607 return do_csst(env, r3, a1, a2, false);
1608}
1609
1610uint32_t HELPER(csst_parallel)(CPUS390XState *env, uint32_t r3, uint64_t a1,
1611 uint64_t a2)
1612{
1613 return do_csst(env, r3, a1, a2, true);
1614}
1615
8ef7f78e 1616#if !defined(CONFIG_USER_ONLY)
19b0516f 1617void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
8ef7f78e 1618{
97ae2149 1619 uintptr_t ra = GETPC();
311918b9 1620 bool PERchanged = false;
8ef7f78e 1621 uint64_t src = a2;
97ae2149 1622 uint32_t i;
8ef7f78e 1623
21fc97c5
DH
1624 if (src & 0x7) {
1625 s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
1626 }
1627
8ef7f78e 1628 for (i = r1;; i = (i + 1) % 16) {
97ae2149 1629 uint64_t val = cpu_ldq_data_ra(env, src, ra);
311918b9
AJ
1630 if (env->cregs[i] != val && i >= 9 && i <= 11) {
1631 PERchanged = true;
1632 }
1633 env->cregs[i] = val;
8ef7f78e 1634 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
97ae2149 1635 i, src, val);
8ef7f78e
BS
1636 src += sizeof(uint64_t);
1637
1638 if (i == r3) {
1639 break;
1640 }
1641 }
1642
311918b9 1643 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
dc79e928 1644 s390_cpu_recompute_watchpoints(env_cpu(env));
311918b9
AJ
1645 }
1646
dc79e928 1647 tlb_flush(env_cpu(env));
8ef7f78e
BS
1648}
1649
19b0516f 1650void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
8ef7f78e 1651{
1b642a73 1652 uintptr_t ra = GETPC();
311918b9 1653 bool PERchanged = false;
8ef7f78e 1654 uint64_t src = a2;
1b642a73 1655 uint32_t i;
8ef7f78e 1656
21fc97c5
DH
1657 if (src & 0x3) {
1658 s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
1659 }
1660
8ef7f78e 1661 for (i = r1;; i = (i + 1) % 16) {
1b642a73 1662 uint32_t val = cpu_ldl_data_ra(env, src, ra);
311918b9
AJ
1663 if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
1664 PERchanged = true;
1665 }
1b642a73
RH
1666 env->cregs[i] = deposit64(env->cregs[i], 0, 32, val);
1667 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val);
8ef7f78e
BS
1668 src += sizeof(uint32_t);
1669
1670 if (i == r3) {
1671 break;
1672 }
1673 }
1674
311918b9 1675 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
dc79e928 1676 s390_cpu_recompute_watchpoints(env_cpu(env));
311918b9
AJ
1677 }
1678
dc79e928 1679 tlb_flush(env_cpu(env));
8ef7f78e
BS
1680}
1681
19b0516f 1682void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
8ef7f78e 1683{
75d6240c 1684 uintptr_t ra = GETPC();
8ef7f78e 1685 uint64_t dest = a2;
75d6240c 1686 uint32_t i;
8ef7f78e 1687
21fc97c5
DH
1688 if (dest & 0x7) {
1689 s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
1690 }
1691
8ef7f78e 1692 for (i = r1;; i = (i + 1) % 16) {
75d6240c 1693 cpu_stq_data_ra(env, dest, env->cregs[i], ra);
8ef7f78e
BS
1694 dest += sizeof(uint64_t);
1695
1696 if (i == r3) {
1697 break;
1698 }
1699 }
1700}
1701
19b0516f 1702void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
8ef7f78e 1703{
75d6240c 1704 uintptr_t ra = GETPC();
8ef7f78e 1705 uint64_t dest = a2;
75d6240c 1706 uint32_t i;
8ef7f78e 1707
21fc97c5
DH
1708 if (dest & 0x3) {
1709 s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
1710 }
1711
8ef7f78e 1712 for (i = r1;; i = (i + 1) % 16) {
75d6240c 1713 cpu_stl_data_ra(env, dest, env->cregs[i], ra);
8ef7f78e
BS
1714 dest += sizeof(uint32_t);
1715
1716 if (i == r3) {
1717 break;
1718 }
1719 }
1720}
1721
f79f1ca4
TH
1722uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
1723{
aef2b01a 1724 uintptr_t ra = GETPC();
f79f1ca4
TH
1725 int i;
1726
e26131c9 1727 real_addr = wrap_address(env, real_addr) & TARGET_PAGE_MASK;
f79f1ca4 1728
f79f1ca4 1729 for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
e26131c9 1730 cpu_stq_real_ra(env, real_addr + i, 0, ra);
f79f1ca4
TH
1731 }
1732
1733 return 0;
1734}
1735
bb879430 1736uint32_t HELPER(tprot)(CPUS390XState *env, uint64_t a1, uint64_t a2)
8ef7f78e 1737{
dc79e928
RH
1738 S390CPU *cpu = env_archcpu(env);
1739 CPUState *cs = env_cpu(env);
bb879430
DH
1740
1741 /*
1742 * TODO: we currently don't handle all access protection types
1743 * (including access-list and key-controlled) as well as AR mode.
1744 */
1745 if (!s390_cpu_virt_mem_check_write(cpu, a1, 0, 1)) {
1746 /* Fetching permitted; storing permitted */
1747 return 0;
1748 }
b5e85329
DH
1749
1750 if (env->int_pgm_code == PGM_PROTECTION) {
1751 /* retry if reading is possible */
1752 cs->exception_index = 0;
1753 if (!s390_cpu_virt_mem_check_read(cpu, a1, 0, 1)) {
1754 /* Fetching permitted; storing not permitted */
1755 return 1;
1756 }
1757 }
1758
bb879430
DH
1759 switch (env->int_pgm_code) {
1760 case PGM_PROTECTION:
bb879430
DH
1761 /* Fetching not permitted; storing not permitted */
1762 cs->exception_index = 0;
1763 return 2;
b5e85329
DH
1764 case PGM_ADDRESSING:
1765 case PGM_TRANS_SPEC:
1766 /* exceptions forwarded to the guest */
1767 s390_cpu_virt_mem_handle_exc(cpu, GETPC());
1768 return 0;
bb879430 1769 }
b5e85329
DH
1770
1771 /* Translation not available */
1772 cs->exception_index = 0;
1773 return 3;
8ef7f78e
BS
1774}
1775
1776/* insert storage key extended */
19b0516f 1777uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
8ef7f78e 1778{
0f5f6691
JH
1779 static S390SKeysState *ss;
1780 static S390SKeysClass *skeyclass;
a5c3cedd 1781 uint64_t addr = wrap_address(env, r2);
0f5f6691 1782 uint8_t key;
8ef7f78e
BS
1783
1784 if (addr > ram_size) {
1785 return 0;
1786 }
1787
0f5f6691
JH
1788 if (unlikely(!ss)) {
1789 ss = s390_get_skeys_device();
1790 skeyclass = S390_SKEYS_GET_CLASS(ss);
1791 }
1792
1793 if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
1794 return 0;
1795 }
1796 return key;
8ef7f78e
BS
1797}
1798
1799/* set storage key extended */
2bbde27f 1800void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
8ef7f78e 1801{
0f5f6691
JH
1802 static S390SKeysState *ss;
1803 static S390SKeysClass *skeyclass;
a5c3cedd 1804 uint64_t addr = wrap_address(env, r2);
0f5f6691 1805 uint8_t key;
8ef7f78e
BS
1806
1807 if (addr > ram_size) {
1808 return;
1809 }
1810
0f5f6691
JH
1811 if (unlikely(!ss)) {
1812 ss = s390_get_skeys_device();
1813 skeyclass = S390_SKEYS_GET_CLASS(ss);
1814 }
1815
1816 key = (uint8_t) r1;
1817 skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
5b773a11
DH
1818 /*
1819 * As we can only flush by virtual address and not all the entries
1820 * that point to a physical address we have to flush the whole TLB.
1821 */
1822 tlb_flush_all_cpus_synced(env_cpu(env));
8ef7f78e
BS
1823}
1824
1825/* reset reference bit extended */
5cc69c54 1826uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
8ef7f78e 1827{
0f5f6691
JH
1828 static S390SKeysState *ss;
1829 static S390SKeysClass *skeyclass;
1830 uint8_t re, key;
8ef7f78e
BS
1831
1832 if (r2 > ram_size) {
1833 return 0;
1834 }
1835
0f5f6691
JH
1836 if (unlikely(!ss)) {
1837 ss = s390_get_skeys_device();
1838 skeyclass = S390_SKEYS_GET_CLASS(ss);
1839 }
1840
1841 if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1842 return 0;
1843 }
1844
8ef7f78e 1845 re = key & (SK_R | SK_C);
0f5f6691
JH
1846 key &= ~SK_R;
1847
1848 if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1849 return 0;
1850 }
5b773a11
DH
1851 /*
1852 * As we can only flush by virtual address and not all the entries
1853 * that point to a physical address we have to flush the whole TLB.
1854 */
1855 tlb_flush_all_cpus_synced(env_cpu(env));
8ef7f78e
BS
1856
1857 /*
1858 * cc
1859 *
1860 * 0 Reference bit zero; change bit zero
1861 * 1 Reference bit zero; change bit one
1862 * 2 Reference bit one; change bit zero
1863 * 3 Reference bit one; change bit one
1864 */
1865
1866 return re >> 1;
1867}
1868
a3084e80 1869uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
8ef7f78e 1870{
b90fb26b 1871 uintptr_t ra = GETPC();
a3084e80 1872 int cc = 0, i;
8ef7f78e 1873
a3084e80
AJ
1874 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1875 __func__, l, a1, a2);
1876
1877 if (l > 256) {
8ef7f78e
BS
1878 /* max 256 */
1879 l = 256;
1880 cc = 3;
1881 }
1882
8ef7f78e
BS
1883 /* XXX replace w/ memcpy */
1884 for (i = 0; i < l; i++) {
b90fb26b
RH
1885 uint8_t x = cpu_ldub_primary_ra(env, a2 + i, ra);
1886 cpu_stb_secondary_ra(env, a1 + i, x, ra);
8ef7f78e
BS
1887 }
1888
1889 return cc;
1890}
1891
a3084e80 1892uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
8ef7f78e 1893{
b90fb26b 1894 uintptr_t ra = GETPC();
a3084e80
AJ
1895 int cc = 0, i;
1896
8ef7f78e
BS
1897 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1898 __func__, l, a1, a2);
1899
a3084e80
AJ
1900 if (l > 256) {
1901 /* max 256 */
1902 l = 256;
1903 cc = 3;
1904 }
8ef7f78e 1905
a3084e80
AJ
1906 /* XXX replace w/ memcpy */
1907 for (i = 0; i < l; i++) {
b90fb26b
RH
1908 uint8_t x = cpu_ldub_secondary_ra(env, a2 + i, ra);
1909 cpu_stb_primary_ra(env, a1 + i, x, ra);
a3084e80 1910 }
8ef7f78e 1911
a3084e80 1912 return cc;
8ef7f78e
BS
1913}
1914
be7f28de
DH
1915void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4)
1916{
dc79e928 1917 CPUState *cs = env_cpu(env);
be7f28de
DH
1918 const uintptr_t ra = GETPC();
1919 uint64_t table, entry, raddr;
1920 uint16_t entries, i, index = 0;
1921
1922 if (r2 & 0xff000) {
8d2f850a 1923 s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
be7f28de
DH
1924 }
1925
1926 if (!(r2 & 0x800)) {
1927 /* invalidation-and-clearing operation */
adab99be 1928 table = r1 & ASCE_ORIGIN;
be7f28de
DH
1929 entries = (r2 & 0x7ff) + 1;
1930
adab99be
TH
1931 switch (r1 & ASCE_TYPE_MASK) {
1932 case ASCE_TYPE_REGION1:
be7f28de
DH
1933 index = (r2 >> 53) & 0x7ff;
1934 break;
adab99be 1935 case ASCE_TYPE_REGION2:
be7f28de
DH
1936 index = (r2 >> 42) & 0x7ff;
1937 break;
adab99be 1938 case ASCE_TYPE_REGION3:
be7f28de
DH
1939 index = (r2 >> 31) & 0x7ff;
1940 break;
adab99be 1941 case ASCE_TYPE_SEGMENT:
be7f28de
DH
1942 index = (r2 >> 20) & 0x7ff;
1943 break;
1944 }
1945 for (i = 0; i < entries; i++) {
1946 /* addresses are not wrapped in 24/31bit mode but table index is */
1947 raddr = table + ((index + i) & 0x7ff) * sizeof(entry);
8eb82de9 1948 entry = cpu_ldq_real_ra(env, raddr, ra);
adab99be 1949 if (!(entry & REGION_ENTRY_INV)) {
be7f28de 1950 /* we are allowed to not store if already invalid */
adab99be 1951 entry |= REGION_ENTRY_INV;
8eb82de9 1952 cpu_stq_real_ra(env, raddr, entry, ra);
be7f28de
DH
1953 }
1954 }
1955 }
1956
1957 /* We simply flush the complete tlb, therefore we can ignore r3. */
1958 if (m4 & 1) {
1959 tlb_flush(cs);
1960 } else {
1961 tlb_flush_all_cpus_synced(cs);
1962 }
1963}
1964
8ef7f78e 1965/* invalidate pte */
1f58720c
AJ
1966void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr,
1967 uint32_t m4)
8ef7f78e 1968{
dc79e928 1969 CPUState *cs = env_cpu(env);
8eb82de9 1970 const uintptr_t ra = GETPC();
8ef7f78e 1971 uint64_t page = vaddr & TARGET_PAGE_MASK;
8a4719f5 1972 uint64_t pte_addr, pte;
8ef7f78e 1973
8a4719f5 1974 /* Compute the page table entry address */
adab99be 1975 pte_addr = (pto & SEGMENT_ENTRY_ORIGIN);
1f58720c 1976 pte_addr += (vaddr & VADDR_PX) >> 9;
8a4719f5
AJ
1977
1978 /* Mark the page table entry as invalid */
8eb82de9 1979 pte = cpu_ldq_real_ra(env, pte_addr, ra);
adab99be 1980 pte |= PAGE_INVALID;
8eb82de9 1981 cpu_stq_real_ra(env, pte_addr, pte, ra);
8ef7f78e
BS
1982
1983 /* XXX we exploit the fact that Linux passes the exact virtual
1984 address here - it's not obliged to! */
1f58720c 1985 if (m4 & 1) {
97b95aae
DH
1986 if (vaddr & ~VADDR_PX) {
1987 tlb_flush_page(cs, page);
1988 /* XXX 31-bit hack */
1989 tlb_flush_page(cs, page ^ 0x80000000);
1990 } else {
1991 /* looks like we don't have a valid virtual address */
1992 tlb_flush(cs);
1993 }
8ef7f78e 1994 } else {
97b95aae
DH
1995 if (vaddr & ~VADDR_PX) {
1996 tlb_flush_page_all_cpus_synced(cs, page);
1997 /* XXX 31-bit hack */
1998 tlb_flush_page_all_cpus_synced(cs, page ^ 0x80000000);
1999 } else {
2000 /* looks like we don't have a valid virtual address */
2001 tlb_flush_all_cpus_synced(cs);
2002 }
8ef7f78e
BS
2003 }
2004}
2005
2006/* flush local tlb */
19b0516f 2007void HELPER(ptlb)(CPUS390XState *env)
8ef7f78e 2008{
dc79e928 2009 tlb_flush(env_cpu(env));
8ef7f78e
BS
2010}
2011
31a18b45
RH
2012/* flush global tlb */
2013void HELPER(purge)(CPUS390XState *env)
2014{
dc79e928 2015 tlb_flush_all_cpus_synced(env_cpu(env));
31a18b45
RH
2016}
2017
9c3fd85b
RH
2018/* load using real address */
2019uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr)
2020{
34499dad 2021 return cpu_ldl_real_ra(env, wrap_address(env, addr), GETPC());
9c3fd85b
RH
2022}
2023
2024uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr)
2025{
34499dad 2026 return cpu_ldq_real_ra(env, wrap_address(env, addr), GETPC());
9c3fd85b
RH
2027}
2028
8ef7f78e 2029/* store using real address */
204504e2 2030void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
8ef7f78e 2031{
4ae43341 2032 cpu_stl_real_ra(env, wrap_address(env, addr), (uint32_t)v1, GETPC());
2f543949
AJ
2033
2034 if ((env->psw.mask & PSW_MASK_PER) &&
2035 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
2036 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
2037 /* PSW is saved just before calling the helper. */
2038 env->per_address = env->psw.addr;
2039 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
2040 }
8ef7f78e
BS
2041}
2042
9c3fd85b
RH
2043void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
2044{
4ae43341 2045 cpu_stq_real_ra(env, wrap_address(env, addr), v1, GETPC());
2f543949
AJ
2046
2047 if ((env->psw.mask & PSW_MASK_PER) &&
2048 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
2049 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
2050 /* PSW is saved just before calling the helper. */
2051 env->per_address = env->psw.addr;
2052 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
2053 }
9c3fd85b
RH
2054}
2055
8ef7f78e 2056/* load real address */
d8fe4a9c 2057uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
8ef7f78e 2058{
dc79e928 2059 CPUState *cs = env_cpu(env);
8ef7f78e 2060 uint32_t cc = 0;
8ef7f78e
BS
2061 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
2062 uint64_t ret;
b157fbe6 2063 int old_exc, flags;
8ef7f78e
BS
2064
2065 /* XXX incomplete - has more corner cases */
2066 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
8d2f850a 2067 s390_program_interrupt(env, PGM_SPECIAL_OP, 2, GETPC());
8ef7f78e
BS
2068 }
2069
b157fbe6 2070 old_exc = cs->exception_index;
e3e09d87 2071 if (mmu_translate(env, addr, 0, asc, &ret, &flags, true)) {
8ef7f78e
BS
2072 cc = 3;
2073 }
27103424 2074 if (cs->exception_index == EXCP_PGM) {
8ef7f78e
BS
2075 ret = env->int_pgm_code | 0x80000000;
2076 } else {
2077 ret |= addr & ~TARGET_PAGE_MASK;
2078 }
27103424 2079 cs->exception_index = old_exc;
8ef7f78e 2080
d8fe4a9c
RH
2081 env->cc_op = cc;
2082 return ret;
8ef7f78e 2083}
8ef7f78e 2084#endif
a5cfc223 2085
e22dfdb2 2086/* load pair from quadword */
0c9fa168 2087uint64_t HELPER(lpq)(CPUS390XState *env, uint64_t addr)
e22dfdb2
AJ
2088{
2089 uintptr_t ra = GETPC();
2090 uint64_t hi, lo;
2091
0c9fa168
RH
2092 check_alignment(env, addr, 16, ra);
2093 hi = cpu_ldq_data_ra(env, addr + 0, ra);
2094 lo = cpu_ldq_data_ra(env, addr + 8, ra);
2095
2096 env->retxl = lo;
2097 return hi;
2098}
2099
2100uint64_t HELPER(lpq_parallel)(CPUS390XState *env, uint64_t addr)
2101{
2102 uintptr_t ra = GETPC();
2103 uint64_t hi, lo;
830bf10c
RH
2104 int mem_idx;
2105 TCGMemOpIdx oi;
2106 Int128 v;
0c9fa168 2107
830bf10c
RH
2108 assert(HAVE_ATOMIC128);
2109
2110 mem_idx = cpu_mmu_index(env, false);
2111 oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
2112 v = helper_atomic_ldo_be_mmu(env, addr, oi, ra);
2113 hi = int128_gethi(v);
2114 lo = int128_getlo(v);
e22dfdb2
AJ
2115
2116 env->retxl = lo;
2117 return hi;
2118}
2119
0c9fa168
RH
2120/* store pair to quadword */
2121void HELPER(stpq)(CPUS390XState *env, uint64_t addr,
2122 uint64_t low, uint64_t high)
6476615d 2123{
0c9fa168 2124 uintptr_t ra = GETPC();
6476615d 2125
0c9fa168
RH
2126 check_alignment(env, addr, 16, ra);
2127 cpu_stq_data_ra(env, addr + 0, high, ra);
2128 cpu_stq_data_ra(env, addr + 8, low, ra);
6476615d
EC
2129}
2130
0c9fa168
RH
2131void HELPER(stpq_parallel)(CPUS390XState *env, uint64_t addr,
2132 uint64_t low, uint64_t high)
c21b610f
AJ
2133{
2134 uintptr_t ra = GETPC();
830bf10c
RH
2135 int mem_idx;
2136 TCGMemOpIdx oi;
2137 Int128 v;
c21b610f 2138
830bf10c
RH
2139 assert(HAVE_ATOMIC128);
2140
2141 mem_idx = cpu_mmu_index(env, false);
2142 oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
2143 v = int128_make128(low, high);
2144 helper_atomic_sto_be_mmu(env, addr, v, oi, ra);
c21b610f
AJ
2145}
2146
303c681a
RH
2147/* Execute instruction. This instruction executes an insn modified with
2148 the contents of r1. It does not change the executed instruction in memory;
2149 it does not change the program counter.
2150
2151 Perform this by recording the modified instruction in env->ex_value.
2152 This will be noticed by cpu_get_tb_cpu_state and thus tb translation.
a5cfc223 2153*/
83500793 2154void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
a5cfc223 2155{
83500793
RH
2156 uint64_t insn = cpu_lduw_code(env, addr);
2157 uint8_t opc = insn >> 8;
2158
2159 /* Or in the contents of R1[56:63]. */
2160 insn |= r1 & 0xff;
2161
2162 /* Load the rest of the instruction. */
2163 insn <<= 48;
2164 switch (get_ilen(opc)) {
2165 case 2:
2166 break;
2167 case 4:
2168 insn |= (uint64_t)cpu_lduw_code(env, addr + 2) << 32;
2169 break;
2170 case 6:
2171 insn |= (uint64_t)(uint32_t)cpu_ldl_code(env, addr + 2) << 16;
2172 break;
2173 default:
2174 g_assert_not_reached();
2175 }
2176
d376f123
RH
2177 /* The very most common cases can be sped up by avoiding a new TB. */
2178 if ((opc & 0xf0) == 0xd0) {
2179 typedef uint32_t (*dx_helper)(CPUS390XState *, uint32_t, uint64_t,
2180 uint64_t, uintptr_t);
2181 static const dx_helper dx[16] = {
ad8c851d 2182 [0x0] = do_helper_trt_bkwd,
d376f123
RH
2183 [0x2] = do_helper_mvc,
2184 [0x4] = do_helper_nc,
2185 [0x5] = do_helper_clc,
2186 [0x6] = do_helper_oc,
2187 [0x7] = do_helper_xc,
2188 [0xc] = do_helper_tr,
ad8c851d 2189 [0xd] = do_helper_trt_fwd,
d376f123
RH
2190 };
2191 dx_helper helper = dx[opc & 0xf];
2192
2193 if (helper) {
2194 uint32_t l = extract64(insn, 48, 8);
2195 uint32_t b1 = extract64(insn, 44, 4);
2196 uint32_t d1 = extract64(insn, 32, 12);
2197 uint32_t b2 = extract64(insn, 28, 4);
2198 uint32_t d2 = extract64(insn, 16, 12);
a5c3cedd
AJ
2199 uint64_t a1 = wrap_address(env, env->regs[b1] + d1);
2200 uint64_t a2 = wrap_address(env, env->regs[b2] + d2);
d376f123
RH
2201
2202 env->cc_op = helper(env, l, a1, a2, 0);
2203 env->psw.addr += ilen;
2204 return;
2205 }
2206 } else if (opc == 0x0a) {
2207 env->int_svc_code = extract64(insn, 48, 8);
2208 env->int_svc_ilen = ilen;
2209 helper_exception(env, EXCP_SVC);
2210 g_assert_not_reached();
2211 }
2212
303c681a
RH
2213 /* Record the insn we want to execute as well as the ilen to use
2214 during the execution of the target insn. This will also ensure
2215 that ex_value is non-zero, which flags that we are in a state
2216 that requires such execution. */
2217 env->ex_value = insn | ilen;
a5cfc223 2218}
3e7e5e0b
DH
2219
2220uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src,
2221 uint64_t len)
2222{
2223 const uint8_t psw_key = (env->psw.mask & PSW_MASK_KEY) >> PSW_SHIFT_KEY;
2224 const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
2225 const uint64_t r0 = env->regs[0];
2226 const uintptr_t ra = GETPC();
3e7e5e0b
DH
2227 uint8_t dest_key, dest_as, dest_k, dest_a;
2228 uint8_t src_key, src_as, src_k, src_a;
2229 uint64_t val;
2230 int cc = 0;
2231
2232 HELPER_LOG("%s dest %" PRIx64 ", src %" PRIx64 ", len %" PRIx64 "\n",
2233 __func__, dest, src, len);
2234
2235 if (!(env->psw.mask & PSW_MASK_DAT)) {
8d2f850a 2236 s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra);
3e7e5e0b
DH
2237 }
2238
2239 /* OAC (operand access control) for the first operand -> dest */
2240 val = (r0 & 0xffff0000ULL) >> 16;
2241 dest_key = (val >> 12) & 0xf;
2242 dest_as = (val >> 6) & 0x3;
2243 dest_k = (val >> 1) & 0x1;
2244 dest_a = val & 0x1;
2245
2246 /* OAC (operand access control) for the second operand -> src */
2247 val = (r0 & 0x0000ffffULL);
2248 src_key = (val >> 12) & 0xf;
2249 src_as = (val >> 6) & 0x3;
2250 src_k = (val >> 1) & 0x1;
2251 src_a = val & 0x1;
2252
2253 if (!dest_k) {
2254 dest_key = psw_key;
2255 }
2256 if (!src_k) {
2257 src_key = psw_key;
2258 }
2259 if (!dest_a) {
2260 dest_as = psw_as;
2261 }
2262 if (!src_a) {
2263 src_as = psw_as;
2264 }
2265
2266 if (dest_a && dest_as == AS_HOME && (env->psw.mask & PSW_MASK_PSTATE)) {
8d2f850a 2267 s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra);
3e7e5e0b
DH
2268 }
2269 if (!(env->cregs[0] & CR0_SECONDARY) &&
2270 (dest_as == AS_SECONDARY || src_as == AS_SECONDARY)) {
8d2f850a 2271 s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra);
3e7e5e0b
DH
2272 }
2273 if (!psw_key_valid(env, dest_key) || !psw_key_valid(env, src_key)) {
8d2f850a 2274 s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra);
3e7e5e0b
DH
2275 }
2276
2277 len = wrap_length(env, len);
2278 if (len > 4096) {
2279 cc = 3;
2280 len = 4096;
2281 }
2282
2283 /* FIXME: AR-mode and proper problem state mode (using PSW keys) missing */
2284 if (src_as == AS_ACCREG || dest_as == AS_ACCREG ||
2285 (env->psw.mask & PSW_MASK_PSTATE)) {
2286 qemu_log_mask(LOG_UNIMP, "%s: AR-mode and PSTATE support missing\n",
2287 __func__);
8d2f850a 2288 s390_program_interrupt(env, PGM_ADDRESSING, 6, ra);
3e7e5e0b
DH
2289 }
2290
2291 /* FIXME: a) LAP
2292 * b) Access using correct keys
2293 * c) AR-mode
2294 */
2295#ifdef CONFIG_USER_ONLY
2296 /* psw keys are never valid in user mode, we will never reach this */
2297 g_assert_not_reached();
2298#else
2299 fast_memmove_as(env, dest, src, len, dest_as, src_as, ra);
2300#endif
2301
2302 return cc;
2303}
941ef3db
RH
2304
2305/* Decode a Unicode character. A return value < 0 indicates success, storing
2306 the UTF-32 result into OCHAR and the input length into OLEN. A return
2307 value >= 0 indicates failure, and the CC value to be returned. */
2308typedef int (*decode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2309 uint64_t ilen, bool enh_check, uintptr_t ra,
2310 uint32_t *ochar, uint32_t *olen);
2311
2312/* Encode a Unicode character. A return value < 0 indicates success, storing
2313 the bytes into ADDR and the output length into OLEN. A return value >= 0
2314 indicates failure, and the CC value to be returned. */
2315typedef int (*encode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2316 uint64_t ilen, uintptr_t ra, uint32_t c,
2317 uint32_t *olen);
2318
2319static int decode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2320 bool enh_check, uintptr_t ra,
2321 uint32_t *ochar, uint32_t *olen)
2322{
2323 uint8_t s0, s1, s2, s3;
2324 uint32_t c, l;
2325
2326 if (ilen < 1) {
2327 return 0;
2328 }
2329 s0 = cpu_ldub_data_ra(env, addr, ra);
2330 if (s0 <= 0x7f) {
2331 /* one byte character */
2332 l = 1;
2333 c = s0;
2334 } else if (s0 <= (enh_check ? 0xc1 : 0xbf)) {
2335 /* invalid character */
2336 return 2;
2337 } else if (s0 <= 0xdf) {
2338 /* two byte character */
2339 l = 2;
2340 if (ilen < 2) {
2341 return 0;
2342 }
2343 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2344 c = s0 & 0x1f;
2345 c = (c << 6) | (s1 & 0x3f);
2346 if (enh_check && (s1 & 0xc0) != 0x80) {
2347 return 2;
2348 }
2349 } else if (s0 <= 0xef) {
2350 /* three byte character */
2351 l = 3;
2352 if (ilen < 3) {
2353 return 0;
2354 }
2355 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2356 s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2357 c = s0 & 0x0f;
2358 c = (c << 6) | (s1 & 0x3f);
2359 c = (c << 6) | (s2 & 0x3f);
2360 /* Fold the byte-by-byte range descriptions in the PoO into
2361 tests against the complete value. It disallows encodings
2362 that could be smaller, and the UTF-16 surrogates. */
2363 if (enh_check
2364 && ((s1 & 0xc0) != 0x80
2365 || (s2 & 0xc0) != 0x80
2366 || c < 0x1000
2367 || (c >= 0xd800 && c <= 0xdfff))) {
2368 return 2;
2369 }
2370 } else if (s0 <= (enh_check ? 0xf4 : 0xf7)) {
2371 /* four byte character */
2372 l = 4;
2373 if (ilen < 4) {
2374 return 0;
2375 }
2376 s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2377 s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2378 s3 = cpu_ldub_data_ra(env, addr + 3, ra);
2379 c = s0 & 0x07;
2380 c = (c << 6) | (s1 & 0x3f);
2381 c = (c << 6) | (s2 & 0x3f);
2382 c = (c << 6) | (s3 & 0x3f);
2383 /* See above. */
2384 if (enh_check
2385 && ((s1 & 0xc0) != 0x80
2386 || (s2 & 0xc0) != 0x80
2387 || (s3 & 0xc0) != 0x80
2388 || c < 0x010000
2389 || c > 0x10ffff)) {
2390 return 2;
2391 }
2392 } else {
2393 /* invalid character */
2394 return 2;
2395 }
2396
2397 *ochar = c;
2398 *olen = l;
2399 return -1;
2400}
2401
2402static int decode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2403 bool enh_check, uintptr_t ra,
2404 uint32_t *ochar, uint32_t *olen)
2405{
2406 uint16_t s0, s1;
2407 uint32_t c, l;
2408
2409 if (ilen < 2) {
2410 return 0;
2411 }
2412 s0 = cpu_lduw_data_ra(env, addr, ra);
2413 if ((s0 & 0xfc00) != 0xd800) {
2414 /* one word character */
2415 l = 2;
2416 c = s0;
2417 } else {
2418 /* two word character */
2419 l = 4;
2420 if (ilen < 4) {
2421 return 0;
2422 }
2423 s1 = cpu_lduw_data_ra(env, addr + 2, ra);
2424 c = extract32(s0, 6, 4) + 1;
2425 c = (c << 6) | (s0 & 0x3f);
2426 c = (c << 10) | (s1 & 0x3ff);
2427 if (enh_check && (s1 & 0xfc00) != 0xdc00) {
2428 /* invalid surrogate character */
2429 return 2;
2430 }
2431 }
2432
2433 *ochar = c;
2434 *olen = l;
2435 return -1;
2436}
2437
2438static int decode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2439 bool enh_check, uintptr_t ra,
2440 uint32_t *ochar, uint32_t *olen)
2441{
2442 uint32_t c;
2443
2444 if (ilen < 4) {
2445 return 0;
2446 }
2447 c = cpu_ldl_data_ra(env, addr, ra);
2448 if ((c >= 0xd800 && c <= 0xdbff) || c > 0x10ffff) {
2449 /* invalid unicode character */
2450 return 2;
2451 }
2452
2453 *ochar = c;
2454 *olen = 4;
2455 return -1;
2456}
2457
2458static int encode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2459 uintptr_t ra, uint32_t c, uint32_t *olen)
2460{
2461 uint8_t d[4];
2462 uint32_t l, i;
2463
2464 if (c <= 0x7f) {
2465 /* one byte character */
2466 l = 1;
2467 d[0] = c;
2468 } else if (c <= 0x7ff) {
2469 /* two byte character */
2470 l = 2;
2471 d[1] = 0x80 | extract32(c, 0, 6);
2472 d[0] = 0xc0 | extract32(c, 6, 5);
2473 } else if (c <= 0xffff) {
2474 /* three byte character */
2475 l = 3;
2476 d[2] = 0x80 | extract32(c, 0, 6);
2477 d[1] = 0x80 | extract32(c, 6, 6);
2478 d[0] = 0xe0 | extract32(c, 12, 4);
2479 } else {
2480 /* four byte character */
2481 l = 4;
2482 d[3] = 0x80 | extract32(c, 0, 6);
2483 d[2] = 0x80 | extract32(c, 6, 6);
2484 d[1] = 0x80 | extract32(c, 12, 6);
2485 d[0] = 0xf0 | extract32(c, 18, 3);
2486 }
2487
2488 if (ilen < l) {
2489 return 1;
2490 }
2491 for (i = 0; i < l; ++i) {
2492 cpu_stb_data_ra(env, addr + i, d[i], ra);
2493 }
2494
2495 *olen = l;
2496 return -1;
2497}
2498
2499static int encode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2500 uintptr_t ra, uint32_t c, uint32_t *olen)
2501{
2502 uint16_t d0, d1;
2503
2504 if (c <= 0xffff) {
2505 /* one word character */
2506 if (ilen < 2) {
2507 return 1;
2508 }
2509 cpu_stw_data_ra(env, addr, c, ra);
2510 *olen = 2;
2511 } else {
2512 /* two word character */
2513 if (ilen < 4) {
2514 return 1;
2515 }
2516 d1 = 0xdc00 | extract32(c, 0, 10);
2517 d0 = 0xd800 | extract32(c, 10, 6);
2518 d0 = deposit32(d0, 6, 4, extract32(c, 16, 5) - 1);
2519 cpu_stw_data_ra(env, addr + 0, d0, ra);
2520 cpu_stw_data_ra(env, addr + 2, d1, ra);
2521 *olen = 4;
2522 }
2523
2524 return -1;
2525}
2526
2527static int encode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2528 uintptr_t ra, uint32_t c, uint32_t *olen)
2529{
2530 if (ilen < 4) {
2531 return 1;
2532 }
2533 cpu_stl_data_ra(env, addr, c, ra);
2534 *olen = 4;
2535 return -1;
2536}
2537
2538static inline uint32_t convert_unicode(CPUS390XState *env, uint32_t r1,
2539 uint32_t r2, uint32_t m3, uintptr_t ra,
2540 decode_unicode_fn decode,
2541 encode_unicode_fn encode)
2542{
2543 uint64_t dst = get_address(env, r1);
2544 uint64_t dlen = get_length(env, r1 + 1);
2545 uint64_t src = get_address(env, r2);
2546 uint64_t slen = get_length(env, r2 + 1);
2547 bool enh_check = m3 & 1;
2548 int cc, i;
2549
2550 /* Lest we fail to service interrupts in a timely manner, limit the
2551 amount of work we're willing to do. For now, let's cap at 256. */
2552 for (i = 0; i < 256; ++i) {
2553 uint32_t c, ilen, olen;
2554
2555 cc = decode(env, src, slen, enh_check, ra, &c, &ilen);
2556 if (unlikely(cc >= 0)) {
2557 break;
2558 }
2559 cc = encode(env, dst, dlen, ra, c, &olen);
2560 if (unlikely(cc >= 0)) {
2561 break;
2562 }
2563
2564 src += ilen;
2565 slen -= ilen;
2566 dst += olen;
2567 dlen -= olen;
2568 cc = 3;
2569 }
2570
2571 set_address(env, r1, dst);
2572 set_length(env, r1 + 1, dlen);
2573 set_address(env, r2, src);
2574 set_length(env, r2 + 1, slen);
2575
2576 return cc;
2577}
2578
2579uint32_t HELPER(cu12)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2580{
2581 return convert_unicode(env, r1, r2, m3, GETPC(),
2582 decode_utf8, encode_utf16);
2583}
2584
2585uint32_t HELPER(cu14)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2586{
2587 return convert_unicode(env, r1, r2, m3, GETPC(),
2588 decode_utf8, encode_utf32);
2589}
2590
2591uint32_t HELPER(cu21)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2592{
2593 return convert_unicode(env, r1, r2, m3, GETPC(),
2594 decode_utf16, encode_utf8);
2595}
2596
2597uint32_t HELPER(cu24)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2598{
2599 return convert_unicode(env, r1, r2, m3, GETPC(),
2600 decode_utf16, encode_utf32);
2601}
2602
2603uint32_t HELPER(cu41)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2604{
2605 return convert_unicode(env, r1, r2, m3, GETPC(),
2606 decode_utf32, encode_utf8);
2607}
2608
2609uint32_t HELPER(cu42)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2610{
2611 return convert_unicode(env, r1, r2, m3, GETPC(),
2612 decode_utf32, encode_utf16);
2613}
c5a7392c
DH
2614
2615void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
2616 uintptr_t ra)
2617{
c5a7392c
DH
2618 /* test the actual access, not just any access to the page due to LAP */
2619 while (len) {
46750128 2620 const uint64_t pagelen = -(addr | TARGET_PAGE_MASK);
c5a7392c
DH
2621 const uint64_t curlen = MIN(pagelen, len);
2622
2623 probe_write(env, addr, curlen, cpu_mmu_index(env, false), ra);
2624 addr = wrap_address(env, addr + curlen);
2625 len -= curlen;
2626 }
c5a7392c
DH
2627}
2628
2629void HELPER(probe_write_access)(CPUS390XState *env, uint64_t addr, uint64_t len)
2630{
2631 probe_write_access(env, addr, len, GETPC());
2632}