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:
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_phdr
#undef elf_shdr #undef elf_shdr
#undef elf_sym #undef elf_sym
#undef elf_rela
#undef elf_note #undef elf_note
#undef elf_word #undef elf_word
#undef elf_sword #undef elf_sword
@ -307,6 +308,7 @@ static void *load_at(int fd, int offset, int size)
#define elf_note elf64_note #define elf_note elf64_note
#define elf_shdr elf64_shdr #define elf_shdr elf64_shdr
#define elf_sym elf64_sym #define elf_sym elf64_sym
#define elf_rela elf64_rela
#define elf_word uint64_t #define elf_word uint64_t
#define elf_sword int64_t #define elf_sword int64_t
#define bswapSZs bswap64s #define bswapSZs bswap64s

View File

@ -14,6 +14,7 @@
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "cpu.h" #include "cpu.h"
#include "elf.h" #include "elf.h"
#include "exec/ram_addr.h"
#include "hw/loader.h" #include "hw/loader.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "hw/s390x/virtio-ccw.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) static int s390_ipl_init(SysBusDevice *dev)
{ {
S390IPLState *ipl = S390_IPL(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. * even if an external kernel has been defined.
*/ */
if (!ipl->kernel || ipl->enforce_bios) { if (!ipl->kernel || ipl->enforce_bios) {
uint64_t fwbase = (MIN(ram_size, 0x80000000U) - 0x200000) & ~0xffffUL;
if (bios_name == NULL) { if (bios_name == NULL) {
bios_name = ipl->firmware; bios_name = ipl->firmware;
} }
@ -118,9 +131,14 @@ static int s390_ipl_init(SysBusDevice *dev)
hw_error("could not find stage1 bootloader\n"); hw_error("could not find stage1 bootloader\n");
} }
bios_size = load_elf(bios_filename, NULL, NULL, &ipl->bios_start_addr, bios_size = load_elf(bios_filename, bios_translate_addr, &fwbase,
NULL, NULL, 1, ELF_MACHINE, 0); &ipl->bios_start_addr, NULL, NULL, 1,
if (bios_size < 0) { 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, bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START,
4096); 4096);
ipl->bios_start_addr = ZIPL_IMAGE_START; 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; return bus;
} }
static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev) static void s390_virtio_device_init(VirtIOS390Device *dev,
VirtIODevice *vdev)
{ {
VirtIOS390Bus *bus; VirtIOS390Bus *bus;
int dev_len; int dev_len;
@ -135,25 +136,26 @@ static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev)
if (dev->qdev.hotplugged) { if (dev->qdev.hotplugged) {
s390_virtio_irq(VIRTIO_PARAM_DEV_ADD, dev->dev_offs); 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); DeviceState *qdev = DEVICE(s390_dev);
VirtIONetS390 *dev = VIRTIO_NET_S390(s390_dev); VirtIONetS390 *dev = VIRTIO_NET_S390(s390_dev);
DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *vdev = DEVICE(&dev->vdev);
Error *err = NULL;
virtio_net_set_config_size(&dev->vdev, s390_dev->host_features); virtio_net_set_config_size(&dev->vdev, s390_dev->host_features);
virtio_net_set_netclient_name(&dev->vdev, qdev->id, virtio_net_set_netclient_name(&dev->vdev, qdev->id,
object_get_typename(OBJECT(qdev))); object_get_typename(OBJECT(qdev)));
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus)); qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
if (qdev_init(vdev) < 0) { object_property_set_bool(OBJECT(vdev), true, "realized", &err);
return -1; 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) 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); "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); VirtIOBlkS390 *dev = VIRTIO_BLK_S390(s390_dev);
DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *vdev = DEVICE(&dev->vdev);
Error *err = NULL;
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus)); qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
if (qdev_init(vdev) < 0) { object_property_set_bool(OBJECT(vdev), true, "realized", &err);
return -1; 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) 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); "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); VirtIOSerialS390 *dev = VIRTIO_SERIAL_S390(s390_dev);
DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *vdev = DEVICE(&dev->vdev);
DeviceState *qdev = DEVICE(s390_dev); DeviceState *qdev = DEVICE(s390_dev);
Error *err = NULL;
VirtIOS390Bus *bus; VirtIOS390Bus *bus;
int r;
char *bus_name; char *bus_name;
bus = DO_UPCAST(VirtIOS390Bus, bus, qdev->parent_bus); 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)); qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
if (qdev_init(vdev) < 0) { object_property_set_bool(OBJECT(vdev), true, "realized", &err);
return -1; if (err) {
error_propagate(errp, err);
return;
} }
r = s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev)); s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
if (!r) { bus->console = s390_dev;
bus->console = s390_dev;
}
return r;
} }
static void s390_virtio_serial_instance_init(Object *obj) 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); 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); VirtIOSCSIS390 *dev = VIRTIO_SCSI_S390(s390_dev);
DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *vdev = DEVICE(&dev->vdev);
DeviceState *qdev = DEVICE(s390_dev); DeviceState *qdev = DEVICE(s390_dev);
Error *err = NULL;
char *bus_name; 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)); qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
if (qdev_init(vdev) < 0) { object_property_set_bool(OBJECT(vdev), true, "realized", &err);
return -1; 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) 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 #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); VHostSCSIS390 *dev = VHOST_SCSI_S390(s390_dev);
DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *vdev = DEVICE(&dev->vdev);
Error *err = NULL;
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus)); qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
if (qdev_init(vdev) < 0) { object_property_set_bool(OBJECT(vdev), true, "realized", &err);
return -1; 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) static void s390_vhost_scsi_instance_init(Object *obj)
@ -288,21 +298,24 @@ static void s390_vhost_scsi_instance_init(Object *obj)
#endif #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); VirtIORNGS390 *dev = VIRTIO_RNG_S390(s390_dev);
DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *vdev = DEVICE(&dev->vdev);
Error *err = NULL;
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus)); qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
if (qdev_init(vdev) < 0) { object_property_set_bool(OBJECT(vdev), true, "realized", &err);
return -1; if (err) {
error_propagate(errp, err);
return;
} }
object_property_set_link(OBJECT(dev), object_property_set_link(OBJECT(dev),
OBJECT(dev->vdev.conf.rng), "rng", OBJECT(dev->vdev.conf.rng), "rng",
NULL); 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) 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); DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOS390DeviceClass *k = VIRTIO_S390_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; 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); 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 = { 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); DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOS390DeviceClass *k = VIRTIO_S390_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; 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); DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOS390DeviceClass *k = VIRTIO_S390_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; dc->props = s390_virtio_rng_properties;
} }
@ -579,14 +592,14 @@ static const TypeInfo s390_virtio_rng = {
.class_init = s390_virtio_rng_class_init, .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; VirtIOS390Device *_dev = (VirtIOS390Device *)dev;
VirtIOS390DeviceClass *_info = VIRTIO_S390_DEVICE_GET_CLASS(dev); VirtIOS390DeviceClass *_info = VIRTIO_S390_DEVICE_GET_CLASS(dev);
virtio_s390_bus_new(&_dev->bus, sizeof(_dev->bus), _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) 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); 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->bus_type = TYPE_S390_VIRTIO_BUS;
dc->reset = s390_virtio_busdev_reset; 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); DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOS390DeviceClass *k = VIRTIO_S390_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; 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); DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOS390DeviceClass *k = VIRTIO_S390_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; dc->props = s390_vhost_scsi_properties;
} }

