diff options
Diffstat (limited to 'hw/s390x/ipl.c')
-rw-r--r-- | hw/s390x/ipl.c | 102 |
1 files changed, 70 insertions, 32 deletions
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index f10420027..2e2664f22 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -30,6 +30,24 @@ #define ZIPL_IMAGE_START 0x009000UL #define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64) +static bool iplb_extended_needed(void *opaque) +{ + S390IPLState *ipl = S390_IPL(object_resolve_path(TYPE_S390_IPL, NULL)); + + return ipl->iplbext_migration; +} + +static const VMStateDescription vmstate_iplb_extended = { + .name = "ipl/iplb_extended", + .version_id = 0, + .minimum_version_id = 0, + .needed = iplb_extended_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(reserved_ext, IplParameterBlock, 4096 - 200), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_iplb = { .name = "ipl/iplb", .version_id = 0, @@ -39,6 +57,10 @@ static const VMStateDescription vmstate_iplb = { VMSTATE_UINT16(devno, IplParameterBlock), VMSTATE_UINT8_ARRAY(reserved2, IplParameterBlock, 88), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription*[]) { + &vmstate_iplb_extended, + NULL } }; @@ -47,8 +69,8 @@ static const VMStateDescription vmstate_ipl = { .version_id = 0, .minimum_version_id = 0, .fields = (VMStateField[]) { - VMSTATE_UINT64(start_addr, S390IPLState), - VMSTATE_UINT64(bios_start_addr, S390IPLState), + VMSTATE_UINT64(compat_start_addr, S390IPLState), + VMSTATE_UINT64(compat_bios_start_addr, S390IPLState), VMSTATE_STRUCT(iplb, S390IPLState, 0, vmstate_iplb, IplParameterBlock), VMSTATE_BOOL(iplb_valid, S390IPLState), VMSTATE_UINT8(cssid, S390IPLState), @@ -107,7 +129,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) /* Adjust ELF start address to final location */ ipl->bios_start_addr += fwbase; } else { - /* Try to load non-ELF file (e.g. s390-ccw.img) */ + /* Try to load non-ELF file */ bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START, 4096); ipl->bios_start_addr = ZIPL_IMAGE_START; @@ -170,6 +192,13 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size); } } + /* + * Don't ever use the migrated values, they could come from a different + * BIOS and therefore don't work. But still migrate the values, so + * QEMUs relying on it don't break. + */ + ipl->compat_start_addr = ipl->start_addr; + ipl->compat_bios_start_addr = ipl->bios_start_addr; qemu_register_reset(qdev_reset_all_fn, dev); error: error_propagate(errp, err); @@ -181,46 +210,52 @@ static Property s390_ipl_properties[] = { DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline), DEFINE_PROP_STRING("firmware", S390IPLState, firmware), DEFINE_PROP_BOOL("enforce_bios", S390IPLState, enforce_bios, false), + DEFINE_PROP_BOOL("iplbext_migration", S390IPLState, iplbext_migration, + true), DEFINE_PROP_END_OF_LIST(), }; -/* - * In addition to updating the iplstate, this function returns: - * - 0 if system was ipled with external kernel - * - -1 if no valid boot device was found - * - ccw id of the boot device otherwise - */ -static uint64_t s390_update_iplstate(S390IPLState *ipl) +static bool s390_gen_initial_iplb(S390IPLState *ipl) { DeviceState *dev_st; - if (ipl->iplb_valid) { - ipl->cssid = 0; - ipl->ssid = 0; - ipl->devno = ipl->iplb.devno; - goto out; - } - - if (ipl->kernel) { - return 0; - } - dev_st = get_boot_device(0); if (dev_st) { - VirtioCcwDevice *ccw_dev = (VirtioCcwDevice *) object_dynamic_cast( - OBJECT(qdev_get_parent_bus(dev_st)->parent), + VirtioCcwDevice *virtio_ccw_dev = (VirtioCcwDevice *) + object_dynamic_cast(OBJECT(qdev_get_parent_bus(dev_st)->parent), TYPE_VIRTIO_CCW_DEVICE); - if (ccw_dev) { - ipl->cssid = ccw_dev->sch->cssid; - ipl->ssid = ccw_dev->sch->ssid; - ipl->devno = ccw_dev->sch->devno; - goto out; + SCSIDevice *sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st), + TYPE_SCSI_DEVICE); + if (virtio_ccw_dev) { + CcwDevice *ccw_dev = CCW_DEVICE(virtio_ccw_dev); + + ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN); + ipl->iplb.blk0_len = + cpu_to_be32(S390_IPLB_MIN_CCW_LEN - S390_IPLB_HEADER_LEN); + ipl->iplb.pbt = S390_IPL_TYPE_CCW; + ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno); + ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3; + return true; + } else if (sd) { + SCSIBus *bus = scsi_bus_from_device(sd); + VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus); + VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw, vdev); + CcwDevice *ccw_dev = CCW_DEVICE(scsi_ccw); + + ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN); + ipl->iplb.blk0_len = + cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN - S390_IPLB_HEADER_LEN); + ipl->iplb.pbt = S390_IPL_TYPE_QEMU_SCSI; + ipl->iplb.scsi.lun = cpu_to_be32(sd->lun); + ipl->iplb.scsi.target = cpu_to_be16(sd->id); + ipl->iplb.scsi.channel = cpu_to_be16(sd->channel); + ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno); + ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3; + return true; } } - return -1; -out: - return (uint32_t) (ipl->cssid << 24 | ipl->ssid << 16 | ipl->devno); + return false; } void s390_ipl_update_diag308(IplParameterBlock *iplb) @@ -258,7 +293,9 @@ void s390_ipl_prepare_cpu(S390CPU *cpu) if (!ipl->kernel || ipl->iplb_valid) { cpu->env.psw.addr = ipl->bios_start_addr; - cpu->env.regs[7] = s390_update_iplstate(ipl); + if (!ipl->iplb_valid) { + ipl->iplb_valid = s390_gen_initial_iplb(ipl); + } } } @@ -268,6 +305,7 @@ static void s390_ipl_reset(DeviceState *dev) if (!ipl->reipl_requested) { ipl->iplb_valid = false; + memset(&ipl->iplb, 0, sizeof(IplParameterBlock)); } ipl->reipl_requested = false; } |