aboutsummaryrefslogtreecommitdiff
path: root/target-s390x
diff options
context:
space:
mode:
Diffstat (limited to 'target-s390x')
-rw-r--r--target-s390x/cpu.h2
-rw-r--r--target-s390x/mem_helper.c46
-rw-r--r--target-s390x/mmu_helper.c28
3 files changed, 63 insertions, 13 deletions
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 63aebf4846..b650890130 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -143,8 +143,6 @@ typedef struct CPUS390XState {
uint32_t cpu_num;
uint32_t machine_type;
- uint8_t *storage_keys;
-
uint64_t tod_offset;
uint64_t tod_basetime;
QEMUTimer *tod_timer;
diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c
index 6f8bd796ad..84bf198e2b 100644
--- a/target-s390x/mem_helper.c
+++ b/target-s390x/mem_helper.c
@@ -21,6 +21,7 @@
#include "cpu.h"
#include "exec/helper-proto.h"
#include "exec/cpu_ldst.h"
+#include "hw/s390x/storage-keys.h"
/*****************************************************************************/
/* Softmmu support */
@@ -937,40 +938,73 @@ uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
/* insert storage key extended */
uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
{
+ static S390SKeysState *ss;
+ static S390SKeysClass *skeyclass;
uint64_t addr = get_address(env, 0, 0, r2);
+ uint8_t key;
if (addr > ram_size) {
return 0;
}
- return env->storage_keys[addr / TARGET_PAGE_SIZE];
+ if (unlikely(!ss)) {
+ ss = s390_get_skeys_device();
+ skeyclass = S390_SKEYS_GET_CLASS(ss);
+ }
+
+ if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
+ return 0;
+ }
+ return key;
}
/* set storage key extended */
void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
{
+ static S390SKeysState *ss;
+ static S390SKeysClass *skeyclass;
uint64_t addr = get_address(env, 0, 0, r2);
+ uint8_t key;
if (addr > ram_size) {
return;
}
- env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
+ if (unlikely(!ss)) {
+ ss = s390_get_skeys_device();
+ skeyclass = S390_SKEYS_GET_CLASS(ss);
+ }
+
+ key = (uint8_t) r1;
+ skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
}
/* reset reference bit extended */
uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
{
- uint8_t re;
- uint8_t key;
+ static S390SKeysState *ss;
+ static S390SKeysClass *skeyclass;
+ uint8_t re, key;
if (r2 > ram_size) {
return 0;
}
- key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
+ if (unlikely(!ss)) {
+ ss = s390_get_skeys_device();
+ skeyclass = S390_SKEYS_GET_CLASS(ss);
+ }
+
+ if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
+ return 0;
+ }
+
re = key & (SK_R | SK_C);
- env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
+ key &= ~SK_R;
+
+ if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
+ return 0;
+ }
/*
* cc
diff --git a/target-s390x/mmu_helper.c b/target-s390x/mmu_helper.c
index 1ea6d812c2..058a37013b 100644
--- a/target-s390x/mmu_helper.c
+++ b/target-s390x/mmu_helper.c
@@ -19,6 +19,8 @@
#include "exec/address-spaces.h"
#include "cpu.h"
#include "sysemu/kvm.h"
+#include "trace.h"
+#include "hw/s390x/storage-keys.h"
/* #define DEBUG_S390 */
/* #define DEBUG_S390_PTE */
@@ -309,8 +311,15 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr,
int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
target_ulong *raddr, int *flags, bool exc)
{
+ static S390SKeysState *ss;
+ static S390SKeysClass *skeyclass;
int r = -1;
- uint8_t *sk;
+ uint8_t key;
+
+ if (unlikely(!ss)) {
+ ss = s390_get_skeys_device();
+ skeyclass = S390_SKEYS_GET_CLASS(ss);
+ }
*flags = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
vaddr &= TARGET_PAGE_MASK;
@@ -358,14 +367,23 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
/* Convert real address -> absolute address */
*raddr = mmu_real2abs(env, *raddr);
- if (*raddr < ram_size) {
- sk = &env->storage_keys[*raddr / TARGET_PAGE_SIZE];
+ if (r == 0 && *raddr < ram_size) {
+ if (skeyclass->get_skeys(ss, *raddr / TARGET_PAGE_SIZE, 1, &key)) {
+ trace_get_skeys_nonzero(r);
+ return 0;
+ }
+
if (*flags & PAGE_READ) {
- *sk |= SK_R;
+ key |= SK_R;
}
if (*flags & PAGE_WRITE) {
- *sk |= SK_C;
+ key |= SK_C;
+ }
+
+ if (skeyclass->set_skeys(ss, *raddr / TARGET_PAGE_SIZE, 1, &key)) {
+ trace_set_skeys_nonzero(r);
+ return 0;
}
}