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"
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"
33 /*****************************************************************************/
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);
52 /* #define DEBUG_HELPER */
54 #define HELPER_LOG(x...) qemu_log(x)
56 #define HELPER_LOG(x...)
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;
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);
76 void *p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
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);
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);
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);
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);
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
113 cpu_stb_data_ra(env, dest, cpu_ldub_data_ra(env, src, ra), ra);
122 static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest,
123 uint64_t src, uintptr_t ra)
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);
135 cpu_stb_data_ra(env, dest + i, x, ra);
140 uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
143 return do_helper_nc(env, l, dest, src, GETPC());
147 static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest,
148 uint64_t src, uintptr_t ra)
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) */
158 fast_memset(env, dest, 0, l + 1, ra);
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);
166 cpu_stb_data_ra(env, dest + i, x, ra);
171 uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
174 return do_helper_xc(env, l, dest, src, GETPC());
178 static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest,
179 uint64_t src, uintptr_t ra)
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);
191 cpu_stb_data_ra(env, dest + i, x, ra);
196 uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
199 return do_helper_oc(env, l, dest, src, GETPC());
203 static void do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest,
204 uint64_t src, uintptr_t ra)
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);
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);
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)
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);
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,
271 uintptr_t ra = GETPC();
274 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
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,
292 mask = (mask << 1) & 0xf;
300 static inline uint64_t fix_address(CPUS390XState *env, uint64_t a)
303 if (!(env->psw.mask & PSW_MASK_64)) {
309 static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2)
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,
330 uintptr_t ra = GETPC();
334 str = fix_address(env, str);
335 end = fix_address(env, end);
337 /* Assume for now that R2 is unmodified. */
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. */
348 v = cpu_ldub_data_ra(env, str + len, ra);
350 /* Character found. Set R1 to the location; R2 is unmodified. */
356 /* CPU-determined bytes processed. Advance R2 to next byte to process. */
357 env->retxl = str + len;
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();
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);
379 /* Equal. CC=0, and don't advance the registers. */
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;
394 /* CPU-determined bytes equal; advance the registers. */
396 env->retxl = s2 + len;
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();
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);
425 /* Complete. Set CC=1 and advance R1. */
432 /* Incomplete. Set CC=3 and signal to advance R1 and R2. */
434 env->retxl = s + len;
438 static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address,
441 int pos = 24; /* top of the lower half of r1 */
442 uint64_t rmask = 0xff000000ULL;
449 env->regs[r1] &= ~rmask;
450 val = cpu_ldub_data(env, address);
451 if ((val & 0x80) && !ccd) {
455 if (val && cc == 0) {
458 env->regs[r1] |= (uint64_t)val << pos;
461 mask = (mask << 1) & 0xf;
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)
474 for (i = r1;; i = (i + 1) % 16) {
475 env->aregs[i] = cpu_ldl_data(env, a2);
484 /* store access registers r1 to r3 in memory at a2 */
485 void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
489 for (i = r1;; i = (i + 1) % 16) {
490 cpu_stl_data(env, a2, env->aregs[i]);
500 uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
502 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
503 uint64_t dest = get_address_31fix(env, r1);
504 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
505 uint64_t src = get_address_31fix(env, r2);
506 uint8_t pad = env->regs[r2 + 1] >> 24;
510 if (destlen == srclen) {
512 } else if (destlen < srclen) {
518 if (srclen > destlen) {
522 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
523 v = cpu_ldub_data(env, src);
524 cpu_stb_data(env, dest, v);
527 for (; destlen; dest++, destlen--) {
528 cpu_stb_data(env, dest, pad);
531 env->regs[r1 + 1] = destlen;
532 /* can't use srclen here, we trunc'ed it */
533 env->regs[r2 + 1] -= src - env->regs[r2];
534 env->regs[r1] = dest;
540 /* move long extended another memcopy insn with more bells and whistles */
541 uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
544 uint64_t destlen = env->regs[r1 + 1];
545 uint64_t dest = env->regs[r1];
546 uint64_t srclen = env->regs[r3 + 1];
547 uint64_t src = env->regs[r3];
548 uint8_t pad = a2 & 0xff;
552 if (!(env->psw.mask & PSW_MASK_64)) {
553 destlen = (uint32_t)destlen;
554 srclen = (uint32_t)srclen;
559 if (destlen == srclen) {
561 } else if (destlen < srclen) {
567 if (srclen > destlen) {
571 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
572 v = cpu_ldub_data(env, src);
573 cpu_stb_data(env, dest, v);
576 for (; destlen; dest++, destlen--) {
577 cpu_stb_data(env, dest, pad);
580 env->regs[r1 + 1] = destlen;
581 /* can't use srclen here, we trunc'ed it */
582 /* FIXME: 31-bit mode! */
583 env->regs[r3 + 1] -= src - env->regs[r3];
584 env->regs[r1] = dest;
590 /* compare logical long extended memcompare insn with padding */
591 uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
594 uint64_t destlen = env->regs[r1 + 1];
595 uint64_t dest = get_address_31fix(env, r1);
596 uint64_t srclen = env->regs[r3 + 1];
597 uint64_t src = get_address_31fix(env, r3);
598 uint8_t pad = a2 & 0xff;
599 uint8_t v1 = 0, v2 = 0;
602 if (!(destlen || srclen)) {
606 if (srclen > destlen) {
610 for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
611 v1 = srclen ? cpu_ldub_data(env, src) : pad;
612 v2 = destlen ? cpu_ldub_data(env, dest) : pad;
614 cc = (v1 < v2) ? 1 : 2;
619 env->regs[r1 + 1] = destlen;
620 /* can't use srclen here, we trunc'ed it */
621 env->regs[r3 + 1] -= src - env->regs[r3];
622 env->regs[r1] = dest;
629 uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
630 uint64_t src, uint64_t src_len)
632 uint64_t max_len, len;
633 uint64_t cksm = (uint32_t)r1;
635 /* Lest we fail to service interrupts in a timely manner, limit the
636 amount of work we're willing to do. For now, let's cap at 8k. */
637 max_len = (src_len > 0x2000 ? 0x2000 : src_len);
639 /* Process full words as available. */
640 for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
641 cksm += (uint32_t)cpu_ldl_data(env, src);
644 switch (max_len - len) {
646 cksm += cpu_ldub_data(env, src) << 24;
650 cksm += cpu_lduw_data(env, src) << 16;
654 cksm += cpu_lduw_data(env, src) << 16;
655 cksm += cpu_ldub_data(env, src + 2) << 8;
660 /* Fold the carry from the checksum. Note that we can see carry-out
661 during folding more than once (but probably not more than twice). */
662 while (cksm > 0xffffffffull) {
663 cksm = (uint32_t)cksm + (cksm >> 32);
666 /* Indicate whether or not we've processed everything. */
667 env->cc_op = (len == src_len ? 0 : 3);
669 /* Return both cksm and processed length. */
674 void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
677 int len_dest = len >> 4;
678 int len_src = len & 0xf;
680 int second_nibble = 0;
685 /* last byte is special, it only flips the nibbles */
686 b = cpu_ldub_data(env, src);
687 cpu_stb_data(env, dest, (b << 4) | (b >> 4));
691 /* now pad every nibble with 0xf0 */
693 while (len_dest > 0) {
694 uint8_t cur_byte = 0;
697 cur_byte = cpu_ldub_data(env, src);
703 /* only advance one nibble at a time */
709 second_nibble = !second_nibble;
712 cur_byte = (cur_byte & 0xf);
716 cpu_stb_data(env, dest, cur_byte);
720 void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
725 for (i = 0; i <= len; i++) {
726 uint8_t byte = cpu_ldub_data(env, array + i);
727 uint8_t new_byte = cpu_ldub_data(env, trans + byte);
729 cpu_stb_data(env, array + i, new_byte);
733 uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array,
734 uint64_t len, uint64_t trans)
736 uint8_t end = env->regs[0] & 0xff;
740 if (!(env->psw.mask & PSW_MASK_64)) {
745 /* Lest we fail to service interrupts in a timely manner, limit the
746 amount of work we're willing to do. For now, let's cap at 8k. */
754 for (i = 0; i < l; i++) {
755 uint8_t byte, new_byte;
757 byte = cpu_ldub_data(env, array + i);
764 new_byte = cpu_ldub_data(env, trans + byte);
765 cpu_stb_data(env, array + i, new_byte);
768 env->retxl = len - i;
772 uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
778 for (i = 0; i <= len; i++) {
779 uint8_t byte = cpu_ldub_data(env, array + i);
780 uint8_t sbyte = cpu_ldub_data(env, trans + byte);
783 env->regs[1] = array + i;
784 env->regs[2] = (env->regs[2] & ~0xff) | sbyte;
785 cc = (i == len) ? 2 : 1;
793 void HELPER(cdsg)(CPUS390XState *env, uint64_t addr,
794 uint32_t r1, uint32_t r3)
796 uintptr_t ra = GETPC();
797 Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
798 Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
803 #ifndef CONFIG_ATOMIC128
804 cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
806 int mem_idx = cpu_mmu_index(env, false);
807 TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
808 oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
809 fail = !int128_eq(oldv, cmpv);
814 oldh = cpu_ldq_data_ra(env, addr + 0, ra);
815 oldl = cpu_ldq_data_ra(env, addr + 8, ra);
817 oldv = int128_make128(oldl, oldh);
818 fail = !int128_eq(oldv, cmpv);
823 cpu_stq_data_ra(env, addr + 0, int128_gethi(newv), ra);
824 cpu_stq_data_ra(env, addr + 8, int128_getlo(newv), ra);
828 env->regs[r1] = int128_gethi(oldv);
829 env->regs[r1 + 1] = int128_getlo(oldv);
832 #if !defined(CONFIG_USER_ONLY)
833 void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
835 S390CPU *cpu = s390_env_get_cpu(env);
836 bool PERchanged = false;
841 for (i = r1;; i = (i + 1) % 16) {
842 val = cpu_ldq_data(env, src);
843 if (env->cregs[i] != val && i >= 9 && i <= 11) {
847 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
848 i, src, env->cregs[i]);
849 src += sizeof(uint64_t);
856 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
857 s390_cpu_recompute_watchpoints(CPU(cpu));
863 void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
865 S390CPU *cpu = s390_env_get_cpu(env);
866 bool PERchanged = false;
871 for (i = r1;; i = (i + 1) % 16) {
872 val = cpu_ldl_data(env, src);
873 if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
876 env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | val;
877 src += sizeof(uint32_t);
884 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
885 s390_cpu_recompute_watchpoints(CPU(cpu));
891 void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
896 for (i = r1;; i = (i + 1) % 16) {
897 cpu_stq_data(env, dest, env->cregs[i]);
898 dest += sizeof(uint64_t);
906 void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
911 for (i = r1;; i = (i + 1) % 16) {
912 cpu_stl_data(env, dest, env->cregs[i]);
913 dest += sizeof(uint32_t);
921 uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
923 CPUState *cs = CPU(s390_env_get_cpu(env));
927 real_addr = fix_address(env, real_addr);
928 abs_addr = mmu_real2abs(env, real_addr) & TARGET_PAGE_MASK;
929 if (!address_space_access_valid(&address_space_memory, abs_addr,
930 TARGET_PAGE_SIZE, true)) {
931 program_interrupt(env, PGM_ADDRESSING, 4);
935 /* Check low-address protection */
936 if ((env->cregs[0] & CR0_LOWPROT) && real_addr < 0x2000) {
937 program_interrupt(env, PGM_PROTECTION, 4);
941 for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
942 stq_phys(cs->as, abs_addr + i, 0);
948 uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
955 /* insert storage key extended */
956 uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
958 static S390SKeysState *ss;
959 static S390SKeysClass *skeyclass;
960 uint64_t addr = get_address(env, 0, 0, r2);
963 if (addr > ram_size) {
968 ss = s390_get_skeys_device();
969 skeyclass = S390_SKEYS_GET_CLASS(ss);
972 if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
978 /* set storage key extended */
979 void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
981 static S390SKeysState *ss;
982 static S390SKeysClass *skeyclass;
983 uint64_t addr = get_address(env, 0, 0, r2);
986 if (addr > ram_size) {
991 ss = s390_get_skeys_device();
992 skeyclass = S390_SKEYS_GET_CLASS(ss);
996 skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
999 /* reset reference bit extended */
1000 uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
1002 static S390SKeysState *ss;
1003 static S390SKeysClass *skeyclass;
1006 if (r2 > ram_size) {
1010 if (unlikely(!ss)) {
1011 ss = s390_get_skeys_device();
1012 skeyclass = S390_SKEYS_GET_CLASS(ss);
1015 if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1019 re = key & (SK_R | SK_C);
1022 if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1029 * 0 Reference bit zero; change bit zero
1030 * 1 Reference bit zero; change bit one
1031 * 2 Reference bit one; change bit zero
1032 * 3 Reference bit one; change bit one
1038 /* compare and swap and purge */
1039 uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint64_t r2)
1041 S390CPU *cpu = s390_env_get_cpu(env);
1043 uint32_t o1 = env->regs[r1];
1044 uint64_t a2 = r2 & ~3ULL;
1045 uint32_t o2 = cpu_ldl_data(env, a2);
1048 cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]);
1050 /* flush TLB / ALB */
1051 tlb_flush(CPU(cpu));
1055 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
1062 uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1066 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1067 __func__, l, a1, a2);
1075 /* XXX replace w/ memcpy */
1076 for (i = 0; i < l; i++) {
1077 cpu_stb_secondary(env, a1 + i, cpu_ldub_primary(env, a2 + i));
1083 uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1087 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1088 __func__, l, a1, a2);
1096 /* XXX replace w/ memcpy */
1097 for (i = 0; i < l; i++) {
1098 cpu_stb_primary(env, a1 + i, cpu_ldub_secondary(env, a2 + i));
1104 /* invalidate pte */
1105 void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr)
1107 CPUState *cs = CPU(s390_env_get_cpu(env));
1108 uint64_t page = vaddr & TARGET_PAGE_MASK;
1111 /* XXX broadcast to other CPUs */
1113 /* XXX Linux is nice enough to give us the exact pte address.
1114 According to spec we'd have to find it out ourselves */
1115 /* XXX Linux is fine with overwriting the pte, the spec requires
1116 us to only set the invalid bit */
1117 stq_phys(cs->as, pte_addr, pte | _PAGE_INVALID);
1119 /* XXX we exploit the fact that Linux passes the exact virtual
1120 address here - it's not obliged to! */
1121 tlb_flush_page(cs, page);
1123 /* XXX 31-bit hack */
1124 if (page & 0x80000000) {
1125 tlb_flush_page(cs, page & ~0x80000000);
1127 tlb_flush_page(cs, page | 0x80000000);
1131 /* flush local tlb */
1132 void HELPER(ptlb)(CPUS390XState *env)
1134 S390CPU *cpu = s390_env_get_cpu(env);
1136 tlb_flush(CPU(cpu));
1139 /* load using real address */
1140 uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr)
1142 CPUState *cs = CPU(s390_env_get_cpu(env));
1144 return (uint32_t)ldl_phys(cs->as, get_address(env, 0, 0, addr));
1147 uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr)
1149 CPUState *cs = CPU(s390_env_get_cpu(env));
1151 return ldq_phys(cs->as, get_address(env, 0, 0, addr));
1154 /* store using real address */
1155 void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
1157 CPUState *cs = CPU(s390_env_get_cpu(env));
1159 stl_phys(cs->as, get_address(env, 0, 0, addr), (uint32_t)v1);
1161 if ((env->psw.mask & PSW_MASK_PER) &&
1162 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
1163 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
1164 /* PSW is saved just before calling the helper. */
1165 env->per_address = env->psw.addr;
1166 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
1170 void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
1172 CPUState *cs = CPU(s390_env_get_cpu(env));
1174 stq_phys(cs->as, get_address(env, 0, 0, addr), v1);
1176 if ((env->psw.mask & PSW_MASK_PER) &&
1177 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
1178 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
1179 /* PSW is saved just before calling the helper. */
1180 env->per_address = env->psw.addr;
1181 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
1185 /* load real address */
1186 uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
1188 CPUState *cs = CPU(s390_env_get_cpu(env));
1190 int old_exc = cs->exception_index;
1191 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1195 /* XXX incomplete - has more corner cases */
1196 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1197 program_interrupt(env, PGM_SPECIAL_OP, 2);
1200 cs->exception_index = old_exc;
1201 if (mmu_translate(env, addr, 0, asc, &ret, &flags, true)) {
1204 if (cs->exception_index == EXCP_PGM) {
1205 ret = env->int_pgm_code | 0x80000000;
1207 ret |= addr & ~TARGET_PAGE_MASK;
1209 cs->exception_index = old_exc;
1216 /* execute instruction
1217 this instruction executes an insn modified with the contents of r1
1218 it does not change the executed instruction in memory
1219 it does not change the program counter
1220 in other words: tricky...
1221 currently implemented by interpreting the cases it is most commonly used.
1223 uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1,
1224 uint64_t addr, uint64_t ret)
1226 S390CPU *cpu = s390_env_get_cpu(env);
1227 uint16_t insn = cpu_lduw_code(env, addr);
1229 HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
1231 if ((insn & 0xf0ff) == 0xd000) {
1232 uint32_t l, insn2, b1, b2, d1, d2;
1235 insn2 = cpu_ldl_code(env, addr + 2);
1236 b1 = (insn2 >> 28) & 0xf;
1237 b2 = (insn2 >> 12) & 0xf;
1238 d1 = (insn2 >> 16) & 0xfff;
1240 switch (insn & 0xf00) {
1242 do_helper_mvc(env, l, get_address(env, 0, b1, d1),
1243 get_address(env, 0, b2, d2), 0);
1246 cc = do_helper_nc(env, l, get_address(env, 0, b1, d1),
1247 get_address(env, 0, b2, d2), 0);
1250 cc = do_helper_clc(env, l, get_address(env, 0, b1, d1),
1251 get_address(env, 0, b2, d2), 0);
1254 cc = do_helper_oc(env, l, get_address(env, 0, b1, d1),
1255 get_address(env, 0, b2, d2), 0);
1258 cc = do_helper_xc(env, l, get_address(env, 0, b1, d1),
1259 get_address(env, 0, b2, d2), 0);
1262 helper_tr(env, l, get_address(env, 0, b1, d1),
1263 get_address(env, 0, b2, d2));
1266 cc = helper_trt(env, l, get_address(env, 0, b1, d1),
1267 get_address(env, 0, b2, d2));
1272 } else if ((insn & 0xff00) == 0x0a00) {
1273 /* supervisor call */
1274 HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff);
1275 env->psw.addr = ret - 4;
1276 env->int_svc_code = (insn | v1) & 0xff;
1277 env->int_svc_ilen = 4;
1278 helper_exception(env, EXCP_SVC);
1279 } else if ((insn & 0xff00) == 0xbf00) {
1280 uint32_t insn2, r1, r3, b2, d2;
1282 insn2 = cpu_ldl_code(env, addr + 2);
1283 r1 = (insn2 >> 20) & 0xf;
1284 r3 = (insn2 >> 16) & 0xf;
1285 b2 = (insn2 >> 12) & 0xf;
1287 cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3);
1291 "EXECUTE on instruction prefix 0x%x not implemented\n",