diff options
Diffstat (limited to 'target/s390x')
-rw-r--r-- | target/s390x/Makefile.objs | 2 | ||||
-rw-r--r-- | target/s390x/cpu-qom.h | 2 | ||||
-rw-r--r-- | target/s390x/cpu.c | 50 | ||||
-rw-r--r-- | target/s390x/cpu.h | 16 | ||||
-rw-r--r-- | target/s390x/cpu_features.c | 2 | ||||
-rw-r--r-- | target/s390x/cpu_models.c | 17 | ||||
-rw-r--r-- | target/s390x/crypto_helper.c | 65 | ||||
-rw-r--r-- | target/s390x/excp_helper.c | 29 | ||||
-rw-r--r-- | target/s390x/helper.h | 3 | ||||
-rw-r--r-- | target/s390x/insn-data.def | 15 | ||||
-rw-r--r-- | target/s390x/internal.h | 16 | ||||
-rw-r--r-- | target/s390x/kvm-stub.c | 10 | ||||
-rw-r--r-- | target/s390x/kvm.c | 98 | ||||
-rw-r--r-- | target/s390x/kvm_s390x.h | 2 | ||||
-rw-r--r-- | target/s390x/mem_helper.c | 51 | ||||
-rw-r--r-- | target/s390x/misc_helper.c | 7 | ||||
-rw-r--r-- | target/s390x/mmu_helper.c | 19 | ||||
-rw-r--r-- | target/s390x/translate.c | 71 |
18 files changed, 358 insertions, 117 deletions
diff --git a/target/s390x/Makefile.objs b/target/s390x/Makefile.objs index 9615256..c88ac81 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-qom.h b/target/s390x/cpu-qom.h index 2e446fa..0510c49 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 34538c3..3fdf9ba 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 @@ -112,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, @@ -149,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, @@ -179,8 +180,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 */ @@ -196,11 +198,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 @@ -209,7 +206,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; @@ -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); } @@ -357,22 +349,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) @@ -448,7 +452,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 9b549dc..7e864c8 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 @@ -59,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; @@ -150,8 +153,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; @@ -292,6 +297,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 +315,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 @@ -349,6 +356,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) { @@ -684,12 +692,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_features.c b/target/s390x/cpu_features.c index 1d3a036..31a4676 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; diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 5169379..07ef8a3 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; @@ -941,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, @@ -1207,9 +1213,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) { @@ -1232,14 +1235,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/crypto_helper.c b/target/s390x/crypto_helper.c new file mode 100644 index 0000000..fa360a2 --- /dev/null +++ b/target/s390x/crypto_helper.c @@ -0,0 +1,65 @@ +/* + * s390x crypto helpers + * + * Copyright (c) 2017 Red Hat Inc + * + * Authors: + * David Hildenbrand <david@redhat.com> + * + * 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/excp_helper.c b/target/s390x/excp_helper.c index 470cf8f..3e4349d 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 @@ -87,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", @@ -97,18 +98,26 @@ 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 */ - 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); diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 4b02907..52c2963 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) @@ -115,6 +114,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) @@ -152,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/insn-data.def b/target/s390x/insn-data.def index ad84c74..d09f2ed 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) @@ -939,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/internal.h b/target/s390x/internal.h index bc8f831..14bf3ea 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, @@ -375,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/kvm-stub.c b/target/s390x/kvm-stub.c index 261e1cd..43f02c2 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 ebb75ca..d3700fc 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); @@ -643,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_set_clock(uint8_t *tod_high, uint64_t *tod_low) +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, @@ -663,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 @@ -1553,22 +1587,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; } @@ -1576,19 +1625,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; - } - 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); + 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]); + } - cpu_physical_memory_unmap(mem, len, 1, len); + cpu_physical_memory_unmap(sa, len, 1, len); return 0; } diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h index 2d594bd..501fc5a 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); diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index ec4760e..bbbe1c6 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) { @@ -1702,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) { @@ -1722,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; @@ -1897,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); } } } @@ -1919,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; @@ -1927,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! */ @@ -1973,24 +1952,18 @@ 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 */ 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) && @@ -2003,9 +1976,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/misc_helper.c b/target/s390x/misc_helper.c index 293fc84..0b93381 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) { diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index b528c59..9daa0fd 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; +} diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 5abd34f..9ef9514 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); @@ -2915,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; } @@ -2923,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; } @@ -3796,6 +3846,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) { @@ -4065,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; } @@ -4073,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; } @@ -5494,6 +5553,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" |