Blame SOURCES/kvm-pc-bios-s390-ccw-net-Use-diag308-to-reset-machine-be.patch

4ec855
From 2f0454ccd0dd12429e8c204933cafe71a248d4eb Mon Sep 17 00:00:00 2001
4ec855
From: Thomas Huth <thuth@redhat.com>
4ec855
Date: Mon, 14 Oct 2019 10:06:30 +0100
4ec855
Subject: [PATCH 05/21] pc-bios/s390-ccw/net: Use diag308 to reset machine
4ec855
 before jumping to the OS
4ec855
4ec855
RH-Author: Thomas Huth <thuth@redhat.com>
4ec855
Message-id: <20191014100645.22862-3-thuth@redhat.com>
4ec855
Patchwork-id: 91777
4ec855
O-Subject: [RHEL-8.2.0 qemu-kvm PATCH v2 02/17] pc-bios/s390-ccw/net: Use diag308 to reset machine before jumping to the OS
4ec855
Bugzilla: 1664376
4ec855
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
4ec855
RH-Acked-by: David Hildenbrand <david@redhat.com>
4ec855
RH-Acked-by: Jens Freimann <jfreimann@redhat.com>
4ec855
4ec855
The netboot firmware so far simply jumped directly into the OS kernel
4ec855
after the download has been completed. This, however, bears the risk
4ec855
that the virtio-net device still might be active in the background and
4ec855
incoming packets are still placed into the buffers - which could destroy
4ec855
memory of the now-running Linux kernel in case it did not take over the
4ec855
device fast enough. Also the SCLP console is not put into a well-defined
4ec855
state here. We should hand over the system in a clean state when jumping
4ec855
into the kernel, so let's use the same mechanism as it's done in the
4ec855
main s390-ccw firmware and reset the machine with diag308 into a clean
4ec855
state before jumping into the OS kernel code. To be able to share the
4ec855
code with the main s390-ccw firmware, the related functions are now
4ec855
extracted from bootmap.c into a new file called jump2ipl.c.
4ec855
4ec855
Since we now also set the boot device schid at address 184 for the network
4ec855
boot device, this patch also slightly changes the way how we detect the
4ec855
entry points for non-ELF binary images: The code now looks for the "S390EP"
4ec855
magic first and then jumps to 0x10000 in case it has been found. This is
4ec855
necessary for booting from network devices, since the normal kernel code
4ec855
(where the PSW at ddress 0 points to) tries to do a block load from the
4ec855
boot device. This of course fails for a virtio-net device and causes the
4ec855
kernel to abort with a panic-PSW silently.
4ec855
4ec855
Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
4ec855
Signed-off-by: Thomas Huth <thuth@redhat.com>
4ec855
(cherry picked from commit 9a848adf45d6732e62551decb3c0255173090767)
4ec855
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
4ec855
---
4ec855
 pc-bios/s390-ccw/Makefile    |  4 +-
4ec855
 pc-bios/s390-ccw/bootmap.c   | 63 +-----------------------------
4ec855
 pc-bios/s390-ccw/bootmap.h   |  4 --
4ec855
 pc-bios/s390-ccw/jump2ipl.c  | 91 ++++++++++++++++++++++++++++++++++++++++++++
4ec855
 pc-bios/s390-ccw/netboot.mak |  3 +-
4ec855
 pc-bios/s390-ccw/netmain.c   | 11 +++++-
4ec855
 pc-bios/s390-ccw/s390-ccw.h  |  4 ++
4ec855
 7 files changed, 111 insertions(+), 69 deletions(-)
4ec855
 create mode 100644 pc-bios/s390-ccw/jump2ipl.c
4ec855
4ec855
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
4ec855
index 1712c2d..439e3cc 100644
4ec855
--- a/pc-bios/s390-ccw/Makefile
4ec855
+++ b/pc-bios/s390-ccw/Makefile
4ec855
@@ -9,7 +9,9 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
4ec855
 
4ec855
 .PHONY : all clean build-all
4ec855
 
4ec855
-OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o virtio-blkdev.o libc.o menu.o
4ec855
+OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o \
4ec855
+	  virtio.o virtio-scsi.o virtio-blkdev.o libc.o
4ec855
+
4ec855
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
4ec855
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
4ec855
 QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
