hw/s390x/ipl: Rework s390_ipl_map_iplb_chain for certificate storage
Rework s390_ipl_map_iplb_chain to always allocate maximum memory for the IPLB chain, regardless of the number of boot devices. This space is also used to store certificates during secure boot, providing a safe location for certificates until the kernel reads them during boot. Rename next_iplb to ipl_data to better reflect its multiple purposes: storing both IPLB chains and certificate data. Signed-off-by: Zhuoying Cai <zycai@linux.ibm.com> Reviewed-by: Eric Farman <farman@linux.ibm.com> Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com> Link: https://lore.kernel.org/qemu-devel/20260730214624.2328883-19-zycai@linux.ibm.com Signed-off-by: Eric Farman <farman@linux.ibm.com>
Zhuoying Cai committed
Jul 30, 2026 at 17:46 UTC
3289d6db95edc408cfeaab33de4cc41a9d7423be
4 files changed
+20
-9
hw/s390x/ipl.c
+14
-4
@@ -426,10 +426,9 @@ static S390PCIBusDevice *s390_get_pci_device(DeviceState *dev_st, int *devtype)
426
return pbdev;
427
}
428
429
-static uint64_t s390_ipl_map_iplb_chain(IplParameterBlock *iplb_chain)
429
+static uint64_t s390_ipl_map_iplb_chain(IplParameterBlock *iplb_chain, uint16_t count)
430
{
431
S390IPLState *ipl = get_ipl_device();
432
- uint16_t count = be16_to_cpu(ipl->qipl.chain_len);
432
uint64_t len = sizeof(IplParameterBlock) * count;
433
uint64_t chain_addr = find_iplb_chain_addr(ipl->bios_start_addr, count);
434
@@ -593,7 +592,7 @@ void s390_rebuild_iplb(uint16_t dev_index, IplParameterBlock *iplb)
592
static bool s390_init_all_iplbs(S390IPLState *ipl)
593
{
594
int iplb_num = 0;
596
- IplParameterBlock iplb_chain[7];
595
+ IplParameterBlock iplb_chain[MAX_BOOT_DEVS - 1] = { 0 };
596
DeviceState *dev_st = get_boot_device(0);
597
Object *machine = qdev_get_machine();
598
@@ -639,13 +638,24 @@ static bool s390_init_all_iplbs(S390IPLState *ipl)
638
dev_st = get_boot_device(i);
639
s390_build_iplb(dev_st, &iplb_chain[i - 1]);
640
}
641
+ }
642
643
- ipl->qipl.next_iplb = cpu_to_be64(s390_ipl_map_iplb_chain(iplb_chain));
643
+ /*
644
+ * Allocate maximum space for IPLB chain and/or certificate storage.
645
+ * Once a valid boot device is found, this space will be used to store
646
+ * certificates if secure boot is enabled.
647
+ */
648
+ if (iplb_num > 1 || s390_has_certificate()) {
649
+ ipl->qipl.ipl_data = cpu_to_be64(s390_ipl_map_iplb_chain(iplb_chain,
650
+ MAX_BOOT_DEVS - 1));
651
}
652
653
return iplb_num;
654
}
655
656
+QEMU_BUILD_BUG_MSG(sizeof(IplParameterBlock) * (MAX_BOOT_DEVS - 1) != CERT_BUF_SIZE,
657
+ "certificate buffer size is wrong");
658
+
659
static void update_machine_ipl_properties(IplParameterBlock *iplb)
660
{
661
Object *machine = qdev_get_machine();
hw/s390x/ipl.h
-2
@@ -23,8 +23,6 @@
23
#include "qom/object.h"
24
#include "target/s390x/kvm/pv.h"
25
26
-#define MAX_BOOT_DEVS 8 /* Max number of devices that may have a bootindex */
27
-
26
void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp);
27
void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp);
28
void s390_rebuild_iplb(uint16_t index, IplParameterBlock *iplb);
include/hw/s390x/ipl/qipl.h
+4
-1
@@ -43,7 +43,10 @@ typedef enum S390IplType S390IplType;
43
#define S390_IPLB_MIN_QEMU_SCSI_LEN 200
44
#define S390_IPLB_MAX_LEN 4096
45
46
+#define MAX_BOOT_DEVS 8 /* Max number of devices that may have a bootindex */
47
+
48
#define MAX_CERTIFICATES 64
49
+#define CERT_BUF_SIZE ((MAX_BOOT_DEVS - 1) * 4096)
50
/* largest supported block size - same as VIRTIO_DASD_DEFAULT_BLOCK_SIZE */
51
#define VIRTIO_MAX_BLOCK_SIZE 4096
52
#define MAX_COMP_ENTRIES ((VIRTIO_MAX_BLOCK_SIZE - 32) / 32)
@@ -63,7 +66,7 @@ struct QemuIplParameters {
66
uint32_t boot_menu_timeout;
67
uint8_t reserved3[2];
68
uint16_t chain_len;
66
- uint64_t next_iplb;
69
+ uint64_t ipl_data;
70
} QEMU_PACKED;
71
typedef struct QemuIplParameters QemuIplParameters;
72
pc-bios/s390-ccw/iplb.h
+2
-2
@@ -61,11 +61,11 @@ static inline bool load_next_iplb(void)
61
}
62
63
qipl.index++;
64
- next_iplb = (IplParameterBlock *) qipl.next_iplb;
64
+ next_iplb = (IplParameterBlock *) qipl.ipl_data;
65
memcpy(iplb, next_iplb, sizeof(IplParameterBlock));
66
67
qipl.chain_len--;
68
- qipl.next_iplb = qipl.next_iplb + sizeof(IplParameterBlock);
68
+ qipl.ipl_data = qipl.ipl_data + sizeof(IplParameterBlock);
69
70
return true;
71
}