qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PULL 00/23] s390-ccw bios update
@ 2024-10-23 13:16 Thomas Huth
  2024-10-23 13:16 ` [PULL 01/23] hw/s390x/ipl: Provide more memory to the s390-ccw.img firmware Thomas Huth
                   ` (23 more replies)
  0 siblings, 24 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell

The following changes since commit 6f625ce2f21d6a1243065d236298277c56f972d5:

  Merge tag 'pull-request-2024-10-21' of https://gitlab.com/thuth/qemu into staging (2024-10-21 17:12:59 +0100)

are available in the Git repository at:

  https://gitlab.com/thuth/qemu.git tags/pull-request-2024-10-23

for you to fetch changes up to 239e351ec415ff3673d9da70d70ca3a5dd95a2f0:

  pc-bios/s390-ccw: Update s390-ccw.img with the full boot order support feature (2024-10-23 06:53:44 +0200)

----------------------------------------------------------------
* Allow multiple boot devices (via bootindex properties) on s390x
* Avoid TEXTREL relocations in the s390-ccw.img firmware

----------------------------------------------------------------
Jared Rossi (16):
      pc-bios/s390-ccw: Use the libc from SLOF and remove sclp prints
      pc-bios/s390-ccw: Link the netboot code into the main s390-ccw.img binary
      docs/system/s390x/bootdevices: Update the documentation about network booting
      pc-bios/s390-ccw: Remove panics from ISO IPL path
      pc-bios/s390-ccw: Remove panics from ECKD IPL path
      pc-bios/s390-ccw: Remove panics from SCSI IPL path
      pc-bios/s390-ccw: Remove panics from DASD IPL path
      pc-bios/s390-ccw: Remove panics from Netboot IPL path
      pc-bios/s390-ccw: Enable failed IPL to return after error
      include/hw/s390x: Add include files for common IPL structs
      s390x: Add individual loadparm assignment to CCW device
      hw/s390x: Build an IPLB for each boot device
      s390x: Rebuild IPLB for SCSI device directly from DIAG308
      pc-bios/s390x: Enable multi-device boot loop
      docs/system: Update documentation for s390x IPL
      tests/qtest: Add s390x boot order tests to cdrom-test.c

Jens Remus (2):
      pc-bios/s390-ccw: Clarify alignment is in bytes
      pc-bios/s390-ccw: Don't generate TEXTRELs

Marc Hartmayer (1):
      pc-bios/s390-ccw: Introduce `EXTRA_LDFLAGS`

Thomas Huth (4):
      hw/s390x/ipl: Provide more memory to the s390-ccw.img firmware
      hw/s390x: Remove the possibility to load the s390-netboot.img binary
      pc-bios/s390-ccw: Merge netboot.mak into the main Makefile
      pc-bios/s390-ccw: Update s390-ccw.img with the full boot order support feature

 docs/system/bootindex.rst               |   7 +-
 docs/system/s390x/bootdevices.rst       |  29 +-
 pc-bios/s390-ccw/netboot.mak            |  62 -----
 hw/s390x/ccw-device.h                   |   2 +
 hw/s390x/ipl.h                          | 123 +--------
 include/hw/s390x/ipl/qipl.h             | 127 +++++++++
 pc-bios/s390-ccw/bootmap.h              |  20 +-
 pc-bios/s390-ccw/cio.h                  |   2 +
 pc-bios/s390-ccw/dasd-ipl.h             |   2 +-
 pc-bios/s390-ccw/iplb.h                 | 108 ++------
 pc-bios/s390-ccw/libc.h                 |  89 -------
 pc-bios/s390-ccw/s390-ccw.h             |  36 +--
 pc-bios/s390-ccw/virtio.h               |   3 +-
 hw/s390x/ccw-device.c                   |  46 ++++
 hw/s390x/ipl.c                          | 282 ++++++++++----------
 hw/s390x/s390-virtio-ccw.c              |  28 +-
 hw/s390x/sclp.c                         |   9 +-
 pc-bios/s390-ccw/bootmap.c              | 455 ++++++++++++++++++++++----------
 pc-bios/s390-ccw/cio.c                  |  81 +++---
 pc-bios/s390-ccw/dasd-ipl.c             |  71 ++---
 pc-bios/s390-ccw/jump2ipl.c             |  22 +-
 pc-bios/s390-ccw/libc.c                 |  88 ------
 pc-bios/s390-ccw/main.c                 |  97 ++++---
 pc-bios/s390-ccw/menu.c                 |  51 ++--
 pc-bios/s390-ccw/netmain.c              |  38 ++-
 pc-bios/s390-ccw/sclp.c                 |   7 +-
 pc-bios/s390-ccw/virtio-blkdev.c        |  12 +-
 pc-bios/s390-ccw/virtio-net.c           |   7 +-
 pc-bios/s390-ccw/virtio-scsi.c          | 160 +++++++----
 pc-bios/s390-ccw/virtio.c               |  67 +++--
 target/s390x/diag.c                     |   9 +-
 tests/qtest/cdrom-test.c                |  24 ++
 tests/tcg/s390x/console.c               |   3 +
 pc-bios/meson.build                     |   1 -
 pc-bios/s390-ccw.img                    | Bin 42608 -> 79608 bytes
 pc-bios/s390-ccw/Makefile               |  72 ++++-
 pc-bios/s390-ccw/start.S                |  11 +-
 pc-bios/s390-netboot.img                | Bin 67232 -> 0 bytes
 tests/tcg/s390x/Makefile.softmmu-target |   2 +-
 39 files changed, 1171 insertions(+), 1082 deletions(-)
 delete mode 100644 pc-bios/s390-ccw/netboot.mak
 create mode 100644 include/hw/s390x/ipl/qipl.h
 delete mode 100644 pc-bios/s390-ccw/libc.h
 delete mode 100644 pc-bios/s390-ccw/libc.c
 delete mode 100644 pc-bios/s390-netboot.img



^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PULL 01/23] hw/s390x/ipl: Provide more memory to the s390-ccw.img firmware
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
@ 2024-10-23 13:16 ` Thomas Huth
  2024-10-23 13:16 ` [PULL 02/23] pc-bios/s390-ccw: Use the libc from SLOF and remove sclp prints Thomas Huth
                   ` (22 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell

We are going to link the SLOF libc into the s390-ccw.img, and this
libc needs more memory for providing space for malloc() and friends.
Thus bump the memory size that we reserve for the bios to 3 MiB
instead of only 2 MiB. While we're at it, add a proper check that
there is really enough memory assigned to the machine before blindly
using it.

Message-ID: <20240621082422.136217-3-thuth@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 hw/s390x/ipl.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 5ab7433908..5f60977ceb 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -45,6 +45,7 @@
 #define INITRD_PARM_START               0x010408UL
 #define PARMFILE_START                  0x001000UL
 #define ZIPL_IMAGE_START                0x009000UL
+#define BIOS_MAX_SIZE                   0x300000UL
 #define IPL_PSW_MASK                    (PSW_MASK_32 | PSW_MASK_64)
 
 static bool iplb_extended_needed(void *opaque)
@@ -144,7 +145,14 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
      * even if an external kernel has been defined.
      */
     if (!ipl->kernel || ipl->enforce_bios) {
-        uint64_t fwbase = (MIN(ms->ram_size, 0x80000000U) - 0x200000) & ~0xffffUL;
+        uint64_t fwbase;
+
+        if (ms->ram_size < BIOS_MAX_SIZE) {
+            error_setg(errp, "not enough RAM to load the BIOS file");
+            return;
+        }
+
+        fwbase = (MIN(ms->ram_size, 0x80000000U) - BIOS_MAX_SIZE) & ~0xffffUL;
 
         bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, ipl->firmware);
         if (bios_filename == NULL) {
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 02/23] pc-bios/s390-ccw: Use the libc from SLOF and remove sclp prints
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
  2024-10-23 13:16 ` [PULL 01/23] hw/s390x/ipl: Provide more memory to the s390-ccw.img firmware Thomas Huth
