@samitouri / QOSamiQemu / commits / 854de451f2

hw/s390x/ipl: Add IPIB flags to IPL Parameter Block

Add IPIB flags to IPL Parameter Block to determine if IPL needs to perform securely and if IPL Information Report Block (IIRB) exists. Move DIAG308 flags to a separated header file and add flags for secure IPL. Move IPLB length related definitions to include/hw/s390x/ipl/qipl.h and add a maximum length constant to support secure IPL. Secure boot in audit mode will perform if certificate(s) exist in the key store. IIRB will exist and results of verification will be stored in IIRB. To ensure proper alignment of the IIRB and prevent overlap, set iplb->len to the maximum length of the IPLB, allowing alignment constraints to be determined based on its size. Signed-off-by: Zhuoying Cai <zycai@linux.ibm.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Collin Walling <walling@linux.ibm.com> Reviewed-by: Jared Rossi <jrossi@linux.ibm.com> Link: https://lore.kernel.org/qemu-devel/20260730214624.2328883-18-zycai@linux.ibm.com Signed-off-by: Eric Farman <farman@linux.ibm.com>

Zhuoying Cai committed Jul 30, 2026 at 17:46 UTC 854de451f21ca1cc6263c5d7d837b4d28b5de9d9
4 files changed +82 -25
hw/s390x/ipl.c
+36
@@ -462,6 +462,34 @@ S390IPLCertificateStore *s390_ipl_get_certificate_store(void)
462 return &ipl->cert_store;
463 }
464
465 +static bool s390_has_certificate(void)
466 +{
467 + S390IPLState *ipl = get_ipl_device();
468 +
469 + return ipl->cert_store.count > 0;
470 +}
471 +
472 +static void s390_set_secure_boot_flags(IplParameterBlock *iplb,
473 + bool audit_mode)
474 +{
475 + if (!audit_mode) {
476 + return;
477 + }
478 +
479 + /*
480 + * For audit mode, enable the IPL Information
481 + * Report (IPLIR) flag so that the firmware generates an IPL
482 + * Information Report Block (IIRB).
483 + *
484 + * Results of secure boot will be stored in IIRB.
485 + *
486 + * Extend the IPL parameter block to its maximum length to ensure
487 + * sufficient space for the BIOS to populate the IIRB.
488 + */
489 + iplb->hdr_flags |= DIAG308_IPIB_FLAGS_IPLIR;
490 + iplb->len = cpu_to_be32(S390_IPLB_MAX_LEN);
491 +}
492 +
493 static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
494 {
495 CcwDevice *ccw_dev = NULL;
@@ -518,6 +546,8 @@ static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
546 s390_ipl_convert_loadparm((char *)lp, iplb->loadparm);
547 iplb->flags |= DIAG308_FLAGS_LP_VALID;
548
549 + s390_set_secure_boot_flags(iplb, s390_has_certificate());
550 +
551 return true;
552 }
553
@@ -654,6 +684,12 @@ void s390_ipl_update_diag308(IplParameterBlock *iplb)
684 } else {
685 ipl->iplb = *iplb;
686 ipl->iplb_valid = true;
687 +
688 + /*
689 + * The kernel does not preserve secure boot flags across a reboot.
690 + * Re-apply them here based on the current machine configuration.
691 + */
692 + s390_set_secure_boot_flags(&ipl->iplb, s390_has_certificate());
693 }
694
695 update_machine_ipl_properties(iplb);
hw/s390x/ipl.h
-24
@@ -23,7 +23,6 @@
23 #include "qom/object.h"
24 #include "target/s390x/kvm/pv.h"
25
26 -#define DIAG308_FLAGS_LP_VALID 0x80
26 #define MAX_BOOT_DEVS 8 /* Max number of devices that may have a bootindex */
27
28 void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp);
@@ -90,29 +89,6 @@ struct S390IPLState {
89 };
90 QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong");
91
93 -#define DIAG_308_RC_OK 0x0001
94 -#define DIAG_308_RC_NO_CONF 0x0102
95 -#define DIAG_308_RC_INVALID 0x0402
96 -#define DIAG_308_RC_NO_PV_CONF 0x0902
97 -#define DIAG_308_RC_INVAL_FOR_PV 0x0a02
98 -
99 -#define DIAG308_RESET_MOD_CLR 0
100 -#define DIAG308_RESET_LOAD_NORM 1
101 -#define DIAG308_LOAD_CLEAR 3
102 -#define DIAG308_LOAD_NORMAL_DUMP 4
103 -#define DIAG308_SET 5
104 -#define DIAG308_STORE 6
105 -#define DIAG308_PV_SET 8
106 -#define DIAG308_PV_STORE 9
107 -#define DIAG308_PV_START 10
108 -
109 -#define S390_IPLB_HEADER_LEN 8
110 -#define S390_IPLB_MIN_PV_LEN 148
111 -#define S390_IPLB_MIN_CCW_LEN 200
112 -#define S390_IPLB_MIN_FCP_LEN 384
113 -#define S390_IPLB_MIN_PCI_LEN 376
114 -#define S390_IPLB_MIN_QEMU_SCSI_LEN 200
115 -
92 static inline bool iplb_valid_len(IplParameterBlock *iplb)
93 {
94 return be32_to_cpu(iplb->len) <= sizeof(IplParameterBlock);
include/hw/s390x/ipl/diag308.h new
+34
@@ -0,0 +1,34 @@
1 +/*
2 + * S/390 DIAGNOSE 308 definitions and structures
3 + *
4 + * Copyright 2025 IBM Corp.
5 + * Author(s): Zhuoying Cai <zycai@linux.ibm.com>
6 + *
7 + * SPDX-License-Identifier: GPL-2.0-or-later
8 + */
9 +
10 +#ifndef S390X_DIAG308_H
11 +#define S390X_DIAG308_H
12 +
13 +#define DIAG_308_RC_OK 0x0001
14 +#define DIAG_308_RC_NO_CONF 0x0102
15 +#define DIAG_308_RC_INVALID 0x0402
16 +#define DIAG_308_RC_NO_PV_CONF 0x0902
17 +#define DIAG_308_RC_INVAL_FOR_PV 0x0a02
18 +
19 +#define DIAG308_RESET_MOD_CLR 0
20 +#define DIAG308_RESET_LOAD_NORM 1
21 +#define DIAG308_LOAD_CLEAR 3
22 +#define DIAG308_LOAD_NORMAL_DUMP 4
23 +#define DIAG308_SET 5
24 +#define DIAG308_STORE 6
25 +#define DIAG308_PV_SET 8
26 +#define DIAG308_PV_STORE 9
27 +#define DIAG308_PV_START 10
28 +
29 +#define DIAG308_FLAGS_LP_VALID 0x80
30 +
31 +#define DIAG308_IPIB_FLAGS_SIPL 0x40
32 +#define DIAG308_IPIB_FLAGS_IPLIR 0x20
33 +
34 +#endif
include/hw/s390x/ipl/qipl.h
+12 -1
@@ -12,6 +12,8 @@
12 #ifndef S390X_QIPL_H
13 #define S390X_QIPL_H
14
15 +#include "diag308.h"
16 +
17 /* Boot Menu flags */
18 #define QIPL_FLAG_BM_OPTS_CMD 0x80
19 #define QIPL_FLAG_BM_OPTS_ZIPL 0x40
@@ -33,6 +35,14 @@ typedef enum S390IplType S390IplType;
35
36 #define QEMU_DEFAULT_IPL S390_IPL_TYPE_CCW
37
38 +#define S390_IPLB_HEADER_LEN 8
39 +#define S390_IPLB_MIN_PV_LEN 148
40 +#define S390_IPLB_MIN_CCW_LEN 200
41 +#define S390_IPLB_MIN_FCP_LEN 384
42 +#define S390_IPLB_MIN_PCI_LEN 376
43 +#define S390_IPLB_MIN_QEMU_SCSI_LEN 200
44 +#define S390_IPLB_MAX_LEN 4096
45 +
46 #define MAX_CERTIFICATES 64
47 /* largest supported block size - same as VIRTIO_DASD_DEFAULT_BLOCK_SIZE */
48 #define VIRTIO_MAX_BLOCK_SIZE 4096
@@ -127,7 +137,8 @@ typedef struct IplBlockPci IplBlockPci;
137 union IplParameterBlock {
138 struct {
139 uint32_t len;
130 - uint8_t reserved0[3];
140 + uint8_t hdr_flags;
141 + uint8_t reserved0[2];
142 uint8_t version;
143 uint32_t blk0_len;
144 uint8_t pbt;