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:
Andreas Färber 2013-05-27 06:49:53 +02:00
parent ce927ed9e4
commit c658b94f6e
16 changed files with 124 additions and 45 deletions

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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,

View File

@ -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);
}

View File

@ -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. */

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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 = {

View File

@ -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);

View File

@ -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 */

View File

@ -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 = {

View File

@ -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);

View File

@ -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);