From: Collin Walling <walling@linux.ibm.com>
In order to support secure IPL (aka secure boot) for the s390-ccw BIOS,
a new s390 DIAGNOSE instruction is introduced to leverage QEMU for
handling operations such as signature verification and certificate
retrieval.
Currently, only subcode 0 is supported with this patch, which is used to
query a bitmap of which subcodes are supported.
Signed-off-by: Collin Walling <walling@linux.ibm.com>
---
docs/specs/s390x-secure-ipl.rst | 18 ++++++++++++++++++
include/hw/s390x/ipl/diag508.h | 15 +++++++++++++++
target/s390x/diag.c | 27 +++++++++++++++++++++++++++
target/s390x/kvm/kvm.c | 14 ++++++++++++++
target/s390x/s390x-internal.h | 2 ++
target/s390x/tcg/misc_helper.c | 7 +++++++
6 files changed, 83 insertions(+)
create mode 100644 include/hw/s390x/ipl/diag508.h
diff --git a/docs/specs/s390x-secure-ipl.rst b/docs/specs/s390x-secure-ipl.rst
index 16868aa823..6b3249173f 100644
--- a/docs/specs/s390x-secure-ipl.rst
+++ b/docs/specs/s390x-secure-ipl.rst
@@ -46,3 +46,21 @@ Subcode 2 - store verification certificates
storage specified in the VCB input length field.
VCE contains various information of a VC from the CS.
+
+
+Secure IPL Data Structures, Facilities, and Functions
+=====================================================
+
+DIAGNOSE function code 'X'508' - KVM IPL extensions
+---------------------------------------------------
+
+DIAGNOSE 'X'508' is reserved for KVM guest use in order to facilitate
+communication of additional IPL operations that cannot be handled by userspace,
+such as signature verification for secure IPL.
+
+If the function code specifies 0x508, KVM IPL extension functions are performed.
+These functions are meant to provide extended functionality for s390 guest boot
+that requires assistance from QEMU.
+
+Subcode 0 - query installed subcodes
+ Returns a 64-bit mask indicating which subcodes are supported.
diff --git a/include/hw/s390x/ipl/diag508.h b/include/hw/s390x/ipl/diag508.h
new file mode 100644
index 0000000000..6281ad8299
--- /dev/null
+++ b/include/hw/s390x/ipl/diag508.h
@@ -0,0 +1,15 @@
+/*
+ * S/390 DIAGNOSE 508 definitions and structures
+ *
+ * Copyright 2025 IBM Corp.
+ * Author(s): Collin Walling <walling@linux.ibm.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef S390X_DIAG508_H
+#define S390X_DIAG508_H
+
+#define DIAG_508_SUBC_QUERY_SUBC 0x0000
+
+#endif
diff --git a/target/s390x/diag.c b/target/s390x/diag.c
index 820f45a0bd..6519a3cedc 100644
--- a/target/s390x/diag.c
+++ b/target/s390x/diag.c
@@ -20,6 +20,7 @@
#include "hw/s390x/cert-store.h"
#include "hw/s390x/ipl.h"
#include "hw/s390x/ipl/diag320.h"
+#include "hw/s390x/ipl/diag508.h"
#include "hw/s390x/s390-virtio-ccw.h"
#include "system/kvm.h"
#include "kvm/kvm_s390x.h"
@@ -571,3 +572,29 @@ void handle_diag_320(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
break;
}
}
+
+void handle_diag_508(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
+{
+ uint64_t subcode = env->regs[r3];
+ int rc;
+
+ if (env->psw.mask & PSW_MASK_PSTATE) {
+ s390_program_interrupt(env, PGM_PRIVILEGED, ra);
+ return;
+ }
+
+ if ((subcode & ~0x0ffffULL) || (r1 & 1)) {
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ return;
+ }
+
+ switch (subcode) {
+ case DIAG_508_SUBC_QUERY_SUBC:
+ rc = 0;
+ break;
+ default:
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ return;
+ }
+ env->regs[r1 + 1] = rc;
+}
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index 5510fc2fc5..ae6cd3d506 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -101,6 +101,7 @@
#define DIAG_CERT_STORE 0x320
#define DIAG_KVM_HYPERCALL 0x500
#define DIAG_KVM_BREAKPOINT 0x501
+#define DIAG_SECURE_IPL 0x508
#define ICPT_INSTRUCTION 0x04
#define ICPT_PROGRAM 0x08
@@ -1571,6 +1572,16 @@ static void kvm_handle_diag_320(S390CPU *cpu, struct kvm_run *run)
handle_diag_320(&cpu->env, r1, r3, RA_IGNORED);
}
+static void kvm_handle_diag_508(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_508(&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)
@@ -1604,6 +1615,9 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
case DIAG_CERT_STORE:
kvm_handle_diag_320(cpu, run);
break;
+ case DIAG_SECURE_IPL:
+ kvm_handle_diag_508(cpu, run);
+ break;
default:
trace_kvm_insn_diag(func_code);
kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
diff --git a/target/s390x/s390x-internal.h b/target/s390x/s390x-internal.h
index ecff2d07a1..7cca8a67de 100644
--- a/target/s390x/s390x-internal.h
+++ b/target/s390x/s390x-internal.h
@@ -393,6 +393,8 @@ 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);
+void handle_diag_508(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 412c34ed93..ddbf495118 100644
--- a/target/s390x/tcg/misc_helper.c
+++ b/target/s390x/tcg/misc_helper.c
@@ -149,6 +149,13 @@ void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num)
bql_unlock();
r = 0;
break;
+ case 0x508:
+ /* secure ipl operations */
+ bql_lock();
+ handle_diag_508(env, r1, r3, GETPC());
+ bql_unlock();
+ r = 0;
+ break;
default:
r = -1;
break;
--
2.50.1