mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/thuth-gitlab/tags/s390x-pull-request-2021-09-07' into staging
* Some CSS related fixes * Storage key related fixes * Test SIGILL and SIGSEGV handling in usermode emulation * Fix SETPREFIX instruction * Replace PAGE_SIZE, PAGE_SHIFT and PAGE_MASK to fix Alpine compilation * Add more feature to gen16 default model # gpg: Signature made Tue 07 Sep 2021 14:07:38 BST # gpg: using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5 # gpg: issuer "thuth@redhat.com" # gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [full] # gpg: aka "Thomas Huth <thuth@redhat.com>" [full] # gpg: aka "Thomas Huth <huth@tuxfamily.org>" [full] # gpg: aka "Thomas Huth <th.huth@posteo.de>" [unknown] # Primary key fingerprint: 27B8 8847 EEE0 2501 18F3 EAB9 2ED9 D774 FE70 2DB5 * remotes/thuth-gitlab/tags/s390x-pull-request-2021-09-07: s390x/cpumodel: Add more feature to gen16 default model s390x: Replace PAGE_SIZE, PAGE_SHIFT and PAGE_MASK hw/s390x/s390-skeys: lazy storage key enablement under TCG hw/s390x/s390-skeys: rename skeys_enabled to skeys_are_enabled hw/s390x/s390-skeys: check if an address is valid before dumping the key hw/s390x/s390-skeys: use memory mapping to detect which storage keys to dump hw/s390x/s390-skeys: use memory mapping to detect which storage keys to migrate s390x/mmu_helper: avoid setting the storage key if nothing changed s390x/mmu_helper: move address validation into mmu_translate*() s390x/mmu_helper: fixup mmu_translate() documentation s390x/mmu_helper: no need to pass access type to mmu_translate_asce() s390x/tcg: check for addressing exceptions for RRBE, SSKE and ISKE s390x/tcg: convert real to absolute address for RRBE, SSKE and ISKE s390x/tcg: fix ignoring bit 63 when setting the storage key in SSKE s390x/tcg: wrap address for RRBE s390x/ioinst: Fix wrong MSCH alignment check on little endian s390x/tcg: fix and optimize SPX (SET PREFIX) tests/tcg/s390x: Test SIGILL and SIGSEGV handling css: fix actl handling for unit exceptions vfio-ccw: forward halt/clear errors Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+34
-4
@@ -1206,23 +1206,53 @@ static void sch_handle_start_func_virtual(SubchDev *sch)
|
||||
|
||||
}
|
||||
|
||||
static void sch_handle_halt_func_passthrough(SubchDev *sch)
|
||||
static IOInstEnding sch_handle_halt_func_passthrough(SubchDev *sch)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = s390_ccw_halt(sch);
|
||||
if (ret == -ENOSYS) {
|
||||
sch_handle_halt_func(sch);
|
||||
return IOINST_CC_EXPECTED;
|
||||
}
|
||||
/*
|
||||
* Some conditions may have been detected prior to starting the halt
|
||||
* function; map them to the correct cc.
|
||||
* Note that we map both -ENODEV and -EACCES to cc 3 (there's not really
|
||||
* anything else we can do.)
|
||||
*/
|
||||
switch (ret) {
|
||||
case -EBUSY:
|
||||
return IOINST_CC_BUSY;
|
||||
case -ENODEV:
|
||||
case -EACCES:
|
||||
return IOINST_CC_NOT_OPERATIONAL;
|
||||
default:
|
||||
return IOINST_CC_EXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
static void sch_handle_clear_func_passthrough(SubchDev *sch)
|
||||
static IOInstEnding sch_handle_clear_func_passthrough(SubchDev *sch)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = s390_ccw_clear(sch);
|
||||
if (ret == -ENOSYS) {
|
||||
sch_handle_clear_func(sch);
|
||||
return IOINST_CC_EXPECTED;
|
||||
}
|
||||
/*
|
||||
* Some conditions may have been detected prior to starting the clear
|
||||
* function; map them to the correct cc.
|
||||
* Note that we map both -ENODEV and -EACCES to cc 3 (there's not really
|
||||
* anything else we can do.)
|
||||
*/
|
||||
switch (ret) {
|
||||
case -ENODEV:
|
||||
case -EACCES:
|
||||
return IOINST_CC_NOT_OPERATIONAL;
|
||||
default:
|
||||
return IOINST_CC_EXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1265,9 +1295,9 @@ IOInstEnding do_subchannel_work_passthrough(SubchDev *sch)
|
||||
SCHIB *schib = &sch->curr_status;
|
||||
|
||||
if (schib->scsw.ctrl & SCSW_FCTL_CLEAR_FUNC) {
|
||||
sch_handle_clear_func_passthrough(sch);
|
||||
return sch_handle_clear_func_passthrough(sch);
|
||||
} else if (schib->scsw.ctrl & SCSW_FCTL_HALT_FUNC) {
|
||||
sch_handle_halt_func_passthrough(sch);
|
||||
return sch_handle_halt_func_passthrough(sch);
|
||||
} else if (schib->scsw.ctrl & SCSW_FCTL_START_FUNC) {
|
||||
return sch_handle_start_func_passthrough(sch);
|
||||
}
|
||||
|
||||
@@ -330,7 +330,7 @@ static unsigned int calc_sx(dma_addr_t ptr)
|
||||
|
||||
static unsigned int calc_px(dma_addr_t ptr)
|
||||
{
|
||||
return ((unsigned long) ptr >> PAGE_SHIFT) & ZPCI_PT_MASK;
|
||||
return ((unsigned long) ptr >> TARGET_PAGE_BITS) & ZPCI_PT_MASK;
|
||||
}
|
||||
|
||||
static uint64_t get_rt_sto(uint64_t entry)
|
||||
@@ -506,7 +506,7 @@ uint16_t s390_guest_io_table_walk(uint64_t g_iota, hwaddr addr,
|
||||
int8_t ett = 1;
|
||||
uint16_t error = 0;
|
||||
|
||||
entry->iova = addr & PAGE_MASK;
|
||||
entry->iova = addr & TARGET_PAGE_MASK;
|
||||
entry->translated_addr = 0;
|
||||
entry->perm = IOMMU_RW;
|
||||
|
||||
@@ -526,7 +526,7 @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr,
|
||||
{
|
||||
S390PCIIOMMU *iommu = container_of(mr, S390PCIIOMMU, iommu_mr);
|
||||
S390IOTLBEntry *entry;
|
||||
uint64_t iova = addr & PAGE_MASK;
|
||||
uint64_t iova = addr & TARGET_PAGE_MASK;
|
||||
uint16_t error = 0;
|
||||
IOMMUTLBEntry ret = {
|
||||
.target_as = &address_space_memory,
|
||||
@@ -562,7 +562,7 @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr,
|
||||
ret.perm = entry->perm;
|
||||
} else {
|
||||
ret.iova = iova;
|
||||
ret.addr_mask = ~PAGE_MASK;
|
||||
ret.addr_mask = ~TARGET_PAGE_MASK;
|
||||
ret.perm = IOMMU_NONE;
|
||||
}
|
||||
|
||||
@@ -868,7 +868,7 @@ static int s390_pci_msix_init(S390PCIBusDevice *pbdev)
|
||||
|
||||
name = g_strdup_printf("msix-s390-%04x", pbdev->uid);
|
||||
memory_region_init_io(&pbdev->msix_notify_mr, OBJECT(pbdev),
|
||||
&s390_msi_ctrl_ops, pbdev, name, PAGE_SIZE);
|
||||
&s390_msi_ctrl_ops, pbdev, name, TARGET_PAGE_SIZE);
|
||||
memory_region_add_subregion(&pbdev->iommu->mr,
|
||||
pbdev->pci_group->zpci_group.msia,
|
||||
&pbdev->msix_notify_mr);
|
||||
|
||||
@@ -613,7 +613,7 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu,
|
||||
.iova = entry->iova,
|
||||
.translated_addr = entry->translated_addr,
|
||||
.perm = entry->perm,
|
||||
.addr_mask = ~PAGE_MASK,
|
||||
.addr_mask = ~TARGET_PAGE_MASK,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -640,7 +640,7 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu,
|
||||
cache = g_new(S390IOTLBEntry, 1);
|
||||
cache->iova = entry->iova;
|
||||
cache->translated_addr = entry->translated_addr;
|
||||
cache->len = PAGE_SIZE;
|
||||
cache->len = TARGET_PAGE_SIZE;
|
||||
cache->perm = entry->perm;
|
||||
g_hash_table_replace(iommu->iotlb, &cache->iova, cache);
|
||||
dec_dma_avail(iommu);
|
||||
@@ -725,8 +725,8 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
|
||||
while (entry.iova < start && entry.iova < end &&
|
||||
(dma_avail > 0 || entry.perm == IOMMU_NONE)) {
|
||||
dma_avail = s390_pci_update_iotlb(iommu, &entry);
|
||||
entry.iova += PAGE_SIZE;
|
||||
entry.translated_addr += PAGE_SIZE;
|
||||
entry.iova += TARGET_PAGE_SIZE;
|
||||
entry.translated_addr += TARGET_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
err:
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
|
||||
static int kvm_s390_skeys_enabled(S390SKeysState *ss)
|
||||
static bool kvm_s390_skeys_are_enabled(S390SKeysState *ss)
|
||||
{
|
||||
S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
|
||||
uint8_t single_key;
|
||||
@@ -57,7 +57,7 @@ static void kvm_s390_skeys_class_init(ObjectClass *oc, void *data)
|
||||
S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc);
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
skeyclass->skeys_enabled = kvm_s390_skeys_enabled;
|
||||
skeyclass->skeys_are_enabled = kvm_s390_skeys_are_enabled;
|
||||
skeyclass->get_skeys = kvm_s390_skeys_get;
|
||||
skeyclass->set_skeys = kvm_s390_skeys_set;
|
||||
|
||||
|
||||
+135
-69
@@ -17,6 +17,8 @@
|
||||
#include "qapi/qapi-commands-misc-target.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/memory_mapping.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "migration/qemu-file-types.h"
|
||||
#include "migration/register.h"
|
||||
@@ -80,11 +82,18 @@ void hmp_info_skeys(Monitor *mon, const QDict *qdict)
|
||||
int r;
|
||||
|
||||
/* Quick check to see if guest is using storage keys*/
|
||||
if (!skeyclass->skeys_enabled(ss)) {
|
||||
if (!skeyclass->skeys_are_enabled(ss)) {
|
||||
monitor_printf(mon, "Error: This guest is not using storage keys\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!address_space_access_valid(&address_space_memory,
|
||||
addr & TARGET_PAGE_MASK, TARGET_PAGE_SIZE,
|
||||
false, MEMTXATTRS_UNSPECIFIED)) {
|
||||
monitor_printf(mon, "Error: The given address is not valid\n");
|
||||
return;
|
||||
}
|
||||
|
||||
r = skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
|
||||
if (r < 0) {
|
||||
monitor_printf(mon, "Error: %s\n", strerror(-r));
|
||||
@@ -109,18 +118,17 @@ void qmp_dump_skeys(const char *filename, Error **errp)
|
||||
{
|
||||
S390SKeysState *ss = s390_get_skeys_device();
|
||||
S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
const uint64_t total_count = ms->ram_size / TARGET_PAGE_SIZE;
|
||||
uint64_t handled_count = 0, cur_count;
|
||||
GuestPhysBlockList guest_phys_blocks;
|
||||
GuestPhysBlock *block;
|
||||
uint64_t pages, gfn;
|
||||
Error *lerr = NULL;
|
||||
vaddr cur_gfn = 0;
|
||||
uint8_t *buf;
|
||||
int ret;
|
||||
int fd;
|
||||
FILE *f;
|
||||
|
||||
/* Quick check to see if guest is using storage keys*/
|
||||
if (!skeyclass->skeys_enabled(ss)) {
|
||||
if (!skeyclass->skeys_are_enabled(ss)) {
|
||||
error_setg(errp, "This guest is not using storage keys - "
|
||||
"nothing to dump");
|
||||
return;
|
||||
@@ -144,53 +152,86 @@ void qmp_dump_skeys(const char *filename, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* we'll only dump initial memory for now */
|
||||
while (handled_count < total_count) {
|
||||
/* Calculate how many keys to ask for & handle overflow case */
|
||||
cur_count = MIN(total_count - handled_count, S390_SKEYS_BUFFER_SIZE);
|
||||
assert(qemu_mutex_iothread_locked());
|
||||
guest_phys_blocks_init(&guest_phys_blocks);
|
||||
guest_phys_blocks_append(&guest_phys_blocks);
|
||||
|
||||
ret = skeyclass->get_skeys(ss, cur_gfn, cur_count, buf);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "get_keys error %d", ret);
|
||||
goto out_free;
|
||||
QTAILQ_FOREACH(block, &guest_phys_blocks.head, next) {
|
||||
assert(QEMU_IS_ALIGNED(block->target_start, TARGET_PAGE_SIZE));
|
||||
assert(QEMU_IS_ALIGNED(block->target_end, TARGET_PAGE_SIZE));
|
||||
|
||||
gfn = block->target_start / TARGET_PAGE_SIZE;
|
||||
pages = (block->target_end - block->target_start) / TARGET_PAGE_SIZE;
|
||||
|
||||
while (pages) {
|
||||
const uint64_t cur_pages = MIN(pages, S390_SKEYS_BUFFER_SIZE);
|
||||
|
||||
ret = skeyclass->get_skeys(ss, gfn, cur_pages, buf);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "get_keys error");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* write keys to stream */
|
||||
write_keys(f, buf, gfn, cur_pages, &lerr);
|
||||
if (lerr) {
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
gfn += cur_pages;
|
||||
pages -= cur_pages;
|
||||
}
|
||||
|
||||
/* write keys to stream */
|
||||
write_keys(f, buf, cur_gfn, cur_count, &lerr);
|
||||
if (lerr) {
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
cur_gfn += cur_count;
|
||||
handled_count += cur_count;
|
||||
}
|
||||
|
||||
out_free:
|
||||
guest_phys_blocks_free(&guest_phys_blocks);
|
||||
error_propagate(errp, lerr);
|
||||
g_free(buf);
|
||||
out:
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void qemu_s390_skeys_init(Object *obj)
|
||||
static bool qemu_s390_skeys_are_enabled(S390SKeysState *ss)
|
||||
{
|
||||
QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(obj);
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(ss);
|
||||
|
||||
skeys->key_count = machine->ram_size / TARGET_PAGE_SIZE;
|
||||
skeys->keydata = g_malloc0(skeys->key_count);
|
||||
/* Lockless check is sufficient. */
|
||||
return !!skeys->keydata;
|
||||
}
|
||||
|
||||
static int qemu_s390_skeys_enabled(S390SKeysState *ss)
|
||||
static bool qemu_s390_enable_skeys(S390SKeysState *ss)
|
||||
{
|
||||
return 1;
|
||||
QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(ss);
|
||||
static gsize initialized;
|
||||
|
||||
if (likely(skeys->keydata)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Modern Linux doesn't use storage keys unless running KVM guests
|
||||
* that use storage keys. Therefore, we keep it simple for now.
|
||||
*
|
||||
* 1) We should initialize to "referenced+changed" for an initial
|
||||
* over-indication. Let's avoid touching megabytes of data for now and
|
||||
* assume that any sane user will issue a storage key instruction before
|
||||
* actually relying on this data.
|
||||
* 2) Relying on ram_size and allocating a big array is ugly. We should
|
||||
* allocate and manage storage key data per RAMBlock or optimally using
|
||||
* some sparse data structure.
|
||||
* 3) We only ever have a single S390SKeysState, so relying on
|
||||
* g_once_init_enter() is good enough.
|
||||
*/
|
||||
if (g_once_init_enter(&initialized)) {
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
|
||||
skeys->key_count = machine->ram_size / TARGET_PAGE_SIZE;
|
||||
skeys->keydata = g_malloc0(skeys->key_count);
|
||||
g_once_init_leave(&initialized, 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: for memory hotplug support qemu_s390_skeys_set and qemu_s390_skeys_get
|
||||
* will have to make sure that the given gfn belongs to a memory region and not
|
||||
* a memory hole.
|
||||
*/
|
||||
static int qemu_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn,
|
||||
uint64_t count, uint8_t *keys)
|
||||
{
|
||||
@@ -198,9 +239,10 @@ static int qemu_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn,
|
||||
int i;
|
||||
|
||||
/* Check for uint64 overflow and access beyond end of key data */
|
||||
if (start_gfn + count > skeydev->key_count || start_gfn + count < count) {
|
||||
error_report("Error: Setting storage keys for page beyond the end "
|
||||
"of memory: gfn=%" PRIx64 " count=%" PRId64,
|
||||
if (unlikely(!skeydev->keydata || start_gfn + count > skeydev->key_count ||
|
||||
start_gfn + count < count)) {
|
||||
error_report("Error: Setting storage keys for pages with unallocated "
|
||||
"storage key memory: gfn=%" PRIx64 " count=%" PRId64,
|
||||
start_gfn, count);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -218,9 +260,10 @@ static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn,
|
||||
int i;
|
||||
|
||||
/* Check for uint64 overflow and access beyond end of key data */
|
||||
if (start_gfn + count > skeydev->key_count || start_gfn + count < count) {
|
||||
error_report("Error: Getting storage keys for page beyond the end "
|
||||
"of memory: gfn=%" PRIx64 " count=%" PRId64,
|
||||
if (unlikely(!skeydev->keydata || start_gfn + count > skeydev->key_count ||
|
||||
start_gfn + count < count)) {
|
||||
error_report("Error: Getting storage keys for pages with unallocated "
|
||||
"storage key memory: gfn=%" PRIx64 " count=%" PRId64,
|
||||
start_gfn, count);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -236,7 +279,8 @@ static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data)
|
||||
S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc);
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
skeyclass->skeys_enabled = qemu_s390_skeys_enabled;
|
||||
skeyclass->skeys_are_enabled = qemu_s390_skeys_are_enabled;
|
||||
skeyclass->enable_skeys = qemu_s390_enable_skeys;
|
||||
skeyclass->get_skeys = qemu_s390_skeys_get;
|
||||
skeyclass->set_skeys = qemu_s390_skeys_set;
|
||||
|
||||
@@ -247,7 +291,6 @@ static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data)
|
||||
static const TypeInfo qemu_s390_skeys_info = {
|
||||
.name = TYPE_QEMU_S390_SKEYS,
|
||||
.parent = TYPE_S390_SKEYS,
|
||||
.instance_init = qemu_s390_skeys_init,
|
||||
.instance_size = sizeof(QEMUS390SKeysState),
|
||||
.class_init = qemu_s390_skeys_class_init,
|
||||
.class_size = sizeof(S390SKeysClass),
|
||||
@@ -257,14 +300,13 @@ static void s390_storage_keys_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
S390SKeysState *ss = S390_SKEYS(opaque);
|
||||
S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
uint64_t pages_left = ms->ram_size / TARGET_PAGE_SIZE;
|
||||
uint64_t read_count, eos = S390_SKEYS_SAVE_FLAG_EOS;
|
||||
vaddr cur_gfn = 0;
|
||||
GuestPhysBlockList guest_phys_blocks;
|
||||
GuestPhysBlock *block;
|
||||
uint64_t pages, gfn;
|
||||
int error = 0;
|
||||
uint8_t *buf;
|
||||
|
||||
if (!skeyclass->skeys_enabled(ss)) {
|
||||
if (!skeyclass->skeys_are_enabled(ss)) {
|
||||
goto end_stream;
|
||||
}
|
||||
|
||||
@@ -274,36 +316,52 @@ static void s390_storage_keys_save(QEMUFile *f, void *opaque)
|
||||
goto end_stream;
|
||||
}
|
||||
|
||||
/* We only support initial memory. Standby memory is not handled yet. */
|
||||
qemu_put_be64(f, (cur_gfn * TARGET_PAGE_SIZE) | S390_SKEYS_SAVE_FLAG_SKEYS);
|
||||
qemu_put_be64(f, pages_left);
|
||||
guest_phys_blocks_init(&guest_phys_blocks);
|
||||
guest_phys_blocks_append(&guest_phys_blocks);
|
||||
|
||||
while (pages_left) {
|
||||
read_count = MIN(pages_left, S390_SKEYS_BUFFER_SIZE);
|
||||
/* Send each contiguous physical memory range separately. */
|
||||
QTAILQ_FOREACH(block, &guest_phys_blocks.head, next) {
|
||||
assert(QEMU_IS_ALIGNED(block->target_start, TARGET_PAGE_SIZE));
|
||||
assert(QEMU_IS_ALIGNED(block->target_end, TARGET_PAGE_SIZE));
|
||||
|
||||
if (!error) {
|
||||
error = skeyclass->get_skeys(ss, cur_gfn, read_count, buf);
|
||||
if (error) {
|
||||
/*
|
||||
* If error: we want to fill the stream with valid data instead
|
||||
* of stopping early so we pad the stream with 0x00 values and
|
||||
* use S390_SKEYS_SAVE_FLAG_ERROR to indicate failure to the
|
||||
* reading side.
|
||||
*/
|
||||
error_report("S390_GET_KEYS error %d", error);
|
||||
memset(buf, 0, S390_SKEYS_BUFFER_SIZE);
|
||||
eos = S390_SKEYS_SAVE_FLAG_ERROR;
|
||||
gfn = block->target_start / TARGET_PAGE_SIZE;
|
||||
pages = (block->target_end - block->target_start) / TARGET_PAGE_SIZE;
|
||||
qemu_put_be64(f, block->target_start | S390_SKEYS_SAVE_FLAG_SKEYS);
|
||||
qemu_put_be64(f, pages);
|
||||
|
||||
while (pages) {
|
||||
const uint64_t cur_pages = MIN(pages, S390_SKEYS_BUFFER_SIZE);
|
||||
|
||||
if (!error) {
|
||||
error = skeyclass->get_skeys(ss, gfn, cur_pages, buf);
|
||||
if (error) {
|
||||
/*
|
||||
* Create a valid stream with all 0x00 and indicate
|
||||
* S390_SKEYS_SAVE_FLAG_ERROR to the destination.
|
||||
*/
|
||||
error_report("S390_GET_KEYS error %d", error);
|
||||
memset(buf, 0, S390_SKEYS_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
qemu_put_buffer(f, buf, cur_pages);
|
||||
gfn += cur_pages;
|
||||
pages -= cur_pages;
|
||||
}
|
||||
|
||||
qemu_put_buffer(f, buf, read_count);
|
||||
cur_gfn += read_count;
|
||||
pages_left -= read_count;
|
||||
if (error) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
guest_phys_blocks_free(&guest_phys_blocks);
|
||||
g_free(buf);
|
||||
end_stream:
|
||||
qemu_put_be64(f, eos);
|
||||
if (error) {
|
||||
qemu_put_be64(f, S390_SKEYS_SAVE_FLAG_ERROR);
|
||||
} else {
|
||||
qemu_put_be64(f, S390_SKEYS_SAVE_FLAG_EOS);
|
||||
}
|
||||
}
|
||||
|
||||
static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id)
|
||||
@@ -312,6 +370,14 @@ static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id)
|
||||
S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Make sure to lazy-enable if required to be done explicitly. No need to
|
||||
* flush any TLB as the VM is not running yet.
|
||||
*/
|
||||
if (skeyclass->enable_skeys) {
|
||||
skeyclass->enable_skeys(ss);
|
||||
}
|
||||
|
||||
while (!ret) {
|
||||
ram_addr_t addr;
|
||||
int flags;
|
||||
|
||||
@@ -803,6 +803,11 @@ DEFINE_CCW_MACHINE(6_2, "6.2", true);
|
||||
static void ccw_machine_6_1_instance_options(MachineState *machine)
|
||||
{
|
||||
ccw_machine_6_2_instance_options(machine);
|
||||
s390_cpudef_featoff_greater(16, 1, S390_FEAT_NNPA);
|
||||
s390_cpudef_featoff_greater(16, 1, S390_FEAT_VECTOR_PACKED_DECIMAL_ENH2);
|
||||
s390_cpudef_featoff_greater(16, 1, S390_FEAT_BEAR_ENH);
|
||||
s390_cpudef_featoff_greater(16, 1, S390_FEAT_RDP);
|
||||
s390_cpudef_featoff_greater(16, 1, S390_FEAT_PAI);
|
||||
}
|
||||
|
||||
static void ccw_machine_6_1_class_options(MachineClass *mc)
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ static bool sccb_verify_boundary(uint64_t sccb_addr, uint16_t sccb_len,
|
||||
uint32_t code)
|
||||
{
|
||||
uint64_t sccb_max_addr = sccb_addr + sccb_len - 1;
|
||||
uint64_t sccb_boundary = (sccb_addr & PAGE_MASK) + PAGE_SIZE;
|
||||
uint64_t sccb_boundary = (sccb_addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
|
||||
|
||||
switch (code & SCLP_CMD_CODE_MASK) {
|
||||
case SCLP_CMDW_READ_SCP_INFO:
|
||||
|
||||
+2
-2
@@ -199,7 +199,7 @@ again:
|
||||
case 0:
|
||||
case -ENODEV:
|
||||
case -EACCES:
|
||||
return 0;
|
||||
return ret;
|
||||
case -EFAULT:
|
||||
default:
|
||||
sch_gen_unit_exception(sch);
|
||||
@@ -240,7 +240,7 @@ again:
|
||||
case -EBUSY:
|
||||
case -ENODEV:
|
||||
case -EACCES:
|
||||
return 0;
|
||||
return ret;
|
||||
case -EFAULT:
|
||||
default:
|
||||
sch_gen_unit_exception(sch);
|
||||
|
||||
@@ -146,7 +146,8 @@ struct SubchDev {
|
||||
|
||||
static inline void sch_gen_unit_exception(SubchDev *sch)
|
||||
{
|
||||
sch->curr_status.scsw.ctrl &= ~SCSW_ACTL_START_PEND;
|
||||
sch->curr_status.scsw.ctrl &= ~(SCSW_ACTL_DEVICE_ACTIVE |
|
||||
SCSW_ACTL_SUBCH_ACTIVE);
|
||||
sch->curr_status.scsw.ctrl |= SCSW_STCTL_PRIMARY |
|
||||
SCSW_STCTL_SECONDARY |
|
||||
SCSW_STCTL_ALERT |
|
||||
|
||||
@@ -81,9 +81,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(S390PCIIOMMU, S390_PCI_IOMMU)
|
||||
#define ZPCI_SDMA_ADDR 0x100000000ULL
|
||||
#define ZPCI_EDMA_ADDR 0x1ffffffffffffffULL
|
||||
|
||||
#define PAGE_SHIFT 12
|
||||
#define PAGE_SIZE (1 << PAGE_SHIFT)
|
||||
#define PAGE_MASK (~(PAGE_SIZE-1))
|
||||
#define PAGE_DEFAULT_ACC 0
|
||||
#define PAGE_DEFAULT_KEY (PAGE_DEFAULT_ACC << 4)
|
||||
|
||||
@@ -137,7 +134,7 @@ enum ZpciIoatDtype {
|
||||
|
||||
#define ZPCI_TABLE_BITS 11
|
||||
#define ZPCI_PT_BITS 8
|
||||
#define ZPCI_ST_SHIFT (ZPCI_PT_BITS + PAGE_SHIFT)
|
||||
#define ZPCI_ST_SHIFT (ZPCI_PT_BITS + TARGET_PAGE_BITS)
|
||||
#define ZPCI_RT_SHIFT (ZPCI_ST_SHIFT + ZPCI_TABLE_BITS)
|
||||
|
||||
#define ZPCI_RTE_FLAG_MASK 0x3fffULL
|
||||
|
||||
@@ -28,9 +28,72 @@ struct S390SKeysState {
|
||||
|
||||
struct S390SKeysClass {
|
||||
DeviceClass parent_class;
|
||||
int (*skeys_enabled)(S390SKeysState *ks);
|
||||
|
||||
/**
|
||||
* @skeys_are_enabled:
|
||||
*
|
||||
* Check whether storage keys are enabled. If not enabled, they were not
|
||||
* enabled lazily either by the guest via a storage key instruction or
|
||||
* by the host during migration.
|
||||
*
|
||||
* If disabled, everything not explicitly triggered by the guest,
|
||||
* such as outgoing migration or dirty/change tracking, should not touch
|
||||
* storage keys and should not lazily enable it.
|
||||
*
|
||||
* @ks: the #S390SKeysState
|
||||
*
|
||||
* Returns false if not enabled and true if enabled.
|
||||
*/
|
||||
bool (*skeys_are_enabled)(S390SKeysState *ks);
|
||||
|
||||
/**
|
||||
* @enable_skeys:
|
||||
*
|
||||
* Lazily enable storage keys. If this function is not implemented,
|
||||
* setting a storage key will lazily enable storage keys implicitly
|
||||
* instead. TCG guests have to make sure to flush the TLB of all CPUs
|
||||
* if storage keys were not enabled before this call.
|
||||
*
|
||||
* @ks: the #S390SKeysState
|
||||
*
|
||||
* Returns false if not enabled before this call, and true if already
|
||||
* enabled.
|
||||
*/
|
||||
bool (*enable_skeys)(S390SKeysState *ks);
|
||||
|
||||
/**
|
||||
* @get_skeys:
|
||||
*
|
||||
* Get storage keys for the given PFN range. This call will fail if
|
||||
* storage keys have not been lazily enabled yet.
|
||||
*
|
||||
* Callers have to validate that a GFN is valid before this call.
|
||||
*
|
||||
* @ks: the #S390SKeysState
|
||||
* @start_gfn: the start GFN to get storage keys for
|
||||
* @count: the number of storage keys to get
|
||||
* @keys: the byte array where storage keys will be stored to
|
||||
*
|
||||
* Returns 0 on success, returns an error if getting a storage key failed.
|
||||
*/
|
||||
int (*get_skeys)(S390SKeysState *ks, uint64_t start_gfn, uint64_t count,
|
||||
uint8_t *keys);
|
||||
/**
|
||||
* @set_skeys:
|
||||
*
|
||||
* Set storage keys for the given PFN range. This call will fail if
|
||||
* storage keys have not been lazily enabled yet and implicit
|
||||
* enablement is not supported.
|
||||
*
|
||||
* Callers have to validate that a GFN is valid before this call.
|
||||
*
|
||||
* @ks: the #S390SKeysState
|
||||
* @start_gfn: the start GFN to set storage keys for
|
||||
* @count: the number of storage keys to set
|
||||
* @keys: the byte array where storage keys will be read from
|
||||
*
|
||||
* Returns 0 on success, returns an error if setting a storage key failed.
|
||||
*/
|
||||
int (*set_skeys)(S390SKeysState *ks, uint64_t start_gfn, uint64_t count,
|
||||
uint8_t *keys);
|
||||
};
|
||||
|
||||
@@ -663,7 +663,13 @@ static uint16_t default_GEN15_GA1[] = {
|
||||
S390_FEAT_ETOKEN,
|
||||
};
|
||||
|
||||
#define default_GEN16_GA1 EmptyFeat
|
||||
static uint16_t default_GEN16_GA1[] = {
|
||||
S390_FEAT_NNPA,
|
||||
S390_FEAT_VECTOR_PACKED_DECIMAL_ENH2,
|
||||
S390_FEAT_BEAR_ENH,
|
||||
S390_FEAT_RDP,
|
||||
S390_FEAT_PAI,
|
||||
};
|
||||
|
||||
/* QEMU (CPU model) features */
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -123,7 +123,7 @@ static int ioinst_schib_valid(SCHIB *schib)
|
||||
}
|
||||
/* for MB format 1 bits 26-31 of word 11 must be 0 */
|
||||
/* MBA uses words 10 and 11, it means align on 2**6 */
|
||||
if ((be16_to_cpu(schib->pmcw.chars) & PMCW_CHARS_MASK_MBFC) &&
|
||||
if ((be32_to_cpu(schib->pmcw.chars) & PMCW_CHARS_MASK_MBFC) &&
|
||||
(be64_to_cpu(schib->mba) & 0x03fUL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
+48
-22
@@ -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)
|
||||
{
|
||||
@@ -117,7 +125,7 @@ static inline bool read_table_entry(CPUS390XState *env, hwaddr gaddr,
|
||||
|
||||
static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr,
|
||||
uint64_t asc, uint64_t asce, target_ulong *raddr,
|
||||
int *flags, int rw)
|
||||
int *flags)
|
||||
{
|
||||
const bool edat1 = (env->cregs[0] & CR0_EDAT) &&
|
||||
s390_has_feat(S390_FEAT_EDAT);
|
||||
@@ -293,19 +301,26 @@ static void mmu_handle_skey(target_ulong addr, int rw, int *flags)
|
||||
{
|
||||
static S390SKeysClass *skeyclass;
|
||||
static S390SKeysState *ss;
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
uint8_t key;
|
||||
uint8_t key, old_key;
|
||||
int rc;
|
||||
|
||||
if (unlikely(addr >= ms->ram_size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We expect to be called with an absolute address that has already been
|
||||
* validated, such that we can reliably use it to lookup the storage key.
|
||||
*/
|
||||
if (unlikely(!ss)) {
|
||||
ss = s390_get_skeys_device();
|
||||
skeyclass = S390_SKEYS_GET_CLASS(ss);
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't enable storage keys if they are still disabled, i.e., no actual
|
||||
* storage key instruction was issued yet.
|
||||
*/
|
||||
if (!skeyclass->skeys_are_enabled(ss)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -330,6 +345,7 @@ static void mmu_handle_skey(target_ulong addr, int rw, int *flags)
|
||||
trace_get_skeys_nonzero(rc);
|
||||
return;
|
||||
}
|
||||
old_key = key;
|
||||
|
||||
switch (rw) {
|
||||
case MMU_DATA_LOAD:
|
||||
@@ -353,20 +369,23 @@ static void mmu_handle_skey(target_ulong addr, int rw, int *flags)
|
||||
/* 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);
|
||||
if (key != old_key) {
|
||||
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.
|
||||
* @param vaddr the virtual address
|
||||
* @param rw 0 = read, 1 = write, 2 = code fetch
|
||||
* @param rw 0 = read, 1 = write, 2 = code fetch, < 0 = load real address
|
||||
* @param asc address space control (one of the PSW_ASC_* modes)
|
||||
* @param raddr the translated address is stored to this pointer
|
||||
* @param flags the PAGE_READ/WRITE/EXEC flags are stored to this pointer
|
||||
* @param exc true = inject a program check if a fault occurred
|
||||
* @param tec the translation exception code if stored to this pointer if
|
||||
* there is an exception to raise
|
||||
* @return 0 = success, != 0, the exception to raise
|
||||
*/
|
||||
int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
|
||||
@@ -420,7 +439,7 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
|
||||
}
|
||||
|
||||
/* perform the DAT translation */
|
||||
r = mmu_translate_asce(env, vaddr, asc, asce, raddr, flags, rw);
|
||||
r = mmu_translate_asce(env, vaddr, asc, asce, raddr, flags);
|
||||
if (unlikely(r)) {
|
||||
return r;
|
||||
}
|
||||
@@ -440,10 +459,17 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
|
||||
}
|
||||
|
||||
nodat:
|
||||
/* Convert real address -> absolute address */
|
||||
*raddr = mmu_real2abs(env, *raddr);
|
||||
if (rw >= 0) {
|
||||
/* Convert real address -> absolute address */
|
||||
*raddr = mmu_real2abs(env, *raddr);
|
||||
|
||||
mmu_handle_skey(*raddr, rw, flags);
|
||||
if (!mmu_absolute_addr_valid(*raddr, rw == MMU_DATA_STORE)) {
|
||||
*tec = 0; /* unused */
|
||||
return PGM_ADDRESSING;
|
||||
}
|
||||
|
||||
mmu_handle_skey(*raddr, rw, flags);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -464,12 +490,6 @@ static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages,
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
if (!address_space_access_valid(&address_space_memory, pages[i],
|
||||
TARGET_PAGE_SIZE, is_write,
|
||||
MEMTXATTRS_UNSPECIFIED)) {
|
||||
*tec = 0; /* unused */
|
||||
return PGM_ADDRESSING;
|
||||
}
|
||||
addr += TARGET_PAGE_SIZE;
|
||||
}
|
||||
|
||||
@@ -579,6 +599,12 @@ int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw,
|
||||
|
||||
*addr = mmu_real2abs(env, raddr & TARGET_PAGE_MASK);
|
||||
|
||||
if (!mmu_absolute_addr_valid(*addr, rw == MMU_DATA_STORE)) {
|
||||
/* unused */
|
||||
*tec = 0;
|
||||
return PGM_ADDRESSING;
|
||||
}
|
||||
|
||||
mmu_handle_skey(*addr, rw, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -373,6 +373,9 @@ 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);
|
||||
/* Special access mode only valid for mmu_translate() */
|
||||
#define MMU_S390_LRA -1
|
||||
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,
|
||||
|
||||
@@ -150,19 +150,6 @@ bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
/* check out of RAM access */
|
||||
if (!excp &&
|
||||
!address_space_access_valid(&address_space_memory, raddr,
|
||||
TARGET_PAGE_SIZE, access_type,
|
||||
MEMTXATTRS_UNSPECIFIED)) {
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
qemu_log_mask(CPU_LOG_MMU,
|
||||
"%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n",
|
||||
__func__, (uint64_t)raddr, (uint64_t)ms->ram_size);
|
||||
excp = PGM_ADDRESSING;
|
||||
tec = 0; /* unused */
|
||||
}
|
||||
|
||||
env->tlb_fill_exc = excp;
|
||||
env->tlb_fill_tec = tec;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -151,13 +151,26 @@ void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num)
|
||||
/* Set Prefix */
|
||||
void HELPER(spx)(CPUS390XState *env, uint64_t a1)
|
||||
{
|
||||
const uint32_t prefix = a1 & 0x7fffe000;
|
||||
const uint32_t old_prefix = env->psa;
|
||||
CPUState *cs = env_cpu(env);
|
||||
uint32_t prefix = a1 & 0x7fffe000;
|
||||
|
||||
if (prefix == old_prefix) {
|
||||
return;
|
||||
}
|
||||
|
||||
env->psa = prefix;
|
||||
HELPER_LOG("prefix: %#x\n", prefix);
|
||||
tlb_flush_page(cs, 0);
|
||||
tlb_flush_page(cs, TARGET_PAGE_SIZE);
|
||||
if (prefix != 0) {
|
||||
tlb_flush_page(cs, prefix);
|
||||
tlb_flush_page(cs, prefix + TARGET_PAGE_SIZE);
|
||||
}
|
||||
if (old_prefix != 0) {
|
||||
tlb_flush_page(cs, old_prefix);
|
||||
tlb_flush_page(cs, old_prefix + TARGET_PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_ckc_timer(CPUS390XState *env)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
VPATH+=$(SRC_PATH)/tests/tcg/s390x
|
||||
S390X_SRC=$(SRC_PATH)/tests/tcg/s390x
|
||||
VPATH+=$(S390X_SRC)
|
||||
CFLAGS+=-march=zEC12 -m64
|
||||
TESTS+=hello-s390x
|
||||
TESTS+=csst
|
||||
@@ -9,3 +10,17 @@ TESTS+=pack
|
||||
TESTS+=mvo
|
||||
TESTS+=mvc
|
||||
TESTS+=trap
|
||||
TESTS+=signals-s390x
|
||||
|
||||
ifneq ($(HAVE_GDB_BIN),)
|
||||
GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py
|
||||
|
||||
run-gdbstub-signals-s390x: signals-s390x
|
||||
$(call run-test, $@, $(GDB_SCRIPT) \
|
||||
--gdb $(HAVE_GDB_BIN) \
|
||||
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
|
||||
--bin $< --test $(S390X_SRC)/gdbstub/test-signals-s390x.py, \
|
||||
"mixing signals and debugging on s390x")
|
||||
|
||||
EXTRA_RUNS += run-gdbstub-signals-s390x
|
||||
endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user