]> Git Repo - qemu.git/blobdiff - hw/s390x/ipl.c
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
[qemu.git] / hw / s390x / ipl.c
index 231713dbc36590e5a2b33d28d1a7eaaa34f8322e..2e0a8b6e0c9662c35c964df4c5decd95a4c13eb9 100644 (file)
@@ -55,6 +55,7 @@ typedef struct S390IPLState {
     bool enforce_bios;
     IplParameterBlock iplb;
     bool iplb_valid;
+    bool reipl_requested;
 
     /*< public >*/
     char *kernel;
@@ -66,6 +67,43 @@ typedef struct S390IPLState {
     uint16_t devno;
 } S390IPLState;
 
+static const VMStateDescription vmstate_iplb = {
+    .name = "ipl/iplb",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8_ARRAY(reserved1, IplParameterBlock, 110),
+        VMSTATE_UINT16(devno, IplParameterBlock),
+        VMSTATE_UINT8_ARRAY(reserved2, IplParameterBlock, 88),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_ipl = {
+    .name = "ipl",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(start_addr, S390IPLState),
+        VMSTATE_UINT64(bios_start_addr, S390IPLState),
+        VMSTATE_STRUCT(iplb, S390IPLState, 0, vmstate_iplb, IplParameterBlock),
+        VMSTATE_BOOL(iplb_valid, S390IPLState),
+        VMSTATE_UINT8(cssid, S390IPLState),
+        VMSTATE_UINT8(ssid, S390IPLState),
+        VMSTATE_UINT16(devno, S390IPLState),
+        VMSTATE_END_OF_LIST()
+     }
+};
+
+static uint64_t bios_translate_addr(void *opaque, uint64_t srcaddr)
+{
+    uint64_t dstaddr = *(uint64_t *) opaque;
+    /*
+     * Assuming that our s390-ccw.img was linked for starting at address 0,
+     * we can simply add the destination address for the final location
+     */
+    return srcaddr + dstaddr;
+}
 
 static int s390_ipl_init(SysBusDevice *dev)
 {
@@ -81,6 +119,8 @@ static int s390_ipl_init(SysBusDevice *dev)
      * even if an external kernel has been defined.
      */
     if (!ipl->kernel || ipl->enforce_bios) {
+        uint64_t fwbase = (MIN(ram_size, 0x80000000U) - 0x200000) & ~0xffffUL;
+
         if (bios_name == NULL) {
             bios_name = ipl->firmware;
         }
@@ -90,15 +130,17 @@ static int s390_ipl_init(SysBusDevice *dev)
             hw_error("could not find stage1 bootloader\n");
         }
 
-        bios_size = load_elf(bios_filename, NULL, NULL, &ipl->bios_start_addr,
-                             NULL, NULL, 1, ELF_MACHINE, 0);
-        if (bios_size < 0) {
+        bios_size = load_elf(bios_filename, bios_translate_addr, &fwbase,
+                             &ipl->bios_start_addr, NULL, NULL, 1,
+                             ELF_MACHINE, 0);
+        if (bios_size > 0) {
+            /* Adjust ELF start address to final location */
+            ipl->bios_start_addr += fwbase;
+        } else {
+            /* Try to load non-ELF file (e.g. s390-zipl.rom) */
             bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START,
                                             4096);
             ipl->bios_start_addr = ZIPL_IMAGE_START;
-            if (bios_size > 4096) {
-                hw_error("stage1 bootloader is > 4k\n");
-            }
         }
         g_free(bios_filename);
 
@@ -206,7 +248,7 @@ static uint64_t s390_update_iplstate(CPUS390XState *env, S390IPLState *ipl)
 
     return -1;
 out:
-    return ipl->cssid << 24 | ipl->ssid << 16 | ipl->devno;
+    return (uint32_t) (ipl->cssid << 24 | ipl->ssid << 16 | ipl->devno);
 }
 
 int s390_ipl_update_diag308(IplParameterBlock *iplb)
@@ -233,6 +275,15 @@ IplParameterBlock *s390_ipl_get_iplb(void)
     return &ipl->iplb;
 }
 
+void s390_reipl_request(void)
+{
+    S390IPLState *ipl;
+
+    ipl = S390_IPL(object_resolve_path(TYPE_S390_IPL, NULL));
+    ipl->reipl_requested = true;
+    qemu_system_reset_request();
+}
+
 static void s390_ipl_reset(DeviceState *dev)
 {
     S390IPLState *ipl = S390_IPL(dev);
@@ -242,6 +293,11 @@ static void s390_ipl_reset(DeviceState *dev)
     env->psw.addr = ipl->start_addr;
     env->psw.mask = IPL_PSW_MASK;
 
+    if (!ipl->reipl_requested) {
+        ipl->iplb_valid = false;
+    }
+    ipl->reipl_requested = false;
+
     if (!ipl->kernel || ipl->iplb_valid) {
         env->psw.addr = ipl->bios_start_addr;
         env->regs[7] = s390_update_iplstate(env, ipl);
@@ -258,6 +314,8 @@ static void s390_ipl_class_init(ObjectClass *klass, void *data)
     k->init = s390_ipl_init;
     dc->props = s390_ipl_properties;
     dc->reset = s390_ipl_reset;
+    dc->vmsd = &vmstate_ipl;
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
 }
 
 static const TypeInfo s390_ipl_info = {
This page took 0.024885 seconds and 4 git commands to generate.