@ 2024-10-23 13:16 ` Thomas Huth
  2024-10-23 13:16 ` [PULL 03/23] pc-bios/s390-ccw: Link the netboot code into the main s390-ccw.img binary Thomas Huth
                   ` (21 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

We are already using the libc from SLOF for the s390-netboot.img, and
this libc implementation is way more complete and accurate than the
simple implementation that we currently use for the s390-ccw.img binary.
Since we are now always assuming that the SLOF submodule is available
when building the s390-ccw bios (see commit bf6903f6944f), we can drop
the simple implementation and use the SLOF libc for the s390-ccw.img
binary, too.

Additionally replace sclp_print calls with puts/printf now that it is
available.

Co-authored by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Message-ID: <20241020012953.1380075-3-jrossi@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/netboot.mak            |  3 -
 pc-bios/s390-ccw/bootmap.h              |  4 +-
 pc-bios/s390-ccw/libc.h                 | 89 -------------------------
 pc-bios/s390-ccw/s390-ccw.h             | 30 +++------
 pc-bios/s390-ccw/bootmap.c              | 47 ++++++-------
 pc-bios/s390-ccw/cio.c                  | 78 ++++++++++------------
 pc-bios/s390-ccw/dasd-ipl.c             |  5 +-
 pc-bios/s390-ccw/jump2ipl.c             |  5 +-
 pc-bios/s390-ccw/libc.c                 | 88 ------------------------
 pc-bios/s390-ccw/main.c                 | 14 ++--
 pc-bios/s390-ccw/menu.c                 | 51 +++++++-------
 pc-bios/s390-ccw/netmain.c              | 10 +--
 pc-bios/s390-ccw/sclp.c                 |  7 +-
 pc-bios/s390-ccw/virtio-blkdev.c        |  6 +-
 pc-bios/s390-ccw/virtio-scsi.c          | 17 ++---
 pc-bios/s390-ccw/virtio.c               |  2 +-
 tests/tcg/s390x/console.c               |  3 +
 pc-bios/s390-ccw/Makefile               | 15 +++--
 tests/tcg/s390x/Makefile.softmmu-target |  2 +-
 19 files changed, 140 insertions(+), 336 deletions(-)
 delete mode 100644 pc-bios/s390-ccw/libc.h
 delete mode 100644 pc-bios/s390-ccw/libc.c

diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak
index 046aa35587..d2b3d8ee74 100644
--- a/pc-bios/s390-ccw/netboot.mak
+++ b/pc-bios/s390-ccw/netboot.mak
@@ -1,9 +1,6 @@
 
-SLOF_DIR := $(SRC_PATH)/../../roms/SLOF
-
 NETOBJS := start.o sclp.o cio.o virtio.o virtio-net.o jump2ipl.o netmain.o
 
-LIBC_INC := -nostdinc -I$(SLOF_DIR)/lib/libc/include
 LIBNET_INC := -I$(SLOF_DIR)/lib/libnet
 
 NETLDFLAGS := $(LDFLAGS) -Wl,-Ttext=0x7800000
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index d4690a88c2..4a7d8a91f1 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -336,9 +336,7 @@ static inline void print_volser(const void *volser)
 
     ebcdic_to_ascii((char *)volser, ascii, 6);
     ascii[6] = '\0';
-    sclp_print("VOLSER=[");
-    sclp_print(ascii);
-    sclp_print("]\n");
+    printf("VOLSER=[%s]\n", ascii);
 }
 
 static inline bool unused_space(const void *p, size_t size)
diff --git a/pc-bios/s390-ccw/libc.h b/pc-bios/s390-ccw/libc.h
deleted file mode 100644
index bcdc45732d..0000000000
--- a/pc-bios/s390-ccw/libc.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * libc-style definitions and functions
- *
- * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#ifndef S390_CCW_LIBC_H
-#define S390_CCW_LIBC_H
-
-typedef unsigned long      size_t;
-typedef int                bool;
-typedef unsigned char      uint8_t;
-typedef unsigned short     uint16_t;
-typedef unsigned int       uint32_t;
-typedef unsigned long long uint64_t;
-
-static inline void *memset(void *s, int c, size_t n)
-{
-    size_t i;
-    unsigned char *p = s;
-
-    for (i = 0; i < n; i++) {
-        p[i] = c;
-    }
-
-    return s;
-}
-
-static inline void *memcpy(void *s1, const void *s2, size_t n)
-{
-    uint8_t *dest = s1;
-    const uint8_t *src = s2;
-    size_t i;
-
-    for (i = 0; i < n; i++) {
-        dest[i] = src[i];
-    }
-
-    return s1;
-}
-
-static inline int memcmp(const void *s1, const void *s2, size_t n)
-{
-    size_t i;
-    const uint8_t *p1 = s1, *p2 = s2;
-
-    for (i = 0; i < n; i++) {
-        if (p1[i] != p2[i]) {
-            return p1[i] > p2[i] ? 1 : -1;
-        }
-    }
-
-    return 0;
-}
-
-static inline size_t strlen(const char *str)
-{
-    size_t i;
-    for (i = 0; *str; i++) {
-        str++;
-    }
-    return i;
-}
-
-static inline char *strcat(char *dest, const char *src)
-{
-    int i;
-    char *dest_end = dest + strlen(dest);
-
-    for (i = 0; i <= strlen(src); i++) {
-        dest_end[i] = src[i];
-    }
-    return dest;
-}
-
-static inline int isdigit(int c)
-{
-    return (c >= '0') && (c <= '9');
-}
-
-uint64_t atoui(const char *str);
-char *uitoa(uint64_t num, char *str, size_t len);
-
-#endif
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index c977a52b50..6f6d95d170 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -13,6 +13,11 @@
 
 /* #define DEBUG */
 
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
 typedef unsigned char      u8;
 typedef unsigned short     u16;
 typedef unsigned int       u32;
@@ -26,9 +31,6 @@ typedef unsigned long long u64;
 #define EBUSY   2
 #define ENODEV  3
 
-#ifndef NULL
-#define NULL    0
-#endif
 #ifndef MIN
 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
 #endif
@@ -87,7 +89,7 @@ bool menu_is_enabled_enum(void);
 __attribute__ ((__noreturn__))
 static inline void panic(const char *string)
 {
-    sclp_print(string);
+    printf("ERROR: %s\n ", string);
     disabled_wait();
 }
 
@@ -109,20 +111,10 @@ static inline void fill_hex_val(char *out, void *ptr, unsigned size)
     }
 }
 
-static inline void print_int(const char *desc, u64 addr)
-{
-    char out[] = ": 0xffffffffffffffff\n";
-
-    fill_hex_val(&out[4], &addr, sizeof(addr));
-
-    sclp_print(desc);
-    sclp_print(out);
-}
-
 static inline void debug_print_int(const char *desc, u64 addr)
 {
 #ifdef DEBUG
-    print_int(desc, addr);
+    printf("%s 0x%X\n", desc, addr);
 #endif
 }
 
@@ -147,18 +139,14 @@ static inline void debug_print_addr(const char *desc, void *p)
 static inline void IPL_assert(bool term, const char *message)
 {
     if (!term) {
-        sclp_print("\n! ");
-        sclp_print(message);
-        panic(" !\n"); /* no return */
+        panic(message); /* no return */
     }
 }
 
 static inline void IPL_check(bool term, const char *message)
 {
     if (!term) {
-        sclp_print("\n! WARNING: ");
-        sclp_print(message);
-        sclp_print(" !\n");
+        printf("WARNING: %s\n", message);
     }
 }
 
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index a2137449dc..3cc79706be 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -8,7 +8,8 @@
  * directory.
  */
 
-#include "libc.h"
+#include <string.h>
+#include <stdio.h>
 #include "s390-ccw.h"
 #include "s390-arch.h"
 #include "bootmap.h"
@@ -21,7 +22,7 @@
 
 #ifdef DEBUG_FALLBACK
 #define dputs(txt) \
-    do { sclp_print("zipl: " txt); } while (0)
+    do { printf("zipl: " txt); } while (0)
 #else
 #define dputs(fmt, ...) \
     do { } while (0)
@@ -270,7 +271,7 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
         prev_block_nr = cur_block_nr;
     }
 
-    sclp_print("No zipl boot menu data found. Booting default entry.");
+    printf("No zipl boot menu data found. Booting default entry.");
     return 0;
 }
 
@@ -338,22 +339,22 @@ static void ipl_eckd_cdl(void)
     block_number_t bmt_block_nr, s1b_block_nr;
 
     /* we have just read the block #0 and recognized it as "IPL1" */
-    sclp_print("CDL\n");
+    puts("CDL");
 
     memset(sec, FREE_SPACE_FILLER, sizeof(sec));
     read_block(1, ipl2, "Cannot read IPL2 record at block 1");
 
     mbr = &ipl2->mbr;
     if (!magic_match(mbr, ZIPL_MAGIC)) {
-        sclp_print("No zIPL section in IPL2 record.\n");
+        puts("No zIPL section in IPL2 record.");
         return;
     }
     if (!block_size_ok(mbr->blockptr.xeckd.bptr.size)) {
-        sclp_print("Bad block size in zIPL section of IPL2 record.\n");
+        puts("Bad block size in zIPL section of IPL2 record.");
         return;
     }
     if (mbr->dev_type != DEV_TYPE_ECKD) {
-        sclp_print("Non-ECKD device type in zIPL section of IPL2 record.\n");
+        puts("Non-ECKD device type in zIPL section of IPL2 record.");
         return;
     }
 
@@ -366,11 +367,11 @@ static void ipl_eckd_cdl(void)
     memset(sec, FREE_SPACE_FILLER, sizeof(sec));
     read_block(2, vlbl, "Cannot read Volume Label at block 2");
     if (!magic_match(vlbl->key, VOL1_MAGIC)) {
-        sclp_print("Invalid magic of volume label block.\n");
+        puts("Invalid magic of volume label block.");
         return;
     }
     if (!magic_match(vlbl->f.key, VOL1_MAGIC)) {
-        sclp_print("Invalid magic of volser block.\n");
+        puts("Invalid magic of volser block.");
         return;
     }
     print_volser(vlbl->f.volser);
@@ -384,8 +385,8 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
     LDL_VTOC *vlbl = (void *)sec; /* already read, 3rd block */
     char msg[4] = { '?', '.', '\n', '\0' };
 
-    sclp_print((mode == ECKD_CMS) ? "CMS" : "LDL");
-    sclp_print(" version ");
+    printf((mode == ECKD_CMS) ? "CMS" : "LDL");
+    printf(" version ");
     switch (vlbl->LDL_version) {
     case LDL1_VERSION:
         msg[0] = '1';
@@ -398,7 +399,7 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
         msg[1] = '?';
         break;
     }
-    sclp_print(msg);
+    printf("%s", msg);
     print_volser(vlbl->volser);
 }
 
@@ -419,7 +420,7 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
         if (!magic_match(ipl1->bip.magic, ZIPL_MAGIC)) {
             return; /* not applicable layout */
         }
-        sclp_print("unlabeled LDL.\n");
+        puts("unlabeled LDL.");
     }
     verify_boot_info(&ipl1->bip);
 
@@ -466,7 +467,7 @@ static void print_eckd_msg(void)
             *p-- = ' ';
         }
     }
-    sclp_print(msg);
+    printf("%s", msg);
 }
 
 static void ipl_eckd(void)
@@ -488,11 +489,11 @@ static void ipl_eckd(void)
     if (eckd_valid_address((ExtEckdBlockPtr *)&vlbl->f.br, 0)) {
         ldipl_bmt = eckd_find_bmt((ExtEckdBlockPtr *)&vlbl->f.br);
         if (ldipl_bmt) {
-            sclp_print("List-Directed\n");
+            puts("List-Directed");
             /* LD-IPL does not use the S1B bock, just make it NULL */
             run_eckd_boot_script(ldipl_bmt, NULL_BLOCK_NR);
             /* Only return in error, retry as CCW-IPL */
-            sclp_print("Retrying IPL ");
+            printf("Retrying IPL ");
             print_eckd_msg();
         }
         memset(sec, FREE_SPACE_FILLER, sizeof(sec));
@@ -634,7 +635,7 @@ static void ipl_scsi(void)
         return;
     }
 
-    sclp_print("Using SCSI scheme.\n");
+    puts("Using SCSI scheme.");
     debug_print_int("MBR Version", mbr->version_id);
     IPL_check(mbr->version_id == 1,
               "Unknown MBR layout version, assuming version 1");
@@ -743,7 +744,7 @@ static inline uint32_t iso_get_file_size(uint32_t load_rba)
             if (cur_record->file_flags & 0x2) {
                 /* Subdirectory */
                 if (level == ISO9660_MAX_DIR_DEPTH - 1) {
-                    sclp_print("ISO-9660 directory depth limit exceeded\n");
+                    puts("ISO-9660 directory depth limit exceeded");
                 } else {
                     level++;
                     sec_loc[level] = iso_733_to_u32(cur_record->ext_loc);
@@ -778,9 +779,9 @@ static void load_iso_bc_entry(IsoBcSection *load)
     if (real_size) {
         /* Round up blocks to load */
         blks_to_load = (real_size + ISO_SECTOR_SIZE - 1) / ISO_SECTOR_SIZE;
-        sclp_print("ISO boot image size verified\n");
+        puts("ISO boot image size verified");
     } else {
-        sclp_print("ISO boot image size could not be verified\n");
+        puts("ISO boot image size could not be verified");
     }
 
     read_iso_boot_image(bswap32(s.load_rba),
@@ -896,7 +897,7 @@ static void zipl_load_vblk(void)
     }
 
     if (blksize != VIRTIO_DASD_DEFAULT_BLOCK_SIZE) {
-        sclp_print("Using guessed DASD geometry.\n");
+        puts("Using guessed DASD geometry.");
         virtio_assume_eckd();
     }
     ipl_eckd();
@@ -909,7 +910,7 @@ static void zipl_load_vscsi(void)
         ipl_iso_el_torito();
     }
 
-    sclp_print("Using guessed DASD geometry.\n");
+    puts("Using guessed DASD geometry.");
     virtio_assume_eckd();
     ipl_eckd();
 }
@@ -944,5 +945,5 @@ void zipl_load(void)
         panic("\n! Unknown IPL device type !\n");
     }
 
-    sclp_print("zIPL load failed.\n");
+    puts("zIPL load failed.");
 }
diff --git a/pc-bios/s390-ccw/cio.c b/pc-bios/s390-ccw/cio.c
index 83ca27ab41..7b09a38c96 100644
--- a/pc-bios/s390-ccw/cio.c
+++ b/pc-bios/s390-ccw/cio.c
@@ -11,7 +11,8 @@
  * directory.
  */
 
-#include "libc.h"
+#include <string.h>
+#include <stdio.h>
 #include "s390-ccw.h"
 #include "s390-arch.h"
 #include "helper.h"
@@ -90,9 +91,9 @@ static void print_eckd_dasd_sense_data(SenseDataEckdDasd *sd)
     char msgline[512];
 
     if (sd->config_info & 0x8000) {
-        sclp_print("Eckd Dasd Sense Data (fmt 24-bytes):\n");
+        puts("Eckd Dasd Sense Data (fmt 24-bytes):");
     } else {
-        sclp_print("Eckd Dasd Sense Data (fmt 32-bytes):\n");
+        puts("Eckd Dasd Sense Data (fmt 32-bytes):");
     }
 
     strcat(msgline, "    Sense Condition Flags :");
@@ -158,22 +159,21 @@ static void print_eckd_dasd_sense_data(SenseDataEckdDasd *sd)
     if (sd->status[1] & SNS_STAT2_IMPRECISE_END) {
         strcat(msgline, " [Imprecise-End]");
     }
-    strcat(msgline, "\n");
-    sclp_print(msgline);
-
-    print_int("    Residual Count     =", sd->res_count);
-    print_int("    Phys Drive ID      =", sd->phys_drive_id);
-    print_int("    low cyl address    =", sd->low_cyl_addr);
-    print_int("    head addr & hi cyl =", sd->head_high_cyl_addr);
-    print_int("    format/message     =", sd->fmt_msg);
-    print_int("    fmt-dependent[0-7] =", sd->fmt_dependent_info[0]);
-    print_int("    fmt-dependent[8-15]=", sd->fmt_dependent_info[1]);
-    print_int("    prog action code   =", sd->program_action_code);
-    print_int("    Configuration info =", sd->config_info);
-    print_int("    mcode / hi-cyl     =", sd->mcode_hicyl);
-    print_int("    cyl & head addr [0]=", sd->cyl_head_addr[0]);
-    print_int("    cyl & head addr [1]=", sd->cyl_head_addr[1]);
-    print_int("    cyl & head addr [2]=", sd->cyl_head_addr[2]);
+    puts(msgline);
+
+    printf("    Residual Count     = 0x%X\n", sd->res_count);
+    printf("    Phys Drive ID      = 0x%X\n", sd->phys_drive_id);
+    printf("    low cyl address    = 0x%X\n", sd->low_cyl_addr);
+    printf("    head addr & hi cyl = 0x%X\n", sd->head_high_cyl_addr);
+    printf("    format/message     = 0x%X\n", sd->fmt_msg);
+    printf("    fmt-dependent[0-7] = 0x%llX\n", sd->fmt_dependent_info[0]);
+    printf("    fmt-dependent[8-15]= 0x%llX\n", sd->fmt_dependent_info[1]);
+    printf("    prog action code   = 0x%X\n", sd->program_action_code);
+    printf("    Configuration info = 0x%X\n", sd->config_info);
+    printf("    mcode / hi-cyl     = 0x%X\n", sd->mcode_hicyl);
+    printf("    cyl & head addr [0]= 0x%X\n", sd->cyl_head_addr[0]);
+    printf("    cyl & head addr [1]= 0x%X\n", sd->cyl_head_addr[1]);
+    printf("    cyl & head addr [2]= 0x%X\n", sd->cyl_head_addr[2]);
 }
 
 static void print_irb_err(Irb *irb)
@@ -182,7 +182,7 @@ static void print_irb_err(Irb *irb)
     uint64_t prev_ccw = *(uint64_t *)u32toptr(irb->scsw.cpa - 8);
     char msgline[256];
 
-    sclp_print("Interrupt Response Block Data:\n");
+    puts("Interrupt Response Block Data:");
 
     strcat(msgline, "    Function Ctrl :");
     if (irb->scsw.ctrl & SCSW_FCTL_START_FUNC) {
@@ -194,8 +194,7 @@ static void print_irb_err(Irb *irb)
     if (irb->scsw.ctrl & SCSW_FCTL_CLEAR_FUNC) {
         strcat(msgline, " [Clear]");
     }
-    strcat(msgline, "\n");
-    sclp_print(msgline);
+    puts(msgline);
 
     msgline[0] = '\0';
     strcat(msgline, "    Activity Ctrl :");
@@ -220,8 +219,7 @@ static void print_irb_err(Irb *irb)
     if (irb->scsw.ctrl & SCSW_ACTL_SUSPENDED) {
         strcat(msgline, " [Suspended]");
     }
-    strcat(msgline, "\n");
-    sclp_print(msgline);
+    puts(msgline);
 
     msgline[0] = '\0';
     strcat(msgline, "    Status Ctrl :");
@@ -240,9 +238,7 @@ static void print_irb_err(Irb *irb)
     if (irb->scsw.ctrl & SCSW_SCTL_STATUS_PEND) {
         strcat(msgline, " [Status-Pending]");
     }
-
-    strcat(msgline, "\n");
-    sclp_print(msgline);
+    puts(msgline);
 
     msgline[0] = '\0';
     strcat(msgline, "    Device Status :");
@@ -270,8 +266,7 @@ static void print_irb_err(Irb *irb)
     if (irb->scsw.dstat & SCSW_DSTAT_UEXCP) {
         strcat(msgline, " [Unit-Exception]");
     }
-    strcat(msgline, "\n");
-    sclp_print(msgline);
+    puts(msgline);
 
     msgline[0] = '\0';
     strcat(msgline, "    Channel Status :");
@@ -299,12 +294,11 @@ static void print_irb_err(Irb *irb)
     if (irb->scsw.cstat & SCSW_CSTAT_CHAINCHK) {
         strcat(msgline, " [Chaining-Check]");
     }
-    strcat(msgline, "\n");
-    sclp_print(msgline);
+    puts(msgline);
 
-    print_int("    cpa=", irb->scsw.cpa);
-    print_int("    prev_ccw=", prev_ccw);
-    print_int("    this_ccw=", this_ccw);
+    printf("    cpa= 0x%X\n", irb->scsw.cpa);
+    printf("    prev_ccw= 0x%llX\n", prev_ccw);
+    printf("    this_ccw= 0x%llX\n", this_ccw);
 }
 
 /*
@@ -341,7 +335,7 @@ static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb)
         return -1;
     }
     if (rc) {
-        print_int("ssch failed with cc=", rc);
+        printf("ssch failed with cc= 0x%x\n", rc);
         return rc;
     }
 
@@ -350,7 +344,7 @@ static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb)
     /* collect status */
     rc = tsch(schid, irb);
     if (rc) {
-        print_int("tsch failed with cc=", rc);
+        printf("tsch failed with cc= 0x%X\n", rc);
     }
 
     return rc;
@@ -406,12 +400,12 @@ int do_cio(SubChannelId schid, uint16_t cutype, uint32_t ccw_addr, int fmt)
             continue;
         }
 
-        sclp_print("cio device error\n");
-        print_int("  ssid  ", schid.ssid);
-        print_int("  cssid ", schid.cssid);
-        print_int("  sch_no", schid.sch_no);
-        print_int("  ctrl-unit type", cutype);
-        sclp_print("\n");
+        printf("cio device error\n");
+        printf("  ssid  0x%X\n", schid.ssid);
+        printf("  cssid 0x%X\n", schid.cssid);
+        printf("  sch_no 0x%X\n", schid.sch_no);
+        printf("  ctrl-unit type 0x%X\n", cutype);
+        printf("\n");
         print_irb_err(&irb);
         if (cutype == CU_TYPE_DASD_3990 || cutype == CU_TYPE_DASD_2107 ||
             cutype == CU_TYPE_UNKNOWN) {
diff --git a/pc-bios/s390-ccw/dasd-ipl.c b/pc-bios/s390-ccw/dasd-ipl.c
index 254bb1a15e..ae751adec1 100644
--- a/pc-bios/s390-ccw/dasd-ipl.c
+++ b/pc-bios/s390-ccw/dasd-ipl.c
@@ -8,7 +8,8 @@
  * directory.
  */
 
-#include "libc.h"
+#include <string.h>
+#include <stdio.h>
 #include "s390-ccw.h"
 #include "s390-arch.h"
 #include "dasd-ipl.h"
@@ -82,7 +83,7 @@ static int run_dynamic_ccw_program(SubChannelId schid, uint16_t cutype,
     do {
         has_next = dynamic_cp_fixup(cpa, &next_cpa);
 
-        print_int("executing ccw chain at ", cpa);
+        printf("executing ccw chain at 0x%X\n", cpa);
         enable_prefixing();
         rc = do_cio(schid, cutype, cpa, CCW_FMT0);
         disable_prefixing();
diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
index 78f5f46533..80b7f6a1f3 100644
--- a/pc-bios/s390-ccw/jump2ipl.c
+++ b/pc-bios/s390-ccw/jump2ipl.c
@@ -6,7 +6,8 @@
  * directory.
  */
 
-#include "libc.h"
+#include <string.h>
+#include <stdio.h>
 #include "s390-ccw.h"
 #include "s390-arch.h"
 
@@ -57,7 +58,7 @@ void jump_to_IPL_code(uint64_t address)
     debug_print_int("set IPL addr to", address ?: *reset_psw & PSW_MASK_SHORT_ADDR);
 
     /* Ensure the guest output starts fresh */
-    sclp_print("\n");
+    printf("\n");
 
     /*
      * HACK ALERT.
diff --git a/pc-bios/s390-ccw/libc.c b/pc-bios/s390-ccw/libc.c
deleted file mode 100644
index 3187923950..0000000000
--- a/pc-bios/s390-ccw/libc.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * libc-style definitions and functions
- *
- * Copyright 2018 IBM Corp.
- * Author(s): Collin L. Walling <walling@linux.vnet.ibm.com>
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include "libc.h"
-#include "s390-ccw.h"
-
-/**
- * atoui:
- * @str: the string to be converted.
- *
- * Given a string @str, convert it to an integer. Leading spaces are
- * ignored. Any other non-numerical value will terminate the conversion
- * and return 0. This function only handles numbers between 0 and
- * UINT64_MAX inclusive.
- *
- * Returns: an integer converted from the string @str, or the number 0
- * if an error occurred.
- */
-uint64_t atoui(const char *str)
-{
-    int val = 0;
-
-    if (!str || !str[0]) {
-        return 0;
-    }
-
-    while (*str == ' ') {
-        str++;
-    }
-
-    while (*str) {
-        if (!isdigit(*(unsigned char *)str)) {
-            break;
-        }
-        val = val * 10 + *str - '0';
-        str++;
-    }
-
-    return val;
-}
-
-/**
- * uitoa:
- * @num: an integer (base 10) to be converted.
- * @str: a pointer to a string to store the conversion.
- * @len: the length of the passed string.
- *
- * Given an integer @num, convert it to a string. The string @str must be
- * allocated beforehand. The resulting string will be null terminated and
- * returned. This function only handles numbers between 0 and UINT64_MAX
- * inclusive.
- *
- * Returns: the string @str of the converted integer @num
- */
-char *uitoa(uint64_t num, char *str, size_t len)
-{
-    long num_idx = 1; /* account for NUL */
-    uint64_t tmp = num;
-
-    IPL_assert(str != NULL, "uitoa: no space allocated to store string");
-
-    /* Count indices of num */
-    while ((tmp /= 10) != 0) {
-        num_idx++;
-    }
-
-    /* Check if we have enough space for num and NUL */
-    IPL_assert(len > num_idx, "uitoa: array too small for conversion");
-
-    str[num_idx--] = '\0';
-
-    /* Convert int to string */
-    while (num_idx >= 0) {
-        str[num_idx--] = num % 10 + '0';
-        num /= 10;
-    }
-
-    return str;
-}
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 5506798098..203df20965 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -8,7 +8,9 @@
  * directory.
  */
 
-#include "libc.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
 #include "helper.h"
 #include "s390-arch.h"
 #include "s390-ccw.h"
@@ -50,7 +52,7 @@ void write_iplb_location(void)
 
 unsigned int get_loadparm_index(void)
 {
-    return atoui(loadparm_str);
+    return atoi(loadparm_str);
 }
 
 static int is_dev_possibly_bootable(int dev_no, int sch_no)
@@ -176,7 +178,7 @@ static void boot_setup(void)
 
     sclp_get_loadparm_ascii(loadparm_str);
     memcpy(lpmsg + 10, loadparm_str, 8);
-    sclp_print(lpmsg);
+    puts(lpmsg);
 
     /*
      * Clear out any potential S390EP magic (see jump_to_low_kernel()),
@@ -228,7 +230,7 @@ static int virtio_setup(void)
 
     switch (vdev->senseid.cu_model) {
     case VIRTIO_ID_NET:
-        sclp_print("Network boot device detected\n");
+        puts("Network boot device detected");
         vdev->netboot_start_addr = qipl.netboot_start_addr;
         return 0;
     case VIRTIO_ID_BLOCK:
@@ -261,7 +263,7 @@ static void ipl_boot_device(void)
         }
         break;
     default:
-        print_int("Attempting to boot from unexpected device type", cutype);
+        printf("Attempting to boot from unexpected device type 0x%X\n", cutype);
         panic("\nBoot failed.\n");
     }
 }
@@ -287,7 +289,7 @@ static void probe_boot_device(void)
         }
     }
 
-    sclp_print("Could not find a suitable boot device (none specified)\n");
+    puts("Could not find a suitable boot device (none specified)");
 }
 
 void main(void)
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index d601952d3e..84062e94af 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -9,7 +9,10 @@
  * directory.
  */
 
-#include "libc.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include "s390-ccw.h"
 #include "sclp.h"
 #include "s390-time.h"
@@ -93,7 +96,7 @@ static int read_prompt(char *buf, size_t len)
         case KEYCODE_BACKSP:
             if (idx > 0) {
                 buf[--idx] = 0;
-                sclp_print("\b \b");
+                printf("\b \b");
             }
             continue;
         case KEYCODE_ENTER:
@@ -103,7 +106,7 @@ static int read_prompt(char *buf, size_t len)
             /* Echo input and add to buffer */
             if (idx < len) {
                 buf[idx++] = inp[0];
-                sclp_print(inp);
+                printf("%s", inp);
             }
         }
     }
@@ -140,22 +143,19 @@ static int get_index(void)
         }
     }
 
-    return atoui(buf);
+    return atoi(buf);
 }
 
 static void boot_menu_prompt(bool retry)
 {
-    char tmp[11];
-
     if (retry) {
-        sclp_print("\nError: undefined configuration"
+        printf("\nError: undefined configuration"
                    "\nPlease choose:\n");
     } else if (timeout > 0) {
-        sclp_print("Please choose (default will boot in ");
-        sclp_print(uitoa(timeout / 1000, tmp, sizeof(tmp)));
-        sclp_print(" seconds):\n");
+        printf("Please choose (default will boot in %d seconds):\n",
+               (int)(timeout / 1000));
     } else {
-        sclp_print("Please choose:\n");
+        puts("Please choose:");
     }
 }
 
@@ -163,7 +163,6 @@ static int get_boot_index(bool *valid_entries)
 {
     int boot_index;
     bool retry = false;
-    char tmp[5];
 
     do {
         boot_menu_prompt(retry);
@@ -172,8 +171,7 @@ static int get_boot_index(bool *valid_entries)
     } while (boot_index < 0 || boot_index >= MAX_BOOT_ENTRIES ||
              !valid_entries[boot_index]);
 
-    sclp_print("\nBooting entry #");
-    sclp_print(uitoa(boot_index, tmp, sizeof(tmp)));
+    printf("\nBooting entry #%d", boot_index);
 
     return boot_index;
 }
@@ -187,9 +185,9 @@ static int zipl_print_entry(const char *data, size_t len)
     buf[len] = '\n';
     buf[len + 1] = '\0';
 
-    sclp_print(buf);
+    printf("%s", buf);
 
-    return buf[0] == ' ' ? atoui(buf + 1) : atoui(buf);
+    return buf[0] == ' ' ? atoi(buf + 1) : atoi(buf);
 }
 
 int menu_get_zipl_boot_index(const char *menu_data)
@@ -209,7 +207,7 @@ int menu_get_zipl_boot_index(const char *menu_data)
     }
 
     /* Print banner */
-    sclp_print("s390-ccw zIPL Boot Menu\n\n");
+    puts("s390-ccw zIPL Boot Menu\n");
     menu_data += strlen(menu_data) + 1;
 
     /* Print entries */
@@ -221,37 +219,34 @@ int menu_get_zipl_boot_index(const char *menu_data)
         valid_entries[entry] = true;
 
         if (entry == 0) {
-            sclp_print("\n");
+            printf("\n");
         }
     }
 
-    sclp_print("\n");
+    printf("\n");
     return get_boot_index(valid_entries);
 }
 
 int menu_get_enum_boot_index(bool *valid_entries)
 {
-    char tmp[3];
     int i;
 
-    sclp_print("s390-ccw Enumerated Boot Menu.\n\n");
+    puts("s390-ccw Enumerated Boot Menu.\n");
 
     for (i = 0; i < MAX_BOOT_ENTRIES; i++) {
         if (valid_entries[i]) {
             if (i < 10) {
-                sclp_print(" ");
+                printf(" ");
             }
-            sclp_print("[");
-            sclp_print(uitoa(i, tmp, sizeof(tmp)));
-            sclp_print("]");
+            printf("[%d]", i);
             if (i == 0) {
-                sclp_print(" default\n");
+                printf(" default\n");
             }
-            sclp_print("\n");
+            printf("\n");
         }
     }
 
-    sclp_print("\n");
+    printf("\n");
     return get_boot_index(valid_entries);
 }
 
diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
index 5cd619b2d6..509119be15 100644
--- a/pc-bios/s390-ccw/netmain.c
+++ b/pc-bios/s390-ccw/netmain.c
@@ -293,7 +293,7 @@ static int load_kernel_with_initrd(filename_ip_t *fn_ip,
     printf("Loading pxelinux.cfg entry '%s'\n", entry->label);
 
     if (!entry->kernel) {
-        printf("Kernel entry is missing!\n");
+        puts("Kernel entry is missing!\n");
         return -1;
     }
 
@@ -515,13 +515,13 @@ void main(void)
     int rc, fnlen;
 
     sclp_setup();
-    sclp_print("Network boot starting...\n");
+    puts("Network boot starting...");
 
     virtio_setup();
 
     rc = net_init(&fn_ip);
     if (rc) {
-        panic("Network initialization failed. Halting.\n");
+        panic("Network initialization failed. Halting.");
     }
 
     fnlen = strlen(fn_ip.filename);
@@ -535,9 +535,9 @@ void main(void)
     net_release(&fn_ip);
 
     if (rc > 0) {
-        sclp_print("Network loading done, starting kernel...\n");
+        puts("Network loading done, starting kernel...");
         jump_to_low_kernel();
     }
 
-    panic("Failed to load OS from network\n");
+    panic("Failed to load OS from network.");
 }
diff --git a/pc-bios/s390-ccw/sclp.c b/pc-bios/s390-ccw/sclp.c
index 7251f9af4d..4a07de018d 100644
--- a/pc-bios/s390-ccw/sclp.c
+++ b/pc-bios/s390-ccw/sclp.c
@@ -8,7 +8,7 @@
  * directory.
  */
 
-#include "libc.h"
+#include <string.h>
 #include "s390-ccw.h"
 #include "sclp.h"
 
@@ -101,11 +101,6 @@ long write(int fd, const void *str, size_t len)
     return len;
 }
 
-void sclp_print(const char *str)
-{
-    write(1, str, strlen(str));
-}
-
 void sclp_get_loadparm_ascii(char *loadparm)
 {
 
diff --git a/pc-bios/s390-ccw/virtio-blkdev.c b/pc-bios/s390-ccw/virtio-blkdev.c
index a81207b52e..2666326801 100644
--- a/pc-bios/s390-ccw/virtio-blkdev.c
+++ b/pc-bios/s390-ccw/virtio-blkdev.c
@@ -8,7 +8,7 @@
  * directory.
  */
 
-#include "libc.h"
+#include <stdio.h>
 #include "s390-ccw.h"
 #include "virtio.h"
 #include "virtio-scsi.h"
@@ -76,7 +76,7 @@ unsigned long virtio_load_direct(unsigned long rec_list1, unsigned long rec_list
         return -1;
     }
 
-    sclp_print(".");
+    printf(".");
     status = virtio_read_many(sec, (void *)addr, sec_num);
     if (status) {
         panic("I/O Error");
@@ -230,7 +230,7 @@ int virtio_blk_setup_device(SubChannelId schid)
     vdev->schid = schid;
     virtio_setup_ccw(vdev);
 
-    sclp_print("Using virtio-blk.\n");
+    puts("Using virtio-blk.");
 
     return 0;
 }
diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c
index d1a84b937c..6b4a1caf8a 100644
--- a/pc-bios/s390-ccw/virtio-scsi.c
+++ b/pc-bios/s390-ccw/virtio-scsi.c
@@ -9,7 +9,8 @@
  * directory.
  */
 
-#include "libc.h"
+#include <string.h>
+#include <stdio.h>
 #include "s390-ccw.h"
 #include "virtio.h"
 #include "scsi.h"
@@ -30,9 +31,9 @@ static inline void vs_assert(bool term, const char **msgs)
     if (!term) {
         int i = 0;
 
-        sclp_print("\n! ");
+        printf("\n! ");
         while (msgs[i]) {
-            sclp_print(msgs[i++]);
+            printf("%s", msgs[i++]);
         }
         panic(" !\n");
     }
@@ -236,11 +237,11 @@ static int virtio_scsi_locate_device(VDev *vdev)
             if (resp.response == VIRTIO_SCSI_S_BAD_TARGET) {
                 continue;
             }
-            print_int("target", target);
+            printf("target 0x%X\n", target);
             virtio_scsi_verify_response(&resp, "SCSI cannot report LUNs");
         }
         if (r->lun_list_len == 0) {
-            print_int("no LUNs for target", target);
+            printf("no LUNs for target 0x%X\n", target);
             continue;
         }
         luns = r->lun_list_len / 8;
@@ -264,7 +265,7 @@ static int virtio_scsi_locate_device(VDev *vdev)
         }
     }
 
-    sclp_print("Warning: Could not locate a usable virtio-scsi device\n");
+    puts("Warning: Could not locate a usable virtio-scsi device");
     return -ENODEV;
 }
 
@@ -379,7 +380,7 @@ static int virtio_scsi_setup(VDev *vdev)
     }
 
     if (virtio_scsi_inquiry_response_is_cdrom(scsi_inquiry_std_response)) {
-        sclp_print("SCSI CD-ROM detected.\n");
+        puts("SCSI CD-ROM detected.");
         vdev->is_cdrom = true;
         vdev->scsi_block_size = VIRTIO_ISO_BLOCK_SIZE;
     }
@@ -443,7 +444,7 @@ int virtio_scsi_setup_device(SubChannelId schid)
     IPL_assert(vdev->config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE,
                "Config: CDB size mismatch");
 
-    sclp_print("Using virtio-scsi.\n");
+    puts("Using virtio-scsi.");
 
     return virtio_scsi_setup(vdev);
 }
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 5edd058d88..8c6b0a8a92 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -8,7 +8,7 @@
  * directory.
  */
 
-#include "libc.h"
+#include <string.h>
 #include "s390-ccw.h"
 #include "cio.h"
 #include "virtio.h"
diff --git a/tests/tcg/s390x/console.c b/tests/tcg/s390x/console.c
index d43ce3f44b..6c26f04949 100644
--- a/tests/tcg/s390x/console.c
+++ b/tests/tcg/s390x/console.c
@@ -4,7 +4,10 @@
  *
  * SPDX-License-Identifier: GPL-2.0-or-later
  */
+
 #include "../../../pc-bios/s390-ccw/sclp.c"
+#include "../../../roms/SLOF/lib/libc/string/memset.c"
+#include "../../../roms/SLOF/lib/libc/string/memcpy.c"
 
 void __sys_outc(char c)
 {
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 6207911b53..3f4232636e 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -33,13 +33,18 @@ QEMU_DGFLAGS = -MMD -MP -MT $@ -MF $(@D)/$(*F).d
 .PHONY : all clean build-all distclean
 
 OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o \
-	  virtio.o virtio-scsi.o virtio-blkdev.o libc.o cio.o dasd-ipl.o
+	  virtio.o virtio-scsi.o virtio-blkdev.o cio.o dasd-ipl.o
+
+SLOF_DIR := $(SRC_PATH)/../../roms/SLOF
+
+LIBC_INC := -nostdinc -I$(SLOF_DIR)/lib/libc/include
 
 EXTRA_CFLAGS += -Wall
 EXTRA_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -fno-common -fPIE
 EXTRA_CFLAGS += -fwrapv -fno-strict-aliasing -fno-asynchronous-unwind-tables
 EXTRA_CFLAGS += -msoft-float
 EXTRA_CFLAGS += -std=gnu99
+EXTRA_CFLAGS += $(LIBC_INC)
 LDFLAGS += -Wl,-pie -nostdlib -z noexecstack
 
 cc-test = $(CC) -Werror $1 -c -o /dev/null -xc /dev/null >/dev/null 2>/dev/null
@@ -55,18 +60,18 @@ config-cc.mak: Makefile
 	    $(call cc-option,-march=z900,-march=z10)) 3> config-cc.mak
 -include config-cc.mak
 
+include $(SRC_PATH)/netboot.mak
+
 build-all: s390-ccw.img s390-netboot.img
 
-s390-ccw.elf: $(OBJECTS)
-	$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS),Linking)
+s390-ccw.elf: $(OBJECTS) libc.a
+	$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^,Linking)
 
 s390-ccw.img: s390-ccw.elf
 	$(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,Stripping $< into)
 
 $(OBJECTS): Makefile
 
-include $(SRC_PATH)/netboot.mak
-
 ALL_OBJS = $(sort $(OBJECTS) $(NETOBJS) $(LIBCOBJS) $(LIBNETOBJS))
 -include $(ALL_OBJS:%.o=%.d)
 
diff --git a/tests/tcg/s390x/Makefile.softmmu-target b/tests/tcg/s390x/Makefile.softmmu-target
index 3227903348..969bc5728f 100644
--- a/tests/tcg/s390x/Makefile.softmmu-target
+++ b/tests/tcg/s390x/Makefile.softmmu-target
@@ -3,7 +3,7 @@ VPATH+=$(S390X_SRC)
 # EXTFLAGS can be passed by the user, e.g. to override the --accel
 QEMU_OPTS+=-action panic=exit-failure -nographic -serial chardev:output $(EXTFLAGS) -kernel
 LINK_SCRIPT=$(S390X_SRC)/softmmu.ld
-CFLAGS+=-ggdb -O0
+CFLAGS+=-ggdb -O0 -I$(SRC_PATH)/include/hw/s390x/ipl/
 LDFLAGS=-nostdlib -static
 
 %.o: %.S
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 03/23] pc-bios/s390-ccw: Link the netboot code into the main s390-ccw.img binary
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
  2024-10-23 13:16 ` [PULL 01/23] hw/s390x/ipl: Provide more memory to the s390-ccw.img firmware Thomas Huth
  2024-10-23 13:16 ` [PULL 02/23] pc-bios/s390-ccw: Use the libc from SLOF and remove sclp prints Thomas Huth
@ 2024-10-23 13:16 ` Thomas Huth
  2024-10-23 13:16 ` [PULL 04/23] hw/s390x: Remove the possibility to load the s390-netboot.img binary Thomas Huth
                   ` (20 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

We originally built a separate binary for the netboot code since it
was considered as experimental and we could not be sure that the
necessary SLOF module had been checked out. Time passed, the code
proved its usefulness, and the build system nowadays makes sure that
the SLOF module is checked out if you have a s390x compiler available
for building the s390-ccw bios. So there is no real compelling reason
anymore to keep the netboot code in a separate binary. Linking the
code together with the main s390-ccw.img will make future enhancements
much easier, like supporting more than one boot device.

Co-authored by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Message-ID: <20241020012953.1380075-4-jrossi@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/netboot.mak | 14 --------------
 pc-bios/s390-ccw/cio.h       |  2 ++
 pc-bios/s390-ccw/iplb.h      |  4 ++--
 pc-bios/s390-ccw/s390-ccw.h  |  3 +++
 pc-bios/s390-ccw/virtio.h    |  1 -
 pc-bios/s390-ccw/bootmap.c   |  2 +-
 pc-bios/s390-ccw/main.c      | 10 +++++++---
 pc-bios/s390-ccw/netmain.c   | 15 ++-------------
 pc-bios/s390-ccw/Makefile    | 13 +++++++------
 9 files changed, 24 insertions(+), 40 deletions(-)

diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak
index d2b3d8ee74..0a24257ff4 100644
--- a/pc-bios/s390-ccw/netboot.mak
+++ b/pc-bios/s390-ccw/netboot.mak
@@ -1,18 +1,4 @@
 
-NETOBJS := start.o sclp.o cio.o virtio.o virtio-net.o jump2ipl.o netmain.o
-
-LIBNET_INC := -I$(SLOF_DIR)/lib/libnet
-
-NETLDFLAGS := $(LDFLAGS) -Wl,-Ttext=0x7800000
-
-$(NETOBJS): EXTRA_CFLAGS += $(LIBC_INC) $(LIBNET_INC)
-
-s390-netboot.elf: $(NETOBJS) libnet.a libc.a
-	$(call quiet-command,$(CC) $(NETLDFLAGS) -o $@ $^,Linking)
-
-s390-netboot.img: s390-netboot.elf
-	$(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,Stripping $< into)
-
 # libc files:
 
 LIBC_CFLAGS = $(EXTRA_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \
diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h
index 8b18153deb..6a5e86ba01 100644
--- a/pc-bios/s390-ccw/cio.h
+++ b/pc-bios/s390-ccw/cio.h
@@ -361,6 +361,8 @@ typedef struct CcwSearchIdData {
     uint8_t record;
 } __attribute__((packed)) CcwSearchIdData;
 
+extern SubChannelId net_schid;
+
 int enable_mss_facility(void);
 void enable_subchannel(SubChannelId schid);
 uint16_t cu_type(SubChannelId schid);
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index cb6ac8a880..3758698468 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -87,9 +87,9 @@ extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 struct QemuIplParameters {
     uint8_t  qipl_flags;
     uint8_t  reserved1[3];
-    uint64_t netboot_start_addr;
+    uint64_t reserved2;
     uint32_t boot_menu_timeout;
-    uint8_t  reserved2[12];
+    uint8_t  reserved3[12];
 } __attribute__ ((packed));
 typedef struct QemuIplParameters QemuIplParameters;
 
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 6f6d95d170..6abb34e563 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -55,6 +55,9 @@ void write_iplb_location(void);
 unsigned int get_loadparm_index(void);
 void main(void);
 
+/* netmain.c */
+void netmain(void);
+
 /* sclp.c */
 void sclp_print(const char *string);
 void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask);
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index 85bd9d1695..6f9a558ff5 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -253,7 +253,6 @@ struct VDev {
     uint8_t scsi_dev_heads;
     bool scsi_device_selected;
     ScsiDevice selected_scsi_device;
-    uint64_t netboot_start_addr;
     uint32_t max_transfer;
     uint32_t guest_features[2];
 };
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 3cc79706be..414c3f1b47 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -929,7 +929,7 @@ void zipl_load(void)
     }
 
     if (virtio_get_device_type() == VIRTIO_ID_NET) {
-        jump_to_IPL_code(vdev->netboot_start_addr);
+        netmain();
     }
 
     ipl_scsi();
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 203df20965..fc44da3161 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -38,8 +38,13 @@ LowCore *lowcore; /* Yes, this *is* a pointer to address 0 */
  */
 void write_subsystem_identification(void)
 {
-    lowcore->subchannel_id = blk_schid.sch_id;
-    lowcore->subchannel_nr = blk_schid.sch_no;
+    if (cutype == CU_TYPE_VIRTIO && virtio_get_device_type() == VIRTIO_ID_NET) {
+        lowcore->subchannel_id = net_schid.sch_id;
+        lowcore->subchannel_nr = net_schid.sch_no;
+    } else {
+        lowcore->subchannel_id = blk_schid.sch_id;
+        lowcore->subchannel_nr = blk_schid.sch_no;
+    }
     lowcore->io_int_parm = 0;
 }
 
@@ -231,7 +236,6 @@ static int virtio_setup(void)
     switch (vdev->senseid.cu_model) {
     case VIRTIO_ID_NET:
         puts("Network boot device detected");
-        vdev->netboot_start_addr = qipl.netboot_start_addr;
         return 0;
     case VIRTIO_ID_BLOCK:
         ret = virtio_blk_setup_device(blk_schid);
diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
index 509119be15..bc6ad8695f 100644
--- a/pc-bios/s390-ccw/netmain.c
+++ b/pc-bios/s390-ccw/netmain.c
@@ -41,7 +41,6 @@
 #define DEFAULT_TFTP_RETRIES 20
 
 extern char _start[];
-void write_iplb_location(void) {}
 
 #define KERNEL_ADDR             ((void *)0L)
 #define KERNEL_MAX_SIZE         ((long)_start)
@@ -50,10 +49,9 @@ void write_iplb_location(void) {}
 /* STSI 3.2.2 offset of first vmdb + offset of uuid inside vmdb */
 #define STSI322_VMDB_UUID_OFFSET ((8 + 12) * 4)
 
-IplParameterBlock iplb __attribute__((aligned(PAGE_SIZE)));
 static char cfgbuf[2048];
 
-static SubChannelId net_schid = { .one = 1 };
+SubChannelId net_schid = { .one = 1 };
 static uint8_t mac[6];
 static uint64_t dest_timer;
 
@@ -438,15 +436,6 @@ static int net_try_direct_tftp_load(filename_ip_t *fn_ip)
     return rc;
 }
 