View File

@ -83,7 +83,7 @@ typedef struct VirtIOS390Device VirtIOS390Device;
typedef struct VirtIOS390DeviceClass { typedef struct VirtIOS390DeviceClass {
DeviceClass qdev; DeviceClass qdev;
int (*init)(VirtIOS390Device *dev); void (*realize)(VirtIOS390Device *dev, Error **errp);
} VirtIOS390DeviceClass; } VirtIOS390DeviceClass;
struct VirtIOS390Device { struct VirtIOS390Device {

View File

@ -97,6 +97,7 @@ static void ccw_init(MachineState *machine)
ram_addr_t pad_size = 0; ram_addr_t pad_size = 0;
ram_addr_t maxmem = qemu_opt_get_size(opts, "maxmem", my_ram_size); ram_addr_t maxmem = qemu_opt_get_size(opts, "maxmem", my_ram_size);
ram_addr_t standby_mem_size = 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 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. * 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. */ /* let's propagate the changed ram size into the global variable. */
ram_size = my_ram_size; 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 */ /* get a BUS */
css_bus = virtual_css_bus_init(); css_bus = virtual_css_bus_init();

View File

@ -607,7 +607,8 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
return ret; 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 cssid = 0;
unsigned int ssid = 0; unsigned int ssid = 0;
@ -616,7 +617,6 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
bool have_devno = false; bool have_devno = false;
bool found = false; bool found = false;
SubchDev *sch; SubchDev *sch;
int ret;
int num; int num;
DeviceState *parent = DEVICE(dev); 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); num = sscanf(dev->bus_id, "%x.%x.%04x", &cssid, &ssid, &devno);
if (num == 3) { if (num == 3) {
if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) { if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) {
ret = -EINVAL; error_setg(errp, "Invalid cssid or ssid: cssid %x, ssid %x",
error_report("Invalid cssid or ssid: cssid %x, ssid %x", cssid, ssid);
cssid, ssid);
goto out_err; goto out_err;
} }
/* Enforce use of virtual cssid. */ /* Enforce use of virtual cssid. */
if (cssid != VIRTUAL_CSSID) { if (cssid != VIRTUAL_CSSID) {
ret = -EINVAL; error_setg(errp, "cssid %x not valid for virtio devices",
error_report("cssid %x not valid for virtio devices", cssid); cssid);
goto out_err; goto out_err;
} }
if (css_devno_used(cssid, ssid, devno)) { if (css_devno_used(cssid, ssid, devno)) {
ret = -EEXIST; error_setg(errp, "Device %x.%x.%04x already exists",
error_report("Device %x.%x.%04x already exists", cssid, ssid, cssid, ssid, devno);
devno);
goto out_err; goto out_err;
} }
sch->cssid = cssid; sch->cssid = cssid;
@ -661,8 +659,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
sch->devno = devno; sch->devno = devno;
have_devno = true; have_devno = true;
} else { } else {
ret = -EINVAL; error_setg(errp, "Malformed devno parameter '%s'", dev->bus_id);
error_report("Malformed devno parameter '%s'", dev->bus_id);
goto out_err; goto out_err;
} }
} }
@ -678,9 +675,8 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
} }
} }
if (!found) { if (!found) {
ret = -ENODEV; error_setg(errp, "No free subchannel found for %x.%x.%04x",
error_report("No free subchannel found for %x.%x.%04x", cssid, ssid, cssid, ssid, devno);
devno);
goto out_err; goto out_err;
} }
trace_virtio_ccw_new_device(cssid, ssid, schid, devno, 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) { if (devno == MAX_SCHID) {
devno = 0; devno = 0;
} else if (devno == schid - 1) { } else if (devno == schid - 1) {
ret = -ENODEV; error_setg(errp, "No free devno found");
error_report("No free devno found");
goto out_err; goto out_err;
} else { } else {
devno++; devno++;
@ -720,8 +715,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
} }
} }
if (!found) { if (!found) {
ret = -ENODEV; error_setg(errp, "Virtual channel subsystem is full!");
error_report("Virtual channel subsystem is full!");
goto out_err; goto out_err;
} }
trace_virtio_ccw_new_device(cssid, ssid, schid, devno, 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, css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid,
parent->hotplugged, 1); parent->hotplugged, 1);
return 0; return;
out_err: out_err:
dev->sch = NULL; dev->sch = NULL;
g_free(sch); g_free(sch);
return ret;
} }
static int virtio_ccw_exit(VirtioCcwDevice *dev) static int virtio_ccw_exit(VirtioCcwDevice *dev)
@ -771,21 +764,24 @@ static int virtio_ccw_exit(VirtioCcwDevice *dev)
return 0; 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); DeviceState *qdev = DEVICE(ccw_dev);
VirtIONetCcw *dev = VIRTIO_NET_CCW(ccw_dev); VirtIONetCcw *dev = VIRTIO_NET_CCW(ccw_dev);
DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *vdev = DEVICE(&dev->vdev);
Error *err = NULL;
virtio_net_set_config_size(&dev->vdev, ccw_dev->host_features[0]); virtio_net_set_config_size(&dev->vdev, ccw_dev->host_features[0]);
virtio_net_set_netclient_name(&dev->vdev, qdev->id, virtio_net_set_netclient_name(&dev->vdev, qdev->id,
object_get_typename(OBJECT(qdev))); object_get_typename(OBJECT(qdev)));
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
if (qdev_init(vdev) < 0) { object_property_set_bool(OBJECT(vdev), true, "realized", &err);
return -1; 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) 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); "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); VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev);
DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *vdev = DEVICE(&dev->vdev);
Error *err = NULL;
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
if (qdev_init(vdev) < 0) { object_property_set_bool(OBJECT(vdev), true, "realized", &err);
return -1; 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) 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); "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); VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(ccw_dev);
DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *vdev = DEVICE(&dev->vdev);
DeviceState *proxy = DEVICE(ccw_dev); DeviceState *proxy = DEVICE(ccw_dev);
Error *err = NULL;
char *bus_name; 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)); qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
if (qdev_init(vdev) < 0) { object_property_set_bool(OBJECT(vdev), true, "realized", &err);
return -1; 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); 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); VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(ccw_dev);
DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *vdev = DEVICE(&dev->vdev);
Error *err = NULL;
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
if (qdev_init(vdev) < 0) { object_property_set_bool(OBJECT(vdev), true, "realized", &err);
return -1; 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, 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); 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); VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(ccw_dev);
DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *vdev = DEVICE(&dev->vdev);
DeviceState *qdev = DEVICE(ccw_dev); DeviceState *qdev = DEVICE(ccw_dev);
Error *err = NULL;
char *bus_name; 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)); qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
if (qdev_init(vdev) < 0) { object_property_set_bool(OBJECT(vdev), true, "realized", &err);
return -1; 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) 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 #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); VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev);
DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *vdev = DEVICE(&dev->vdev);
Error *err = NULL;
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
if (qdev_init(vdev) < 0) { object_property_set_bool(OBJECT(vdev), true, "realized", &err);
return -1; 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) static void vhost_ccw_scsi_instance_init(Object *obj)
@ -967,21 +979,24 @@ static void vhost_ccw_scsi_instance_init(Object *obj)
} }
#endif #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); VirtIORNGCcw *dev = VIRTIO_RNG_CCW(ccw_dev);
DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *vdev = DEVICE(&dev->vdev);
Error *err = NULL;
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
if (qdev_init(vdev) < 0) { object_property_set_bool(OBJECT(vdev), true, "realized", &err);
return -1; if (err) {
error_propagate(errp, err);
return;
} }
object_property_set_link(OBJECT(dev), object_property_set_link(OBJECT(dev),
OBJECT(dev->vdev.conf.rng), "rng", OBJECT(dev->vdev.conf.rng), "rng",
NULL); 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, /* 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); DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_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; k->exit = virtio_ccw_exit;
dc->reset = virtio_ccw_reset; dc->reset = virtio_ccw_reset;
dc->props = virtio_ccw_net_properties; 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); DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_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; k->exit = virtio_ccw_exit;
dc->reset = virtio_ccw_reset; dc->reset = virtio_ccw_reset;
dc->props = virtio_ccw_blk_properties; 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); DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_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; k->exit = virtio_ccw_exit;
dc->reset = virtio_ccw_reset; dc->reset = virtio_ccw_reset;
dc->props = virtio_ccw_serial_properties; 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); DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_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; k->exit = virtio_ccw_exit;
dc->reset = virtio_ccw_reset; dc->reset = virtio_ccw_reset;
dc->props = virtio_ccw_balloon_properties; 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); DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_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; k->exit = virtio_ccw_exit;
dc->reset = virtio_ccw_reset; dc->reset = virtio_ccw_reset;
dc->props = virtio_ccw_scsi_properties; 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); DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_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; k->exit = virtio_ccw_exit;
dc->reset = virtio_ccw_reset; dc->reset = virtio_ccw_reset;
dc->props = vhost_ccw_scsi_properties; 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); DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_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; k->exit = virtio_ccw_exit;
dc->reset = virtio_ccw_reset; dc->reset = virtio_ccw_reset;
dc->props = virtio_ccw_rng_properties; dc->props = virtio_ccw_rng_properties;
@ -1572,14 +1587,13 @@ static const TypeInfo virtio_ccw_rng = {
.class_init = virtio_ccw_rng_class_init, .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; VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev); VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
virtio_ccw_bus_new(&_dev->bus, sizeof(_dev->bus), _dev); virtio_ccw_bus_new(&_dev->bus, sizeof(_dev->bus), _dev);
_info->realize(_dev, errp);
return _info->init(_dev);
} }
static int virtio_ccw_busdev_exit(DeviceState *dev) 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); DeviceClass *dc = DEVICE_CLASS(klass);
dc->props = virtio_ccw_properties; dc->props = virtio_ccw_properties;
dc->init = virtio_ccw_busdev_init; dc->realize = virtio_ccw_busdev_realize;
dc->exit = virtio_ccw_busdev_exit; dc->exit = virtio_ccw_busdev_exit;
dc->bus_type = TYPE_VIRTUAL_CSS_BUS; dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
} }

View File

@ -64,7 +64,7 @@ typedef struct VirtioCcwDevice VirtioCcwDevice;
typedef struct VirtIOCCWDeviceClass { typedef struct VirtIOCCWDeviceClass {
DeviceClass parent_class; DeviceClass parent_class;
int (*init)(VirtioCcwDevice *dev); void (*realize)(VirtioCcwDevice *dev, Error **errp);
int (*exit)(VirtioCcwDevice *dev); int (*exit)(VirtioCcwDevice *dev);
} VirtIOCCWDeviceClass; } VirtIOCCWDeviceClass;

View File

@ -1508,6 +1508,7 @@ struct elf32_fdpic_loadmap {
#define elf_shdr elf32_shdr #define elf_shdr elf32_shdr
#define elf_sym elf32_sym #define elf_sym elf32_sym
#define elf_addr_t Elf32_Off #define elf_addr_t Elf32_Off
#define elf_rela elf32_rela
#ifdef ELF_USES_RELOCA #ifdef ELF_USES_RELOCA
# define ELF_RELOC Elf32_Rela # define ELF_RELOC Elf32_Rela
@ -1523,6 +1524,7 @@ struct elf32_fdpic_loadmap {
#define elf_shdr elf64_shdr #define elf_shdr elf64_shdr
#define elf_sym elf64_sym #define elf_sym elf64_sym
#define elf_addr_t Elf64_Off #define elf_addr_t Elf64_Off
#define elf_rela elf64_rela
#ifdef ELF_USES_RELOCA #ifdef ELF_USES_RELOCA
# define ELF_RELOC Elf64_Rela # 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); 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, static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
int n, int type) int n, int type)
{ {
@ -182,6 +189,75 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
return -1; 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, static int glue(load_elf, SZ)(const char *name, int fd,
uint64_t (*translate_fn)(void *, uint64_t), uint64_t (*translate_fn)(void *, uint64_t),
void *translate_opaque, void *translate_opaque,
@ -271,6 +347,8 @@ static int glue(load_elf, SZ)(const char *name, int fd,
linked at the wrong physical address. */ linked at the wrong physical address. */
if (translate_fn) { if (translate_fn) {
addr = translate_fn(translate_opaque, ph->p_paddr); 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 { } else {
addr = ph->p_paddr; addr = ph->p_paddr;
} }

View File

@ -74,39 +74,12 @@ struct virtio_net_config {
uint16_t max_virtqueue_pairs; uint16_t max_virtqueue_pairs;
} QEMU_PACKED; } 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 * This header comes first in the scatter-gather list. If you don't
* specify GSO or CSUM features, you can simply ignore the header. * 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 { struct virtio_net_hdr_v1 {
#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 /* Use csum_start, csum_offset */ #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 csum_offset; /* Offset after that to place checksum */
__virtio16 num_buffers; /* Number of merged rx buffers */ __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 */ #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_SHIFT 0
#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) #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_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 */ /* KVM_IRQ_LINE irq field index values */
#define KVM_ARM_IRQ_TYPE_SHIFT 24 #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_DIST_SIZE 0x1000
#define KVM_VGIC_V2_CPU_SIZE 0x2000 #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_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_EL1_32BIT 1 /* CPU running a 32bit VM */
#define KVM_ARM_VCPU_PSCI_0_2 2 /* CPU uses PSCI v0.2 */ #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_SHIFT 0
#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) #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_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 */ /* KVM_IRQ_LINE irq field index values */
#define KVM_ARM_IRQ_TYPE_SHIFT 24 #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 */ /* kvm attr_group on vm fd */
#define KVM_S390_VM_MEM_CTRL 0 #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 */ /* kvm attributes for mem_ctrl */
#define KVM_S390_VM_MEM_ENABLE_CMMA 0 #define KVM_S390_VM_MEM_ENABLE_CMMA 0
#define KVM_S390_VM_MEM_CLR_CMMA 1 #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 */ /* for KVM_GET_REGS and KVM_SET_REGS */
struct kvm_regs { struct kvm_regs {
@ -107,6 +141,9 @@ struct kvm_guest_debug_arch {
struct kvm_hw_breakpoint *hw_bp; 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_PREFIX (1UL << 0)
#define KVM_SYNC_GPRS (1UL << 1) #define KVM_SYNC_GPRS (1UL << 1)
#define KVM_SYNC_ACRS (1UL << 2) #define KVM_SYNC_ACRS (1UL << 2)

View File

@ -187,6 +187,17 @@
#define HV_X64_MSR_SINT14 0x4000009E #define HV_X64_MSR_SINT14 0x4000009E
#define HV_X64_MSR_SINT15 0x4000009F #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_ENABLE 0x00000001
#define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT 12 #define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT 12

View File

@ -491,6 +491,11 @@ struct kvm_s390_emerg_info {
__u16 code; __u16 code;
}; };
#define KVM_S390_STOP_FLAG_STORE_STATUS 0x01
struct kvm_s390_stop_info {
__u32 flags;
};
struct kvm_s390_mchk_info { struct kvm_s390_mchk_info {
__u64 cr14; __u64 cr14;
__u64 mcic; __u64 mcic;
@ -509,6 +514,7 @@ struct kvm_s390_irq {
struct kvm_s390_emerg_info emerg; struct kvm_s390_emerg_info emerg;
struct kvm_s390_extcall_info extcall; struct kvm_s390_extcall_info extcall;
struct kvm_s390_prefix_info prefix; struct kvm_s390_prefix_info prefix;
struct kvm_s390_stop_info stop;
struct kvm_s390_mchk_info mchk; struct kvm_s390_mchk_info mchk;
char reserved[64]; char reserved[64];
} u; } u;
@ -647,11 +653,7 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_MP_STATE 14 #define KVM_CAP_MP_STATE 14
#define KVM_CAP_COALESCED_MMIO 15 #define KVM_CAP_COALESCED_MMIO 15
#define KVM_CAP_SYNC_MMU 16 /* Changes to host mmap are reflected in guest */ #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 #define KVM_CAP_IOMMU 18
#ifdef __KVM_HAVE_MSI
#define KVM_CAP_DEVICE_MSI 20
#endif
/* Bug in KVM_SET_USER_MEMORY_REGION fixed: */ /* Bug in KVM_SET_USER_MEMORY_REGION fixed: */
#define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21 #define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21
#define KVM_CAP_USER_NMI 22 #define KVM_CAP_USER_NMI 22
@ -663,10 +665,6 @@ struct kvm_ppc_smmu_info {
#endif #endif
#define KVM_CAP_IRQ_ROUTING 25 #define KVM_CAP_IRQ_ROUTING 25
#define KVM_CAP_IRQ_INJECT_STATUS 26 #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 #define KVM_CAP_ASSIGN_DEV_IRQ 29
/* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */ /* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
#define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30 #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_FIXUP_HCALL 103
#define KVM_CAP_PPC_ENABLE_HCALL 104 #define KVM_CAP_PPC_ENABLE_HCALL 104
#define KVM_CAP_CHECK_EXTENSION_VM 105 #define KVM_CAP_CHECK_EXTENSION_VM 105
#define KVM_CAP_S390_USER_SIGP 106
#ifdef KVM_CAP_IRQ_ROUTING #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 #define KVM_DEV_TYPE_ARM_VGIC_V2 KVM_DEV_TYPE_ARM_VGIC_V2
KVM_DEV_TYPE_FLIC, KVM_DEV_TYPE_FLIC,
#define KVM_DEV_TYPE_FLIC 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, 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_SETUP_MCE _IOW(KVMIO, 0x9c, __u64)
#define KVM_X86_GET_MCE_CAP_SUPPORTED _IOR(KVMIO, 0x9d, __u64) #define KVM_X86_GET_MCE_CAP_SUPPORTED _IOR(KVMIO, 0x9d, __u64)
#define KVM_X86_SET_MCE _IOW(KVMIO, 0x9e, struct kvm_x86_mce) #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 */ /* Available with KVM_CAP_VCPU_EVENTS */
#define KVM_GET_VCPU_EVENTS _IOR(KVMIO, 0x9f, struct kvm_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) #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 .PHONY : all clean build-all
OBJECTS=main.o bootmap.o sclp-ascii.o virtio.o start.o OBJECTS = start.o main.o bootmap.o sclp-ascii.o virtio.o
CFLAGS += -fno-stack-protector CFLAGS += -fPIE -fno-stack-protector -ffreestanding
# XXX find a more clever to locate the bootloader LDFLAGS += -Wl,-pie -nostdlib
LDFLAGS += -Wl,-Ttext,0x7e00000,-Tbss,0x7f00000 -nostdlib
build-all: s390-ccw.img build-all: s390-ccw.img
@ -20,7 +19,9 @@ s390-ccw.elf: $(OBJECTS)
$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS)," Building $(TARGET_DIR)$@") $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS)," Building $(TARGET_DIR)$@")
s390-ccw.img: s390-ccw.elf 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: clean:
rm -f *.o *.d *.img *.elf *~ rm -f *.o *.d *.img *.elf *~

View File

@ -12,6 +12,7 @@
#include "virtio.h" #include "virtio.h"
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE))); char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
char ring_area[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
uint64_t boot_value; uint64_t boot_value;
static struct subchannel_id blk_schid = { .one = 1 }; 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 virtio_panic(const char *string);
void write_subsystem_identification(void); void write_subsystem_identification(void);
extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE))); 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; extern uint64_t boot_value;
/* sclp-ascii.c */ /* sclp-ascii.c */

