|
@@ -30,11 +30,27 @@
|
|
#define TABLES_PER_PAGE 4
|
|
#define TABLES_PER_PAGE 4
|
|
#define FRAG_MASK 15UL
|
|
#define FRAG_MASK 15UL
|
|
#define SECOND_HALVES 10UL
|
|
#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
|
|
#else
|
|
#define ALLOC_ORDER 2
|
|
#define ALLOC_ORDER 2
|
|
#define TABLES_PER_PAGE 2
|
|
#define TABLES_PER_PAGE 2
|
|
#define FRAG_MASK 3UL
|
|
#define FRAG_MASK 3UL
|
|
#define SECOND_HALVES 2UL
|
|
#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
|
|
#endif
|
|
|
|
|
|
unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec)
|
|
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 *table;
|
|
unsigned long bits;
|
|
unsigned long bits;
|
|
|
|
|
|
- bits = mm->context.noexec ? 3UL : 1UL;
|
|
|
|
|
|
+ bits = (mm->context.noexec || mm->context.pgstes) ? 3UL : 1UL;
|
|
spin_lock(&mm->page_table_lock);
|
|
spin_lock(&mm->page_table_lock);
|
|
page = NULL;
|
|
page = NULL;
|
|
if (!list_empty(&mm->context.pgtable_list)) {
|
|
if (!list_empty(&mm->context.pgtable_list)) {
|
|
@@ -170,7 +186,10 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
|
|
pgtable_page_ctor(page);
|
|
pgtable_page_ctor(page);
|
|
page->flags &= ~FRAG_MASK;
|
|
page->flags &= ~FRAG_MASK;
|
|
table = (unsigned long *) page_to_phys(page);
|
|
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);
|
|
spin_lock(&mm->page_table_lock);
|
|
list_add(&page->lru, &mm->context.pgtable_list);
|
|
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;
|
|
struct page *page;
|
|
unsigned long bits;
|
|
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);
|
|
bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
|
|
page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
|
|
page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
|
|
spin_lock(&mm->page_table_lock);
|
|
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;
|
|
mm->context.noexec = 0;
|
|
update_mm(mm, tsk);
|
|
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);
|