-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;
@@ -509,7 +498,7 @@ static void virtio_setup(void)
     IPL_assert(found, "No virtio net device found");
 }
 
-void main(void)
+void netmain(void)
 {
     filename_ip_t fn_ip;
     int rc, fnlen;
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 3f4232636e..cf6859823a 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -32,19 +32,20 @@ QEMU_DGFLAGS = -MMD -MP -MT $@ -MF $(@D)/$(*F).d
 
 .PHONY : all clean build-all distclean
 
-OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o \
-	  virtio.o virtio-scsi.o virtio-blkdev.o cio.o dasd-ipl.o
+OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o netmain.o \
+	  virtio.o virtio-net.o virtio-scsi.o virtio-blkdev.o cio.o dasd-ipl.o
 
 SLOF_DIR := $(SRC_PATH)/../../roms/SLOF
 
 LIBC_INC := -nostdinc -I$(SLOF_DIR)/lib/libc/include
+LIBNET_INC := -I$(SLOF_DIR)/lib/libnet
 
 EXTRA_CFLAGS += -Wall
 EXTRA_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -fno-common -fPIE
 EXTRA_CFLAGS += -fwrapv -fno-strict-aliasing -fno-asynchronous-unwind-tables
 EXTRA_CFLAGS += -msoft-float
 EXTRA_CFLAGS += -std=gnu99
-EXTRA_CFLAGS += $(LIBC_INC)
+EXTRA_CFLAGS += $(LIBC_INC) $(LIBNET_INC)
 LDFLAGS += -Wl,-pie -nostdlib -z noexecstack
 
 cc-test = $(CC) -Werror $1 -c -o /dev/null -xc /dev/null >/dev/null 2>/dev/null
@@ -62,9 +63,9 @@ config-cc.mak: Makefile
 
 include $(SRC_PATH)/netboot.mak
 
-build-all: s390-ccw.img s390-netboot.img
+build-all: s390-ccw.img
 
-s390-ccw.elf: $(OBJECTS) libc.a
+s390-ccw.elf: $(OBJECTS) libnet.a libc.a
 	$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^,Linking)
 
 s390-ccw.img: s390-ccw.elf
@@ -72,7 +73,7 @@ s390-ccw.img: s390-ccw.elf
 
 $(OBJECTS): Makefile
 
-ALL_OBJS = $(sort $(OBJECTS) $(NETOBJS) $(LIBCOBJS) $(LIBNETOBJS))
+ALL_OBJS = $(sort $(OBJECTS) $(LIBCOBJS) $(LIBNETOBJS))
 -include $(ALL_OBJS:%.o=%.d)
 
 clean:
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 04/23] hw/s390x: Remove the possibility to load the s390-netboot.img binary
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (2 preceding siblings ...)
  2024-10-23 13:16 ` [PULL 03/23] pc-bios/s390-ccw: Link the netboot code into the main s390-ccw.img binary Thomas Huth
@ 2024-10-23 13:16 ` Thomas Huth
  2024-10-23 13:16 ` [PULL 05/23] pc-bios/s390-ccw: Merge netboot.mak into the main Makefile Thomas Huth
                   ` (19 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell

Since the netboot code has now been merged into the main s390-ccw.img
binary, we don't need the separate s390-netboot.img anymore. Remove
it and the code that was responsible for loading it.

Message-Id: <20240621082422.136217-6-thuth@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 hw/s390x/ipl.h             |  12 +++-----
 hw/s390x/ipl.c             |  55 -------------------------------------
 hw/s390x/s390-virtio-ccw.c |  10 ++-----
 pc-bios/meson.build        |   1 -
 pc-bios/s390-netboot.img   | Bin 67232 -> 0 bytes
 5 files changed, 6 insertions(+), 72 deletions(-)
 delete mode 100644 pc-bios/s390-netboot.img

diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 57cd125769..b2105b616a 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -134,11 +134,8 @@ void s390_ipl_clear_reset_request(void);
 /*
  * The QEMU IPL Parameters will be stored at absolute address
  * 204 (0xcc) which means it is 32-bit word aligned but not
- * double-word aligned.
- * Placement of data fields in this area must account for
- * their alignment needs. E.g., netboot_start_address must
- * have an offset of 4 + n * 8 bytes within the struct in order
- * to keep it double-word aligned.
+ * double-word aligned. Placement of 64-bit data fields in this
+ * area must account for their alignment needs.
  * The total size of the struct must never exceed 28 bytes.
  * This definition must be kept in sync with the definition
  * in pc-bios/s390-ccw/iplb.h.
@@ -146,9 +143,9 @@ void s390_ipl_clear_reset_request(void);
 struct QemuIplParameters {
     uint8_t  qipl_flags;
     uint8_t  reserved1[3];
-    uint64_t netboot_start_addr;
+    uint64_t reserved2;
     uint32_t boot_menu_timeout;
-    uint8_t  reserved2[12];
+    uint8_t  reserved3[12];
 } QEMU_PACKED;
 typedef struct QemuIplParameters QemuIplParameters;
 
@@ -178,7 +175,6 @@ struct S390IPLState {
     char *initrd;
     char *cmdline;
     char *firmware;
-    char *netboot_fw;
     uint8_t cssid;
     uint8_t ssid;
     uint16_t devno;
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 5f60977ceb..8c490eeb52 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -288,7 +288,6 @@ static Property s390_ipl_properties[] = {
     DEFINE_PROP_STRING("initrd", S390IPLState, initrd),
     DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline),
     DEFINE_PROP_STRING("firmware", S390IPLState, firmware),
-    DEFINE_PROP_STRING("netboot_fw", S390IPLState, netboot_fw),
     DEFINE_PROP_BOOL("enforce_bios", S390IPLState, enforce_bios, false),
     DEFINE_PROP_BOOL("iplbext_migration", S390IPLState, iplbext_migration,
                      true),
@@ -480,56 +479,6 @@ int s390_ipl_set_loadparm(uint8_t *loadparm)
     return -1;
 }
 
-static int load_netboot_image(Error **errp)
-{
-    MachineState *ms = MACHINE(qdev_get_machine());
-    S390IPLState *ipl = get_ipl_device();
-    char *netboot_filename;
-    MemoryRegion *sysmem =  get_system_memory();
-    MemoryRegion *mr = NULL;
-    void *ram_ptr = NULL;
-    int img_size = -1;
-
-    mr = memory_region_find(sysmem, 0, 1).mr;
-    if (!mr) {
-        error_setg(errp, "Failed to find memory region at address 0");
-        return -1;
-    }
-
-    ram_ptr = memory_region_get_ram_ptr(mr);
-    if (!ram_ptr) {
-        error_setg(errp, "No RAM found");
-        goto unref_mr;
-    }
-
-    netboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, ipl->netboot_fw);
-    if (netboot_filename == NULL) {
-        error_setg(errp, "Could not find network bootloader '%s'",
-                   ipl->netboot_fw);
-        goto unref_mr;
-    }
-
-    img_size = load_elf_ram(netboot_filename, NULL, NULL, NULL,
-                            &ipl->start_addr,
-                            NULL, NULL, NULL, 1, EM_S390, 0, 0, NULL,
-                            false);
-
-    if (img_size < 0) {
-        img_size = load_image_size(netboot_filename, ram_ptr, ms->ram_size);
-        ipl->start_addr = KERN_IMAGE_START;
-    }
-
-    if (img_size < 0) {
-        error_setg(errp, "Failed to load network bootloader");
-    }
-
-    g_free(netboot_filename);
-
-unref_mr:
-    memory_region_unref(mr);
-    return img_size;
-}
-
 static bool is_virtio_ccw_device_of_type(IplParameterBlock *iplb,
                                          int virtio_id)
 {
@@ -754,10 +703,6 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
             ipl->iplb_valid = s390_gen_initial_iplb(ipl);
         }
     }
-    if (ipl->netboot) {
-        load_netboot_image(&error_fatal);
-        ipl->qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
-    }
     s390_ipl_set_boot_menu(ipl);
     s390_ipl_prepare_qipl(cpu);
 }
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 5aa8d207a3..529e53f308 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -197,11 +197,10 @@ static void s390_memory_init(MemoryRegion *ram)
 static void s390_init_ipl_dev(const char *kernel_filename,
                               const char *kernel_cmdline,
                               const char *initrd_filename, const char *firmware,
-                              const char *netboot_fw, bool enforce_bios)
+                              bool enforce_bios)
 {
     Object *new = object_new(TYPE_S390_IPL);
     DeviceState *dev = DEVICE(new);
-    char *netboot_fw_prop;
 
     if (kernel_filename) {
         qdev_prop_set_string(dev, "kernel", kernel_filename);
@@ -212,11 +211,6 @@ static void s390_init_ipl_dev(const char *kernel_filename,
     qdev_prop_set_string(dev, "cmdline", kernel_cmdline);
     qdev_prop_set_string(dev, "firmware", firmware);
     qdev_prop_set_bit(dev, "enforce_bios", enforce_bios);
-    netboot_fw_prop = object_property_get_str(new, "netboot_fw", &error_abort);
-    if (!strlen(netboot_fw_prop)) {
-        qdev_prop_set_string(dev, "netboot_fw", netboot_fw);
-    }
-    g_free(netboot_fw_prop);
     object_property_add_child(qdev_get_machine(), TYPE_S390_IPL,
                               new);
     object_unref(new);
@@ -284,7 +278,7 @@ static void ccw_init(MachineState *machine)
     s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
                       machine->initrd_filename,
                       machine->firmware ?: "s390-ccw.img",
-                      "s390-netboot.img", true);
+                      true);
 
     dev = qdev_new(TYPE_S390_PCI_HOST_BRIDGE);
     object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE,
diff --git a/pc-bios/meson.build b/pc-bios/meson.build
index 090379763e..4823dff189 100644
--- a/pc-bios/meson.build
+++ b/pc-bios/meson.build
@@ -68,7 +68,6 @@ blobs = [
   'kvmvapic.bin',
   'pvh.bin',
   's390-ccw.img',
-  's390-netboot.img',
   'slof.bin',
   'skiboot.lid',
   'palcode-clipper',
diff --git a/pc-bios/s390-netboot.img b/pc-bios/s390-netboot.img
deleted file mode 100644
index 6908e49f06801808b826d3a01f88132cf1b2f57c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 67232
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
ba_Yxv8Q%DF#((bPsWNoHC+0@D`RV@w*b1Nq

-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 05/23] pc-bios/s390-ccw: Merge netboot.mak into the main Makefile
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (3 preceding siblings ...)
  2024-10-23 13:16 ` [PULL 04/23] hw/s390x: Remove the possibility to load the s390-netboot.img binary Thomas Huth
@ 2024-10-23 13:16 ` Thomas Huth
  2024-10-23 13:16 ` [PULL 06/23] docs/system/s390x/bootdevices: Update the documentation about network booting Thomas Huth
                   ` (18 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell

Now that the netboot code has been merged into the main s390-ccw.img,
it also does not make sense to keep the build rules in a separate
file. Thus let's merge netboot.mak into the main Makefile.

Message-Id: <20240621082422.136217-7-thuth@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/netboot.mak | 45 ----------------------------------
 pc-bios/s390-ccw/Makefile    | 47 +++++++++++++++++++++++++++++++++++-
 2 files changed, 46 insertions(+), 46 deletions(-)
 delete mode 100644 pc-bios/s390-ccw/netboot.mak

diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak
deleted file mode 100644
index 0a24257ff4..0000000000
--- a/pc-bios/s390-ccw/netboot.mak
+++ /dev/null
@@ -1,45 +0,0 @@
-
-# libc files:
-
-LIBC_CFLAGS = $(EXTRA_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \
-	      -MMD -MP -MT $@ -MF $(@:%.o=%.d)
-
-CTYPE_OBJS = isdigit.o isxdigit.o toupper.o
-%.o : $(SLOF_DIR)/lib/libc/ctype/%.c
-	$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
-
-STRING_OBJS = strcat.o strchr.o strrchr.o strcpy.o strlen.o strncpy.o \
-	      strcmp.o strncmp.o strcasecmp.o strncasecmp.o strstr.o \
-	      memset.o memcpy.o memmove.o memcmp.o
-%.o : $(SLOF_DIR)/lib/libc/string/%.c
-	$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
-
-STDLIB_OBJS = atoi.o atol.o strtoul.o strtol.o rand.o malloc.o free.o
-%.o : $(SLOF_DIR)/lib/libc/stdlib/%.c
-	$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
-
-STDIO_OBJS = sprintf.o snprintf.o vfprintf.o vsnprintf.o vsprintf.o fprintf.o \
-	     printf.o putc.o puts.o putchar.o stdchnls.o fileno.o
-%.o : $(SLOF_DIR)/lib/libc/stdio/%.c
-	$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
-
-sbrk.o: $(SLOF_DIR)/slof/sbrk.c
-	$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
-
-LIBCOBJS := $(STRING_OBJS) $(CTYPE_OBJS) $(STDLIB_OBJS) $(STDIO_OBJS) sbrk.o
-
-libc.a: $(LIBCOBJS)
-	$(call quiet-command,$(AR) -rc $@ $^,Creating static library)
-
-# libnet files:
-
-LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \
-	      dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o pxelinux.o
-LIBNETCFLAGS = $(EXTRA_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \
-	       -DDHCPARCH=0x1F -MMD -MP -MT $@ -MF $(@:%.o=%.d)
-
-%.o : $(SLOF_DIR)/lib/libnet/%.c
-	$(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,Compiling)
-
-libnet.a: $(LIBNETOBJS)
-	$(call quiet-command,$(AR) -rc $@ $^,Creating static library)
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index cf6859823a..27cbb354af 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -61,7 +61,52 @@ config-cc.mak: Makefile
 	    $(call cc-option,-march=z900,-march=z10)) 3> config-cc.mak
 -include config-cc.mak
 
-include $(SRC_PATH)/netboot.mak
+# libc files:
+
+LIBC_CFLAGS = $(EXTRA_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \
+	      -MMD -MP -MT $@ -MF $(@:%.o=%.d)
+
+CTYPE_OBJS = isdigit.o isxdigit.o toupper.o
+%.o : $(SLOF_DIR)/lib/libc/ctype/%.c
+	$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
+
+STRING_OBJS = strcat.o strchr.o strrchr.o strcpy.o strlen.o strncpy.o \
+	      strcmp.o strncmp.o strcasecmp.o strncasecmp.o strstr.o \
+	      memset.o memcpy.o memmove.o memcmp.o
+%.o : $(SLOF_DIR)/lib/libc/string/%.c
+	$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
+
+STDLIB_OBJS = atoi.o atol.o strtoul.o strtol.o rand.o malloc.o free.o
+%.o : $(SLOF_DIR)/lib/libc/stdlib/%.c
+	$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
+
+STDIO_OBJS = sprintf.o snprintf.o vfprintf.o vsnprintf.o vsprintf.o fprintf.o \
+	     printf.o putc.o puts.o putchar.o stdchnls.o fileno.o
+%.o : $(SLOF_DIR)/lib/libc/stdio/%.c
+	$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
+
+sbrk.o: $(SLOF_DIR)/slof/sbrk.c
+	$(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
+
+LIBCOBJS := $(STRING_OBJS) $(CTYPE_OBJS) $(STDLIB_OBJS) $(STDIO_OBJS) sbrk.o
+
+libc.a: $(LIBCOBJS)
+	$(call quiet-command,$(AR) -rc $@ $^,Creating static library)
+
+# libnet files:
+
+LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \
+	      dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o pxelinux.o
+LIBNETCFLAGS = $(EXTRA_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \
+	       -DDHCPARCH=0x1F -MMD -MP -MT $@ -MF $(@:%.o=%.d)
+
+%.o : $(SLOF_DIR)/lib/libnet/%.c
+	$(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,Compiling)
+
+libnet.a: $(LIBNETOBJS)
+	$(call quiet-command,$(AR) -rc $@ $^,Creating static library)
+
+# Main targets:
 
 build-all: s390-ccw.img
 
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 06/23] docs/system/s390x/bootdevices: Update the documentation about network booting
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (4 preceding siblings ...)
  2024-10-23 13:16 ` [PULL 05/23] pc-bios/s390-ccw: Merge netboot.mak into the main Makefile Thomas Huth
@ 2024-10-23 13:16 ` Thomas Huth
  2024-10-23 13:16 ` [PULL 07/23] pc-bios/s390-ccw: Remove panics from ISO IPL path Thomas Huth
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

Remove the information about the separate s390-netboot.img from
the documentation.

Co-authored by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Message-ID: <20241020012953.1380075-7-jrossi@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 docs/system/s390x/bootdevices.rst | 20 +++++++-------------
 1 file changed, 7 insertions(+), 13 deletions(-)

diff --git a/docs/system/s390x/bootdevices.rst b/docs/system/s390x/bootdevices.rst
index 1a7a18b43b..c97efb8fc0 100644
--- a/docs/system/s390x/bootdevices.rst
+++ b/docs/system/s390x/bootdevices.rst
@@ -82,23 +82,17 @@ Note that ``0`` can be used to boot the default entry.
 Booting from a network device
 -----------------------------
 
-Beside the normal guest firmware (which is loaded from the file ``s390-ccw.img``
-in the data directory of QEMU, or via the ``-bios`` option), QEMU ships with
-a small TFTP network bootloader firmware for virtio-net-ccw devices, too. This
-firmware is loaded from a file called ``s390-netboot.img`` in the QEMU data
-directory. In case you want to load it from a different filename instead,
-you can specify it via the ``-global s390-ipl.netboot_fw=filename``
-command line option.
-
-The ``bootindex`` property is especially important for booting via the network.
-If you don't specify the ``bootindex`` property here, the network bootloader
-firmware code won't get loaded into the guest memory so that the network boot
-will fail. For a successful network boot, try something like this::
+The firmware that ships with QEMU includes a small TFTP network bootloader
+for virtio-net-ccw devices.  The ``bootindex`` property is especially
+important for booting via the network. If you don't specify the ``bootindex``
+property here, the network bootloader won't be taken into consideration and
+the network boot will fail. For a successful network boot, try something
+like this::
 
  qemu-system-s390x -netdev user,id=n1,tftp=...,bootfile=... \
                    -device virtio-net-ccw,netdev=n1,bootindex=1
 
-The network bootloader firmware also has basic support for pxelinux.cfg-style
+The network bootloader also has basic support for pxelinux.cfg-style
 configuration files. See the `PXELINUX Configuration page
 <https://wiki.syslinux.org/wiki/index.php?title=PXELINUX#Configuration>`__
 for details how to set up the configuration file on your TFTP server.
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 07/23] pc-bios/s390-ccw: Remove panics from ISO IPL path
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (5 preceding siblings ...)
  2024-10-23 13:16 ` [PULL 06/23] docs/system/s390x/bootdevices: Update the documentation about network booting Thomas Huth
@ 2024-10-23 13:16 ` Thomas Huth
  2024-10-23 13:16 ` [PULL 08/23] pc-bios/s390-ccw: Remove panics from ECKD " Thomas Huth
                   ` (16 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

Remove panic-on-error from IPL ISO El Torito specific functions so that error
recovery may be possible in the future.

Functions that would previously panic now provide a return code.

Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20241020012953.1380075-8-jrossi@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/bootmap.h  | 15 +++----
 pc-bios/s390-ccw/s390-ccw.h |  1 +
 pc-bios/s390-ccw/bootmap.c  | 87 ++++++++++++++++++++++++-------------
 3 files changed, 65 insertions(+), 38 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index 4a7d8a91f1..3cb573b86b 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -385,17 +385,14 @@ static inline uint32_t iso_733_to_u32(uint64_t x)
 
 #define ISO_PRIMARY_VD_SECTOR 16
 
-static inline void read_iso_sector(uint32_t block_offset, void *buf,
-                                   const char *errmsg)
-{
-    IPL_assert(virtio_read_many(block_offset, buf, 1) == 0, errmsg);
-}
-
-static inline void read_iso_boot_image(uint32_t block_offset, void *load_addr,
+static inline int read_iso_boot_image(uint32_t block_offset, void *load_addr,
                                        uint32_t blks_to_load)
 {
-    IPL_assert(virtio_read_many(block_offset, load_addr, blks_to_load) == 0,
-               "Failed to read boot image!");
+    if (virtio_read_many(block_offset, load_addr, blks_to_load)) {
+        puts("Failed to read boot image!");
+        return -1;
+    }
+    return 0;
 }
 
 #define ISO9660_MAX_DIR_DEPTH 8
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 6abb34e563..3e844abd71 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -30,6 +30,7 @@ typedef unsigned long long u64;
 #define EIO     1
 #define EBUSY   2
 #define ENODEV  3
+#define EINVAL  4
 
 #ifndef MIN
 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 414c3f1b47..af73254acb 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -678,8 +678,10 @@ static bool is_iso_bc_entry_compatible(IsoBcSection *s)
     if (s->unused || !s->sector_count) {
         return false;
     }
-    read_iso_sector(bswap32(s->load_rba), magic_sec,
-                    "Failed to read image sector 0");
+    if (virtio_read(bswap32(s->load_rba), magic_sec)) {
+        puts("Failed to read image sector 0");
+        return false;
+    }
 
     /* Checking bytes 8 - 32 for S390 Linux magic */
     return !memcmp(magic_sec + 8, linux_s390_magic, 24);
@@ -692,28 +694,35 @@ static uint32_t sec_offset[ISO9660_MAX_DIR_DEPTH];
 /* Remained directory space in bytes */
 static uint32_t dir_rem[ISO9660_MAX_DIR_DEPTH];
 
-static inline uint32_t iso_get_file_size(uint32_t load_rba)
+static inline long iso_get_file_size(uint32_t load_rba)
 {
     IsoVolDesc *vd = (IsoVolDesc *)sec;
     IsoDirHdr *cur_record = &vd->vd.primary.rootdir;
     uint8_t *temp = sec + ISO_SECTOR_SIZE;
     int level = 0;
 
-    read_iso_sector(ISO_PRIMARY_VD_SECTOR, sec,
-                    "Failed to read ISO primary descriptor");
+    if (virtio_read(ISO_PRIMARY_VD_SECTOR, sec)) {
+        puts("Failed to read ISO primary descriptor");
+        return -EIO;
+    }
+
     sec_loc[0] = iso_733_to_u32(cur_record->ext_loc);
     dir_rem[0] = 0;
     sec_offset[0] = 0;
 
     while (level >= 0) {
-        IPL_assert(sec_offset[level] <= ISO_SECTOR_SIZE,
-                   "Directory tree structure violation");
+        if (sec_offset[level] > ISO_SECTOR_SIZE) {
+            puts("Directory tree structure violation");
+            return -EIO;
+        }
 
         cur_record = (IsoDirHdr *)(temp + sec_offset[level]);
 
         if (sec_offset[level] == 0) {
-            read_iso_sector(sec_loc[level], temp,
-                            "Failed to read ISO directory");
+            if (virtio_read(sec_loc[level], temp)) {
+                puts("Failed to read ISO directory");
+                return -EIO;
+            }
             if (dir_rem[level] == 0) {
                 /* Skip self and parent records */
                 dir_rem[level] = iso_733_to_u32(cur_record->data_len) -
@@ -758,8 +767,10 @@ static inline uint32_t iso_get_file_size(uint32_t load_rba)
         if (dir_rem[level] == 0) {
             /* Nothing remaining */
             level--;
-            read_iso_sector(sec_loc[level], temp,
-                            "Failed to read ISO directory");
+            if (virtio_read(sec_loc[level], temp)) {
+                puts("Failed to read ISO directory");
+                return -EIO;
+            }
         }
     }
 
@@ -774,19 +785,24 @@ static void load_iso_bc_entry(IsoBcSection *load)
      * is padded and ISO_SECTOR_SIZE bytes aligned
      */
     uint32_t blks_to_load = bswap16(s.sector_count) >> ET_SECTOR_SHIFT;
-    uint32_t real_size = iso_get_file_size(bswap32(s.load_rba));
+    long real_size = iso_get_file_size(bswap32(s.load_rba));
 
-    if (real_size) {
+    if (real_size > 0) {
         /* Round up blocks to load */
         blks_to_load = (real_size + ISO_SECTOR_SIZE - 1) / ISO_SECTOR_SIZE;
         puts("ISO boot image size verified");
     } else {
         puts("ISO boot image size could not be verified");
+        if (real_size < 0) {
+            return;
+        }
     }
 
-    read_iso_boot_image(bswap32(s.load_rba),
+    if (read_iso_boot_image(bswap32(s.load_rba),
                         (void *)((uint64_t)bswap16(s.load_segment)),
-                        blks_to_load);
+                        blks_to_load)) {
+        return;
+    }
 
     jump_to_low_kernel();
 }
@@ -809,17 +825,18 @@ static uint32_t find_iso_bc(void)
                 return bswap32(et->bc_offset);
             }
         }
-        read_iso_sector(block_num++, sec,
-                        "Failed to read ISO volume descriptor");
+        if (virtio_read(block_num++, sec)) {
+            puts("Failed to read ISO volume descriptor");
+            return 0;
+        }
     }
 
     return 0;
 }
 
-static IsoBcSection *find_iso_bc_entry(void)
+static IsoBcSection *find_iso_bc_entry(uint32_t offset)
 {
     IsoBcEntry *e = (IsoBcEntry *)sec;
-    uint32_t offset = find_iso_bc();
     int i;
     unsigned int loadparm = get_loadparm_index();
 
@@ -827,11 +844,13 @@ static IsoBcSection *find_iso_bc_entry(void)
         return NULL;
     }
 
-    read_iso_sector(offset, sec, "Failed to read El Torito boot catalog");
+    if (virtio_read(offset, sec)) {
+        puts("Failed to read El Torito boot catalog");
+        return NULL;
+    }
 
     if (!is_iso_bc_valid(e)) {
         /* The validation entry is mandatory */
-        panic("No valid boot catalog found!\n");
         return NULL;
     }
 
@@ -851,19 +870,25 @@ static IsoBcSection *find_iso_bc_entry(void)
         }
     }
 
-    panic("No suitable boot entry found on ISO-9660 media!\n");
-
     return NULL;
 }
 
-static void ipl_iso_el_torito(void)
+static int ipl_iso_el_torito(void)
 {
-    IsoBcSection *s = find_iso_bc_entry();
+    uint32_t offset = find_iso_bc();
+    if (!offset) {
+        return 0;
+    }
+
+    IsoBcSection *s = find_iso_bc_entry(offset);
 
     if (s) {
-        load_iso_bc_entry(s);
-        /* no return */
+        load_iso_bc_entry(s); /* only return in error */
+        return -1;
     }
+
+    puts("No suitable boot entry found on ISO-9660 media!");
+    return -EIO;
 }
 
 /**
@@ -893,7 +918,9 @@ static void zipl_load_vblk(void)
         if (blksize != VIRTIO_ISO_BLOCK_SIZE) {
             virtio_assume_iso9660();
         }
-        ipl_iso_el_torito();
+        if (ipl_iso_el_torito()) {
+            return;
+        }
     }
 
     if (blksize != VIRTIO_DASD_DEFAULT_BLOCK_SIZE) {
@@ -907,7 +934,9 @@ static void zipl_load_vscsi(void)
 {
     if (virtio_get_block_size() == VIRTIO_ISO_BLOCK_SIZE) {
         /* Is it an ISO image in non-CD drive? */
