s390x/kvm: Features and fixes for 2.3
- an extension to the elf loader to allow relocations - make the ccw bios relocatable. This allows for bigger ramdisks or smaller guests - Handle all slow SIGPs in QEMU (instead of kernel) for better compliance and correctness - tell the KVM module the maximum guest size. This allows KVM to reduce the number or page table levels - Several fixes/cleanups -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iQIcBAABAgAGBQJVABYpAAoJEBF7vIC1phx8M/kP/AsuFTCrWebziX5qdeIFX8Cu RBcnqm7Dgt7lg+fyt/mj7g7/PVZEoe9AQ5hWoXmguR850/PmMuEDfHhY6pAfKU+r RokYiQR2pHDWFU9D2qf3ggEcI4suym1mmuMjx4TEs9318zpREHu9fGpzfJxlQgXa SUqQDZWElYyiF1nu8cxvH7wqeJLalKSiQBRtkM3w2oG8Nw1TgFxt/xiYHkiz/rkr U2sQrCabOCcVC/nlDAaWajBq18rzqhFk6QZEZsf9O4jsxy8Pbmkw2cqSp68KBMeB o50lRrguGhuejQg6g4AXZWGgUt5YnNL0CIHmTXp0KTnijGSAHnWUPf+qCOOR/sfn 1roTNwCH8rjSfpEPKAhmiLRcPTVzy6IYxaT+J7KniCRAyHdIk2NBF3cHzDBy47uC pre1pIHnKkwBkxv/xkj8CHlfcpCjp8sXhW6FSXoX9On5SKiROnQUwiLoUjtnvRXe kQZRhtgJSKnLTtEEZ3XWh/UDyD2QJiwnm1E5SjXEa/mdDqgUmsVsPtz29f/xDKJA GZGNOCsIew0286C+tf5M88JpIXqpAiEYXA9vw5ZUqzxh3ArNuT0GJGxrlWxbqD8j tbvjHIja62IbCxM8dtZ9v0M4YFNU+VLHdKEREziK6RKS9Ek7rJmSh8128JNQhJ/X RjiUxdcbApvEunZInwB/ =6Cw+ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/borntraeger/tags/s390x-20150310' into staging s390x/kvm: Features and fixes for 2.3 - an extension to the elf loader to allow relocations - make the ccw bios relocatable. This allows for bigger ramdisks or smaller guests - Handle all slow SIGPs in QEMU (instead of kernel) for better compliance and correctness - tell the KVM module the maximum guest size. This allows KVM to reduce the number or page table levels - Several fixes/cleanups # gpg: Signature made Wed Mar 11 10:17:13 2015 GMT using RSA key ID B5A61C7C # gpg: Good signature from "Christian Borntraeger (IBM) <borntraeger@de.ibm.com>" * remotes/borntraeger/tags/s390x-20150310: s390-ccw: rebuild BIOS s390/bios: Make the s390-ccw.img relocatable elf-loader: Provide the possibility to relocate s390 ELF files s390-ccw.img: Reinitialize guessing on reboot s390-ccw.img: Allow bigger ramdisk sizes or offsets s390x/kvm: passing max memory size to accelerator virtio-ccw: Convert to realize() virtio-s390: Convert to realize() virtio-s390: s390_virtio_device_init() can't fail, simplify s390x/kvm: enable the new SIGP handling in user space s390x/kvm: deliver SIGP RESTART directly if stopped s390x: add function to deliver restart irqs s390x/kvm: SIGP START is only applicable when STOPPED s390x/kvm: implement handling of new SIGP orders s390x/kvm: trace all SIGP orders s390x/kvm: helper to set the SIGP status in SigpInfo s390x/kvm: pass the SIGP instruction parameter to the SIGP handler s390x/kvm: more details for SIGP handler with one destination vcpu s390x: introduce defines for SIGP condition codes synchronize Linux headers to 4.0-rc3 Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
165fa4091e
@ -297,6 +297,7 @@ static void *load_at(int fd, int offset, int size)
|
||||
#undef elf_phdr
|
||||
#undef elf_shdr
|
||||
#undef elf_sym
|
||||
#undef elf_rela
|
||||
#undef elf_note
|
||||
#undef elf_word
|
||||
#undef elf_sword
|
||||
@ -307,6 +308,7 @@ static void *load_at(int fd, int offset, int size)
|
||||
#define elf_note elf64_note
|
||||
#define elf_shdr elf64_shdr
|
||||
#define elf_sym elf64_sym
|
||||
#define elf_rela elf64_rela
|
||||
#define elf_word uint64_t
|
||||
#define elf_sword int64_t
|
||||
#define bswapSZs bswap64s
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "cpu.h"
|
||||
#include "elf.h"
|
||||
#include "exec/ram_addr.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/s390x/virtio-ccw.h"
|
||||
@ -95,6 +96,16 @@ static const VMStateDescription vmstate_ipl = {
|
||||
}
|
||||
};
|
||||
|
||||
static uint64_t bios_translate_addr(void *opaque, uint64_t srcaddr)
|
||||
{
|
||||
uint64_t dstaddr = *(uint64_t *) opaque;
|
||||
/*
|
||||
* Assuming that our s390-ccw.img was linked for starting at address 0,
|
||||
* we can simply add the destination address for the final location
|
||||
*/
|
||||
return srcaddr + dstaddr;
|
||||
}
|
||||
|
||||
static int s390_ipl_init(SysBusDevice *dev)
|
||||
{
|
||||
S390IPLState *ipl = S390_IPL(dev);
|
||||
@ -109,6 +120,8 @@ static int s390_ipl_init(SysBusDevice *dev)
|
||||
* even if an external kernel has been defined.
|
||||
*/
|
||||
if (!ipl->kernel || ipl->enforce_bios) {
|
||||
uint64_t fwbase = (MIN(ram_size, 0x80000000U) - 0x200000) & ~0xffffUL;
|
||||
|
||||
if (bios_name == NULL) {
|
||||
bios_name = ipl->firmware;
|
||||
}
|
||||
@ -118,9 +131,14 @@ static int s390_ipl_init(SysBusDevice *dev)
|
||||
hw_error("could not find stage1 bootloader\n");
|
||||
}
|
||||
|
||||
bios_size = load_elf(bios_filename, NULL, NULL, &ipl->bios_start_addr,
|
||||
NULL, NULL, 1, ELF_MACHINE, 0);
|
||||
if (bios_size < 0) {
|
||||
bios_size = load_elf(bios_filename, bios_translate_addr, &fwbase,
|
||||
&ipl->bios_start_addr, NULL, NULL, 1,
|
||||
ELF_MACHINE, 0);
|
||||
if (bios_size > 0) {
|
||||
/* Adjust ELF start address to final location */
|
||||
ipl->bios_start_addr += fwbase;
|
||||
} else {
|
||||
/* Try to load non-ELF file (e.g. s390-zipl.rom) */
|
||||
bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START,
|
||||
4096);
|
||||
ipl->bios_start_addr = ZIPL_IMAGE_START;
|
||||
|
@ -111,7 +111,8 @@ VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size)
|
||||
return bus;
|
||||
}
|
||||
|
||||
static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev)
|
||||
static void s390_virtio_device_init(VirtIOS390Device *dev,
|
||||
VirtIODevice *vdev)
|
||||
{
|
||||
VirtIOS390Bus *bus;
|
||||
int dev_len;
|
||||
@ -135,25 +136,26 @@ static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev)
|
||||
if (dev->qdev.hotplugged) {
|
||||
s390_virtio_irq(VIRTIO_PARAM_DEV_ADD, dev->dev_offs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s390_virtio_net_init(VirtIOS390Device *s390_dev)
|
||||
static void s390_virtio_net_realize(VirtIOS390Device *s390_dev, Error **errp)
|
||||
{
|
||||
DeviceState *qdev = DEVICE(s390_dev);
|
||||
VirtIONetS390 *dev = VIRTIO_NET_S390(s390_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
Error *err = NULL;
|
||||
|
||||
virtio_net_set_config_size(&dev->vdev, s390_dev->host_features);
|
||||
virtio_net_set_netclient_name(&dev->vdev, qdev->id,
|
||||
object_get_typename(OBJECT(qdev)));
|
||||
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
|
||||
if (qdev_init(vdev) < 0) {
|
||||
return -1;
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
return s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
|
||||
s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
|
||||
}
|
||||
|
||||
static void s390_virtio_net_instance_init(Object *obj)
|
||||
@ -166,15 +168,19 @@ static void s390_virtio_net_instance_init(Object *obj)
|
||||
"bootindex", &error_abort);
|
||||
}
|
||||
|
||||
static int s390_virtio_blk_init(VirtIOS390Device *s390_dev)
|
||||
static void s390_virtio_blk_realize(VirtIOS390Device *s390_dev, Error **errp)
|
||||
{
|
||||
VirtIOBlkS390 *dev = VIRTIO_BLK_S390(s390_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
Error *err = NULL;
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
|
||||
if (qdev_init(vdev) < 0) {
|
||||
return -1;
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
return s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
|
||||
s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
|
||||
}
|
||||
|
||||
static void s390_virtio_blk_instance_init(Object *obj)
|
||||
@ -189,13 +195,13 @@ static void s390_virtio_blk_instance_init(Object *obj)
|
||||
"bootindex", &error_abort);
|
||||
}
|
||||
|
||||
static int s390_virtio_serial_init(VirtIOS390Device *s390_dev)
|
||||
static void s390_virtio_serial_realize(VirtIOS390Device *s390_dev, Error **errp)
|
||||
{
|
||||
VirtIOSerialS390 *dev = VIRTIO_SERIAL_S390(s390_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
DeviceState *qdev = DEVICE(s390_dev);
|
||||
Error *err = NULL;
|
||||
VirtIOS390Bus *bus;
|
||||
int r;
|
||||
char *bus_name;
|
||||
|
||||
bus = DO_UPCAST(VirtIOS390Bus, bus, qdev->parent_bus);
|
||||
@ -211,16 +217,14 @@ static int s390_virtio_serial_init(VirtIOS390Device *s390_dev)
|
||||
}
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
|
||||
if (qdev_init(vdev) < 0) {
|
||||
return -1;
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
r = s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
|
||||
if (!r) {
|
||||
bus->console = s390_dev;
|
||||
}
|
||||
|
||||
return r;
|
||||
s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
|
||||
bus->console = s390_dev;
|
||||
}
|
||||
|
||||
static void s390_virtio_serial_instance_init(Object *obj)
|
||||
@ -231,11 +235,12 @@ static void s390_virtio_serial_instance_init(Object *obj)
|
||||
TYPE_VIRTIO_SERIAL);
|
||||
}
|
||||
|
||||
static int s390_virtio_scsi_init(VirtIOS390Device *s390_dev)
|
||||
static void s390_virtio_scsi_realize(VirtIOS390Device *s390_dev, Error **errp)
|
||||
{
|
||||
VirtIOSCSIS390 *dev = VIRTIO_SCSI_S390(s390_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
DeviceState *qdev = DEVICE(s390_dev);
|
||||
Error *err = NULL;
|
||||
char *bus_name;
|
||||
|
||||
/*
|
||||
@ -249,11 +254,13 @@ static int s390_virtio_scsi_init(VirtIOS390Device *s390_dev)
|
||||
}
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
|
||||
if (qdev_init(vdev) < 0) {
|
||||
return -1;
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
return s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
|
||||
s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
|
||||
}
|
||||
|
||||
static void s390_virtio_scsi_instance_init(Object *obj)
|
||||
@ -265,17 +272,20 @@ static void s390_virtio_scsi_instance_init(Object *obj)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VHOST_SCSI
|
||||
static int s390_vhost_scsi_init(VirtIOS390Device *s390_dev)
|
||||
static void s390_vhost_scsi_realize(VirtIOS390Device *s390_dev, Error **errp)
|
||||
{
|
||||
VHostSCSIS390 *dev = VHOST_SCSI_S390(s390_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
Error *err = NULL;
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
|
||||
if (qdev_init(vdev) < 0) {
|
||||
return -1;
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
return s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
|
||||
s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
|
||||
}
|
||||
|
||||
static void s390_vhost_scsi_instance_init(Object *obj)
|
||||
@ -288,21 +298,24 @@ static void s390_vhost_scsi_instance_init(Object *obj)
|
||||
#endif
|
||||
|
||||
|
||||
static int s390_virtio_rng_init(VirtIOS390Device *s390_dev)
|
||||
static void s390_virtio_rng_realize(VirtIOS390Device *s390_dev, Error **errp)
|
||||
{
|
||||
VirtIORNGS390 *dev = VIRTIO_RNG_S390(s390_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
Error *err = NULL;
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
|
||||
if (qdev_init(vdev) < 0) {
|
||||
return -1;
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set_link(OBJECT(dev),
|
||||
OBJECT(dev->vdev.conf.rng), "rng",
|
||||
NULL);
|
||||
|
||||
return s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
|
||||
s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
|
||||
}
|
||||
|
||||
static void s390_virtio_rng_instance_init(Object *obj)
|
||||
@ -509,7 +522,7 @@ static void s390_virtio_net_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = s390_virtio_net_init;
|
||||
k->realize = s390_virtio_net_realize;
|
||||
dc->props = s390_virtio_net_properties;
|
||||
}
|
||||
|
||||
@ -525,7 +538,7 @@ static void s390_virtio_blk_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = s390_virtio_blk_init;
|
||||
k->realize = s390_virtio_blk_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo s390_virtio_blk = {
|
||||
@ -545,7 +558,7 @@ static void s390_virtio_serial_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = s390_virtio_serial_init;
|
||||
k->realize = s390_virtio_serial_realize;
|
||||
dc->props = s390_virtio_serial_properties;
|
||||
}
|
||||
|
||||
@ -567,7 +580,7 @@ static void s390_virtio_rng_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = s390_virtio_rng_init;
|
||||
k->realize = s390_virtio_rng_realize;
|
||||
dc->props = s390_virtio_rng_properties;
|
||||
}
|
||||
|
||||
@ -579,14 +592,14 @@ static const TypeInfo s390_virtio_rng = {
|
||||
.class_init = s390_virtio_rng_class_init,
|
||||
};
|
||||
|
||||
static int s390_virtio_busdev_init(DeviceState *dev)
|
||||
static void s390_virtio_busdev_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIOS390Device *_dev = (VirtIOS390Device *)dev;
|
||||
VirtIOS390DeviceClass *_info = VIRTIO_S390_DEVICE_GET_CLASS(dev);
|
||||
|
||||
virtio_s390_bus_new(&_dev->bus, sizeof(_dev->bus), _dev);
|
||||
|
||||
return _info->init(_dev);
|
||||
_info->realize(_dev, errp);
|
||||
}
|
||||
|
||||
static void s390_virtio_busdev_reset(DeviceState *dev)
|
||||
@ -600,7 +613,7 @@ static void virtio_s390_device_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->init = s390_virtio_busdev_init;
|
||||
dc->realize = s390_virtio_busdev_realize;
|
||||
dc->bus_type = TYPE_S390_VIRTIO_BUS;
|
||||
dc->reset = s390_virtio_busdev_reset;
|
||||
}
|
||||
@ -625,7 +638,7 @@ static void s390_virtio_scsi_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = s390_virtio_scsi_init;
|
||||
k->realize = s390_virtio_scsi_realize;
|
||||
dc->props = s390_virtio_scsi_properties;
|
||||
}
|
||||
|
||||
@ -648,7 +661,7 @@ static void s390_vhost_scsi_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = s390_vhost_scsi_init;
|
||||
k->realize = s390_vhost_scsi_realize;
|
||||
dc->props = s390_vhost_scsi_properties;
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ typedef struct VirtIOS390Device VirtIOS390Device;
|
||||
|
||||
typedef struct VirtIOS390DeviceClass {
|
||||
DeviceClass qdev;
|
||||
int (*init)(VirtIOS390Device *dev);
|
||||
void (*realize)(VirtIOS390Device *dev, Error **errp);
|
||||
} VirtIOS390DeviceClass;
|
||||
|
||||
struct VirtIOS390Device {
|
||||
|
@ -97,6 +97,7 @@ static void ccw_init(MachineState *machine)
|
||||
ram_addr_t pad_size = 0;
|
||||
ram_addr_t maxmem = qemu_opt_get_size(opts, "maxmem", my_ram_size);
|
||||
ram_addr_t standby_mem_size = maxmem - my_ram_size;
|
||||
uint64_t kvm_limit;
|
||||
|
||||
/* The storage increment size is a multiple of 1M and is a power of 2.
|
||||
* The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer.
|
||||
@ -121,6 +122,15 @@ static void ccw_init(MachineState *machine)
|
||||
|
||||
/* let's propagate the changed ram size into the global variable. */
|
||||
ram_size = my_ram_size;
|
||||
machine->maxram_size = my_ram_size + standby_mem_size;
|
||||
|
||||
ret = s390_set_memory_limit(machine->maxram_size, &kvm_limit);
|
||||
if (ret == -E2BIG) {
|
||||
hw_error("qemu: host supports a maximum of %" PRIu64 " GB",
|
||||
kvm_limit >> 30);
|
||||
} else if (ret) {
|
||||
hw_error("qemu: setting the guest size failed");
|
||||
}
|
||||
|
||||
/* get a BUS */
|
||||
css_bus = virtual_css_bus_init();
|
||||
|
@ -607,7 +607,8 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
|
||||
static void virtio_ccw_device_realize(VirtioCcwDevice *dev,
|
||||
VirtIODevice *vdev, Error **errp)
|
||||
{
|
||||
unsigned int cssid = 0;
|
||||
unsigned int ssid = 0;
|
||||
@ -616,7 +617,6 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
|
||||
bool have_devno = false;
|
||||
bool found = false;
|
||||
SubchDev *sch;
|
||||
int ret;
|
||||
int num;
|
||||
DeviceState *parent = DEVICE(dev);
|
||||
|
||||
@ -639,21 +639,19 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
|
||||
num = sscanf(dev->bus_id, "%x.%x.%04x", &cssid, &ssid, &devno);
|
||||
if (num == 3) {
|
||||
if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) {
|
||||
ret = -EINVAL;
|
||||
error_report("Invalid cssid or ssid: cssid %x, ssid %x",
|
||||
cssid, ssid);
|
||||
error_setg(errp, "Invalid cssid or ssid: cssid %x, ssid %x",
|
||||
cssid, ssid);
|
||||
goto out_err;
|
||||
}
|
||||
/* Enforce use of virtual cssid. */
|
||||
if (cssid != VIRTUAL_CSSID) {
|
||||
ret = -EINVAL;
|
||||
error_report("cssid %x not valid for virtio devices", cssid);
|
||||
error_setg(errp, "cssid %x not valid for virtio devices",
|
||||
cssid);
|
||||
goto out_err;
|
||||
}
|
||||
if (css_devno_used(cssid, ssid, devno)) {
|
||||
ret = -EEXIST;
|
||||
error_report("Device %x.%x.%04x already exists", cssid, ssid,
|
||||
devno);
|
||||
error_setg(errp, "Device %x.%x.%04x already exists",
|
||||
cssid, ssid, devno);
|
||||
goto out_err;
|
||||
}
|
||||
sch->cssid = cssid;
|
||||
@ -661,8 +659,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
|
||||
sch->devno = devno;
|
||||
have_devno = true;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
error_report("Malformed devno parameter '%s'", dev->bus_id);
|
||||
error_setg(errp, "Malformed devno parameter '%s'", dev->bus_id);
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
@ -678,9 +675,8 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
ret = -ENODEV;
|
||||
error_report("No free subchannel found for %x.%x.%04x", cssid, ssid,
|
||||
devno);
|
||||
error_setg(errp, "No free subchannel found for %x.%x.%04x",
|
||||
cssid, ssid, devno);
|
||||
goto out_err;
|
||||
}
|
||||
trace_virtio_ccw_new_device(cssid, ssid, schid, devno,
|
||||
@ -702,8 +698,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
|
||||
if (devno == MAX_SCHID) {
|
||||
devno = 0;
|
||||
} else if (devno == schid - 1) {
|
||||
ret = -ENODEV;
|
||||
error_report("No free devno found");
|
||||
error_setg(errp, "No free devno found");
|
||||
goto out_err;
|
||||
} else {
|
||||
devno++;
|
||||
@ -720,8 +715,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
ret = -ENODEV;
|
||||
error_report("Virtual channel subsystem is full!");
|
||||
error_setg(errp, "Virtual channel subsystem is full!");
|
||||
goto out_err;
|
||||
}
|
||||
trace_virtio_ccw_new_device(cssid, ssid, schid, devno,
|
||||
@ -748,12 +742,11 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
|
||||
|
||||
css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid,
|
||||
parent->hotplugged, 1);
|
||||
return 0;
|
||||
return;
|
||||
|
||||
out_err:
|
||||
dev->sch = NULL;
|
||||
g_free(sch);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int virtio_ccw_exit(VirtioCcwDevice *dev)
|
||||
@ -771,21 +764,24 @@ static int virtio_ccw_exit(VirtioCcwDevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_ccw_net_init(VirtioCcwDevice *ccw_dev)
|
||||
static void virtio_ccw_net_realize(VirtioCcwDevice *ccw_dev, Error **errp)
|
||||
{
|
||||
DeviceState *qdev = DEVICE(ccw_dev);
|
||||
VirtIONetCcw *dev = VIRTIO_NET_CCW(ccw_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
Error *err = NULL;
|
||||
|
||||
virtio_net_set_config_size(&dev->vdev, ccw_dev->host_features[0]);
|
||||
virtio_net_set_netclient_name(&dev->vdev, qdev->id,
|
||||
object_get_typename(OBJECT(qdev)));
|
||||
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
|
||||
if (qdev_init(vdev) < 0) {
|
||||
return -1;
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
|
||||
virtio_ccw_device_realize(ccw_dev, VIRTIO_DEVICE(vdev), errp);
|
||||
}
|
||||
|
||||
static void virtio_ccw_net_instance_init(Object *obj)
|
||||
@ -798,16 +794,20 @@ static void virtio_ccw_net_instance_init(Object *obj)
|
||||
"bootindex", &error_abort);
|
||||
}
|
||||
|
||||
static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev)
|
||||
static void virtio_ccw_blk_realize(VirtioCcwDevice *ccw_dev, Error **errp)
|
||||
{
|
||||
VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
Error *err = NULL;
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
|
||||
if (qdev_init(vdev) < 0) {
|
||||
return -1;
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
|
||||
virtio_ccw_device_realize(ccw_dev, VIRTIO_DEVICE(vdev), errp);
|
||||
}
|
||||
|
||||
static void virtio_ccw_blk_instance_init(Object *obj)
|
||||
@ -822,11 +822,12 @@ static void virtio_ccw_blk_instance_init(Object *obj)
|
||||
"bootindex", &error_abort);
|
||||
}
|
||||
|
||||
static int virtio_ccw_serial_init(VirtioCcwDevice *ccw_dev)
|
||||
static void virtio_ccw_serial_realize(VirtioCcwDevice *ccw_dev, Error **errp)
|
||||
{
|
||||
VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(ccw_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
DeviceState *proxy = DEVICE(ccw_dev);
|
||||
Error *err = NULL;
|
||||
char *bus_name;
|
||||
|
||||
/*
|
||||
@ -840,11 +841,13 @@ static int virtio_ccw_serial_init(VirtioCcwDevice *ccw_dev)
|
||||
}
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
|
||||
if (qdev_init(vdev) < 0) {
|
||||
return -1;
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
|
||||
virtio_ccw_device_realize(ccw_dev, VIRTIO_DEVICE(vdev), errp);
|
||||
}
|
||||
|
||||
|
||||
@ -856,17 +859,20 @@ static void virtio_ccw_serial_instance_init(Object *obj)
|
||||
TYPE_VIRTIO_SERIAL);
|
||||
}
|
||||
|
||||
static int virtio_ccw_balloon_init(VirtioCcwDevice *ccw_dev)
|
||||
static void virtio_ccw_balloon_realize(VirtioCcwDevice *ccw_dev, Error **errp)
|
||||
{
|
||||
VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(ccw_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
Error *err = NULL;
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
|
||||
if (qdev_init(vdev) < 0) {
|
||||
return -1;
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
|
||||
virtio_ccw_device_realize(ccw_dev, VIRTIO_DEVICE(vdev), errp);
|
||||
}
|
||||
|
||||
static void balloon_ccw_stats_get_all(Object *obj, struct Visitor *v,
|
||||
@ -909,11 +915,12 @@ static void virtio_ccw_balloon_instance_init(Object *obj)
|
||||
NULL, dev, NULL);
|
||||
}
|
||||
|
||||
static int virtio_ccw_scsi_init(VirtioCcwDevice *ccw_dev)
|
||||
static void virtio_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp)
|
||||
{
|
||||
VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(ccw_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
DeviceState *qdev = DEVICE(ccw_dev);
|
||||
Error *err = NULL;
|
||||
char *bus_name;
|
||||
|
||||
/*
|
||||
@ -927,11 +934,13 @@ static int virtio_ccw_scsi_init(VirtioCcwDevice *ccw_dev)
|
||||
}
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
|
||||
if (qdev_init(vdev) < 0) {
|
||||
return -1;
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
|
||||
virtio_ccw_device_realize(ccw_dev, VIRTIO_DEVICE(vdev), errp);
|
||||
}
|
||||
|
||||
static void virtio_ccw_scsi_instance_init(Object *obj)
|
||||
@ -945,17 +954,20 @@ static void virtio_ccw_scsi_instance_init(Object *obj)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VHOST_SCSI
|
||||
static int vhost_ccw_scsi_init(VirtioCcwDevice *ccw_dev)
|
||||
static void vhost_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp)
|
||||
{
|
||||
VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
Error *err = NULL;
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
|
||||
if (qdev_init(vdev) < 0) {
|
||||
return -1;
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
|
||||
virtio_ccw_device_realize(ccw_dev, VIRTIO_DEVICE(vdev), errp);
|
||||
}
|
||||
|
||||
static void vhost_ccw_scsi_instance_init(Object *obj)
|
||||
@ -967,21 +979,24 @@ static void vhost_ccw_scsi_instance_init(Object *obj)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int virtio_ccw_rng_init(VirtioCcwDevice *ccw_dev)
|
||||
static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp)
|
||||
{
|
||||
VirtIORNGCcw *dev = VIRTIO_RNG_CCW(ccw_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
Error *err = NULL;
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
|
||||
if (qdev_init(vdev) < 0) {
|
||||
return -1;
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set_link(OBJECT(dev),
|
||||
OBJECT(dev->vdev.conf.rng), "rng",
|
||||
NULL);
|
||||
|
||||
return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
|
||||
virtio_ccw_device_realize(ccw_dev, VIRTIO_DEVICE(vdev), errp);
|
||||
}
|
||||
|
||||
/* DeviceState to VirtioCcwDevice. Note: used on datapath,
|
||||
@ -1391,7 +1406,7 @@ static void virtio_ccw_net_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = virtio_ccw_net_init;
|
||||
k->realize = virtio_ccw_net_realize;
|
||||
k->exit = virtio_ccw_exit;
|
||||
dc->reset = virtio_ccw_reset;
|
||||
dc->props = virtio_ccw_net_properties;
|
||||
@ -1417,7 +1432,7 @@ static void virtio_ccw_blk_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = virtio_ccw_blk_init;
|
||||
k->realize = virtio_ccw_blk_realize;
|
||||
k->exit = virtio_ccw_exit;
|
||||
dc->reset = virtio_ccw_reset;
|
||||
dc->props = virtio_ccw_blk_properties;
|
||||
@ -1443,7 +1458,7 @@ static void virtio_ccw_serial_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = virtio_ccw_serial_init;
|
||||
k->realize = virtio_ccw_serial_realize;
|
||||
k->exit = virtio_ccw_exit;
|
||||
dc->reset = virtio_ccw_reset;
|
||||
dc->props = virtio_ccw_serial_properties;
|
||||
@ -1469,7 +1484,7 @@ static void virtio_ccw_balloon_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = virtio_ccw_balloon_init;
|
||||
k->realize = virtio_ccw_balloon_realize;
|
||||
k->exit = virtio_ccw_exit;
|
||||
dc->reset = virtio_ccw_reset;
|
||||
dc->props = virtio_ccw_balloon_properties;
|
||||
@ -1496,7 +1511,7 @@ static void virtio_ccw_scsi_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = virtio_ccw_scsi_init;
|
||||
k->realize = virtio_ccw_scsi_realize;
|
||||
k->exit = virtio_ccw_exit;
|
||||
dc->reset = virtio_ccw_reset;
|
||||
dc->props = virtio_ccw_scsi_properties;
|
||||
@ -1521,7 +1536,7 @@ static void vhost_ccw_scsi_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = vhost_ccw_scsi_init;
|
||||
k->realize = vhost_ccw_scsi_realize;
|
||||
k->exit = virtio_ccw_exit;
|
||||
dc->reset = virtio_ccw_reset;
|
||||
dc->props = vhost_ccw_scsi_properties;
|
||||
@ -1558,7 +1573,7 @@ static void virtio_ccw_rng_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = virtio_ccw_rng_init;
|
||||
k->realize = virtio_ccw_rng_realize;
|
||||
k->exit = virtio_ccw_exit;
|
||||
dc->reset = virtio_ccw_reset;
|
||||
dc->props = virtio_ccw_rng_properties;
|
||||
@ -1572,14 +1587,13 @@ static const TypeInfo virtio_ccw_rng = {
|
||||
.class_init = virtio_ccw_rng_class_init,
|
||||
};
|
||||
|
||||
static int virtio_ccw_busdev_init(DeviceState *dev)
|
||||
static void virtio_ccw_busdev_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
|
||||
VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
|
||||
|
||||
virtio_ccw_bus_new(&_dev->bus, sizeof(_dev->bus), _dev);
|
||||
|
||||
return _info->init(_dev);
|
||||
_info->realize(_dev, errp);
|
||||
}
|
||||
|
||||
static int virtio_ccw_busdev_exit(DeviceState *dev)
|
||||
@ -1622,7 +1636,7 @@ static void virtio_ccw_device_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->props = virtio_ccw_properties;
|
||||
dc->init = virtio_ccw_busdev_init;
|
||||
dc->realize = virtio_ccw_busdev_realize;
|
||||
dc->exit = virtio_ccw_busdev_exit;
|
||||
dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ typedef struct VirtioCcwDevice VirtioCcwDevice;
|
||||
|
||||
typedef struct VirtIOCCWDeviceClass {
|
||||
DeviceClass parent_class;
|
||||
int (*init)(VirtioCcwDevice *dev);
|
||||
void (*realize)(VirtioCcwDevice *dev, Error **errp);
|
||||
int (*exit)(VirtioCcwDevice *dev);
|
||||
} VirtIOCCWDeviceClass;
|
||||
|
||||
|
@ -1508,6 +1508,7 @@ struct elf32_fdpic_loadmap {
|
||||
#define elf_shdr elf32_shdr
|
||||
#define elf_sym elf32_sym
|
||||
#define elf_addr_t Elf32_Off
|
||||
#define elf_rela elf32_rela
|
||||
|
||||
#ifdef ELF_USES_RELOCA
|
||||
# define ELF_RELOC Elf32_Rela
|
||||
@ -1523,6 +1524,7 @@ struct elf32_fdpic_loadmap {
|
||||
#define elf_shdr elf64_shdr
|
||||
#define elf_sym elf64_sym
|
||||
#define elf_addr_t Elf64_Off
|
||||
#define elf_rela elf64_rela
|
||||
|
||||
#ifdef ELF_USES_RELOCA
|
||||
# define ELF_RELOC Elf64_Rela
|
||||
|
@ -49,6 +49,13 @@ static void glue(bswap_sym, SZ)(struct elf_sym *sym)
|
||||
bswap16s(&sym->st_shndx);
|
||||
}
|
||||
|
||||
static void glue(bswap_rela, SZ)(struct elf_rela *rela)
|
||||
{
|
||||
bswapSZs(&rela->r_offset);
|
||||
bswapSZs(&rela->r_info);
|
||||
bswapSZs((elf_word *)&rela->r_addend);
|
||||
}
|
||||
|
||||
static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
|
||||
int n, int type)
|
||||
{
|
||||
@ -182,6 +189,75 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int glue(elf_reloc, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
|
||||
uint64_t (*translate_fn)(void *, uint64_t),
|
||||
void *translate_opaque, uint8_t *data,
|
||||
struct elf_phdr *ph, int elf_machine)
|
||||
{
|
||||
struct elf_shdr *reltab, *shdr_table = NULL;
|
||||
struct elf_rela *rels = NULL;
|
||||
int nrels, i, ret = -1;
|
||||
elf_word wordval;
|
||||
void *addr;
|
||||
|
||||
shdr_table = load_at(fd, ehdr->e_shoff,
|
||||
sizeof(struct elf_shdr) * ehdr->e_shnum);
|
||||
if (!shdr_table) {
|
||||
return -1;
|
||||
}
|
||||
if (must_swab) {
|
||||
for (i = 0; i < ehdr->e_shnum; i++) {
|
||||
glue(bswap_shdr, SZ)(&shdr_table[i]);
|
||||
}
|
||||
}
|
||||
|
||||
reltab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_RELA);
|
||||
if (!reltab) {
|
||||
goto fail;
|
||||
}
|
||||
rels = load_at(fd, reltab->sh_offset, reltab->sh_size);
|
||||
if (!rels) {
|
||||
goto fail;
|
||||
}
|
||||
nrels = reltab->sh_size / sizeof(struct elf_rela);
|
||||
|
||||
for (i = 0; i < nrels; i++) {
|
||||
if (must_swab) {
|
||||
glue(bswap_rela, SZ)(&rels[i]);
|
||||
}
|
||||
if (rels[i].r_offset < ph->p_vaddr ||
|
||||
rels[i].r_offset >= ph->p_vaddr + ph->p_filesz) {
|
||||
continue;
|
||||
}
|
||||
addr = &data[rels[i].r_offset - ph->p_vaddr];
|
||||
switch (elf_machine) {
|
||||
case EM_S390:
|
||||
switch (rels[i].r_info) {
|
||||
case R_390_RELATIVE:
|
||||
wordval = *(elf_word *)addr;
|
||||
if (must_swab) {
|
||||
bswapSZs(&wordval);
|
||||
}
|
||||
wordval = translate_fn(translate_opaque, wordval);
|
||||
if (must_swab) {
|
||||
bswapSZs(&wordval);
|
||||
}
|
||||
*(elf_word *)addr = wordval;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported relocation type %i!\n",
|
||||
(int)rels[i].r_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
g_free(rels);
|
||||
g_free(shdr_table);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int glue(load_elf, SZ)(const char *name, int fd,
|
||||
uint64_t (*translate_fn)(void *, uint64_t),
|
||||
void *translate_opaque,
|
||||
@ -271,6 +347,8 @@ static int glue(load_elf, SZ)(const char *name, int fd,
|
||||
linked at the wrong physical address. */
|
||||
if (translate_fn) {
|
||||
addr = translate_fn(translate_opaque, ph->p_paddr);
|
||||
glue(elf_reloc, SZ)(&ehdr, fd, must_swab, translate_fn,
|
||||
translate_opaque, data, ph, elf_machine);
|
||||
} else {
|
||||
addr = ph->p_paddr;
|
||||
}
|
||||
|
@ -74,39 +74,12 @@ struct virtio_net_config {
|
||||
uint16_t max_virtqueue_pairs;
|
||||
} QEMU_PACKED;
|
||||
|
||||
#ifndef VIRTIO_NET_NO_LEGACY
|
||||
/* This header comes first in the scatter-gather list.
|
||||
* For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, it must
|
||||
* be the first element of the scatter-gather list. If you don't
|
||||
* specify GSO or CSUM features, you can simply ignore the header. */
|
||||
struct virtio_net_hdr {
|
||||
#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 // Use csum_start, csum_offset
|
||||
#define VIRTIO_NET_HDR_F_DATA_VALID 2 // Csum is valid
|
||||
uint8_t flags;
|
||||
#define VIRTIO_NET_HDR_GSO_NONE 0 // Not a GSO frame
|
||||
#define VIRTIO_NET_HDR_GSO_TCPV4 1 // GSO frame, IPv4 TCP (TSO)
|
||||
#define VIRTIO_NET_HDR_GSO_UDP 3 // GSO frame, IPv4 UDP (UFO)
|
||||
#define VIRTIO_NET_HDR_GSO_TCPV6 4 // GSO frame, IPv6 TCP
|
||||
#define VIRTIO_NET_HDR_GSO_ECN 0x80 // TCP has ECN set
|
||||
uint8_t gso_type;
|
||||
__virtio16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */
|
||||
__virtio16 gso_size; /* Bytes to append to hdr_len per frame */
|
||||
__virtio16 csum_start; /* Position to start checksumming from */
|
||||
__virtio16 csum_offset; /* Offset after that to place checksum */
|
||||
};
|
||||
|
||||
/* This is the version of the header to use when the MRG_RXBUF
|
||||
* feature has been negotiated. */
|
||||
struct virtio_net_hdr_mrg_rxbuf {
|
||||
struct virtio_net_hdr hdr;
|
||||
__virtio16 num_buffers; /* Number of merged rx buffers */
|
||||
};
|
||||
#else /* ... VIRTIO_NET_NO_LEGACY */
|
||||
/*
|
||||
* This header comes first in the scatter-gather list. If you don't
|
||||
* specify GSO or CSUM features, you can simply ignore the header.
|
||||
*
|
||||
* This is bitwise-equivalent to the legacy struct virtio_net_hdr_mrg_rxbuf.
|
||||
* This is bitwise-equivalent to the legacy struct virtio_net_hdr_mrg_rxbuf,
|
||||
* only flattened.
|
||||
*/
|
||||
struct virtio_net_hdr_v1 {
|
||||
#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 /* Use csum_start, csum_offset */
|
||||
@ -124,6 +97,29 @@ struct virtio_net_hdr_v1 {
|
||||
__virtio16 csum_offset; /* Offset after that to place checksum */
|
||||
__virtio16 num_buffers; /* Number of merged rx buffers */
|
||||
};
|
||||
|
||||
#ifndef VIRTIO_NET_NO_LEGACY
|
||||
/* This header comes first in the scatter-gather list.
|
||||
* For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, it must
|
||||
* be the first element of the scatter-gather list. If you don't
|
||||
* specify GSO or CSUM features, you can simply ignore the header. */
|
||||
struct virtio_net_hdr {
|
||||
/* See VIRTIO_NET_HDR_F_* */
|
||||
uint8_t flags;
|
||||
/* See VIRTIO_NET_HDR_GSO_* */
|
||||
uint8_t gso_type;
|
||||
__virtio16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */
|
||||
__virtio16 gso_size; /* Bytes to append to hdr_len per frame */
|
||||
__virtio16 csum_start; /* Position to start checksumming from */
|
||||
__virtio16 csum_offset; /* Offset after that to place checksum */
|
||||
};
|
||||
|
||||
/* This is the version of the header to use when the MRG_RXBUF
|
||||
* feature has been negotiated. */
|
||||
struct virtio_net_hdr_mrg_rxbuf {
|
||||
struct virtio_net_hdr hdr;
|
||||
__virtio16 num_buffers; /* Number of merged rx buffers */
|
||||
};
|
||||
#endif /* ...VIRTIO_NET_NO_LEGACY */
|
||||
|
||||
/*
|
||||
|
@ -175,6 +175,8 @@ struct kvm_arch_memory_slot {
|
||||
#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0
|
||||
#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
|
||||
#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3
|
||||
#define KVM_DEV_ARM_VGIC_GRP_CTRL 4
|
||||
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
|
||||
|
||||
/* KVM_IRQ_LINE irq field index values */
|
||||
#define KVM_ARM_IRQ_TYPE_SHIFT 24
|
||||
|
@ -78,6 +78,13 @@ struct kvm_regs {
|
||||
#define KVM_VGIC_V2_DIST_SIZE 0x1000
|
||||
#define KVM_VGIC_V2_CPU_SIZE 0x2000
|
||||
|
||||
/* Supported VGICv3 address types */
|
||||
#define KVM_VGIC_V3_ADDR_TYPE_DIST 2
|
||||
#define KVM_VGIC_V3_ADDR_TYPE_REDIST 3
|
||||
|
||||
#define KVM_VGIC_V3_DIST_SIZE SZ_64K
|
||||
#define KVM_VGIC_V3_REDIST_SIZE (2 * SZ_64K)
|
||||
|
||||
#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
|
||||
#define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */
|
||||
#define KVM_ARM_VCPU_PSCI_0_2 2 /* CPU uses PSCI v0.2 */
|
||||
@ -161,6 +168,8 @@ struct kvm_arch_memory_slot {
|
||||
#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0
|
||||
#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
|
||||
#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3
|
||||
#define KVM_DEV_ARM_VGIC_GRP_CTRL 4
|
||||
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
|
||||
|
||||
/* KVM_IRQ_LINE irq field index values */
|
||||
#define KVM_ARM_IRQ_TYPE_SHIFT 24
|
||||
|
@ -57,10 +57,44 @@ struct kvm_s390_io_adapter_req {
|
||||
|
||||
/* kvm attr_group on vm fd */
|
||||
#define KVM_S390_VM_MEM_CTRL 0
|
||||
#define KVM_S390_VM_TOD 1
|
||||
#define KVM_S390_VM_CRYPTO 2
|
||||
#define KVM_S390_VM_CPU_MODEL 3
|
||||
|
||||
/* kvm attributes for mem_ctrl */
|
||||
#define KVM_S390_VM_MEM_ENABLE_CMMA 0
|
||||
#define KVM_S390_VM_MEM_CLR_CMMA 1
|
||||
#define KVM_S390_VM_MEM_LIMIT_SIZE 2
|
||||
|
||||
/* kvm attributes for KVM_S390_VM_TOD */
|
||||
#define KVM_S390_VM_TOD_LOW 0
|
||||
#define KVM_S390_VM_TOD_HIGH 1
|
||||
|
||||
/* kvm attributes for KVM_S390_VM_CPU_MODEL */
|
||||
/* processor related attributes are r/w */
|
||||
#define KVM_S390_VM_CPU_PROCESSOR 0
|
||||
struct kvm_s390_vm_cpu_processor {
|
||||
__u64 cpuid;
|
||||
__u16 ibc;
|
||||
__u8 pad[6];
|
||||
__u64 fac_list[256];
|
||||
};
|
||||
|
||||
/* machine related attributes are r/o */
|
||||
#define KVM_S390_VM_CPU_MACHINE 1
|
||||
struct kvm_s390_vm_cpu_machine {
|
||||
__u64 cpuid;
|
||||
__u32 ibc;
|
||||
__u8 pad[4];
|
||||
__u64 fac_mask[256];
|
||||
__u64 fac_list[256];
|
||||
};
|
||||
|
||||
/* kvm attributes for crypto */
|
||||
#define KVM_S390_VM_CRYPTO_ENABLE_AES_KW 0
|
||||
#define KVM_S390_VM_CRYPTO_ENABLE_DEA_KW 1
|
||||
#define KVM_S390_VM_CRYPTO_DISABLE_AES_KW 2
|
||||
#define KVM_S390_VM_CRYPTO_DISABLE_DEA_KW 3
|
||||
|
||||
/* for KVM_GET_REGS and KVM_SET_REGS */
|
||||
struct kvm_regs {
|
||||
@ -107,6 +141,9 @@ struct kvm_guest_debug_arch {
|
||||
struct kvm_hw_breakpoint *hw_bp;
|
||||
};
|
||||
|
||||
/* for KVM_SYNC_PFAULT and KVM_REG_S390_PFTOKEN */
|
||||
#define KVM_S390_PFAULT_TOKEN_INVALID 0xffffffffffffffffULL
|
||||
|
||||
#define KVM_SYNC_PREFIX (1UL << 0)
|
||||
#define KVM_SYNC_GPRS (1UL << 1)
|
||||
#define KVM_SYNC_ACRS (1UL << 2)
|
||||
|
@ -187,6 +187,17 @@
|
||||
#define HV_X64_MSR_SINT14 0x4000009E
|
||||
#define HV_X64_MSR_SINT15 0x4000009F
|
||||
|
||||
/*
|
||||
* Synthetic Timer MSRs. Four timers per vcpu.
|
||||
*/
|
||||
#define HV_X64_MSR_STIMER0_CONFIG 0x400000B0
|
||||
#define HV_X64_MSR_STIMER0_COUNT 0x400000B1
|
||||
#define HV_X64_MSR_STIMER1_CONFIG 0x400000B2
|
||||
#define HV_X64_MSR_STIMER1_COUNT 0x400000B3
|
||||
#define HV_X64_MSR_STIMER2_CONFIG 0x400000B4
|
||||
#define HV_X64_MSR_STIMER2_COUNT 0x400000B5
|
||||
#define HV_X64_MSR_STIMER3_CONFIG 0x400000B6
|
||||
#define HV_X64_MSR_STIMER3_COUNT 0x400000B7
|
||||
|
||||
#define HV_X64_MSR_HYPERCALL_ENABLE 0x00000001
|
||||
#define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT 12
|
||||
|
@ -491,6 +491,11 @@ struct kvm_s390_emerg_info {
|
||||
__u16 code;
|
||||
};
|
||||
|
||||
#define KVM_S390_STOP_FLAG_STORE_STATUS 0x01
|
||||
struct kvm_s390_stop_info {
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
struct kvm_s390_mchk_info {
|
||||
__u64 cr14;
|
||||
__u64 mcic;
|
||||
@ -509,6 +514,7 @@ struct kvm_s390_irq {
|
||||
struct kvm_s390_emerg_info emerg;
|
||||
struct kvm_s390_extcall_info extcall;
|
||||
struct kvm_s390_prefix_info prefix;
|
||||
struct kvm_s390_stop_info stop;
|
||||
struct kvm_s390_mchk_info mchk;
|
||||
char reserved[64];
|
||||
} u;
|
||||
@ -647,11 +653,7 @@ struct kvm_ppc_smmu_info {
|
||||
#define KVM_CAP_MP_STATE 14
|
||||
#define KVM_CAP_COALESCED_MMIO 15
|
||||
#define KVM_CAP_SYNC_MMU 16 /* Changes to host mmap are reflected in guest */
|
||||
#define KVM_CAP_DEVICE_ASSIGNMENT 17
|
||||
#define KVM_CAP_IOMMU 18
|
||||
#ifdef __KVM_HAVE_MSI
|
||||
#define KVM_CAP_DEVICE_MSI 20
|
||||
#endif
|
||||
/* Bug in KVM_SET_USER_MEMORY_REGION fixed: */
|
||||
#define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21
|
||||
#define KVM_CAP_USER_NMI 22
|
||||
@ -663,10 +665,6 @@ struct kvm_ppc_smmu_info {
|
||||
#endif
|
||||
#define KVM_CAP_IRQ_ROUTING 25
|
||||
#define KVM_CAP_IRQ_INJECT_STATUS 26
|
||||
#define KVM_CAP_DEVICE_DEASSIGNMENT 27
|
||||
#ifdef __KVM_HAVE_MSIX
|
||||
#define KVM_CAP_DEVICE_MSIX 28
|
||||
#endif
|
||||
#define KVM_CAP_ASSIGN_DEV_IRQ 29
|
||||
/* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
|
||||
#define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
|
||||
@ -761,6 +759,7 @@ struct kvm_ppc_smmu_info {
|
||||
#define KVM_CAP_PPC_FIXUP_HCALL 103
|
||||
#define KVM_CAP_PPC_ENABLE_HCALL 104
|
||||
#define KVM_CAP_CHECK_EXTENSION_VM 105
|
||||
#define KVM_CAP_S390_USER_SIGP 106
|
||||
|
||||
#ifdef KVM_CAP_IRQ_ROUTING
|
||||
|
||||
@ -960,6 +959,8 @@ enum kvm_device_type {
|
||||
#define KVM_DEV_TYPE_ARM_VGIC_V2 KVM_DEV_TYPE_ARM_VGIC_V2
|
||||
KVM_DEV_TYPE_FLIC,
|
||||
#define KVM_DEV_TYPE_FLIC KVM_DEV_TYPE_FLIC
|
||||
KVM_DEV_TYPE_ARM_VGIC_V3,
|
||||
#define KVM_DEV_TYPE_ARM_VGIC_V3 KVM_DEV_TYPE_ARM_VGIC_V3
|
||||
KVM_DEV_TYPE_MAX,
|
||||
};
|
||||
|
||||
@ -1107,9 +1108,6 @@ struct kvm_s390_ucas_mapping {
|
||||
#define KVM_X86_SETUP_MCE _IOW(KVMIO, 0x9c, __u64)
|
||||
#define KVM_X86_GET_MCE_CAP_SUPPORTED _IOR(KVMIO, 0x9d, __u64)
|
||||
#define KVM_X86_SET_MCE _IOW(KVMIO, 0x9e, struct kvm_x86_mce)
|
||||
/* IA64 stack access */
|
||||
#define KVM_IA64_VCPU_GET_STACK _IOR(KVMIO, 0x9a, void *)
|
||||
#define KVM_IA64_VCPU_SET_STACK _IOW(KVMIO, 0x9b, void *)
|
||||
/* Available with KVM_CAP_VCPU_EVENTS */
|
||||
#define KVM_GET_VCPU_EVENTS _IOR(KVMIO, 0x9f, struct kvm_vcpu_events)
|
||||
#define KVM_SET_VCPU_EVENTS _IOW(KVMIO, 0xa0, struct kvm_vcpu_events)
|
||||
|
Binary file not shown.
@ -9,10 +9,9 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
|
||||
|
||||
.PHONY : all clean build-all
|
||||
|
||||
OBJECTS=main.o bootmap.o sclp-ascii.o virtio.o start.o
|
||||
CFLAGS += -fno-stack-protector
|
||||
# XXX find a more clever to locate the bootloader
|
||||
LDFLAGS += -Wl,-Ttext,0x7e00000,-Tbss,0x7f00000 -nostdlib
|
||||
OBJECTS = start.o main.o bootmap.o sclp-ascii.o virtio.o
|
||||
CFLAGS += -fPIE -fno-stack-protector -ffreestanding
|
||||
LDFLAGS += -Wl,-pie -nostdlib
|
||||
|
||||
build-all: s390-ccw.img
|
||||
|
||||
@ -20,7 +19,9 @@ s390-ccw.elf: $(OBJECTS)
|
||||
$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS)," Building $(TARGET_DIR)$@")
|
||||
|
||||
s390-ccw.img: s390-ccw.elf
|
||||
$(call quiet-command,strip $< -o $@," Stripping $(TARGET_DIR)$@")
|
||||
$(call quiet-command,strip --strip-unneeded $< -o $@," Stripping $(TARGET_DIR)$@")
|
||||
|
||||
$(OBJECTS): Makefile
|
||||
|
||||
clean:
|
||||
rm -f *.o *.d *.img *.elf *~
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "virtio.h"
|
||||
|
||||
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
|
||||
char ring_area[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
|
||||
uint64_t boot_value;
|
||||
static struct subchannel_id blk_schid = { .one = 1 };
|
||||
|
||||
|
@ -52,6 +52,7 @@ void disabled_wait(void);
|
||||
void virtio_panic(const char *string);
|
||||
void write_subsystem_identification(void);
|
||||
extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
|
||||
extern char ring_area[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
|
||||
extern uint64_t boot_value;
|
||||
|
||||
/* sclp-ascii.c */
|
||||
|
@ -362,6 +362,7 @@ void virtio_setup_block(struct subchannel_id schid)
|
||||
struct vq_config_block config = {};
|
||||
|
||||
blk_cfg.blk_size = 0; /* mark "illegal" - setup started... */
|
||||
guessed_disk_nature = false;
|
||||
|
||||
virtio_reset(schid);
|
||||
|
||||
@ -378,10 +379,10 @@ void virtio_setup_block(struct subchannel_id schid)
|
||||
if (run_ccw(schid, CCW_CMD_READ_CONF, &blk_cfg, sizeof(blk_cfg))) {
|
||||
virtio_panic("Could not get block device configuration\n");
|
||||
}
|
||||
vring_init(&block, config.num, (void *)(100 * 1024 * 1024),
|
||||
vring_init(&block, config.num, ring_area,
|
||||
KVM_S390_VIRTIO_RING_ALIGN);
|
||||
|
||||
info.queue = (100ULL * 1024ULL* 1024ULL);
|
||||
info.queue = (unsigned long long) ring_area;
|
||||
info.align = KVM_S390_VIRTIO_RING_ALIGN;
|
||||
info.index = 0;
|
||||
info.num = config.num;
|
||||
|
@ -96,6 +96,7 @@ static void s390_cpu_reset(CPUState *s)
|
||||
|
||||
env->pfault_token = -1UL;
|
||||
scc->parent_reset(s);
|
||||
cpu->env.sigp_order = 0;
|
||||
s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
|
||||
tlb_flush(s, 1);
|
||||
}
|
||||
@ -131,6 +132,7 @@ static void s390_cpu_full_reset(CPUState *s)
|
||||
CPUS390XState *env = &cpu->env;
|
||||
|
||||
scc->parent_reset(s);
|
||||
cpu->env.sigp_order = 0;
|
||||
s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
|
||||
|
||||
memset(env, 0, offsetof(CPUS390XState, cpu_num));
|
||||
|
@ -157,6 +157,9 @@ typedef struct CPUS390XState {
|
||||
#define CPU_STATE_LOAD 0x04
|
||||
uint8_t cpu_state;
|
||||
|
||||
/* currently processed sigp order */
|
||||
uint8_t sigp_order;
|
||||
|
||||
} CPUS390XState;
|
||||
|
||||
#include "cpu-qom.h"
|
||||
@ -349,7 +352,10 @@ int s390_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
|
||||
|
||||
#include "ioinst.h"
|
||||
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
void do_restart_interrupt(CPUS390XState *env);
|
||||
|
||||
static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb)
|
||||
{
|
||||
hwaddr addr = 0;
|
||||
@ -411,6 +417,10 @@ S390CPU *s390_cpu_addr2state(uint16_t cpu_addr);
|
||||
unsigned int s390_cpu_halt(S390CPU *cpu);
|
||||
void s390_cpu_unhalt(S390CPU *cpu);
|
||||
unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu);
|
||||
static inline uint8_t s390_cpu_get_state(S390CPU *cpu)
|
||||
{
|
||||
return cpu->env.cpu_state;
|
||||
}
|
||||
|
||||
/* service interrupts are floating therefore we must not pass an cpustate */
|
||||
void s390_sclp_extint(uint32_t parm);
|
||||
@ -664,7 +674,7 @@ typedef struct LowCore
|
||||
PSW mcck_old_psw; /* 0x160 */
|
||||
PSW io_old_psw; /* 0x170 */
|
||||
uint8_t pad7[0x1a0-0x180]; /* 0x180 */
|
||||
PSW restart_psw; /* 0x1a0 */
|
||||
PSW restart_new_psw; /* 0x1a0 */
|
||||
PSW external_new_psw; /* 0x1b0 */
|
||||
PSW svc_new_psw; /* 0x1c0 */
|
||||
PSW program_new_psw; /* 0x1d0 */
|
||||
@ -864,6 +874,7 @@ struct sysib_322 {
|
||||
#define SK_F (0x1 << 3)
|
||||
#define SK_ACC_MASK (0xf << 4)
|
||||
|
||||
/* SIGP order codes */
|
||||
#define SIGP_SENSE 0x01
|
||||
#define SIGP_EXTERNAL_CALL 0x02
|
||||
#define SIGP_EMERGENCY 0x03
|
||||
@ -877,7 +888,13 @@ struct sysib_322 {
|
||||
#define SIGP_STORE_STATUS_ADDR 0x0e
|
||||
#define SIGP_SET_ARCH 0x12
|
||||
|
||||
/* cpu status bits */
|
||||
/* SIGP condition codes */
|
||||
#define SIGP_CC_ORDER_CODE_ACCEPTED 0
|
||||
#define SIGP_CC_STATUS_STORED 1
|
||||
#define SIGP_CC_BUSY 2
|
||||
#define SIGP_CC_NOT_OPERATIONAL 3
|
||||
|
||||
/* SIGP status bits */
|
||||
#define SIGP_STAT_EQUIPMENT_CHECK 0x80000000UL
|
||||
#define SIGP_STAT_INCORRECT_STATE 0x00000200UL
|
||||
#define SIGP_STAT_INVALID_PARAMETER 0x00000100UL
|
||||
@ -889,6 +906,11 @@ struct sysib_322 {
|
||||
#define SIGP_STAT_INVALID_ORDER 0x00000002UL
|
||||
#define SIGP_STAT_RECEIVER_CHECK 0x00000001UL
|
||||
|
||||
/* SIGP SET ARCHITECTURE modes */
|
||||
#define SIGP_MODE_ESA_S390 0
|
||||
#define SIGP_MODE_Z_ARCH_TRANS_ALL_PSW 1
|
||||
#define SIGP_MODE_Z_ARCH_TRANS_CUR_PSW 2
|
||||
|
||||
void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
|
||||
int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
|
||||
target_ulong *raddr, int *flags, bool exc);
|
||||
@ -1007,6 +1029,7 @@ int kvm_s390_get_memslot_count(KVMState *s);
|
||||
void kvm_s390_clear_cmma_callback(void *opaque);
|
||||
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state);
|
||||
void kvm_s390_reset_vcpu(S390CPU *cpu);
|
||||
int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit);
|
||||
#else
|
||||
static inline void kvm_s390_io_interrupt(uint16_t subchannel_id,
|
||||
uint16_t subchannel_nr,
|
||||
@ -1044,8 +1067,21 @@ static inline int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
|
||||
static inline void kvm_s390_reset_vcpu(S390CPU *cpu)
|
||||
{
|
||||
}
|
||||
static inline int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit,
|
||||
uint64_t *hw_limit)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
|
||||
{
|
||||
if (kvm_enabled()) {
|
||||
return kvm_s390_set_mem_limit(kvm_state, new_limit, hw_limit);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void cmma_reset(S390CPU *cpu)
|
||||
{
|
||||
if (kvm_enabled()) {
|
||||
|
@ -183,7 +183,9 @@ void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
|
||||
{
|
||||
env->psw.addr = addr;
|
||||
env->psw.mask = mask;
|
||||
env->cc_op = (mask >> 44) & 3;
|
||||
if (tcg_enabled()) {
|
||||
env->cc_op = (mask >> 44) & 3;
|
||||
}
|
||||
|
||||
if (mask & PSW_MASK_WAIT) {
|
||||
S390CPU *cpu = s390_env_get_cpu(env);
|
||||
@ -197,14 +199,16 @@ void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
|
||||
|
||||
static uint64_t get_psw_mask(CPUS390XState *env)
|
||||
{
|
||||
uint64_t r;
|
||||
uint64_t r = env->psw.mask;
|
||||
|
||||
env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr);
|
||||
if (tcg_enabled()) {
|
||||
env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst,
|
||||
env->cc_vr);
|
||||
|
||||
r = env->psw.mask;
|
||||
r &= ~PSW_MASK_CC;
|
||||
assert(!(env->cc_op & ~3));
|
||||
r |= (uint64_t)env->cc_op << 44;
|
||||
r &= ~PSW_MASK_CC;
|
||||
assert(!(env->cc_op & ~3));
|
||||
r |= (uint64_t)env->cc_op << 44;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -229,6 +233,23 @@ static void cpu_unmap_lowcore(LowCore *lowcore)
|
||||
cpu_physical_memory_unmap(lowcore, sizeof(LowCore), 1, sizeof(LowCore));
|
||||
}
|
||||
|
||||
void do_restart_interrupt(CPUS390XState *env)
|
||||
{
|
||||
uint64_t mask, addr;
|
||||
LowCore *lowcore;
|
||||
|
||||
lowcore = cpu_map_lowcore(env);
|
||||
|
||||
lowcore->restart_old_psw.mask = cpu_to_be64(get_psw_mask(env));
|
||||
lowcore->restart_old_psw.addr = cpu_to_be64(env->psw.addr);
|
||||
mask = be64_to_cpu(lowcore->restart_new_psw.mask);
|
||||
addr = be64_to_cpu(lowcore->restart_new_psw.addr);
|
||||
|
||||
cpu_unmap_lowcore(lowcore);
|
||||
|
||||
load_psw(env, mask, addr);
|
||||
}
|
||||
|
||||
static void do_svc_interrupt(CPUS390XState *env)
|
||||
{
|
||||
uint64_t mask, addr;
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "trace.h"
|
||||
#include "qapi-event.h"
|
||||
#include "hw/s390x/s390-pci-inst.h"
|
||||
@ -121,6 +122,51 @@ static int cap_async_pf;
|
||||
|
||||
static void *legacy_s390_alloc(size_t size, uint64_t *align);
|
||||
|
||||
static int kvm_s390_supports_mem_limit(KVMState *s)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_S390_VM_MEM_CTRL,
|
||||
.attr = KVM_S390_VM_MEM_LIMIT_SIZE,
|
||||
};
|
||||
|
||||
return (kvm_vm_ioctl(s, KVM_HAS_DEVICE_ATTR, &attr) == 0);
|
||||
}
|
||||
|
||||
static int kvm_s390_query_mem_limit(KVMState *s, uint64_t *memory_limit)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_S390_VM_MEM_CTRL,
|
||||
.attr = KVM_S390_VM_MEM_LIMIT_SIZE,
|
||||
.addr = (uint64_t) memory_limit,
|
||||
};
|
||||
|
||||
return kvm_vm_ioctl(s, KVM_GET_DEVICE_ATTR, &attr);
|
||||
}
|
||||
|
||||
int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit)
|
||||
{
|
||||
int rc;
|
||||
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_S390_VM_MEM_CTRL,
|
||||
.attr = KVM_S390_VM_MEM_LIMIT_SIZE,
|
||||
.addr = (uint64_t) &new_limit,
|
||||
};
|
||||
|
||||
if (!kvm_s390_supports_mem_limit(s)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = kvm_s390_query_mem_limit(s, hw_limit);
|
||||
if (rc) {
|
||||
return rc;
|
||||
} else if (*hw_limit < new_limit) {
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
return kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr);
|
||||
}
|
||||
|
||||
static int kvm_s390_check_clear_cmma(KVMState *s)
|
||||
{
|
||||
struct kvm_device_attr attr = {
|
||||
@ -186,6 +232,9 @@ int kvm_arch_init(KVMState *s)
|
||||
|| !kvm_check_extension(s, KVM_CAP_S390_COW)) {
|
||||
phys_mem_set_alloc(legacy_s390_alloc);
|
||||
}
|
||||
|
||||
kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1111,52 +1160,315 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
|
||||
return r;
|
||||
}
|
||||
|
||||
static void sigp_cpu_start(void *arg)
|
||||
{
|
||||
CPUState *cs = arg;
|
||||
S390CPU *cpu = S390_CPU(cs);
|
||||
typedef struct SigpInfo {
|
||||
S390CPU *cpu;
|
||||
uint64_t param;
|
||||
int cc;
|
||||
uint64_t *status_reg;
|
||||
} SigpInfo;
|
||||
|
||||
s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
|
||||
DPRINTF("DONE: KVM cpu start: %p\n", &cpu->env);
|
||||
static void set_sigp_status(SigpInfo *si, uint64_t status)
|
||||
{
|
||||
*si->status_reg &= 0xffffffff00000000ULL;
|
||||
*si->status_reg |= status;
|
||||
si->cc = SIGP_CC_STATUS_STORED;
|
||||
}
|
||||
|
||||
static void sigp_cpu_restart(void *arg)
|
||||
static void sigp_start(void *arg)
|
||||
{
|
||||
CPUState *cs = arg;
|
||||
S390CPU *cpu = S390_CPU(cs);
|
||||
SigpInfo *si = arg;
|
||||
|
||||
if (s390_cpu_get_state(si->cpu) != CPU_STATE_STOPPED) {
|
||||
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
return;
|
||||
}
|
||||
|
||||
s390_cpu_set_state(CPU_STATE_OPERATING, si->cpu);
|
||||
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
}
|
||||
|
||||
static void sigp_stop(void *arg)
|
||||
{
|
||||
SigpInfo *si = arg;
|
||||
struct kvm_s390_irq irq = {
|
||||
.type = KVM_S390_SIGP_STOP,
|
||||
};
|
||||
|
||||
if (s390_cpu_get_state(si->cpu) != CPU_STATE_OPERATING) {
|
||||
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
return;
|
||||
}
|
||||
|
||||
/* disabled wait - sleeping in user space */
|
||||
if (CPU(si->cpu)->halted) {
|
||||
s390_cpu_set_state(CPU_STATE_STOPPED, si->cpu);
|
||||
} else {
|
||||
/* execute the stop function */
|
||||
si->cpu->env.sigp_order = SIGP_STOP;
|
||||
kvm_s390_vcpu_interrupt(si->cpu, &irq);
|
||||
}
|
||||
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
}
|
||||
|
||||
#define KVM_S390_STORE_STATUS_DEF_ADDR offsetof(LowCore, floating_pt_save_area)
|
||||
#define SAVE_AREA_SIZE 512
|
||||
static int kvm_s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch)
|
||||
{
|
||||
static const uint8_t ar_id = 1;
|
||||
uint64_t ckc = cpu->env.ckc >> 8;
|
||||
void *mem;
|
||||
hwaddr len = SAVE_AREA_SIZE;
|
||||
|
||||
mem = cpu_physical_memory_map(addr, &len, 1);
|
||||
if (!mem) {
|
||||
return -EFAULT;
|
||||
}
|
||||
if (len != SAVE_AREA_SIZE) {
|
||||
cpu_physical_memory_unmap(mem, len, 1, 0);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (store_arch) {
|
||||
cpu_physical_memory_write(offsetof(LowCore, ar_access_id), &ar_id, 1);
|
||||
}
|
||||
memcpy(mem, &cpu->env.fregs, 128);
|
||||
memcpy(mem + 128, &cpu->env.regs, 128);
|
||||
memcpy(mem + 256, &cpu->env.psw, 16);
|
||||
memcpy(mem + 280, &cpu->env.psa, 4);
|
||||
memcpy(mem + 284, &cpu->env.fpc, 4);
|
||||
memcpy(mem + 292, &cpu->env.todpr, 4);
|
||||
memcpy(mem + 296, &cpu->env.cputm, 8);
|
||||
memcpy(mem + 304, &ckc, 8);
|
||||
memcpy(mem + 320, &cpu->env.aregs, 64);
|
||||
memcpy(mem + 384, &cpu->env.cregs, 128);
|
||||
|
||||
cpu_physical_memory_unmap(mem, len, 1, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sigp_stop_and_store_status(void *arg)
|
||||
{
|
||||
SigpInfo *si = arg;
|
||||
struct kvm_s390_irq irq = {
|
||||
.type = KVM_S390_SIGP_STOP,
|
||||
};
|
||||
|
||||
/* disabled wait - sleeping in user space */
|
||||
if (s390_cpu_get_state(si->cpu) == CPU_STATE_OPERATING &&
|
||||
CPU(si->cpu)->halted) {
|
||||
s390_cpu_set_state(CPU_STATE_STOPPED, si->cpu);
|
||||
}
|
||||
|
||||
switch (s390_cpu_get_state(si->cpu)) {
|
||||
case CPU_STATE_OPERATING:
|
||||
si->cpu->env.sigp_order = SIGP_STOP_STORE_STATUS;
|
||||
kvm_s390_vcpu_interrupt(si->cpu, &irq);
|
||||
/* store will be performed when handling the stop intercept */
|
||||
break;
|
||||
case CPU_STATE_STOPPED:
|
||||
/* already stopped, just store the status */
|
||||
cpu_synchronize_state(CPU(si->cpu));
|
||||
kvm_s390_store_status(si->cpu, KVM_S390_STORE_STATUS_DEF_ADDR, true);
|
||||
break;
|
||||
}
|
||||
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
}
|
||||
|
||||
static void sigp_store_status_at_address(void *arg)
|
||||
{
|
||||
SigpInfo *si = arg;
|
||||
uint32_t address = si->param & 0x7ffffe00u;
|
||||
|
||||
/* cpu has to be stopped */
|
||||
if (s390_cpu_get_state(si->cpu) != CPU_STATE_STOPPED) {
|
||||
set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
|
||||
return;
|
||||
}
|
||||
|
||||
cpu_synchronize_state(CPU(si->cpu));
|
||||
|
||||
if (kvm_s390_store_status(si->cpu, address, false)) {
|
||||
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
|
||||
return;
|
||||
}
|
||||
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
}
|
||||
|
||||
static void sigp_restart(void *arg)
|
||||
{
|
||||
SigpInfo *si = arg;
|
||||
struct kvm_s390_irq irq = {
|
||||
.type = KVM_S390_RESTART,
|
||||
};
|
||||
|
||||
kvm_s390_vcpu_interrupt(cpu, &irq);
|
||||
s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
|
||||
switch (s390_cpu_get_state(si->cpu)) {
|
||||
case CPU_STATE_STOPPED:
|
||||
/* the restart irq has to be delivered prior to any other pending irq */
|
||||
cpu_synchronize_state(CPU(si->cpu));
|
||||
do_restart_interrupt(&si->cpu->env);
|
||||
s390_cpu_set_state(CPU_STATE_OPERATING, si->cpu);
|
||||
break;
|
||||
case CPU_STATE_OPERATING:
|
||||
kvm_s390_vcpu_interrupt(si->cpu, &irq);
|
||||
break;
|
||||
}
|
||||
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
}
|
||||
|
||||
int kvm_s390_cpu_restart(S390CPU *cpu)
|
||||
{
|
||||
run_on_cpu(CPU(cpu), sigp_cpu_restart, CPU(cpu));
|
||||
SigpInfo si = {
|
||||
.cpu = cpu,
|
||||
};
|
||||
|
||||
run_on_cpu(CPU(cpu), sigp_restart, &si);
|
||||
DPRINTF("DONE: KVM cpu restart: %p\n", &cpu->env);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sigp_initial_cpu_reset(void *arg)
|
||||
{
|
||||
CPUState *cpu = arg;
|
||||
S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
|
||||
SigpInfo *si = arg;
|
||||
CPUState *cs = CPU(si->cpu);
|
||||
S390CPUClass *scc = S390_CPU_GET_CLASS(si->cpu);
|
||||
|
||||
cpu_synchronize_state(cpu);
|
||||
scc->initial_cpu_reset(cpu);
|
||||
cpu_synchronize_post_reset(cpu);
|
||||
cpu_synchronize_state(cs);
|
||||
scc->initial_cpu_reset(cs);
|
||||
cpu_synchronize_post_reset(cs);
|
||||
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
}
|
||||
|
||||
static void sigp_cpu_reset(void *arg)
|
||||
{
|
||||
CPUState *cpu = arg;
|
||||
S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
|
||||
SigpInfo *si = arg;
|
||||
CPUState *cs = CPU(si->cpu);
|
||||
S390CPUClass *scc = S390_CPU_GET_CLASS(si->cpu);
|
||||
|
||||
cpu_synchronize_state(cpu);
|
||||
scc->cpu_reset(cpu);
|
||||
cpu_synchronize_post_reset(cpu);
|
||||
cpu_synchronize_state(cs);
|
||||
scc->cpu_reset(cs);
|
||||
cpu_synchronize_post_reset(cs);
|
||||
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
}
|
||||
|
||||
static void sigp_set_prefix(void *arg)
|
||||
{
|
||||
SigpInfo *si = arg;
|
||||
uint32_t addr = si->param & 0x7fffe000u;
|
||||
|
||||
cpu_synchronize_state(CPU(si->cpu));
|
||||
|
||||
if (!address_space_access_valid(&address_space_memory, addr,
|
||||
sizeof(struct LowCore), false)) {
|
||||
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
|
||||
return;
|
||||
}
|
||||
|
||||
/* cpu has to be stopped */
|
||||
if (s390_cpu_get_state(si->cpu) != CPU_STATE_STOPPED) {
|
||||
set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
|
||||
return;
|
||||
}
|
||||
|
||||
si->cpu->env.psa = addr;
|
||||
cpu_synchronize_post_init(CPU(si->cpu));
|
||||
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
}
|
||||
|
||||
static int handle_sigp_single_dst(S390CPU *dst_cpu, uint8_t order,
|
||||
uint64_t param, uint64_t *status_reg)
|
||||
{
|
||||
SigpInfo si = {
|
||||
.cpu = dst_cpu,
|
||||
.param = param,
|
||||
.status_reg = status_reg,
|
||||
};
|
||||
|
||||
/* cpu available? */
|
||||
if (dst_cpu == NULL) {
|
||||
return SIGP_CC_NOT_OPERATIONAL;
|
||||
}
|
||||
|
||||
/* only resets can break pending orders */
|
||||
if (dst_cpu->env.sigp_order != 0 &&
|
||||
order != SIGP_CPU_RESET &&
|
||||
order != SIGP_INITIAL_CPU_RESET) {
|
||||
return SIGP_CC_BUSY;
|
||||
}
|
||||
|
||||
switch (order) {
|
||||
case SIGP_START:
|
||||
run_on_cpu(CPU(dst_cpu), sigp_start, &si);
|
||||
break;
|
||||
case SIGP_STOP:
|
||||
run_on_cpu(CPU(dst_cpu), sigp_stop, &si);
|
||||
break;
|
||||
case SIGP_RESTART:
|
||||
run_on_cpu(CPU(dst_cpu), sigp_restart, &si);
|
||||
break;
|
||||
case SIGP_STOP_STORE_STATUS:
|
||||
run_on_cpu(CPU(dst_cpu), sigp_stop_and_store_status, &si);
|
||||
break;
|
||||
case SIGP_STORE_STATUS_ADDR:
|
||||
run_on_cpu(CPU(dst_cpu), sigp_store_status_at_address, &si);
|
||||
break;
|
||||
case SIGP_SET_PREFIX:
|
||||
run_on_cpu(CPU(dst_cpu), sigp_set_prefix, &si);
|
||||
break;
|
||||
case SIGP_INITIAL_CPU_RESET:
|
||||
run_on_cpu(CPU(dst_cpu), sigp_initial_cpu_reset, &si);
|
||||
break;
|
||||
case SIGP_CPU_RESET:
|
||||
run_on_cpu(CPU(dst_cpu), sigp_cpu_reset, &si);
|
||||
break;
|
||||
default:
|
||||
DPRINTF("KVM: unknown SIGP: 0x%x\n", order);
|
||||
set_sigp_status(&si, SIGP_STAT_INVALID_ORDER);
|
||||
}
|
||||
|
||||
return si.cc;
|
||||
}
|
||||
|
||||
static int sigp_set_architecture(S390CPU *cpu, uint32_t param,
|
||||
uint64_t *status_reg)
|
||||
{
|
||||
CPUState *cur_cs;
|
||||
S390CPU *cur_cpu;
|
||||
|
||||
/* due to the BQL, we are the only active cpu */
|
||||
CPU_FOREACH(cur_cs) {
|
||||
cur_cpu = S390_CPU(cur_cs);
|
||||
if (cur_cpu->env.sigp_order != 0) {
|
||||
return SIGP_CC_BUSY;
|
||||
}
|
||||
cpu_synchronize_state(cur_cs);
|
||||
/* all but the current one have to be stopped */
|
||||
if (cur_cpu != cpu &&
|
||||
s390_cpu_get_state(cur_cpu) != CPU_STATE_STOPPED) {
|
||||
*status_reg &= 0xffffffff00000000ULL;
|
||||
*status_reg |= SIGP_STAT_INCORRECT_STATE;
|
||||
return SIGP_CC_STATUS_STORED;
|
||||
}
|
||||
}
|
||||
|
||||
switch (param & 0xff) {
|
||||
case SIGP_MODE_ESA_S390:
|
||||
/* not supported */
|
||||
return SIGP_CC_NOT_OPERATIONAL;
|
||||
case SIGP_MODE_Z_ARCH_TRANS_ALL_PSW:
|
||||
case SIGP_MODE_Z_ARCH_TRANS_CUR_PSW:
|
||||
CPU_FOREACH(cur_cs) {
|
||||
cur_cpu = S390_CPU(cur_cs);
|
||||
cur_cpu->env.pfault_token = -1UL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*status_reg &= 0xffffffff00000000ULL;
|
||||
*status_reg |= SIGP_STAT_INVALID_PARAMETER;
|
||||
return SIGP_CC_STATUS_STORED;
|
||||
}
|
||||
|
||||
return SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
}
|
||||
|
||||
#define SIGP_ORDER_MASK 0x000000ff
|
||||
@ -1164,57 +1476,40 @@ static void sigp_cpu_reset(void *arg)
|
||||
static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
|
||||
{
|
||||
CPUS390XState *env = &cpu->env;
|
||||
uint8_t order_code;
|
||||
uint16_t cpu_addr;
|
||||
S390CPU *target_cpu;
|
||||
uint64_t *statusreg = &env->regs[ipa1 >> 4];
|
||||
int cc;
|
||||
const uint8_t r1 = ipa1 >> 4;
|
||||
const uint8_t r3 = ipa1 & 0x0f;
|
||||
int ret;
|
||||
uint8_t order;
|
||||
uint64_t *status_reg;
|
||||
uint64_t param;
|
||||
S390CPU *dst_cpu = NULL;
|
||||
|
||||
cpu_synchronize_state(CPU(cpu));
|
||||
|
||||
/* get order code */
|
||||
order_code = decode_basedisp_rs(env, run->s390_sieic.ipb) & SIGP_ORDER_MASK;
|
||||
order = decode_basedisp_rs(env, run->s390_sieic.ipb) & SIGP_ORDER_MASK;
|
||||
status_reg = &env->regs[r1];
|
||||
param = (r1 % 2) ? env->regs[r1] : env->regs[r1 + 1];
|
||||
|
||||
cpu_addr = env->regs[ipa1 & 0x0f];
|
||||
target_cpu = s390_cpu_addr2state(cpu_addr);
|
||||
if (target_cpu == NULL) {
|
||||
cc = 3; /* not operational */
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (order_code) {
|
||||
case SIGP_START:
|
||||
run_on_cpu(CPU(target_cpu), sigp_cpu_start, CPU(target_cpu));
|
||||
cc = 0;
|
||||
break;
|
||||
case SIGP_RESTART:
|
||||
run_on_cpu(CPU(target_cpu), sigp_cpu_restart, CPU(target_cpu));
|
||||
cc = 0;
|
||||
break;
|
||||
switch (order) {
|
||||
case SIGP_SET_ARCH:
|
||||
*statusreg &= 0xffffffff00000000UL;
|
||||
*statusreg |= SIGP_STAT_INVALID_PARAMETER;
|
||||
cc = 1; /* status stored */
|
||||
break;
|
||||
case SIGP_INITIAL_CPU_RESET:
|
||||
run_on_cpu(CPU(target_cpu), sigp_initial_cpu_reset, CPU(target_cpu));
|
||||
cc = 0;
|
||||
break;
|
||||
case SIGP_CPU_RESET:
|
||||
run_on_cpu(CPU(target_cpu), sigp_cpu_reset, CPU(target_cpu));
|
||||
cc = 0;
|
||||
ret = sigp_set_architecture(cpu, param, status_reg);
|
||||
break;
|
||||
default:
|
||||
DPRINTF("KVM: unknown SIGP: 0x%x\n", order_code);
|
||||
*statusreg &= 0xffffffff00000000UL;
|
||||
*statusreg |= SIGP_STAT_INVALID_ORDER;
|
||||
cc = 1; /* status stored */
|
||||
break;
|
||||
/* all other sigp orders target a single vcpu */
|
||||
dst_cpu = s390_cpu_addr2state(env->regs[r3]);
|
||||
ret = handle_sigp_single_dst(dst_cpu, order, param, status_reg);
|
||||
}
|
||||
|
||||
out:
|
||||
setcc(cpu, cc);
|
||||
return 0;
|
||||
trace_kvm_sigp_finished(order, CPU(cpu)->cpu_index,
|
||||
dst_cpu ? CPU(dst_cpu)->cpu_index : -1, ret);
|
||||
|
||||
if (ret >= 0) {
|
||||
setcc(cpu, ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int handle_instruction(S390CPU *cpu, struct kvm_run *run)
|
||||
@ -1317,6 +1612,11 @@ static int handle_intercept(S390CPU *cpu)
|
||||
if (s390_cpu_set_state(CPU_STATE_STOPPED, cpu) == 0) {
|
||||
qemu_system_shutdown_request();
|
||||
}
|
||||
if (cpu->env.sigp_order == SIGP_STOP_STORE_STATUS) {
|
||||
kvm_s390_store_status(cpu, KVM_S390_STORE_STATUS_DEF_ADDR,
|
||||
true);
|
||||
}
|
||||
cpu->env.sigp_order = 0;
|
||||
r = EXCP_HALTED;
|
||||
break;
|
||||
case ICPT_SOFT_INTERCEPT:
|
||||
|
@ -36,8 +36,8 @@ static int cpu_post_load(void *opaque, int version_id)
|
||||
const VMStateDescription vmstate_s390_cpu = {
|
||||
.name = "cpu",
|
||||
.post_load = cpu_post_load,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(env.fregs[0].ll, S390CPU),
|
||||
VMSTATE_UINT64(env.fregs[1].ll, S390CPU),
|
||||
@ -71,6 +71,7 @@ const VMStateDescription vmstate_s390_cpu = {
|
||||
VMSTATE_UINT32_ARRAY(env.aregs, S390CPU, 16),
|
||||
VMSTATE_UINT64_ARRAY(env.cregs, S390CPU, 16),
|
||||
VMSTATE_UINT8(env.cpu_state, S390CPU),
|
||||
VMSTATE_UINT8(env.sigp_order, S390CPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
@ -456,7 +456,7 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
|
||||
uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
|
||||
uint64_t cpu_addr)
|
||||
{
|
||||
int cc = 0;
|
||||
int cc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
|
||||
HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
|
||||
__func__, order_code, r1, cpu_addr);
|
||||
@ -490,7 +490,7 @@ uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
|
||||
default:
|
||||
/* unknown sigp */
|
||||
fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
|
||||
cc = 3;
|
||||
cc = SIGP_CC_NOT_OPERATIONAL;
|
||||
}
|
||||
|
||||
return cc;
|
||||
|
@ -1581,6 +1581,7 @@ mhp_pc_dimm_assigned_address(uint64_t addr) "0x%"PRIx64
|
||||
kvm_enable_cmma(int rc) "CMMA: enabling with result code %d"
|
||||
kvm_clear_cmma(int rc) "CMMA: clearing with result code %d"
|
||||
kvm_failed_cpu_state_set(int cpu_index, uint8_t state, const char *msg) "Warning: Unable to set cpu %d state %" PRIu8 " to KVM: %s"
|
||||
kvm_sigp_finished(uint8_t order, int cpu_index, int dst_index, int cc) "SIGP: Finished order %u on cpu %d -> cpu %d with cc=%d"
|
||||
|
||||
# hw/dma/i8257.c
|
||||
i8257_unregistered_dma(int nchan, int dma_pos, int dma_len) "unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d"
|
||||
|
Loading…
Reference in New Issue
Block a user