aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pc-bios/s390-ccw.imgbin42608 -> 42608 bytes
-rw-r--r--pc-bios/s390-ccw/Makefile7
-rw-r--r--pc-bios/s390-ccw/bootmap.c47
-rw-r--r--pc-bios/s390-ccw/bootmap.h7
-rw-r--r--pc-bios/s390-ccw/jump2ipl.c45
-rw-r--r--pc-bios/s390-ccw/main.c172
-rw-r--r--pc-bios/s390-ccw/s390-ccw.h9
-rw-r--r--pc-bios/s390-ccw/start.S5
-rw-r--r--pc-bios/s390-ccw/virtio-blkdev.c7
-rw-r--r--pc-bios/s390-ccw/virtio-scsi.c28
-rw-r--r--pc-bios/s390-ccw/virtio-scsi.h2
-rw-r--r--pc-bios/s390-netboot.imgbin67232 -> 67232 bytes
-rw-r--r--tests/qtest/cdrom-test.c12
13 files changed, 218 insertions, 123 deletions
diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index 3074686..5b57ea2 100644
--- a/pc-bios/s390-ccw.img
+++ b/pc-bios/s390-ccw.img
Binary files differ
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 3eb7850..29fd901 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -30,10 +30,11 @@ 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
QEMU_CFLAGS := -Wall $(filter -W%, $(QEMU_CFLAGS))
-QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
-QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
-QEMU_CFLAGS += -fno-asynchronous-unwind-tables
+QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -fno-common -fPIE
+QEMU_CFLAGS += -fwrapv -fno-strict-aliasing -fno-asynchronous-unwind-tables
QEMU_CFLAGS += $(call cc-option, $(QEMU_CFLAGS), -fno-stack-protector)
+QEMU_CFLAGS += -msoft-float -march=z900
+QEMU_CFLAGS += -std=gnu99
LDFLAGS += -Wl,-pie -nostdlib
build-all: s390-ccw.img s390-netboot.img
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 9720567..44df7d1 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -10,6 +10,7 @@
#include "libc.h"
#include "s390-ccw.h"
+#include "s390-arch.h"
#include "bootmap.h"
#include "virtio.h"
#include "bswap.h"
@@ -163,7 +164,7 @@ static bool find_zipl_boot_menu_banner(int *offset)
int i;
/* Menu banner starts with "zIPL" */
- for (i = 0; i < virtio_get_block_size() - 4; i++) {
+ for (i = 0; i <= virtio_get_block_size() - 4; i++) {
if (magic_match(s2_cur_blk + i, ZIPL_MAGIC_EBCDIC)) {
*offset = i;
return true;
@@ -192,7 +193,7 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
for (i = 0; i < STAGE2_BLK_CNT_MAX; i++) {
cur_block_nr = eckd_block_num(&s1b->seek[i].chs);
- if (!cur_block_nr) {
+ if (!cur_block_nr || is_null_block_number(cur_block_nr)) {
break;
}
@@ -272,7 +273,8 @@ static void run_eckd_boot_script(block_number_t bmt_block_nr,
IPL_assert(bms->entry[i].type == BOOT_SCRIPT_EXEC,
"Unknown script entry type");
- jump_to_IPL_code(bms->entry[i].address.load_address); /* no return */
+ write_reset_psw(bms->entry[i].address.load_address); /* no return */
+ jump_to_IPL_code(0); /* no return */
}
static void ipl_eckd_cdl(void)
@@ -289,11 +291,18 @@ static void ipl_eckd_cdl(void)
read_block(1, ipl2, "Cannot read IPL2 record at block 1");
mbr = &ipl2->mbr;
- IPL_assert(magic_match(mbr, ZIPL_MAGIC), "No zIPL section in IPL2 record.");
- IPL_assert(block_size_ok(mbr->blockptr.xeckd.bptr.size),
- "Bad block size in zIPL section of IPL2 record.");
- IPL_assert(mbr->dev_type == DEV_TYPE_ECKD,
- "Non-ECKD device type in zIPL section of IPL2 record.");
+ if (!magic_match(mbr, ZIPL_MAGIC)) {
+ sclp_print("No zIPL section in IPL2 record.\n");
+ return;
+ }
+ if (!block_size_ok(mbr->blockptr.xeckd.bptr.size)) {
+ sclp_print("Bad block size in zIPL section of IPL2 record.\n");
+ return;
+ }
+ if (!mbr->dev_type == DEV_TYPE_ECKD) {
+ sclp_print("Non-ECKD device type in zIPL section of IPL2 record.\n");
+ return;
+ }
/* save pointer to Boot Map Table */
bmt_block_nr = eckd_block_num(&mbr->blockptr.xeckd.bptr.chs);
@@ -303,10 +312,14 @@ static void ipl_eckd_cdl(void)
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
read_block(2, vlbl, "Cannot read Volume Label at block 2");
- IPL_assert(magic_match(vlbl->key, VOL1_MAGIC),
- "Invalid magic of volume label block");
- IPL_assert(magic_match(vlbl->f.key, VOL1_MAGIC),
- "Invalid magic of volser block");
+ if (!magic_match(vlbl->key, VOL1_MAGIC)) {
+ sclp_print("Invalid magic of volume label block.\n");
+ return;
+ }
+ if (!magic_match(vlbl->f.key, VOL1_MAGIC)) {
+ sclp_print("Invalid magic of volser block.\n");
+ return;
+ }
print_volser(vlbl->f.volser);
run_eckd_boot_script(bmt_block_nr, s1b_block_nr);
@@ -398,7 +411,8 @@ static void ipl_eckd(void)
read_block(0, mbr, "Cannot read block 0 on DASD");
if (magic_match(mbr->magic, IPL1_MAGIC)) {
- ipl_eckd_cdl(); /* no return */
+ ipl_eckd_cdl(); /* only returns in case of error */
+ return;
}
/* LDL/CMS? */
@@ -436,7 +450,7 @@ static void zipl_load_segment(ComponentEntry *entry)
char *blk_no = &err_msg[30]; /* where to print blockno in (those ZZs) */
blockno = entry->data.blockno;
- address = entry->load_address;
+ address = entry->compdat.load_addr;
debug_print_int("loading segment at block", blockno);
debug_print_int("addr", address);
@@ -514,7 +528,8 @@ static void zipl_run(ScsiBlockPtr *pte)
IPL_assert(entry->component_type == ZIPL_COMP_ENTRY_EXEC, "No EXEC entry");
/* should not return */
- jump_to_IPL_code(entry->load_address);
+ write_reset_psw(entry->compdat.load_psw);
+ jump_to_IPL_code(0);
}
static void ipl_scsi(void)
@@ -825,5 +840,5 @@ void zipl_load(void)
panic("\n! Unknown IPL device type !\n");
}
- panic("\n* this can never happen *\n");
+ sclp_print("zIPL load failed.\n");
}
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index 12a0166..3946aa3 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -64,11 +64,16 @@ typedef struct BootMapTable {
BootMapPointer entry[];
} __attribute__ ((packed)) BootMapTable;
+typedef union ComponentEntryData {
+ uint64_t load_psw;
+ uint64_t load_addr;
+} ComponentEntryData;
+
typedef struct ComponentEntry {
ScsiBlockPtr data;
uint8_t pad[7];
uint8_t component_type;
- uint64_t load_address;
+ ComponentEntryData compdat;
} __attribute((packed)) ComponentEntry;
typedef struct ComponentHeader {
diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
index 767012b..fbae45b 100644
--- a/pc-bios/s390-ccw/jump2ipl.c
+++ b/pc-bios/s390-ccw/jump2ipl.c
@@ -12,21 +12,24 @@
#define KERN_IMAGE_START 0x010000UL
#define RESET_PSW_MASK (PSW_MASK_SHORTPSW | PSW_MASK_64)
+#define RESET_PSW ((uint64_t)&jump_to_IPL_addr | RESET_PSW_MASK)
-typedef struct ResetInfo {
- uint64_t ipl_psw;
- uint32_t ipl_continue;
-} ResetInfo;
+static uint64_t *reset_psw = 0, save_psw, ipl_continue;
-static ResetInfo save;
+void write_reset_psw(uint64_t psw)
+{
+ *reset_psw = psw;
+}
-static void jump_to_IPL_2(void)
+static void jump_to_IPL_addr(void)
{
- ResetInfo *current = 0;
+ __attribute__((noreturn)) void (*ipl)(void) = (void *)ipl_continue;
- void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue;
- *current = save;
- ipl(); /* should not return */
+ /* Restore reset PSW */
+ write_reset_psw(save_psw);
+
+ ipl();
+ /* should not return */
}
void jump_to_IPL_code(uint64_t address)
@@ -46,15 +49,12 @@ void jump_to_IPL_code(uint64_t address)
* content of non-BIOS memory after we loaded the guest, so we
* save the original content and restore it in jump_to_IPL_2.
*/
- ResetInfo *current = 0;
-
- save = *current;
-
- current->ipl_psw = (uint64_t) &jump_to_IPL_2;
- current->ipl_psw |= RESET_PSW_MASK;
- current->ipl_continue = address & PSW_MASK_SHORT_ADDR;
-
- debug_print_int("set IPL addr to", current->ipl_continue);
+ if (address) {
+ save_psw = *reset_psw;
+ write_reset_psw(RESET_PSW);
+ ipl_continue = address;
+ }
+ debug_print_int("set IPL addr to", address ?: *reset_psw & PSW_MASK_SHORT_ADDR);
/* Ensure the guest output starts fresh */
sclp_print("\n");
@@ -84,7 +84,12 @@ void jump_to_low_kernel(void)
/* Trying to get PSW at zero address */
if (*((uint64_t *)0) & RESET_PSW_MASK) {
- jump_to_IPL_code((*((uint64_t *)0)) & PSW_MASK_SHORT_ADDR);
+ /*
+ * Surely nobody will try running directly from lowcore, so
+ * let's use 0 as an indication that we want to load the reset
+ * psw at 0x0 and not jump to the entry.
+ */
+ jump_to_IPL_code(0);
}
/* No other option left, so use the Linux kernel start address */
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 146a507..43c792c 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -51,6 +51,60 @@ unsigned int get_loadparm_index(void)
return atoui(loadparm_str);
}
+static int is_dev_possibly_bootable(int dev_no, int sch_no)
+{
+ bool is_virtio;
+ Schib schib;
+ int r;
+
+ blk_schid.sch_no = sch_no;
+ r = stsch_err(blk_schid, &schib);
+ if (r == 3 || r == -EIO) {
+ return -ENODEV;
+ }
+ if (!schib.pmcw.dnv) {
+ return false;
+ }
+
+ enable_subchannel(blk_schid);
+ cutype = cu_type(blk_schid);
+
+ /*
+ * Note: we always have to run virtio_is_supported() here to make
+ * sure that the vdev.senseid data gets pre-initialized correctly
+ */
+ is_virtio = virtio_is_supported(blk_schid);
+
+ /* No specific devno given, just return whether the device is possibly bootable */
+ if (dev_no < 0) {
+ switch (cutype) {
+ case CU_TYPE_VIRTIO:
+ if (is_virtio) {
+ /*
+ * Skip net devices since no IPLB is created and therefore
+ * no network bootloader has been loaded
+ */
+ if (virtio_get_device_type() != VIRTIO_ID_NET) {
+ return true;
+ }
+ }
+ return false;
+ case CU_TYPE_DASD_3990:
+ case CU_TYPE_DASD_2107:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /* Caller asked for a specific devno */
+ if (schib.pmcw.dev == dev_no) {
+ return true;
+ }
+
+ return false;
+}
+
/*
* Find the subchannel connected to the given device (dev_no) and fill in the
* subchannel information block (schib) with the connected subchannel's info.
@@ -62,53 +116,14 @@ unsigned int get_loadparm_index(void)
*/
static bool find_subch(int dev_no)
{
- Schib schib;
int i, r;
- bool is_virtio;
for (i = 0; i < 0x10000; i++) {
- blk_schid.sch_no = i;
- r = stsch_err(blk_schid, &schib);
- if ((r == 3) || (r == -EIO)) {
+ r = is_dev_possibly_bootable(dev_no, i);
+ if (r < 0) {
break;
}
- if (!schib.pmcw.dnv) {
- continue;
- }
-
- enable_subchannel(blk_schid);
- cutype = cu_type(blk_schid);
-
- /*
- * Note: we always have to run virtio_is_supported() here to make
- * sure that the vdev.senseid data gets pre-initialized correctly
- */
- is_virtio = virtio_is_supported(blk_schid);
-
- /* No specific devno given, just return 1st possibly bootable device */
- if (dev_no < 0) {
- switch (cutype) {
- case CU_TYPE_VIRTIO:
- if (is_virtio) {
- /*
- * Skip net devices since no IPLB is created and therefore
- * no network bootloader has been loaded
- */
- if (virtio_get_device_type() != VIRTIO_ID_NET) {
- return true;
- }
- }
- continue;
- case CU_TYPE_DASD_3990:
- case CU_TYPE_DASD_2107:
- return true;
- default:
- continue;
- }
- }
-
- /* Caller asked for a specific devno */
- if (schib.pmcw.dev == dev_no) {
+ if (r == true) {
return true;
}
}
@@ -167,20 +182,8 @@ static void boot_setup(void)
static void find_boot_device(void)
{
VDev *vdev = virtio_get_device();
- int ssid;
bool found;
- if (!have_iplb) {
- for (ssid = 0; ssid < 0x3; ssid++) {
- blk_schid.ssid = ssid;
- found = find_subch(-1);
- if (found) {
- return;
- }
- }
- panic("Could not find a suitable boot device (none specified)\n");
- }
-
switch (iplb.pbt) {
case S390_IPL_TYPE_CCW:
debug_print_int("device no. ", iplb.ccw.devno);
@@ -203,7 +206,7 @@ static void find_boot_device(void)
IPL_assert(found, "Boot device not found\n");
}
-static void virtio_setup(void)
+static int virtio_setup(void)
{
VDev *vdev = virtio_get_device();
QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
@@ -218,31 +221,68 @@ static void virtio_setup(void)
sclp_print("Network boot device detected\n");
vdev->netboot_start_addr = qipl.netboot_start_addr;
} else {
- virtio_blk_setup_device(blk_schid);
+ int ret = virtio_blk_setup_device(blk_schid);
+ if (ret) {
+ return ret;
+ }
IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
}
+
+ return 0;
}
-int main(void)
+static void ipl_boot_device(void)
{
- sclp_setup();
- css_setup();
- boot_setup();
- find_boot_device();
- enable_subchannel(blk_schid);
-
switch (cutype) {
case CU_TYPE_DASD_3990:
case CU_TYPE_DASD_2107:
dasd_ipl(blk_schid, cutype); /* no return */
break;
case CU_TYPE_VIRTIO:
- virtio_setup();
- zipl_load(); /* no return */
+ if (virtio_setup() == 0) {
+ zipl_load(); /* Only returns in case of errors */
+ }
break;
default:
print_int("Attempting to boot from unexpected device type", cutype);
- panic("");
+ panic("\nBoot failed.\n");
+ }
+}
+
+/*
+ * No boot device has been specified, so we have to scan through the
+ * channels to find one.
+ */
+static void probe_boot_device(void)
+{
+ int ssid, sch_no, ret;
+
+ for (ssid = 0; ssid < 0x3; ssid++) {
+ blk_schid.ssid = ssid;
+ for (sch_no = 0; sch_no < 0x10000; sch_no++) {
+ ret = is_dev_possibly_bootable(-1, sch_no);
+ if (ret < 0) {
+ break;
+ }
+ if (ret == true) {
+ ipl_boot_device(); /* Only returns if unsuccessful */
+ }
+ }
+ }
+
+ sclp_print("Could not find a suitable boot device (none specified)\n");
+}
+
+int main(void)
+{
+ sclp_setup();
+ css_setup();
+ boot_setup();
+ if (have_iplb) {
+ find_boot_device();
+ ipl_boot_device();
+ } else {
+ probe_boot_device();
}
panic("Failed to load OS from hard disk\n");
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 36b884c..6cd9266 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -27,12 +27,10 @@ typedef unsigned long long __u64;
#define false 0
#define PAGE_SIZE 4096
-#ifndef EIO
#define EIO 1
-#endif
-#ifndef EBUSY
#define EBUSY 2
-#endif
+#define ENODEV 3
+
#ifndef NULL
#define NULL 0
#endif
@@ -71,13 +69,14 @@ int sclp_read(char *str, size_t count);
unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
ulong subchan_id, void *load_addr);
bool virtio_is_supported(SubChannelId schid);
-void virtio_blk_setup_device(SubChannelId schid);
+int virtio_blk_setup_device(SubChannelId schid);
int virtio_read(ulong sector, void *load_addr);
/* bootmap.c */
void zipl_load(void);
/* jump2ipl.c */
+void write_reset_psw(uint64_t psw);
void jump_to_IPL_code(uint64_t address);
void jump_to_low_kernel(void);
diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S
index ce51930..4d5ad21 100644
--- a/pc-bios/s390-ccw/start.S
+++ b/pc-bios/s390-ccw/start.S
@@ -34,7 +34,10 @@ remainder:
larl %r2,memsetxc
ex %r3,0(%r2)
done:
- j main /* And call C */
+ /* set up a pgm exception disabled wait psw */
+ larl %r2, disabled_wait_psw
+ mvc 0x01d0(16), 0(%r2)
+ j main /* And call C */
memsetxc:
xc 0(1,%r1),0(%r1)
diff --git a/pc-bios/s390-ccw/virtio-blkdev.c b/pc-bios/s390-ccw/virtio-blkdev.c
index 11c5626..7d35050 100644
--- a/pc-bios/s390-ccw/virtio-blkdev.c
+++ b/pc-bios/s390-ccw/virtio-blkdev.c
@@ -263,9 +263,10 @@ uint64_t virtio_get_blocks(void)
return 0;
}
-void virtio_blk_setup_device(SubChannelId schid)
+int virtio_blk_setup_device(SubChannelId schid)
{
VDev *vdev = virtio_get_device();
+ int ret = 0;
vdev->schid = schid;
virtio_setup_ccw(vdev);
@@ -288,9 +289,11 @@ void virtio_blk_setup_device(SubChannelId schid)
"Config: CDB size mismatch");
sclp_print("Using virtio-scsi.\n");
- virtio_scsi_setup(vdev);
+ ret = virtio_scsi_setup(vdev);
break;
default:
panic("\n! No IPL device available !\n");
}
+
+ return ret;
}
diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c
index eddfb8a..2c8d0f3 100644
--- a/pc-bios/s390-ccw/virtio-scsi.c
+++ b/pc-bios/s390-ccw/virtio-scsi.c
@@ -194,7 +194,12 @@ static bool scsi_read_capacity(VDev *vdev,
/* virtio-scsi routines */
-static void virtio_scsi_locate_device(VDev *vdev)
+/*
+ * Tries to locate a SCSI device and and adds the information for the found
+ * device to the vdev->scsi_device structure.
+ * Returns 0 if SCSI device could be located, or a error code < 0 otherwise
+ */
+static int virtio_scsi_locate_device(VDev *vdev)
{
const uint16_t channel = 0; /* again, it's what QEMU does */
uint16_t target;
@@ -220,7 +225,7 @@ static void virtio_scsi_locate_device(VDev *vdev)
IPL_check(sdev->channel == 0, "non-zero channel requested");
IPL_check(sdev->target <= vdev->config.scsi.max_target, "target# high");
IPL_check(sdev->lun <= vdev->config.scsi.max_lun, "LUN# high");
- return;
+ return 0;
}
for (target = 0; target <= vdev->config.scsi.max_target; target++) {
@@ -247,18 +252,20 @@ static void virtio_scsi_locate_device(VDev *vdev)
*/
sdev->lun = r->lun[0].v16[0]; /* it's returned this way */
debug_print_int("Have to use LUN", sdev->lun);
- return; /* we have to use this device */
+ return 0; /* we have to use this device */
}
for (i = 0; i < luns; i++) {
if (r->lun[i].v64) {
/* Look for non-zero LUN - we have where to choose from */
sdev->lun = r->lun[i].v16[0];
debug_print_int("Will use LUN", sdev->lun);
- return; /* we have found a device */
+ return 0; /* we have found a device */
}
}
}
- panic("\n! Cannot locate virtio-scsi device !\n");
+
+ sclp_print("Warning: Could not locate a usable virtio-scsi device\n");
+ return -ENODEV;
}
int virtio_scsi_read_many(VDev *vdev,
@@ -322,17 +329,20 @@ static void scsi_parse_capacity_report(void *data,
}
}
-void virtio_scsi_setup(VDev *vdev)
+int virtio_scsi_setup(VDev *vdev)
{
int retry_test_unit_ready = 3;
uint8_t data[256];
uint32_t data_size = sizeof(data);
ScsiInquiryEvpdPages *evpd = &scsi_inquiry_evpd_pages_response;
ScsiInquiryEvpdBl *evpd_bl = &scsi_inquiry_evpd_bl_response;
- int i;
+ int i, ret;
vdev->scsi_device = &default_scsi_device;
- virtio_scsi_locate_device(vdev);
+ ret = virtio_scsi_locate_device(vdev);
+ if (ret < 0) {
+ return ret;
+ }
/* We have to "ping" the device before it becomes readable */
while (!scsi_test_unit_ready(vdev)) {
@@ -417,4 +427,6 @@ void virtio_scsi_setup(VDev *vdev)
}
scsi_parse_capacity_report(data, &vdev->scsi_last_block,
(uint32_t *) &vdev->scsi_block_size);
+
+ return 0;
}
diff --git a/pc-bios/s390-ccw/virtio-scsi.h b/pc-bios/s390-ccw/virtio-scsi.h
index 4c4f4bb..4b14c2c 100644
--- a/pc-bios/s390-ccw/virtio-scsi.h
+++ b/pc-bios/s390-ccw/virtio-scsi.h
@@ -67,7 +67,7 @@ static inline bool virtio_scsi_response_ok(const VirtioScsiCmdResp *r)
return r->response == VIRTIO_SCSI_S_OK && r->status == CDB_STATUS_GOOD;
}
-void virtio_scsi_setup(VDev *vdev);
+int virtio_scsi_setup(VDev *vdev);
int virtio_scsi_read_many(VDev *vdev,
ulong sector, void *load_addr, int sec_num);
diff --git a/pc-bios/s390-netboot.img b/pc-bios/s390-netboot.img
index d9c3196..3dfce69 100644
--- a/pc-bios/s390-netboot.img
+++ b/pc-bios/s390-netboot.img
Binary files differ
diff --git a/tests/qtest/cdrom-test.c b/tests/qtest/cdrom-test.c
index e9afab6..eef242d 100644
--- a/tests/qtest/cdrom-test.c
+++ b/tests/qtest/cdrom-test.c
@@ -163,6 +163,18 @@ static void add_s390x_tests(void)
qtest_add_data_func("cdrom/boot/virtio-scsi",
"-device virtio-scsi -device scsi-cd,drive=cdr "
"-blockdev file,node-name=cdr,filename=", test_cdboot);
+ qtest_add_data_func("cdrom/boot/with-bootindex",
+ "-device virtio-serial -device virtio-scsi "
+ "-device virtio-blk,drive=d1 "
+ "-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/without-bootindex",
+ "-device virtio-scsi -device virtio-serial "
+ "-device x-terminal3270 -device virtio-blk,drive=d1 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d1 "
+ "-device virtio-blk,drive=d2 "
+ "-drive if=none,id=d2,media=cdrom,file=", test_cdboot);
}
int main(int argc, char **argv)