cpu: Turn cpu_unassigned_access() into a CPUState hook
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>
This commit is contained in:
parent
ce927ed9e4
commit
c658b94f6e
15
cputlb.c
15
cputlb.c
@ -331,12 +331,15 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
|
||||
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);
|
||||
|
@ -197,7 +197,8 @@ static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -214,6 +215,7 @@ static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
|
||||
static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
TyphoonState *s = opaque;
|
||||
CPUState *cs;
|
||||
uint64_t ret = 0;
|
||||
|
||||
if (addr & 4) {
|
||||
@ -300,7 +302,8 @@ static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -312,6 +315,7 @@ static void cchip_write(void *opaque, hwaddr addr,
|
||||
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) {
|
||||
@ -461,7 +465,7 @@ static void cchip_write(void *opaque, hwaddr addr,
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -476,6 +480,7 @@ static void pchip_write(void *opaque, hwaddr addr,
|
||||
uint64_t v32, unsigned size)
|
||||
{
|
||||
TyphoonState *s = opaque;
|
||||
CPUState *cs;
|
||||
uint64_t val, oldval;
|
||||
|
||||
if (addr & 4) {
|
||||
@ -577,7 +582,8 @@ static void pchip_write(void *opaque, hwaddr addr,
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <signal.h>
|
||||
#include "hw/qdev-core.h"
|
||||
#include "exec/hwaddr.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/typedefs.h"
|
||||
|
||||
@ -42,12 +43,17 @@ typedef int (*WriteCoreDumpFunction)(void *buf, size_t size, void *opaque);
|
||||
|
||||
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.
|
||||
@ -66,6 +72,7 @@ typedef struct CPUClass {
|
||||
|
||||
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,
|
||||
@ -280,6 +287,17 @@ static inline void cpu_class_set_vmsd(CPUClass *cc,
|
||||
#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
|
||||
@ -403,6 +421,21 @@ void cpu_interrupt(CPUState *cpu, int mask);
|
||||
|
||||
#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.
|
||||
|
14
memory.c
14
memory.c
@ -855,9 +855,10 @@ static uint64_t unassigned_mem_read(void *opaque, hwaddr addr,
|
||||
#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;
|
||||
}
|
||||
|
||||
@ -867,9 +868,10 @@ static void unassigned_mem_write(void *opaque, hwaddr addr,
|
||||
#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,
|
||||
|
@ -263,6 +263,7 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data)
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -457,9 +457,9 @@ uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env);
|
||||
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. */
|
||||
|
@ -109,11 +109,15 @@ static void do_unaligned_access(CPUAlphaState *env, target_ulong addr,
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -138,8 +138,8 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -367,8 +367,9 @@ static inline void cpu_get_tb_cpu_state(CPUMBState *env, target_ulong *pc,
|
||||
}
|
||||
|
||||
#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)
|
||||
|
@ -495,12 +495,21 @@ void helper_mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,7 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
|
||||
|
||||
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 = {
|
||||
|
@ -493,8 +493,9 @@ void r4k_helper_tlbwr(CPUMIPSState *env);
|
||||
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);
|
||||
|
@ -2147,13 +2147,18 @@ void tlb_fill(CPUMIPSState *env, target_ulong addr, int is_write, int mmu_idx,
|
||||
}
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
|
@ -771,6 +771,7 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
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 = {
|
||||
|
@ -582,8 +582,9 @@ static inline int tlb_compare_context(const SparcTLBEntry *tlb,
|
||||
|
||||
/* 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);
|
||||
|
@ -686,7 +686,8 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
|
||||
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;
|
||||
}
|
||||
@ -1088,7 +1089,8 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
|
||||
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
|
||||
@ -1594,7 +1596,8 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
|
||||
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;
|
||||
}
|
||||
@ -2027,7 +2030,8 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -2322,9 +2326,12 @@ void helper_stqf(CPUSPARCState *env, target_ulong addr, int mem_idx)
|
||||
|
||||
#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
|
||||
@ -2382,9 +2389,13 @@ void cpu_unassigned_access(CPUSPARCState *env, hwaddr addr,
|
||||
}
|
||||
}
|
||||
#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);
|
||||
|
Loading…
Reference in New Issue
Block a user