]> git.proxmox.com Git - qemu.git/blobdiff - hw/s390x/ipl.c
s390x: fix flat file load on 32 bit systems
[qemu.git] / hw / s390x / ipl.c
index 206d552e16240132892546340ba9facfb1aefa39..65d39da314fc1ca31315f011b57362ffa8c629d2 100644 (file)
@@ -16,6 +16,8 @@
 #include "elf.h"
 #include "hw/loader.h"
 #include "hw/sysbus.h"
+#include "hw/s390x/virtio-ccw.h"
+#include "hw/s390x/css.h"
 
 #define KERN_IMAGE_START                0x010000UL
 #define KERN_PARM_AREA                  0x010480UL
@@ -23,7 +25,6 @@
 #define INITRD_PARM_START               0x010408UL
 #define INITRD_PARM_SIZE                0x010410UL
 #define PARMFILE_START                  0x001000UL
-#define ZIPL_FILENAME                   "s390-zipl.rom"
 #define ZIPL_IMAGE_START                0x009000UL
 #define IPL_PSW_MASK                    (PSW_MASK_32 | PSW_MASK_64)
 
@@ -48,65 +49,74 @@ typedef struct S390IPLClass {
 typedef struct S390IPLState {
     /*< private >*/
     SysBusDevice parent_obj;
-    /*< public >*/
+    uint64_t start_addr;
 
+    /*< public >*/
     char *kernel;
     char *initrd;
     char *cmdline;
+    char *firmware;
 } S390IPLState;
 
 
-static void s390_ipl_cpu(uint64_t pswaddr)
-{
-    S390CPU *cpu = S390_CPU(qemu_get_cpu(0));
-    CPUS390XState *env = &cpu->env;
-
-    env->psw.addr = pswaddr;
-    env->psw.mask = IPL_PSW_MASK;
-    s390_add_running_cpu(cpu);
-}
-
 static int s390_ipl_init(SysBusDevice *dev)
 {
     S390IPLState *ipl = S390_IPL(dev);
-    ram_addr_t kernel_size = 0;
+    int kernel_size;
 
     if (!ipl->kernel) {
-        ram_addr_t bios_size = 0;
+        int bios_size;
         char *bios_filename;
 
         /* Load zipl bootloader */
         if (bios_name == NULL) {
-            bios_name = ZIPL_FILENAME;
+            bios_name = ipl->firmware;
         }
 
         bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-        bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START, 4096);
-        g_free(bios_filename);
+        if (bios_filename == NULL) {
+            hw_error("could not find stage1 bootloader\n");
+        }
 
-        if ((long)bios_size < 0) {
-            hw_error("could not load bootloader '%s'\n", bios_name);
+        bios_size = load_elf(bios_filename, NULL, NULL, &ipl->start_addr, NULL,
+                             NULL, 1, ELF_MACHINE, 0);
+        if (bios_size == -1) {
+            bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START,
+                                            4096);
+            ipl->start_addr = ZIPL_IMAGE_START;
+            if (bios_size > 4096) {
+                hw_error("stage1 bootloader is > 4k\n");
+            }
         }
+        g_free(bios_filename);
 
-        if (bios_size > 4096) {
-            hw_error("stage1 bootloader is > 4k\n");
+        if (bios_size == -1) {
+            hw_error("could not load bootloader '%s'\n", bios_name);
         }
         return 0;
     } else {
         kernel_size = load_elf(ipl->kernel, NULL, NULL, NULL, NULL,
                                NULL, 1, ELF_MACHINE, 0);
-        if (kernel_size == -1UL) {
+        if (kernel_size == -1) {
             kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
         }
-        if (kernel_size == -1UL) {
+        if (kernel_size == -1) {
             fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel);
             return -1;
         }
         /* we have to overwrite values in the kernel image, which are "rom" */
         strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
+
+        /*
+         * we can not rely on the ELF entry point, since up to 3.2 this
+         * value was 0x800 (the SALIPL loader) and it wont work. For
+         * all (Linux) cases 0x10000 (KERN_IMAGE_START) should be fine.
+         */
+        ipl->start_addr = KERN_IMAGE_START;
     }
     if (ipl->initrd) {
-        ram_addr_t initrd_offset, initrd_size;
+        ram_addr_t initrd_offset;
+        int initrd_size;
 
         initrd_offset = INITRD_START;
         while (kernel_size + 0x100000 > initrd_offset) {
@@ -114,7 +124,7 @@ static int s390_ipl_init(SysBusDevice *dev)
         }
         initrd_size = load_image_targphys(ipl->initrd, initrd_offset,
                                           ram_size - initrd_offset);
-        if (initrd_size == -1UL) {
+        if (initrd_size == -1) {
             fprintf(stderr, "qemu: could not load initrd '%s'\n", ipl->initrd);
             exit(1);
         }
@@ -131,23 +141,37 @@ static Property s390_ipl_properties[] = {
     DEFINE_PROP_STRING("kernel", S390IPLState, kernel),
     DEFINE_PROP_STRING("initrd", S390IPLState, initrd),
     DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline),
+    DEFINE_PROP_STRING("firmware", S390IPLState, firmware),
     DEFINE_PROP_END_OF_LIST(),
 };
 
 static void s390_ipl_reset(DeviceState *dev)
 {
     S390IPLState *ipl = S390_IPL(dev);
+    S390CPU *cpu = S390_CPU(qemu_get_cpu(0));
+    CPUS390XState *env = &cpu->env;
 
-    if (ipl->kernel) {
-        /*
-         * we can not rely on the ELF entry point, since up to 3.2 this
-         * value was 0x800 (the SALIPL loader) and it wont work. For
-         * all (Linux) cases 0x10000 (KERN_IMAGE_START) should be fine.
-         */
-        return s390_ipl_cpu(KERN_IMAGE_START);
-    } else {
-        return s390_ipl_cpu(ZIPL_IMAGE_START);
+    env->psw.addr = ipl->start_addr;
+    env->psw.mask = IPL_PSW_MASK;
+
+    if (!ipl->kernel) {
+        /* Tell firmware, if there is a preferred boot device */
+        env->regs[7] = -1;
+        DeviceState *dev_st = get_boot_device(0);
+        if (dev_st) {
+            VirtioCcwDevice *ccw_dev = (VirtioCcwDevice *) object_dynamic_cast(
+                OBJECT(qdev_get_parent_bus(dev_st)->parent),
+                TYPE_VIRTIO_CCW_DEVICE);
+
+            if (ccw_dev) {
+                env->regs[7] = ccw_dev->sch->cssid << 24 |
+                               ccw_dev->sch->ssid << 16 |
+                               ccw_dev->sch->devno;
+            }
+        }
     }
+
+    s390_add_running_cpu(cpu);
 }
 
 static void s390_ipl_class_init(ObjectClass *klass, void *data)