diff options
Diffstat (limited to 'qemu/target-s390x')
-rw-r--r-- | qemu/target-s390x/arch_dump.c | 7 | ||||
-rw-r--r-- | qemu/target-s390x/cc_helper.c | 3 | ||||
-rw-r--r-- | qemu/target-s390x/cpu-qom.h | 5 | ||||
-rw-r--r-- | qemu/target-s390x/cpu.c | 119 | ||||
-rw-r--r-- | qemu/target-s390x/cpu.h | 85 | ||||
-rw-r--r-- | qemu/target-s390x/fpu_helper.c | 1 | ||||
-rw-r--r-- | qemu/target-s390x/gdbstub.c | 123 | ||||
-rw-r--r-- | qemu/target-s390x/helper.c | 52 | ||||
-rw-r--r-- | qemu/target-s390x/int_helper.c | 1 | ||||
-rw-r--r-- | qemu/target-s390x/interrupt.c | 12 | ||||
-rw-r--r-- | qemu/target-s390x/ioinst.c | 6 | ||||
-rw-r--r-- | qemu/target-s390x/kvm.c | 79 | ||||
-rw-r--r-- | qemu/target-s390x/machine.c | 5 | ||||
-rw-r--r-- | qemu/target-s390x/mem_helper.c | 51 | ||||
-rw-r--r-- | qemu/target-s390x/misc_helper.c | 20 | ||||
-rw-r--r-- | qemu/target-s390x/mmu_helper.c | 33 | ||||
-rw-r--r-- | qemu/target-s390x/translate.c | 137 |
17 files changed, 536 insertions, 203 deletions
diff --git a/qemu/target-s390x/arch_dump.c b/qemu/target-s390x/arch_dump.c index dab63eb44..4731869f6 100644 --- a/qemu/target-s390x/arch_dump.c +++ b/qemu/target-s390x/arch_dump.c @@ -11,6 +11,7 @@ * */ +#include "qemu/osdep.h" #include "cpu.h" #include "elf.h" #include "exec/cpu-all.h" @@ -246,9 +247,3 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) return (elf_note_size) * nr_cpus; } - -int s390_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, - CPUState *cpu, void *opaque) -{ - return 0; -} diff --git a/qemu/target-s390x/cc_helper.c b/qemu/target-s390x/cc_helper.c index bfce3f1e6..0d9411bdf 100644 --- a/qemu/target-s390x/cc_helper.c +++ b/qemu/target-s390x/cc_helper.c @@ -18,6 +18,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" #include "qemu/host-utils.h" @@ -560,7 +561,7 @@ void HELPER(sacf)(CPUS390XState *env, uint64_t a1) env->psw.mask |= PSW_ASC_HOME; break; default: - qemu_log("unknown sacf mode: %" PRIx64 "\n", a1); + HELPER_LOG("unknown sacf mode: %" PRIx64 "\n", a1); program_interrupt(env, PGM_SPECIFICATION, 2); break; } diff --git a/qemu/target-s390x/cpu-qom.h b/qemu/target-s390x/cpu-qom.h index 491c1b876..1c9093396 100644 --- a/qemu/target-s390x/cpu-qom.h +++ b/qemu/target-s390x/cpu-qom.h @@ -47,6 +47,8 @@ typedef struct S390CPUClass { CPUClass parent_class; /*< public >*/ + int64_t next_cpu_id; + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); void (*load_normal)(CPUState *cpu); @@ -66,6 +68,7 @@ typedef struct S390CPU { /*< public >*/ CPUS390XState env; + int64_t id; /* needed for live migration */ void *irqstate; uint32_t irqstate_saved_size; @@ -91,8 +94,6 @@ void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, int cpuid, void *opaque); -int s390_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, - CPUState *cpu, void *opaque); hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr); int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); diff --git a/qemu/target-s390x/cpu.c b/qemu/target-s390x/cpu.c index c3e21b445..4bfff341d 100644 --- a/qemu/target-s390x/cpu.c +++ b/qemu/target-s390x/cpu.c @@ -23,14 +23,20 @@ * GNU GPL, version 2 or (at your option) any later version. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "cpu.h" #include "qemu-common.h" +#include "qemu/cutils.h" #include "qemu/timer.h" #include "qemu/error-report.h" #include "hw/hw.h" #include "trace.h" +#include "qapi/visitor.h" #ifndef CONFIG_USER_ONLY #include "sysemu/arch_init.h" +#include "sysemu/sysemu.h" +#include "hw/s390x/sclp.h" #endif #define CR0_RESET 0xE0UL @@ -184,11 +190,49 @@ static void s390_cpu_machine_reset_cb(void *opaque) } #endif +static void s390_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) +{ + info->mach = bfd_mach_s390_64; + info->print_insn = print_insn_s390; +} + static void s390_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); S390CPUClass *scc = S390_CPU_GET_CLASS(dev); + S390CPU *cpu = S390_CPU(dev); + CPUS390XState *env = &cpu->env; + Error *err = NULL; + +#if !defined(CONFIG_USER_ONLY) + if (cpu->id >= max_cpus) { + error_setg(&err, "Unable to add CPU: %" PRIi64 + ", max allowed: %d", cpu->id, max_cpus - 1); + goto out; + } +#endif + if (cpu_exists(cpu->id)) { + error_setg(&err, "Unable to add CPU: %" PRIi64 + ", it already exists", cpu->id); + goto out; + } + if (cpu->id != scc->next_cpu_id) { + error_setg(&err, "Unable to add CPU: %" PRIi64 + ", The next available id is %" PRIi64, cpu->id, + scc->next_cpu_id); + goto out; + } + cpu_exec_init(cs, &err); + if (err != NULL) { + goto out; + } + scc->next_cpu_id++; + +#if !defined(CONFIG_USER_ONLY) + qemu_register_reset(s390_cpu_machine_reset_cb, cpu); +#endif + env->cpu_num = cpu->id; s390_cpu_gdb_init(cs); qemu_init_vcpu(cs); #if !defined(CONFIG_USER_ONLY) @@ -197,7 +241,55 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp) cpu_reset(cs); #endif - scc->parent_realize(dev, errp); + scc->parent_realize(dev, &err); + +#if !defined(CONFIG_USER_ONLY) + if (dev->hotplugged) { + raise_irq_cpu_hotplug(); + } +#endif + +out: + error_propagate(errp, err); +} + +static void s390x_cpu_get_id(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + S390CPU *cpu = S390_CPU(obj); + int64_t value = cpu->id; + + visit_type_int(v, name, &value, errp); +} + +static void s390x_cpu_set_id(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + S390CPU *cpu = S390_CPU(obj); + DeviceState *dev = DEVICE(obj); + const int64_t min = 0; + const int64_t max = UINT32_MAX; + Error *err = NULL; + int64_t value; + + if (dev->realized) { + error_setg(errp, "Attempt to set property '%s' on '%s' after " + "it was realized", name, object_get_typename(obj)); + return; + } + + visit_type_int(v, name, &value, &err); + if (err) { + error_propagate(errp, err); + return; + } + if (value < min || value > max) { + error_setg(errp, "Property %s.%s doesn't take value %" PRId64 + " (minimum: %" PRId64 ", maximum: %" PRId64 ")" , + object_get_typename(obj), name, value, min, max); + return; + } + cpu->id = value; } static void s390_cpu_initfn(Object *obj) @@ -206,15 +298,16 @@ static void s390_cpu_initfn(Object *obj) S390CPU *cpu = S390_CPU(obj); CPUS390XState *env = &cpu->env; static bool inited; - static int cpu_num = 0; #if !defined(CONFIG_USER_ONLY) struct tm tm; #endif cs->env_ptr = env; - cpu_exec_init(cs, &error_abort); + cs->halted = 1; + cs->exception_index = EXCP_HLT; + object_property_add(OBJECT(cpu), "id", "int64_t", s390x_cpu_get_id, + s390x_cpu_set_id, NULL, NULL, NULL); #if !defined(CONFIG_USER_ONLY) - qemu_register_reset(s390_cpu_machine_reset_cb, cpu); qemu_get_timedate(&tm, 0); env->tod_offset = TOD_UNIX_EPOCH + (time2tod(mktimegm(&tm)) * 1000000000ULL); @@ -223,7 +316,6 @@ static void s390_cpu_initfn(Object *obj) env->cpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu); s390_cpu_set_state(CPU_STATE_STOPPED, cpu); #endif - env->cpu_num = cpu_num++; if (tcg_enabled() && !inited) { inited = true; @@ -319,12 +411,18 @@ unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) } #endif +static gchar *s390_gdb_arch_name(CPUState *cs) +{ + return g_strdup("s390:64-bit"); +} + static void s390_cpu_class_init(ObjectClass *oc, void *data) { S390CPUClass *scc = S390_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(scc); DeviceClass *dc = DEVICE_CLASS(oc); + scc->next_cpu_id = 0; scc->parent_realize = dc->realize; dc->realize = s390_cpu_realizefn; @@ -347,12 +445,21 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) cc->get_phys_page_debug = s390_cpu_get_phys_page_debug; cc->vmsd = &vmstate_s390_cpu; cc->write_elf64_note = s390_cpu_write_elf64_note; - cc->write_elf64_qemunote = s390_cpu_write_elf64_qemunote; cc->cpu_exec_interrupt = s390_cpu_exec_interrupt; cc->debug_excp_handler = s390x_cpu_debug_excp_handler; #endif + cc->disas_set_info = s390_cpu_disas_set_info; + cc->gdb_num_core_regs = S390_NUM_CORE_REGS; cc->gdb_core_xml_file = "s390x-core64.xml"; + cc->gdb_arch_name = s390_gdb_arch_name; + + /* + * Reason: s390_cpu_realizefn() calls cpu_exec_init(), which saves + * the object in cpus -> dangling pointer after final + * object_unref(). + */ + dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo s390_cpu_type_info = { diff --git a/qemu/target-s390x/cpu.h b/qemu/target-s390x/cpu.h index 63aebf484..6d97c089a 100644 --- a/qemu/target-s390x/cpu.h +++ b/qemu/target-s390x/cpu.h @@ -22,12 +22,10 @@ #ifndef CPU_S390X_H #define CPU_S390X_H -#include "config.h" #include "qemu-common.h" #define TARGET_LONG_BITS 64 -#define ELF_MACHINE EM_S390 #define ELF_MACHINE_UNAME "S390X" #define CPUArchState struct CPUS390XState @@ -43,6 +41,7 @@ #include "fpu/softfloat.h" #define NB_MMU_MODES 3 +#define TARGET_INSN_START_EXTRA_WORDS 1 #define MMU_MODE0_SUFFIX _primary #define MMU_MODE1_SUFFIX _secondary @@ -143,8 +142,6 @@ typedef struct CPUS390XState { uint32_t cpu_num; uint32_t machine_type; - uint8_t *storage_keys; - uint64_t tod_offset; uint64_t tod_basetime; QEMUTimer *tod_timer; @@ -310,7 +307,7 @@ static inline CPU_DoubleU *get_freg(CPUS390XState *cs, int nr) #define MMU_SECONDARY_IDX 1 #define MMU_HOME_IDX 2 -static inline int cpu_mmu_index (CPUS390XState *env) +static inline int cpu_mmu_index (CPUS390XState *env, bool ifetch) { switch (env->psw.mask & PSW_MASK_ASC) { case PSW_ASC_PRIMARY: @@ -416,6 +413,8 @@ void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen); #endif S390CPU *cpu_s390x_init(const char *cpu_model); +S390CPU *s390x_new_cpu(const char *cpu_model, int64_t id, Error **errp); +S390CPU *cpu_s390x_create(const char *cpu_model, Error **errp); void s390x_translate_init(void); int cpu_s390x_exec(CPUState *cpu); @@ -473,10 +472,8 @@ void s390x_tod_timer(void *opaque); void s390x_cpu_timer(void *opaque); int s390_virtio_hypercall(CPUS390XState *env); -void s390_virtio_irq(int config_change, uint64_t token); #ifdef CONFIG_KVM -void kvm_s390_virtio_irq(int config_change, uint64_t token); void kvm_s390_service_interrupt(uint32_t parm); void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq); void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq); @@ -487,9 +484,6 @@ int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf, int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock); int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_clock); #else -static inline void kvm_s390_virtio_irq(int config_change, uint64_t token) -{ -} static inline void kvm_s390_service_interrupt(uint32_t parm) { } @@ -547,9 +541,6 @@ int gtod_load(QEMUFile *f, void *opaque, int version_id); /* service interrupts are floating therefore we must not pass an cpustate */ void s390_sclp_extint(uint32_t parm); -/* from s390-virtio-bus */ -extern const hwaddr virtio_size; - #else static inline unsigned int s390_cpu_halt(S390CPU *cpu) { @@ -571,7 +562,7 @@ void cpu_unlock(void); typedef struct SubchDev SubchDev; #ifndef CONFIG_USER_ONLY -extern void io_subsystem_reset(void); +extern void subsystem_reset(void); SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, uint16_t schid); bool css_subch_visible(SubchDev *sch); @@ -600,7 +591,6 @@ bool css_present(uint8_t cssid); #define cpu_init(model) CPU(cpu_s390x_init(model)) #define cpu_exec cpu_s390x_exec -#define cpu_gen_code cpu_s390x_gen_code #define cpu_signal_handler cpu_s390x_signal_handler void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf); @@ -1163,12 +1153,13 @@ int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, int vq, bool assign); int kvm_s390_cpu_restart(S390CPU *cpu); int kvm_s390_get_memslot_count(KVMState *s); -void kvm_s390_clear_cmma_callback(void *opaque); +void kvm_s390_cmma_reset(void); int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state); void kvm_s390_reset_vcpu(S390CPU *cpu); int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit); void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu); int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu); +void kvm_s390_crypto_reset(void); #else static inline void kvm_s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, @@ -1192,7 +1183,7 @@ static inline int kvm_s390_cpu_restart(S390CPU *cpu) { return -ENOSYS; } -static inline void kvm_s390_clear_cmma_callback(void *opaque) +static inline void kvm_s390_cmma_reset(void) { } static inline int kvm_s390_get_memslot_count(KVMState *s) @@ -1218,6 +1209,9 @@ static inline int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu) { return 0; } +static inline void kvm_s390_crypto_reset(void) +{ +} #endif static inline int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit) @@ -1228,11 +1222,10 @@ static inline int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit) return 0; } -static inline void cmma_reset(S390CPU *cpu) +static inline void s390_cmma_reset(void) { if (kvm_enabled()) { - CPUState *cs = CPU(cpu); - kvm_s390_clear_cmma_callback(cs->kvm_state); + kvm_s390_cmma_reset(); } } @@ -1264,6 +1257,13 @@ static inline int s390_assign_subch_ioeventfd(EventNotifier *notifier, return kvm_s390_assign_subch_ioeventfd(notifier, sch_id, vq, assign); } +static inline void s390_crypto_reset(void) +{ + if (kvm_enabled()) { + kvm_s390_crypto_reset(); + } +} + #ifdef CONFIG_KVM static inline bool vregs_needed(void *opaque) { @@ -1278,4 +1278,49 @@ static inline bool vregs_needed(void *opaque) return 0; } #endif + +/* machine check interruption code */ + +/* subclasses */ +#define MCIC_SC_SD 0x8000000000000000ULL +#define MCIC_SC_PD 0x4000000000000000ULL +#define MCIC_SC_SR 0x2000000000000000ULL +#define MCIC_SC_CD 0x0800000000000000ULL +#define MCIC_SC_ED 0x0400000000000000ULL +#define MCIC_SC_DG 0x0100000000000000ULL +#define MCIC_SC_W 0x0080000000000000ULL +#define MCIC_SC_CP 0x0040000000000000ULL +#define MCIC_SC_SP 0x0020000000000000ULL +#define MCIC_SC_CK 0x0010000000000000ULL + +/* subclass modifiers */ +#define MCIC_SCM_B 0x0002000000000000ULL +#define MCIC_SCM_DA 0x0000000020000000ULL +#define MCIC_SCM_AP 0x0000000000080000ULL + +/* storage errors */ +#define MCIC_SE_SE 0x0000800000000000ULL +#define MCIC_SE_SC 0x0000400000000000ULL +#define MCIC_SE_KE 0x0000200000000000ULL +#define MCIC_SE_DS 0x0000100000000000ULL +#define MCIC_SE_IE 0x0000000080000000ULL + +/* validity bits */ +#define MCIC_VB_WP 0x0000080000000000ULL +#define MCIC_VB_MS 0x0000040000000000ULL +#define MCIC_VB_PM 0x0000020000000000ULL +#define MCIC_VB_IA 0x0000010000000000ULL +#define MCIC_VB_FA 0x0000008000000000ULL +#define MCIC_VB_VR 0x0000004000000000ULL +#define MCIC_VB_EC 0x0000002000000000ULL +#define MCIC_VB_FP 0x0000001000000000ULL +#define MCIC_VB_GR 0x0000000800000000ULL +#define MCIC_VB_CR 0x0000000400000000ULL +#define MCIC_VB_ST 0x0000000100000000ULL +#define MCIC_VB_AR 0x0000000040000000ULL +#define MCIC_VB_PR 0x0000000000200000ULL +#define MCIC_VB_FC 0x0000000000100000ULL +#define MCIC_VB_CT 0x0000000000020000ULL +#define MCIC_VB_CC 0x0000000000010000ULL + #endif diff --git a/qemu/target-s390x/fpu_helper.c b/qemu/target-s390x/fpu_helper.c index 45b7ddfbe..1c7f67354 100644 --- a/qemu/target-s390x/fpu_helper.c +++ b/qemu/target-s390x/fpu_helper.c @@ -18,6 +18,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/cpu_ldst.h" #include "exec/helper-proto.h" diff --git a/qemu/target-s390x/gdbstub.c b/qemu/target-s390x/gdbstub.c index 31f204964..9fc36cb54 100644 --- a/qemu/target-s390x/gdbstub.c +++ b/qemu/target-s390x/gdbstub.c @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" +#include "qemu/osdep.h" #include "qemu-common.h" #include "exec/gdbstub.h" #include "qemu/bitops.h" @@ -174,6 +174,115 @@ static int cpu_write_vreg(CPUS390XState *env, uint8_t *mem_buf, int n) } } +/* the values represent the positions in s390-cr.xml */ +#define S390_C0_REGNUM 0 +#define S390_C15_REGNUM 15 +/* total number of registers in s390-cr.xml */ +#define S390_NUM_C_REGS 16 + +#ifndef CONFIG_USER_ONLY +static int cpu_read_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n) +{ + switch (n) { + case S390_C0_REGNUM ... S390_C15_REGNUM: + return gdb_get_regl(mem_buf, env->cregs[n]); + default: + return 0; + } +} + +static int cpu_write_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n) +{ + switch (n) { + case S390_C0_REGNUM ... S390_C15_REGNUM: + env->cregs[n] = ldtul_p(mem_buf); + if (tcg_enabled()) { + tlb_flush(ENV_GET_CPU(env), 1); + } + cpu_synchronize_post_init(ENV_GET_CPU(env)); + return 8; + default: + return 0; + } +} + +/* the values represent the positions in s390-virt.xml */ +#define S390_VIRT_CKC_REGNUM 0 +#define S390_VIRT_CPUTM_REGNUM 1 +#define S390_VIRT_BEA_REGNUM 2 +#define S390_VIRT_PREFIX_REGNUM 3 +#define S390_VIRT_PP_REGNUM 4 +#define S390_VIRT_PFT_REGNUM 5 +#define S390_VIRT_PFS_REGNUM 6 +#define S390_VIRT_PFC_REGNUM 7 +/* total number of registers in s390-virt.xml */ +#define S390_NUM_VIRT_REGS 8 + +static int cpu_read_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n) +{ + switch (n) { + case S390_VIRT_CKC_REGNUM: + return gdb_get_regl(mem_buf, env->ckc); + case S390_VIRT_CPUTM_REGNUM: + return gdb_get_regl(mem_buf, env->cputm); + case S390_VIRT_BEA_REGNUM: + return gdb_get_regl(mem_buf, env->gbea); + case S390_VIRT_PREFIX_REGNUM: + return gdb_get_regl(mem_buf, env->psa); + case S390_VIRT_PP_REGNUM: + return gdb_get_regl(mem_buf, env->pp); + case S390_VIRT_PFT_REGNUM: + return gdb_get_regl(mem_buf, env->pfault_token); + case S390_VIRT_PFS_REGNUM: + return gdb_get_regl(mem_buf, env->pfault_select); + case S390_VIRT_PFC_REGNUM: + return gdb_get_regl(mem_buf, env->pfault_compare); + default: + return 0; + } +} + +static int cpu_write_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n) +{ + switch (n) { + case S390_VIRT_CKC_REGNUM: + env->ckc = ldtul_p(mem_buf); + cpu_synchronize_post_init(ENV_GET_CPU(env)); + return 8; + case S390_VIRT_CPUTM_REGNUM: + env->cputm = ldtul_p(mem_buf); + cpu_synchronize_post_init(ENV_GET_CPU(env)); + return 8; + case S390_VIRT_BEA_REGNUM: + env->gbea = ldtul_p(mem_buf); + cpu_synchronize_post_init(ENV_GET_CPU(env)); + return 8; + case S390_VIRT_PREFIX_REGNUM: + env->psa = ldtul_p(mem_buf); + cpu_synchronize_post_init(ENV_GET_CPU(env)); + return 8; + case S390_VIRT_PP_REGNUM: + env->pp = ldtul_p(mem_buf); + cpu_synchronize_post_init(ENV_GET_CPU(env)); + return 8; + case S390_VIRT_PFT_REGNUM: + env->pfault_token = ldtul_p(mem_buf); + cpu_synchronize_post_init(ENV_GET_CPU(env)); + return 8; + case S390_VIRT_PFS_REGNUM: + env->pfault_select = ldtul_p(mem_buf); + cpu_synchronize_post_init(ENV_GET_CPU(env)); + return 8; + case S390_VIRT_PFC_REGNUM: + env->pfault_compare = ldtul_p(mem_buf); + cpu_synchronize_post_init(ENV_GET_CPU(env)); + return 8; + default: + return 0; + } +} +#endif + void s390_cpu_gdb_init(CPUState *cs) { gdb_register_coprocessor(cs, cpu_read_ac_reg, @@ -187,4 +296,16 @@ void s390_cpu_gdb_init(CPUState *cs) gdb_register_coprocessor(cs, cpu_read_vreg, cpu_write_vreg, S390_NUM_VREGS, "s390-vx.xml", 0); + +#ifndef CONFIG_USER_ONLY + gdb_register_coprocessor(cs, cpu_read_c_reg, + cpu_write_c_reg, + S390_NUM_C_REGS, "s390-cr.xml", 0); + + if (kvm_enabled()) { + gdb_register_coprocessor(cs, cpu_read_virt_reg, + cpu_write_virt_reg, + S390_NUM_VIRT_REGS, "s390-virt.xml", 0); + } +#endif } diff --git a/qemu/target-s390x/helper.c b/qemu/target-s390x/helper.c index d88700695..92abe7e67 100644 --- a/qemu/target-s390x/helper.c +++ b/qemu/target-s390x/helper.c @@ -18,6 +18,8 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "cpu.h" #include "exec/gdbstub.h" #include "qemu/timer.h" @@ -33,7 +35,7 @@ #ifdef DEBUG_S390_STDOUT #define DPRINTF(fmt, ...) \ do { fprintf(stderr, fmt, ## __VA_ARGS__); \ - qemu_log(fmt, ##__VA_ARGS__); } while (0) + if (qemu_log_separate()) qemu_log(fmt, ##__VA_ARGS__); } while (0) #else #define DPRINTF(fmt, ...) \ do { qemu_log(fmt, ## __VA_ARGS__); } while (0) @@ -64,14 +66,51 @@ void s390x_cpu_timer(void *opaque) } #endif -S390CPU *cpu_s390x_init(const char *cpu_model) +S390CPU *cpu_s390x_create(const char *cpu_model, Error **errp) { S390CPU *cpu; cpu = S390_CPU(object_new(TYPE_S390_CPU)); - object_property_set_bool(OBJECT(cpu), true, "realized", NULL); + return cpu; +} + +S390CPU *s390x_new_cpu(const char *cpu_model, int64_t id, Error **errp) +{ + S390CPU *cpu; + Error *err = NULL; + cpu = cpu_s390x_create(cpu_model, &err); + if (err != NULL) { + goto out; + } + + object_property_set_int(OBJECT(cpu), id, "id", &err); + if (err != NULL) { + goto out; + } + object_property_set_bool(OBJECT(cpu), true, "realized", &err); + +out: + if (err) { + error_propagate(errp, err); + object_unref(OBJECT(cpu)); + cpu = NULL; + } + return cpu; +} + +S390CPU *cpu_s390x_init(const char *cpu_model) +{ + Error *err = NULL; + S390CPU *cpu; + /* Use to track CPU ID for linux-user only */ + static int64_t next_cpu_id; + + cpu = s390x_new_cpu(cpu_model, next_cpu_id++, &err); + if (err) { + error_report_err(err); + } return cpu; } @@ -133,7 +172,7 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr, } /* check out of RAM access */ - if (raddr > (ram_size + virtio_size)) { + if (raddr > ram_size) { DPRINTF("%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, (uint64_t)raddr, (uint64_t)ram_size); trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_LATER); @@ -162,8 +201,9 @@ hwaddr s390_cpu_get_phys_page_debug(CPUState *cs, vaddr vaddr) vaddr &= 0x7fffffff; } - mmu_translate(env, vaddr, MMU_INST_FETCH, asc, &raddr, &prot, false); - + if (mmu_translate(env, vaddr, MMU_INST_FETCH, asc, &raddr, &prot, false)) { + return -1; + } return raddr; } diff --git a/qemu/target-s390x/int_helper.c b/qemu/target-s390x/int_helper.c index a46c736d6..cc1071eea 100644 --- a/qemu/target-s390x/int_helper.c +++ b/qemu/target-s390x/int_helper.c @@ -18,6 +18,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" diff --git a/qemu/target-s390x/interrupt.c b/qemu/target-s390x/interrupt.c index 1404d0afd..bad60a7e1 100644 --- a/qemu/target-s390x/interrupt.c +++ b/qemu/target-s390x/interrupt.c @@ -7,6 +7,7 @@ * option) any later version. See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include "cpu.h" #include "sysemu/kvm.h" @@ -27,17 +28,6 @@ void s390_sclp_extint(uint32_t parm) } } -void s390_virtio_irq(int config_change, uint64_t token) -{ - if (kvm_enabled()) { - kvm_s390_virtio_irq(config_change, token); - } else { - S390CPU *dummy_cpu = s390_cpu_addr2state(0); - - cpu_inject_ext(dummy_cpu, EXT_VIRTIO, config_change, token); - } -} - void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, uint32_t io_int_parm, uint32_t io_int_word) { diff --git a/qemu/target-s390x/ioinst.c b/qemu/target-s390x/ioinst.c index 77f2a1fb9..142ff9384 100644 --- a/qemu/target-s390x/ioinst.c +++ b/qemu/target-s390x/ioinst.c @@ -9,7 +9,7 @@ * directory. */ -#include <sys/types.h> +#include "qemu/osdep.h" #include "cpu.h" #include "ioinst.h" @@ -614,9 +614,11 @@ static void ioinst_handle_chsc_sei(ChscReq *req, ChscResp *res) (*res_flags) |= 0x80; } else { (*res_flags) &= ~0x80; + css_clear_sei_pending(); } } else { - res->code = cpu_to_be16(0x0004); + res->code = cpu_to_be16(0x0005); + res->len = cpu_to_be16(CHSC_MIN_RESP_LEN); } } diff --git a/qemu/target-s390x/kvm.c b/qemu/target-s390x/kvm.c index ae3a0affe..e1859cae0 100644 --- a/qemu/target-s390x/kvm.c +++ b/qemu/target-s390x/kvm.c @@ -21,7 +21,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include <sys/types.h> +#include "qemu/osdep.h" #include <sys/ioctl.h> #include <sys/mman.h> @@ -173,16 +173,15 @@ int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit) return kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr); } -void kvm_s390_clear_cmma_callback(void *opaque) +void kvm_s390_cmma_reset(void) { int rc; - KVMState *s = opaque; struct kvm_device_attr attr = { .group = KVM_S390_VM_MEM_CTRL, .attr = KVM_S390_VM_MEM_CLR_CMMA, }; - rc = kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr); + rc = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr); trace_kvm_clear_cmma(rc); } @@ -200,9 +199,6 @@ static void kvm_s390_enable_cmma(KVMState *s) } rc = kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr); - if (!rc) { - qemu_register_reset(kvm_s390_clear_cmma_callback, s); - } trace_kvm_enable_cmma(rc); } @@ -249,7 +245,7 @@ static void kvm_s390_init_dea_kw(void) } } -static void kvm_s390_init_crypto(void) +void kvm_s390_crypto_reset(void) { kvm_s390_init_aes_kw(); kvm_s390_init_dea_kw(); @@ -262,7 +258,9 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP); cap_s390_irq = kvm_check_extension(s, KVM_CAP_S390_INJECT_IRQ); - kvm_s390_enable_cmma(s); + if (!mem_path) { + kvm_s390_enable_cmma(s); + } if (!kvm_check_extension(s, KVM_CAP_S390_GMAP) || !kvm_check_extension(s, KVM_CAP_S390_COW)) { @@ -301,8 +299,6 @@ void kvm_s390_reset_vcpu(S390CPU *cpu) if (kvm_vcpu_ioctl(cs, KVM_S390_INITIAL_RESET, NULL)) { error_report("Initial CPU reset failed on CPU %i", cs->cpu_index); } - - kvm_s390_init_crypto(); } static int can_sync_regs(CPUState *cs, int regs) @@ -346,6 +342,12 @@ int kvm_arch_put_registers(CPUState *cs, int level) } cs->kvm_run->s.regs.fpc = env->fpc; cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_VRS; + } else if (can_sync_regs(cs, KVM_SYNC_FPRS)) { + for (i = 0; i < 16; i++) { + cs->kvm_run->s.regs.fprs[i] = get_freg(env, i)->ll; + } + cs->kvm_run->s.regs.fpc = env->fpc; + cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_FPRS; } else { /* Floating point */ for (i = 0; i < 16; i++) { @@ -486,6 +488,11 @@ int kvm_arch_get_registers(CPUState *cs) env->vregs[i][1].ll = cs->kvm_run->s.regs.vrs[i][1]; } env->fpc = cs->kvm_run->s.regs.fpc; + } else if (can_sync_regs(cs, KVM_SYNC_FPRS)) { + for (i = 0; i < 16; i++) { + get_freg(env, i)->ll = cs->kvm_run->s.regs.fprs[i]; + } + env->fpc = cs->kvm_run->s.regs.fpc; } else { r = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu); if (r < 0) { @@ -588,9 +595,9 @@ int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low) * @addr: the logical start address in guest memory * @ar: the access register number * @hostbuf: buffer in host memory. NULL = do only checks w/o copying - * @len: length that should be transfered + * @len: length that should be transferred * @is_write: true = write, false = read - * Returns: 0 on success, non-zero if an exception or error occured + * Returns: 0 on success, non-zero if an exception or error occurred * * Use KVM ioctl to read/write from/to guest memory. An access exception * is injected into the vCPU in case of translation errors. @@ -929,17 +936,6 @@ void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq) __kvm_s390_floating_interrupt(irq); } -void kvm_s390_virtio_irq(int config_change, uint64_t token) -{ - struct kvm_s390_irq irq = { - .type = KVM_S390_INT_VIRTIO, - .u.ext.ext_params = config_change, - .u.ext.ext_params2 = token, - }; - - kvm_s390_floating_interrupt(&irq); -} - void kvm_s390_service_interrupt(uint32_t parm) { struct kvm_s390_irq irq = { @@ -1437,7 +1433,7 @@ 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 *)mem + i) = get_freg(&cpu->env, i)->ll; + *((uint64_t *)mem + i) = get_freg(&cpu->env, i)->ll; } memcpy(mem + 128, &cpu->env.regs, 128); memcpy(mem + 256, &cpu->env.psw, 16); @@ -1796,13 +1792,6 @@ static bool is_special_wait_psw(CPUState *cs) return cs->kvm_run->psw_addr == 0xfffUL; } -static void guest_panicked(void) -{ - qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, - &error_abort); - vm_stop(RUN_STATE_GUEST_PANICKED); -} - static void unmanageable_intercept(S390CPU *cpu, const char *str, int pswoffset) { CPUState *cs = CPU(cpu); @@ -1811,7 +1800,7 @@ static void unmanageable_intercept(S390CPU *cpu, const char *str, int pswoffset) str, cs->cpu_index, ldq_phys(cs->as, cpu->env.psa + pswoffset), ldq_phys(cs->as, cpu->env.psa + pswoffset + 8)); s390_cpu_halt(cpu); - guest_panicked(); + qemu_system_guest_panicked(); } static int handle_intercept(S390CPU *cpu) @@ -1844,7 +1833,7 @@ static int handle_intercept(S390CPU *cpu) if (is_special_wait_psw(cs)) { qemu_system_shutdown_request(); } else { - guest_panicked(); + qemu_system_guest_panicked(); } } r = EXCP_HALTED; @@ -2072,12 +2061,30 @@ void kvm_s390_io_interrupt(uint16_t subchannel_id, kvm_s390_floating_interrupt(&irq); } +static uint64_t build_channel_report_mcic(void) +{ + uint64_t mcic; + + /* subclass: indicate channel report pending */ + mcic = MCIC_SC_CP | + /* subclass modifiers: none */ + /* storage errors: none */ + /* validity bits: no damage */ + MCIC_VB_WP | MCIC_VB_MS | MCIC_VB_PM | MCIC_VB_IA | MCIC_VB_FP | + MCIC_VB_GR | MCIC_VB_CR | MCIC_VB_ST | MCIC_VB_AR | MCIC_VB_PR | + MCIC_VB_FC | MCIC_VB_CT | MCIC_VB_CC; + if (kvm_check_extension(kvm_state, KVM_CAP_S390_VECTOR_REGISTERS)) { + mcic |= MCIC_VB_VR; + } + return mcic; +} + void kvm_s390_crw_mchk(void) { struct kvm_s390_irq irq = { .type = KVM_S390_MCHK, .u.mchk.cr14 = 1 << 28, - .u.mchk.mcic = 0x00400f1d40330000ULL, + .u.mchk.mcic = build_channel_report_mcic(), }; kvm_s390_floating_interrupt(&irq); } @@ -2215,7 +2222,7 @@ int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu) } int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, - uint64_t address, uint32_t data) + uint64_t address, uint32_t data, PCIDevice *dev) { S390PCIBusDevice *pbdev; uint32_t fid = data >> ZPCI_MSI_VEC_BITS; diff --git a/qemu/target-s390x/machine.c b/qemu/target-s390x/machine.c index b76fb0831..6b2609054 100644 --- a/qemu/target-s390x/machine.c +++ b/qemu/target-s390x/machine.c @@ -14,6 +14,7 @@ * or (at your option) any later version. */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "cpu.h" #include "sysemu/kvm.h" @@ -48,7 +49,7 @@ static inline bool fpu_needed(void *opaque) return true; } -const VMStateDescription vmstate_fpu = { +static const VMStateDescription vmstate_fpu = { .name = "cpu/fpu", .version_id = 1, .minimum_version_id = 1, @@ -75,7 +76,7 @@ const VMStateDescription vmstate_fpu = { } }; -const VMStateDescription vmstate_vregs = { +static const VMStateDescription vmstate_vregs = { .name = "cpu/vregs", .version_id = 1, .minimum_version_id = 1, diff --git a/qemu/target-s390x/mem_helper.c b/qemu/target-s390x/mem_helper.c index 6f8bd796a..707862203 100644 --- a/qemu/target-s390x/mem_helper.c +++ b/qemu/target-s390x/mem_helper.c @@ -18,9 +18,11 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" #include "exec/cpu_ldst.h" +#include "hw/s390x/storage-keys.h" /*****************************************************************************/ /* Softmmu support */ @@ -68,7 +70,7 @@ static inline uint64_t adj_len_to_page(uint64_t len, uint64_t addr) static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte, uint32_t l) { - int mmu_idx = cpu_mmu_index(env); + int mmu_idx = cpu_mmu_index(env, false); while (l > 0) { void *p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx); @@ -91,7 +93,7 @@ static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte, static void fast_memmove(CPUS390XState *env, uint64_t dest, uint64_t src, uint32_t l) { - int mmu_idx = cpu_mmu_index(env); + int mmu_idx = cpu_mmu_index(env, false); while (l > 0) { void *src_p = tlb_vaddr_to_host(env, src, MMU_DATA_LOAD, mmu_idx); @@ -937,40 +939,73 @@ uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2) /* insert storage key extended */ uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2) { + static S390SKeysState *ss; + static S390SKeysClass *skeyclass; uint64_t addr = get_address(env, 0, 0, r2); + uint8_t key; if (addr > ram_size) { return 0; } - return env->storage_keys[addr / TARGET_PAGE_SIZE]; + if (unlikely(!ss)) { + ss = s390_get_skeys_device(); + skeyclass = S390_SKEYS_GET_CLASS(ss); + } + + if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) { + return 0; + } + return key; } /* set storage key extended */ void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2) { + static S390SKeysState *ss; + static S390SKeysClass *skeyclass; uint64_t addr = get_address(env, 0, 0, r2); + uint8_t key; if (addr > ram_size) { return; } - env->storage_keys[addr / TARGET_PAGE_SIZE] = r1; + if (unlikely(!ss)) { + ss = s390_get_skeys_device(); + skeyclass = S390_SKEYS_GET_CLASS(ss); + } + + key = (uint8_t) r1; + skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key); } /* reset reference bit extended */ uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2) { - uint8_t re; - uint8_t key; + static S390SKeysState *ss; + static S390SKeysClass *skeyclass; + uint8_t re, key; if (r2 > ram_size) { return 0; } - key = env->storage_keys[r2 / TARGET_PAGE_SIZE]; + if (unlikely(!ss)) { + ss = s390_get_skeys_device(); + skeyclass = S390_SKEYS_GET_CLASS(ss); + } + + if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) { + return 0; + } + re = key & (SK_R | SK_C); - env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R); + key &= ~SK_R; + + if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) { + return 0; + } /* * cc diff --git a/qemu/target-s390x/misc_helper.c b/qemu/target-s390x/misc_helper.c index 8eac0e12b..71cbe34e0 100644 --- a/qemu/target-s390x/misc_helper.c +++ b/qemu/target-s390x/misc_helper.c @@ -18,11 +18,11 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/memory.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" -#include <string.h> #include "sysemu/kvm.h" #include "qemu/timer.h" #include "exec/address-spaces.h" @@ -127,8 +127,9 @@ static int modified_clear_reset(S390CPU *cpu) CPU_FOREACH(t) { run_on_cpu(t, s390_do_cpu_full_reset, t); } - cmma_reset(cpu); - io_subsystem_reset(); + s390_cmma_reset(); + subsystem_reset(); + s390_crypto_reset(); scc->load_normal(CPU(cpu)); cpu_synchronize_all_post_reset(); resume_all_vcpus(); @@ -145,8 +146,8 @@ static int load_normal_reset(S390CPU *cpu) CPU_FOREACH(t) { run_on_cpu(t, s390_do_cpu_reset, t); } - cmma_reset(cpu); - io_subsystem_reset(); + s390_cmma_reset(); + subsystem_reset(); scc->initial_cpu_reset(CPU(cpu)); scc->load_normal(CPU(cpu)); cpu_synchronize_all_post_reset(); @@ -233,11 +234,8 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3) } iplb = g_malloc0(sizeof(struct IplParameterBlock)); cpu_physical_memory_read(addr, iplb, sizeof(struct IplParameterBlock)); - if (!s390_ipl_update_diag308(iplb)) { - env->regs[r1 + 1] = DIAG_308_RC_OK; - } else { - env->regs[r1 + 1] = DIAG_308_RC_INVALID; - } + s390_ipl_update_diag308(iplb); + env->regs[r1 + 1] = DIAG_308_RC_OK; g_free(iplb); return; case 6: @@ -301,7 +299,7 @@ void HELPER(spx)(CPUS390XState *env, uint64_t a1) uint32_t prefix = a1 & 0x7fffe000; env->psa = prefix; - qemu_log("prefix: %#x\n", prefix); + HELPER_LOG("prefix: %#x\n", prefix); tlb_flush_page(cs, 0); tlb_flush_page(cs, TARGET_PAGE_SIZE); } diff --git a/qemu/target-s390x/mmu_helper.c b/qemu/target-s390x/mmu_helper.c index 1ea6d812c..b11a02706 100644 --- a/qemu/target-s390x/mmu_helper.c +++ b/qemu/target-s390x/mmu_helper.c @@ -15,10 +15,13 @@ * GNU General Public License for more details. */ +#include "qemu/osdep.h" #include "qemu/error-report.h" #include "exec/address-spaces.h" #include "cpu.h" #include "sysemu/kvm.h" +#include "trace.h" +#include "hw/s390x/storage-keys.h" /* #define DEBUG_S390 */ /* #define DEBUG_S390_PTE */ @@ -28,7 +31,7 @@ #ifdef DEBUG_S390_STDOUT #define DPRINTF(fmt, ...) \ do { fprintf(stderr, fmt, ## __VA_ARGS__); \ - qemu_log(fmt, ##__VA_ARGS__); } while (0) + if (qemu_log_separate()) qemu_log(fmt, ##__VA_ARGS__); } while (0) #else #define DPRINTF(fmt, ...) \ do { qemu_log(fmt, ## __VA_ARGS__); } while (0) @@ -87,7 +90,7 @@ static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, tec = vaddr | (rw == MMU_DATA_STORE ? FS_WRITE : FS_READ) | asc >> 46; - DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); + DPRINTF("%s: trans_exc_code=%016" PRIx64 "\n", __func__, tec); if (!exc) { return; @@ -309,8 +312,15 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, target_ulong *raddr, int *flags, bool exc) { + static S390SKeysState *ss; + static S390SKeysClass *skeyclass; int r = -1; - uint8_t *sk; + uint8_t key; + + if (unlikely(!ss)) { + ss = s390_get_skeys_device(); + skeyclass = S390_SKEYS_GET_CLASS(ss); + } *flags = PAGE_READ | PAGE_WRITE | PAGE_EXEC; vaddr &= TARGET_PAGE_MASK; @@ -358,14 +368,23 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, /* Convert real address -> absolute address */ *raddr = mmu_real2abs(env, *raddr); - if (*raddr < ram_size) { - sk = &env->storage_keys[*raddr / TARGET_PAGE_SIZE]; + if (r == 0 && *raddr < ram_size) { + if (skeyclass->get_skeys(ss, *raddr / TARGET_PAGE_SIZE, 1, &key)) { + trace_get_skeys_nonzero(r); + return 0; + } + if (*flags & PAGE_READ) { - *sk |= SK_R; + key |= SK_R; } if (*flags & PAGE_WRITE) { - *sk |= SK_C; + key |= SK_C; + } + + if (skeyclass->set_skeys(ss, *raddr / TARGET_PAGE_SIZE, 1, &key)) { + trace_set_skeys_nonzero(r); + return 0; } } diff --git a/qemu/target-s390x/translate.c b/qemu/target-s390x/translate.c index c748290d5..c871ef2bb 100644 --- a/qemu/target-s390x/translate.c +++ b/qemu/target-s390x/translate.c @@ -28,6 +28,7 @@ # define LOG_DISAS(...) do { } while (0) #endif +#include "qemu/osdep.h" #include "cpu.h" #include "disas/disas.h" #include "tcg-op.h" @@ -36,13 +37,14 @@ #include "exec/cpu_ldst.h" /* global register indexes */ -static TCGv_ptr cpu_env; +static TCGv_env cpu_env; #include "exec/gen-icount.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" #include "trace-tcg.h" +#include "exec/log.h" /* Information that (most) every instruction needs to manipulate. */ @@ -124,7 +126,7 @@ void s390_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, for (i = 0; i < 32; i++) { cpu_fprintf(f, "V%02d=%016" PRIx64 "%016" PRIx64, i, env->vregs[i][0].ll, env->vregs[i][1].ll); - cpu_fprintf(f, (i % 2) ? " " : "\n"); + cpu_fprintf(f, (i % 2) ? "\n" : " "); } #ifndef CONFIG_USER_ONLY @@ -161,42 +163,40 @@ static char cpu_reg_names[32][4]; static TCGv_i64 regs[16]; static TCGv_i64 fregs[16]; -static uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; - void s390x_translate_init(void) { int i; cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); - psw_addr = tcg_global_mem_new_i64(TCG_AREG0, + psw_addr = tcg_global_mem_new_i64(cpu_env, offsetof(CPUS390XState, psw.addr), "psw_addr"); - psw_mask = tcg_global_mem_new_i64(TCG_AREG0, + psw_mask = tcg_global_mem_new_i64(cpu_env, offsetof(CPUS390XState, psw.mask), "psw_mask"); - gbea = tcg_global_mem_new_i64(TCG_AREG0, + gbea = tcg_global_mem_new_i64(cpu_env, offsetof(CPUS390XState, gbea), "gbea"); - cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUS390XState, cc_op), + cc_op = tcg_global_mem_new_i32(cpu_env, offsetof(CPUS390XState, cc_op), "cc_op"); - cc_src = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUS390XState, cc_src), + cc_src = tcg_global_mem_new_i64(cpu_env, offsetof(CPUS390XState, cc_src), "cc_src"); - cc_dst = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUS390XState, cc_dst), + cc_dst = tcg_global_mem_new_i64(cpu_env, offsetof(CPUS390XState, cc_dst), "cc_dst"); - cc_vr = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUS390XState, cc_vr), + cc_vr = tcg_global_mem_new_i64(cpu_env, offsetof(CPUS390XState, cc_vr), "cc_vr"); for (i = 0; i < 16; i++) { snprintf(cpu_reg_names[i], sizeof(cpu_reg_names[0]), "r%d", i); - regs[i] = tcg_global_mem_new(TCG_AREG0, + regs[i] = tcg_global_mem_new(cpu_env, offsetof(CPUS390XState, regs[i]), cpu_reg_names[i]); } for (i = 0; i < 16; i++) { snprintf(cpu_reg_names[i + 16], sizeof(cpu_reg_names[0]), "f%d", i); - fregs[i] = tcg_global_mem_new(TCG_AREG0, + fregs[i] = tcg_global_mem_new(cpu_env, offsetof(CPUS390XState, vregs[i][0].d), cpu_reg_names[i + 16]); } @@ -811,7 +811,7 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) case CC_OP_LTGT0_32: c->is_64 = false; c->u.s32.a = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(c->u.s32.a, cc_dst); + tcg_gen_extrl_i64_i32(c->u.s32.a, cc_dst); c->u.s32.b = tcg_const_i32(0); break; case CC_OP_LTGT_32: @@ -819,9 +819,9 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) case CC_OP_SUBU_32: c->is_64 = false; c->u.s32.a = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(c->u.s32.a, cc_src); + tcg_gen_extrl_i64_i32(c->u.s32.a, cc_src); c->u.s32.b = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(c->u.s32.b, cc_dst); + tcg_gen_extrl_i64_i32(c->u.s32.b, cc_dst); break; case CC_OP_LTGT0_64: @@ -851,11 +851,11 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) c->is_64 = false; c->u.s32.a = tcg_temp_new_i32(); c->u.s32.b = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(c->u.s32.a, cc_vr); + tcg_gen_extrl_i64_i32(c->u.s32.a, cc_vr); if (cond == TCG_COND_EQ || cond == TCG_COND_NE) { tcg_gen_movi_i32(c->u.s32.b, 0); } else { - tcg_gen_trunc_i64_i32(c->u.s32.b, cc_src); + tcg_gen_extrl_i64_i32(c->u.s32.b, cc_src); } break; @@ -1532,7 +1532,7 @@ static ExitStatus op_bct32(DisasContext *s, DisasOps *o) store_reg32_i64(r1, t); c.u.s32.a = tcg_temp_new_i32(); c.u.s32.b = tcg_const_i32(0); - tcg_gen_trunc_i64_i32(c.u.s32.a, t); + tcg_gen_extrl_i64_i32(c.u.s32.a, t); tcg_temp_free_i64(t); return help_branch(s, &c, is_imm, imm, o->in2); @@ -1556,7 +1556,7 @@ static ExitStatus op_bcth(DisasContext *s, DisasOps *o) store_reg32h_i64(r1, t); c.u.s32.a = tcg_temp_new_i32(); c.u.s32.b = tcg_const_i32(0); - tcg_gen_trunc_i64_i32(c.u.s32.a, t); + tcg_gen_extrl_i64_i32(c.u.s32.a, t); tcg_temp_free_i64(t); return help_branch(s, &c, 1, imm, o->in2); @@ -1599,8 +1599,8 @@ static ExitStatus op_bx32(DisasContext *s, DisasOps *o) tcg_gen_add_i64(t, regs[r1], regs[r3]); c.u.s32.a = tcg_temp_new_i32(); c.u.s32.b = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(c.u.s32.a, t); - tcg_gen_trunc_i64_i32(c.u.s32.b, regs[r3 | 1]); + tcg_gen_extrl_i64_i32(c.u.s32.a, t); + tcg_gen_extrl_i64_i32(c.u.s32.b, regs[r3 | 1]); store_reg32_i64(r1, t); tcg_temp_free_i64(t); @@ -1905,7 +1905,7 @@ static ExitStatus op_clm(DisasContext *s, DisasOps *o) { TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); TCGv_i32 t1 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(t1, o->in1); + tcg_gen_extrl_i64_i32(t1, o->in1); potential_page_fault(s); gen_helper_clm(cc_op, cpu_env, t1, m3, o->in2); set_cc_static(s); @@ -1977,7 +1977,7 @@ static ExitStatus op_cs(DisasContext *s, DisasOps *o) /* Store CC back to cc_op. Wait until after the store so that any exception gets the old cc_op value. */ - tcg_gen_trunc_i64_i32(cc_op, cc); + tcg_gen_extrl_i64_i32(cc_op, cc); tcg_temp_free_i64(cc); set_cc_static(s); return NO_EXIT; @@ -2027,7 +2027,7 @@ static ExitStatus op_cdsg(DisasContext *s, DisasOps *o) /* Save back state now that we've passed all exceptions. */ tcg_gen_mov_i64(regs[r1], outh); tcg_gen_mov_i64(regs[r1 + 1], outl); - tcg_gen_trunc_i64_i32(cc_op, cc); + tcg_gen_extrl_i64_i32(cc_op, cc); tcg_temp_free_i64(outh); tcg_temp_free_i64(outl); tcg_temp_free_i64(cc); @@ -2051,7 +2051,7 @@ static ExitStatus op_cvd(DisasContext *s, DisasOps *o) { TCGv_i64 t1 = tcg_temp_new_i64(); TCGv_i32 t2 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(t2, o->in1); + tcg_gen_extrl_i64_i32(t2, o->in1); gen_helper_cvd(t1, t2); tcg_temp_free_i32(t2); tcg_gen_qemu_st64(t1, o->in2, get_mem_index(s)); @@ -3235,8 +3235,8 @@ static ExitStatus op_rll32(DisasContext *s, DisasOps *o) TCGv_i32 t1 = tcg_temp_new_i32(); TCGv_i32 t2 = tcg_temp_new_i32(); TCGv_i32 to = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(t1, o->in1); - tcg_gen_trunc_i64_i32(t2, o->in2); + tcg_gen_extrl_i64_i32(t1, o->in1); + tcg_gen_extrl_i64_i32(t2, o->in2); tcg_gen_rotl_i32(to, t1, t2); tcg_gen_extu_i32_i64(o->out, to); tcg_temp_free_i32(t1); @@ -5319,18 +5319,14 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) return ret; } -static inline void gen_intermediate_code_internal(S390CPU *cpu, - TranslationBlock *tb, - bool search_pc) +void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb) { + S390CPU *cpu = s390_env_get_cpu(env); CPUState *cs = CPU(cpu); - CPUS390XState *env = &cpu->env; DisasContext dc; target_ulong pc_start; uint64_t next_page_start; - int j, lj = -1; int num_insns, max_insns; - CPUBreakpoint *bp; ExitStatus status; bool do_debug; @@ -5353,41 +5349,32 @@ static inline void gen_intermediate_code_internal(S390CPU *cpu, if (max_insns == 0) { max_insns = CF_COUNT_MASK; } + if (max_insns > TCG_MAX_INSNS) { + max_insns = TCG_MAX_INSNS; + } gen_tb_start(tb); do { - if (search_pc) { - j = tcg_op_buf_count(); - if (lj < j) { - lj++; - while (lj < j) { - tcg_ctx.gen_opc_instr_start[lj++] = 0; - } - } - tcg_ctx.gen_opc_pc[lj] = dc.pc; - gen_opc_cc_op[lj] = dc.cc_op; - tcg_ctx.gen_opc_instr_start[lj] = 1; - tcg_ctx.gen_opc_icount[lj] = num_insns; - } - if (++num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { - gen_io_start(); + tcg_gen_insn_start(dc.pc, dc.cc_op); + num_insns++; + + if (unlikely(cpu_breakpoint_test(cs, dc.pc, BP_ANY))) { + status = EXIT_PC_STALE; + do_debug = true; + /* The address covered by the breakpoint must be included in + [tb->pc, tb->pc + tb->size) in order to for it to be + properly cleared -- thus we increment the PC here so that + the logic setting tb->size below does the right thing. */ + dc.pc += 2; + break; } - if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { - tcg_gen_debug_insn_start(dc.pc); + if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { + gen_io_start(); } status = NO_EXIT; - if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) { - QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { - if (bp->pc == dc.pc) { - status = EXIT_PC_STALE; - do_debug = true; - break; - } - } - } if (status == NO_EXIT) { status = translate_one(env, &dc); } @@ -5432,16 +5419,8 @@ static inline void gen_intermediate_code_internal(S390CPU *cpu, gen_tb_end(tb, num_insns); - if (search_pc) { - j = tcg_op_buf_count(); - lj++; - while (lj <= j) { - tcg_ctx.gen_opc_instr_start[lj++] = 0; - } - } else { - tb->size = dc.pc - pc_start; - tb->icount = num_insns; - } + tb->size = dc.pc - pc_start; + tb->icount = num_insns; #if defined(S390X_DEBUG_DISAS) if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { @@ -5452,21 +5431,11 @@ static inline void gen_intermediate_code_internal(S390CPU *cpu, #endif } -void gen_intermediate_code (CPUS390XState *env, struct TranslationBlock *tb) -{ - gen_intermediate_code_internal(s390_env_get_cpu(env), tb, false); -} - -void gen_intermediate_code_pc (CPUS390XState *env, struct TranslationBlock *tb) -{ - gen_intermediate_code_internal(s390_env_get_cpu(env), tb, true); -} - -void restore_state_to_opc(CPUS390XState *env, TranslationBlock *tb, int pc_pos) +void restore_state_to_opc(CPUS390XState *env, TranslationBlock *tb, + target_ulong *data) { - int cc_op; - env->psw.addr = tcg_ctx.gen_opc_pc[pc_pos]; - cc_op = gen_opc_cc_op[pc_pos]; + int cc_op = data[1]; + env->psw.addr = data[0]; if ((cc_op != CC_OP_DYNAMIC) && (cc_op != CC_OP_STATIC)) { env->cc_op = cc_op; } |