From 1f973083f5fe328b2f26271fa3ccdc6da48c7c9c Mon Sep 17 00:00:00 2001 From: Collin Walling Date: Tue, 15 Sep 2020 15:44:16 -0400 Subject: [PATCH 7/8] s390: guest support for diagnose 0x318 DIAGNOSE 0x318 (diag318) is an s390 instruction that allows the storage of diagnostic information that is collected by the firmware in the case of hardware/firmware service events. QEMU handles the instruction by storing the info in the CPU state. A subsequent register sync will communicate the data to the hypervisor. QEMU handles the migration via a VM State Description. This feature depends on the Extended-Length SCCB (els) feature. If els is not present, then a warning will be printed and the SCLP bit that allows the Linux kernel to execute the instruction will not be set. Availability of this instruction is determined by byte 134 (aka fac134) bit 0 of the SCLP Read Info block. This coincidentally expands into the space used for CPU entries, which means VMs running with the diag318 capability may not be able to read information regarding all CPUs unless the guest kernel supports an extended-length SCCB. This feature is not supported in protected virtualization mode. Signed-off-by: Collin Walling Acked-by: Janosch Frank Acked-by: Thomas Huth Acked-by: David Hildenbrand Acked-by: Claudio Imbrenda Message-Id: <20200915194416.107460-9-walling@linux.ibm.com> Signed-off-by: Cornelia Huck (backported from commit: fabdada9357b9cfd980c7744ddce47e34600bbef) Signed-off-by: Collin Walling --- hw/s390x/sclp.c | 5 ++++ include/hw/s390x/sclp.h | 10 +++++++- linux-headers/asm-s390/kvm.h | 5 +++- linux-headers/linux/kvm.h | 1 + target/s390x/cpu.h | 2 ++ target/s390x/cpu_features.h | 1 + target/s390x/cpu_features_def.inc.h | 3 +++ target/s390x/cpu_models.c | 1 + target/s390x/gen-features.c | 1 + target/s390x/kvm.c | 38 +++++++++++++++++++++++++++++ target/s390x/machine.c | 17 +++++++++++++ 11 files changed, 82 insertions(+), 2 deletions(-) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index d2fd37c9c5..6349ed935f 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -123,6 +123,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); diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h index e2b95a7590..340ea24aac 100644 --- a/include/hw/s390x/sclp.h +++ b/include/hw/s390x/sclp.h @@ -133,7 +133,15 @@ typedef struct ReadInfo { uint16_t highest_cpu; uint8_t _reserved5[124 - 122]; /* 122-123 */ uint32_t hmfai; - struct CPUEntry entries[0]; + 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 { diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h index 0138ccb0d8..63fff57c17 100644 --- a/linux-headers/asm-s390/kvm.h +++ b/linux-headers/asm-s390/kvm.h @@ -231,11 +231,13 @@ struct kvm_guest_debug_arch { #define KVM_SYNC_GSCB (1UL << 9) #define KVM_SYNC_BPBC (1UL << 10) #define KVM_SYNC_ETOKEN (1UL << 11) +#define KVM_SYNC_DIAG318 (1UL << 12) #define KVM_SYNC_S390_VALID_FIELDS \ (KVM_SYNC_PREFIX | KVM_SYNC_GPRS | KVM_SYNC_ACRS | KVM_SYNC_CRS | \ KVM_SYNC_ARCH0 | KVM_SYNC_PFAULT | KVM_SYNC_VRS | KVM_SYNC_RICCB | \ - KVM_SYNC_FPRS | KVM_SYNC_GSCB | KVM_SYNC_BPBC | KVM_SYNC_ETOKEN) + KVM_SYNC_FPRS | KVM_SYNC_GSCB | KVM_SYNC_BPBC | KVM_SYNC_ETOKEN | \ + KVM_SYNC_DIAG318) /* length and alignment of the sdnx as a power of two */ #define SDNXC 8 @@ -264,6 +266,7 @@ struct kvm_sync_regs { __u8 reserved2 : 7; __u8 padding1[51]; /* riccb needs to be 64byte aligned */ __u8 riccb[64]; /* runtime instrumentation controls block */ + __u64 diag318; /* diagnose 0x318 info */ __u8 padding2[192]; /* sdnx needs to be 256byte aligned */ union { __u8 sdnx[SDNXL]; /* state description annex */ diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 3d9b18f7f8..3b216222a9 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1000,6 +1000,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_PMU_EVENT_FILTER 173 #define KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 174 #define KVM_CAP_HYPERV_DIRECT_TLBFLUSH 175 +#define KVM_CAP_S390_DIAG318 186 #ifdef KVM_CAP_IRQ_ROUTING diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 17460ed7b3..1924f0faaa 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -63,6 +63,8 @@ struct CPUS390XState { uint64_t etoken; /* etoken */ uint64_t etoken_extension; /* etoken extension */ + uint64_t diag318_info; + /* Fields up to this point are not cleared by initial CPU reset */ struct {} start_initial_reset_fields; diff --git a/target/s390x/cpu_features.h b/target/s390x/cpu_features.h index da695a8346..f74f7fc3a1 100644 --- a/target/s390x/cpu_features.h +++ b/target/s390x/cpu_features.h @@ -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, diff --git a/target/s390x/cpu_features_def.inc.h b/target/s390x/cpu_features_def.inc.h index 7594f7a7ef..7302292f8d 100644 --- a/target/s390x/cpu_features_def.inc.h +++ b/target/s390x/cpu_features_def.inc.h @@ -121,6 +121,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") diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 7e92fb2e15..522a9216a0 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -820,6 +820,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; diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c index 3e2429f702..06e8e5aa56 100644 --- a/target/s390x/gen-features.c +++ b/target/s390x/gen-features.c @@ -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[] = { diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index eb6a6c5cd1..ab9c1d67d4 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -104,6 +104,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 @@ -563,6 +564,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; @@ -702,6 +708,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; } @@ -1525,6 +1535,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) @@ -1544,6 +1575,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; @@ -2357,6 +2391,10 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp) */ set_bit(S390_FEAT_EXTENDED_LENGTH_SCCB, model->features); + if (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); diff --git a/target/s390x/machine.c b/target/s390x/machine.c index 549bb6c280..5b4e82f1ab 100644 --- a/target/s390x/machine.c +++ b/target/s390x/machine.c @@ -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 }, }; -- 2.25.1