@@ -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
}
};
@@ -181,6 +203,8 @@ 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(),
};
@@ -15,11 +15,59 @@
#include "hw/qdev.h"
#include "cpu.h"
-typedef struct IplParameterBlock {
- uint8_t reserved1[110];
- uint16_t devno;
- uint8_t reserved2[88];
-} IplParameterBlock;
+struct IplBlockCcw {
+ uint8_t reserved0[86];
+ uint16_t devno;
+ uint8_t vm_flags;
+ uint8_t reserved3[3];
+ uint32_t vm_parm_len;
+ uint8_t nss_name[8];
+ uint8_t vm_parm[64];
+ uint8_t reserved4[8];
+} QEMU_PACKED;
+typedef struct IplBlockCcw IplBlockCcw;
+
+struct IplBlockFcp {
+ uint8_t reserved1[305 - 1];
+ uint8_t opt;
+ uint8_t reserved2[3];
+ uint16_t reserved3;
+ uint16_t devno;
+ uint8_t reserved4[4];
+ uint64_t wwpn;
+ uint64_t lun;
+ uint32_t bootprog;
+ uint8_t reserved5[12];
+ uint64_t br_lba;
+ uint32_t scp_data_len;
+ uint8_t reserved6[260];
+ uint8_t scp_data[];
+} QEMU_PACKED;
+typedef struct IplBlockFcp IplBlockFcp;
+
+union IplParameterBlock {
+ struct {
+ uint32_t len;
+ uint8_t reserved0[3];
+ uint8_t version;
+ uint32_t blk0_len;
+ uint8_t pbt;
+ uint8_t flags;
+ uint16_t reserved01;
+ uint8_t loadparm[8];
+ union {
+ IplBlockCcw ccw;
+ IplBlockFcp fcp;
+ };
+ } QEMU_PACKED;
+ struct {
+ uint8_t reserved1[110];
+ uint16_t devno;
+ uint8_t reserved2[88];
+ uint8_t reserved_ext[4096 - 200];
+ } QEMU_PACKED;
+} QEMU_PACKED;
+typedef union IplParameterBlock IplParameterBlock;
void s390_ipl_update_diag308(IplParameterBlock *iplb);
void s390_ipl_prepare_cpu(S390CPU *cpu);
@@ -47,7 +95,10 @@ struct S390IPLState {
uint8_t cssid;
uint8_t ssid;
uint16_t devno;
+ bool iplbext_migration;
};
typedef struct S390IPLState S390IPLState;
+#define S390_IPLB_MIN_CCW_LEN 200
+
#endif
@@ -25,6 +25,7 @@
#include "s390-pci-bus.h"
#include "hw/s390x/storage-keys.h"
#include "hw/compat.h"
+#include "ipl.h"
#include "hw/s390x/s390-virtio-ccw.h"
static const char *const reset_dev_types[] = {
@@ -317,7 +318,12 @@ static const TypeInfo ccw_machine_info = {
type_init(ccw_machine_register_##suffix)
#define CCW_COMPAT_2_6 \
- HW_COMPAT_2_6
+ HW_COMPAT_2_6 \
+ {\
+ .driver = TYPE_S390_IPL,\
+ .property = "iplbext_migration",\
+ .value = "off",\
+ },
#define CCW_COMPAT_2_5 \
CCW_COMPAT_2_6 \
@@ -232,8 +232,8 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
return;
}
- iplb = g_malloc0(sizeof(struct IplParameterBlock));
- cpu_physical_memory_read(addr, iplb, sizeof(struct IplParameterBlock));
+ iplb = g_malloc0(sizeof(IplParameterBlock));
+ cpu_physical_memory_read(addr, iplb, S390_IPLB_MIN_CCW_LEN);
s390_ipl_update_diag308(iplb);
env->regs[r1 + 1] = DIAG_308_RC_OK;
g_free(iplb);
@@ -250,8 +250,7 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
}
iplb = s390_ipl_get_iplb();
if (iplb) {
- cpu_physical_memory_write(addr, iplb,
- sizeof(struct IplParameterBlock));
+ cpu_physical_memory_write(addr, iplb, S390_IPLB_MIN_CCW_LEN);
env->regs[r1 + 1] = DIAG_308_RC_OK;
} else {
env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;