libobj-$(TARGET_SPARC) += int32_helper.o
libobj-$(TARGET_SPARC64) += int64_helper.o
libobj-$(TARGET_UNICORE32) += cpu.o
+libobj-$(TARGET_XTENSA) += cpu.o
libobj-$(TARGET_ALPHA) += int_helper.o fpu_helper.o sys_helper.o mem_helper.o
+libobj-$(TARGET_ALPHA) += cpu.o
libobj-y += disas.o
libobj-$(CONFIG_TCI_DIS) += tci-dis.o
obj-arm-y += cadence_ttc.o
obj-arm-y += cadence_gem.o
obj-arm-y += xilinx_zynq.o zynq_slcr.o
+obj-arm-y += arm_gic.o
obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
obj-arm-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
obj-arm-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
obj-xtensa-y += xtensa_lx60.o
obj-xtensa-y += xtensa-semi.o
obj-xtensa-y += core-dc232b.o
+obj-xtensa-y += core-dc233c.o
obj-xtensa-y += core-fsf.o
main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
static struct soundhw soundhw[] = {
#ifdef HAS_AUDIO_CHOICE
-#if defined(TARGET_I386) || defined(TARGET_MIPS)
+#ifdef CONFIG_PCSPK
{
"pcspk",
"PC speaker",
Coroutine base;
GThread *thread;
bool runnable;
+ bool free_on_thread_exit;
CoroutineAction action;
} CoroutineGThread;
-static GCond *coroutine_cond;
static GStaticMutex coroutine_lock = G_STATIC_MUTEX_INIT;
+
+/* GLib 2.31 and beyond deprecated various parts of the thread API,
+ * but the new interfaces are not available in older GLib versions
+ * so we have to cope with both.
+ */
+#if GLIB_CHECK_VERSION(2, 31, 0)
+/* Default zero-initialisation is sufficient for 2.31+ GCond */
+static GCond the_coroutine_cond;
+static GCond *coroutine_cond = &the_coroutine_cond;
+static inline void init_coroutine_cond(void)
+{
+}
+
+/* Awkwardly, the GPrivate API doesn't provide a way to update the
+ * GDestroyNotify handler for the coroutine key dynamically. So instead
+ * we track whether or not the CoroutineGThread should be freed on
+ * thread exit / coroutine key update using the free_on_thread_exit
+ * field.
+ */
+static void coroutine_destroy_notify(gpointer data)
+{
+ CoroutineGThread *co = data;
+ if (co && co->free_on_thread_exit) {
+ g_free(co);
+ }
+}
+
+static GPrivate coroutine_key = G_PRIVATE_INIT(coroutine_destroy_notify);
+
+static inline CoroutineGThread *get_coroutine_key(void)
+{
+ return g_private_get(&coroutine_key);
+}
+
+static inline void set_coroutine_key(CoroutineGThread *co,
+ bool free_on_thread_exit)
+{
+ /* Unlike g_static_private_set() this does not call the GDestroyNotify
+ * if the previous value of the key was NULL. Fortunately we only need
+ * the GDestroyNotify in the non-NULL key case.
+ */
+ co->free_on_thread_exit = free_on_thread_exit;
+ g_private_replace(&coroutine_key, co);
+}
+
+static inline GThread *create_thread(GThreadFunc func, gpointer data)
+{
+ return g_thread_new("coroutine", func, data);
+}
+
+#else
+
+/* Handle older GLib versions */
+static GCond *coroutine_cond;
+static inline void init_coroutine_cond(void)
+{
+ coroutine_cond = g_cond_new();
+}
+
static GStaticPrivate coroutine_key = G_STATIC_PRIVATE_INIT;
+static inline CoroutineGThread *get_coroutine_key(void)
+{
+ return g_static_private_get(&coroutine_key);
+}
+
+static inline void set_coroutine_key(CoroutineGThread *co,
+ bool free_on_thread_exit)
+{
+ g_static_private_set(&coroutine_key, co,
+ free_on_thread_exit ? (GDestroyNotify)g_free : NULL);
+}
+
+static inline GThread *create_thread(GThreadFunc func, gpointer data)
+{
+ return g_thread_create_full(func, data, 0, TRUE, TRUE,
+ G_THREAD_PRIORITY_NORMAL, NULL);
+}
+
+#endif
+
+
static void __attribute__((constructor)) coroutine_init(void)
{
if (!g_thread_supported()) {
#endif
}
- coroutine_cond = g_cond_new();
+ init_coroutine_cond();
}
static void coroutine_wait_runnable_locked(CoroutineGThread *co)
{
CoroutineGThread *co = opaque;
- g_static_private_set(&coroutine_key, co, NULL);
+ set_coroutine_key(co, false);
coroutine_wait_runnable(co);
co->base.entry(co->base.entry_arg);
qemu_coroutine_switch(&co->base, co->base.caller, COROUTINE_TERMINATE);
CoroutineGThread *co;
co = g_malloc0(sizeof(*co));
- co->thread = g_thread_create_full(coroutine_thread, co, 0, TRUE, TRUE,
- G_THREAD_PRIORITY_NORMAL, NULL);
+ co->thread = create_thread(coroutine_thread, co);
if (!co->thread) {
g_free(co);
return NULL;
Coroutine *qemu_coroutine_self(void)
{
- CoroutineGThread *co = g_static_private_get(&coroutine_key);
-
+ CoroutineGThread *co = get_coroutine_key();
if (!co) {
co = g_malloc0(sizeof(*co));
co->runnable = true;
- g_static_private_set(&coroutine_key, co, (GDestroyNotify)g_free);
+ set_coroutine_key(co, true);
}
return &co->base;
bool qemu_in_coroutine(void)
{
- CoroutineGThread *co = g_static_private_get(&coroutine_key);
+ CoroutineGThread *co = get_coroutine_key();
return co && co->base.caller;
}
#else /* !CONFIG_USER_ONLY */
/* NOTE: we use double casts if pointers and target_ulong have
different sizes */
-#define saddr(x) (uint8_t *)(long)(x)
-#define laddr(x) (uint8_t *)(long)(x)
+#define saddr(x) (uint8_t *)(intptr_t)(x)
+#define laddr(x) (uint8_t *)(intptr_t)(x)
#endif
#define ldub_raw(p) ldub_p(laddr((p)))
#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
-/* ??? These should be the larger of unsigned long and target_ulong. */
-extern unsigned long qemu_real_host_page_size;
-extern unsigned long qemu_host_page_size;
-extern unsigned long qemu_host_page_mask;
+/* ??? These should be the larger of uintptr_t and target_ulong. */
+extern uintptr_t qemu_real_host_page_size;
+extern uintptr_t qemu_host_page_size;
+extern uintptr_t qemu_host_page_mask;
#define HOST_PAGE_ALIGN(addr) (((addr) + qemu_host_page_size - 1) & qemu_host_page_mask)
target_ulong addr_code;
/* Addend to virtual address to get host address. IO accesses
use the corresponding iotlb value. */
- unsigned long addend;
+ uintptr_t addend;
/* padding to get a power of two size */
- uint8_t dummy[(1 << CPU_TLB_ENTRY_BITS) -
- (sizeof(target_ulong) * 3 +
- ((-sizeof(target_ulong) * 3) & (sizeof(unsigned long) - 1)) +
- sizeof(unsigned long))];
+ uint8_t dummy[(1 << CPU_TLB_ENTRY_BITS) -
+ (sizeof(target_ulong) * 3 +
+ ((-sizeof(target_ulong) * 3) & (sizeof(uintptr_t) - 1)) +
+ sizeof(uintptr_t))];
} CPUTLBEntry;
extern int CPUTLBEntry_wrong_size[sizeof(CPUTLBEntry) == (1 << CPU_TLB_ENTRY_BITS) ? 1 : -1];
/* in order to avoid passing too many arguments to the MMIO \
helpers, we store some rarely used information in the CPU \
context) */ \
- unsigned long mem_io_pc; /* host pc at which the memory was \
- accessed */ \
+ uintptr_t mem_io_pc; /* host pc at which the memory was \
+ accessed */ \
target_ulong mem_io_vaddr; /* target virtual addr at which the \
memory was accessed */ \
uint32_t halted; /* Nonzero if the CPU is in suspend state */ \
tb_invalidated_flag = 0;
}
#ifdef CONFIG_DEBUG_EXEC
- qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
- (long)tb->tc_ptr, tb->pc,
+ qemu_log_mask(CPU_LOG_EXEC, "Trace %p [" TARGET_FMT_lx "] %s\n",
+ tb->tc_ptr, tb->pc,
lookup_symbol(tb->pc));
#endif
/* see if we can patch the calling TB. When the TB
/* Disassemble this for me please... (debugging). */
void disas(FILE *out, void *code, unsigned long size)
{
- unsigned long pc;
+ uintptr_t pc;
int count;
struct disassemble_info disasm_info;
int (*print_insn)(bfd_vma pc, disassemble_info *info);
INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
disasm_info.buffer = code;
- disasm_info.buffer_vma = (unsigned long)code;
+ disasm_info.buffer_vma = (uintptr_t)code;
disasm_info.buffer_length = size;
#ifdef HOST_WORDS_BIGENDIAN
(long) code);
return;
#endif
- for (pc = (unsigned long)code; size > 0; pc += count, size -= count) {
- fprintf(out, "0x%08lx: ", pc);
+ for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
+ fprintf(out, "0x%08" PRIxPTR ": ", pc);
count = print_insn(pc, &disasm_info);
fprintf(out, "\n");
if (count < 0)
int cpu_restore_state(struct TranslationBlock *tb,
CPUArchState *env, uintptr_t searched_pc);
void QEMU_NORETURN cpu_resume_from_signal(CPUArchState *env1, void *puc);
-void QEMU_NORETURN cpu_io_recompile(CPUArchState *env, void *retaddr);
+void QEMU_NORETURN cpu_io_recompile(CPUArchState *env, uintptr_t retaddr);
TranslationBlock *tb_gen_code(CPUArchState *env,
target_ulong pc, target_ulong cs_base, int flags,
int cflags);
void tlb_set_page(CPUArchState *env, target_ulong vaddr,
target_phys_addr_t paddr, int prot,
int mmu_idx, target_ulong size);
+void tb_invalidate_phys_addr(target_phys_addr_t addr);
#endif
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
# endif
#elif defined(__s390__) && !defined(__s390x__)
# define GETPC() \
- ((void *)(((uintptr_t)__builtin_return_address(0) & 0x7fffffffUL) - 1))
+ (((uintptr_t)__builtin_return_address(0) & 0x7fffffffUL) - 1)
#elif defined(__arm__)
/* Thumb return addresses have the low bit set, so we need to subtract two.
This is still safe in ARM mode because instructions are 4 bytes. */
-# define GETPC() ((void *)((uintptr_t)__builtin_return_address(0) - 2))
+# define GETPC() ((uintptr_t)__builtin_return_address(0) - 2)
#else
-# define GETPC() ((void *)((uintptr_t)__builtin_return_address(0) - 1))
+# define GETPC() ((uintptr_t)__builtin_return_address(0) - 1)
#endif
#if !defined(CONFIG_USER_ONLY)
uint64_t value, unsigned size);
void tlb_fill(CPUArchState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr);
+ uintptr_t retaddr);
#include "softmmu_defs.h"
#define code_gen_section \
__attribute__((__section__(".gen_code"))) \
__attribute__((aligned (32)))
-#elif defined(_WIN32)
-/* Maximum alignment for Win32 is 16. */
+#elif defined(_WIN32) && !defined(_WIN64)
#define code_gen_section \
__attribute__((aligned (16)))
#else
#define V_L1_SHIFT (L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS - V_L1_BITS)
-unsigned long qemu_real_host_page_size;
-unsigned long qemu_host_page_size;
-unsigned long qemu_host_page_mask;
+uintptr_t qemu_real_host_page_size;
+uintptr_t qemu_host_page_size;
+uintptr_t qemu_host_page_mask;
/* This is a multi-level map on the virtual address space.
The bottom level has pointers to PageDesc. */
for(;;) {
tb1 = *ptb;
- n1 = (long)tb1 & 3;
- tb1 = (TranslationBlock *)((long)tb1 & ~3);
+ n1 = (uintptr_t)tb1 & 3;
+ tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
if (tb1 == tb) {
*ptb = tb1->page_next[n1];
break;
/* find tb(n) in circular list */
for(;;) {
tb1 = *ptb;
- n1 = (long)tb1 & 3;
- tb1 = (TranslationBlock *)((long)tb1 & ~3);
+ n1 = (uintptr_t)tb1 & 3;
+ tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
if (n1 == n && tb1 == tb)
break;
if (n1 == 2) {
another TB */
static inline void tb_reset_jump(TranslationBlock *tb, int n)
{
- tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
+ tb_set_jmp_target(tb, n, (uintptr_t)(tb->tc_ptr + tb->tb_next_offset[n]));
}
void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr)
/* suppress any remaining jumps to this TB */
tb1 = tb->jmp_first;
for(;;) {
- n1 = (long)tb1 & 3;
+ n1 = (uintptr_t)tb1 & 3;
if (n1 == 2)
break;
- tb1 = (TranslationBlock *)((long)tb1 & ~3);
+ tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
tb2 = tb1->jmp_next[n1];
tb_reset_jump(tb1, n1);
tb1->jmp_next[n1] = NULL;
tb1 = tb2;
}
- tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
+ tb->jmp_first = (TranslationBlock *)((uintptr_t)tb | 2); /* fail safe */
tb_phys_invalidate_count++;
}
tb = p->first_tb;
while (tb != NULL) {
- n = (long)tb & 3;
- tb = (TranslationBlock *)((long)tb & ~3);
+ n = (uintptr_t)tb & 3;
+ tb = (TranslationBlock *)((uintptr_t)tb & ~3);
/* NOTE: this is subtle as a TB may span two physical pages */
if (n == 0) {
/* NOTE: tb_end may be after the end of the page, but
tb->flags = flags;
tb->cflags = cflags;
cpu_gen_code(env, tb, &code_gen_size);
- code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
+ code_gen_ptr = (void *)(((uintptr_t)code_gen_ptr + code_gen_size +
+ CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
/* check next page if needed */
virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
/* XXX: see if in some cases it could be faster to invalidate all the code */
tb = p->first_tb;
while (tb != NULL) {
- n = (long)tb & 3;
- tb = (TranslationBlock *)((long)tb & ~3);
+ n = (uintptr_t)tb & 3;
+ tb = (TranslationBlock *)((uintptr_t)tb & ~3);
tb_next = tb->page_next[n];
/* NOTE: this is subtle as a TB may span two physical pages */
if (n == 0) {
qemu_log("modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
cpu_single_env->mem_io_vaddr, len,
cpu_single_env->eip,
- cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
+ cpu_single_env->eip +
+ (intptr_t)cpu_single_env->segs[R_CS].base);
}
#endif
p = page_find(start >> TARGET_PAGE_BITS);
#if !defined(CONFIG_SOFTMMU)
static void tb_invalidate_phys_page(tb_page_addr_t addr,
- unsigned long pc, void *puc)
+ uintptr_t pc, void *puc)
{
TranslationBlock *tb;
PageDesc *p;
}
#endif
while (tb != NULL) {
- n = (long)tb & 3;
- tb = (TranslationBlock *)((long)tb & ~3);
+ n = (uintptr_t)tb & 3;
+ tb = (TranslationBlock *)((uintptr_t)tb & ~3);
#ifdef TARGET_HAS_PRECISE_SMC
if (current_tb == tb &&
(current_tb->cflags & CF_COUNT_MASK) != 1) {
#ifndef CONFIG_USER_ONLY
page_already_protected = p->first_tb != NULL;
#endif
- p->first_tb = (TranslationBlock *)((long)tb | n);
+ p->first_tb = (TranslationBlock *)((uintptr_t)tb | n);
invalidate_page_bitmap(p);
#if defined(TARGET_HAS_SMC) || 1
else
tb->page_addr[1] = -1;
- tb->jmp_first = (TranslationBlock *)((long)tb | 2);
+ tb->jmp_first = (TranslationBlock *)((uintptr_t)tb | 2);
tb->jmp_next[0] = NULL;
tb->jmp_next[1] = NULL;
TranslationBlock *tb_find_pc(uintptr_t tc_ptr)
{
int m_min, m_max, m;
- unsigned long v;
+ uintptr_t v;
TranslationBlock *tb;
if (nb_tbs <= 0)
return NULL;
- if (tc_ptr < (unsigned long)code_gen_buffer ||
- tc_ptr >= (unsigned long)code_gen_ptr)
+ if (tc_ptr < (uintptr_t)code_gen_buffer ||
+ tc_ptr >= (uintptr_t)code_gen_ptr) {
return NULL;
+ }
/* binary search (cf Knuth) */
m_min = 0;
m_max = nb_tbs - 1;
while (m_min <= m_max) {
m = (m_min + m_max) >> 1;
tb = &tbs[m];
- v = (unsigned long)tb->tc_ptr;
+ v = (uintptr_t)tb->tc_ptr;
if (v == tc_ptr)
return tb;
else if (tc_ptr < v) {
if (tb1 != NULL) {
/* find head of list */
for(;;) {
- n1 = (long)tb1 & 3;
- tb1 = (TranslationBlock *)((long)tb1 & ~3);
+ n1 = (uintptr_t)tb1 & 3;
+ tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
if (n1 == 2)
break;
tb1 = tb1->jmp_next[n1];
ptb = &tb_next->jmp_first;
for(;;) {
tb1 = *ptb;
- n1 = (long)tb1 & 3;
- tb1 = (TranslationBlock *)((long)tb1 & ~3);
+ n1 = (uintptr_t)tb1 & 3;
+ tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
if (n1 == n && tb1 == tb)
break;
ptb = &tb1->jmp_next[n1];
tb_invalidate_phys_page_range(pc, pc + 1, 0);
}
#else
-static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
+void tb_invalidate_phys_addr(target_phys_addr_t addr)
{
- target_phys_addr_t addr;
ram_addr_t ram_addr;
MemoryRegionSection *section;
- addr = cpu_get_phys_page_debug(env, pc);
section = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!(memory_region_is_ram(section->mr)
|| (section->mr->rom_device && section->mr->readable))) {
+ section_addr(section, addr);
tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
}
+
+static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
+{
+ tb_invalidate_phys_addr(cpu_get_phys_page_debug(env, pc));
+}
#endif
#endif /* TARGET_HAS_ICE */
}
static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
- unsigned long start, unsigned long length)
+ uintptr_t start, uintptr_t length)
{
- unsigned long addr;
+ uintptr_t addr;
if (tlb_is_dirty_ram(tlb_entry)) {
addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
if ((addr - start) < length) {
int dirty_flags)
{
CPUArchState *env;
- unsigned long length, start1;
+ uintptr_t length, start1;
int i;
start &= TARGET_PAGE_MASK;
/* we modify the TLB cache so that the dirty bit will be set again
when accessing the range */
- start1 = (unsigned long)qemu_safe_ram_ptr(start);
+ start1 = (uintptr_t)qemu_safe_ram_ptr(start);
/* Check that we don't span multiple blocks - this breaks the
address comparisons below. */
- if ((unsigned long)qemu_safe_ram_ptr(end - 1) - start1
+ if ((uintptr_t)qemu_safe_ram_ptr(end - 1) - start1
!= (end - 1) - start) {
abort();
}
void *p;
if (tlb_is_dirty_ram(tlb_entry)) {
- p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
+ p = (void *)(uintptr_t)((tlb_entry->addr_write & TARGET_PAGE_MASK)
+ tlb_entry->addend);
ram_addr = qemu_ram_addr_from_host_nofail(p);
if (!cpu_physical_memory_is_dirty(ram_addr)) {
unsigned int index;
target_ulong address;
target_ulong code_address;
- unsigned long addend;
+ uintptr_t addend;
CPUTLBEntry *te;
CPUWatchpoint *wp;
target_phys_addr_t iotlb;
address |= TLB_MMIO;
}
if (is_ram_rom_romd(section)) {
- addend = (unsigned long)memory_region_get_ram_ptr(section->mr)
+ addend = (uintptr_t)memory_region_get_ram_ptr(section->mr)
+ section_addr(section, paddr);
} else {
addend = 0;
{
walk_memory_regions_fn fn;
void *priv;
- unsigned long start;
+ uintptr_t start;
int prot;
};
int walk_memory_regions(void *priv, walk_memory_regions_fn fn)
{
struct walk_memory_regions_data data;
- unsigned long i;
+ uintptr_t i;
data.fn = fn;
data.priv = priv;
}
static inline void tlb_set_dirty(CPUArchState *env,
- unsigned long addr, target_ulong vaddr)
+ uintptr_t addr, target_ulong vaddr)
{
}
#endif /* defined(CONFIG_USER_ONLY) */
/* in deterministic execution mode, instructions doing device I/Os
must be at the end of the TB */
-void cpu_io_recompile(CPUArchState *env, void *retaddr)
+void cpu_io_recompile(CPUArchState *env, uintptr_t retaddr)
{
TranslationBlock *tb;
uint32_t n, cflags;
target_ulong pc, cs_base;
uint64_t flags;
- tb = tb_find_pc((uintptr_t)retaddr);
+ tb = tb_find_pc(retaddr);
if (!tb) {
cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
- retaddr);
+ (void *)retaddr);
}
n = env->icount_decr.u16.low + tb->icount;
- cpu_restore_state(tb, env, (unsigned long)retaddr);
+ cpu_restore_state(tb, env, retaddr);
/* Calculate how many instructions had been executed before the fault
occurred. */
n = n - env->icount_decr.u16.low;
#define MMUSUFFIX _cmmu
#undef GETPC
-#define GETPC() NULL
+#define GETPC() ((uintptr_t)0)
#define env cpu_single_env
#define SOFTMMU_CODE_ACCESS
#include "sysbus.h"
-/* Configuration for arm_gic.c:
- * max number of CPUs, how to ID current CPU
- */
-#define NCPU 4
-
-static inline int gic_get_current_cpu(void)
-{
- return cpu_single_env->cpu_index;
-}
-
-#include "arm_gic.c"
-
/* A15MP private memory region. */
typedef struct A15MPPrivState {
- gic_state gic;
+ SysBusDevice busdev;
uint32_t num_cpu;
uint32_t num_irq;
MemoryRegion container;
+ DeviceState *gic;
} A15MPPrivState;
+static void a15mp_priv_set_irq(void *opaque, int irq, int level)
+{
+ A15MPPrivState *s = (A15MPPrivState *)opaque;
+ qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
+}
+
static int a15mp_priv_init(SysBusDevice *dev)
{
- A15MPPrivState *s = FROM_SYSBUSGIC(A15MPPrivState, dev);
+ A15MPPrivState *s = FROM_SYSBUS(A15MPPrivState, dev);
+ SysBusDevice *busdev;
+
+ s->gic = qdev_create(NULL, "arm_gic");
+ qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
+ qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
+ qdev_init_nofail(s->gic);
+ busdev = sysbus_from_qdev(s->gic);
- if (s->num_cpu > NCPU) {
- hw_error("a15mp_priv_init: num-cpu may not be more than %d\n", NCPU);
- }
+ /* Pass through outbound IRQ lines from the GIC */
+ sysbus_pass_irq(dev, busdev);
- gic_init(&s->gic, s->num_cpu, s->num_irq);
+ /* Pass through inbound GPIO lines to the GIC */
+ qdev_init_gpio_in(&s->busdev.qdev, a15mp_priv_set_irq, s->num_irq - 32);
/* Memory map (addresses are offsets from PERIPHBASE):
* 0x0000-0x0fff -- reserved
* 0x6000-0x7fff -- GIC virtual CPU interface (not modelled)
*/
memory_region_init(&s->container, "a15mp-priv-container", 0x8000);
- memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
- memory_region_add_subregion(&s->container, 0x2000, &s->gic.cpuiomem[0]);
+ memory_region_add_subregion(&s->container, 0x1000,
+ sysbus_mmio_get_region(busdev, 0));
+ memory_region_add_subregion(&s->container, 0x2000,
+ sysbus_mmio_get_region(busdev, 1));
sysbus_init_mmio(dev, &s->container);
return 0;
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
k->init = a15mp_priv_init;
dc->props = a15mp_priv_properties;
- /* We currently have no savable state outside the common GIC state */
+ /* We currently have no savable state */
}
static TypeInfo a15mp_priv_info = {
#include "sysbus.h"
-/* Configuration for arm_gic.c:
- * max number of CPUs, how to ID current CPU
- */
-#define NCPU 4
-
-static inline int
-gic_get_current_cpu(void)
-{
- return cpu_single_env->cpu_index;
-}
-
-#include "arm_gic.c"
-
/* A9MP private memory region. */
typedef struct a9mp_priv_state {
- gic_state gic;
+ SysBusDevice busdev;
uint32_t scu_control;
uint32_t scu_status;
uint32_t old_timer_status[8];
uint32_t num_cpu;
- qemu_irq *timer_irq;
MemoryRegion scu_iomem;
MemoryRegion ptimer_iomem;
MemoryRegion container;
DeviceState *mptimer;
+ DeviceState *gic;
uint32_t num_irq;
} a9mp_priv_state;
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static void a9mpcore_timer_irq_handler(void *opaque, int irq, int level)
-{
- a9mp_priv_state *s = (a9mp_priv_state *)opaque;
- if (level && !s->old_timer_status[irq]) {
- gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1));
- }
- s->old_timer_status[irq] = level;
-}
-
static void a9mp_priv_reset(DeviceState *dev)
{
- a9mp_priv_state *s = FROM_SYSBUSGIC(a9mp_priv_state, sysbus_from_qdev(dev));
+ a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, sysbus_from_qdev(dev));
int i;
s->scu_control = 0;
for (i = 0; i < ARRAY_SIZE(s->old_timer_status); i++) {
}
}
+static void a9mp_priv_set_irq(void *opaque, int irq, int level)
+{
+ a9mp_priv_state *s = (a9mp_priv_state *)opaque;
+ qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
+}
+
static int a9mp_priv_init(SysBusDevice *dev)
{
- a9mp_priv_state *s = FROM_SYSBUSGIC(a9mp_priv_state, dev);
- SysBusDevice *busdev;
+ a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, dev);
+ SysBusDevice *busdev, *gicbusdev;
int i;
- if (s->num_cpu > NCPU) {
- hw_error("a9mp_priv_init: num-cpu may not be more than %d\n", NCPU);
- }
+ s->gic = qdev_create(NULL, "arm_gic");
+ qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
+ qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
+ qdev_init_nofail(s->gic);
+ gicbusdev = sysbus_from_qdev(s->gic);
- gic_init(&s->gic, s->num_cpu, s->num_irq);
+ /* Pass through outbound IRQ lines from the GIC */
+ sysbus_pass_irq(dev, gicbusdev);
+
+ /* Pass through inbound GPIO lines to the GIC */
+ qdev_init_gpio_in(&s->busdev.qdev, a9mp_priv_set_irq, s->num_irq - 32);
s->mptimer = qdev_create(NULL, "arm_mptimer");
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
memory_region_init_io(&s->scu_iomem, &a9_scu_ops, s, "a9mp-scu", 0x100);
memory_region_add_subregion(&s->container, 0, &s->scu_iomem);
/* GIC CPU interface */
- memory_region_add_subregion(&s->container, 0x100, &s->gic.cpuiomem[0]);
+ memory_region_add_subregion(&s->container, 0x100,
+ sysbus_mmio_get_region(gicbusdev, 1));
/* Note that the A9 exposes only the "timer/watchdog for this core"
* memory region, not the "timer/watchdog for core X" ones 11MPcore has.
*/
sysbus_mmio_get_region(busdev, 0));
memory_region_add_subregion(&s->container, 0x620,
sysbus_mmio_get_region(busdev, 1));
- memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
+ memory_region_add_subregion(&s->container, 0x1000,
+ sysbus_mmio_get_region(gicbusdev, 0));
sysbus_init_mmio(dev, &s->container);
- /* Wire up the interrupt from each watchdog and timer. */
- s->timer_irq = qemu_allocate_irqs(a9mpcore_timer_irq_handler,
- s, (s->num_cpu + 1) * 2);
- for (i = 0; i < s->num_cpu * 2; i++) {
- sysbus_connect_irq(busdev, i, s->timer_irq[i]);
+ /* Wire up the interrupt from each watchdog and timer.
+ * For each core the timer is PPI 29 and the watchdog PPI 30.
+ */
+ for (i = 0; i < s->num_cpu; i++) {
+ int ppibase = (s->num_irq - 32) + i * 32;
+ sysbus_connect_irq(busdev, i * 2,
+ qdev_get_gpio_in(s->gic, ppibase + 29));
+ sysbus_connect_irq(busdev, i * 2 + 1,
+ qdev_get_gpio_in(s->gic, ppibase + 30));
}
return 0;
}
#include "sysbus.h"
#include "qemu-timer.h"
-#define NCPU 4
-
-static inline int
-gic_get_current_cpu(void)
-{
- return cpu_single_env->cpu_index;
-}
-
-#include "arm_gic.c"
-
/* MPCore private memory region. */
typedef struct mpcore_priv_state {
- gic_state gic;
+ SysBusDevice busdev;
uint32_t scu_control;
int iomemtype;
uint32_t old_timer_status[8];
uint32_t num_cpu;
- qemu_irq *timer_irq;
MemoryRegion iomem;
MemoryRegion container;
DeviceState *mptimer;
+ DeviceState *gic;
uint32_t num_irq;
} mpcore_priv_state;
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static void mpcore_timer_irq_handler(void *opaque, int irq, int level)
+static void mpcore_priv_set_irq(void *opaque, int irq, int level)
{
mpcore_priv_state *s = (mpcore_priv_state *)opaque;
- if (level && !s->old_timer_status[irq]) {
- gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1));
- }
- s->old_timer_status[irq] = level;
+ qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
}
static void mpcore_priv_map_setup(mpcore_priv_state *s)
{
int i;
+ SysBusDevice *gicbusdev = sysbus_from_qdev(s->gic);
SysBusDevice *busdev = sysbus_from_qdev(s->mptimer);
memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
memory_region_init_io(&s->iomem, &mpcore_scu_ops, s, "mpcore-scu", 0x100);
*/
for (i = 0; i < (s->num_cpu + 1); i++) {
target_phys_addr_t offset = 0x100 + (i * 0x100);
- memory_region_add_subregion(&s->container, offset, &s->gic.cpuiomem[i]);
+ memory_region_add_subregion(&s->container, offset,
+ sysbus_mmio_get_region(gicbusdev, i + 1));
}
/* Add the regions for timer and watchdog for "current CPU" and
* for each specific CPU.
*/
- s->timer_irq = qemu_allocate_irqs(mpcore_timer_irq_handler,
- s, (s->num_cpu + 1) * 2);
for (i = 0; i < (s->num_cpu + 1) * 2; i++) {
/* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */
target_phys_addr_t offset = 0x600 + (i >> 1) * 0x100 + (i & 1) * 0x20;
memory_region_add_subregion(&s->container, offset,
sysbus_mmio_get_region(busdev, i));
}
- memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
- /* Wire up the interrupt from each watchdog and timer. */
- for (i = 0; i < s->num_cpu * 2; i++) {
- sysbus_connect_irq(busdev, i, s->timer_irq[i]);
+ memory_region_add_subregion(&s->container, 0x1000,
+ sysbus_mmio_get_region(gicbusdev, 0));
+ /* Wire up the interrupt from each watchdog and timer.
+ * For each core the timer is PPI 29 and the watchdog PPI 30.
+ */
+ for (i = 0; i < s->num_cpu; i++) {
+ int ppibase = (s->num_irq - 32) + i * 32;
+ sysbus_connect_irq(busdev, i * 2,
+ qdev_get_gpio_in(s->gic, ppibase + 29));
+ sysbus_connect_irq(busdev, i * 2 + 1,
+ qdev_get_gpio_in(s->gic, ppibase + 30));
}
}
static int mpcore_priv_init(SysBusDevice *dev)
{
- mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
+ mpcore_priv_state *s = FROM_SYSBUS(mpcore_priv_state, dev);
+
+ s->gic = qdev_create(NULL, "arm_gic");
+ qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
+ qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
+ qdev_init_nofail(s->gic);
+
+ /* Pass through outbound IRQ lines from the GIC */
+ sysbus_pass_irq(dev, sysbus_from_qdev(s->gic));
+
+ /* Pass through inbound GPIO lines to the GIC */
+ qdev_init_gpio_in(&s->busdev.qdev, mpcore_priv_set_irq, s->num_irq - 32);
- gic_init(&s->gic, s->num_cpu, s->num_irq);
s->mptimer = qdev_create(NULL, "arm_mptimer");
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
qdev_init_nofail(s->mptimer);
*/
/* This file contains implementation code for the RealView EB interrupt
- controller, MPCore distributed interrupt controller and ARMv7-M
- Nested Vectored Interrupt Controller. */
+ * controller, MPCore distributed interrupt controller and ARMv7-M
+ * Nested Vectored Interrupt Controller.
+ * It is compiled in two ways:
+ * (1) as a standalone file to produce a sysbus device which is a GIC
+ * that can be used on the realview board and as one of the builtin
+ * private peripherals for the ARM MP CPUs (11MPCore, A9, etc)
+ * (2) by being directly #included into armv7m_nvic.c to produce the
+ * armv7m_nvic device.
+ */
+
+#include "sysbus.h"
/* Maximum number of possible interrupts, determined by the GIC architecture */
#define GIC_MAXIRQ 1020
/* First 32 are private to each CPU (SGIs and PPIs). */
#define GIC_INTERNAL 32
+/* Maximum number of possible CPU interfaces, determined by GIC architecture */
+#ifdef NVIC
+#define NCPU 1
+#else
+#define NCPU 8
+#endif
+
//#define DEBUG_GIC
#ifdef DEBUG_GIC
unsigned trigger:1; /* nonzero = edge triggered. */
} gic_irq_state;
-#define ALL_CPU_MASK ((1 << NCPU) - 1)
+#define ALL_CPU_MASK ((unsigned)(((1 << NCPU) - 1)))
#if NCPU > 1
#define NUM_CPU(s) ((s)->num_cpu)
#else
int current_pending[NCPU];
#if NCPU > 1
- int num_cpu;
+ uint32_t num_cpu;
#endif
MemoryRegion iomem; /* Distributor */
uint32_t num_irq;
} gic_state;
+static inline int gic_get_current_cpu(gic_state *s)
+{
+#if NCPU > 1
+ if (s->num_cpu > 1) {
+ return cpu_single_env->cpu_index;
+ }
+#endif
+ return 0;
+}
+
/* TODO: Many places that call this routine could be optimized. */
/* Update interrupt status after enabled or pending bits have been changed. */
static void gic_update(gic_state *s)
cm = 1 << cpu;
s->current_pending[cpu] = 1023;
if (!s->enabled || !s->cpu_enabled[cpu]) {
- qemu_irq_lower(s->parent_irq[cpu]);
+ qemu_irq_lower(s->parent_irq[cpu]);
return;
}
best_prio = 0x100;
}
}
-static void __attribute__((unused))
-gic_set_pending_private(gic_state *s, int cpu, int irq)
+#ifdef NVIC
+static void gic_set_pending_private(gic_state *s, int cpu, int irq)
{
int cm = 1 << cpu;
GIC_SET_PENDING(irq, cm);
gic_update(s);
}
+#endif
/* Process a change in an external IRQ input. */
static void gic_set_irq(void *opaque, int irq, int level)
{
+ /* Meaning of the 'irq' parameter:
+ * [0..N-1] : external interrupts
+ * [N..N+31] : PPI (internal) interrupts for CPU 0
+ * [N+32..N+63] : PPI (internal interrupts for CPU 1
+ * ...
+ */
gic_state *s = (gic_state *)opaque;
- /* The first external input line is internal interrupt 32. */
- irq += GIC_INTERNAL;
- if (level == GIC_TEST_LEVEL(irq, ALL_CPU_MASK))
+ int cm, target;
+ if (irq < (s->num_irq - GIC_INTERNAL)) {
+ /* The first external input line is internal interrupt 32. */
+ cm = ALL_CPU_MASK;
+ irq += GIC_INTERNAL;
+ target = GIC_TARGET(irq);
+ } else {
+ int cpu;
+ irq -= (s->num_irq - GIC_INTERNAL);
+ cpu = irq / GIC_INTERNAL;
+ irq %= GIC_INTERNAL;
+ cm = 1 << cpu;
+ target = cm;
+ }
+
+ if (level == GIC_TEST_LEVEL(irq, cm)) {
return;
+ }
if (level) {
- GIC_SET_LEVEL(irq, ALL_CPU_MASK);
- if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, ALL_CPU_MASK)) {
- DPRINTF("Set %d pending mask %x\n", irq, GIC_TARGET(irq));
- GIC_SET_PENDING(irq, GIC_TARGET(irq));
+ GIC_SET_LEVEL(irq, cm);
+ if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
+ DPRINTF("Set %d pending mask %x\n", irq, target);
+ GIC_SET_PENDING(irq, target);
}
} else {
- GIC_CLEAR_LEVEL(irq, ALL_CPU_MASK);
+ GIC_CLEAR_LEVEL(irq, cm);
}
gic_update(s);
}
int cm;
int mask;
- cpu = gic_get_current_cpu();
+ cpu = gic_get_current_cpu(s);
cm = 1 << cpu;
if (offset < 0x100) {
#ifndef NVIC
int i;
int cpu;
- cpu = gic_get_current_cpu();
+ cpu = gic_get_current_cpu(s);
if (offset < 0x100) {
#ifdef NVIC
goto bad_reg;
int irq;
int mask;
- cpu = gic_get_current_cpu();
+ cpu = gic_get_current_cpu(s);
irq = value & 0x3ff;
switch ((value >> 24) & 3) {
case 0:
unsigned size)
{
gic_state *s = (gic_state *)opaque;
- return gic_cpu_read(s, gic_get_current_cpu(), addr);
+ return gic_cpu_read(s, gic_get_current_cpu(s), addr);
}
static void gic_thiscpu_write(void *opaque, target_phys_addr_t addr,
uint64_t value, unsigned size)
{
gic_state *s = (gic_state *)opaque;
- gic_cpu_write(s, gic_get_current_cpu(), addr, value);
+ gic_cpu_write(s, gic_get_current_cpu(s), addr, value);
}
/* Wrappers to read/write the GIC CPU interface for a specific CPU.
};
#endif
-static void gic_reset(gic_state *s)
+static void gic_reset(DeviceState *dev)
{
+ gic_state *s = FROM_SYSBUS(gic_state, sysbus_from_qdev(dev));
int i;
memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
for (i = 0 ; i < NUM_CPU(s); i++) {
#if NCPU > 1
s->num_cpu = num_cpu;
+ if (s->num_cpu > NCPU) {
+ hw_error("requested %u CPUs exceeds GIC maximum %d\n",
+ num_cpu, NCPU);
+ }
#endif
s->num_irq = num_irq + GIC_BASE_IRQ;
if (s->num_irq > GIC_MAXIRQ) {
num_irq);
}
- qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, s->num_irq - GIC_INTERNAL);
+ i = s->num_irq - GIC_INTERNAL;
+#ifndef NVIC
+ /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
+ * GPIO array layout is thus:
+ * [0..N-1] SPIs
+ * [N..N+31] PPIs for CPU 0
+ * [N+32..N+63] PPIs for CPU 1
+ * ...
+ */
+ i += (GIC_INTERNAL * num_cpu);
+#endif
+ qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, i);
for (i = 0; i < NUM_CPU(s); i++) {
sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
}
}
#endif
- gic_reset(s);
register_savevm(NULL, "arm_gic", -1, 2, gic_save, gic_load, s);
}
+
+#ifndef NVIC
+
+static int arm_gic_init(SysBusDevice *dev)
+{
+ /* Device instance init function for the GIC sysbus device */
+ int i;
+ gic_state *s = FROM_SYSBUS(gic_state, dev);
+ gic_init(s, s->num_cpu, s->num_irq);
+ /* Distributor */
+ sysbus_init_mmio(dev, &s->iomem);
+ /* cpu interfaces (one for "current cpu" plus one per cpu) */
+ for (i = 0; i <= NUM_CPU(s); i++) {
+ sysbus_init_mmio(dev, &s->cpuiomem[i]);
+ }
+ return 0;
+}
+
+static Property arm_gic_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", gic_state, num_cpu, 1),
+ DEFINE_PROP_UINT32("num-irq", gic_state, num_irq, 32),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void arm_gic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+ sbc->init = arm_gic_init;
+ dc->props = arm_gic_properties;
+ dc->reset = gic_reset;
+ dc->no_user = 1;
+}
+
+static TypeInfo arm_gic_info = {
+ .name = "arm_gic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(gic_state),
+ .class_init = arm_gic_class_init,
+};
+
+static void arm_gic_register_types(void)
+{
+ type_register_static(&arm_gic_info);
+}
+
+type_init(arm_gic_register_types)
+
+#endif
#include "arm-misc.h"
#include "exec-memory.h"
-#define NCPU 1
#define NVIC 1
-/* Only a single "CPU" interface is present. */
-static inline int
-gic_get_current_cpu(void)
-{
- return 0;
-}
-
static uint32_t nvic_readl(void *opaque, uint32_t offset);
static void nvic_writel(void *opaque, uint32_t offset, uint32_t value);
}
}
+static void systick_reset(nvic_state *s)
+{
+ s->systick.control = 0;
+ s->systick.reload = 0;
+ s->systick.tick = 0;
+ qemu_del_timer(s->systick.timer);
+}
+
/* The external routines use the hardware vector numbering, ie. the first
IRQ is #16. The internal GIC routines use #32 as the first IRQ. */
void armv7m_nvic_set_pending(void *opaque, int irq)
}
};
+static void armv7m_nvic_reset(DeviceState *dev)
+{
+ nvic_state *s = FROM_SYSBUSGIC(nvic_state, sysbus_from_qdev(dev));
+ gic_reset(&s->gic.busdev.qdev);
+ systick_reset(s);
+}
+
static int armv7m_nvic_init(SysBusDevice *dev)
{
nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
sdc->init = armv7m_nvic_init;
dc->vmsd = &vmstate_nvic;
+ dc->reset = armv7m_nvic_reset;
dc->props = armv7m_nvic_properties;
}
#include "sysemu.h"
#include "sysbus.h"
#include "arm-misc.h"
+#include "loader.h"
#include "exynos4210.h"
#define EXYNOS4210_CHIPID_ADDR 0x10000000
static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43,
0x09, 0x00, 0x00, 0x00 };
+void exynos4210_write_secondary(CPUARMState *env,
+ const struct arm_boot_info *info)
+{
+ int n;
+ uint32_t smpboot[] = {
+ 0xe59f3024, /* ldr r3, External gic_cpu_if */
+ 0xe59f2024, /* ldr r2, Internal gic_cpu_if */
+ 0xe59f0024, /* ldr r0, startaddr */
+ 0xe3a01001, /* mov r1, #1 */
+ 0xe5821000, /* str r1, [r2] */
+ 0xe5831000, /* str r1, [r3] */
+ 0xe320f003, /* wfi */
+ 0xe5901000, /* ldr r1, [r0] */
+ 0xe1110001, /* tst r1, r1 */
+ 0x0afffffb, /* beq <wfi> */
+ 0xe12fff11, /* bx r1 */
+ EXYNOS4210_EXT_GIC_CPU_BASE_ADDR,
+ 0, /* gic_cpu_if: base address of Internal GIC CPU interface */
+ 0 /* bootreg: Boot register address is held here */
+ };
+ smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
+ smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr;
+ for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
+ smpboot[n] = tswap32(smpboot[n]);
+ }
+ rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
+ info->smp_loader_start);
+}
+
Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
unsigned long ram_size)
{
MemoryRegion bootreg_mem;
} Exynos4210State;
+void exynos4210_write_secondary(CPUARMState *env,
+ const struct arm_boot_info *info);
+
Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
unsigned long ram_size);
uint32_t reg_n; /* Register number inside the quad */
uint32_t val;
- if (s->external && (offset > 0x3c && offset != 0x100)) {
- hw_error("exynos4210.combiner: unallowed read access at offset 0x"
- TARGET_FMT_plx "\n", offset);
- }
-
req_quad_base_n = offset >> 4;
grp_quad_base_n = req_quad_base_n << 2;
reg_n = (offset - (req_quad_base_n << 4)) >> 2;
uint32_t grp_quad_base_n; /* Base of group quad */
uint32_t reg_n; /* Register number inside the quad */
- if (s->external && (offset > 0x3c && offset != 0x100)) {
- hw_error("exynos4210.combiner: unallowed write access at offset 0x"
- TARGET_FMT_plx "\n", offset);
- }
-
req_quad_base_n = offset >> 4;
grp_quad_base_n = req_quad_base_n << 2;
reg_n = (offset - (req_quad_base_n << 4)) >> 2;
};
#define EXYNOS4210_GIC_NIRQ 160
-#define NCPU EXYNOS4210_NCPUS
#define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE 0x10000
#define EXYNOS4210_EXT_GIC_DIST_REGION_SIZE 0x10000
/********* GIC part *********/
-static inline int
-gic_get_current_cpu(void)
-{
- return cpu_single_env->cpu_index;
-}
-
-#include "arm_gic.c"
-
typedef struct {
- gic_state gic;
+ SysBusDevice busdev;
MemoryRegion cpu_container;
MemoryRegion dist_container;
- MemoryRegion cpu_alias[NCPU];
- MemoryRegion dist_alias[NCPU];
+ MemoryRegion cpu_alias[EXYNOS4210_NCPUS];
+ MemoryRegion dist_alias[EXYNOS4210_NCPUS];
uint32_t num_cpu;
+ DeviceState *gic;
} Exynos4210GicState;
+static void exynos4210_gic_set_irq(void *opaque, int irq, int level)
+{
+ Exynos4210GicState *s = (Exynos4210GicState *)opaque;
+ qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
+}
+
static int exynos4210_gic_init(SysBusDevice *dev)
{
- Exynos4210GicState *s = FROM_SYSBUSGIC(Exynos4210GicState, dev);
+ Exynos4210GicState *s = FROM_SYSBUS(Exynos4210GicState, dev);
uint32_t i;
const char cpu_prefix[] = "exynos4210-gic-alias_cpu";
const char dist_prefix[] = "exynos4210-gic-alias_dist";
char cpu_alias_name[sizeof(cpu_prefix) + 3];
char dist_alias_name[sizeof(cpu_prefix) + 3];
+ SysBusDevice *busdev;
+
+ s->gic = qdev_create(NULL, "arm_gic");
+ qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
+ qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ);
+ qdev_init_nofail(s->gic);
+ busdev = sysbus_from_qdev(s->gic);
- gic_init(&s->gic, s->num_cpu, EXYNOS4210_GIC_NIRQ);
+ /* Pass through outbound IRQ lines from the GIC */
+ sysbus_pass_irq(dev, busdev);
+
+ /* Pass through inbound GPIO lines to the GIC */
+ qdev_init_gpio_in(&s->busdev.qdev, exynos4210_gic_set_irq,
+ EXYNOS4210_GIC_NIRQ - 32);
memory_region_init(&s->cpu_container, "exynos4210-cpu-container",
EXYNOS4210_EXT_GIC_CPU_REGION_SIZE);
sprintf(cpu_alias_name, "%s%x", cpu_prefix, i);
memory_region_init_alias(&s->cpu_alias[i],
cpu_alias_name,
- &s->gic.cpuiomem[0],
+ sysbus_mmio_get_region(busdev, 1),
0,
EXYNOS4210_GIC_CPU_REGION_SIZE);
memory_region_add_subregion(&s->cpu_container,
sprintf(dist_alias_name, "%s%x", dist_prefix, i);
memory_region_init_alias(&s->dist_alias[i],
dist_alias_name,
- &s->gic.iomem,
+ sysbus_mmio_get_region(busdev, 0),
0,
EXYNOS4210_GIC_DIST_REGION_SIZE);
memory_region_add_subregion(&s->dist_container,
sysbus_init_mmio(dev, &s->cpu_container);
sysbus_init_mmio(dev, &s->dist_container);
- gic_cpu_write(&s->gic, 1, 0, 1);
-
return 0;
}
typedef struct {
SysBusDevice busdev;
- qemu_irq pic_irq[NCPU]; /* output IRQs to PICs */
+ qemu_irq pic_irq[EXYNOS4210_NCPUS]; /* output IRQs to PICs */
uint32_t gpio_level[EXYNOS4210_IRQ_GATE_NINPUTS]; /* Input levels */
} Exynos4210IRQGateState;
EXYNOS4210_IRQ_GATE_NINPUTS);
/* Connect SysBusDev irqs to device specific irqs */
- for (i = 0; i < NCPU; i++) {
+ for (i = 0; i < EXYNOS4210_NCPUS; i++) {
sysbus_init_irq(dev, &s->pic_irq[i]);
}
uint32_t level = 0;
uint32_t reg;
- reg = (s->reg[I_(UFCON)] && UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
+ reg = (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT;
switch (s->channel) {
* The Tx interrupt is always requested if the number of data in the
* transmit FIFO is smaller than the trigger level.
*/
- if (s->reg[I_(UFCON)] && UFCON_FIFO_ENABLE) {
+ if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
- uint32_t count = (s->reg[I_(UFSTAT)] && UFSTAT_Tx_FIFO_COUNT) >>
+ uint32_t count = (s->reg[I_(UFSTAT)] & UFSTAT_Tx_FIFO_COUNT) >>
UFSTAT_Tx_FIFO_COUNT_SHIFT;
if (count <= exynos4210_uart_Tx_FIFO_trigger_level(s)) {
.loader_start = EXYNOS4210_BASE_BOOT_ADDR,
.smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR,
.nb_cpus = EXYNOS4210_NCPUS,
+ .write_secondary_boot = exynos4210_write_secondary,
};
static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS];
#include "sysbus.h"
-#define NCPU 1
-
-/* Only a single "CPU" interface is present. */
-static inline int
-gic_get_current_cpu(void)
-{
- return 0;
-}
-
-#include "arm_gic.c"
-
typedef struct {
- gic_state gic;
+ SysBusDevice busdev;
+ DeviceState *gic;
MemoryRegion container;
} RealViewGICState;
-static void realview_gic_map_setup(RealViewGICState *s)
+static void realview_gic_set_irq(void *opaque, int irq, int level)
{
- memory_region_init(&s->container, "realview-gic-container", 0x2000);
- memory_region_add_subregion(&s->container, 0, &s->gic.cpuiomem[0]);
- memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
+ RealViewGICState *s = (RealViewGICState *)opaque;
+ qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
}
static int realview_gic_init(SysBusDevice *dev)
{
- RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
-
+ RealViewGICState *s = FROM_SYSBUS(RealViewGICState, dev);
+ SysBusDevice *busdev;
/* The GICs on the RealView boards have a fixed nonconfigurable
* number of interrupt lines, so we don't need to expose this as
* a qdev property.
*/
- gic_init(&s->gic, 96);
- realview_gic_map_setup(s);
+ int numirq = 96;
+
+ s->gic = qdev_create(NULL, "arm_gic");
+ qdev_prop_set_uint32(s->gic, "num-cpu", 1);
+ qdev_prop_set_uint32(s->gic, "num-irq", numirq);
+ qdev_init_nofail(s->gic);
+ busdev = sysbus_from_qdev(s->gic);
+
+ /* Pass through outbound IRQ lines from the GIC */
+ sysbus_pass_irq(dev, busdev);
+
+ /* Pass through inbound GPIO lines to the GIC */
+ qdev_init_gpio_in(&s->busdev.qdev, realview_gic_set_irq, numirq - 32);
+
+ memory_region_init(&s->container, "realview-gic-container", 0x2000);
+ memory_region_add_subregion(&s->container, 0,
+ sysbus_mmio_get_region(busdev, 1));
+ memory_region_add_subregion(&s->container, 0x1000,
+ sysbus_mmio_get_region(busdev, 0));
sysbus_init_mmio(dev, &s->container);
return 0;
}
#ifdef DEBUG_SPAPR_HCALLS
#define hcall_dprintf(fmt, ...) \
- do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+ do { fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); } while (0)
#else
#define hcall_dprintf(fmt, ...) \
do { } while (0)
.receive = spapr_vlan_receive,
};
+static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
+{
+ VIOsPAPRVLANDevice *dev = DO_UPCAST(VIOsPAPRVLANDevice, sdev, sdev);
+
+ dev->buf_list = 0;
+ dev->rx_bufs = 0;
+ dev->isopen = 0;
+}
+
static int spapr_vlan_init(VIOsPAPRDevice *sdev)
{
VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_VIO_TCE_PAGE_SIZE),
SPAPR_VIO_TCE_PAGE_SIZE) < 0) {
- hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx " for "
- "H_REGISTER_LOGICAL_LAN\n", buf_list);
+ hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx "\n", buf_list);
return H_PARAMETER;
}
filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_VIO_TCE_PAGE_SIZE);
if (check_bd(dev, filter_list_bd, SPAPR_VIO_TCE_PAGE_SIZE) < 0) {
- hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx " for "
- "H_REGISTER_LOGICAL_LAN\n", filter_list);
+ hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx "\n", filter_list);
return H_PARAMETER;
}
if (!(rec_queue & VLAN_BD_VALID)
|| (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) {
- hcall_dprintf("Bad receive queue for H_REGISTER_LOGICAL_LAN\n");
+ hcall_dprintf("Bad receive queue\n");
return H_PARAMETER;
}
return H_RESOURCE;
}
- dev->buf_list = 0;
- dev->rx_bufs = 0;
- dev->isopen = 0;
+ spapr_vlan_reset(sdev);
return H_SUCCESS;
}
", 0x" TARGET_FMT_lx ")\n", reg, buf);
if (!sdev) {
- hcall_dprintf("Wrong device in h_add_logical_lan_buffer\n");
+ hcall_dprintf("Bad device\n");
return H_PARAMETER;
}
if ((check_bd(dev, buf, 4) < 0)
|| (VLAN_BD_LEN(buf) < 16)) {
- hcall_dprintf("Bad buffer enqueued in h_add_logical_lan_buffer\n");
+ hcall_dprintf("Bad buffer enqueued\n");
return H_PARAMETER;
}
VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
k->init = spapr_vlan_init;
+ k->reset = spapr_vlan_reset;
k->devnode = spapr_vlan_devnode;
k->dt_name = "l-lan";
k->dt_type = "network";
static uint32_t rtas_pci_cfgaddr(uint32_t arg)
{
+ /* This handles the encoding of extended config space addresses */
return ((arg >> 20) & 0xf00) | (arg & 0xff);
}
-static uint32_t rtas_read_pci_config_do(PCIDevice *pci_dev, uint32_t addr,
- uint32_t limit, uint32_t len)
+static void finish_read_pci_config(sPAPREnvironment *spapr, uint64_t buid,
+ uint32_t addr, uint32_t size,
+ target_ulong rets)
{
- if ((addr + len) <= limit) {
- return pci_host_config_read_common(pci_dev, addr, limit, len);
- } else {
- return ~0x0;
+ PCIDevice *pci_dev;
+ uint32_t val;
+
+ if ((size != 1) && (size != 2) && (size != 4)) {
+ /* access must be 1, 2 or 4 bytes */
+ rtas_st(rets, 0, -1);
+ return;
}
-}
-static void rtas_write_pci_config_do(PCIDevice *pci_dev, uint32_t addr,
- uint32_t limit, uint32_t val,
- uint32_t len)
-{
- if ((addr + len) <= limit) {
- pci_host_config_write_common(pci_dev, addr, limit, val, len);
+ pci_dev = find_dev(spapr, buid, addr);
+ addr = rtas_pci_cfgaddr(addr);
+
+ if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) {
+ /* Access must be to a valid device, within bounds and
+ * naturally aligned */
+ rtas_st(rets, 0, -1);
+ return;
}
+
+ val = pci_host_config_read_common(pci_dev, addr,
+ pci_config_size(pci_dev), size);
+
+ rtas_st(rets, 0, 0);
+ rtas_st(rets, 1, val);
}
static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
target_ulong args,
uint32_t nret, target_ulong rets)
{
- uint32_t val, size, addr;
- uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
- PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0));
+ uint64_t buid;
+ uint32_t size, addr;
- if (!dev) {
+ if ((nargs != 4) || (nret != 2)) {
rtas_st(rets, 0, -1);
return;
}
+
+ buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
size = rtas_ld(args, 3);
- addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
- val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
- rtas_st(rets, 0, 0);
- rtas_st(rets, 1, val);
+ addr = rtas_ld(args, 0);
+
+ finish_read_pci_config(spapr, buid, addr, size, rets);
}
static void rtas_read_pci_config(sPAPREnvironment *spapr,
target_ulong args,
uint32_t nret, target_ulong rets)
{
- uint32_t val, size, addr;
- PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0));
+ uint32_t size, addr;
- if (!dev) {
+ if ((nargs != 2) || (nret != 2)) {
rtas_st(rets, 0, -1);
return;
}
+
size = rtas_ld(args, 1);
- addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
- val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
+ addr = rtas_ld(args, 0);
+
+ finish_read_pci_config(spapr, 0, addr, size, rets);
+}
+
+static void finish_write_pci_config(sPAPREnvironment *spapr, uint64_t buid,
+ uint32_t addr, uint32_t size,
+ uint32_t val, target_ulong rets)
+{
+ PCIDevice *pci_dev;
+
+ if ((size != 1) && (size != 2) && (size != 4)) {
+ /* access must be 1, 2 or 4 bytes */
+ rtas_st(rets, 0, -1);
+ return;
+ }
+
+ pci_dev = find_dev(spapr, buid, addr);
+ addr = rtas_pci_cfgaddr(addr);
+
+ if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) {
+ /* Access must be to a valid device, within bounds and
+ * naturally aligned */
+ rtas_st(rets, 0, -1);
+ return;
+ }
+
+ pci_host_config_write_common(pci_dev, addr, pci_config_size(pci_dev),
+ val, size);
+
rtas_st(rets, 0, 0);
- rtas_st(rets, 1, val);
}
static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr,
target_ulong args,
uint32_t nret, target_ulong rets)
{
+ uint64_t buid;
uint32_t val, size, addr;
- uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
- PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0));
- if (!dev) {
+ if ((nargs != 5) || (nret != 1)) {
rtas_st(rets, 0, -1);
return;
}
+
+ buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
val = rtas_ld(args, 4);
size = rtas_ld(args, 3);
- addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
- rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
- rtas_st(rets, 0, 0);
+ addr = rtas_ld(args, 0);
+
+ finish_write_pci_config(spapr, buid, addr, size, val, rets);
}
static void rtas_write_pci_config(sPAPREnvironment *spapr,
uint32_t nret, target_ulong rets)
{
uint32_t val, size, addr;
- PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0));
- if (!dev) {
+ if ((nargs != 3) || (nret != 1)) {
rtas_st(rets, 0, -1);
return;
}
+
+
val = rtas_ld(args, 2);
size = rtas_ld(args, 1);
- addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
- rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
- rtas_st(rets, 0, 0);
+ addr = rtas_ld(args, 0);
+
+ finish_write_pci_config(spapr, 0, addr, size, val, rets);
}
static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num)
uint32_t nret, target_ulong rets)
{
uint8_t c = rtas_ld(args, 0);
- VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus,
- SPAPR_VTY_BASE_ADDRESS);
+ VIOsPAPRDevice *sdev = vty_lookup(spapr, 0);
if (!sdev) {
rtas_st(rets, 0, -1);
rtas_st(rets, 0, 0);
}
+static void rtas_system_reboot(sPAPREnvironment *spapr,
+ uint32_t token, uint32_t nargs,
+ target_ulong args,
+ uint32_t nret, target_ulong rets)
+{
+ if (nargs != 0 || nret != 1) {
+ rtas_st(rets, 0, -3);
+ return;
+ }
+ qemu_system_reset_request();
+ rtas_st(rets, 0, 0);
+}
+
static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
spapr_rtas_register("get-time-of-day", rtas_get_time_of_day);
spapr_rtas_register("set-time-of-day", rtas_set_time_of_day);
spapr_rtas_register("power-off", rtas_power_off);
+ spapr_rtas_register("system-reboot", rtas_system_reboot);
spapr_rtas_register("query-cpu-stopped-state",
rtas_query_cpu_stopped_state);
spapr_rtas_register("start-cpu", rtas_start_cpu);
VIOsPAPR_RTCE *rtce;
if (!dev) {
- hcall_dprintf("spapr_vio_put_tce on non-existent LIOBN "
- TARGET_FMT_lx "\n", liobn);
+ hcall_dprintf("LIOBN 0x" TARGET_FMT_lx " does not exist\n", liobn);
return H_PARAMETER;
}
#endif
if (ioba >= dev->rtce_window_size) {
- hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x"
- TARGET_FMT_lx "\n", ioba);
+ hcall_dprintf("Out-of-bounds IOBA 0x" TARGET_FMT_lx "\n", ioba);
return H_PARAMETER;
}
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
if (!dev) {
- hcall_dprintf("h_reg_crq on non-existent unit 0x"
- TARGET_FMT_lx "\n", reg);
+ hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
return H_PARAMETER;
}
/* We can't grok a queue size bigger than 256M for now */
if (queue_len < 0x1000 || queue_len > 0x10000000) {
- hcall_dprintf("h_reg_crq, queue size too small or too big (0x%llx)\n",
- (unsigned long long)queue_len);
+ hcall_dprintf("Queue size too small or too big (0x" TARGET_FMT_lx
+ ")\n", queue_len);
return H_PARAMETER;
}
/* Check queue alignment */
if (queue_addr & 0xfff) {
- hcall_dprintf("h_reg_crq, queue not aligned (0x%llx)\n",
- (unsigned long long)queue_addr);
+ hcall_dprintf("Queue not aligned (0x" TARGET_FMT_lx ")\n", queue_addr);
return H_PARAMETER;
}
/* Check if device supports CRQs */
if (!dev->crq.SendFunc) {
+ hcall_dprintf("Device does not support CRQ\n");
return H_NOT_FOUND;
}
-
/* Already a queue ? */
if (dev->crq.qsize) {
+ hcall_dprintf("CRQ already registered\n");
return H_RESOURCE;
}
dev->crq.qladdr = queue_addr;
return H_SUCCESS;
}
+static target_ulong free_crq(VIOsPAPRDevice *dev)
+{
+ dev->crq.qladdr = 0;
+ dev->crq.qsize = 0;
+ dev->crq.qnext = 0;
+
+ dprintf("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg);
+
+ return H_SUCCESS;
+}
+
static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
if (!dev) {
- hcall_dprintf("h_free_crq on non-existent unit 0x"
- TARGET_FMT_lx "\n", reg);
+ hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
return H_PARAMETER;
}
- dev->crq.qladdr = 0;
- dev->crq.qsize = 0;
- dev->crq.qnext = 0;
-
- dprintf("CRQ for dev 0x" TARGET_FMT_lx " freed\n", reg);
-
- return H_SUCCESS;
+ return free_crq(dev);
}
static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr,
uint64_t crq_mangle[2];
if (!dev) {
- hcall_dprintf("h_send_crq on non-existent unit 0x"
- TARGET_FMT_lx "\n", reg);
+ hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
return H_PARAMETER;
}
crq_mangle[0] = cpu_to_be64(msg_hi);
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
if (!dev) {
- hcall_dprintf("h_enable_crq on non-existent unit 0x"
- TARGET_FMT_lx "\n", reg);
+ hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
return H_PARAMETER;
}
return 0;
}
+static void spapr_vio_busdev_reset(DeviceState *qdev)
+{
+ VIOsPAPRDevice *dev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev);
+ VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
+
+ if (dev->crq.qsize) {
+ free_crq(dev);
+ }
+
+ if (pc->reset) {
+ pc->reset(dev);
+ }
+}
+
static int spapr_vio_busdev_init(DeviceState *qdev)
{
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
{
DeviceClass *k = DEVICE_CLASS(klass);
k->init = spapr_vio_busdev_init;
+ k->reset = spapr_vio_busdev_reset;
k->bus_info = &spapr_vio_bus_info;
}
const char *dt_name, *dt_type, *dt_compatible;
target_ulong signal_mask;
int (*init)(VIOsPAPRDevice *dev);
- void (*hcalls)(VIOsPAPRBus *bus);
+ void (*reset)(VIOsPAPRDevice *dev);
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
} VIOsPAPRDeviceClass;
struct VIOsPAPRBus {
BusState bus;
- const char *dt_name, *dt_type, *dt_compatible;
- target_ulong signal_mask;
int (*init)(VIOsPAPRDevice *dev);
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
};
int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq);
+VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg);
void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev);
void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd);
vscsi_req reqs[VSCSI_REQ_LIMIT];
} VSCSIState;
-/* XXX Debug only */
-static VSCSIState *dbg_vscsi_state;
-
-
static struct vscsi_req *vscsi_get_req(VSCSIState *s)
{
vscsi_req *req;
.cancel = vscsi_request_cancelled
};
-static int spapr_vscsi_init(VIOsPAPRDevice *dev)
+static void spapr_vscsi_reset(VIOsPAPRDevice *dev)
{
VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
int i;
- dbg_vscsi_state = s;
-
- /* Initialize qemu request tags */
memset(s->reqs, 0, sizeof(s->reqs));
for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
s->reqs[i].qtag = i;
}
+}
+
+static int spapr_vscsi_init(VIOsPAPRDevice *dev)
+{
+ VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
dev->crq.SendFunc = vscsi_do_crq;
VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
k->init = spapr_vscsi_init;
+ k->reset = spapr_vscsi_reset;
k->devnode = spapr_vscsi_devnode;
k->dt_name = "v-scsi";
k->dt_type = "vscsi";
}
/* Forward declaration */
-static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg);
-
static target_ulong h_put_term_char(CPUPPCState *env, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
return selected;
}
-static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
+VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
{
VIOsPAPRDevice *sdev;
NULL, NULL, 0);
}
thread_env = NULL;
+#ifdef ENV_GET_CPU
+ object_delete(OBJECT(ENV_GET_CPU(cpu_env)));
+#else
g_free(cpu_env);
+#endif
g_free(ts);
pthread_exit(NULL);
}
g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
for (i = 0; i < w->num; i++) {
- poll_fds[n_poll_fds + i].fd = (DWORD) w->events[i];
+ poll_fds[n_poll_fds + i].fd = (DWORD_PTR)w->events[i];
poll_fds[n_poll_fds + i].events = G_IO_IN;
}
LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
", Offset: %" PRIu64 "\n",
request.from, request.len,
- (uint64_t)exp->size, exp->dev_offset);
+ (uint64_t)exp->size, (uint64_t)exp->dev_offset);
LOG("requested operation past EOF--bad client?");
goto invalid_request;
}
#include <winsock2.h>
#include "main-loop.h"
+/* Workaround for older versions of MinGW. */
+#ifndef ECONNREFUSED
+# define ECONNREFUSED WSAECONNREFUSED
+#endif
+#ifndef EINPROGRESS
+# define EINPROGRESS WSAEINPROGRESS
+#endif
+#ifndef EHOSTUNREACH
+# define EHOSTUNREACH WSAEHOSTUNREACH
+#endif
+#ifndef EINTR
+# define EINTR WSAEINTR
+#endif
+#ifndef EINPROGRESS
+# define EINPROGRESS WSAEINPROGRESS
+#endif
+#ifndef ENETUNREACH
+# define ENETUNREACH WSAENETUNREACH
+#endif
+#ifndef ENOTCONN
+# define ENOTCONN WSAENOTCONN
+#endif
+#ifndef EWOULDBLOCK
+# define EWOULDBLOCK WSAEWOULDBLOCK
+#endif
+
+#if defined(_WIN64)
+/* On w64, setjmp is implemented by _setjmp which needs a second parameter.
+ * If this parameter is NULL, longjump does no stack unwinding.
+ * That is what we need for QEMU. Passing the value of register rsp (default)
+ * lets longjmp try a stack unwinding which will crash with generated code. */
+# undef setjmp
+# define setjmp(env) _setjmp(env, NULL)
+#endif
+
/* Declaration of ffs() is missing in MinGW's strings.h. */
int ffs(int i);
#include <ws2tcpip.h>
#define socket_error() WSAGetLastError()
-#undef EWOULDBLOCK
-#undef EINTR
-#undef EINPROGRESS
-#define EWOULDBLOCK WSAEWOULDBLOCK
-#define EINTR WSAEINTR
-#define EINPROGRESS WSAEINPROGRESS
int inet_aton(const char *cp, struct in_addr *ia);
}
} else {
#ifdef _WIN32
- ptm = localtime(&tb.time);
+ time_t t = tb.time;
+ ptm = localtime(&t);
strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", ptm);
#else
/* cast below needed for OpenBSD where tv_sec is still 'long' */
# include <sys/timeb.h>
# include <iphlpapi.h>
-# undef EWOULDBLOCK
-# undef EINPROGRESS
-# undef ENOTCONN
-# undef EHOSTUNREACH
-# undef ENETUNREACH
-# undef ECONNREFUSED
-# define EWOULDBLOCK WSAEWOULDBLOCK
-# define EINPROGRESS WSAEINPROGRESS
-# define ENOTCONN WSAENOTCONN
-# define EHOSTUNREACH WSAEHOSTUNREACH
-# define ENETUNREACH WSAENETUNREACH
-# define ECONNREFUSED WSAECONNREFUSED
#else
# define ioctlsocket ioctl
# define closesocket(s) close(s)
int page_index;
RES_TYPE res;
target_ulong addr;
- unsigned long physaddr;
int mmu_idx;
addr = ptr;
addr,
mmu_idx);
} else {
- physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
- res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
+ uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
+ res = glue(glue(ld, USUFFIX), _raw)(hostaddr);
}
return res;
}
{
int res, page_index;
target_ulong addr;
- unsigned long physaddr;
int mmu_idx;
addr = ptr;
res = (DATA_STYPE)glue(glue(glue(HELPER_PREFIX, ld), SUFFIX),
MMUSUFFIX)(ENV_VAR addr, mmu_idx);
} else {
- physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
- res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr);
+ uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
+ res = glue(glue(lds, SUFFIX), _raw)(hostaddr);
}
return res;
}
{
int page_index;
target_ulong addr;
- unsigned long physaddr;
int mmu_idx;
addr = ptr;
glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_VAR addr, v,
mmu_idx);
} else {
- physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
- glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v);
+ uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
+ glue(glue(st, SUFFIX), _raw)(hostaddr, v);
}
}
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_PARAM
target_ulong addr,
int mmu_idx,
- void *retaddr);
+ uintptr_t retaddr);
static inline DATA_TYPE glue(io_read, SUFFIX)(ENV_PARAM
target_phys_addr_t physaddr,
target_ulong addr,
- void *retaddr)
+ uintptr_t retaddr)
{
DATA_TYPE res;
MemoryRegion *mr = iotlb_to_region(physaddr);
physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
- env->mem_io_pc = (unsigned long)retaddr;
+ env->mem_io_pc = retaddr;
if (mr != &io_mem_ram && mr != &io_mem_rom
&& mr != &io_mem_unassigned
&& mr != &io_mem_notdirty
int index;
target_ulong tlb_addr;
target_phys_addr_t ioaddr;
- unsigned long addend;
- void *retaddr;
+ uintptr_t retaddr;
/* test if there is match for unaligned or IO access */
/* XXX: could done more in memory macro in a non portable way */
mmu_idx, retaddr);
} else {
/* unaligned/aligned access in the same page */
+ uintptr_t addend;
#ifdef ALIGNED_ONLY
if ((addr & (DATA_SIZE - 1)) != 0) {
retaddr = GETPC();
}
#endif
addend = env->tlb_table[mmu_idx][index].addend;
- res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend));
+ res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(intptr_t)
+ (addr + addend));
}
} else {
/* the page is not in the TLB : fill it */
glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_PARAM
target_ulong addr,
int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
DATA_TYPE res, res1, res2;
int index, shift;
target_phys_addr_t ioaddr;
- unsigned long addend;
target_ulong tlb_addr, addr1, addr2;
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
res = (DATA_TYPE)res;
} else {
/* unaligned/aligned access in the same page */
- addend = env->tlb_table[mmu_idx][index].addend;
- res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)(addr+addend));
+ uintptr_t addend = env->tlb_table[mmu_idx][index].addend;
+ res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(intptr_t)
+ (addr + addend));
}
} else {
/* the page is not in the TLB : fill it */
target_ulong addr,
DATA_TYPE val,
int mmu_idx,
- void *retaddr);
+ uintptr_t retaddr);
static inline void glue(io_write, SUFFIX)(ENV_PARAM
target_phys_addr_t physaddr,
DATA_TYPE val,
target_ulong addr,
- void *retaddr)
+ uintptr_t retaddr)
{
MemoryRegion *mr = iotlb_to_region(physaddr);
}
env->mem_io_vaddr = addr;
- env->mem_io_pc = (unsigned long)retaddr;
+ env->mem_io_pc = retaddr;
#if SHIFT <= 2
io_mem_write(mr, physaddr, val, 1 << SHIFT);
#else
int mmu_idx)
{
target_phys_addr_t ioaddr;
- unsigned long addend;
target_ulong tlb_addr;
- void *retaddr;
+ uintptr_t retaddr;
int index;
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
mmu_idx, retaddr);
} else {
/* aligned/unaligned access in the same page */
+ uintptr_t addend;
#ifdef ALIGNED_ONLY
if ((addr & (DATA_SIZE - 1)) != 0) {
retaddr = GETPC();
}
#endif
addend = env->tlb_table[mmu_idx][index].addend;
- glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val);
+ glue(glue(st, SUFFIX), _raw)((uint8_t *)(intptr_t)
+ (addr + addend), val);
}
} else {
/* the page is not in the TLB : fill it */
target_ulong addr,
DATA_TYPE val,
int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
target_phys_addr_t ioaddr;
- unsigned long addend;
target_ulong tlb_addr;
int index, i;
}
} else {
/* aligned/unaligned access in the same page */
- addend = env->tlb_table[mmu_idx][index].addend;
- glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)(addr+addend), val);
+ uintptr_t addend = env->tlb_table[mmu_idx][index].addend;
+ glue(glue(st, SUFFIX), _raw)((uint8_t *)(intptr_t)
+ (addr + addend), val);
}
} else {
/* the page is not in the TLB : fill it */
--- /dev/null
+/*
+ * QEMU Alpha CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * 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/lgpl-2.1.html>
+ */
+#ifndef QEMU_ALPHA_CPU_QOM_H
+#define QEMU_ALPHA_CPU_QOM_H
+
+#include "qemu/cpu.h"
+#include "cpu.h"
+
+#define TYPE_ALPHA_CPU "alpha-cpu"
+
+#define ALPHA_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(AlphaCPUClass, (klass), TYPE_ALPHA_CPU)
+#define ALPHA_CPU(obj) \
+ OBJECT_CHECK(AlphaCPU, (obj), TYPE_ALPHA_CPU)
+#define ALPHA_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(AlphaCPUClass, (obj), TYPE_ALPHA_CPU)
+
+/**
+ * AlphaCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * An Alpha CPU model.
+ */
+typedef struct AlphaCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+} AlphaCPUClass;
+
+/**
+ * AlphaCPU:
+ * @env: #CPUAlphaState
+ *
+ * An Alpha CPU.
+ */
+typedef struct AlphaCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUAlphaState env;
+} AlphaCPU;
+
+static inline AlphaCPU *alpha_env_get_cpu(CPUAlphaState *env)
+{
+ return ALPHA_CPU(container_of(env, AlphaCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(alpha_env_get_cpu(e))
+
+
+#endif
--- /dev/null
+/*
+ * QEMU Alpha CPU
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * 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/lgpl-2.1.html>
+ */
+
+#include "cpu-qom.h"
+#include "qemu-common.h"
+
+
+static void alpha_cpu_initfn(Object *obj)
+{
+ AlphaCPU *cpu = ALPHA_CPU(obj);
+ CPUAlphaState *env = &cpu->env;
+
+ cpu_exec_init(env);
+ tlb_flush(env, 1);
+
+#if defined(CONFIG_USER_ONLY)
+ env->ps = PS_USER_MODE;
+ cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD
+ | FPCR_UNFD | FPCR_INED | FPCR_DNOD
+ | FPCR_DYN_NORMAL));
+#endif
+ env->lock_addr = -1;
+ env->fen = 1;
+}
+
+static const TypeInfo alpha_cpu_type_info = {
+ .name = TYPE_ALPHA_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(AlphaCPU),
+ .instance_init = alpha_cpu_initfn,
+ .abstract = false,
+ .class_size = sizeof(AlphaCPUClass),
+};
+
+static void alpha_cpu_register_types(void)
+{
+ type_register_static(&alpha_cpu_type_info);
+}
+
+type_init(alpha_cpu_register_types)
#define cpu_signal_handler cpu_alpha_signal_handler
#include "cpu-all.h"
+#include "cpu-qom.h"
enum {
FEATURE_ASN = 0x00000001,
int mmu_idx);
#define cpu_handle_mmu_fault cpu_alpha_handle_mmu_fault
void do_interrupt (CPUAlphaState *env);
-void do_restore_state(CPUAlphaState *, void *retaddr);
-void QEMU_NORETURN dynamic_excp(CPUAlphaState *, void *, int, int);
-void QEMU_NORETURN arith_excp(CPUAlphaState *, void *, int, uint64_t);
+void do_restore_state(CPUAlphaState *, uintptr_t retaddr);
+void QEMU_NORETURN dynamic_excp(CPUAlphaState *, uintptr_t, int, int);
+void QEMU_NORETURN arith_excp(CPUAlphaState *, uintptr_t, int, uint64_t);
uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env);
void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val);
return get_float_exception_flags(&FP_STATUS);
}
-static inline void inline_fp_exc_raise(CPUAlphaState *env, void *retaddr,
+static inline void inline_fp_exc_raise(CPUAlphaState *env, uintptr_t retaddr,
uint32_t exc, uint32_t regno)
{
if (exc) {
return r;
}
-static float32 f_to_float32(CPUAlphaState *env, void *retaddr, uint64_t a)
+static float32 f_to_float32(CPUAlphaState *env, uintptr_t retaddr, uint64_t a)
{
uint32_t exp, mant_sig;
CPU_FloatU r;
return r;
}
-static float64 g_to_float64(CPUAlphaState *env, void *retaddr, uint64_t a)
+static float64 g_to_float64(CPUAlphaState *env, uintptr_t retaddr, uint64_t a)
{
uint64_t exp, mant_sig;
CPU_DoubleU r;
cpu_fprintf(f, "\n");
}
-void do_restore_state(CPUAlphaState *env, void *retaddr)
+void do_restore_state(CPUAlphaState *env, uintptr_t retaddr)
{
- uintptr_t pc = (uintptr_t)retaddr;
- if (pc) {
- TranslationBlock *tb = tb_find_pc(pc);
+ if (retaddr) {
+ TranslationBlock *tb = tb_find_pc(retaddr);
if (tb) {
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
}
}
/* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
-void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, void *retaddr,
+void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, uintptr_t retaddr,
int excp, int error)
{
env->exception_index = excp;
cpu_loop_exit(env);
}
-void QEMU_NORETURN arith_excp(CPUAlphaState *env, void *retaddr,
+void QEMU_NORETURN arith_excp(CPUAlphaState *env, uintptr_t retaddr,
int exc, uint64_t mask)
{
env->trap_arg0 = exc;
}
static void do_unaligned_access(CPUAlphaState *env, target_ulong addr,
- int is_write, int is_user, void *retaddr)
+ int is_write, int is_user, uintptr_t retaddr)
{
uint64_t pc;
uint32_t insn;
{
env->trap_arg0 = addr;
env->trap_arg1 = is_write;
- dynamic_excp(env, NULL, EXCP_MCHK, 0);
+ dynamic_excp(env, 0, EXCP_MCHK, 0);
}
#include "softmmu_exec.h"
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUAlphaState *env, target_ulong addr, int is_write,
- int mmu_idx, void *retaddr)
+ int mmu_idx, uintptr_t retaddr)
{
int ret;
CPUAlphaState * cpu_alpha_init (const char *cpu_model)
{
+ AlphaCPU *cpu;
CPUAlphaState *env;
int implver, amask, i, max;
- env = g_malloc0(sizeof(CPUAlphaState));
- cpu_exec_init(env);
+ cpu = ALPHA_CPU(object_new(TYPE_ALPHA_CPU));
+ env = &cpu->env;
+
alpha_translate_init();
- tlb_flush(env, 1);
/* Default to ev67; no reason not to emulate insns by default. */
implver = IMPLVER_21264;
env->implver = implver;
env->amask = amask;
-#if defined (CONFIG_USER_ONLY)
- env->ps = PS_USER_MODE;
- cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD
- | FPCR_UNFD | FPCR_INED | FPCR_DNOD
- | FPCR_DYN_NORMAL));
-#endif
- env->lock_addr = -1;
- env->fen = 1;
-
qemu_init_vcpu(env);
return env;
}
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUARMState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPUARMState *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
if (unlikely(ret)) {
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
raise_exception(env->exception_index);
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUCRISState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPUCRISState *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
env = env1;
- D_LOG("%s pc=%x tpc=%x ra=%x\n", __func__,
- env->pc, env->debug1, retaddr);
+ D_LOG("%s pc=%x tpc=%x ra=%p\n", __func__,
+ env->pc, env->debug1, (void *)retaddr);
ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx);
if (unlikely(ret)) {
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
/* Evaluate flags after retranslation. */
helper_top_evaluate_flags();
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUX86State *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
int ret;
- unsigned long pc;
CPUX86State *saved_env;
saved_env = env;
if (ret) {
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
raise_exception_err(env->exception_index, env->error_code);
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPULM32State *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPULM32State *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
if (unlikely(ret)) {
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
cpu_loop_exit(env);
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUM68KState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPUM68KState *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
if (unlikely(ret)) {
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
cpu_loop_exit(env);
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUMBState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPUMBState *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
if (unlikely(ret)) {
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
cpu_loop_exit(env);
}
#if !defined(CONFIG_USER_ONLY)
-static void do_restore_state (void *pc_ptr)
+static void do_restore_state(uintptr_t pc)
{
TranslationBlock *tb;
- unsigned long pc = (unsigned long) pc_ptr;
-
+
tb = tb_find_pc (pc);
if (tb) {
cpu_restore_state(tb, env, pc);
break;
case 158:
{
- unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4];
+ unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
printf("%s", fmt);
}
break;
#if !defined(CONFIG_USER_ONLY)
static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
- int is_user, void *retaddr);
+ int is_user, uintptr_t retaddr);
#define MMUSUFFIX _mmu
#define ALIGNED_ONLY
#define SHIFT 3
#include "softmmu_template.h"
-static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
+static void do_unaligned_access(target_ulong addr, int is_write,
+ int is_user, uintptr_t retaddr)
{
env->CP0_BadVAddr = addr;
do_restore_state (retaddr);
}
void tlb_fill(CPUMIPSState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPUMIPSState *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
if (ret) {
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
helper_raise_exception_err(env->exception_index, env->error_code);
--- /dev/null
+/*
+ * QEMU PowerPC CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * 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/lgpl-2.1.html>
+ */
+#ifndef QEMU_PPC_CPU_QOM_H
+#define QEMU_PPC_CPU_QOM_H
+
+#include "qemu/cpu.h"
+#include "cpu.h"
+
+#ifdef TARGET_PPC64
+#define TYPE_POWERPC_CPU "powerpc64-cpu"
+#elif defined(TARGET_PPCEMB)
+#define TYPE_POWERPC_CPU "embedded-powerpc-cpu"
+#else
+#define TYPE_POWERPC_CPU "powerpc-cpu"
+#endif
+
+#define POWERPC_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(PowerPCCPUClass, (klass), TYPE_POWERPC_CPU)
+#define POWERPC_CPU(obj) \
+ OBJECT_CHECK(PowerPCCPU, (obj), TYPE_POWERPC_CPU)
+#define POWERPC_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(PowerPCCPUClass, (obj), TYPE_POWERPC_CPU)
+
+/**
+ * PowerPCCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A PowerPC CPU model.
+ */
+typedef struct PowerPCCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+} PowerPCCPUClass;
+
+/**
+ * PowerPCCPU:
+ * @env: #CPUPPCState
+ *
+ * A PowerPC CPU.
+ */
+typedef struct PowerPCCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUPPCState env;
+} PowerPCCPU;
+
+static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
+{
+ return POWERPC_CPU(container_of(env, PowerPCCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(ppc_env_get_cpu(e))
+
+
+#endif
};
#endif
+#include "cpu-qom.h"
+
/*****************************************************************************/
CPUPPCState *cpu_ppc_init (const char *cpu_model);
void ppc_translate_init(void);
int cpu_ppc_exec (CPUPPCState *s);
-void cpu_ppc_close (CPUPPCState *s);
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
if (asrr1 != -1)
env->spr[asrr1] = env->spr[srr1];
/* If we disactivated any translation, flush TLBs */
- if (new_msr & ((1 << MSR_IR) | (1 << MSR_DR)))
+ if (msr & ((1 << MSR_IR) | (1 << MSR_DR)))
tlb_flush(env, 1);
if (msr_ile) {
void cpu_state_reset(CPUPPCState *env)
{
- target_ulong msr;
-
- if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
- log_cpu_state(env, 0);
- }
-
- msr = (target_ulong)0;
- if (0) {
- /* XXX: find a suitable condition to enable the hypervisor mode */
- msr |= (target_ulong)MSR_HVB;
- }
- msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
- msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
- msr |= (target_ulong)1 << MSR_EP;
-#if defined (DO_SINGLE_STEP) && 0
- /* Single step trace mode */
- msr |= (target_ulong)1 << MSR_SE;
- msr |= (target_ulong)1 << MSR_BE;
-#endif
-#if defined(CONFIG_USER_ONLY)
- msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
- msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
- msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
- msr |= (target_ulong)1 << MSR_PR;
-#else
- env->excp_prefix = env->hreset_excp_prefix;
- env->nip = env->hreset_vector | env->excp_prefix;
- if (env->mmu_model != POWERPC_MMU_REAL)
- ppc_tlb_invalidate_all(env);
-#endif
- env->msr = msr & env->msr_mask;
-#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64)
- env->msr |= (1ULL << MSR_SF);
-#endif
- hreg_compute_hflags(env);
- env->reserve_addr = (target_ulong)-1ULL;
- /* Be sure no exception or interrupt is pending */
- env->pending_interrupts = 0;
- env->exception_index = POWERPC_EXCP_NONE;
- env->error_code = 0;
- /* Flush all TLBs */
- tlb_flush(env, 1);
+ cpu_reset(ENV_GET_CPU(env));
}
CPUPPCState *cpu_ppc_init (const char *cpu_model)
{
+ PowerPCCPU *cpu;
CPUPPCState *env;
const ppc_def_t *def;
if (!def)
return NULL;
- env = g_malloc0(sizeof(CPUPPCState));
- cpu_exec_init(env);
+ cpu = POWERPC_CPU(object_new(TYPE_POWERPC_CPU));
+ env = &cpu->env;
+
if (tcg_enabled()) {
ppc_translate_init();
}
- /* Adjust cpu index for SMT */
-#if !defined(CONFIG_USER_ONLY)
- if (kvm_enabled()) {
- int smt = kvmppc_smt_threads();
- env->cpu_index = (env->cpu_index / smp_threads)*smt
- + (env->cpu_index % smp_threads);
- }
-#endif /* !CONFIG_USER_ONLY */
env->cpu_model_str = cpu_model;
cpu_ppc_register_internal(env, def);
return env;
}
-
-void cpu_ppc_close (CPUPPCState *env)
-{
- /* Should also remove all opcode tables... */
- g_free(env);
-}
#include "kvm.h"
#include "kvm_ppc.h"
#include "cpu.h"
+#include "cpus.h"
#include "device_tree.h"
#include "hw/sysbus.h"
#include "hw/spapr.h"
return spec;
}
+int kvmppc_fixup_cpu(CPUPPCState *env)
+{
+ int smt;
+
+ /* Adjust cpu index for SMT */
+ smt = kvmppc_smt_threads();
+ env->cpu_index = (env->cpu_index / smp_threads) * smt
+ + (env->cpu_index % smp_threads);
+
+ return 0;
+}
+
+
bool kvm_arch_stop_on_emulation_error(CPUPPCState *env)
{
return true;
int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
#endif /* !CONFIG_USER_ONLY */
const ppc_def_t *kvmppc_host_cpu_def(void);
+int kvmppc_fixup_cpu(CPUPPCState *env);
#else
return NULL;
}
+static inline int kvmppc_fixup_cpu(CPUPPCState *env)
+{
+ return -1;
+}
#endif
#ifndef CONFIG_KVM
}
qemu_put_be32s(f, &env->fpscr);
qemu_put_sbe32s(f, &env->access_type);
-#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
qemu_put_betls(f, &env->asr);
qemu_put_sbe32s(f, &env->slb_nr);
}
for (i = 0; i < 4; i++)
qemu_put_betls(f, &env->pb[i]);
-#endif
for (i = 0; i < 1024; i++)
qemu_put_betls(f, &env->spr[i]);
qemu_put_be32s(f, &env->vscr);
qemu_put_be32s(f, &env->flags);
qemu_put_sbe32s(f, &env->error_code);
qemu_put_be32s(f, &env->pending_interrupts);
-#if !defined(CONFIG_USER_ONLY)
qemu_put_be32s(f, &env->irq_input_state);
for (i = 0; i < POWERPC_EXCP_NB; i++)
qemu_put_betls(f, &env->excp_vectors[i]);
qemu_put_betls(f, &env->ivor_mask);
qemu_put_betls(f, &env->ivpr_mask);
qemu_put_betls(f, &env->hreset_vector);
-#endif
qemu_put_betls(f, &env->nip);
qemu_put_betls(f, &env->hflags);
qemu_put_betls(f, &env->hflags_nmsr);
}
qemu_get_be32s(f, &env->fpscr);
qemu_get_sbe32s(f, &env->access_type);
-#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
qemu_get_betls(f, &env->asr);
qemu_get_sbe32s(f, &env->slb_nr);
}
for (i = 0; i < 4; i++)
qemu_get_betls(f, &env->pb[i]);
-#endif
for (i = 0; i < 1024; i++)
qemu_get_betls(f, &env->spr[i]);
ppc_store_sdr1(env, sdr1);
qemu_get_be32s(f, &env->flags);
qemu_get_sbe32s(f, &env->error_code);
qemu_get_be32s(f, &env->pending_interrupts);
-#if !defined(CONFIG_USER_ONLY)
qemu_get_be32s(f, &env->irq_input_state);
for (i = 0; i < POWERPC_EXCP_NB; i++)
qemu_get_betls(f, &env->excp_vectors[i]);
qemu_get_betls(f, &env->ivor_mask);
qemu_get_betls(f, &env->ivpr_mask);
qemu_get_betls(f, &env->hreset_vector);
-#endif
qemu_get_betls(f, &env->nip);
qemu_get_betls(f, &env->hflags);
qemu_get_betls(f, &env->hflags_nmsr);
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPUPPCState *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
if (unlikely(ret != 0)) {
if (likely(retaddr)) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (likely(tb)) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
helper_raise_exception_err(env->exception_index, env->error_code);
GEN_SPEOP_LDST(evstwwo, 0x1E, 2),
};
-#include "translate_init.c"
#include "helper_regs.h"
+#include "translate_init.c"
/*****************************************************************************/
/* Misc PowerPC helpers */
&spr_read_spefscr, &spr_write_spefscr,
0x00000000);
/* Memory management */
-#if !defined(CONFIG_USER_ONLY)
+#if defined(CONFIG_USER_ONLY)
+ env->dcache_line_size = 32;
+ env->icache_line_size = 32;
+#else /* !defined(CONFIG_USER_ONLY) */
env->nb_pids = 3;
env->nb_ways = 2;
env->id_tlbs = 0;
static inline int is_indirect_opcode (void *handler)
{
- return ((unsigned long)handler & 0x03) == PPC_INDIRECT;
+ return ((uintptr_t)handler & 0x03) == PPC_INDIRECT;
}
static inline opc_handler_t **ind_table(void *handler)
{
- return (opc_handler_t **)((unsigned long)handler & ~3);
+ return (opc_handler_t **)((uintptr_t)handler & ~3);
}
/* Instruction table creation */
tmp = malloc(0x20 * sizeof(opc_handler_t));
fill_new_table(tmp, 0x20);
- table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT);
+ table[idx] = (opc_handler_t *)((uintptr_t)tmp | PPC_INDIRECT);
return 0;
}
return 0;
}
+static int ppc_fixup_cpu(CPUPPCState *env)
+{
+ /* TCG doesn't (yet) emulate some groups of instructions that
+ * are implemented on some otherwise supported CPUs (e.g. VSX
+ * and decimal floating point instructions on POWER7). We
+ * remove unsupported instruction groups from the cpu state's
+ * instruction masks and hope the guest can cope. For at
+ * least the pseries machine, the unavailability of these
+ * instructions can be advertised to the guest via the device
+ * tree. */
+ if ((env->insns_flags & ~PPC_TCG_INSNS)
+ || (env->insns_flags2 & ~PPC_TCG_INSNS2)) {
+ fprintf(stderr, "Warning: Disabling some instructions which are not "
+ "emulated by TCG (0x%" PRIx64 ", 0x%" PRIx64 ")\n",
+ env->insns_flags & ~PPC_TCG_INSNS,
+ env->insns_flags2 & ~PPC_TCG_INSNS2);
+ }
+ env->insns_flags &= PPC_TCG_INSNS;
+ env->insns_flags2 &= PPC_TCG_INSNS2;
+ return 0;
+}
+
int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
{
env->msr_mask = def->msr_mask;
env->bus_model = def->bus_model;
env->insns_flags = def->insns_flags;
env->insns_flags2 = def->insns_flags2;
- if (!kvm_enabled()) {
- /* TCG doesn't (yet) emulate some groups of instructions that
- * are implemented on some otherwise supported CPUs (e.g. VSX
- * and decimal floating point instructions on POWER7). We
- * remove unsupported instruction groups from the cpu state's
- * instruction masks and hope the guest can cope. For at
- * least the pseries machine, the unavailability of these
- * instructions can be advertise to the guest via the device
- * tree.
- *
- * FIXME: we should have a similar masking for CPU features
- * not accessible under KVM, but so far, there aren't any of
- * those. */
- env->insns_flags &= PPC_TCG_INSNS;
- env->insns_flags2 &= PPC_TCG_INSNS2;
- }
env->flags = def->flags;
env->bfd_mach = def->bfd_mach;
env->check_pow = def->check_pow;
+
+ if (kvm_enabled()) {
+ if (kvmppc_fixup_cpu(env) != 0) {
+ fprintf(stderr, "Unable to virtualize selected CPU with KVM\n");
+ exit(1);
+ }
+ } else {
+ if (ppc_fixup_cpu(env) != 0) {
+ fprintf(stderr, "Unable to emulate selected CPU with TCG\n");
+ exit(1);
+ }
+ }
+
if (create_ppc_opcodes(env, def) < 0)
return -1;
init_ppc_proc(env, def);
ppc_defs[i].name, ppc_defs[i].pvr);
}
}
+
+/* CPUClass::reset() */
+static void ppc_cpu_reset(CPUState *s)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(s);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ CPUPPCState *env = &cpu->env;
+ target_ulong msr;
+
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
+ pcc->parent_reset(s);
+
+ msr = (target_ulong)0;
+ if (0) {
+ /* XXX: find a suitable condition to enable the hypervisor mode */
+ msr |= (target_ulong)MSR_HVB;
+ }
+ msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
+ msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
+ msr |= (target_ulong)1 << MSR_EP;
+#if defined(DO_SINGLE_STEP) && 0
+ /* Single step trace mode */
+ msr |= (target_ulong)1 << MSR_SE;
+ msr |= (target_ulong)1 << MSR_BE;
+#endif
+#if defined(CONFIG_USER_ONLY)
+ msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
+ msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
+ msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
+ msr |= (target_ulong)1 << MSR_PR;
+#else
+ env->excp_prefix = env->hreset_excp_prefix;
+ env->nip = env->hreset_vector | env->excp_prefix;
+ if (env->mmu_model != POWERPC_MMU_REAL) {
+ ppc_tlb_invalidate_all(env);
+ }
+#endif
+ env->msr = msr & env->msr_mask;
+#if defined(TARGET_PPC64)
+ if (env->mmu_model & POWERPC_MMU_64) {
+ env->msr |= (1ULL << MSR_SF);
+ }
+#endif
+ hreg_compute_hflags(env);
+ env->reserve_addr = (target_ulong)-1ULL;
+ /* Be sure no exception or interrupt is pending */
+ env->pending_interrupts = 0;
+ env->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+ /* Flush all TLBs */
+ tlb_flush(env, 1);
+}
+
+static void ppc_cpu_initfn(Object *obj)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(obj);
+ CPUPPCState *env = &cpu->env;
+
+ cpu_exec_init(env);
+}
+
+static void ppc_cpu_class_init(ObjectClass *oc, void *data)
+{
+ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
+ CPUClass *cc = CPU_CLASS(oc);
+
+ pcc->parent_reset = cc->reset;
+ cc->reset = ppc_cpu_reset;
+}
+
+static const TypeInfo ppc_cpu_type_info = {
+ .name = TYPE_POWERPC_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(PowerPCCPU),
+ .instance_init = ppc_cpu_initfn,
+ .abstract = false,
+ .class_size = sizeof(PowerPCCPUClass),
+ .class_init = ppc_cpu_class_init,
+};
+
+static void ppc_cpu_register_types(void)
+{
+ type_register_static(&ppc_cpu_type_info);
+}
+
+type_init(ppc_cpu_register_types)
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
TranslationBlock *tb;
CPUS390XState *saved_env;
- unsigned long pc;
int ret;
saved_env = env;
if (unlikely(ret != 0)) {
if (likely(retaddr)) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (likely(tb)) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
cpu_loop_exit(env);
#include "dyngen-exec.h"
#include "helper.h"
-static void cpu_restore_state_from_retaddr(void *retaddr)
+static void cpu_restore_state_from_retaddr(uintptr_t retaddr)
{
TranslationBlock *tb;
- unsigned long pc;
if (retaddr) {
- pc = (unsigned long) retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
}
#include "softmmu_template.h"
void tlb_fill(CPUSH4State *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
CPUSH4State *saved_env;
int ret;
#endif
}
-static inline void raise_exception(int index, void *retaddr)
+static inline void raise_exception(int index, uintptr_t retaddr)
{
env->exception_index = index;
cpu_restore_state_from_retaddr(retaddr);
set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
}
-static void update_fpscr(void *retaddr)
+static void update_fpscr(uintptr_t retaddr)
{
int xcpt, cause, enable;
#endif
void QEMU_NORETURN do_unaligned_access(CPUSPARCState *env, target_ulong addr,
int is_write, int is_user,
- void *retaddr);
+ uintptr_t retaddr);
#define TB_FLAG_FPU_ENABLED (1 << 4)
#define TB_FLAG_AM_ENABLED (1 << 5)
#if !defined(CONFIG_USER_ONLY)
/* XXX: make it generic ? */
-static void cpu_restore_state2(CPUSPARCState *env, void *retaddr)
+static void cpu_restore_state2(CPUSPARCState *env, uintptr_t retaddr)
{
TranslationBlock *tb;
- unsigned long pc;
if (retaddr) {
/* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
+ tb = tb_find_pc(retaddr);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
+ cpu_restore_state(tb, env, retaddr);
}
}
}
void do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write,
- int is_user, void *retaddr)
+ int is_user, uintptr_t retaddr)
{
#ifdef DEBUG_UNALIGNED
printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill(CPUSPARCState *env, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
int ret;
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Open Source and Linux Lab nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
#include "cpu.h"
#include "exec-all.h"
#include "gdbstub.h"
--- /dev/null
+/*
+ * Copyright (c) 2012, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Open Source and Linux Lab nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "gdbstub.h"
+#include "qemu-common.h"
+#include "host-utils.h"
+
+#include "core-dc233c/core-isa.h"
+#include "overlay_tool.h"
+
+static const XtensaConfig dc233c = {
+ .name = "dc233c",
+ .options = XTENSA_OPTIONS,
+ .gdb_regmap = {
+ .num_regs = 121,
+ .num_core_regs = 52,
+ .reg = {
+#include "core-dc233c/gdb-config.c"
+ }
+ },
+ .nareg = XCHAL_NUM_AREGS,
+ .ndepc = 1,
+ EXCEPTIONS_SECTION,
+ INTERRUPTS_SECTION,
+ TLB_SECTION,
+ .clock_freq_khz = 10000,
+};
+
+REGISTER_CORE(dc233c)
--- /dev/null
+/*
+ * xtensa/config/core-isa.h -- HAL definitions that are dependent on Xtensa
+ * processor CORE configuration
+ *
+ * See <xtensa/config/core.h>, which includes this file, for more details.
+ */
+
+/* Xtensa processor core configuration information.
+
+ Copyright (c) 1999-2010 Tensilica Inc.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _XTENSA_CORE_CONFIGURATION_H
+#define _XTENSA_CORE_CONFIGURATION_H
+
+
+/****************************************************************************
+ Parameters Useful for Any Code, USER or PRIVILEGED
+ ****************************************************************************/
+
+/*
+ * Note: Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is
+ * configured, and a value of 0 otherwise. These macros are always defined.
+ */
+
+
+/*----------------------------------------------------------------------
+ ISA
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_BE 0 /* big-endian byte ordering */
+#define XCHAL_HAVE_WINDOWED 1 /* windowed registers option */
+#define XCHAL_NUM_AREGS 32 /* num of physical addr regs */
+#define XCHAL_NUM_AREGS_LOG2 5 /* log2(XCHAL_NUM_AREGS) */
+#define XCHAL_MAX_INSTRUCTION_SIZE 3 /* max instr bytes (3..8) */
+#define XCHAL_HAVE_DEBUG 1 /* debug option */
+#define XCHAL_HAVE_DENSITY 1 /* 16-bit instructions */
+#define XCHAL_HAVE_LOOPS 1 /* zero-overhead loops */
+#define XCHAL_HAVE_NSA 1 /* NSA/NSAU instructions */
+#define XCHAL_HAVE_MINMAX 1 /* MIN/MAX instructions */
+#define XCHAL_HAVE_SEXT 1 /* SEXT instruction */
+#define XCHAL_HAVE_CLAMPS 1 /* CLAMPS instruction */
+#define XCHAL_HAVE_MUL16 1 /* MUL16S/MUL16U instructions */
+#define XCHAL_HAVE_MUL32 1 /* MULL instruction */
+#define XCHAL_HAVE_MUL32_HIGH 0 /* MULUH/MULSH instructions */
+#define XCHAL_HAVE_DIV32 1 /* QUOS/QUOU/REMS/REMU instructions */
+#define XCHAL_HAVE_L32R 1 /* L32R instruction */
+#define XCHAL_HAVE_ABSOLUTE_LITERALS 1 /* non-PC-rel (extended) L32R */
+#define XCHAL_HAVE_CONST16 0 /* CONST16 instruction */
+#define XCHAL_HAVE_ADDX 1 /* ADDX#/SUBX# instructions */
+#define XCHAL_HAVE_WIDE_BRANCHES 0 /* B*.W18 or B*.W15 instr's */
+#define XCHAL_HAVE_PREDICTED_BRANCHES 0 /* B[EQ/EQZ/NE/NEZ]T instr's */
+#define XCHAL_HAVE_CALL4AND12 1 /* (obsolete option) */
+#define XCHAL_HAVE_ABS 1 /* ABS instruction */
+/*#define XCHAL_HAVE_POPC 0*/ /* POPC instruction */
+/*#define XCHAL_HAVE_CRC 0*/ /* CRC instruction */
+#define XCHAL_HAVE_RELEASE_SYNC 1 /* L32AI/S32RI instructions */
+#define XCHAL_HAVE_S32C1I 1 /* S32C1I instruction */
+#define XCHAL_HAVE_SPECULATION 0 /* speculation */
+#define XCHAL_HAVE_FULL_RESET 1 /* all regs/state reset */
+#define XCHAL_NUM_CONTEXTS 1 /* */
+#define XCHAL_NUM_MISC_REGS 2 /* num of scratch regs (0..4) */
+#define XCHAL_HAVE_TAP_MASTER 0 /* JTAG TAP control instr's */
+#define XCHAL_HAVE_PRID 1 /* processor ID register */
+#define XCHAL_HAVE_EXTERN_REGS 1 /* WER/RER instructions */
+#define XCHAL_HAVE_MP_INTERRUPTS 0 /* interrupt distributor port */
+#define XCHAL_HAVE_MP_RUNSTALL 0 /* core RunStall control port */
+#define XCHAL_HAVE_THREADPTR 1 /* THREADPTR register */
+#define XCHAL_HAVE_BOOLEANS 0 /* boolean registers */
+#define XCHAL_HAVE_CP 1 /* CPENABLE reg (coprocessor) */
+#define XCHAL_CP_MAXCFG 8 /* max allowed cp id plus one */
+#define XCHAL_HAVE_MAC16 1 /* MAC16 package */
+#define XCHAL_HAVE_VECTORFPU2005 0 /* vector floating-point pkg */
+#define XCHAL_HAVE_FP 0 /* floating point pkg */
+#define XCHAL_HAVE_DFP 0 /* double precision FP pkg */
+#define XCHAL_HAVE_DFP_accel 0 /* double precision FP acceleration pkg */
+#define XCHAL_HAVE_VECTRA1 0 /* Vectra I pkg */
+#define XCHAL_HAVE_VECTRALX 0 /* Vectra LX pkg */
+#define XCHAL_HAVE_HIFIPRO 0 /* HiFiPro Audio Engine pkg */
+#define XCHAL_HAVE_HIFI2 0 /* HiFi2 Audio Engine pkg */
+#define XCHAL_HAVE_HIFI2EP 0 /* HiFi2EP */
+#define XCHAL_HAVE_CONNXD2 0 /* ConnX D2 pkg */
+#define XCHAL_HAVE_BBE16 0 /* ConnX BBE16 pkg */
+#define XCHAL_HAVE_BBE16_RSQRT 0 /* BBE16 & vector recip sqrt */
+#define XCHAL_HAVE_BBE16_VECDIV 0 /* BBE16 & vector divide */
+#define XCHAL_HAVE_BBE16_DESPREAD 0 /* BBE16 & despread */
+#define XCHAL_HAVE_BSP3 0 /* ConnX BSP3 pkg */
+#define XCHAL_HAVE_SSP16 0 /* ConnX SSP16 pkg */
+#define XCHAL_HAVE_SSP16_VITERBI 0 /* SSP16 & viterbi */
+#define XCHAL_HAVE_TURBO16 0 /* ConnX Turbo16 pkg */
+#define XCHAL_HAVE_BBP16 0 /* ConnX BBP16 pkg */
+
+
+/*----------------------------------------------------------------------
+ MISC
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_WRITEBUFFER_ENTRIES 8 /* size of write buffer */
+#define XCHAL_INST_FETCH_WIDTH 4 /* instr-fetch width in bytes */
+#define XCHAL_DATA_WIDTH 4 /* data width in bytes */
+/* In T1050, applies to selected core load and store instructions (see ISA): */
+#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* unaligned loads cause exc. */
+#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* unaligned stores cause exc.*/
+#define XCHAL_UNALIGNED_LOAD_HW 0 /* unaligned loads work in hw */
+#define XCHAL_UNALIGNED_STORE_HW 0 /* unaligned stores work in hw*/
+
+#define XCHAL_SW_VERSION 900001 /* sw version of this header */
+
+#define XCHAL_CORE_ID "dc233c" /* alphanum core name
+(CoreID) set in the Xtensa
+Processor Generator */
+
+#define XCHAL_CORE_DESCRIPTION "dc233c"
+#define XCHAL_BUILD_UNIQUE_ID 0x00004B21 /* 22-bit sw build ID */
+
+/*
+ * These definitions describe the hardware targeted by this software.
+ */
+#define XCHAL_HW_CONFIGID0 0xC56707FE /* ConfigID hi 32 bits*/
+#define XCHAL_HW_CONFIGID1 0x14404B21 /* ConfigID lo 32 bits*/
+#define XCHAL_HW_VERSION_NAME "LX4.0.1" /* full version name */
+#define XCHAL_HW_VERSION_MAJOR 2400 /* major ver# of targeted hw */
+#define XCHAL_HW_VERSION_MINOR 1 /* minor ver# of targeted hw */
+#define XCHAL_HW_VERSION 240001 /* major*100+minor */
+#define XCHAL_HW_REL_LX4 1
+#define XCHAL_HW_REL_LX4_0 1
+#define XCHAL_HW_REL_LX4_0_1 1
+#define XCHAL_HW_CONFIGID_RELIABLE 1
+/* If software targets a *range* of hardware versions, these are the bounds: */
+#define XCHAL_HW_MIN_VERSION_MAJOR 2400 /* major v of earliest tgt hw */
+#define XCHAL_HW_MIN_VERSION_MINOR 1 /* minor v of earliest tgt hw */
+#define XCHAL_HW_MIN_VERSION 240001 /* earliest targeted hw */
+#define XCHAL_HW_MAX_VERSION_MAJOR 2400 /* major v of latest tgt hw */
+#define XCHAL_HW_MAX_VERSION_MINOR 1 /* minor v of latest tgt hw */
+#define XCHAL_HW_MAX_VERSION 240001 /* latest targeted hw */
+
+
+/*----------------------------------------------------------------------
+ CACHE
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_ICACHE_LINESIZE 32 /* I-cache line size in bytes */
+#define XCHAL_DCACHE_LINESIZE 32 /* D-cache line size in bytes */
+#define XCHAL_ICACHE_LINEWIDTH 5 /* log2(I line size in bytes) */
+#define XCHAL_DCACHE_LINEWIDTH 5 /* log2(D line size in bytes) */
+
+#define XCHAL_ICACHE_SIZE 16384 /* I-cache size in bytes or 0 */
+#define XCHAL_DCACHE_SIZE 16384 /* D-cache size in bytes or 0 */
+
+#define XCHAL_DCACHE_IS_WRITEBACK 1 /* writeback feature */
+#define XCHAL_DCACHE_IS_COHERENT 0 /* MP coherence feature */
+
+#define XCHAL_HAVE_PREFETCH 0 /* PREFCTL register */
+
+
+
+
+/****************************************************************************
+ Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code
+ ****************************************************************************/
+
+
+#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY
+
+/*----------------------------------------------------------------------
+ CACHE
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_PIF 1 /* any outbound PIF present */
+
+/* If present, cache size in bytes == (ways * 2^(linewidth + setwidth)). */
+
+/* Number of cache sets in log2(lines per way): */
+#define XCHAL_ICACHE_SETWIDTH 7
+#define XCHAL_DCACHE_SETWIDTH 7
+
+/* Cache set associativity (number of ways): */
+#define XCHAL_ICACHE_WAYS 4
+#define XCHAL_DCACHE_WAYS 4
+
+/* Cache features: */
+#define XCHAL_ICACHE_LINE_LOCKABLE 1
+#define XCHAL_DCACHE_LINE_LOCKABLE 1
+#define XCHAL_ICACHE_ECC_PARITY 0
+#define XCHAL_DCACHE_ECC_PARITY 0
+
+/* Cache access size in bytes (affects operation of SICW instruction): */
+#define XCHAL_ICACHE_ACCESS_SIZE 4
+#define XCHAL_DCACHE_ACCESS_SIZE 4
+
+/* Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits): */
+#define XCHAL_CA_BITS 4
+
+
+/*----------------------------------------------------------------------
+ INTERNAL I/D RAM/ROMs and XLMI
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_INSTROM 0 /* number of core instr. ROMs */
+#define XCHAL_NUM_INSTRAM 0 /* number of core instr. RAMs */
+#define XCHAL_NUM_DATAROM 0 /* number of core data ROMs */
+#define XCHAL_NUM_DATARAM 0 /* number of core data RAMs */
+#define XCHAL_NUM_URAM 0 /* number of core unified RAMs*/
+#define XCHAL_NUM_XLMI 0 /* number of core XLMI ports */
+
+#define XCHAL_HAVE_IMEM_LOADSTORE 1 /* can load/store to IROM/IRAM*/
+
+
+/*----------------------------------------------------------------------
+ INTERRUPTS and TIMERS
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_INTERRUPTS 1 /* interrupt option */
+#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* med/high-pri. interrupts */
+#define XCHAL_HAVE_NMI 1 /* non-maskable interrupt */
+#define XCHAL_HAVE_CCOUNT 1 /* CCOUNT reg. (timer option) */
+#define XCHAL_NUM_TIMERS 3 /* number of CCOMPAREn regs */
+#define XCHAL_NUM_INTERRUPTS 22 /* number of interrupts */
+#define XCHAL_NUM_INTERRUPTS_LOG2 5 /* ceil(log2(NUM_INTERRUPTS)) */
+#define XCHAL_NUM_EXTINTERRUPTS 17 /* num of external interrupts */
+#define XCHAL_NUM_INTLEVELS 6 /* number of interrupt levels
+(not including level zero) */
+#define XCHAL_EXCM_LEVEL 3 /* level masked by PS.EXCM */
+/* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */
+
+/* Masks of interrupts at each interrupt level: */
+#define XCHAL_INTLEVEL1_MASK 0x001F80FF
+#define XCHAL_INTLEVEL2_MASK 0x00000100
+#define XCHAL_INTLEVEL3_MASK 0x00200E00
+#define XCHAL_INTLEVEL4_MASK 0x00001000
+#define XCHAL_INTLEVEL5_MASK 0x00002000
+#define XCHAL_INTLEVEL6_MASK 0x00000000
+#define XCHAL_INTLEVEL7_MASK 0x00004000
+
+/* Masks of interrupts at each range 1..n of interrupt levels: */
+#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x001F80FF
+#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x001F81FF
+#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x003F8FFF
+#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x003F9FFF
+#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0x003FBFFF
+#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0x003FBFFF
+#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0x003FFFFF
+
+/* Level of each interrupt: */
+#define XCHAL_INT0_LEVEL 1
+#define XCHAL_INT1_LEVEL 1
+#define XCHAL_INT2_LEVEL 1
+#define XCHAL_INT3_LEVEL 1
+#define XCHAL_INT4_LEVEL 1
+#define XCHAL_INT5_LEVEL 1
+#define XCHAL_INT6_LEVEL 1
+#define XCHAL_INT7_LEVEL 1
+#define XCHAL_INT8_LEVEL 2
+#define XCHAL_INT9_LEVEL 3
+#define XCHAL_INT10_LEVEL 3
+#define XCHAL_INT11_LEVEL 3
+#define XCHAL_INT12_LEVEL 4
+#define XCHAL_INT13_LEVEL 5
+#define XCHAL_INT14_LEVEL 7
+#define XCHAL_INT15_LEVEL 1
+#define XCHAL_INT16_LEVEL 1
+#define XCHAL_INT17_LEVEL 1
+#define XCHAL_INT18_LEVEL 1
+#define XCHAL_INT19_LEVEL 1
+#define XCHAL_INT20_LEVEL 1
+#define XCHAL_INT21_LEVEL 3
+#define XCHAL_DEBUGLEVEL 6 /* debug interrupt level */
+#define XCHAL_HAVE_DEBUG_EXTERN_INT 1 /* OCD external db interrupt */
+#define XCHAL_NMILEVEL 7 /* NMI "level" (for use with
+EXCSAVE/EPS/EPC_n, RFI n) */
+
+/* Type of each interrupt: */
+#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT6_TYPE XTHAL_INTTYPE_TIMER
+#define XCHAL_INT7_TYPE XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT10_TYPE XTHAL_INTTYPE_TIMER
+#define XCHAL_INT11_TYPE XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT12_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT13_TYPE XTHAL_INTTYPE_TIMER
+#define XCHAL_INT14_TYPE XTHAL_INTTYPE_NMI
+#define XCHAL_INT15_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT16_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT17_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT18_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT19_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT20_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT21_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+
+/* Masks of interrupts for each type of interrupt: */
+#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFC00000
+#define XCHAL_INTTYPE_MASK_SOFTWARE 0x00000880
+#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x003F8000
+#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000133F
+#define XCHAL_INTTYPE_MASK_TIMER 0x00002440
+#define XCHAL_INTTYPE_MASK_NMI 0x00004000
+#define XCHAL_INTTYPE_MASK_WRITE_ERROR 0x00000000
+
+/* Interrupt numbers assigned to specific interrupt sources: */
+#define XCHAL_TIMER0_INTERRUPT 6 /* CCOMPARE0 */
+#define XCHAL_TIMER1_INTERRUPT 10 /* CCOMPARE1 */
+#define XCHAL_TIMER2_INTERRUPT 13 /* CCOMPARE2 */
+#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED
+#define XCHAL_NMI_INTERRUPT 14 /* non-maskable interrupt */
+
+/* Interrupt numbers for levels at which only one interrupt is configured: */
+#define XCHAL_INTLEVEL2_NUM 8
+#define XCHAL_INTLEVEL4_NUM 12
+#define XCHAL_INTLEVEL5_NUM 13
+#define XCHAL_INTLEVEL7_NUM 14
+/* (There are many interrupts each at level(s) 1, 3.) */
+
+
+/*
+ * External interrupt vectors/levels.
+ * These macros describe how Xtensa processor interrupt numbers
+ * (as numbered internally, eg. in INTERRUPT and INTENABLE registers)
+ * map to external BInterrupt<n> pins, for those interrupts
+ * configured as external (level-triggered, edge-triggered, or NMI).
+ * See the Xtensa processor databook for more details.
+ */
+
+/* Core interrupt numbers mapped to each EXTERNAL interrupt number: */
+#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */
+#define XCHAL_EXTINT1_NUM 1 /* (intlevel 1) */
+#define XCHAL_EXTINT2_NUM 2 /* (intlevel 1) */
+#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */
+#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */
+#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */
+#define XCHAL_EXTINT6_NUM 8 /* (intlevel 2) */
+#define XCHAL_EXTINT7_NUM 9 /* (intlevel 3) */
+#define XCHAL_EXTINT8_NUM 12 /* (intlevel 4) */
+#define XCHAL_EXTINT9_NUM 14 /* (intlevel 7) */
+#define XCHAL_EXTINT10_NUM 15 /* (intlevel 1) */
+#define XCHAL_EXTINT11_NUM 16 /* (intlevel 1) */
+#define XCHAL_EXTINT12_NUM 17 /* (intlevel 1) */
+#define XCHAL_EXTINT13_NUM 18 /* (intlevel 1) */
+#define XCHAL_EXTINT14_NUM 19 /* (intlevel 1) */
+#define XCHAL_EXTINT15_NUM 20 /* (intlevel 1) */
+#define XCHAL_EXTINT16_NUM 21 /* (intlevel 3) */
+
+
+/*----------------------------------------------------------------------
+ EXCEPTIONS and VECTORS
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture
+number: 1 == XEA1 (old)
+2 == XEA2 (new)
+0 == XEAX (extern) or TX */
+#define XCHAL_HAVE_XEA1 0 /* Exception Architecture 1 */
+#define XCHAL_HAVE_XEA2 1 /* Exception Architecture 2 */
+#define XCHAL_HAVE_XEAX 0 /* External Exception Arch. */
+#define XCHAL_HAVE_EXCEPTIONS 1 /* exception option */
+#define XCHAL_HAVE_HALT 0 /* halt architecture option */
+#define XCHAL_HAVE_BOOTLOADER 0 /* boot loader (for TX) */
+#define XCHAL_HAVE_MEM_ECC_PARITY 0 /* local memory ECC/parity */
+#define XCHAL_HAVE_VECTOR_SELECT 1 /* relocatable vectors */
+#define XCHAL_HAVE_VECBASE 1 /* relocatable vectors */
+#define XCHAL_VECBASE_RESET_VADDR 0x00002000 /* VECBASE reset value */
+#define XCHAL_VECBASE_RESET_PADDR 0x00002000
+#define XCHAL_RESET_VECBASE_OVERLAP 0
+
+#define XCHAL_RESET_VECTOR0_VADDR 0xFE000000
+#define XCHAL_RESET_VECTOR0_PADDR 0xFE000000
+#define XCHAL_RESET_VECTOR1_VADDR 0x00001000
+#define XCHAL_RESET_VECTOR1_PADDR 0x00001000
+#define XCHAL_RESET_VECTOR_VADDR 0xFE000000
+#define XCHAL_RESET_VECTOR_PADDR 0xFE000000
+#define XCHAL_USER_VECOFS 0x00000340
+#define XCHAL_USER_VECTOR_VADDR 0x00002340
+#define XCHAL_USER_VECTOR_PADDR 0x00002340
+#define XCHAL_KERNEL_VECOFS 0x00000300
+#define XCHAL_KERNEL_VECTOR_VADDR 0x00002300
+#define XCHAL_KERNEL_VECTOR_PADDR 0x00002300
+#define XCHAL_DOUBLEEXC_VECOFS 0x000003C0
+#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0x000023C0
+#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x000023C0
+#define XCHAL_WINDOW_OF4_VECOFS 0x00000000
+#define XCHAL_WINDOW_UF4_VECOFS 0x00000040
+#define XCHAL_WINDOW_OF8_VECOFS 0x00000080
+#define XCHAL_WINDOW_UF8_VECOFS 0x000000C0
+#define XCHAL_WINDOW_OF12_VECOFS 0x00000100
+#define XCHAL_WINDOW_UF12_VECOFS 0x00000140
+#define XCHAL_WINDOW_VECTORS_VADDR 0x00002000
+#define XCHAL_WINDOW_VECTORS_PADDR 0x00002000
+#define XCHAL_INTLEVEL2_VECOFS 0x00000180
+#define XCHAL_INTLEVEL2_VECTOR_VADDR 0x00002180
+#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x00002180
+#define XCHAL_INTLEVEL3_VECOFS 0x000001C0
+#define XCHAL_INTLEVEL3_VECTOR_VADDR 0x000021C0
+#define XCHAL_INTLEVEL3_VECTOR_PADDR 0x000021C0
+#define XCHAL_INTLEVEL4_VECOFS 0x00000200
+#define XCHAL_INTLEVEL4_VECTOR_VADDR 0x00002200
+#define XCHAL_INTLEVEL4_VECTOR_PADDR 0x00002200
+#define XCHAL_INTLEVEL5_VECOFS 0x00000240
+#define XCHAL_INTLEVEL5_VECTOR_VADDR 0x00002240
+#define XCHAL_INTLEVEL5_VECTOR_PADDR 0x00002240
+#define XCHAL_INTLEVEL6_VECOFS 0x00000280
+#define XCHAL_INTLEVEL6_VECTOR_VADDR 0x00002280
+#define XCHAL_INTLEVEL6_VECTOR_PADDR 0x00002280
+#define XCHAL_DEBUG_VECOFS XCHAL_INTLEVEL6_VECOFS
+#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL6_VECTOR_VADDR
+#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL6_VECTOR_PADDR
+#define XCHAL_NMI_VECOFS 0x000002C0
+#define XCHAL_NMI_VECTOR_VADDR 0x000022C0
+#define XCHAL_NMI_VECTOR_PADDR 0x000022C0
+#define XCHAL_INTLEVEL7_VECOFS XCHAL_NMI_VECOFS
+#define XCHAL_INTLEVEL7_VECTOR_VADDR XCHAL_NMI_VECTOR_VADDR
+#define XCHAL_INTLEVEL7_VECTOR_PADDR XCHAL_NMI_VECTOR_PADDR
+
+
+/*----------------------------------------------------------------------
+ DEBUG
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_OCD 1 /* OnChipDebug option */
+#define XCHAL_NUM_IBREAK 2 /* number of IBREAKn regs */
+#define XCHAL_NUM_DBREAK 2 /* number of DBREAKn regs */
+#define XCHAL_HAVE_OCD_DIR_ARRAY 1 /* faster OCD option */
+
+
+/*----------------------------------------------------------------------
+ MMU
+ ----------------------------------------------------------------------*/
+
+/* See core-matmap.h header file for more details. */
+
+#define XCHAL_HAVE_TLBS 1 /* inverse of HAVE_CACHEATTR */
+#define XCHAL_HAVE_SPANNING_WAY 1 /* one way maps I+D 4GB vaddr */
+#define XCHAL_SPANNING_WAY 6 /* TLB spanning way number */
+#define XCHAL_HAVE_IDENTITY_MAP 0 /* vaddr == paddr always */
+#define XCHAL_HAVE_CACHEATTR 0 /* CACHEATTR register present */
+#define XCHAL_HAVE_MIMIC_CACHEATTR 0 /* region protection */
+#define XCHAL_HAVE_XLT_CACHEATTR 0 /* region prot. w/translation */
+#define XCHAL_HAVE_PTP_MMU 1 /* full MMU (with page table
+[autorefill] and protection)
+usable for an MMU-based OS */
+/* If none of the above last 4 are set, it's a custom TLB configuration. */
+#define XCHAL_ITLB_ARF_ENTRIES_LOG2 2 /* log2(autorefill way size) */
+#define XCHAL_DTLB_ARF_ENTRIES_LOG2 2 /* log2(autorefill way size) */
+
+#define XCHAL_MMU_ASID_BITS 8 /* number of bits in ASIDs */
+#define XCHAL_MMU_RINGS 4 /* number of rings (1..4) */
+#define XCHAL_MMU_RING_BITS 2 /* num of bits in RING field */
+
+#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */
+
+
+#endif /* _XTENSA_CORE_CONFIGURATION_H */
--- /dev/null
+/* Configuration for the Xtensa architecture for GDB, the GNU debugger.
+
+ Copyright (c) 2003-2010 Tensilica Inc.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+/* idx ofs bi sz al targno flags cp typ group name */
+XTREG(0, 0, 32, 4, 4, 0x0020, 0x0006, -2, 9, 0x0100, pc, 0, 0, 0, 0, 0, 0)
+XTREG(1, 4, 32, 4, 4, 0x0100, 0x0006, -2, 1, 0x0002, ar0, 0, 0, 0, 0, 0, 0)
+XTREG(2, 8, 32, 4, 4, 0x0101, 0x0006, -2, 1, 0x0002, ar1, 0, 0, 0, 0, 0, 0)
+XTREG(3, 12, 32, 4, 4, 0x0102, 0x0006, -2, 1, 0x0002, ar2, 0, 0, 0, 0, 0, 0)
+XTREG(4, 16, 32, 4, 4, 0x0103, 0x0006, -2, 1, 0x0002, ar3, 0, 0, 0, 0, 0, 0)
+XTREG(5, 20, 32, 4, 4, 0x0104, 0x0006, -2, 1, 0x0002, ar4, 0, 0, 0, 0, 0, 0)
+XTREG(6, 24, 32, 4, 4, 0x0105, 0x0006, -2, 1, 0x0002, ar5, 0, 0, 0, 0, 0, 0)
+XTREG(7, 28, 32, 4, 4, 0x0106, 0x0006, -2, 1, 0x0002, ar6, 0, 0, 0, 0, 0, 0)
+XTREG(8, 32, 32, 4, 4, 0x0107, 0x0006, -2, 1, 0x0002, ar7, 0, 0, 0, 0, 0, 0)
+XTREG(9, 36, 32, 4, 4, 0x0108, 0x0006, -2, 1, 0x0002, ar8, 0, 0, 0, 0, 0, 0)
+XTREG(10, 40, 32, 4, 4, 0x0109, 0x0006, -2, 1, 0x0002, ar9, 0, 0, 0, 0, 0, 0)
+XTREG(11, 44, 32, 4, 4, 0x010a, 0x0006, -2, 1, 0x0002, ar10, 0, 0, 0, 0, 0, 0)
+XTREG(12, 48, 32, 4, 4, 0x010b, 0x0006, -2, 1, 0x0002, ar11, 0, 0, 0, 0, 0, 0)
+XTREG(13, 52, 32, 4, 4, 0x010c, 0x0006, -2, 1, 0x0002, ar12, 0, 0, 0, 0, 0, 0)
+XTREG(14, 56, 32, 4, 4, 0x010d, 0x0006, -2, 1, 0x0002, ar13, 0, 0, 0, 0, 0, 0)
+XTREG(15, 60, 32, 4, 4, 0x010e, 0x0006, -2, 1, 0x0002, ar14, 0, 0, 0, 0, 0, 0)
+XTREG(16, 64, 32, 4, 4, 0x010f, 0x0006, -2, 1, 0x0002, ar15, 0, 0, 0, 0, 0, 0)
+XTREG(17, 68, 32, 4, 4, 0x0110, 0x0006, -2, 1, 0x0002, ar16, 0, 0, 0, 0, 0, 0)
+XTREG(18, 72, 32, 4, 4, 0x0111, 0x0006, -2, 1, 0x0002, ar17, 0, 0, 0, 0, 0, 0)
+XTREG(19, 76, 32, 4, 4, 0x0112, 0x0006, -2, 1, 0x0002, ar18, 0, 0, 0, 0, 0, 0)
+XTREG(20, 80, 32, 4, 4, 0x0113, 0x0006, -2, 1, 0x0002, ar19, 0, 0, 0, 0, 0, 0)
+XTREG(21, 84, 32, 4, 4, 0x0114, 0x0006, -2, 1, 0x0002, ar20, 0, 0, 0, 0, 0, 0)
+XTREG(22, 88, 32, 4, 4, 0x0115, 0x0006, -2, 1, 0x0002, ar21, 0, 0, 0, 0, 0, 0)
+XTREG(23, 92, 32, 4, 4, 0x0116, 0x0006, -2, 1, 0x0002, ar22, 0, 0, 0, 0, 0, 0)
+XTREG(24, 96, 32, 4, 4, 0x0117, 0x0006, -2, 1, 0x0002, ar23, 0, 0, 0, 0, 0, 0)
+XTREG(25, 100, 32, 4, 4, 0x0118, 0x0006, -2, 1, 0x0002, ar24, 0, 0, 0, 0, 0, 0)
+XTREG(26, 104, 32, 4, 4, 0x0119, 0x0006, -2, 1, 0x0002, ar25, 0, 0, 0, 0, 0, 0)
+XTREG(27, 108, 32, 4, 4, 0x011a, 0x0006, -2, 1, 0x0002, ar26, 0, 0, 0, 0, 0, 0)
+XTREG(28, 112, 32, 4, 4, 0x011b, 0x0006, -2, 1, 0x0002, ar27, 0, 0, 0, 0, 0, 0)
+XTREG(29, 116, 32, 4, 4, 0x011c, 0x0006, -2, 1, 0x0002, ar28, 0, 0, 0, 0, 0, 0)
+XTREG(30, 120, 32, 4, 4, 0x011d, 0x0006, -2, 1, 0x0002, ar29, 0, 0, 0, 0, 0, 0)
+XTREG(31, 124, 32, 4, 4, 0x011e, 0x0006, -2, 1, 0x0002, ar30, 0, 0, 0, 0, 0, 0)
+XTREG(32, 128, 32, 4, 4, 0x011f, 0x0006, -2, 1, 0x0002, ar31, 0, 0, 0, 0, 0, 0)
+XTREG(33, 132, 32, 4, 4, 0x0200, 0x0006, -2, 2, 0x1100, lbeg, 0, 0, 0, 0, 0, 0)
+XTREG(34, 136, 32, 4, 4, 0x0201, 0x0006, -2, 2, 0x1100, lend, 0, 0, 0, 0, 0, 0)
+XTREG(35, 140, 32, 4, 4, 0x0202, 0x0006, -2, 2, 0x1100, lcount, 0, 0, 0, 0, 0, 0)
+XTREG(36, 144, 6, 4, 4, 0x0203, 0x0006, -2, 2, 0x1100, sar, 0, 0, 0, 0, 0, 0)
+XTREG(37, 148, 32, 4, 4, 0x0205, 0x0006, -2, 2, 0x1100, litbase, 0, 0, 0, 0, 0, 0)
+XTREG(38, 152, 3, 4, 4, 0x0248, 0x0006, -2, 2, 0x1002, windowbase, 0, 0, 0, 0, 0, 0)
+XTREG(39, 156, 8, 4, 4, 0x0249, 0x0006, -2, 2, 0x1002, windowstart, 0, 0, 0, 0, 0, 0)
+XTREG(40, 160, 32, 4, 4, 0x02b0, 0x0002, -2, 2, 0x1000, sr176, 0, 0, 0, 0, 0, 0)
+XTREG(41, 164, 32, 4, 4, 0x02d0, 0x0002, -2, 2, 0x1000, sr208, 0, 0, 0, 0, 0, 0)
+XTREG(42, 168, 19, 4, 4, 0x02e6, 0x0006, -2, 2, 0x1100, ps, 0, 0, 0, 0, 0, 0)
+XTREG(43, 172, 32, 4, 4, 0x03e7, 0x0006, -2, 3, 0x0110, threadptr, 0, 0, 0, 0, 0, 0)
+XTREG(44, 176, 32, 4, 4, 0x020c, 0x0006, -1, 2, 0x1100, scompare1, 0, 0, 0, 0, 0, 0)
+XTREG(45, 180, 32, 4, 4, 0x0210, 0x0006, -1, 2, 0x1100, acclo, 0, 0, 0, 0, 0, 0)
+XTREG(46, 184, 8, 4, 4, 0x0211, 0x0006, -1, 2, 0x1100, acchi, 0, 0, 0, 0, 0, 0)
+XTREG(47, 188, 32, 4, 4, 0x0220, 0x0006, -1, 2, 0x1100, m0, 0, 0, 0, 0, 0, 0)
+XTREG(48, 192, 32, 4, 4, 0x0221, 0x0006, -1, 2, 0x1100, m1, 0, 0, 0, 0, 0, 0)
+XTREG(49, 196, 32, 4, 4, 0x0222, 0x0006, -1, 2, 0x1100, m2, 0, 0, 0, 0, 0, 0)
+XTREG(50, 200, 32, 4, 4, 0x0223, 0x0006, -1, 2, 0x1100, m3, 0, 0, 0, 0, 0, 0)
+XTREG(51, 204, 32, 4, 4, 0x03e6, 0x000e, -1, 3, 0x0110, expstate, 0, 0, 0, 0, 0, 0)
+XTREG(52, 208, 32, 4, 4, 0x0253, 0x0007, -2, 2, 0x1000, ptevaddr, 0, 0, 0, 0, 0, 0)
+XTREG(53, 212, 32, 4, 4, 0x0259, 0x000d, -2, 2, 0x1000, mmid, 0, 0, 0, 0, 0, 0)
+XTREG(54, 216, 32, 4, 4, 0x025a, 0x0007, -2, 2, 0x1000, rasid, 0, 0, 0, 0, 0, 0)
+XTREG(55, 220, 25, 4, 4, 0x025b, 0x0007, -2, 2, 0x1000, itlbcfg, 0, 0, 0, 0, 0, 0)
+XTREG(56, 224, 25, 4, 4, 0x025c, 0x0007, -2, 2, 0x1000, dtlbcfg, 0, 0, 0, 0, 0, 0)
+XTREG(57, 228, 2, 4, 4, 0x0260, 0x0007, -2, 2, 0x1000, ibreakenable, 0, 0, 0, 0, 0, 0)
+XTREG(58, 232, 6, 4, 4, 0x0263, 0x0007, -2, 2, 0x1000, atomctl, 0, 0, 0, 0, 0, 0)
+XTREG(59, 236, 32, 4, 4, 0x0268, 0x0007, -2, 2, 0x1000, ddr, 0, 0, 0, 0, 0, 0)
+XTREG(60, 240, 32, 4, 4, 0x0280, 0x0007, -2, 2, 0x1000, ibreaka0, 0, 0, 0, 0, 0, 0)
+XTREG(61, 244, 32, 4, 4, 0x0281, 0x0007, -2, 2, 0x1000, ibreaka1, 0, 0, 0, 0, 0, 0)
+XTREG(62, 248, 32, 4, 4, 0x0290, 0x0007, -2, 2, 0x1000, dbreaka0, 0, 0, 0, 0, 0, 0)
+XTREG(63, 252, 32, 4, 4, 0x0291, 0x0007, -2, 2, 0x1000, dbreaka1, 0, 0, 0, 0, 0, 0)
+XTREG(64, 256, 32, 4, 4, 0x02a0, 0x0007, -2, 2, 0x1000, dbreakc0, 0, 0, 0, 0, 0, 0)
+XTREG(65, 260, 32, 4, 4, 0x02a1, 0x0007, -2, 2, 0x1000, dbreakc1, 0, 0, 0, 0, 0, 0)
+XTREG(66, 264, 32, 4, 4, 0x02b1, 0x0007, -2, 2, 0x1000, epc1, 0, 0, 0, 0, 0, 0)
+XTREG(67, 268, 32, 4, 4, 0x02b2, 0x0007, -2, 2, 0x1000, epc2, 0, 0, 0, 0, 0, 0)
+XTREG(68, 272, 32, 4, 4, 0x02b3, 0x0007, -2, 2, 0x1000, epc3, 0, 0, 0, 0, 0, 0)
+XTREG(69, 276, 32, 4, 4, 0x02b4, 0x0007, -2, 2, 0x1000, epc4, 0, 0, 0, 0, 0, 0)
+XTREG(70, 280, 32, 4, 4, 0x02b5, 0x0007, -2, 2, 0x1000, epc5, 0, 0, 0, 0, 0, 0)
+XTREG(71, 284, 32, 4, 4, 0x02b6, 0x0007, -2, 2, 0x1000, epc6, 0, 0, 0, 0, 0, 0)
+XTREG(72, 288, 32, 4, 4, 0x02b7, 0x0007, -2, 2, 0x1000, epc7, 0, 0, 0, 0, 0, 0)
+XTREG(73, 292, 32, 4, 4, 0x02c0, 0x0007, -2, 2, 0x1000, depc, 0, 0, 0, 0, 0, 0)
+XTREG(74, 296, 19, 4, 4, 0x02c2, 0x0007, -2, 2, 0x1000, eps2, 0, 0, 0, 0, 0, 0)
+XTREG(75, 300, 19, 4, 4, 0x02c3, 0x0007, -2, 2, 0x1000, eps3, 0, 0, 0, 0, 0, 0)
+XTREG(76, 304, 19, 4, 4, 0x02c4, 0x0007, -2, 2, 0x1000, eps4, 0, 0, 0, 0, 0, 0)
+XTREG(77, 308, 19, 4, 4, 0x02c5, 0x0007, -2, 2, 0x1000, eps5, 0, 0, 0, 0, 0, 0)
+XTREG(78, 312, 19, 4, 4, 0x02c6, 0x0007, -2, 2, 0x1000, eps6, 0, 0, 0, 0, 0, 0)
+XTREG(79, 316, 19, 4, 4, 0x02c7, 0x0007, -2, 2, 0x1000, eps7, 0, 0, 0, 0, 0, 0)
+XTREG(80, 320, 32, 4, 4, 0x02d1, 0x0007, -2, 2, 0x1000, excsave1, 0, 0, 0, 0, 0, 0)
+XTREG(81, 324, 32, 4, 4, 0x02d2, 0x0007, -2, 2, 0x1000, excsave2, 0, 0, 0, 0, 0, 0)
+XTREG(82, 328, 32, 4, 4, 0x02d3, 0x0007, -2, 2, 0x1000, excsave3, 0, 0, 0, 0, 0, 0)
+XTREG(83, 332, 32, 4, 4, 0x02d4, 0x0007, -2, 2, 0x1000, excsave4, 0, 0, 0, 0, 0, 0)
+XTREG(84, 336, 32, 4, 4, 0x02d5, 0x0007, -2, 2, 0x1000, excsave5, 0, 0, 0, 0, 0, 0)
+XTREG(85, 340, 32, 4, 4, 0x02d6, 0x0007, -2, 2, 0x1000, excsave6, 0, 0, 0, 0, 0, 0)
+XTREG(86, 344, 32, 4, 4, 0x02d7, 0x0007, -2, 2, 0x1000, excsave7, 0, 0, 0, 0, 0, 0)
+XTREG(87, 348, 8, 4, 4, 0x02e0, 0x0007, -2, 2, 0x1000, cpenable, 0, 0, 0, 0, 0, 0)
+XTREG(88, 352, 22, 4, 4, 0x02e2, 0x000b, -2, 2, 0x1000, interrupt, 0, 0, 0, 0, 0, 0)
+XTREG(89, 356, 22, 4, 4, 0x02e2, 0x000d, -2, 2, 0x1000, intset, 0, 0, 0, 0, 0, 0)
+XTREG(90, 360, 22, 4, 4, 0x02e3, 0x000d, -2, 2, 0x1000, intclear, 0, 0, 0, 0, 0, 0)
+XTREG(91, 364, 22, 4, 4, 0x02e4, 0x0007, -2, 2, 0x1000, intenable, 0, 0, 0, 0, 0, 0)
+XTREG(92, 368, 32, 4, 4, 0x02e7, 0x0007, -2, 2, 0x1000, vecbase, 0, 0, 0, 0, 0, 0)
+XTREG(93, 372, 6, 4, 4, 0x02e8, 0x0007, -2, 2, 0x1000, exccause, 0, 0, 0, 0, 0, 0)
+XTREG(94, 376, 12, 4, 4, 0x02e9, 0x0003, -2, 2, 0x1000, debugcause, 0, 0, 0, 0, 0, 0)
+XTREG(95, 380, 32, 4, 4, 0x02ea, 0x000f, -2, 2, 0x1000, ccount, 0, 0, 0, 0, 0, 0)
+XTREG(96, 384, 32, 4, 4, 0x02eb, 0x0003, -2, 2, 0x1000, prid, 0, 0, 0, 0, 0, 0)
+XTREG(97, 388, 32, 4, 4, 0x02ec, 0x000f, -2, 2, 0x1000, icount, 0, 0, 0, 0, 0, 0)
+XTREG(98, 392, 4, 4, 4, 0x02ed, 0x0007, -2, 2, 0x1000, icountlevel, 0, 0, 0, 0, 0, 0)
+XTREG(99, 396, 32, 4, 4, 0x02ee, 0x0007, -2, 2, 0x1000, excvaddr, 0, 0, 0, 0, 0, 0)
+XTREG(100, 400, 32, 4, 4, 0x02f0, 0x000f, -2, 2, 0x1000, ccompare0, 0, 0, 0, 0, 0, 0)
+XTREG(101, 404, 32, 4, 4, 0x02f1, 0x000f, -2, 2, 0x1000, ccompare1, 0, 0, 0, 0, 0, 0)
+XTREG(102, 408, 32, 4, 4, 0x02f2, 0x000f, -2, 2, 0x1000, ccompare2, 0, 0, 0, 0, 0, 0)
+XTREG(103, 412, 32, 4, 4, 0x02f4, 0x0007, -2, 2, 0x1000, misc0, 0, 0, 0, 0, 0, 0)
+XTREG(104, 416, 32, 4, 4, 0x02f5, 0x0007, -2, 2, 0x1000, misc1, 0, 0, 0, 0, 0, 0)
+XTREG(105, 420, 32, 4, 4, 0x0000, 0x0006, -2, 8, 0x0100, a0, 0, 0, 0, 0, 0, 0)
+XTREG(106, 424, 32, 4, 4, 0x0001, 0x0006, -2, 8, 0x0100, a1, 0, 0, 0, 0, 0, 0)
+XTREG(107, 428, 32, 4, 4, 0x0002, 0x0006, -2, 8, 0x0100, a2, 0, 0, 0, 0, 0, 0)
+XTREG(108, 432, 32, 4, 4, 0x0003, 0x0006, -2, 8, 0x0100, a3, 0, 0, 0, 0, 0, 0)
+XTREG(109, 436, 32, 4, 4, 0x0004, 0x0006, -2, 8, 0x0100, a4, 0, 0, 0, 0, 0, 0)
+XTREG(110, 440, 32, 4, 4, 0x0005, 0x0006, -2, 8, 0x0100, a5, 0, 0, 0, 0, 0, 0)
+XTREG(111, 444, 32, 4, 4, 0x0006, 0x0006, -2, 8, 0x0100, a6, 0, 0, 0, 0, 0, 0)
+XTREG(112, 448, 32, 4, 4, 0x0007, 0x0006, -2, 8, 0x0100, a7, 0, 0, 0, 0, 0, 0)
+XTREG(113, 452, 32, 4, 4, 0x0008, 0x0006, -2, 8, 0x0100, a8, 0, 0, 0, 0, 0, 0)
+XTREG(114, 456, 32, 4, 4, 0x0009, 0x0006, -2, 8, 0x0100, a9, 0, 0, 0, 0, 0, 0)
+XTREG(115, 460, 32, 4, 4, 0x000a, 0x0006, -2, 8, 0x0100, a10, 0, 0, 0, 0, 0, 0)
+XTREG(116, 464, 32, 4, 4, 0x000b, 0x0006, -2, 8, 0x0100, a11, 0, 0, 0, 0, 0, 0)
+XTREG(117, 468, 32, 4, 4, 0x000c, 0x0006, -2, 8, 0x0100, a12, 0, 0, 0, 0, 0, 0)
+XTREG(118, 472, 32, 4, 4, 0x000d, 0x0006, -2, 8, 0x0100, a13, 0, 0, 0, 0, 0, 0)
+XTREG(119, 476, 32, 4, 4, 0x000e, 0x0006, -2, 8, 0x0100, a14, 0, 0, 0, 0, 0, 0)
+XTREG(120, 480, 32, 4, 4, 0x000f, 0x0006, -2, 8, 0x0100, a15, 0, 0, 0, 0, 0, 0)
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Open Source and Linux Lab nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
#include "cpu.h"
#include "exec-all.h"
#include "gdbstub.h"
--- /dev/null
+/*
+ * QEMU Xtensa CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Open Source and Linux Lab nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef QEMU_XTENSA_CPU_QOM_H
+#define QEMU_XTENSA_CPU_QOM_H
+
+#include "qemu/cpu.h"
+#include "cpu.h"
+
+#define TYPE_XTENSA_CPU "xtensa-cpu"
+
+#define XTENSA_CPU_CLASS(class) \
+ OBJECT_CLASS_CHECK(XtensaCPUClass, (class), TYPE_XTENSA_CPU)
+#define XTENSA_CPU(obj) \
+ OBJECT_CHECK(XtensaCPU, (obj), TYPE_XTENSA_CPU)
+#define XTENSA_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(XtensaCPUClass, (obj), TYPE_XTENSA_CPU)
+
+/**
+ * XtensaCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * An Xtensa CPU model.
+ */
+typedef struct XtensaCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+} XtensaCPUClass;
+
+/**
+ * XtensaCPU:
+ * @env: #CPUXtensaState
+ *
+ * An Xtensa CPU.
+ */
+typedef struct XtensaCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUXtensaState env;
+} XtensaCPU;
+
+static inline XtensaCPU *xtensa_env_get_cpu(const CPUXtensaState *env)
+{
+ return XTENSA_CPU(container_of(env, XtensaCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(xtensa_env_get_cpu(e))
+
+
+#endif
--- /dev/null
+/*
+ * QEMU Xtensa CPU
+ *
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Open Source and Linux Lab nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu-qom.h"
+#include "qemu-common.h"
+
+
+/* CPUClass::reset() */
+static void xtensa_cpu_reset(CPUState *s)
+{
+ XtensaCPU *cpu = XTENSA_CPU(s);
+ XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+ CPUXtensaState *env = &cpu->env;
+
+ xcc->parent_reset(s);
+
+ env->exception_taken = 0;
+ env->pc = env->config->exception_vector[EXC_RESET];
+ env->sregs[LITBASE] &= ~1;
+ env->sregs[PS] = xtensa_option_enabled(env->config,
+ XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
+ env->sregs[VECBASE] = env->config->vecbase;
+ env->sregs[IBREAKENABLE] = 0;
+
+ env->pending_irq_level = 0;
+ reset_mmu(env);
+}
+
+static void xtensa_cpu_initfn(Object *obj)
+{
+ XtensaCPU *cpu = XTENSA_CPU(obj);
+ CPUXtensaState *env = &cpu->env;
+
+ cpu_exec_init(env);
+}
+
+static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
+{
+ CPUClass *cc = CPU_CLASS(oc);
+ XtensaCPUClass *xcc = XTENSA_CPU_CLASS(cc);
+
+ xcc->parent_reset = cc->reset;
+ cc->reset = xtensa_cpu_reset;
+}
+
+static const TypeInfo xtensa_cpu_type_info = {
+ .name = TYPE_XTENSA_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(XtensaCPU),
+ .instance_init = xtensa_cpu_initfn,
+ .abstract = false,
+ .class_size = sizeof(XtensaCPUClass),
+ .class_init = xtensa_cpu_class_init,
+};
+
+static void xtensa_cpu_register_types(void)
+{
+ type_register_static(&xtensa_cpu_type_info);
+}
+
+type_init(xtensa_cpu_register_types)
int xtensa_get_physical_addr(CPUXtensaState *env,
uint32_t vaddr, int is_write, int mmu_idx,
uint32_t *paddr, uint32_t *page_size, unsigned *access);
+void reset_mmu(CPUXtensaState *env);
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env);
void debug_exception_env(CPUXtensaState *new_env, uint32_t cause);
}
#include "cpu-all.h"
+#include "cpu-qom.h"
#include "exec-all.h"
static inline int cpu_has_work(CPUXtensaState *env)
#include "hw/loader.h"
#endif
-static void reset_mmu(CPUXtensaState *env);
-
void cpu_state_reset(CPUXtensaState *env)
{
- env->exception_taken = 0;
- env->pc = env->config->exception_vector[EXC_RESET];
- env->sregs[LITBASE] &= ~1;
- env->sregs[PS] = xtensa_option_enabled(env->config,
- XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
- env->sregs[VECBASE] = env->config->vecbase;
- env->sregs[IBREAKENABLE] = 0;
-
- env->pending_irq_level = 0;
- reset_mmu(env);
+ cpu_reset(ENV_GET_CPU(env));
}
static struct XtensaConfigList *xtensa_cores;
{
static int tcg_inited;
static int debug_handler_inited;
+ XtensaCPU *cpu;
CPUXtensaState *env;
const XtensaConfig *config = NULL;
XtensaConfigList *core = xtensa_cores;
return NULL;
}
- env = g_malloc0(sizeof(*env));
+ cpu = XTENSA_CPU(object_new(TYPE_XTENSA_CPU));
+ env = &cpu->env;
env->config = config;
- cpu_exec_init(env);
if (!tcg_inited) {
tcg_inited = 1;
}
}
-static void reset_mmu(CPUXtensaState *env)
+void reset_mmu(CPUXtensaState *env)
{
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
env->sregs[RASID] = 0x04030201;
--- /dev/null
+#include "def-helper.h"
+
+DEF_HELPER_1(exception, void, i32)
+DEF_HELPER_2(exception_cause, void, i32, i32)
+DEF_HELPER_3(exception_cause_vaddr, void, i32, i32, i32)
+DEF_HELPER_2(debug_exception, void, i32, i32)
+
+DEF_HELPER_1(nsa, i32, i32)
+DEF_HELPER_1(nsau, i32, i32)
+DEF_HELPER_1(wsr_windowbase, void, i32)
+DEF_HELPER_3(entry, void, i32, i32, i32)
+DEF_HELPER_1(retw, i32, i32)
+DEF_HELPER_1(rotw, void, i32)
+DEF_HELPER_2(window_check, void, i32, i32)
+DEF_HELPER_0(restore_owb, void)
+DEF_HELPER_1(movsp, void, i32)
+DEF_HELPER_1(wsr_lbeg, void, i32)
+DEF_HELPER_1(wsr_lend, void, i32)
+DEF_HELPER_1(simcall, void, env)
+DEF_HELPER_0(dump_state, void)
+
+DEF_HELPER_2(waiti, void, i32, i32)
+DEF_HELPER_2(timer_irq, void, i32, i32)
+DEF_HELPER_1(advance_ccount, void, i32)
+DEF_HELPER_1(check_interrupts, void, env)
+
+DEF_HELPER_1(wsr_rasid, void, i32)
+DEF_HELPER_2(rtlb0, i32, i32, i32)
+DEF_HELPER_2(rtlb1, i32, i32, i32)
+DEF_HELPER_2(itlb, void, i32, i32)
+DEF_HELPER_2(ptlb, i32, i32, i32)
+DEF_HELPER_3(wtlb, void, i32, i32, i32)
+
+DEF_HELPER_1(wsr_ibreakenable, void, i32)
+DEF_HELPER_2(wsr_ibreaka, void, i32, i32)
+DEF_HELPER_2(wsr_dbreaka, void, i32, i32)
+DEF_HELPER_2(wsr_dbreakc, void, i32, i32)
+
+#include "def-helper.h"
+++ /dev/null
-#include "def-helper.h"
-
-DEF_HELPER_1(exception, void, i32)
-DEF_HELPER_2(exception_cause, void, i32, i32)
-DEF_HELPER_3(exception_cause_vaddr, void, i32, i32, i32)
-DEF_HELPER_2(debug_exception, void, i32, i32)
-
-DEF_HELPER_1(nsa, i32, i32)
-DEF_HELPER_1(nsau, i32, i32)
-DEF_HELPER_1(wsr_windowbase, void, i32)
-DEF_HELPER_3(entry, void, i32, i32, i32)
-DEF_HELPER_1(retw, i32, i32)
-DEF_HELPER_1(rotw, void, i32)
-DEF_HELPER_2(window_check, void, i32, i32)
-DEF_HELPER_0(restore_owb, void)
-DEF_HELPER_1(movsp, void, i32)
-DEF_HELPER_1(wsr_lbeg, void, i32)
-DEF_HELPER_1(wsr_lend, void, i32)
-DEF_HELPER_1(simcall, void, env)
-DEF_HELPER_0(dump_state, void)
-
-DEF_HELPER_2(waiti, void, i32, i32)
-DEF_HELPER_2(timer_irq, void, i32, i32)
-DEF_HELPER_1(advance_ccount, void, i32)
-DEF_HELPER_1(check_interrupts, void, env)
-
-DEF_HELPER_1(wsr_rasid, void, i32)
-DEF_HELPER_2(rtlb0, i32, i32, i32)
-DEF_HELPER_2(rtlb1, i32, i32, i32)
-DEF_HELPER_2(itlb, void, i32, i32)
-DEF_HELPER_2(ptlb, i32, i32, i32)
-DEF_HELPER_3(wtlb, void, i32, i32, i32)
-
-DEF_HELPER_1(wsr_ibreakenable, void, i32)
-DEF_HELPER_2(wsr_ibreaka, void, i32, i32)
-DEF_HELPER_2(wsr_dbreaka, void, i32, i32)
-DEF_HELPER_2(wsr_dbreakc, void, i32, i32)
-
-#include "def-helper.h"
#include "cpu.h"
#include "dyngen-exec.h"
-#include "helpers.h"
+#include "helper.h"
#include "host-utils.h"
static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
- void *retaddr);
+ uintptr_t retaddr);
#define ALIGNED_ONLY
#define MMUSUFFIX _mmu
#define SHIFT 3
#include "softmmu_template.h"
-static void do_restore_state(void *pc_ptr)
+static void do_restore_state(uintptr_t pc)
{
TranslationBlock *tb;
- uint32_t pc = (uint32_t)(intptr_t)pc_ptr;
tb = tb_find_pc(pc);
if (tb) {
}
static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
- void *retaddr)
+ uintptr_t retaddr)
{
if (xtensa_option_enabled(env->config, XTENSA_OPTION_UNALIGNED_EXCEPTION) &&
!xtensa_option_enabled(env->config, XTENSA_OPTION_HW_ALIGNMENT)) {
}
void tlb_fill(CPUXtensaState *env1, target_ulong vaddr, int is_write, int mmu_idx,
- void *retaddr)
+ uintptr_t retaddr)
{
CPUXtensaState *saved_env = env;
env = saved_env;
}
+static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr)
+{
+ uint32_t paddr;
+ uint32_t page_size;
+ unsigned access;
+ int ret = xtensa_get_physical_addr(env, vaddr, 2, 0,
+ &paddr, &page_size, &access);
+ if (ret == 0) {
+ tb_invalidate_phys_addr(paddr);
+ }
+}
+
void HELPER(exception)(uint32_t excp)
{
env->exception_index = excp;
void HELPER(wsr_lbeg)(uint32_t v)
{
if (env->sregs[LBEG] != v) {
- tb_invalidate_phys_page_range(
- env->sregs[LEND] - 1, env->sregs[LEND], 0);
+ tb_invalidate_virtual_addr(env, env->sregs[LEND] - 1);
env->sregs[LBEG] = v;
}
}
void HELPER(wsr_lend)(uint32_t v)
{
if (env->sregs[LEND] != v) {
- tb_invalidate_phys_page_range(
- env->sregs[LEND] - 1, env->sregs[LEND], 0);
+ tb_invalidate_virtual_addr(env, env->sregs[LEND] - 1);
env->sregs[LEND] = v;
- tb_invalidate_phys_page_range(
- env->sregs[LEND] - 1, env->sregs[LEND], 0);
+ tb_invalidate_virtual_addr(env, env->sregs[LEND] - 1);
}
}
for (i = 0; i < env->config->nibreak; ++i) {
if (change & (1 << i)) {
- tb_invalidate_phys_page_range(
- env->sregs[IBREAKA + i], env->sregs[IBREAKA + i] + 1, 0);
+ tb_invalidate_virtual_addr(env, env->sregs[IBREAKA + i]);
}
}
env->sregs[IBREAKENABLE] = v & ((1 << env->config->nibreak) - 1);
void HELPER(wsr_ibreaka)(uint32_t i, uint32_t v)
{
if (env->sregs[IBREAKENABLE] & (1 << i) && env->sregs[IBREAKA + i] != v) {
- tb_invalidate_phys_page_range(
- env->sregs[IBREAKA + i], env->sregs[IBREAKA + i] + 1, 0);
- tb_invalidate_phys_page_range(v, v + 1, 0);
+ tb_invalidate_virtual_addr(env, env->sregs[IBREAKA + i]);
+ tb_invalidate_virtual_addr(env, v);
}
env->sregs[IBREAKA + i] = v;
}
#include "qemu-log.h"
#include "sysemu.h"
-#include "helpers.h"
+#include "helper.h"
#define GEN_HELPER 1
-#include "helpers.h"
+#include "helper.h"
typedef struct DisasContext {
const XtensaConfig *config;
}
}
#define GEN_HELPER 2
-#include "helpers.h"
+#include "helper.h"
}
static inline bool option_bits_enabled(DisasContext *dc, uint64_t opt)
static void gen_wsr_lbeg(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
gen_helper_wsr_lbeg(s);
+ gen_jumpi_check_loop_end(dc, 0);
}
static void gen_wsr_lend(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
gen_helper_wsr_lend(s);
+ gen_jumpi_check_loop_end(dc, 0);
}
static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
static const int tcg_target_call_iarg_regs[] = {
#if TCG_TARGET_REG_BITS == 64
+#if defined(_WIN64)
+ TCG_REG_RCX,
+ TCG_REG_RDX,
+#else
TCG_REG_RDI,
TCG_REG_RSI,
TCG_REG_RDX,
TCG_REG_RCX,
+#endif
TCG_REG_R8,
TCG_REG_R9,
#else
ct->ct |= TCG_CT_REG;
if (TCG_TARGET_REG_BITS == 64) {
tcg_regset_set32(ct->u.regs, 0, 0xffff);
- tcg_regset_reset_reg(ct->u.regs, TCG_REG_RSI);
- tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDI);
+ tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[0]);
+ tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[1]);
#ifdef CONFIG_TCG_PASS_AREG0
- tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDX);
+ tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[2]);
#endif
} else {
tcg_regset_set32(ct->u.regs, 0, 0xff);
use the ADDR32 prefix. For now, do nothing. */
if (offset != GUEST_BASE) {
- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_RDI, GUEST_BASE);
- tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_RDI, base);
- base = TCG_REG_RDI, offset = 0;
+ tcg_out_movi(s, TCG_TYPE_I64,
+ tcg_target_call_iarg_regs[0], GUEST_BASE);
+ tgen_arithr(s, ARITH_ADD + P_REXW,
+ tcg_target_call_iarg_regs[0], base);
+ base = tcg_target_call_iarg_regs[0];
+ offset = 0;
}
}
#endif
#else
tcg_out_mov(s, (opc == 3 ? TCG_TYPE_I64 : TCG_TYPE_I32),
- TCG_REG_RSI, data_reg);
- tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index);
+ tcg_target_call_iarg_regs[1], data_reg);
+ tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], mem_index);
stack_adjust = 0;
#ifdef CONFIG_TCG_PASS_AREG0
/* XXX/FIXME: suboptimal */
use the ADDR32 prefix. For now, do nothing. */
if (offset != GUEST_BASE) {
- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_RDI, GUEST_BASE);
- tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_RDI, base);
- base = TCG_REG_RDI, offset = 0;
+ tcg_out_movi(s, TCG_TYPE_I64,
+ tcg_target_call_iarg_regs[0], GUEST_BASE);
+ tgen_arithr(s, ARITH_ADD + P_REXW,
+ tcg_target_call_iarg_regs[0], base);
+ base = tcg_target_call_iarg_regs[0];
+ offset = 0;
}
}
#if TCG_TARGET_REG_BITS == 64
TCG_REG_RBP,
TCG_REG_RBX,
+#if defined(_WIN64)
+ TCG_REG_RDI,
+ TCG_REG_RSI,
+#endif
TCG_REG_R12,
TCG_REG_R13,
TCG_REG_R14, /* Currently used for the global env. */
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_EDX);
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_ECX);
if (TCG_TARGET_REG_BITS == 64) {
+#if !defined(_WIN64)
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RDI);
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RSI);
+#endif
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R8);
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R9);
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R10);
DebugFrameFDE fde;
} DebugFrame;
-#if TCG_TARGET_REG_BITS == 64
+#if !defined(__ELF__)
+ /* Host machine without ELF. */
+#elif TCG_TARGET_REG_BITS == 64
#define ELF_HOST_MACHINE EM_X86_64
static DebugFrame debug_frame = {
.cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
};
#endif
+#if defined(ELF_HOST_MACHINE)
void tcg_register_jit(void *buf, size_t buf_size)
{
/* We're expecting a 2 byte uleb128 encoded value. */
tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
}
+#endif
@echo "Default options are -k and (for make V=1) --verbose; they can be"
@echo "changed with variable GTESTER_OPTIONS."
-.SECONDARY:
-
SPEED = quick
GTESTER_OPTIONS = -k $(if $(V),--verbose,-q)
debug-%.tst: %.tst
$(SIM) $(SIMDEBUG) $(SIMFLAGS) ./$<
+host-debug-%.tst: %.tst
+ gdb --args $(SIM) $(SIMFLAGS) ./$<
+
clean:
$(RM) -fr $(TESTCASES) $(CRT)
exit
.endm
+.macro print text
+.data
+97: .ascii "\text\n"
+98:
+ .align 4
+.text
+ movi a2, 4
+ movi a3, 2
+ movi a4, 97b
+ movi a5, 98b
+ sub a5, a5, a4
+ simcall
+.endm
+
.macro test name
+ //print test_\name
+test_\name:
+.global test_\name
.endm
.macro test_end
assert eq, a2, a3
test_end
+test ibreak_remove
+ set_vector debug_vector, 3f
+ rsil a2, debug_level - 1
+ movi a2, 2f
+ wsr a2, ibreaka0
+ movi a3, 1
+1:
+ wsr a3, ibreakenable
+ isync
+2:
+ beqz a3, 4f
+ test_fail
+3:
+ assert eqi, a3, 1
+ rsr a2, ps
+ movi a3, 0x1f
+ and a2, a2, a3
+ movi a3, 0x10 | debug_level
+ assert eq, a2, a3
+ rsr a2, epc6
+ movi a3, 2b
+ assert eq, a2, a3
+ rsr a2, debugcause
+ movi a3, 0x2
+ assert eq, a2, a3
+
+ movi a2, 0x40000
+ wsr a2, ps
+ isync
+ movi a3, 0
+ j 1b
+4:
+test_end
+
test ibreak_priority
set_vector debug_vector, 2f
rsil a2, debug_level - 1
assert eqi, a2, 1
test_end
+test lbeg_invalidation
+ movi a2, 0
+ movi a3, 1
+ movi a4, 1f
+ movi a5, 3f
+ wsr a3, lcount
+ wsr a4, lbeg
+ wsr a5, lend
+ isync
+ j 1f
+.align 4
+1:
+ addi a2, a2, 1
+ j 2f
+.align 4
+2:
+ addi a2, a2, 2
+ movi a3, 2b
+ wsr a3, lbeg
+ isync
+ nop
+3:
+ assert eqi, a2, 5
+test_end
+
+test lend_invalidation
+ movi a2, 0
+ movi a3, 5
+ movi a4, 1f
+ movi a5, 2f
+ wsr a3, lcount
+ wsr a4, lbeg
+ wsr a5, lend
+ isync
+ j 1f
+.align 4
+1:
+ addi a2, a2, 1
+2:
+ beqi a3, 3, 1f
+ assert eqi, a2, 6
+ movi a3, 3
+ wsr a3, lcount
+ wsr a4, lend
+ isync
+ j 1b
+1:
+ assert eqi, a2, 7
+test_end
+
test_suite_end
the effective address of the memory exception. 'is_write' is 1 if a
write caused the exception and otherwise 0'. 'old_set' is the
signal set which should be restored */
-static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
#include <stddef.h>
#include "cpu.h"
#include "dyngen-exec.h"
-#include "helpers.h"
+#include "helper.h"
#include "qemu-log.h"
enum {