From 40844d63d6493a2e2f41bc7d14cd0696e0c23112 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 13 Jul 2012 17:27:21 +0100 Subject: [PATCH] Blackfin: add softmmu support Semi-functional -- it can run Das U-Boot! Signed-off-by: Mike Frysinger --- configs/devices/bfin-softmmu/default.mak | 12 +++ configs/targets/bfin-softmmu.mak | 2 + include/sysemu/arch_init.h | 1 + target/bfin/cpu.c | 42 ++++++++++ target/bfin/cpu.h | 19 ++++- target/bfin/dv-bfin_cec.h | 5 ++ target/bfin/helper.c | 97 ++++++++++++++++++++++++ target/bfin/helper.h | 1 + target/bfin/machine.c | 53 +++++++++++++ target/bfin/meson.build | 7 ++ target/bfin/monitor.c | 80 +++++++++++++++++++ target/bfin/op_helper.c | 24 +++++- target/bfin/translate.c | 3 +- 13 files changed, 342 insertions(+), 4 deletions(-) create mode 100644 configs/devices/bfin-softmmu/default.mak create mode 100644 configs/targets/bfin-softmmu.mak create mode 100644 target/bfin/dv-bfin_cec.h create mode 100644 target/bfin/machine.c create mode 100644 target/bfin/monitor.c diff --git a/configs/devices/bfin-softmmu/default.mak b/configs/devices/bfin-softmmu/default.mak new file mode 100644 index 0000000000000..c881648792437 --- /dev/null +++ b/configs/devices/bfin-softmmu/default.mak @@ -0,0 +1,12 @@ +# Default configuration for arm-softmmu + +CONFIG_NAND=y +CONFIG_ECC=y +CONFIG_SERIAL=y +CONFIG_SD=y +CONFIG_SSI_SD=y +CONFIG_SMC91C111=y +CONFIG_PFLASH_CFI01=y +CONFIG_PFLASH_CFI02=y +CONFIG_SSI=y +CONFIG_SSI_M25P80=y diff --git a/configs/targets/bfin-softmmu.mak b/configs/targets/bfin-softmmu.mak new file mode 100644 index 0000000000000..a1d27a43221f1 --- /dev/null +++ b/configs/targets/bfin-softmmu.mak @@ -0,0 +1,2 @@ +TARGET_ARCH=bfin +TARGET_ALIGNED_ONLY=y diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index 8850cb1a14b9b..1f1dd5adf1b2a 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -25,6 +25,7 @@ enum { QEMU_ARCH_AVR = (1 << 21), QEMU_ARCH_HEXAGON = (1 << 22), QEMU_ARCH_LOONGARCH = (1 << 23), + QEMU_ARCH_BFIN = (1 << 24), }; extern const uint32_t arch_type; diff --git a/target/bfin/cpu.c b/target/bfin/cpu.c index 11bc6f09fd2f0..81c07eb2def28 100644 --- a/target/bfin/cpu.c +++ b/target/bfin/cpu.c @@ -102,6 +102,14 @@ static ObjectClass *bfin_cpu_class_by_name(const char *cpu_model) return oc; } +#ifndef CONFIG_USER_ONLY +#include "hw/core/sysemu-cpu-ops.h" + +static const struct SysemuCPUOps bfin_sysemu_ops = { + .get_phys_page_debug = bfin_cpu_get_phys_page_debug, +}; +#endif + #ifdef CONFIG_TCG static const struct TCGCPUOps bfin_tcg_ops = { .initialize = bfin_translate_init, @@ -132,6 +140,10 @@ static void bfin_cpu_class_init(ObjectClass *oc, void *data) cc->gdb_write_register = bfin_cpu_gdb_write_register; cc->dump_state = bfin_cpu_dump_state; cc->disas_set_info = bfin_cpu_disas_set_info; +#ifndef CONFIG_USER_ONLY + dc->vmsd = &vmstate_bfin_cpu; + cc->sysemu_ops = &bfin_sysemu_ops; +#endif #ifdef CONFIG_TCG cc->tcg_ops = &bfin_tcg_ops; @@ -161,7 +173,37 @@ static const TypeInfo bfin_cpu_type_infos[] = { .class_size = sizeof(BlackfinCPUClass), .class_init = bfin_cpu_class_init, }, + DEFINE_BLACKFIN_CPU_TYPE("bf504"), + DEFINE_BLACKFIN_CPU_TYPE("bf506"), + DEFINE_BLACKFIN_CPU_TYPE("bf512"), + DEFINE_BLACKFIN_CPU_TYPE("bf514"), + DEFINE_BLACKFIN_CPU_TYPE("bf516"), + DEFINE_BLACKFIN_CPU_TYPE("bf518"), + DEFINE_BLACKFIN_CPU_TYPE("bf522"), + DEFINE_BLACKFIN_CPU_TYPE("bf523"), + DEFINE_BLACKFIN_CPU_TYPE("bf524"), + DEFINE_BLACKFIN_CPU_TYPE("bf525"), + DEFINE_BLACKFIN_CPU_TYPE("bf526"), + DEFINE_BLACKFIN_CPU_TYPE("bf527"), + DEFINE_BLACKFIN_CPU_TYPE("bf531"), + DEFINE_BLACKFIN_CPU_TYPE("bf532"), + DEFINE_BLACKFIN_CPU_TYPE("bf533"), + DEFINE_BLACKFIN_CPU_TYPE("bf534"), + /*DEFINE_BLACKFIN_CPU_TYPE("bf535"),*/ + DEFINE_BLACKFIN_CPU_TYPE("bf536"), + DEFINE_BLACKFIN_CPU_TYPE("bf537"), + DEFINE_BLACKFIN_CPU_TYPE("bf538"), + DEFINE_BLACKFIN_CPU_TYPE("bf539"), + DEFINE_BLACKFIN_CPU_TYPE("bf542"), + DEFINE_BLACKFIN_CPU_TYPE("bf544"), + DEFINE_BLACKFIN_CPU_TYPE("bf547"), + DEFINE_BLACKFIN_CPU_TYPE("bf548"), + DEFINE_BLACKFIN_CPU_TYPE("bf549"), + DEFINE_BLACKFIN_CPU_TYPE("bf561"), + DEFINE_BLACKFIN_CPU_TYPE("bf592"), +#ifdef CONFIG_USER_ONLY DEFINE_BLACKFIN_CPU_TYPE("any"), +#endif }; DEFINE_TYPES(bfin_cpu_type_infos); diff --git a/target/bfin/cpu.h b/target/bfin/cpu.h index 9d5e0a72e849d..66696b9c9969f 100644 --- a/target/bfin/cpu.h +++ b/target/bfin/cpu.h @@ -151,15 +151,21 @@ static inline BlackfinCPU *bfin_env_get_cpu(CPUArchState *env) #define ENV_OFFSET offsetof(BlackfinCPU, env) +#ifndef CONFIG_USER_ONLY +extern const struct VMStateDescription vmstate_bfin_cpu; +#endif + #define BLACKFIN_CPU_TYPE_SUFFIX "-" TYPE_BLACKFIN_CPU #define BLACKFIN_CPU_TYPE_NAME(model) (model BLACKFIN_CPU_TYPE_SUFFIX) #define CPU_RESOLVING_TYPE TYPE_BLACKFIN_CPU +#define cpu_list cpu_bfin_list #define cpu_signal_handler cpu_bfin_signal_handler void bfin_cpu_do_interrupt(CPUState *cpu); void bfin_cpu_dump_state(CPUState *cs, FILE *f, int flags); +hwaddr bfin_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int bfin_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int bfin_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); @@ -210,6 +216,7 @@ enum astat_ops { ASTAT_OP_VECTOR_SUB_ADD, /* -|+ */ }; +void cpu_list(void); bool bfin_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); @@ -219,8 +226,16 @@ void bfin_translate_init(void); extern const char * const greg_names[]; extern const char *get_allreg_name(int grp, int reg); -#define MMU_KERNEL_IDX 0 -#define MMU_USER_IDX 1 +#include "dv-bfin_cec.h" + +/* */ +#define MMU_MODE0_SUFFIX _kernel +#define MMU_MODE1_SUFFIX _user +#define MMU_USER_IDX 1 +static inline int cpu_mmu_index(CPUArchState *env, bool ifetch) +{ + return !cec_is_supervisor_mode(env); +} int cpu_bfin_handle_mmu_fault(CPUState *cs, target_ulong address, MMUAccessType access_type, int mmu_idx); diff --git a/target/bfin/dv-bfin_cec.h b/target/bfin/dv-bfin_cec.h new file mode 100644 index 0000000000000..3f4dbbb7635d8 --- /dev/null +++ b/target/bfin/dv-bfin_cec.h @@ -0,0 +1,5 @@ +#include +static inline bool cec_is_supervisor_mode(CPUBfinState *env) +{ + return true; +} diff --git a/target/bfin/helper.c b/target/bfin/helper.c index 7dc7ceedb0733..28b30b8154dfb 100644 --- a/target/bfin/helper.c +++ b/target/bfin/helper.c @@ -8,9 +8,13 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "cpu.h" #include "exec/exec-all.h" #include "qemu/host-utils.h" +#include "qemu/qemu-print.h" + +#if defined(CONFIG_USER_ONLY) void bfin_cpu_do_interrupt(CPUState *cs) { @@ -25,6 +29,43 @@ int cpu_handle_mmu_fault(CPUState *cs, target_ulong address, return 1; } +#else + +void bfin_cpu_do_interrupt(CPUState *cs) +{ + BlackfinCPU *cpu = BFIN_CPU(cs); + CPUBfinState *env = &cpu->env; + + qemu_log_mask(CPU_LOG_INT, + "exception at pc=%x type=%x\n", env->pc, cs->exception_index); + + switch (cs->exception_index) { + default: + cpu_abort(cs, "unhandled exception type=%d\n", + cs->exception_index); + break; + } +} + +hwaddr bfin_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +{ + return addr & TARGET_PAGE_MASK; +} + +int cpu_handle_mmu_fault(CPUState *cs, target_ulong address, + MMUAccessType access_type, int mmu_idx) +{ + int prot; + + address &= TARGET_PAGE_MASK; + prot = PAGE_BITS; + tlb_set_page(cs, address, address, prot, mmu_idx, TARGET_PAGE_SIZE); + + return 0; +} + +#endif + /* Try to fill the TLB and return an exception if error. If retaddr is NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ @@ -33,7 +74,63 @@ bool bfin_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr) { +#ifdef CONFIG_USER_ONLY // TODO: This should depend on access_type. cs->exception_index = EXCP_DCPLB_VIOLATE; cpu_loop_exit_restore(cs, retaddr); +#else + int ret; + + ret = cpu_bfin_handle_mmu_fault(cs, address, access_type, mmu_idx); + if (likely(!ret)) { + return true; + } else if (probe) { + return false; + } else { + /* now we have a real cpu fault */ + cpu_restore_state(cs, retaddr); + cpu_loop_exit(cs); + } +#endif +} + +/* Sort alphabetically by type name, except for "any". */ +static gint cpu_list_compare(gconstpointer a, gconstpointer b) +{ + ObjectClass *class_a = (ObjectClass *)a; + ObjectClass *class_b = (ObjectClass *)b; + const char *name_a, *name_b; + + name_a = object_class_get_name(class_a); + name_b = object_class_get_name(class_b); + if (strcmp(name_a, BLACKFIN_CPU_TYPE_NAME("any")) == 0) { + return 1; + } else if (strcmp(name_b, BLACKFIN_CPU_TYPE_NAME("any")) == 0) { + return -1; + } else { + return strcmp(name_a, name_b); + } +} + +static void cpu_list_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + const char *typename; + char *name; + + typename = object_class_get_name(oc); + name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_BLACKFIN_CPU)); + qemu_printf(" %s\n", name); + g_free(name); +} + +void cpu_bfin_list(void) +{ + GSList *list; + + list = object_class_get_list(TYPE_BLACKFIN_CPU, false); + list = g_slist_sort(list, cpu_list_compare); + qemu_printf("Available CPUs:\n"); + g_slist_foreach(list, cpu_list_entry, NULL); + g_slist_free(list); } diff --git a/target/bfin/helper.h b/target/bfin/helper.h index 44600f93ba54f..ad4ffc738350b 100644 --- a/target/bfin/helper.h +++ b/target/bfin/helper.h @@ -9,6 +9,7 @@ DEF_HELPER_FLAGS_3(raise_exception, TCG_CALL_NO_WG, void, env, i32, i32) DEF_HELPER_FLAGS_5(memalign, TCG_CALL_NO_WG, void, env, i32, i32, i32, i32) +DEF_HELPER_FLAGS_2(require_supervisor, TCG_CALL_NO_WG, void, env, i32) DEF_HELPER_FLAGS_4(dbga_l, TCG_CALL_NO_WG, void, env, i32, i32, i32) DEF_HELPER_FLAGS_4(dbga_h, TCG_CALL_NO_WG, void, env, i32, i32, i32) diff --git a/target/bfin/machine.c b/target/bfin/machine.c new file mode 100644 index 0000000000000..75081e03f2d60 --- /dev/null +++ b/target/bfin/machine.c @@ -0,0 +1,53 @@ +/* + * Blackfin cpu save/load logic + * + * Copyright 2007-2023 Mike Frysinger + * Copyright 2007-2011 Analog Devices, Inc. + * + * Licensed under the Lesser GPL 2 or later. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "hw/hw.h" +#include "hw/boards.h" +#include "migration/cpu.h" + +#define VMSTATE_AUTO32_ARRAY(member) \ + VMSTATE_UINT32_ARRAY(member, CPUArchState, ARRAY_SIZE(((CPUArchState *)NULL)->member)) +#define VMSTATE_AUTO64_ARRAY(member) \ + VMSTATE_UINT64_ARRAY(member, CPUArchState, ARRAY_SIZE(((CPUArchState *)NULL)->member)) +#define _VMSTATE_UINT32(member) \ + VMSTATE_UINT32(member, CPUArchState) +const VMStateDescription vmstate_bfin_cpu = { + .name = "cpu", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_AUTO32_ARRAY(dreg), + VMSTATE_AUTO32_ARRAY(preg), + VMSTATE_AUTO32_ARRAY(ireg), + VMSTATE_AUTO32_ARRAY(mreg), + VMSTATE_AUTO32_ARRAY(breg), + VMSTATE_AUTO32_ARRAY(lreg), + VMSTATE_AUTO64_ARRAY(areg), + _VMSTATE_UINT32(rets), + VMSTATE_AUTO32_ARRAY(lcreg), + VMSTATE_AUTO32_ARRAY(ltreg), + VMSTATE_AUTO32_ARRAY(lbreg), + VMSTATE_AUTO32_ARRAY(cycles), + _VMSTATE_UINT32(uspreg), + _VMSTATE_UINT32(seqstat), + _VMSTATE_UINT32(syscfg), + _VMSTATE_UINT32(reti), + _VMSTATE_UINT32(retx), + _VMSTATE_UINT32(retn), + _VMSTATE_UINT32(rete), + _VMSTATE_UINT32(emudat), + _VMSTATE_UINT32(pc), + VMSTATE_AUTO32_ARRAY(astat), + _VMSTATE_UINT32(astat_op), + VMSTATE_AUTO32_ARRAY(astat_arg), + VMSTATE_END_OF_LIST() + } +}; diff --git a/target/bfin/meson.build b/target/bfin/meson.build index 2b8fa1e20d920..e41a9f8456b8a 100644 --- a/target/bfin/meson.build +++ b/target/bfin/meson.build @@ -7,4 +7,11 @@ bfin_ss.add(files( 'translate.c', )) +bfin_system_ss = ss.source_set() +bfin_system_ss.add(files( + 'machine.c', + 'monitor.c', +)) + target_arch += {'bfin': bfin_ss} +target_system_arch += {'bfin': bfin_system_ss} diff --git a/target/bfin/monitor.c b/target/bfin/monitor.c new file mode 100644 index 0000000000000..f3381c7e09e44 --- /dev/null +++ b/target/bfin/monitor.c @@ -0,0 +1,80 @@ +/* + * QEMU Blackfin CPU + * + * Copyright 2007-2023 Mike Frysinger + * Copyright 2007-2011 Analog Devices, Inc. + * + * Licensed under the Lesser GPL 2 or later. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "monitor/monitor.h" +#include "monitor/hmp-target.h" +#include "monitor/hmp.h" + +const MonitorDef monitor_defs[] = { +#define _REG(name, var) { name, offsetof(CPUArchState, var) } +#define REG(name) _REG(#name, name) +#define _REG_ARR(name, idx, arr) _REG(#name #idx, arr[idx]) +#define REG_ARR(name, idx) _REG_ARR(name, idx, name##reg) + _REG_ARR(r, 0, dreg), + _REG_ARR(r, 1, dreg), + _REG_ARR(r, 2, dreg), + _REG_ARR(r, 3, dreg), + _REG_ARR(r, 4, dreg), + _REG_ARR(r, 5, dreg), + _REG_ARR(r, 6, dreg), + _REG_ARR(r, 7, dreg), + REG_ARR(p, 0), + REG_ARR(p, 1), + REG_ARR(p, 2), + REG_ARR(p, 3), + REG_ARR(p, 4), + REG_ARR(p, 5), + REG_ARR(i, 0), + REG_ARR(i, 1), + REG_ARR(i, 2), + REG_ARR(i, 3), + REG_ARR(m, 0), + REG_ARR(m, 1), + REG_ARR(m, 2), + REG_ARR(m, 3), + REG_ARR(b, 0), + REG_ARR(b, 1), + REG_ARR(b, 2), + REG_ARR(b, 3), + REG_ARR(l, 0), + REG_ARR(l, 1), + REG_ARR(l, 2), + REG_ARR(l, 3), + REG(rets), + REG_ARR(lc, 0), + REG_ARR(lc, 1), + REG_ARR(lt, 0), + REG_ARR(lt, 1), + REG_ARR(lb, 0), + REG_ARR(lb, 1), + _REG_ARR(cycles, 0, cycles), + _REG_ARR(cycles, 1, cycles), + _REG("usp", uspreg), + _REG("fp", fpreg), + _REG("sp", spreg), + REG(seqstat), + REG(syscfg), + REG(reti), + REG(retx), + REG(retn), + REG(rete), + REG(emudat), + REG(pc), +#undef REG_ARR +#undef _REG_ARR +#undef REG +#undef _REG +}; + +const MonitorDef *target_monitor_defs(void) +{ + return monitor_defs; +} diff --git a/target/bfin/op_helper.c b/target/bfin/op_helper.c index 75316fff3acf4..8a79bb6e44068 100644 --- a/target/bfin/op_helper.c +++ b/target/bfin/op_helper.c @@ -11,12 +11,21 @@ #include "qemu/timer.h" #include "cpu.h" #include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "sysemu/runstate.h" void HELPER(raise_exception)(CPUArchState *env, uint32_t excp, uint32_t pc) { BlackfinCPU *cpu = bfin_env_get_cpu(env); CPUState *cs = CPU(cpu); +#ifndef CONFIG_LINUX_USER + /* TODO: This doesn't seem like the right place. */ + if (excp == EXCP_HLT) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + } +#endif + cs->exception_index = excp; if (pc != -1) { env->pc = pc; @@ -34,6 +43,12 @@ void HELPER(memalign)(CPUArchState *env, uint32_t excp, uint32_t pc, HELPER(raise_exception)(env, excp, pc); } +void HELPER(require_supervisor)(CPUArchState *env, uint32_t pc) +{ + if (!cec_is_supervisor_mode(env)) + HELPER(raise_exception)(env, EXCP_ILL_SUPV, pc); +} + void HELPER(dbga_l)(CPUArchState *env, uint32_t pc, uint32_t actual, uint32_t expected) { @@ -82,7 +97,14 @@ void HELPER(astat_store)(CPUArchState *env, uint32_t astat) So this code really should be returning CYCLES + clock offset. */ uint32_t HELPER(cycles_read)(CPUArchState *env) { - uint64_t cycles = cpu_get_host_ticks(); + uint64_t cycles; + +#ifndef CONFIG_USER_ONLY + cycles = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +#else + cycles = cpu_get_host_ticks(); +#endif + env->cycles[1] = cycles >> 32; env->cycles[0] = cycles; return env->cycles[0]; diff --git a/target/bfin/translate.c b/target/bfin/translate.c index 1247b987687bc..0e0357e9e390d 100644 --- a/target/bfin/translate.c +++ b/target/bfin/translate.c @@ -230,7 +230,8 @@ static void cec_require_supervisor(DisasContext *dc) #ifdef CONFIG_LINUX_USER cec_exception(dc, EXCP_ILL_SUPV); #else -# error todo + TCGv pc = tcg_constant_tl(dc->pc); + gen_helper_require_supervisor(tcg_env, pc); #endif }