@samitouri / QOSamiQemu / commits / 66deb27152

s390x/diag: Introduce DIAG 320 for Certificate Store Facility

DIAGNOSE 320 is introduced to support Certificate Store (CS) Facility, which includes operations such as query certificate storage information and provide certificates in the certificate store. Currently, only subcode 0 is supported with this patch, which is used to query the Installed Subcodes Mask (ISM). This subcode is only supported when the CS facility is enabled. Availability of CS facility is determined by byte 134 bit 5 of the SCLP Read Info block. Byte 134's facilities cannot be represented without the availability of the extended-length-SCCB, so add it as a check for consistency. Note: secure IPL is not available for Secure Execution (SE) guests, as their images are already integrity protected, and an additional protection of the kernel by secure IPL is not necessary. This feature is available starting with the gen16 CPU model. Signed-off-by: Zhuoying Cai <zycai@linux.ibm.com> Reviewed-by: Collin Walling <walling@linux.ibm.com> Reviewed-by: Farhan Ali <alifm@linux.ibm.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Link: https://lore.kernel.org/qemu-devel/20260730214624.2328883-6-zycai@linux.ibm.com Signed-off-by: Eric Farman <farman@linux.ibm.com>

Zhuoying Cai committed Jul 30, 2026 at 17:45 UTC 66deb271528020cdf8be4611c9562cf5d5dab73e
10 files changed +106
docs/specs/s390x-secure-ipl.rst
+12
@@ -18,3 +18,15 @@ PEM Base64 data.
18
19 Note: A maximum of 64 certificates are allowed to be stored in the certificate
20 store.
21 +
22 +DIAGNOSE function code 'X'320' - Certificate Store Facility
23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24 +
25 +DIAGNOSE 'X'320' is used to provide support for guest code to directly
26 +query the s390 certificate store. Guest code may be the s390-ccw BIOS or
27 +the guest kernel.
28 +
29 +Subcode 0 - query installed subcodes
30 + Returns a 256-bit installed subcodes mask (ISM) stored in the installed
31 + subcodes block (ISB). This mask indicates which subcodes are currently
32 + installed and available for use.
include/hw/s390x/ipl/diag320.h new
+20
@@ -0,0 +1,20 @@
1 +/*
2 + * S/390 DIAGNOSE 320 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_DIAG320_H
11 +#define S390X_DIAG320_H
12 +
13 +#define DIAG_320_SUBC_QUERY_ISM 0
14 +
15 +#define DIAG_320_RC_OK 0x0001
16 +#define DIAG_320_RC_NOT_SUPPORTED 0x0102
17 +
18 +#define DIAG_320_ISM_QUERY_SUBCODES 0x80000000
19 +
20 +#endif
target/s390x/cpu_features.c
+1
@@ -147,6 +147,7 @@ void s390_fill_feat_block(const S390FeatBitmap features, S390FeatType type,
147 break;
148 case S390_FEAT_TYPE_SCLP_FAC134:
149 clear_be_bit(s390_feat_def(S390_FEAT_DIAG_318)->bit, data);
150 + clear_be_bit(s390_feat_def(S390_FEAT_CERT_STORE)->bit, data);
151 break;
152 case S390_FEAT_TYPE_SCLP_FAC139:
153 clear_be_bit(s390_feat_def(S390_FEAT_SIE_ASTFLEIE2)->bit, data);
target/s390x/cpu_features_def.h.inc
+1
@@ -138,6 +138,7 @@ DEF_FEAT(SIE_IBS, "ibs", SCLP_CONF_CHAR_EXT, 10, "SIE: Interlock-and-broadcast-s
138
139 /* Features exposed via SCLP SCCB Facilities byte 134 (bit numbers relative to byte-134) */
140 DEF_FEAT(DIAG_318, "diag318", SCLP_FAC134, 0, "Control program name and version codes")
141 +DEF_FEAT(CERT_STORE, "cstore", SCLP_FAC134, 5, "Certificate Store functions")
142
143 /* Features exposed via SCLP SCCB Facilities byte 139 (bit numbers relative to byte-139) */
144 DEF_FEAT(SIE_ASTFLEIE2, "astfleie2", SCLP_FAC139, 1, "SIE: ASTFLE interpretation execution facility 2")
target/s390x/cpu_models.c
+2
@@ -248,6 +248,7 @@ bool s390_has_feat(S390Feat feat)
248 if (s390_is_pv()) {
249 switch (feat) {
250 case S390_FEAT_DIAG_318:
251 + case S390_FEAT_CERT_STORE:
252 case S390_FEAT_HPMA2:
253 case S390_FEAT_SIE_F2:
254 case S390_FEAT_SIE_SKEY:
@@ -506,6 +507,7 @@ static void check_consistency(const S390CPUModel *model)
507 { S390_FEAT_PTFF_STOUE, S390_FEAT_MULTIPLE_EPOCH },
508 { S390_FEAT_AP_QUEUE_INTERRUPT_CONTROL, S390_FEAT_AP },
509 { S390_FEAT_DIAG_318, S390_FEAT_EXTENDED_LENGTH_SCCB },
510 + { S390_FEAT_CERT_STORE, S390_FEAT_EXTENDED_LENGTH_SCCB },
511 { S390_FEAT_NNPA, S390_FEAT_VECTOR },
512 { S390_FEAT_RDP, S390_FEAT_LOCAL_TLB_CLEARING },
513 { S390_FEAT_UV_FEAT_AP, S390_FEAT_AP },
target/s390x/diag.c
+42
@@ -18,6 +18,7 @@
18 #include "hw/watchdog/wdt_diag288.h"
19 #include "system/cpus.h"
20 #include "hw/s390x/ipl.h"
21 +#include "hw/s390x/ipl/diag320.h"
22 #include "hw/s390x/s390-virtio-ccw.h"
23 #include "system/kvm.h"
24 #include "kvm/kvm_s390x.h"
@@ -199,3 +200,44 @@ out:
200 return false;
201 }
202 }
203 +
204 +void handle_diag_320(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
205 +{
206 + S390CPU *cpu = env_archcpu(env);
207 + uint64_t subcode = env->regs[r3];
208 + uint64_t addr = env->regs[r1];
209 + uint32_t ism_word0;
210 +
211 + if (env->psw.mask & PSW_MASK_PSTATE) {
212 + s390_program_interrupt(env, PGM_PRIVILEGED, ra);
213 + return;
214 + }
215 +
216 + if (!s390_has_feat(S390_FEAT_CERT_STORE) ||
217 + (subcode & ~0x000ffULL) ||
218 + (r1 & 1)) {
219 + s390_program_interrupt(env, PGM_SPECIFICATION, ra);
220 + return;
221 + }
222 +
223 + switch (subcode) {
224 + case DIAG_320_SUBC_QUERY_ISM:
225 + /*
226 + * The Installed Subcode Block (ISB) can be up 8 words in size,
227 + * but the current set of subcodes can fit within a single word
228 + * for now.
229 + */
230 + ism_word0 = cpu_to_be32(DIAG_320_ISM_QUERY_SUBCODES);
231 +
232 + if (s390_cpu_virt_mem_write(cpu, addr, r1, &ism_word0, sizeof(ism_word0))) {
233 + s390_cpu_virt_mem_handle_exc(cpu, ra);
234 + return;
235 + }
236 +
237 + env->regs[r1 + 1] = DIAG_320_RC_OK;
238 + break;
239 + default:
240 + env->regs[r1 + 1] = DIAG_320_RC_NOT_SUPPORTED;
241 + break;
242 + }
243 +}
target/s390x/gen-features.c
+3
@@ -721,6 +721,7 @@ static uint16_t full_GEN16_GA1[] = {
721 S390_FEAT_UV_FEAT_AP,
722 S390_FEAT_UV_FEAT_AP_INTR,
723 S390_FEAT_SIE_ASTFLEIE2,
724 + S390_FEAT_CERT_STORE,
725 };
726
727 static uint16_t full_GEN17_GA1[] = {
@@ -920,6 +921,8 @@ static uint16_t qemu_MAX[] = {
921 S390_FEAT_KIMD_SHA_512,
922 S390_FEAT_KLMD_SHA_512,
923 S390_FEAT_PRNO_TRNG,
924 + S390_FEAT_EXTENDED_LENGTH_SCCB,
925 + S390_FEAT_CERT_STORE,
926 };
927
928 /****** END FEATURE DEFS ******/
target/s390x/kvm/kvm.c
+16
@@ -99,6 +99,7 @@
99 #define DIAG_TIMEREVENT 0x288
100 #define DIAG_IPL 0x308
101 #define DIAG_SET_CONTROL_PROGRAM_CODES 0x318
102 +#define DIAG_CERT_STORE 0x320
103 #define DIAG_KVM_HYPERCALL 0x500
104 #define DIAG_KVM_BREAKPOINT 0x501
105
@@ -1531,6 +1532,16 @@ static void handle_diag_318(S390CPU *cpu, struct kvm_run *run)
1532 }
1533 }
1534
1535 +static void kvm_handle_diag_320(S390CPU *cpu, struct kvm_run *run)
1536 +{
1537 + uint64_t r1, r3;
1538 +
1539 + r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
1540 + r3 = run->s390_sieic.ipa & 0x000f;
1541 +
1542 + handle_diag_320(&cpu->env, r1, r3, RA_IGNORED);
1543 +}
1544 +
1545 #define DIAG_KVM_CODE_MASK 0x000000000000ffff
1546
1547 static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
@@ -1561,6 +1572,9 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
1572 case DIAG_KVM_BREAKPOINT:
1573 r = handle_sw_breakpoint(cpu, run);
1574 break;
1575 + case DIAG_CERT_STORE:
1576 + kvm_handle_diag_320(cpu, run);
1577 + break;
1578 default:
1579 trace_kvm_insn_diag(func_code);
1580 kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
@@ -2472,6 +2486,8 @@ bool kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp)
2486 set_bit(S390_FEAT_DIAG_318, model->features);
2487 }
2488
2489 + set_bit(S390_FEAT_CERT_STORE, model->features);
2490 +
2491 /* Test for Ultravisor features that influence secure guest behavior */
2492 query_uv_feat_guest(model->features);
2493
target/s390x/s390x-internal.h
+2
@@ -388,6 +388,8 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3);
388 /* Return whether a CPU reset is pending */
389 bool handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3,
390 uintptr_t ra);
391 +void handle_diag_320(CPUS390XState *env, uint64_t r1, uint64_t r3,
392 + uintptr_t ra);
393
394
395 /* translate.c */
target/s390x/tcg/misc_helper.c
+7
@@ -147,6 +147,13 @@ void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num)
147 /* time bomb (watchdog) */
148 r = handle_diag_288(env, r1, r3);
149 break;
150 + case 0x320:
151 + /* cert store */
152 + bql_lock();
153 + handle_diag_320(env, r1, r3, GETPC());
154 + bql_unlock();
155 + r = 0;
156 + break;
157 default:
158 r = -1;
159 break;