-        ipl_iso_el_torito();
+        if (ipl_iso_el_torito()) {
+            return;
+        }
     }
 
     puts("Using guessed DASD geometry.");
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 08/23] pc-bios/s390-ccw: Remove panics from ECKD IPL path
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (6 preceding siblings ...)
  2024-10-23 13:16 ` [PULL 07/23] pc-bios/s390-ccw: Remove panics from ISO IPL path Thomas Huth
@ 2024-10-23 13:16 ` Thomas Huth
  2024-10-23 13:16 ` [PULL 09/23] pc-bios/s390-ccw: Remove panics from SCSI " Thomas Huth
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

Remove panic-on-error from ECKD block device IPL specific functions so that
error recovery may be possible in the future.

Functions that would previously panic now provide a return code.

Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20241020012953.1380075-9-jrossi@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/bootmap.h |   1 +
 pc-bios/s390-ccw/bootmap.c | 187 +++++++++++++++++++++++++------------
 2 files changed, 130 insertions(+), 58 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index 3cb573b86b..95943441d3 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -16,6 +16,7 @@
 
 typedef uint64_t block_number_t;
 #define NULL_BLOCK_NR 0xffffffffffffffffULL
+#define ERROR_BLOCK_NR 0xfffffffffffffffeULL
 
 #define FREE_SPACE_FILLER '\xAA'
 
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index af73254acb..b9596e28c7 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -145,14 +145,17 @@ static block_number_t load_eckd_segments(block_number_t blk, bool ldipl,
     bool more_data;
 
     memset(_bprs, FREE_SPACE_FILLER, sizeof(_bprs));
-    read_block(blk, bprs, "BPRS read failed");
+    if (virtio_read(blk, bprs)) {
+        puts("BPRS read failed");
+        return ERROR_BLOCK_NR;
+    }
 
     do {
         more_data = false;
         for (j = 0;; j++) {
             block_nr = gen_eckd_block_num(&bprs[j].xeckd, ldipl);
             if (is_null_block_number(block_nr)) { /* end of chunk */
-                break;
+                return NULL_BLOCK_NR;
             }
 
             /* we need the updated blockno for the next indirect entry
@@ -163,15 +166,20 @@ static block_number_t load_eckd_segments(block_number_t blk, bool ldipl,
             }
 
             /* List directed pointer does not store block size */
-            IPL_assert(ldipl || block_size_ok(bprs[j].xeckd.bptr.size),
-                       "bad chunk block size");
+            if (!ldipl && !block_size_ok(bprs[j].xeckd.bptr.size)) {
+                puts("Bad chunk block size");
+                return ERROR_BLOCK_NR;
+            }
 
             if (!eckd_valid_address(&bprs[j].xeckd, ldipl)) {
                 /*
                  * If an invalid address is found during LD-IPL then break and
-                 * retry as CCW
+                 * retry as CCW-IPL, otherwise abort on error
                  */
-                IPL_assert(ldipl, "bad chunk ECKD addr");
+                if (!ldipl) {
+                    puts("Bad chunk ECKD address");
+                    return ERROR_BLOCK_NR;
+                }
                 break;
             }
 
@@ -189,7 +197,10 @@ static block_number_t load_eckd_segments(block_number_t blk, bool ldipl,
                  * I.e. the next ptr must point to the unused memory area
                  */
                 memset(_bprs, FREE_SPACE_FILLER, sizeof(_bprs));
-                read_block(block_nr, bprs, "BPRS continuation read failed");
+                if (virtio_read(block_nr, bprs)) {
+                    puts("BPRS continuation read failed");
+                    return ERROR_BLOCK_NR;
+                }
                 more_data = true;
                 break;
             }
@@ -198,7 +209,10 @@ static block_number_t load_eckd_segments(block_number_t blk, bool ldipl,
              * to memory (address).
              */
             rc = virtio_read_many(block_nr, (void *)(*address), count + 1);
-            IPL_assert(rc == 0, "code chunk read failed");
+            if (rc != 0) {
+                puts("Code chunk read failed");
+                return ERROR_BLOCK_NR;
+            }
 
             *address += (count + 1) * virtio_get_block_size();
         }
@@ -232,7 +246,10 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
 
     /* Get Stage1b data */
     memset(sec, FREE_SPACE_FILLER, sizeof(sec));
-    read_block(s1b_block_nr, s1b, "Cannot read stage1b boot loader");
+    if (virtio_read(s1b_block_nr, s1b)) {
+        puts("Cannot read stage1b boot loader");
+        return -EIO;
+    }
 
     memset(_s2, FREE_SPACE_FILLER, sizeof(_s2));
 
@@ -244,7 +261,10 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
             break;
         }
 
-        read_block(cur_block_nr, s2_cur_blk, "Cannot read stage2 boot loader");
+        if (virtio_read(cur_block_nr, s2_cur_blk)) {
+            puts("Cannot read stage2 boot loader");
+            return -EIO;
+        }
 
         if (find_zipl_boot_menu_banner(&banner_offset)) {
             /*
@@ -252,8 +272,10 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
              * possibility of menu data spanning multiple blocks.
              */
             if (prev_block_nr) {
-                read_block(prev_block_nr, s2_prev_blk,
-                           "Cannot read stage2 boot loader");
+                if (virtio_read(prev_block_nr, s2_prev_blk)) {
+                    puts("Cannot read stage2 boot loader");
+                    return -EIO;
+                }
             }
 
             if (i + 1 < STAGE2_BLK_CNT_MAX) {
@@ -261,8 +283,10 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
             }
 
             if (next_block_nr && !is_null_block_number(next_block_nr)) {
-                read_block(next_block_nr, s2_next_blk,
-                           "Cannot read stage2 boot loader");
+                if (virtio_read(next_block_nr, s2_next_blk)) {
+                    puts("Cannot read stage2 boot loader");
+                    return -EIO;
+                }
             }
 
             return menu_get_zipl_boot_index(s2_cur_blk + banner_offset);
@@ -275,7 +299,7 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
     return 0;
 }
 
-static void run_eckd_boot_script(block_number_t bmt_block_nr,
+static int run_eckd_boot_script(block_number_t bmt_block_nr,
                                  block_number_t s1b_block_nr)
 {
     int i;
@@ -292,17 +316,28 @@ static void run_eckd_boot_script(block_number_t bmt_block_nr,
     }
 
     debug_print_int("loadparm", loadparm);
-    IPL_assert(loadparm < MAX_BOOT_ENTRIES, "loadparm value greater than"
-               " maximum number of boot entries allowed");
+    if (loadparm >= MAX_BOOT_ENTRIES) {
+        puts("loadparm value greater than max number of boot entries allowed");
+        return -EINVAL;
+    }
 
     memset(sec, FREE_SPACE_FILLER, sizeof(sec));
-    read_block(bmt_block_nr, sec, "Cannot read Boot Map Table");
+    if (virtio_read(bmt_block_nr, sec)) {
+        puts("Cannot read Boot Map Table");
+        return -EIO;
+    }
 
     block_nr = gen_eckd_block_num(&bmt->entry[loadparm].xeckd, ldipl);
-    IPL_assert(block_nr != -1, "Cannot find Boot Map Table Entry");
+    if (block_nr == NULL_BLOCK_NR) {
+        puts("Cannot find Boot Map Table Entry");
+        return -EIO;
+    }
 
     memset(sec, FREE_SPACE_FILLER, sizeof(sec));
-    read_block(block_nr, sec, "Cannot read Boot Map Script");
+    if (virtio_read(block_nr, sec)) {
+        puts("Cannot read Boot Map Script");
+        return -EIO;
+    }
 
     for (i = 0; bms->entry[i].type == BOOT_SCRIPT_LOAD ||
                 bms->entry[i].type == BOOT_SCRIPT_SIGNATURE; i++) {
@@ -317,21 +352,27 @@ static void run_eckd_boot_script(block_number_t bmt_block_nr,
 
         do {
             block_nr = load_eckd_segments(block_nr, ldipl, &address);
-        } while (block_nr != -1);
+            if (block_nr == ERROR_BLOCK_NR) {
+                return ldipl ? 0 : -EIO;
+            }
+        } while (block_nr != NULL_BLOCK_NR);
     }
 
     if (ldipl && bms->entry[i].type != BOOT_SCRIPT_EXEC) {
         /* Abort LD-IPL and retry as CCW-IPL */
-        return;
+        return 0;
     }
 
-    IPL_assert(bms->entry[i].type == BOOT_SCRIPT_EXEC,
-               "Unknown script entry type");
+    if (bms->entry[i].type != BOOT_SCRIPT_EXEC) {
+        puts("Unknown script entry type");
+        return -EINVAL;
+    }
     write_reset_psw(bms->entry[i].address.load_address); /* no return */
     jump_to_IPL_code(0); /* no return */
+    return -1;
 }
 
-static void ipl_eckd_cdl(void)
+static int ipl_eckd_cdl(void)
 {
     XEckdMbr *mbr;
     EckdCdlIpl2 *ipl2 = (void *)sec;
@@ -342,20 +383,23 @@ static void ipl_eckd_cdl(void)
     puts("CDL");
 
     memset(sec, FREE_SPACE_FILLER, sizeof(sec));
-    read_block(1, ipl2, "Cannot read IPL2 record at block 1");
+    if (virtio_read(1, ipl2)) {
+        puts("Cannot read IPL2 record at block 1");
+        return -EIO;
+    }
 
     mbr = &ipl2->mbr;
     if (!magic_match(mbr, ZIPL_MAGIC)) {
         puts("No zIPL section in IPL2 record.");
-        return;
+        return 0;
     }
     if (!block_size_ok(mbr->blockptr.xeckd.bptr.size)) {
         puts("Bad block size in zIPL section of IPL2 record.");
-        return;
+        return 0;
     }
     if (mbr->dev_type != DEV_TYPE_ECKD) {
         puts("Non-ECKD device type in zIPL section of IPL2 record.");
-        return;
+        return 0;
     }
 
     /* save pointer to Boot Map Table */
@@ -365,19 +409,21 @@ static void ipl_eckd_cdl(void)
     s1b_block_nr = eckd_block_num(&ipl2->stage1.seek[0].chs);
 
     memset(sec, FREE_SPACE_FILLER, sizeof(sec));
-    read_block(2, vlbl, "Cannot read Volume Label at block 2");
+    if (virtio_read(2, vlbl)) {
+        puts("Cannot read Volume Label at block 2");
+        return -EIO;
+    }
     if (!magic_match(vlbl->key, VOL1_MAGIC)) {
         puts("Invalid magic of volume label block.");
-        return;
+        return 0;
     }
     if (!magic_match(vlbl->f.key, VOL1_MAGIC)) {
         puts("Invalid magic of volser block.");
-        return;
+        return 0;
     }
     print_volser(vlbl->f.volser);
 
-    run_eckd_boot_script(bmt_block_nr, s1b_block_nr);
-    /* no return */
+    return run_eckd_boot_script(bmt_block_nr, s1b_block_nr);
 }
 
 static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
@@ -403,7 +449,7 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
     print_volser(vlbl->volser);
 }
 
-static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
+static int ipl_eckd_ldl(ECKD_IPL_mode_t mode)
 {
     block_number_t bmt_block_nr, s1b_block_nr;
     EckdLdlIpl1 *ipl1 = (void *)sec;
@@ -415,10 +461,13 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
     /* DO NOT read BootMap pointer (only one, xECKD) at block #2 */
 
     memset(sec, FREE_SPACE_FILLER, sizeof(sec));
-    read_block(0, sec, "Cannot read block 0 to grab boot info.");
+    if (virtio_read(0, sec)) {
+        puts("Cannot read block 0 to grab boot info.");
+        return -EIO;
+    }
     if (mode == ECKD_LDL_UNLABELED) {
         if (!magic_match(ipl1->bip.magic, ZIPL_MAGIC)) {
-            return; /* not applicable layout */
+            return 0; /* not applicable layout */
         }
         puts("unlabeled LDL.");
     }
@@ -430,8 +479,7 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
     /* save pointer to Stage1b Data */
     s1b_block_nr = eckd_block_num(&ipl1->stage1.seek[0].chs);
 
-    run_eckd_boot_script(bmt_block_nr, s1b_block_nr);
-    /* no return */
+    return run_eckd_boot_script(bmt_block_nr, s1b_block_nr);
 }
 
 static block_number_t eckd_find_bmt(ExtEckdBlockPtr *ptr)
@@ -441,7 +489,10 @@ static block_number_t eckd_find_bmt(ExtEckdBlockPtr *ptr)
     BootRecord *br;
 
     blockno = gen_eckd_block_num(ptr, 0);
-    read_block(blockno, tmp_sec, "Cannot read boot record");
+    if (virtio_read(blockno, tmp_sec)) {
+        puts("Cannot read boot record");
+        return ERROR_BLOCK_NR;
+    }
     br = (BootRecord *)tmp_sec;
     if (!magic_match(br->magic, ZIPL_MAGIC)) {
         /* If the boot record is invalid, return and try CCW-IPL instead */
@@ -470,7 +521,7 @@ static void print_eckd_msg(void)
     printf("%s", msg);
 }
 
-static void ipl_eckd(void)
+static int ipl_eckd(void)
 {
     IplVolumeLabel *vlbl = (void *)sec;
     LDL_VTOC *vtoc = (void *)sec;
@@ -480,7 +531,10 @@ static void ipl_eckd(void)
 
     /* Block 2 can contain either the CDL VOL1 label or the LDL VTOC */
     memset(sec, FREE_SPACE_FILLER, sizeof(sec));
-    read_block(2, vlbl, "Cannot read block 2");
+    if (virtio_read(2, vlbl)) {
+        puts("Cannot read block 2");
+        return -EIO;
+    }
 
     /*
      * First check for a list-directed-format pointer which would
@@ -488,36 +542,53 @@ static void ipl_eckd(void)
      */
     if (eckd_valid_address((ExtEckdBlockPtr *)&vlbl->f.br, 0)) {
         ldipl_bmt = eckd_find_bmt((ExtEckdBlockPtr *)&vlbl->f.br);
-        if (ldipl_bmt) {
+        switch (ldipl_bmt) {
+        case ERROR_BLOCK_NR:
+            return -EIO;
+        case NULL_BLOCK_NR:
+            break; /* Invalid BMT but the device may still boot with CCW-IPL */
+        default:
             puts("List-Directed");
-            /* LD-IPL does not use the S1B bock, just make it NULL */
-            run_eckd_boot_script(ldipl_bmt, NULL_BLOCK_NR);
-            /* Only return in error, retry as CCW-IPL */
+            /*
+             * LD-IPL does not use the S1B bock, just make it NULL_BLOCK_NR.
+             * In some failure cases retry IPL before aborting.
+             */
+            if (run_eckd_boot_script(ldipl_bmt, NULL_BLOCK_NR)) {
+                return -EIO;
+            }
+            /* Non-fatal error, retry as CCW-IPL */
             printf("Retrying IPL ");
             print_eckd_msg();
         }
         memset(sec, FREE_SPACE_FILLER, sizeof(sec));
-        read_block(2, vtoc, "Cannot read block 2");
+        if (virtio_read(2, vtoc)) {
+            puts("Cannot read block 2");
+            return -EIO;
+        }
     }
 
     /* Not list-directed */
     if (magic_match(vtoc->magic, VOL1_MAGIC)) {
-        ipl_eckd_cdl(); /* may return in error */
+        if (ipl_eckd_cdl()) {
+            return -1;
+        }
     }
 
     if (magic_match(vtoc->magic, CMS1_MAGIC)) {
-        ipl_eckd_ldl(ECKD_CMS); /* no return */
+        return ipl_eckd_ldl(ECKD_CMS);
     }
     if (magic_match(vtoc->magic, LNX1_MAGIC)) {
-        ipl_eckd_ldl(ECKD_LDL); /* no return */
+        return ipl_eckd_ldl(ECKD_LDL);
     }
 
-    ipl_eckd_ldl(ECKD_LDL_UNLABELED); /* it still may return */
+    if (ipl_eckd_ldl(ECKD_LDL_UNLABELED)) {
+        return -1;
+    }
     /*
      * Ok, it is not a LDL by any means.
      * It still might be a CDL with zero record keys for IPL1 and IPL2
      */
-    ipl_eckd_cdl();
+    return ipl_eckd_cdl();
 }
 
 /***********************************************************************
@@ -910,7 +981,7 @@ static bool has_iso_signature(void)
  * Bus specific IPL sequences
  */
 
-static void zipl_load_vblk(void)
+static int zipl_load_vblk(void)
 {
     int blksize = virtio_get_block_size();
 
@@ -919,7 +990,7 @@ static void zipl_load_vblk(void)
             virtio_assume_iso9660();
         }
         if (ipl_iso_el_torito()) {
-            return;
+            return 0;
         }
     }
 
@@ -927,21 +998,21 @@ static void zipl_load_vblk(void)
         puts("Using guessed DASD geometry.");
         virtio_assume_eckd();
     }
-    ipl_eckd();
+    return ipl_eckd();
 }
 
-static void zipl_load_vscsi(void)
+static int zipl_load_vscsi(void)
 {
     if (virtio_get_block_size() == VIRTIO_ISO_BLOCK_SIZE) {
         /* Is it an ISO image in non-CD drive? */
         if (ipl_iso_el_torito()) {
-            return;
+            return 0;
         }
     }
 
     puts("Using guessed DASD geometry.");
     virtio_assume_eckd();
-    ipl_eckd();
+    return ipl_eckd();
 }
 
 /***********************************************************************
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 09/23] pc-bios/s390-ccw: Remove panics from SCSI IPL path
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (7 preceding siblings ...)
  2024-10-23 13:16 ` [PULL 08/23] pc-bios/s390-ccw: Remove panics from ECKD " Thomas Huth
@ 2024-10-23 13:16 ` Thomas Huth
  2024-10-23 13:16 ` [PULL 10/23] pc-bios/s390-ccw: Remove panics from DASD " Thomas Huth
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

Remove panic-on-error from virtio-scsi IPL specific functions so that error
recovery may be possible in the future.

Functions that would previously panic now provide a return code.

Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20241020012953.1380075-10-jrossi@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/bootmap.c       |  88 ++++++++++++++-----
 pc-bios/s390-ccw/virtio-blkdev.c |   4 +-
 pc-bios/s390-ccw/virtio-scsi.c   | 143 +++++++++++++++++++++----------
 3 files changed, 164 insertions(+), 71 deletions(-)

diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index b9596e28c7..652807a16a 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -595,7 +595,7 @@ static int ipl_eckd(void)
  * IPL a SCSI disk
  */
 
-static void zipl_load_segment(ComponentEntry *entry)
+static int zipl_load_segment(ComponentEntry *entry)
 {
     const int max_entries = (MAX_SECTOR_SIZE / sizeof(ScsiBlockPtr));
     ScsiBlockPtr *bprs = (void *)sec;
@@ -615,7 +615,10 @@ static void zipl_load_segment(ComponentEntry *entry)
     do {
         memset(bprs, FREE_SPACE_FILLER, bprs_size);
         fill_hex_val(blk_no, &blockno, sizeof(blockno));
-        read_block(blockno, bprs, err_msg);
+        if (virtio_read(blockno, bprs)) {
+            puts(err_msg);
+            return -EIO;
+        }
 
         for (i = 0;; i++) {
             uint64_t *cur_desc = (void *)&bprs[i];
@@ -643,23 +646,37 @@ static void zipl_load_segment(ComponentEntry *entry)
             }
             address = virtio_load_direct(cur_desc[0], cur_desc[1], 0,
                                          (void *)address);
-            IPL_assert(address != -1, "zIPL load segment failed");
+            if (!address) {
+                puts("zIPL load segment failed");
+                return -EIO;
+            }
         }
     } while (blockno);
+
+    return 0;
 }
 
 /* Run a zipl program */
-static void zipl_run(ScsiBlockPtr *pte)
+static int zipl_run(ScsiBlockPtr *pte)
 {
     ComponentHeader *header;
     ComponentEntry *entry;
     uint8_t tmp_sec[MAX_SECTOR_SIZE];
 
-    read_block(pte->blockno, tmp_sec, "Cannot read header");
+    if (virtio_read(pte->blockno, tmp_sec)) {
+        puts("Cannot read header");
+        return -EIO;
+    }
     header = (ComponentHeader *)tmp_sec;
 
-    IPL_assert(magic_match(tmp_sec, ZIPL_MAGIC), "No zIPL magic in header");
-    IPL_assert(header->type == ZIPL_COMP_HEADER_IPL, "Bad header type");
+    if (!magic_match(tmp_sec, ZIPL_MAGIC)) {
+        puts("No zIPL magic in header");
+        return -EINVAL;
+    }
+    if (header->type != ZIPL_COMP_HEADER_IPL) {
+        puts("Bad header type");
+        return -EINVAL;
+    }
 
     dputs("start loading images\n");
 
@@ -674,22 +691,30 @@ static void zipl_run(ScsiBlockPtr *pte)
             continue;
         }
 
-        zipl_load_segment(entry);
+        if (zipl_load_segment(entry)) {
+            return -1;
+        }
 
         entry++;
 
-        IPL_assert((uint8_t *)(&entry[1]) <= (tmp_sec + MAX_SECTOR_SIZE),
-                   "Wrong entry value");
+        if ((uint8_t *)(&entry[1]) > (tmp_sec + MAX_SECTOR_SIZE)) {
+            puts("Wrong entry value");
+            return -EINVAL;
+        }
     }
 
-    IPL_assert(entry->component_type == ZIPL_COMP_ENTRY_EXEC, "No EXEC entry");
+    if (entry->component_type != ZIPL_COMP_ENTRY_EXEC) {
+        puts("No EXEC entry");
+        return -EINVAL;
+    }
 
     /* should not return */
     write_reset_psw(entry->compdat.load_psw);
     jump_to_IPL_code(0);
+    return -1;
 }
 
