On 8/18/25 17:42, Zhuoying Cai wrote:
> 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.

Please add in the commit message that this feature is available starting
with the gen16 CPU model.

> 
> 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.
> 
> Signed-off-by: Zhuoying Cai <zy...@linux.ibm.com>

Other than the question below regarding the documentation, code LGTM!

Reviewed-by: Collin Walling <wall...@linux.ibm.com>

> ---
>  docs/specs/s390x-secure-ipl.rst     | 25 ++++++++++++++++
>  include/hw/s390x/ipl/diag320.h      | 20 +++++++++++++
>  target/s390x/cpu_features.c         |  1 +
>  target/s390x/cpu_features_def.h.inc |  1 +
>  target/s390x/cpu_models.c           |  2 ++
>  target/s390x/diag.c                 | 44 +++++++++++++++++++++++++++++
>  target/s390x/gen-features.c         |  3 ++
>  target/s390x/kvm/kvm.c              | 16 +++++++++++
>  target/s390x/s390x-internal.h       |  2 ++
>  target/s390x/tcg/misc_helper.c      |  7 +++++
>  10 files changed, 121 insertions(+)
>  create mode 100644 docs/specs/s390x-secure-ipl.rst
>  create mode 100644 include/hw/s390x/ipl/diag320.h
> 
> diff --git a/docs/specs/s390x-secure-ipl.rst b/docs/specs/s390x-secure-ipl.rst
> new file mode 100644
> index 0000000000..70e9a66fe0
> --- /dev/null
> +++ b/docs/specs/s390x-secure-ipl.rst
> @@ -0,0 +1,25 @@
> +.. SPDX-License-Identifier: GPL-2.0-or-later
> +
> +s390 Certificate Store and Functions
> +====================================
> +
> +s390 Certificate Store
> +----------------------
> +
> +A certificate store is implemented for s390-ccw guests to retain within
> +memory all certificates provided by the user via the command-line, which
> +are expected to be stored somewhere on the host's file system. The store
> +will keep track of the number of certificates, their respective size,
> +and a summation of the sizes.
> +

Perhaps the above should go with patch #4, since that one introduces the
cert store?

