Enable faults for unassigned memory accesses and unimplemented ASIs
authorblueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>
Thu, 17 May 2007 19:30:10 +0000 (19:30 +0000)
committerblueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>
Thu, 17 May 2007 19:30:10 +0000 (19:30 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2824 c046a42c-6fe2-441c-8c8c-71466251a162

exec-all.h
exec.c
target-sparc/cpu.h
target-sparc/op_helper.c
target-sparc/translate.c

index 2b93769..c6b7bd1 100644 (file)
@@ -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 4261dc0..bf2d82b 100644 (file)
--- 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
 }
 
index 91ed11f..7e993b7 100644 (file)
@@ -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"
 
index 4349503..bdc5b0e 100644 (file)
@@ -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
index c5eefad..38d2a13 100644 (file)
@@ -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