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/>.
22 #include "dyngen-exec.h"
25 /*****************************************************************************/
27 #if !defined(CONFIG_USER_ONLY)
28 #include "softmmu_exec.h"
30 #define MMUSUFFIX _mmu
33 #include "softmmu_template.h"
36 #include "softmmu_template.h"
39 #include "softmmu_template.h"
42 #include "softmmu_template.h"
44 /* try to fill the TLB and return an exception if error. If retaddr is
45 NULL, it means that the function was called in C code (i.e. not
46 from generated code or from helper.c) */
47 /* XXX: fix it to restore all registers */
48 void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx,
52 CPUS390XState *saved_env;
57 ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
58 if (unlikely(ret != 0)) {
59 if (likely(retaddr)) {
60 /* now we have a real cpu fault */
61 tb = tb_find_pc(retaddr);
63 /* the PC is inside the translated code. It means that we have
64 a virtual CPU fault */
65 cpu_restore_state(tb, env, retaddr);
75 /* #define DEBUG_HELPER */
77 #define HELPER_LOG(x...) qemu_log(x)
79 #define HELPER_LOG(x...)
82 #ifndef CONFIG_USER_ONLY
83 static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest,
86 target_phys_addr_t dest_phys;
87 target_phys_addr_t len = l;
89 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
92 if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
94 cpu_abort(env, "should never reach here");
96 dest_phys |= dest & ~TARGET_PAGE_MASK;
98 dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
100 memset(dest_p, byte, len);
102 cpu_physical_memory_unmap(dest_p, 1, len, len);
105 static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest,
108 target_phys_addr_t dest_phys;
109 target_phys_addr_t src_phys;
110 target_phys_addr_t len = l;
113 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
116 if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
118 cpu_abort(env, "should never reach here");
120 dest_phys |= dest & ~TARGET_PAGE_MASK;
122 if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) {
124 cpu_abort(env, "should never reach here");
126 src_phys |= src & ~TARGET_PAGE_MASK;
128 dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
129 src_p = cpu_physical_memory_map(src_phys, &len, 0);
131 memmove(dest_p, src_p, len);
133 cpu_physical_memory_unmap(dest_p, 1, len, len);
134 cpu_physical_memory_unmap(src_p, 0, len, len);
139 uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src)
145 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
146 __func__, l, dest, src);
147 for (i = 0; i <= l; i++) {
148 x = ldub(dest + i) & ldub(src + i);
158 uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src)
164 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
165 __func__, l, dest, src);
167 #ifndef CONFIG_USER_ONLY
168 /* xor with itself is the same as memset(0) */
169 if ((l > 32) && (src == dest) &&
170 (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) {
171 mvc_fast_memset(env, l + 1, dest, 0);
176 memset(g2h(dest), 0, l + 1);
181 for (i = 0; i <= l; i++) {
182 x = ldub(dest + i) ^ ldub(src + i);
192 uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src)
198 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
199 __func__, l, dest, src);
200 for (i = 0; i <= l; i++) {
201 x = ldub(dest + i) | ldub(src + i);
211 void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src)
215 uint32_t l_64 = (l + 1) / 8;
217 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
218 __func__, l, dest, src);
220 #ifndef CONFIG_USER_ONLY
222 (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) &&
223 (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) {
224 if (dest == (src + 1)) {
225 mvc_fast_memset(env, l + 1, dest, ldub(src));
227 } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
228 mvc_fast_memmove(env, l + 1, dest, src);
233 if (dest == (src + 1)) {
234 memset(g2h(dest), ldub(src), l + 1);
237 memmove(g2h(dest), g2h(src), l + 1);
242 /* handle the parts that fit into 8-byte loads/stores */
243 if (dest != (src + 1)) {
244 for (i = 0; i < l_64; i++) {
245 stq(dest + x, ldq(src + x));
250 /* slow version crossing pages with byte accesses */
251 for (i = x; i <= l; i++) {
252 stb(dest + i, ldub(src + i));
256 /* compare unsigned byte arrays */
257 uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2)
263 HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
264 __func__, l, s1, s2);
265 for (i = 0; i <= l; i++) {
268 HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
283 /* compare logical under mask */
284 uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr)
289 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
295 r = (r1 & 0xff000000UL) >> 24;
296 HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
307 mask = (mask << 1) & 0xf;
314 /* store character under mask */
315 void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr)
319 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask,
323 r = (r1 & 0xff000000UL) >> 24;
325 HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr);
328 mask = (mask << 1) & 0xf;
334 static inline uint64_t get_address(int x2, int b2, int d2)
347 if (!(env->psw.mask & PSW_MASK_64)) {
354 static inline uint64_t get_address_31fix(int reg)
356 uint64_t r = env->regs[reg];
359 if (!(env->psw.mask & PSW_MASK_64)) {
366 /* search string (c is byte to search, r2 is string, r1 end of string) */
367 uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2)
371 uint64_t str = get_address_31fix(r2);
372 uint64_t end = get_address_31fix(r1);
374 HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__,
375 c, env->regs[r1], env->regs[r2]);
377 for (i = str; i != end; i++) {
388 /* unsigned string compare (c is string terminator) */
389 uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2)
391 uint64_t s1 = get_address_31fix(r1);
392 uint64_t s2 = get_address_31fix(r2);
397 #ifdef CONFIG_USER_ONLY
399 HELPER_LOG("%s: comparing '%s' and '%s'\n",
400 __func__, (char *)g2h(s1), (char *)g2h(s2));
406 if ((v1 == c || v2 == c) || (v1 != v2)) {
416 cc = (v1 < v2) ? 1 : 2;
417 /* FIXME: 31-bit mode! */
425 void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2)
427 /* XXX missing r0 handling */
428 #ifdef CONFIG_USER_ONLY
431 for (i = 0; i < TARGET_PAGE_SIZE; i++) {
432 stb(r1 + i, ldub(r2 + i));
435 mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
439 /* string copy (c is string terminator) */
440 void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2)
442 uint64_t dest = get_address_31fix(r1);
443 uint64_t src = get_address_31fix(r2);
447 #ifdef CONFIG_USER_ONLY
449 HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src),
462 env->regs[r1] = dest; /* FIXME: 31-bit mode! */
465 /* compare and swap 64-bit */
466 uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3)
468 /* FIXME: locking? */
470 uint64_t v2 = ldq(a2);
472 if (env->regs[r1] == v2) {
474 stq(a2, env->regs[r3]);
482 /* compare double and swap 64-bit */
483 uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3)
485 /* FIXME: locking? */
487 uint64_t v2_hi = ldq(a2);
488 uint64_t v2_lo = ldq(a2 + 8);
489 uint64_t v1_hi = env->regs[r1];
490 uint64_t v1_lo = env->regs[r1 + 1];
492 if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
494 stq(a2, env->regs[r3]);
495 stq(a2 + 8, env->regs[r3 + 1]);
498 env->regs[r1] = v2_hi;
499 env->regs[r1 + 1] = v2_lo;
505 /* compare and swap 32-bit */
506 uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3)
508 /* FIXME: locking? */
510 uint32_t v2 = ldl(a2);
512 HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3);
513 if (((uint32_t)env->regs[r1]) == v2) {
515 stl(a2, (uint32_t)env->regs[r3]);
518 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2;
523 static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask)
525 int pos = 24; /* top of the lower half of r1 */
526 uint64_t rmask = 0xff000000ULL;
533 env->regs[r1] &= ~rmask;
535 if ((val & 0x80) && !ccd) {
539 if (val && cc == 0) {
542 env->regs[r1] |= (uint64_t)val << pos;
545 mask = (mask << 1) & 0xf;
553 /* execute instruction
554 this instruction executes an insn modified with the contents of r1
555 it does not change the executed instruction in memory
556 it does not change the program counter
557 in other words: tricky...
558 currently implemented by interpreting the cases it is most commonly used in
560 uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret)
562 uint16_t insn = lduw_code(addr);
564 HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
566 if ((insn & 0xf0ff) == 0xd000) {
567 uint32_t l, insn2, b1, b2, d1, d2;
570 insn2 = ldl_code(addr + 2);
571 b1 = (insn2 >> 28) & 0xf;
572 b2 = (insn2 >> 12) & 0xf;
573 d1 = (insn2 >> 16) & 0xfff;
575 switch (insn & 0xf00) {
577 helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2));
580 cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2));
583 cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2));
586 helper_tr(l, get_address(0, b1, d1), get_address(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_ilc = 4;
598 helper_exception(EXCP_SVC);
599 } else if ((insn & 0xff00) == 0xbf00) {
600 uint32_t insn2, r1, r3, b2, d2;
602 insn2 = ldl_code(addr + 2);
603 r1 = (insn2 >> 20) & 0xf;
604 r3 = (insn2 >> 16) & 0xf;
605 b2 = (insn2 >> 12) & 0xf;
607 cc = helper_icm(r1, get_address(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)(uint32_t r1, uint64_t address, uint32_t mask)
619 int pos = 56; /* top of the upper half of r1 */
623 stb(address, (env->regs[r1] >> pos) & 0xff);
626 mask = (mask << 1) & 0xf;
631 /* insert character under mask high; same as icm, but operates on the
633 uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask)
635 int pos = 56; /* top of the upper half of r1 */
636 uint64_t rmask = 0xff00000000000000ULL;
643 env->regs[r1] &= ~rmask;
645 if ((val & 0x80) && !ccd) {
649 if (val && cc == 0) {
652 env->regs[r1] |= (uint64_t)val << pos;
655 mask = (mask << 1) & 0xf;
663 /* load access registers r1 to r3 from memory at a2 */
664 void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3)
668 for (i = r1;; i = (i + 1) % 16) {
669 env->aregs[i] = ldl(a2);
678 /* store access registers r1 to r3 in memory at a2 */
679 void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3)
683 for (i = r1;; i = (i + 1) % 16) {
684 stl(a2, env->aregs[i]);
694 uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2)
696 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
697 uint64_t dest = get_address_31fix(r1);
698 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
699 uint64_t src = get_address_31fix(r2);
700 uint8_t pad = src >> 24;
704 if (destlen == srclen) {
706 } else if (destlen < srclen) {
712 if (srclen > destlen) {
716 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
721 for (; destlen; dest++, destlen--) {
725 env->regs[r1 + 1] = destlen;
726 /* can't use srclen here, we trunc'ed it */
727 env->regs[r2 + 1] -= src - env->regs[r2];
728 env->regs[r1] = dest;
734 /* move long extended another memcopy insn with more bells and whistles */
735 uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3)
737 uint64_t destlen = env->regs[r1 + 1];
738 uint64_t dest = env->regs[r1];
739 uint64_t srclen = env->regs[r3 + 1];
740 uint64_t src = env->regs[r3];
741 uint8_t pad = a2 & 0xff;
745 if (!(env->psw.mask & PSW_MASK_64)) {
746 destlen = (uint32_t)destlen;
747 srclen = (uint32_t)srclen;
752 if (destlen == srclen) {
754 } else if (destlen < srclen) {
760 if (srclen > destlen) {
764 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
769 for (; destlen; dest++, destlen--) {
773 env->regs[r1 + 1] = destlen;
774 /* can't use srclen here, we trunc'ed it */
775 /* FIXME: 31-bit mode! */
776 env->regs[r3 + 1] -= src - env->regs[r3];
777 env->regs[r1] = dest;
783 /* compare logical long extended memcompare insn with padding */
784 uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3)
786 uint64_t destlen = env->regs[r1 + 1];
787 uint64_t dest = get_address_31fix(r1);
788 uint64_t srclen = env->regs[r3 + 1];
789 uint64_t src = get_address_31fix(r3);
790 uint8_t pad = a2 & 0xff;
791 uint8_t v1 = 0, v2 = 0;
794 if (!(destlen || srclen)) {
798 if (srclen > destlen) {
802 for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
803 v1 = srclen ? ldub(src) : pad;
804 v2 = destlen ? ldub(dest) : pad;
806 cc = (v1 < v2) ? 1 : 2;
811 env->regs[r1 + 1] = destlen;
812 /* can't use srclen here, we trunc'ed it */
813 env->regs[r3 + 1] -= src - env->regs[r3];
814 env->regs[r1] = dest;
821 void HELPER(cksm)(uint32_t r1, uint32_t r2)
823 uint64_t src = get_address_31fix(r2);
824 uint64_t src_len = env->regs[(r2 + 1) & 15];
825 uint64_t cksm = (uint32_t)env->regs[r1];
827 while (src_len >= 4) {
830 /* move to next word */
839 cksm += ldub(src) << 24;
842 cksm += lduw(src) << 16;
845 cksm += lduw(src) << 16;
846 cksm += ldub(src + 2) << 8;
850 /* indicate we've processed everything */
851 env->regs[r2] = src + src_len;
852 env->regs[(r2 + 1) & 15] = 0;
855 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
856 ((uint32_t)cksm + (cksm >> 32));
859 void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src)
861 int len_dest = len >> 4;
862 int len_src = len & 0xf;
864 int second_nibble = 0;
869 /* last byte is special, it only flips the nibbles */
871 stb(dest, (b << 4) | (b >> 4));
875 /* now pad every nibble with 0xf0 */
877 while (len_dest > 0) {
878 uint8_t cur_byte = 0;
881 cur_byte = ldub(src);
887 /* only advance one nibble at a time */
893 second_nibble = !second_nibble;
896 cur_byte = (cur_byte & 0xf);
904 void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans)
908 for (i = 0; i <= len; i++) {
909 uint8_t byte = ldub(array + i);
910 uint8_t new_byte = ldub(trans + byte);
912 stb(array + i, new_byte);
916 #if !defined(CONFIG_USER_ONLY)
917 void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3)
922 for (i = r1;; i = (i + 1) % 16) {
923 env->cregs[i] = ldq(src);
924 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
925 i, src, env->cregs[i]);
926 src += sizeof(uint64_t);
936 void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3)
941 for (i = r1;; i = (i + 1) % 16) {
942 env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src);
943 src += sizeof(uint32_t);
953 void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3)
958 for (i = r1;; i = (i + 1) % 16) {
959 stq(dest, env->cregs[i]);
960 dest += sizeof(uint64_t);
968 void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3)
973 for (i = r1;; i = (i + 1) % 16) {
974 stl(dest, env->cregs[i]);
975 dest += sizeof(uint32_t);
983 uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
990 /* insert storage key extended */
991 uint64_t HELPER(iske)(uint64_t r2)
993 uint64_t addr = get_address(0, 0, r2);
995 if (addr > ram_size) {
999 return env->storage_keys[addr / TARGET_PAGE_SIZE];
1002 /* set storage key extended */
1003 void HELPER(sske)(uint32_t r1, uint64_t r2)
1005 uint64_t addr = get_address(0, 0, r2);
1007 if (addr > ram_size) {
1011 env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
1014 /* reset reference bit extended */
1015 uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2)
1020 if (r2 > ram_size) {
1024 key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
1025 re = key & (SK_R | SK_C);
1026 env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
1031 * 0 Reference bit zero; change bit zero
1032 * 1 Reference bit zero; change bit one
1033 * 2 Reference bit one; change bit zero
1034 * 3 Reference bit one; change bit one
1040 /* compare and swap and purge */
1041 uint32_t HELPER(csp)(uint32_t r1, uint32_t r2)
1044 uint32_t o1 = env->regs[r1];
1045 uint64_t a2 = get_address_31fix(r2) & ~3ULL;
1046 uint32_t o2 = ldl(a2);
1049 stl(a2, env->regs[(r1 + 1) & 15]);
1050 if (env->regs[r2] & 0x3) {
1051 /* flush TLB / ALB */
1056 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
1063 static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2,
1066 target_ulong src, dest;
1067 int flags, cc = 0, i;
1071 } else if (l > 256) {
1077 if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
1080 dest |= a1 & ~TARGET_PAGE_MASK;
1082 if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
1085 src |= a2 & ~TARGET_PAGE_MASK;
1087 /* XXX replace w/ memcpy */
1088 for (i = 0; i < l; i++) {
1089 /* XXX be more clever */
1090 if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
1091 (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
1092 mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2);
1095 stb_phys(dest + i, ldub_phys(src + i));
1101 uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2)
1103 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1104 __func__, l, a1, a2);
1106 return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
1109 uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2)
1111 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1112 __func__, l, a1, a2);
1114 return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
1117 /* invalidate pte */
1118 void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr)
1120 uint64_t page = vaddr & TARGET_PAGE_MASK;
1123 /* XXX broadcast to other CPUs */
1125 /* XXX Linux is nice enough to give us the exact pte address.
1126 According to spec we'd have to find it out ourselves */
1127 /* XXX Linux is fine with overwriting the pte, the spec requires
1128 us to only set the invalid bit */
1129 stq_phys(pte_addr, pte | _PAGE_INVALID);
1131 /* XXX we exploit the fact that Linux passes the exact virtual
1132 address here - it's not obliged to! */
1133 tlb_flush_page(env, page);
1135 /* XXX 31-bit hack */
1136 if (page & 0x80000000) {
1137 tlb_flush_page(env, page & ~0x80000000);
1139 tlb_flush_page(env, page | 0x80000000);
1143 /* flush local tlb */
1144 void HELPER(ptlb)(void)
1149 /* store using real address */
1150 void HELPER(stura)(uint64_t addr, uint32_t v1)
1152 stw_phys(get_address(0, 0, addr), v1);
1155 /* load real address */
1156 uint32_t HELPER(lra)(uint64_t addr, uint32_t r1)
1159 int old_exc = env->exception_index;
1160 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1164 /* XXX incomplete - has more corner cases */
1165 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1166 program_interrupt(env, PGM_SPECIAL_OP, 2);
1169 env->exception_index = old_exc;
1170 if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
1173 if (env->exception_index == EXCP_PGM) {
1174 ret = env->int_pgm_code | 0x80000000;
1176 ret |= addr & ~TARGET_PAGE_MASK;
1178 env->exception_index = old_exc;
1180 if (!(env->psw.mask & PSW_MASK_64)) {
1181 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
1182 (ret & 0xffffffffULL);
1184 env->regs[r1] = ret;
1192 /* temporary wrappers */
1193 #if defined(CONFIG_USER_ONLY)
1194 #define ldub_data(addr) ldub_raw(addr)
1195 #define lduw_data(addr) lduw_raw(addr)
1196 #define ldl_data(addr) ldl_raw(addr)
1197 #define ldq_data(addr) ldq_raw(addr)
1199 #define stb_data(addr, data) stb_raw(addr, data)
1200 #define stw_data(addr, data) stw_raw(addr, data)
1201 #define stl_data(addr, data) stl_raw(addr, data)
1202 #define stq_data(addr, data) stq_raw(addr, data)
1205 #define WRAP_LD(rettype, fn) \
1206 rettype cpu_ ## fn(CPUS390XState *env1, target_ulong addr) \
1208 CPUS390XState *saved_env; \
1218 WRAP_LD(uint32_t, ldub_data)
1219 WRAP_LD(uint32_t, lduw_data)
1220 WRAP_LD(uint32_t, ldl_data)
1221 WRAP_LD(uint64_t, ldq_data)
1224 #define WRAP_ST(datatype, fn) \
1225 void cpu_ ## fn(CPUS390XState *env1, target_ulong addr, datatype val) \
1227 CPUS390XState *saved_env; \
1235 WRAP_ST(uint32_t, stb_data)
1236 WRAP_ST(uint32_t, stw_data)
1237 WRAP_ST(uint32_t, stl_data)
1238 WRAP_ST(uint64_t, stq_data)