mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-07 09:43:56 -06:00
s390x/mmu: Factor out storage key handling
Factor it out, add a comment how it all works, and also use it in the REAL MMU. Reviewed-by: Cornelia Huck <cohuck@redhat.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Signed-off-by: David Hildenbrand <david@redhat.com> Message-Id: <20190816084708.602-7-david@redhat.com> Signed-off-by: Cornelia Huck <cohuck@redhat.com>
This commit is contained in:
parent
2d3bb388ad
commit
065fe80fe0
1 changed files with 71 additions and 44 deletions
|
@ -335,6 +335,75 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mmu_handle_skey(target_ulong addr, int rw, int *flags)
|
||||||
|
{
|
||||||
|
static S390SKeysClass *skeyclass;
|
||||||
|
static S390SKeysState *ss;
|
||||||
|
uint8_t key;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (unlikely(addr >= ram_size)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely(!ss)) {
|
||||||
|
ss = s390_get_skeys_device();
|
||||||
|
skeyclass = S390_SKEYS_GET_CLASS(ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Whenever we create a new TLB entry, we set the storage key reference
|
||||||
|
* bit. In case we allow write accesses, we set the storage key change
|
||||||
|
* bit. Whenever the guest changes the storage key, we have to flush the
|
||||||
|
* TLBs of all CPUs (the whole TLB or all affected entries), so that the
|
||||||
|
* next reference/change will result in an MMU fault and make us properly
|
||||||
|
* update the storage key here.
|
||||||
|
*
|
||||||
|
* Note 1: "record of references ... is not necessarily accurate",
|
||||||
|
* "change bit may be set in case no storing has occurred".
|
||||||
|
* -> We can set reference/change bits even on exceptions.
|
||||||
|
* Note 2: certain accesses seem to ignore storage keys. For example,
|
||||||
|
* DAT translation does not set reference bits for table accesses.
|
||||||
|
*
|
||||||
|
* TODO: key-controlled protection. Only CPU accesses make use of the
|
||||||
|
* PSW key. CSS accesses are different - we have to pass in the key.
|
||||||
|
*
|
||||||
|
* TODO: we have races between getting and setting the key.
|
||||||
|
*/
|
||||||
|
rc = skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
|
||||||
|
if (rc) {
|
||||||
|
trace_get_skeys_nonzero(rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (rw) {
|
||||||
|
case MMU_DATA_LOAD:
|
||||||
|
case MMU_INST_FETCH:
|
||||||
|
/*
|
||||||
|
* The TLB entry has to remain write-protected on read-faults if
|
||||||
|
* the storage key does not indicate a change already. Otherwise
|
||||||
|
* we might miss setting the change bit on write accesses.
|
||||||
|
*/
|
||||||
|
if (!(key & SK_C)) {
|
||||||
|
*flags &= ~PAGE_WRITE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MMU_DATA_STORE:
|
||||||
|
key |= SK_C;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Any store/fetch sets the reference bit */
|
||||||
|
key |= SK_R;
|
||||||
|
|
||||||
|
rc = skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
|
||||||
|
if (rc) {
|
||||||
|
trace_set_skeys_nonzero(rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translate a virtual (logical) address into a physical (absolute) address.
|
* Translate a virtual (logical) address into a physical (absolute) address.
|
||||||
* @param vaddr the virtual address
|
* @param vaddr the virtual address
|
||||||
|
@ -348,16 +417,9 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr,
|
||||||
int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
|
int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
|
||||||
target_ulong *raddr, int *flags, bool exc)
|
target_ulong *raddr, int *flags, bool exc)
|
||||||
{
|
{
|
||||||
static S390SKeysState *ss;
|
|
||||||
static S390SKeysClass *skeyclass;
|
|
||||||
uint64_t asce;
|
uint64_t asce;
|
||||||
uint8_t key;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (unlikely(!ss)) {
|
|
||||||
ss = s390_get_skeys_device();
|
|
||||||
skeyclass = S390_SKEYS_GET_CLASS(ss);
|
|
||||||
}
|
|
||||||
|
|
||||||
*flags = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
*flags = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||||
if (is_low_address(vaddr & TARGET_PAGE_MASK) && lowprot_enabled(env, asc)) {
|
if (is_low_address(vaddr & TARGET_PAGE_MASK) && lowprot_enabled(env, asc)) {
|
||||||
|
@ -414,42 +476,7 @@ nodat:
|
||||||
/* Convert real address -> absolute address */
|
/* Convert real address -> absolute address */
|
||||||
*raddr = mmu_real2abs(env, *raddr);
|
*raddr = mmu_real2abs(env, *raddr);
|
||||||
|
|
||||||
if (*raddr < ram_size) {
|
mmu_handle_skey(*raddr, rw, flags);
|
||||||
r = skeyclass->get_skeys(ss, *raddr / TARGET_PAGE_SIZE, 1, &key);
|
|
||||||
if (r) {
|
|
||||||
trace_get_skeys_nonzero(r);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (rw) {
|
|
||||||
case MMU_DATA_LOAD:
|
|
||||||
case MMU_INST_FETCH:
|
|
||||||
/*
|
|
||||||
* The TLB entry has to remain write-protected on read-faults if
|
|
||||||
* the storage key does not indicate a change already. Otherwise
|
|
||||||
* we might miss setting the change bit on write accesses.
|
|
||||||
*/
|
|
||||||
if (!(key & SK_C)) {
|
|
||||||
*flags &= ~PAGE_WRITE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MMU_DATA_STORE:
|
|
||||||
key |= SK_C;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Any store/fetch sets the reference bit */
|
|
||||||
key |= SK_R;
|
|
||||||
|
|
||||||
r = skeyclass->set_skeys(ss, *raddr / TARGET_PAGE_SIZE, 1, &key);
|
|
||||||
if (r) {
|
|
||||||
trace_set_skeys_nonzero(r);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,6 +594,6 @@ int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw,
|
||||||
|
|
||||||
*addr = mmu_real2abs(env, raddr & TARGET_PAGE_MASK);
|
*addr = mmu_real2abs(env, raddr & TARGET_PAGE_MASK);
|
||||||
|
|
||||||
/* TODO: storage key handling */
|
mmu_handle_skey(*addr, rw, flags);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue