Use it for all targets, but be careful not to pass invalid CPUState.
cpu_single_env can be NULL, e.g. on Xen.
Signed-off-by: Andreas Färber <afaerber@suse.de>
pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK;
mr = iotlb_to_region(pd);
if (memory_region_is_unassigned(mr)) {
-#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SPARC)
- cpu_unassigned_access(env1, addr, 0, 1, 0, 4);
-#else
- cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x"
- TARGET_FMT_lx "\n", addr);
-#endif
+ CPUState *cpu = ENV_GET_CPU(env1);
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+
+ if (cc->do_unassigned_access) {
+ cc->do_unassigned_access(cpu, addr, false, true, 0, 4);
+ } else {
+ cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x"
+ TARGET_FMT_lx "\n", addr);
+ }
}
p = (void *)((uintptr_t)addr + env1->tlb_table[mmu_idx][page_index].addend);
return qemu_ram_addr_from_host_nofail(p);
break;
default:
- cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size);
+ cpu = CPU(alpha_env_get_cpu(cpu_single_env));
+ cpu_unassigned_access(cpu, addr, false, false, 0, size);
return -1;
}
static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size)
{
TyphoonState *s = opaque;
+ CPUState *cs;
uint64_t ret = 0;
if (addr & 4) {
break;
default:
- cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size);
+ cs = CPU(alpha_env_get_cpu(cpu_single_env));
+ cpu_unassigned_access(cs, addr, false, false, 0, size);
return -1;
}
uint64_t v32, unsigned size)
{
TyphoonState *s = opaque;
+ CPUState *cpu_single_cpu = CPU(alpha_env_get_cpu(cpu_single_env));
uint64_t val, oldval, newval;
if (addr & 4) {
break;
default:
- cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size);
+ cpu_unassigned_access(cpu_single_cpu, addr, true, false, 0, size);
return;
}
}
uint64_t v32, unsigned size)
{
TyphoonState *s = opaque;
+ CPUState *cs;
uint64_t val, oldval;
if (addr & 4) {
break;
default:
- cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size);
+ cs = CPU(alpha_env_get_cpu(cpu_single_env));
+ cpu_unassigned_access(cs, addr, true, false, 0, size);
return;
}
}
#include <signal.h>
#include "hw/qdev-core.h"
+#include "exec/hwaddr.h"
#include "qemu/thread.h"
#include "qemu/typedefs.h"
typedef struct CPUState CPUState;
+typedef void (*CPUUnassignedAccess)(CPUState *cpu, hwaddr addr,
+ bool is_write, bool is_exec, int opaque,
+ unsigned size);
+
/**
* CPUClass:
* @class_by_name: Callback to map -cpu command line model name to an
* instantiatable CPU type.
* @reset: Callback to reset the #CPUState to its initial state.
* @do_interrupt: Callback for interrupt handling.
+ * @do_unassigned_access: Callback for unassigned access handling.
* @dump_state: Callback for dumping state.
* @dump_statistics: Callback for dumping statistics.
* @get_arch_id: Callback for getting architecture-dependent CPU ID.
void (*reset)(CPUState *cpu);
void (*do_interrupt)(CPUState *cpu);
+ CPUUnassignedAccess do_unassigned_access;
void (*dump_state)(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags);
void (*dump_statistics)(CPUState *cpu, FILE *f,
#define cpu_class_set_vmsd(cc, value) ((cc)->vmsd = NULL)
#endif
+#ifndef CONFIG_USER_ONLY
+static inline void cpu_class_set_do_unassigned_access(CPUClass *cc,
+ CPUUnassignedAccess value)
+{
+ cc->do_unassigned_access = value;
+}
+#else
+#define cpu_class_set_do_unassigned_access(cc, value) \
+ ((cc)->do_unassigned_access = NULL)
+#endif
+
/**
* device_class_set_vmsd:
* @dc: Device class
#endif /* USER_ONLY */
+#ifndef CONFIG_USER_ONLY
+
+static inline void cpu_unassigned_access(CPUState *cpu, hwaddr addr,
+ bool is_write, bool is_exec,
+ int opaque, unsigned size)
+{
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+
+ if (cc->do_unassigned_access) {
+ cc->do_unassigned_access(cpu, addr, is_write, is_exec, opaque, size);
+ }
+}
+
+#endif
+
/**
* cpu_reset_interrupt:
* @cpu: The CPU to clear the interrupt on.
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
#endif
-#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
- cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size);
-#endif
+ if (cpu_single_env != NULL) {
+ cpu_unassigned_access(ENV_GET_CPU(cpu_single_env),
+ addr, false, false, 0, size);
+ }
return 0;
}
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem write " TARGET_FMT_plx " = 0x%"PRIx64"\n", addr, val);
#endif
-#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
- cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size);
-#endif
+ if (cpu_single_env != NULL) {
+ cpu_unassigned_access(ENV_GET_CPU(cpu_single_env),
+ addr, true, false, 0, size);
+ }
}
static bool unassigned_mem_accepts(void *opaque, hwaddr addr,
cc->class_by_name = alpha_cpu_class_by_name;
cc->do_interrupt = alpha_cpu_do_interrupt;
cc->dump_state = alpha_cpu_dump_state;
+ cpu_class_set_do_unassigned_access(cc, alpha_cpu_unassigned_access);
device_class_set_vmsd(dc, &vmstate_alpha_cpu);
}
void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val);
#ifndef CONFIG_USER_ONLY
void swap_shadow_regs(CPUAlphaState *env);
-QEMU_NORETURN void cpu_unassigned_access(CPUAlphaState *env1,
- hwaddr addr, int is_write,
- int is_exec, int unused, int size);
+QEMU_NORETURN void alpha_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
+ bool is_write, bool is_exec,
+ int unused, unsigned size);
#endif
/* Bits in TB->FLAGS that control how translation is processed. */
cpu_loop_exit(env);
}
-void cpu_unassigned_access(CPUAlphaState *env, hwaddr addr,
- int is_write, int is_exec, int unused, int size)
+void alpha_cpu_unassigned_access(CPUState *cs, hwaddr addr,
+ bool is_write, bool is_exec, int unused,
+ unsigned size)
{
+ AlphaCPU *cpu = ALPHA_CPU(cs);
+ CPUAlphaState *env = &cpu->env;
+
env->trap_arg0 = addr;
- env->trap_arg1 = is_write;
+ env->trap_arg1 = is_write ? 1 : 0;
dynamic_excp(env, 0, EXCP_MCHK, 0);
}
cc->do_interrupt = mb_cpu_do_interrupt;
cc->dump_state = mb_cpu_dump_state;
+ cpu_class_set_do_unassigned_access(cc, mb_cpu_unassigned_access);
dc->vmsd = &vmstate_mb_cpu;
-
dc->props = mb_properties;
}
}
#if !defined(CONFIG_USER_ONLY)
-void cpu_unassigned_access(CPUMBState *env1, hwaddr addr,
- int is_write, int is_exec, int is_asi, int size);
+void mb_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
+ bool is_write, bool is_exec, int is_asi,
+ unsigned size);
#endif
static inline bool cpu_has_work(CPUState *cpu)
mmu_write(env, rn, v);
}
-void cpu_unassigned_access(CPUMBState *env, hwaddr addr,
- int is_write, int is_exec, int is_asi, int size)
+void mb_cpu_unassigned_access(CPUState *cs, hwaddr addr,
+ bool is_write, bool is_exec, int is_asi,
+ unsigned size)
{
+ MicroBlazeCPU *cpu;
+ CPUMBState *env;
+
qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n",
- addr, is_write, is_exec);
- if (!env || !(env->sregs[SR_MSR] & MSR_EE)) {
+ addr, is_write ? 1 : 0, is_exec ? 1 : 0);
+ if (cs == NULL) {
+ return;
+ }
+ cpu = MICROBLAZE_CPU(cs);
+ env = &cpu->env;
+ if (!(env->sregs[SR_MSR] & MSR_EE)) {
return;
}
cc->do_interrupt = mips_cpu_do_interrupt;
cc->dump_state = mips_cpu_dump_state;
+ cpu_class_set_do_unassigned_access(cc, mips_cpu_unassigned_access);
}
static const TypeInfo mips_cpu_type_info = {
void r4k_helper_tlbp(CPUMIPSState *env);
void r4k_helper_tlbr(CPUMIPSState *env);
-void cpu_unassigned_access(CPUMIPSState *env, hwaddr addr,
- int is_write, int is_exec, int unused, int size);
+void mips_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
+ bool is_write, bool is_exec, int unused,
+ unsigned size);
#endif
void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf);
}
}
-void cpu_unassigned_access(CPUMIPSState *env, hwaddr addr,
- int is_write, int is_exec, int unused, int size)
+void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
+ bool is_write, bool is_exec, int unused,
+ unsigned size)
{
- if (is_exec)
+ MIPSCPU *cpu = MIPS_CPU(cs);
+ CPUMIPSState *env = &cpu->env;
+
+ if (is_exec) {
helper_raise_exception(env, EXCP_IBE);
- else
+ } else {
helper_raise_exception(env, EXCP_DBE);
+ }
}
#endif /* !CONFIG_USER_ONLY */
cc->do_interrupt = sparc_cpu_do_interrupt;
cc->dump_state = sparc_cpu_dump_state;
+ cpu_class_set_do_unassigned_access(cc, sparc_cpu_unassigned_access);
}
static const TypeInfo sparc_cpu_type_info = {
/* cpu-exec.c */
#if !defined(CONFIG_USER_ONLY)
-void cpu_unassigned_access(CPUSPARCState *env1, hwaddr addr,
- int is_write, int is_exec, int is_asi, int size);
+void sparc_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
+ bool is_write, bool is_exec, int is_asi,
+ unsigned size);
#if defined(TARGET_SPARC64)
hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr,
int mmu_idx);
break;
case 8: /* User code access, XXX */
default:
- cpu_unassigned_access(env, addr, 0, 0, asi, size);
+ cpu_unassigned_access(CPU(sparc_env_get_cpu(env)),
+ addr, false, false, asi, size);
ret = 0;
break;
}
case 8: /* User code access, XXX */
case 9: /* Supervisor code access, XXX */
default:
- cpu_unassigned_access(env, addr, 1, 0, asi, size);
+ cpu_unassigned_access(CPU(sparc_env_get_cpu(env)),
+ addr, true, false, asi, size);
break;
}
#ifdef DEBUG_ASI
case 0x5f: /* D-MMU demap, WO */
case 0x77: /* Interrupt vector, WO */
default:
- cpu_unassigned_access(env, addr, 0, 0, 1, size);
+ cpu_unassigned_access(CPU(sparc_env_get_cpu(env)),
+ addr, false, false, 1, size);
ret = 0;
break;
}
case 0x8a: /* Primary no-fault LE, RO */
case 0x8b: /* Secondary no-fault LE, RO */
default:
- cpu_unassigned_access(env, addr, 1, 0, 1, size);
+ cpu_unassigned_access(CPU(sparc_env_get_cpu(env)),
+ addr, true, false, 1, size);
return;
}
}
#if !defined(CONFIG_USER_ONLY)
#ifndef TARGET_SPARC64
-void cpu_unassigned_access(CPUSPARCState *env, hwaddr addr,
- int is_write, int is_exec, int is_asi, int size)
+void sparc_cpu_unassigned_access(CPUState *cs, hwaddr addr,
+ bool is_write, bool is_exec, int is_asi,
+ unsigned size)
{
+ SPARCCPU *cpu = SPARC_CPU(cs);
+ CPUSPARCState *env = &cpu->env;
int fault_type;
#ifdef DEBUG_UNASSIGNED
}
}
#else
-void cpu_unassigned_access(CPUSPARCState *env, hwaddr addr,
- int is_write, int is_exec, int is_asi, int size)
+void sparc_cpu_unassigned_access(CPUState *cs, hwaddr addr,
+ bool is_write, bool is_exec, int is_asi,
+ unsigned size)
{
+ SPARCCPU *cpu = SPARC_CPU(cs);
+ CPUSPARCState *env = &cpu->env;
+
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
"\n", addr, env->pc);