diff options
Diffstat (limited to 'target/s390x/mem_helper.c')
| -rw-r--r-- | target/s390x/mem_helper.c | 84 |
1 files changed, 44 insertions, 40 deletions
diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 44e535856d..2325767f17 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "internal.h" +#include "tcg_s390x.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" @@ -71,7 +72,7 @@ static inline void check_alignment(CPUS390XState *env, uint64_t v, int wordsize, uintptr_t ra) { if (v % wordsize) { - s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); + tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra); } } @@ -730,7 +731,7 @@ void HELPER(srst)(CPUS390XState *env, uint32_t r1, uint32_t r2) /* Bits 32-55 must contain all 0. */ if (env->regs[0] & 0xffffff00u) { - s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); + tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra); } str = get_address(env, r2); @@ -767,7 +768,7 @@ void HELPER(srstu)(CPUS390XState *env, uint32_t r1, uint32_t r2) /* Bits 32-47 of R0 must be zero. */ if (env->regs[0] & 0xffff0000u) { - s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); + tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra); } str = get_address(env, r2); @@ -846,7 +847,7 @@ uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2) S390Access srca, desta; if ((f && s) || extract64(r0, 12, 4)) { - s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC()); + tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); } r1 = wrap_address(env, r1 & TARGET_PAGE_MASK); @@ -879,7 +880,7 @@ uint32_t HELPER(mvst)(CPUS390XState *env, uint32_t r1, uint32_t r2) int i; if (env->regs[0] & 0xffffff00ull) { - s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra); + tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra); } /* @@ -911,8 +912,7 @@ void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) int i; if (a2 & 0x3) { - /* we either came here by lam or lamy, which have different lengths */ - s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra); + tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra); } for (i = r1;; i = (i + 1) % 16) { @@ -932,7 +932,7 @@ void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) int i; if (a2 & 0x3) { - s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); + tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra); } for (i = r1;; i = (i + 1) % 16) { @@ -1015,6 +1015,7 @@ uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) uint64_t srclen = env->regs[r2 + 1] & 0xffffff; uint64_t src = get_address(env, r2); uint8_t pad = env->regs[r2 + 1] >> 24; + CPUState *cs = env_cpu(env); S390Access srca, desta; uint32_t cc, cur_len; @@ -1065,7 +1066,15 @@ uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, destlen); set_address_zero(env, r1, dest); - /* TODO: Deliver interrupts. */ + /* + * MVCL is interruptible. Return to the main loop if requested after + * writing back all state to registers. If no interrupt will get + * injected, we'll end up back in this handler and continue processing + * the remaining parts. + */ + if (destlen && unlikely(cpu_loop_exit_requested(cs))) { + cpu_loop_exit_restore(cs, ra); + } } return cc; } @@ -1888,8 +1897,7 @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1, return cc; spec_exception: - s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); - g_assert_not_reached(); + tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra); } uint32_t HELPER(csst)(CPUS390XState *env, uint32_t r3, uint64_t a1, uint64_t a2) @@ -1912,7 +1920,7 @@ void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) uint32_t i; if (src & 0x7) { - s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); + tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra); } for (i = r1;; i = (i + 1) % 16) { @@ -1945,7 +1953,7 @@ void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) uint32_t i; if (src & 0x3) { - s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); + tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra); } for (i = r1;; i = (i + 1) % 16) { @@ -1976,7 +1984,7 @@ void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) uint32_t i; if (dest & 0x7) { - s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); + tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra); } for (i = r1;; i = (i + 1) % 16) { @@ -1996,7 +2004,7 @@ void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) uint32_t i; if (dest & 0x3) { - s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); + tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra); } for (i = r1;; i = (i + 1) % 16) { @@ -2168,7 +2176,7 @@ uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) || psw_as == AS_HOME || psw_as == AS_ACCREG) { - s390_program_interrupt(env, PGM_SPECIAL_OP, ILEN_AUTO, ra); + s390_program_interrupt(env, PGM_SPECIAL_OP, ra); } l = wrap_length32(env, l); @@ -2199,7 +2207,7 @@ uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) || psw_as == AS_HOME || psw_as == AS_ACCREG) { - s390_program_interrupt(env, PGM_SPECIAL_OP, ILEN_AUTO, ra); + s390_program_interrupt(env, PGM_SPECIAL_OP, ra); } l = wrap_length32(env, l); @@ -2226,7 +2234,7 @@ void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4) uint16_t entries, i, index = 0; if (r2 & 0xff000) { - s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); + tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra); } if (!(r2 & 0x800)) { @@ -2252,9 +2260,9 @@ void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4) /* addresses are not wrapped in 24/31bit mode but table index is */ raddr = table + ((index + i) & 0x7ff) * sizeof(entry); entry = cpu_ldq_real_ra(env, raddr, ra); - if (!(entry & REGION_ENTRY_INV)) { + if (!(entry & REGION_ENTRY_I)) { /* we are allowed to not store if already invalid */ - entry |= REGION_ENTRY_INV; + entry |= REGION_ENTRY_I; cpu_stq_real_ra(env, raddr, entry, ra); } } @@ -2279,17 +2287,17 @@ void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr, /* Compute the page table entry address */ pte_addr = (pto & SEGMENT_ENTRY_ORIGIN); - pte_addr += (vaddr & VADDR_PX) >> 9; + pte_addr += VADDR_PAGE_TX(vaddr) * 8; /* Mark the page table entry as invalid */ pte = cpu_ldq_real_ra(env, pte_addr, ra); - pte |= PAGE_INVALID; + pte |= PAGE_ENTRY_I; cpu_stq_real_ra(env, pte_addr, pte, ra); /* XXX we exploit the fact that Linux passes the exact virtual address here - it's not obliged to! */ if (m4 & 1) { - if (vaddr & ~VADDR_PX) { + if (vaddr & ~VADDR_PAGE_TX_MASK) { tlb_flush_page(cs, page); /* XXX 31-bit hack */ tlb_flush_page(cs, page ^ 0x80000000); @@ -2298,7 +2306,7 @@ void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr, tlb_flush(cs); } } else { - if (vaddr & ~VADDR_PX) { + if (vaddr & ~VADDR_PAGE_TX_MASK) { tlb_flush_page_all_cpus_synced(cs, page); /* XXX 31-bit hack */ tlb_flush_page_all_cpus_synced(cs, page ^ 0x80000000); @@ -2362,27 +2370,23 @@ void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1) /* load real address */ uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr) { - CPUState *cs = env_cpu(env); - uint32_t cc = 0; uint64_t asc = env->psw.mask & PSW_MASK_ASC; - uint64_t ret; - int old_exc, flags; + uint64_t ret, tec; + int flags, exc, cc; /* XXX incomplete - has more corner cases */ if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) { - s390_program_interrupt(env, PGM_SPECIAL_OP, 2, GETPC()); + tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, GETPC()); } - old_exc = cs->exception_index; - if (mmu_translate(env, addr, 0, asc, &ret, &flags, true)) { + exc = mmu_translate(env, addr, 0, asc, &ret, &flags, &tec); + if (exc) { cc = 3; - } - if (cs->exception_index == EXCP_PGM) { - ret = env->int_pgm_code | 0x80000000; + ret = exc | 0x80000000; } else { + cc = 0; ret |= addr & ~TARGET_PAGE_MASK; } - cs->exception_index = old_exc; env->cc_op = cc; return ret; @@ -2539,7 +2543,7 @@ uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src, __func__, dest, src, len); if (!(env->psw.mask & PSW_MASK_DAT)) { - s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra); + tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra); } /* OAC (operand access control) for the first operand -> dest */ @@ -2570,14 +2574,14 @@ uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src, } if (dest_a && dest_as == AS_HOME && (env->psw.mask & PSW_MASK_PSTATE)) { - s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra); + tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra); } if (!(env->cregs[0] & CR0_SECONDARY) && (dest_as == AS_SECONDARY || src_as == AS_SECONDARY)) { - s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra); + tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra); } if (!psw_key_valid(env, dest_key) || !psw_key_valid(env, src_key)) { - s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra); + tcg_s390_program_interrupt(env, PGM_PRIVILEGED, ra); } len = wrap_length32(env, len); @@ -2591,7 +2595,7 @@ uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src, (env->psw.mask & PSW_MASK_PSTATE)) { qemu_log_mask(LOG_UNIMP, "%s: AR-mode and PSTATE support missing\n", __func__); - s390_program_interrupt(env, PGM_ADDRESSING, 6, ra); + tcg_s390_program_interrupt(env, PGM_ADDRESSING, ra); } /* FIXME: Access using correct keys and AR-mode */ |