master
h 183 lines 5.2 KB
Raw
1 /*
2 * S/390 Secure IPL
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 _PC_BIOS_S390_CCW_SECURE_IPL_H
11 #define _PC_BIOS_S390_CCW_SECURE_IPL_H
12
13 #include "bootmap.h"
14 #include <diag320.h>
15 #include <diag508.h>
16
17 #define MAX_SIGNED_COMP 3
18
19 int zipl_secure_get_vcssb(void);
20 bool secure_ipl_supported(void);
21 void update_iirb(IplDeviceComponentList *comp_list,
22 IplSignatureCertificateList *cert_list);
23 void update_cert_list(IplSignatureCertificateList *cert_list);
24 int zipl_run_secure(ComponentEntry **entry_ptr, const uint8_t *tmp_sec,
25 IplDeviceComponentList *comp_list,
26 IplSignatureCertificateList *cert_list,
27 uint8_t **tmp_cert_buf);
28
29 #define S390_SCLAB_OPSW 0x8000 /* override PSW flag */
30 #define S390_SCLAB_OLA 0x4000 /* override load address flag */
31 #define S390_SCLAB_NUC 0x2000 /* no unsigned components flag */
32 #define S390_SCLAB_SC 0x1000 /* single component flag */
33
34 #define S390_SCLAB_MIN_LEN 32
35 #define S390_UNSIGNED_MIN_ADDR 0x2000
36
37 /* Secure Code Loading Attributes Block */
38 struct SclaBlock {
39 uint8_t format;
40 uint8_t reserved1;
41 uint16_t flags;
42 uint8_t reserved2[4];
43 uint64_t load_psw;
44 uint64_t load_addr;
45 uint64_t reserved3[];
46 } __attribute__ ((packed));
47 typedef struct SclaBlock SclaBlock;
48
49 struct SclabOriginLocator {
50 uint8_t reserved[2];
51 uint16_t len;
52 uint8_t magic[4];
53 } __attribute__ ((packed));
54 typedef struct SclabOriginLocator SclabOriginLocator;
55
56 static inline void zipl_secure_error(const char *message)
57 {
58 switch (boot_mode) {
59 case ZIPL_BOOT_MODE_SECURE_AUDIT:
60 printf("AUDIT MODE WARNING: %s\n", message);
61 break;
62 case ZIPL_BOOT_MODE_SECURE:
63 panic(message);
64 break;
65 default:
66 /*
67 * Errors are intentionally ignored in non-secure boot modes.
68 * This function should only be reached in SECURE modes.
69 */
70 break;
71 }
72 }
73
74 static inline void zipl_secure_validate_u16(bool condition, uint16_t *flags,
75 uint16_t flag, const char *message)
76 {
77 if (!condition) {
78 *flags |= flag;
79 zipl_secure_error(message);
80 }
81 }
82
83 static inline void zipl_secure_validate_u32(bool condition, uint32_t *flags,
84 uint32_t flag, const char *message)
85 {
86 if (!condition) {
87 *flags |= flag;
88 zipl_secure_error(message);
89 }
90 }
91
92 #define zipl_secure_validate(condition, flags, flag, message) \
93 _Generic((flags), \
94 uint16_t * : zipl_secure_validate_u16, \
95 uint32_t * : zipl_secure_validate_u32 \
96 )(condition, flags, flag, message)
97
98 static inline uint64_t _diag320(void *data, unsigned long subcode)
99 {
100 register unsigned long addr asm("0") = (unsigned long)data;
101 register unsigned long rc asm("1") = 0;
102
103 asm volatile ("diag %0,%2,0x320\n"
104 : "+d" (addr), "+d" (rc)
105 : "d" (subcode)
106 : "memory", "cc");
107 return rc;
108 }
109
110 static inline bool is_cert_store_facility_supported(void)
111 {
112 uint32_t d320_ism;
113
114 if (!sclp_is_diag320_on()) {
115 return false;
116 }
117
118 if (_diag320(&d320_ism, DIAG_320_SUBC_QUERY_ISM) != DIAG_320_RC_OK) {
119 return false;
120 }
121
122 return d320_ism & (DIAG_320_ISM_QUERY_VCSI | DIAG_320_ISM_STORE_VC);
123 }
124
125 static inline uint64_t _diag508(void *data, unsigned long subcode)
126 {
127 register unsigned long addr asm("0") = (unsigned long)data;
128 register unsigned long rc asm("1") = 0;
129
130 asm volatile ("diag %0,%2,0x508\n"
131 : "+d" (addr), "+d" (rc)
132 : "d" (subcode)
133 : "memory", "cc");
134 return rc;
135 }
136
137 static inline bool is_signature_verif_supported(void)
138 {
139 uint64_t d508_subcodes;
140
141 d508_subcodes = _diag508(NULL, DIAG_508_SUBC_QUERY_SUBC);
142 return d508_subcodes & DIAG_508_SUBC_SIG_VERIF;
143 }
144
145 static inline bool verify_signature(IplDeviceComponentEntry comp_entry,
146 IplSignatureCertificateEntry sig_entry,
147 uint64_t *cert_len, uint8_t *cert_idx)
148 {
149 Diag508SigVerifBlock svb;
150
151 svb.length = sizeof(Diag508SigVerifBlock);
152 svb.version = 0;
153 svb.comp_len = comp_entry.len;
154 svb.comp_addr = comp_entry.addr;
155 svb.sig_len = sig_entry.len;
156 svb.sig_addr = sig_entry.addr;
157
158 if (_diag508(&svb, DIAG_508_SUBC_SIG_VERIF) == DIAG_508_RC_OK) {
159 *cert_len = svb.cert_len;
160 /*
161 * DIAG 508 utilizes an index origin of 0 when indexing the cert store.
162 * The cert_idx will be used for DIAG 320 data structures, which expects
163 * an index origin of 1. Account for the offset here so it's easier to
164 * manage later.
165 */
166 *cert_idx = svb.cert_store_index + 1;
167 return true;
168 }
169
170 return false;
171 }
172
173 static inline bool intersects(uint64_t addr0, uint64_t size0,
174 uint64_t addr1, uint64_t size1)
175 {
176 if (addr1 > addr0) {
177 return addr1 - addr0 < size0;
178 }
179
180 return addr0 - addr1 < size1;
181 }
182
183 #endif /* _PC_BIOS_S390_CCW_SECURE_IPL_H */