*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/datadir.h"
#include "qapi/error.h"
#include "sysemu/reset.h"
#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
#include "sysemu/tcg.h"
-#include "cpu.h"
#include "elf.h"
#include "hw/loader.h"
#include "hw/qdev-properties.h"
#include "hw/s390x/css.h"
#include "hw/s390x/ebcdic.h"
#include "hw/s390x/pv.h"
+#include "hw/scsi/scsi.h"
+#include "hw/virtio/virtio-net.h"
#include "ipl.h"
#include "qemu/error-report.h"
#include "qemu/config-file.h"
#include "qemu/cutils.h"
#include "qemu/option.h"
+#include "standard-headers/linux/virtio_ids.h"
#include "exec/exec-all.h"
#define KERN_IMAGE_START 0x010000UL
#define LINUX_MAGIC_ADDR 0x010008UL
+#define KERN_PARM_AREA_SIZE_ADDR 0x010430UL
#define KERN_PARM_AREA 0x010480UL
+#define LEGACY_KERN_PARM_AREA_SIZE 0x000380UL
#define INITRD_START 0x800000UL
#define INITRD_PARM_START 0x010408UL
#define PARMFILE_START 0x001000UL
return srcaddr + dstaddr;
}
+static uint64_t get_max_kernel_cmdline_size(void)
+{
+ uint64_t *size_ptr = rom_ptr(KERN_PARM_AREA_SIZE_ADDR, sizeof(*size_ptr));
+
+ if (size_ptr) {
+ uint64_t size;
+
+ size = be64_to_cpu(*size_ptr);
+ if (size) {
+ return size;
+ }
+ }
+ return LEGACY_KERN_PARM_AREA_SIZE;
+}
+
static void s390_ipl_realize(DeviceState *dev, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
* loader) and it won't work. For this case we force it to 0x10000, too.
*/
if (pentry == KERN_IMAGE_START || pentry == 0x800) {
- char *parm_area = rom_ptr(KERN_PARM_AREA, strlen(ipl->cmdline) + 1);
+ size_t cmdline_size = strlen(ipl->cmdline) + 1;
+ char *parm_area = rom_ptr(KERN_PARM_AREA, cmdline_size);
+
ipl->start_addr = KERN_IMAGE_START;
/* Overwrite parameters in the kernel image, which are "rom" */
if (parm_area) {
+ uint64_t max_cmdline_size = get_max_kernel_cmdline_size();
+
+ if (cmdline_size > max_cmdline_size) {
+ error_setg(errp,
+ "kernel command line exceeds maximum size:"
+ " %zu > %" PRIu64,
+ cmdline_size, max_cmdline_size);
+ return;
+ }
+
strcpy(parm_area, ipl->cmdline);
}
} else {
static void s390_ipl_set_boot_menu(S390IPLState *ipl)
{
- QemuOptsList *plist = qemu_find_opts("boot-opts");
- QemuOpts *opts = QTAILQ_FIRST(&plist->head);
- const char *tmp;
unsigned long splash_time = 0;
if (!get_boot_device(0)) {
- if (boot_menu) {
+ if (current_machine->boot_config.has_menu && current_machine->boot_config.menu) {
error_report("boot menu requires a bootindex to be specified for "
"the IPL device");
}
switch (ipl->iplb.pbt) {
case S390_IPL_TYPE_CCW:
/* In the absence of -boot menu, use zipl parameters */
- if (!qemu_opt_get(opts, "menu")) {
+ if (!current_machine->boot_config.has_menu) {
ipl->qipl.qipl_flags |= QIPL_FLAG_BM_OPTS_ZIPL;
return;
}
case S390_IPL_TYPE_QEMU_SCSI:
break;
default:
- if (boot_menu) {
+ if (current_machine->boot_config.has_menu && current_machine->boot_config.menu) {
error_report("boot menu is not supported for this device type");
}
return;
}
- if (!boot_menu) {
+ if (!current_machine->boot_config.has_menu || !current_machine->boot_config.menu) {
return;
}
ipl->qipl.qipl_flags |= QIPL_FLAG_BM_OPTS_CMD;
- tmp = qemu_opt_get(opts, "splash-time");
-
- if (tmp && qemu_strtoul(tmp, NULL, 10, &splash_time)) {
- error_report("splash-time is invalid, forcing it to 0");
- ipl->qipl.boot_menu_timeout = 0;
- return;
+ if (current_machine->boot_config.has_splash_time) {
+ splash_time = current_machine->boot_config.splash_time;
}
-
if (splash_time > 0xffffffff) {
error_report("splash-time is too large, forcing it to max value");
ipl->qipl.boot_menu_timeout = 0xffffffff;
object_dynamic_cast(OBJECT(dev_st),
TYPE_SCSI_DEVICE);
if (sd) {
- SCSIBus *bus = scsi_bus_from_device(sd);
- VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus);
- VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw,
- vdev);
-
- ccw_dev = (CcwDevice *)object_dynamic_cast(OBJECT(scsi_ccw),
- TYPE_CCW_DEVICE);
- tmp_dt = CCW_DEVTYPE_SCSI;
+ SCSIBus *sbus = scsi_bus_from_device(sd);
+ VirtIODevice *vdev = (VirtIODevice *)
+ object_dynamic_cast(OBJECT(sbus->qbus.parent),
+ TYPE_VIRTIO_DEVICE);
+ if (vdev) {
+ ccw_dev = (CcwDevice *)
+ object_dynamic_cast(OBJECT(qdev_get_parent_bus(DEVICE(vdev))->parent),
+ TYPE_CCW_DEVICE);
+ if (ccw_dev) {
+ tmp_dt = CCW_DEVTYPE_SCSI;
+ }
+ }
}
}
}
void s390_ipl_prepare_cpu(S390CPU *cpu)
{
S390IPLState *ipl = get_ipl_device();
- Error *err = NULL;
cpu->env.psw.addr = ipl->start_addr;
cpu->env.psw.mask = IPL_PSW_MASK;
}
}
if (ipl->netboot) {
- if (load_netboot_image(&err) < 0) {
- error_report_err(err);
- exit(1);
- }
+ load_netboot_image(&error_fatal);
ipl->qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
}
s390_ipl_set_boot_menu(ipl);