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

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