On 2/12/26 3:43 PM, Zhuoying Cai wrote:
> DIAG 320 subcode 2 provides verification-certificates (VCs) that are in the
> certificate store. Only X509 certificates in DER format and SHA-256 hash
> type are recognized.
>
> The subcode value is denoted by setting the second-left-most bit
> of an 8-byte field.
>
> The Verification Certificate Block (VCB) contains the output data
> when the operation completes successfully. It includes a common
> header followed by zero or more Verification Certificate Entries (VCEs),
> depending on the VCB input length and the VC range (from the first VC
> index to the last VC index) in the certificate store.
>
> Each VCE contains information about a certificate retrieved from
> the S390IPLCertificateStore, such as the certificate name, key type,
> key ID length, hash length, and the raw certificate data.
> The key ID and hash are extracted from the raw certificate by the crypto API.
>
> Note: SHA2-256 VC hash type is required for retrieving the hash
> (fingerprint) of the certificate.
>
> Signed-off-by: Zhuoying Cai <[email protected]>
> ---
> docs/specs/s390x-secure-ipl.rst | 22 +++
> hw/s390x/cert-store.h | 3 +-
> include/hw/s390x/ipl/diag320.h | 50 +++++
> target/s390x/diag.c | 328 +++++++++++++++++++++++++++++++-
> 4 files changed, 400 insertions(+), 3 deletions(-)
>
> diff --git a/docs/specs/s390x-secure-ipl.rst b/docs/specs/s390x-secure-ipl.rst
> index d3ece8a82d..22da589162 100644
> --- a/docs/specs/s390x-secure-ipl.rst
> +++ b/docs/specs/s390x-secure-ipl.rst
> @@ -38,3 +38,25 @@ Subcode 1 - query verification certificate storage
> information
> The output is returned in the verification-certificate-storage-size block
> (VCSSB). A VCSSB length of 4 indicates that no certificates are available
> in the CS.
> +
> +Subcode 2 - store verification certificates
> + Provides VCs that are in the certificate store.
> +
> + The output is provided in a VCB, which includes a common header followed
> by
> + zero or more verification-certificate entries (VCEs).
> +
> + The instruction expects the cert store to
> + maintain an origin of 1 for the index (i.e. a retrieval of the first
> + certificate in the store should be denoted by setting first-VC to 1).
> +
> + The first-VC index and last-VC index fields of VCB specify the range of
> VCs
> + to be stored by subcode 2. Stored count and remained count fields specify
> + the number of VCs stored and could not be stored in the VCB due to
> + insufficient storage specified in the VCB input length field.
> +
> + Each VCE contains a header followed by information extracted from a
> + certificate within the certificate store. The information includes:
> + key-id, hash, and certificate data. This information is stored
> + contiguously in a VCE (with zero-padding). Following the header, the
> + key-id is immediately stored. The hash and certificate data follow and
> + may be accessed via the respective offset fields stored in the VCE.
[...]
> QEMU_BUILD_BUG_MSG(sizeof(VCStorageSizeBlock) != VCSSB_MIN_LEN,
> "size of VCStorageSizeBlock is wrong");
> +QEMU_BUILD_BUG_MSG(sizeof(VCBlock) != VCB_HEADER_LEN, "size of VCBlock is
> wrong");
> +QEMU_BUILD_BUG_MSG(sizeof(VCEntry) != VCE_HEADER_LEN, "size of VCEntry is
> wrong");
>
> void handle_diag_320(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t
> ra)
> {
> @@ -267,7 +585,8 @@ void handle_diag_320(CPUS390XState *env, uint64_t r1,
> uint64_t r3, uintptr_t ra)
> * for now.
> */
> uint32_t ism_word0 = cpu_to_be32(DIAG_320_ISM_QUERY_SUBCODES |
> - DIAG_320_ISM_QUERY_VCSI);
> + DIAG_320_ISM_QUERY_VCSI |
> + DIAG_320_ISM_STORE_VC);
>
> if (s390_cpu_virt_mem_write(cpu, addr, r1, &ism_word0,
> sizeof(ism_word0))) {
> s390_cpu_virt_mem_handle_exc(cpu, ra);
> @@ -293,6 +612,13 @@ void handle_diag_320(CPUS390XState *env, uint64_t r1,
> uint64_t r3, uintptr_t ra)
> }
> env->regs[r1 + 1] = rc;
> break;
Subcode 2 should raise a specification exception if the address in
register r1 is not on a 4K‑byte boundary. I will handle this with the
appropriate changes in the next version.
> + case DIAG_320_SUBC_STORE_VC:
> + rc = handle_diag320_store_vc(cpu, addr, r1, ra, cs);
> + if (rc == -1) {
> + return;
> + }
> + env->regs[r1 + 1] = rc;
> + break;
> default:
> env->regs[r1 + 1] = DIAG_320_RC_NOT_SUPPORTED;
> break;