]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/s390/mm/pgtable.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux...
[linux-2.6-omap-h63xx.git] / arch / s390 / mm / pgtable.c
index fd072013f88ce11658adab8b7db4818a6479f50b..5c1aea97cd1229b2e231c7dd838ee71663087316 100644 (file)
 #define TABLES_PER_PAGE        4
 #define FRAG_MASK      15UL
 #define SECOND_HALVES  10UL
+
+void clear_table_pgstes(unsigned long *table)
+{
+       clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE/4);
+       memset(table + 256, 0, PAGE_SIZE/4);
+       clear_table(table + 512, _PAGE_TYPE_EMPTY, PAGE_SIZE/4);
+       memset(table + 768, 0, PAGE_SIZE/4);
+}
+
 #else
 #define ALLOC_ORDER    2
 #define TABLES_PER_PAGE        2
 #define FRAG_MASK      3UL
 #define SECOND_HALVES  2UL
+
+void clear_table_pgstes(unsigned long *table)
+{
+       clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE/2);
+       memset(table + 256, 0, PAGE_SIZE/2);
+}
+
 #endif
 
 unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec)
@@ -153,7 +169,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
        unsigned long *table;
        unsigned long bits;
 
-       bits = mm->context.noexec ? 3UL : 1UL;
+       bits = (mm->context.noexec || mm->context.pgstes) ? 3UL : 1UL;
        spin_lock(&mm->page_table_lock);
        page = NULL;
        if (!list_empty(&mm->context.pgtable_list)) {
@@ -170,7 +186,10 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
                pgtable_page_ctor(page);
                page->flags &= ~FRAG_MASK;
                table = (unsigned long *) page_to_phys(page);
-               clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
+               if (mm->context.pgstes)
+                       clear_table_pgstes(table);
+               else
+                       clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
                spin_lock(&mm->page_table_lock);
                list_add(&page->lru, &mm->context.pgtable_list);
        }
@@ -191,7 +210,7 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
        struct page *page;
        unsigned long bits;
 
-       bits = mm->context.noexec ? 3UL : 1UL;
+       bits = (mm->context.noexec || mm->context.pgstes) ? 3UL : 1UL;
        bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
        page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
        spin_lock(&mm->page_table_lock);
@@ -228,3 +247,43 @@ void disable_noexec(struct mm_struct *mm, struct task_struct *tsk)
        mm->context.noexec = 0;
        update_mm(mm, tsk);
 }
+
+/*
+ * switch on pgstes for its userspace process (for kvm)
+ */
+int s390_enable_sie(void)
+{
+       struct task_struct *tsk = current;
+       struct mm_struct *mm;
+       int rc;
+
+       task_lock(tsk);
+
+       rc = 0;
+       if (tsk->mm->context.pgstes)
+               goto unlock;
+
+       rc = -EINVAL;
+       if (!tsk->mm || atomic_read(&tsk->mm->mm_users) > 1 ||
+           tsk->mm != tsk->active_mm || tsk->mm->ioctx_list)
+               goto unlock;
+
+       tsk->mm->context.pgstes = 1;    /* dirty little tricks .. */
+       mm = dup_mm(tsk);
+       tsk->mm->context.pgstes = 0;
+
+       rc = -ENOMEM;
+       if (!mm)
+               goto unlock;
+       mmput(tsk->mm);
+       tsk->mm = tsk->active_mm = mm;
+       preempt_disable();
+       update_mm(mm, tsk);
+       cpu_set(smp_processor_id(), mm->cpu_vm_mask);
+       preempt_enable();
+       rc = 0;
+unlock:
+       task_unlock(tsk);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(s390_enable_sie);