diff options
85 files changed, 2236 insertions, 632 deletions
diff --git a/Makefile.target b/Makefile.target index f9ce361d1f..84951a09ec 100644 --- a/Makefile.target +++ b/Makefile.target @@ -102,7 +102,9 @@ endif 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 @@ -366,6 +368,7 @@ obj-arm-y += cadence_uart.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 @@ -414,6 +417,7 @@ obj-xtensa-y += xtensa_sim.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) diff --git a/arch_init.c b/arch_init.c index 595badf50f..9a35aeea30 100644 --- a/arch_init.c +++ b/arch_init.c @@ -475,7 +475,7 @@ struct soundhw { static struct soundhw soundhw[] = { #ifdef HAS_AUDIO_CHOICE -#if defined(TARGET_I386) || defined(TARGET_MIPS) +#ifdef CONFIG_PCSPK { "pcspk", "PC speaker", diff --git a/coroutine-gthread.c b/coroutine-gthread.c index 662801b2fa..30c24c94b8 100644 --- a/coroutine-gthread.c +++ b/coroutine-gthread.c @@ -26,13 +26,93 @@ typedef struct { 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()) { @@ -44,7 +124,7 @@ static void __attribute__((constructor)) coroutine_init(void) #endif } - coroutine_cond = g_cond_new(); + init_coroutine_cond(); } static void coroutine_wait_runnable_locked(CoroutineGThread *co) @@ -65,7 +145,7 @@ static gpointer coroutine_thread(gpointer opaque) { 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); @@ -77,8 +157,7 @@ Coroutine *qemu_coroutine_new(void) 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; @@ -117,12 +196,11 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, 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; @@ -130,7 +208,7 @@ Coroutine *qemu_coroutine_self(void) bool qemu_in_coroutine(void) { - CoroutineGThread *co = g_static_private_get(&coroutine_key); + CoroutineGThread *co = get_coroutine_key(); return co && co->base.caller; } @@ -222,8 +222,8 @@ extern unsigned long reserved_va; #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))) @@ -299,10 +299,10 @@ extern unsigned long reserved_va; #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) diff --git a/cpu-defs.h b/cpu-defs.h index 326896826e..f49e9500a9 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -98,12 +98,12 @@ typedef struct CPUTLBEntry { 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]; @@ -166,8 +166,8 @@ typedef struct CPUWatchpoint { /* 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 */ \ diff --git a/cpu-exec.c b/cpu-exec.c index d153f978e1..0344cd5c59 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -541,8 +541,8 @@ int cpu_exec(CPUArchState *env) 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 @@ -268,7 +268,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) /* 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); @@ -276,7 +276,7 @@ void disas(FILE *out, void *code, unsigned long size) 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 @@ -320,8 +320,8 @@ void disas(FILE *out, void *code, unsigned long size) (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) diff --git a/exec-all.h b/exec-all.h index fa7bdfecd8..6bcc07538f 100644 --- a/exec-all.h +++ b/exec-all.h @@ -87,7 +87,7 @@ int cpu_gen_code(CPUArchState *env, struct TranslationBlock *tb, 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); @@ -102,6 +102,7 @@ void tlb_flush(CPUArchState *env, int flush_global); 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 */ @@ -287,13 +288,13 @@ extern void *tci_tb_ptr; # 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) @@ -305,7 +306,7 @@ void io_mem_write(struct MemoryRegion *mr, target_phys_addr_t addr, 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" @@ -93,8 +93,7 @@ spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; #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 @@ -177,9 +176,9 @@ typedef struct PageDesc { #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. */ @@ -888,8 +887,8 @@ static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb) 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; @@ -909,8 +908,8 @@ static inline void tb_jmp_remove(TranslationBlock *tb, int n) /* 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) { @@ -930,7 +929,7 @@ static inline void tb_jmp_remove(TranslationBlock *tb, int n) 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) @@ -975,16 +974,16 @@ 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++; } @@ -1025,8 +1024,8 @@ static void build_page_bitmap(PageDesc *p) 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 @@ -1070,7 +1069,8 @@ TranslationBlock *tb_gen_code(CPUArchState *env, 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; @@ -1118,8 +1118,8 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, /* 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) { @@ -1202,7 +1202,8 @@ static inline void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len) 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); @@ -1221,7 +1222,7 @@ static inline void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len) #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; @@ -1246,8 +1247,8 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr, } #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) { @@ -1295,7 +1296,7 @@ static inline void tb_alloc_page(TranslationBlock *tb, #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 @@ -1362,7 +1363,7 @@ void tb_link_page(TranslationBlock *tb, 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; @@ -1383,21 +1384,22 @@ void tb_link_page(TranslationBlock *tb, 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) { @@ -1420,8 +1422,8 @@ static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n) 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]; @@ -1433,8 +1435,8 @@ static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n) 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]; @@ -1463,13 +1465,11 @@ static void breakpoint_invalidate(CPUArchState *env, target_ulong pc) 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))) { @@ -1479,6 +1479,11 @@ static void breakpoint_invalidate(CPUArchState *env, target_ulong pc) + 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 */ @@ -2038,9 +2043,9 @@ static bool tlb_is_dirty_ram(CPUTLBEntry *tlbe) } 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) { @@ -2054,7 +2059,7 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, int dirty_flags) { CPUArchState *env; - unsigned long length, start1; + uintptr_t length, start1; int i; start &= TARGET_PAGE_MASK; @@ -2067,10 +2072,10 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, /* 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(); } @@ -2098,7 +2103,7 @@ static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry) 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)) { @@ -2188,7 +2193,7 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr, 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; @@ -2210,7 +2215,7 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr, 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; @@ -2300,7 +2305,7 @@ struct walk_memory_regions_data { walk_memory_regions_fn fn; void *priv; - unsigned long start; + uintptr_t start; int prot; }; @@ -2361,7 +2366,7 @@ static int walk_memory_regions_1(struct walk_memory_regions_data *data, 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; @@ -2549,7 +2554,7 @@ int page_unprotect(target_ulong address, uintptr_t pc, void *puc) } 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) */ @@ -4477,20 +4482,20 @@ int cpu_memory_rw_debug(CPUArchState *env, target_ulong addr, /* 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; @@ -4638,7 +4643,7 @@ bool virtio_is_big_endian(void) #define MMUSUFFIX _cmmu #undef GETPC -#define GETPC() NULL +#define GETPC() ((uintptr_t)0) #define env cpu_single_env #define SOFTMMU_CODE_ACCESS diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c index 71142e51f5..5a7b365548 100644 --- a/hw/a15mpcore.c +++ b/hw/a15mpcore.c @@ -20,36 +20,38 @@ #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 @@ -60,8 +62,10 @@ static int a15mp_priv_init(SysBusDevice *dev) * 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; @@ -85,7 +89,7 @@ static void a15mp_priv_class_init(ObjectClass *klass, void *data) 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 = { diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index 03b128ce5b..c2ff74d4b6 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -10,32 +10,19 @@ #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; @@ -124,18 +111,9 @@ static const MemoryRegionOps a9_scu_ops = { .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++) { @@ -143,17 +121,29 @@ static void a9mp_priv_reset(DeviceState *dev) } } +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); @@ -175,7 +165,8 @@ static int a9mp_priv_init(SysBusDevice *dev) 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. */ @@ -183,15 +174,20 @@ static int a9mp_priv_init(SysBusDevice *dev) 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; } diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c index ba6a89d3ed..c528d7aa01 100644 --- a/hw/arm11mpcore.c +++ b/hw/arm11mpcore.c @@ -10,28 +10,18 @@ #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; @@ -81,18 +71,16 @@ static const MemoryRegionOps mpcore_scu_ops = { .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); @@ -102,31 +90,47 @@ static void mpcore_priv_map_setup(mpcore_priv_state *s) */ 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); diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 6b34c06a8f..72298b4b41 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -8,13 +8,29 @@ */ /* 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 @@ -50,7 +66,7 @@ typedef struct gic_irq_state 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 @@ -105,7 +121,7 @@ typedef struct gic_state int current_pending[NCPU]; #if NCPU > 1 - int num_cpu; + uint32_t num_cpu; #endif MemoryRegion iomem; /* Distributor */ @@ -119,6 +135,16 @@ typedef struct gic_state 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) @@ -134,7 +160,7 @@ 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; @@ -159,8 +185,8 @@ static void gic_update(gic_state *s) } } -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; @@ -171,24 +197,45 @@ gic_set_pending_private(gic_state *s, int cpu, int irq) 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); } @@ -278,7 +325,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) int cm; int mask; - cpu = gic_get_current_cpu(); + cpu = gic_get_current_cpu(s); cm = 1 << cpu; if (offset < 0x100) { #ifndef NVIC @@ -413,7 +460,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, int i; int cpu; - cpu = gic_get_current_cpu(); + cpu = gic_get_current_cpu(s); if (offset < 0x100) { #ifdef NVIC goto bad_reg; @@ -575,7 +622,7 @@ static void gic_dist_writel(void *opaque, target_phys_addr_t offset, int irq; int mask; - cpu = gic_get_current_cpu(); + cpu = gic_get_current_cpu(s); irq = value & 0x3ff; switch ((value >> 24) & 3) { case 0: @@ -658,14 +705,14 @@ static uint64_t gic_thiscpu_read(void *opaque, target_phys_addr_t addr, 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. @@ -702,8 +749,9 @@ static const MemoryRegionOps gic_cpu_ops = { }; #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++) { @@ -813,6 +861,10 @@ static void gic_init(gic_state *s, int num_irq) #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) { @@ -828,7 +880,18 @@ static void gic_init(gic_state *s, int num_irq) 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]); } @@ -851,6 +914,54 @@ static void gic_init(gic_state *s, int num_irq) } #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 diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index 3210129c3f..986a6bbd0c 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -15,16 +15,8 @@ #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); @@ -83,6 +75,14 @@ static void systick_timer_tick(void * opaque) } } +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) @@ -378,6 +378,13 @@ static const VMStateDescription vmstate_nvic = { } }; +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); @@ -407,6 +414,7 @@ static void armv7m_nvic_class_init(ObjectClass *klass, void *data) sdc->init = armv7m_nvic_init; dc->vmsd = &vmstate_nvic; + dc->reset = armv7m_nvic_reset; dc->props = armv7m_nvic_properties; } diff --git a/hw/exynos4210.c b/hw/exynos4210.c index f904370505..afc4bdc7e0 100644 --- a/hw/exynos4210.c +++ b/hw/exynos4210.c @@ -25,6 +25,7 @@ #include "sysemu.h" #include "sysbus.h" #include "arm-misc.h" +#include "loader.h" #include "exynos4210.h" #define EXYNOS4210_CHIPID_ADDR 0x10000000 @@ -64,6 +65,35 @@ 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) { diff --git a/hw/exynos4210.h b/hw/exynos4210.h index c112e03bfb..f7c7027302 100644 --- a/hw/exynos4210.h +++ b/hw/exynos4210.h @@ -97,6 +97,9 @@ typedef struct Exynos4210State { 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); diff --git a/hw/exynos4210_combiner.c b/hw/exynos4210_combiner.c index 6110c19d5d..80af22cc33 100644 --- a/hw/exynos4210_combiner.c +++ b/hw/exynos4210_combiner.c @@ -184,11 +184,6 @@ exynos4210_combiner_read(void *opaque, target_phys_addr_t offset, unsigned 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; @@ -281,11 +276,6 @@ static void exynos4210_combiner_write(void *opaque, target_phys_addr_t offset, 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; diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c index ec13140f9f..e1b215eff0 100644 --- a/hw/exynos4210_gic.c +++ b/hw/exynos4210_gic.c @@ -174,7 +174,6 @@ combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { }; #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 @@ -263,33 +262,44 @@ uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit) /********* 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); @@ -301,7 +311,7 @@ static int exynos4210_gic_init(SysBusDevice *dev) 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, @@ -311,7 +321,7 @@ static int exynos4210_gic_init(SysBusDevice *dev) 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, @@ -321,8 +331,6 @@ static int exynos4210_gic_init(SysBusDevice *dev) sysbus_init_mmio(dev, &s->cpu_container); sysbus_init_mmio(dev, &s->dist_container); - gic_cpu_write(&s->gic, 1, 0, 1); - return 0; } @@ -361,7 +369,7 @@ type_init(exynos4210_gic_register_types) 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; @@ -426,7 +434,7 @@ static int exynos4210_irq_gate_init(SysBusDevice *dev) 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]); } diff --git a/hw/exynos4210_uart.c b/hw/exynos4210_uart.c index 73a9c18f30..ccc47804f9 100644 --- a/hw/exynos4210_uart.c +++ b/hw/exynos4210_uart.c @@ -246,7 +246,7 @@ static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(Exynos4210UartState *s) 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) { @@ -275,9 +275,9 @@ static void exynos4210_uart_update_irq(Exynos4210UartState *s) * 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)) { diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c index 553a02b910..ea32c51dcc 100644 --- a/hw/exynos4_boards.c +++ b/hw/exynos4_boards.c @@ -70,6 +70,7 @@ static struct arm_boot_info exynos4_board_binfo = { .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]; diff --git a/hw/realview_gic.c b/hw/realview_gic.c index 071ef13c9e..5bc37a7120 100644 --- a/hw/realview_gic.c +++ b/hw/realview_gic.c @@ -9,39 +9,45 @@ #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; } diff --git a/hw/spapr.h b/hw/spapr.h index 11160b02da..654a7a8a34 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -272,7 +272,7 @@ extern sPAPREnvironment *spapr; #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) diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index cfc777804b..e18d2eb901 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -182,6 +182,15 @@ static NetClientInfo net_spapr_vlan_info = { .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; @@ -279,21 +288,19 @@ static target_ulong h_register_logical_lan(CPUPPCState *env, 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; } @@ -337,9 +344,7 @@ static target_ulong h_free_logical_lan(CPUPPCState *env, sPAPREnvironment *spapr return H_RESOURCE; } - dev->buf_list = 0; - dev->rx_bufs = 0; - dev->isopen = 0; + spapr_vlan_reset(sdev); return H_SUCCESS; } @@ -358,13 +363,13 @@ static target_ulong h_add_logical_lan_buffer(CPUPPCState *env, ", 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; } @@ -486,6 +491,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data) 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"; diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index e7ef551c1c..a564c007b4 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -57,26 +57,38 @@ static PCIDevice *find_dev(sPAPREnvironment *spapr, 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, @@ -84,19 +96,19 @@ 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, @@ -104,18 +116,45 @@ 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, @@ -123,19 +162,20 @@ 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, @@ -144,17 +184,18 @@ 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) diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c index 09465853ba..ae18595150 100644 --- a/hw/spapr_rtas.c +++ b/hw/spapr_rtas.c @@ -44,8 +44,7 @@ static void rtas_display_character(sPAPREnvironment *spapr, 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); @@ -112,6 +111,19 @@ static void rtas_power_off(sPAPREnvironment *spapr, 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, @@ -294,6 +306,7 @@ static void core_rtas_register_types(void) 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); diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index dbf5a9017e..fccf48bd67 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -204,8 +204,7 @@ static target_ulong h_put_tce(CPUPPCState *env, sPAPREnvironment *spapr, 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; } @@ -217,8 +216,7 @@ static target_ulong h_put_tce(CPUPPCState *env, sPAPREnvironment *spapr, #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; } @@ -414,33 +412,32 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr, 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; @@ -453,6 +450,17 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr, 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) { @@ -460,18 +468,11 @@ static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr, 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, @@ -484,8 +485,7 @@ 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); @@ -505,8 +505,7 @@ static target_ulong h_enable_crq(CPUPPCState *env, sPAPREnvironment *spapr, 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; } @@ -649,6 +648,20 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev) 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; @@ -766,6 +779,7 @@ static void vio_spapr_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->init = spapr_vio_busdev_init; + k->reset = spapr_vio_busdev_reset; k->bus_info = &spapr_vio_bus_info; } diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index d8527bed90..10ab3594c0 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -64,7 +64,7 @@ typedef struct VIOsPAPRDeviceClass { 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; @@ -89,8 +89,6 @@ struct VIOsPAPRDevice { 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); }; @@ -119,6 +117,7 @@ uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr); 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); diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 21670170e8..538e0b7938 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -99,10 +99,6 @@ typedef struct { 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; @@ -897,18 +893,20 @@ static const struct SCSIBusInfo vscsi_scsi_info = { .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; @@ -958,6 +956,7 @@ static void spapr_vscsi_class_init(ObjectClass *klass, void *data) 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"; diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index 60e22b1600..a30c040b97 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -70,8 +70,6 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev) } /* 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) { @@ -195,7 +193,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) return selected; } -static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg) +VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg) { VIOsPAPRDevice *sdev; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 8a92162155..712861829a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -5045,7 +5045,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, 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); } diff --git a/main-loop.c b/main-loop.c index 1ebdc4baf1..4887c732fa 100644 --- a/main-loop.c +++ b/main-loop.c @@ -430,7 +430,7 @@ static int os_host_main_loop_wait(int timeout) 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; } @@ -813,7 +813,7 @@ static void nbd_trip(void *opaque) 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; } diff --git a/qemu-os-win32.h b/qemu-os-win32.h index 8eda4bdc20..753679b194 100644 --- a/qemu-os-win32.h +++ b/qemu-os-win32.h @@ -30,6 +30,41 @@ #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); diff --git a/qemu_socket.h b/qemu_socket.h index 51ad210a7f..a5d0a84fb6 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -8,12 +8,6 @@ #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); @@ -2106,7 +2106,8 @@ void do_savevm(Monitor *mon, const QDict *qdict) } } 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' */ diff --git a/slirp/slirp.h b/slirp/slirp.h index 46bfe4636d..f2c5eca892 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -15,18 +15,6 @@ typedef char *caddr_t; # 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) diff --git a/softmmu_header.h b/softmmu_header.h index 6b72093a0c..cf1aa38fc7 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -99,7 +99,6 @@ glue(glue(glue(CPU_PREFIX, ld), USUFFIX), MEMSUFFIX)(ENV_PARAM int page_index; RES_TYPE res; target_ulong addr; - unsigned long physaddr; int mmu_idx; addr = ptr; @@ -111,8 +110,8 @@ glue(glue(glue(CPU_PREFIX, ld), USUFFIX), MEMSUFFIX)(ENV_PARAM 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; } @@ -124,7 +123,6 @@ glue(glue(glue(CPU_PREFIX, lds), SUFFIX), MEMSUFFIX)(ENV_PARAM { int res, page_index; target_ulong addr; - unsigned long physaddr; int mmu_idx; addr = ptr; @@ -135,8 +133,8 @@ glue(glue(glue(CPU_PREFIX, lds), SUFFIX), MEMSUFFIX)(ENV_PARAM 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; } @@ -152,7 +150,6 @@ glue(glue(glue(CPU_PREFIX, st), SUFFIX), MEMSUFFIX)(ENV_PARAM target_ulong ptr, { int page_index; target_ulong addr; - unsigned long physaddr; int mmu_idx; addr = ptr; @@ -163,8 +160,8 @@ glue(glue(glue(CPU_PREFIX, st), SUFFIX), MEMSUFFIX)(ENV_PARAM target_ulong 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); } } diff --git a/softmmu_template.h b/softmmu_template.h index afcab1e6a9..b8bd700325 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -69,17 +69,17 @@ 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 @@ -112,8 +112,7 @@ glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_PARAM 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 */ @@ -139,6 +138,7 @@ glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_PARAM 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(); @@ -146,7 +146,8 @@ glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_PARAM } #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 */ @@ -166,12 +167,11 @@ static DATA_TYPE 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); @@ -202,8 +202,9 @@ glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_PARAM 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 */ @@ -219,13 +220,13 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM 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); @@ -238,7 +239,7 @@ static inline void glue(io_write, SUFFIX)(ENV_PARAM } 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 @@ -258,9 +259,8 @@ void glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_PARAM 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); @@ -284,6 +284,7 @@ void glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_PARAM 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(); @@ -291,7 +292,8 @@ void glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_PARAM } #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 */ @@ -310,10 +312,9 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM 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; @@ -345,8 +346,9 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM } } 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 */ diff --git a/target-alpha/cpu-qom.h b/target-alpha/cpu-qom.h new file mode 100644 index 0000000000..6b4ca6d1d1 --- /dev/null +++ b/target-alpha/cpu-qom.h @@ -0,0 +1,71 @@ +/* + * 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 diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c new file mode 100644 index 0000000000..62d2a669a9 --- /dev/null +++ b/target-alpha/cpu.c @@ -0,0 +1,58 @@ +/* + * 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) diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index 74bf7f7ff4..99f9ee168d 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -292,6 +292,7 @@ struct CPUAlphaState { #define cpu_signal_handler cpu_alpha_signal_handler #include "cpu-all.h" +#include "cpu-qom.h" enum { FEATURE_ASN = 0x00000001, @@ -433,9 +434,9 @@ int cpu_alpha_handle_mmu_fault (CPUAlphaState *env, uint64_t address, int rw, 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); diff --git a/target-alpha/fpu_helper.c b/target-alpha/fpu_helper.c index dda110352e..fe988ec459 100644 --- a/target-alpha/fpu_helper.c +++ b/target-alpha/fpu_helper.c @@ -44,7 +44,7 @@ uint32_t helper_fp_exc_get(CPUAlphaState *env) 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) { @@ -160,7 +160,7 @@ static uint64_t float32_to_f(float32 fa) 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; @@ -291,7 +291,7 @@ static uint64_t float64_to_g(float64 fa) 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; diff --git a/target-alpha/helper.c b/target-alpha/helper.c index 765e650002..81d4763b49 100644 --- a/target-alpha/helper.c +++ b/target-alpha/helper.c @@ -494,13 +494,12 @@ void cpu_dump_state (CPUAlphaState *env, FILE *f, fprintf_function cpu_fprintf, 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); } } } @@ -515,7 +514,7 @@ void QEMU_NORETURN helper_excp(CPUAlphaState *env, int excp, int error) } /* 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; @@ -524,7 +523,7 @@ void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, void *retaddr, 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; diff --git a/target-alpha/mem_helper.c b/target-alpha/mem_helper.c index dd5ca4933a..87cada48f9 100644 --- a/target-alpha/mem_helper.c +++ b/target-alpha/mem_helper.c @@ -89,7 +89,7 @@ uint64_t helper_stq_c_phys(CPUAlphaState *env, uint64_t p, uint64_t v) } 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; @@ -112,7 +112,7 @@ void cpu_unassigned_access(CPUAlphaState *env, target_phys_addr_t addr, { 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" @@ -137,7 +137,7 @@ void cpu_unassigned_access(CPUAlphaState *env, target_phys_addr_t addr, 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; diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 1f4565d794..12de6a3fb6 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -3525,13 +3525,14 @@ static const struct cpu_def_t cpu_defs[] = { 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; @@ -3549,15 +3550,6 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model) 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; } diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index c728432654..b53369d7cb 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -76,11 +76,10 @@ uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def, 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; @@ -89,12 +88,11 @@ void tlb_fill(CPUARMState *env1, target_ulong addr, int is_write, int 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); } } raise_exception(env->exception_index); diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c index c568e2b930..b92c106e10 100644 --- a/target-cris/op_helper.c +++ b/target-cris/op_helper.c @@ -57,28 +57,26 @@ 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(); diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index c04ae4464f..bc3b94e149 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -5003,11 +5003,10 @@ void helper_boundl(target_ulong a0, int v) 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; @@ -5017,12 +5016,11 @@ void tlb_fill(CPUX86State *env1, target_ulong addr, int is_write, int mmu_idx, 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); diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c index e9c96383af..51edc1a0e1 100644 --- a/target-lm32/op_helper.c +++ b/target-lm32/op_helper.c @@ -76,11 +76,10 @@ uint32_t helper_rcsr_jrx(void) 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; @@ -90,12 +89,11 @@ void tlb_fill(CPULM32State *env1, target_ulong addr, int is_write, int 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); } } cpu_loop_exit(env); diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index bc8c1f02c6..1971a57892 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -56,11 +56,10 @@ extern int semihosting_enabled; 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; @@ -69,12 +68,11 @@ void tlb_fill(CPUM68KState *env1, target_ulong addr, int is_write, int 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); } } cpu_loop_exit(env); diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c index a83da8da86..3b1f07243e 100644 --- a/target-microblaze/op_helper.c +++ b/target-microblaze/op_helper.c @@ -44,11 +44,10 @@ 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; @@ -58,12 +57,11 @@ void tlb_fill(CPUMBState *env1, target_ulong addr, int is_write, int 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); } } cpu_loop_exit(env); diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index ce01225e6c..5627447953 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -101,11 +101,10 @@ void helper_raise_exception (uint32_t exception) } #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); @@ -2276,7 +2275,7 @@ void helper_pmon (int function) 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; @@ -2293,7 +2292,7 @@ void helper_wait (void) #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 @@ -2310,7 +2309,8 @@ static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write, #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); @@ -2318,11 +2318,10 @@ static void do_unaligned_access (target_ulong addr, int is_write, int is_user, v } 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; @@ -2331,12 +2330,11 @@ void tlb_fill(CPUMIPSState *env1, target_ulong addr, int is_write, int mmu_idx, 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); diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h new file mode 100644 index 0000000000..fef6f95a04 --- /dev/null +++ b/target-ppc/cpu-qom.h @@ -0,0 +1,77 @@ +/* + * 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 diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index e7fb3641a7..84c9674157 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1096,11 +1096,12 @@ struct mmu_ctx_t { }; #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. */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index e13b74993d..c610ce3e28 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2960,7 +2960,7 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp) 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) { @@ -3138,54 +3138,12 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr) 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; @@ -3193,20 +3151,13 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model) 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); @@ -3214,9 +3165,3 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model) return env; } - -void cpu_ppc_close (CPUPPCState *env) -{ - /* Should also remove all opcode tables... */ - g_free(env); -} diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index d929213a04..c09cc39c78 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -27,6 +27,7 @@ #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" @@ -938,6 +939,19 @@ const ppc_def_t *kvmppc_host_cpu_def(void) 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; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 8f1267c6cc..34ecad3e26 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -29,6 +29,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd); 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 @@ -95,6 +96,10 @@ static inline const ppc_def_t *kvmppc_host_cpu_def(void) return NULL; } +static inline int kvmppc_fixup_cpu(CPUPPCState *env) +{ + return -1; +} #endif #ifndef CONFIG_KVM diff --git a/target-ppc/machine.c b/target-ppc/machine.c index 70e25825fb..d6c2ee41b3 100644 --- a/target-ppc/machine.c +++ b/target-ppc/machine.c @@ -32,7 +32,6 @@ void cpu_save(QEMUFile *f, void *opaque) } 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); @@ -62,7 +61,6 @@ void cpu_save(QEMUFile *f, void *opaque) } 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); @@ -72,7 +70,6 @@ void cpu_save(QEMUFile *f, void *opaque) 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]); @@ -81,7 +78,6 @@ void cpu_save(QEMUFile *f, void *opaque) 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); @@ -120,7 +116,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) } 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); @@ -150,7 +145,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) } 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); @@ -161,7 +155,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) 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]); @@ -170,7 +163,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) 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); diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 40927b65b1..4ef2332a5a 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -3715,11 +3715,10 @@ uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2) 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; @@ -3728,12 +3727,11 @@ void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx, 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); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index c9a503a1db..cf59765405 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -9306,8 +9306,8 @@ GEN_SPEOP_LDST(evstwwe, 0x1C, 2), GEN_SPEOP_LDST(evstwwo, 0x1E, 2), }; -#include "translate_init.c" #include "helper_regs.h" +#include "translate_init.c" /*****************************************************************************/ /* Misc PowerPC helpers */ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index b1f87854a0..ba4b84d86b 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4462,7 +4462,10 @@ static void init_proc_e500 (CPUPPCState *env, int version) &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; @@ -9504,12 +9507,12 @@ enum { 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 */ @@ -9528,7 +9531,7 @@ static int create_new_table (opc_handler_t **table, unsigned char idx) 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; } @@ -9889,6 +9892,28 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n) 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; @@ -9897,25 +9922,22 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) 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); @@ -10185,3 +10207,93 @@ void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf) 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) diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c index 18fdbb2e8e..7b7247316e 100644 --- a/target-s390x/op_helper.c +++ b/target-s390x/op_helper.c @@ -57,11 +57,10 @@ 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; @@ -70,12 +69,11 @@ void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx, 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); diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c index 30f762f514..40547911cd 100644 --- a/target-sh4/op_helper.c +++ b/target-sh4/op_helper.c @@ -22,18 +22,16 @@ #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); } } } @@ -56,7 +54,7 @@ static void cpu_restore_state_from_retaddr(void *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; @@ -84,7 +82,7 @@ void helper_ldtlb(void) #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); @@ -447,7 +445,7 @@ void helper_ld_fpscr(uint32_t val) 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; diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 865288cc94..29c63c711f 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -702,7 +702,7 @@ trap_state* cpu_tsptr(CPUSPARCState* env); #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) diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c index 1418205f99..04ffddf3c0 100644 --- a/target-sparc/ldst_helper.c +++ b/target-sparc/ldst_helper.c @@ -2376,25 +2376,23 @@ void cpu_unassigned_access(CPUSPARCState *env, target_phys_addr_t addr, #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 @@ -2409,7 +2407,7 @@ void do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write, 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; diff --git a/target-xtensa/core-dc232b.c b/target-xtensa/core-dc232b.c index 7c038351b3..804fdef56a 100644 --- a/target-xtensa/core-dc232b.c +++ b/target-xtensa/core-dc232b.c @@ -1,3 +1,30 @@ +/* + * 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" diff --git a/target-xtensa/core-dc233c.c b/target-xtensa/core-dc233c.c new file mode 100644 index 0000000000..d643f41d37 --- /dev/null +++ b/target-xtensa/core-dc233c.c @@ -0,0 +1,55 @@ +/* + * 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) diff --git a/target-xtensa/core-dc233c/core-isa.h b/target-xtensa/core-dc233c/core-isa.h new file mode 100644 index 0000000000..e82c3cbe48 --- /dev/null +++ b/target-xtensa/core-dc233c/core-isa.h @@ -0,0 +1,474 @@ +/* + * 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 */ diff --git a/target-xtensa/core-dc233c/gdb-config.c b/target-xtensa/core-dc233c/gdb-config.c new file mode 100644 index 0000000000..b632341b28 --- /dev/null +++ b/target-xtensa/core-dc233c/gdb-config.c @@ -0,0 +1,145 @@ +/* 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) diff --git a/target-xtensa/core-fsf.c b/target-xtensa/core-fsf.c index c11d9708e7..e36b0de9d5 100644 --- a/target-xtensa/core-fsf.c +++ b/target-xtensa/core-fsf.c @@ -1,3 +1,30 @@ +/* + * 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" diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h new file mode 100644 index 0000000000..1fd2f274a1 --- /dev/null +++ b/target-xtensa/cpu-qom.h @@ -0,0 +1,80 @@ +/* + * 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 diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c new file mode 100644 index 0000000000..97deacb478 --- /dev/null +++ b/target-xtensa/cpu.c @@ -0,0 +1,88 @@ +/* + * 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) diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h index a7bcf52220..6d0ea7c038 100644 --- a/target-xtensa/cpu.h +++ b/target-xtensa/cpu.h @@ -375,6 +375,7 @@ void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb, 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); @@ -470,6 +471,7 @@ static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc, } #include "cpu-all.h" +#include "cpu-qom.h" #include "exec-all.h" static inline int cpu_has_work(CPUXtensaState *env) diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c index dab135c4a9..2094227843 100644 --- a/target-xtensa/helper.c +++ b/target-xtensa/helper.c @@ -33,20 +33,9 @@ #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; @@ -95,6 +84,7 @@ CPUXtensaState *cpu_xtensa_init(const char *cpu_model) { static int tcg_inited; static int debug_handler_inited; + XtensaCPU *cpu; CPUXtensaState *env; const XtensaConfig *config = NULL; XtensaConfigList *core = xtensa_cores; @@ -109,9 +99,9 @@ CPUXtensaState *cpu_xtensa_init(const char *cpu_model) 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; @@ -334,7 +324,7 @@ static void reset_tlb_region_way0(CPUXtensaState *env, } } -static void reset_mmu(CPUXtensaState *env) +void reset_mmu(CPUXtensaState *env) { if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { env->sregs[RASID] = 0x04030201; diff --git a/target-xtensa/helpers.h b/target-xtensa/helper.h index 48a741e46d..48a741e46d 100644 --- a/target-xtensa/helpers.h +++ b/target-xtensa/helper.h diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c index cdef0db52e..364dc19bc0 100644 --- a/target-xtensa/op_helper.c +++ b/target-xtensa/op_helper.c @@ -27,11 +27,11 @@ #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 @@ -48,10 +48,9 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user, #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) { @@ -60,7 +59,7 @@ static void do_restore_state(void *pc_ptr) } 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)) { @@ -71,7 +70,7 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user, } void tlb_fill(CPUXtensaState *env1, target_ulong vaddr, int is_write, int mmu_idx, - void *retaddr) + uintptr_t retaddr) { CPUXtensaState *saved_env = env; @@ -99,6 +98,18 @@ void tlb_fill(CPUXtensaState *env1, target_ulong vaddr, int is_write, int mmu_id 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; @@ -358,8 +369,7 @@ void HELPER(movsp)(uint32_t pc) 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; } } @@ -367,11 +377,9 @@ void HELPER(wsr_lbeg)(uint32_t 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); } } @@ -692,8 +700,7 @@ void HELPER(wsr_ibreakenable)(uint32_t v) 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); @@ -702,9 +709,8 @@ void HELPER(wsr_ibreakenable)(uint32_t v) 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; } diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index e0ff72b3f8..6900123983 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -37,9 +37,9 @@ #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; @@ -183,7 +183,7 @@ void xtensa_translate_init(void) } } #define GEN_HELPER 2 -#include "helpers.h" +#include "helper.h" } static inline bool option_bits_enabled(DisasContext *dc, uint64_t opt) @@ -459,11 +459,13 @@ static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr) 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) diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index 871a7e74f5..da17bba39d 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -63,10 +63,15 @@ static const int tcg_target_reg_alloc_order[] = { 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 @@ -176,10 +181,10 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) 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); @@ -1300,9 +1305,12 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, 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; } } @@ -1434,8 +1442,8 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, #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 */ @@ -1474,9 +1482,12 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, 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; } } @@ -1977,6 +1988,10 @@ static int tcg_target_callee_save_regs[] = { #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. */ @@ -2064,8 +2079,10 @@ static void tcg_target_init(TCGContext *s) 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); @@ -2102,7 +2119,9 @@ typedef struct { 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 */ @@ -2156,6 +2175,7 @@ static DebugFrame debug_frame = { }; #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. */ @@ -2166,3 +2186,4 @@ void tcg_register_jit(void *buf, size_t buf_size) tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame)); } +#endif diff --git a/tests/Makefile b/tests/Makefile index a98a848ec9..baf1d70ee8 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -92,8 +92,6 @@ check-help: @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) diff --git a/tests/tcg/xtensa/Makefile b/tests/tcg/xtensa/Makefile index 7e1e619d23..0ff0ccfb8c 100644 --- a/tests/tcg/xtensa/Makefile +++ b/tests/tcg/xtensa/Makefile @@ -72,5 +72,8 @@ run-test_fail.tst: test_fail.tst debug-%.tst: %.tst $(SIM) $(SIMDEBUG) $(SIMFLAGS) ./$< +host-debug-%.tst: %.tst + gdb --args $(SIM) $(SIMFLAGS) ./$< + clean: $(RM) -fr $(TESTCASES) $(CRT) diff --git a/tests/tcg/xtensa/macros.inc b/tests/tcg/xtensa/macros.inc index 2d4515e14f..23bf3e96c8 100644 --- a/tests/tcg/xtensa/macros.inc +++ b/tests/tcg/xtensa/macros.inc @@ -29,7 +29,24 @@ main: 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 diff --git a/tests/tcg/xtensa/test_break.S b/tests/tcg/xtensa/test_break.S index 8a8db8033b..7574cbefc8 100644 --- a/tests/tcg/xtensa/test_break.S +++ b/tests/tcg/xtensa/test_break.S @@ -91,6 +91,40 @@ test ibreak 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 diff --git a/tests/tcg/xtensa/test_loop.S b/tests/tcg/xtensa/test_loop.S index a5ea933913..5cead47a27 100644 --- a/tests/tcg/xtensa/test_loop.S +++ b/tests/tcg/xtensa/test_loop.S @@ -74,4 +74,54 @@ test loop_excm 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 diff --git a/user-exec.c b/user-exec.c index cd905ff189..be6bc4f64c 100644 --- a/user-exec.c +++ b/user-exec.c @@ -82,7 +82,7 @@ void cpu_resume_from_signal(CPUArchState *env1, void *puc) 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) { diff --git a/xtensa-semi.c b/xtensa-semi.c index 5754b7782a..b7c8c34564 100644 --- a/xtensa-semi.c +++ b/xtensa-semi.c @@ -31,7 +31,7 @@ #include <stddef.h> #include "cpu.h" #include "dyngen-exec.h" -#include "helpers.h" +#include "helper.h" #include "qemu-log.h" enum { |