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>
master
Peter Maydell 2015-03-11 15:11:58 +00:00
commit 165fa4091e
27 changed files with 785 additions and 230 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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 {

View File

@ -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();

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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 */
/*

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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.

View File

@ -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 *~

View File

@ -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 };

View File

@ -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 */

View File

@ -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;

View File

@ -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));

View File

@ -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()) {

View File

@ -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;

View File

@ -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:

View File

@ -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()
},
};

View File

@ -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;

View File

@ -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"