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