Added icache flushing
authorAndrew Waterman <waterman@ubuntu.(none)>
Sat, 27 Mar 2010 08:38:17 +0000 (01:38 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:38 +0000 (17:35 -0700)
Some ISAs (cough) require icache flushes after code has been
self-modified, e.g. after faulting in a new page.  The lack
of this support caused the RAMP HW to crash.  I've added an
arch-specific "icache_flush_page" primitive; it's a nop on
x86, and on SPARC it flushes the I$/D$.

kern/arch/i686/arch.h
kern/arch/sparc/arch.h
kern/arch/sparc/trap.c
kern/arch/sparc/trap.h
kern/arch/sparc/trap_entry.S
kern/include/mm.h
kern/src/mm.c

index f9e812c..77d6d4f 100644 (file)
@@ -13,6 +13,7 @@
 static __inline void breakpoint(void) __attribute__((always_inline));
 static __inline void invlpg(void *SNT addr) __attribute__((always_inline));
 static __inline void tlbflush(void) __attribute__((always_inline));
+static __inline void icache_flush_page(void* va, void* kva) __attribute__((always_inline));
 static __inline uint64_t read_tsc(void) __attribute__((always_inline));
 static __inline uint64_t read_tsc_serialized(void) __attribute__((always_inline));
 static __inline void enable_irq(void) __attribute__((always_inline));
@@ -58,6 +59,12 @@ tlbflush(void)
        __asm __volatile("movl %0,%%cr3" : : "r" (cr3));
 }
 
+static __inline void
+icache_flush_page(void* va, void* kva)
+{
+       // x86 handles self-modifying code (mostly) without SW support
+}
+
 static __inline uint64_t
 read_tsc(void)
 {
index 5361579..840c710 100644 (file)
@@ -24,6 +24,8 @@ static __inline void enable_irqsave(int8_t* state) __attribute__((always_inline)
 static __inline void disable_irqsave(int8_t* state) __attribute__((always_inline));
 static __inline void cpu_relax(void) __attribute__((always_inline));
 static __inline void cpu_halt(void) __attribute__((always_inline));
+static __inline void tlbflush(void) __attribute__((always_inline));
+static __inline void icache_flush_page(void* va, void* pa)__attribute__((always_inline));
 static __inline void clflush(uintptr_t* addr) __attribute__((always_inline));
 static __inline int irq_is_enabled(void) __attribute__((always_inline));
 static __inline uint32_t core_id(void) __attribute__((always_inline));
@@ -53,11 +55,16 @@ invlpg(void *addr)
 static __inline void
 tlbflush(void)
 {
-       // unsure if we'll support this yet...
-       // may have to just do invlpg() in a loop
        store_alternate(0x400,3,0);
 }
 
+static __inline void
+icache_flush_page(void* va, void* kva)
+{
+       for(int i = 0; i < PGSIZE; i+=32) // functional pipeline line size
+               clflush((uintptr_t*)((char*)kva+i));
+}
+
 static __inline uint64_t
 read_tsc(void)
 {
index b1c8c12..2c951a0 100644 (file)
@@ -11,6 +11,7 @@
 #include <slab.h>
 #include <mm.h>
 #include <ros/mman.h>
+#include <pmap.h>
 
 #ifdef __SHARC__
 #pragma nosharc
@@ -83,8 +84,8 @@ void
                        "  psr  0x%08x  pc   0x%08x  npc  0x%08x  wim  0x%08x\n",
                        tf->psr,tf->pc,tf->npc,tf->wim);
        len += snprintf(buf+len,sizeof(buf)-len,
-                       "  y    0x%08x  fsr  0x%08x  far  0x%08x\n",
-                       tf->y,tf->fault_status,tf->fault_addr);
+                       "  y    0x%08x  insn 0x%08x  fsr  0x%08x  far  0x%08x\n",
+                       tf->y,tf->pc_insn,tf->fault_status,tf->fault_addr);
        len += snprintf(buf+len,sizeof(buf)-len,
                        "  timestamp  %21lld\n",tf->timestamp);
 
@@ -185,8 +186,7 @@ stack_fucked(trapframe_t* state)
        {
                // the trap happened while flushing out windows.
                // hope this happened in the user, or else we're hosed...
-               extern char bootstacktop;
-               state = (trapframe_t*)(&bootstacktop-SIZEOF_TRAPFRAME_T-core_id()*KSTKSIZE);
+               state = (trapframe_t*)(bootstacktop-SIZEOF_TRAPFRAME_T-core_id()*KSTKSIZE);
        }
 
        warn("You just got stack fucked!");
index 776599b..3aeee38 100644 (file)
@@ -18,7 +18,7 @@ typedef struct
        uint32_t tbr;
        uint32_t y;
        uint32_t asr13;
-       uint32_t pad;
+       uint32_t pc_insn;
        uint32_t fault_status;
        uint32_t fault_addr;
        uint64_t timestamp;
index e02c4be..e7b89ef 100644 (file)
@@ -110,6 +110,15 @@ env_save_tf:
        lda     [%o5] 2,%o5
        std     %o4,[%o0+168]
 
+       # try to read out the faulting insn (in no-fault mode)
+       andn    %o1,3,%o1
+       lda     [%g0] 4,%o2
+       or      %o2,2,%o3
+       sta     %o3,[%g0] 4
+       ld      [%o1],%o1
+       st      %o1,[%o0+156]
+       sta     %o2,[%g0] 4
+
        std     %g0,[%o0+ 0]
        std     %g2,[%o0+ 8]
        std     %g4,[%o0+16]
@@ -140,7 +149,6 @@ env_save_tf:
        // a fault
        .global env_pop_tf
 env_pop_tf:
-
        mov     %psr,%o1
        wr      %o1,PSR_ET,%psr
 
index 8ecf159..4ec7410 100644 (file)
@@ -68,7 +68,7 @@ typedef struct pfault_info {
        struct file* file; // or NULL for zero-fill
        size_t pgoff; // offset into file
        size_t read_len; // amount of file to read into this page (zero-fill rest)
-       int perm;
+       int prot;
 } pfault_info_t;
 
 void mmap_init(void);
index cf3dc65..2171713 100644 (file)
@@ -109,8 +109,6 @@ void *do_mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
        }
 
        // make the lazy mapping finally