-static void ipl_scsi(void)
+static int ipl_scsi(void)
 {
     ScsiMbr *mbr = (void *)sec;
     int program_table_entries = 0;
@@ -700,10 +725,13 @@ static void ipl_scsi(void)
 
     /* Grab the MBR */
     memset(sec, FREE_SPACE_FILLER, sizeof(sec));
-    read_block(0, mbr, "Cannot read block 0");
+    if (virtio_read(0, mbr)) {
+        puts("Cannot read block 0");
+        return -EIO;
+    }
 
     if (!magic_match(mbr->magic, ZIPL_MAGIC)) {
-        return;
+        return 0;
     }
 
     puts("Using SCSI scheme.");
@@ -711,11 +739,20 @@ static void ipl_scsi(void)
     IPL_check(mbr->version_id == 1,
               "Unknown MBR layout version, assuming version 1");
     debug_print_int("program table", mbr->pt.blockno);
-    IPL_assert(mbr->pt.blockno, "No Program Table");
+    if (!mbr->pt.blockno) {
+        puts("No Program Table");
+        return -EINVAL;
+    }
 
     /* Parse the program table */
-    read_block(mbr->pt.blockno, sec, "Error reading Program Table");
-    IPL_assert(magic_match(sec, ZIPL_MAGIC), "No zIPL magic in PT");
+    if (virtio_read(mbr->pt.blockno, sec)) {
+        puts("Error reading Program Table");
+        return -EIO;
+    }
+    if (!magic_match(sec, ZIPL_MAGIC)) {
+        puts("No zIPL magic in Program Table");
+        return -EINVAL;
+    }
 
     for (i = 0; i < MAX_BOOT_ENTRIES; i++) {
         if (prog_table->entry[i].scsi.blockno) {
@@ -725,17 +762,22 @@ static void ipl_scsi(void)
     }
 
     debug_print_int("program table entries", program_table_entries);
-    IPL_assert(program_table_entries != 0, "Empty Program Table");
+    if (program_table_entries == 0) {
+        puts("Empty Program Table");
+        return -EINVAL;
+    }
 
     if (menu_is_enabled_enum()) {
         loadparm = menu_get_enum_boot_index(valid_entries);
     }
 
     debug_print_int("loadparm", loadparm);
-    IPL_assert(loadparm < MAX_BOOT_ENTRIES, "loadparm value greater than"
-               " maximum number of boot entries allowed");
+    if (loadparm >= MAX_BOOT_ENTRIES) {
+        puts("loadparm value greater than max number of boot entries allowed");
+        return -EINVAL;
+    }
 
-    zipl_run(&prog_table->entry[loadparm].scsi); /* no return */
+    return zipl_run(&prog_table->entry[loadparm].scsi);
 }
 
 /***********************************************************************
@@ -1032,7 +1074,9 @@ void zipl_load(void)
         netmain();
     }
 
-    ipl_scsi();
+    if (ipl_scsi()) {
+        panic("\n! Cannot IPL this SCSI device !\n");
+    }
 
     switch (virtio_get_device_type()) {
     case VIRTIO_ID_BLOCK:
diff --git a/pc-bios/s390-ccw/virtio-blkdev.c b/pc-bios/s390-ccw/virtio-blkdev.c
index 2666326801..1c585f034b 100644
--- a/pc-bios/s390-ccw/virtio-blkdev.c
+++ b/pc-bios/s390-ccw/virtio-blkdev.c
@@ -73,13 +73,13 @@ unsigned long virtio_load_direct(unsigned long rec_list1, unsigned long rec_list
     unsigned long addr = (unsigned long)load_addr;
 
     if (sec_len != virtio_get_block_size()) {
-        return -1;
+        return 0;
     }
 
     printf(".");
     status = virtio_read_many(sec, (void *)addr, sec_num);
     if (status) {
-        panic("I/O Error");
+        return 0;
     }
     addr += sec_num * virtio_get_block_size();
 
diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c
index 6b4a1caf8a..71db75ce7b 100644
--- a/pc-bios/s390-ccw/virtio-scsi.c
+++ b/pc-bios/s390-ccw/virtio-scsi.c
@@ -26,7 +26,7 @@ static uint8_t scsi_inquiry_std_response[256];
 static ScsiInquiryEvpdPages scsi_inquiry_evpd_pages_response;
 static ScsiInquiryEvpdBl scsi_inquiry_evpd_bl_response;
 
-static inline void vs_assert(bool term, const char **msgs)
+static inline bool vs_assert(bool term, const char **msgs)
 {
     if (!term) {
         int i = 0;
@@ -35,11 +35,13 @@ static inline void vs_assert(bool term, const char **msgs)
         while (msgs[i]) {
             printf("%s", msgs[i++]);
         }
-        panic(" !\n");
+        puts(" !");
     }
+
+    return term;
 }
 
-static void virtio_scsi_verify_response(VirtioScsiCmdResp *resp,
+static bool virtio_scsi_verify_response(VirtioScsiCmdResp *resp,
                                         const char *title)
 {
     const char *mr[] = {
@@ -56,8 +58,8 @@ static void virtio_scsi_verify_response(VirtioScsiCmdResp *resp,
         0
     };
 
-    vs_assert(resp->response == VIRTIO_SCSI_S_OK, mr);
-    vs_assert(resp->status == CDB_STATUS_GOOD, ms);
+    return vs_assert(resp->response == VIRTIO_SCSI_S_OK, mr) &&
+           vs_assert(resp->status == CDB_STATUS_GOOD, ms);
 }
 
 static void prepare_request(VDev *vdev, const void *cdb, int cdb_size,
@@ -78,24 +80,31 @@ static void prepare_request(VDev *vdev, const void *cdb, int cdb_size,
     }
 }
 
-static inline void vs_io_assert(bool term, const char *msg)
+static inline bool vs_io_assert(bool term, const char *msg)
 {
-    if (!term) {
-        virtio_scsi_verify_response(&resp, msg);
+    if (!term && !virtio_scsi_verify_response(&resp, msg)) {
+        return false;
     }
+
+    return true;
 }
 
-static void vs_run(const char *title, VirtioCmd *cmd, VDev *vdev,
+static int vs_run(const char *title, VirtioCmd *cmd, VDev *vdev,
                    const void *cdb, int cdb_size,
                    void *data, uint32_t data_size)
 {
     prepare_request(vdev, cdb, cdb_size, data, data_size);
-    vs_io_assert(virtio_run(vdev, VR_REQUEST, cmd) == 0, title);
+    if (!vs_io_assert(virtio_run(vdev, VR_REQUEST, cmd) == 0, title)) {
+        puts(title);
+        return -EIO;
+    }
+
+    return 0;
 }
 
 /* SCSI protocol implementation routines */
 
-static bool scsi_inquiry(VDev *vdev, uint8_t evpd, uint8_t page,
+static int scsi_inquiry(VDev *vdev, uint8_t evpd, uint8_t page,
                          void *data, uint32_t data_size)
 {
     ScsiCdbInquiry cdb = {
@@ -110,12 +119,13 @@ static bool scsi_inquiry(VDev *vdev, uint8_t evpd, uint8_t page,
         { data, data_size, VRING_DESC_F_WRITE },
     };
 
-    vs_run("inquiry", inquiry, vdev, &cdb, sizeof(cdb), data, data_size);
+    int ret = vs_run("inquiry", inquiry,
+                     vdev, &cdb, sizeof(cdb), data, data_size);
 
-    return virtio_scsi_response_ok(&resp);
+    return ret ? ret : virtio_scsi_response_ok(&resp);
 }
 
-static bool scsi_test_unit_ready(VDev *vdev)
+static int scsi_test_unit_ready(VDev *vdev)
 {
     ScsiCdbTestUnitReady cdb = {
         .command = 0x00,
@@ -131,7 +141,7 @@ static bool scsi_test_unit_ready(VDev *vdev)
     return virtio_scsi_response_ok(&resp);
 }
 
-static bool scsi_report_luns(VDev *vdev, void *data, uint32_t data_size)
+static int scsi_report_luns(VDev *vdev, void *data, uint32_t data_size)
 {
     ScsiCdbReportLuns cdb = {
         .command = 0xa0,
@@ -144,13 +154,13 @@ static bool scsi_report_luns(VDev *vdev, void *data, uint32_t data_size)
         { data, data_size, VRING_DESC_F_WRITE },
     };
 
-    vs_run("report luns", report_luns,
+    int ret = vs_run("report luns", report_luns,
            vdev, &cdb, sizeof(cdb), data, data_size);
 
-    return virtio_scsi_response_ok(&resp);
+    return ret ? ret : virtio_scsi_response_ok(&resp);
 }
 
-static bool scsi_read_10(VDev *vdev,
+static int scsi_read_10(VDev *vdev,
                          unsigned long sector, int sectors, void *data,
                          unsigned int data_size)
 {
@@ -168,12 +178,13 @@ static bool scsi_read_10(VDev *vdev,
     debug_print_int("read_10  sector", sector);
     debug_print_int("read_10 sectors", sectors);
 
-    vs_run("read(10)", read_10, vdev, &cdb, sizeof(cdb), data, data_size);
+    int ret = vs_run("read(10)", read_10,
+            vdev, &cdb, sizeof(cdb), data, data_size);
 
-    return virtio_scsi_response_ok(&resp);
+    return ret ? ret : virtio_scsi_response_ok(&resp);
 }
 
-static bool scsi_read_capacity(VDev *vdev,
+static int scsi_read_capacity(VDev *vdev,
                                void *data, uint32_t data_size)
 {
     ScsiCdbReadCapacity16 cdb = {
@@ -187,10 +198,10 @@ static bool scsi_read_capacity(VDev *vdev,
         { data, data_size, VRING_DESC_F_WRITE },
     };
 
-    vs_run("read capacity", read_capacity_16,
+    int ret = vs_run("read capacity", read_capacity_16,
            vdev, &cdb, sizeof(cdb), data, data_size);
 
-    return virtio_scsi_response_ok(&resp);
+    return ret ? ret : virtio_scsi_response_ok(&resp);
 }
 
 /* virtio-scsi routines */
@@ -207,7 +218,7 @@ static int virtio_scsi_locate_device(VDev *vdev)
     static uint8_t data[16 + 8 * 63];
     ScsiLunReport *r = (void *) data;
     ScsiDevice *sdev = vdev->scsi_device;
-    int i, luns;
+    int i, ret, luns;
 
     /* QEMU has hardcoded channel #0 in many places.
      * If this hardcoded value is ever changed, we'll need to add code for
@@ -233,13 +244,21 @@ static int virtio_scsi_locate_device(VDev *vdev)
         sdev->channel = channel;
         sdev->target = target;
         sdev->lun = 0;          /* LUN has to be 0 for REPORT LUNS */
-        if (!scsi_report_luns(vdev, data, sizeof(data))) {
+        ret = scsi_report_luns(vdev, data, sizeof(data));
+        if (ret < 0) {
+            return ret;
+        }
+
+        else if (ret == 0) {
             if (resp.response == VIRTIO_SCSI_S_BAD_TARGET) {
                 continue;
             }
             printf("target 0x%X\n", target);
-            virtio_scsi_verify_response(&resp, "SCSI cannot report LUNs");
+            if (!virtio_scsi_verify_response(&resp, "SCSI cannot report LUNs")) {
+                return -EIO;
+            }
         }
+
         if (r->lun_list_len == 0) {
             printf("no LUNs for target 0x%X\n", target);
             continue;
@@ -283,7 +302,9 @@ int virtio_scsi_read_many(VDev *vdev,
         data_size = sector_count * virtio_get_block_size() * f;
         if (!scsi_read_10(vdev, sector * f, sector_count * f, load_addr,
                           data_size)) {
-            virtio_scsi_verify_response(&resp, "virtio-scsi:read_many");
+            if (!virtio_scsi_verify_response(&resp, "virtio-scsi:read_many")) {
+                return -1;
+            }
         }
         load_addr += data_size;
         sector += sector_count;
@@ -352,11 +373,16 @@ static int virtio_scsi_setup(VDev *vdev)
             uint8_t code = resp.sense[0] & SCSI_SENSE_CODE_MASK;
             uint8_t sense_key = resp.sense[2] & SCSI_SENSE_KEY_MASK;
 
-            IPL_assert(resp.sense_len != 0, "virtio-scsi:setup: no SENSE data");
+            if (resp.sense_len == 0) {
+                puts("virtio-scsi: setup: no SENSE data");
+                return -EINVAL;
+            }
 
-            IPL_assert(retry_test_unit_ready && code == 0x70 &&
-                       sense_key == SCSI_SENSE_KEY_UNIT_ATTENTION,
-                       "virtio-scsi:setup: cannot retry");
+            if (!retry_test_unit_ready || code != 0x70 ||
+                       sense_key != SCSI_SENSE_KEY_UNIT_ATTENTION) {
+                puts("virtio-scsi:setup: cannot retry");
+                return -EIO;
+            }
 
             /* retry on CHECK_CONDITION/UNIT_ATTENTION as it
              * may not designate a real error, but it may be
@@ -367,16 +393,22 @@ static int virtio_scsi_setup(VDev *vdev)
             continue;
         }
 
-        virtio_scsi_verify_response(&resp, "virtio-scsi:setup");
+        if (!virtio_scsi_verify_response(&resp, "virtio-scsi:setup")) {
+            return -1;
+        }
     }
 
     /* read and cache SCSI INQUIRY response */
-    if (!scsi_inquiry(vdev,
+    ret = scsi_inquiry(vdev,
                       SCSI_INQUIRY_STANDARD,
                       SCSI_INQUIRY_STANDARD_NONE,
                       scsi_inquiry_std_response,
-                      sizeof(scsi_inquiry_std_response))) {
-        virtio_scsi_verify_response(&resp, "virtio-scsi:setup:inquiry");
+                      sizeof(scsi_inquiry_std_response));
+    if (ret < 1) {
+        if (ret != 0 || !virtio_scsi_verify_response(&resp,
+                "virtio-scsi:setup:inquiry")) {
+            return -1;
+        }
     }
 
     if (virtio_scsi_inquiry_response_is_cdrom(scsi_inquiry_std_response)) {
@@ -385,12 +417,16 @@ static int virtio_scsi_setup(VDev *vdev)
         vdev->scsi_block_size = VIRTIO_ISO_BLOCK_SIZE;
     }
 
-    if (!scsi_inquiry(vdev,
+    ret = scsi_inquiry(vdev,
                       SCSI_INQUIRY_EVPD,
                       SCSI_INQUIRY_EVPD_SUPPORTED_PAGES,
                       evpd,
-                      sizeof(*evpd))) {
-        virtio_scsi_verify_response(&resp, "virtio-scsi:setup:supported_pages");
+                      sizeof(*evpd));
+    if (ret < 1) {
+        if (ret != 0 || !virtio_scsi_verify_response(&resp,
+                "virtio-scsi:setup:supported_pages")) {
+            return -1;
+        }
     }
 
     debug_print_int("EVPD length", evpd->page_length);
@@ -402,12 +438,16 @@ static int virtio_scsi_setup(VDev *vdev)
             continue;
         }
 
-        if (!scsi_inquiry(vdev,
+        ret = scsi_inquiry(vdev,
                           SCSI_INQUIRY_EVPD,
                           SCSI_INQUIRY_EVPD_BLOCK_LIMITS,
                           evpd_bl,
-                          sizeof(*evpd_bl))) {
-            virtio_scsi_verify_response(&resp, "virtio-scsi:setup:blocklimits");
+                          sizeof(*evpd_bl));
+        if (ret < 1) {
+            if (ret != 0 || !virtio_scsi_verify_response(&resp,
+                    "virtio-scsi:setup:blocklimits")) {
+                return -1;
+            }
         }
 
         debug_print_int("max transfer", evpd_bl->max_transfer);
@@ -423,8 +463,12 @@ static int virtio_scsi_setup(VDev *vdev)
     vdev->max_transfer = MIN_NON_ZERO(VIRTIO_SCSI_MAX_SECTORS,
                                       vdev->max_transfer);
 
-    if (!scsi_read_capacity(vdev, data, data_size)) {
-        virtio_scsi_verify_response(&resp, "virtio-scsi:setup:read_capacity");
+    ret = scsi_read_capacity(vdev, data, data_size);
+    if (ret < 1) {
+        if (ret != 0 || !virtio_scsi_verify_response(&resp,
+                "virtio-scsi:setup:read_capacity")) {
+            return -1;
+        }
     }
     scsi_parse_capacity_report(data, &vdev->scsi_last_block,
                                (uint32_t *) &vdev->scsi_block_size);
@@ -439,10 +483,15 @@ int virtio_scsi_setup_device(SubChannelId schid)
     vdev->schid = schid;
     virtio_setup_ccw(vdev);
 
-    IPL_assert(vdev->config.scsi.sense_size == VIRTIO_SCSI_SENSE_SIZE,
-               "Config: sense size mismatch");
-    IPL_assert(vdev->config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE,
-               "Config: CDB size mismatch");
+    if (vdev->config.scsi.sense_size != VIRTIO_SCSI_SENSE_SIZE) {
+        puts("Config: sense size mismatch");
+        return -EINVAL;
+    }
+
+    if (vdev->config.scsi.cdb_size != VIRTIO_SCSI_CDB_SIZE) {
+        puts("Config: CDB size mismatch");
+        return -EINVAL;
+    }
 
     puts("Using virtio-scsi.");
 
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 10/23] pc-bios/s390-ccw: Remove panics from DASD IPL path
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (8 preceding siblings ...)
  2024-10-23 13:16 ` [PULL 09/23] pc-bios/s390-ccw: Remove panics from SCSI " Thomas Huth
@ 2024-10-23 13:16 ` Thomas Huth
  2024-10-23 13:16 ` [PULL 11/23] pc-bios/s390-ccw: Remove panics from Netboot " Thomas Huth
                   ` (13 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

Remove panic-on-error from DASD IPL specific functions so that error recovery
may be possible in the future.

Functions that would previously panic now provide a return code.

Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20241020012953.1380075-11-jrossi@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/dasd-ipl.h |  2 +-
 pc-bios/s390-ccw/dasd-ipl.c | 66 ++++++++++++++++++++-----------------
 2 files changed, 37 insertions(+), 31 deletions(-)

diff --git a/pc-bios/s390-ccw/dasd-ipl.h b/pc-bios/s390-ccw/dasd-ipl.h
index c394828906..eb1898c84a 100644
--- a/pc-bios/s390-ccw/dasd-ipl.h
+++ b/pc-bios/s390-ccw/dasd-ipl.h
@@ -11,6 +11,6 @@
 #ifndef DASD_IPL_H
 #define DASD_IPL_H
 
-void dasd_ipl(SubChannelId schid, uint16_t cutype);
+int dasd_ipl(SubChannelId schid, uint16_t cutype);
 
 #endif /* DASD_IPL_H */
diff --git a/pc-bios/s390-ccw/dasd-ipl.c b/pc-bios/s390-ccw/dasd-ipl.c
index ae751adec1..babece95ea 100644
--- a/pc-bios/s390-ccw/dasd-ipl.c
+++ b/pc-bios/s390-ccw/dasd-ipl.c
@@ -111,38 +111,29 @@ static void make_readipl(void)
     ccwIplRead->count = 0x18; /* Read 0x18 bytes of data */
 }
 
-static void run_readipl(SubChannelId schid, uint16_t cutype)
+static int run_readipl(SubChannelId schid, uint16_t cutype)
 {
-    if (do_cio(schid, cutype, 0x00, CCW_FMT0)) {
-        panic("dasd-ipl: Failed to run Read IPL channel program\n");
-    }
+    return do_cio(schid, cutype, 0x00, CCW_FMT0);
 }
 
 /*
  * The architecture states that IPL1 data should consist of a psw followed by
  * format-0 READ and TIC CCWs. Let's sanity check.
  */
-static void check_ipl1(void)
+static bool check_ipl1(void)
 {
     Ccw0 *ccwread = (Ccw0 *)0x08;
     Ccw0 *ccwtic = (Ccw0 *)0x10;
 
-    if (ccwread->cmd_code != CCW_CMD_DASD_READ ||
-        ccwtic->cmd_code != CCW_CMD_TIC) {
-        panic("dasd-ipl: IPL1 data invalid. Is this disk really bootable?\n");
-    }
+    return (ccwread->cmd_code == CCW_CMD_DASD_READ &&
+            ccwtic->cmd_code == CCW_CMD_TIC);
 }
 
-static void check_ipl2(uint32_t ipl2_addr)
+static bool check_ipl2(uint32_t ipl2_addr)
 {
     Ccw0 *ccw = u32toptr(ipl2_addr);
 
-    if (ipl2_addr == 0x00) {
-        panic("IPL2 address invalid. Is this disk really bootable?\n");
-    }
-    if (ccw->cmd_code == 0x00) {
-        panic("IPL2 ccw data invalid. Is this disk really bootable?\n");
-    }
+    return (ipl2_addr != 0x00 && ccw->cmd_code != 0x00);
 }
 
 static uint32_t read_ipl2_addr(void)
@@ -188,52 +179,67 @@ static void ipl1_fixup(void)
     ccwSearchTic->cda = ptr2u32(ccwSearchID);
 }
 
-static void run_ipl1(SubChannelId schid, uint16_t cutype)
+static int run_ipl1(SubChannelId schid, uint16_t cutype)
  {
     uint32_t startAddr = 0x08;
 
-    if (do_cio(schid, cutype, startAddr, CCW_FMT0)) {
-        panic("dasd-ipl: Failed to run IPL1 channel program\n");
-    }
+    return do_cio(schid, cutype, startAddr, CCW_FMT0);
 }
 
-static void run_ipl2(SubChannelId schid, uint16_t cutype, uint32_t addr)
+static int run_ipl2(SubChannelId schid, uint16_t cutype, uint32_t addr)
 {
-    if (run_dynamic_ccw_program(schid, cutype, addr)) {
-        panic("dasd-ipl: Failed to run IPL2 channel program\n");
-    }
+    return run_dynamic_ccw_program(schid, cutype, addr);
 }
 
 /*
  * Limitations in vfio-ccw support complicate the IPL process. Details can
  * be found in docs/devel/s390-dasd-ipl.rst
  */
-void dasd_ipl(SubChannelId schid, uint16_t cutype)
+int dasd_ipl(SubChannelId schid, uint16_t cutype)
 {
     PSWLegacy *pswl = (PSWLegacy *) 0x00;
     uint32_t ipl2_addr;
 
     /* Construct Read IPL CCW and run it to read IPL1 from boot disk */
     make_readipl();
-    run_readipl(schid, cutype);
+    if (run_readipl(schid, cutype)) {
+        puts("Failed to run Read IPL channel program");
+        return -EIO;
+    }
+
     ipl2_addr = read_ipl2_addr();
-    check_ipl1();
+
+    if (!check_ipl1()) {
+        puts("IPL1 invalid for DASD-IPL");
+        return -EINVAL;
+    }
 
     /*
      * Fixup IPL1 channel program to account for vfio-ccw limitations, then run
      * it to read IPL2 channel program from boot disk.
      */
     ipl1_fixup();
-    run_ipl1(schid, cutype);
-    check_ipl2(ipl2_addr);
+    if (run_ipl1(schid, cutype)) {
+        puts("Failed to run IPL1 channel program");
+        return -EIO;
+    }
+
+    if (!check_ipl2(ipl2_addr)) {
+        puts("IPL2 invalid for DASD-IPL");
+        return -EINVAL;
+    }
 
     /*
      * Run IPL2 channel program to read operating system code from boot disk
      */
-    run_ipl2(schid, cutype, ipl2_addr);
+    if (run_ipl2(schid, cutype, ipl2_addr)) {
+        puts("Failed to run IPL2 channel program");
+        return -EIO;
+    }
 
     /* Transfer control to the guest operating system */
     pswl->mask |= PSW_MASK_EAMODE;   /* Force z-mode */
     pswl->addr |= PSW_MASK_BAMODE;   /* ...          */
     jump_to_low_kernel();
+    return -1;
 }
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 11/23] pc-bios/s390-ccw: Remove panics from Netboot IPL path
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (9 preceding siblings ...)
  2024-10-23 13:16 ` [PULL 10/23] pc-bios/s390-ccw: Remove panics from DASD " Thomas Huth
@ 2024-10-23 13:16 ` Thomas Huth
  2024-10-23 13:16 ` [PULL 12/23] pc-bios/s390-ccw: Enable failed IPL to return after error Thomas Huth
                   ` (12 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

Remove panic-on-error from Netboot specific functions so that error recovery
may be possible in the future.

Functions that would previously panic now provide a return code.

Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20241020012953.1380075-12-jrossi@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/s390-ccw.h   |  2 +-
 pc-bios/s390-ccw/bootmap.c    |  1 +
 pc-bios/s390-ccw/netmain.c    | 17 +++++++++++------
 pc-bios/s390-ccw/virtio-net.c |  7 +++++--
 4 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 3e844abd71..344ad15655 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -57,7 +57,7 @@ unsigned int get_loadparm_index(void);
 void main(void);
 
 /* netmain.c */
-void netmain(void);
+int netmain(void);
 
 /* sclp.c */
 void sclp_print(const char *string);
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 652807a16a..95ef9104d0 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -1072,6 +1072,7 @@ void zipl_load(void)
 
     if (virtio_get_device_type() == VIRTIO_ID_NET) {
         netmain();
+        panic("\n! Cannot IPL from this network !\n");
     }
 
     if (ipl_scsi()) {
diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
index bc6ad8695f..d1a6c9a91c 100644
--- a/pc-bios/s390-ccw/netmain.c
+++ b/pc-bios/s390-ccw/netmain.c
@@ -464,7 +464,7 @@ static bool find_net_dev(Schib *schib, int dev_no)
     return false;
 }
 
-static void virtio_setup(void)
+static bool virtio_setup(void)
 {
     Schib schib;
     int ssid;
@@ -495,10 +495,10 @@ static void virtio_setup(void)
         }
     }
 
-    IPL_assert(found, "No virtio net device found");
+    return found;
 }
 
-void netmain(void)
+int netmain(void)
 {
     filename_ip_t fn_ip;
     int rc, fnlen;
@@ -506,11 +506,15 @@ void netmain(void)
     sclp_setup();
     puts("Network boot starting...");
 
-    virtio_setup();
+    if (!virtio_setup()) {
+        puts("No virtio net device found.");
+        return -1;
+    }
 
     rc = net_init(&fn_ip);
     if (rc) {
-        panic("Network initialization failed. Halting.");
+        puts("Network initialization failed.");
+        return -1;
     }
 
     fnlen = strlen(fn_ip.filename);
@@ -528,5 +532,6 @@ void netmain(void)
         jump_to_low_kernel();
     }
 
-    panic("Failed to load OS from network.");
+    puts("Failed to load OS from network.");
+    return -1;
 }
diff --git a/pc-bios/s390-ccw/virtio-net.c b/pc-bios/s390-ccw/virtio-net.c
index 2fcb0a58c5..f9854a22c3 100644
--- a/pc-bios/s390-ccw/virtio-net.c
+++ b/pc-bios/s390-ccw/virtio-net.c
@@ -54,8 +54,11 @@ int virtio_net_init(void *mac_addr)
     vdev->guest_features[0] = VIRTIO_NET_F_MAC_BIT;
     virtio_setup_ccw(vdev);
 
-    IPL_assert(vdev->guest_features[0] & VIRTIO_NET_F_MAC_BIT,
-               "virtio-net device does not support the MAC address feature");
+    if (!(vdev->guest_features[0] & VIRTIO_NET_F_MAC_BIT)) {
+        puts("virtio-net device does not support the MAC address feature");
+        return -1;
+    }
+
     memcpy(mac_addr, vdev->config.net.mac, ETH_ALEN);
 
     for (i = 0; i < 64; i++) {
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 12/23] pc-bios/s390-ccw: Enable failed IPL to return after error
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (10 preceding siblings ...)
  2024-10-23 13:16 ` [PULL 11/23] pc-bios/s390-ccw: Remove panics from Netboot " Thomas Huth
@ 2024-10-23 13:16 ` Thomas Huth
  2024-10-23 13:17 ` [PULL 13/23] include/hw/s390x: Add include files for common IPL structs Thomas Huth
                   ` (11 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

Remove panic-on-error from IPL functions such that a return code is propagated
back to the main IPL calling function (rather than terminating immediately),
which facilitates possible error recovery in the future.

A select few panics remain, which indicate fatal non-devices errors that must
result in termination.

Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20241020012953.1380075-13-jrossi@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/s390-ccw.h      |  2 +-
 pc-bios/s390-ccw/virtio.h        |  2 +-
 pc-bios/s390-ccw/bootmap.c       | 53 ++++++++++++++++++--------
 pc-bios/s390-ccw/cio.c           |  3 +-
 pc-bios/s390-ccw/jump2ipl.c      |  5 ++-
 pc-bios/s390-ccw/main.c          | 32 +++++++++-------
 pc-bios/s390-ccw/virtio-blkdev.c |  2 +-
 pc-bios/s390-ccw/virtio.c        | 65 +++++++++++++++++++++-----------
 8 files changed, 108 insertions(+), 56 deletions(-)

diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 344ad15655..6cdce3e5e5 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -78,7 +78,7 @@ void zipl_load(void);
 
 /* jump2ipl.c */
 void write_reset_psw(uint64_t psw);
-void jump_to_IPL_code(uint64_t address);
+int jump_to_IPL_code(uint64_t address);
 void jump_to_low_kernel(void);
 
 /* menu.c */
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index 6f9a558ff5..9faf3986b1 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -274,7 +274,7 @@ void vring_send_buf(VRing *vr, void *p, int len, int flags);
 int vr_poll(VRing *vr);
 int vring_wait_reply(void);
 int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd);
-void virtio_setup_ccw(VDev *vdev);
+int virtio_setup_ccw(VDev *vdev);
 
 int virtio_net_init(void *mac_addr);
 
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 95ef9104d0..56f2f75640 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -62,15 +62,34 @@ static void *s2_prev_blk = _s2;
 static void *s2_cur_blk = _s2 + MAX_SECTOR_SIZE;
 static void *s2_next_blk = _s2 + MAX_SECTOR_SIZE * 2;
 
-static inline void verify_boot_info(BootInfo *bip)
+static inline int verify_boot_info(BootInfo *bip)
 {
-    IPL_assert(magic_match(bip->magic, ZIPL_MAGIC), "No zIPL sig in BootInfo");
-    IPL_assert(bip->version == BOOT_INFO_VERSION, "Wrong zIPL version");
-    IPL_assert(bip->bp_type == BOOT_INFO_BP_TYPE_IPL, "DASD is not for IPL");
-    IPL_assert(bip->dev_type == BOOT_INFO_DEV_TYPE_ECKD, "DASD is not ECKD");
-    IPL_assert(bip->flags == BOOT_INFO_FLAGS_ARCH, "Not for this arch");
-    IPL_assert(block_size_ok(bip->bp.ipl.bm_ptr.eckd.bptr.size),
-               "Bad block size in zIPL section of the 1st record.");
+    if (!magic_match(bip->magic, ZIPL_MAGIC)) {
+        puts("No zIPL sig in BootInfo");
+        return -EINVAL;
+    }
+    if (bip->version != BOOT_INFO_VERSION) {
+        puts("Wrong zIPL version");
+        return -EINVAL;
+    }
+    if (bip->bp_type != BOOT_INFO_BP_TYPE_IPL) {
+        puts("DASD is not for IPL");
+        return -ENODEV;
+    }
+    if (bip->dev_type != BOOT_INFO_DEV_TYPE_ECKD) {
+        puts("DASD is not ECKD");
+        return -ENODEV;
+    }
+    if (bip->flags != BOOT_INFO_FLAGS_ARCH) {
+        puts("Not for this arch");
+        return -EINVAL;
+    }
+    if (!block_size_ok(bip->bp.ipl.bm_ptr.eckd.bptr.size)) {
+        puts("Bad block size in zIPL section of 1st record");
+        return -EINVAL;
+    }
+
+    return 0;
 }
 
 static void eckd_format_chs(ExtEckdBlockPtr *ptr,  bool ldipl,
@@ -367,8 +386,8 @@ static int run_eckd_boot_script(block_number_t bmt_block_nr,
         puts("Unknown script entry type");
         return -EINVAL;
     }
-    write_reset_psw(bms->entry[i].address.load_address); /* no return */
-    jump_to_IPL_code(0); /* no return */
+    write_reset_psw(bms->entry[i].address.load_address);
+    jump_to_IPL_code(0);
     return -1;
 }
 
@@ -1067,16 +1086,19 @@ void zipl_load(void)
 
     if (vdev->is_cdrom) {
         ipl_iso_el_torito();
-        panic("\n! Cannot IPL this ISO image !\n");
+        puts("Failed to IPL this ISO image!");
+        return;
     }
 
     if (virtio_get_device_type() == VIRTIO_ID_NET) {
         netmain();
-        panic("\n! Cannot IPL from this network !\n");
+        puts("Failed to IPL from this network!");
+        return;
     }
 
     if (ipl_scsi()) {
-        panic("\n! Cannot IPL this SCSI device !\n");
+        puts("Failed to IPL from this SCSI device!");
+        return;
     }
 
     switch (virtio_get_device_type()) {
@@ -1087,8 +1109,9 @@ void zipl_load(void)
         zipl_load_vscsi();
         break;
     default:
-        panic("\n! Unknown IPL device type !\n");
+        puts("Unknown IPL device type!");
+        return;
     }
 
-    puts("zIPL load failed.");
+    puts("zIPL load failed!");
 }
diff --git a/pc-bios/s390-ccw/cio.c b/pc-bios/s390-ccw/cio.c
index 7b09a38c96..5d543da73f 100644
--- a/pc-bios/s390-ccw/cio.c
+++ b/pc-bios/s390-ccw/cio.c
@@ -59,7 +59,8 @@ uint16_t cu_type(SubChannelId schid)
     };
 
     if (do_cio(schid, CU_TYPE_UNKNOWN, ptr2u32(&sense_id_ccw), CCW_FMT1)) {
-        panic("Failed to run SenseID CCw\n");
+        puts("Failed to run SenseID CCW");
+        return CU_TYPE_UNKNOWN;
     }
 
     return sense_data.cu_type;
diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
index 80b7f6a1f3..8db1764ff3 100644
--- a/pc-bios/s390-ccw/jump2ipl.c
+++ b/pc-bios/s390-ccw/jump2ipl.c
@@ -33,7 +33,7 @@ static void jump_to_IPL_addr(void)
     /* should not return */
 }
 
-void jump_to_IPL_code(uint64_t address)
+int jump_to_IPL_code(uint64_t address)
 {
     /* store the subsystem information _after_ the bootmap was loaded */
     write_subsystem_identification();
@@ -68,7 +68,8 @@ void jump_to_IPL_code(uint64_t address)
     asm volatile("lghi %%r1,1\n\t"
                  "diag %%r1,%%r1,0x308\n\t"
                  : : : "1", "memory");
-    panic("\n! IPL returns !\n");
+    puts("IPL code jump failed");
+    return -1;
 }
 
 void jump_to_low_kernel(void)
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index fc44da3161..34ef27d7a6 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -77,6 +77,9 @@ static int is_dev_possibly_bootable(int dev_no, int sch_no)
 
     enable_subchannel(blk_schid);
     cutype = cu_type(blk_schid);
+    if (cutype == CU_TYPE_UNKNOWN) {
+        return -EIO;
+    }
 
     /*
      * Note: we always have to run virtio_is_supported() here to make
@@ -194,10 +197,10 @@ static void boot_setup(void)
     have_iplb = store_iplb(&iplb);
 }
 
-static void find_boot_device(void)
+static bool find_boot_device(void)
 {
     VDev *vdev = virtio_get_device();
-    bool found;
+    bool found = false;
 
     switch (iplb.pbt) {
     case S390_IPL_TYPE_CCW:
@@ -215,10 +218,10 @@ static void find_boot_device(void)
         found = find_subch(iplb.scsi.devno);
         break;
     default:
-        panic("List-directed IPL not supported yet!\n");
+        puts("Unsupported IPLB");
     }
 
-    IPL_assert(found, "Boot device not found\n");
+    return found;
 }
 
 static int virtio_setup(void)
@@ -244,11 +247,13 @@ static int virtio_setup(void)
         ret = virtio_scsi_setup_device(blk_schid);
         break;
     default:
-        panic("\n! No IPL device available !\n");
+        puts("\n! No IPL device available !\n");
+        return -1;
     }
 
-    if (!ret) {
-        IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
+    if (!ret && !virtio_ipl_disk_is_valid()) {
+        puts("No valid IPL device detected");
+        return -ENODEV;
     }
 
     return ret;
@@ -259,16 +264,16 @@ static void ipl_boot_device(void)
     switch (cutype) {
     case CU_TYPE_DASD_3990:
     case CU_TYPE_DASD_2107:
-        dasd_ipl(blk_schid, cutype); /* no return */
+        dasd_ipl(blk_schid, cutype);
         break;
     case CU_TYPE_VIRTIO:
-        if (virtio_setup() == 0) {
-            zipl_load();             /* Only returns in case of errors */
+        if (virtio_setup()) {
+            return;    /* Only returns in case of errors */
         }
+        zipl_load();
         break;
     default:
         printf("Attempting to boot from unexpected device type 0x%X\n", cutype);
-        panic("\nBoot failed.\n");
     }
 }
 
@@ -301,12 +306,11 @@ void main(void)
     sclp_setup();
     css_setup();
     boot_setup();
-    if (have_iplb) {
-        find_boot_device();
+    if (have_iplb && find_boot_device()) {
         ipl_boot_device();
     } else {
         probe_boot_device();
     }
 
-    panic("Failed to load OS from hard disk\n");
+    panic("Failed to IPL. Halting...");
 }
diff --git a/pc-bios/s390-ccw/virtio-blkdev.c b/pc-bios/s390-ccw/virtio-blkdev.c
index 1c585f034b..7b2d1e20f4 100644
--- a/pc-bios/s390-ccw/virtio-blkdev.c
+++ b/pc-bios/s390-ccw/virtio-blkdev.c
@@ -59,7 +59,7 @@ int virtio_read_many(unsigned long sector, void *load_addr, int sec_num)
     case VIRTIO_ID_SCSI:
         return virtio_scsi_read_many(vdev, sector, load_addr, sec_num);
     }
-    panic("\n! No readable IPL device !\n");
+
     return -1;
 }
 
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 8c6b0a8a92..8b5a370bb3 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -217,16 +217,19 @@ int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
     return 0;
 }
 
-void virtio_setup_ccw(VDev *vdev)
+int virtio_setup_ccw(VDev *vdev)
 {
-    int i, rc, cfg_size = 0;
+    int i, cfg_size = 0;
     uint8_t status;
     struct VirtioFeatureDesc {
         uint32_t features;
         uint8_t index;
     } __attribute__((packed)) feats;
 
-    IPL_assert(virtio_is_supported(vdev->schid), "PE");
+    if (!virtio_is_supported(vdev->schid)) {
+        puts("Virtio unsupported for this device ID");
+        return -ENODEV;
+    }
     /* device ID has been established now */
 
     vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
@@ -235,8 +238,10 @@ void virtio_setup_ccw(VDev *vdev)
     run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false);
 
     status = VIRTIO_CONFIG_S_ACKNOWLEDGE;
-    rc = run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false);
-    IPL_assert(rc == 0, "Could not write ACKNOWLEDGE status to host");
+    if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
+        puts("Could not write ACKNOWLEDGE status to host");
+        return -EIO;
+    }
 
     switch (vdev->senseid.cu_model) {
     case VIRTIO_ID_NET:
@@ -255,27 +260,37 @@ void virtio_setup_ccw(VDev *vdev)
         cfg_size = sizeof(vdev->config.scsi);
         break;
     default:
-        panic("Unsupported virtio device\n");
+        puts("Unsupported virtio device");
+        return -ENODEV;
     }
 
     status |= VIRTIO_CONFIG_S_DRIVER;
-    rc = run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false);
-    IPL_assert(rc == 0, "Could not write DRIVER status to host");
+    if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
+        puts("Could not write DRIVER status to host");
+        return -EIO;
+    }
 
     /* Feature negotiation */
     for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
         feats.features = 0;
         feats.index = i;
