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