Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / arch / um / kernel / skas / tlb.c
index 02e3e06..27eb29c 100644 (file)
@@ -1,5 +1,6 @@
 /* 
  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright 2003 PathScale, Inc.
  * Licensed under the GPL
  */
 
 #include "asm/mmu.h"
 #include "user_util.h"
 #include "mem_user.h"
+#include "mem.h"
 #include "skas.h"
 #include "os.h"
+#include "tlb.h"
 
-static void fix_range(struct mm_struct *mm, unsigned long start_addr,
-                     unsigned long end_addr, int force)
+static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last,
+                 int finished, void **flush)
 {
-       pgd_t *npgd;
-       pmd_t *npmd;
-       pte_t *npte;
-       unsigned long addr;
-       int r, w, x, err, fd;
+       struct host_vm_op *op;
+        int i, ret = 0;
 
-       if(mm == NULL) return;
-       fd = mm->context.skas.mm_fd;
-       for(addr = start_addr; addr < end_addr;){
-               npgd = pgd_offset(mm, addr);
-               npmd = pmd_offset(npgd, addr);
-               if(pmd_present(*npmd)){
-                       npte = pte_offset_kernel(npmd, addr);
-                       r = pte_read(*npte);
-                       w = pte_write(*npte);
-                       x = pte_exec(*npte);
-                       if(!pte_dirty(*npte)) w = 0;
-                       if(!pte_young(*npte)){
-                               r = 0;
-                               w = 0;
-                       }
-                       if(force || pte_newpage(*npte)){
-                               err = unmap(fd, (void *) addr, PAGE_SIZE);
-                               if(err < 0)
-                                       panic("munmap failed, errno = %d\n",
-                                             -err);
-                               if(pte_present(*npte))
-                                       map(fd, addr, 
-                                           pte_val(*npte) & PAGE_MASK,
-                                           PAGE_SIZE, r, w, x);
-                       }
-                       else if(pte_newprot(*npte)){
-                               protect(fd, addr, PAGE_SIZE, r, w, x, 1);
-                       }
-                       *npte = pte_mkuptodate(*npte);
-                       addr += PAGE_SIZE;
-               }
-               else {
-                       if(force || pmd_newpage(*npmd)){
-                               err = unmap(fd, (void *) addr, PMD_SIZE);
-                               if(err < 0)
-                                       panic("munmap failed, errno = %d\n",
-                                             -err);
-                               pmd_mkuptodate(*npmd);
-                       }
-                       addr += PMD_SIZE;
+        for(i = 0; i <= last && !ret; i++){
+               op = &ops[i];
+               switch(op->type){
+               case MMAP:
+                       ret = map(&mmu->skas.id, op->u.mmap.addr,
+                                 op->u.mmap.len, op->u.mmap.r, op->u.mmap.w,
+                                 op->u.mmap.x, op->u.mmap.fd,
+                                 op->u.mmap.offset, finished, flush);
+                       break;
+               case MUNMAP:
+                       ret = unmap(&mmu->skas.id,
+                                   (void *) op->u.munmap.addr,
+                                   op->u.munmap.len, finished, flush);
+                       break;
+               case MPROTECT:
+                       ret = protect(&mmu->skas.id, op->u.mprotect.addr,
+                                     op->u.mprotect.len, op->u.mprotect.r,
+                                     op->u.mprotect.w, op->u.mprotect.x,
+                                     finished, flush);
+                       break;
+               default:
+                       printk("Unknown op type %d in do_ops\n", op->type);
+                       break;
                }
        }
-}
 
-void flush_tlb_kernel_range_skas(unsigned long start, unsigned long end)
-{
-       struct mm_struct *mm;
-       pgd_t *pgd;
-       pmd_t *pmd;
-       pte_t *pte;
-       unsigned long addr;
-       int updated = 0, err;
-
-       mm = &init_mm;
-       for(addr = start; addr < end;){
-               pgd = pgd_offset(mm, addr);
-               pmd = pmd_offset(pgd, addr);
-               if(pmd_present(*pmd)){
-                       pte = pte_offset_kernel(pmd, addr);
-                       if(!pte_present(*pte) || pte_newpage(*pte)){
-                               updated = 1;
-                               err = os_unmap_memory((void *) addr, 
-                                                     PAGE_SIZE);
-                               if(err < 0)
-                                       panic("munmap failed, errno = %d\n",
-                                             -err);
-                               if(pte_present(*pte))
-                                       map_memory(addr, 
-                                                  pte_val(*pte) & PAGE_MASK,
-                                                  PAGE_SIZE, 1, 1, 1);
-                       }
-                       else if(pte_newprot(*pte)){
-                               updated = 1;
-                               protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1);
-                       }
-                       addr += PAGE_SIZE;
-               }
-               else {
-                       if(pmd_newpage(*pmd)){
-                               updated = 1;
-                               err = os_unmap_memory((void *) addr, PMD_SIZE);
-                               if(err < 0)
-                                       panic("munmap failed, errno = %d\n",
-                                             -err);
-                       }
-                       addr += PMD_SIZE;
-               }
-       }
+       return ret;
 }
 
-void flush_tlb_kernel_vm_skas(void)
+extern int proc_mm;
+
+static void fix_range(struct mm_struct *mm, unsigned long start_addr,
+                     unsigned long end_addr, int force)
 {
-       flush_tlb_kernel_range_skas(start_vm, end_vm);
+        if(!proc_mm && (end_addr > CONFIG_STUB_START))
+                end_addr = CONFIG_STUB_START;
+
+        fix_range_common(mm, start_addr, end_addr, force, do_ops);
 }
 
 void __flush_tlb_one_skas(unsigned long addr)
 {
-       flush_tlb_kernel_range_skas(addr, addr + PAGE_SIZE);
+        flush_tlb_kernel_range_common(addr, addr + PAGE_SIZE);
 }
 
 void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start, 
                     unsigned long end)
 {
-       if(vma->vm_mm == NULL)
-               flush_tlb_kernel_range_skas(start, end);
-       else fix_range(vma->vm_mm, start, end, 0);
+        if(vma->vm_mm == NULL)
+                flush_tlb_kernel_range_common(start, end);
+        else fix_range(vma->vm_mm, start, end, 0);
 }
 
 void flush_tlb_mm_skas(struct mm_struct *mm)
 {
-       flush_tlb_kernel_vm_skas();
-       fix_range(mm, 0, host_task_size, 0);
+       unsigned long end;
+
+       /* Don't bother flushing if this address space is about to be
+         * destroyed.
+         */
+        if(atomic_read(&mm->mm_users) == 0)
+                return;
+
+       end = proc_mm ? task_size : CONFIG_STUB_START;
+        fix_range(mm, 0, end, 0);
 }
 
 void force_flush_all_skas(void)
 {
-       fix_range(current->mm, 0, host_task_size, 1);
+       unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
+        fix_range(current->mm, 0, end, 1);
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */