From 6b257354c4912d536b999ef32968b1cbb8add4f2 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Wed, 20 Sep 2017 17:30:14 +0200 Subject: [PATCH 01/33] s390x/tcg: implement spm (SET PROGRAM MASK) Missing and is used inside Linux in the context of CPACF. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20170920153016.3858-2-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/cpu.h | 2 ++ target/s390x/insn-data.def | 2 ++ target/s390x/translate.c | 11 +++++++++++ 3 files changed, 15 insertions(+) diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 9b549dc491..4414485089 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -292,6 +292,7 @@ extern const struct VMStateDescription vmstate_s390_cpu; #undef PSW_SHIFT_ASC #undef PSW_MASK_CC #undef PSW_MASK_PM +#undef PSW_SHIFT_MASK_PM #undef PSW_MASK_64 #undef PSW_MASK_32 #undef PSW_MASK_ESA_ADDR @@ -309,6 +310,7 @@ extern const struct VMStateDescription vmstate_s390_cpu; #define PSW_SHIFT_ASC 46 #define PSW_MASK_CC 0x0000300000000000ULL #define PSW_MASK_PM 0x00000F0000000000ULL +#define PSW_SHIFT_MASK_PM 40 #define PSW_MASK_64 0x0000000100000000ULL #define PSW_MASK_32 0x0000000080000000ULL #define PSW_MASK_ESA_ADDR 0x000000007fffffffULL diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index ad84c748e3..84233a456d 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -755,6 +755,8 @@ C(0xb2b8, SRNMB, S, FPE, 0, 0, 0, 0, srnm, 0) /* SET DFP ROUNDING MODE */ C(0xb2b9, SRNMT, S, DFPR, 0, 0, 0, 0, srnm, 0) +/* SET PROGRAM MASK */ + C(0x0400, SPM, RR_a, Z, r1, 0, 0, 0, spm, 0) /* SHIFT LEFT SINGLE */ D(0x8b00, SLA, RS_a, Z, r1, sh32, new, r1_32, sla, 0, 31) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 5abd34fb34..59fde44d55 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3796,6 +3796,17 @@ static ExitStatus op_srnm(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_spm(DisasContext *s, DisasOps *o) +{ + tcg_gen_extrl_i64_i32(cc_op, o->in1); + tcg_gen_extract_i32(cc_op, cc_op, 28, 2); + set_cc_static(s); + + tcg_gen_shri_i64(o->in1, o->in1, 24); + tcg_gen_deposit_i64(psw_mask, psw_mask, o->in1, PSW_SHIFT_MASK_PM, 4); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_spka(DisasContext *s, DisasOps *o) { From 7634d658e601714a917d91367a27340ffa77c3db Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Wed, 20 Sep 2017 17:30:15 +0200 Subject: [PATCH 02/33] s390x/tcg: move wrap_address() to internal.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to use it in another file. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20170920153016.3858-3-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/internal.h | 14 ++++++++++++++ target/s390x/mem_helper.c | 14 -------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/target/s390x/internal.h b/target/s390x/internal.h index bc8f83129a..70d2b87e55 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -162,6 +162,20 @@ static inline uint8_t get_per_atmid(CPUS390XState *env) ((env->psw.mask & PSW_ASC_ACCREG) ? (1 << 2) : 0); } +static inline uint64_t wrap_address(CPUS390XState *env, uint64_t a) +{ + if (!(env->psw.mask & PSW_MASK_64)) { + if (!(env->psw.mask & PSW_MASK_32)) { + /* 24-Bit mode */ + a &= 0x00ffffff; + } else { + /* 31-Bit mode */ + a &= 0x7fffffff; + } + } + return a; +} + /* CC optimization */ /* Instead of computing the condition codes after each x86 instruction, diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index ec4760e390..a254613dc2 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -122,20 +122,6 @@ static inline void cpu_stsize_data_ra(CPUS390XState *env, uint64_t addr, } } -static inline uint64_t wrap_address(CPUS390XState *env, uint64_t a) -{ - if (!(env->psw.mask & PSW_MASK_64)) { - if (!(env->psw.mask & PSW_MASK_32)) { - /* 24-Bit mode */ - a &= 0x00ffffff; - } else { - /* 31-Bit mode */ - a &= 0x7fffffff; - } - } - return a; -} - static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte, uint32_t l, uintptr_t ra) { From 7705c75048cab58ca9c4e25ed5880b20598777cf Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Wed, 20 Sep 2017 17:30:16 +0200 Subject: [PATCH 03/33] s390x/tcg: add basic MSA features The STFLE bits for the MSA (extension) facilities simply indicate that the respective instructions can be executed. The QUERY subfunction can then be used to identify which features exactly are available. Availability of subfunctions can also vary on real hardware. For now, we simply implement a CPU model without any available subfunctions except QUERY (which is always around). As all MSA functions behave quite similarly, we can use one translation handler for now. Prepare the code for implementation of actual subfunctions. At least MSA is helpful for now, as older Linux kernels require this facility when compiled for a z9 model. Allow to enable the facilities for the qemu cpu model. Signed-off-by: David Hildenbrand Message-Id: <20170920153016.3858-4-david@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Cornelia Huck --- target/s390x/Makefile.objs | 2 +- target/s390x/cpu_models.c | 4 +++ target/s390x/crypto_helper.c | 65 ++++++++++++++++++++++++++++++++++++ target/s390x/helper.h | 1 + target/s390x/insn-data.def | 13 ++++++++ target/s390x/translate.c | 56 +++++++++++++++++++++++++++++++ 6 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 target/s390x/crypto_helper.c diff --git a/target/s390x/Makefile.objs b/target/s390x/Makefile.objs index 9615256d81..c88ac81e84 100644 --- a/target/s390x/Makefile.objs +++ b/target/s390x/Makefile.objs @@ -1,6 +1,6 @@ obj-y += cpu.o cpu_models.o cpu_features.o gdbstub.o interrupt.o helper.o obj-$(CONFIG_TCG) += translate.o cc_helper.o excp_helper.o fpu_helper.o -obj-$(CONFIG_TCG) += int_helper.o mem_helper.o misc_helper.o +obj-$(CONFIG_TCG) += int_helper.o mem_helper.o misc_helper.o crypto_helper.o obj-$(CONFIG_SOFTMMU) += machine.o ioinst.o arch_dump.o mmu_helper.o diag.o obj-$(CONFIG_KVM) += kvm.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 5169379db5..1051a16ece 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -825,6 +825,7 @@ static void add_qemu_cpu_model_features(S390FeatBitmap fbm) S390_FEAT_STFLE, S390_FEAT_EXTENDED_IMMEDIATE, S390_FEAT_EXTENDED_TRANSLATION_2, + S390_FEAT_MSA, S390_FEAT_EXTENDED_TRANSLATION_3, S390_FEAT_LONG_DISPLACEMENT, S390_FEAT_LONG_DISPLACEMENT_FAST, @@ -841,6 +842,9 @@ static void add_qemu_cpu_model_features(S390FeatBitmap fbm) S390_FEAT_STFLE_49, S390_FEAT_LOCAL_TLB_CLEARING, S390_FEAT_STFLE_53, + S390_FEAT_MSA_EXT_5, + S390_FEAT_MSA_EXT_3, + S390_FEAT_MSA_EXT_4, }; int i; diff --git a/target/s390x/crypto_helper.c b/target/s390x/crypto_helper.c new file mode 100644 index 0000000000..fa360a2d6e --- /dev/null +++ b/target/s390x/crypto_helper.c @@ -0,0 +1,65 @@ +/* + * s390x crypto helpers + * + * Copyright (c) 2017 Red Hat Inc + * + * Authors: + * David Hildenbrand + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "internal.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" + +uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3, + uint32_t type) +{ + const uintptr_t ra = GETPC(); + const uint8_t mod = env->regs[0] & 0x80ULL; + const uint8_t fc = env->regs[0] & 0x7fULL; + CPUState *cs = CPU(s390_env_get_cpu(env)); + uint8_t subfunc[16] = { 0 }; + uint64_t param_addr; + int i; + + switch (type) { + case S390_FEAT_TYPE_KMAC: + case S390_FEAT_TYPE_KIMD: + case S390_FEAT_TYPE_KLMD: + case S390_FEAT_TYPE_PCKMO: + case S390_FEAT_TYPE_PCC: + if (mod) { + cpu_restore_state(cs, ra); + program_interrupt(env, PGM_SPECIFICATION, 4); + return 0; + } + break; + } + + s390_get_feat_block(type, subfunc); + if (!test_be_bit(fc, subfunc)) { + cpu_restore_state(cs, ra); + program_interrupt(env, PGM_SPECIFICATION, 4); + return 0; + } + + switch (fc) { + case 0: /* query subfunction */ + for (i = 0; i < 16; i++) { + param_addr = wrap_address(env, env->regs[1] + i); + cpu_stb_data_ra(env, param_addr, subfunc[i], ra); + } + break; + default: + /* we don't implement any other subfunction yet */ + g_assert_not_reached(); + } + + return 0; +} diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 4b0290774e..75ba04fc15 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -115,6 +115,7 @@ DEF_HELPER_4(cu21, i32, env, i32, i32, i32) DEF_HELPER_4(cu24, i32, env, i32, i32, i32) DEF_HELPER_4(cu41, i32, env, i32, i32, i32) DEF_HELPER_4(cu42, i32, env, i32, i32, i32) +DEF_HELPER_5(msa, i32, env, i32, i32, i32, i32) #ifndef CONFIG_USER_ONLY DEF_HELPER_3(servc, i32, env, i64, i64) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 84233a456d..d09f2ed538 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -941,6 +941,19 @@ /* UNPACK UNICODE */ C(0xe200, UNPKU, SS_a, E2, la1, a2, 0, 0, unpku, 0) +/* MSA Instructions */ + D(0xb91e, KMAC, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMAC) + D(0xb928, PCKMO, RRE, MSA3, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PCKMO) + D(0xb92a, KMF, RRE, MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMF) + D(0xb92b, KMO, RRE, MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMO) + D(0xb92c, PCC, RRE, MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PCC) + D(0xb92d, KMCTR, RRF_b, MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMCTR) + D(0xb92e, KM, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KM) + D(0xb92f, KMC, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMC) + D(0xb93c, PPNO, RRE, MSA5, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PPNO) + D(0xb93e, KIMD, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KIMD) + D(0xb93f, KLMD, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KLMD) + #ifndef CONFIG_USER_ONLY /* COMPARE AND SWAP AND PURGE */ D(0xb250, CSP, RRE, Z, r1_32u, ra2, r1_P, 0, csp, 0, MO_TEUL) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 59fde44d55..78ffd8ff24 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2422,6 +2422,58 @@ static ExitStatus op_iske(DisasContext *s, DisasOps *o) } #endif +static ExitStatus op_msa(DisasContext *s, DisasOps *o) +{ + int r1 = have_field(s->fields, r1) ? get_field(s->fields, r1) : 0; + int r2 = have_field(s->fields, r2) ? get_field(s->fields, r2) : 0; + int r3 = have_field(s->fields, r3) ? get_field(s->fields, r3) : 0; + TCGv_i32 t_r1, t_r2, t_r3, type; + + switch (s->insn->data) { + case S390_FEAT_TYPE_KMCTR: + if (r3 & 1 || !r3) { + gen_program_exception(s, PGM_SPECIFICATION); + return EXIT_NORETURN; + } + /* FALL THROUGH */ + case S390_FEAT_TYPE_PPNO: + case S390_FEAT_TYPE_KMF: + case S390_FEAT_TYPE_KMC: + case S390_FEAT_TYPE_KMO: + case S390_FEAT_TYPE_KM: + if (r1 & 1 || !r1) { + gen_program_exception(s, PGM_SPECIFICATION); + return EXIT_NORETURN; + } + /* FALL THROUGH */ + case S390_FEAT_TYPE_KMAC: + case S390_FEAT_TYPE_KIMD: + case S390_FEAT_TYPE_KLMD: + if (r2 & 1 || !r2) { + gen_program_exception(s, PGM_SPECIFICATION); + return EXIT_NORETURN; + } + /* FALL THROUGH */ + case S390_FEAT_TYPE_PCKMO: + case S390_FEAT_TYPE_PCC: + break; + default: + g_assert_not_reached(); + }; + + t_r1 = tcg_const_i32(r1); + t_r2 = tcg_const_i32(r2); + t_r3 = tcg_const_i32(r3); + type = tcg_const_i32(s->insn->data); + gen_helper_msa(cc_op, cpu_env, t_r1, t_r2, t_r3, type); + set_cc_static(s); + tcg_temp_free_i32(t_r1); + tcg_temp_free_i32(t_r2); + tcg_temp_free_i32(t_r3); + tcg_temp_free_i32(type); + return NO_EXIT; +} + static ExitStatus op_keb(DisasContext *s, DisasOps *o) { gen_helper_keb(cc_op, cpu_env, o->in1, o->in2); @@ -5505,6 +5557,10 @@ enum DisasInsnEnum { #define FAC_PPA S390_FEAT_STFLE_49 /* processor-assist */ #define FAC_LZRB S390_FEAT_STFLE_53 /* load-and-zero-rightmost-byte */ #define FAC_ETF3 S390_FEAT_EXTENDED_TRANSLATION_3 +#define FAC_MSA S390_FEAT_MSA /* message-security-assist facility */ +#define FAC_MSA3 S390_FEAT_MSA_EXT_3 /* msa-extension-3 facility */ +#define FAC_MSA4 S390_FEAT_MSA_EXT_4 /* msa-extension-4 facility */ +#define FAC_MSA5 S390_FEAT_MSA_EXT_5 /* msa-extension-5 facility */ static const DisasInsn insn_info[] = { #include "insn-data.def" From b6805e127c6b7815ea3abc6516b461a18d9c4d3d Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 21 Sep 2017 14:59:08 +0200 Subject: [PATCH 04/33] s390x: use generic cpu_model parsing Define default CPU type in generic way in machine class_init and let common machine code handle cpu_model parsing. Signed-off-by: Igor Mammedov Reviewed-by: David Hildenbrand Message-Id: <1505998749-269631-1-git-send-email-imammedo@redhat.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 28 +++------------------------- target/s390x/cpu.h | 6 ++++-- target/s390x/cpu_models.c | 11 ----------- target/s390x/kvm.c | 3 +++ 4 files changed, 10 insertions(+), 38 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index fafbc6d4fe..1bcb7000ab 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -55,15 +55,8 @@ S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) static void s390_init_cpus(MachineState *machine) { MachineClass *mc = MACHINE_GET_CLASS(machine); - const char *typename; - gchar **model_pieces; - ObjectClass *oc; - CPUClass *cc; int i; - if (machine->cpu_model == NULL) { - machine->cpu_model = s390_default_cpu_model_name(); - } if (tcg_enabled() && max_cpus > 1) { error_report("Number of SMP CPUs requested (%d) exceeds max CPUs " "supported by TCG (1) on s390x", max_cpus); @@ -73,25 +66,8 @@ static void s390_init_cpus(MachineState *machine) /* initialize possible_cpus */ mc->possible_cpu_arch_ids(machine); - model_pieces = g_strsplit(machine->cpu_model, ",", 2); - if (!model_pieces[0]) { - error_report("Invalid/empty CPU model name"); - exit(1); - } - - oc = cpu_class_by_name(TYPE_S390_CPU, model_pieces[0]); - if (!oc) { - error_report("Unable to find CPU definition: %s", model_pieces[0]); - exit(1); - } - typename = object_class_get_name(oc); - cc = CPU_CLASS(oc); - /* after parsing, properties will be applied to all *typename* instances */ - cc->parse_features(typename, model_pieces[1], &error_fatal); - g_strfreev(model_pieces); - for (i = 0; i < smp_cpus; i++) { - s390x_new_cpu(typename, i, &error_fatal); + s390x_new_cpu(machine->cpu_type, i, &error_fatal); } } @@ -446,6 +422,8 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data) mc->get_hotplug_handler = s390_get_hotplug_handler; mc->cpu_index_to_instance_props = s390_cpu_index_to_props; mc->possible_cpu_arch_ids = s390_possible_cpu_arch_ids; + /* it is overridden with 'host' cpu *in kvm_arch_init* */ + mc->default_cpu_type = S390_CPU_TYPE_NAME("qemu"); hc->plug = s390_machine_device_plug; hc->unplug_request = s390_machine_device_unplug_request; nc->nmi_monitor_handler = s390_nmi; diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 4414485089..5e2504d679 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -686,12 +686,14 @@ static inline unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) /* cpu_models.c */ void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf); #define cpu_list s390_cpu_list -const char *s390_default_cpu_model_name(void); - /* helper.c */ #define cpu_init(cpu_model) cpu_generic_init(TYPE_S390_CPU, cpu_model) S390CPU *s390x_new_cpu(const char *typename, uint32_t core_id, Error **errp); + +#define S390_CPU_TYPE_SUFFIX "-" TYPE_S390_CPU +#define S390_CPU_TYPE_NAME(name) (name S390_CPU_TYPE_SUFFIX) + /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 1051a16ece..48dd7beddd 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -1211,9 +1211,6 @@ static void s390_qemu_cpu_model_class_init(ObjectClass *oc, void *data) qemu_hw_version()); } -#define S390_CPU_TYPE_SUFFIX "-" TYPE_S390_CPU -#define S390_CPU_TYPE_NAME(name) (name S390_CPU_TYPE_SUFFIX) - /* Generate type name for a cpu model. Caller has to free the string. */ static char *s390_cpu_type_name(const char *model_name) { @@ -1236,14 +1233,6 @@ ObjectClass *s390_cpu_class_by_name(const char *name) return oc; } -const char *s390_default_cpu_model_name(void) -{ - if (kvm_enabled()) { - return "host"; - } - return "qemu"; -} - static const TypeInfo qemu_s390_cpu_type_info = { .name = S390_CPU_TYPE_NAME("qemu"), .parent = TYPE_S390_CPU, diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index ebb75cafaa..c65d76f01a 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -287,6 +287,9 @@ void kvm_s390_crypto_reset(void) int kvm_arch_init(MachineState *ms, KVMState *s) { + MachineClass *mc = MACHINE_GET_CLASS(ms); + + mc->default_cpu_type = S390_CPU_TYPE_NAME("host"); cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS); cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF); cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP); From 947a38bd6f1301a97f3c9c7485e7fa118bbc40cf Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 22 Sep 2017 16:03:38 +0200 Subject: [PATCH 05/33] s390x/kvm: fix and cleanup storing CPU status env->psa is a 64bit value, while we copy 4 bytes into the save area, resulting always in 0 getting stored. Let's try to reduce such errors by using a proper structure. While at it, use correct cpu->be conversion (and get_psw_mask()), as we will be reusing this code for TCG soon. Signed-off-by: David Hildenbrand Message-Id: <20170922140338.6068-1-david@redhat.com> Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- target/s390x/kvm.c | 60 +++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index c65d76f01a..7f8c6c4993 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -1556,22 +1556,37 @@ static int do_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len) return 0; } +struct sigp_save_area { + uint64_t fprs[16]; /* 0x0000 */ + uint64_t grs[16]; /* 0x0080 */ + PSW psw; /* 0x0100 */ + uint8_t pad_0x0110[0x0118 - 0x0110]; /* 0x0110 */ + uint32_t prefix; /* 0x0118 */ + uint32_t fpc; /* 0x011c */ + uint8_t pad_0x0120[0x0124 - 0x0120]; /* 0x0120 */ + uint32_t todpr; /* 0x0124 */ + uint64_t cputm; /* 0x0128 */ + uint64_t ckc; /* 0x0130 */ + uint8_t pad_0x0138[0x0140 - 0x0138]; /* 0x0138 */ + uint32_t ars[16]; /* 0x0140 */ + uint64_t crs[16]; /* 0x0384 */ +}; +QEMU_BUILD_BUG_ON(sizeof(struct sigp_save_area) != 512); + #define KVM_S390_STORE_STATUS_DEF_ADDR offsetof(LowCore, floating_pt_save_area) -#define SAVE_AREA_SIZE 512 static int kvm_s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch) { static const uint8_t ar_id = 1; - uint64_t ckc = cpu->env.ckc >> 8; - void *mem; + struct sigp_save_area *sa; + hwaddr len = sizeof(*sa); int i; - hwaddr len = SAVE_AREA_SIZE; - mem = cpu_physical_memory_map(addr, &len, 1); - if (!mem) { + sa = cpu_physical_memory_map(addr, &len, 1); + if (!sa) { return -EFAULT; } - if (len != SAVE_AREA_SIZE) { - cpu_physical_memory_unmap(mem, len, 1, 0); + if (len != sizeof(*sa)) { + cpu_physical_memory_unmap(sa, len, 1, 0); return -EFAULT; } @@ -1579,19 +1594,26 @@ static int kvm_s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch) cpu_physical_memory_write(offsetof(LowCore, ar_access_id), &ar_id, 1); } for (i = 0; i < 16; ++i) { - *((uint64_t *)mem + i) = get_freg(&cpu->env, i)->ll; + sa->fprs[i] = cpu_to_be64(get_freg(&cpu->env, i)->ll); + } + for (i = 0; i < 16; ++i) { + sa->grs[i] = cpu_to_be64(cpu->env.regs[i]); + } + sa->psw.addr = cpu_to_be64(cpu->env.psw.addr); + sa->psw.mask = cpu_to_be64(get_psw_mask(&cpu->env)); + sa->prefix = cpu_to_be32(cpu->env.psa); + sa->fpc = cpu_to_be32(cpu->env.fpc); + sa->todpr = cpu_to_be32(cpu->env.todpr); + sa->cputm = cpu_to_be64(cpu->env.cputm); + sa->ckc = cpu_to_be64(cpu->env.ckc >> 8); + for (i = 0; i < 16; ++i) { + sa->ars[i] = cpu_to_be32(cpu->env.aregs[i]); + } + for (i = 0; i < 16; ++i) { + sa->ars[i] = cpu_to_be64(cpu->env.cregs[i]); } - memcpy(mem + 128, &cpu->env.regs, 128); - memcpy(mem + 256, &cpu->env.psw, 16); - memcpy(mem + 280, &cpu->env.psa, 4); - memcpy(mem + 284, &cpu->env.fpc, 4); - memcpy(mem + 292, &cpu->env.todpr, 4); - memcpy(mem + 296, &cpu->env.cputm, 8); - memcpy(mem + 304, &ckc, 8); - memcpy(mem + 320, &cpu->env.aregs, 64); - memcpy(mem + 384, &cpu->env.cregs, 128); - cpu_physical_memory_unmap(mem, len, 1, len); + cpu_physical_memory_unmap(sa, len, 1, len); return 0; } From 57065a70d00c36f5d20d430eb64d16db8e761c31 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 21 Sep 2017 20:08:37 +0200 Subject: [PATCH 06/33] s390x/css: introduce css data stream This is a preparation for introducing handling for indirect data addressing and modified indirect data addressing (CCW). Here we introduce an interface which should make the addressing scheme transparent for the client code. Here we implement only the basic scheme (no IDA or MIDA). Signed-off-by: Halil Pasic Reviewed-by: Dong Jia Shi Reviewed-by: Pierre Morel Message-Id: <20170921180841.24490-2-pasic@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 55 ++++++++++++++++++++++++++++++++++ include/hw/s390x/css.h | 67 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index c59be1aad1..248e9d47e5 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -787,6 +787,61 @@ static CCW1 copy_ccw_from_guest(hwaddr addr, bool fmt1) } return ret; } +/** + * If out of bounds marks the stream broken. If broken returns -EINVAL, + * otherwise the requested length (may be zero) + */ +static inline int cds_check_len(CcwDataStream *cds, int len) +{ + if (cds->at_byte + len > cds->count) { + cds->flags |= CDS_F_STREAM_BROKEN; + } + return cds->flags & CDS_F_STREAM_BROKEN ? -EINVAL : len; +} + +static int ccw_dstream_rw_noflags(CcwDataStream *cds, void *buff, int len, + CcwDataStreamOp op) +{ + int ret; + + ret = cds_check_len(cds, len); + if (ret <= 0) { + return ret; + } + if (op == CDS_OP_A) { + goto incr; + } + ret = address_space_rw(&address_space_memory, cds->cda, + MEMTXATTRS_UNSPECIFIED, buff, len, op); + if (ret != MEMTX_OK) { + cds->flags |= CDS_F_STREAM_BROKEN; + return -EINVAL; + } +incr: + cds->at_byte += len; + cds->cda += len; + return 0; +} + +void ccw_dstream_init(CcwDataStream *cds, CCW1 const *ccw, ORB const *orb) +{ + /* + * We don't support MIDA (an optional facility) yet and we + * catch this earlier. Just for expressing the precondition. + */ + g_assert(!(orb->ctrl1 & ORB_CTRL1_MASK_MIDAW)); + cds->flags = (orb->ctrl0 & ORB_CTRL0_MASK_I2K ? CDS_F_I2K : 0) | + (orb->ctrl0 & ORB_CTRL0_MASK_C64 ? CDS_F_C64 : 0) | + (ccw->flags & CCW_FLAG_IDA ? CDS_F_IDA : 0); + cds->count = ccw->count; + cds->cda_orig = ccw->cda; + ccw_dstream_rewind(cds); + if (!(cds->flags & CDS_F_IDA)) { + cds->op_handler = ccw_dstream_rw_noflags; + } else { + assert(false); + } +} static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, bool suspend_allowed) diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index 0653d3c9be..078356e94c 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h @@ -75,6 +75,29 @@ typedef struct CMBE { uint32_t reserved[7]; } QEMU_PACKED CMBE; +typedef enum CcwDataStreamOp { + CDS_OP_R = 0, /* read, false when used as is_write */ + CDS_OP_W = 1, /* write, true when used as is_write */ + CDS_OP_A = 2 /* advance, should not be used as is_write */ +} CcwDataStreamOp; + +/* normal usage is via SuchchDev.cds instead of instantiating */ +typedef struct CcwDataStream { +#define CDS_F_IDA 0x01 +#define CDS_F_MIDA 0x02 +#define CDS_F_I2K 0x04 +#define CDS_F_C64 0x08 +#define CDS_F_STREAM_BROKEN 0x80 + uint8_t flags; + uint8_t at_idaw; + uint16_t at_byte; + uint16_t count; + uint32_t cda_orig; + int (*op_handler)(struct CcwDataStream *cds, void *buff, int len, + CcwDataStreamOp op); + hwaddr cda; +} CcwDataStream; + typedef struct SubchDev SubchDev; struct SubchDev { /* channel-subsystem related things: */ @@ -92,6 +115,7 @@ struct SubchDev { uint8_t ccw_no_data_cnt; uint16_t migrated_schid; /* used for missmatch detection */ ORB orb; + CcwDataStream cds; /* transport-provided data: */ int (*ccw_cb) (SubchDev *, CCW1); void (*disable_cb)(SubchDev *); @@ -240,4 +264,47 @@ SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss, /** Turn on css migration */ void css_register_vmstate(void); + +void ccw_dstream_init(CcwDataStream *cds, CCW1 const *ccw, ORB const *orb); + +static inline void ccw_dstream_rewind(CcwDataStream *cds) +{ + cds->at_byte = 0; + cds->at_idaw = 0; + cds->cda = cds->cda_orig; +} + +static inline bool ccw_dstream_good(CcwDataStream *cds) +{ + return !(cds->flags & CDS_F_STREAM_BROKEN); +} + +static inline uint16_t ccw_dstream_residual_count(CcwDataStream *cds) +{ + return cds->count - cds->at_byte; +} + +static inline uint16_t ccw_dstream_avail(CcwDataStream *cds) +{ + return ccw_dstream_good(cds) ? ccw_dstream_residual_count(cds) : 0; +} + +static inline int ccw_dstream_advance(CcwDataStream *cds, int len) +{ + return cds->op_handler(cds, NULL, len, CDS_OP_A); +} + +static inline int ccw_dstream_write_buf(CcwDataStream *cds, void *buff, int len) +{ + return cds->op_handler(cds, buff, len, CDS_OP_W); +} + +static inline int ccw_dstream_read_buf(CcwDataStream *cds, void *buff, int len) +{ + return cds->op_handler(cds, buff, len, CDS_OP_R); +} + +#define ccw_dstream_read(cds, v) ccw_dstream_read_buf((cds), &(v), sizeof(v)) +#define ccw_dstream_write(cds, v) ccw_dstream_write_buf((cds), &(v), sizeof(v)) + #endif From 0a22eac5aaf90b2c2c1a4c29eecc25ef508d520b Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 21 Sep 2017 20:08:38 +0200 Subject: [PATCH 07/33] s390x/css: use ccw data stream Replace direct access which implicitly assumes no IDA or MIDA with the new ccw data stream interface which should cope with these transparently in the future. Note that checking the return code for ccw_dstream_* will be done in a follow-on patch. Signed-off-by: Halil Pasic Reviewed-by: Dong Jia Shi Reviewed-by: Pierre Morel Message-Id: <20170921180841.24490-3-pasic@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 248e9d47e5..390c78f7d0 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -894,6 +894,7 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, } /* Look at the command. */ + ccw_dstream_init(&sch->cds, &ccw, &(sch->orb)); switch (ccw.cmd_code) { case CCW_CMD_NOOP: /* Nothing to do. */ @@ -907,8 +908,8 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, } } len = MIN(ccw.count, sizeof(sch->sense_data)); - cpu_physical_memory_write(ccw.cda, sch->sense_data, len); - sch->curr_status.scsw.count = ccw.count - len; + ccw_dstream_write_buf(&sch->cds, sch->sense_data, len); + sch->curr_status.scsw.count = ccw_dstream_residual_count(&sch->cds); memset(sch->sense_data, 0, sizeof(sch->sense_data)); ret = 0; break; @@ -934,8 +935,8 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, } else { sense_id.reserved = 0; } - cpu_physical_memory_write(ccw.cda, &sense_id, len); - sch->curr_status.scsw.count = ccw.count - len; + ccw_dstream_write_buf(&sch->cds, &sense_id, len); + sch->curr_status.scsw.count = ccw_dstream_residual_count(&sch->cds); ret = 0; break; } From f57ba05823b7c444133f0862077b45824a6a89b5 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 21 Sep 2017 20:08:39 +0200 Subject: [PATCH 08/33] virtio-ccw: use ccw data stream Replace direct access which implicitly assumes no IDA or MIDA with the new ccw data stream interface which should cope with these transparently in the future. Note that checking the return code for ccw_dstream_* will be done in a follow-on patch. Signed-off-by: Halil Pasic Reviewed-by: Pierre Morel Reviewed-by: Dong Jia Shi Message-Id: <20170921180841.24490-4-pasic@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/virtio-ccw.c | 155 +++++++++++++----------------------------- 1 file changed, 46 insertions(+), 109 deletions(-) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 62d69aa30b..085f17f871 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -289,49 +289,19 @@ static int virtio_ccw_handle_set_vq(SubchDev *sch, CCW1 ccw, bool check_len, return -EFAULT; } if (is_legacy) { - linfo.queue = address_space_ldq_be(&address_space_memory, ccw.cda, - MEMTXATTRS_UNSPECIFIED, NULL); - linfo.align = address_space_ldl_be(&address_space_memory, - ccw.cda + sizeof(linfo.queue), - MEMTXATTRS_UNSPECIFIED, - NULL); - linfo.index = address_space_lduw_be(&address_space_memory, - ccw.cda + sizeof(linfo.queue) - + sizeof(linfo.align), - MEMTXATTRS_UNSPECIFIED, - NULL); - linfo.num = address_space_lduw_be(&address_space_memory, - ccw.cda + sizeof(linfo.queue) - + sizeof(linfo.align) - + sizeof(linfo.index), - MEMTXATTRS_UNSPECIFIED, - NULL); + ccw_dstream_read(&sch->cds, linfo); + be64_to_cpus(&linfo.queue); + be32_to_cpus(&linfo.align); + be16_to_cpus(&linfo.index); + be16_to_cpus(&linfo.num); ret = virtio_ccw_set_vqs(sch, NULL, &linfo); } else { - info.desc = address_space_ldq_be(&address_space_memory, ccw.cda, - MEMTXATTRS_UNSPECIFIED, NULL); - info.index = address_space_lduw_be(&address_space_memory, - ccw.cda + sizeof(info.desc) - + sizeof(info.res0), - MEMTXATTRS_UNSPECIFIED, NULL); - info.num = address_space_lduw_be(&address_space_memory, - ccw.cda + sizeof(info.desc) - + sizeof(info.res0) - + sizeof(info.index), - MEMTXATTRS_UNSPECIFIED, NULL); - info.avail = address_space_ldq_be(&address_space_memory, - ccw.cda + sizeof(info.desc) - + sizeof(info.res0) - + sizeof(info.index) - + sizeof(info.num), - MEMTXATTRS_UNSPECIFIED, NULL); - info.used = address_space_ldq_be(&address_space_memory, - ccw.cda + sizeof(info.desc) - + sizeof(info.res0) - + sizeof(info.index) - + sizeof(info.num) - + sizeof(info.avail), - MEMTXATTRS_UNSPECIFIED, NULL); + ccw_dstream_read(&sch->cds, info); + be64_to_cpus(&info.desc); + be16_to_cpus(&info.index); + be16_to_cpus(&info.num); + be64_to_cpus(&info.avail); + be64_to_cpus(&info.used); ret = virtio_ccw_set_vqs(sch, &info, NULL); } sch->curr_status.scsw.count = 0; @@ -344,15 +314,13 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) VirtioRevInfo revinfo; uint8_t status; VirtioFeatDesc features; - void *config; hwaddr indicators; VqConfigBlock vq_config; VirtioCcwDevice *dev = sch->driver_data; VirtIODevice *vdev = virtio_ccw_get_vdev(sch); bool check_len; int len; - hwaddr hw_len; - VirtioThinintInfo *thinint; + VirtioThinintInfo thinint; if (!dev) { return -EINVAL; @@ -396,11 +364,8 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) } else { VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); - features.index = address_space_ldub(&address_space_memory, - ccw.cda - + sizeof(features.features), - MEMTXATTRS_UNSPECIFIED, - NULL); + ccw_dstream_advance(&sch->cds, sizeof(features.features)); + ccw_dstream_read(&sch->cds, features.index); if (features.index == 0) { if (dev->revision >= 1) { /* Don't offer legacy features for modern devices. */ @@ -419,9 +384,9 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) /* Return zeroes if the guest supports more feature bits. */ features.features = 0; } - address_space_stl_le(&address_space_memory, ccw.cda, - features.features, MEMTXATTRS_UNSPECIFIED, - NULL); + ccw_dstream_rewind(&sch->cds); + cpu_to_le32s(&features.features); + ccw_dstream_write(&sch->cds, features.features); sch->curr_status.scsw.count = ccw.count - sizeof(features); ret = 0; } @@ -440,15 +405,8 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) if (!ccw.cda) { ret = -EFAULT; } else { - features.index = address_space_ldub(&address_space_memory, - ccw.cda - + sizeof(features.features), - MEMTXATTRS_UNSPECIFIED, - NULL); - features.features = address_space_ldl_le(&address_space_memory, - ccw.cda, - MEMTXATTRS_UNSPECIFIED, - NULL); + ccw_dstream_read(&sch->cds, features); + le32_to_cpus(&features.features); if (features.index == 0) { virtio_set_features(vdev, (vdev->guest_features & 0xffffffff00000000ULL) | @@ -489,7 +447,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) ret = -EFAULT; } else { virtio_bus_get_vdev_config(&dev->bus, vdev->config); - cpu_physical_memory_write(ccw.cda, vdev->config, len); + ccw_dstream_write_buf(&sch->cds, vdev->config, len); sch->curr_status.scsw.count = ccw.count - len; ret = 0; } @@ -502,20 +460,13 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) } } len = MIN(ccw.count, vdev->config_len); - hw_len = len; if (!ccw.cda) { ret = -EFAULT; } else { - config = cpu_physical_memory_map(ccw.cda, &hw_len, 0); - if (!config) { - ret = -EFAULT; - } else { - len = hw_len; - memcpy(vdev->config, config, len); - cpu_physical_memory_unmap(config, hw_len, 0, hw_len); + ret = ccw_dstream_read_buf(&sch->cds, vdev->config, len); + if (!ret) { virtio_bus_set_vdev_config(&dev->bus, vdev->config); sch->curr_status.scsw.count = ccw.count - len; - ret = 0; } } break; @@ -553,8 +504,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) if (!ccw.cda) { ret = -EFAULT; } else { - status = address_space_ldub(&address_space_memory, ccw.cda, - MEMTXATTRS_UNSPECIFIED, NULL); + ccw_dstream_read(&sch->cds, status); if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) { virtio_ccw_stop_ioeventfd(dev); } @@ -597,8 +547,8 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) if (!ccw.cda) { ret = -EFAULT; } else { - indicators = address_space_ldq_be(&address_space_memory, ccw.cda, - MEMTXATTRS_UNSPECIFIED, NULL); + ccw_dstream_read(&sch->cds, indicators); + be64_to_cpus(&indicators); dev->indicators = get_indicator(indicators, sizeof(uint64_t)); sch->curr_status.scsw.count = ccw.count - sizeof(indicators); ret = 0; @@ -618,8 +568,8 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) if (!ccw.cda) { ret = -EFAULT; } else { - indicators = address_space_ldq_be(&address_space_memory, ccw.cda, - MEMTXATTRS_UNSPECIFIED, NULL); + ccw_dstream_read(&sch->cds, indicators); + be64_to_cpus(&indicators); dev->indicators2 = get_indicator(indicators, sizeof(uint64_t)); sch->curr_status.scsw.count = ccw.count - sizeof(indicators); ret = 0; @@ -639,67 +589,58 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) if (!ccw.cda) { ret = -EFAULT; } else { - vq_config.index = address_space_lduw_be(&address_space_memory, - ccw.cda, - MEMTXATTRS_UNSPECIFIED, - NULL); + ccw_dstream_read(&sch->cds, vq_config.index); + be16_to_cpus(&vq_config.index); if (vq_config.index >= VIRTIO_QUEUE_MAX) { ret = -EINVAL; break; } vq_config.num_max = virtio_queue_get_num(vdev, vq_config.index); - address_space_stw_be(&address_space_memory, - ccw.cda + sizeof(vq_config.index), - vq_config.num_max, - MEMTXATTRS_UNSPECIFIED, - NULL); + cpu_to_be16s(&vq_config.num_max); + ccw_dstream_write(&sch->cds, vq_config.num_max); sch->curr_status.scsw.count = ccw.count - sizeof(vq_config); ret = 0; } break; case CCW_CMD_SET_IND_ADAPTER: if (check_len) { - if (ccw.count != sizeof(*thinint)) { + if (ccw.count != sizeof(thinint)) { ret = -EINVAL; break; } - } else if (ccw.count < sizeof(*thinint)) { + } else if (ccw.count < sizeof(thinint)) { /* Can't execute command. */ ret = -EINVAL; break; } - len = sizeof(*thinint); - hw_len = len; if (!ccw.cda) { ret = -EFAULT; } else if (dev->indicators && !sch->thinint_active) { /* Trigger a command reject. */ ret = -ENOSYS; } else { - thinint = cpu_physical_memory_map(ccw.cda, &hw_len, 0); - if (!thinint) { + if (ccw_dstream_read(&sch->cds, thinint)) { ret = -EFAULT; } else { - uint64_t ind_bit = ldq_be_p(&thinint->ind_bit); + be64_to_cpus(&thinint.ind_bit); + be64_to_cpus(&thinint.summary_indicator); + be64_to_cpus(&thinint.device_indicator); - len = hw_len; dev->summary_indicator = - get_indicator(ldq_be_p(&thinint->summary_indicator), - sizeof(uint8_t)); + get_indicator(thinint.summary_indicator, sizeof(uint8_t)); dev->indicators = - get_indicator(ldq_be_p(&thinint->device_indicator), - ind_bit / 8 + 1); - dev->thinint_isc = thinint->isc; - dev->routes.adapter.ind_offset = ind_bit; + get_indicator(thinint.device_indicator, + thinint.ind_bit / 8 + 1); + dev->thinint_isc = thinint.isc; + dev->routes.adapter.ind_offset = thinint.ind_bit; dev->routes.adapter.summary_offset = 7; - cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len); dev->routes.adapter.adapter_id = css_get_adapter_id( CSS_IO_ADAPTER_VIRTIO, dev->thinint_isc); sch->thinint_active = ((dev->indicators != NULL) && (dev->summary_indicator != NULL)); - sch->curr_status.scsw.count = ccw.count - len; + sch->curr_status.scsw.count = ccw.count - sizeof(thinint); ret = 0; } } @@ -714,13 +655,9 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) ret = -EFAULT; break; } - revinfo.revision = - address_space_lduw_be(&address_space_memory, ccw.cda, - MEMTXATTRS_UNSPECIFIED, NULL); - revinfo.length = - address_space_lduw_be(&address_space_memory, - ccw.cda + sizeof(revinfo.revision), - MEMTXATTRS_UNSPECIFIED, NULL); + ccw_dstream_read_buf(&sch->cds, &revinfo, 4); + be16_to_cpus(&revinfo.revision); + be16_to_cpus(&revinfo.length); if (ccw.count < len + revinfo.length || (check_len && ccw.count > len + revinfo.length)) { ret = -EINVAL; From 62a2554ec2630896d1299e1a282a64c7f3b00da0 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 21 Sep 2017 20:08:40 +0200 Subject: [PATCH 09/33] 390x/css: introduce maximum data address checking The architecture mandates the addresses to be accessed on the first indirection level (that is, the data addresses without IDA, and the (M)IDAW addresses with (M)IDA) to be checked against an CCW format dependent limit maximum address. If a violation is detected, the storage access is not to be performed and a channel program check needs to be generated. As of today, we fail to do this check. Let us stick even closer to the architecture specification. Signed-off-by: Halil Pasic Message-Id: <20170921180841.24490-5-pasic@linux.vnet.ibm.com> Reviewed-by: Pierre Morel Reviewed-by: Dong Jia Shi Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 10 ++++++++++ include/hw/s390x/css.h | 1 + 2 files changed, 11 insertions(+) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 390c78f7d0..ab7333fde8 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -799,6 +799,11 @@ static inline int cds_check_len(CcwDataStream *cds, int len) return cds->flags & CDS_F_STREAM_BROKEN ? -EINVAL : len; } +static inline bool cds_ccw_addrs_ok(hwaddr addr, int len, bool ccw_fmt1) +{ + return (addr + len) < (ccw_fmt1 ? (1UL << 31) : (1UL << 24)); +} + static int ccw_dstream_rw_noflags(CcwDataStream *cds, void *buff, int len, CcwDataStreamOp op) { @@ -808,6 +813,9 @@ static int ccw_dstream_rw_noflags(CcwDataStream *cds, void *buff, int len, if (ret <= 0) { return ret; } + if (!cds_ccw_addrs_ok(cds->cda, len, cds->flags & CDS_F_FMT)) { + return -EINVAL; /* channel program check */ + } if (op == CDS_OP_A) { goto incr; } @@ -832,7 +840,9 @@ void ccw_dstream_init(CcwDataStream *cds, CCW1 const *ccw, ORB const *orb) g_assert(!(orb->ctrl1 & ORB_CTRL1_MASK_MIDAW)); cds->flags = (orb->ctrl0 & ORB_CTRL0_MASK_I2K ? CDS_F_I2K : 0) | (orb->ctrl0 & ORB_CTRL0_MASK_C64 ? CDS_F_C64 : 0) | + (orb->ctrl0 & ORB_CTRL0_MASK_FMT ? CDS_F_FMT : 0) | (ccw->flags & CCW_FLAG_IDA ? CDS_F_IDA : 0); + cds->count = ccw->count; cds->cda_orig = ccw->cda; ccw_dstream_rewind(cds); diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index 078356e94c..69b374730e 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h @@ -87,6 +87,7 @@ typedef struct CcwDataStream { #define CDS_F_MIDA 0x02 #define CDS_F_I2K 0x04 #define CDS_F_C64 0x08 +#define CDS_F_FMT 0x10 /* CCW format-1 */ #define CDS_F_STREAM_BROKEN 0x80 uint8_t flags; uint8_t at_idaw; From 93973f8f154e70d6cf22c418e82b0b80213d31b2 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Thu, 21 Sep 2017 20:08:41 +0200 Subject: [PATCH 10/33] s390x/css: support ccw IDA Let's add indirect data addressing support for our virtual channel subsystem. This implementation does not bother with any kind of prefetching. We simply step through the IDAL on demand. Signed-off-by: Halil Pasic Message-Id: <20170921180841.24490-6-pasic@linux.vnet.ibm.com> Reviewed-by: Dong Jia Shi Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index ab7333fde8..35683d7954 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -831,6 +831,118 @@ incr: return 0; } +/* returns values between 1 and bsz, where bsz is a power of 2 */ +static inline uint16_t ida_continuous_left(hwaddr cda, uint64_t bsz) +{ + return bsz - (cda & (bsz - 1)); +} + +static inline uint64_t ccw_ida_block_size(uint8_t flags) +{ + if ((flags & CDS_F_C64) && !(flags & CDS_F_I2K)) { + return 1ULL << 12; + } + return 1ULL << 11; +} + +static inline int ida_read_next_idaw(CcwDataStream *cds) +{ + union {uint64_t fmt2; uint32_t fmt1; } idaw; + int ret; + hwaddr idaw_addr; + bool idaw_fmt2 = cds->flags & CDS_F_C64; + bool ccw_fmt1 = cds->flags & CDS_F_FMT; + + if (idaw_fmt2) { + idaw_addr = cds->cda_orig + sizeof(idaw.fmt2) * cds->at_idaw; + if (idaw_addr & 0x07 || !cds_ccw_addrs_ok(idaw_addr, 0, ccw_fmt1)) { + return -EINVAL; /* channel program check */ + } + ret = address_space_rw(&address_space_memory, idaw_addr, + MEMTXATTRS_UNSPECIFIED, (void *) &idaw.fmt2, + sizeof(idaw.fmt2), false); + cds->cda = be64_to_cpu(idaw.fmt2); + } else { + idaw_addr = cds->cda_orig + sizeof(idaw.fmt1) * cds->at_idaw; + if (idaw_addr & 0x03 || !cds_ccw_addrs_ok(idaw_addr, 0, ccw_fmt1)) { + return -EINVAL; /* channel program check */ + } + ret = address_space_rw(&address_space_memory, idaw_addr, + MEMTXATTRS_UNSPECIFIED, (void *) &idaw.fmt1, + sizeof(idaw.fmt1), false); + cds->cda = be64_to_cpu(idaw.fmt1); + if (cds->cda & 0x80000000) { + return -EINVAL; /* channel program check */ + } + } + ++(cds->at_idaw); + if (ret != MEMTX_OK) { + /* assume inaccessible address */ + return -EINVAL; /* channel program check */ + } + return 0; +} + +static int ccw_dstream_rw_ida(CcwDataStream *cds, void *buff, int len, + CcwDataStreamOp op) +{ + uint64_t bsz = ccw_ida_block_size(cds->flags); + int ret = 0; + uint16_t cont_left, iter_len; + + ret = cds_check_len(cds, len); + if (ret <= 0) { + return ret; + } + if (!cds->at_idaw) { + /* read first idaw */ + ret = ida_read_next_idaw(cds); + if (ret) { + goto err; + } + cont_left = ida_continuous_left(cds->cda, bsz); + } else { + cont_left = ida_continuous_left(cds->cda, bsz); + if (cont_left == bsz) { + ret = ida_read_next_idaw(cds); + if (ret) { + goto err; + } + if (cds->cda & (bsz - 1)) { + ret = -EINVAL; /* channel program check */ + goto err; + } + } + } + do { + iter_len = MIN(len, cont_left); + if (op != CDS_OP_A) { + ret = address_space_rw(&address_space_memory, cds->cda, + MEMTXATTRS_UNSPECIFIED, buff, iter_len, op); + if (ret != MEMTX_OK) { + /* assume inaccessible address */ + ret = -EINVAL; /* channel program check */ + goto err; + } + } + cds->at_byte += iter_len; + cds->cda += iter_len; + len -= iter_len; + if (!len) { + break; + } + ret = ida_read_next_idaw(cds); + if (ret) { + goto err; + } + cont_left = bsz; + } while (true); + return ret; +err: + cds->flags |= CDS_F_STREAM_BROKEN; + return ret; +} + void ccw_dstream_init(CcwDataStream *cds, CCW1 const *ccw, ORB const *orb) { /* @@ -849,7 +961,7 @@ void ccw_dstream_init(CcwDataStream *cds, CCW1 const *ccw, ORB const *orb) if (!(cds->flags & CDS_F_IDA)) { cds->op_handler = ccw_dstream_rw_noflags; } else { - assert(false); + cds->op_handler = ccw_dstream_rw_ida; } } From 0bd695a960bf05f27ad6d710d2b64059037574ce Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2017 20:33:13 +0200 Subject: [PATCH 11/33] s390x/tcg: fix checking for invalid memory check It should have been a >=, but let's directly perform a proper access check to also be able to deal with hotplugged memory later. Signed-off-by: David Hildenbrand Message-Id: <20170926183318.12995-2-david@redhat.com> Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- target/s390x/excp_helper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c index 470cf8f5bc..308605d9ed 100644 --- a/target/s390x/excp_helper.c +++ b/target/s390x/excp_helper.c @@ -26,6 +26,7 @@ #include "exec/exec-all.h" #include "exec/cpu_ldst.h" #include "hw/s390x/ioinst.h" +#include "exec/address-spaces.h" #ifndef CONFIG_USER_ONLY #include "sysemu/sysemu.h" #endif @@ -108,7 +109,8 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr, } /* check out of RAM access */ - if (raddr > ram_size) { + if (!address_space_access_valid(&address_space_memory, raddr, + TARGET_PAGE_SIZE, rw)) { DPRINTF("%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, (uint64_t)raddr, (uint64_t)ram_size); trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_AUTO); From fb66944df92f4cf28b6f66232f82b9dd46ddcdb2 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2017 20:33:14 +0200 Subject: [PATCH 12/33] s390x/tcg: add MMU for real addresses This makes it easy to access real addresses (prefix) and in addition checks for valid memory addresses, which is missing when using e.g. stl_phys(). We can later reuse it to implement low address protection checks (then we might even decide to introduce yet another MMU for absolute addresses, just for handling storage keys and low address protection). Signed-off-by: David Hildenbrand Message-Id: <20170926183318.12995-3-david@redhat.com> Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- target/s390x/cpu.h | 4 +++- target/s390x/excp_helper.c | 25 ++++++++++++++++--------- target/s390x/internal.h | 2 ++ target/s390x/mmu_helper.c | 19 +++++++++++++++++++ 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 5e2504d679..c57ef71f6d 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -43,12 +43,13 @@ #include "fpu/softfloat.h" -#define NB_MMU_MODES 3 +#define NB_MMU_MODES 4 #define TARGET_INSN_START_EXTRA_WORDS 1 #define MMU_MODE0_SUFFIX _primary #define MMU_MODE1_SUFFIX _secondary #define MMU_MODE2_SUFFIX _home +#define MMU_MODE3_SUFFIX _real #define MMU_USER_IDX 0 @@ -351,6 +352,7 @@ extern const struct VMStateDescription vmstate_s390_cpu; #define MMU_PRIMARY_IDX 0 #define MMU_SECONDARY_IDX 1 #define MMU_HOME_IDX 2 +#define MMU_REAL_IDX 3 static inline int cpu_mmu_index(CPUS390XState *env, bool ifetch) { diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c index 308605d9ed..3e4349d00b 100644 --- a/target/s390x/excp_helper.c +++ b/target/s390x/excp_helper.c @@ -88,8 +88,8 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr, { S390CPU *cpu = S390_CPU(cs); CPUS390XState *env = &cpu->env; - uint64_t asc = cpu_mmu_idx_to_asc(mmu_idx); target_ulong vaddr, raddr; + uint64_t asc; int prot; DPRINTF("%s: address 0x%" VADDR_PRIx " rw %d mmu_idx %d\n", @@ -98,14 +98,21 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr, orig_vaddr &= TARGET_PAGE_MASK; vaddr = orig_vaddr; - /* 31-Bit mode */ - if (!(env->psw.mask & PSW_MASK_64)) { - vaddr &= 0x7fffffff; - } - - if (mmu_translate(env, vaddr, rw, asc, &raddr, &prot, true)) { - /* Translation ended in exception */ - return 1; + if (mmu_idx < MMU_REAL_IDX) { + asc = cpu_mmu_idx_to_asc(mmu_idx); + /* 31-Bit mode */ + if (!(env->psw.mask & PSW_MASK_64)) { + vaddr &= 0x7fffffff; + } + if (mmu_translate(env, vaddr, rw, asc, &raddr, &prot, true)) { + return 1; + } + } else if (mmu_idx == MMU_REAL_IDX) { + if (mmu_translate_real(env, vaddr, rw, &raddr, &prot)) { + return 1; + } + } else { + abort(); } /* check out of RAM access */ diff --git a/target/s390x/internal.h b/target/s390x/internal.h index 70d2b87e55..14bf3ea5e2 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -389,6 +389,8 @@ target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr); /* mmu_helper.c */ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, target_ulong *raddr, int *flags, bool exc); +int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw, + target_ulong *addr, int *flags); /* misc_helper.c */ diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index b528c5921d..9daa0fd8e2 100644 --- a/target/s390x/mmu_helper.c +++ b/target/s390x/mmu_helper.c @@ -497,3 +497,22 @@ int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf, g_free(pages); return ret; } + +/** + * Translate a real address into a physical (absolute) address. + * @param raddr the real address + * @param rw 0 = read, 1 = write, 2 = code fetch + * @param addr the translated address is stored to this pointer + * @param flags the PAGE_READ/WRITE/EXEC flags are stored to this pointer + * @return 0 if the translation was successful, < 0 if a fault occurred + */ +int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw, + target_ulong *addr, int *flags) +{ + /* TODO: low address protection once we flush the tlb on cr changes */ + *flags = PAGE_READ | PAGE_WRITE; + *addr = mmu_real2abs(env, raddr); + + /* TODO: storage key handling */ + return 0; +} From 34499dadc1360c873009a30cd89fa8b9ec269b6e Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2017 20:33:15 +0200 Subject: [PATCH 13/33] s390x/tcg: make lura(g) use the new _real mmu. Looks like, lurag was not loading 64bit but only 32bit. As we properly handle the return address now, we can drop potential_page_fault(). Signed-off-by: David Hildenbrand Message-Id: <20170926183318.12995-4-david@redhat.com> Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- target/s390x/mem_helper.c | 8 ++------ target/s390x/translate.c | 2 -- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index a254613dc2..bc50bc0686 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1959,16 +1959,12 @@ void HELPER(purge)(CPUS390XState *env) /* load using real address */ uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr) { - CPUState *cs = CPU(s390_env_get_cpu(env)); - - return (uint32_t)ldl_phys(cs->as, wrap_address(env, addr)); + return cpu_ldl_real_ra(env, wrap_address(env, addr), GETPC()); } uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr) { - CPUState *cs = CPU(s390_env_get_cpu(env)); - - return ldq_phys(cs->as, wrap_address(env, addr)); + return cpu_ldq_real_ra(env, wrap_address(env, addr), GETPC()); } /* store using real address */ diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 78ffd8ff24..f64a31760e 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2967,7 +2967,6 @@ static ExitStatus op_lpq(DisasContext *s, DisasOps *o) static ExitStatus op_lura(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_lura(o->out, cpu_env, o->in2); return NO_EXIT; } @@ -2975,7 +2974,6 @@ static ExitStatus op_lura(DisasContext *s, DisasOps *o) static ExitStatus op_lurag(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_lurag(o->out, cpu_env, o->in2); return NO_EXIT; } From 4ae433417e36c78cf51fc654fb0e4086d2879a7c Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2017 20:33:16 +0200 Subject: [PATCH 14/33] s390x/tcg: make stora(g) use the new _real mmu As we properly handle the return address now, we can drop potential_page_fault(). Signed-off-by: David Hildenbrand Message-Id: <20170926183318.12995-5-david@redhat.com> Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- target/s390x/mem_helper.c | 8 ++------ target/s390x/translate.c | 2 -- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index bc50bc0686..b4f2779428 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1970,9 +1970,7 @@ uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr) /* store using real address */ void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1) { - CPUState *cs = CPU(s390_env_get_cpu(env)); - - stl_phys(cs->as, wrap_address(env, addr), (uint32_t)v1); + cpu_stl_real_ra(env, wrap_address(env, addr), (uint32_t)v1, GETPC()); if ((env->psw.mask & PSW_MASK_PER) && (env->cregs[9] & PER_CR9_EVENT_STORE) && @@ -1985,9 +1983,7 @@ void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1) void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1) { - CPUState *cs = CPU(s390_env_get_cpu(env)); - - stq_phys(cs->as, wrap_address(env, addr), v1); + cpu_stq_real_ra(env, wrap_address(env, addr), v1, GETPC()); if ((env->psw.mask & PSW_MASK_PER) && (env->cregs[9] & PER_CR9_EVENT_STORE) && diff --git a/target/s390x/translate.c b/target/s390x/translate.c index f64a31760e..9ef95141f9 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4126,7 +4126,6 @@ static ExitStatus op_stnosm(DisasContext *s, DisasOps *o) static ExitStatus op_stura(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_stura(cpu_env, o->in2, o->in1); return NO_EXIT; } @@ -4134,7 +4133,6 @@ static ExitStatus op_stura(DisasContext *s, DisasOps *o) static ExitStatus op_sturg(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_sturg(cpu_env, o->in2, o->in1); return NO_EXIT; } From e26131c9049f63779d38fc3eb61a79722b3499f8 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2017 20:33:17 +0200 Subject: [PATCH 15/33] s390x/tcg: make testblock use the new _real mmu Low address protection checks will be moved into the mmu later. Signed-off-by: David Hildenbrand Message-Id: <20170926183318.12995-6-david@redhat.com> Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- target/s390x/mem_helper.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index b4f2779428..3650c1b678 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1688,17 +1688,9 @@ uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr) { uintptr_t ra = GETPC(); CPUState *cs = CPU(s390_env_get_cpu(env)); - uint64_t abs_addr; int i; - real_addr = wrap_address(env, real_addr); - abs_addr = mmu_real2abs(env, real_addr) & TARGET_PAGE_MASK; - if (!address_space_access_valid(&address_space_memory, abs_addr, - TARGET_PAGE_SIZE, true)) { - cpu_restore_state(cs, ra); - program_interrupt(env, PGM_ADDRESSING, 4); - return 1; - } + real_addr = wrap_address(env, real_addr) & TARGET_PAGE_MASK; /* Check low-address protection */ if ((env->cregs[0] & CR0_LOWPROT) && real_addr < 0x2000) { @@ -1708,7 +1700,7 @@ uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr) } for (i = 0; i < TARGET_PAGE_SIZE; i += 8) { - stq_phys(cs->as, abs_addr + i, 0); + cpu_stq_real_ra(env, real_addr + i, 0, ra); } return 0; From 8eb82de91b013c0a566c5b79400dde41689129cb Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 26 Sep 2017 20:33:18 +0200 Subject: [PATCH 16/33] s390x/tcg: make idte/ipte use the new _real mmu We don't wrap addresses in the mmu for the _real case, therefore the behavior should be unchanged. Signed-off-by: David Hildenbrand Message-Id: <20170926183318.12995-7-david@redhat.com> Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- target/s390x/mem_helper.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 3650c1b678..bbbe1c62b3 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1875,11 +1875,11 @@ void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4) for (i = 0; i < entries; i++) { /* addresses are not wrapped in 24/31bit mode but table index is */ raddr = table + ((index + i) & 0x7ff) * sizeof(entry); - entry = ldq_phys(cs->as, raddr); + entry = cpu_ldq_real_ra(env, raddr, ra); if (!(entry & _REGION_ENTRY_INV)) { /* we are allowed to not store if already invalid */ entry |= _REGION_ENTRY_INV; - stq_phys(cs->as, raddr, entry); + cpu_stq_real_ra(env, raddr, entry, ra); } } } @@ -1897,6 +1897,7 @@ void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr, uint32_t m4) { CPUState *cs = CPU(s390_env_get_cpu(env)); + const uintptr_t ra = GETPC(); uint64_t page = vaddr & TARGET_PAGE_MASK; uint64_t pte_addr, pte; @@ -1905,9 +1906,9 @@ void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr, pte_addr += (vaddr & VADDR_PX) >> 9; /* Mark the page table entry as invalid */ - pte = ldq_phys(cs->as, pte_addr); + pte = cpu_ldq_real_ra(env, pte_addr, ra); pte |= _PAGE_INVALID; - stq_phys(cs->as, pte_addr, pte); + cpu_stq_real_ra(env, pte_addr, pte, ra); /* XXX we exploit the fact that Linux passes the exact virtual address here - it's not obliged to! */ From c1843e20924c9f79c8233ea34db31f3ae2a74677 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 28 Sep 2017 15:18:31 +0200 Subject: [PATCH 17/33] Revert "s390x/ccw: create s390 phb conditionally" This reverts commit d32bd032d8fde41281aae34c16a4aa97e9acfeac. Turns out that old QEMUs always created a pci host bridge and for many CPU models the migration from old QEMUs to new QEMUs will fail with qemu-system-s390x: Unknown savevm section or instance 'PCIBUS' 0 qemu-system-s390x: load of migration failed: Invalid argument As a quick fix we will revert the commit and always create the pci host bridge. Signed-off-by: Christian Borntraeger [fixed revert to keep the comment fixup, added a comment in the code] Cc: Cornelia Huck Cc: David Hildenbrand Message-Id: <20170928131831.81393-1-borntraeger@de.ibm.com> Reviewed-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 1bcb7000ab..2c689d50bc 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -251,6 +251,7 @@ static void ccw_init(MachineState *machine) { int ret; VirtualCssBus *css_bus; + DeviceState *dev; s390_sclp_init(); s390_memory_init(machine->ram_size); @@ -266,13 +267,14 @@ static void ccw_init(MachineState *machine) machine->initrd_filename, "s390-ccw.img", "s390-netboot.img", true); - if (s390_has_feat(S390_FEAT_ZPCI)) { - DeviceState *dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE); - object_property_add_child(qdev_get_machine(), - TYPE_S390_PCI_HOST_BRIDGE, - OBJECT(dev), NULL); - qdev_init_nofail(dev); - } + /* + * We cannot easily make the pci host bridge conditional as older QEMUs + * always created it. Doing so would break migration across QEMU versions. + */ + dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE); + object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE, + OBJECT(dev), NULL); + qdev_init_nofail(dev); /* register hypercalls */ virtio_ccw_register_hcalls(); From 1baa2eb01e349889a25f7a038e6ae7c335f6246b Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Wed, 20 Sep 2017 19:23:13 +0200 Subject: [PATCH 18/33] s390x/3270: IDA support for 3270 via CcwDataStream Let us convert the 3270 code so it uses the recently introduced CcwDataStream abstraction instead of blindly assuming direct data access. This patch does not change behavior beyond introducing IDA support: for direct data access CCWs everything stays as-is. (If there are bugs, they are also preserved). Signed-off-by: Halil Pasic Acked-by: Christian Borntraeger Reviewed-by: Dong Jia Shi Message-Id: <20170920172314.102710-2-pasic@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/char/terminal3270.c | 18 +++++++++++------- hw/s390x/3270-ccw.c | 4 ++-- include/hw/s390x/3270-ccw.h | 5 ++--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/hw/char/terminal3270.c b/hw/char/terminal3270.c index 28f599111d..c976a63cc2 100644 --- a/hw/char/terminal3270.c +++ b/hw/char/terminal3270.c @@ -182,14 +182,18 @@ static void terminal_init(EmulatedCcw3270Device *dev, Error **errp) terminal_read, chr_event, NULL, t, NULL, true); } -static int read_payload_3270(EmulatedCcw3270Device *dev, uint32_t cda, - uint16_t count) +static inline CcwDataStream *get_cds(Terminal3270 *t) +{ + return &(CCW_DEVICE(&t->cdev)->sch->cds); +} + +static int read_payload_3270(EmulatedCcw3270Device *dev) { Terminal3270 *t = TERMINAL_3270(dev); int len; - len = MIN(count, t->in_len); - cpu_physical_memory_write(cda, t->inv, len); + len = MIN(ccw_dstream_avail(get_cds(t)), t->in_len); + ccw_dstream_write_buf(get_cds(t), t->inv, len); t->in_len -= len; return len; @@ -222,11 +226,11 @@ static int insert_IAC_escape_char(uint8_t *outv, int out_len) * Write 3270 outbound to socket. * Return the count of 3270 data field if succeeded, zero if failed. */ -static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd, - uint32_t cda, uint16_t count) +static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd) { Terminal3270 *t = TERMINAL_3270(dev); int retval = 0; + int count = ccw_dstream_avail(get_cds(t)); assert(count <= (OUTPUT_BUFFER_SIZE - 3) / 2); @@ -244,7 +248,7 @@ static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd, return count; } t->outv[0] = cmd; - cpu_physical_memory_read(cda, &t->outv[1], count); + ccw_dstream_read_buf(get_cds(t), &t->outv[1], count); t->out_len = count + 1; t->out_len = insert_IAC_escape_char(t->outv, t->out_len); diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c index 1554aa2484..eaca28e224 100644 --- a/hw/s390x/3270-ccw.c +++ b/hw/s390x/3270-ccw.c @@ -28,7 +28,7 @@ static int handle_payload_3270_read(EmulatedCcw3270Device *dev, CCW1 *ccw) return -EFAULT; } - len = ck->read_payload_3270(dev, ccw->cda, ccw->count); + len = ck->read_payload_3270(dev); ccw_dev->sch->curr_status.scsw.count = ccw->count - len; return 0; @@ -45,7 +45,7 @@ static int handle_payload_3270_write(EmulatedCcw3270Device *dev, CCW1 *ccw) return -EFAULT; } - len = ck->write_payload_3270(dev, ccw->cmd_code, ccw->cda, ccw->count); + len = ck->write_payload_3270(dev, ccw->cmd_code); if (len <= 0) { return -EIO; diff --git a/include/hw/s390x/3270-ccw.h b/include/hw/s390x/3270-ccw.h index 46bee2533c..9d1d18e2bd 100644 --- a/include/hw/s390x/3270-ccw.h +++ b/include/hw/s390x/3270-ccw.h @@ -45,9 +45,8 @@ typedef struct EmulatedCcw3270Class { CCWDeviceClass parent_class; void (*init)(EmulatedCcw3270Device *, Error **); - int (*read_payload_3270)(EmulatedCcw3270Device *, uint32_t, uint16_t); - int (*write_payload_3270)(EmulatedCcw3270Device *, uint8_t, uint32_t, - uint16_t); + int (*read_payload_3270)(EmulatedCcw3270Device *); + int (*write_payload_3270)(EmulatedCcw3270Device *, uint8_t); } EmulatedCcw3270Class; #endif From 17ec9921a7e40d47c05effcf2c254f162bd63aad Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Wed, 20 Sep 2017 19:23:14 +0200 Subject: [PATCH 19/33] s390x/3270: handle writes of arbitrary length The problem is, that the current implementation places unrealistic and arbitrary constraints on the length of writes to the device (that is the outbound requests), by asserting ccw.count being such that that even the worst case escaped payload will fit an more or less arbitrary sized buffer. Actually on protocol level there is nothing to justify such a limitation. Another strange thing is the return value which more or less reflects the size (written) after escaping instead of before escaping. This is strange, because this return value is used to calculate SCSW.count. Let us teach 3270 how to deal with arbitrary long writes. Signed-off-by: Halil Pasic Acked-by: Christian Borntraeger Reviewed-by: Dong Jia Shi Reported-by: Jason J . Herne Tested-by: Jason J . Herne Message-Id: <20170920172314.102710-3-pasic@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/char/terminal3270.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/hw/char/terminal3270.c b/hw/char/terminal3270.c index c976a63cc2..a109ce5987 100644 --- a/hw/char/terminal3270.c +++ b/hw/char/terminal3270.c @@ -30,7 +30,6 @@ typedef struct Terminal3270 { uint8_t inv[INPUT_BUFFER_SIZE]; uint8_t outv[OUTPUT_BUFFER_SIZE]; int in_len; - int out_len; bool handshake_done; guint timer_tag; } Terminal3270; @@ -145,7 +144,6 @@ static void chr_event(void *opaque, int event) /* Ensure the initial status correct, always reset them. */ t->in_len = 0; - t->out_len = 0; t->handshake_done = false; if (t->timer_tag) { g_source_remove(t->timer_tag); @@ -231,8 +229,9 @@ static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd) Terminal3270 *t = TERMINAL_3270(dev); int retval = 0; int count = ccw_dstream_avail(get_cds(t)); - - assert(count <= (OUTPUT_BUFFER_SIZE - 3) / 2); + int bound = (OUTPUT_BUFFER_SIZE - 3) / 2; + int len = MIN(count, bound); + int out_len = 0; if (!t->handshake_done) { if (!(t->outv[0] == IAC && t->outv[1] != IAC)) { @@ -247,16 +246,23 @@ static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd) /* We just say we consumed all data if there's no backend. */ return count; } - t->outv[0] = cmd; - ccw_dstream_read_buf(get_cds(t), &t->outv[1], count); - t->out_len = count + 1; - t->out_len = insert_IAC_escape_char(t->outv, t->out_len); - t->outv[t->out_len++] = IAC; - t->outv[t->out_len++] = IAC_EOR; + t->outv[out_len++] = cmd; + do { + ccw_dstream_read_buf(get_cds(t), &t->outv[out_len], len); + count = ccw_dstream_avail(get_cds(t)); + out_len += len; - retval = qemu_chr_fe_write_all(&t->chr, t->outv, t->out_len); - return (retval <= 0) ? 0 : (retval - 3); + out_len = insert_IAC_escape_char(t->outv, out_len); + if (!count) { + t->outv[out_len++] = IAC; + t->outv[out_len++] = IAC_EOR; + } + retval = qemu_chr_fe_write_all(&t->chr, t->outv, out_len); + len = MIN(count, bound); + out_len = 0; + } while (len && retval >= 0); + return (retval <= 0) ? 0 : get_cds(t)->count; } static Property terminal_properties[] = { From 040078e06d5ed5ce73e5aaaeeb877cbb7a44bdf5 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 28 Sep 2017 15:46:05 +0200 Subject: [PATCH 20/33] MAINTAINERS: use KVM s390x maintainers for kvm-stubs.c and kvm_s390x.h Forgot it when factoring code out into these files. This is 100% s390x KVM material. Signed-off-by: David Hildenbrand Message-Id: <20170928134609.16985-2-david@redhat.com> Acked-by: Christian Borntraeger Signed-off-by: Cornelia Huck --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 932443df41..772ac209e1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -299,6 +299,8 @@ M: Cornelia Huck M: Alexander Graf S: Maintained F: target/s390x/kvm.c +F: target/s390x/kvm_s390x.h +F: target/s390x/kvm-stub.c F: target/s390x/ioinst.[ch] F: target/s390x/machine.c F: hw/intc/s390_flic.c From c5b934303cf83fe3dda31e8d3e5778458c8a9eeb Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 28 Sep 2017 15:46:06 +0200 Subject: [PATCH 21/33] s390x: raise CPU hotplug irq after really hotplugged Let's move it into the machine, so we trigger the IRQ after setting ms->possible_cpus (which SCLP uses to construct the list of online CPUs). This also fixes a problem reported by Thomas Huth, whereby qemu can be crashed using the none machine qemu-s390x-softmmu -M none -monitor stdio -> device_add qemu-s390-cpu Reviewed-by: Christian Borntraeger Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20170928134609.16985-3-david@redhat.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 4 ++++ target/s390x/cpu.c | 8 -------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 2c689d50bc..679a1a858c 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -307,6 +307,10 @@ static void s390_cpu_plug(HotplugHandler *hotplug_dev, g_assert(!ms->possible_cpus->cpus[cpu->env.core_id].cpu); ms->possible_cpus->cpus[cpu->env.core_id].cpu = OBJECT(dev); + + if (dev->hotplugged) { + raise_irq_cpu_hotplug(); + } } static void s390_machine_reset(void) diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 34538c3ab9..4920da3625 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -41,7 +41,6 @@ #include "hw/hw.h" #include "sysemu/arch_init.h" #include "sysemu/sysemu.h" -#include "hw/s390x/sclp.h" #endif #define CR0_RESET 0xE0UL @@ -227,13 +226,6 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp) #endif scc->parent_realize(dev, &err); - -#if !defined(CONFIG_USER_ONLY) - if (dev->hotplugged) { - raise_irq_cpu_hotplug(); - } -#endif - out: error_propagate(errp, err); } From c547a757f492cb037aec81965893046b7ef6d201 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 28 Sep 2017 15:46:07 +0200 Subject: [PATCH 22/33] s390x/cpumodel: fix max STFL(E) bit number Not that it would matter in the near future, but it is actually 2048 bytes, therefore 16384 possible bits. Reviewed-by: Christian Borntraeger Reviewed-by: Thomas Huth Signed-off-by: David Hildenbrand Message-Id: <20170928134609.16985-4-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/cpu_features.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/s390x/cpu_features.c b/target/s390x/cpu_features.c index 1d3a036393..31a4676f05 100644 --- a/target/s390x/cpu_features.c +++ b/target/s390x/cpu_features.c @@ -381,7 +381,7 @@ void s390_add_from_feat_block(S390FeatBitmap features, S390FeatType type, switch (type) { case S390_FEAT_TYPE_STFL: - nr_bits = 2048; + nr_bits = 16384; break; case S390_FEAT_TYPE_PLO: nr_bits = 256; From 1e70ba24a906211c26930f4f41a674fcb685f8ef Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 28 Sep 2017 15:46:08 +0200 Subject: [PATCH 23/33] target/s390x: get rid of next_core_id core_id is not needed by linux-user, as the core_id a.k.a. CPU address is only accessible from kernel space. Therefore, drop next_core_id and make cpu_index get autoassigned again for linux-user. While at it, shield core_id and cpuid completely from linux-user. cpuid can also only be queried from kernel space. Suggested-by: Igor Mammedov Reviewed-by: Igor Mammedov Signed-off-by: David Hildenbrand Message-Id: <20170928134609.16985-5-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/cpu-qom.h | 2 -- target/s390x/cpu.c | 14 +++++++------- target/s390x/cpu.h | 2 ++ target/s390x/cpu_models.c | 2 ++ 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/target/s390x/cpu-qom.h b/target/s390x/cpu-qom.h index 2e446fab51..0510c49e07 100644 --- a/target/s390x/cpu-qom.h +++ b/target/s390x/cpu-qom.h @@ -54,8 +54,6 @@ typedef struct S390CPUClass { bool is_migration_safe; const char *desc; - uint32_t next_core_id; - DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); void (*load_normal)(CPUState *cpu); diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 4920da3625..f42e28ea25 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -178,8 +178,9 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); S390CPUClass *scc = S390_CPU_GET_CLASS(dev); +#if !defined(CONFIG_USER_ONLY) S390CPU *cpu = S390_CPU(dev); - CPUS390XState *env = &cpu->env; +#endif Error *err = NULL; /* the model has to be realized before qemu_init_vcpu() due to kvm */ @@ -195,11 +196,6 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp) max_cpus - 1); goto out; } -#else - /* implicitly set for linux-user only */ - cpu->env.core_id = scc->next_core_id; - scc->next_core_id++; -#endif if (cpu_exists(cpu->env.core_id)) { error_setg(&err, "Unable to add CPU with core-id: %" PRIu32 @@ -208,7 +204,9 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp) } /* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */ - cs->cpu_index = env->core_id; + cs->cpu_index = cpu->env.core_id; +#endif + cpu_exec_realizefn(cs, &err); if (err != NULL) { goto out; @@ -440,7 +438,9 @@ static gchar *s390_gdb_arch_name(CPUState *cs) } static Property s390x_cpu_properties[] = { +#if !defined(CONFIG_USER_ONLY) DEFINE_PROP_UINT32("core-id", S390CPU, env.core_id, 0), +#endif DEFINE_PROP_END_OF_LIST() }; diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index c57ef71f6d..ff3cc59c02 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -151,8 +151,10 @@ struct CPUS390XState { CPU_COMMON +#if !defined(CONFIG_USER_ONLY) uint32_t core_id; /* PoP "CPU address", same as cpu_index */ uint64_t cpuid; +#endif uint64_t tod_offset; uint64_t tod_basetime; diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 48dd7beddd..07ef8a3b6e 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -945,11 +945,13 @@ void s390_realize_cpu_model(CPUState *cs, Error **errp) apply_cpu_model(cpu->model, errp); +#if !defined(CONFIG_USER_ONLY) cpu->env.cpuid = s390_cpuid_from_cpu_model(cpu->model); if (tcg_enabled()) { /* basic mode, write the cpu address into the first 4 bit of the ID */ cpu->env.cpuid = deposit64(cpu->env.cpuid, 54, 4, cpu->env.core_id); } +#endif } static void get_feature(Object *obj, Visitor *v, const char *name, From f42dc44a1481949e900cd50846a42c60d756758e Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 28 Sep 2017 15:46:09 +0200 Subject: [PATCH 24/33] s390x: introduce and use S390_MAX_CPUS Will be handy in the future. Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20170928134609.16985-6-david@redhat.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 2 +- target/s390x/cpu.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 679a1a858c..14a0545e6f 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -423,7 +423,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data) mc->no_parallel = 1; mc->no_sdcard = 1; mc->use_sclp = 1; - mc->max_cpus = 248; + mc->max_cpus = S390_MAX_CPUS; mc->has_hotpluggable_cpus = true; mc->get_hotplug_handler = s390_get_hotplug_handler; mc->cpu_index_to_instance_props = s390_cpu_index_to_props; diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index ff3cc59c02..7e864c8478 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -60,6 +60,8 @@ #define PSW_MCHK_MASK 0x0004000000000000 #define PSW_IO_MASK 0x0200000000000000 +#define S390_MAX_CPUS 248 + typedef struct PSW { uint64_t mask; uint64_t addr; From 86b5ab390992fd57f3a23764994a7e082bcc2fc4 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Wed, 27 Sep 2017 19:00:27 +0200 Subject: [PATCH 25/33] s390x/tcg: make STFL store into the lowcore Using virtual memory access is wrong and will soon include low-address protection checks, which is to be bypassed for STFL. STFL is a privileged instruction and using LowCore requires !CONFIG_USER_ONLY, so add the ifdef and move the declaration to the right place. This was originally part of a bigger STFL(E) refactoring. Signed-off-by: David Hildenbrand Message-Id: <20170927170027.8539-4-david@redhat.com> Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 2 +- target/s390x/misc_helper.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 75ba04fc15..52c2963baa 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -104,7 +104,6 @@ DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env) DEF_HELPER_2(stfle, i32, env, i64) DEF_HELPER_FLAGS_2(lpq, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_4(stpq, TCG_CALL_NO_WG, void, env, i64, i64, i64) @@ -153,6 +152,7 @@ DEF_HELPER_FLAGS_3(sturg, TCG_CALL_NO_WG, void, env, i64, i64) DEF_HELPER_1(per_check_exception, void, env) DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env) DEF_HELPER_2(xsch, void, env, i64) DEF_HELPER_2(csch, void, env, i64) diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index 293fc8428a..0b93381188 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -541,13 +541,18 @@ static unsigned do_stfle(CPUS390XState *env, uint64_t words[MAX_STFL_WORDS]) return max_bit / 64; } +#ifndef CONFIG_USER_ONLY void HELPER(stfl)(CPUS390XState *env) { uint64_t words[MAX_STFL_WORDS]; + LowCore *lowcore; + lowcore = cpu_map_lowcore(env); do_stfle(env, words); - cpu_stl_data(env, 200, words[0] >> 32); + lowcore->stfl_fac_list = cpu_to_be32(words[0] >> 32); + cpu_unmap_lowcore(lowcore); } +#endif uint32_t HELPER(stfle)(CPUS390XState *env, uint64_t addr) { From bd2aef10653e8ad1b61d9a56d3056b8b83cda389 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 4 Oct 2017 10:51:49 +0200 Subject: [PATCH 26/33] s390x: sort some devices into categories Add missing categorizations for some s390x devices: - zpci device -> misc - 3270 -> display - vfio-ccw -> misc Acked-by: Christian Borntraeger Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- hw/s390x/3270-ccw.c | 1 + hw/s390x/s390-pci-bus.c | 1 + hw/vfio/ccw.c | 1 + 3 files changed, 3 insertions(+) diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c index eaca28e224..081e3ef6f4 100644 --- a/hw/s390x/3270-ccw.c +++ b/hw/s390x/3270-ccw.c @@ -160,6 +160,7 @@ static void emulated_ccw_3270_class_init(ObjectClass *klass, void *data) dc->bus_type = TYPE_VIRTUAL_CSS_BUS; dc->realize = emulated_ccw_3270_realize; dc->hotpluggable = false; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); } static const TypeInfo emulated_ccw_3270_info = { diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 3b9965fde0..96116b7d1e 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -1032,6 +1032,7 @@ static void s390_pci_device_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->desc = "zpci device"; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->reset = s390_pci_device_reset; dc->bus_type = TYPE_S390_PCI_BUS; dc->realize = s390_pci_device_realize; diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index a8baadf57a..76323c6bde 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -413,6 +413,7 @@ static void vfio_ccw_class_init(ObjectClass *klass, void *data) dc->props = vfio_ccw_properties; dc->vmsd = &vfio_ccw_vmstate; dc->desc = "VFIO-based subchannel assignment"; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->realize = vfio_ccw_realize; dc->unrealize = vfio_ccw_unrealize; dc->reset = vfio_ccw_reset; From 489c909f097a387eb6913c89cf1851750397110c Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Wed, 4 Oct 2017 13:01:09 +0200 Subject: [PATCH 27/33] s390x/css: fix css migration compat handling Commit e996583eb3 ("s390x/css: activate ChannelSubSys migration", 2017-07-11) was supposed to enable css migration for virtio-ccw machines starting 2.10, but it ended up effectively enabling it only for 2.10 as the registration of the appropriate VMStateDescription happens in ccw_machine_2_10_instance_options which does not get called for machines more recent than 2_10. Let us move the corresponding chunk of code (which conditionally enables the migration based on the value of the corresponding class property) to ccw_init, which is called for each virtio-ccw machine instance. Signed-off-by: Halil Pasic Reported-by: Thomas Huth Message-Id: <20171004110109.16525-1-pasic@linux.vnet.ibm.com> Tested-by: Christian Borntraeger Acked-by: Christian Borntraeger Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 14a0545e6f..76156ce873 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -291,6 +291,9 @@ static void ccw_init(MachineState *machine) ret = css_create_css_image(VIRTUAL_CSSID, true); } assert(ret == 0); + if (css_migration_enabled()) { + css_register_vmstate(); + } /* Create VirtIO network adapters */ s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw"); @@ -715,9 +718,6 @@ DEFINE_CCW_MACHINE(2_11, "2.11", true); static void ccw_machine_2_10_instance_options(MachineState *machine) { ccw_machine_2_11_instance_options(machine); - if (css_migration_enabled()) { - css_register_vmstate(); - } } static void ccw_machine_2_10_class_options(MachineClass *mc) From 7edd4a4967536f9e1a6474223e824049a13dd39c Mon Sep 17 00:00:00 2001 From: "Collin L. Walling" Date: Wed, 4 Oct 2017 12:57:50 +0200 Subject: [PATCH 28/33] s390/kvm: Support for get/set of extended TOD-Clock for guest Provides an interface for getting and setting the guest's extended TOD-Clock via a single ioctl to kvm. If the ioctl fails because it is not support by kvm, then we fall back to the old style of retrieving the clock via two ioctls. Signed-off-by: Collin L. Walling Reviewed-by: Eric Farman Reviewed-by: Claudio Imbrenda Signed-off-by: Christian Borntraeger [split failure change from epoch index change] Message-Id: <20171004105751.24655-2-borntraeger@de.ibm.com> Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck [some cosmetic fixes] --- target/s390x/cpu.c | 26 +++++++++++++++++++------- target/s390x/kvm-stub.c | 10 ++++++++++ target/s390x/kvm.c | 33 ++++++++++++++++++++++++++++++++- target/s390x/kvm_s390x.h | 2 ++ 4 files changed, 63 insertions(+), 8 deletions(-) diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index f42e28ea25..4e1823a3e0 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -347,22 +347,34 @@ unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) int s390_get_clock(uint8_t *tod_high, uint64_t *tod_low) { + int r = 0; + if (kvm_enabled()) { - return kvm_s390_get_clock(tod_high, tod_low); + r = kvm_s390_get_clock_ext(tod_high, tod_low); + if (r == -ENXIO) { + return kvm_s390_get_clock(tod_high, tod_low); + } + } else { + /* Fixme TCG */ + *tod_high = 0; + *tod_low = 0; } - /* Fixme TCG */ - *tod_high = 0; - *tod_low = 0; - return 0; + + return r; } int s390_set_clock(uint8_t *tod_high, uint64_t *tod_low) { + int r = 0; + if (kvm_enabled()) { - return kvm_s390_set_clock(tod_high, tod_low); + r = kvm_s390_set_clock_ext(tod_high, tod_low); + if (r == -ENXIO) { + return kvm_s390_set_clock(tod_high, tod_low); + } } /* Fixme TCG */ - return 0; + return r; } int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit) diff --git a/target/s390x/kvm-stub.c b/target/s390x/kvm-stub.c index 261e1cdc44..43f02c2d69 100644 --- a/target/s390x/kvm-stub.c +++ b/target/s390x/kvm-stub.c @@ -68,11 +68,21 @@ int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_low) return -ENOSYS; } +int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low) +{ + return -ENOSYS; +} + int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low) { return -ENOSYS; } +int kvm_s390_set_clock_ext(uint8_t *tod_high, uint64_t *tod_low) +{ + return -ENOSYS; +} + void kvm_s390_enable_css_support(S390CPU *cpu) { } diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index 7f8c6c4993..d3700fc2c2 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -646,10 +646,26 @@ int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_low) return kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr); } +int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low) +{ + int r; + struct kvm_s390_vm_tod_clock gtod; + struct kvm_device_attr attr = { + .group = KVM_S390_VM_TOD, + .attr = KVM_S390_VM_TOD_EXT, + .addr = (uint64_t)>od, + }; + + r = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr); + *tod_high = gtod.epoch_idx; + *tod_low = gtod.tod; + + return r; +} + int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low) { int r; - struct kvm_device_attr attr = { .group = KVM_S390_VM_TOD, .attr = KVM_S390_VM_TOD_LOW, @@ -666,6 +682,21 @@ int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low) return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr); } +int kvm_s390_set_clock_ext(uint8_t *tod_high, uint64_t *tod_low) +{ + struct kvm_s390_vm_tod_clock gtod = { + .epoch_idx = *tod_high, + .tod = *tod_low, + }; + struct kvm_device_attr attr = { + .group = KVM_S390_VM_TOD, + .attr = KVM_S390_VM_TOD_EXT, + .addr = (uint64_t)>od, + }; + + return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr); +} + /** * kvm_s390_mem_op: * @addr: the logical start address in guest memory diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h index 2d594bd4ee..501fc5aabd 100644 --- a/target/s390x/kvm_s390x.h +++ b/target/s390x/kvm_s390x.h @@ -29,7 +29,9 @@ int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu); int kvm_s390_get_ri(void); int kvm_s390_get_gs(void); int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock); +int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_clock); int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_clock); +int kvm_s390_set_clock_ext(uint8_t *tod_high, uint64_t *tod_clock); void kvm_s390_enable_css_support(S390CPU *cpu); int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, int vq, bool assign); From 28f8dbe85db3d28f0ecddb48c072533fe58a70ea Mon Sep 17 00:00:00 2001 From: "Collin L. Walling" Date: Wed, 4 Oct 2017 12:57:51 +0200 Subject: [PATCH 29/33] s390/kvm: make TOD setting failures fatal for migration If we fail to set a proper TOD clock on the target system, this can already result in some problematic cases. We print several warn messages on source and target in that case. If kvm fails to set a nonzero epoch index, then we must ultimately fail the migration as this will result in a giant time leap backwards. This patch lets the migration fail if we can not set the guest time on the target. On failure the guest will resume normally on the original host machine. Signed-off-by: Collin L. Walling Reviewed-by: Eric Farman Reviewed-by: Claudio Imbrenda Signed-off-by: Christian Borntraeger [split failure change from epoch index change, minor fixups] Message-Id: <20171004105751.24655-3-borntraeger@de.ibm.com> Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 76156ce873..32d3f11d8a 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -189,13 +189,10 @@ static int gtod_load(QEMUFile *f, void *opaque, int version_id) r = s390_set_clock(&tod_high, &tod_low); if (r) { - warn_report("Unable to set guest clock for migration: %s", - strerror(-r)); - error_printf("Guest clock will not be restored " - "which could cause the guest to hang."); + error_report("Unable to set KVM guest TOD clock: %s", strerror(-r)); } - return 0; + return r; } static SaveVMHandlers savevm_gtod = { From e6cb60bf158fe7ea4505d760fdbb7abe4dbf4362 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 4 Oct 2017 15:53:19 +0200 Subject: [PATCH 30/33] s390x/sclp: Mark the sclp device with user_creatable = false The "sclp" device is just an internal device that can not be instantiated by the users. If they try to use it, they only get a simple error message: $ qemu-system-s390x -nographic -device sclp qemu-system-s390x: Option '-device s390-sclp-event-facility' cannot be handled by this machine Since sclp_init() tries to create a TYPE_SCLP_EVENT_FACILITY which is a non-pluggable sysbus device, there is really no way that the "sclp" device can be used by the user, so let's set the user_creatable = false accordingly. Signed-off-by: Thomas Huth Message-Id: <1507125199-22562-1-git-send-email-thuth@redhat.com> Reviewed-by: Claudio Imbrenda Reviewed-by: Farhan Ali Acked-by: Halil Pasic Signed-off-by: Cornelia Huck --- hw/s390x/sclp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 30aefbfd15..9be0cb80ad 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -606,6 +606,11 @@ static void sclp_class_init(ObjectClass *oc, void *data) dc->realize = sclp_realize; dc->hotpluggable = false; set_bit(DEVICE_CATEGORY_MISC, dc->categories); + /* + * Reason: Creates TYPE_SCLP_EVENT_FACILITY in sclp_init + * which is a non-pluggable sysbus device + */ + dc->user_creatable = false; sc->read_SCP_info = read_SCP_info; sc->read_storage_element0_info = read_storage_element0_info; From 7aa4d85d2962a072931657bee964113727ebf0c8 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 4 Oct 2017 17:34:23 +0200 Subject: [PATCH 31/33] s390x/sclp: mark sclp-cpu-hotplug as non-usercreatable A TYPE_SCLP_CPU_HOTPLUG device for handling cpu hotplug events is already created by the sclp event facility. Adding a second TYPE_SCLP_CPU_HOTPLUG device via -device sclp-cpu-hotplug creates an ambiguity in raise_irq_cpu_hotplug(), leading to a crash once a cpu is hotplugged. To fix this, disallow creating a sclp-cpu-hotplug device manually. Reviewed-by: Thomas Huth Acked-by: Christian Borntraeger Signed-off-by: Cornelia Huck --- hw/s390x/sclpcpu.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/s390x/sclpcpu.c b/hw/s390x/sclpcpu.c index 023d059a46..3ee890b392 100644 --- a/hw/s390x/sclpcpu.c +++ b/hw/s390x/sclpcpu.c @@ -82,6 +82,12 @@ static void cpu_class_init(ObjectClass *oc, void *data) k->get_receive_mask = receive_mask; k->read_event_data = read_event_data; set_bit(DEVICE_CATEGORY_MISC, dc->categories); + /* + * Reason: raise_irq_cpu_hotplug() depends on an unique + * TYPE_SCLP_CPU_HOTPLUG device, which is already created + * by the sclp event facility + */ + dc->user_creatable = false; } static const TypeInfo sclp_cpu_info = { From 8986db4922cf5b810b775c135d74a75290840660 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 29 Sep 2017 16:49:59 +0200 Subject: [PATCH 32/33] s390x/tcg: initialize machine check queue Just as for external interrupts and I/O interrupts, we need to initialize mchk_index during cpu reset. Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- target/s390x/cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 4e1823a3e0..3fdf9bae70 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -111,6 +111,7 @@ static void s390_cpu_initial_reset(CPUState *s) for (i = 0; i < ARRAY_SIZE(env->io_index); i++) { env->io_index[i] = -1; } + env->mchk_index = -1; /* tininess for underflow is detected before rounding */ set_float_detect_tininess(float_tininess_before_rounding, @@ -148,6 +149,7 @@ static void s390_cpu_full_reset(CPUState *s) for (i = 0; i < ARRAY_SIZE(env->io_index); i++) { env->io_index[i] = -1; } + env->mchk_index = -1; /* tininess for underflow is detected before rounding */ set_float_detect_tininess(float_tininess_before_rounding, From b923ab3112ed5ab47c2ff35776f17ab54c60d651 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 5 Oct 2017 10:45:05 +0200 Subject: [PATCH 33/33] hw/s390x: Mark the "sclpquiesce" device with user_creatable = false The "sclpquiesce" device is just an internal device that should not be created by the user directly. Though it currently does not seem to cause any obvious trouble when the user instantiates an additional device, let's better mark it with user_creatable = false to avoid unexpected behavior, e.g. because the quiesce notifier gets registered multiple times. Signed-off-by: Thomas Huth Message-Id: <1507193105-15627-1-git-send-email-thuth@redhat.com> Reviewed-by: Halil Pasic Reviewed-by: Claudio Imbrenda Signed-off-by: Cornelia Huck --- hw/s390x/sclpquiesce.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index 762cb184ac..02416435a1 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -118,8 +118,13 @@ static void quiesce_class_init(ObjectClass *klass, void *data) dc->reset = quiesce_reset; dc->vmsd = &vmstate_sclpquiesce; set_bit(DEVICE_CATEGORY_MISC, dc->categories); - k->init = quiesce_init; + /* + * Reason: This is just an internal device - the notifier should + * not be registered multiple times in quiesce_init() + */ + dc->user_creatable = false; + k->init = quiesce_init; k->get_send_mask = send_mask; k->get_receive_mask = receive_mask; k->can_handle_event = can_handle_event;