s390x/tcg: check for addressing exceptions for RRBE, SSKE and ISKE

Let's replace the ram_size check by a proper physical address space
check (for example, to prepare for memory hotplug), trigger addressing
exceptions and trace the return value of the storage key getter/setter.

Provide an helper mmu_absolute_addr_valid() to be used in other context
soon. Always test for "read" instead of "write" as we are not actually
modifying the page itself.

Signed-off-by: David Hildenbrand <david@redhat.com>
Acked-by: Thomas Huth <thuth@redhat.com>
Message-Id: <20210903155514.44772-5-david@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
This commit is contained in:
David Hildenbrand 2021-09-03 17:55:05 +02:00 committed by Thomas Huth
parent 06d8a10a70
commit eaa0feea75
4 changed files with 35 additions and 16 deletions

View file

@ -336,9 +336,9 @@ DEF_HELPER_FLAGS_4(stctl, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_FLAGS_4(stctg, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_FLAGS_2(testblock, TCG_CALL_NO_WG, i32, env, i64)
DEF_HELPER_FLAGS_3(tprot, TCG_CALL_NO_WG, i32, env, i64, i64)
DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64)
DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64)
DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_NO_RWG, i32, env, i64)
DEF_HELPER_2(iske, i64, env, i64)
DEF_HELPER_3(sske, void, env, i64, i64)
DEF_HELPER_2(rrbe, i32, env, i64)
DEF_HELPER_4(mvcs, i32, env, i64, i64, i64)
DEF_HELPER_4(mvcp, i32, env, i64, i64, i64)
DEF_HELPER_4(sigp, i32, env, i64, i32, i32)

View file

@ -94,6 +94,14 @@ target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr)
return raddr;
}
bool mmu_absolute_addr_valid(target_ulong addr, bool is_write)
{
return address_space_access_valid(&address_space_memory,
addr & TARGET_PAGE_MASK,
TARGET_PAGE_SIZE, is_write,
MEMTXATTRS_UNSPECIFIED);
}
static inline bool read_table_entry(CPUS390XState *env, hwaddr gaddr,
uint64_t *entry)
{

View file

@ -373,6 +373,7 @@ void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
/* mmu_helper.c */
bool mmu_absolute_addr_valid(target_ulong addr, bool is_write);
int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
target_ulong *raddr, int *flags, uint64_t *tec);
int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw,

View file

@ -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,15 +2172,15 @@ 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;
addr = mmu_real2abs(env, addr);
if (addr > ms->ram_size) {
return 0;
if (!mmu_absolute_addr_valid(addr, false)) {
tcg_s390_program_interrupt(env, PGM_ADDRESSING, GETPC());
}
if (unlikely(!ss)) {
@ -2187,7 +2188,9 @@ uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
skeyclass = S390_SKEYS_GET_CLASS(ss);
}
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;
@ -2196,15 +2199,15 @@ 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;
addr = mmu_real2abs(env, addr);
if (addr > ms->ram_size) {
return;
if (!mmu_absolute_addr_valid(addr, false)) {
tcg_s390_program_interrupt(env, PGM_ADDRESSING, GETPC());
}
if (unlikely(!ss)) {
@ -2213,7 +2216,10 @@ void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
}
key = r1 & 0xfe;
skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
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.
@ -2224,15 +2230,15 @@ 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;
addr = mmu_real2abs(env, addr);
if (addr > ms->ram_size) {
return 0;
if (!mmu_absolute_addr_valid(addr, false)) {
tcg_s390_program_interrupt(env, PGM_ADDRESSING, GETPC());
}
if (unlikely(!ss)) {
@ -2240,14 +2246,18 @@ uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
skeyclass = S390_SKEYS_GET_CLASS(ss);
}
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;
}
re = key & (SK_R | SK_C);
key &= ~SK_R;
if (skeyclass->set_skeys(ss, addr / 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;
}
/*