X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=target-mips%2Fhelper.c;h=33e0e8863772f0eec7c8a4e108b2bedc8430c895;hb=30c367ed446b6ea53245589a5cf373578ac075d7;hp=8102f03c264ff5854a6342f770c06fbfc8bd6684;hpb=7d834c7450245335db0a7055ccdc783ccab21935;p=qemu.git diff --git a/target-mips/helper.c b/target-mips/helper.c index 8102f03c2..33e0e8863 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -24,7 +24,6 @@ #include #include "cpu.h" -#include "exec-all.h" enum { TLBRET_DIRTY = -4, @@ -37,7 +36,7 @@ enum { #if !defined(CONFIG_USER_ONLY) /* no MMU emulation */ -int no_mmu_map_address (CPUState *env, target_phys_addr_t *physical, int *prot, +int no_mmu_map_address (CPUMIPSState *env, hwaddr *physical, int *prot, target_ulong address, int rw, int access_type) { *physical = address; @@ -46,7 +45,7 @@ int no_mmu_map_address (CPUState *env, target_phys_addr_t *physical, int *prot, } /* fixed mapping MMU emulation */ -int fixed_mmu_map_address (CPUState *env, target_phys_addr_t *physical, int *prot, +int fixed_mmu_map_address (CPUMIPSState *env, hwaddr *physical, int *prot, target_ulong address, int rw, int access_type) { if (address <= (int32_t)0x7FFFFFFFUL) { @@ -64,7 +63,7 @@ int fixed_mmu_map_address (CPUState *env, target_phys_addr_t *physical, int *pro } /* MIPS32/MIPS64 R4000-style MMU emulation */ -int r4k_map_address (CPUState *env, target_phys_addr_t *physical, int *prot, +int r4k_map_address (CPUMIPSState *env, hwaddr *physical, int *prot, target_ulong address, int rw, int access_type) { uint8_t ASID = env->CP0_EntryHi & 0xFF; @@ -100,7 +99,7 @@ int r4k_map_address (CPUState *env, target_phys_addr_t *physical, int *prot, return TLBRET_NOMATCH; } -static int get_physical_address (CPUState *env, target_phys_addr_t *physical, +static int get_physical_address (CPUMIPSState *env, hwaddr *physical, int *prot, target_ulong address, int rw, int access_type) { @@ -194,7 +193,7 @@ static int get_physical_address (CPUState *env, target_phys_addr_t *physical, } } #if 0 - qemu_log(TARGET_FMT_lx " %d %d => " TARGET_FMT_lx " %d (%d)\n", + qemu_log(TARGET_FMT_lx " %d %d => %" HWADDR_PRIx " %d (%d)\n", address, rw, access_type, *physical, *prot, ret); #endif @@ -202,7 +201,7 @@ static int get_physical_address (CPUState *env, target_phys_addr_t *physical, } #endif -static void raise_mmu_exception(CPUState *env, target_ulong address, +static void raise_mmu_exception(CPUMIPSState *env, target_ulong address, int rw, int tlb_error) { int exception = 0, error_code = 0; @@ -255,51 +254,52 @@ static void raise_mmu_exception(CPUState *env, target_ulong address, } #if !defined(CONFIG_USER_ONLY) -target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +hwaddr mips_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) { - target_phys_addr_t phys_addr; + MIPSCPU *cpu = MIPS_CPU(cs); + hwaddr phys_addr; int prot; - if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0) + if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, + ACCESS_INT) != 0) { return -1; + } return phys_addr; } #endif -int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int mmu_idx, int is_softmmu) +int cpu_mips_handle_mmu_fault (CPUMIPSState *env, target_ulong address, int rw, + int mmu_idx) { #if !defined(CONFIG_USER_ONLY) - target_phys_addr_t physical; + hwaddr physical; int prot; -#endif int access_type; +#endif int ret = 0; #if 0 - log_cpu_state(env, 0); + log_cpu_state(CPU(mips_env_get_cpu(env)), 0); #endif - qemu_log("%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d smmu %d\n", - __func__, env->active_tc.PC, address, rw, mmu_idx, is_softmmu); + qemu_log("%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d\n", + __func__, env->active_tc.PC, address, rw, mmu_idx); rw &= 1; /* data access */ +#if !defined(CONFIG_USER_ONLY) /* XXX: put correct access by using cpu_restore_state() correctly */ access_type = ACCESS_INT; -#if defined(CONFIG_USER_ONLY) - ret = TLBRET_NOMATCH; -#else ret = get_physical_address(env, &physical, &prot, address, rw, access_type); qemu_log("%s address=" TARGET_FMT_lx " ret %d physical " TARGET_FMT_plx " prot %d\n", __func__, address, ret, physical, prot); if (ret == TLBRET_MATCH) { - tlb_set_page(env, address & TARGET_PAGE_MASK, - physical & TARGET_PAGE_MASK, prot | PAGE_EXEC, - mmu_idx, TARGET_PAGE_SIZE); - ret = 0; + tlb_set_page(env, address & TARGET_PAGE_MASK, + physical & TARGET_PAGE_MASK, prot | PAGE_EXEC, + mmu_idx, TARGET_PAGE_SIZE); + ret = 0; } else if (ret < 0) #endif { @@ -311,9 +311,9 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, } #if !defined(CONFIG_USER_ONLY) -target_phys_addr_t cpu_mips_translate_address(CPUState *env, target_ulong address, int rw) +hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, int rw) { - target_phys_addr_t physical; + hwaddr physical; int prot; int access_type; int ret = 0; @@ -369,8 +369,7 @@ static const char * const excp_names[EXCP_LAST + 1] = { [EXCP_CACHE] = "cache error", }; -#if !defined(CONFIG_USER_ONLY) -static target_ulong exception_resume_pc (CPUState *env) +target_ulong exception_resume_pc (CPUMIPSState *env) { target_ulong bad_pc; target_ulong isa_mode; @@ -385,10 +384,25 @@ static target_ulong exception_resume_pc (CPUState *env) return bad_pc; } + +#if !defined(CONFIG_USER_ONLY) +static void set_hflags_for_handler (CPUMIPSState *env) +{ + /* Exception handlers are entered in 32-bit mode. */ + env->hflags &= ~(MIPS_HFLAG_M16); + /* ...except that microMIPS lets you choose. */ + if (env->insn_flags & ASE_MICROMIPS) { + env->hflags |= (!!(env->CP0_Config3 + & (1 << CP0C3_ISA_ON_EXC)) + << MIPS_HFLAG_M16_SHIFT); + } +} #endif -void do_interrupt (CPUState *env) +void mips_cpu_do_interrupt(CPUState *cs) { + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; #if !defined(CONFIG_USER_ONLY) target_ulong offset; int cause = -1; @@ -440,11 +454,10 @@ void do_interrupt (CPUState *env) if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); env->active_tc.PC = (int32_t)0xBFC00480; - /* Exception handlers are entered in 32-bit mode. */ - env->hflags &= ~(MIPS_HFLAG_M16); + set_hflags_for_handler(env); break; case EXCP_RESET: - cpu_reset(env); + cpu_reset(CPU(cpu)); break; case EXCP_SRESET: env->CP0_Status |= (1 << CP0St_SR); @@ -461,13 +474,39 @@ void do_interrupt (CPUState *env) if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); env->active_tc.PC = (int32_t)0xBFC00000; - /* Exception handlers are entered in 32-bit mode. */ - env->hflags &= ~(MIPS_HFLAG_M16); + set_hflags_for_handler(env); break; case EXCP_EXT_INTERRUPT: cause = 0; if (env->CP0_Cause & (1 << CP0Ca_IV)) offset = 0x200; + + if (env->CP0_Config3 & ((1 << CP0C3_VInt) | (1 << CP0C3_VEIC))) { + /* Vectored Interrupts. */ + unsigned int spacing; + unsigned int vector; + unsigned int pending = (env->CP0_Cause & CP0Ca_IP_mask) >> 8; + + pending &= env->CP0_Status >> 8; + /* Compute the Vector Spacing. */ + spacing = (env->CP0_IntCtl >> CP0IntCtl_VS) & ((1 << 6) - 1); + spacing <<= 5; + + if (env->CP0_Config3 & (1 << CP0C3_VInt)) { + /* For VInt mode, the MIPS computes the vector internally. */ + for (vector = 7; vector > 0; vector--) { + if (pending & (1 << vector)) { + /* Found it. */ + break; + } + } + } else { + /* For VEIC mode, the external interrupt controller feeds the + vector through the CP0Cause IP lines. */ + vector = pending; + } + offset = 0x200 + vector * spacing; + } goto set_EPC; case EXCP_LTLBL: cause = 1; @@ -481,7 +520,8 @@ void do_interrupt (CPUState *env) int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; - if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) + if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) && + (!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)))) offset = 0x080; else #endif @@ -497,7 +537,8 @@ void do_interrupt (CPUState *env) int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; - if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) + if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) && + (!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)))) offset = 0x080; else #endif @@ -555,6 +596,9 @@ void do_interrupt (CPUState *env) case EXCP_THREAD: cause = 25; goto set_EPC; + case EXCP_DSPDIS: + cause = 26; + goto set_EPC; case EXCP_CACHE: cause = 30; if (env->CP0_Status & (1 << CP0St_BEV)) { @@ -581,8 +625,7 @@ void do_interrupt (CPUState *env) env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff); } env->active_tc.PC += offset; - /* Exception handlers are entered in 32-bit mode. */ - env->hflags &= ~(MIPS_HFLAG_M16); + set_hflags_for_handler(env); env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC); break; default: @@ -602,7 +645,7 @@ void do_interrupt (CPUState *env) } #if !defined(CONFIG_USER_ONLY) -void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) +void r4k_invalidate_tlb (CPUMIPSState *env, int idx, int use_extra) { r4k_tlb_t *tlb; target_ulong addr;