target/s390x: End the TB after EXECUTE
[qemu/ar7.git] / target / s390x / mem_helper.c
blobd57d5b17029f1915cb65c5f826cd5a4614cbe13a
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 static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte,
71 uint32_t l, uintptr_t ra)
73 int mmu_idx = cpu_mmu_index(env, false);
75 while (l > 0) {
76 void *p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
77 if (p) {
78 /* Access to the whole page in write mode granted. */
79 uint32_t l_adj = adj_len_to_page(l, dest);
80 memset(p, byte, l_adj);
81 dest += l_adj;
82 l -= l_adj;
83 } else {
84 /* We failed to get access to the whole page. The next write
85 access will likely fill the QEMU TLB for the next iteration. */
86 cpu_stb_data_ra(env, dest, byte, ra);
87 dest++;
88 l--;
93 static void fast_memmove(CPUS390XState *env, uint64_t dest, uint64_t src,
94 uint32_t l, uintptr_t ra)
96 int mmu_idx = cpu_mmu_index(env, false);
98 while (l > 0) {
99 void *src_p = tlb_vaddr_to_host(env, src, MMU_DATA_LOAD, mmu_idx);
100 void *dest_p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
101 if (src_p && dest_p) {
102 /* Access to both whole pages granted. */
103 uint32_t l_adj = adj_len_to_page(l, src);
104 l_adj = adj_len_to_page(l_adj, dest);
105 memmove(dest_p, src_p, l_adj);
106 src += l_adj;
107 dest += l_adj;
108 l -= l_adj;
109 } else {
110 /* We failed to get access to one or both whole pages. The next
111 read or write access will likely fill the QEMU TLB for the
112 next iteration. */
113 cpu_stb_data_ra(env, dest, cpu_ldub_data_ra(env, src, ra), ra);
114 src++;
115 dest++;
116 l--;
121 /* and on array */
122 static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest,
123 uint64_t src, uintptr_t ra)
125 uint32_t i;
126 uint8_t c = 0;
128 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
129 __func__, l, dest, src);
131 for (i = 0; i <= l; i++) {
132 uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
133 x &= cpu_ldub_data_ra(env, dest + i, ra);
134 c |= x;
135 cpu_stb_data_ra(env, dest + i, x, ra);
137 return c != 0;
140 uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
141 uint64_t src)
143 return do_helper_nc(env, l, dest, src, GETPC());
146 /* xor on array */
147 static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest,
148 uint64_t src, uintptr_t ra)
150 uint32_t i;
151 uint8_t c = 0;
153 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
154 __func__, l, dest, src);
156 /* xor with itself is the same as memset(0) */
157 if (src == dest) {
158 fast_memset(env, dest, 0, l + 1, ra);
159 return 0;
162 for (i = 0; i <= l; i++) {
163 uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
164 x ^= cpu_ldub_data_ra(env, dest + i, ra);
165 c |= x;
166 cpu_stb_data_ra(env, dest + i, x, ra);
168 return c != 0;
171 uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
172 uint64_t src)
174 return do_helper_xc(env, l, dest, src, GETPC());
177 /* or on array */
178 static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest,
179 uint64_t src, uintptr_t ra)
181 uint32_t i;
182 uint8_t c = 0;
184 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
185 __func__, l, dest, src);
187 for (i = 0; i <= l; i++) {
188 uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
189 x |= cpu_ldub_data_ra(env, dest + i, ra);
190 c |= x;
191 cpu_stb_data_ra(env, dest + i, x, ra);
193 return c != 0;
196 uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
197 uint64_t src)
199 return do_helper_oc(env, l, dest, src, GETPC());
202 /* memmove */
203 static void do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest,
204 uint64_t src, uintptr_t ra)
206 uint32_t i;
208 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
209 __func__, l, dest, src);
211 /* mvc with source pointing to the byte after the destination is the
212 same as memset with the first source byte */
213 if (dest == src + 1) {
214 fast_memset(env, dest, cpu_ldub_data_ra(env, src, ra), l + 1, ra);
215 return;
218 /* mvc and memmove do not behave the same when areas overlap! */
219 if (dest < src || src + l < dest) {
220 fast_memmove(env, dest, src, l + 1, ra);
221 return;
224 /* slow version with byte accesses which always work */
225 for (i = 0; i <= l; i++) {
226 cpu_stb_data_ra(env, dest + i, cpu_ldub_data_ra(env, src + i, ra), ra);
230 void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
232 do_helper_mvc(env, l, dest, src, GETPC());
235 /* compare unsigned byte arrays */
236 static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1,
237 uint64_t s2, uintptr_t ra)
239 uint32_t i;
240 uint32_t cc = 0;
242 HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
243 __func__, l, s1, s2);
245 for (i = 0; i <= l; i++) {
246 uint8_t x = cpu_ldub_data_ra(env, s1 + i, ra);
247 uint8_t y = cpu_ldub_data_ra(env, s2 + i, ra);
248 HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
249 if (x < y) {
250 cc = 1;
251 break;
252 } else if (x > y) {
253 cc = 2;
254 break;
258 HELPER_LOG("\n");
259 return cc;
262 uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2)
264 return do_helper_clc(env, l, s1, s2, GETPC());
267 /* compare logical under mask */
268 uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
269 uint64_t addr)
271 uintptr_t ra = GETPC();
272 uint32_t cc = 0;
274 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
275 mask, addr);
277 while (mask) {
278 if (mask & 8) {
279 uint8_t d = cpu_ldub_data_ra(env, addr, ra);
280 uint8_t r = extract32(r1, 24, 8);
281 HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
282 addr);
283 if (r < d) {
284 cc = 1;
285 break;
286 } else if (r > d) {
287 cc = 2;
288 break;
290 addr++;
292 mask = (mask << 1) & 0xf;
293 r1 <<= 8;
296 HELPER_LOG("\n");
297 return cc;
300 static inline uint64_t fix_address(CPUS390XState *env, uint64_t a)
302 /* 31-Bit mode */
303 if (!(env->psw.mask & PSW_MASK_64)) {
304 a &= 0x7fffffff;
306 return a;
309 static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2)
311 uint64_t r = d2;
312 if (x2) {
313 r += env->regs[x2];
315 if (b2) {
316 r += env->regs[b2];
318 return fix_address(env, r);
321 static inline uint64_t get_address_31fix(CPUS390XState *env, int reg)
323 return fix_address(env, env->regs[reg]);
326 /* search string (c is byte to search, r2 is string, r1 end of string) */
327 uint64_t HELPER(srst)(CPUS390XState *env, uint64_t r0, uint64_t end,
328 uint64_t str)
330 uintptr_t ra = GETPC();
331 uint32_t len;
332 uint8_t v, c = r0;
334 str = fix_address(env, str);
335 end = fix_address(env, end);
337 /* Assume for now that R2 is unmodified. */
338 env->retxl = str;
340 /* Lest we fail to service interrupts in a timely manner, limit the
341 amount of work we're willing to do. For now, let's cap at 8k. */
342 for (len = 0; len < 0x2000; ++len) {
343 if (str + len == end) {
344 /* Character not found. R1 & R2 are unmodified. */
345 env->cc_op = 2;
346 return end;
348 v = cpu_ldub_data_ra(env, str + len, ra);
349 if (v == c) {
350 /* Character found. Set R1 to the location; R2 is unmodified. */
351 env->cc_op = 1;
352 return str + len;
356 /* CPU-determined bytes processed. Advance R2 to next byte to process. */
357 env->retxl = str + len;
358 env->cc_op = 3;
359 return end;
362 /* unsigned string compare (c is string terminator) */
363 uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
365 uintptr_t ra = GETPC();
366 uint32_t len;
368 c = c & 0xff;
369 s1 = fix_address(env, s1);
370 s2 = fix_address(env, s2);
372 /* Lest we fail to service interrupts in a timely manner, limit the
373 amount of work we're willing to do. For now, let's cap at 8k. */
374 for (len = 0; len < 0x2000; ++len) {
375 uint8_t v1 = cpu_ldub_data_ra(env, s1 + len, ra);
376 uint8_t v2 = cpu_ldub_data_ra(env, s2 + len, ra);
377 if (v1 == v2) {
378 if (v1 == c) {
379 /* Equal. CC=0, and don't advance the registers. */
380 env->cc_op = 0;
381 env->retxl = s2;
382 return s1;
384 } else {
385 /* Unequal. CC={1,2}, and advance the registers. Note that
386 the terminator need not be zero, but the string that contains
387 the terminator is by definition "low". */
388 env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2);
389 env->retxl = s2 + len;
390 return s1 + len;
394 /* CPU-determined bytes equal; advance the registers. */
395 env->cc_op = 3;
396 env->retxl = s2 + len;
397 return s1 + len;
400 /* move page */
401 uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
403 /* ??? missing r0 handling, which includes access keys, but more
404 importantly optional suppression of the exception! */
405 fast_memmove(env, r1, r2, TARGET_PAGE_SIZE, GETPC());
406 return 0; /* data moved */
409 /* string copy (c is string terminator) */
410 uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s)
412 uintptr_t ra = GETPC();
413 uint32_t len;
415 c = c & 0xff;
416 d = fix_address(env, d);
417 s = fix_address(env, s);
419 /* Lest we fail to service interrupts in a timely manner, limit the
420 amount of work we're willing to do. For now, let's cap at 8k. */
421 for (len = 0; len < 0x2000; ++len) {
422 uint8_t v = cpu_ldub_data_ra(env, s + len, ra);
423 cpu_stb_data_ra(env, d + len, v, ra);
424 if (v == c) {
425 /* Complete. Set CC=1 and advance R1. */
426 env->cc_op = 1;
427 env->retxl = s;
428 return d + len;
432 /* Incomplete. Set CC=3 and signal to advance R1 and R2. */
433 env->cc_op = 3;
434 env->retxl = s + len;
435 return d + len;
438 static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address,
439 uint32_t mask)
441 int pos = 24; /* top of the lower half of r1 */
442 uint64_t rmask = 0xff000000ULL;
443 uint8_t val = 0;
444 int ccd = 0;
445 uint32_t cc = 0;
447 while (mask) {
448 if (mask & 8) {
449 env->regs[r1] &= ~rmask;
450 val = cpu_ldub_data(env, address);
451 if ((val & 0x80) && !ccd) {
452 cc = 1;
454 ccd = 1;
455 if (val && cc == 0) {
456 cc = 2;
458 env->regs[r1] |= (uint64_t)val << pos;
459 address++;
461 mask = (mask << 1) & 0xf;
462 pos -= 8;
463 rmask >>= 8;
466 return cc;
469 /* load access registers r1 to r3 from memory at a2 */
470 void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
472 uintptr_t ra = GETPC();
473 int i;
475 for (i = r1;; i = (i + 1) % 16) {
476 env->aregs[i] = cpu_ldl_data_ra(env, a2, ra);
477 a2 += 4;
479 if (i == r3) {
480 break;
485 /* store access registers r1 to r3 in memory at a2 */
486 void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
488 uintptr_t ra = GETPC();
489 int i;
491 for (i = r1;; i = (i + 1) % 16) {
492 cpu_stl_data_ra(env, a2, env->aregs[i], ra);
493 a2 += 4;
495 if (i == r3) {
496 break;
501 /* move long */
502 uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
504 uintptr_t ra = GETPC();
505 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
506 uint64_t dest = get_address_31fix(env, r1);
507 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
508 uint64_t src = get_address_31fix(env, r2);
509 uint8_t pad = env->regs[r2 + 1] >> 24;
510 uint8_t v;
511 uint32_t cc;
513 if (destlen == srclen) {
514 cc = 0;
515 } else if (destlen < srclen) {
516 cc = 1;
517 } else {
518 cc = 2;
521 if (srclen > destlen) {
522 srclen = destlen;
525 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
526 v = cpu_ldub_data_ra(env, src, ra);
527 cpu_stb_data_ra(env, dest, v, ra);
530 for (; destlen; dest++, destlen--) {
531 cpu_stb_data_ra(env, dest, pad, ra);
534 env->regs[r1 + 1] = destlen;
535 /* can't use srclen here, we trunc'ed it */
536 env->regs[r2 + 1] -= src - env->regs[r2];
537 env->regs[r1] = dest;
538 env->regs[r2] = src;
540 return cc;
543 /* move long extended another memcopy insn with more bells and whistles */
544 uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
545 uint32_t r3)
547 uintptr_t ra = GETPC();
548 uint64_t destlen = env->regs[r1 + 1];
549 uint64_t dest = env->regs[r1];
550 uint64_t srclen = env->regs[r3 + 1];
551 uint64_t src = env->regs[r3];
552 uint8_t pad = a2 & 0xff;
553 uint8_t v;
554 uint32_t cc;
556 if (!(env->psw.mask & PSW_MASK_64)) {
557 destlen = (uint32_t)destlen;
558 srclen = (uint32_t)srclen;
559 dest &= 0x7fffffff;
560 src &= 0x7fffffff;
563 if (destlen == srclen) {
564 cc = 0;
565 } else if (destlen < srclen) {
566 cc = 1;
567 } else {
568 cc = 2;
571 if (srclen > destlen) {
572 srclen = destlen;
575 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
576 v = cpu_ldub_data_ra(env, src, ra);
577 cpu_stb_data_ra(env, dest, v, ra);
580 for (; destlen; dest++, destlen--) {
581 cpu_stb_data_ra(env, dest, pad, ra);
584 env->regs[r1 + 1] = destlen;
585 /* can't use srclen here, we trunc'ed it */
586 /* FIXME: 31-bit mode! */
587 env->regs[r3 + 1] -= src - env->regs[r3];
588 env->regs[r1] = dest;
589 env->regs[r3] = src;
591 return cc;
594 /* compare logical long extended memcompare insn with padding */
595 uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
596 uint32_t r3)
598 uintptr_t ra = GETPC();
599 uint64_t destlen = env->regs[r1 + 1];
600 uint64_t dest = get_address_31fix(env, r1);
601 uint64_t srclen = env->regs[r3 + 1];
602 uint64_t src = get_address_31fix(env, r3);
603 uint8_t pad = a2 & 0xff;
604 uint32_t cc = 0;
606 if (!(destlen || srclen)) {
607 return cc;
610 if (srclen > destlen) {
611 srclen = destlen;
614 for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
615 uint8_t v1 = srclen ? cpu_ldub_data_ra(env, src, ra) : pad;
616 uint8_t v2 = destlen ? cpu_ldub_data_ra(env, dest, ra) : pad;
617 if (v1 != v2) {
618 cc = (v1 < v2) ? 1 : 2;
619 break;
623 env->regs[r1 + 1] = destlen;
624 /* can't use srclen here, we trunc'ed it */
625 env->regs[r3 + 1] -= src - env->regs[r3];
626 env->regs[r1] = dest;
627 env->regs[r3] = src;
629 return cc;
632 /* checksum */
633 uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
634 uint64_t src, uint64_t src_len)
636 uintptr_t ra = GETPC();
637 uint64_t max_len, len;
638 uint64_t cksm = (uint32_t)r1;
640 /* Lest we fail to service interrupts in a timely manner, limit the
641 amount of work we're willing to do. For now, let's cap at 8k. */
642 max_len = (src_len > 0x2000 ? 0x2000 : src_len);
644 /* Process full words as available. */
645 for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
646 cksm += (uint32_t)cpu_ldl_data_ra(env, src, ra);
649 switch (max_len - len) {
650 case 1:
651 cksm += cpu_ldub_data_ra(env, src, ra) << 24;
652 len += 1;
653 break;
654 case 2:
655 cksm += cpu_lduw_data_ra(env, src, ra) << 16;
656 len += 2;
657 break;
658 case 3:
659 cksm += cpu_lduw_data_ra(env, src, ra) << 16;
660 cksm += cpu_ldub_data_ra(env, src + 2, ra) << 8;
661 len += 3;
662 break;
665 /* Fold the carry from the checksum. Note that we can see carry-out
666 during folding more than once (but probably not more than twice). */
667 while (cksm > 0xffffffffull) {
668 cksm = (uint32_t)cksm + (cksm >> 32);
671 /* Indicate whether or not we've processed everything. */
672 env->cc_op = (len == src_len ? 0 : 3);
674 /* Return both cksm and processed length. */
675 env->retxl = cksm;
676 return len;
679 void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
680 uint64_t src)
682 uintptr_t ra = GETPC();
683 int len_dest = len >> 4;
684 int len_src = len & 0xf;
685 uint8_t b;
686 int second_nibble = 0;
688 dest += len_dest;
689 src += len_src;
691 /* last byte is special, it only flips the nibbles */
692 b = cpu_ldub_data_ra(env, src, ra);
693 cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
694 src--;
695 len_src--;
697 /* now pad every nibble with 0xf0 */
699 while (len_dest > 0) {
700 uint8_t cur_byte = 0;
702 if (len_src > 0) {
703 cur_byte = cpu_ldub_data_ra(env, src, ra);
706 len_dest--;
707 dest--;
709 /* only advance one nibble at a time */
710 if (second_nibble) {
711 cur_byte >>= 4;
712 len_src--;
713 src--;
715 second_nibble = !second_nibble;
717 /* digit */
718 cur_byte = (cur_byte & 0xf);
719 /* zone bits */
720 cur_byte |= 0xf0;
722 cpu_stb_data_ra(env, dest, cur_byte, ra);
726 static void do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array,
727 uint64_t trans, uintptr_t ra)
729 uint32_t i;
731 for (i = 0; i <= len; i++) {
732 uint8_t byte = cpu_ldub_data_ra(env, array + i, ra);
733 uint8_t new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
734 cpu_stb_data_ra(env, array + i, new_byte, ra);
738 void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
739 uint64_t trans)
741 return do_helper_tr(env, len, array, trans, GETPC());
744 uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array,
745 uint64_t len, uint64_t trans)
747 uintptr_t ra = GETPC();
748 uint8_t end = env->regs[0] & 0xff;
749 uint64_t l = len;
750 uint64_t i;
751 uint32_t cc = 0;
753 if (!(env->psw.mask & PSW_MASK_64)) {
754 array &= 0x7fffffff;
755 l = (uint32_t)l;
758 /* Lest we fail to service interrupts in a timely manner, limit the
759 amount of work we're willing to do. For now, let's cap at 8k. */
760 if (l > 0x2000) {
761 l = 0x2000;
762 cc = 3;
765 for (i = 0; i < l; i++) {
766 uint8_t byte, new_byte;
768 byte = cpu_ldub_data_ra(env, array + i, ra);
770 if (byte == end) {
771 cc = 1;
772 break;
775 new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
776 cpu_stb_data_ra(env, array + i, new_byte, ra);
779 env->cc_op = cc;
780 env->retxl = len - i;
781 return array + i;
784 static uint32_t do_helper_trt(CPUS390XState *env, uint32_t len, uint64_t array,
785 uint64_t trans, uintptr_t ra)
787 uint32_t i;
789 for (i = 0; i <= len; i++) {
790 uint8_t byte = cpu_ldub_data_ra(env, array + i, ra);
791 uint8_t sbyte = cpu_ldub_data_ra(env, trans + byte, ra);
793 if (sbyte != 0) {
794 env->regs[1] = array + i;
795 env->regs[2] = deposit64(env->regs[2], 0, 8, sbyte);
796 return (i == len) ? 2 : 1;
800 return 0;
803 uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
804 uint64_t trans)
806 return do_helper_trt(env, len, array, trans, GETPC());
809 void HELPER(cdsg)(CPUS390XState *env, uint64_t addr,
810 uint32_t r1, uint32_t r3)
812 uintptr_t ra = GETPC();
813 Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
814 Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
815 Int128 oldv;
816 bool fail;
818 if (parallel_cpus) {
819 #ifndef CONFIG_ATOMIC128
820 cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
821 #else
822 int mem_idx = cpu_mmu_index(env, false);
823 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
824 oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
825 fail = !int128_eq(oldv, cmpv);
826 #endif
827 } else {
828 uint64_t oldh, oldl;
830 oldh = cpu_ldq_data_ra(env, addr + 0, ra);
831 oldl = cpu_ldq_data_ra(env, addr + 8, ra);
833 oldv = int128_make128(oldl, oldh);
834 fail = !int128_eq(oldv, cmpv);
835 if (fail) {
836 newv = oldv;
839 cpu_stq_data_ra(env, addr + 0, int128_gethi(newv), ra);
840 cpu_stq_data_ra(env, addr + 8, int128_getlo(newv), ra);
843 env->cc_op = fail;
844 env->regs[r1] = int128_gethi(oldv);
845 env->regs[r1 + 1] = int128_getlo(oldv);
848 #if !defined(CONFIG_USER_ONLY)
849 void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
851 uintptr_t ra = GETPC();
852 S390CPU *cpu = s390_env_get_cpu(env);
853 bool PERchanged = false;
854 uint64_t src = a2;
855 uint32_t i;
857 for (i = r1;; i = (i + 1) % 16) {
858 uint64_t val = cpu_ldq_data_ra(env, src, ra);
859 if (env->cregs[i] != val && i >= 9 && i <= 11) {
860 PERchanged = true;
862 env->cregs[i] = val;
863 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
864 i, src, val);
865 src += sizeof(uint64_t);
867 if (i == r3) {
868 break;
872 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
873 s390_cpu_recompute_watchpoints(CPU(cpu));
876 tlb_flush(CPU(cpu));
879 void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
881 uintptr_t ra = GETPC();
882 S390CPU *cpu = s390_env_get_cpu(env);
883 bool PERchanged = false;
884 uint64_t src = a2;
885 uint32_t i;
887 for (i = r1;; i = (i + 1) % 16) {
888 uint32_t val = cpu_ldl_data_ra(env, src, ra);
889 if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
890 PERchanged = true;
892 env->cregs[i] = deposit64(env->cregs[i], 0, 32, val);
893 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val);
894 src += sizeof(uint32_t);
896 if (i == r3) {
897 break;
901 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
902 s390_cpu_recompute_watchpoints(CPU(cpu));
905 tlb_flush(CPU(cpu));
908 void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
910 uintptr_t ra = GETPC();
911 uint64_t dest = a2;
912 uint32_t i;
914 for (i = r1;; i = (i + 1) % 16) {
915 cpu_stq_data_ra(env, dest, env->cregs[i], ra);
916 dest += sizeof(uint64_t);
918 if (i == r3) {
919 break;
924 void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
926 uintptr_t ra = GETPC();
927 uint64_t dest = a2;
928 uint32_t i;
930 for (i = r1;; i = (i + 1) % 16) {
931 cpu_stl_data_ra(env, dest, env->cregs[i], ra);
932 dest += sizeof(uint32_t);
934 if (i == r3) {
935 break;
940 uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
942 uintptr_t ra = GETPC();
943 CPUState *cs = CPU(s390_env_get_cpu(env));
944 uint64_t abs_addr;
945 int i;
947 real_addr = fix_address(env, real_addr);
948 abs_addr = mmu_real2abs(env, real_addr) & TARGET_PAGE_MASK;
949 if (!address_space_access_valid(&address_space_memory, abs_addr,
950 TARGET_PAGE_SIZE, true)) {
951 cpu_restore_state(cs, ra);
952 program_interrupt(env, PGM_ADDRESSING, 4);
953 return 1;
956 /* Check low-address protection */
957 if ((env->cregs[0] & CR0_LOWPROT) && real_addr < 0x2000) {
958 cpu_restore_state(cs, ra);
959 program_interrupt(env, PGM_PROTECTION, 4);
960 return 1;
963 for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
964 stq_phys(cs->as, abs_addr + i, 0);
967 return 0;
970 uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
972 /* XXX implement */
973 return 0;
976 /* insert storage key extended */
977 uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
979 static S390SKeysState *ss;
980 static S390SKeysClass *skeyclass;
981 uint64_t addr = get_address(env, 0, 0, r2);
982 uint8_t key;
984 if (addr > ram_size) {
985 return 0;
988 if (unlikely(!ss)) {
989 ss = s390_get_skeys_device();
990 skeyclass = S390_SKEYS_GET_CLASS(ss);
993 if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
994 return 0;
996 return key;
999 /* set storage key extended */
1000 void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
1002 static S390SKeysState *ss;
1003 static S390SKeysClass *skeyclass;
1004 uint64_t addr = get_address(env, 0, 0, r2);
1005 uint8_t key;
1007 if (addr > ram_size) {
1008 return;
1011 if (unlikely(!ss)) {
1012 ss = s390_get_skeys_device();
1013 skeyclass = S390_SKEYS_GET_CLASS(ss);
1016 key = (uint8_t) r1;
1017 skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
1020 /* reset reference bit extended */
1021 uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
1023 static S390SKeysState *ss;
1024 static S390SKeysClass *skeyclass;
1025 uint8_t re, key;
1027 if (r2 > ram_size) {
1028 return 0;
1031 if (unlikely(!ss)) {
1032 ss = s390_get_skeys_device();
1033 skeyclass = S390_SKEYS_GET_CLASS(ss);
1036 if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1037 return 0;
1040 re = key & (SK_R | SK_C);
1041 key &= ~SK_R;
1043 if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1044 return 0;
1048 * cc
1050 * 0 Reference bit zero; change bit zero
1051 * 1 Reference bit zero; change bit one
1052 * 2 Reference bit one; change bit zero
1053 * 3 Reference bit one; change bit one
1056 return re >> 1;
1059 uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1061 uintptr_t ra = GETPC();
1062 int cc = 0, i;
1064 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1065 __func__, l, a1, a2);
1067 if (l > 256) {
1068 /* max 256 */
1069 l = 256;
1070 cc = 3;
1073 /* XXX replace w/ memcpy */
1074 for (i = 0; i < l; i++) {
1075 uint8_t x = cpu_ldub_primary_ra(env, a2 + i, ra);
1076 cpu_stb_secondary_ra(env, a1 + i, x, ra);
1079 return cc;
1082 uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1084 uintptr_t ra = GETPC();
1085 int cc = 0, i;
1087 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1088 __func__, l, a1, a2);
1090 if (l > 256) {
1091 /* max 256 */
1092 l = 256;
1093 cc = 3;
1096 /* XXX replace w/ memcpy */
1097 for (i = 0; i < l; i++) {
1098 uint8_t x = cpu_ldub_secondary_ra(env, a2 + i, ra);
1099 cpu_stb_primary_ra(env, a1 + i, x, ra);
1102 return cc;
1105 /* invalidate pte */
1106 void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr)
1108 CPUState *cs = CPU(s390_env_get_cpu(env));
1109 uint64_t page = vaddr & TARGET_PAGE_MASK;
1110 uint64_t pte = 0;
1112 /* XXX broadcast to other CPUs */
1114 /* XXX Linux is nice enough to give us the exact pte address.
1115 According to spec we'd have to find it out ourselves */
1116 /* XXX Linux is fine with overwriting the pte, the spec requires
1117 us to only set the invalid bit */
1118 stq_phys(cs->as, pte_addr, pte | _PAGE_INVALID);
1120 /* XXX we exploit the fact that Linux passes the exact virtual
1121 address here - it's not obliged to! */
1122 tlb_flush_page(cs, page);
1124 /* XXX 31-bit hack */
1125 if (page & 0x80000000) {
1126 tlb_flush_page(cs, page & ~0x80000000);
1127 } else {
1128 tlb_flush_page(cs, page | 0x80000000);
1132 /* flush local tlb */
1133 void HELPER(ptlb)(CPUS390XState *env)
1135 S390CPU *cpu = s390_env_get_cpu(env);
1137 tlb_flush(CPU(cpu));
1140 /* flush global tlb */
1141 void HELPER(purge)(CPUS390XState *env)
1143 S390CPU *cpu = s390_env_get_cpu(env);
1145 tlb_flush_all_cpus_synced(CPU(cpu));
1148 /* load using real address */
1149 uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr)
1151 CPUState *cs = CPU(s390_env_get_cpu(env));
1153 return (uint32_t)ldl_phys(cs->as, get_address(env, 0, 0, addr));
1156 uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr)
1158 CPUState *cs = CPU(s390_env_get_cpu(env));
1160 return ldq_phys(cs->as, get_address(env, 0, 0, addr));
1163 /* store using real address */
1164 void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
1166 CPUState *cs = CPU(s390_env_get_cpu(env));
1168 stl_phys(cs->as, get_address(env, 0, 0, addr), (uint32_t)v1);
1170 if ((env->psw.mask & PSW_MASK_PER) &&
1171 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
1172 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
1173 /* PSW is saved just before calling the helper. */
1174 env->per_address = env->psw.addr;
1175 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
1179 void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
1181 CPUState *cs = CPU(s390_env_get_cpu(env));
1183 stq_phys(cs->as, get_address(env, 0, 0, addr), v1);
1185 if ((env->psw.mask & PSW_MASK_PER) &&
1186 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
1187 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
1188 /* PSW is saved just before calling the helper. */
1189 env->per_address = env->psw.addr;
1190 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
1194 /* load real address */
1195 uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
1197 CPUState *cs = CPU(s390_env_get_cpu(env));
1198 uint32_t cc = 0;
1199 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1200 uint64_t ret;
1201 int old_exc, flags;
1203 /* XXX incomplete - has more corner cases */
1204 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1205 cpu_restore_state(cs, GETPC());
1206 program_interrupt(env, PGM_SPECIAL_OP, 2);
1209 old_exc = cs->exception_index;
1210 if (mmu_translate(env, addr, 0, asc, &ret, &flags, true)) {
1211 cc = 3;
1213 if (cs->exception_index == EXCP_PGM) {
1214 ret = env->int_pgm_code | 0x80000000;
1215 } else {
1216 ret |= addr & ~TARGET_PAGE_MASK;
1218 cs->exception_index = old_exc;
1220 env->cc_op = cc;
1221 return ret;
1223 #endif
1225 /* execute instruction
1226 this instruction executes an insn modified with the contents of r1
1227 it does not change the executed instruction in memory
1228 it does not change the program counter
1229 in other words: tricky...
1230 currently implemented by interpreting the cases it is most commonly used.
1232 void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
1234 S390CPU *cpu = s390_env_get_cpu(env);
1235 uint64_t insn = cpu_lduw_code(env, addr);
1236 uint8_t opc = insn >> 8;
1237 uint32_t cc;
1239 /* Or in the contents of R1[56:63]. */
1240 insn |= r1 & 0xff;
1242 /* Load the rest of the instruction. */
1243 insn <<= 48;
1244 switch (get_ilen(opc)) {
1245 case 2:
1246 break;
1247 case 4:
1248 insn |= (uint64_t)cpu_lduw_code(env, addr + 2) << 32;
1249 break;
1250 case 6:
1251 insn |= (uint64_t)(uint32_t)cpu_ldl_code(env, addr + 2) << 16;
1252 break;
1253 default:
1254 g_assert_not_reached();
1257 HELPER_LOG("%s: addr 0x%lx insn 0x%" PRIx64 "\n", __func__, addr, insn);
1259 if ((opc & 0xf0) == 0xd0) {
1260 uint32_t l, b1, b2, d1, d2;
1262 l = extract64(insn, 48, 8);
1263 b1 = extract64(insn, 44, 4);
1264 b2 = extract64(insn, 28, 4);
1265 d1 = extract64(insn, 32, 12);
1266 d2 = extract64(insn, 16, 12);
1268 cc = env->cc_op;
1269 switch (opc & 0xf) {
1270 case 0x2:
1271 do_helper_mvc(env, l, get_address(env, 0, b1, d1),
1272 get_address(env, 0, b2, d2), 0);
1273 break;
1274 case 0x4:
1275 cc = do_helper_nc(env, l, get_address(env, 0, b1, d1),
1276 get_address(env, 0, b2, d2), 0);
1277 break;
1278 case 0x5:
1279 cc = do_helper_clc(env, l, get_address(env, 0, b1, d1),
1280 get_address(env, 0, b2, d2), 0);
1281 break;
1282 case 0x6:
1283 cc = do_helper_oc(env, l, get_address(env, 0, b1, d1),
1284 get_address(env, 0, b2, d2), 0);
1285 break;
1286 case 0x7:
1287 cc = do_helper_xc(env, l, get_address(env, 0, b1, d1),
1288 get_address(env, 0, b2, d2), 0);
1289 break;
1290 case 0xc:
1291 do_helper_tr(env, l, get_address(env, 0, b1, d1),
1292 get_address(env, 0, b2, d2), 0);
1293 break;
1294 case 0xd:
1295 cc = do_helper_trt(env, l, get_address(env, 0, b1, d1),
1296 get_address(env, 0, b2, d2), 0);
1297 break;
1298 default:
1299 goto abort;
1301 } else if (opc == 0x0a) {
1302 /* supervisor call */
1303 env->int_svc_code = extract64(insn, 48, 8);
1304 env->int_svc_ilen = ilen;
1305 helper_exception(env, EXCP_SVC);
1306 g_assert_not_reached();
1307 } else if (opc == 0xbf) {
1308 uint32_t r1, r3, b2, d2;
1310 r1 = extract64(insn, 52, 4);
1311 r3 = extract64(insn, 48, 4);
1312 b2 = extract64(insn, 44, 4);
1313 d2 = extract64(insn, 32, 12);
1314 cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3);
1315 } else {
1316 abort:
1317 cpu_abort(CPU(cpu),
1318 "EXECUTE on instruction prefix 0x%x not implemented\n",
1319 opc);
1320 g_assert_not_reached();
1323 env->cc_op = cc;
1324 env->psw.addr += ilen;