summaryrefslogtreecommitdiffstats
path: root/qemu/target-s390x
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/target-s390x')
-rw-r--r--qemu/target-s390x/arch_dump.c7
-rw-r--r--qemu/target-s390x/cc_helper.c3
-rw-r--r--qemu/target-s390x/cpu-qom.h5
-rw-r--r--qemu/target-s390x/cpu.c119
-rw-r--r--qemu/target-s390x/cpu.h85
-rw-r--r--qemu/target-s390x/fpu_helper.c1
-rw-r--r--qemu/target-s390x/gdbstub.c123
-rw-r--r--qemu/target-s390x/helper.c52
-rw-r--r--qemu/target-s390x/int_helper.c1
-rw-r--r--qemu/target-s390x/interrupt.c12
-rw-r--r--qemu/target-s390x/ioinst.c6
-rw-r--r--qemu/target-s390x/kvm.c79
-rw-r--r--qemu/target-s390x/machine.c5
-rw-r--r--qemu/target-s390x/mem_helper.c51
-rw-r--r--qemu/target-s390x/misc_helper.c20
-rw-r--r--qemu/target-s390x/mmu_helper.c33
-rw-r--r--qemu/target-s390x/translate.c137
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;
}