-        rc = run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats), false);
-        IPL_assert(rc == 0, "Could not get features bits");
+        if (run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats), false)) {
+            puts("Could not get features bits");
+            return -EIO;
+        }
+
         vdev->guest_features[i] &= bswap32(feats.features);
         feats.features = bswap32(vdev->guest_features[i]);
-        rc = run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats), false);
-        IPL_assert(rc == 0, "Could not set features bits");
+        if (run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats), false)) {
+            puts("Could not set features bits");
+            return -EIO;
+        }
     }
 
-    rc = run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false);
-    IPL_assert(rc == 0, "Could not get virtio device configuration");
+    if (run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false)) {
+        puts("Could not get virtio device configuration");
+        return -EIO;
+    }
 
     for (i = 0; i < vdev->nr_vqs; i++) {
         VqInfo info = {
@@ -289,19 +304,27 @@ void virtio_setup_ccw(VDev *vdev)
             .num = 0,
         };
 
-        rc = run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config), false);
-        IPL_assert(rc == 0, "Could not get virtio device VQ configuration");
+        if (run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config),
+                false)) {
+            puts("Could not get virtio device VQ config");
+            return -EIO;
+        }
         info.num = config.num;
         vring_init(&vdev->vrings[i], &info);
         vdev->vrings[i].schid = vdev->schid;
-        IPL_assert(
-            run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false) == 0,
-            "Cannot set VQ info");
+        if (run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false)) {
+            puts("Cannot set VQ info");
+            return -EIO;
+        }
     }
 
     status |= VIRTIO_CONFIG_S_DRIVER_OK;
-    rc = run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false);
-    IPL_assert(rc == 0, "Could not write DRIVER_OK status to host");
+    if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
+        puts("Could not write DRIVER_OK status to host");
+        return -EIO;
+    }
+
+    return 0;
 }
 
 bool virtio_is_supported(SubChannelId schid)
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 13/23] include/hw/s390x: Add include files for common IPL structs
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (11 preceding siblings ...)
  2024-10-23 13:16 ` [PULL 12/23] pc-bios/s390-ccw: Enable failed IPL to return after error Thomas Huth
@ 2024-10-23 13:17 ` Thomas Huth
  2024-10-23 13:17 ` [PULL 14/23] s390x: Add individual loadparm assignment to CCW device Thomas Huth
                   ` (10 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

Currently, structures defined in both hw/s390x/ipl.h and pc-bios/s390-ccw/iplb.h
must be kept in sync, which is prone to error. Instead, create a new directory
at include/hw/s390x/ipl/ to contain the definitions that must be shared.

Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20241020012953.1380075-14-jrossi@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 hw/s390x/ipl.h              | 104 +-----------------------------
 include/hw/s390x/ipl/qipl.h | 123 ++++++++++++++++++++++++++++++++++++
 pc-bios/s390-ccw/iplb.h     |  84 ++----------------------
 pc-bios/s390-ccw/Makefile   |   2 +-
 4 files changed, 130 insertions(+), 183 deletions(-)
 create mode 100644 include/hw/s390x/ipl/qipl.h

diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index b2105b616a..fa394c339d 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -16,95 +16,11 @@
 #include "cpu.h"
 #include "exec/address-spaces.h"
 #include "hw/qdev-core.h"
+#include "hw/s390x/ipl/qipl.h"
 #include "qom/object.h"
 
-struct IPLBlockPVComp {
-    uint64_t tweak_pref;
-    uint64_t addr;
-    uint64_t size;
-} QEMU_PACKED;
-typedef struct IPLBlockPVComp IPLBlockPVComp;
-
-struct IPLBlockPV {
-    uint8_t  reserved18[87];    /* 0x18 */
-    uint8_t  version;           /* 0x6f */
-    uint32_t reserved70;        /* 0x70 */
-    uint32_t num_comp;          /* 0x74 */
-    uint64_t pv_header_addr;    /* 0x78 */
-    uint64_t pv_header_len;     /* 0x80 */
-    struct IPLBlockPVComp components[0];
-} QEMU_PACKED;
-typedef struct IPLBlockPV IPLBlockPV;
-
-struct IplBlockCcw {
-    uint8_t  reserved0[85];
-    uint8_t  ssid;
-    uint16_t devno;
-    uint8_t  vm_flags;
-    uint8_t  reserved3[3];
-    uint32_t vm_parm_len;
-    uint8_t  nss_name[8];
-    uint8_t  vm_parm[64];
-    uint8_t  reserved4[8];
-} QEMU_PACKED;
-typedef struct IplBlockCcw IplBlockCcw;
-
-struct IplBlockFcp {
-    uint8_t  reserved1[305 - 1];
-    uint8_t  opt;
-    uint8_t  reserved2[3];
-    uint16_t reserved3;
-    uint16_t devno;
-    uint8_t  reserved4[4];
-    uint64_t wwpn;
-    uint64_t lun;
-    uint32_t bootprog;
-    uint8_t  reserved5[12];
-    uint64_t br_lba;
-    uint32_t scp_data_len;
-    uint8_t  reserved6[260];
-    uint8_t  scp_data[0];
-} QEMU_PACKED;
-typedef struct IplBlockFcp IplBlockFcp;
-
-struct IplBlockQemuScsi {
-    uint32_t lun;
-    uint16_t target;
-    uint16_t channel;
-    uint8_t  reserved0[77];
-    uint8_t  ssid;
-    uint16_t devno;
-} QEMU_PACKED;
-typedef struct IplBlockQemuScsi IplBlockQemuScsi;
-
 #define DIAG308_FLAGS_LP_VALID 0x80
 
-union IplParameterBlock {
-    struct {
-        uint32_t len;
-        uint8_t  reserved0[3];
-        uint8_t  version;
-        uint32_t blk0_len;
-        uint8_t  pbt;
-        uint8_t  flags;
-        uint16_t reserved01;
-        uint8_t  loadparm[8];
-        union {
-            IplBlockCcw ccw;
-            IplBlockFcp fcp;
-            IPLBlockPV pv;
-            IplBlockQemuScsi scsi;
-        };
-    } QEMU_PACKED;
-    struct {
-        uint8_t  reserved1[110];
-        uint16_t devno;
-        uint8_t  reserved2[88];
-        uint8_t  reserved_ext[4096 - 200];
-    } QEMU_PACKED;
-} QEMU_PACKED;
-typedef union IplParameterBlock IplParameterBlock;
-
 int s390_ipl_set_loadparm(uint8_t *loadparm);
 void s390_ipl_update_diag308(IplParameterBlock *iplb);
 int s390_ipl_prepare_pv_header(Error **errp);
@@ -131,24 +47,6 @@ void s390_ipl_clear_reset_request(void);
 #define QIPL_FLAG_BM_OPTS_CMD   0x80
 #define QIPL_FLAG_BM_OPTS_ZIPL  0x40
 
-/*
- * The QEMU IPL Parameters will be stored at absolute address
- * 204 (0xcc) which means it is 32-bit word aligned but not
- * double-word aligned. Placement of 64-bit data fields in this
- * area must account for their alignment needs.
- * The total size of the struct must never exceed 28 bytes.
- * This definition must be kept in sync with the definition
- * in pc-bios/s390-ccw/iplb.h.
- */
-struct QemuIplParameters {
-    uint8_t  qipl_flags;
-    uint8_t  reserved1[3];
-    uint64_t reserved2;
-    uint32_t boot_menu_timeout;
-    uint8_t  reserved3[12];
-} QEMU_PACKED;
-typedef struct QemuIplParameters QemuIplParameters;
-
 #define TYPE_S390_IPL "s390-ipl"
 OBJECT_DECLARE_SIMPLE_TYPE(S390IPLState, S390_IPL)
 
diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h
new file mode 100644
index 0000000000..0ef04af027
--- /dev/null
+++ b/include/hw/s390x/ipl/qipl.h
@@ -0,0 +1,123 @@
+/*
+ * S/390 boot structures
+ *
+ * Copyright 2024 IBM Corp.
+ * Author(s): Jared Rossi <jrossi@linux.ibm.com>
+ *
+ * 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.
+ */
+
+#ifndef S390X_QIPL_H
+#define S390X_QIPL_H
+
+/* Boot Menu flags */
+#define QIPL_FLAG_BM_OPTS_CMD   0x80
+#define QIPL_FLAG_BM_OPTS_ZIPL  0x40
+
+#define QIPL_ADDRESS  0xcc
+#define LOADPARM_LEN    8
+
+/*
+ * The QEMU IPL Parameters will be stored at absolute address
+ * 204 (0xcc) which means it is 32-bit word aligned but not
+ * double-word aligned. Placement of 64-bit data fields in this
+ * area must account for their alignment needs.
+ * The total size of the struct must never exceed 28 bytes.
+ */
+struct QemuIplParameters {
+    uint8_t  qipl_flags;
+    uint8_t  reserved1[3];
+    uint64_t reserved2;
+    uint32_t boot_menu_timeout;
+    uint8_t  reserved3[12];
+} QEMU_PACKED;
+typedef struct QemuIplParameters QemuIplParameters;
+
+struct IPLBlockPVComp {
+    uint64_t tweak_pref;
+    uint64_t addr;
+    uint64_t size;
+} QEMU_PACKED;
+typedef struct IPLBlockPVComp IPLBlockPVComp;
+
+struct IPLBlockPV {
+    uint8_t  reserved18[87];    /* 0x18 */
+    uint8_t  version;           /* 0x6f */
+    uint32_t reserved70;        /* 0x70 */
+    uint32_t num_comp;          /* 0x74 */
+    uint64_t pv_header_addr;    /* 0x78 */
+    uint64_t pv_header_len;     /* 0x80 */
+    struct IPLBlockPVComp components[0];
+} QEMU_PACKED;
+typedef struct IPLBlockPV IPLBlockPV;
+
+struct IplBlockCcw {
+    uint8_t  reserved0[85];
+    uint8_t  ssid;
+    uint16_t devno;
+    uint8_t  vm_flags;
+    uint8_t  reserved3[3];
+    uint32_t vm_parm_len;
+    uint8_t  nss_name[8];
+    uint8_t  vm_parm[64];
+    uint8_t  reserved4[8];
+} QEMU_PACKED;
+typedef struct IplBlockCcw IplBlockCcw;
+
+struct IplBlockFcp {
+    uint8_t  reserved1[305 - 1];
+    uint8_t  opt;
+    uint8_t  reserved2[3];
+    uint16_t reserved3;
+    uint16_t devno;
+    uint8_t  reserved4[4];
+    uint64_t wwpn;
+    uint64_t lun;
+    uint32_t bootprog;
+    uint8_t  reserved5[12];
+    uint64_t br_lba;
+    uint32_t scp_data_len;
+    uint8_t  reserved6[260];
+    uint8_t  scp_data[0];
+} QEMU_PACKED;
+typedef struct IplBlockFcp IplBlockFcp;
+
+struct IplBlockQemuScsi {
+    uint32_t lun;
+    uint16_t target;
+    uint16_t channel;
+    uint8_t  reserved0[77];
+    uint8_t  ssid;
+    uint16_t devno;
+} QEMU_PACKED;
+typedef struct IplBlockQemuScsi IplBlockQemuScsi;
+
+union IplParameterBlock {
+    struct {
+        uint32_t len;
+        uint8_t  reserved0[3];
+        uint8_t  version;
+        uint32_t blk0_len;
+        uint8_t  pbt;
+        uint8_t  flags;
+        uint16_t reserved01;
+        uint8_t  loadparm[LOADPARM_LEN];
+        union {
+            IplBlockCcw ccw;
+            IplBlockFcp fcp;
+            IPLBlockPV pv;
+            IplBlockQemuScsi scsi;
+        };
+    } QEMU_PACKED;
+    struct {
+        uint8_t  reserved1[110];
+        uint16_t devno;
+        uint8_t  reserved2[88];
+        uint8_t  reserved_ext[4096 - 200];
+    } QEMU_PACKED;
+} QEMU_PACKED;
+typedef union IplParameterBlock IplParameterBlock;
+
+#endif
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 3758698468..16643f5879 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -12,88 +12,14 @@
 #ifndef IPLB_H
 #define IPLB_H
 
-#define LOADPARM_LEN    8
+#ifndef QEMU_PACKED
+#define QEMU_PACKED __attribute__((packed))
+#endif
 
-struct IplBlockCcw {
-    uint8_t  reserved0[85];
-    uint8_t  ssid;
-    uint16_t devno;
-    uint8_t  vm_flags;
-    uint8_t  reserved3[3];
-    uint32_t vm_parm_len;
-    uint8_t  nss_name[8];
-    uint8_t  vm_parm[64];
-    uint8_t  reserved4[8];
-} __attribute__ ((packed));
-typedef struct IplBlockCcw IplBlockCcw;
-
-struct IplBlockFcp {
-    uint8_t  reserved1[305 - 1];
-    uint8_t  opt;
-    uint8_t  reserved2[3];
-    uint16_t reserved3;
-    uint16_t devno;
-    uint8_t  reserved4[4];
-    uint64_t wwpn;
-    uint64_t lun;
-    uint32_t bootprog;
-    uint8_t  reserved5[12];
-    uint64_t br_lba;
-    uint32_t scp_data_len;
-    uint8_t  reserved6[260];
-    uint8_t  scp_data[];
-} __attribute__ ((packed));
-typedef struct IplBlockFcp IplBlockFcp;
-
-struct IplBlockQemuScsi {
-    uint32_t lun;
-    uint16_t target;
-    uint16_t channel;
-    uint8_t  reserved0[77];
-    uint8_t  ssid;
-    uint16_t devno;
-} __attribute__ ((packed));
-typedef struct IplBlockQemuScsi IplBlockQemuScsi;
-
-struct IplParameterBlock {
-    uint32_t len;
-    uint8_t  reserved0[3];
-    uint8_t  version;
-    uint32_t blk0_len;
-    uint8_t  pbt;
-    uint8_t  flags;
-    uint16_t reserved01;
-    uint8_t  loadparm[LOADPARM_LEN];
-    union {
-        IplBlockCcw ccw;
-        IplBlockFcp fcp;
-        IplBlockQemuScsi scsi;
-    };
-} __attribute__ ((packed));
-typedef struct IplParameterBlock IplParameterBlock;
-
-extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
-
-#define QIPL_ADDRESS  0xcc
-
-/* Boot Menu flags */
-#define QIPL_FLAG_BM_OPTS_CMD   0x80
-#define QIPL_FLAG_BM_OPTS_ZIPL  0x40
-
-/*
- * This definition must be kept in sync with the definition
- * in hw/s390x/ipl.h
- */
-struct QemuIplParameters {
-    uint8_t  qipl_flags;
-    uint8_t  reserved1[3];
-    uint64_t reserved2;
-    uint32_t boot_menu_timeout;
-    uint8_t  reserved3[12];
-} __attribute__ ((packed));
-typedef struct QemuIplParameters QemuIplParameters;
+#include <qipl.h>
 
 extern QemuIplParameters qipl;
+extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 
 #define S390_IPL_TYPE_FCP 0x00
 #define S390_IPL_TYPE_CCW 0x02
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 27cbb354af..db9e8f0892 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -3,7 +3,7 @@ all: build-all
 	@true
 
 include config-host.mak
-CFLAGS = -O2 -g
+CFLAGS = -O2 -g -I $(SRC_PATH)/../../include/hw/s390x/ipl
 MAKEFLAGS += -rR
 
 GIT_SUBMODULES = roms/SLOF
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 14/23] s390x: Add individual loadparm assignment to CCW device
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (12 preceding siblings ...)
  2024-10-23 13:17 ` [PULL 13/23] include/hw/s390x: Add include files for common IPL structs Thomas Huth
@ 2024-10-23 13:17 ` Thomas Huth
  2024-10-23 13:17 ` [PULL 15/23] hw/s390x: Build an IPLB for each boot device Thomas Huth
                   ` (9 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

Add a loadparm property to the VirtioCcwDevice object so that different
loadparms can be defined on a per-device basis for CCW boot devices.

The machine/global loadparm is still supported. If both a global and per-device
loadparm are defined, the per-device value will override the global value for
that device, but any other devices that do not specify a per-device loadparm
will still use the global loadparm.

It is invalid to assign a loadparm to a non-boot device.

Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20241020012953.1380075-15-jrossi@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 hw/s390x/ccw-device.h       |  2 ++
 hw/s390x/ipl.h              |  3 +-
 include/hw/s390x/ipl/qipl.h |  1 +
 hw/s390x/ccw-device.c       | 46 +++++++++++++++++++++++++
 hw/s390x/ipl.c              | 68 ++++++++++++++++++++++---------------
 hw/s390x/s390-virtio-ccw.c  | 18 +---------
 hw/s390x/sclp.c             |  9 ++---
 pc-bios/s390-ccw/main.c     | 10 ++++--
 8 files changed, 102 insertions(+), 55 deletions(-)

diff --git a/hw/s390x/ccw-device.h b/hw/s390x/ccw-device.h
index 5feeb0ee7a..1e1737c0f3 100644
--- a/hw/s390x/ccw-device.h
+++ b/hw/s390x/ccw-device.h
@@ -26,6 +26,8 @@ struct CcwDevice {
     CssDevId dev_id;
     /* The actual busid of the virtual subchannel. */
     CssDevId subch_id;
+    /* If set, use this loadparm value when device is boot target */
+    uint8_t loadparm[8];
 };
 typedef struct CcwDevice CcwDevice;
 
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index fa394c339d..b670bad551 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -21,7 +21,8 @@
 
 #define DIAG308_FLAGS_LP_VALID 0x80
 
-int s390_ipl_set_loadparm(uint8_t *loadparm);
+void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp);
+void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp);
 void s390_ipl_update_diag308(IplParameterBlock *iplb);
 int s390_ipl_prepare_pv_header(Error **errp);
 int s390_ipl_pv_unpack(void);
diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h
index 0ef04af027..b67d2ae061 100644
--- a/include/hw/s390x/ipl/qipl.h
+++ b/include/hw/s390x/ipl/qipl.h
@@ -18,6 +18,7 @@
 
 #define QIPL_ADDRESS  0xcc
 #define LOADPARM_LEN    8
+#define NO_LOADPARM "\0\0\0\0\0\0\0\0"
 
 /*
  * The QEMU IPL Parameters will be stored at absolute address
diff --git a/hw/s390x/ccw-device.c b/hw/s390x/ccw-device.c
index 14c24e3890..230cc09e03 100644
--- a/hw/s390x/ccw-device.c
+++ b/hw/s390x/ccw-device.c
@@ -13,6 +13,10 @@
 #include "ccw-device.h"
 #include "hw/qdev-properties.h"
 #include "qemu/module.h"
+#include "ipl.h"
+#include "qapi/visitor.h"
+#include "qemu/ctype.h"
+#include "qapi/error.h"
 
 static void ccw_device_refill_ids(CcwDevice *dev)
 {
@@ -37,10 +41,52 @@ static bool ccw_device_realize(CcwDevice *dev, Error **errp)
     return true;
 }
 
+static void ccw_device_get_loadparm(Object *obj, Visitor *v,
+                                 const char *name, void *opaque,
+                                 Error **errp)
+{
+    CcwDevice *dev = CCW_DEVICE(obj);
+    char *str = g_strndup((char *) dev->loadparm, sizeof(dev->loadparm));
+
+    visit_type_str(v, name, &str, errp);
+    g_free(str);
+}
+
+static void ccw_device_set_loadparm(Object *obj, Visitor *v,
+                                 const char *name, void *opaque,
+                                 Error **errp)
+{
+    CcwDevice *dev = CCW_DEVICE(obj);
+    char *val;
+    int index;
+
+    index = object_property_get_int(obj, "bootindex", NULL);
+
+    if (index < 0) {
+        error_setg(errp, "LOADPARM is only valid for boot devices!");
+    }
+
+    if (!visit_type_str(v, name, &val, errp)) {
+        return;
+    }
+
+    s390_ipl_fmt_loadparm(dev->loadparm, val, errp);
+}
+
+static const PropertyInfo ccw_loadparm = {
+    .name  = "ccw_loadparm",
+    .description = "Up to 8 chars in set of [A-Za-z0-9. ] to pass"
+            " to the guest loader/kernel",
+    .get = ccw_device_get_loadparm,
+    .set = ccw_device_set_loadparm,
+};
+
 static Property ccw_device_properties[] = {
     DEFINE_PROP_CSS_DEV_ID("devno", CcwDevice, devno),
     DEFINE_PROP_CSS_DEV_ID_RO("dev_id", CcwDevice, dev_id),
     DEFINE_PROP_CSS_DEV_ID_RO("subch_id", CcwDevice, subch_id),
+    DEFINE_PROP("loadparm", CcwDevice, loadparm, ccw_loadparm,
+            typeof(uint8_t[8])),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 8c490eeb52..656996b500 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -34,6 +34,7 @@
 #include "qemu/config-file.h"
 #include "qemu/cutils.h"
 #include "qemu/option.h"
+#include "qemu/ctype.h"
 #include "standard-headers/linux/virtio_ids.h"
 
 #define KERN_IMAGE_START                0x010000UL
@@ -397,12 +398,43 @@ static CcwDevice *s390_get_ccw_device(DeviceState *dev_st, int *devtype)
     return ccw_dev;
 }
 
+void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp)
+{
+    int i;
+
+    /* Initialize the loadparm with spaces */
+    memset(loadparm, ' ', LOADPARM_LEN);
+    for (i = 0; i < LOADPARM_LEN && str[i]; i++) {
+        uint8_t c = qemu_toupper(str[i]); /* mimic HMC */
+
+        if (qemu_isalnum(c) || c == '.' || c == ' ') {
+            loadparm[i] = c;
+        } else {
+            error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)",
+                       c, c);
+            return;
+        }
+    }
+}
+
+void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp)
+{
+    int i;
+
+    /* Initialize the loadparm with EBCDIC spaces (0x40) */
+    memset(ebcdic_lp, '@', LOADPARM_LEN);
+    for (i = 0; i < LOADPARM_LEN && ascii_lp[i]; i++) {
+        ebcdic_lp[i] = ascii2ebcdic[(uint8_t) ascii_lp[i]];
+    }
+}
+
 static bool s390_gen_initial_iplb(S390IPLState *ipl)
 {
     DeviceState *dev_st;
     CcwDevice *ccw_dev = NULL;
     SCSIDevice *sd;
     int devtype;
+    uint8_t *lp;
 
     dev_st = get_boot_device(0);
     if (dev_st) {
@@ -413,6 +445,8 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
      * Currently allow IPL only from CCW devices.
      */
     if (ccw_dev) {
+        lp = ccw_dev->loadparm;
+
         switch (devtype) {
         case CCW_DEVTYPE_SCSI:
             sd = SCSI_DEVICE(dev_st);
@@ -445,40 +479,20 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
             break;
         }
 
-        if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) {
-            ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID;
+        /* If the device loadparm is empty use the global machine loadparm */
+        if (memcmp(lp, NO_LOADPARM, 8) == 0) {
+            lp = S390_CCW_MACHINE(qdev_get_machine())->loadparm;
         }
 
+        s390_ipl_convert_loadparm((char *)lp, ipl->iplb.loadparm);
+        ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID;
+
         return true;
     }
 
     return false;
 }
 
-int s390_ipl_set_loadparm(uint8_t *loadparm)
-{
-    MachineState *machine = MACHINE(qdev_get_machine());
-    char *lp = object_property_get_str(OBJECT(machine), "loadparm", NULL);
-
-    if (lp) {
-        int i;
-
-        /* lp is an uppercase string without leading/embedded spaces */
-        for (i = 0; i < 8 && lp[i]; i++) {
-            loadparm[i] = ascii2ebcdic[(uint8_t) lp[i]];
-        }
-
-        if (i < 8) {
-            memset(loadparm + i, 0x40, 8 - i); /* fill with EBCDIC spaces */
-        }
-
-        g_free(lp);
-        return 0;
-    }
-
-    return -1;
-}
-
 static bool is_virtio_ccw_device_of_type(IplParameterBlock *iplb,
                                          int virtio_id)
 {
@@ -534,7 +548,7 @@ static void update_machine_ipl_properties(IplParameterBlock *iplb)
         ascii_loadparm[i] = 0;
         object_property_set_str(machine, "loadparm", ascii_loadparm, &err);
     } else {
-        object_property_set_str(machine, "loadparm", "", &err);
+        object_property_set_str(machine, "loadparm", "        ", &err);
     }
     if (err) {
         warn_report_err(err);
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 529e53f308..fe03f716f3 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -722,28 +722,12 @@ static void machine_set_loadparm(Object *obj, Visitor *v,
 {
     S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
     char *val;
-    int i;
 
     if (!visit_type_str(v, name, &val, errp)) {
         return;
     }
 
-    for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) {
-        uint8_t c = qemu_toupper(val[i]); /* mimic HMC */
-
-        if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '.') ||
-            (c == ' ')) {
-            ms->loadparm[i] = c;
-        } else {
-            error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)",
-                       c, c);
-            return;
-        }
-    }
-
-    for (; i < sizeof(ms->loadparm); i++) {
-        ms->loadparm[i] = ' '; /* pad right with spaces */
-    }
+    s390_ipl_fmt_loadparm(ms->loadparm, val, errp);
 }
 
 static void ccw_machine_class_init(ObjectClass *oc, void *data)
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index e725dcd5fd..8757626b5c 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -110,7 +110,6 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
     MachineState *machine = MACHINE(qdev_get_machine());
     int cpu_count;
     int rnsize, rnmax;
