Merge master.kernel.org:/pub/scm/linux/kernel/git/herbert/crypto-2.6
[linux-drm-fsl-dcu.git] / arch / um / kernel / skas / tlb.c
index 6e84963dfc29e99c93bcdfe1cd2e11c1103c9310..c0f0693743babd98095f834a73407876afcbe354 100644 (file)
@@ -6,12 +6,10 @@
 
 #include "linux/stddef.h"
 #include "linux/sched.h"
-#include "linux/config.h"
 #include "linux/mm.h"
 #include "asm/page.h"
 #include "asm/pgtable.h"
 #include "asm/mmu.h"
-#include "user_util.h"
 #include "mem_user.h"
 #include "mem.h"
 #include "skas.h"
@@ -29,19 +27,17 @@ static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last,
                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);
+                                 op->u.mmap.len, op->u.mmap.prot,
+                                 op->u.mmap.fd, op->u.mmap.offset, finished,
+                                 flush);
                        break;
                case MUNMAP:
-                       ret = unmap(&mmu->skas.id,
-                                   (void *) op->u.munmap.addr,
+                       ret = unmap(&mmu->skas.id, 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,
+                                     op->u.mprotect.len, op->u.mprotect.prot,
                                      finished, flush);
                        break;
                default:
@@ -93,6 +89,76 @@ void flush_tlb_mm_skas(struct mm_struct *mm)
 
 void force_flush_all_skas(void)
 {
-       unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
-        fix_range(current->mm, 0, end, 1);
+       struct mm_struct *mm = current->mm;
+       struct vm_area_struct *vma = mm->mmap;
+
+       while(vma != NULL) {
+               fix_range(mm, vma->vm_start, vma->vm_end, 1);
+               vma = vma->vm_next;
+       }
+}
+
+void flush_tlb_page_skas(struct vm_area_struct *vma, unsigned long address)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+       struct mm_struct *mm = vma->vm_mm;
+       void *flush = NULL;
+       int r, w, x, prot, err = 0;
+       struct mm_id *mm_id;
+
+       pgd = pgd_offset(mm, address);
+       if(!pgd_present(*pgd))
+               goto kill;
+
+       pud = pud_offset(pgd, address);
+       if(!pud_present(*pud))
+               goto kill;
+
+       pmd = pmd_offset(pud, address);
+       if(!pmd_present(*pmd))
+               goto kill;
+
+       pte = pte_offset_kernel(pmd, address);
+
+       r = pte_read(*pte);
+       w = pte_write(*pte);
+       x = pte_exec(*pte);
+       if (!pte_young(*pte)) {
+               r = 0;
+               w = 0;
+       } else if (!pte_dirty(*pte)) {
+               w = 0;
+       }
+
+       mm_id = &mm->context.skas.id;
+       prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) |
+               (x ? UM_PROT_EXEC : 0));
+       if(pte_newpage(*pte)){
+               if(pte_present(*pte)){
+                       unsigned long long offset;
+                       int fd;
+
+                       fd = phys_mapping(pte_val(*pte) & PAGE_MASK, &offset);
+                       err = map(mm_id, address, PAGE_SIZE, prot, fd, offset,
+                                 1, &flush);
+               }
+               else err = unmap(mm_id, address, PAGE_SIZE, 1, &flush);
+       }
+       else if(pte_newprot(*pte))
+               err = protect(mm_id, address, PAGE_SIZE, prot, 1, &flush);
+
+       if(err)
+               goto kill;
+
+       *pte = pte_mkuptodate(*pte);
+
+       return;
+
+kill:
+       printk("Failed to flush page for address 0x%lx\n", address);
+       force_sig(SIGKILL, current);
 }
+