aboutsummaryrefslogtreecommitdiff
path: root/target/s390x/tcg/mem_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/s390x/tcg/mem_helper.c')
-rw-r--r--target/s390x/tcg/mem_helper.c53
1 files changed, 38 insertions, 15 deletions
diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c
index 21a4de4067..0bf775a37d 100644
--- a/target/s390x/tcg/mem_helper.c
+++ b/target/s390x/tcg/mem_helper.c
@@ -28,6 +28,7 @@
#include "qemu/int128.h"
#include "qemu/atomic128.h"
#include "tcg/tcg.h"
+#include "trace.h"
#if !defined(CONFIG_USER_ONLY)
#include "hw/s390x/storage-keys.h"
@@ -2171,22 +2172,28 @@ uint32_t HELPER(tprot)(CPUS390XState *env, uint64_t a1, uint64_t a2)
/* insert storage key extended */
uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
{
- MachineState *ms = MACHINE(qdev_get_machine());
static S390SKeysState *ss;
static S390SKeysClass *skeyclass;
uint64_t addr = wrap_address(env, r2);
uint8_t key;
+ int rc;
- if (addr > ms->ram_size) {
- return 0;
+ addr = mmu_real2abs(env, addr);
+ if (!mmu_absolute_addr_valid(addr, false)) {
+ tcg_s390_program_interrupt(env, PGM_ADDRESSING, GETPC());
}
if (unlikely(!ss)) {
ss = s390_get_skeys_device();
skeyclass = S390_SKEYS_GET_CLASS(ss);
+ if (skeyclass->enable_skeys && !skeyclass->enable_skeys(ss)) {
+ tlb_flush_all_cpus_synced(env_cpu(env));
+ }
}
- if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
+ rc = skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
+ if (rc) {
+ trace_get_skeys_nonzero(rc);
return 0;
}
return key;
@@ -2195,23 +2202,30 @@ uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
/* set storage key extended */
void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
{
- MachineState *ms = MACHINE(qdev_get_machine());
static S390SKeysState *ss;
static S390SKeysClass *skeyclass;
uint64_t addr = wrap_address(env, r2);
uint8_t key;
+ int rc;
- if (addr > ms->ram_size) {
- return;
+ addr = mmu_real2abs(env, addr);
+ if (!mmu_absolute_addr_valid(addr, false)) {
+ tcg_s390_program_interrupt(env, PGM_ADDRESSING, GETPC());
}
if (unlikely(!ss)) {
ss = s390_get_skeys_device();
skeyclass = S390_SKEYS_GET_CLASS(ss);
+ if (skeyclass->enable_skeys && !skeyclass->enable_skeys(ss)) {
+ tlb_flush_all_cpus_synced(env_cpu(env));
+ }
}
- key = (uint8_t) r1;
- skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
+ key = r1 & 0xfe;
+ rc = skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
+ if (rc) {
+ trace_set_skeys_nonzero(rc);
+ }
/*
* As we can only flush by virtual address and not all the entries
* that point to a physical address we have to flush the whole TLB.
@@ -2222,28 +2236,37 @@ void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
/* reset reference bit extended */
uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
{
- MachineState *ms = MACHINE(qdev_get_machine());
+ uint64_t addr = wrap_address(env, r2);
static S390SKeysState *ss;
static S390SKeysClass *skeyclass;
uint8_t re, key;
+ int rc;
- if (r2 > ms->ram_size) {
- return 0;
+ addr = mmu_real2abs(env, addr);
+ if (!mmu_absolute_addr_valid(addr, false)) {
+ tcg_s390_program_interrupt(env, PGM_ADDRESSING, GETPC());
}
if (unlikely(!ss)) {
ss = s390_get_skeys_device();
skeyclass = S390_SKEYS_GET_CLASS(ss);
+ if (skeyclass->enable_skeys && !skeyclass->enable_skeys(ss)) {
+ tlb_flush_all_cpus_synced(env_cpu(env));
+ }
}
- if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
+ rc = skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
+ if (rc) {
+ trace_get_skeys_nonzero(rc);
return 0;
}
re = key & (SK_R | SK_C);
key &= ~SK_R;
- if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
+ rc = skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
+ if (rc) {
+ trace_set_skeys_nonzero(rc);
return 0;
}
/*
@@ -2441,7 +2464,7 @@ uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, GETPC());
}
- exc = mmu_translate(env, addr, 0, asc, &ret, &flags, &tec);
+ exc = mmu_translate(env, addr, MMU_S390_LRA, asc, &ret, &flags, &tec);
if (exc) {
cc = 3;
ret = exc | 0x80000000;