summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/um/include/os.h2
-rw-r--r--arch/um/include/skas/mode_kern_skas.h2
-rw-r--r--arch/um/kernel/skas/tlb.c66
-rw-r--r--arch/um/kernel/tlb.c4
-rw-r--r--arch/um/os-Linux/skas/mem.c4
5 files changed, 72 insertions, 6 deletions
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index d6638090870..e11bdcd8afc 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -302,7 +302,7 @@ extern long syscall_stub_data(struct mm_id * mm_idp,
extern int map(struct mm_id * mm_idp, unsigned long virt,
unsigned long len, int r, int w, int x, int phys_fd,
unsigned long long offset, int done, void **data);
-extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len,
+extern int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
int done, void **data);
extern int protect(struct mm_id * mm_idp, unsigned long addr,
unsigned long len, int r, int w, int x, int done,
diff --git a/arch/um/include/skas/mode_kern_skas.h b/arch/um/include/skas/mode_kern_skas.h
index 9cd9c6ec9a6..8ee6285dfac 100644
--- a/arch/um/include/skas/mode_kern_skas.h
+++ b/arch/um/include/skas/mode_kern_skas.h
@@ -33,6 +33,8 @@ extern unsigned long set_task_sizes_skas(unsigned long *task_size_out);
extern int start_uml_skas(void);
extern int external_pid_skas(struct task_struct *task);
extern int thread_pid_skas(struct task_struct *task);
+extern void flush_tlb_page_skas(struct vm_area_struct *vma,
+ unsigned long address);
#define kmem_end_skas (host_task_size - 1024 * 1024)
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
index 304a5b0695a..c43901aa936 100644
--- a/arch/um/kernel/skas/tlb.c
+++ b/arch/um/kernel/skas/tlb.c
@@ -32,8 +32,7 @@ static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last,
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:
@@ -94,3 +93,66 @@ void force_flush_all_skas(void)
unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
fix_range(current->mm, 0, end, 1);
}
+
+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, err = 0;
+ struct mm_id *mm_id;
+
+ pgd = pgd_offset(vma->vm_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;
+ 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, r, w, x, 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, r, w, x, 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);
+}
+
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index e201ccf0ec8..00de86efcca 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -381,7 +381,9 @@ pte_t *addr_pte(struct task_struct *task, unsigned long addr)
void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
{
address &= PAGE_MASK;
- flush_tlb_range(vma, address, address + PAGE_SIZE);
+
+ CHOOSE_MODE(flush_tlb_range(vma, address, address + PAGE_SIZE),
+ flush_tlb_page_skas(vma, address));
}
void flush_tlb_all(void)
diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c
index 6cdfda807b6..af0790719b7 100644
--- a/arch/um/os-Linux/skas/mem.c
+++ b/arch/um/os-Linux/skas/mem.c
@@ -219,8 +219,8 @@ int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
return ret;
}
-int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done,
- void **data)
+int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
+ int done, void **data)
{
int ret;