qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH][MIPS] Full MIPS64 MMU implementation


From: Aurelien Jarno
Subject: [Qemu-devel] [PATCH][MIPS] Full MIPS64 MMU implementation
Date: Sat, 12 May 2007 16:48:36 +0200
User-agent: Mutt/1.5.13 (2006-08-11)

Hi all,

The patch below finally adds full support for MIPS64 MMU. With it I am
able to boot a 64-bit MALTA kernel up to a kernel panic, as it does not
detect any devices. There is probably a bug somewhere in map_address().

Note that the long hardcoded masks are a bit ugly, but I am working on
a patch to add a per-CPU SEGBITS value.

Cheers,
Aurelien


diff -u target-mips/helper.c target-mips/helper.c
--- target-mips/helper.c        12 May 2007 13:49:53 -0000
+++ target-mips/helper.c        12 May 2007 13:53:39 -0000
@@ -50,6 +50,9 @@
         target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
         target_ulong tag = address & ~mask;
         target_ulong VPN = tlb->VPN & ~mask;
+#ifdef TARGET_MIPS64
+        tag &= 0xC00000FFFFFFFFFFULL;
+#endif
 
         /* Check ASID, virtual page number & size */
         if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
@@ -285,10 +288,16 @@
         }
         /* Raise exception */
         env->CP0_BadVAddr = address;
-        env->CP0_Context = (env->CP0_Context & 0xff800000) |
+        env->CP0_Context = (env->CP0_Context & ~0x007fffff) |
                           ((address >> 9) &   0x007ffff0);
         env->CP0_EntryHi =
             (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
+#ifdef TARGET_MIPS64
+        env->CP0_EntryHi &= 0xc00000ffffffffffULL;
+        env->CP0_XContext = (env->CP0_XContext & 0xfffffffe00000000ULL) |
+                            ((address >> 31) & 0x0000000180000000ULL) |
+                            ((address >> 9) & 0x000000007ffffff0ULL);
+#endif
         env->exception_index = exception;
         env->error_code = error_code;
         ret = 1;
@@ -401,8 +410,19 @@
         goto set_EPC;
     case EXCP_TLBL:
         cause = 2;
-        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL)))
-            offset = 0x000;
+        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
+#ifdef TARGET_MIPS64
+            int R = env->CP0_BadVAddr >> 62;
+            int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
+            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))
+                offset = 0x080;
+            else
+#endif
+                offset = 0x000;
+        }
         goto set_EPC;
     case EXCP_IBE:
         cause = 6;
@@ -438,8 +458,19 @@
         goto set_EPC;
     case EXCP_TLBS:
         cause = 3;
-        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL)))
-            offset = 0x000;
+        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
+#ifdef TARGET_MIPS64
+            int R = env->CP0_BadVAddr >> 62;
+            int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
+            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))
+                offset = 0x080;
+            else
+#endif
+                offset = 0x000;
+        }
     set_EPC:
         if (!(env->CP0_Status & (1 << CP0St_EXL))) {
             if (env->hflags & MIPS_HFLAG_BMASK) {
@@ -510,6 +541,11 @@
     mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
     if (tlb->V0) {
         addr = tlb->VPN & ~mask;
+#ifdef TARGET_MIPS64
+        if (addr >= 0xC00000FF80000000ULL) {
+            addr |= 0x3FFFFF0000000000ULL;
+        }
+#endif
         end = addr | (mask >> 1);
         while (addr < end) {
             tlb_flush_page (env, addr);
@@ -518,6 +554,11 @@
     }
     if (tlb->V1) {
         addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
+#ifdef TARGET_MIPS64
+        if (addr >= 0xC00000FF80000000ULL) {
+            addr |= 0x3FFFFF0000000000ULL;
+        }
+#endif
         end = addr | mask;
         while (addr < end) {
             tlb_flush_page (env, addr);
diff -u target-mips/op.c target-mips/op.c
--- target-mips/op.c    12 May 2007 13:49:54 -0000
+++ target-mips/op.c    12 May 2007 13:53:39 -0000
@@ -1313,8 +1313,10 @@
     target_ulong old, val;
 
     /* 1k pages not implemented */
-    /* Ignore MIPS64 TLB for now */
-    val = (target_ulong)(int32_t)T0 & ~(target_ulong)0x1F00;
+    val = T0 & ((TARGET_PAGE_MASK << 1) | 0xFF);
+#ifdef TARGET_MIPS64
+    val = T0 & 0xC00000FFFFFFFFFFULL;
+#endif
     old = env->CP0_EntryHi;
     env->CP0_EntryHi = val;
     /* If the ASID changes, flush qemu's TLB.  */
diff -u target-mips/op_helper.c target-mips/op_helper.c
--- target-mips/op_helper.c     12 May 2007 13:49:54 -0000
+++ target-mips/op_helper.c     12 May 2007 13:53:39 -0000
@@ -412,6 +412,9 @@
     /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
     tlb = &env->tlb[idx];
     tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
+#ifdef TARGET_MIPS64
+    tlb->VPN = env->CP0_EntryHi & 0xC00000FFFFFFFFFFULL;
+#endif
     tlb->ASID = env->CP0_EntryHi & 0xFF;
     tlb->PageMask = env->CP0_PageMask;
     tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;

-- 
  .''`.  Aurelien Jarno             | GPG: 1024D/F1BCDB73
 : :' :  Debian developer           | Electrical Engineer
 `. `'   address@hidden         | address@hidden
   `-    people.debian.org/~aurel32 | www.aurel32.net




reply via email to

[Prev in Thread] Current Thread [Next in Thread]