aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/s390x/ipl.c39
-rw-r--r--hw/s390x/ipl.h3
-rw-r--r--hw/s390x/s390-virtio-ccw.c37
-rw-r--r--hw/s390x/sclp.c9
4 files changed, 85 insertions, 3 deletions
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 7978c7d..75d3c68 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -17,8 +17,10 @@
#include "cpu.h"
#include "elf.h"
#include "hw/loader.h"
+#include "hw/boards.h"
#include "hw/s390x/virtio-ccw.h"
#include "hw/s390x/css.h"
+#include "hw/s390x/ebcdic.h"
#include "ipl.h"
#include "qemu/error-report.h"
@@ -243,12 +245,17 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
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);
+ CcwDevice *ccw_dev;
+
+ ccw_dev = (CcwDevice *)object_dynamic_cast(OBJECT(scsi_ccw),
+ TYPE_CCW_DEVICE);
+ if (!ccw_dev) { /* It might be a PCI device instead */
+ return false;
+ }
ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
ipl->iplb.blk0_len =
@@ -259,13 +266,39 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
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;
+ } else {
+ return false; /* unknown device */
}
+
+ if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) {
+ ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID;
+ }
+ return true;
}
return false;
}
+int s390_ipl_set_loadparm(uint8_t *loadparm)
+{
+ MachineState *machine = MACHINE(qdev_get_machine());
+ char *lp = object_property_get_str(OBJECT(machine), "loadparm", NULL);
+
+ if (lp) {
+ int i;
+
+ /* lp is an uppercase string without leading/embedded spaces */
+ for (i = 0; i < 8 && lp[i]; i++) {
+ loadparm[i] = ascii2ebcdic[(uint8_t) lp[i]];
+ }
+
+ g_free(lp);
+ return 0;
+ }
+
+ return -1;
+}
+
static int load_netboot_image(Error **errp)
{
S390IPLState *ipl = get_ipl_device();
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 46930e4..8a705e0 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -57,6 +57,8 @@ struct IplBlockQemuScsi {
} QEMU_PACKED;
typedef struct IplBlockQemuScsi IplBlockQemuScsi;
+#define DIAG308_FLAGS_LP_VALID 0x80
+
union IplParameterBlock {
struct {
uint32_t len;
@@ -82,6 +84,7 @@ union IplParameterBlock {
} QEMU_PACKED;
typedef union IplParameterBlock IplParameterBlock;
+int s390_ipl_set_loadparm(uint8_t *loadparm);
void s390_ipl_update_diag308(IplParameterBlock *iplb);
void s390_ipl_prepare_cpu(S390CPU *cpu);
IplParameterBlock *s390_ipl_get_iplb(void);
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 04bd0eb..fdd4384 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -274,6 +274,36 @@ bool cpu_model_allowed(void)
return true;
}
+static char *machine_get_loadparm(Object *obj, Error **errp)
+{
+ S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
+
+ return g_memdup(ms->loadparm, sizeof(ms->loadparm));
+}
+
+static void machine_set_loadparm(Object *obj, const char *val, Error **errp)
+{
+ S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
+ int i;
+
+ for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) {
+ uint8_t c = toupper(val[i]); /* mimic HMC */
+
+ if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '.') ||
+ (c == ' ')) {
+ ms->loadparm[i] = c;
+ } else {
+ error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)",
+ c, c);
+ return;
+ }
+ }
+
+ for (; i < sizeof(ms->loadparm); i++) {
+ ms->loadparm[i] = ' '; /* pad right with spaces */
+ }
+}
+
static inline void s390_machine_initfn(Object *obj)
{
object_property_add_bool(obj, "aes-key-wrap",
@@ -291,6 +321,13 @@ static inline void s390_machine_initfn(Object *obj)
"enable/disable DEA key wrapping using the CPACF wrapping key",
NULL);
object_property_set_bool(obj, true, "dea-key-wrap", NULL);
+ object_property_add_str(obj, "loadparm",
+ machine_get_loadparm, machine_set_loadparm, NULL);
+ object_property_set_description(obj, "loadparm",
+ "Up to 8 chars in set of [A-Za-z0-9. ] (lower case chars converted"
+ " to upper case) to pass to machine loader, boot manager,"
+ " and guest kernel",
+ NULL);
}
static const TypeInfo ccw_machine_info = {
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index e741da1..b4f6dd5 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -23,6 +23,7 @@
#include "hw/s390x/sclp.h"
#include "hw/s390x/event-facility.h"
#include "hw/s390x/s390-pci-bus.h"
+#include "hw/s390x/ipl.h"
static inline SCLPDevice *get_sclp_device(void)
{
@@ -57,6 +58,7 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
int cpu_count = 0;
int rnsize, rnmax;
int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state));
+ IplParameterBlock *ipib = s390_ipl_get_iplb();
CPU_FOREACH(cpu) {
cpu_count++;
@@ -129,6 +131,13 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
read_info->rnmax2 = cpu_to_be64(rnmax);
}
+ if (ipib && ipib->flags & DIAG308_FLAGS_LP_VALID) {
+ memcpy(&read_info->loadparm, &ipib->loadparm,
+ sizeof(read_info->loadparm));
+ } else {
+ s390_ipl_set_loadparm(read_info->loadparm);
+ }
+
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
}