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 uint64_t HELPER(csg)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3)
462 /* FIXME: locking? */
463 uint64_t v2 = cpu_ldq_data(env, a2);
465 cpu_stq_data(env, a2, r3);
474 /* compare double and swap 64-bit */
475 uint32_t HELPER(cdsg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
477 /* FIXME: locking? */
479 uint64_t v2_hi = cpu_ldq_data(env, a2);
480 uint64_t v2_lo = cpu_ldq_data(env, a2 + 8);
481 uint64_t v1_hi = env->regs[r1];
482 uint64_t v1_lo = env->regs[r1 + 1];
484 if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
486 cpu_stq_data(env, a2, env->regs[r3]);
487 cpu_stq_data(env, a2 + 8, env->regs[r3 + 1]);
490 env->regs[r1] = v2_hi;
491 env->regs[r1 + 1] = v2_lo;
497 /* compare and swap 32-bit */
498 uint64_t HELPER(cs)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3)
500 /* FIXME: locking? */
501 uint32_t v2 = cpu_ldl_data(env, a2);
502 if ((uint32_t)r1 == v2) {
503 cpu_stl_data(env, a2, (uint32_t)r3);
512 static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address,
515 int pos = 24; /* top of the lower half of r1 */
516 uint64_t rmask = 0xff000000ULL;
523 env->regs[r1] &= ~rmask;
524 val = cpu_ldub_data(env, address);
525 if ((val & 0x80) && !ccd) {
529 if (val && cc == 0) {
532 env->regs[r1] |= (uint64_t)val << pos;
535 mask = (mask << 1) & 0xf;
543 /* execute instruction
544 this instruction executes an insn modified with the contents of r1
545 it does not change the executed instruction in memory
546 it does not change the program counter
547 in other words: tricky...
548 currently implemented by interpreting the cases it is most commonly used in
550 uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1,
551 uint64_t addr, uint64_t ret)
553 uint16_t insn = cpu_lduw_code(env, addr);
555 HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
557 if ((insn & 0xf0ff) == 0xd000) {
558 uint32_t l, insn2, b1, b2, d1, d2;
561 insn2 = cpu_ldl_code(env, addr + 2);
562 b1 = (insn2 >> 28) & 0xf;
563 b2 = (insn2 >> 12) & 0xf;
564 d1 = (insn2 >> 16) & 0xfff;
566 switch (insn & 0xf00) {
568 helper_mvc(env, l, get_address(env, 0, b1, d1),
569 get_address(env, 0, b2, d2));
572 cc = helper_clc(env, l, get_address(env, 0, b1, d1),
573 get_address(env, 0, b2, d2));
576 cc = helper_xc(env, l, get_address(env, 0, b1, d1),
577 get_address(env, 0, b2, d2));
580 helper_tr(env, l, get_address(env, 0, b1, d1),
581 get_address(env, 0, b2, d2));
587 } else if ((insn & 0xff00) == 0x0a00) {
588 /* supervisor call */
589 HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff);
590 env->psw.addr = ret - 4;
591 env->int_svc_code = (insn | v1) & 0xff;
592 env->int_svc_ilen = 4;
593 helper_exception(env, EXCP_SVC);
594 } else if ((insn & 0xff00) == 0xbf00) {
595 uint32_t insn2, r1, r3, b2, d2;
597 insn2 = cpu_ldl_code(env, addr + 2);
598 r1 = (insn2 >> 20) & 0xf;
599 r3 = (insn2 >> 16) & 0xf;
600 b2 = (insn2 >> 12) & 0xf;
602 cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3);
605 cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
611 /* store character under mask high operates on the upper half of r1 */
612 void HELPER(stcmh)(CPUS390XState *env, uint32_t r1, uint64_t address,
615 int pos = 56; /* top of the upper half of r1 */
619 cpu_stb_data(env, address, (env->regs[r1] >> pos) & 0xff);
622 mask = (mask << 1) & 0xf;
627 /* load access registers r1 to r3 from memory at a2 */
628 void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
632 for (i = r1;; i = (i + 1) % 16) {
633 env->aregs[i] = cpu_ldl_data(env, a2);
642 /* store access registers r1 to r3 in memory at a2 */
643 void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
647 for (i = r1;; i = (i + 1) % 16) {
648 cpu_stl_data(env, a2, env->aregs[i]);
658 uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
660 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
661 uint64_t dest = get_address_31fix(env, r1);
662 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
663 uint64_t src = get_address_31fix(env, r2);
664 uint8_t pad = src >> 24;
668 if (destlen == srclen) {
670 } else if (destlen < srclen) {
676 if (srclen > destlen) {
680 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
681 v = cpu_ldub_data(env, src);
682 cpu_stb_data(env, dest, v);
685 for (; destlen; dest++, destlen--) {
686 cpu_stb_data(env, dest, pad);
689 env->regs[r1 + 1] = destlen;
690 /* can't use srclen here, we trunc'ed it */
691 env->regs[r2 + 1] -= src - env->regs[r2];
692 env->regs[r1] = dest;
698 /* move long extended another memcopy insn with more bells and whistles */
699 uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
702 uint64_t destlen = env->regs[r1 + 1];
703 uint64_t dest = env->regs[r1];
704 uint64_t srclen = env->regs[r3 + 1];
705 uint64_t src = env->regs[r3];
706 uint8_t pad = a2 & 0xff;
710 if (!(env->psw.mask & PSW_MASK_64)) {
711 destlen = (uint32_t)destlen;
712 srclen = (uint32_t)srclen;
717 if (destlen == srclen) {
719 } else if (destlen < srclen) {
725 if (srclen > destlen) {
729 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
730 v = cpu_ldub_data(env, src);
731 cpu_stb_data(env, dest, v);
734 for (; destlen; dest++, destlen--) {
735 cpu_stb_data(env, dest, pad);
738 env->regs[r1 + 1] = destlen;
739 /* can't use srclen here, we trunc'ed it */
740 /* FIXME: 31-bit mode! */
741 env->regs[r3 + 1] -= src - env->regs[r3];
742 env->regs[r1] = dest;
748 /* compare logical long extended memcompare insn with padding */
749 uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
752 uint64_t destlen = env->regs[r1 + 1];
753 uint64_t dest = get_address_31fix(env, r1);
754 uint64_t srclen = env->regs[r3 + 1];
755 uint64_t src = get_address_31fix(env, r3);
756 uint8_t pad = a2 & 0xff;
757 uint8_t v1 = 0, v2 = 0;
760 if (!(destlen || srclen)) {
764 if (srclen > destlen) {
768 for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
769 v1 = srclen ? cpu_ldub_data(env, src) : pad;
770 v2 = destlen ? cpu_ldub_data(env, dest) : pad;
772 cc = (v1 < v2) ? 1 : 2;
777 env->regs[r1 + 1] = destlen;
778 /* can't use srclen here, we trunc'ed it */
779 env->regs[r3 + 1] -= src - env->regs[r3];
780 env->regs[r1] = dest;
787 void HELPER(cksm)(CPUS390XState *env, uint32_t r1, uint32_t r2)
789 uint64_t src = get_address_31fix(env, r2);
790 uint64_t src_len = env->regs[(r2 + 1) & 15];
791 uint64_t cksm = (uint32_t)env->regs[r1];
793 while (src_len >= 4) {
794 cksm += cpu_ldl_data(env, src);
796 /* move to next word */
805 cksm += cpu_ldub_data(env, src) << 24;
808 cksm += cpu_lduw_data(env, src) << 16;
811 cksm += cpu_lduw_data(env, src) << 16;
812 cksm += cpu_ldub_data(env, src + 2) << 8;
816 /* indicate we've processed everything */
817 env->regs[r2] = src + src_len;
818 env->regs[(r2 + 1) & 15] = 0;
821 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
822 ((uint32_t)cksm + (cksm >> 32));
825 void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
828 int len_dest = len >> 4;
829 int len_src = len & 0xf;
831 int second_nibble = 0;
836 /* last byte is special, it only flips the nibbles */
837 b = cpu_ldub_data(env, src);
838 cpu_stb_data(env, dest, (b << 4) | (b >> 4));
842 /* now pad every nibble with 0xf0 */
844 while (len_dest > 0) {
845 uint8_t cur_byte = 0;
848 cur_byte = cpu_ldub_data(env, src);
854 /* only advance one nibble at a time */
860 second_nibble = !second_nibble;
863 cur_byte = (cur_byte & 0xf);
867 cpu_stb_data(env, dest, cur_byte);
871 void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
876 for (i = 0; i <= len; i++) {
877 uint8_t byte = cpu_ldub_data(env, array + i);
878 uint8_t new_byte = cpu_ldub_data(env, trans + byte);
880 cpu_stb_data(env, array + i, new_byte);
884 #if !defined(CONFIG_USER_ONLY)
885 void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
890 for (i = r1;; i = (i + 1) % 16) {
891 env->cregs[i] = cpu_ldq_data(env, src);
892 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
893 i, src, env->cregs[i]);
894 src += sizeof(uint64_t);
904 void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
909 for (i = r1;; i = (i + 1) % 16) {
910 env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) |
911 cpu_ldl_data(env, src);
912 src += sizeof(uint32_t);
922 void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
927 for (i = r1;; i = (i + 1) % 16) {
928 cpu_stq_data(env, dest, env->cregs[i]);
929 dest += sizeof(uint64_t);
937 void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
942 for (i = r1;; i = (i + 1) % 16) {
943 cpu_stl_data(env, dest, env->cregs[i]);
944 dest += sizeof(uint32_t);
952 uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
959 /* insert storage key extended */
960 uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
962 uint64_t addr = get_address(env, 0, 0, r2);
964 if (addr > ram_size) {
968 return env->storage_keys[addr / TARGET_PAGE_SIZE];
971 /* set storage key extended */
972 void HELPER(sske)(CPUS390XState *env, uint32_t r1, uint64_t r2)
974 uint64_t addr = get_address(env, 0, 0, r2);
976 if (addr > ram_size) {
980 env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
983 /* reset reference bit extended */
984 uint32_t HELPER(rrbe)(CPUS390XState *env, uint32_t r1, uint64_t r2)
993 key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
994 re = key & (SK_R | SK_C);
995 env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
1000 * 0 Reference bit zero; change bit zero
1001 * 1 Reference bit zero; change bit one
1002 * 2 Reference bit one; change bit zero
1003 * 3 Reference bit one; change bit one
1009 /* compare and swap and purge */
1010 uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint32_t r2)
1013 uint32_t o1 = env->regs[r1];
1014 uint64_t a2 = get_address_31fix(env, r2) & ~3ULL;
1015 uint32_t o2 = cpu_ldl_data(env, a2);
1018 cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]);
1019 if (env->regs[r2] & 0x3) {
1020 /* flush TLB / ALB */
1025 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
1032 static uint32_t mvc_asc(CPUS390XState *env, int64_t l, uint64_t a1,
1033 uint64_t mode1, uint64_t a2, uint64_t mode2)
1035 target_ulong src, dest;
1036 int flags, cc = 0, i;
1040 } else if (l > 256) {
1046 if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
1049 dest |= a1 & ~TARGET_PAGE_MASK;
1051 if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
1054 src |= a2 & ~TARGET_PAGE_MASK;
1056 /* XXX replace w/ memcpy */
1057 for (i = 0; i < l; i++) {
1058 /* XXX be more clever */
1059 if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
1060 (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
1061 mvc_asc(env, l - i, a1 + i, mode1, a2 + i, mode2);
1064 stb_phys(dest + i, ldub_phys(src + i));
1070 uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1072 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1073 __func__, l, a1, a2);
1075 return mvc_asc(env, l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
1078 uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1080 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1081 __func__, l, a1, a2);
1083 return mvc_asc(env, l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
1086 /* invalidate pte */
1087 void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr)
1089 uint64_t page = vaddr & TARGET_PAGE_MASK;
1092 /* XXX broadcast to other CPUs */
1094 /* XXX Linux is nice enough to give us the exact pte address.
1095 According to spec we'd have to find it out ourselves */
1096 /* XXX Linux is fine with overwriting the pte, the spec requires
1097 us to only set the invalid bit */
1098 stq_phys(pte_addr, pte | _PAGE_INVALID);
1100 /* XXX we exploit the fact that Linux passes the exact virtual
1101 address here - it's not obliged to! */
1102 tlb_flush_page(env, page);
1104 /* XXX 31-bit hack */
1105 if (page & 0x80000000) {
1106 tlb_flush_page(env, page & ~0x80000000);
1108 tlb_flush_page(env, page | 0x80000000);
1112 /* flush local tlb */
1113 void HELPER(ptlb)(CPUS390XState *env)
1118 /* store using real address */
1119 void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint32_t v1)
1121 stw_phys(get_address(env, 0, 0, addr), v1);
1124 /* load real address */
1125 uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
1128 int old_exc = env->exception_index;
1129 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1133 /* XXX incomplete - has more corner cases */
1134 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1135 program_interrupt(env, PGM_SPECIAL_OP, 2);
1138 env->exception_index = old_exc;
1139 if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
1142 if (env->exception_index == EXCP_PGM) {
1143 ret = env->int_pgm_code | 0x80000000;
1145 ret |= addr & ~TARGET_PAGE_MASK;
1147 env->exception_index = old_exc;