> +DIAGNOSE function code 'X'320' - Certificate Store Facility
> +-----------------------------------------------------------
> +
> +DIAGNOSE 'X'320' is used to provide support for userspace to directly
> +query the s390 certificate store. Userspace may be the s390-ccw BIOS or
> +the guest kernel.
> +
> +Subcode 0 - query installed subcodes
> +    Returns a 256-bit installed subcodes mask (ISM) stored in the installed
> +    subcodes block (ISB). This mask indicates which sucodes are currently
> +    installed and available for use.
> diff --git a/include/hw/s390x/ipl/diag320.h b/include/hw/s390x/ipl/diag320.h
> new file mode 100644
> index 0000000000..aa04b699c6
> --- /dev/null
> +++ b/include/hw/s390x/ipl/diag320.h
> @@ -0,0 +1,20 @@
> +/*
> + * S/390 DIAGNOSE 320 definitions and structures
> + *
> + * Copyright 2025 IBM Corp.
> + * Author(s): Zhuoying Cai <zy...@linux.ibm.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef S390X_DIAG320_H
> +#define S390X_DIAG320_H
> +
> +#define DIAG_320_SUBC_QUERY_ISM     0
> +
> +#define DIAG_320_RC_OK              0x0001
> +#define DIAG_320_RC_NOT_SUPPORTED   0x0102
> +
> +#define DIAG_320_ISM_QUERY_SUBCODES 0x80000000
> +
> +#endif
> diff --git a/target/s390x/cpu_features.c b/target/s390x/cpu_features.c
> index 4b5be6798e..436471f4b4 100644
> --- a/target/s390x/cpu_features.c
> +++ b/target/s390x/cpu_features.c
> @@ -147,6 +147,7 @@ void s390_fill_feat_block(const S390FeatBitmap features, 
> S390FeatType type,
>          break;
>      case S390_FEAT_TYPE_SCLP_FAC134:
>          clear_be_bit(s390_feat_def(S390_FEAT_DIAG_318)->bit, data);
> +        clear_be_bit(s390_feat_def(S390_FEAT_CERT_STORE)->bit, data);
>          break;
>      default:
>          return;
> diff --git a/target/s390x/cpu_features_def.h.inc 
> b/target/s390x/cpu_features_def.h.inc
> index c017bffcdc..941a69e013 100644
> --- a/target/s390x/cpu_features_def.h.inc
> +++ b/target/s390x/cpu_features_def.h.inc
> @@ -138,6 +138,7 @@ DEF_FEAT(SIE_IBS, "ibs", SCLP_CONF_CHAR_EXT, 10, "SIE: 
> Interlock-and-broadcast-s
>  
>  /* Features exposed via SCLP SCCB Facilities byte 134 (bit numbers relative 
> to byte-134) */
>  DEF_FEAT(DIAG_318, "diag318", SCLP_FAC134, 0, "Control program name and 
> version codes")
> +DEF_FEAT(CERT_STORE, "cstore", SCLP_FAC134, 5, "Provide Certificate Store 
> functions")
>  
>  /* Features exposed via SCLP CPU info. */
>  DEF_FEAT(SIE_F2, "sief2", SCLP_CPU, 4, "SIE: interception format 2 (Virtual 
> SIE)")
> diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
> index 954a7a99a9..6b8471700e 100644
> --- a/target/s390x/cpu_models.c
> +++ b/target/s390x/cpu_models.c
> @@ -248,6 +248,7 @@ bool s390_has_feat(S390Feat feat)
>      if (s390_is_pv()) {
>          switch (feat) {
>          case S390_FEAT_DIAG_318:
> +        case S390_FEAT_CERT_STORE:
>          case S390_FEAT_HPMA2:
>          case S390_FEAT_SIE_F2:
>          case S390_FEAT_SIE_SKEY:
> @@ -505,6 +506,7 @@ static void check_consistency(const S390CPUModel *model)
>          { S390_FEAT_PTFF_STOUE, S390_FEAT_MULTIPLE_EPOCH },
>          { S390_FEAT_AP_QUEUE_INTERRUPT_CONTROL, S390_FEAT_AP },
>          { S390_FEAT_DIAG_318, S390_FEAT_EXTENDED_LENGTH_SCCB },
> +        { S390_FEAT_CERT_STORE, S390_FEAT_EXTENDED_LENGTH_SCCB },
>          { S390_FEAT_NNPA, S390_FEAT_VECTOR },
>          { S390_FEAT_RDP, S390_FEAT_LOCAL_TLB_CLEARING },
>          { S390_FEAT_UV_FEAT_AP, S390_FEAT_AP },
> diff --git a/target/s390x/diag.c b/target/s390x/diag.c
> index cff9fbc4b0..a35d808fd7 100644
> --- a/target/s390x/diag.c
> +++ b/target/s390x/diag.c
> @@ -18,6 +18,7 @@
>  #include "hw/watchdog/wdt_diag288.h"
>  #include "system/cpus.h"
>  #include "hw/s390x/ipl.h"
> +#include "hw/s390x/ipl/diag320.h"
>  #include "hw/s390x/s390-virtio-ccw.h"
>  #include "system/kvm.h"
>  #include "kvm/kvm_s390x.h"
> @@ -191,3 +192,46 @@ out:
>          break;
>      }
>  }
> +
> +void handle_diag_320(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t 
> ra)
> +{
> +    S390CPU *cpu = env_archcpu(env);
> +    uint64_t subcode = env->regs[r3];
> +    uint64_t addr = env->regs[r1];
> +
> +    if (env->psw.mask & PSW_MASK_PSTATE) {
> +        s390_program_interrupt(env, PGM_PRIVILEGED, ra);
> +        return;
> +    }
> +
> +    if (!s390_has_feat(S390_FEAT_CERT_STORE)) {
> +        s390_program_interrupt(env, PGM_SPECIFICATION, ra);
> +        return;
> +    }
> +
> +    if ((subcode & ~0x000ffULL) || (r1 & 1)) {
> +        s390_program_interrupt(env, PGM_SPECIFICATION, ra);
> +        return;
> +    }
> +
> +    switch (subcode) {
> +    case DIAG_320_SUBC_QUERY_ISM:
> +        /*
> +         * The Installed Subcode Block (ISB) can be up 8 words in size,
> +         * but the current set of subcodes can fit within a single word
> +         * for now.
> +         */
> +        uint32_t ism_word0 = cpu_to_be32(DIAG_320_ISM_QUERY_SUBCODES);
> +
> +        if (s390_cpu_virt_mem_write(cpu, addr, r1, &ism_word0, 
> sizeof(ism_word0))) {
> +            s390_cpu_virt_mem_handle_exc(cpu, ra);
> +            return;
> +        }
> +
> +        env->regs[r1 + 1] = DIAG_320_RC_OK;
> +        break;
> +    default:
> +        env->regs[r1 + 1] = DIAG_320_RC_NOT_SUPPORTED;
> +        break;
> +    }
> +}
> diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
> index 8218e6470e..6c20c3a862 100644
> --- a/target/s390x/gen-features.c
> +++ b/target/s390x/gen-features.c
> @@ -720,6 +720,7 @@ static uint16_t full_GEN16_GA1[] = {
>      S390_FEAT_PAIE,
>      S390_FEAT_UV_FEAT_AP,
>      S390_FEAT_UV_FEAT_AP_INTR,
> +    S390_FEAT_CERT_STORE,
>  };
>  
>  static uint16_t full_GEN17_GA1[] = {
> @@ -919,6 +920,8 @@ static uint16_t qemu_MAX[] = {
>      S390_FEAT_KIMD_SHA_512,
>      S390_FEAT_KLMD_SHA_512,
>      S390_FEAT_PRNO_TRNG,
> +    S390_FEAT_EXTENDED_LENGTH_SCCB,
> +    S390_FEAT_CERT_STORE,
>  };
>  
>  /****** END FEATURE DEFS ******/
> diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
> index 8ee33924df..5510fc2fc5 100644
> --- a/target/s390x/kvm/kvm.c
> +++ b/target/s390x/kvm/kvm.c
> @@ -98,6 +98,7 @@
>  #define DIAG_TIMEREVENT                 0x288
>  #define DIAG_IPL                        0x308
>  #define DIAG_SET_CONTROL_PROGRAM_CODES  0x318
> +#define DIAG_CERT_STORE                 0x320
>  #define DIAG_KVM_HYPERCALL              0x500
>  #define DIAG_KVM_BREAKPOINT             0x501
>  
> @@ -1560,6 +1561,16 @@ static void handle_diag_318(S390CPU *cpu, struct 
> kvm_run *run)
>      }
>  }
>  
> +static void kvm_handle_diag_320(S390CPU *cpu, struct kvm_run *run)
> +{
> +    uint64_t r1, r3;
> +
> +    r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
> +    r3 = run->s390_sieic.ipa & 0x000f;
> +
> +    handle_diag_320(&cpu->env, r1, r3, RA_IGNORED);
> +}
> +
>  #define DIAG_KVM_CODE_MASK 0x000000000000ffff
>  
>  static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
> @@ -1590,6 +1601,9 @@ static int handle_diag(S390CPU *cpu, struct kvm_run 
> *run, uint32_t ipb)
>      case DIAG_KVM_BREAKPOINT:
>          r = handle_sw_breakpoint(cpu, run);
>          break;
> +    case DIAG_CERT_STORE:
> +        kvm_handle_diag_320(cpu, run);
> +        break;
>      default:
>          trace_kvm_insn_diag(func_code);
>          kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
> @@ -2490,6 +2504,8 @@ bool kvm_s390_get_host_cpu_model(S390CPUModel *model, 
> Error **errp)
>          set_bit(S390_FEAT_DIAG_318, model->features);
>      }
>  
> +    set_bit(S390_FEAT_CERT_STORE, model->features);
> +
>      /* Test for Ultravisor features that influence secure guest behavior */
>      query_uv_feat_guest(model->features);
>  
> diff --git a/target/s390x/s390x-internal.h b/target/s390x/s390x-internal.h
> index 56cce2e7f5..ecff2d07a1 100644
> --- a/target/s390x/s390x-internal.h
> +++ b/target/s390x/s390x-internal.h
> @@ -391,6 +391,8 @@ int mmu_translate_real(CPUS390XState *env, target_ulong 
> raddr, int rw,
>  int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3);
>  void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3,
>                       uintptr_t ra);
> +void handle_diag_320(CPUS390XState *env, uint64_t r1, uint64_t r3,
> +                     uintptr_t ra);
>  
>  
>  /* translate.c */
> diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c
> index f7101be574..412c34ed93 100644
> --- a/target/s390x/tcg/misc_helper.c
> +++ b/target/s390x/tcg/misc_helper.c
> @@ -142,6 +142,13 @@ void HELPER(diag)(CPUS390XState *env, uint32_t r1, 
> uint32_t r3, uint32_t num)
>          /* time bomb (watchdog) */
>          r = handle_diag_288(env, r1, r3);
>          break;
> +    case 0x320:
> +        /* cert store */
> +        bql_lock();
> +        handle_diag_320(env, r1, r3, GETPC());
> +        bql_unlock();
> +        r = 0;
> +        break;
>      default:
>          r = -1;
>          break;


-- 
Regards,
  Collin

Reply via email to