4ec855
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
4ec855
index ffbf671..d13b7cb 100644
4ec855
--- a/pc-bios/s390-ccw/bootmap.c
4ec855
+++ b/pc-bios/s390-ccw/bootmap.c
4ec855
@@ -29,14 +29,6 @@
4ec855
 /* Scratch space */
4ec855
 static uint8_t sec[MAX_SECTOR_SIZE*4] __attribute__((__aligned__(PAGE_SIZE)));
4ec855
 
4ec855
-typedef struct ResetInfo {
4ec855
-    uint32_t ipl_mask;
4ec855
-    uint32_t ipl_addr;
4ec855
-    uint32_t ipl_continue;
4ec855
-} ResetInfo;
4ec855
-
4ec855
-static ResetInfo save;
4ec855
-
4ec855
 const uint8_t el_torito_magic[] = "EL TORITO SPECIFICATION"
4ec855
                                   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
4ec855
 
4ec855
@@ -57,53 +49,6 @@ static inline bool is_iso_vd_valid(IsoVolDesc *vd)
4ec855
            vd->type <= VOL_DESC_TYPE_PARTITION;
4ec855
 }
4ec855
 
4ec855
-static void jump_to_IPL_2(void)
4ec855
-{
4ec855
-    ResetInfo *current = 0;
4ec855
-
4ec855
-    void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
4ec855
-    *current = save;
4ec855
-    ipl(); /* should not return */
4ec855
-}
4ec855
-
4ec855
-static void jump_to_IPL_code(uint64_t address)
4ec855
-{
4ec855
-    /* store the subsystem information _after_ the bootmap was loaded */
4ec855
-    write_subsystem_identification();
4ec855
-
4ec855
-    /* prevent unknown IPL types in the guest */
4ec855
-    if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
4ec855
-        iplb.pbt = S390_IPL_TYPE_CCW;
4ec855
-        set_iplb(&iplb);
4ec855
-    }
4ec855
-
4ec855
-    /*
4ec855
-     * The IPL PSW is at address 0. We also must not overwrite the
4ec855
-     * content of non-BIOS memory after we loaded the guest, so we
4ec855
-     * save the original content and restore it in jump_to_IPL_2.
4ec855
-     */
4ec855
-    ResetInfo *current = 0;
4ec855
-
4ec855
-    save = *current;
4ec855
-    current->ipl_addr = (uint32_t) (uint64_t) &jump_to_IPL_2;
4ec855
-    current->ipl_continue = address & 0x7fffffff;
4ec855
-
4ec855
-    debug_print_int("set IPL addr to", current->ipl_continue);
4ec855
-
4ec855
-    /* Ensure the guest output starts fresh */
4ec855
-    sclp_print("\n");
4ec855
-
4ec855
-    /*
4ec855
-     * HACK ALERT.
4ec855
-     * We use the load normal reset to keep r15 unchanged. jump_to_IPL_2
4ec855
-     * can then use r15 as its stack pointer.
4ec855
-     */
4ec855
-    asm volatile("lghi 1,1\n\t"
4ec855
-                 "diag 1,1,0x308\n\t"
4ec855
-                 : : : "1", "memory");
4ec855
-    panic("\n! IPL returns !\n");
4ec855
-}
4ec855
-
4ec855
 /***********************************************************************
4ec855
  * IPL an ECKD DASD (CDL or LDL/CMS format)
4ec855
  */
4ec855
@@ -744,13 +689,7 @@ static void load_iso_bc_entry(IsoBcSection *load)
4ec855
                         (void *)((uint64_t)bswap16(s.load_segment)),
4ec855
                         blks_to_load);
4ec855
 
4ec855
-    /* Trying to get PSW at zero address */
4ec855
-    if (*((uint64_t *)0) & IPL_PSW_MASK) {
4ec855
-        jump_to_IPL_code((*((uint64_t *)0)) & 0x7fffffff);
4ec855
-    }
4ec855
-
4ec855
-    /* Try default linux start address */
4ec855
-    jump_to_IPL_code(KERN_IMAGE_START);
4ec855
+    jump_to_low_kernel();
4ec855
 }
4ec855
 
