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 <[email protected]> Reviewed-by: Eric Farman <[email protected]> Reviewed-by: Matthew Rosato <[email protected]> --- hw/s390x/ipl.c | 18 ++++++++++++++---- hw/s390x/ipl.h | 2 -- include/hw/s390x/ipl/qipl.h | 5 ++++- pc-bios/s390-ccw/iplb.h | 4 ++-- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 627544b361..85fe2d3cb4 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -426,10 +426,9 @@ static S390PCIBusDevice *s390_get_pci_device(DeviceState *dev_st, int *devtype) return pbdev; } -static uint64_t s390_ipl_map_iplb_chain(IplParameterBlock *iplb_chain) +static uint64_t s390_ipl_map_iplb_chain(IplParameterBlock *iplb_chain, uint16_t count) { 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); @@ -593,7 +592,7 @@ void s390_rebuild_iplb(uint16_t dev_index, IplParameterBlock *iplb) static bool s390_init_all_iplbs(S390IPLState *ipl) { int iplb_num = 0; - IplParameterBlock iplb_chain[7]; + IplParameterBlock iplb_chain[MAX_BOOT_DEVS - 1] = { 0 }; DeviceState *dev_st = get_boot_device(0); Object *machine = qdev_get_machine(); @@ -639,13 +638,24 @@ static bool s390_init_all_iplbs(S390IPLState *ipl) 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)); + /* + * Allocate maximum space for IPLB chain and/or certificate storage. + * Once a valid boot device is found, this space will be used to store + * certificates if secure boot is enabled. + */ + if (iplb_num > 1 || s390_has_certificate()) { + ipl->qipl.ipl_data = cpu_to_be64(s390_ipl_map_iplb_chain(iplb_chain, + MAX_BOOT_DEVS - 1)); } return iplb_num; } +QEMU_BUILD_BUG_MSG(sizeof(IplParameterBlock) * (MAX_BOOT_DEVS - 1) != CERT_BUF_SIZE, + "certificate buffer size is wrong"); + static void update_machine_ipl_properties(IplParameterBlock *iplb) { Object *machine = qdev_get_machine(); diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index 9807ef18f2..7b8a51452b 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -23,8 +23,6 @@ #include "qom/object.h" #include "target/s390x/kvm/pv.h" -#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); void s390_rebuild_iplb(uint16_t index, IplParameterBlock *iplb); diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h index a2180719b1..37452faaa6 100644 --- a/include/hw/s390x/ipl/qipl.h +++ b/include/hw/s390x/ipl/qipl.h @@ -41,7 +41,10 @@ typedef enum S390IplType S390IplType; #define S390_IPLB_MIN_QEMU_SCSI_LEN 200 #define S390_IPLB_MAX_LEN 4096 +#define MAX_BOOT_DEVS 8 /* Max number of devices that may have a bootindex */ + #define MAX_CERTIFICATES 64 +#define CERT_BUF_SIZE ((MAX_BOOT_DEVS - 1) * 4096) /* largest supported block size - same as VIRTIO_DASD_DEFAULT_BLOCK_SIZE */ #define VIRTIO_MAX_BLOCK_SIZE 4096 #define MAX_COMP_ENTRIES ((VIRTIO_MAX_BLOCK_SIZE - 32) / 32) @@ -61,7 +64,7 @@ struct QemuIplParameters { uint32_t boot_menu_timeout; uint8_t reserved3[2]; uint16_t chain_len; - uint64_t next_iplb; + uint64_t ipl_data; } QEMU_PACKED; typedef struct QemuIplParameters QemuIplParameters; diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h index c92a3d0f0c..c807e7f49b 100644 --- a/pc-bios/s390-ccw/iplb.h +++ b/pc-bios/s390-ccw/iplb.h @@ -61,11 +61,11 @@ static inline bool load_next_iplb(void) } qipl.index++; - next_iplb = (IplParameterBlock *) qipl.next_iplb; + next_iplb = (IplParameterBlock *) qipl.ipl_data; memcpy(iplb, next_iplb, sizeof(IplParameterBlock)); qipl.chain_len--; - qipl.next_iplb = qipl.next_iplb + sizeof(IplParameterBlock); + qipl.ipl_data = qipl.ipl_data + sizeof(IplParameterBlock); return true; } -- 2.54.0
