DIAG 320 subcode 1 provides information needed to determine the amount of storage to store one or more certificates.
The subcode value is denoted by setting the left-most bit of an 8-byte field. The verification-certificate-storage-size block (VCSSB) contains the output data when the operation completes successfully. Signed-off-by: Zhuoying Cai <zy...@linux.ibm.com> --- include/hw/s390x/ipl/diag320.h | 25 ++++++++++++++++++++++ target/s390x/diag.c | 39 +++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/include/hw/s390x/ipl/diag320.h b/include/hw/s390x/ipl/diag320.h index d6f70c65df..ded336df25 100644 --- a/include/hw/s390x/ipl/diag320.h +++ b/include/hw/s390x/ipl/diag320.h @@ -13,7 +13,32 @@ #define S390X_DIAG320_H #define DIAG_320_SUBC_QUERY_ISM 0 +#define DIAG_320_SUBC_QUERY_VCSI 1 #define DIAG_320_RC_OK 0x0001 +#define DIAG_320_RC_NOMEM 0x0202 + +#define VCSSB_MAX_LEN 128 +#define VCE_HEADER_LEN 128 +#define VCB_HEADER_LEN 64 + +#define DIAG_320_ISM_QUERY_VCSI 0x4000000000000000 + +struct VerificationCertificateStorageSizeBlock { + uint32_t length; + uint8_t reserved0[3]; + uint8_t version; + uint32_t reserved1[6]; + uint16_t totalvc; + uint16_t maxvc; + uint32_t reserved3[7]; + uint32_t maxvcelen; + uint32_t reserved4[3]; + uint32_t largestvcblen; + uint32_t totalvcblen; + uint32_t reserved5[10]; +} QEMU_PACKED; +typedef struct VerificationCertificateStorageSizeBlock \ +VerificationCertificateStorageSizeBlock; #endif diff --git a/target/s390x/diag.c b/target/s390x/diag.c index c64b935c87..cc639819ec 100644 --- a/target/s390x/diag.c +++ b/target/s390x/diag.c @@ -194,6 +194,7 @@ out: void handle_diag_320(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra) { S390CPU *cpu = env_archcpu(env); + S390IPLCertificateStore *qcs = s390_ipl_get_certificate_store(); uint64_t subcode = env->regs[r3]; uint64_t addr = env->regs[r1]; int rc; @@ -210,7 +211,7 @@ void handle_diag_320(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra) switch (subcode) { case DIAG_320_SUBC_QUERY_ISM: - uint64_t ism = 0; + uint64_t ism = DIAG_320_ISM_QUERY_VCSI; if (s390_cpu_virt_mem_write(cpu, addr, (uint8_t)r1, &ism, be64_to_cpu(sizeof(ism)))) { @@ -218,6 +219,42 @@ void handle_diag_320(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra) return; } + rc = DIAG_320_RC_OK; + break; + case DIAG_320_SUBC_QUERY_VCSI: + VerificationCertificateStorageSizeBlock vcssb; + + if (!diag_parm_addr_valid(addr, sizeof(VerificationCertificateStorageSizeBlock), + true)) { + s390_program_interrupt(env, PGM_ADDRESSING, ra); + return; + } + + if (!qcs || !qcs->count) { + vcssb.length = 4; + } else { + vcssb.length = VCSSB_MAX_LEN; + vcssb.version = 0; + vcssb.totalvc = qcs->count; + vcssb.maxvc = MAX_CERTIFICATES; + vcssb.maxvcelen = VCE_HEADER_LEN + qcs->max_cert_size; + vcssb.largestvcblen = VCB_HEADER_LEN + vcssb.maxvcelen; + vcssb.totalvcblen = VCB_HEADER_LEN + qcs->count * VCE_HEADER_LEN + + qcs->total_bytes; + } + + if (vcssb.length < 128) { + rc = DIAG_320_RC_NOMEM; + break; + } + + if (s390_cpu_virt_mem_write(cpu, addr, (uint8_t)r1, &vcssb, + be64_to_cpu( + sizeof(VerificationCertificateStorageSizeBlock) + ))) { + s390_cpu_virt_mem_handle_exc(cpu, ra); + return; + } rc = DIAG_320_RC_OK; break; default: -- 2.49.0