1 From a44aee2570031bfcf99098d278c53ab39a582ba6 Mon Sep 17 00:00:00 2001
2 From: Blue Swirl <blauwirbel@gmail.com>
3 Date: Sun, 2 Sep 2012 07:33:34 +0000
4 Subject: [PATCH] target-s390x: split memory access helpers
6 Move memory access helpers to mem_helper.c.
8 Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
9 [agraf: fold softmmu include ifdefs together]
10 Signed-off-by: Alexander Graf <agraf@suse.de>
12 Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
14 target-s390x/Makefile.objs | 3 +-
15 target-s390x/mem_helper.c | 1190 ++++++++++++++++++++++++++++++++++++++++++++
16 target-s390x/op_helper.c | 1159 +-----------------------------------------
17 3 files changed, 1193 insertions(+), 1159 deletions(-)
18 create mode 100644 target-s390x/mem_helper.c
20 diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs
21 index e8f66e9..b9b3061 100644
22 --- a/target-s390x/Makefile.objs
23 +++ b/target-s390x/Makefile.objs
25 obj-y += translate.o op_helper.o helper.o cpu.o interrupt.o
26 -obj-y += int_helper.o fpu_helper.o cc_helper.o
27 +obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o
28 obj-$(CONFIG_SOFTMMU) += machine.o
29 obj-$(CONFIG_KVM) += kvm.o
31 @@ -7,3 +7,4 @@ $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
32 $(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
33 $(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
34 $(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
35 +$(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
36 diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c
38 index 0000000..ba05e65
40 +++ b/target-s390x/mem_helper.c
43 + * S/390 memory access helper routines
45 + * Copyright (c) 2009 Ulrich Hecht
46 + * Copyright (c) 2009 Alexander Graf
48 + * This library is free software; you can redistribute it and/or
49 + * modify it under the terms of the GNU Lesser General Public
50 + * License as published by the Free Software Foundation; either
51 + * version 2 of the License, or (at your option) any later version.
53 + * This library is distributed in the hope that it will be useful,
54 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
55 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
56 + * Lesser General Public License for more details.
58 + * You should have received a copy of the GNU Lesser General Public
59 + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
63 +#include "dyngen-exec.h"
66 +/*****************************************************************************/
67 +/* Softmmu support */
68 +#if !defined(CONFIG_USER_ONLY)
69 +#include "softmmu_exec.h"
71 +#define MMUSUFFIX _mmu
74 +#include "softmmu_template.h"
77 +#include "softmmu_template.h"
80 +#include "softmmu_template.h"
83 +#include "softmmu_template.h"
85 +/* try to fill the TLB and return an exception if error. If retaddr is
86 + NULL, it means that the function was called in C code (i.e. not
87 + from generated code or from helper.c) */
88 +/* XXX: fix it to restore all registers */
89 +void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx,
92 + TranslationBlock *tb;
93 + CPUS390XState *saved_env;
98 + ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
99 + if (unlikely(ret != 0)) {
100 + if (likely(retaddr)) {
101 + /* now we have a real cpu fault */
102 + tb = tb_find_pc(retaddr);
104 + /* the PC is inside the translated code. It means that we have
105 + a virtual CPU fault */
106 + cpu_restore_state(tb, env, retaddr);
109 + cpu_loop_exit(env);
116 +/* #define DEBUG_HELPER */
118 +#define HELPER_LOG(x...) qemu_log(x)
120 +#define HELPER_LOG(x...)
123 +#ifndef CONFIG_USER_ONLY
124 +static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest,
127 + target_phys_addr_t dest_phys;
128 + target_phys_addr_t len = l;
130 + uint64_t asc = env->psw.mask & PSW_MASK_ASC;
133 + if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
135 + cpu_abort(env, "should never reach here");
137 + dest_phys |= dest & ~TARGET_PAGE_MASK;
139 + dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
141 + memset(dest_p, byte, len);
143 + cpu_physical_memory_unmap(dest_p, 1, len, len);
146 +static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest,
149 + target_phys_addr_t dest_phys;
150 + target_phys_addr_t src_phys;
151 + target_phys_addr_t len = l;
154 + uint64_t asc = env->psw.mask & PSW_MASK_ASC;
157 + if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
159 + cpu_abort(env, "should never reach here");
161 + dest_phys |= dest & ~TARGET_PAGE_MASK;
163 + if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) {
165 + cpu_abort(env, "should never reach here");
167 + src_phys |= src & ~TARGET_PAGE_MASK;
169 + dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
170 + src_p = cpu_physical_memory_map(src_phys, &len, 0);
172 + memmove(dest_p, src_p, len);
174 + cpu_physical_memory_unmap(dest_p, 1, len, len);
175 + cpu_physical_memory_unmap(src_p, 0, len, len);
180 +uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src)
186 + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
187 + __func__, l, dest, src);
188 + for (i = 0; i <= l; i++) {
189 + x = ldub(dest + i) & ldub(src + i);
199 +uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src)
205 + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
206 + __func__, l, dest, src);
208 +#ifndef CONFIG_USER_ONLY
209 + /* xor with itself is the same as memset(0) */
210 + if ((l > 32) && (src == dest) &&
211 + (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) {
212 + mvc_fast_memset(env, l + 1, dest, 0);
217 + memset(g2h(dest), 0, l + 1);
222 + for (i = 0; i <= l; i++) {
223 + x = ldub(dest + i) ^ ldub(src + i);
233 +uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src)
239 + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
240 + __func__, l, dest, src);
241 + for (i = 0; i <= l; i++) {
242 + x = ldub(dest + i) | ldub(src + i);
252 +void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src)
256 + uint32_t l_64 = (l + 1) / 8;
258 + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
259 + __func__, l, dest, src);
261 +#ifndef CONFIG_USER_ONLY
263 + (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) &&
264 + (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) {
265 + if (dest == (src + 1)) {
266 + mvc_fast_memset(env, l + 1, dest, ldub(src));
268 + } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
269 + mvc_fast_memmove(env, l + 1, dest, src);
274 + if (dest == (src + 1)) {
275 + memset(g2h(dest), ldub(src), l + 1);
278 + memmove(g2h(dest), g2h(src), l + 1);
283 + /* handle the parts that fit into 8-byte loads/stores */
284 + if (dest != (src + 1)) {
285 + for (i = 0; i < l_64; i++) {
286 + stq(dest + x, ldq(src + x));
291 + /* slow version crossing pages with byte accesses */
292 + for (i = x; i <= l; i++) {
293 + stb(dest + i, ldub(src + i));
297 +/* compare unsigned byte arrays */
298 +uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2)
301 + unsigned char x, y;
304 + HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
305 + __func__, l, s1, s2);
306 + for (i = 0; i <= l; i++) {
309 + HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
313 + } else if (x > y) {
324 +/* compare logical under mask */
325 +uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr)
330 + HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
336 + r = (r1 & 0xff000000UL) >> 24;
337 + HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
342 + } else if (r > d) {
348 + mask = (mask << 1) & 0xf;
355 +/* store character under mask */
356 +void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr)
360 + HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask,
364 + r = (r1 & 0xff000000UL) >> 24;
366 + HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr);
369 + mask = (mask << 1) & 0xf;
375 +static inline uint64_t get_address(int x2, int b2, int d2)
380 + r += env->regs[x2];
384 + r += env->regs[b2];
388 + if (!(env->psw.mask & PSW_MASK_64)) {
395 +static inline uint64_t get_address_31fix(int reg)
397 + uint64_t r = env->regs[reg];
400 + if (!(env->psw.mask & PSW_MASK_64)) {
407 +/* search string (c is byte to search, r2 is string, r1 end of string) */
408 +uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2)
412 + uint64_t str = get_address_31fix(r2);
413 + uint64_t end = get_address_31fix(r1);
415 + HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__,
416 + c, env->regs[r1], env->regs[r2]);
418 + for (i = str; i != end; i++) {
419 + if (ldub(i) == c) {
429 +/* unsigned string compare (c is string terminator) */
430 +uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2)
432 + uint64_t s1 = get_address_31fix(r1);
433 + uint64_t s2 = get_address_31fix(r2);
438 +#ifdef CONFIG_USER_ONLY
440 + HELPER_LOG("%s: comparing '%s' and '%s'\n",
441 + __func__, (char *)g2h(s1), (char *)g2h(s2));
447 + if ((v1 == c || v2 == c) || (v1 != v2)) {
457 + cc = (v1 < v2) ? 1 : 2;
458 + /* FIXME: 31-bit mode! */
459 + env->regs[r1] = s1;
460 + env->regs[r2] = s2;
466 +void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2)
468 + /* XXX missing r0 handling */
469 +#ifdef CONFIG_USER_ONLY
472 + for (i = 0; i < TARGET_PAGE_SIZE; i++) {
473 + stb(r1 + i, ldub(r2 + i));
476 + mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
480 +/* string copy (c is string terminator) */
481 +void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2)
483 + uint64_t dest = get_address_31fix(r1);
484 + uint64_t src = get_address_31fix(r2);
488 +#ifdef CONFIG_USER_ONLY
490 + HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src),
503 + env->regs[r1] = dest; /* FIXME: 31-bit mode! */
506 +/* compare and swap 64-bit */
507 +uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3)
509 + /* FIXME: locking? */
511 + uint64_t v2 = ldq(a2);
513 + if (env->regs[r1] == v2) {
515 + stq(a2, env->regs[r3]);
518 + env->regs[r1] = v2;
523 +/* compare double and swap 64-bit */
524 +uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3)
526 + /* FIXME: locking? */
528 + uint64_t v2_hi = ldq(a2);
529 + uint64_t v2_lo = ldq(a2 + 8);
530 + uint64_t v1_hi = env->regs[r1];
531 + uint64_t v1_lo = env->regs[r1 + 1];
533 + if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
535 + stq(a2, env->regs[r3]);
536 + stq(a2 + 8, env->regs[r3 + 1]);
539 + env->regs[r1] = v2_hi;
540 + env->regs[r1 + 1] = v2_lo;
546 +/* compare and swap 32-bit */
547 +uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3)
549 + /* FIXME: locking? */
551 + uint32_t v2 = ldl(a2);
553 + HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3);
554 + if (((uint32_t)env->regs[r1]) == v2) {
556 + stl(a2, (uint32_t)env->regs[r3]);
559 + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2;
564 +static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask)
566 + int pos = 24; /* top of the lower half of r1 */
567 + uint64_t rmask = 0xff000000ULL;
574 + env->regs[r1] &= ~rmask;
575 + val = ldub(address);
576 + if ((val & 0x80) && !ccd) {
580 + if (val && cc == 0) {
583 + env->regs[r1] |= (uint64_t)val << pos;
586 + mask = (mask << 1) & 0xf;
594 +/* execute instruction
595 + this instruction executes an insn modified with the contents of r1
596 + it does not change the executed instruction in memory
597 + it does not change the program counter
598 + in other words: tricky...
599 + currently implemented by interpreting the cases it is most commonly used in
601 +uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret)
603 + uint16_t insn = lduw_code(addr);
605 + HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
607 + if ((insn & 0xf0ff) == 0xd000) {
608 + uint32_t l, insn2, b1, b2, d1, d2;
611 + insn2 = ldl_code(addr + 2);
612 + b1 = (insn2 >> 28) & 0xf;
613 + b2 = (insn2 >> 12) & 0xf;
614 + d1 = (insn2 >> 16) & 0xfff;
615 + d2 = insn2 & 0xfff;
616 + switch (insn & 0xf00) {
618 + helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2));
621 + cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2));
624 + cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2));
627 + helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2));
633 + } else if ((insn & 0xff00) == 0x0a00) {
634 + /* supervisor call */
635 + HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff);
636 + env->psw.addr = ret - 4;
637 + env->int_svc_code = (insn | v1) & 0xff;
638 + env->int_svc_ilc = 4;
639 + helper_exception(EXCP_SVC);
640 + } else if ((insn & 0xff00) == 0xbf00) {
641 + uint32_t insn2, r1, r3, b2, d2;
643 + insn2 = ldl_code(addr + 2);
644 + r1 = (insn2 >> 20) & 0xf;
645 + r3 = (insn2 >> 16) & 0xf;
646 + b2 = (insn2 >> 12) & 0xf;
647 + d2 = insn2 & 0xfff;
648 + cc = helper_icm(r1, get_address(0, b2, d2), r3);
651 + cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
657 +/* store character under mask high operates on the upper half of r1 */
658 +void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask)
660 + int pos = 56; /* top of the upper half of r1 */
664 + stb(address, (env->regs[r1] >> pos) & 0xff);
667 + mask = (mask << 1) & 0xf;
672 +/* insert character under mask high; same as icm, but operates on the
673 + upper half of r1 */
674 +uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask)
676 + int pos = 56; /* top of the upper half of r1 */
677 + uint64_t rmask = 0xff00000000000000ULL;
684 + env->regs[r1] &= ~rmask;
685 + val = ldub(address);
686 + if ((val & 0x80) && !ccd) {
690 + if (val && cc == 0) {
693 + env->regs[r1] |= (uint64_t)val << pos;
696 + mask = (mask << 1) & 0xf;
704 +/* load access registers r1 to r3 from memory at a2 */
705 +void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3)
709 + for (i = r1;; i = (i + 1) % 16) {
710 + env->aregs[i] = ldl(a2);
719 +/* store access registers r1 to r3 in memory at a2 */
720 +void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3)
724 + for (i = r1;; i = (i + 1) % 16) {
725 + stl(a2, env->aregs[i]);
735 +uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2)
737 + uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
738 + uint64_t dest = get_address_31fix(r1);
739 + uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
740 + uint64_t src = get_address_31fix(r2);
741 + uint8_t pad = src >> 24;
745 + if (destlen == srclen) {
747 + } else if (destlen < srclen) {
753 + if (srclen > destlen) {
757 + for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
762 + for (; destlen; dest++, destlen--) {
766 + env->regs[r1 + 1] = destlen;
767 + /* can't use srclen here, we trunc'ed it */
768 + env->regs[r2 + 1] -= src - env->regs[r2];
769 + env->regs[r1] = dest;
770 + env->regs[r2] = src;
775 +/* move long extended another memcopy insn with more bells and whistles */
776 +uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3)
778 + uint64_t destlen = env->regs[r1 + 1];
779 + uint64_t dest = env->regs[r1];
780 + uint64_t srclen = env->regs[r3 + 1];
781 + uint64_t src = env->regs[r3];
782 + uint8_t pad = a2 & 0xff;
786 + if (!(env->psw.mask & PSW_MASK_64)) {
787 + destlen = (uint32_t)destlen;
788 + srclen = (uint32_t)srclen;
789 + dest &= 0x7fffffff;
793 + if (destlen == srclen) {
795 + } else if (destlen < srclen) {
801 + if (srclen > destlen) {
805 + for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
810 + for (; destlen; dest++, destlen--) {
814 + env->regs[r1 + 1] = destlen;
815 + /* can't use srclen here, we trunc'ed it */
816 + /* FIXME: 31-bit mode! */
817 + env->regs[r3 + 1] -= src - env->regs[r3];
818 + env->regs[r1] = dest;
819 + env->regs[r3] = src;
824 +/* compare logical long extended memcompare insn with padding */
825 +uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3)
827 + uint64_t destlen = env->regs[r1 + 1];
828 + uint64_t dest = get_address_31fix(r1);
829 + uint64_t srclen = env->regs[r3 + 1];
830 + uint64_t src = get_address_31fix(r3);
831 + uint8_t pad = a2 & 0xff;
832 + uint8_t v1 = 0, v2 = 0;
835 + if (!(destlen || srclen)) {
839 + if (srclen > destlen) {
843 + for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
844 + v1 = srclen ? ldub(src) : pad;
845 + v2 = destlen ? ldub(dest) : pad;
847 + cc = (v1 < v2) ? 1 : 2;
852 + env->regs[r1 + 1] = destlen;
853 + /* can't use srclen here, we trunc'ed it */
854 + env->regs[r3 + 1] -= src - env->regs[r3];
855 + env->regs[r1] = dest;
856 + env->regs[r3] = src;
862 +void HELPER(cksm)(uint32_t r1, uint32_t r2)
864 + uint64_t src = get_address_31fix(r2);
865 + uint64_t src_len = env->regs[(r2 + 1) & 15];
866 + uint64_t cksm = (uint32_t)env->regs[r1];
868 + while (src_len >= 4) {
871 + /* move to next word */
880 + cksm += ldub(src) << 24;
883 + cksm += lduw(src) << 16;
886 + cksm += lduw(src) << 16;
887 + cksm += ldub(src + 2) << 8;
891 + /* indicate we've processed everything */
892 + env->regs[r2] = src + src_len;
893 + env->regs[(r2 + 1) & 15] = 0;
896 + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
897 + ((uint32_t)cksm + (cksm >> 32));
900 +void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src)
902 + int len_dest = len >> 4;
903 + int len_src = len & 0xf;
905 + int second_nibble = 0;
910 + /* last byte is special, it only flips the nibbles */
912 + stb(dest, (b << 4) | (b >> 4));
916 + /* now pad every nibble with 0xf0 */
918 + while (len_dest > 0) {
919 + uint8_t cur_byte = 0;
922 + cur_byte = ldub(src);
928 + /* only advance one nibble at a time */
929 + if (second_nibble) {
934 + second_nibble = !second_nibble;
937 + cur_byte = (cur_byte & 0xf);
941 + stb(dest, cur_byte);
945 +void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans)
949 + for (i = 0; i <= len; i++) {
950 + uint8_t byte = ldub(array + i);
951 + uint8_t new_byte = ldub(trans + byte);
953 + stb(array + i, new_byte);
957 +#if !defined(CONFIG_USER_ONLY)
958 +void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3)
963 + for (i = r1;; i = (i + 1) % 16) {
964 + env->cregs[i] = ldq(src);
965 + HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
966 + i, src, env->cregs[i]);
967 + src += sizeof(uint64_t);
977 +void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3)
982 + for (i = r1;; i = (i + 1) % 16) {
983 + env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src);
984 + src += sizeof(uint32_t);
994 +void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3)
997 + uint64_t dest = a2;
999 + for (i = r1;; i = (i + 1) % 16) {
1000 + stq(dest, env->cregs[i]);
1001 + dest += sizeof(uint64_t);
1009 +void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3)
1012 + uint64_t dest = a2;
1014 + for (i = r1;; i = (i + 1) % 16) {
1015 + stl(dest, env->cregs[i]);
1016 + dest += sizeof(uint32_t);
1024 +uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
1026 + /* XXX implement */
1031 +/* insert storage key extended */
1032 +uint64_t HELPER(iske)(uint64_t r2)
1034 + uint64_t addr = get_address(0, 0, r2);
1036 + if (addr > ram_size) {
1040 + return env->storage_keys[addr / TARGET_PAGE_SIZE];
1043 +/* set storage key extended */
1044 +void HELPER(sske)(uint32_t r1, uint64_t r2)
1046 + uint64_t addr = get_address(0, 0, r2);
1048 + if (addr > ram_size) {
1052 + env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
1055 +/* reset reference bit extended */
1056 +uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2)
1061 + if (r2 > ram_size) {
1065 + key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
1066 + re = key & (SK_R | SK_C);
1067 + env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
1072 + * 0 Reference bit zero; change bit zero
1073 + * 1 Reference bit zero; change bit one
1074 + * 2 Reference bit one; change bit zero
1075 + * 3 Reference bit one; change bit one
1081 +/* compare and swap and purge */
1082 +uint32_t HELPER(csp)(uint32_t r1, uint32_t r2)
1085 + uint32_t o1 = env->regs[r1];
1086 + uint64_t a2 = get_address_31fix(r2) & ~3ULL;
1087 + uint32_t o2 = ldl(a2);
1090 + stl(a2, env->regs[(r1 + 1) & 15]);
1091 + if (env->regs[r2] & 0x3) {
1092 + /* flush TLB / ALB */
1093 + tlb_flush(env, 1);
1097 + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
1104 +static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2,
1107 + target_ulong src, dest;
1108 + int flags, cc = 0, i;
1112 + } else if (l > 256) {
1118 + if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
1119 + cpu_loop_exit(env);
1121 + dest |= a1 & ~TARGET_PAGE_MASK;
1123 + if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
1124 + cpu_loop_exit(env);
1126 + src |= a2 & ~TARGET_PAGE_MASK;
1128 + /* XXX replace w/ memcpy */
1129 + for (i = 0; i < l; i++) {
1130 + /* XXX be more clever */
1131 + if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
1132 + (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
1133 + mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2);
1136 + stb_phys(dest + i, ldub_phys(src + i));
1142 +uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2)
1144 + HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1145 + __func__, l, a1, a2);
1147 + return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
1150 +uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2)
1152 + HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1153 + __func__, l, a1, a2);
1155 + return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
1158 +/* invalidate pte */
1159 +void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr)
1161 + uint64_t page = vaddr & TARGET_PAGE_MASK;
1164 + /* XXX broadcast to other CPUs */
1166 + /* XXX Linux is nice enough to give us the exact pte address.
1167 + According to spec we'd have to find it out ourselves */
1168 + /* XXX Linux is fine with overwriting the pte, the spec requires
1169 + us to only set the invalid bit */
1170 + stq_phys(pte_addr, pte | _PAGE_INVALID);
1172 + /* XXX we exploit the fact that Linux passes the exact virtual
1173 + address here - it's not obliged to! */
1174 + tlb_flush_page(env, page);
1176 + /* XXX 31-bit hack */
1177 + if (page & 0x80000000) {
1178 + tlb_flush_page(env, page & ~0x80000000);
1180 + tlb_flush_page(env, page | 0x80000000);
1184 +/* flush local tlb */
1185 +void HELPER(ptlb)(void)
1187 + tlb_flush(env, 1);
1190 +/* store using real address */
1191 +void HELPER(stura)(uint64_t addr, uint32_t v1)
1193 + stw_phys(get_address(0, 0, addr), v1);
1196 +/* load real address */
1197 +uint32_t HELPER(lra)(uint64_t addr, uint32_t r1)
1200 + int old_exc = env->exception_index;
1201 + uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1205 + /* XXX incomplete - has more corner cases */
1206 + if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1207 + program_interrupt(env, PGM_SPECIAL_OP, 2);
1210 + env->exception_index = old_exc;
1211 + if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
1214 + if (env->exception_index == EXCP_PGM) {
1215 + ret = env->int_pgm_code | 0x80000000;
1217 + ret |= addr & ~TARGET_PAGE_MASK;
1219 + env->exception_index = old_exc;
1221 + if (!(env->psw.mask & PSW_MASK_64)) {
1222 + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
1223 + (ret & 0xffffffffULL);
1225 + env->regs[r1] = ret;
1232 diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
1233 index 3b8b997..bb8dbf5 100644
1234 --- a/target-s390x/op_helper.c
1235 +++ b/target-s390x/op_helper.c
1239 #if !defined(CONFIG_USER_ONLY)
1240 -#include "sysemu.h"
1243 -/*****************************************************************************/
1244 -/* Softmmu support */
1245 -#if !defined(CONFIG_USER_ONLY)
1246 #include "softmmu_exec.h"
1248 -#define MMUSUFFIX _mmu
1251 -#include "softmmu_template.h"
1254 -#include "softmmu_template.h"
1257 -#include "softmmu_template.h"
1260 -#include "softmmu_template.h"
1262 -/* try to fill the TLB and return an exception if error. If retaddr is
1263 - NULL, it means that the function was called in C code (i.e. not
1264 - from generated code or from helper.c) */
1265 -/* XXX: fix it to restore all registers */
1266 -void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx,
1267 - uintptr_t retaddr)
1269 - TranslationBlock *tb;
1270 - CPUS390XState *saved_env;
1275 - ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
1276 - if (unlikely(ret != 0)) {
1277 - if (likely(retaddr)) {
1278 - /* now we have a real cpu fault */
1279 - tb = tb_find_pc(retaddr);
1281 - /* the PC is inside the translated code. It means that we have
1282 - a virtual CPU fault */
1283 - cpu_restore_state(tb, env, retaddr);
1286 - cpu_loop_exit(env);
1291 +#include "sysemu.h"
1294 /* #define DEBUG_HELPER */
1295 @@ -101,840 +52,6 @@ void HELPER(exception)(uint32_t excp)
1298 #ifndef CONFIG_USER_ONLY
1299 -static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest,
1302 - target_phys_addr_t dest_phys;
1303 - target_phys_addr_t len = l;
1305 - uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1308 - if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
1310 - cpu_abort(env, "should never reach here");
1312 - dest_phys |= dest & ~TARGET_PAGE_MASK;
1314 - dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
1316 - memset(dest_p, byte, len);
1318 - cpu_physical_memory_unmap(dest_p, 1, len, len);
1321 -static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest,
1324 - target_phys_addr_t dest_phys;
1325 - target_phys_addr_t src_phys;
1326 - target_phys_addr_t len = l;
1329 - uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1332 - if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
1334 - cpu_abort(env, "should never reach here");
1336 - dest_phys |= dest & ~TARGET_PAGE_MASK;
1338 - if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) {
1340 - cpu_abort(env, "should never reach here");
1342 - src_phys |= src & ~TARGET_PAGE_MASK;
1344 - dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
1345 - src_p = cpu_physical_memory_map(src_phys, &len, 0);
1347 - memmove(dest_p, src_p, len);
1349 - cpu_physical_memory_unmap(dest_p, 1, len, len);
1350 - cpu_physical_memory_unmap(src_p, 0, len, len);
1355 -uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src)
1361 - HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
1362 - __func__, l, dest, src);
1363 - for (i = 0; i <= l; i++) {
1364 - x = ldub(dest + i) & ldub(src + i);
1374 -uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src)
1380 - HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
1381 - __func__, l, dest, src);
1383 -#ifndef CONFIG_USER_ONLY
1384 - /* xor with itself is the same as memset(0) */
1385 - if ((l > 32) && (src == dest) &&
1386 - (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) {
1387 - mvc_fast_memset(env, l + 1, dest, 0);
1391 - if (src == dest) {
1392 - memset(g2h(dest), 0, l + 1);
1397 - for (i = 0; i <= l; i++) {
1398 - x = ldub(dest + i) ^ ldub(src + i);
1408 -uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src)
1414 - HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
1415 - __func__, l, dest, src);
1416 - for (i = 0; i <= l; i++) {
1417 - x = ldub(dest + i) | ldub(src + i);
1427 -void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src)
1431 - uint32_t l_64 = (l + 1) / 8;
1433 - HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
1434 - __func__, l, dest, src);
1436 -#ifndef CONFIG_USER_ONLY
1438 - (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) &&
1439 - (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) {
1440 - if (dest == (src + 1)) {
1441 - mvc_fast_memset(env, l + 1, dest, ldub(src));
1443 - } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
1444 - mvc_fast_memmove(env, l + 1, dest, src);
1449 - if (dest == (src + 1)) {
1450 - memset(g2h(dest), ldub(src), l + 1);
1453 - memmove(g2h(dest), g2h(src), l + 1);
1458 - /* handle the parts that fit into 8-byte loads/stores */
1459 - if (dest != (src + 1)) {
1460 - for (i = 0; i < l_64; i++) {
1461 - stq(dest + x, ldq(src + x));
1466 - /* slow version crossing pages with byte accesses */
1467 - for (i = x; i <= l; i++) {
1468 - stb(dest + i, ldub(src + i));
1472 -/* compare unsigned byte arrays */
1473 -uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2)
1476 - unsigned char x, y;
1479 - HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
1480 - __func__, l, s1, s2);
1481 - for (i = 0; i <= l; i++) {
1484 - HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
1488 - } else if (x > y) {
1499 -/* compare logical under mask */
1500 -uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr)
1505 - HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
1511 - r = (r1 & 0xff000000UL) >> 24;
1512 - HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
1517 - } else if (r > d) {
1523 - mask = (mask << 1) & 0xf;
1530 -/* store character under mask */
1531 -void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr)
1535 - HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask,
1539 - r = (r1 & 0xff000000UL) >> 24;
1541 - HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr);
1544 - mask = (mask << 1) & 0xf;
1550 -static inline uint64_t get_address(int x2, int b2, int d2)
1555 - r += env->regs[x2];
1559 - r += env->regs[b2];
1563 - if (!(env->psw.mask & PSW_MASK_64)) {
1570 -static inline uint64_t get_address_31fix(int reg)
1572 - uint64_t r = env->regs[reg];
1575 - if (!(env->psw.mask & PSW_MASK_64)) {
1582 -/* search string (c is byte to search, r2 is string, r1 end of string) */
1583 -uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2)
1587 - uint64_t str = get_address_31fix(r2);
1588 - uint64_t end = get_address_31fix(r1);
1590 - HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__,
1591 - c, env->regs[r1], env->regs[r2]);
1593 - for (i = str; i != end; i++) {
1594 - if (ldub(i) == c) {
1595 - env->regs[r1] = i;
1604 -/* unsigned string compare (c is string terminator) */
1605 -uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2)
1607 - uint64_t s1 = get_address_31fix(r1);
1608 - uint64_t s2 = get_address_31fix(r2);
1613 -#ifdef CONFIG_USER_ONLY
1615 - HELPER_LOG("%s: comparing '%s' and '%s'\n",
1616 - __func__, (char *)g2h(s1), (char *)g2h(s2));
1622 - if ((v1 == c || v2 == c) || (v1 != v2)) {
1632 - cc = (v1 < v2) ? 1 : 2;
1633 - /* FIXME: 31-bit mode! */
1634 - env->regs[r1] = s1;
1635 - env->regs[r2] = s2;
1641 -void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2)
1643 - /* XXX missing r0 handling */
1644 -#ifdef CONFIG_USER_ONLY
1647 - for (i = 0; i < TARGET_PAGE_SIZE; i++) {
1648 - stb(r1 + i, ldub(r2 + i));
1651 - mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
1655 -/* string copy (c is string terminator) */
1656 -void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2)
1658 - uint64_t dest = get_address_31fix(r1);
1659 - uint64_t src = get_address_31fix(r2);
1663 -#ifdef CONFIG_USER_ONLY
1665 - HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src),
1678 - env->regs[r1] = dest; /* FIXME: 31-bit mode! */
1681 -/* compare and swap 64-bit */
1682 -uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3)
1684 - /* FIXME: locking? */
1686 - uint64_t v2 = ldq(a2);
1688 - if (env->regs[r1] == v2) {
1690 - stq(a2, env->regs[r3]);
1693 - env->regs[r1] = v2;
1698 -/* compare double and swap 64-bit */
1699 -uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3)
1701 - /* FIXME: locking? */
1703 - uint64_t v2_hi = ldq(a2);
1704 - uint64_t v2_lo = ldq(a2 + 8);
1705 - uint64_t v1_hi = env->regs[r1];
1706 - uint64_t v1_lo = env->regs[r1 + 1];
1708 - if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
1710 - stq(a2, env->regs[r3]);
1711 - stq(a2 + 8, env->regs[r3 + 1]);
1714 - env->regs[r1] = v2_hi;
1715 - env->regs[r1 + 1] = v2_lo;
1721 -/* compare and swap 32-bit */
1722 -uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3)
1724 - /* FIXME: locking? */
1726 - uint32_t v2 = ldl(a2);
1728 - HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3);
1729 - if (((uint32_t)env->regs[r1]) == v2) {
1731 - stl(a2, (uint32_t)env->regs[r3]);
1734 - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2;
1739 -static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask)
1741 - int pos = 24; /* top of the lower half of r1 */
1742 - uint64_t rmask = 0xff000000ULL;
1749 - env->regs[r1] &= ~rmask;
1750 - val = ldub(address);
1751 - if ((val & 0x80) && !ccd) {
1755 - if (val && cc == 0) {
1758 - env->regs[r1] |= (uint64_t)val << pos;
1761 - mask = (mask << 1) & 0xf;
1769 -/* execute instruction
1770 - this instruction executes an insn modified with the contents of r1
1771 - it does not change the executed instruction in memory
1772 - it does not change the program counter
1773 - in other words: tricky...
1774 - currently implemented by interpreting the cases it is most commonly used in
1776 -uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret)
1778 - uint16_t insn = lduw_code(addr);
1780 - HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
1782 - if ((insn & 0xf0ff) == 0xd000) {
1783 - uint32_t l, insn2, b1, b2, d1, d2;
1786 - insn2 = ldl_code(addr + 2);
1787 - b1 = (insn2 >> 28) & 0xf;
1788 - b2 = (insn2 >> 12) & 0xf;
1789 - d1 = (insn2 >> 16) & 0xfff;
1790 - d2 = insn2 & 0xfff;
1791 - switch (insn & 0xf00) {
1793 - helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2));
1796 - cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2));
1799 - cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2));
1802 - helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2));
1808 - } else if ((insn & 0xff00) == 0x0a00) {
1809 - /* supervisor call */
1810 - HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff);
1811 - env->psw.addr = ret - 4;
1812 - env->int_svc_code = (insn | v1) & 0xff;
1813 - env->int_svc_ilc = 4;
1814 - helper_exception(EXCP_SVC);
1815 - } else if ((insn & 0xff00) == 0xbf00) {
1816 - uint32_t insn2, r1, r3, b2, d2;
1818 - insn2 = ldl_code(addr + 2);
1819 - r1 = (insn2 >> 20) & 0xf;
1820 - r3 = (insn2 >> 16) & 0xf;
1821 - b2 = (insn2 >> 12) & 0xf;
1822 - d2 = insn2 & 0xfff;
1823 - cc = helper_icm(r1, get_address(0, b2, d2), r3);
1826 - cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
1832 -/* store character under mask high operates on the upper half of r1 */
1833 -void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask)
1835 - int pos = 56; /* top of the upper half of r1 */
1839 - stb(address, (env->regs[r1] >> pos) & 0xff);
1842 - mask = (mask << 1) & 0xf;
1847 -/* insert character under mask high; same as icm, but operates on the
1848 - upper half of r1 */
1849 -uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask)
1851 - int pos = 56; /* top of the upper half of r1 */
1852 - uint64_t rmask = 0xff00000000000000ULL;
1859 - env->regs[r1] &= ~rmask;
1860 - val = ldub(address);
1861 - if ((val & 0x80) && !ccd) {
1865 - if (val && cc == 0) {
1868 - env->regs[r1] |= (uint64_t)val << pos;
1871 - mask = (mask << 1) & 0xf;
1879 -/* load access registers r1 to r3 from memory at a2 */
1880 -void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3)
1884 - for (i = r1;; i = (i + 1) % 16) {
1885 - env->aregs[i] = ldl(a2);
1894 -/* store access registers r1 to r3 in memory at a2 */
1895 -void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3)
1899 - for (i = r1;; i = (i + 1) % 16) {
1900 - stl(a2, env->aregs[i]);
1910 -uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2)
1912 - uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
1913 - uint64_t dest = get_address_31fix(r1);
1914 - uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
1915 - uint64_t src = get_address_31fix(r2);
1916 - uint8_t pad = src >> 24;
1920 - if (destlen == srclen) {
1922 - } else if (destlen < srclen) {
1928 - if (srclen > destlen) {
1932 - for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
1937 - for (; destlen; dest++, destlen--) {
1941 - env->regs[r1 + 1] = destlen;
1942 - /* can't use srclen here, we trunc'ed it */
1943 - env->regs[r2 + 1] -= src - env->regs[r2];
1944 - env->regs[r1] = dest;
1945 - env->regs[r2] = src;
1950 -/* move long extended another memcopy insn with more bells and whistles */
1951 -uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3)
1953 - uint64_t destlen = env->regs[r1 + 1];
1954 - uint64_t dest = env->regs[r1];
1955 - uint64_t srclen = env->regs[r3 + 1];
1956 - uint64_t src = env->regs[r3];
1957 - uint8_t pad = a2 & 0xff;
1961 - if (!(env->psw.mask & PSW_MASK_64)) {
1962 - destlen = (uint32_t)destlen;
1963 - srclen = (uint32_t)srclen;
1964 - dest &= 0x7fffffff;
1965 - src &= 0x7fffffff;
1968 - if (destlen == srclen) {
1970 - } else if (destlen < srclen) {
1976 - if (srclen > destlen) {
1980 - for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
1985 - for (; destlen; dest++, destlen--) {
1989 - env->regs[r1 + 1] = destlen;
1990 - /* can't use srclen here, we trunc'ed it */
1991 - /* FIXME: 31-bit mode! */
1992 - env->regs[r3 + 1] -= src - env->regs[r3];
1993 - env->regs[r1] = dest;
1994 - env->regs[r3] = src;
1999 -/* compare logical long extended memcompare insn with padding */
2000 -uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3)
2002 - uint64_t destlen = env->regs[r1 + 1];
2003 - uint64_t dest = get_address_31fix(r1);
2004 - uint64_t srclen = env->regs[r3 + 1];
2005 - uint64_t src = get_address_31fix(r3);
2006 - uint8_t pad = a2 & 0xff;
2007 - uint8_t v1 = 0, v2 = 0;
2010 - if (!(destlen || srclen)) {
2014 - if (srclen > destlen) {
2018 - for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
2019 - v1 = srclen ? ldub(src) : pad;
2020 - v2 = destlen ? ldub(dest) : pad;
2022 - cc = (v1 < v2) ? 1 : 2;
2027 - env->regs[r1 + 1] = destlen;
2028 - /* can't use srclen here, we trunc'ed it */
2029 - env->regs[r3 + 1] -= src - env->regs[r3];
2030 - env->regs[r1] = dest;
2031 - env->regs[r3] = src;
2037 -void HELPER(cksm)(uint32_t r1, uint32_t r2)
2039 - uint64_t src = get_address_31fix(r2);
2040 - uint64_t src_len = env->regs[(r2 + 1) & 15];
2041 - uint64_t cksm = (uint32_t)env->regs[r1];
2043 - while (src_len >= 4) {
2046 - /* move to next word */
2051 - switch (src_len) {
2055 - cksm += ldub(src) << 24;
2058 - cksm += lduw(src) << 16;
2061 - cksm += lduw(src) << 16;
2062 - cksm += ldub(src + 2) << 8;
2066 - /* indicate we've processed everything */
2067 - env->regs[r2] = src + src_len;
2068 - env->regs[(r2 + 1) & 15] = 0;
2070 - /* store result */
2071 - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
2072 - ((uint32_t)cksm + (cksm >> 32));
2075 -void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src)
2077 - int len_dest = len >> 4;
2078 - int len_src = len & 0xf;
2080 - int second_nibble = 0;
2085 - /* last byte is special, it only flips the nibbles */
2087 - stb(dest, (b << 4) | (b >> 4));
2091 - /* now pad every nibble with 0xf0 */
2093 - while (len_dest > 0) {
2094 - uint8_t cur_byte = 0;
2096 - if (len_src > 0) {
2097 - cur_byte = ldub(src);
2103 - /* only advance one nibble at a time */
2104 - if (second_nibble) {
2109 - second_nibble = !second_nibble;
2112 - cur_byte = (cur_byte & 0xf);
2116 - stb(dest, cur_byte);
2120 -void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans)
2124 - for (i = 0; i <= len; i++) {
2125 - uint8_t byte = ldub(array + i);
2126 - uint8_t new_byte = ldub(trans + byte);
2128 - stb(array + i, new_byte);
2132 -#ifndef CONFIG_USER_ONLY
2133 void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
2135 qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr);
2136 @@ -1267,206 +384,6 @@ uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1)
2140 -void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3)
2143 - uint64_t src = a2;
2145 - for (i = r1;; i = (i + 1) % 16) {
2146 - env->cregs[i] = ldq(src);
2147 - HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
2148 - i, src, env->cregs[i]);
2149 - src += sizeof(uint64_t);
2156 - tlb_flush(env, 1);
2159 -void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3)
2162 - uint64_t src = a2;
2164 - for (i = r1;; i = (i + 1) % 16) {
2165 - env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src);
2166 - src += sizeof(uint32_t);
2173 - tlb_flush(env, 1);
2176 -void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3)
2179 - uint64_t dest = a2;
2181 - for (i = r1;; i = (i + 1) % 16) {
2182 - stq(dest, env->cregs[i]);
2183 - dest += sizeof(uint64_t);
2191 -void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3)
2194 - uint64_t dest = a2;
2196 - for (i = r1;; i = (i + 1) % 16) {
2197 - stl(dest, env->cregs[i]);
2198 - dest += sizeof(uint32_t);
2206 -uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
2208 - /* XXX implement */
2213 -/* insert storage key extended */
2214 -uint64_t HELPER(iske)(uint64_t r2)
2216 - uint64_t addr = get_address(0, 0, r2);
2218 - if (addr > ram_size) {
2222 - return env->storage_keys[addr / TARGET_PAGE_SIZE];
2225 -/* set storage key extended */
2226 -void HELPER(sske)(uint32_t r1, uint64_t r2)
2228 - uint64_t addr = get_address(0, 0, r2);
2230 - if (addr > ram_size) {
2234 - env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
2237 -/* reset reference bit extended */
2238 -uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2)
2243 - if (r2 > ram_size) {
2247 - key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
2248 - re = key & (SK_R | SK_C);
2249 - env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
2254 - * 0 Reference bit zero; change bit zero
2255 - * 1 Reference bit zero; change bit one
2256 - * 2 Reference bit one; change bit zero
2257 - * 3 Reference bit one; change bit one
2263 -/* compare and swap and purge */
2264 -uint32_t HELPER(csp)(uint32_t r1, uint32_t r2)
2267 - uint32_t o1 = env->regs[r1];
2268 - uint64_t a2 = get_address_31fix(r2) & ~3ULL;
2269 - uint32_t o2 = ldl(a2);
2272 - stl(a2, env->regs[(r1 + 1) & 15]);
2273 - if (env->regs[r2] & 0x3) {
2274 - /* flush TLB / ALB */
2275 - tlb_flush(env, 1);
2279 - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
2286 -static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2,
2289 - target_ulong src, dest;
2290 - int flags, cc = 0, i;
2294 - } else if (l > 256) {
2300 - if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
2301 - cpu_loop_exit(env);
2303 - dest |= a1 & ~TARGET_PAGE_MASK;
2305 - if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
2306 - cpu_loop_exit(env);
2308 - src |= a2 & ~TARGET_PAGE_MASK;
2310 - /* XXX replace w/ memcpy */
2311 - for (i = 0; i < l; i++) {
2312 - /* XXX be more clever */
2313 - if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
2314 - (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
2315 - mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2);
2318 - stb_phys(dest + i, ldub_phys(src + i));
2324 -uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2)
2326 - HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
2327 - __func__, l, a1, a2);
2329 - return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
2332 -uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2)
2334 - HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
2335 - __func__, l, a1, a2);
2337 - return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
2340 uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr)
2343 @@ -1508,78 +425,4 @@ uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr)
2348 -/* invalidate pte */
2349 -void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr)
2351 - uint64_t page = vaddr & TARGET_PAGE_MASK;
2354 - /* XXX broadcast to other CPUs */
2356 - /* XXX Linux is nice enough to give us the exact pte address.
2357 - According to spec we'd have to find it out ourselves */
2358 - /* XXX Linux is fine with overwriting the pte, the spec requires
2359 - us to only set the invalid bit */
2360 - stq_phys(pte_addr, pte | _PAGE_INVALID);
2362 - /* XXX we exploit the fact that Linux passes the exact virtual
2363 - address here - it's not obliged to! */
2364 - tlb_flush_page(env, page);
2366 - /* XXX 31-bit hack */
2367 - if (page & 0x80000000) {
2368 - tlb_flush_page(env, page & ~0x80000000);
2370 - tlb_flush_page(env, page | 0x80000000);
2374 -/* flush local tlb */
2375 -void HELPER(ptlb)(void)
2377 - tlb_flush(env, 1);
2380 -/* store using real address */
2381 -void HELPER(stura)(uint64_t addr, uint32_t v1)
2383 - stw_phys(get_address(0, 0, addr), v1);
2386 -/* load real address */
2387 -uint32_t HELPER(lra)(uint64_t addr, uint32_t r1)
2390 - int old_exc = env->exception_index;
2391 - uint64_t asc = env->psw.mask & PSW_MASK_ASC;
2395 - /* XXX incomplete - has more corner cases */
2396 - if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
2397 - program_interrupt(env, PGM_SPECIAL_OP, 2);
2400 - env->exception_index = old_exc;
2401 - if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
2404 - if (env->exception_index == EXCP_PGM) {
2405 - ret = env->int_pgm_code | 0x80000000;
2407 - ret |= addr & ~TARGET_PAGE_MASK;
2409 - env->exception_index = old_exc;
2411 - if (!(env->psw.mask & PSW_MASK_64)) {
2412 - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
2413 - (ret & 0xffffffffULL);
2415 - env->regs[r1] = ret;