View File

@ -362,6 +362,7 @@ void virtio_setup_block(struct subchannel_id schid)
struct vq_config_block config = {}; struct vq_config_block config = {};
blk_cfg.blk_size = 0; /* mark "illegal" - setup started... */ blk_cfg.blk_size = 0; /* mark "illegal" - setup started... */
guessed_disk_nature = false;
virtio_reset(schid); 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))) { if (run_ccw(schid, CCW_CMD_READ_CONF, &blk_cfg, sizeof(blk_cfg))) {
virtio_panic("Could not get block device configuration\n"); 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); 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.align = KVM_S390_VIRTIO_RING_ALIGN;
info.index = 0; info.index = 0;
info.num = config.num; info.num = config.num;

View File

@ -96,6 +96,7 @@ static void s390_cpu_reset(CPUState *s)
env->pfault_token = -1UL; env->pfault_token = -1UL;
scc->parent_reset(s); scc->parent_reset(s);
cpu->env.sigp_order = 0;
s390_cpu_set_state(CPU_STATE_STOPPED, cpu); s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
tlb_flush(s, 1); tlb_flush(s, 1);
} }
@ -131,6 +132,7 @@ static void s390_cpu_full_reset(CPUState *s)
CPUS390XState *env = &cpu->env; CPUS390XState *env = &cpu->env;
scc->parent_reset(s); scc->parent_reset(s);
cpu->env.sigp_order = 0;
s390_cpu_set_state(CPU_STATE_STOPPED, cpu); s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
memset(env, 0, offsetof(CPUS390XState, cpu_num)); memset(env, 0, offsetof(CPUS390XState, cpu_num));