-       int perm = (prot & PROT_WRITE) ? PTE_USER_RW :
-                  (prot & (PROT_READ|PROT_EXEC))  ? PTE_USER_RO : 0;
        for(int i = 0; i < num_pages; i++)
        {
                // free an old page that was present here
@@ -126,7 +124,7 @@ void *do_mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
                // zero-fill end of last page
                if(i == num_pages-1 && len % PGSIZE)
                        pfis[i]->read_len = len % PGSIZE;
-               pfis[i]->perm = perm;
+               pfis[i]->prot = prot;
                *ptes[i] = PFAULT_INFO2PTE(pfis[i]);
 
                // uncomment the line below to simulate aggressive loading
@@ -208,7 +206,7 @@ int mprotect(struct proc* p, void* addr, size_t len, int prot)
                                *pte = 0;
                        }
                        else
-                               PTE2PFAULT_INFO(*pte)->perm = newperm;
+                               PTE2PFAULT_INFO(*pte)->prot = prot;
                }
        }
 
@@ -289,10 +287,17 @@ int handle_page_fault(struct proc* p, uintptr_t va, int prot)
                // if we read too much, zero that part out
                if(info->read_len < read_len)
                        memset(page2kva(a_page)+info->read_len,0,read_len-info->read_len);
+
+               // if this is an executable page, we might have to flush
+               // the instruction cache if our HW requires it
+               if(info->prot & PROT_EXEC)
+                       icache_flush_page((void*)va,page2kva(a_page));
        }
 
+       int perm = (info->prot & PROT_WRITE) ? PTE_USER_RW :
+                  (info->prot & (PROT_READ|PROT_EXEC))  ? PTE_USER_RO : 0;
        // update the page table
-       if(page_insert(p->env_pgdir, a_page, (void*)va, info->perm))
+       if(page_insert(p->env_pgdir, a_page, (void*)va, perm))
        {
                page_free(a_page);
                goto out;