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