aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/alpha/translate.c1
-rw-r--r--target/arm/cpu.h4
-rw-r--r--target/arm/helper.c81
-rw-r--r--target/i386/cpu.c21
-rw-r--r--target/i386/cpu.h6
-rw-r--r--target/i386/kvm.c29
-rw-r--r--target/i386/seg_helper.c20
-rw-r--r--target/i386/svm_helper.c22
-rw-r--r--target/mips/op_helper.c21
-rw-r--r--target/nios2/op_helper.c3
-rw-r--r--target/ppc/cpu.h2
-rw-r--r--target/ppc/translate.c2
-rw-r--r--target/s390x/Makefile.objs2
-rw-r--r--target/s390x/misc_helper.c21
-rw-r--r--target/sparc/int64_helper.c3
-rw-r--r--target/sparc/win_helper.c13
-rw-r--r--target/xtensa/helper.c1
-rw-r--r--target/xtensa/op_helper.c7
18 files changed, 223 insertions, 36 deletions
diff --git a/target/alpha/translate.c b/target/alpha/translate.c
index 055286a7b8..df5d695344 100644
--- a/target/alpha/translate.c
+++ b/target/alpha/translate.c
@@ -19,6 +19,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
+#include "sysemu/cpus.h"
#include "disas/disas.h"
#include "qemu/host-utils.h"
#include "exec/exec-all.h"
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 25ceaabb5d..a8aabce7dd 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -536,8 +536,8 @@ typedef void ARMELChangeHook(ARMCPU *cpu, void *opaque);
/* These values map onto the return values for
* QEMU_PSCI_0_2_FN_AFFINITY_INFO */
typedef enum ARMPSCIState {
- PSCI_OFF = 0,
- PSCI_ON = 1,
+ PSCI_ON = 0,
+ PSCI_OFF = 1,
PSCI_ON_PENDING = 2
} ARMPSCIState;
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 3f4211b572..8646a7a119 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -885,7 +885,7 @@ static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri,
*/
int el = arm_current_el(env);
- if (el == 0 && !env->cp15.c9_pmuserenr) {
+ if (el == 0 && !(env->cp15.c9_pmuserenr & 1)) {
return CP_ACCESS_TRAP;
}
if (el < 2 && (env->cp15.mdcr_el2 & MDCR_TPM)
@@ -899,8 +899,67 @@ static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri,
return CP_ACCESS_OK;
}
+static CPAccessResult pmreg_access_xevcntr(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ bool isread)
+{
+ /* ER: event counter read trap control */
+ if (arm_feature(env, ARM_FEATURE_V8)
+ && arm_current_el(env) == 0
+ && (env->cp15.c9_pmuserenr & (1 << 3)) != 0
+ && isread) {
+ return CP_ACCESS_OK;
+ }
+
+ return pmreg_access(env, ri, isread);
+}
+
+static CPAccessResult pmreg_access_swinc(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ bool isread)
+{
+ /* SW: software increment write trap control */
+ if (arm_feature(env, ARM_FEATURE_V8)
+ && arm_current_el(env) == 0
+ && (env->cp15.c9_pmuserenr & (1 << 1)) != 0
+ && !isread) {
+ return CP_ACCESS_OK;
+ }
+
+ return pmreg_access(env, ri, isread);
+}
+
#ifndef CONFIG_USER_ONLY
+static CPAccessResult pmreg_access_selr(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ bool isread)
+{
+ /* ER: event counter read trap control */
+ if (arm_feature(env, ARM_FEATURE_V8)
+ && arm_current_el(env) == 0
+ && (env->cp15.c9_pmuserenr & (1 << 3)) != 0) {
+ return CP_ACCESS_OK;
+ }
+
+ return pmreg_access(env, ri, isread);
+}
+
+static CPAccessResult pmreg_access_ccntr(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ bool isread)
+{
+ /* CR: cycle counter read trap control */
+ if (arm_feature(env, ARM_FEATURE_V8)
+ && arm_current_el(env) == 0
+ && (env->cp15.c9_pmuserenr & (1 << 2)) != 0
+ && isread) {
+ return CP_ACCESS_OK;
+ }
+
+ return pmreg_access(env, ri, isread);
+}
+
static inline bool arm_ccnt_enabled(CPUARMState *env)
{
/* This does not support checking PMCCFILTR_EL0 register */
@@ -1068,7 +1127,11 @@ static uint64_t pmxevtyper_read(CPUARMState *env, const ARMCPRegInfo *ri)
static void pmuserenr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
- env->cp15.c9_pmuserenr = value & 1;
+ if (arm_feature(env, ARM_FEATURE_V8)) {
+ env->cp15.c9_pmuserenr = value & 0xf;
+ } else {
+ env->cp15.c9_pmuserenr = value & 1;
+ }
}
static void pmintenset_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -1212,25 +1275,25 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
.raw_writefn = raw_write },
/* Unimplemented so WI. */
{ .name = "PMSWINC", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 4,
- .access = PL0_W, .accessfn = pmreg_access, .type = ARM_CP_NOP },
+ .access = PL0_W, .accessfn = pmreg_access_swinc, .type = ARM_CP_NOP },
#ifndef CONFIG_USER_ONLY
{ .name = "PMSELR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 5,
.access = PL0_RW, .type = ARM_CP_ALIAS,
.fieldoffset = offsetoflow32(CPUARMState, cp15.c9_pmselr),
- .accessfn = pmreg_access, .writefn = pmselr_write,
+ .accessfn = pmreg_access_selr, .writefn = pmselr_write,
.raw_writefn = raw_write},
{ .name = "PMSELR_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 5,
- .access = PL0_RW, .accessfn = pmreg_access,
+ .access = PL0_RW, .accessfn = pmreg_access_selr,
.fieldoffset = offsetof(CPUARMState, cp15.c9_pmselr),
.writefn = pmselr_write, .raw_writefn = raw_write, },
{ .name = "PMCCNTR", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 0,
.access = PL0_RW, .resetvalue = 0, .type = ARM_CP_IO,
.readfn = pmccntr_read, .writefn = pmccntr_write32,
- .accessfn = pmreg_access },
+ .accessfn = pmreg_access_ccntr },
{ .name = "PMCCNTR_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 9, .crm = 13, .opc2 = 0,
- .access = PL0_RW, .accessfn = pmreg_access,
+ .access = PL0_RW, .accessfn = pmreg_access_ccntr,
.type = ARM_CP_IO,
.readfn = pmccntr_read, .writefn = pmccntr_write, },
#endif
@@ -1251,7 +1314,7 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
/* Unimplemented, RAZ/WI. */
{ .name = "PMXEVCNTR", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 2,
.access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0,
- .accessfn = pmreg_access },
+ .accessfn = pmreg_access_xevcntr },
{ .name = "PMUSERENR", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 0,
.access = PL0_R | PL1_RW, .accessfn = access_tpm,
.fieldoffset = offsetof(CPUARMState, cp15.c9_pmuserenr),
@@ -6857,7 +6920,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
new_el);
if (qemu_loglevel_mask(CPU_LOG_INT)
&& !excp_is_internal(cs->exception_index)) {
- qemu_log_mask(CPU_LOG_INT, "...with ESR %x/0x%" PRIx32 "\n",
+ qemu_log_mask(CPU_LOG_INT, "...with ESR 0x%x/0x%" PRIx32 "\n",
env->exception.syndrome >> ARM_EL_EC_SHIFT,
env->exception.syndrome);
}
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index fba92125ab..7aa762245a 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -688,6 +688,25 @@ void host_cpuid(uint32_t function, uint32_t count,
*edx = vec[3];
}
+void host_vendor_fms(char *vendor, int *family, int *model, int *stepping)
+{
+ uint32_t eax, ebx, ecx, edx;
+
+ host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
+ x86_cpu_vendor_words2str(vendor, ebx, edx, ecx);
+
+ host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
+ if (family) {
+ *family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
+ }
+ if (model) {
+ *model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
+ }
+ if (stepping) {
+ *stepping = eax & 0x0F;
+ }
+}
+
/* CPU class name definitions: */
#define X86_CPU_TYPE_SUFFIX "-" TYPE_X86_CPU
@@ -1177,7 +1196,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 60,
- .stepping = 1,
+ .stepping = 4,
.features[FEAT_1_EDX] =
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index ac2ad6d443..07401ad9fe 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -30,6 +30,9 @@
#define TARGET_LONG_BITS 32
#endif
+/* The x86 has a strong memory model with some store-after-load re-ordering */
+#define TCG_GUEST_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
+
/* Maximum instruction code size */
#define TARGET_MAX_INSN_SIZE 16
@@ -694,6 +697,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
#define EXCP_SYSCALL 0x100 /* only happens in user only emulation
for syscall instruction */
+#define EXCP_VMEXIT 0x100
/* i386-specific interrupt pending bits. */
#define CPU_INTERRUPT_POLL CPU_INTERRUPT_TGT_EXT_1
@@ -1436,6 +1440,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
void cpu_clear_apic_feature(CPUX86State *env);
void host_cpuid(uint32_t function, uint32_t count,
uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
+void host_vendor_fms(char *vendor, int *family, int *model, int *stepping);
/* helper.c */
int x86_cpu_handle_mmu_fault(CPUState *cpu, vaddr addr,
@@ -1629,6 +1634,7 @@ void cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type,
uint64_t param, uintptr_t retaddr);
void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1,
uintptr_t retaddr);
+void do_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1);
/* seg_helper.c */
void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw);
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index 887a81268f..55865dbee0 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -266,6 +266,19 @@ static int get_para_features(KVMState *s)
return features;
}
+static bool host_tsx_blacklisted(void)
+{
+ int family, model, stepping;\
+ char vendor[CPUID_VENDOR_SZ + 1];
+
+ host_vendor_fms(vendor, &family, &model, &stepping);
+
+ /* Check if we are running on a Haswell host known to have broken TSX */
+ return !strcmp(vendor, CPUID_VENDOR_INTEL) &&
+ (family == 6) &&
+ ((model == 63 && stepping < 4) ||
+ model == 60 || model == 69 || model == 70);
+}
/* Returns the value for a specific register on the cpuid entry
*/
@@ -349,6 +362,10 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function,
}
} else if (function == 6 && reg == R_EAX) {
ret |= CPUID_6_EAX_ARAT; /* safe to allow because of emulated APIC */
+ } else if (function == 7 && index == 0 && reg == R_EBX) {
+ if (host_tsx_blacklisted()) {
+ ret &= ~(CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_HLE);
+ }
} else if (function == 0x80000001 && reg == R_EDX) {
/* On Intel, kvm returns cpuid according to the Intel spec,
* so add missing bits according to the AMD spec:
@@ -1807,6 +1824,12 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
return ret;
}
+ if (ret < cpu->kvm_msr_buf->nmsrs) {
+ struct kvm_msr_entry *e = &cpu->kvm_msr_buf->entries[ret];
+ error_report("error: failed to set MSR 0x%" PRIx32 " to 0x%" PRIx64,
+ (uint32_t)e->index, (uint64_t)e->data);
+ }
+
assert(ret == cpu->kvm_msr_buf->nmsrs);
return 0;
}
@@ -2172,6 +2195,12 @@ static int kvm_get_msrs(X86CPU *cpu)
return ret;
}
+ if (ret < cpu->kvm_msr_buf->nmsrs) {
+ struct kvm_msr_entry *e = &cpu->kvm_msr_buf->entries[ret];
+ error_report("error: failed to get MSR 0x%" PRIx32,
+ (uint32_t)e->index);
+ }
+
assert(ret == cpu->kvm_msr_buf->nmsrs);
/*
* MTRR masks: Each mask consists of 5 parts
diff --git a/target/i386/seg_helper.c b/target/i386/seg_helper.c
index 5c845dc25c..0374031ea2 100644
--- a/target/i386/seg_helper.c
+++ b/target/i386/seg_helper.c
@@ -1297,15 +1297,17 @@ void x86_cpu_do_interrupt(CPUState *cs)
/* successfully delivered */
env->old_exception = -1;
#else
- /* simulate a real cpu exception. On i386, it can
- trigger new exceptions, but we do not handle
- double or triple faults yet. */
- do_interrupt_all(cpu, cs->exception_index,
- env->exception_is_int,
- env->error_code,
- env->exception_next_eip, 0);
- /* successfully delivered */
- env->old_exception = -1;
+ if (cs->exception_index >= EXCP_VMEXIT) {
+ assert(env->old_exception == -1);
+ do_vmexit(env, cs->exception_index - EXCP_VMEXIT, env->error_code);
+ } else {
+ do_interrupt_all(cpu, cs->exception_index,
+ env->exception_is_int,
+ env->error_code,
+ env->exception_next_eip, 0);
+ /* successfully delivered */
+ env->old_exception = -1;
+ }
#endif
}
diff --git a/target/i386/svm_helper.c b/target/i386/svm_helper.c
index 78d8df4af6..59e8b5091c 100644
--- a/target/i386/svm_helper.c
+++ b/target/i386/svm_helper.c
@@ -580,12 +580,10 @@ void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
}
}
-/* Note: currently only 32 bits of exit_code are used */
void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1,
uintptr_t retaddr)
{
CPUState *cs = CPU(x86_env_get_cpu(env));
- uint32_t int_ctl;
if (retaddr) {
cpu_restore_state(cs, retaddr);
@@ -598,6 +596,19 @@ void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1,
control.exit_info_2)),
env->eip);
+ cs->exception_index = EXCP_VMEXIT + exit_code;
+ env->error_code = exit_info_1;
+
+ /* remove any pending exception */
+ env->old_exception = -1;
+ cpu_loop_exit(cs);
+}
+
+void do_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
+{
+ CPUState *cs = CPU(x86_env_get_cpu(env));
+ uint32_t int_ctl;
+
if (env->hflags & HF_INHIBIT_IRQ_MASK) {
x86_stl_phys(cs,
env->vm_vmcb + offsetof(struct vmcb, control.int_state),
@@ -759,13 +770,6 @@ void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1,
/* If the host's rIP reloaded by #VMEXIT is outside the limit of the
host's code segment or non-canonical (in the case of long mode), a
#GP fault is delivered inside the host. */
-
- /* remove any pending exception */
- cs->exception_index = -1;
- env->error_code = 0;
- env->old_exception = -1;
-
- cpu_loop_exit(cs);
}
#endif
diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c
index b683fcb025..e5f3ea4042 100644
--- a/target/mips/op_helper.c
+++ b/target/mips/op_helper.c
@@ -17,6 +17,7 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
#include "cpu.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
@@ -827,7 +828,11 @@ target_ulong helper_mftc0_tcschefback(CPUMIPSState *env)
target_ulong helper_mfc0_count(CPUMIPSState *env)
{
- return (int32_t)cpu_mips_get_count(env);
+ int32_t count;
+ qemu_mutex_lock_iothread();
+ count = (int32_t) cpu_mips_get_count(env);
+ qemu_mutex_unlock_iothread();
+ return count;
}
target_ulong helper_mftc0_entryhi(CPUMIPSState *env)
@@ -1375,7 +1380,9 @@ void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
{
+ qemu_mutex_lock_iothread();
cpu_mips_store_count(env, arg1);
+ qemu_mutex_unlock_iothread();
}
void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
@@ -1424,7 +1431,9 @@ void helper_mttc0_entryhi(CPUMIPSState *env, target_ulong arg1)
void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1)
{
+ qemu_mutex_lock_iothread();
cpu_mips_store_compare(env, arg1);
+ qemu_mutex_unlock_iothread();
}
void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
@@ -1475,7 +1484,9 @@ void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1)
void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1)
{
+ qemu_mutex_lock_iothread();
cpu_mips_store_cause(env, arg1);
+ qemu_mutex_unlock_iothread();
}
void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1)
@@ -2296,12 +2307,16 @@ target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
target_ulong helper_rdhwr_cc(CPUMIPSState *env)
{
+ int32_t count;
check_hwrena(env, 2, GETPC());
#ifdef CONFIG_USER_ONLY
- return env->CP0_Count;
+ count = env->CP0_Count;
#else
- return (int32_t)cpu_mips_get_count(env);
+ qemu_mutex_lock_iothread();
+ count = (int32_t)cpu_mips_get_count(env);
+ qemu_mutex_unlock_iothread();
#endif
+ return count;
}
target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
diff --git a/target/nios2/op_helper.c b/target/nios2/op_helper.c
index 538853cda7..efb1c489c9 100644
--- a/target/nios2/op_helper.c
+++ b/target/nios2/op_helper.c
@@ -21,6 +21,7 @@
#include "cpu.h"
#include "exec/helper-proto.h"
#include "exec/cpu_ldst.h"
+#include "qemu/main-loop.h"
#if !defined(CONFIG_USER_ONLY)
void helper_mmu_read_debug(CPUNios2State *env, uint32_t rn)
@@ -35,7 +36,9 @@ void helper_mmu_write(CPUNios2State *env, uint32_t rn, uint32_t v)
void helper_check_interrupts(CPUNios2State *env)
{
+ qemu_mutex_lock_iothread();
nios2_check_interrupts(env);
+ qemu_mutex_unlock_iothread();
}
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 7c4a1f50b3..5ee33b3fd3 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1408,7 +1408,7 @@ int ppc_compat_max_threads(PowerPCCPU *cpu);
#define SPR_601_UDECR (0x006)
#define SPR_LR (0x008)
#define SPR_CTR (0x009)
-#define SPR_UAMR (0x00C)
+#define SPR_UAMR (0x00D)
#define SPR_DSCR (0x011)
#define SPR_DSISR (0x012)
#define SPR_DAR (0x013) /* DAE for PowerPC 601 */
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index b6abc60a00..f40b5a1abf 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -818,7 +818,7 @@ static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0,
if (is_isa300(ctx)) {
tcg_gen_extract_tl(cpu_ov32, cpu_ov, 31, 1);
}
- tcg_gen_extract_tl(cpu_ov, cpu_ov, 63, 1);
+ tcg_gen_extract_tl(cpu_ov, cpu_ov, TARGET_LONG_BITS - 1, 1);
}
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
}
diff --git a/target/s390x/Makefile.objs b/target/s390x/Makefile.objs
index c573633bd1..46f6a8c6b6 100644
--- a/target/s390x/Makefile.objs
+++ b/target/s390x/Makefile.objs
@@ -8,7 +8,7 @@ obj-$(CONFIG_KVM) += kvm.o
feat-src = $(SRC_PATH)/target/$(TARGET_BASE_ARCH)/
feat-dst = $(BUILD_DIR)/$(TARGET_DIR)
ifneq ($(MAKECMDGOALS),clean)
-GENERATED_HEADERS += $(feat-dst)gen-features.h
+GENERATED_FILES += $(feat-dst)gen-features.h
endif
$(feat-dst)gen-features.h: $(feat-dst)gen-features.h-timestamp
diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c
index 3cb942e8bb..93b0e61366 100644
--- a/target/s390x/misc_helper.c
+++ b/target/s390x/misc_helper.c
@@ -19,6 +19,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
#include "cpu.h"
#include "exec/memory.h"
#include "qemu/host-utils.h"
@@ -551,61 +552,81 @@ uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
void HELPER(xsch)(CPUS390XState *env, uint64_t r1)
{
S390CPU *cpu = s390_env_get_cpu(env);
+ qemu_mutex_lock_iothread();
ioinst_handle_xsch(cpu, r1);
+ qemu_mutex_unlock_iothread();
}
void HELPER(csch)(CPUS390XState *env, uint64_t r1)
{
S390CPU *cpu = s390_env_get_cpu(env);
+ qemu_mutex_lock_iothread();
ioinst_handle_csch(cpu, r1);
+ qemu_mutex_unlock_iothread();
}
void HELPER(hsch)(CPUS390XState *env, uint64_t r1)
{
S390CPU *cpu = s390_env_get_cpu(env);
+ qemu_mutex_lock_iothread();
ioinst_handle_hsch(cpu, r1);
+ qemu_mutex_unlock_iothread();
}
void HELPER(msch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
S390CPU *cpu = s390_env_get_cpu(env);
+ qemu_mutex_lock_iothread();
ioinst_handle_msch(cpu, r1, inst >> 16);
+ qemu_mutex_unlock_iothread();
}
void HELPER(rchp)(CPUS390XState *env, uint64_t r1)
{
S390CPU *cpu = s390_env_get_cpu(env);
+ qemu_mutex_lock_iothread();
ioinst_handle_rchp(cpu, r1);
+ qemu_mutex_unlock_iothread();
}
void HELPER(rsch)(CPUS390XState *env, uint64_t r1)
{
S390CPU *cpu = s390_env_get_cpu(env);
+ qemu_mutex_lock_iothread();
ioinst_handle_rsch(cpu, r1);
+ qemu_mutex_unlock_iothread();
}
void HELPER(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
S390CPU *cpu = s390_env_get_cpu(env);
+ qemu_mutex_lock_iothread();
ioinst_handle_ssch(cpu, r1, inst >> 16);
+ qemu_mutex_unlock_iothread();
}
void HELPER(stsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
S390CPU *cpu = s390_env_get_cpu(env);
+ qemu_mutex_lock_iothread();
ioinst_handle_stsch(cpu, r1, inst >> 16);
+ qemu_mutex_unlock_iothread();
}
void HELPER(tsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
S390CPU *cpu = s390_env_get_cpu(env);
+ qemu_mutex_lock_iothread();
ioinst_handle_tsch(cpu, r1, inst >> 16);
+ qemu_mutex_unlock_iothread();
}
void HELPER(chsc)(CPUS390XState *env, uint64_t inst)
{
S390CPU *cpu = s390_env_get_cpu(env);
+ qemu_mutex_lock_iothread();
ioinst_handle_chsc(cpu, inst >> 16);
+ qemu_mutex_unlock_iothread();
}
#endif
diff --git a/target/sparc/int64_helper.c b/target/sparc/int64_helper.c
index 605747c93c..f942973c22 100644
--- a/target/sparc/int64_helper.c
+++ b/target/sparc/int64_helper.c
@@ -18,6 +18,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
#include "cpu.h"
#include "exec/helper-proto.h"
#include "exec/log.h"
@@ -208,7 +209,9 @@ static bool do_modify_softint(CPUSPARCState *env, uint32_t value)
env->softint = value;
#if !defined(CONFIG_USER_ONLY)
if (cpu_interrupts_enabled(env)) {
+ qemu_mutex_lock_iothread();
cpu_check_irqs(env);
+ qemu_mutex_unlock_iothread();
}
#endif
return true;
diff --git a/target/sparc/win_helper.c b/target/sparc/win_helper.c
index 71b3dd37e8..154279ecda 100644
--- a/target/sparc/win_helper.c
+++ b/target/sparc/win_helper.c
@@ -18,6 +18,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
@@ -82,6 +83,7 @@ void cpu_put_psr_raw(CPUSPARCState *env, target_ulong val)
#endif
}
+/* Called with BQL held */
void cpu_put_psr(CPUSPARCState *env, target_ulong val)
{
cpu_put_psr_raw(env, val);
@@ -153,7 +155,10 @@ void helper_wrpsr(CPUSPARCState *env, target_ulong new_psr)
if ((new_psr & PSR_CWP) >= env->nwindows) {
cpu_raise_exception_ra(env, TT_ILL_INSN, GETPC());
} else {
+ /* cpu_put_psr may trigger interrupts, hence BQL */
+ qemu_mutex_lock_iothread();
cpu_put_psr(env, new_psr);
+ qemu_mutex_unlock_iothread();
}
}
@@ -368,7 +373,9 @@ void helper_wrpstate(CPUSPARCState *env, target_ulong new_state)
#if !defined(CONFIG_USER_ONLY)
if (cpu_interrupts_enabled(env)) {
+ qemu_mutex_lock_iothread();
cpu_check_irqs(env);
+ qemu_mutex_unlock_iothread();
}
#endif
}
@@ -381,7 +388,9 @@ void helper_wrpil(CPUSPARCState *env, target_ulong new_pil)
env->psrpil = new_pil;
if (cpu_interrupts_enabled(env)) {
+ qemu_mutex_lock_iothread();
cpu_check_irqs(env);
+ qemu_mutex_unlock_iothread();
}
#endif
}
@@ -408,7 +417,9 @@ void helper_done(CPUSPARCState *env)
#if !defined(CONFIG_USER_ONLY)
if (cpu_interrupts_enabled(env)) {
+ qemu_mutex_lock_iothread();
cpu_check_irqs(env);
+ qemu_mutex_unlock_iothread();
}
#endif
}
@@ -435,7 +446,9 @@ void helper_retry(CPUSPARCState *env)
#if !defined(CONFIG_USER_ONLY)
if (cpu_interrupts_enabled(env)) {
+ qemu_mutex_lock_iothread();
cpu_check_irqs(env);
+ qemu_mutex_unlock_iothread();
}
#endif
}
diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c
index c67d715c4b..bcd0b7738d 100644
--- a/target/xtensa/helper.c
+++ b/target/xtensa/helper.c
@@ -217,6 +217,7 @@ static void handle_interrupt(CPUXtensaState *env)
}
}
+/* Called from cpu_handle_interrupt with BQL held */
void xtensa_cpu_do_interrupt(CPUState *cs)
{
XtensaCPU *cpu = XTENSA_CPU(cs);
diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c
index af2723445d..519fbeddd6 100644
--- a/target/xtensa/op_helper.c
+++ b/target/xtensa/op_helper.c
@@ -26,6 +26,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
#include "cpu.h"
#include "exec/helper-proto.h"
#include "qemu/host-utils.h"
@@ -381,7 +382,11 @@ void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel)
env->pc = pc;
env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) |
(intlevel << PS_INTLEVEL_SHIFT);
+
+ qemu_mutex_lock_iothread();
check_interrupts(env);
+ qemu_mutex_unlock_iothread();
+
if (env->pending_irq_level) {
cpu_loop_exit(CPU(xtensa_env_get_cpu(env)));
return;
@@ -426,7 +431,9 @@ void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i)
void HELPER(check_interrupts)(CPUXtensaState *env)
{
+ qemu_mutex_lock_iothread();
check_interrupts(env);
+ qemu_mutex_unlock_iothread();
}
void HELPER(itlb_hit_test)(CPUXtensaState *env, uint32_t vaddr)