diff options
author | Chanho Park <chanho61.park@samsung.com> | 2014-12-10 15:42:55 +0900 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-12-10 15:42:55 +0900 |
commit | 0d6a2f7e595218b5632ba7005128470e65138951 (patch) | |
tree | 596b09930ef1538e6606450e2d8b88ec2e296a9b /target-s390x | |
parent | 16b1353a36171ae06d63fd309f4772dbfb1da113 (diff) | |
download | qemu-0d6a2f7e595218b5632ba7005128470e65138951.tar.gz qemu-0d6a2f7e595218b5632ba7005128470e65138951.tar.bz2 qemu-0d6a2f7e595218b5632ba7005128470e65138951.zip |
Imported Upstream version 2.2.0upstream/2.2.1upstream/2.2.0
Diffstat (limited to 'target-s390x')
-rw-r--r-- | target-s390x/Makefile.objs | 2 | ||||
-rw-r--r-- | target-s390x/cpu-qom.h | 6 | ||||
-rw-r--r-- | target-s390x/cpu.c | 125 | ||||
-rw-r--r-- | target-s390x/cpu.h | 114 | ||||
-rw-r--r-- | target-s390x/gdbstub.c | 109 | ||||
-rw-r--r-- | target-s390x/helper.c | 32 | ||||
-rw-r--r-- | target-s390x/insn-data.def | 6 | ||||
-rw-r--r-- | target-s390x/interrupt.c | 2 | ||||
-rw-r--r-- | target-s390x/ioinst.h | 10 | ||||
-rw-r--r-- | target-s390x/kvm.c | 100 | ||||
-rw-r--r-- | target-s390x/machine.c | 76 | ||||
-rw-r--r-- | target-s390x/misc_helper.c | 30 | ||||
-rw-r--r-- | target-s390x/translate.c | 14 |
13 files changed, 461 insertions, 165 deletions
diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index f8731463f..2c5749447 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -1,5 +1,5 @@ obj-y += translate.o helper.o cpu.o interrupt.o obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o obj-y += gdbstub.o -obj-$(CONFIG_SOFTMMU) += ioinst.o arch_dump.o +obj-$(CONFIG_SOFTMMU) += machine.o ioinst.o arch_dump.o obj-$(CONFIG_KVM) += kvm.o diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h index f9c96d13a..8b376df1b 100644 --- a/target-s390x/cpu-qom.h +++ b/target-s390x/cpu-qom.h @@ -77,7 +77,12 @@ static inline S390CPU *s390_env_get_cpu(CPUS390XState *env) #define ENV_OFFSET offsetof(S390CPU, env) +#ifndef CONFIG_USER_ONLY +extern const struct VMStateDescription vmstate_s390_cpu; +#endif + void s390_cpu_do_interrupt(CPUState *cpu); +bool s390_cpu_exec_interrupt(CPUState *cpu, int int_req); void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, @@ -89,5 +94,6 @@ 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); int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +void s390_cpu_gdb_init(CPUState *cs); #endif diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index c3082b73c..d2f6312e0 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -26,7 +26,9 @@ #include "cpu.h" #include "qemu-common.h" #include "qemu/timer.h" +#include "qemu/error-report.h" #include "hw/hw.h" +#include "trace.h" #ifndef CONFIG_USER_ONLY #include "sysemu/arch_init.h" #endif @@ -81,7 +83,7 @@ static void s390_cpu_load_normal(CPUState *s) S390CPU *cpu = S390_CPU(s); cpu->env.psw.addr = ldl_phys(s->as, 4) & PSW_MASK_ESA_ADDR; cpu->env.psw.mask = PSW_MASK_32 | PSW_MASK_64; - s390_add_running_cpu(cpu); + s390_cpu_set_state(CPU_STATE_OPERATING, cpu); } #endif @@ -93,11 +95,8 @@ static void s390_cpu_reset(CPUState *s) CPUS390XState *env = &cpu->env; env->pfault_token = -1UL; - s390_del_running_cpu(cpu); scc->parent_reset(s); -#if !defined(CONFIG_USER_ONLY) - s->halted = 1; -#endif + s390_cpu_set_state(CPU_STATE_STOPPED, cpu); tlb_flush(s, 1); } @@ -118,14 +117,10 @@ static void s390_cpu_initial_reset(CPUState *s) env->pfault_token = -1UL; -#if defined(CONFIG_KVM) /* Reset state inside the kernel that we cannot access yet from QEMU. */ if (kvm_enabled()) { - if (kvm_vcpu_ioctl(s, KVM_S390_INITIAL_RESET, NULL)) { - perror("Initial CPU reset failed"); - } + kvm_s390_reset_vcpu(cpu); } -#endif } /* CPUClass:reset() */ @@ -135,9 +130,8 @@ static void s390_cpu_full_reset(CPUState *s) S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); CPUS390XState *env = &cpu->env; - s390_del_running_cpu(cpu); - scc->parent_reset(s); + s390_cpu_set_state(CPU_STATE_STOPPED, cpu); memset(env, 0, offsetof(CPUS390XState, cpu_num)); @@ -147,16 +141,10 @@ static void s390_cpu_full_reset(CPUState *s) env->pfault_token = -1UL; - /* set halted to 1 to make sure we can add the cpu in - * s390_ipl_cpu code, where CPUState::halted is set back to 0 - * after incrementing the cpu counter */ -#if !defined(CONFIG_USER_ONLY) - s->halted = 1; - + /* Reset state inside the kernel that we cannot access yet from QEMU. */ if (kvm_enabled()) { kvm_s390_reset_vcpu(cpu); } -#endif tlb_flush(s, 1); } @@ -165,7 +153,7 @@ static void s390_cpu_machine_reset_cb(void *opaque) { S390CPU *cpu = opaque; - cpu_reset(CPU(cpu)); + run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, CPU(cpu)); } #endif @@ -174,8 +162,13 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp) CPUState *cs = CPU(dev); S390CPUClass *scc = S390_CPU_GET_CLASS(dev); + s390_cpu_gdb_init(cs); qemu_init_vcpu(cs); +#if !defined(CONFIG_USER_ONLY) + run_on_cpu(cs, s390_do_cpu_full_reset, cs); +#else cpu_reset(cs); +#endif scc->parent_realize(dev, errp); } @@ -201,10 +194,7 @@ static void s390_cpu_initfn(Object *obj) env->tod_basetime = 0; env->tod_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu); env->cpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu); - /* set CPUState::halted state to 1 to avoid decrementing the running - * cpu counter in s390_cpu_reset to a negative number at - * initial ipl */ - cs->halted = 1; + s390_cpu_set_state(CPU_STATE_STOPPED, cpu); #endif env->cpu_num = cpu_num++; env->ext_index = -1; @@ -224,10 +214,83 @@ static void s390_cpu_finalize(Object *obj) #endif } -static const VMStateDescription vmstate_s390_cpu = { - .name = "cpu", - .unmigratable = 1, -}; +#if !defined(CONFIG_USER_ONLY) +static bool disabled_wait(CPUState *cpu) +{ + return cpu->halted && !(S390_CPU(cpu)->env.psw.mask & + (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK)); +} + +static unsigned s390_count_running_cpus(void) +{ + CPUState *cpu; + int nr_running = 0; + + CPU_FOREACH(cpu) { + uint8_t state = S390_CPU(cpu)->env.cpu_state; + if (state == CPU_STATE_OPERATING || + state == CPU_STATE_LOAD) { + if (!disabled_wait(cpu)) { + nr_running++; + } + } + } + + return nr_running; +} + +unsigned int s390_cpu_halt(S390CPU *cpu) +{ + CPUState *cs = CPU(cpu); + trace_cpu_halt(cs->cpu_index); + + if (!cs->halted) { + cs->halted = 1; + cs->exception_index = EXCP_HLT; + } + + return s390_count_running_cpus(); +} + +void s390_cpu_unhalt(S390CPU *cpu) +{ + CPUState *cs = CPU(cpu); + trace_cpu_unhalt(cs->cpu_index); + + if (cs->halted) { + cs->halted = 0; + cs->exception_index = -1; + } +} + +unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) + { + trace_cpu_set_state(CPU(cpu)->cpu_index, cpu_state); + + switch (cpu_state) { + case CPU_STATE_STOPPED: + case CPU_STATE_CHECK_STOP: + /* halt the cpu for common infrastructure */ + s390_cpu_halt(cpu); + break; + case CPU_STATE_OPERATING: + case CPU_STATE_LOAD: + /* unhalt the cpu for common infrastructure */ + s390_cpu_unhalt(cpu); + break; + default: + error_report("Requested CPU state is not a valid S390 CPU state: %u", + cpu_state); + exit(1); + } + if (kvm_enabled() && cpu->env.cpu_state != cpu_state) { + kvm_s390_set_cpu_state(cpu, cpu_state); + } + cpu->env.cpu_state = cpu_state; + + return s390_count_running_cpus(); +} +#endif static void s390_cpu_class_init(ObjectClass *oc, void *data) { @@ -255,11 +318,13 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) cc->handle_mmu_fault = s390_cpu_handle_mmu_fault; #else 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; #endif - dc->vmsd = &vmstate_s390_cpu; - cc->gdb_num_core_regs = S390_NUM_REGS; + cc->gdb_num_core_regs = S390_NUM_CORE_REGS; + cc->gdb_core_xml_file = "s390x-core64.xml"; } static const TypeInfo s390_cpu_type_info = { diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index b13761d92..fe2f95d08 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -141,6 +141,20 @@ typedef struct CPUS390XState { QEMUTimer *tod_timer; QEMUTimer *cpu_timer; + + /* + * The cpu state represents the logical state of a cpu. In contrast to other + * architectures, there is a difference between a halt and a stop on s390. + * If all cpus are either stopped (including check stop) or in the disabled + * wait state, the vm can be shut down. + */ +#define CPU_STATE_UNINITIALIZED 0x00 +#define CPU_STATE_STOPPED 0x01 +#define CPU_STATE_CHECK_STOP 0x02 +#define CPU_STATE_OPERATING 0x03 +#define CPU_STATE_LOAD 0x04 + uint8_t cpu_state; + } CPUS390XState; #include "cpu-qom.h" @@ -353,6 +367,21 @@ static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb) /* Base/displacement are at the same locations. */ #define decode_basedisp_rs decode_basedisp_s +/* helper functions for run_on_cpu() */ +static inline void s390_do_cpu_reset(void *arg) +{ + CPUState *cs = arg; + S390CPUClass *scc = S390_CPU_GET_CLASS(cs); + + scc->cpu_reset(cs); +} +static inline void s390_do_cpu_full_reset(void *arg) +{ + CPUState *cs = arg; + + cpu_reset(cs); +} + void s390x_tod_timer(void *opaque); void s390x_cpu_timer(void *opaque); @@ -360,16 +389,12 @@ int s390_virtio_hypercall(CPUS390XState *env); void s390_virtio_irq(int config_change, uint64_t token); #ifdef CONFIG_KVM -void kvm_s390_reset_vcpu(S390CPU *cpu); 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); int kvm_s390_inject_flic(struct kvm_s390_irq *irq); #else -static inline void kvm_s390_reset_vcpu(S390CPU *cpu) -{ -} static inline void kvm_s390_virtio_irq(int config_change, uint64_t token) { } @@ -378,8 +403,9 @@ static inline void kvm_s390_service_interrupt(uint32_t parm) } #endif S390CPU *s390_cpu_addr2state(uint16_t cpu_addr); -void s390_add_running_cpu(S390CPU *cpu); -unsigned s390_del_running_cpu(S390CPU *cpu); +unsigned int s390_cpu_halt(S390CPU *cpu); +void s390_cpu_unhalt(S390CPU *cpu); +unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu); /* service interrupts are floating therefore we must not pass an cpustate */ void s390_sclp_extint(uint32_t parm); @@ -388,11 +414,16 @@ void s390_sclp_extint(uint32_t parm); extern const hwaddr virtio_size; #else -static inline void s390_add_running_cpu(S390CPU *cpu) +static inline unsigned int s390_cpu_halt(S390CPU *cpu) +{ + return 0; +} + +static inline void s390_cpu_unhalt(S390CPU *cpu) { } -static inline unsigned s390_del_running_cpu(S390CPU *cpu) +static inline unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) { return 0; } @@ -551,44 +582,8 @@ void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf); #define S390_R13_REGNUM 15 #define S390_R14_REGNUM 16 #define S390_R15_REGNUM 17 -/* Access Registers. */ -#define S390_A0_REGNUM 18 -#define S390_A1_REGNUM 19 -#define S390_A2_REGNUM 20 -#define S390_A3_REGNUM 21 -#define S390_A4_REGNUM 22 -#define S390_A5_REGNUM 23 -#define S390_A6_REGNUM 24 -#define S390_A7_REGNUM 25 -#define S390_A8_REGNUM 26 -#define S390_A9_REGNUM 27 -#define S390_A10_REGNUM 28 -#define S390_A11_REGNUM 29 -#define S390_A12_REGNUM 30 -#define S390_A13_REGNUM 31 -#define S390_A14_REGNUM 32 -#define S390_A15_REGNUM 33 -/* Floating Point Control Word. */ -#define S390_FPC_REGNUM 34 -/* Floating Point Registers. */ -#define S390_F0_REGNUM 35 -#define S390_F1_REGNUM 36 -#define S390_F2_REGNUM 37 -#define S390_F3_REGNUM 38 -#define S390_F4_REGNUM 39 -#define S390_F5_REGNUM 40 -#define S390_F6_REGNUM 41 -#define S390_F7_REGNUM 42 -#define S390_F8_REGNUM 43 -#define S390_F9_REGNUM 44 -#define S390_F10_REGNUM 45 -#define S390_F11_REGNUM 46 -#define S390_F12_REGNUM 47 -#define S390_F13_REGNUM 48 -#define S390_F14_REGNUM 49 -#define S390_F15_REGNUM 50 -/* Total. */ -#define S390_NUM_REGS 51 +/* Total Core Registers. */ +#define S390_NUM_CORE_REGS 18 /* CC optimization */ @@ -1045,6 +1040,10 @@ static inline void cpu_inject_crw_mchk(S390CPU *cpu) cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); } +/* from s390-virtio-ccw */ +#define MEM_SECTION_SIZE 0x10000000UL +#define MAX_AVAIL_SLOTS 32 + /* fpu_helper.c */ uint32_t set_cc_nz_f32(float32 v); uint32_t set_cc_nz_f64(float64 v); @@ -1067,7 +1066,10 @@ void kvm_s390_enable_css_support(S390CPU *cpu); 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); +int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state); +void kvm_s390_reset_vcpu(S390CPU *cpu); #else static inline void kvm_s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, @@ -1094,6 +1096,17 @@ static inline int kvm_s390_cpu_restart(S390CPU *cpu) static inline void kvm_s390_clear_cmma_callback(void *opaque) { } +static inline int kvm_s390_get_memslot_count(KVMState *s) +{ + return MAX_AVAIL_SLOTS; +} +static inline int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state) +{ + return -ENOSYS; +} +static inline void kvm_s390_reset_vcpu(S390CPU *cpu) +{ +} #endif static inline void cmma_reset(S390CPU *cpu) @@ -1112,6 +1125,15 @@ static inline int s390_cpu_restart(S390CPU *cpu) return -ENOSYS; } +static inline int s390_get_memslot_count(KVMState *s) +{ + if (kvm_enabled()) { + return kvm_s390_get_memslot_count(s); + } else { + return MAX_AVAIL_SLOTS; + } +} + void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, uint32_t io_int_parm, uint32_t io_int_word); void s390_crw_mchk(void); diff --git a/target-s390x/gdbstub.c b/target-s390x/gdbstub.c index a129742e2..8945f0271 100644 --- a/target-s390x/gdbstub.c +++ b/target-s390x/gdbstub.c @@ -31,21 +31,18 @@ int s390_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) switch (n) { case S390_PSWM_REGNUM: - cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr); - val = deposit64(env->psw.mask, 44, 2, cc_op); - return gdb_get_regl(mem_buf, val); + if (tcg_enabled()) { + cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, + env->cc_vr); + val = deposit64(env->psw.mask, 44, 2, cc_op); + return gdb_get_regl(mem_buf, val); + } + return gdb_get_regl(mem_buf, env->psw.mask); case S390_PSWA_REGNUM: return gdb_get_regl(mem_buf, env->psw.addr); case S390_R0_REGNUM ... S390_R15_REGNUM: - return gdb_get_regl(mem_buf, env->regs[n-S390_R0_REGNUM]); - case S390_A0_REGNUM ... S390_A15_REGNUM: - return gdb_get_reg32(mem_buf, env->aregs[n-S390_A0_REGNUM]); - case S390_FPC_REGNUM: - return gdb_get_reg32(mem_buf, env->fpc); - case S390_F0_REGNUM ... S390_F15_REGNUM: - return gdb_get_reg64(mem_buf, env->fregs[n-S390_F0_REGNUM].ll); + return gdb_get_regl(mem_buf, env->regs[n - S390_R0_REGNUM]); } - return 0; } @@ -53,36 +50,94 @@ int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) { S390CPU *cpu = S390_CPU(cs); CPUS390XState *env = &cpu->env; - target_ulong tmpl; - uint32_t tmp32; - int r = 8; - tmpl = ldtul_p(mem_buf); - tmp32 = ldl_p(mem_buf); + target_ulong tmpl = ldtul_p(mem_buf); switch (n) { case S390_PSWM_REGNUM: env->psw.mask = tmpl; - env->cc_op = extract64(tmpl, 44, 2); + if (tcg_enabled()) { + env->cc_op = extract64(tmpl, 44, 2); + } break; case S390_PSWA_REGNUM: env->psw.addr = tmpl; break; case S390_R0_REGNUM ... S390_R15_REGNUM: - env->regs[n-S390_R0_REGNUM] = tmpl; + env->regs[n - S390_R0_REGNUM] = tmpl; break; + default: + return 0; + } + return 8; +} + +/* the values represent the positions in s390-acr.xml */ +#define S390_A0_REGNUM 0 +#define S390_A15_REGNUM 15 +/* total number of registers in s390-acr.xml */ +#define S390_NUM_AC_REGS 16 + +static int cpu_read_ac_reg(CPUS390XState *env, uint8_t *mem_buf, int n) +{ + switch (n) { case S390_A0_REGNUM ... S390_A15_REGNUM: - env->aregs[n-S390_A0_REGNUM] = tmp32; - r = 4; - break; + return gdb_get_reg32(mem_buf, env->aregs[n]); + default: + return 0; + } +} + +static int cpu_write_ac_reg(CPUS390XState *env, uint8_t *mem_buf, int n) +{ + switch (n) { + case S390_A0_REGNUM ... S390_A15_REGNUM: + env->aregs[n] = ldl_p(mem_buf); + return 4; + default: + return 0; + } +} + +/* the values represent the positions in s390-fpr.xml */ +#define S390_FPC_REGNUM 0 +#define S390_F0_REGNUM 1 +#define S390_F15_REGNUM 16 +/* total number of registers in s390-fpr.xml */ +#define S390_NUM_FP_REGS 17 + +static int cpu_read_fp_reg(CPUS390XState *env, uint8_t *mem_buf, int n) +{ + switch (n) { case S390_FPC_REGNUM: - env->fpc = tmp32; - r = 4; - break; + return gdb_get_reg32(mem_buf, env->fpc); case S390_F0_REGNUM ... S390_F15_REGNUM: - env->fregs[n-S390_F0_REGNUM].ll = tmpl; - break; + return gdb_get_reg64(mem_buf, env->fregs[n - S390_F0_REGNUM].ll); default: return 0; } - return r; +} + +static int cpu_write_fp_reg(CPUS390XState *env, uint8_t *mem_buf, int n) +{ + switch (n) { + case S390_FPC_REGNUM: + env->fpc = ldl_p(mem_buf); + return 4; + case S390_F0_REGNUM ... S390_F15_REGNUM: + env->fregs[n - S390_F0_REGNUM].ll = ldtul_p(mem_buf); + return 8; + default: + return 0; + } +} + +void s390_cpu_gdb_init(CPUState *cs) +{ + gdb_register_coprocessor(cs, cpu_read_ac_reg, + cpu_write_ac_reg, + S390_NUM_AC_REGS, "s390-acr.xml", 0); + + gdb_register_coprocessor(cs, cpu_read_fp_reg, + cpu_write_fp_reg, + S390_NUM_FP_REGS, "s390-fpr.xml", 0); } diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 67ab1065a..09aec7b42 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -504,23 +504,18 @@ hwaddr s390_cpu_get_phys_addr_debug(CPUState *cs, vaddr vaddr) void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr) { + env->psw.addr = addr; + env->psw.mask = mask; + env->cc_op = (mask >> 44) & 3; + if (mask & PSW_MASK_WAIT) { S390CPU *cpu = s390_env_get_cpu(env); - CPUState *cs = CPU(cpu); - if (!(mask & (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK))) { - if (s390_del_running_cpu(cpu) == 0) { + if (s390_cpu_halt(cpu) == 0) { #ifndef CONFIG_USER_ONLY - qemu_system_shutdown_request(); + qemu_system_shutdown_request(); #endif - } } - cs->halted = 1; - cs->exception_index = EXCP_HLT; } - - env->psw.addr = addr; - env->psw.mask = mask; - env->cc_op = (mask >> 44) & 3; } static uint64_t get_psw_mask(CPUS390XState *env) @@ -818,7 +813,7 @@ void s390_cpu_do_interrupt(CPUState *cs) qemu_log_mask(CPU_LOG_INT, "%s: %d at pc=%" PRIx64 "\n", __func__, cs->exception_index, env->psw.addr); - s390_add_running_cpu(cpu); + s390_cpu_set_state(CPU_STATE_OPERATING, cpu); /* handle machine checks */ if ((env->psw.mask & PSW_MASK_MCHECK) && (cs->exception_index == -1)) { @@ -876,4 +871,17 @@ void s390_cpu_do_interrupt(CPUState *cs) } } +bool s390_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + if (interrupt_request & CPU_INTERRUPT_HARD) { + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; + + if (env->psw.mask & PSW_MASK_EXT) { + s390_cpu_do_interrupt(cs); + return true; + } + } + return false; +} #endif /* CONFIG_USER_ONLY */ diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index b42ebb6a1..4d2feb697 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -744,9 +744,9 @@ /* SERVICE CALL LOGICAL PROCESSOR (PV hypercall) */ C(0xb220, SERVC, RRE, Z, r1_o, r2_o, 0, 0, servc, 0) /* SET ADDRESSING MODE */ - /* We only do 64-bit, so accept this as a no-op. - Let SAM24 and SAM31 signal illegal instruction. */ - C(0x010e, SAM64, E, Z, 0, 0, 0, 0, 0, 0) + D(0x010c, SAM24, E, Z, 0, 0, 0, 0, sam, 0, 0) + D(0x010d, SAM31, E, Z, 0, 0, 0, 0, sam, 0, 1) + D(0x010e, SAM64, E, Z, 0, 0, 0, 0, sam, 0, 3) /* SET ADDRESS SPACE CONTROL FAST */ C(0xb279, SACF, S, Z, 0, a2, 0, 0, sacf, 0) /* SET CLOCK */ diff --git a/target-s390x/interrupt.c b/target-s390x/interrupt.c index 23a9114f5..1404d0afd 100644 --- a/target-s390x/interrupt.c +++ b/target-s390x/interrupt.c @@ -22,9 +22,7 @@ void s390_sclp_extint(uint32_t parm) kvm_s390_service_interrupt(parm); } else { S390CPU *dummy_cpu = s390_cpu_addr2state(0); - CPUS390XState *env = &dummy_cpu->env; - env->psw.addr += 4; cpu_inject_ext(dummy_cpu, EXT_SERVICE, parm, 0); } } diff --git a/target-s390x/ioinst.h b/target-s390x/ioinst.h index 5bbc67d15..29f6423df 100644 --- a/target-s390x/ioinst.h +++ b/target-s390x/ioinst.h @@ -156,6 +156,16 @@ typedef struct ORB { #define ORB_CTRL1_MASK_ORBX 0x01 #define ORB_CTRL1_MASK_INVALID 0x3e +/* channel command word (type 0) */ +typedef struct CCW0 { + uint8_t cmd_code; + uint8_t cda0; + uint16_t cda1; + uint8_t flags; + uint8_t reserved; + uint16_t count; +} QEMU_PACKED CCW0; + /* channel command word (type 1) */ typedef struct CCW1 { uint8_t cmd_code; diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index a32d91aa0..2c638ab7b 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -106,7 +106,7 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { static int cap_sync_regs; static int cap_async_pf; -static void *legacy_s390_alloc(size_t size); +static void *legacy_s390_alloc(size_t size, uint64_t *align); static int kvm_s390_check_clear_cmma(KVMState *s) { @@ -181,9 +181,10 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu) return cpu->cpu_index; } -int kvm_arch_init_vcpu(CPUState *cpu) +int kvm_arch_init_vcpu(CPUState *cs) { - /* nothing todo yet */ + S390CPU *cpu = S390_CPU(cs); + kvm_s390_set_cpu_state(cpu, cpu->env.cpu_state); return 0; } @@ -197,7 +198,7 @@ void kvm_s390_reset_vcpu(S390CPU *cpu) * Before this ioctl cpu_synchronize_state() is called in common kvm * code (kvm-all) */ if (kvm_vcpu_ioctl(cs, KVM_S390_INITIAL_RESET, NULL)) { - perror("Can't reset vcpu\n"); + error_report("Initial CPU reset failed on CPU %i\n", cs->cpu_index); } } @@ -403,7 +404,7 @@ int kvm_arch_get_registers(CPUState *cs) * to grow. We also have to use MAP parameters that avoid * read-only mapping of guest pages. */ -static void *legacy_s390_alloc(size_t size) +static void *legacy_s390_alloc(size_t size, uint64_t *align) { void *mem; @@ -826,18 +827,18 @@ static int handle_b9(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) return r; } -static int handle_eb(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) +static int handle_eb(S390CPU *cpu, struct kvm_run *run, uint8_t ipbl) { int r = 0; - switch (ipa1) { + switch (ipbl) { case PRIV_EB_SQBS: /* just inject exception */ r = -1; break; default: r = -1; - DPRINTF("KVM: unhandled PRIV: 0xeb%x\n", ipa1); + DPRINTF("KVM: unhandled PRIV: 0xeb%x\n", ipbl); break; } @@ -916,23 +917,30 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb) return r; } -static int kvm_s390_cpu_start(S390CPU *cpu) +static void sigp_cpu_start(void *arg) { - s390_add_running_cpu(cpu); - qemu_cpu_kick(CPU(cpu)); + CPUState *cs = arg; + S390CPU *cpu = S390_CPU(cs); + + s390_cpu_set_state(CPU_STATE_OPERATING, cpu); DPRINTF("DONE: KVM cpu start: %p\n", &cpu->env); - return 0; } -int kvm_s390_cpu_restart(S390CPU *cpu) +static void sigp_cpu_restart(void *arg) { + CPUState *cs = arg; + S390CPU *cpu = S390_CPU(cs); struct kvm_s390_irq irq = { .type = KVM_S390_RESTART, }; kvm_s390_vcpu_interrupt(cpu, &irq); - s390_add_running_cpu(cpu); - qemu_cpu_kick(CPU(cpu)); + s390_cpu_set_state(CPU_STATE_OPERATING, cpu); +} + +int kvm_s390_cpu_restart(S390CPU *cpu) +{ + run_on_cpu(CPU(cpu), sigp_cpu_restart, CPU(cpu)); DPRINTF("DONE: KVM cpu restart: %p\n", &cpu->env); return 0; } @@ -944,6 +952,7 @@ static void sigp_initial_cpu_reset(void *arg) cpu_synchronize_state(cpu); scc->initial_cpu_reset(cpu); + cpu_synchronize_post_reset(cpu); } static void sigp_cpu_reset(void *arg) @@ -953,6 +962,7 @@ static void sigp_cpu_reset(void *arg) cpu_synchronize_state(cpu); scc->cpu_reset(cpu); + cpu_synchronize_post_reset(cpu); } #define SIGP_ORDER_MASK 0x000000ff @@ -980,10 +990,12 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) switch (order_code) { case SIGP_START: - cc = kvm_s390_cpu_start(target_cpu); + run_on_cpu(CPU(target_cpu), sigp_cpu_start, CPU(target_cpu)); + cc = 0; break; case SIGP_RESTART: - cc = kvm_s390_cpu_restart(target_cpu); + run_on_cpu(CPU(target_cpu), sigp_cpu_restart, CPU(target_cpu)); + cc = 0; break; case SIGP_SET_ARCH: *statusreg &= 0xffffffff00000000UL; @@ -1027,7 +1039,7 @@ static int handle_instruction(S390CPU *cpu, struct kvm_run *run) r = handle_b9(cpu, run, ipa1); break; case IPA0_EB: - r = handle_eb(cpu, run, ipa1); + r = handle_eb(cpu, run, run->s390_sieic.ipb & 0xff); break; case IPA0_DIAG: r = handle_diag(cpu, run, run->s390_sieic.ipb); @@ -1065,7 +1077,7 @@ static void unmanageable_intercept(S390CPU *cpu, const char *str, int pswoffset) error_report("Unmanageable %s! CPU%i new PSW: 0x%016lx:%016lx", str, cs->cpu_index, ldq_phys(cs->as, cpu->env.psa + pswoffset), ldq_phys(cs->as, cpu->env.psa + pswoffset + 8)); - s390_del_running_cpu(cpu); + s390_cpu_halt(cpu); guest_panicked(); } @@ -1094,7 +1106,8 @@ static int handle_intercept(S390CPU *cpu) break; case ICPT_WAITPSW: /* disabled wait, since enabled wait is handled in kernel */ - if (s390_del_running_cpu(cpu) == 0) { + cpu_synchronize_state(cs); + if (s390_cpu_halt(cpu) == 0) { if (is_special_wait_psw(cs)) { qemu_system_shutdown_request(); } else { @@ -1104,7 +1117,7 @@ static int handle_intercept(S390CPU *cpu) r = EXCP_HALTED; break; case ICPT_CPU_STOP: - if (s390_del_running_cpu(cpu) == 0) { + if (s390_cpu_set_state(CPU_STATE_STOPPED, cpu) == 0) { qemu_system_shutdown_request(); } r = EXCP_HALTED; @@ -1259,7 +1272,7 @@ void kvm_s390_crw_mchk(void) struct kvm_s390_irq irq = { .type = KVM_S390_MCHK, .u.mchk.cr14 = 1 << 28, - .u.mchk.mcic = 0x00400f1d40330000, + .u.mchk.mcic = 0x00400f1d40330000ULL, }; kvm_s390_floating_interrupt(&irq); } @@ -1306,3 +1319,46 @@ int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, } return kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick); } + +int kvm_s390_get_memslot_count(KVMState *s) +{ + return kvm_check_extension(s, KVM_CAP_NR_MEMSLOTS); +} + +int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state) +{ + struct kvm_mp_state mp_state = {}; + int ret; + + /* the kvm part might not have been initialized yet */ + if (CPU(cpu)->kvm_state == NULL) { + return 0; + } + + switch (cpu_state) { + case CPU_STATE_STOPPED: + mp_state.mp_state = KVM_MP_STATE_STOPPED; + break; + case CPU_STATE_CHECK_STOP: + mp_state.mp_state = KVM_MP_STATE_CHECK_STOP; + break; + case CPU_STATE_OPERATING: + mp_state.mp_state = KVM_MP_STATE_OPERATING; + break; + case CPU_STATE_LOAD: + mp_state.mp_state = KVM_MP_STATE_LOAD; + break; + default: + error_report("Requested CPU state is not a valid S390 CPU state: %u", + cpu_state); + exit(1); + } + + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MP_STATE, &mp_state); + if (ret) { + trace_kvm_failed_cpu_state_set(CPU(cpu)->cpu_index, cpu_state, + strerror(-ret)); + } + + return ret; +} diff --git a/target-s390x/machine.c b/target-s390x/machine.c new file mode 100644 index 000000000..fbcb0d086 --- /dev/null +++ b/target-s390x/machine.c @@ -0,0 +1,76 @@ +/* + * S390x machine definitions and functions + * + * Copyright IBM Corp. 2014 + * + * Authors: + * Thomas Huth <thuth@linux.vnet.ibm.com> + * Christian Borntraeger <borntraeger@de.ibm.com> + * Jason J. Herne <jjherne@us.ibm.com> + * + * This work is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + */ + +#include "hw/hw.h" +#include "cpu.h" +#include "sysemu/kvm.h" + +static int cpu_post_load(void *opaque, int version_id) +{ + S390CPU *cpu = opaque; + + /* + * As the cpu state is pushed to kvm via kvm_set_mp_state rather + * than via cpu_synchronize_state, we need update kvm here. + */ + if (kvm_enabled()) { + kvm_s390_set_cpu_state(cpu, cpu->env.cpu_state); + } + + return 0; +} + +const VMStateDescription vmstate_s390_cpu = { + .name = "cpu", + .post_load = cpu_post_load, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(env.fregs[0].ll, S390CPU), + VMSTATE_UINT64(env.fregs[1].ll, S390CPU), + VMSTATE_UINT64(env.fregs[2].ll, S390CPU), + VMSTATE_UINT64(env.fregs[3].ll, S390CPU), + VMSTATE_UINT64(env.fregs[4].ll, S390CPU), + VMSTATE_UINT64(env.fregs[5].ll, S390CPU), + VMSTATE_UINT64(env.fregs[6].ll, S390CPU), + VMSTATE_UINT64(env.fregs[7].ll, S390CPU), + VMSTATE_UINT64(env.fregs[8].ll, S390CPU), + VMSTATE_UINT64(env.fregs[9].ll, S390CPU), + VMSTATE_UINT64(env.fregs[10].ll, S390CPU), + VMSTATE_UINT64(env.fregs[11].ll, S390CPU), + VMSTATE_UINT64(env.fregs[12].ll, S390CPU), + VMSTATE_UINT64(env.fregs[13].ll, S390CPU), + VMSTATE_UINT64(env.fregs[14].ll, S390CPU), + VMSTATE_UINT64(env.fregs[15].ll, S390CPU), + VMSTATE_UINT64_ARRAY(env.regs, S390CPU, 16), + VMSTATE_UINT64(env.psw.mask, S390CPU), + VMSTATE_UINT64(env.psw.addr, S390CPU), + VMSTATE_UINT64(env.psa, S390CPU), + VMSTATE_UINT32(env.fpc, S390CPU), + VMSTATE_UINT32(env.todpr, S390CPU), + VMSTATE_UINT64(env.pfault_token, S390CPU), + VMSTATE_UINT64(env.pfault_compare, S390CPU), + VMSTATE_UINT64(env.pfault_select, S390CPU), + VMSTATE_UINT64(env.cputm, S390CPU), + VMSTATE_UINT64(env.ckc, S390CPU), + VMSTATE_UINT64(env.gbea, S390CPU), + VMSTATE_UINT64(env.pp, S390CPU), + VMSTATE_UINT32_ARRAY(env.aregs, S390CPU, 16), + VMSTATE_UINT64_ARRAY(env.cregs, S390CPU, 16), + VMSTATE_UINT8(env.cpu_state, S390CPU), + VMSTATE_END_OF_LIST() + }, +}; diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 0b625826e..ef9758a96 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -114,33 +114,16 @@ uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2) } #ifndef CONFIG_USER_ONLY -static void cpu_reset_all(void) -{ - CPUState *cs; - S390CPUClass *scc; - - CPU_FOREACH(cs) { - scc = S390_CPU_GET_CLASS(cs); - scc->cpu_reset(cs); - } -} - -static void cpu_full_reset_all(void) -{ - CPUState *cpu; - - CPU_FOREACH(cpu) { - cpu_reset(cpu); - } -} - static int modified_clear_reset(S390CPU *cpu) { S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); + CPUState *t; pause_all_vcpus(); cpu_synchronize_all_states(); - cpu_full_reset_all(); + CPU_FOREACH(t) { + run_on_cpu(t, s390_do_cpu_full_reset, t); + } cmma_reset(cpu); io_subsystem_reset(); scc->load_normal(CPU(cpu)); @@ -152,10 +135,13 @@ static int modified_clear_reset(S390CPU *cpu) static int load_normal_reset(S390CPU *cpu) { S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); + CPUState *t; pause_all_vcpus(); cpu_synchronize_all_states(); - cpu_reset_all(); + CPU_FOREACH(t) { + run_on_cpu(t, s390_do_cpu_reset, t); + } cmma_reset(cpu); io_subsystem_reset(); scc->initial_cpu_reset(CPU(cpu)); diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e2a1d05f1..dbf1993d4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -42,6 +42,8 @@ static TCGv_ptr cpu_env; #include "exec/helper-proto.h" #include "exec/helper-gen.h" +#include "trace-tcg.h" + /* Information that (most) every instruction needs to manipulate. */ typedef struct DisasContext DisasContext; @@ -2923,6 +2925,18 @@ static ExitStatus op_sacf(DisasContext *s, DisasOps *o) /* Addressing mode has changed, so end the block. */ return EXIT_PC_STALE; } + +static ExitStatus op_sam(DisasContext *s, DisasOps *o) +{ + int sam = s->insn->data; + TCGv_i64 tsam = tcg_const_i64(sam); + + /* Overwrite PSW_MASK_64 and PSW_MASK_32 */ + tcg_gen_deposit_i64(psw_mask, psw_mask, tsam, 31, 2); + + tcg_temp_free_i64(tsam); + return EXIT_PC_STALE; +} #endif static ExitStatus op_sar(DisasContext *s, DisasOps *o) |