diff --git a/exec-all.h b/exec-all.h index 2b9376930f2f21bb580c329841dfb674a73e9c34..c6b7bd19865432fee07719b523ca21574f5a2c9a 100644 --- a/exec-all.h +++ b/exec-all.h @@ -593,7 +593,11 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) } pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK; if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { +#ifdef TARGET_SPARC + do_unassigned_access(addr, 0, 1, 0); +#else cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr); +#endif } return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base; } diff --git a/exec.c b/exec.c index 4261dc06b11218832d158aa014ad2cb642b904ac..bf2d82b9f43074f899b0c5032f02bb44c08e7fef 100644 --- a/exec.c +++ b/exec.c @@ -1957,11 +1957,10 @@ void qemu_ram_free(ram_addr_t addr) static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) { #ifdef DEBUG_UNASSIGNED - printf("Unassigned mem read 0x%08x\n", (int)addr); + printf("Unassigned mem read " TARGET_FMT_lx "\n", addr); #endif #ifdef TARGET_SPARC - // Not enabled yet because of bugs in gdbstub etc. - //raise_exception(TT_DATA_ACCESS); + do_unassigned_access(addr, 0, 0, 0); #endif return 0; } @@ -1969,11 +1968,10 @@ static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { #ifdef DEBUG_UNASSIGNED - printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val); + printf("Unassigned mem write " TARGET_FMT_lx " = 0x%x\n", addr, val); #endif #ifdef TARGET_SPARC - // Not enabled yet because of bugs in gdbstub etc. - //raise_exception(TT_DATA_ACCESS); + do_unassigned_access(addr, 1, 0, 0); #endif } diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 91ed11fd05ee8f7324de2dd1f9c5194aa8cda053..7e993b7a1d23fac967be6921e8cb3e0bcbaf4ed2 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -290,6 +290,8 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); void raise_exception(int tt); +void do_unassigned_access(target_ulong addr, int is_write, int is_exec, + int is_asi); #include "cpu-all.h" diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 4349503ffc30de0d8865d266c4ab7c4217b1583f..bdc5b0e15444041d24844fd1b52c30ed9985c2a9 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -3,6 +3,7 @@ //#define DEBUG_PCALL //#define DEBUG_MMU //#define DEBUG_UNALIGNED +//#define DEBUG_UNASSIGNED void raise_exception(int tt) { @@ -151,6 +152,8 @@ void helper_ld_asi(int asi, int size, int sign) uint32_t ret = 0; switch (asi) { + case 2: /* SuperSparc MXCC registers */ + break; case 3: /* MMU probe */ { int mmulev; @@ -179,7 +182,30 @@ void helper_ld_asi(int asi, int size, int sign) #endif } break; - case 0x20 ... 0x2f: /* MMU passthrough */ + case 9: /* Supervisor code access */ + switch(size) { + case 1: + ret = ldub_code(T0); + break; + case 2: + ret = lduw_code(T0 & ~1); + break; + default: + case 4: + ret = ldl_code(T0 & ~3); + break; + case 8: + ret = ldl_code(T0 & ~3); + T0 = ldl_code((T0 + 4) & ~3); + break; + } + break; + case 0xc: /* I-cache tag */ + case 0xd: /* I-cache data */ + case 0xe: /* D-cache tag */ + case 0xf: /* D-cache data */ + break; + case 0x20: /* MMU passthrough */ switch(size) { case 1: ret = ldub_phys(T0); @@ -197,7 +223,9 @@ void helper_ld_asi(int asi, int size, int sign) break; } break; + case 0x21 ... 0x2f: /* MMU passthrough, unassigned */ default: + do_unassigned_access(T0, 0, 0, 1); ret = 0; break; } @@ -207,6 +235,8 @@ void helper_ld_asi(int asi, int size, int sign) void helper_st_asi(int asi, int size, int sign) { switch(asi) { + case 2: /* SuperSparc MXCC registers */ + break; case 3: /* MMU flush */ { int mmulev; @@ -271,18 +301,28 @@ void helper_st_asi(int asi, int size, int sign) #endif return; } + case 0xc: /* I-cache tag */ + case 0xd: /* I-cache data */ + case 0xe: /* D-cache tag */ + case 0xf: /* D-cache data */ + case 0x10: /* I/D-cache flush page */ + case 0x11: /* I/D-cache flush segment */ + case 0x12: /* I/D-cache flush region */ + case 0x13: /* I/D-cache flush context */ + case 0x14: /* I/D-cache flush user */ + break; case 0x17: /* Block copy, sta access */ { // value (T1) = src // address (T0) = dst // copy 32 bytes - uint32_t src = T1, dst = T0; - uint8_t temp[32]; + unsigned int i; + uint32_t src = T1 & ~3, dst = T0 & ~3, temp; - tswap32s(&src); - - cpu_physical_memory_read(src, (void *) &temp, 32); - cpu_physical_memory_write(dst, (void *) &temp, 32); + for (i = 0; i < 32; i += 4, src += 4, dst += 4) { + temp = ldl_kernel(src); + stl_kernel(dst, temp); + } } return; case 0x1f: /* Block fill, stda access */ @@ -290,19 +330,17 @@ void helper_st_asi(int asi, int size, int sign) // value (T1, T2) // address (T0) = dst // fill 32 bytes - int i; - uint32_t dst = T0; - uint64_t val; - - val = (((uint64_t)T1) << 32) | T2; - tswap64s(&val); + unsigned int i; + uint32_t dst = T0 & 7; + uint64_t val; - for (i = 0; i < 32; i += 8, dst += 8) { - cpu_physical_memory_write(dst, (void *) &val, 8); - } + val = (((uint64_t)T1) << 32) | T2; + + for (i = 0; i < 32; i += 8, dst += 8) + stq_kernel(dst, val); } return; - case 0x20 ... 0x2f: /* MMU passthrough */ + case 0x20: /* MMU passthrough */ { switch(size) { case 1: @@ -322,7 +360,14 @@ void helper_st_asi(int asi, int size, int sign) } } return; + case 0x31: /* Ross RT620 I-cache flush */ + case 0x36: /* I-cache flash clear */ + case 0x37: /* D-cache flash clear */ + break; + case 9: /* Supervisor code access, XXX */ + case 0x21 ... 0x2f: /* MMU passthrough, unassigned */ default: + do_unassigned_access(T0, 1, 0, 1); return; } } @@ -441,6 +486,7 @@ void helper_ld_asi(int asi, int size, int sign) case 0x5f: // D-MMU demap, WO case 0x77: // Interrupt vector, WO default: + do_unassigned_access(T0, 0, 0, 1); ret = 0; break; } @@ -656,6 +702,7 @@ void helper_st_asi(int asi, int size, int sign) case 0x8a: // Primary no-fault LE, RO case 0x8b: // Secondary no-fault LE, RO default: + do_unassigned_access(T0, 1, 0, 1); return; } } @@ -986,3 +1033,53 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) } #endif + +#ifndef TARGET_SPARC64 +void do_unassigned_access(target_ulong addr, int is_write, int is_exec, + int is_asi) +{ + CPUState *saved_env; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + if (env->mmuregs[3]) /* Fault status register */ + env->mmuregs[3] = 1; /* overflow (not read before another fault) */ + if (is_asi) + env->mmuregs[3] |= 1 << 16; + if (env->psrs) + env->mmuregs[3] |= 1 << 5; + if (is_exec) + env->mmuregs[3] |= 1 << 6; + if (is_write) + env->mmuregs[3] |= 1 << 7; + env->mmuregs[3] |= (5 << 2) | 2; + env->mmuregs[4] = addr; /* Fault address register */ + if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) { +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem access to " TARGET_FMT_lx " from " TARGET_FMT_lx + "\n", addr, env->pc); +#endif + raise_exception(TT_DATA_ACCESS); + } + env = saved_env; +} +#else +void do_unassigned_access(target_ulong addr, int is_write, int is_exec, + int is_asi) +{ +#ifdef DEBUG_UNASSIGNED + CPUState *saved_env; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + printf("Unassigned mem access to " TARGET_FMT_lx " from " TARGET_FMT_lx "\n", + addr, env->pc); + env = saved_env; +#endif + raise_exception(TT_DATA_ACCESS); +} +#endif diff --git a/target-sparc/translate.c b/target-sparc/translate.c index c5eefad4ef4474521d71cec747fadb67422bd1ae..38d2a13195ed7cd7fc65e346b308958ba98b2459 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3494,6 +3494,8 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, 0) != 0) if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 0, 0) != 0) return -1; + if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) + return -1; return phys_addr; } #endif