diff options
-rw-r--r-- | arch/s390/include/asm/processor.h | 2 | ||||
-rw-r--r-- | arch/s390/kernel/entry.h | 1 | ||||
-rw-r--r-- | arch/s390/kernel/pgm_check.S | 2 | ||||
-rw-r--r-- | arch/s390/mm/fault.c | 37 | ||||
-rw-r--r-- | arch/s390/mm/mmap.c | 12 | ||||
-rw-r--r-- | arch/s390/mm/pgtable.c | 18 |
6 files changed, 21 insertions, 51 deletions
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index a56e63483e0f..0a876bc543d3 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h | |||
@@ -144,9 +144,7 @@ struct stack_frame { | |||
144 | regs->psw.mask = PSW_USER_BITS | PSW_MASK_BA; \ | 144 | regs->psw.mask = PSW_USER_BITS | PSW_MASK_BA; \ |
145 | regs->psw.addr = new_psw | PSW_ADDR_AMODE; \ | 145 | regs->psw.addr = new_psw | PSW_ADDR_AMODE; \ |
146 | regs->gprs[15] = new_stackp; \ | 146 | regs->gprs[15] = new_stackp; \ |
147 | __tlb_flush_mm(current->mm); \ | ||
148 | crst_table_downgrade(current->mm, 1UL << 31); \ | 147 | crst_table_downgrade(current->mm, 1UL << 31); \ |
149 | update_mm(current->mm, current); \ | ||
150 | execve_tail(); \ | 148 | execve_tail(); \ |
151 | } while (0) | 149 | } while (0) |
152 | 150 | ||
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index e9b04c33d383..cb533f78c09e 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h | |||
@@ -23,7 +23,6 @@ asmlinkage void do_syscall_trace_exit(struct pt_regs *regs); | |||
23 | 23 | ||
24 | void do_protection_exception(struct pt_regs *regs); | 24 | void do_protection_exception(struct pt_regs *regs); |
25 | void do_dat_exception(struct pt_regs *regs); | 25 | void do_dat_exception(struct pt_regs *regs); |
26 | void do_asce_exception(struct pt_regs *regs); | ||
27 | 26 | ||
28 | void addressing_exception(struct pt_regs *regs); | 27 | void addressing_exception(struct pt_regs *regs); |
29 | void data_exception(struct pt_regs *regs); | 28 | void data_exception(struct pt_regs *regs); |
diff --git a/arch/s390/kernel/pgm_check.S b/arch/s390/kernel/pgm_check.S index 14bdecb61923..4a460c44e17e 100644 --- a/arch/s390/kernel/pgm_check.S +++ b/arch/s390/kernel/pgm_check.S | |||
@@ -78,7 +78,7 @@ PGM_CHECK_DEFAULT /* 34 */ | |||
78 | PGM_CHECK_DEFAULT /* 35 */ | 78 | PGM_CHECK_DEFAULT /* 35 */ |
79 | PGM_CHECK_DEFAULT /* 36 */ | 79 | PGM_CHECK_DEFAULT /* 36 */ |
80 | PGM_CHECK_DEFAULT /* 37 */ | 80 | PGM_CHECK_DEFAULT /* 37 */ |
81 | PGM_CHECK_64BIT(do_asce_exception) /* 38 */ | 81 | PGM_CHECK_DEFAULT /* 38 */ |
82 | PGM_CHECK_64BIT(do_dat_exception) /* 39 */ | 82 | PGM_CHECK_64BIT(do_dat_exception) /* 39 */ |
83 | PGM_CHECK_64BIT(do_dat_exception) /* 3a */ | 83 | PGM_CHECK_64BIT(do_dat_exception) /* 3a */ |
84 | PGM_CHECK_64BIT(do_dat_exception) /* 3b */ | 84 | PGM_CHECK_64BIT(do_dat_exception) /* 3b */ |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 8f29762671cf..d95265b2719f 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
@@ -423,43 +423,6 @@ void __kprobes do_dat_exception(struct pt_regs *regs) | |||
423 | do_fault_error(regs, fault); | 423 | do_fault_error(regs, fault); |
424 | } | 424 | } |
425 | 425 | ||
426 | #ifdef CONFIG_64BIT | ||
427 | void __kprobes do_asce_exception(struct pt_regs *regs) | ||
428 | { | ||
429 | struct mm_struct *mm = current->mm; | ||
430 | struct vm_area_struct *vma; | ||
431 | unsigned long trans_exc_code; | ||
432 | |||
433 | /* | ||
434 | * The instruction that caused the program check has | ||
435 | * been nullified. Don't signal single step via SIGTRAP. | ||
436 | */ | ||
437 | clear_tsk_thread_flag(current, TIF_PER_TRAP); | ||
438 | |||
439 | trans_exc_code = regs->int_parm_long; | ||
440 | if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm)) | ||
441 | goto no_context; | ||
442 | |||
443 | down_read(&mm->mmap_sem); | ||
444 | vma = find_vma(mm, trans_exc_code & __FAIL_ADDR_MASK); | ||
445 | up_read(&mm->mmap_sem); | ||
446 | |||
447 | if (vma) { | ||
448 | update_mm(mm, current); | ||
449 | return; | ||
450 | } | ||
451 | |||
452 | /* User mode accesses just cause a SIGSEGV */ | ||
453 | if (user_mode(regs)) { | ||
454 | do_sigsegv(regs, SEGV_MAPERR); | ||
455 | return; | ||
456 | } | ||
457 | |||
458 | no_context: | ||
459 | do_no_context(regs); | ||
460 | } | ||
461 | #endif | ||
462 | |||
463 | int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write) | 426 | int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write) |
464 | { | 427 | { |
465 | struct pt_regs regs; | 428 | struct pt_regs regs; |
diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c index 40023290ee5b..6bcb045d2bd2 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c | |||
@@ -101,18 +101,12 @@ void arch_pick_mmap_layout(struct mm_struct *mm) | |||
101 | 101 | ||
102 | int s390_mmap_check(unsigned long addr, unsigned long len, unsigned long flags) | 102 | int s390_mmap_check(unsigned long addr, unsigned long len, unsigned long flags) |
103 | { | 103 | { |
104 | int rc; | ||
105 | |||
106 | if (is_compat_task() || (TASK_SIZE >= (1UL << 53))) | 104 | if (is_compat_task() || (TASK_SIZE >= (1UL << 53))) |
107 | return 0; | 105 | return 0; |
108 | if (!(flags & MAP_FIXED)) | 106 | if (!(flags & MAP_FIXED)) |
109 | addr = 0; | 107 | addr = 0; |
110 | if ((addr + len) >= TASK_SIZE) { | 108 | if ((addr + len) >= TASK_SIZE) |
111 | rc = crst_table_upgrade(current->mm, 1UL << 53); | 109 | return crst_table_upgrade(current->mm, 1UL << 53); |
112 | if (rc) | ||
113 | return rc; | ||
114 | update_mm(current->mm, current); | ||
115 | } | ||
116 | return 0; | 110 | return 0; |
117 | } | 111 | } |
118 | 112 | ||
@@ -132,7 +126,6 @@ s390_get_unmapped_area(struct file *filp, unsigned long addr, | |||
132 | rc = crst_table_upgrade(mm, 1UL << 53); | 126 | rc = crst_table_upgrade(mm, 1UL << 53); |
133 | if (rc) | 127 | if (rc) |
134 | return (unsigned long) rc; | 128 | return (unsigned long) rc; |
135 | update_mm(mm, current); | ||
136 | area = arch_get_unmapped_area(filp, addr, len, pgoff, flags); | 129 | area = arch_get_unmapped_area(filp, addr, len, pgoff, flags); |
137 | } | 130 | } |
138 | return area; | 131 | return area; |
@@ -155,7 +148,6 @@ s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr, | |||
155 | rc = crst_table_upgrade(mm, 1UL << 53); | 148 | rc = crst_table_upgrade(mm, 1UL << 53); |
156 | if (rc) | 149 | if (rc) |
157 | return (unsigned long) rc; | 150 | return (unsigned long) rc; |
158 | update_mm(mm, current); | ||
159 | area = arch_get_unmapped_area_topdown(filp, addr, len, | 151 | area = arch_get_unmapped_area_topdown(filp, addr, len, |
160 | pgoff, flags); | 152 | pgoff, flags); |
161 | } | 153 | } |
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index a9be08899b0c..0a2e5e086749 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -48,12 +48,23 @@ void crst_table_free(struct mm_struct *mm, unsigned long *table) | |||
48 | } | 48 | } |
49 | 49 | ||
50 | #ifdef CONFIG_64BIT | 50 | #ifdef CONFIG_64BIT |
51 | static void __crst_table_upgrade(void *arg) | ||
52 | { | ||
53 | struct mm_struct *mm = arg; | ||
54 | |||
55 | if (current->active_mm == mm) | ||
56 | update_mm(mm, current); | ||
57 | __tlb_flush_local(); | ||
58 | } | ||
59 | |||
51 | int crst_table_upgrade(struct mm_struct *mm, unsigned long limit) | 60 | int crst_table_upgrade(struct mm_struct *mm, unsigned long limit) |
52 | { | 61 | { |
53 | unsigned long *table, *pgd; | 62 | unsigned long *table, *pgd; |
54 | unsigned long entry; | 63 | unsigned long entry; |
64 | int flush; | ||
55 | 65 | ||
56 | BUG_ON(limit > (1UL << 53)); | 66 | BUG_ON(limit > (1UL << 53)); |
67 | flush = 0; | ||
57 | repeat: | 68 | repeat: |
58 | table = crst_table_alloc(mm); | 69 | table = crst_table_alloc(mm); |
59 | if (!table) | 70 | if (!table) |
@@ -79,12 +90,15 @@ repeat: | |||
79 | mm->pgd = (pgd_t *) table; | 90 | mm->pgd = (pgd_t *) table; |
80 | mm->task_size = mm->context.asce_limit; | 91 | mm->task_size = mm->context.asce_limit; |
81 | table = NULL; | 92 | table = NULL; |
93 | flush = 1; | ||
82 | } | 94 | } |
83 | spin_unlock_bh(&mm->page_table_lock); | 95 | spin_unlock_bh(&mm->page_table_lock); |
84 | if (table) | 96 | if (table) |
85 | crst_table_free(mm, table); | 97 | crst_table_free(mm, table); |
86 | if (mm->context.asce_limit < limit) | 98 | if (mm->context.asce_limit < limit) |
87 | goto repeat; | 99 | goto repeat; |
100 | if (flush) | ||
101 | on_each_cpu(__crst_table_upgrade, mm, 0); | ||
88 | return 0; | 102 | return 0; |
89 | } | 103 | } |
90 | 104 | ||
@@ -92,6 +106,8 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit) | |||
92 | { | 106 | { |
93 | pgd_t *pgd; | 107 | pgd_t *pgd; |
94 | 108 | ||
109 | if (current->active_mm == mm) | ||
110 | __tlb_flush_mm(mm); | ||
95 | while (mm->context.asce_limit > limit) { | 111 | while (mm->context.asce_limit > limit) { |
96 | pgd = mm->pgd; | 112 | pgd = mm->pgd; |
97 | switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) { | 113 | switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) { |
@@ -114,6 +130,8 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit) | |||
114 | mm->task_size = mm->context.asce_limit; | 130 | mm->task_size = mm->context.asce_limit; |
115 | crst_table_free(mm, (unsigned long *) pgd); | 131 | crst_table_free(mm, (unsigned long *) pgd); |
116 | } | 132 | } |
133 | if (current->active_mm == mm) | ||
134 | update_mm(mm, current); | ||
117 | } | 135 | } |
118 | #endif | 136 | #endif |
119 | 137 | ||