Kernel/armv7 - Implementing COW
authorJohn Hodge <[email protected]>
Wed, 26 Oct 2011 10:00:49 +0000 (18:00 +0800)
committerJohn Hodge <[email protected]>
Wed, 26 Oct 2011 10:00:49 +0000 (18:00 +0800)
Kernel/arch/armv7/mm_virt.c
Kernel/arch/armv7/start.S

index 2c0a2bd..8689e09 100644 (file)
@@ -52,6 +52,7 @@ tPAddr        MM_Clone(void);
 tVAddr MM_NewKStack(int bGlobal);
 void   MM_int_DumpTableEnt(tVAddr Start, size_t Len, tMM_PageInfo *Info);
 //void MM_DumpTables(tVAddr Start, tVAddr End);
+void   MM_PageFault(Uint32 PC, Uint32 Addr, Uint32 DFSR, int bPrefetch);
 
 // === GLOBALS ===
 tPAddr giMM_ZeroPage;
@@ -118,11 +119,9 @@ int MM_int_AllocateCoarse(tVAddr VAddr, int Domain)
        desc[3] = desc[0] + 0xC00;
 
        if( VAddr < 0x80000000 ) {
-//             Log("USRFRACTAL(%p) = %p", VAddr, &USRFRACTAL(VAddr));
                USRFRACTAL(VAddr) = paddr | 0x13;
        }
        else {
-//             Log("FRACTAL(%p) = %p", VAddr, &FRACTAL(table1, VAddr));
                FRACTAL(table1, VAddr) = paddr | 0x13;
        }
 
@@ -168,7 +167,7 @@ int MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
 
                        *desc = (pi->PhysAddr & 0xFFFFF000) | 2;
                        if(!pi->bExecutable)    *desc |= 1;     // XN
-                       if(!pi->bGlobal)        *desc |= 1 << 11;       // NG
+                       if(!pi->bGlobal)        *desc |= 1 << 11;       // nG
                        if( pi->bShared)        *desc |= 1 << 10;       // S
                        *desc |= (pi->AP & 3) << 4;     // AP
                        *desc |= ((pi->AP >> 2) & 1) << 9;      // APX
@@ -933,3 +932,47 @@ void MM_DumpTables(tVAddr Start, tVAddr End)
        Debug("Done");
 }
 
+// NOTE: Runs in abort context, not much differe, just a smaller stack
+void MM_PageFault(Uint32 PC, Uint32 Addr, Uint32 DFSR, int bPrefetch)
+{
+        int    rv;
+       tMM_PageInfo    pi;
+       
+       rv = MM_int_GetPageInfo(Addr, &pi);
+       
+       // Check for COW
+       if( rv == 0 &&  pi.AP == AP_RO_BOTH )
+       {
+               Log_Notice("MMVirt", "COW %p caused by %p", Addr, PC);
+               pi.AP = AP_RW_BOTH;
+               if( MM_GetRefCount(pi.PhysAddr) > 1 )
+               {
+                       // Duplicate the page
+                       tPAddr  newpage;
+                       void    *dst, *src;
+                       
+                       newpage = MM_AllocPhys();
+                       if(!newpage) {
+                               Log_Error("MMVirt", "Unable to allocate new page for COW");
+                               for(;;);
+                       }
+                       dst = (void*)MM_MapTemp(newpage);
+                       src = (void*)(Addr & ~(PAGE_SIZE-1));
+                       memcpy( dst, src, PAGE_SIZE );
+                       MM_FreeTemp( (tVAddr)dst );
+                       
+                       pi.PhysAddr = newpage;
+               }
+               // Unset COW
+               pi.AP = AP_RW_BOTH;
+               MM_int_SetPageInfo(Addr, &pi);
+               return ;
+       }
+       
+
+       Log_Error("MMVirt", "Code at %p accessed %p (DFSR = 0x%x)%s", PC, Addr, DFSR,
+               (bPrefetch ? " - Prefetch" : "")
+               );
+       for(;;);
+}
+
index 95bcd47..3c0779f 100644 (file)
@@ -143,22 +143,19 @@ IRQHandler:
 .globl DataAbort
 DataAbort:
        sub lr, #8      @ Adjust LR to the correct value
-@      srsdb sp!, #19  @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
+       srsdb sp!, #23  @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
 @      cpsid ifa, #19
-@      PUSH_GPRS
+       PUSH_GPRS
 
-       mrc p15, 0, r4, c5, c0, 0       @ Read DFSR (Data Fault Address Register) to stack
-       push {r4}
-       mrc p15, 0, r3, c6, c0, 0       @ Read DFAR (Data Fault Address Register) into R3
-       mov r2, lr
-       ldr r1, =csDataAbort_Fmt
-       ldr r0, =csAbort_Tag
-       ldr r4, =Log_Error
+       mov r3, #0      @ not a prefetch abort
+       mrc p15, 0, r2, c5, c0, 0       @ Read DFSR (Data Fault Status Register) to R2
+       mrc p15, 0, r1, c6, c0, 0       @ Read DFAR (Data Fault Address Register) into R1
+       mov r0, lr      @ PC
+       ldr r4, =MM_PageFault
        blx r4
-       b .
 
-@      POP_GPRS
-@      rfeia sp!       @ Pop state (actually RFEFD)
+       POP_GPRS
+       rfeia sp!       @ Pop state (actually RFEFD)
 
 .globl PrefetchAbort
 PrefetchAbort:
@@ -224,7 +221,7 @@ kernel_table0:
        .long PCI_PADDR + 12*(1 << 20) + 0x402
        .long PCI_PADDR + 13*(1 << 20) + 0x402
        .long PCI_PADDR + 14*(1 << 20) + 0x402
-       .long PCI_PADDR + 15*(1 << 20) + 0x042
+       .long PCI_PADDR + 15*(1 << 20) + 0x402
 #else
        .rept 16
                .long 0
@@ -250,7 +247,7 @@ kernel_table0:
 @ PID0 user table
 .globl user_table1_map
 @ User table1 data table (only the first half is needed)
-@ - Abused to provide kernel stacks in upper half
+@ - Abused to provide kernel stacks in the unused half of the table
 user_table1_map:       @ Size = 4KiB (only 2KiB used)
        .rept 0x800/4-1
                .long 0
@@ -277,13 +274,13 @@ kernel_table1_map:        @ Size = 4KiB
        .rept 0xFF8/4 - (0xF00+16)/4 - 1
                .long 0
        .endr
-       .long kernel_table1_map - KERNEL_BASE + (1 << 4) + 3
+       .long kernel_table1_map - KERNEL_BASE + 0x13
        .long kernel_exception_map - KERNEL_BASE + 0x13
 
 @ Hardware mappings 
 .globl hwmap_table_0
 hwmap_table_0:
-       .long UART0_PADDR + (1 << 4) + 0x13     @ UART0
+       .long UART0_PADDR + 0x13        @ UART0
        .rept 1024 - 1
                .long 0
        .endr
@@ -297,7 +294,7 @@ kernel_exception_map:
        .rept 256-16
                .long   0
        .endr
-       .long 0x213     @ Map first page for exceptions (Kernel RO)
+       .long 0x212     @ Map first page for exceptions (Kernel RO, Execute)
        .rept 15
                .long 0
        .endr

UCC git Repository :: git.ucc.asn.au