diff options
Diffstat (limited to 'target/s390x/mem_helper.c')
-rw-r--r-- | target/s390x/mem_helper.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 20cef9a3e5..ede84711d1 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1610,6 +1610,57 @@ uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) return cc; } +void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4) +{ + CPUState *cs = CPU(s390_env_get_cpu(env)); + const uintptr_t ra = GETPC(); + uint64_t table, entry, raddr; + uint16_t entries, i, index = 0; + + if (r2 & 0xff000) { + cpu_restore_state(cs, ra); + program_interrupt(env, PGM_SPECIFICATION, 4); + } + + if (!(r2 & 0x800)) { + /* invalidation-and-clearing operation */ + table = r1 & _ASCE_ORIGIN; + entries = (r2 & 0x7ff) + 1; + + switch (r1 & _ASCE_TYPE_MASK) { + case _ASCE_TYPE_REGION1: + index = (r2 >> 53) & 0x7ff; + break; + case _ASCE_TYPE_REGION2: + index = (r2 >> 42) & 0x7ff; + break; + case _ASCE_TYPE_REGION3: + index = (r2 >> 31) & 0x7ff; + break; + case _ASCE_TYPE_SEGMENT: + index = (r2 >> 20) & 0x7ff; + break; + } + for (i = 0; i < entries; i++) { + /* addresses are not wrapped in 24/31bit mode but table index is */ + raddr = table + ((index + i) & 0x7ff) * sizeof(entry); + entry = ldq_phys(cs->as, raddr); + if (!(entry & _REGION_ENTRY_INV)) { + /* we are allowed to not store if already invalid */ + entry |= _REGION_ENTRY_INV; + stq_phys(cs->as, raddr, entry); + } + } + } + + /* We simply flush the complete tlb, therefore we can ignore r3. */ + if (m4 & 1) { + tlb_flush(cs); + } else { + tlb_flush_all_cpus_synced(cs); + } +} + /* invalidate pte */ void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr, uint32_t m4) |