@@ -139,6 +139,11 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
s390_get_feat_block(S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT,
read_info->conf_char_ext);
+ if (s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB)) {
+ s390_get_feat_block(S390_FEAT_TYPE_SCLP_FAC134,
+ &read_info->fac134);
+ }
+
read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO |
SCLP_HAS_IOA_RECONFIG);
@@ -134,7 +134,15 @@ typedef struct ReadInfo {
uint16_t highest_cpu;
uint8_t _reserved5[124 - 122]; /* 122-123 */
uint32_t hmfai;
+ uint8_t _reserved7[134 - 128]; /* 128-133 */
+ uint8_t fac134;
+ uint8_t _reserved8[144 - 135]; /* 135-143 */
struct CPUEntry entries[];
+ /*
+ * When the Extended-Length SCCB (ELS) feature is enabled the
+ * start of the entries field begins at an offset denoted by the
+ * offset_cpu field, otherwise it's at an offset of 128.
+ */
} QEMU_PACKED ReadInfo;
typedef struct ReadCpuInfo {
@@ -112,6 +112,8 @@ struct CPUS390XState {
uint16_t external_call_addr;
DECLARE_BITMAP(emergency_signals, S390_MAX_CPUS);
+ uint64_t diag318_info;
+
/* Fields up to this point are cleared by a CPU reset */
struct {} end_reset_fields;
@@ -23,6 +23,7 @@ typedef enum {
S390_FEAT_TYPE_STFL,
S390_FEAT_TYPE_SCLP_CONF_CHAR,
S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT,
+ S390_FEAT_TYPE_SCLP_FAC134,
S390_FEAT_TYPE_SCLP_CPU,
S390_FEAT_TYPE_MISC,
S390_FEAT_TYPE_PLO,
@@ -122,6 +122,9 @@ DEF_FEAT(SIE_CMMA, "cmma", SCLP_CONF_CHAR_EXT, 1, "SIE: Collaborative-memory-man
DEF_FEAT(SIE_PFMFI, "pfmfi", SCLP_CONF_CHAR_EXT, 9, "SIE: PFMF interpretation facility")
DEF_FEAT(SIE_IBS, "ibs", SCLP_CONF_CHAR_EXT, 10, "SIE: Interlock-and-broadcast-suppression facility")
+/* 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")
+
/* Features exposed via SCLP CPU info. */
DEF_FEAT(SIE_F2, "sief2", SCLP_CPU, 4, "SIE: interception format 2 (Virtual SIE)")
DEF_FEAT(SIE_SKEY, "skey", SCLP_CPU, 5, "SIE: Storage-key facility")
@@ -824,6 +824,7 @@ static void check_consistency(const S390CPUModel *model)
{ S390_FEAT_PTFF_STOE, S390_FEAT_MULTIPLE_EPOCH },
{ 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 },
};
int i;
@@ -523,6 +523,7 @@ static uint16_t full_GEN12_GA1[] = {
S390_FEAT_AP_FACILITIES_TEST,
S390_FEAT_AP,
S390_FEAT_EXTENDED_LENGTH_SCCB,
+ S390_FEAT_DIAG_318,
};
static uint16_t full_GEN12_GA2[] = {
@@ -105,6 +105,7 @@
#define DIAG_TIMEREVENT 0x288
#define DIAG_IPL 0x308
+#define DIAG_SET_CONTROL_PROGRAM_CODES 0x318
#define DIAG_KVM_HYPERCALL 0x500
#define DIAG_KVM_BREAKPOINT 0x501
@@ -602,6 +603,11 @@ int kvm_arch_put_registers(CPUState *cs, int level)
cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ETOKEN;
}
+ if (can_sync_regs(cs, KVM_SYNC_DIAG318)) {
+ cs->kvm_run->s.regs.diag318 = env->diag318_info;
+ cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
+ }
+
/* Finally the prefix */
if (can_sync_regs(cs, KVM_SYNC_PREFIX)) {
cs->kvm_run->s.regs.prefix = env->psa;
@@ -741,6 +747,10 @@ int kvm_arch_get_registers(CPUState *cs)
}
}
+ if (can_sync_regs(cs, KVM_SYNC_DIAG318)) {
+ env->diag318_info = cs->kvm_run->s.regs.diag318;
+ }
+
return 0;
}
@@ -1601,6 +1611,27 @@ static int handle_sw_breakpoint(S390CPU *cpu, struct kvm_run *run)
return -ENOENT;
}
+static void handle_diag_318(S390CPU *cpu, struct kvm_run *run)
+{
+ uint64_t reg = (run->s390_sieic.ipa & 0x00f0) >> 4;
+ uint64_t diag318_info = run->s.regs.gprs[reg];
+
+ /*
+ * DIAG 318 can only be enabled with KVM support. As such, let's
+ * ensure a guest cannot execute this instruction erroneously.
+ */
+ if (!s390_has_feat(S390_FEAT_DIAG_318)) {
+ kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
+ }
+
+ cpu->env.diag318_info = diag318_info;
+
+ if (can_sync_regs(CPU(cpu), KVM_SYNC_DIAG318)) {
+ run->s.regs.diag318 = diag318_info;
+ run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
+ }
+}
+
#define DIAG_KVM_CODE_MASK 0x000000000000ffff
static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
@@ -1620,6 +1651,9 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
case DIAG_IPL:
kvm_handle_diag_308(cpu, run);
break;
+ case DIAG_SET_CONTROL_PROGRAM_CODES:
+ handle_diag_318(cpu, run);
+ break;
case DIAG_KVM_HYPERCALL:
r = handle_hypercall(cpu, run);
break;
@@ -2464,6 +2498,11 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp)
*/
set_bit(S390_FEAT_EXTENDED_LENGTH_SCCB, model->features);
+ /* DIAGNOSE 0x318 is not supported under protected virtualization */
+ if (!s390_is_pv() && kvm_check_extension(kvm_state, KVM_CAP_S390_DIAG318)) {
+ set_bit(S390_FEAT_DIAG_318, model->features);
+ }
+
/* strip of features that are not part of the maximum model */
bitmap_and(model->features, model->features, model->def->full_feat,
S390_FEAT_MAX);
@@ -234,6 +234,22 @@ const VMStateDescription vmstate_etoken = {
}
};
+static bool diag318_needed(void *opaque)
+{
+ return s390_has_feat(S390_FEAT_DIAG_318);
+}
+
+const VMStateDescription vmstate_diag318 = {
+ .name = "cpu/diag318",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = diag318_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(env.diag318_info, S390CPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
const VMStateDescription vmstate_s390_cpu = {
.name = "cpu",
.post_load = cpu_post_load,
@@ -270,6 +286,7 @@ const VMStateDescription vmstate_s390_cpu = {
&vmstate_gscb,
&vmstate_bpbc,
&vmstate_etoken,
+ &vmstate_diag318,
NULL
},
};