migration: Fix race of image locking between src and dst
[qemu/ar7.git] / target / s390x / mem_helper.c
blob80caab9c9d0943f0ceb3a66238738b3f7fbc713a
1 /*
2 * S/390 memory access helper routines
4 * Copyright (c) 2009 Ulrich Hecht
5 * Copyright (c) 2009 Alexander Graf
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "exec/address-spaces.h"
24 #include "exec/helper-proto.h"
25 #include "exec/exec-all.h"
26 #include "exec/cpu_ldst.h"
27 #include "qemu/int128.h"
29 #if !defined(CONFIG_USER_ONLY)
30 #include "hw/s390x/storage-keys.h"
31 #endif
33 /*****************************************************************************/
34 /* Softmmu support */
35 #if !defined(CONFIG_USER_ONLY)
37 /* try to fill the TLB and return an exception if error. If retaddr is
38 NULL, it means that the function was called in C code (i.e. not
39 from generated code or from helper.c) */
40 /* XXX: fix it to restore all registers */
41 void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
42 int mmu_idx, uintptr_t retaddr)
44 int ret = s390_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx);
45 if (unlikely(ret != 0)) {
46 cpu_loop_exit_restore(cs, retaddr);
50 #endif
52 /* #define DEBUG_HELPER */
53 #ifdef DEBUG_HELPER
54 #define HELPER_LOG(x...) qemu_log(x)
55 #else
56 #define HELPER_LOG(x...)
57 #endif
59 /* Reduce the length so that addr + len doesn't cross a page boundary. */
60 static inline uint32_t adj_len_to_page(uint32_t len, uint64_t addr)
62 #ifndef CONFIG_USER_ONLY
63 if ((addr & ~TARGET_PAGE_MASK) + len - 1 >= TARGET_PAGE_SIZE) {
64 return -(addr | TARGET_PAGE_MASK);
66 #endif
67 return len;
70 /* Trigger a SPECIFICATION exception if an address or a length is not
71 naturally aligned. */
72 static inline void check_alignment(CPUS390XState *env, uint64_t v,
73 int wordsize, uintptr_t ra)
75 if (v % wordsize) {
76 CPUState *cs = CPU(s390_env_get_cpu(env));
77 cpu_restore_state(cs, ra);
78 program_interrupt(env, PGM_SPECIFICATION, 6);
82 /* Load a value from memory according to its size. */
83 static inline uint64_t cpu_ldusize_data_ra(CPUS390XState *env, uint64_t addr,
84 int wordsize, uintptr_t ra)
86 switch (wordsize) {
87 case 1:
88 return cpu_ldub_data_ra(env, addr, ra);
89 case 2:
90 return cpu_lduw_data_ra(env, addr, ra);
91 default:
92 abort();
96 /* Store a to memory according to its size. */
97 static inline void cpu_stsize_data_ra(CPUS390XState *env, uint64_t addr,
98 uint64_t value, int wordsize,
99 uintptr_t ra)
101 switch (wordsize) {
102 case 1:
103 cpu_stb_data_ra(env, addr, value, ra);
104 break;
105 case 2:
106 cpu_stw_data_ra(env, addr, value, ra);
107 break;
108 default:
109 abort();
113 static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte,
114 uint32_t l, uintptr_t ra)
116 int mmu_idx = cpu_mmu_index(env, false);
118 while (l > 0) {
119 void *p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
120 if (p) {
121 /* Access to the whole page in write mode granted. */
122 uint32_t l_adj = adj_len_to_page(l, dest);
123 memset(p, byte, l_adj);
124 dest += l_adj;
125 l -= l_adj;
126 } else {
127 /* We failed to get access to the whole page. The next write
128 access will likely fill the QEMU TLB for the next iteration. */
129 cpu_stb_data_ra(env, dest, byte, ra);
130 dest++;
131 l--;
136 static void fast_memmove(CPUS390XState *env, uint64_t dest, uint64_t src,
137 uint32_t l, uintptr_t ra)
139 int mmu_idx = cpu_mmu_index(env, false);
141 while (l > 0) {
142 void *src_p = tlb_vaddr_to_host(env, src, MMU_DATA_LOAD, mmu_idx);
143 void *dest_p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
144 if (src_p && dest_p) {
145 /* Access to both whole pages granted. */
146 uint32_t l_adj = adj_len_to_page(l, src);
147 l_adj = adj_len_to_page(l_adj, dest);
148 memmove(dest_p, src_p, l_adj);
149 src += l_adj;
150 dest += l_adj;
151 l -= l_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 cpu_stb_data_ra(env, dest, cpu_ldub_data_ra(env, src, ra), ra);
157 src++;
158 dest++;
159 l--;
164 /* and on array */
165 static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest,
166 uint64_t src, uintptr_t ra)
168 uint32_t i;
169 uint8_t c = 0;
171 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
172 __func__, l, dest, src);
174 for (i = 0; i <= l; i++) {
175 uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
176 x &= cpu_ldub_data_ra(env, dest + i, ra);
177 c |= x;
178 cpu_stb_data_ra(env, dest + i, x, ra);
180 return c != 0;
183 uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
184 uint64_t src)
186 return do_helper_nc(env, l, dest, src, GETPC());
189 /* xor on array */
190 static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest,
191 uint64_t src, uintptr_t ra)
193 uint32_t i;
194 uint8_t c = 0;
196 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
197 __func__, l, dest, src);
199 /* xor with itself is the same as memset(0) */
200 if (src == dest) {
201 fast_memset(env, dest, 0, l + 1, ra);
202 return 0;
205 for (i = 0; i <= l; i++) {
206 uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
207 x ^= cpu_ldub_data_ra(env, dest + i, ra);
208 c |= x;
209 cpu_stb_data_ra(env, dest + i, x, ra);
211 return c != 0;
214 uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
215 uint64_t src)
217 return do_helper_xc(env, l, dest, src, GETPC());
220 /* or on array */
221 static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest,
222 uint64_t src, uintptr_t ra)
224 uint32_t i;
225 uint8_t c = 0;
227 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
228 __func__, l, dest, src);
230 for (i = 0; i <= l; i++) {
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);
236 return c != 0;
239 uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
240 uint64_t src)
242 return do_helper_oc(env, l, dest, src, GETPC());
245 /* memmove */
246 static uint32_t do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest,
247 uint64_t src, uintptr_t ra)
249 uint32_t i;
251 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
252 __func__, l, dest, src);
254 /* mvc and memmove do not behave the same when areas overlap! */
255 /* mvc with source pointing to the byte after the destination is the
256 same as memset with the first source byte */
257 if (dest == src + 1) {
258 fast_memset(env, dest, cpu_ldub_data_ra(env, src, ra), l + 1, ra);
259 } else if (dest < src || src + l < dest) {
260 fast_memmove(env, dest, src, l + 1, ra);
261 } else {
262 /* slow version with byte accesses which always work */
263 for (i = 0; i <= l; i++) {
264 uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
265 cpu_stb_data_ra(env, dest + i, x, ra);
269 return env->cc_op;
272 void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
274 do_helper_mvc(env, l, dest, src, GETPC());
277 /* move inverse */
278 void HELPER(mvcin)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
280 uintptr_t ra = GETPC();
281 int i;
283 for (i = 0; i <= l; i++) {
284 uint8_t v = cpu_ldub_data_ra(env, src - i, ra);
285 cpu_stb_data_ra(env, dest + i, v, ra);
289 /* move numerics */
290 void HELPER(mvn)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
292 uintptr_t ra = GETPC();
293 int i;
295 for (i = 0; i <= l; i++) {
296 uint8_t v = cpu_ldub_data_ra(env, dest + i, ra) & 0xf0;
297 v |= cpu_ldub_data_ra(env, src + i, ra) & 0x0f;
298 cpu_stb_data_ra(env, dest + i, v, ra);
302 /* move with offset */
303 void HELPER(mvo)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
305 uintptr_t ra = GETPC();
306 int len_dest = l >> 4;
307 int len_src = l & 0xf;
308 uint8_t byte_dest, byte_src;
309 int i;
311 src += len_src;
312 dest += len_dest;
314 /* Handle rightmost byte */
315 byte_src = cpu_ldub_data_ra(env, src, ra);
316 byte_dest = cpu_ldub_data_ra(env, dest, ra);
317 byte_dest = (byte_dest & 0x0f) | (byte_src << 4);
318 cpu_stb_data_ra(env, dest, byte_dest, ra);
320 /* Process remaining bytes from right to left */
321 for (i = 1; i <= len_dest; i++) {
322 byte_dest = byte_src >> 4;
323 if (len_src - i >= 0) {
324 byte_src = cpu_ldub_data_ra(env, src - i, ra);
325 } else {
326 byte_src = 0;
328 byte_dest |= byte_src << 4;
329 cpu_stb_data_ra(env, dest - i, byte_dest, ra);
333 /* move zones */
334 void HELPER(mvz)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
336 uintptr_t ra = GETPC();
337 int i;
339 for (i = 0; i <= l; i++) {
340 uint8_t b = cpu_ldub_data_ra(env, dest + i, ra) & 0x0f;
341 b |= cpu_ldub_data_ra(env, src + i, ra) & 0xf0;
342 cpu_stb_data_ra(env, dest + i, b, ra);
346 /* compare unsigned byte arrays */
347 static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1,
348 uint64_t s2, uintptr_t ra)
350 uint32_t i;
351 uint32_t cc = 0;
353 HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
354 __func__, l, s1, s2);
356 for (i = 0; i <= l; i++) {
357 uint8_t x = cpu_ldub_data_ra(env, s1 + i, ra);
358 uint8_t y = cpu_ldub_data_ra(env, s2 + i, ra);
359 HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
360 if (x < y) {
361 cc = 1;
362 break;
363 } else if (x > y) {
364 cc = 2;
365 break;
369 HELPER_LOG("\n");
370 return cc;
373 uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2)
375 return do_helper_clc(env, l, s1, s2, GETPC());
378 /* compare logical under mask */
379 uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
380 uint64_t addr)
382 uintptr_t ra = GETPC();
383 uint32_t cc = 0;
385 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
386 mask, addr);
388 while (mask) {
389 if (mask & 8) {
390 uint8_t d = cpu_ldub_data_ra(env, addr, ra);
391 uint8_t r = extract32(r1, 24, 8);
392 HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
393 addr);
394 if (r < d) {
395 cc = 1;
396 break;
397 } else if (r > d) {
398 cc = 2;
399 break;
401 addr++;
403 mask = (mask << 1) & 0xf;
404 r1 <<= 8;
407 HELPER_LOG("\n");
408 return cc;
411 static inline uint64_t wrap_address(CPUS390XState *env, uint64_t a)
413 if (!(env->psw.mask & PSW_MASK_64)) {
414 if (!(env->psw.mask & PSW_MASK_32)) {
415 /* 24-Bit mode */
416 a &= 0x00ffffff;
417 } else {
418 /* 31-Bit mode */
419 a &= 0x7fffffff;
422 return a;
425 static inline uint64_t get_address(CPUS390XState *env, int reg)
427 return wrap_address(env, env->regs[reg]);
430 static inline void set_address(CPUS390XState *env, int reg, uint64_t address)
432 if (env->psw.mask & PSW_MASK_64) {
433 /* 64-Bit mode */
434 env->regs[reg] = address;
435 } else {
436 if (!(env->psw.mask & PSW_MASK_32)) {
437 /* 24-Bit mode. According to the PoO it is implementation
438 dependent if bits 32-39 remain unchanged or are set to
439 zeros. Choose the former so that the function can also be
440 used for TRT. */
441 env->regs[reg] = deposit64(env->regs[reg], 0, 24, address);
442 } else {
443 /* 31-Bit mode. According to the PoO it is implementation
444 dependent if bit 32 remains unchanged or is set to zero.
445 Choose the latter so that the function can also be used for
446 TRT. */
447 address &= 0x7fffffff;
448 env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
453 static inline uint64_t wrap_length(CPUS390XState *env, uint64_t length)
455 if (!(env->psw.mask & PSW_MASK_64)) {
456 /* 24-Bit and 31-Bit mode */
457 length &= 0x7fffffff;
459 return length;
462 static inline uint64_t get_length(CPUS390XState *env, int reg)
464 return wrap_length(env, env->regs[reg]);
467 static inline void set_length(CPUS390XState *env, int reg, uint64_t length)
469 if (env->psw.mask & PSW_MASK_64) {
470 /* 64-Bit mode */
471 env->regs[reg] = length;
472 } else {
473 /* 24-Bit and 31-Bit mode */
474 env->regs[reg] = deposit64(env->regs[reg], 0, 32, length);
478 /* search string (c is byte to search, r2 is string, r1 end of string) */
479 uint64_t HELPER(srst)(CPUS390XState *env, uint64_t r0, uint64_t end,
480 uint64_t str)
482 uintptr_t ra = GETPC();
483 uint32_t len;
484 uint8_t v, c = r0;
486 str = wrap_address(env, str);
487 end = wrap_address(env, end);
489 /* Assume for now that R2 is unmodified. */
490 env->retxl = str;
492 /* Lest we fail to service interrupts in a timely manner, limit the
493 amount of work we're willing to do. For now, let's cap at 8k. */
494 for (len = 0; len < 0x2000; ++len) {
495 if (str + len == end) {
496 /* Character not found. R1 & R2 are unmodified. */
497 env->cc_op = 2;
498 return end;
500 v = cpu_ldub_data_ra(env, str + len, ra);
501 if (v == c) {
502 /* Character found. Set R1 to the location; R2 is unmodified. */
503 env->cc_op = 1;
504 return str + len;
508 /* CPU-determined bytes processed. Advance R2 to next byte to process. */
509 env->retxl = str + len;
510 env->cc_op = 3;
511 return end;
514 /* unsigned string compare (c is string terminator) */
515 uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
517 uintptr_t ra = GETPC();
518 uint32_t len;
520 c = c & 0xff;
521 s1 = wrap_address(env, s1);
522 s2 = wrap_address(env, s2);
524 /* Lest we fail to service interrupts in a timely manner, limit the
525 amount of work we're willing to do. For now, let's cap at 8k. */
526 for (len = 0; len < 0x2000; ++len) {
527 uint8_t v1 = cpu_ldub_data_ra(env, s1 + len, ra);
528 uint8_t v2 = cpu_ldub_data_ra(env, s2 + len, ra);
529 if (v1 == v2) {
530 if (v1 == c) {
531 /* Equal. CC=0, and don't advance the registers. */
532 env->cc_op = 0;
533 env->retxl = s2;
534 return s1;
536 } else {
537 /* Unequal. CC={1,2}, and advance the registers. Note that
538 the terminator need not be zero, but the string that contains
539 the terminator is by definition "low". */
540 env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2);
541 env->retxl = s2 + len;
542 return s1 + len;
546 /* CPU-determined bytes equal; advance the registers. */
547 env->cc_op = 3;
548 env->retxl = s2 + len;
549 return s1 + len;
552 /* move page */
553 uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
555 /* ??? missing r0 handling, which includes access keys, but more
556 importantly optional suppression of the exception! */
557 fast_memmove(env, r1, r2, TARGET_PAGE_SIZE, GETPC());
558 return 0; /* data moved */
561 /* string copy (c is string terminator) */
562 uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s)
564 uintptr_t ra = GETPC();
565 uint32_t len;
567 c = c & 0xff;
568 d = wrap_address(env, d);
569 s = wrap_address(env, s);
571 /* Lest we fail to service interrupts in a timely manner, limit the
572 amount of work we're willing to do. For now, let's cap at 8k. */
573 for (len = 0; len < 0x2000; ++len) {
574 uint8_t v = cpu_ldub_data_ra(env, s + len, ra);
575 cpu_stb_data_ra(env, d + len, v, ra);
576 if (v == c) {
577 /* Complete. Set CC=1 and advance R1. */
578 env->cc_op = 1;
579 env->retxl = s;
580 return d + len;
584 /* Incomplete. Set CC=3 and signal to advance R1 and R2. */
585 env->cc_op = 3;
586 env->retxl = s + len;
587 return d + len;
590 /* load access registers r1 to r3 from memory at a2 */
591 void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
593 uintptr_t ra = GETPC();
594 int i;
596 for (i = r1;; i = (i + 1) % 16) {
597 env->aregs[i] = cpu_ldl_data_ra(env, a2, ra);
598 a2 += 4;
600 if (i == r3) {
601 break;
606 /* store access registers r1 to r3 in memory at a2 */
607 void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
609 uintptr_t ra = GETPC();
610 int i;
612 for (i = r1;; i = (i + 1) % 16) {
613 cpu_stl_data_ra(env, a2, env->aregs[i], ra);
614 a2 += 4;
616 if (i == r3) {
617 break;
622 /* move long helper */
623 static inline uint32_t do_mvcl(CPUS390XState *env,
624 uint64_t *dest, uint64_t *destlen,
625 uint64_t *src, uint64_t *srclen,
626 uint16_t pad, int wordsize, uintptr_t ra)
628 uint64_t len = MIN(*srclen, *destlen);
629 uint32_t cc;
631 if (*destlen == *srclen) {
632 cc = 0;
633 } else if (*destlen < *srclen) {
634 cc = 1;
635 } else {
636 cc = 2;
639 /* Copy the src array */
640 fast_memmove(env, *dest, *src, len, ra);
641 *src += len;
642 *srclen -= len;
643 *dest += len;
644 *destlen -= len;
646 /* Pad the remaining area */
647 if (wordsize == 1) {
648 fast_memset(env, *dest, pad, *destlen, ra);
649 *dest += *destlen;
650 *destlen = 0;
651 } else {
652 /* If remaining length is odd, pad with odd byte first. */
653 if (*destlen & 1) {
654 cpu_stb_data_ra(env, *dest, pad & 0xff, ra);
655 *dest += 1;
656 *destlen -= 1;
658 /* The remaining length is even, pad using words. */
659 for (; *destlen; *dest += 2, *destlen -= 2) {
660 cpu_stw_data_ra(env, *dest, pad, ra);
664 return cc;
667 /* move long */
668 uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
670 uintptr_t ra = GETPC();
671 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
672 uint64_t dest = get_address(env, r1);
673 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
674 uint64_t src = get_address(env, r2);
675 uint8_t pad = env->regs[r2 + 1] >> 24;
676 uint32_t cc;
678 cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra);
680 env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, destlen);
681 env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, srclen);
682 set_address(env, r1, dest);
683 set_address(env, r2, src);
685 return cc;
688 /* move long extended */
689 uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
690 uint32_t r3)
692 uintptr_t ra = GETPC();
693 uint64_t destlen = get_length(env, r1 + 1);
694 uint64_t dest = get_address(env, r1);
695 uint64_t srclen = get_length(env, r3 + 1);
696 uint64_t src = get_address(env, r3);
697 uint8_t pad = a2;
698 uint32_t cc;
700 cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra);
702 set_length(env, r1 + 1, destlen);
703 set_length(env, r3 + 1, srclen);
704 set_address(env, r1, dest);
705 set_address(env, r3, src);
707 return cc;
710 /* move long unicode */
711 uint32_t HELPER(mvclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
712 uint32_t r3)
714 uintptr_t ra = GETPC();
715 uint64_t destlen = get_length(env, r1 + 1);
716 uint64_t dest = get_address(env, r1);
717 uint64_t srclen = get_length(env, r3 + 1);
718 uint64_t src = get_address(env, r3);
719 uint16_t pad = a2;
720 uint32_t cc;
722 cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 2, ra);
724 set_length(env, r1 + 1, destlen);
725 set_length(env, r3 + 1, srclen);
726 set_address(env, r1, dest);
727 set_address(env, r3, src);
729 return cc;
732 /* compare logical long helper */
733 static inline uint32_t do_clcl(CPUS390XState *env,
734 uint64_t *src1, uint64_t *src1len,
735 uint64_t *src3, uint64_t *src3len,
736 uint16_t pad, uint64_t limit,
737 int wordsize, uintptr_t ra)
739 uint64_t len = MAX(*src1len, *src3len);
740 uint32_t cc = 0;
742 check_alignment(env, *src1len | *src3len, wordsize, ra);
744 if (!len) {
745 return cc;
748 /* Lest we fail to service interrupts in a timely manner, limit the
749 amount of work we're willing to do. */
750 if (len > limit) {
751 len = limit;
752 cc = 3;
755 for (; len; len -= wordsize) {
756 uint16_t v1 = pad;
757 uint16_t v3 = pad;
759 if (*src1len) {
760 v1 = cpu_ldusize_data_ra(env, *src1, wordsize, ra);
762 if (*src3len) {
763 v3 = cpu_ldusize_data_ra(env, *src3, wordsize, ra);
766 if (v1 != v3) {
767 cc = (v1 < v3) ? 1 : 2;
768 break;
771 if (*src1len) {
772 *src1 += wordsize;
773 *src1len -= wordsize;
775 if (*src3len) {
776 *src3 += wordsize;
777 *src3len -= wordsize;
781 return cc;
785 /* compare logical long */
786 uint32_t HELPER(clcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
788 uintptr_t ra = GETPC();
789 uint64_t src1len = extract64(env->regs[r1 + 1], 0, 24);
790 uint64_t src1 = get_address(env, r1);
791 uint64_t src3len = extract64(env->regs[r2 + 1], 0, 24);
792 uint64_t src3 = get_address(env, r2);
793 uint8_t pad = env->regs[r2 + 1] >> 24;
794 uint32_t cc;
796 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, -1, 1, ra);
798 env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, src1len);
799 env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, src3len);
800 set_address(env, r1, src1);
801 set_address(env, r2, src3);
803 return cc;
806 /* compare logical long extended memcompare insn with padding */
807 uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
808 uint32_t r3)
810 uintptr_t ra = GETPC();
811 uint64_t src1len = get_length(env, r1 + 1);
812 uint64_t src1 = get_address(env, r1);
813 uint64_t src3len = get_length(env, r3 + 1);
814 uint64_t src3 = get_address(env, r3);
815 uint8_t pad = a2;
816 uint32_t cc;
818 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x2000, 1, ra);
820 set_length(env, r1 + 1, src1len);
821 set_length(env, r3 + 1, src3len);
822 set_address(env, r1, src1);
823 set_address(env, r3, src3);
825 return cc;
828 /* compare logical long unicode memcompare insn with padding */
829 uint32_t HELPER(clclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
830 uint32_t r3)
832 uintptr_t ra = GETPC();
833 uint64_t src1len = get_length(env, r1 + 1);
834 uint64_t src1 = get_address(env, r1);
835 uint64_t src3len = get_length(env, r3 + 1);
836 uint64_t src3 = get_address(env, r3);
837 uint16_t pad = a2;
838 uint32_t cc = 0;
840 cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x1000, 2, ra);
842 set_length(env, r1 + 1, src1len);
843 set_length(env, r3 + 1, src3len);
844 set_address(env, r1, src1);
845 set_address(env, r3, src3);
847 return cc;
850 /* checksum */
851 uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
852 uint64_t src, uint64_t src_len)
854 uintptr_t ra = GETPC();
855 uint64_t max_len, len;
856 uint64_t cksm = (uint32_t)r1;
858 /* Lest we fail to service interrupts in a timely manner, limit the
859 amount of work we're willing to do. For now, let's cap at 8k. */
860 max_len = (src_len > 0x2000 ? 0x2000 : src_len);
862 /* Process full words as available. */
863 for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
864 cksm += (uint32_t)cpu_ldl_data_ra(env, src, ra);
867 switch (max_len - len) {
868 case 1:
869 cksm += cpu_ldub_data_ra(env, src, ra) << 24;
870 len += 1;
871 break;
872 case 2:
873 cksm += cpu_lduw_data_ra(env, src, ra) << 16;
874 len += 2;
875 break;
876 case 3:
877 cksm += cpu_lduw_data_ra(env, src, ra) << 16;
878 cksm += cpu_ldub_data_ra(env, src + 2, ra) << 8;
879 len += 3;
880 break;
883 /* Fold the carry from the checksum. Note that we can see carry-out
884 during folding more than once (but probably not more than twice). */
885 while (cksm > 0xffffffffull) {
886 cksm = (uint32_t)cksm + (cksm >> 32);
889 /* Indicate whether or not we've processed everything. */
890 env->cc_op = (len == src_len ? 0 : 3);
892 /* Return both cksm and processed length. */
893 env->retxl = cksm;
894 return len;
897 void HELPER(pack)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src)
899 uintptr_t ra = GETPC();
900 int len_dest = len >> 4;
901 int len_src = len & 0xf;
902 uint8_t b;
904 dest += len_dest;
905 src += len_src;
907 /* last byte is special, it only flips the nibbles */
908 b = cpu_ldub_data_ra(env, src, ra);
909 cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
910 src--;
911 len_src--;
913 /* now pack every value */
914 while (len_dest >= 0) {
915 b = 0;
917 if (len_src > 0) {
918 b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
919 src--;
920 len_src--;
922 if (len_src > 0) {
923 b |= cpu_ldub_data_ra(env, src, ra) << 4;
924 src--;
925 len_src--;
928 len_dest--;
929 dest--;
930 cpu_stb_data_ra(env, dest, b, ra);
934 static inline void do_pkau(CPUS390XState *env, uint64_t dest, uint64_t src,
935 uint32_t srclen, int ssize, uintptr_t ra)
937 int i;
938 /* The destination operand is always 16 bytes long. */
939 const int destlen = 16;
941 /* The operands are processed from right to left. */
942 src += srclen - 1;
943 dest += destlen - 1;
945 for (i = 0; i < destlen; i++) {
946 uint8_t b = 0;
948 /* Start with a positive sign */
949 if (i == 0) {
950 b = 0xc;
951 } else if (srclen > ssize) {
952 b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
953 src -= ssize;
954 srclen -= ssize;
957 if (srclen > ssize) {
958 b |= cpu_ldub_data_ra(env, src, ra) << 4;
959 src -= ssize;
960 srclen -= ssize;
963 cpu_stb_data_ra(env, dest, b, ra);
964 dest--;
969 void HELPER(pka)(CPUS390XState *env, uint64_t dest, uint64_t src,
970 uint32_t srclen)
972 do_pkau(env, dest, src, srclen, 1, GETPC());
975 void HELPER(pku)(CPUS390XState *env, uint64_t dest, uint64_t src,
976 uint32_t srclen)
978 do_pkau(env, dest, src, srclen, 2, GETPC());
981 void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
982 uint64_t src)
984 uintptr_t ra = GETPC();
985 int len_dest = len >> 4;
986 int len_src = len & 0xf;
987 uint8_t b;
988 int second_nibble = 0;
990 dest += len_dest;
991 src += len_src;
993 /* last byte is special, it only flips the nibbles */
994 b = cpu_ldub_data_ra(env, src, ra);
995 cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
996 src--;
997 len_src--;
999 /* now pad every nibble with 0xf0 */
1001 while (len_dest > 0) {
1002 uint8_t cur_byte = 0;
1004 if (len_src > 0) {
1005 cur_byte = cpu_ldub_data_ra(env, src, ra);
1008 len_dest--;
1009 dest--;
1011 /* only advance one nibble at a time */
1012 if (second_nibble) {
1013 cur_byte >>= 4;
1014 len_src--;
1015 src--;
1017 second_nibble = !second_nibble;
1019 /* digit */
1020 cur_byte = (cur_byte & 0xf);
1021 /* zone bits */
1022 cur_byte |= 0xf0;
1024 cpu_stb_data_ra(env, dest, cur_byte, ra);
1028 static inline uint32_t do_unpkau(CPUS390XState *env, uint64_t dest,
1029 uint32_t destlen, int dsize, uint64_t src,
1030 uintptr_t ra)
1032 int i;
1033 uint32_t cc;
1034 uint8_t b;
1035 /* The source operand is always 16 bytes long. */
1036 const int srclen = 16;
1038 /* The operands are processed from right to left. */
1039 src += srclen - 1;
1040 dest += destlen - dsize;
1042 /* Check for the sign. */
1043 b = cpu_ldub_data_ra(env, src, ra);
1044 src--;
1045 switch (b & 0xf) {
1046 case 0xa:
1047 case 0xc:
1048 case 0xe ... 0xf:
1049 cc = 0; /* plus */
1050 break;
1051 case 0xb:
1052 case 0xd:
1053 cc = 1; /* minus */
1054 break;
1055 default:
1056 case 0x0 ... 0x9:
1057 cc = 3; /* invalid */
1058 break;
1061 /* Now pad every nibble with 0x30, advancing one nibble at a time. */
1062 for (i = 0; i < destlen; i += dsize) {
1063 if (i == (31 * dsize)) {
1064 /* If length is 32/64 bytes, the leftmost byte is 0. */
1065 b = 0;
1066 } else if (i % (2 * dsize)) {
1067 b = cpu_ldub_data_ra(env, src, ra);
1068 src--;
1069 } else {
1070 b >>= 4;
1072 cpu_stsize_data_ra(env, dest, 0x30 + (b & 0xf), dsize, ra);
1073 dest -= dsize;
1076 return cc;
1079 uint32_t HELPER(unpka)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1080 uint64_t src)
1082 return do_unpkau(env, dest, destlen, 1, src, GETPC());
1085 uint32_t HELPER(unpku)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1086 uint64_t src)
1088 return do_unpkau(env, dest, destlen, 2, src, GETPC());
1091 uint32_t HELPER(tp)(CPUS390XState *env, uint64_t dest, uint32_t destlen)
1093 uintptr_t ra = GETPC();
1094 uint32_t cc = 0;
1095 int i;
1097 for (i = 0; i < destlen; i++) {
1098 uint8_t b = cpu_ldub_data_ra(env, dest + i, ra);
1099 /* digit */
1100 cc |= (b & 0xf0) > 0x90 ? 2 : 0;
1102 if (i == (destlen - 1)) {
1103 /* sign */
1104 cc |= (b & 0xf) < 0xa ? 1 : 0;
1105 } else {
1106 /* digit */
1107 cc |= (b & 0xf) > 0x9 ? 2 : 0;
1111 return cc;
1114 static uint32_t do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array,
1115 uint64_t trans, uintptr_t ra)
1117 uint32_t i;
1119 for (i = 0; i <= len; i++) {
1120 uint8_t byte = cpu_ldub_data_ra(env, array + i, ra);
1121 uint8_t new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
1122 cpu_stb_data_ra(env, array + i, new_byte, ra);
1125 return env->cc_op;
1128 void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
1129 uint64_t trans)
1131 do_helper_tr(env, len, array, trans, GETPC());
1134 uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array,
1135 uint64_t len, uint64_t trans)
1137 uintptr_t ra = GETPC();
1138 uint8_t end = env->regs[0] & 0xff;
1139 uint64_t l = len;
1140 uint64_t i;
1141 uint32_t cc = 0;
1143 if (!(env->psw.mask & PSW_MASK_64)) {
1144 array &= 0x7fffffff;
1145 l = (uint32_t)l;
1148 /* Lest we fail to service interrupts in a timely manner, limit the
1149 amount of work we're willing to do. For now, let's cap at 8k. */
1150 if (l > 0x2000) {
1151 l = 0x2000;
1152 cc = 3;
1155 for (i = 0; i < l; i++) {
1156 uint8_t byte, new_byte;
1158 byte = cpu_ldub_data_ra(env, array + i, ra);
1160 if (byte == end) {
1161 cc = 1;
1162 break;
1165 new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
1166 cpu_stb_data_ra(env, array + i, new_byte, ra);
1169 env->cc_op = cc;
1170 env->retxl = len - i;
1171 return array + i;
1174 static uint32_t do_helper_trt(CPUS390XState *env, uint32_t len, uint64_t array,
1175 uint64_t trans, uintptr_t ra)
1177 uint32_t i;
1179 for (i = 0; i <= len; i++) {
1180 uint8_t byte = cpu_ldub_data_ra(env, array + i, ra);
1181 uint8_t sbyte = cpu_ldub_data_ra(env, trans + byte, ra);
1183 if (sbyte != 0) {
1184 set_address(env, 1, array + i);
1185 env->regs[2] = deposit64(env->regs[2], 0, 8, sbyte);
1186 return (i == len) ? 2 : 1;
1190 return 0;
1193 uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
1194 uint64_t trans)
1196 return do_helper_trt(env, len, array, trans, GETPC());
1199 /* Translate one/two to one/two */
1200 uint32_t HELPER(trXX)(CPUS390XState *env, uint32_t r1, uint32_t r2,
1201 uint32_t tst, uint32_t sizes)
1203 uintptr_t ra = GETPC();
1204 int dsize = (sizes & 1) ? 1 : 2;
1205 int ssize = (sizes & 2) ? 1 : 2;
1206 uint64_t tbl = get_address(env, 1) & ~7;
1207 uint64_t dst = get_address(env, r1);
1208 uint64_t len = get_length(env, r1 + 1);
1209 uint64_t src = get_address(env, r2);
1210 uint32_t cc = 3;
1211 int i;
1213 check_alignment(env, len, ssize, ra);
1215 /* Lest we fail to service interrupts in a timely manner, */
1216 /* limit the amount of work we're willing to do. */
1217 for (i = 0; i < 0x2000; i++) {
1218 uint16_t sval = cpu_ldusize_data_ra(env, src, ssize, ra);
1219 uint64_t tble = tbl + (sval * dsize);
1220 uint16_t dval = cpu_ldusize_data_ra(env, tble, dsize, ra);
1221 if (dval == tst) {
1222 cc = 1;
1223 break;
1225 cpu_stsize_data_ra(env, dst, dval, dsize, ra);
1227 len -= ssize;
1228 src += ssize;
1229 dst += dsize;
1231 if (len == 0) {
1232 cc = 0;
1233 break;
1237 set_address(env, r1, dst);
1238 set_length(env, r1 + 1, len);
1239 set_address(env, r2, src);
1241 return cc;
1244 void HELPER(cdsg)(CPUS390XState *env, uint64_t addr,
1245 uint32_t r1, uint32_t r3)
1247 uintptr_t ra = GETPC();
1248 Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
1249 Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1250 Int128 oldv;
1251 bool fail;
1253 if (parallel_cpus) {
1254 #ifndef CONFIG_ATOMIC128
1255 cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
1256 #else
1257 int mem_idx = cpu_mmu_index(env, false);
1258 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1259 oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
1260 fail = !int128_eq(oldv, cmpv);
1261 #endif
1262 } else {
1263 uint64_t oldh, oldl;
1265 check_alignment(env, addr, 16, ra);
1267 oldh = cpu_ldq_data_ra(env, addr + 0, ra);
1268 oldl = cpu_ldq_data_ra(env, addr + 8, ra);
1270 oldv = int128_make128(oldl, oldh);
1271 fail = !int128_eq(oldv, cmpv);
1272 if (fail) {
1273 newv = oldv;
1276 cpu_stq_data_ra(env, addr + 0, int128_gethi(newv), ra);
1277 cpu_stq_data_ra(env, addr + 8, int128_getlo(newv), ra);
1280 env->cc_op = fail;
1281 env->regs[r1] = int128_gethi(oldv);
1282 env->regs[r1 + 1] = int128_getlo(oldv);
1285 #if !defined(CONFIG_USER_ONLY)
1286 void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1288 uintptr_t ra = GETPC();
1289 S390CPU *cpu = s390_env_get_cpu(env);
1290 bool PERchanged = false;
1291 uint64_t src = a2;
1292 uint32_t i;
1294 for (i = r1;; i = (i + 1) % 16) {
1295 uint64_t val = cpu_ldq_data_ra(env, src, ra);
1296 if (env->cregs[i] != val && i >= 9 && i <= 11) {
1297 PERchanged = true;
1299 env->cregs[i] = val;
1300 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
1301 i, src, val);
1302 src += sizeof(uint64_t);
1304 if (i == r3) {
1305 break;
1309 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
1310 s390_cpu_recompute_watchpoints(CPU(cpu));
1313 tlb_flush(CPU(cpu));
1316 void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1318 uintptr_t ra = GETPC();
1319 S390CPU *cpu = s390_env_get_cpu(env);
1320 bool PERchanged = false;
1321 uint64_t src = a2;
1322 uint32_t i;
1324 for (i = r1;; i = (i + 1) % 16) {
1325 uint32_t val = cpu_ldl_data_ra(env, src, ra);
1326 if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
1327 PERchanged = true;
1329 env->cregs[i] = deposit64(env->cregs[i], 0, 32, val);
1330 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val);
1331 src += sizeof(uint32_t);
1333 if (i == r3) {
1334 break;
1338 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
1339 s390_cpu_recompute_watchpoints(CPU(cpu));
1342 tlb_flush(CPU(cpu));
1345 void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1347 uintptr_t ra = GETPC();
1348 uint64_t dest = a2;
1349 uint32_t i;
1351 for (i = r1;; i = (i + 1) % 16) {
1352 cpu_stq_data_ra(env, dest, env->cregs[i], ra);
1353 dest += sizeof(uint64_t);
1355 if (i == r3) {
1356 break;
1361 void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1363 uintptr_t ra = GETPC();
1364 uint64_t dest = a2;
1365 uint32_t i;
1367 for (i = r1;; i = (i + 1) % 16) {
1368 cpu_stl_data_ra(env, dest, env->cregs[i], ra);
1369 dest += sizeof(uint32_t);
1371 if (i == r3) {
1372 break;
1377 uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
1379 uintptr_t ra = GETPC();
1380 CPUState *cs = CPU(s390_env_get_cpu(env));
1381 uint64_t abs_addr;
1382 int i;
1384 real_addr = wrap_address(env, real_addr);
1385 abs_addr = mmu_real2abs(env, real_addr) & TARGET_PAGE_MASK;
1386 if (!address_space_access_valid(&address_space_memory, abs_addr,
1387 TARGET_PAGE_SIZE, true)) {
1388 cpu_restore_state(cs, ra);
1389 program_interrupt(env, PGM_ADDRESSING, 4);
1390 return 1;
1393 /* Check low-address protection */
1394 if ((env->cregs[0] & CR0_LOWPROT) && real_addr < 0x2000) {
1395 cpu_restore_state(cs, ra);
1396 program_interrupt(env, PGM_PROTECTION, 4);
1397 return 1;
1400 for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
1401 stq_phys(cs->as, abs_addr + i, 0);
1404 return 0;
1407 uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
1409 /* XXX implement */
1410 return 0;
1413 /* insert storage key extended */
1414 uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
1416 static S390SKeysState *ss;
1417 static S390SKeysClass *skeyclass;
1418 uint64_t addr = wrap_address(env, r2);
1419 uint8_t key;
1421 if (addr > ram_size) {
1422 return 0;
1425 if (unlikely(!ss)) {
1426 ss = s390_get_skeys_device();
1427 skeyclass = S390_SKEYS_GET_CLASS(ss);
1430 if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
1431 return 0;
1433 return key;
1436 /* set storage key extended */
1437 void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
1439 static S390SKeysState *ss;
1440 static S390SKeysClass *skeyclass;
1441 uint64_t addr = wrap_address(env, r2);
1442 uint8_t key;
1444 if (addr > ram_size) {
1445 return;
1448 if (unlikely(!ss)) {
1449 ss = s390_get_skeys_device();
1450 skeyclass = S390_SKEYS_GET_CLASS(ss);
1453 key = (uint8_t) r1;
1454 skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
1457 /* reset reference bit extended */
1458 uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
1460 static S390SKeysState *ss;
1461 static S390SKeysClass *skeyclass;
1462 uint8_t re, key;
1464 if (r2 > ram_size) {
1465 return 0;
1468 if (unlikely(!ss)) {
1469 ss = s390_get_skeys_device();
1470 skeyclass = S390_SKEYS_GET_CLASS(ss);
1473 if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1474 return 0;
1477 re = key & (SK_R | SK_C);
1478 key &= ~SK_R;
1480 if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1481 return 0;
1485 * cc
1487 * 0 Reference bit zero; change bit zero
1488 * 1 Reference bit zero; change bit one
1489 * 2 Reference bit one; change bit zero
1490 * 3 Reference bit one; change bit one
1493 return re >> 1;
1496 uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1498 uintptr_t ra = GETPC();
1499 int cc = 0, i;
1501 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1502 __func__, l, a1, a2);
1504 if (l > 256) {
1505 /* max 256 */
1506 l = 256;
1507 cc = 3;
1510 /* XXX replace w/ memcpy */
1511 for (i = 0; i < l; i++) {
1512 uint8_t x = cpu_ldub_primary_ra(env, a2 + i, ra);
1513 cpu_stb_secondary_ra(env, a1 + i, x, ra);
1516 return cc;
1519 uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1521 uintptr_t ra = GETPC();
1522 int cc = 0, i;
1524 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1525 __func__, l, a1, a2);
1527 if (l > 256) {
1528 /* max 256 */
1529 l = 256;
1530 cc = 3;
1533 /* XXX replace w/ memcpy */
1534 for (i = 0; i < l; i++) {
1535 uint8_t x = cpu_ldub_secondary_ra(env, a2 + i, ra);
1536 cpu_stb_primary_ra(env, a1 + i, x, ra);
1539 return cc;
1542 /* invalidate pte */
1543 void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr,
1544 uint32_t m4)
1546 CPUState *cs = CPU(s390_env_get_cpu(env));
1547 uint64_t page = vaddr & TARGET_PAGE_MASK;
1548 uint64_t pte_addr, pte;
1550 /* Compute the page table entry address */
1551 pte_addr = (pto & _SEGMENT_ENTRY_ORIGIN);
1552 pte_addr += (vaddr & VADDR_PX) >> 9;
1554 /* Mark the page table entry as invalid */
1555 pte = ldq_phys(cs->as, pte_addr);
1556 pte |= _PAGE_INVALID;
1557 stq_phys(cs->as, pte_addr, pte);
1559 /* XXX we exploit the fact that Linux passes the exact virtual
1560 address here - it's not obliged to! */
1561 /* XXX: the LC bit should be considered as 0 if the local-TLB-clearing
1562 facility is not installed. */
1563 if (m4 & 1) {
1564 tlb_flush_page(cs, page);
1565 } else {
1566 tlb_flush_page_all_cpus_synced(cs, page);
1569 /* XXX 31-bit hack */
1570 if (m4 & 1) {
1571 tlb_flush_page(cs, page ^ 0x80000000);
1572 } else {
1573 tlb_flush_page_all_cpus_synced(cs, page ^ 0x80000000);
1577 /* flush local tlb */
1578 void HELPER(ptlb)(CPUS390XState *env)
1580 S390CPU *cpu = s390_env_get_cpu(env);
1582 tlb_flush(CPU(cpu));
1585 /* flush global tlb */
1586 void HELPER(purge)(CPUS390XState *env)
1588 S390CPU *cpu = s390_env_get_cpu(env);
1590 tlb_flush_all_cpus_synced(CPU(cpu));
1593 /* load using real address */
1594 uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr)
1596 CPUState *cs = CPU(s390_env_get_cpu(env));
1598 return (uint32_t)ldl_phys(cs->as, wrap_address(env, addr));
1601 uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr)
1603 CPUState *cs = CPU(s390_env_get_cpu(env));
1605 return ldq_phys(cs->as, wrap_address(env, addr));
1608 /* store using real address */
1609 void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
1611 CPUState *cs = CPU(s390_env_get_cpu(env));
1613 stl_phys(cs->as, wrap_address(env, addr), (uint32_t)v1);
1615 if ((env->psw.mask & PSW_MASK_PER) &&
1616 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
1617 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
1618 /* PSW is saved just before calling the helper. */
1619 env->per_address = env->psw.addr;
1620 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
1624 void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
1626 CPUState *cs = CPU(s390_env_get_cpu(env));
1628 stq_phys(cs->as, wrap_address(env, addr), v1);
1630 if ((env->psw.mask & PSW_MASK_PER) &&
1631 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
1632 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
1633 /* PSW is saved just before calling the helper. */
1634 env->per_address = env->psw.addr;
1635 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
1639 /* load real address */
1640 uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
1642 CPUState *cs = CPU(s390_env_get_cpu(env));
1643 uint32_t cc = 0;
1644 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1645 uint64_t ret;
1646 int old_exc, flags;
1648 /* XXX incomplete - has more corner cases */
1649 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1650 cpu_restore_state(cs, GETPC());
1651 program_interrupt(env, PGM_SPECIAL_OP, 2);
1654 old_exc = cs->exception_index;
1655 if (mmu_translate(env, addr, 0, asc, &ret, &flags, true)) {
1656 cc = 3;
1658 if (cs->exception_index == EXCP_PGM) {
1659 ret = env->int_pgm_code | 0x80000000;
1660 } else {
1661 ret |= addr & ~TARGET_PAGE_MASK;
1663 cs->exception_index = old_exc;
1665 env->cc_op = cc;
1666 return ret;
1668 #endif
1670 /* load pair from quadword */
1671 uint64_t HELPER(lpq)(CPUS390XState *env, uint64_t addr)
1673 uintptr_t ra = GETPC();
1674 uint64_t hi, lo;
1676 if (parallel_cpus) {
1677 #ifndef CONFIG_ATOMIC128
1678 cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
1679 #else
1680 int mem_idx = cpu_mmu_index(env, false);
1681 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1682 Int128 v = helper_atomic_ldo_be_mmu(env, addr, oi, ra);
1683 hi = int128_gethi(v);
1684 lo = int128_getlo(v);
1685 #endif
1686 } else {
1687 check_alignment(env, addr, 16, ra);
1689 hi = cpu_ldq_data_ra(env, addr + 0, ra);
1690 lo = cpu_ldq_data_ra(env, addr + 8, ra);
1693 env->retxl = lo;
1694 return hi;
1697 /* store pair to quadword */
1698 void HELPER(stpq)(CPUS390XState *env, uint64_t addr,
1699 uint64_t low, uint64_t high)
1701 uintptr_t ra = GETPC();
1703 if (parallel_cpus) {
1704 #ifndef CONFIG_ATOMIC128
1705 cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
1706 #else
1707 int mem_idx = cpu_mmu_index(env, false);
1708 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1710 Int128 v = int128_make128(low, high);
1711 helper_atomic_sto_be_mmu(env, addr, v, oi, ra);
1712 #endif
1713 } else {
1714 check_alignment(env, addr, 16, ra);
1716 cpu_stq_data_ra(env, addr + 0, high, ra);
1717 cpu_stq_data_ra(env, addr + 8, low, ra);
1721 /* Execute instruction. This instruction executes an insn modified with
1722 the contents of r1. It does not change the executed instruction in memory;
1723 it does not change the program counter.
1725 Perform this by recording the modified instruction in env->ex_value.
1726 This will be noticed by cpu_get_tb_cpu_state and thus tb translation.
1728 void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
1730 uint64_t insn = cpu_lduw_code(env, addr);
1731 uint8_t opc = insn >> 8;
1733 /* Or in the contents of R1[56:63]. */
1734 insn |= r1 & 0xff;
1736 /* Load the rest of the instruction. */
1737 insn <<= 48;
1738 switch (get_ilen(opc)) {
1739 case 2:
1740 break;
1741 case 4:
1742 insn |= (uint64_t)cpu_lduw_code(env, addr + 2) << 32;
1743 break;
1744 case 6:
1745 insn |= (uint64_t)(uint32_t)cpu_ldl_code(env, addr + 2) << 16;
1746 break;
1747 default:
1748 g_assert_not_reached();
1751 /* The very most common cases can be sped up by avoiding a new TB. */
1752 if ((opc & 0xf0) == 0xd0) {
1753 typedef uint32_t (*dx_helper)(CPUS390XState *, uint32_t, uint64_t,
1754 uint64_t, uintptr_t);
1755 static const dx_helper dx[16] = {
1756 [0x2] = do_helper_mvc,
1757 [0x4] = do_helper_nc,
1758 [0x5] = do_helper_clc,
1759 [0x6] = do_helper_oc,
1760 [0x7] = do_helper_xc,
1761 [0xc] = do_helper_tr,
1762 [0xd] = do_helper_trt,
1764 dx_helper helper = dx[opc & 0xf];
1766 if (helper) {
1767 uint32_t l = extract64(insn, 48, 8);
1768 uint32_t b1 = extract64(insn, 44, 4);
1769 uint32_t d1 = extract64(insn, 32, 12);
1770 uint32_t b2 = extract64(insn, 28, 4);
1771 uint32_t d2 = extract64(insn, 16, 12);
1772 uint64_t a1 = wrap_address(env, env->regs[b1] + d1);
1773 uint64_t a2 = wrap_address(env, env->regs[b2] + d2);
1775 env->cc_op = helper(env, l, a1, a2, 0);
1776 env->psw.addr += ilen;
1777 return;
1779 } else if (opc == 0x0a) {
1780 env->int_svc_code = extract64(insn, 48, 8);
1781 env->int_svc_ilen = ilen;
1782 helper_exception(env, EXCP_SVC);
1783 g_assert_not_reached();
1786 /* Record the insn we want to execute as well as the ilen to use
1787 during the execution of the target insn. This will also ensure
1788 that ex_value is non-zero, which flags that we are in a state
1789 that requires such execution. */
1790 env->ex_value = insn | ilen;