Files
Yaya48 cf256aa081 Import QEMU upstream snapshot d2e570c
Upstream: https://gitlab.com/qemu-project/qemu.git

Upstream-Commit: d2e570cc0f97b936902a5b1b86b73c0f5998b475
2026-08-31 02:15:30 +02:00

184 lines
5.2 KiB
C

/*
* S/390 Secure IPL
*
* Copyright 2025 IBM Corp.
* Author(s): Zhuoying Cai <[email protected]>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef _PC_BIOS_S390_CCW_SECURE_IPL_H
#define _PC_BIOS_S390_CCW_SECURE_IPL_H
#include "bootmap.h"
#include <diag320.h>
#include <diag508.h>
#define MAX_SIGNED_COMP 3
int zipl_secure_get_vcssb(void);
bool secure_ipl_supported(void);
void update_iirb(IplDeviceComponentList *comp_list,
IplSignatureCertificateList *cert_list);
void update_cert_list(IplSignatureCertificateList *cert_list);
int zipl_run_secure(ComponentEntry **entry_ptr, const uint8_t *tmp_sec,
IplDeviceComponentList *comp_list,
IplSignatureCertificateList *cert_list,
uint8_t **tmp_cert_buf);
#define S390_SCLAB_OPSW 0x8000 /* override PSW flag */
#define S390_SCLAB_OLA 0x4000 /* override load address flag */
#define S390_SCLAB_NUC 0x2000 /* no unsigned components flag */
#define S390_SCLAB_SC 0x1000 /* single component flag */
#define S390_SCLAB_MIN_LEN 32
#define S390_UNSIGNED_MIN_ADDR 0x2000
/* Secure Code Loading Attributes Block */
struct SclaBlock {
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 SclaBlock SclaBlock;
struct SclabOriginLocator {
uint8_t reserved[2];
uint16_t len;
uint8_t magic[4];
} __attribute__ ((packed));
typedef struct SclabOriginLocator SclabOriginLocator;
static inline void zipl_secure_error(const char *message)
{
switch (boot_mode) {
case ZIPL_BOOT_MODE_SECURE_AUDIT:
printf("AUDIT MODE WARNING: %s\n", message);
break;
case ZIPL_BOOT_MODE_SECURE:
panic(message);
break;
default:
/*
* Errors are intentionally ignored in non-secure boot modes.
* This function should only be reached in SECURE modes.
*/
break;
}
}
static inline void zipl_secure_validate_u16(bool condition, uint16_t *flags,
uint16_t flag, const char *message)
{
if (!condition) {
*flags |= flag;
zipl_secure_error(message);
}
}
static inline void zipl_secure_validate_u32(bool condition, uint32_t *flags,
uint32_t flag, const char *message)
{
if (!condition) {
*flags |= flag;
zipl_secure_error(message);
}
}
#define zipl_secure_validate(condition, flags, flag, message) \
_Generic((flags), \
uint16_t * : zipl_secure_validate_u16, \
uint32_t * : zipl_secure_validate_u32 \
)(condition, flags, flag, message)
static inline uint64_t _diag320(void *data, unsigned long subcode)
{
register unsigned long addr asm("0") = (unsigned long)data;
register unsigned long rc asm("1") = 0;
asm volatile ("diag %0,%2,0x320\n"
: "+d" (addr), "+d" (rc)
: "d" (subcode)
: "memory", "cc");
return rc;
}
static inline bool is_cert_store_facility_supported(void)
{
uint32_t d320_ism;
if (!sclp_is_diag320_on()) {
return false;
}
if (_diag320(&d320_ism, DIAG_320_SUBC_QUERY_ISM) != DIAG_320_RC_OK) {
return false;
}
return d320_ism & (DIAG_320_ISM_QUERY_VCSI | DIAG_320_ISM_STORE_VC);
}
static inline uint64_t _diag508(void *data, unsigned long subcode)
{
register unsigned long addr asm("0") = (unsigned long)data;
register unsigned long rc asm("1") = 0;
asm volatile ("diag %0,%2,0x508\n"
: "+d" (addr), "+d" (rc)
: "d" (subcode)
: "memory", "cc");
return rc;
}
static inline bool is_signature_verif_supported(void)
{
uint64_t d508_subcodes;
d508_subcodes = _diag508(NULL, DIAG_508_SUBC_QUERY_SUBC);
return d508_subcodes & DIAG_508_SUBC_SIG_VERIF;
}
static inline bool verify_signature(IplDeviceComponentEntry comp_entry,
IplSignatureCertificateEntry sig_entry,
uint64_t *cert_len, uint8_t *cert_idx)
{
Diag508SigVerifBlock svb;
svb.length = sizeof(Diag508SigVerifBlock);
svb.version = 0;
svb.comp_len = comp_entry.len;
svb.comp_addr = comp_entry.addr;
svb.sig_len = sig_entry.len;
svb.sig_addr = sig_entry.addr;
if (_diag508(&svb, DIAG_508_SUBC_SIG_VERIF) == DIAG_508_RC_OK) {
*cert_len = svb.cert_len;
/*
* DIAG 508 utilizes an index origin of 0 when indexing the cert store.
* The cert_idx will be used for DIAG 320 data structures, which expects
* an index origin of 1. Account for the offset here so it's easier to
* manage later.
*/
*cert_idx = svb.cert_store_index + 1;
return true;
}
return false;
}
static inline bool intersects(uint64_t addr0, uint64_t size0,
uint64_t addr1, uint64_t size1)
{
if (addr1 > addr0) {
return addr1 - addr0 < size0;
}
return addr0 - addr1 < size1;
}
#endif /* _PC_BIOS_S390_CCW_SECURE_IPL_H */