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/>.
24 /*****************************************************************************/
26 #if !defined(CONFIG_USER_ONLY)
27 #include "exec/softmmu_exec.h"
29 #define MMUSUFFIX _mmu
32 #include "exec/softmmu_template.h"
35 #include "exec/softmmu_template.h"
38 #include "exec/softmmu_template.h"
41 #include "exec/softmmu_template.h"
43 /* try to fill the TLB and return an exception if error. If retaddr is
44 NULL, it means that the function was called in C code (i.e. not
45 from generated code or from helper.c) */
46 /* XXX: fix it to restore all registers */
47 void tlb_fill(CPUS390XState *env, target_ulong addr, int is_write, int mmu_idx,
52 ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
53 if (unlikely(ret != 0)) {
54 if (likely(retaddr)) {
55 /* now we have a real cpu fault */
56 cpu_restore_state(env, retaddr);
64 /* #define DEBUG_HELPER */
66 #define HELPER_LOG(x...) qemu_log(x)
68 #define HELPER_LOG(x...)
71 #ifndef CONFIG_USER_ONLY
72 static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest,
78 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
81 if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
82 cpu_stb_data(env, dest, byte);
83 cpu_abort(env, "should never reach here");
85 dest_phys |= dest & ~TARGET_PAGE_MASK;
87 dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
89 memset(dest_p, byte, len);
91 cpu_physical_memory_unmap(dest_p, 1, len, len);
94 static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest,
102 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
105 if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
106 cpu_stb_data(env, dest, 0);
107 cpu_abort(env, "should never reach here");
109 dest_phys |= dest & ~TARGET_PAGE_MASK;
111 if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) {
112 cpu_ldub_data(env, src);
113 cpu_abort(env, "should never reach here");
115 src_phys |= src & ~TARGET_PAGE_MASK;
117 dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
118 src_p = cpu_physical_memory_map(src_phys, &len, 0);
120 memmove(dest_p, src_p, len);
122 cpu_physical_memory_unmap(dest_p, 1, len, len);
123 cpu_physical_memory_unmap(src_p, 0, len, len);
128 uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
135 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
136 __func__, l, dest, src);
137 for (i = 0; i <= l; i++) {
138 x = cpu_ldub_data(env, dest + i) & cpu_ldub_data(env, src + i);
142 cpu_stb_data(env, dest + i, x);
148 uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
155 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
156 __func__, l, dest, src);
158 #ifndef CONFIG_USER_ONLY
159 /* xor with itself is the same as memset(0) */
160 if ((l > 32) && (src == dest) &&
161 (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) {
162 mvc_fast_memset(env, l + 1, dest, 0);
167 memset(g2h(dest), 0, l + 1);
172 for (i = 0; i <= l; i++) {
173 x = cpu_ldub_data(env, dest + i) ^ cpu_ldub_data(env, src + i);
177 cpu_stb_data(env, dest + i, x);
183 uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
190 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
191 __func__, l, dest, src);
192 for (i = 0; i <= l; i++) {
193 x = cpu_ldub_data(env, dest + i) | cpu_ldub_data(env, src + i);
197 cpu_stb_data(env, dest + i, x);
203 void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
207 uint32_t l_64 = (l + 1) / 8;
209 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
210 __func__, l, dest, src);
212 #ifndef CONFIG_USER_ONLY
214 (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) &&
215 (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) {
216 if (dest == (src + 1)) {
217 mvc_fast_memset(env, l + 1, dest, cpu_ldub_data(env, src));
219 } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
220 mvc_fast_memmove(env, l + 1, dest, src);
225 if (dest == (src + 1)) {
226 memset(g2h(dest), cpu_ldub_data(env, src), l + 1);
229 memmove(g2h(dest), g2h(src), l + 1);
234 /* handle the parts that fit into 8-byte loads/stores */
235 if (dest != (src + 1)) {
236 for (i = 0; i < l_64; i++) {
237 cpu_stq_data(env, dest + x, cpu_ldq_data(env, src + x));
242 /* slow version crossing pages with byte accesses */
243 for (i = x; i <= l; i++) {
244 cpu_stb_data(env, dest + i, cpu_ldub_data(env, src + i));
248 /* compare unsigned byte arrays */
249 uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2)
255 HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
256 __func__, l, s1, s2);
257 for (i = 0; i <= l; i++) {
258 x = cpu_ldub_data(env, s1 + i);
259 y = cpu_ldub_data(env, s2 + i);
260 HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
275 /* compare logical under mask */
276 uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
282 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
287 d = cpu_ldub_data(env, addr);
288 r = (r1 & 0xff000000UL) >> 24;
289 HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
300 mask = (mask << 1) & 0xf;
307 /* store character under mask */
308 void HELPER(stcm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
313 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask,
317 r = (r1 & 0xff000000UL) >> 24;
318 cpu_stb_data(env, addr, r);
319 HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr);
322 mask = (mask << 1) & 0xf;
328 static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2)
341 if (!(env->psw.mask & PSW_MASK_64)) {
348 static inline uint64_t get_address_31fix(CPUS390XState *env, int reg)
350 uint64_t r = env->regs[reg];
353 if (!(env->psw.mask & PSW_MASK_64)) {
360 /* search string (c is byte to search, r2 is string, r1 end of string) */
361 uint32_t HELPER(srst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2)
365 uint64_t str = get_address_31fix(env, r2);
366 uint64_t end = get_address_31fix(env, r1);
368 HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__,
369 c, env->regs[r1], env->regs[r2]);
371 for (i = str; i != end; i++) {
372 if (cpu_ldub_data(env, i) == c) {
382 /* unsigned string compare (c is string terminator) */
383 uint32_t HELPER(clst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2)
385 uint64_t s1 = get_address_31fix(env, r1);
386 uint64_t s2 = get_address_31fix(env, r2);
391 #ifdef CONFIG_USER_ONLY
393 HELPER_LOG("%s: comparing '%s' and '%s'\n",
394 __func__, (char *)g2h(s1), (char *)g2h(s2));
398 v1 = cpu_ldub_data(env, s1);
399 v2 = cpu_ldub_data(env, s2);
400 if ((v1 == c || v2 == c) || (v1 != v2)) {
410 cc = (v1 < v2) ? 1 : 2;
411 /* FIXME: 31-bit mode! */
419 void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
421 /* XXX missing r0 handling */
422 #ifdef CONFIG_USER_ONLY
425 for (i = 0; i < TARGET_PAGE_SIZE; i++) {
426 cpu_stb_data(env, r1 + i, cpu_ldub_data(env, r2 + i));
429 mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
433 /* string copy (c is string terminator) */
434 void HELPER(mvst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2)
436 uint64_t dest = get_address_31fix(env, r1);
437 uint64_t src = get_address_31fix(env, r2);
441 #ifdef CONFIG_USER_ONLY
443 HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src),
448 v = cpu_ldub_data(env, src);
449 cpu_stb_data(env, dest, v);
456 env->regs[r1] = dest; /* FIXME: 31-bit mode! */
459 /* compare and swap 64-bit */
460 uint32_t HELPER(csg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
462 /* FIXME: locking? */
464 uint64_t v2 = cpu_ldq_data(env, a2);
466 if (env->regs[r1] == v2) {
468 cpu_stq_data(env, a2, env->regs[r3]);
476 /* compare double and swap 64-bit */
477 uint32_t HELPER(cdsg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
479 /* FIXME: locking? */
481 uint64_t v2_hi = cpu_ldq_data(env, a2);
482 uint64_t v2_lo = cpu_ldq_data(env, a2 + 8);
483 uint64_t v1_hi = env->regs[r1];
484 uint64_t v1_lo = env->regs[r1 + 1];
486 if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
488 cpu_stq_data(env, a2, env->regs[r3]);
489 cpu_stq_data(env, a2 + 8, env->regs[r3 + 1]);
492 env->regs[r1] = v2_hi;
493 env->regs[r1 + 1] = v2_lo;
499 /* compare and swap 32-bit */
500 uint32_t HELPER(cs)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
502 /* FIXME: locking? */
504 uint32_t v2 = cpu_ldl_data(env, a2);
506 HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3);
507 if (((uint32_t)env->regs[r1]) == v2) {
509 cpu_stl_data(env, a2, (uint32_t)env->regs[r3]);
512 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2;
517 static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address,
520 int pos = 24; /* top of the lower half of r1 */
521 uint64_t rmask = 0xff000000ULL;
528 env->regs[r1] &= ~rmask;
529 val = cpu_ldub_data(env, address);
530 if ((val & 0x80) && !ccd) {
534 if (val && cc == 0) {
537 env->regs[r1] |= (uint64_t)val << pos;
540 mask = (mask << 1) & 0xf;
548 /* execute instruction
549 this instruction executes an insn modified with the contents of r1
550 it does not change the executed instruction in memory
551 it does not change the program counter
552 in other words: tricky...
553 currently implemented by interpreting the cases it is most commonly used in
555 uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1,
556 uint64_t addr, uint64_t ret)
558 uint16_t insn = cpu_lduw_code(env, addr);
560 HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
562 if ((insn & 0xf0ff) == 0xd000) {
563 uint32_t l, insn2, b1, b2, d1, d2;
566 insn2 = cpu_ldl_code(env, addr + 2);
567 b1 = (insn2 >> 28) & 0xf;
568 b2 = (insn2 >> 12) & 0xf;
569 d1 = (insn2 >> 16) & 0xfff;
571 switch (insn & 0xf00) {
573 helper_mvc(env, l, get_address(env, 0, b1, d1),
574 get_address(env, 0, b2, d2));
577 cc = helper_clc(env, l, get_address(env, 0, b1, d1),
578 get_address(env, 0, b2, d2));
581 cc = helper_xc(env, l, get_address(env, 0, b1, d1),
582 get_address(env, 0, b2, d2));
585 helper_tr(env, l, get_address(env, 0, b1, d1),
586 get_address(env, 0, b2, d2));
592 } else if ((insn & 0xff00) == 0x0a00) {
593 /* supervisor call */
594 HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff);
595 env->psw.addr = ret - 4;
596 env->int_svc_code = (insn | v1) & 0xff;
597 env->int_svc_ilen = 4;
598 helper_exception(env, EXCP_SVC);
599 } else if ((insn & 0xff00) == 0xbf00) {
600 uint32_t insn2, r1, r3, b2, d2;
602 insn2 = cpu_ldl_code(env, addr + 2);
603 r1 = (insn2 >> 20) & 0xf;
604 r3 = (insn2 >> 16) & 0xf;
605 b2 = (insn2 >> 12) & 0xf;
607 cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3);
610 cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
616 /* store character under mask high operates on the upper half of r1 */
617 void HELPER(stcmh)(CPUS390XState *env, uint32_t r1, uint64_t address,
620 int pos = 56; /* top of the upper half of r1 */
624 cpu_stb_data(env, address, (env->regs[r1] >> pos) & 0xff);
627 mask = (mask << 1) & 0xf;
632 /* load access registers r1 to r3 from memory at a2 */
633 void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
637 for (i = r1;; i = (i + 1) % 16) {
638 env->aregs[i] = cpu_ldl_data(env, a2);
647 /* store access registers r1 to r3 in memory at a2 */
648 void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
652 for (i = r1;; i = (i + 1) % 16) {
653 cpu_stl_data(env, a2, env->aregs[i]);
663 uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
665 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
666 uint64_t dest = get_address_31fix(env, r1);
667 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
668 uint64_t src = get_address_31fix(env, r2);
669 uint8_t pad = src >> 24;
673 if (destlen == srclen) {
675 } else if (destlen < srclen) {
681 if (srclen > destlen) {
685 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
686 v = cpu_ldub_data(env, src);
687 cpu_stb_data(env, dest, v);
690 for (; destlen; dest++, destlen--) {
691 cpu_stb_data(env, dest, pad);
694 env->regs[r1 + 1] = destlen;
695 /* can't use srclen here, we trunc'ed it */
696 env->regs[r2 + 1] -= src - env->regs[r2];
697 env->regs[r1] = dest;
703 /* move long extended another memcopy insn with more bells and whistles */
704 uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
707 uint64_t destlen = env->regs[r1 + 1];
708 uint64_t dest = env->regs[r1];
709 uint64_t srclen = env->regs[r3 + 1];
710 uint64_t src = env->regs[r3];
711 uint8_t pad = a2 & 0xff;
715 if (!(env->psw.mask & PSW_MASK_64)) {
716 destlen = (uint32_t)destlen;
717 srclen = (uint32_t)srclen;
722 if (destlen == srclen) {
724 } else if (destlen < srclen) {
730 if (srclen > destlen) {
734 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
735 v = cpu_ldub_data(env, src);
736 cpu_stb_data(env, dest, v);
739 for (; destlen; dest++, destlen--) {
740 cpu_stb_data(env, dest, pad);
743 env->regs[r1 + 1] = destlen;
744 /* can't use srclen here, we trunc'ed it */
745 /* FIXME: 31-bit mode! */
746 env->regs[r3 + 1] -= src - env->regs[r3];
747 env->regs[r1] = dest;
753 /* compare logical long extended memcompare insn with padding */
754 uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
757 uint64_t destlen = env->regs[r1 + 1];
758 uint64_t dest = get_address_31fix(env, r1);
759 uint64_t srclen = env->regs[r3 + 1];
760 uint64_t src = get_address_31fix(env, r3);
761 uint8_t pad = a2 & 0xff;
762 uint8_t v1 = 0, v2 = 0;
765 if (!(destlen || srclen)) {
769 if (srclen > destlen) {
773 for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
774 v1 = srclen ? cpu_ldub_data(env, src) : pad;
775 v2 = destlen ? cpu_ldub_data(env, dest) : pad;
777 cc = (v1 < v2) ? 1 : 2;
782 env->regs[r1 + 1] = destlen;
783 /* can't use srclen here, we trunc'ed it */
784 env->regs[r3 + 1] -= src - env->regs[r3];
785 env->regs[r1] = dest;
792 void HELPER(cksm)(CPUS390XState *env, uint32_t r1, uint32_t r2)
794 uint64_t src = get_address_31fix(env, r2);
795 uint64_t src_len = env->regs[(r2 + 1) & 15];
796 uint64_t cksm = (uint32_t)env->regs[r1];
798 while (src_len >= 4) {
799 cksm += cpu_ldl_data(env, src);
801 /* move to next word */
810 cksm += cpu_ldub_data(env, src) << 24;
813 cksm += cpu_lduw_data(env, src) << 16;
816 cksm += cpu_lduw_data(env, src) << 16;
817 cksm += cpu_ldub_data(env, src + 2) << 8;
821 /* indicate we've processed everything */
822 env->regs[r2] = src + src_len;
823 env->regs[(r2 + 1) & 15] = 0;
826 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
827 ((uint32_t)cksm + (cksm >> 32));
830 void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
833 int len_dest = len >> 4;
834 int len_src = len & 0xf;
836 int second_nibble = 0;
841 /* last byte is special, it only flips the nibbles */
842 b = cpu_ldub_data(env, src);
843 cpu_stb_data(env, dest, (b << 4) | (b >> 4));
847 /* now pad every nibble with 0xf0 */
849 while (len_dest > 0) {
850 uint8_t cur_byte = 0;
853 cur_byte = cpu_ldub_data(env, src);
859 /* only advance one nibble at a time */
865 second_nibble = !second_nibble;
868 cur_byte = (cur_byte & 0xf);
872 cpu_stb_data(env, dest, cur_byte);
876 void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
881 for (i = 0; i <= len; i++) {
882 uint8_t byte = cpu_ldub_data(env, array + i);
883 uint8_t new_byte = cpu_ldub_data(env, trans + byte);
885 cpu_stb_data(env, array + i, new_byte);
889 #if !defined(CONFIG_USER_ONLY)
890 void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
895 for (i = r1;; i = (i + 1) % 16) {
896 env->cregs[i] = cpu_ldq_data(env, src);
897 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
898 i, src, env->cregs[i]);
899 src += sizeof(uint64_t);
909 void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
914 for (i = r1;; i = (i + 1) % 16) {
915 env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) |
916 cpu_ldl_data(env, src);
917 src += sizeof(uint32_t);
927 void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
932 for (i = r1;; i = (i + 1) % 16) {
933 cpu_stq_data(env, dest, env->cregs[i]);
934 dest += sizeof(uint64_t);
942 void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
947 for (i = r1;; i = (i + 1) % 16) {
948 cpu_stl_data(env, dest, env->cregs[i]);
949 dest += sizeof(uint32_t);
957 uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
964 /* insert storage key extended */
965 uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
967 uint64_t addr = get_address(env, 0, 0, r2);
969 if (addr > ram_size) {
973 return env->storage_keys[addr / TARGET_PAGE_SIZE];
976 /* set storage key extended */
977 void HELPER(sske)(CPUS390XState *env, uint32_t r1, uint64_t r2)
979 uint64_t addr = get_address(env, 0, 0, r2);
981 if (addr > ram_size) {
985 env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
988 /* reset reference bit extended */
989 uint32_t HELPER(rrbe)(CPUS390XState *env, uint32_t r1, uint64_t r2)
998 key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
999 re = key & (SK_R | SK_C);
1000 env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
1005 * 0 Reference bit zero; change bit zero
1006 * 1 Reference bit zero; change bit one
1007 * 2 Reference bit one; change bit zero
1008 * 3 Reference bit one; change bit one
1014 /* compare and swap and purge */
1015 uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint32_t r2)
1018 uint32_t o1 = env->regs[r1];
1019 uint64_t a2 = get_address_31fix(env, r2) & ~3ULL;
1020 uint32_t o2 = cpu_ldl_data(env, a2);
1023 cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]);
1024 if (env->regs[r2] & 0x3) {
1025 /* flush TLB / ALB */
1030 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
1037 static uint32_t mvc_asc(CPUS390XState *env, int64_t l, uint64_t a1,
1038 uint64_t mode1, uint64_t a2, uint64_t mode2)
1040 target_ulong src, dest;
1041 int flags, cc = 0, i;
1045 } else if (l > 256) {
1051 if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
1054 dest |= a1 & ~TARGET_PAGE_MASK;
1056 if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
1059 src |= a2 & ~TARGET_PAGE_MASK;
1061 /* XXX replace w/ memcpy */
1062 for (i = 0; i < l; i++) {
1063 /* XXX be more clever */
1064 if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
1065 (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
1066 mvc_asc(env, l - i, a1 + i, mode1, a2 + i, mode2);
1069 stb_phys(dest + i, ldub_phys(src + i));
1075 uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1077 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1078 __func__, l, a1, a2);
1080 return mvc_asc(env, l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
1083 uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1085 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1086 __func__, l, a1, a2);
1088 return mvc_asc(env, l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
1091 /* invalidate pte */
1092 void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr)
1094 uint64_t page = vaddr & TARGET_PAGE_MASK;
1097 /* XXX broadcast to other CPUs */
1099 /* XXX Linux is nice enough to give us the exact pte address.
1100 According to spec we'd have to find it out ourselves */
1101 /* XXX Linux is fine with overwriting the pte, the spec requires
1102 us to only set the invalid bit */
1103 stq_phys(pte_addr, pte | _PAGE_INVALID);
1105 /* XXX we exploit the fact that Linux passes the exact virtual
1106 address here - it's not obliged to! */
1107 tlb_flush_page(env, page);
1109 /* XXX 31-bit hack */
1110 if (page & 0x80000000) {
1111 tlb_flush_page(env, page & ~0x80000000);
1113 tlb_flush_page(env, page | 0x80000000);
1117 /* flush local tlb */
1118 void HELPER(ptlb)(CPUS390XState *env)
1123 /* store using real address */
1124 void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint32_t v1)
1126 stw_phys(get_address(env, 0, 0, addr), v1);
1129 /* load real address */
1130 uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
1133 int old_exc = env->exception_index;
1134 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1138 /* XXX incomplete - has more corner cases */
1139 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1140 program_interrupt(env, PGM_SPECIAL_OP, 2);
1143 env->exception_index = old_exc;
1144 if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
1147 if (env->exception_index == EXCP_PGM) {
1148 ret = env->int_pgm_code | 0x80000000;
1150 ret |= addr & ~TARGET_PAGE_MASK;
1152 env->exception_index = old_exc;