-    IplParameterBlock *ipib = s390_ipl_get_iplb();
     int required_len = SCCB_REQ_LEN(ReadInfo, machine->possible_cpus->len);
     int offset_cpu = s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB) ?
                      offsetof(ReadInfo, entries) :
@@ -171,12 +170,8 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
         read_info->rnmax2 = cpu_to_be64(rnmax);
     }
 
-    if (ipib && ipib->flags & DIAG308_FLAGS_LP_VALID) {
-        memcpy(&read_info->loadparm, &ipib->loadparm,
-               sizeof(read_info->loadparm));
-    } else {
-        s390_ipl_set_loadparm(read_info->loadparm);
-    }
+    s390_ipl_convert_loadparm((char *)S390_CCW_MACHINE(machine)->loadparm,
+                                read_info->loadparm);
 
     sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
 }
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 34ef27d7a6..ab4709e16e 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -183,8 +183,14 @@ static void css_setup(void)
 static void boot_setup(void)
 {
     char lpmsg[] = "LOADPARM=[________]\n";
+    have_iplb = store_iplb(&iplb);
+
+    if (memcmp(iplb.loadparm, NO_LOADPARM, LOADPARM_LEN) != 0) {
+        ebcdic_to_ascii((char *) iplb.loadparm, loadparm_str, LOADPARM_LEN);
+    } else {
+        sclp_get_loadparm_ascii(loadparm_str);
+    }
 
-    sclp_get_loadparm_ascii(loadparm_str);
     memcpy(lpmsg + 10, loadparm_str, 8);
     puts(lpmsg);
 
@@ -193,8 +199,6 @@ static void boot_setup(void)
      * so we don't taint our decision-making process during a reboot.
      */
     memset((char *)S390EP, 0, 6);
-
-    have_iplb = store_iplb(&iplb);
 }
 
 static bool find_boot_device(void)
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 15/23] hw/s390x: Build an IPLB for each boot device
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (13 preceding siblings ...)
  2024-10-23 13:17 ` [PULL 14/23] s390x: Add individual loadparm assignment to CCW device Thomas Huth
@ 2024-10-23 13:17 ` Thomas Huth
  2025-06-16 10:04   ` Philippe Mathieu-Daudé
  2024-10-23 13:17 ` [PULL 16/23] s390x: Rebuild IPLB for SCSI device directly from DIAG308 Thomas Huth
                   ` (8 subsequent siblings)
  23 siblings, 1 reply; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

Build an IPLB for any device with a bootindex (up to a maximum of 8 devices).

The IPLB chain is placed immediately before the BIOS in memory. Because this
is not a fixed address, the location of the next IPLB and number of remaining
boot devices is stored in the QIPL global variable for possible later access by
the guest during IPL.

Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20241020012953.1380075-16-jrossi@linux.ibm.com>
[thuth: Fix endianness problem when accessing the qipl structure]
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 hw/s390x/ipl.h              |   1 +
 include/hw/s390x/ipl/qipl.h |   4 +-
 hw/s390x/ipl.c              | 129 ++++++++++++++++++++++++++++--------
 3 files changed, 105 insertions(+), 29 deletions(-)

diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index b670bad551..54eb48fd6e 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -20,6 +20,7 @@
 #include "qom/object.h"
 
 #define DIAG308_FLAGS_LP_VALID 0x80
+#define MAX_BOOT_DEVS 8 /* Max number of devices that may have a bootindex */
 
 void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp);
 void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp);
diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h
index b67d2ae061..1da4f75aa8 100644
--- a/include/hw/s390x/ipl/qipl.h
+++ b/include/hw/s390x/ipl/qipl.h
@@ -32,7 +32,9 @@ struct QemuIplParameters {
     uint8_t  reserved1[3];
     uint64_t reserved2;
     uint32_t boot_menu_timeout;
-    uint8_t  reserved3[12];
+    uint8_t  reserved3[2];
+    uint16_t chain_len;
+    uint64_t next_iplb;
 } QEMU_PACKED;
 typedef struct QemuIplParameters QemuIplParameters;
 
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 656996b500..b9d741d0b0 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -56,6 +56,13 @@ static bool iplb_extended_needed(void *opaque)
     return ipl->iplbext_migration;
 }
 
+/* Place the IPLB chain immediately before the BIOS in memory */
+static uint64_t find_iplb_chain_addr(uint64_t bios_addr, uint16_t count)
+{
+    return (bios_addr & TARGET_PAGE_MASK)
+            - (count * sizeof(IplParameterBlock));
+}
+
 static const VMStateDescription vmstate_iplb_extended = {
     .name = "ipl/iplb_extended",
     .version_id = 0,
@@ -398,6 +405,17 @@ static CcwDevice *s390_get_ccw_device(DeviceState *dev_st, int *devtype)
     return ccw_dev;
 }
 
+static uint64_t s390_ipl_map_iplb_chain(IplParameterBlock *iplb_chain)
+{
+    S390IPLState *ipl = get_ipl_device();
+    uint16_t count = be16_to_cpu(ipl->qipl.chain_len);
+    uint64_t len = sizeof(IplParameterBlock) * count;
+    uint64_t chain_addr = find_iplb_chain_addr(ipl->bios_start_addr, count);
+
+    cpu_physical_memory_write(chain_addr, iplb_chain, len);
+    return chain_addr;
+}
+
 void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp)
 {
     int i;
@@ -428,54 +446,51 @@ void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp)
     }
 }
 
-static bool s390_gen_initial_iplb(S390IPLState *ipl)
+static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
 {
-    DeviceState *dev_st;
+    S390IPLState *ipl = get_ipl_device();
     CcwDevice *ccw_dev = NULL;
     SCSIDevice *sd;
     int devtype;
     uint8_t *lp;
 
-    dev_st = get_boot_device(0);
-    if (dev_st) {
-        ccw_dev = s390_get_ccw_device(dev_st, &devtype);
-    }
-
     /*
      * Currently allow IPL only from CCW devices.
      */
+    ccw_dev = s390_get_ccw_device(dev_st, &devtype);
     if (ccw_dev) {
         lp = ccw_dev->loadparm;
 
         switch (devtype) {
         case CCW_DEVTYPE_SCSI:
             sd = SCSI_DEVICE(dev_st);
-            ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
-            ipl->iplb.blk0_len =
+            iplb->len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
+            iplb->blk0_len =
                 cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN - S390_IPLB_HEADER_LEN);
-            ipl->iplb.pbt = S390_IPL_TYPE_QEMU_SCSI;
-            ipl->iplb.scsi.lun = cpu_to_be32(sd->lun);
-            ipl->iplb.scsi.target = cpu_to_be16(sd->id);
-            ipl->iplb.scsi.channel = cpu_to_be16(sd->channel);
-            ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
-            ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3;
+            iplb->pbt = S390_IPL_TYPE_QEMU_SCSI;
+            iplb->scsi.lun = cpu_to_be32(sd->lun);
+            iplb->scsi.target = cpu_to_be16(sd->id);
+            iplb->scsi.channel = cpu_to_be16(sd->channel);
+            iplb->scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
+            iplb->scsi.ssid = ccw_dev->sch->ssid & 3;
             break;
         case CCW_DEVTYPE_VFIO:
-            ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
-            ipl->iplb.pbt = S390_IPL_TYPE_CCW;
-            ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
-            ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
+            iplb->len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
+            iplb->pbt = S390_IPL_TYPE_CCW;
+            iplb->ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
+            iplb->ccw.ssid = ccw_dev->sch->ssid & 3;
             break;
         case CCW_DEVTYPE_VIRTIO_NET:
+            /* The S390IPLState netboot is true if ANY IPLB may use netboot */
             ipl->netboot = true;
             /* Fall through to CCW_DEVTYPE_VIRTIO case */
         case CCW_DEVTYPE_VIRTIO:
-            ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
-            ipl->iplb.blk0_len =
+            iplb->len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
+            iplb->blk0_len =
                 cpu_to_be32(S390_IPLB_MIN_CCW_LEN - S390_IPLB_HEADER_LEN);
-            ipl->iplb.pbt = S390_IPL_TYPE_CCW;
-            ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
-            ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
+            iplb->pbt = S390_IPL_TYPE_CCW;
+            iplb->ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
+            iplb->ccw.ssid = ccw_dev->sch->ssid & 3;
             break;
         }
 
@@ -484,8 +499,8 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
             lp = S390_CCW_MACHINE(qdev_get_machine())->loadparm;
         }
 
-        s390_ipl_convert_loadparm((char *)lp, ipl->iplb.loadparm);
-        ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID;
+        s390_ipl_convert_loadparm((char *)lp, iplb->loadparm);
+        iplb->flags |= DIAG308_FLAGS_LP_VALID;
 
         return true;
     }
@@ -493,6 +508,62 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
     return false;
 }
 
+static bool s390_init_all_iplbs(S390IPLState *ipl)
+{
+    int iplb_num = 0;
+    IplParameterBlock iplb_chain[7];
+    DeviceState *dev_st = get_boot_device(0);
+    Object *machine = qdev_get_machine();
+
+    /*
+     * Parse the boot devices.  Generate an IPLB for only the first boot device
+     * which will later be set with DIAG308.
+     */
+    if (!dev_st) {
+        ipl->qipl.chain_len = 0;
+        return false;
+    }
+
+    /* If no machine loadparm was defined fill it with spaces */
+    if (memcmp(S390_CCW_MACHINE(machine)->loadparm, NO_LOADPARM, 8) == 0) {
+        object_property_set_str(machine, "loadparm", "        ", NULL);
+    }
+
+    iplb_num = 1;
+    s390_build_iplb(dev_st, &ipl->iplb);
+
+    /*  Index any fallback boot devices */
+    while (get_boot_device(iplb_num)) {
+        iplb_num++;
+    }
+
+    if (iplb_num > MAX_BOOT_DEVS) {
+        warn_report("Excess boot devices defined! %d boot devices found, "
+                    "but only the first %d will be considered.",
+                    iplb_num, MAX_BOOT_DEVS);
+
+        iplb_num = MAX_BOOT_DEVS;
+    }
+
+    ipl->qipl.chain_len = cpu_to_be16(iplb_num - 1);
+
+    /*
+     * Build fallback IPLBs for any boot devices above index 0, up to a
+     * maximum amount as defined in ipl.h
+     */
+    if (iplb_num > 1) {
+        /* Start at 1 because the IPLB for boot index 0 is not chained */
+        for (int i = 1; i < iplb_num; i++) {
+            dev_st = get_boot_device(i);
+            s390_build_iplb(dev_st, &iplb_chain[i - 1]);
+        }
+
+        ipl->qipl.next_iplb = cpu_to_be64(s390_ipl_map_iplb_chain(iplb_chain));
+    }
+
+    return iplb_num;
+}
+
 static bool is_virtio_ccw_device_of_type(IplParameterBlock *iplb,
                                          int virtio_id)
 {
@@ -620,7 +691,7 @@ void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type)
              * this is the original boot device's SCSI
              * so restore IPL parameter info from it
              */
-            ipl->iplb_valid = s390_gen_initial_iplb(ipl);
+            ipl->iplb_valid = s390_build_iplb(get_boot_device(0), &ipl->iplb);
         }
     }
     if (reset_type == S390_RESET_MODIFIED_CLEAR ||
@@ -714,7 +785,9 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
     if (!ipl->kernel || ipl->iplb_valid) {
         cpu->env.psw.addr = ipl->bios_start_addr;
         if (!ipl->iplb_valid) {
-            ipl->iplb_valid = s390_gen_initial_iplb(ipl);
+            ipl->iplb_valid = s390_init_all_iplbs(ipl);
+        } else {
+            ipl->qipl.chain_len = 0;
         }
     }
     s390_ipl_set_boot_menu(ipl);
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 16/23] s390x: Rebuild IPLB for SCSI device directly from DIAG308
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (14 preceding siblings ...)
  2024-10-23 13:17 ` [PULL 15/23] hw/s390x: Build an IPLB for each boot device Thomas Huth
@ 2024-10-23 13:17 ` Thomas Huth
  2024-10-23 13:17 ` [PULL 17/23] pc-bios/s390x: Enable multi-device boot loop Thomas Huth
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

Because virtio-scsi type devices use a non-architected IPLB pbt code they cannot
be set and stored normally. Instead, the IPLB must be rebuilt during re-ipl.

As s390x does not natively support multiple boot devices, the devno field is
used to store the position in the boot order for the device.

Handling the rebuild as part of DIAG308 removes the need to check the devices
for invalid IPLBs later in the IPL.

Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Acked-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20241020012953.1380075-17-jrossi@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 hw/s390x/ipl.h              | 11 ++++--
 include/hw/s390x/ipl/qipl.h |  3 +-
 hw/s390x/ipl.c              | 74 ++++++-------------------------------
 pc-bios/s390-ccw/jump2ipl.c | 11 ++++--
 target/s390x/diag.c         |  9 ++++-
 5 files changed, 38 insertions(+), 70 deletions(-)

diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 54eb48fd6e..d7d0b7bfd2 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -24,6 +24,7 @@
 
 void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp);
 void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp);
+void s390_rebuild_iplb(uint16_t index, IplParameterBlock *iplb);
 void s390_ipl_update_diag308(IplParameterBlock *iplb);
 int s390_ipl_prepare_pv_header(Error **errp);
 int s390_ipl_pv_unpack(void);
@@ -65,7 +66,8 @@ struct S390IPLState {
     bool enforce_bios;
     bool iplb_valid;
     bool iplb_valid_pv;
-    bool netboot;
+    bool rebuilt_iplb;
+    uint16_t iplb_index;
     /* reset related properties don't have to be migrated or reset */
     enum s390_reset reset_type;
     int reset_cpu_index;
@@ -172,11 +174,14 @@ static inline bool iplb_valid_pv(IplParameterBlock *iplb)
 
 static inline bool iplb_valid(IplParameterBlock *iplb)
 {
+    uint32_t len = be32_to_cpu(iplb->len);
+
     switch (iplb->pbt) {
     case S390_IPL_TYPE_FCP:
-        return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_FCP_LEN;
+        return len >= S390_IPLB_MIN_FCP_LEN;
     case S390_IPL_TYPE_CCW:
-        return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_CCW_LEN;
+        return len >= S390_IPLB_MIN_CCW_LEN;
+    case S390_IPL_TYPE_QEMU_SCSI:
     default:
         return false;
     }
diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h
index 1da4f75aa8..6824391111 100644
--- a/include/hw/s390x/ipl/qipl.h
+++ b/include/hw/s390x/ipl/qipl.h
@@ -29,7 +29,8 @@
  */
 struct QemuIplParameters {
     uint8_t  qipl_flags;
-    uint8_t  reserved1[3];
+    uint8_t  index;
+    uint8_t  reserved1[2];
     uint64_t reserved2;
     uint32_t boot_menu_timeout;
     uint8_t  reserved3[2];
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index b9d741d0b0..dc02b0fdda 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -448,7 +448,6 @@ void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp)
 
 static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
 {
-    S390IPLState *ipl = get_ipl_device();
     CcwDevice *ccw_dev = NULL;
     SCSIDevice *sd;
     int devtype;
@@ -481,9 +480,6 @@ static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
             iplb->ccw.ssid = ccw_dev->sch->ssid & 3;
             break;
         case CCW_DEVTYPE_VIRTIO_NET:
-            /* The S390IPLState netboot is true if ANY IPLB may use netboot */
-            ipl->netboot = true;
-            /* Fall through to CCW_DEVTYPE_VIRTIO case */
         case CCW_DEVTYPE_VIRTIO:
             iplb->len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
             iplb->blk0_len =
@@ -508,6 +504,16 @@ static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
     return false;
 }
 
+void s390_rebuild_iplb(uint16_t dev_index, IplParameterBlock *iplb)
+{
+    S390IPLState *ipl = get_ipl_device();
+    uint16_t index;
+    index = ipl->rebuilt_iplb ? ipl->iplb_index : dev_index;
+
+    ipl->rebuilt_iplb = s390_build_iplb(get_boot_device(index), iplb);
+    ipl->iplb_index = index;
+}
+
 static bool s390_init_all_iplbs(S390IPLState *ipl)
 {
     int iplb_num = 0;
@@ -564,44 +570,6 @@ static bool s390_init_all_iplbs(S390IPLState *ipl)
     return iplb_num;
 }
 
-static bool is_virtio_ccw_device_of_type(IplParameterBlock *iplb,
-                                         int virtio_id)
-{
-    uint8_t cssid;
-    uint8_t ssid;
-    uint16_t devno;
-    uint16_t schid;
-    SubchDev *sch = NULL;
-
-    if (iplb->pbt != S390_IPL_TYPE_CCW) {
-        return false;
-    }
-
-    devno = be16_to_cpu(iplb->ccw.devno);
-    ssid = iplb->ccw.ssid & 3;
-
-    for (schid = 0; schid < MAX_SCHID; schid++) {
-        for (cssid = 0; cssid < MAX_CSSID; cssid++) {
-            sch = css_find_subch(1, cssid, ssid, schid);
-
-            if (sch && sch->devno == devno) {
-                return sch->id.cu_model == virtio_id;
-            }
-        }
-    }
-    return false;
-}
-
-static bool is_virtio_net_device(IplParameterBlock *iplb)
-{
-    return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_NET);
-}
-
-static bool is_virtio_scsi_device(IplParameterBlock *iplb)
-{
-    return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_SCSI);
-}
-
 static void update_machine_ipl_properties(IplParameterBlock *iplb)
 {
     Object *machine = qdev_get_machine();
@@ -641,7 +609,7 @@ void s390_ipl_update_diag308(IplParameterBlock *iplb)
         ipl->iplb = *iplb;
         ipl->iplb_valid = true;
     }
-    ipl->netboot = is_virtio_net_device(iplb);
+
     update_machine_ipl_properties(iplb);
 }
 
@@ -668,32 +636,14 @@ IplParameterBlock *s390_ipl_get_iplb(void)
 void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type)
 {
     S390IPLState *ipl = get_ipl_device();
-
     if (reset_type == S390_RESET_EXTERNAL || reset_type == S390_RESET_REIPL) {
         /* use CPU 0 for full resets */
         ipl->reset_cpu_index = 0;
     } else {
         ipl->reset_cpu_index = cs->cpu_index;
     }
-    ipl->reset_type = reset_type;
 
-    if (reset_type == S390_RESET_REIPL &&
-        ipl->iplb_valid &&
-        !ipl->netboot &&
-        ipl->iplb.pbt == S390_IPL_TYPE_CCW &&
-        is_virtio_scsi_device(&ipl->iplb)) {
-        CcwDevice *ccw_dev = s390_get_ccw_device(get_boot_device(0), NULL);
-
-        if (ccw_dev &&
-            cpu_to_be16(ccw_dev->sch->devno) == ipl->iplb.ccw.devno &&
-            (ccw_dev->sch->ssid & 3) == ipl->iplb.ccw.ssid) {
-            /*
-             * this is the original boot device's SCSI
-             * so restore IPL parameter info from it
-             */
-            ipl->iplb_valid = s390_build_iplb(get_boot_device(0), &ipl->iplb);
-        }
-    }
+    ipl->reset_type = reset_type;
     if (reset_type == S390_RESET_MODIFIED_CLEAR ||
         reset_type == S390_RESET_LOAD_NORMAL ||
         reset_type == S390_RESET_PV) {
diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
index 8db1764ff3..99d18947d1 100644
--- a/pc-bios/s390-ccw/jump2ipl.c
+++ b/pc-bios/s390-ccw/jump2ipl.c
@@ -39,10 +39,15 @@ int jump_to_IPL_code(uint64_t address)
     write_subsystem_identification();
     write_iplb_location();
 
-    /* prevent unknown IPL types in the guest */
+    /*
+     * The IPLB for QEMU SCSI type devices must be rebuilt during re-ipl. The
+     * iplb.devno is set to the boot position of the target SCSI device.
+     */
     if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
-        iplb.pbt = S390_IPL_TYPE_CCW;
-        set_iplb(&iplb);
+        iplb.devno = qipl.index;
+        if (!set_iplb(&iplb)) {
+            panic("Failed to set IPLB");
+        }
     }
 
     /*
diff --git a/target/s390x/diag.c b/target/s390x/diag.c
index 27ffd48576..a1fd54ddac 100644
--- a/target/s390x/diag.c
+++ b/target/s390x/diag.c
@@ -133,7 +133,14 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
 
         valid = subcode == DIAG308_PV_SET ? iplb_valid_pv(iplb) : iplb_valid(iplb);
         if (!valid) {
-            env->regs[r1 + 1] = DIAG_308_RC_INVALID;
+            if (subcode == DIAG308_SET && iplb->pbt == S390_IPL_TYPE_QEMU_SCSI) {
+                s390_rebuild_iplb(iplb->devno, iplb);
+                s390_ipl_update_diag308(iplb);
+                env->regs[r1 + 1] = DIAG_308_RC_OK;
+            } else {
+                env->regs[r1 + 1] = DIAG_308_RC_INVALID;
+            }
+
             goto out;
         }
 
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 17/23] pc-bios/s390x: Enable multi-device boot loop
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (15 preceding siblings ...)
  2024-10-23 13:17 ` [PULL 16/23] s390x: Rebuild IPLB for SCSI device directly from DIAG308 Thomas Huth
@ 2024-10-23 13:17 ` Thomas Huth
  2024-10-23 13:17 ` [PULL 18/23] docs/system: Update documentation for s390x IPL Thomas Huth
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

Allow attempts to boot from multiple IPL devices. If the first device fails to
IPL, select the pre-built IPLB for the next device in the boot order and attempt
to IPL from it. Continue this process until IPL is successful or there are no
devices left to try.

Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20241020012953.1380075-18-jrossi@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/iplb.h     | 24 ++++++++++++++++++++
 pc-bios/s390-ccw/jump2ipl.c |  7 +++---
 pc-bios/s390-ccw/main.c     | 45 +++++++++++++++++++++++--------------
 pc-bios/s390-ccw/netmain.c  |  2 +-
 4 files changed, 57 insertions(+), 21 deletions(-)

diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index 16643f5879..08f259ff31 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -17,9 +17,11 @@
 #endif
 
 #include <qipl.h>
+#include <string.h>
 
 extern QemuIplParameters qipl;
 extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
+extern bool have_iplb;
 
 #define S390_IPL_TYPE_FCP 0x00
 #define S390_IPL_TYPE_CCW 0x02
@@ -49,4 +51,26 @@ static inline bool set_iplb(IplParameterBlock *iplb)
     return manage_iplb(iplb, false);
 }
 
+/*
+ * The IPL started on the device, but failed in some way.  If the IPLB chain
+ * still has more devices left to try, use the next device in order.
+ */
+static inline bool load_next_iplb(void)
+{
+    IplParameterBlock *next_iplb;
+
+    if (qipl.chain_len < 1) {
+        return false;
+    }
+
+    qipl.index++;
+    next_iplb = (IplParameterBlock *) qipl.next_iplb;
+    memcpy(&iplb, next_iplb, sizeof(IplParameterBlock));
+
+    qipl.chain_len--;
+    qipl.next_iplb = qipl.next_iplb + sizeof(IplParameterBlock);
+
+    return true;
+}
+
 #endif /* IPLB_H */
diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
index 99d18947d1..86321d0f46 100644
--- a/pc-bios/s390-ccw/jump2ipl.c
+++ b/pc-bios/s390-ccw/jump2ipl.c
@@ -45,9 +45,10 @@ int jump_to_IPL_code(uint64_t address)
      */
     if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
         iplb.devno = qipl.index;
-        if (!set_iplb(&iplb)) {
-            panic("Failed to set IPLB");
-        }
+    }
+
+    if (have_iplb && !set_iplb(&iplb)) {
+        panic("Failed to set IPLB");
     }
 
     /*
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index ab4709e16e..a4d1c05aac 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -23,7 +23,7 @@ static SubChannelId blk_schid = { .one = 1 };
 static char loadparm_str[LOADPARM_LEN + 1];
 QemuIplParameters qipl;
 IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
-static bool have_iplb;
+bool have_iplb;
 static uint16_t cutype;
 LowCore *lowcore; /* Yes, this *is* a pointer to address 0 */
 
@@ -55,6 +55,12 @@ void write_iplb_location(void)
     }
 }
 
