Commit 6c36d3fa860b1dfa55de1e8248be6fffcd876f69
1 parent
4edebb0e
Enable faults for unassigned memory accesses and unimplemented ASIs
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2824 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
126 additions
and
23 deletions
exec-all.h
| @@ -593,7 +593,11 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) | @@ -593,7 +593,11 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) | ||
| 593 | } | 593 | } |
| 594 | pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK; | 594 | pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK; |
| 595 | if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { | 595 | if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { |
| 596 | +#ifdef TARGET_SPARC | ||
| 597 | + do_unassigned_access(addr, 0, 1, 0); | ||
| 598 | +#else | ||
| 596 | cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr); | 599 | cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr); |
| 600 | +#endif | ||
| 597 | } | 601 | } |
| 598 | return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base; | 602 | return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base; |
| 599 | } | 603 | } |
exec.c
| @@ -1957,11 +1957,10 @@ void qemu_ram_free(ram_addr_t addr) | @@ -1957,11 +1957,10 @@ void qemu_ram_free(ram_addr_t addr) | ||
| 1957 | static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) | 1957 | static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) |
| 1958 | { | 1958 | { |
| 1959 | #ifdef DEBUG_UNASSIGNED | 1959 | #ifdef DEBUG_UNASSIGNED |
| 1960 | - printf("Unassigned mem read 0x%08x\n", (int)addr); | 1960 | + printf("Unassigned mem read " TARGET_FMT_lx "\n", addr); |
| 1961 | #endif | 1961 | #endif |
| 1962 | #ifdef TARGET_SPARC | 1962 | #ifdef TARGET_SPARC |
| 1963 | - // Not enabled yet because of bugs in gdbstub etc. | ||
| 1964 | - //raise_exception(TT_DATA_ACCESS); | 1963 | + do_unassigned_access(addr, 0, 0, 0); |
| 1965 | #endif | 1964 | #endif |
| 1966 | return 0; | 1965 | return 0; |
| 1967 | } | 1966 | } |
| @@ -1969,11 +1968,10 @@ static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) | @@ -1969,11 +1968,10 @@ static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) | ||
| 1969 | static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | 1968 | static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
| 1970 | { | 1969 | { |
| 1971 | #ifdef DEBUG_UNASSIGNED | 1970 | #ifdef DEBUG_UNASSIGNED |
| 1972 | - printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val); | 1971 | + printf("Unassigned mem write " TARGET_FMT_lx " = 0x%x\n", addr, val); |
| 1973 | #endif | 1972 | #endif |
| 1974 | #ifdef TARGET_SPARC | 1973 | #ifdef TARGET_SPARC |
| 1975 | - // Not enabled yet because of bugs in gdbstub etc. | ||
| 1976 | - //raise_exception(TT_DATA_ACCESS); | 1974 | + do_unassigned_access(addr, 1, 0, 0); |
| 1977 | #endif | 1975 | #endif |
| 1978 | } | 1976 | } |
| 1979 | 1977 |
target-sparc/cpu.h
| @@ -290,6 +290,8 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); | @@ -290,6 +290,8 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); | ||
| 290 | 290 | ||
| 291 | int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); | 291 | int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); |
| 292 | void raise_exception(int tt); | 292 | void raise_exception(int tt); |
| 293 | +void do_unassigned_access(target_ulong addr, int is_write, int is_exec, | ||
| 294 | + int is_asi); | ||
| 293 | 295 | ||
| 294 | #include "cpu-all.h" | 296 | #include "cpu-all.h" |
| 295 | 297 |
target-sparc/op_helper.c
| @@ -3,6 +3,7 @@ | @@ -3,6 +3,7 @@ | ||
| 3 | //#define DEBUG_PCALL | 3 | //#define DEBUG_PCALL |
| 4 | //#define DEBUG_MMU | 4 | //#define DEBUG_MMU |
| 5 | //#define DEBUG_UNALIGNED | 5 | //#define DEBUG_UNALIGNED |
| 6 | +//#define DEBUG_UNASSIGNED | ||
| 6 | 7 | ||
| 7 | void raise_exception(int tt) | 8 | void raise_exception(int tt) |
| 8 | { | 9 | { |
| @@ -151,6 +152,8 @@ void helper_ld_asi(int asi, int size, int sign) | @@ -151,6 +152,8 @@ void helper_ld_asi(int asi, int size, int sign) | ||
| 151 | uint32_t ret = 0; | 152 | uint32_t ret = 0; |
| 152 | 153 | ||
| 153 | switch (asi) { | 154 | switch (asi) { |
| 155 | + case 2: /* SuperSparc MXCC registers */ | ||
| 156 | + break; | ||
| 154 | case 3: /* MMU probe */ | 157 | case 3: /* MMU probe */ |
| 155 | { | 158 | { |
| 156 | int mmulev; | 159 | int mmulev; |
| @@ -179,7 +182,30 @@ void helper_ld_asi(int asi, int size, int sign) | @@ -179,7 +182,30 @@ void helper_ld_asi(int asi, int size, int sign) | ||
| 179 | #endif | 182 | #endif |
| 180 | } | 183 | } |
| 181 | break; | 184 | break; |
| 182 | - case 0x20 ... 0x2f: /* MMU passthrough */ | 185 | + case 9: /* Supervisor code access */ |
| 186 | + switch(size) { | ||
| 187 | + case 1: | ||
| 188 | + ret = ldub_code(T0); | ||
| 189 | + break; | ||
| 190 | + case 2: | ||
| 191 | + ret = lduw_code(T0 & ~1); | ||
| 192 | + break; | ||
| 193 | + default: | ||
| 194 | + case 4: | ||
| 195 | + ret = ldl_code(T0 & ~3); | ||
| 196 | + break; | ||
| 197 | + case 8: | ||
| 198 | + ret = ldl_code(T0 & ~3); | ||
| 199 | + T0 = ldl_code((T0 + 4) & ~3); | ||
| 200 | + break; | ||
| 201 | + } | ||
| 202 | + break; | ||
| 203 | + case 0xc: /* I-cache tag */ | ||
| 204 | + case 0xd: /* I-cache data */ | ||
| 205 | + case 0xe: /* D-cache tag */ | ||
| 206 | + case 0xf: /* D-cache data */ | ||
| 207 | + break; | ||
| 208 | + case 0x20: /* MMU passthrough */ | ||
| 183 | switch(size) { | 209 | switch(size) { |
| 184 | case 1: | 210 | case 1: |
| 185 | ret = ldub_phys(T0); | 211 | ret = ldub_phys(T0); |
| @@ -197,7 +223,9 @@ void helper_ld_asi(int asi, int size, int sign) | @@ -197,7 +223,9 @@ void helper_ld_asi(int asi, int size, int sign) | ||
| 197 | break; | 223 | break; |
| 198 | } | 224 | } |
| 199 | break; | 225 | break; |
| 226 | + case 0x21 ... 0x2f: /* MMU passthrough, unassigned */ | ||
| 200 | default: | 227 | default: |
| 228 | + do_unassigned_access(T0, 0, 0, 1); | ||
| 201 | ret = 0; | 229 | ret = 0; |
| 202 | break; | 230 | break; |
| 203 | } | 231 | } |
| @@ -207,6 +235,8 @@ void helper_ld_asi(int asi, int size, int sign) | @@ -207,6 +235,8 @@ void helper_ld_asi(int asi, int size, int sign) | ||
| 207 | void helper_st_asi(int asi, int size, int sign) | 235 | void helper_st_asi(int asi, int size, int sign) |
| 208 | { | 236 | { |
| 209 | switch(asi) { | 237 | switch(asi) { |
| 238 | + case 2: /* SuperSparc MXCC registers */ | ||
| 239 | + break; | ||
| 210 | case 3: /* MMU flush */ | 240 | case 3: /* MMU flush */ |
| 211 | { | 241 | { |
| 212 | int mmulev; | 242 | int mmulev; |
| @@ -271,18 +301,28 @@ void helper_st_asi(int asi, int size, int sign) | @@ -271,18 +301,28 @@ void helper_st_asi(int asi, int size, int sign) | ||
| 271 | #endif | 301 | #endif |
| 272 | return; | 302 | return; |
| 273 | } | 303 | } |
| 304 | + case 0xc: /* I-cache tag */ | ||
| 305 | + case 0xd: /* I-cache data */ | ||
| 306 | + case 0xe: /* D-cache tag */ | ||
| 307 | + case 0xf: /* D-cache data */ | ||
| 308 | + case 0x10: /* I/D-cache flush page */ | ||
| 309 | + case 0x11: /* I/D-cache flush segment */ | ||
| 310 | + case 0x12: /* I/D-cache flush region */ | ||
| 311 | + case 0x13: /* I/D-cache flush context */ | ||
| 312 | + case 0x14: /* I/D-cache flush user */ | ||
| 313 | + break; | ||
| 274 | case 0x17: /* Block copy, sta access */ | 314 | case 0x17: /* Block copy, sta access */ |
| 275 | { | 315 | { |
| 276 | // value (T1) = src | 316 | // value (T1) = src |
| 277 | // address (T0) = dst | 317 | // address (T0) = dst |
| 278 | // copy 32 bytes | 318 | // copy 32 bytes |
| 279 | - uint32_t src = T1, dst = T0; | ||
| 280 | - uint8_t temp[32]; | 319 | + unsigned int i; |
| 320 | + uint32_t src = T1 & ~3, dst = T0 & ~3, temp; | ||
| 281 | 321 | ||
| 282 | - tswap32s(&src); | ||
| 283 | - | ||
| 284 | - cpu_physical_memory_read(src, (void *) &temp, 32); | ||
| 285 | - cpu_physical_memory_write(dst, (void *) &temp, 32); | 322 | + for (i = 0; i < 32; i += 4, src += 4, dst += 4) { |
| 323 | + temp = ldl_kernel(src); | ||
| 324 | + stl_kernel(dst, temp); | ||
| 325 | + } | ||
| 286 | } | 326 | } |
| 287 | return; | 327 | return; |
| 288 | case 0x1f: /* Block fill, stda access */ | 328 | case 0x1f: /* Block fill, stda access */ |
| @@ -290,19 +330,17 @@ void helper_st_asi(int asi, int size, int sign) | @@ -290,19 +330,17 @@ void helper_st_asi(int asi, int size, int sign) | ||
| 290 | // value (T1, T2) | 330 | // value (T1, T2) |
| 291 | // address (T0) = dst | 331 | // address (T0) = dst |
| 292 | // fill 32 bytes | 332 | // fill 32 bytes |
| 293 | - int i; | ||
| 294 | - uint32_t dst = T0; | ||
| 295 | - uint64_t val; | ||
| 296 | - | ||
| 297 | - val = (((uint64_t)T1) << 32) | T2; | ||
| 298 | - tswap64s(&val); | 333 | + unsigned int i; |
| 334 | + uint32_t dst = T0 & 7; | ||
| 335 | + uint64_t val; | ||
| 299 | 336 | ||
| 300 | - for (i = 0; i < 32; i += 8, dst += 8) { | ||
| 301 | - cpu_physical_memory_write(dst, (void *) &val, 8); | ||
| 302 | - } | 337 | + val = (((uint64_t)T1) << 32) | T2; |
| 338 | + | ||
| 339 | + for (i = 0; i < 32; i += 8, dst += 8) | ||
| 340 | + stq_kernel(dst, val); | ||
| 303 | } | 341 | } |
| 304 | return; | 342 | return; |
| 305 | - case 0x20 ... 0x2f: /* MMU passthrough */ | 343 | + case 0x20: /* MMU passthrough */ |
| 306 | { | 344 | { |
| 307 | switch(size) { | 345 | switch(size) { |
| 308 | case 1: | 346 | case 1: |
| @@ -322,7 +360,14 @@ void helper_st_asi(int asi, int size, int sign) | @@ -322,7 +360,14 @@ void helper_st_asi(int asi, int size, int sign) | ||
| 322 | } | 360 | } |
| 323 | } | 361 | } |
| 324 | return; | 362 | return; |
| 363 | + case 0x31: /* Ross RT620 I-cache flush */ | ||
| 364 | + case 0x36: /* I-cache flash clear */ | ||
| 365 | + case 0x37: /* D-cache flash clear */ | ||
| 366 | + break; | ||
| 367 | + case 9: /* Supervisor code access, XXX */ | ||
| 368 | + case 0x21 ... 0x2f: /* MMU passthrough, unassigned */ | ||
| 325 | default: | 369 | default: |
| 370 | + do_unassigned_access(T0, 1, 0, 1); | ||
| 326 | return; | 371 | return; |
| 327 | } | 372 | } |
| 328 | } | 373 | } |
| @@ -441,6 +486,7 @@ void helper_ld_asi(int asi, int size, int sign) | @@ -441,6 +486,7 @@ void helper_ld_asi(int asi, int size, int sign) | ||
| 441 | case 0x5f: // D-MMU demap, WO | 486 | case 0x5f: // D-MMU demap, WO |
| 442 | case 0x77: // Interrupt vector, WO | 487 | case 0x77: // Interrupt vector, WO |
| 443 | default: | 488 | default: |
| 489 | + do_unassigned_access(T0, 0, 0, 1); | ||
| 444 | ret = 0; | 490 | ret = 0; |
| 445 | break; | 491 | break; |
| 446 | } | 492 | } |
| @@ -656,6 +702,7 @@ void helper_st_asi(int asi, int size, int sign) | @@ -656,6 +702,7 @@ void helper_st_asi(int asi, int size, int sign) | ||
| 656 | case 0x8a: // Primary no-fault LE, RO | 702 | case 0x8a: // Primary no-fault LE, RO |
| 657 | case 0x8b: // Secondary no-fault LE, RO | 703 | case 0x8b: // Secondary no-fault LE, RO |
| 658 | default: | 704 | default: |
| 705 | + do_unassigned_access(T0, 1, 0, 1); | ||
| 659 | return; | 706 | return; |
| 660 | } | 707 | } |
| 661 | } | 708 | } |
| @@ -986,3 +1033,53 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) | @@ -986,3 +1033,53 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) | ||
| 986 | } | 1033 | } |
| 987 | 1034 | ||
| 988 | #endif | 1035 | #endif |
| 1036 | + | ||
| 1037 | +#ifndef TARGET_SPARC64 | ||
| 1038 | +void do_unassigned_access(target_ulong addr, int is_write, int is_exec, | ||
| 1039 | + int is_asi) | ||
| 1040 | +{ | ||
| 1041 | + CPUState *saved_env; | ||
| 1042 | + | ||
| 1043 | + /* XXX: hack to restore env in all cases, even if not called from | ||
| 1044 | + generated code */ | ||
| 1045 | + saved_env = env; | ||
| 1046 | + env = cpu_single_env; | ||
| 1047 | + if (env->mmuregs[3]) /* Fault status register */ | ||
| 1048 | + env->mmuregs[3] = 1; /* overflow (not read before another fault) */ | ||
| 1049 | + if (is_asi) | ||
| 1050 | + env->mmuregs[3] |= 1 << 16; | ||
| 1051 | + if (env->psrs) | ||
| 1052 | + env->mmuregs[3] |= 1 << 5; | ||
| 1053 | + if (is_exec) | ||
| 1054 | + env->mmuregs[3] |= 1 << 6; | ||
| 1055 | + if (is_write) | ||
| 1056 | + env->mmuregs[3] |= 1 << 7; | ||
| 1057 | + env->mmuregs[3] |= (5 << 2) | 2; | ||
| 1058 | + env->mmuregs[4] = addr; /* Fault address register */ | ||
| 1059 | + if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) { | ||
| 1060 | +#ifdef DEBUG_UNASSIGNED | ||
| 1061 | + printf("Unassigned mem access to " TARGET_FMT_lx " from " TARGET_FMT_lx | ||
| 1062 | + "\n", addr, env->pc); | ||
| 1063 | +#endif | ||
| 1064 | + raise_exception(TT_DATA_ACCESS); | ||
| 1065 | + } | ||
| 1066 | + env = saved_env; | ||
| 1067 | +} | ||
| 1068 | +#else | ||
| 1069 | +void do_unassigned_access(target_ulong addr, int is_write, int is_exec, | ||
| 1070 | + int is_asi) | ||
| 1071 | +{ | ||
| 1072 | +#ifdef DEBUG_UNASSIGNED | ||
| 1073 | + CPUState *saved_env; | ||
| 1074 | + | ||
| 1075 | + /* XXX: hack to restore env in all cases, even if not called from | ||
| 1076 | + generated code */ | ||
| 1077 | + saved_env = env; | ||
| 1078 | + env = cpu_single_env; | ||
| 1079 | + printf("Unassigned mem access to " TARGET_FMT_lx " from " TARGET_FMT_lx "\n", | ||
| 1080 | + addr, env->pc); | ||
| 1081 | + env = saved_env; | ||
| 1082 | +#endif | ||
| 1083 | + raise_exception(TT_DATA_ACCESS); | ||
| 1084 | +} | ||
| 1085 | +#endif |
target-sparc/translate.c
| @@ -3494,6 +3494,8 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | @@ -3494,6 +3494,8 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | ||
| 3494 | if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, 0) != 0) | 3494 | if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, 0) != 0) |
| 3495 | if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 0, 0) != 0) | 3495 | if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 0, 0) != 0) |
| 3496 | return -1; | 3496 | return -1; |
| 3497 | + if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) | ||
| 3498 | + return -1; | ||
| 3497 | return phys_addr; | 3499 | return phys_addr; |
| 3498 | } | 3500 | } |
| 3499 | #endif | 3501 | #endif |