4ec855
 static uint32_t find_iso_bc(void)
4ec855
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
4ec855
index f1ce423..94f53a5 100644
4ec855
--- a/pc-bios/s390-ccw/bootmap.h
4ec855
+++ b/pc-bios/s390-ccw/bootmap.h
4ec855
@@ -355,10 +355,6 @@ static inline uint32_t iso_733_to_u32(uint64_t x)
4ec855
 #define ISO_SECTOR_SIZE 2048
4ec855
 /* El Torito specifies boot image size in 512 byte blocks */
4ec855
 #define ET_SECTOR_SHIFT 2
4ec855
-#define KERN_IMAGE_START 0x010000UL
4ec855
-#define PSW_MASK_64 0x0000000100000000ULL
4ec855
-#define PSW_MASK_32 0x0000000080000000ULL
4ec855
-#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64)
4ec855
 
4ec855
 #define ISO_PRIMARY_VD_SECTOR 16
4ec855
 
4ec855
diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
4ec855
new file mode 100644
4ec855
index 0000000..266f150
4ec855
--- /dev/null
4ec855
+++ b/pc-bios/s390-ccw/jump2ipl.c
4ec855
@@ -0,0 +1,91 @@
4ec855
+/*
4ec855
+ * QEMU s390-ccw firmware - jump to IPL code
4ec855
+ *
4ec855
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
4ec855
+ * your option) any later version. See the COPYING file in the top-level
4ec855
+ * directory.
4ec855
+ */
4ec855
+
4ec855
+#include "libc.h"
4ec855
+#include "s390-ccw.h"
4ec855
+
4ec855
+#define KERN_IMAGE_START 0x010000UL
4ec855
+#define PSW_MASK_64 0x0000000100000000ULL
4ec855
+#define PSW_MASK_32 0x0000000080000000ULL
4ec855
+#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64)
4ec855
+
4ec855
+typedef struct ResetInfo {
4ec855
+    uint32_t ipl_mask;
4ec855
+    uint32_t ipl_addr;
4ec855
+    uint32_t ipl_continue;
4ec855
+} ResetInfo;
4ec855
+
4ec855
+static ResetInfo save;
4ec855
+
4ec855
+static void jump_to_IPL_2(void)
4ec855
+{
4ec855
+    ResetInfo *current = 0;
4ec855
+
4ec855
+    void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
4ec855
+    *current = save;
4ec855
+    ipl(); /* should not return */
4ec855
+}
4ec855
+
4ec855
+void jump_to_IPL_code(uint64_t address)
4ec855
+{
4ec855
+    /* store the subsystem information _after_ the bootmap was loaded */
4ec855
+    write_subsystem_identification();
4ec855
+
4ec855
+    /* prevent unknown IPL types in the guest */
4ec855
+    if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
4ec855
+        iplb.pbt = S390_IPL_TYPE_CCW;
4ec855
+        set_iplb(&iplb);
4ec855
+    }
4ec855
+
4ec855
+    /*
4ec855
+     * The IPL PSW is at address 0. We also must not overwrite the
4ec855
+     * content of non-BIOS memory after we loaded the guest, so we
4ec855
+     * save the original content and restore it in jump_to_IPL_2.
4ec855
+     */
4ec855
+    ResetInfo *current = 0;
4ec855
+
4ec855
+    save = *current;
4ec855
+    current->ipl_addr = (uint32_t) (uint64_t) &jump_to_IPL_2;
4ec855
+    current->ipl_continue = address & 0x7fffffff;
4ec855
+
4ec855
+    debug_print_int("set IPL addr to", current->ipl_continue);
4ec855
+
4ec855
+    /* Ensure the guest output starts fresh */
4ec855
+    sclp_print("\n");
4ec855
+
4ec855
+    /*
4ec855
+     * HACK ALERT.
4ec855
+     * We use the load normal reset to keep r15 unchanged. jump_to_IPL_2
4ec855
+     * can then use r15 as its stack pointer.
4ec855
+     */
4ec855
+    asm volatile("lghi 1,1\n\t"
4ec855
+                 "diag 1,1,0x308\n\t"
4ec855
+                 : : : "1", "memory");
4ec855
+    panic("\n! IPL returns !\n");
4ec855
+}
4ec855
+
4ec855
+void jump_to_low_kernel(void)
4ec855
+{
4ec855
+    /*
4ec855
+     * If it looks like a Linux binary, i.e. there is the "S390EP" magic from
4ec855
+     * arch/s390/kernel/head.S here, then let's jump to the well-known Linux
4ec855
+     * kernel start address (when jumping to the PSW-at-zero address instead,
4ec855
+     * the kernel startup code fails when we booted from a network device).
4ec855
+     */
4ec855
+    if (!memcmp((char *)0x10008, "S390EP", 6)) {
4ec855
+        jump_to_IPL_code(KERN_IMAGE_START);
4ec855
+    }
4ec855
+
4ec855
+    /* Trying to get PSW at zero address */
4ec855
+    if (*((uint64_t *)0) & IPL_PSW_MASK) {
4ec855
+        jump_to_IPL_code((*((uint64_t *)0)) & 0x7fffffff);
4ec855
+    }
4ec855
+
4ec855
+    /* No other option left, so use the Linux kernel start address */
4ec855
+    jump_to_IPL_code(KERN_IMAGE_START);
4ec855
+}
4ec855
diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak
4ec855
index a25d238..4f64128 100644
4ec855
--- a/pc-bios/s390-ccw/netboot.mak
4ec855
+++ b/pc-bios/s390-ccw/netboot.mak
4ec855
@@ -1,7 +1,8 @@
4ec855
 
