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
diff --git a/exec-all.h b/exec-all.h
index 2b93769..c6b7bd1 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -593,7 +593,11 @@
     }
     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
--- a/exec.c
+++ b/exec.c
@@ -1957,11 +1957,10 @@
 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 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 91ed11f..7e993b7 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -290,6 +290,8 @@
 
 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 4349503..bdc5b0e 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 @@
     uint32_t ret = 0;
 
     switch (asi) {
+    case 2: /* SuperSparc MXCC registers */
+        break;
     case 3: /* MMU probe */
 	{
 	    int mmulev;
@@ -179,7 +182,30 @@
 #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 @@
 	    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_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 @@
 #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 @@
 	    // 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 @@
             }
 	}
 	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 @@
     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 @@
     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 @@
 }
 
 #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 c5eefad..38d2a13 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -3494,6 +3494,8 @@
     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