From: Collin Walling <walling@linux.ibm.com>
To: Zhuoying Cai <zycai@linux.ibm.com>,
thuth@redhat.com, berrange@redhat.com, jrossi@linux.ibm.com,
qemu-s390x@nongnu.org, qemu-devel@nongnu.org
Cc: richard.henderson@linaro.org, pierrick.bouvier@linaro.org,
david@kernel.org, jjherne@linux.ibm.com, pasic@linux.ibm.com,
borntraeger@linux.ibm.com, farman@linux.ibm.com,
mjrosato@linux.ibm.com, iii@linux.ibm.com, eblake@redhat.com,
armbru@redhat.com, alifm@linux.ibm.com, brueckner@linux.ibm.com,
jdaley@linux.ibm.com
Subject: Re: [PATCH v9 22/30] pc-bios/s390-ccw: Add additional security checks for secure boot
Date: Tue, 17 Mar 2026 02:54:15 -0400 [thread overview]
Message-ID: <655c1663-787d-4a42-a90e-36798506c303@linux.ibm.com> (raw)
In-Reply-To: <20260305224146.664053-23-zycai@linux.ibm.com>
On 3/5/26 17:41, Zhuoying Cai wrote:
> Add additional checks to ensure that components do not overlap with
> signed components when loaded into memory.
>
> Add additional checks to ensure the load addresses of unsigned components
> are greater than or equal to 0x2000.
>
> When the secure IPL code loading attributes facility (SCLAF) is installed,
> all signed components must contain a secure code loading attributes block
> (SCLAB).
>
> The SCLAB provides further validation of information on where to load the
> signed binary code from the load device, and where to start the execution
> of the loaded OS code.
>
> When SCLAF is installed, its content must be evaluated during secure IPL.
> However, a missing SCLAB will not be reported in audit mode. The SCALB
> checking will be skipped in this case.
>
> Add IPL Information Error Indicators (IIEI) and Component Error
> Indicators (CEI) for IPL Information Report Block (IIRB).
This goes back to my comment in patch 19: who/what is going to make use
of the IIRB? If no one or nothing will inspect this data structure, then
perhaps it's sufficient enough to simply log the errors?
>
> When SCLAF is installed, additional secure boot checks are performed
> during zipl and store results of verification into IIRB.
>
> Signed-off-by: Zhuoying Cai <zycai@linux.ibm.com>
> ---
> include/hw/s390x/ipl/qipl.h | 29 +++-
> pc-bios/s390-ccw/s390-ccw.h | 1 +
> pc-bios/s390-ccw/sclp.c | 8 +
> pc-bios/s390-ccw/sclp.h | 1 +
> pc-bios/s390-ccw/secure-ipl.c | 314 +++++++++++++++++++++++++++++++++-
> pc-bios/s390-ccw/secure-ipl.h | 42 +++++
> 6 files changed, 391 insertions(+), 4 deletions(-)
>
> diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h
> index 1b6cb3231d..9518fcb1dc 100644
> --- a/include/hw/s390x/ipl/qipl.h
> +++ b/include/hw/s390x/ipl/qipl.h
> @@ -136,10 +136,20 @@ struct IplInfoReportBlockHeader {
> };
> typedef struct IplInfoReportBlockHeader IplInfoReportBlockHeader;
>
> +/* IPL Info Error Indicators */
> +#define S390_IIEI_NO_SIGNED_COMP 0x8000 /* bit 0 */
> +#define S390_IIEI_NO_SCLAB 0x4000 /* bit 1 */
> +#define S390_IIEI_NO_GLOBAL_SCLAB 0x2000 /* bit 2 */
> +#define S390_IIEI_MORE_GLOBAL_SCLAB 0x1000 /* bit 3 */
> +#define S390_IIEI_FOUND_UNSIGNED_COMP 0x800 /* bit 4 */
> +#define S390_IIEI_MORE_SIGNED_COMP 0x400 /* bit 5 */
> +
> struct IplInfoBlockHeader {
> uint32_t len;
> uint8_t type;
> - uint8_t reserved1[11];
> + uint8_t reserved1[3];
> + uint16_t iiei;
> + uint8_t reserved2[6];
> };
> typedef struct IplInfoBlockHeader IplInfoBlockHeader;
>
> @@ -163,13 +173,28 @@ typedef struct IplSignatureCertificateList IplSignatureCertificateList;
> #define S390_IPL_DEV_COMP_FLAG_SC 0x80
> #define S390_IPL_DEV_COMP_FLAG_CSV 0x40
>
> +/* IPL Device Component Error Indicators */
> +#define S390_CEI_INVALID_SCLAB 0x80000000 /* bit 0 */
> +#define S390_CEI_INVALID_SCLAB_LEN 0x40000000 /* bit 1 */
> +#define S390_CEI_INVALID_SCLAB_FORMAT 0x20000000 /* bit 2 */
> +#define S390_CEI_UNMATCHED_SCLAB_LOAD_ADDR 0x10000000 /* bit 3 */
> +#define S390_CEI_UNMATCHED_SCLAB_LOAD_PSW 0x8000000 /* bit 4 */
> +#define S390_CEI_INVALID_LOAD_PSW 0x4000000 /* bit 5 */
> +#define S390_CEI_NUC_NOT_IN_GLOBAL_SCLA 0x2000000 /* bit 6 */
> +#define S390_CEI_SCLAB_OLA_NOT_ONE 0x1000000 /* bit 7 */
> +#define S390_CEI_SC_NOT_IN_GLOBAL_SCLAB 0x800000 /* bit 8 */
> +#define S390_CEI_SCLAB_LOAD_ADDR_NOT_ZERO 0x400000 /* bit 9 */
> +#define S390_CEI_SCLAB_LOAD_PSW_NOT_ZERO 0x200000 /* bit 10 */
> +#define S390_CEI_INVALID_UNSIGNED_ADDR 0x100000 /* bit 11 */
> +
> struct IplDeviceComponentEntry {
> uint64_t addr;
> uint64_t len;
> uint8_t flags;
> uint8_t reserved1[5];
> uint16_t cert_index;
> - uint8_t reserved2[8];
> + uint32_t cei;
> + uint8_t reserved2[4];
> };
> typedef struct IplDeviceComponentEntry IplDeviceComponentEntry;
>
> diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
> index a0d568696a..7d1a9d4acc 100644
> --- a/pc-bios/s390-ccw/s390-ccw.h
> +++ b/pc-bios/s390-ccw/s390-ccw.h
> @@ -82,6 +82,7 @@ void sclp_setup(void);
> void sclp_get_loadparm_ascii(char *loadparm);
> bool sclp_is_diag320_on(void);
> bool sclp_is_sipl_on(void);
> +bool sclp_is_sclaf_on(void);
> int sclp_read(char *str, size_t count);
>
> /* virtio.c */
> diff --git a/pc-bios/s390-ccw/sclp.c b/pc-bios/s390-ccw/sclp.c
> index e3b6a1f07e..5dbddff9ae 100644
> --- a/pc-bios/s390-ccw/sclp.c
> +++ b/pc-bios/s390-ccw/sclp.c
> @@ -151,6 +151,14 @@ bool sclp_is_sipl_on(void)
> return fac_ipl & SCCB_FAC_IPL_SIPL_BIT;
> }
>
> +bool sclp_is_sclaf_on(void)
> +{
> + uint16_t fac_ipl = 0;
> +
> + sclp_get_fac_ipl(&fac_ipl);
> + return fac_ipl & SCCB_FAC_IPL_SCLAF_BIT;
> +}
> +
> int sclp_read(char *str, size_t count)
> {
> ReadEventData *sccb = (void *)_sccb;
> diff --git a/pc-bios/s390-ccw/sclp.h b/pc-bios/s390-ccw/sclp.h
> index cf147f4634..3441020d6b 100644
> --- a/pc-bios/s390-ccw/sclp.h
> +++ b/pc-bios/s390-ccw/sclp.h
> @@ -52,6 +52,7 @@ typedef struct SCCBHeader {
> #define SCCB_DATA_LEN (SCCB_SIZE - sizeof(SCCBHeader))
> #define SCCB_FAC134_DIAG320_BIT 0x4
> #define SCCB_FAC_IPL_SIPL_BIT 0x4000
> +#define SCCB_FAC_IPL_SCLAF_BIT 0x1000
>
> typedef struct ReadInfo {
> SCCBHeader h;
> diff --git a/pc-bios/s390-ccw/secure-ipl.c b/pc-bios/s390-ccw/secure-ipl.c
> index 68596491c5..840b88a699 100644
> --- a/pc-bios/s390-ccw/secure-ipl.c
> +++ b/pc-bios/s390-ccw/secure-ipl.c
> @@ -198,6 +198,12 @@ static bool secure_ipl_supported(void)
> return false;
> }
>
> + if (!sclp_is_sclaf_on()) {
> + puts("Secure IPL Code Loading Attributes Facility is not supported by"
> + " the hypervisor!");
> + return false;
> + }
> +
> return true;
> }
>
> @@ -258,6 +264,286 @@ static void addr_overlap_check(SecureIplCompAddrRange *comp_addr_range,
> *addr_range_index += 1;
> }
>
> +static void check_unsigned_addr(uint64_t load_addr, IplDeviceComponentEntry *comp_entry)
> +{
> + /* unsigned load address must be greater than or equal to 0x2000 */
> + if (load_addr >= 0x2000) {
> + return;
> + }
> +
> + set_comp_cei_with_log(comp_entry, S390_CEI_INVALID_UNSIGNED_ADDR,
> + "Load address is less than 0x2000");
> +}
I think I still would have preferred some sort of assert-styled function
that could be used in place of a lot of these simpler functions e.g.:
```
component_check(load_addr >= 0x2000, comp_entry,
S390_CEI_INVALID_UNSIGNED_ADDR,
"Load address is less than 0x2000");
```
(Might need a more fitting name, though.)
It's basically the `set_comp_cei_with_log()` function with a boolean
parameter up front.
> +
> +static bool check_sclab_presence(uint8_t *sclab_magic,
> + IplDeviceComponentEntry *comp_entry)
> +{
> + /* identifies the presence of SCLAB */
> + if (magic_match(sclab_magic, ZIPL_MAGIC)) {
> + return true;
> + }
> +
> + if (comp_entry) {
> + comp_entry->cei |= S390_CEI_INVALID_SCLAB;
> + }
> +
> + /* a missing SCLAB will not be reported in audit mode */
> + return false;
> +}
> +
> +static void check_sclab_length(uint16_t sclab_len, IplDeviceComponentEntry *comp_entry)
> +{
> + if (sclab_len >= S390_SECURE_IPL_SCLAB_MIN_LEN) {
> + return;
> + }
> +
> + set_comp_cei_with_log(comp_entry,
> + S390_CEI_INVALID_SCLAB_LEN | S390_CEI_INVALID_SCLAB,
> + "Invalid SCLAB length");
> +}
> +
> +static void check_sclab_format(uint8_t sclab_format, IplDeviceComponentEntry *comp_entry)
> +{
> + /* SCLAB format must set to zero, indicating a format-0 SCLAB being used */
> + if (sclab_format == 0) {
> + return;
> + }
> +
> + set_comp_cei_with_log(comp_entry, S390_CEI_INVALID_SCLAB_FORMAT,
> + "Format-0 SCLAB is not being used");
> +}
> +
> +static void check_sclab_opsw(SecureCodeLoadingAttributesBlock *sclab,
> + SecureIplSclabInfo *sclab_info,
> + IplDeviceComponentEntry *comp_entry)
> +{
> + const char *msg;
> + uint32_t cei_flag = 0;
> +
> + if (!(sclab->flags & S390_SECURE_IPL_SCLAB_FLAG_OPSW)) {
> + /* OPSW = 0 - Load PSW field in SCLAB must contain zeros */
> + if (sclab->load_psw != 0) {
> + cei_flag |= S390_CEI_SCLAB_LOAD_PSW_NOT_ZERO;
> + msg = "Load PSW is not zero when Override PSW bit is zero";
> + }
> + } else {
> + /* OPSW = 1 indicating global SCLAB */
> + sclab_info->global_count += 1;
> + if (sclab_info->global_count == 1) {
> + sclab_info->load_psw = sclab->load_psw;
> + sclab_info->flags = sclab->flags;
> + }
> +
> + /* OLA must set to one */
> + if (!(sclab->flags & S390_SECURE_IPL_SCLAB_FLAG_OLA)) {
> + cei_flag |= S390_CEI_SCLAB_OLA_NOT_ONE;
> + msg = "Override Load Address bit is not set to one in the global SCLAB";
> + }
> + }
> +
> + if (cei_flag) {
> + set_comp_cei_with_log(comp_entry, cei_flag, msg);
> + }
> +}
> +
> +static void check_sclab_ola(SecureCodeLoadingAttributesBlock *sclab, uint64_t load_addr,
> + IplDeviceComponentEntry *comp_entry)
> +{
> + const char *msg;
> + uint32_t cei_flag = 0;
> +
> + if (!(sclab->flags & S390_SECURE_IPL_SCLAB_FLAG_OLA)) {
> + /* OLA = 0 - Load address field in SCLAB must contain zeros */
> + if (sclab->load_addr != 0) {
> + cei_flag |= S390_CEI_SCLAB_LOAD_ADDR_NOT_ZERO;
> + msg = "Load Address is not zero when Override Load Address bit is zero";
> + }
> + } else {
> + /* OLA = 1 - Load address field must match storage address of the component */
> + if (sclab->load_addr != load_addr) {
> + cei_flag |= S390_CEI_UNMATCHED_SCLAB_LOAD_ADDR;
> + msg = "Load Address does not match with component load address";
> + }
> + }
> +
> + if (cei_flag) {
> + set_comp_cei_with_log(comp_entry, cei_flag, msg);
> + }
> +}
> +
> +static void check_sclab_nuc(uint16_t sclab_flags, IplDeviceComponentEntry *comp_entry)
> +{
> + const char *msg;
> + bool is_nuc_set;
> + bool is_global_sclab;
> +
> + is_nuc_set = sclab_flags & S390_SECURE_IPL_SCLAB_FLAG_NUC;
> + is_global_sclab = sclab_flags & S390_SECURE_IPL_SCLAB_FLAG_OPSW;
> + if (is_nuc_set && !is_global_sclab) {
> + msg = "No Unsigned Components bit is set, but not in the global SCLAB";
> + set_comp_cei_with_log(comp_entry, S390_CEI_NUC_NOT_IN_GLOBAL_SCLA, msg);
> + }
> +}
> +
> +static void check_sclab_sc(uint16_t sclab_flags, IplDeviceComponentEntry *comp_entry)
> +{
> + const char *msg;
> + bool is_sc_set;
> + bool is_global_sclab;
> +
> + is_sc_set = sclab_flags & S390_SECURE_IPL_SCLAB_FLAG_SC;
> + is_global_sclab = sclab_flags & S390_SECURE_IPL_SCLAB_FLAG_OPSW;
> + if (is_sc_set && !is_global_sclab) {
> + msg = "Single Component bit is set, but not in the global SCLAB";
> + set_comp_cei_with_log(comp_entry, S390_CEI_SC_NOT_IN_GLOBAL_SCLAB, msg);
> + }
> +}
> +
> +static bool is_psw_valid(uint64_t psw, SecureIplCompAddrRange *comp_addr_range,
> + int range_index)
> +{
> + uint32_t addr = psw & 0x7fffffff;
> +
> + /* PSW points within a signed binary code component */
> + for (int i = 0; i < range_index; i++) {
> + if (comp_addr_range[i].is_signed &&
> + addr >= comp_addr_range[i].start_addr &&
> + addr <= comp_addr_range[i].end_addr - 2) {
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> +static void check_load_psw(SecureIplCompAddrRange *comp_addr_range,
> + int addr_range_index, uint64_t sclab_load_psw,
> + uint64_t load_psw, IplDeviceComponentEntry *comp_entry)
> +{
> + bool valid;
> +
> + valid = is_psw_valid(sclab_load_psw, comp_addr_range, addr_range_index) &&
> + is_psw_valid(load_psw, comp_addr_range, addr_range_index);
> + if (!valid) {
> + set_comp_cei_with_log(comp_entry, S390_CEI_INVALID_LOAD_PSW, "Invalid PSW");
> + }
> +
> + /* compare load PSW with the PSW specified in component */
> + if (sclab_load_psw != load_psw) {
> + set_comp_cei_with_log(comp_entry, S390_CEI_UNMATCHED_SCLAB_LOAD_PSW,
> + "Load PSW does not match with PSW in component");
> + }
> +}
> +
> +static void check_nuc(uint16_t global_sclab_flags, int unsigned_count,
> + IplDeviceComponentList *comp_list)
> +{
> + bool is_nuc_set;
> +
> + is_nuc_set = global_sclab_flags & S390_SECURE_IPL_SCLAB_FLAG_NUC;
> + if (is_nuc_set && unsigned_count > 0) {
> + comp_list->ipl_info_header.iiei |= S390_IIEI_FOUND_UNSIGNED_COMP;
> + zipl_secure_handle("Unsigned components are not allowed");
> + }
> +}
> +
> +static void check_sc(uint16_t global_sclab_flags,
> + int signed_count, int unsigned_count,
> + IplDeviceComponentList *comp_list)
> +{
> + bool is_sc_set;
> +
> + is_sc_set = global_sclab_flags & S390_SECURE_IPL_SCLAB_FLAG_SC;
> + if (is_sc_set && signed_count != 1 && unsigned_count >= 0) {
> + comp_list->ipl_info_header.iiei |= S390_IIEI_MORE_SIGNED_COMP;
> + zipl_secure_handle("Only one signed component is allowed");
> + }
> +}
> +
> +void check_global_sclab(SecureIplSclabInfo sclab_info,
> + int unsigned_count, int signed_count,
> + IplDeviceComponentList *comp_list)
> +{
> + if (sclab_info.count == 0) {
> + return;
> + }
> +
> + if (sclab_info.global_count == 0) {
> + comp_list->ipl_info_header.iiei |= S390_IIEI_NO_GLOBAL_SCLAB;
> + zipl_secure_handle("Global SCLAB does not exists");
> + return;
> + }
> +
> + if (sclab_info.global_count > 1) {
> + comp_list->ipl_info_header.iiei |= S390_IIEI_MORE_GLOBAL_SCLAB;
> + zipl_secure_handle("More than one global SCLAB");
> + return;
> + }
> +
> + if (sclab_info.flags) {
> + /* Unsigned components are not allowed if NUC flag is set in the global SCLAB */
> + check_nuc(sclab_info.flags, unsigned_count, comp_list);
> +
> + /* Only one signed component is allowed is SC flag is set in the global SCLAB */
> + check_sc(sclab_info.flags, signed_count, unsigned_count, comp_list);
There's `check_sc()` and also `check_sclab_sc()` (and
`check_signed_comp()`, which is similar). At least with the first two,
the functions are very easy to mix up (in fact, I was going to suggest
renaming check_sc to check_sclab_sc).
> + }
> +}
> +
> +static void check_signed_comp(int signed_count, IplDeviceComponentList *comp_list)
> +{
> + if (signed_count > 0) {
> + return;
> + }
> +
> + comp_list->ipl_info_header.iiei |= S390_IIEI_NO_SIGNED_COMP;
> + zipl_secure_handle("Secure boot is on, but components are not signed");
> +}
> +
> +static void check_sclab_count(int count, IplDeviceComponentList *comp_list)
> +{
> + if (count > 0) {
> + return;
> + }
> +
> + comp_list->ipl_info_header.iiei |= S390_IIEI_NO_SCLAB;
> + zipl_secure_handle("No recognizable SCLAB");
> +}
> +
> +static void check_sclab(uint64_t comp_addr, uint64_t comp_len,
> + IplDeviceComponentEntry *comp_entry,
> + SecureIplSclabInfo *sclab_info)
> +{
> + SclabOriginLocator *sclab_locator;
> + SecureCodeLoadingAttributesBlock *sclab;
> + bool exist;
> +
> + /* sclab locator is located at the last 8 bytes of the signed comp */
> + sclab_locator = (SclabOriginLocator *)(comp_addr + comp_len - 8);
> +
> + /* return early if sclab does not exist */
> + exist = check_sclab_presence(sclab_locator->magic, comp_entry);
Could just merge this into the check below:
```
if (!check_sclab_presence(...)) {
return;
}
```
> + if (!exist) {
> + return;
> + }
> +
> + check_sclab_length(sclab_locator->len, comp_entry);
> +
> + /* return early if sclab is invalid */
> + if (comp_entry && (comp_entry->cei & S390_CEI_INVALID_SCLAB)) {
> + return;
> + }
> +
> + sclab_info->count += 1;
> + sclab = (SecureCodeLoadingAttributesBlock *)(comp_addr + comp_len -
> + sclab_locator->len);
> +
> + check_sclab_format(sclab->format, comp_entry);
> + check_sclab_opsw(sclab, sclab_info, comp_entry);
> + check_sclab_ola(sclab, comp_addr, comp_entry);
> + check_sclab_nuc(sclab->flags, comp_entry);
> + check_sclab_sc(sclab->flags, comp_entry);
> +}
> +
> static int zipl_load_signature(ComponentEntry *entry, uint64_t sig_sec)
> {
> if (zipl_load_segment(entry, sig_sec) < 0) {
> @@ -304,6 +590,9 @@ int zipl_run_secure(ComponentEntry **entry_ptr, uint8_t *tmp_sec)
> SecureIplCompAddrRange comp_addr_range[MAX_CERTIFICATES];
> int addr_range_index = 0;
> int signed_count = 0;
> + int unsigned_count = 0;
> + SecureIplSclabInfo sclab_info = { 0 };
> + IplDeviceComponentEntry *comp_entry;
>
> if (!secure_ipl_supported()) {
> panic("Unable to boot in secure/audit mode");
> @@ -335,10 +624,21 @@ int zipl_run_secure(ComponentEntry **entry_ptr, uint8_t *tmp_sec)
> addr_overlap_check(comp_addr_range, &addr_range_index,
> comp_addr, comp_addr + comp_len, sig_len > 0);
>
> + comp_entry = (comp_entry_idx < MAX_CERTIFICATES) ?
> + &comp_list.device_entries[comp_entry_idx] : NULL;
> +
This took me a little bit of time to understand why this was happening.
It'd make a *little* more sense if it were nested under the if statement
below.
It would read better to `#define` a `MAX_COMPONENTS` as well. Could
just alias `MAX_CERTIFICATES` so both use the same value.
> if (!sig_len) {
> + check_unsigned_addr(comp_addr, comp_entry);
> + comp_list_add(&comp_list, comp_entry_idx, cert_entry_idx,
> + comp_addr, comp_len, 0x00);
> +
> + unsigned_count += 1;
> + comp_entry_idx++;
> break;
> }
>
> + check_sclab(comp_addr, comp_len,
> + &comp_list.device_entries[comp_entry_idx], &sclab_info);
> verified = verify_signature(comp_len, comp_addr, sig_len, (uint64_t)sig,
> &cert_len, &cert_table_idx);
>
> @@ -391,10 +691,20 @@ int zipl_run_secure(ComponentEntry **entry_ptr, uint8_t *tmp_sec)
> }
> }
>
> - if (signed_count == 0) {
> - zipl_secure_handle("Secure boot is on, but components are not signed");
> + /* validate load PSW with PSW specified in the final entry */
> + if (sclab_info.load_psw) {
> + comp_entry = (comp_entry_idx < MAX_CERTIFICATES) ?
> + &comp_list.device_entries[comp_entry_idx] : NULL;
Silently accepting a NULL component makes it seem like an error should
be thrown, or a special case should be handled.
It looks like these `check_*()` functions only need the `cei` field of
the `comp_entry`. Instead of passing the entire `comp_entry` to these
functions, pass something like an independent `cei_flags` variable. The
functions will set the appropriate error bits where appropriate. This
also eliminates the various checks for `comp_entry != NULL`.
Then change `comp_list_add()` to accept the `cei_flags` field and set it
in the respective component while still accounting for the
`MAX_CERTIFICATES` check.
> + check_load_psw(comp_addr_range, addr_range_index,
> + sclab_info.load_psw, entry->compdat.load_psw, comp_entry);
> + comp_list_add(&comp_list, comp_entry_idx, -1,
> + entry->compdat.load_psw, 0, 0x00);
Why is the exec component added to the list? It wasn't added before
this patch.
> }
>
> + check_signed_comp(signed_count, &comp_list);
> + check_sclab_count(sclab_info.count, &comp_list);
> + check_global_sclab(sclab_info, unsigned_count, signed_count, &comp_list);
> +
> update_iirb(&comp_list, &cert_list);
>
> *entry_ptr = entry;
> diff --git a/pc-bios/s390-ccw/secure-ipl.h b/pc-bios/s390-ccw/secure-ipl.h
> index 69edfce241..4e9f4f08b9 100644
> --- a/pc-bios/s390-ccw/secure-ipl.h
> +++ b/pc-bios/s390-ccw/secure-ipl.h
> @@ -16,6 +16,38 @@
> VCStorageSizeBlock *zipl_secure_get_vcssb(void);
> int zipl_run_secure(ComponentEntry **entry_ptr, uint8_t *tmp_sec);
>
> +#define S390_SECURE_IPL_SCLAB_FLAG_OPSW 0x8000
> +#define S390_SECURE_IPL_SCLAB_FLAG_OLA 0x4000
> +#define S390_SECURE_IPL_SCLAB_FLAG_NUC 0x2000
> +#define S390_SECURE_IPL_SCLAB_FLAG_SC 0x1000
> +
> +#define S390_SECURE_IPL_SCLAB_MIN_LEN 32
> +
> +struct SecureCodeLoadingAttributesBlock {
> + uint8_t format;
> + uint8_t reserved1;
> + uint16_t flags;
> + uint8_t reserved2[4];
> + uint64_t load_psw;
> + uint64_t load_addr;
> + uint64_t reserved3[];
> +} __attribute__ ((packed));
> +typedef struct SecureCodeLoadingAttributesBlock SecureCodeLoadingAttributesBlock;
> +
> +struct SclabOriginLocator {
> + uint8_t reserved[2];
> + uint16_t len;
> + uint8_t magic[4];
> +} __attribute__ ((packed));
> +typedef struct SclabOriginLocator SclabOriginLocator;
> +
> +typedef struct SecureIplSclabInfo {
> + int count;
> + int global_count;
> + uint64_t load_psw;
> + uint16_t flags;
> +} SecureIplSclabInfo;
IIRC, `SecureIplSclabInfo` was invented in these patches to help
consolidate some fields. Unless I'm wrong, you could add an
`unsigned_count` and `signed_count` fields. That will clear up some
stuff in `zipl_run_secure()`.
I'd also suggest prepending `global_` to `load_psw` and `flags` here to
make it clear what they represent.
Put a comment above explaining something like "Custom struct used to
consolidate SCLAB overhead". Anything to signal that this isn't a
documented s390 data structure.
> +
> typedef struct SecureIplCompAddrRange {
> bool is_signed;
> uint64_t start_addr;
> @@ -33,6 +65,16 @@ static inline void zipl_secure_handle(const char *message)
> }
> }
>
> +static inline void set_comp_cei_with_log(IplDeviceComponentEntry *comp_entry,
> + uint32_t flag, const char *message)
> +{
> + if (comp_entry) {
> + comp_entry->cei |= flag;
> + }
> +
> + zipl_secure_handle(message);
> +}
> +
> static inline uint64_t diag320(void *data, unsigned long subcode)
> {
> register unsigned long addr asm("0") = (unsigned long)data;
Functionally, I think things look sane. Please look into a way to
simplify the functions that exhibit similar patterns and reduce the
number of parameters required by each function. SCLAF is a bit of an
abstract concept, so anything to make code simpler will help out a lot.
--
Regards,
Collin
next prev parent reply other threads:[~2026-03-17 6:55 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-05 22:41 [PATCH v9 00/30] Secure IPL Support for SCSI Scheme of virtio-blk/virtio-scsi Devices Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 01/30] Add boot-certs to s390-ccw-virtio machine type option Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 02/30] crypto/x509-utils: Refactor with GNUTLS fallback Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 03/30] crypto/x509-utils: Add helper functions for certificate store Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 04/30] hw/s390x/ipl: Create " Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 05/30] s390x/diag: Introduce DIAG 320 for Certificate Store Facility Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 06/30] s390x/diag: Refactor address validation check from diag308_parm_check Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 07/30] s390x/diag: Implement DIAG 320 subcode 1 Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 08/30] crypto/x509-utils: Add helper functions for DIAG 320 subcode 2 Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 09/30] s390x/diag: Implement " Zhuoying Cai
2026-03-13 19:58 ` Collin Walling
2026-03-16 18:04 ` Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 10/30] s390x/diag: Introduce DIAG 508 for secure IPL operations Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 11/30] crypto/x509-utils: Add helper functions for DIAG 508 subcode 1 Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 12/30] s390x/diag: Implement DIAG 508 subcode 1 for signature verification Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 13/30] s390x/ipl: Introduce IPL Information Report Block (IIRB) Zhuoying Cai
2026-03-13 20:00 ` Collin Walling
2026-03-05 22:41 ` [PATCH v9 14/30] pc-bios/s390-ccw: Define memory for IPLB and convert IPLB to pointers Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 15/30] hw/s390x/ipl: Add IPIB flags to IPL Parameter Block Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 16/30] s390x: Guest support for Secure-IPL Facility Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 17/30] pc-bios/s390-ccw: Refactor zipl_run() Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 18/30] pc-bios/s390-ccw: Rework zipl_load_segment function Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 19/30] pc-bios/s390-ccw: Add signature verification for secure IPL in audit mode Zhuoying Cai
2026-03-17 3:41 ` Collin Walling
2026-03-25 19:11 ` Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 20/30] pc-bios/s390-ccw: Add signed component address overlap checks Zhuoying Cai
2026-03-17 4:25 ` Collin Walling
2026-03-05 22:41 ` [PATCH v9 21/30] s390x: Guest support for Secure-IPL Code Loading Attributes Facility (SCLAF) Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 22/30] pc-bios/s390-ccw: Add additional security checks for secure boot Zhuoying Cai
2026-03-17 6:54 ` Collin Walling [this message]
2026-03-05 22:41 ` [PATCH v9 23/30] Add secure-boot to s390-ccw-virtio machine type option Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 24/30] hw/s390x/ipl: Set IPIB flags for secure IPL Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 25/30] pc-bios/s390-ccw: Handle true secure IPL mode Zhuoying Cai
2026-03-17 7:02 ` Collin Walling
2026-03-05 22:41 ` [PATCH v9 26/30] hw/s390x/ipl: Handle secure boot with multiple boot devices Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 27/30] hw/s390x/ipl: Handle secure boot without specifying a boot device Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 28/30] tests/functional/s390x: Add secure IPL functional test Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 29/30] docs/specs: Add secure IPL documentation Zhuoying Cai
2026-03-05 22:41 ` [PATCH v9 30/30] docs/system/s390x: " Zhuoying Cai
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=655c1663-787d-4a42-a90e-36798506c303@linux.ibm.com \
--to=walling@linux.ibm.com \
--cc=alifm@linux.ibm.com \
--cc=armbru@redhat.com \
--cc=berrange@redhat.com \
--cc=borntraeger@linux.ibm.com \
--cc=brueckner@linux.ibm.com \
--cc=david@kernel.org \
--cc=eblake@redhat.com \
--cc=farman@linux.ibm.com \
--cc=iii@linux.ibm.com \
--cc=jdaley@linux.ibm.com \
--cc=jjherne@linux.ibm.com \
--cc=jrossi@linux.ibm.com \
--cc=mjrosato@linux.ibm.com \
--cc=pasic@linux.ibm.com \
--cc=pierrick.bouvier@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=qemu-s390x@nongnu.org \
--cc=richard.henderson@linaro.org \
--cc=thuth@redhat.com \
--cc=zycai@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox