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 static inline uint64_t fix_address(CPUS390XState *env, uint64_t a)
310 if (!(env->psw.mask & PSW_MASK_64)) {
316 static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2)
325 return fix_address(env, r);
328 static inline uint64_t get_address_31fix(CPUS390XState *env, int reg)
330 return fix_address(env, env->regs[reg]);
333 /* search string (c is byte to search, r2 is string, r1 end of string) */
334 uint32_t HELPER(srst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2)
338 uint64_t str = get_address_31fix(env, r2);
339 uint64_t end = get_address_31fix(env, r1);
341 HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__,
342 c, env->regs[r1], env->regs[r2]);
344 for (i = str; i != end; i++) {
345 if (cpu_ldub_data(env, i) == c) {
355 /* unsigned string compare (c is string terminator) */
356 uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
361 s1 = fix_address(env, s1);
362 s2 = fix_address(env, s2);
364 /* Lest we fail to service interrupts in a timely manner, limit the
365 amount of work we're willing to do. For now, lets cap at 8k. */
366 for (len = 0; len < 0x2000; ++len) {
367 uint8_t v1 = cpu_ldub_data(env, s1 + len);
368 uint8_t v2 = cpu_ldub_data(env, s2 + len);
371 /* Equal. CC=0, and don't advance the registers. */
377 /* Unequal. CC={1,2}, and advance the registers. Note that
378 the terminator need not be zero, but the string that contains
379 the terminator is by definition "low". */
380 env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2);
381 env->retxl = s2 + len;
386 /* CPU-determined bytes equal; advance the registers. */
388 env->retxl = s2 + len;
393 void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
395 /* XXX missing r0 handling */
397 #ifdef CONFIG_USER_ONLY
398 memmove(g2h(r1), g2h(r2), TARGET_PAGE_SIZE);
400 mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
404 /* string copy (c is string terminator) */
405 uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s)
410 d = fix_address(env, d);
411 s = fix_address(env, s);
413 /* Lest we fail to service interrupts in a timely manner, limit the
414 amount of work we're willing to do. For now, lets cap at 8k. */
415 for (len = 0; len < 0x2000; ++len) {
416 uint8_t v = cpu_ldub_data(env, s + len);
417 cpu_stb_data(env, d + len, v);
419 /* Complete. Set CC=1 and advance R1. */
426 /* Incomplete. Set CC=3 and signal to advance R1 and R2. */
428 env->retxl = s + len;
432 /* compare and swap 64-bit */
433 uint64_t HELPER(csg)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3)
435 /* FIXME: locking? */
436 uint64_t v2 = cpu_ldq_data(env, a2);
438 cpu_stq_data(env, a2, r3);
447 /* compare double and swap 64-bit */
448 uint32_t HELPER(cdsg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
450 /* FIXME: locking? */
452 uint64_t v2_hi = cpu_ldq_data(env, a2);
453 uint64_t v2_lo = cpu_ldq_data(env, a2 + 8);
454 uint64_t v1_hi = env->regs[r1];
455 uint64_t v1_lo = env->regs[r1 + 1];
457 if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
459 cpu_stq_data(env, a2, env->regs[r3]);
460 cpu_stq_data(env, a2 + 8, env->regs[r3 + 1]);
463 env->regs[r1] = v2_hi;
464 env->regs[r1 + 1] = v2_lo;
470 /* compare and swap 32-bit */
471 uint64_t HELPER(cs)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3)
473 /* FIXME: locking? */
474 uint32_t v2 = cpu_ldl_data(env, a2);
475 if ((uint32_t)r1 == v2) {
476 cpu_stl_data(env, a2, (uint32_t)r3);
485 static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address,
488 int pos = 24; /* top of the lower half of r1 */
489 uint64_t rmask = 0xff000000ULL;
496 env->regs[r1] &= ~rmask;
497 val = cpu_ldub_data(env, address);
498 if ((val & 0x80) && !ccd) {
502 if (val && cc == 0) {
505 env->regs[r1] |= (uint64_t)val << pos;
508 mask = (mask << 1) & 0xf;
516 /* execute instruction
517 this instruction executes an insn modified with the contents of r1
518 it does not change the executed instruction in memory
519 it does not change the program counter
520 in other words: tricky...
521 currently implemented by interpreting the cases it is most commonly used in
523 uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1,
524 uint64_t addr, uint64_t ret)
526 uint16_t insn = cpu_lduw_code(env, addr);
528 HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
530 if ((insn & 0xf0ff) == 0xd000) {
531 uint32_t l, insn2, b1, b2, d1, d2;
534 insn2 = cpu_ldl_code(env, addr + 2);
535 b1 = (insn2 >> 28) & 0xf;
536 b2 = (insn2 >> 12) & 0xf;
537 d1 = (insn2 >> 16) & 0xfff;
539 switch (insn & 0xf00) {
541 helper_mvc(env, l, get_address(env, 0, b1, d1),
542 get_address(env, 0, b2, d2));
545 cc = helper_clc(env, l, get_address(env, 0, b1, d1),
546 get_address(env, 0, b2, d2));
549 cc = helper_xc(env, l, get_address(env, 0, b1, d1),
550 get_address(env, 0, b2, d2));
553 helper_tr(env, l, get_address(env, 0, b1, d1),
554 get_address(env, 0, b2, d2));
560 } else if ((insn & 0xff00) == 0x0a00) {
561 /* supervisor call */
562 HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff);
563 env->psw.addr = ret - 4;
564 env->int_svc_code = (insn | v1) & 0xff;
565 env->int_svc_ilen = 4;
566 helper_exception(env, EXCP_SVC);
567 } else if ((insn & 0xff00) == 0xbf00) {
568 uint32_t insn2, r1, r3, b2, d2;
570 insn2 = cpu_ldl_code(env, addr + 2);
571 r1 = (insn2 >> 20) & 0xf;
572 r3 = (insn2 >> 16) & 0xf;
573 b2 = (insn2 >> 12) & 0xf;
575 cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3);
578 cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
584 /* load access registers r1 to r3 from memory at a2 */
585 void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
589 for (i = r1;; i = (i + 1) % 16) {
590 env->aregs[i] = cpu_ldl_data(env, a2);
599 /* store access registers r1 to r3 in memory at a2 */
600 void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
604 for (i = r1;; i = (i + 1) % 16) {
605 cpu_stl_data(env, a2, env->aregs[i]);
615 uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
617 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
618 uint64_t dest = get_address_31fix(env, r1);
619 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
620 uint64_t src = get_address_31fix(env, r2);
621 uint8_t pad = src >> 24;
625 if (destlen == srclen) {
627 } else if (destlen < srclen) {
633 if (srclen > destlen) {
637 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
638 v = cpu_ldub_data(env, src);
639 cpu_stb_data(env, dest, v);
642 for (; destlen; dest++, destlen--) {
643 cpu_stb_data(env, dest, pad);
646 env->regs[r1 + 1] = destlen;
647 /* can't use srclen here, we trunc'ed it */
648 env->regs[r2 + 1] -= src - env->regs[r2];
649 env->regs[r1] = dest;
655 /* move long extended another memcopy insn with more bells and whistles */
656 uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
659 uint64_t destlen = env->regs[r1 + 1];
660 uint64_t dest = env->regs[r1];
661 uint64_t srclen = env->regs[r3 + 1];
662 uint64_t src = env->regs[r3];
663 uint8_t pad = a2 & 0xff;
667 if (!(env->psw.mask & PSW_MASK_64)) {
668 destlen = (uint32_t)destlen;
669 srclen = (uint32_t)srclen;
674 if (destlen == srclen) {
676 } else if (destlen < srclen) {
682 if (srclen > destlen) {
686 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
687 v = cpu_ldub_data(env, src);
688 cpu_stb_data(env, dest, v);
691 for (; destlen; dest++, destlen--) {
692 cpu_stb_data(env, dest, pad);
695 env->regs[r1 + 1] = destlen;
696 /* can't use srclen here, we trunc'ed it */
697 /* FIXME: 31-bit mode! */
698 env->regs[r3 + 1] -= src - env->regs[r3];
699 env->regs[r1] = dest;
705 /* compare logical long extended memcompare insn with padding */
706 uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
709 uint64_t destlen = env->regs[r1 + 1];
710 uint64_t dest = get_address_31fix(env, r1);
711 uint64_t srclen = env->regs[r3 + 1];
712 uint64_t src = get_address_31fix(env, r3);
713 uint8_t pad = a2 & 0xff;
714 uint8_t v1 = 0, v2 = 0;
717 if (!(destlen || srclen)) {
721 if (srclen > destlen) {
725 for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
726 v1 = srclen ? cpu_ldub_data(env, src) : pad;
727 v2 = destlen ? cpu_ldub_data(env, dest) : pad;
729 cc = (v1 < v2) ? 1 : 2;
734 env->regs[r1 + 1] = destlen;
735 /* can't use srclen here, we trunc'ed it */
736 env->regs[r3 + 1] -= src - env->regs[r3];
737 env->regs[r1] = dest;
744 uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
745 uint64_t src, uint64_t src_len)
747 uint64_t max_len, len;
748 uint64_t cksm = (uint32_t)r1;
750 /* Lest we fail to service interrupts in a timely manner, limit the
751 amount of work we're willing to do. For now, lets cap at 8k. */
752 max_len = (src_len > 0x2000 ? 0x2000 : src_len);
754 /* Process full words as available. */
755 for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
756 cksm += (uint32_t)cpu_ldl_data(env, src);
759 switch (max_len - len) {
761 cksm += cpu_ldub_data(env, src) << 24;
765 cksm += cpu_lduw_data(env, src) << 16;
769 cksm += cpu_lduw_data(env, src) << 16;
770 cksm += cpu_ldub_data(env, src + 2) << 8;
775 /* Fold the carry from the checksum. Note that we can see carry-out
776 during folding more than once (but probably not more than twice). */
777 while (cksm > 0xffffffffull) {
778 cksm = (uint32_t)cksm + (cksm >> 32);
781 /* Indicate whether or not we've processed everything. */
782 env->cc_op = (len == src_len ? 0 : 3);
784 /* Return both cksm and processed length. */
789 void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
792 int len_dest = len >> 4;
793 int len_src = len & 0xf;
795 int second_nibble = 0;
800 /* last byte is special, it only flips the nibbles */
801 b = cpu_ldub_data(env, src);
802 cpu_stb_data(env, dest, (b << 4) | (b >> 4));
806 /* now pad every nibble with 0xf0 */
808 while (len_dest > 0) {
809 uint8_t cur_byte = 0;
812 cur_byte = cpu_ldub_data(env, src);
818 /* only advance one nibble at a time */
824 second_nibble = !second_nibble;
827 cur_byte = (cur_byte & 0xf);
831 cpu_stb_data(env, dest, cur_byte);
835 void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
840 for (i = 0; i <= len; i++) {
841 uint8_t byte = cpu_ldub_data(env, array + i);
842 uint8_t new_byte = cpu_ldub_data(env, trans + byte);
844 cpu_stb_data(env, array + i, new_byte);
848 #if !defined(CONFIG_USER_ONLY)
849 void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
854 for (i = r1;; i = (i + 1) % 16) {
855 env->cregs[i] = cpu_ldq_data(env, src);
856 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
857 i, src, env->cregs[i]);
858 src += sizeof(uint64_t);
868 void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
873 for (i = r1;; i = (i + 1) % 16) {
874 env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) |
875 cpu_ldl_data(env, src);
876 src += sizeof(uint32_t);
886 void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
891 for (i = r1;; i = (i + 1) % 16) {
892 cpu_stq_data(env, dest, env->cregs[i]);
893 dest += sizeof(uint64_t);
901 void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
906 for (i = r1;; i = (i + 1) % 16) {
907 cpu_stl_data(env, dest, env->cregs[i]);
908 dest += sizeof(uint32_t);
916 uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
923 /* insert storage key extended */
924 uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
926 uint64_t addr = get_address(env, 0, 0, r2);
928 if (addr > ram_size) {
932 return env->storage_keys[addr / TARGET_PAGE_SIZE];
935 /* set storage key extended */
936 void HELPER(sske)(CPUS390XState *env, uint32_t r1, uint64_t r2)
938 uint64_t addr = get_address(env, 0, 0, r2);
940 if (addr > ram_size) {
944 env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
947 /* reset reference bit extended */
948 uint32_t HELPER(rrbe)(CPUS390XState *env, uint32_t r1, uint64_t r2)
957 key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
958 re = key & (SK_R | SK_C);
959 env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
964 * 0 Reference bit zero; change bit zero
965 * 1 Reference bit zero; change bit one
966 * 2 Reference bit one; change bit zero
967 * 3 Reference bit one; change bit one
973 /* compare and swap and purge */
974 uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint32_t r2)
977 uint32_t o1 = env->regs[r1];
978 uint64_t a2 = get_address_31fix(env, r2) & ~3ULL;
979 uint32_t o2 = cpu_ldl_data(env, a2);
982 cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]);
983 if (env->regs[r2] & 0x3) {
984 /* flush TLB / ALB */
989 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
996 static uint32_t mvc_asc(CPUS390XState *env, int64_t l, uint64_t a1,
997 uint64_t mode1, uint64_t a2, uint64_t mode2)
999 target_ulong src, dest;
1000 int flags, cc = 0, i;
1004 } else if (l > 256) {
1010 if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
1013 dest |= a1 & ~TARGET_PAGE_MASK;
1015 if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
1018 src |= a2 & ~TARGET_PAGE_MASK;
1020 /* XXX replace w/ memcpy */
1021 for (i = 0; i < l; i++) {
1022 /* XXX be more clever */
1023 if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
1024 (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
1025 mvc_asc(env, l - i, a1 + i, mode1, a2 + i, mode2);
1028 stb_phys(dest + i, ldub_phys(src + i));
1034 uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1036 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1037 __func__, l, a1, a2);
1039 return mvc_asc(env, l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
1042 uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1044 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1045 __func__, l, a1, a2);
1047 return mvc_asc(env, l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
1050 /* invalidate pte */
1051 void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr)
1053 uint64_t page = vaddr & TARGET_PAGE_MASK;
1056 /* XXX broadcast to other CPUs */
1058 /* XXX Linux is nice enough to give us the exact pte address.
1059 According to spec we'd have to find it out ourselves */
1060 /* XXX Linux is fine with overwriting the pte, the spec requires
1061 us to only set the invalid bit */
1062 stq_phys(pte_addr, pte | _PAGE_INVALID);
1064 /* XXX we exploit the fact that Linux passes the exact virtual
1065 address here - it's not obliged to! */
1066 tlb_flush_page(env, page);
1068 /* XXX 31-bit hack */
1069 if (page & 0x80000000) {
1070 tlb_flush_page(env, page & ~0x80000000);
1072 tlb_flush_page(env, page | 0x80000000);
1076 /* flush local tlb */
1077 void HELPER(ptlb)(CPUS390XState *env)
1082 /* store using real address */
1083 void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint32_t v1)
1085 stw_phys(get_address(env, 0, 0, addr), v1);
1088 /* load real address */
1089 uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
1092 int old_exc = env->exception_index;
1093 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1097 /* XXX incomplete - has more corner cases */
1098 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1099 program_interrupt(env, PGM_SPECIAL_OP, 2);
1102 env->exception_index = old_exc;
1103 if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
1106 if (env->exception_index == EXCP_PGM) {
1107 ret = env->int_pgm_code | 0x80000000;
1109 ret |= addr & ~TARGET_PAGE_MASK;
1111 env->exception_index = old_exc;