View File

@ -157,6 +157,9 @@ typedef struct CPUS390XState {
#define CPU_STATE_LOAD 0x04 #define CPU_STATE_LOAD 0x04
uint8_t cpu_state; uint8_t cpu_state;
/* currently processed sigp order */
uint8_t sigp_order;
} CPUS390XState; } CPUS390XState;
#include "cpu-qom.h" #include "cpu-qom.h"
@ -349,7 +352,10 @@ int s390_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
#include "ioinst.h" #include "ioinst.h"
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
void do_restart_interrupt(CPUS390XState *env);
static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb) static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb)
{ {
hwaddr addr = 0; hwaddr addr = 0;
@ -411,6 +417,10 @@ S390CPU *s390_cpu_addr2state(uint16_t cpu_addr);
unsigned int s390_cpu_halt(S390CPU *cpu); unsigned int s390_cpu_halt(S390CPU *cpu);
void s390_cpu_unhalt(S390CPU *cpu); void s390_cpu_unhalt(S390CPU *cpu);
unsigned int s390_cpu_set_state(uint8_t cpu_state, 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 */ /* service interrupts are floating therefore we must not pass an cpustate */
void s390_sclp_extint(uint32_t parm); void s390_sclp_extint(uint32_t parm);
@ -664,7 +674,7 @@ typedef struct LowCore
PSW mcck_old_psw; /* 0x160 */ PSW mcck_old_psw; /* 0x160 */
PSW io_old_psw; /* 0x170 */ PSW io_old_psw; /* 0x170 */
uint8_t pad7[0x1a0-0x180]; /* 0x180 */ uint8_t pad7[0x1a0-0x180]; /* 0x180 */
PSW restart_psw; /* 0x1a0 */ PSW restart_new_psw; /* 0x1a0 */
PSW external_new_psw; /* 0x1b0 */ PSW external_new_psw; /* 0x1b0 */
PSW svc_new_psw; /* 0x1c0 */ PSW svc_new_psw; /* 0x1c0 */
PSW program_new_psw; /* 0x1d0 */ PSW program_new_psw; /* 0x1d0 */
@ -864,6 +874,7 @@ struct sysib_322 {
#define SK_F (0x1 << 3) #define SK_F (0x1 << 3)
#define SK_ACC_MASK (0xf << 4) #define SK_ACC_MASK (0xf << 4)
/* SIGP order codes */
#define SIGP_SENSE 0x01 #define SIGP_SENSE 0x01
#define SIGP_EXTERNAL_CALL 0x02 #define SIGP_EXTERNAL_CALL 0x02
#define SIGP_EMERGENCY 0x03 #define SIGP_EMERGENCY 0x03
@ -877,7 +888,13 @@ struct sysib_322 {
#define SIGP_STORE_STATUS_ADDR 0x0e #define SIGP_STORE_STATUS_ADDR 0x0e
#define SIGP_SET_ARCH 0x12 #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_EQUIPMENT_CHECK 0x80000000UL
#define SIGP_STAT_INCORRECT_STATE 0x00000200UL #define SIGP_STAT_INCORRECT_STATE 0x00000200UL
#define SIGP_STAT_INVALID_PARAMETER 0x00000100UL #define SIGP_STAT_INVALID_PARAMETER 0x00000100UL
@ -889,6 +906,11 @@ struct sysib_322 {
#define SIGP_STAT_INVALID_ORDER 0x00000002UL #define SIGP_STAT_INVALID_ORDER 0x00000002UL
#define SIGP_STAT_RECEIVER_CHECK 0x00000001UL #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); void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
target_ulong *raddr, int *flags, bool exc); target_ulong *raddr, int *flags, bool exc);
@ -1007,6 +1029,7 @@ int kvm_s390_get_memslot_count(KVMState *s);
void kvm_s390_clear_cmma_callback(void *opaque); void kvm_s390_clear_cmma_callback(void *opaque);
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state); int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state);
void kvm_s390_reset_vcpu(S390CPU *cpu); void kvm_s390_reset_vcpu(S390CPU *cpu);
int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit);
#else #else
static inline void kvm_s390_io_interrupt(uint16_t subchannel_id, static inline void kvm_s390_io_interrupt(uint16_t subchannel_id,
uint16_t subchannel_nr, 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 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 #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) static inline void cmma_reset(S390CPU *cpu)
{ {
if (kvm_enabled()) { 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.addr = addr;
env->psw.mask = mask; env->psw.mask = mask;
env->cc_op = (mask >> 44) & 3; if (tcg_enabled()) {
env->cc_op = (mask >> 44) & 3;
}
if (mask & PSW_MASK_WAIT) { if (mask & PSW_MASK_WAIT) {
S390CPU *cpu = s390_env_get_cpu(env); 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) 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;
r &= ~PSW_MASK_CC; assert(!(env->cc_op & ~3));
assert(!(env->cc_op & ~3)); r |= (uint64_t)env->cc_op << 44;
r |= (uint64_t)env->cc_op << 44; }
return r; return r;
} }
@ -229,6 +233,23 @@ static void cpu_unmap_lowcore(LowCore *lowcore)
cpu_physical_memory_unmap(lowcore, sizeof(LowCore), 1, sizeof(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) static void do_svc_interrupt(CPUS390XState *env)
{ {
uint64_t mask, addr; uint64_t mask, addr;

View File

@ -38,6 +38,7 @@
#include "qapi/qmp/qjson.h" #include "qapi/qmp/qjson.h"
#include "monitor/monitor.h" #include "monitor/monitor.h"
#include "exec/gdbstub.h" #include "exec/gdbstub.h"
#include "exec/address-spaces.h"
#include "trace.h" #include "trace.h"
#include "qapi-event.h" #include "qapi-event.h"
#include "hw/s390x/s390-pci-inst.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 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) static int kvm_s390_check_clear_cmma(KVMState *s)
{ {
struct kvm_device_attr attr = { struct kvm_device_attr attr = {
@ -186,6 +232,9 @@ int kvm_arch_init(KVMState *s)
|| !kvm_check_extension(s, KVM_CAP_S390_COW)) { || !kvm_check_extension(s, KVM_CAP_S390_COW)) {
phys_mem_set_alloc(legacy_s390_alloc); phys_mem_set_alloc(legacy_s390_alloc);
} }
kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
return 0; return 0;
} }
@ -1111,52 +1160,315 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
return r; return r;
} }
static void sigp_cpu_start(void *arg) typedef struct SigpInfo {
{ S390CPU *cpu;
CPUState *cs = arg; uint64_t param;
S390CPU *cpu = S390_CPU(cs); int cc;
uint64_t *status_reg;
} SigpInfo;
s390_cpu_set_state(CPU_STATE_OPERATING, cpu); static void set_sigp_status(SigpInfo *si, uint64_t status)
DPRINTF("DONE: KVM cpu start: %p\n", &cpu->env); {
*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; SigpInfo *si = arg;
S390CPU *cpu = S390_CPU(cs);
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 = { struct kvm_s390_irq irq = {
.type = KVM_S390_RESTART, .type = KVM_S390_RESTART,
}; };
kvm_s390_vcpu_interrupt(cpu, &irq); switch (s390_cpu_get_state(si->cpu)) {
s390_cpu_set_state(CPU_STATE_OPERATING, 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) 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); DPRINTF("DONE: KVM cpu restart: %p\n", &cpu->env);
return 0; return 0;
} }
static void sigp_initial_cpu_reset(void *arg) static void sigp_initial_cpu_reset(void *arg)
{ {
CPUState *cpu = arg; SigpInfo *si = arg;
S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); CPUState *cs = CPU(si->cpu);
S390CPUClass *scc = S390_CPU_GET_CLASS(si->cpu);
cpu_synchronize_state(cpu); cpu_synchronize_state(cs);
scc->initial_cpu_reset(cpu); scc->initial_cpu_reset(cs);
cpu_synchronize_post_reset(cpu); cpu_synchronize_post_reset(cs);
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
} }
static void sigp_cpu_reset(void *arg) static void sigp_cpu_reset(void *arg)
{ {
CPUState *cpu = arg; SigpInfo *si = arg;
S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); CPUState *cs = CPU(si->cpu);
S390CPUClass *scc = S390_CPU_GET_CLASS(si->cpu);
cpu_synchronize_state(cpu); cpu_synchronize_state(cs);
scc->cpu_reset(cpu); scc->cpu_reset(cs);
cpu_synchronize_post_reset(cpu); 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 #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) static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
{ {
CPUS390XState *env = &cpu->env; CPUS390XState *env = &cpu->env;
uint8_t order_code; const uint8_t r1 = ipa1 >> 4;
uint16_t cpu_addr; const uint8_t r3 = ipa1 & 0x0f;
S390CPU *target_cpu; int ret;
uint64_t *statusreg = &env->regs[ipa1 >> 4]; uint8_t order;
int cc; uint64_t *status_reg;
uint64_t param;
S390CPU *dst_cpu = NULL;
cpu_synchronize_state(CPU(cpu)); cpu_synchronize_state(CPU(cpu));
/* get order code */ /* 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]; switch (order) {
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;
case SIGP_SET_ARCH: case SIGP_SET_ARCH:
*statusreg &= 0xffffffff00000000UL; ret = sigp_set_architecture(cpu, param, status_reg);
*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;
break; break;
default: default:
DPRINTF("KVM: unknown SIGP: 0x%x\n", order_code); /* all other sigp orders target a single vcpu */
*statusreg &= 0xffffffff00000000UL; dst_cpu = s390_cpu_addr2state(env->regs[r3]);
*statusreg |= SIGP_STAT_INVALID_ORDER; ret = handle_sigp_single_dst(dst_cpu, order, param, status_reg);
cc = 1; /* status stored */
break;
} }
out: trace_kvm_sigp_finished(order, CPU(cpu)->cpu_index,
setcc(cpu, cc); dst_cpu ? CPU(dst_cpu)->cpu_index : -1, ret);
return 0;
if (ret >= 0) {
setcc(cpu, ret);
return 0;
}
return ret;
} }
static int handle_instruction(S390CPU *cpu, struct kvm_run *run) 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) { if (s390_cpu_set_state(CPU_STATE_STOPPED, cpu) == 0) {
qemu_system_shutdown_request(); 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; r = EXCP_HALTED;
break; break;
case ICPT_SOFT_INTERCEPT: 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 = { const VMStateDescription vmstate_s390_cpu = {
.name = "cpu", .name = "cpu",
.post_load = cpu_post_load, .post_load = cpu_post_load,
.version_id = 1, .version_id = 2,
.minimum_version_id = 1, .minimum_version_id = 2,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT64(env.fregs[0].ll, S390CPU), VMSTATE_UINT64(env.fregs[0].ll, S390CPU),
VMSTATE_UINT64(env.fregs[1].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_UINT32_ARRAY(env.aregs, S390CPU, 16),
VMSTATE_UINT64_ARRAY(env.cregs, S390CPU, 16), VMSTATE_UINT64_ARRAY(env.cregs, S390CPU, 16),
VMSTATE_UINT8(env.cpu_state, S390CPU), VMSTATE_UINT8(env.cpu_state, S390CPU),
VMSTATE_UINT8(env.sigp_order, S390CPU),
VMSTATE_END_OF_LIST() 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, uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
uint64_t cpu_addr) uint64_t cpu_addr)
{ {
int cc = 0; int cc = SIGP_CC_ORDER_CODE_ACCEPTED;
HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n", HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
__func__, order_code, r1, cpu_addr); __func__, order_code, r1, cpu_addr);
@ -490,7 +490,7 @@ uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
default: default:
/* unknown sigp */ /* unknown sigp */
fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code); fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
cc = 3; cc = SIGP_CC_NOT_OPERATIONAL;
} }
return cc; 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_enable_cmma(int rc) "CMMA: enabling with result code %d"
kvm_clear_cmma(int rc) "CMMA: clearing 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_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 # 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" i8257_unregistered_dma(int nchan, int dma_pos, int dma_len) "unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d"