4ec855
 SLOF_DIR := $(SRC_PATH)/roms/SLOF
4ec855
 
4ec855
-NETOBJS := start.o sclp.o virtio.o virtio-net.o netmain.o libnet.a libc.a
4ec855
+NETOBJS := start.o sclp.o virtio.o virtio-net.o jump2ipl.o netmain.o \
4ec855
+	   libnet.a libc.a
4ec855
 
4ec855
 LIBC_INC := -nostdinc -I$(SLOF_DIR)/lib/libc/include
4ec855
 LIBNET_INC := -I$(SLOF_DIR)/lib/libnet
4ec855
diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
4ec855
index d86d46b..d60e84f 100644
4ec855
--- a/pc-bios/s390-ccw/netmain.c
4ec855
+++ b/pc-bios/s390-ccw/netmain.c
4ec855
@@ -281,6 +281,15 @@ void panic(const char *string)
4ec855
     }
4ec855
 }
4ec855
 
4ec855
+void write_subsystem_identification(void)
4ec855
+{
4ec855
+    SubChannelId *schid = (SubChannelId *) 184;
4ec855
+    uint32_t *zeroes = (uint32_t *) 188;
4ec855
+
4ec855
+    *schid = net_schid;
4ec855
+    *zeroes = 0;
4ec855
+}
4ec855
+
4ec855
 static bool find_net_dev(Schib *schib, int dev_no)
4ec855
 {
4ec855
     int i, r;
4ec855
@@ -354,7 +363,7 @@ void main(void)
4ec855
     rc = net_load(NULL, (long)_start);
4ec855
     if (rc > 0) {
4ec855
         sclp_print("Network loading done, starting kernel...\n");
4ec855
-        asm volatile (" lpsw 0(%0) " : : "r"(0) : "memory");
4ec855
+        jump_to_low_kernel();
4ec855
     }
4ec855
 
4ec855
     panic("Failed to load OS from network\n");
4ec855
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
4ec855
index a1bdb4c..9828aa2 100644
4ec855
--- a/pc-bios/s390-ccw/s390-ccw.h
4ec855
+++ b/pc-bios/s390-ccw/s390-ccw.h
4ec855
@@ -87,6 +87,10 @@ ulong get_second(void);
4ec855
 /* bootmap.c */
4ec855
 void zipl_load(void);
4ec855
 
4ec855
+/* jump2ipl.c */
4ec855
+void jump_to_IPL_code(uint64_t address);
4ec855
+void jump_to_low_kernel(void);
4ec855
+
4ec855
 /* menu.c */
4ec855
 void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout);
4ec855
 int menu_get_zipl_boot_index(const char *menu_data);
4ec855
-- 
4ec855
1.8.3.1
4ec855