+static void copy_qipl(void)
+{
+    QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
+    memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
+}
+
 unsigned int get_loadparm_index(void)
 {
     return atoi(loadparm_str);
@@ -152,6 +158,7 @@ static void menu_setup(void)
 
     /* If loadparm was set to any other value, then do not enable menu */
     if (memcmp(loadparm_str, LOADPARM_EMPTY, LOADPARM_LEN) != 0) {
+        menu_set_parms(qipl.qipl_flags & ~BOOT_MENU_FLAG_MASK, 0);
         return;
     }
 
@@ -183,7 +190,6 @@ static void css_setup(void)
 static void boot_setup(void)
 {
     char lpmsg[] = "LOADPARM=[________]\n";
-    have_iplb = store_iplb(&iplb);
 
     if (memcmp(iplb.loadparm, NO_LOADPARM, LOADPARM_LEN) != 0) {
         ebcdic_to_ascii((char *) iplb.loadparm, loadparm_str, LOADPARM_LEN);
@@ -191,6 +197,10 @@ static void boot_setup(void)
         sclp_get_loadparm_ascii(loadparm_str);
     }
 
+    if (have_iplb) {
+        menu_setup();
+    }
+
     memcpy(lpmsg + 10, loadparm_str, 8);
     puts(lpmsg);
 
@@ -208,6 +218,7 @@ static bool find_boot_device(void)
 
     switch (iplb.pbt) {
     case S390_IPL_TYPE_CCW:
+        vdev->scsi_device_selected = false;
         debug_print_int("device no. ", iplb.ccw.devno);
         blk_schid.ssid = iplb.ccw.ssid & 0x3;
         debug_print_int("ssid ", blk_schid.ssid);
@@ -231,15 +242,8 @@ static bool find_boot_device(void)
 static int virtio_setup(void)
 {
     VDev *vdev = virtio_get_device();
-    QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
     int ret;
 
-    memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
-
-    if (have_iplb) {
-        menu_setup();
-    }
-
     switch (vdev->senseid.cu_model) {
     case VIRTIO_ID_NET:
         puts("Network boot device detected");
@@ -271,10 +275,9 @@ static void ipl_boot_device(void)
         dasd_ipl(blk_schid, cutype);
         break;
     case CU_TYPE_VIRTIO:
-        if (virtio_setup()) {
-            return;    /* Only returns in case of errors */
+        if (virtio_setup() == 0) {
+            zipl_load();
         }
-        zipl_load();
         break;
     default:
         printf("Attempting to boot from unexpected device type 0x%X\n", cutype);
@@ -307,14 +310,22 @@ static void probe_boot_device(void)
 
 void main(void)
 {
+    copy_qipl();
     sclp_setup();
     css_setup();
-    boot_setup();
-    if (have_iplb && find_boot_device()) {
-        ipl_boot_device();
-    } else {
+    have_iplb = store_iplb(&iplb);
+    if (!have_iplb) {
         probe_boot_device();
     }
 
-    panic("Failed to IPL. Halting...");
+    while (have_iplb) {
+        boot_setup();
+        if (have_iplb && find_boot_device()) {
+            ipl_boot_device();
+        }
+        have_iplb = load_next_iplb();
+    }
+
+    panic("No suitable device for IPL. Halting...");
+
 }
diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
index d1a6c9a91c..e46e470db4 100644
--- a/pc-bios/s390-ccw/netmain.c
+++ b/pc-bios/s390-ccw/netmain.c
@@ -478,7 +478,7 @@ static bool virtio_setup(void)
      */
     enable_mss_facility();
 
-    if (store_iplb(&iplb)) {
+    if (have_iplb || store_iplb(&iplb)) {
         IPL_assert(iplb.pbt == S390_IPL_TYPE_CCW, "IPL_TYPE_CCW expected");
         dev_no = iplb.ccw.devno;
         debug_print_int("device no. ", dev_no);
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 18/23] docs/system: Update documentation for s390x IPL
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (16 preceding siblings ...)
  2024-10-23 13:17 ` [PULL 17/23] pc-bios/s390x: Enable multi-device boot loop Thomas Huth
@ 2024-10-23 13:17 ` Thomas Huth
  2024-10-23 13:17 ` [PULL 19/23] tests/qtest: Add s390x boot order tests to cdrom-test.c Thomas Huth
                   ` (5 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

Update docs to show that s390x PC BIOS can support more than one boot device.

Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20241020012953.1380075-19-jrossi@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 docs/system/bootindex.rst         | 7 ++++---
 docs/system/s390x/bootdevices.rst | 9 ++++++---
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/docs/system/bootindex.rst b/docs/system/bootindex.rst
index 8b057f812f..988f7b3beb 100644
--- a/docs/system/bootindex.rst
+++ b/docs/system/bootindex.rst
@@ -49,10 +49,11 @@ Limitations
 -----------
 
 Some firmware has limitations on which devices can be considered for
-booting.  For instance, the PC BIOS boot specification allows only one
-disk to be bootable.  If boot from disk fails for some reason, the BIOS
+booting.  For instance, the x86 PC BIOS boot specification allows only one
+disk to be bootable.  If boot from disk fails for some reason, the x86 BIOS
 won't retry booting from other disk.  It can still try to boot from
-floppy or net, though.
+floppy or net, though. In the case of s390x BIOS, the BIOS will try up to
+8 total devices, any number of which may be disks.
 
 Sometimes, firmware cannot map the device path QEMU wants firmware to
 boot from to a boot method.  It doesn't happen for devices the firmware
diff --git a/docs/system/s390x/bootdevices.rst b/docs/system/s390x/bootdevices.rst
index c97efb8fc0..1a1a764c1c 100644
--- a/docs/system/s390x/bootdevices.rst
+++ b/docs/system/s390x/bootdevices.rst
@@ -6,9 +6,7 @@ Booting with bootindex parameter
 
 For classical mainframe guests (i.e. LPAR or z/VM installations), you always
 have to explicitly specify the disk where you want to boot from (or "IPL" from,
-in s390x-speak -- IPL means "Initial Program Load"). In particular, there can
-also be only one boot device according to the architecture specification, thus
-specifying multiple boot devices is not possible (yet).
+in s390x-speak -- IPL means "Initial Program Load").
 
 So for booting an s390x guest in QEMU, you should always mark the
 device where you want to boot from with the ``bootindex`` property, for
@@ -17,6 +15,11 @@ example::
  qemu-system-s390x -drive if=none,id=dr1,file=guest.qcow2 \
                    -device virtio-blk,drive=dr1,bootindex=1
 
+Multiple devices may have a bootindex. The lowest bootindex is assigned to the
+device to IPL first.  If the IPL fails for the first, the device with the second
+lowest bootindex will be tried and so on until IPL is successful or there are no
+remaining boot devices to try.
+
 For booting from a CD-ROM ISO image (which needs to include El-Torito boot
 information in order to be bootable), it is recommended to specify a ``scsi-cd``
 device, for example like this::
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 19/23] tests/qtest: Add s390x boot order tests to cdrom-test.c
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (17 preceding siblings ...)
  2024-10-23 13:17 ` [PULL 18/23] docs/system: Update documentation for s390x IPL Thomas Huth
@ 2024-10-23 13:17 ` Thomas Huth
  2024-10-23 13:17 ` [PULL 20/23] pc-bios/s390-ccw: Clarify alignment is in bytes Thomas Huth
                   ` (4 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jared Rossi

From: Jared Rossi <jrossi@linux.ibm.com>

Add two new qtests to verify that a valid IPL device can successfully boot after
failed IPL attempts from one or more invalid devices.

cdrom-test/as-fallback-device: Defines the primary boot target as a device that
is invalid for IPL and a second boot target that is valid for IPL. Ensures that
the valid device will be selected after the initial failed IPL.

cdrom-test/as-last-option: Defines the maximum number of boot devices (8)
where only the final entry in the boot order is valid. Ensures that a valid
device will be selected even after multiple failed IPL attempts from both
virtio-blk and virtio-scsi device types.

Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20241020012953.1380075-20-jrossi@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 tests/qtest/cdrom-test.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/tests/qtest/cdrom-test.c b/tests/qtest/cdrom-test.c
index 9d72b24e4b..c86725a511 100644
--- a/tests/qtest/cdrom-test.c
+++ b/tests/qtest/cdrom-test.c
@@ -213,6 +213,30 @@ static void add_s390x_tests(void)
                         "-drive driver=null-co,read-zeroes=on,if=none,id=d1 "
                         "-device virtio-blk,drive=d2,bootindex=1 "
                         "-drive if=none,id=d2,media=cdrom,file=", test_cdboot);
+    qtest_add_data_func("cdrom/boot/as-fallback-device",
+                        "-device virtio-serial -device virtio-scsi "
+                        "-device virtio-blk,drive=d1,bootindex=1 "
+                        "-drive driver=null-co,read-zeroes=on,if=none,id=d1 "
+                        "-device virtio-blk,drive=d2,bootindex=2 "
+                        "-drive if=none,id=d2,media=cdrom,file=", test_cdboot);
+    qtest_add_data_func("cdrom/boot/as-last-option",
+                        "-device virtio-serial -device virtio-scsi "
+                        "-device virtio-blk,drive=d1,bootindex=1 "
+                        "-drive driver=null-co,read-zeroes=on,if=none,id=d1 "
+                        "-device virtio-blk,drive=d2,bootindex=2 "
+                        "-drive driver=null-co,read-zeroes=on,if=none,id=d2 "
+                        "-device virtio-blk,drive=d3,bootindex=3 "
+                        "-drive driver=null-co,read-zeroes=on,if=none,id=d3 "
+                        "-device scsi-hd,drive=d4,bootindex=4 "
+                        "-drive driver=null-co,read-zeroes=on,if=none,id=d4 "
+                        "-device scsi-hd,drive=d5,bootindex=5 "
+                        "-drive driver=null-co,read-zeroes=on,if=none,id=d5 "
+                        "-device virtio-blk,drive=d6,bootindex=6 "
+                        "-drive driver=null-co,read-zeroes=on,if=none,id=d6 "
+                        "-device scsi-hd,drive=d7,bootindex=7 "
+                        "-drive driver=null-co,read-zeroes=on,if=none,id=d7 "
+                        "-device scsi-cd,drive=d8,bootindex=8 "
+                        "-drive if=none,id=d8,media=cdrom,file=", test_cdboot);
     if (qtest_has_device("x-terminal3270")) {
         qtest_add_data_func("cdrom/boot/without-bootindex",
                             "-device virtio-scsi -device virtio-serial "
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 20/23] pc-bios/s390-ccw: Clarify alignment is in bytes
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (18 preceding siblings ...)
  2024-10-23 13:17 ` [PULL 19/23] tests/qtest: Add s390x boot order tests to cdrom-test.c Thomas Huth
@ 2024-10-23 13:17 ` Thomas Huth
  2024-10-23 13:17 ` [PULL 21/23] pc-bios/s390-ccw: Don't generate TEXTRELs Thomas Huth
                   ` (3 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jens Remus, Marc Hartmayer

From: Jens Remus <jremus@linux.ibm.com>

The assembler directive .align [1] has architecture-dependent behavior,
which may be ambiguous for the reader. Some architectures perform the
alignment in bytes, others in power of two. s390 does in bytes.

Use the directive .balign [2] instead, to clarify that the alignment
request is in bytes. No functional change.

[1] https://sourceware.org/binutils/docs/as/Align.html
[2] https://sourceware.org/binutils/docs/as/Balign.html

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Message-ID: <20241001153618.17791-2-mhartmay@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/start.S | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S
index 061b06591c..576fc12c06 100644
--- a/pc-bios/s390-ccw/start.S
+++ b/pc-bios/s390-ccw/start.S
@@ -112,7 +112,7 @@ io_new_code:
     lctlg   %c6,%c6,0(%r15)
     br      %r14
 
-    .align  8
+    .balign 8
 bss_start_literal:
     .quad   __bss_start
 disabled_wait_psw:
@@ -125,7 +125,7 @@ io_new_mask:
     .quad   0x0000000180000000
 
 .bss
-    .align  8
+    .balign 8
 stack:
     .space  STACK_SIZE
     .size   stack,STACK_SIZE
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 21/23] pc-bios/s390-ccw: Don't generate TEXTRELs
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (19 preceding siblings ...)
  2024-10-23 13:17 ` [PULL 20/23] pc-bios/s390-ccw: Clarify alignment is in bytes Thomas Huth
@ 2024-10-23 13:17 ` Thomas Huth
  2024-10-23 13:17 ` [PULL 22/23] pc-bios/s390-ccw: Introduce `EXTRA_LDFLAGS` Thomas Huth
                   ` (2 subsequent siblings)
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Jens Remus, Marc Hartmayer

From: Jens Remus <jremus@linux.ibm.com>

Commit 7cd50cbe4ca3 ("pc-bios/s390-ccw: Don't use __bss_start with the
"larl" instruction") introduced the address constant bss_start_literal
for __bss_start in the .text section, which introduced a relocation in
code (i.e. TEXTREL). The dedicated constant is required, as __bss_start
may not necessarily be aligned on a 2-byte boundary (see subject commit
for details).

Move the constant to the .data section to get rid of the relocation in
the .text section. Add the linker option -z text to prevent TEXTRELs to
get introduced in the future.

Note that the R_390_RELATIVE relocations are taken care of by function
glue() in include/hw/elf_ops.h.inc introduced by commit 5dce07e1cb67
("elf-loader: Provide the possibility to relocate s390 ELF files").

Reported-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Message-ID: <20241001153618.17791-3-mhartmay@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/Makefile | 2 +-
 pc-bios/s390-ccw/start.S  | 7 +++++--
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index db9e8f0892..38254e22df 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -46,7 +46,7 @@ EXTRA_CFLAGS += -fwrapv -fno-strict-aliasing -fno-asynchronous-unwind-tables
 EXTRA_CFLAGS += -msoft-float
 EXTRA_CFLAGS += -std=gnu99
 EXTRA_CFLAGS += $(LIBC_INC) $(LIBNET_INC)
-LDFLAGS += -Wl,-pie -nostdlib -z noexecstack
+LDFLAGS += -Wl,-pie -nostdlib -z noexecstack -z text
 
 cc-test = $(CC) -Werror $1 -c -o /dev/null -xc /dev/null >/dev/null 2>/dev/null
 cc-option = if $(call cc-test, $1); then \
diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S
index 576fc12c06..b70213e412 100644
--- a/pc-bios/s390-ccw/start.S
+++ b/pc-bios/s390-ccw/start.S
@@ -113,8 +113,6 @@ io_new_code:
     br      %r14
 
     .balign 8
-bss_start_literal:
-    .quad   __bss_start
 disabled_wait_psw:
     .quad   0x0002000180000000,0x0000000000000000
 enabled_wait_psw:
@@ -124,6 +122,11 @@ external_new_mask:
 io_new_mask:
     .quad   0x0000000180000000
 
+.data
+    .balign 8
+bss_start_literal:
+    .quad   __bss_start
+
 .bss
     .balign 8
 stack:
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 22/23] pc-bios/s390-ccw: Introduce `EXTRA_LDFLAGS`
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (20 preceding siblings ...)
  2024-10-23 13:17 ` [PULL 21/23] pc-bios/s390-ccw: Don't generate TEXTRELs Thomas Huth
@ 2024-10-23 13:17 ` Thomas Huth
  2024-10-23 13:17 ` [PULL 23/23] pc-bios/s390-ccw: Update s390-ccw.img with the full boot order support feature Thomas Huth
  2024-10-25 12:34 ` [PULL 00/23] s390-ccw bios update Peter Maydell
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Marc Hartmayer

From: Marc Hartmayer <mhartmay@linux.ibm.com>

Some packaging tools want to override `LDFLAGS` when building QEMU, this will
result in a build error as most likely no `-nostdlib` flag is passed. Introduce
`EXTRA_LDFLAGS` so that the packager can override `LDFLAGS` without breaking the
build.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Message-ID: <20241001153618.17791-4-mhartmay@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
[thuth: Drop the hunk to netbook.mak which is not necessary anymore]
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw/Makefile | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 38254e22df..dc69dd484f 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -4,6 +4,7 @@ all: build-all
 
 include config-host.mak
 CFLAGS = -O2 -g -I $(SRC_PATH)/../../include/hw/s390x/ipl
+LDFLAGS ?=
 MAKEFLAGS += -rR
 
 GIT_SUBMODULES = roms/SLOF
@@ -46,7 +47,7 @@ EXTRA_CFLAGS += -fwrapv -fno-strict-aliasing -fno-asynchronous-unwind-tables
 EXTRA_CFLAGS += -msoft-float
 EXTRA_CFLAGS += -std=gnu99
 EXTRA_CFLAGS += $(LIBC_INC) $(LIBNET_INC)
-LDFLAGS += -Wl,-pie -nostdlib -z noexecstack -z text
+EXTRA_LDFLAGS += -Wl,-pie -nostdlib -z noexecstack -z text
 
 cc-test = $(CC) -Werror $1 -c -o /dev/null -xc /dev/null >/dev/null 2>/dev/null
 cc-option = if $(call cc-test, $1); then \
@@ -111,7 +112,7 @@ libnet.a: $(LIBNETOBJS)
 build-all: s390-ccw.img
 
 s390-ccw.elf: $(OBJECTS) libnet.a libc.a
-	$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^,Linking)
+	$(call quiet-command,$(CC) $(EXTRA_LDFLAGS) $(LDFLAGS) -o $@ $^,Linking)
 
 s390-ccw.img: s390-ccw.elf
 	$(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,Stripping $< into)
-- 
2.47.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PULL 23/23] pc-bios/s390-ccw: Update s390-ccw.img with the full boot order support feature
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (21 preceding siblings ...)
  2024-10-23 13:17 ` [PULL 22/23] pc-bios/s390-ccw: Introduce `EXTRA_LDFLAGS` Thomas Huth
@ 2024-10-23 13:17 ` Thomas Huth
  2024-10-25 12:34 ` [PULL 00/23] s390-ccw bios update Peter Maydell
  23 siblings, 0 replies; 27+ messages in thread
From: Thomas Huth @ 2024-10-23 13:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell

This update includes the full boot order support feature from Jared Rossi
and the TEXTREL fix from Jens Remus.

Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 pc-bios/s390-ccw.img | Bin 42608 -> 79608 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)

diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index f0d9ef6d4d86eb8d8ace19cac3929b9c06ae826f..f9bac253066d71b64659a76d216e04040a365355 100644
GIT binary patch
literal 79608
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

literal 42608
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
KJ?w*7AO0Wc<54pJ

-- 
2.47.0



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PULL 00/23] s390-ccw bios update
  2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
                   ` (22 preceding siblings ...)
  2024-10-23 13:17 ` [PULL 23/23] pc-bios/s390-ccw: Update s390-ccw.img with the full boot order support feature Thomas Huth
@ 2024-10-25 12:34 ` Peter Maydell
  23 siblings, 0 replies; 27+ messages in thread
From: Peter Maydell @ 2024-10-25 12:34 UTC (permalink / raw)
  To: Thomas Huth; +Cc: qemu-devel

On Wed, 23 Oct 2024 at 14:17, Thomas Huth <thuth@redhat.com> wrote:
>
> The following changes since commit 6f625ce2f21d6a1243065d236298277c56f972d5:
>
>   Merge tag 'pull-request-2024-10-21' of https://gitlab.com/thuth/qemu into staging (2024-10-21 17:12:59 +0100)
>
> are available in the Git repository at:
>
>   https://gitlab.com/thuth/qemu.git tags/pull-request-2024-10-23
>
> for you to fetch changes up to 239e351ec415ff3673d9da70d70ca3a5dd95a2f0:
>
>   pc-bios/s390-ccw: Update s390-ccw.img with the full boot order support feature (2024-10-23 06:53:44 +0200)
>
> ----------------------------------------------------------------
> * Allow multiple boot devices (via bootindex properties) on s390x
> * Avoid TEXTREL relocations in the s390-ccw.img firmware
>


Applied, thanks.

Please update the changelog at https://wiki.qemu.org/ChangeLog/9.2
for any user-visible changes.

-- PMM


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PULL 15/23] hw/s390x: Build an IPLB for each boot device
  2024-10-23 13:17 ` [PULL 15/23] hw/s390x: Build an IPLB for each boot device Thomas Huth
@ 2025-06-16 10:04   ` Philippe Mathieu-Daudé
  2025-06-16 15:04     ` Jared Rossi
  0 siblings, 1 reply; 27+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-06-16 10:04 UTC (permalink / raw)
  To: Thomas Huth, qemu-devel; +Cc: Peter Maydell, Jared Rossi

Hi,

On 23/10/24 15:17, Thomas Huth wrote:
> From: Jared Rossi <jrossi@linux.ibm.com>
> 
> Build an IPLB for any device with a bootindex (up to a maximum of 8 devices).
> 
> The IPLB chain is placed immediately before the BIOS in memory. Because this
> is not a fixed address, the location of the next IPLB and number of remaining
> boot devices is stored in the QIPL global variable for possible later access by
> the guest during IPL.
> 
> Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
> Reviewed-by: Thomas Huth <thuth@redhat.com>
> Message-ID: <20241020012953.1380075-16-jrossi@linux.ibm.com>
> [thuth: Fix endianness problem when accessing the qipl structure]
> Signed-off-by: Thomas Huth <thuth@redhat.com>
> ---
>   hw/s390x/ipl.h              |   1 +
>   include/hw/s390x/ipl/qipl.h |   4 +-
>   hw/s390x/ipl.c              | 129 ++++++++++++++++++++++++++++--------
>   3 files changed, 105 insertions(+), 29 deletions(-)

> diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
> index 656996b500..b9d741d0b0 100644
> --- a/hw/s390x/ipl.c
> +++ b/hw/s390x/ipl.c


> +static uint64_t s390_ipl_map_iplb_chain(IplParameterBlock *iplb_chain)
> +{
> +    S390IPLState *ipl = get_ipl_device();
> +    uint16_t count = be16_to_cpu(ipl->qipl.chain_len);
> +    uint64_t len = sizeof(IplParameterBlock) * count;
> +    uint64_t chain_addr = find_iplb_chain_addr(ipl->bios_start_addr, count);
> +
> +    cpu_physical_memory_write(chain_addr, iplb_chain, len);

This patch introduces a call to a legacy API (documented since at least
2017 in commit b7ecba0f6f6: "docs/devel/loads-stores.rst: Document our
various load and store APIs"). Can we access the device address space 
instead?

> +    return chain_addr;
> +}



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PULL 15/23] hw/s390x: Build an IPLB for each boot device
  2025-06-16 10:04   ` Philippe Mathieu-Daudé
@ 2025-06-16 15:04     ` Jared Rossi
  0 siblings, 0 replies; 27+ messages in thread
From: Jared Rossi @ 2025-06-16 15:04 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Thomas Huth, qemu-devel; +Cc: Peter Maydell

Hi Philippe,

I update this to use the proper API call.

Regards,
Jared Rossi

On 6/16/25 6:04 AM, Philippe Mathieu-Daudé wrote:
> Hi,
>
> On 23/10/24 15:17, Thomas Huth wrote:
>> From: Jared Rossi <jrossi@linux.ibm.com>
>>
>> Build an IPLB for any device with a bootindex (up to a maximum of 8 
>> devices).
>>
>> The IPLB chain is placed immediately before the BIOS in memory. 
>> Because this
>> is not a fixed address, the location of the next IPLB and number of 
>> remaining
>> boot devices is stored in the QIPL global variable for possible later 
>> access by
>> the guest during IPL.
>>
>> Signed-off-by: Jared Rossi <jrossi@linux.ibm.com>
>> Reviewed-by: Thomas Huth <thuth@redhat.com>
>> Message-ID: <20241020012953.1380075-16-jrossi@linux.ibm.com>
>> [thuth: Fix endianness problem when accessing the qipl structure]
>> Signed-off-by: Thomas Huth <thuth@redhat.com>
>> ---
>>   hw/s390x/ipl.h              |   1 +
>>   include/hw/s390x/ipl/qipl.h |   4 +-
>>   hw/s390x/ipl.c              | 129 ++++++++++++++++++++++++++++--------
>>   3 files changed, 105 insertions(+), 29 deletions(-)
>
>> diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
>> index 656996b500..b9d741d0b0 100644
>> --- a/hw/s390x/ipl.c
>> +++ b/hw/s390x/ipl.c
>
>
>> +static uint64_t s390_ipl_map_iplb_chain(IplParameterBlock *iplb_chain)
>> +{
>> +    S390IPLState *ipl = get_ipl_device();
>> +    uint16_t count = be16_to_cpu(ipl->qipl.chain_len);
>> +    uint64_t len = sizeof(IplParameterBlock) * count;
>> +    uint64_t chain_addr = find_iplb_chain_addr(ipl->bios_start_addr, 
>> count);
>> +
>> +    cpu_physical_memory_write(chain_addr, iplb_chain, len);
>
> This patch introduces a call to a legacy API (documented since at least
> 2017 in commit b7ecba0f6f6: "docs/devel/loads-stores.rst: Document our
> various load and store APIs"). Can we access the device address space 
> instead?
>
>> +    return chain_addr;
>> +}
>



^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2025-06-16 15:05 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-23 13:16 [PULL 00/23] s390-ccw bios update Thomas Huth
2024-10-23 13:16 ` [PULL 01/23] hw/s390x/ipl: Provide more memory to the s390-ccw.img firmware Thomas Huth
2024-10-23 13:16 ` [PULL 02/23] pc-bios/s390-ccw: Use the libc from SLOF and remove sclp prints Thomas Huth
2024-10-23 13:16 ` [PULL 03/23] pc-bios/s390-ccw: Link the netboot code into the main s390-ccw.img binary Thomas Huth
2024-10-23 13:16 ` [PULL 04/23] hw/s390x: Remove the possibility to load the s390-netboot.img binary Thomas Huth
2024-10-23 13:16 ` [PULL 05/23] pc-bios/s390-ccw: Merge netboot.mak into the main Makefile Thomas Huth
2024-10-23 13:16 ` [PULL 06/23] docs/system/s390x/bootdevices: Update the documentation about network booting Thomas Huth
2024-10-23 13:16 ` [PULL 07/23] pc-bios/s390-ccw: Remove panics from ISO IPL path Thomas Huth
2024-10-23 13:16 ` [PULL 08/23] pc-bios/s390-ccw: Remove panics from ECKD " Thomas Huth
2024-10-23 13:16 ` [PULL 09/23] pc-bios/s390-ccw: Remove panics from SCSI " Thomas Huth
2024-10-23 13:16 ` [PULL 10/23] pc-bios/s390-ccw: Remove panics from DASD " Thomas Huth
2024-10-23 13:16 ` [PULL 11/23] pc-bios/s390-ccw: Remove panics from Netboot " Thomas Huth
2024-10-23 13:16 ` [PULL 12/23] pc-bios/s390-ccw: Enable failed IPL to return after error Thomas Huth
2024-10-23 13:17 ` [PULL 13/23] include/hw/s390x: Add include files for common IPL structs Thomas Huth
2024-10-23 13:17 ` [PULL 14/23] s390x: Add individual loadparm assignment to CCW device Thomas Huth
2024-10-23 13:17 ` [PULL 15/23] hw/s390x: Build an IPLB for each boot device Thomas Huth
2025-06-16 10:04   ` Philippe Mathieu-Daudé
2025-06-16 15:04     ` Jared Rossi
2024-10-23 13:17 ` [PULL 16/23] s390x: Rebuild IPLB for SCSI device directly from DIAG308 Thomas Huth
2024-10-23 13:17 ` [PULL 17/23] pc-bios/s390x: Enable multi-device boot loop Thomas Huth
2024-10-23 13:17 ` [PULL 18/23] docs/system: Update documentation for s390x IPL Thomas Huth
2024-10-23 13:17 ` [PULL 19/23] tests/qtest: Add s390x boot order tests to cdrom-test.c Thomas Huth
2024-10-23 13:17 ` [PULL 20/23] pc-bios/s390-ccw: Clarify alignment is in bytes Thomas Huth
2024-10-23 13:17 ` [PULL 21/23] pc-bios/s390-ccw: Don't generate TEXTRELs Thomas Huth
2024-10-23 13:17 ` [PULL 22/23] pc-bios/s390-ccw: Introduce `EXTRA_LDFLAGS` Thomas Huth
2024-10-23 13:17 ` [PULL 23/23] pc-bios/s390-ccw: Update s390-ccw.img with the full boot order support feature Thomas Huth
2024-10-25 12:34 ` [PULL 00/23] s390-ccw bios update Peter Maydell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).