mirror of https://gitee.com/openkylin/qemu.git
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:
parent
06d8a10a70
commit
eaa0feea75
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue