aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/kernel/head31.S11
-rw-r--r--arch/s390/kernel/head64.S11
-rw-r--r--arch/s390/mm/fault.c105
3 files changed, 63 insertions, 64 deletions
diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S
index da7c8bb80982..dc364c1419af 100644
--- a/arch/s390/kernel/head31.S
+++ b/arch/s390/kernel/head31.S
@@ -121,7 +121,7 @@ startup_continue:
121 .long .Lduct # cr2: dispatchable unit control table 121 .long .Lduct # cr2: dispatchable unit control table
122 .long 0 # cr3: instruction authorization 122 .long 0 # cr3: instruction authorization
123 .long 0 # cr4: instruction authorization 123 .long 0 # cr4: instruction authorization
124 .long 0xffffffff # cr5: primary-aste origin 124 .long .Lduct # cr5: primary-aste origin
125 .long 0 # cr6: I/O interrupts 125 .long 0 # cr6: I/O interrupts
126 .long 0 # cr7: secondary space segment table 126 .long 0 # cr7: secondary space segment table
127 .long 0 # cr8: access registers translation 127 .long 0 # cr8: access registers translation
@@ -132,8 +132,6 @@ startup_continue:
132 .long 0 # cr13: home space segment table 132 .long 0 # cr13: home space segment table
133 .long 0xc0000000 # cr14: machine check handling off 133 .long 0xc0000000 # cr14: machine check handling off
134 .long 0 # cr15: linkage stack operations 134 .long 0 # cr15: linkage stack operations
135.Lduct: .long 0,0,0,0,0,0,0,0
136 .long 0,0,0,0,0,0,0,0
137.Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu 135.Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu
138.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp 136.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp
139.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg 137.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
@@ -147,6 +145,13 @@ startup_continue:
147.Linittu: .long init_thread_union 145.Linittu: .long init_thread_union
148.Lstartup_init: 146.Lstartup_init:
149 .long startup_init 147 .long startup_init
148 .align 64
149.Lduct: .long 0,0,0,0,.Lduald,0,0,0
150 .long 0,0,0,0,0,0,0,0
151 .align 128
152.Lduald:.rept 8
153 .long 0x80000000,0,0,0 # invalid access-list entries
154 .endr
150 155
151 .org 0x12000 156 .org 0x12000
152 .globl _ehead 157 .globl _ehead
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index af09e18cc5d0..37010709fe68 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -134,7 +134,7 @@ startup_continue:
134 .quad .Lduct # cr2: dispatchable unit control table 134 .quad .Lduct # cr2: dispatchable unit control table
135 .quad 0 # cr3: instruction authorization 135 .quad 0 # cr3: instruction authorization
136 .quad 0 # cr4: instruction authorization 136 .quad 0 # cr4: instruction authorization
137 .quad 0xffffffffffffffff # cr5: primary-aste origin 137 .quad .Lduct # cr5: primary-aste origin
138 .quad 0 # cr6: I/O interrupts 138 .quad 0 # cr6: I/O interrupts
139 .quad 0 # cr7: secondary space segment table 139 .quad 0 # cr7: secondary space segment table
140 .quad 0 # cr8: access registers translation 140 .quad 0 # cr8: access registers translation
@@ -145,14 +145,19 @@ startup_continue:
145 .quad 0 # cr13: home space segment table 145 .quad 0 # cr13: home space segment table
146 .quad 0xc0000000 # cr14: machine check handling off 146 .quad 0xc0000000 # cr14: machine check handling off
147 .quad 0 # cr15: linkage stack operations 147 .quad 0 # cr15: linkage stack operations
148.Lduct: .long 0,0,0,0,0,0,0,0
149 .long 0,0,0,0,0,0,0,0
150.Lpcmsk:.quad 0x0000000180000000 148.Lpcmsk:.quad 0x0000000180000000
151.L4malign:.quad 0xffffffffffc00000 149.L4malign:.quad 0xffffffffffc00000
152.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8 150.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
153.Lnop: .long 0x07000700 151.Lnop: .long 0x07000700
154.Lparmaddr: 152.Lparmaddr:
155 .quad PARMAREA 153 .quad PARMAREA
154 .align 64
155.Lduct: .long 0,0,0,0,.Lduald,0,0,0
156 .long 0,0,0,0,0,0,0,0
157 .align 128
158.Lduald:.rept 8
159 .long 0x80000000,0,0,0 # invalid access-list entries
160 .endr
156 161
157 .org 0x12000 162 .org 0x12000
158 .globl _ehead 163 .globl _ehead
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 641aef36ccc4..7462aebd3eb6 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -108,53 +108,40 @@ void bust_spinlocks(int yes)
108} 108}
109 109
110/* 110/*
111 * Check which address space is addressed by the access 111 * Returns the address space associated with the fault.
112 * register in S390_lowcore.exc_access_id. 112 * Returns 0 for kernel space, 1 for user space and
113 * Returns 1 for user space and 0 for kernel space. 113 * 2 for code execution in user space with noexec=on.
114 */ 114 */
115static int __check_access_register(struct pt_regs *regs, int error_code) 115static inline int check_space(struct task_struct *tsk)
116{
117 int areg = S390_lowcore.exc_access_id;
118
119 if (areg == 0)
120 /* Access via access register 0 -> kernel address */
121 return 0;
122 save_access_regs(current->thread.acrs);
123 if (regs && areg < NUM_ACRS && current->thread.acrs[areg] <= 1)
124 /*
125 * access register contains 0 -> kernel address,
126 * access register contains 1 -> user space address
127 */
128 return current->thread.acrs[areg];
129
130 /* Something unhealthy was done with the access registers... */
131 die("page fault via unknown access register", regs, error_code);
132 do_exit(SIGKILL);
133 return 0;
134}
135
136/*
137 * Check which address space the address belongs to.
138 * May return 1 or 2 for user space and 0 for kernel space.
139 * Returns 2 for user space in primary addressing mode with
140 * CONFIG_S390_EXEC_PROTECT on and kernel parameter noexec=on.
141 */
142static inline int check_user_space(struct pt_regs *regs, int error_code)
143{ 116{
144 /* 117 /*
145 * The lowest two bits of S390_lowcore.trans_exc_code indicate 118 * The lowest two bits of S390_lowcore.trans_exc_code
146 * which paging table was used: 119 * indicate which paging table was used.
147 * 0: Primary Segment Table Descriptor
148 * 1: STD determined via access register
149 * 2: Secondary Segment Table Descriptor
150 * 3: Home Segment Table Descriptor
151 */ 120 */
152 int descriptor = S390_lowcore.trans_exc_code & 3; 121 int desc = S390_lowcore.trans_exc_code & 3;
153 if (unlikely(descriptor == 1)) 122
154 return __check_access_register(regs, error_code); 123 if (desc == 3) /* Home Segment Table Descriptor */
155 if (descriptor == 2) 124 return switch_amode == 0;
156 return current->thread.mm_segment.ar4; 125 if (desc == 2) /* Secondary Segment Table Descriptor */
157 return ((descriptor != 0) ^ (switch_amode)) << s390_noexec; 126 return tsk->thread.mm_segment.ar4;
127#ifdef CONFIG_S390_SWITCH_AMODE
128 if (unlikely(desc == 1)) { /* STD determined via access register */
129 /* %a0 always indicates primary space. */
130 if (S390_lowcore.exc_access_id != 0) {
131 save_access_regs(tsk->thread.acrs);
132 /*
133 * An alet of 0 indicates primary space.
134 * An alet of 1 indicates secondary space.
135 * Any other alet values generate an
136 * alen-translation exception.
137 */
138 if (tsk->thread.acrs[S390_lowcore.exc_access_id])
139 return tsk->thread.mm_segment.ar4;
140 }
141 }
142#endif
143 /* Primary Segment Table Descriptor */
144 return switch_amode << s390_noexec;
158} 145}
159 146
160/* 147/*
@@ -265,16 +252,16 @@ out_fault:
265 * 11 Page translation -> Not present (nullification) 252 * 11 Page translation -> Not present (nullification)
266 * 3b Region third trans. -> Not present (nullification) 253 * 3b Region third trans. -> Not present (nullification)
267 */ 254 */
268static inline void __kprobes 255static inline void
269do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection) 256do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
270{ 257{
271 struct task_struct *tsk; 258 struct task_struct *tsk;
272 struct mm_struct *mm; 259 struct mm_struct *mm;
273 struct vm_area_struct * vma; 260 struct vm_area_struct * vma;
274 unsigned long address; 261 unsigned long address;
275 int user_address;
276 const struct exception_table_entry *fixup; 262 const struct exception_table_entry *fixup;
277 int si_code = SEGV_MAPERR; 263 int si_code;
264 int space;
278 265
279 tsk = current; 266 tsk = current;
280 mm = tsk->mm; 267 mm = tsk->mm;
@@ -294,7 +281,7 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
294 NULL pointer write access in kernel mode. */ 281 NULL pointer write access in kernel mode. */
295 if (!(regs->psw.mask & PSW_MASK_PSTATE)) { 282 if (!(regs->psw.mask & PSW_MASK_PSTATE)) {
296 address = 0; 283 address = 0;
297 user_address = 0; 284 space = 0;
298 goto no_context; 285 goto no_context;
299 } 286 }
300 287
@@ -309,15 +296,15 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
309 * the address 296 * the address
310 */ 297 */
311 address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK; 298 address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK;
312 user_address = check_user_space(regs, error_code); 299 space = check_space(tsk);
313 300
314 /* 301 /*
315 * Verify that the fault happened in user space, that 302 * Verify that the fault happened in user space, that
316 * we are not in an interrupt and that there is a 303 * we are not in an interrupt and that there is a
317 * user context. 304 * user context.
318 */ 305 */
319 if (user_address == 0 || in_atomic() || !mm) 306 if (unlikely(space == 0 || in_atomic() || !mm))
320 goto no_context; 307 goto no_context;
321 308
322 /* 309 /*
323 * When we get here, the fault happened in the current 310 * When we get here, the fault happened in the current
@@ -328,12 +315,13 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
328 315
329 down_read(&mm->mmap_sem); 316 down_read(&mm->mmap_sem);
330 317
331 vma = find_vma(mm, address); 318 si_code = SEGV_MAPERR;
332 if (!vma) 319 vma = find_vma(mm, address);
333 goto bad_area; 320 if (!vma)
321 goto bad_area;
334 322
335#ifdef CONFIG_S390_EXEC_PROTECT 323#ifdef CONFIG_S390_EXEC_PROTECT
336 if (unlikely((user_address == 2) && !(vma->vm_flags & VM_EXEC))) 324 if (unlikely((space == 2) && !(vma->vm_flags & VM_EXEC)))
337 if (!signal_return(mm, regs, address, error_code)) 325 if (!signal_return(mm, regs, address, error_code))
338 /* 326 /*
339 * signal_return() has done an up_read(&mm->mmap_sem) 327 * signal_return() has done an up_read(&mm->mmap_sem)
@@ -389,7 +377,7 @@ survive:
389 * The instruction that caused the program check will 377 * The instruction that caused the program check will
390 * be repeated. Don't signal single step via SIGTRAP. 378 * be repeated. Don't signal single step via SIGTRAP.
391 */ 379 */
392 clear_tsk_thread_flag(current, TIF_SINGLE_STEP); 380 clear_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
393 return; 381 return;
394 382
395/* 383/*
@@ -419,7 +407,7 @@ no_context:
419 * Oops. The kernel tried to access some bad page. We'll have to 407 * Oops. The kernel tried to access some bad page. We'll have to
420 * terminate things with extreme prejudice. 408 * terminate things with extreme prejudice.
421 */ 409 */
422 if (user_address == 0) 410 if (space == 0)
423 printk(KERN_ALERT "Unable to handle kernel pointer dereference" 411 printk(KERN_ALERT "Unable to handle kernel pointer dereference"
424 " at virtual kernel address %p\n", (void *)address); 412 " at virtual kernel address %p\n", (void *)address);
425 else 413 else
@@ -462,13 +450,14 @@ do_sigbus:
462 goto no_context; 450 goto no_context;
463} 451}
464 452
465void do_protection_exception(struct pt_regs *regs, unsigned long error_code) 453void __kprobes do_protection_exception(struct pt_regs *regs,
454 unsigned long error_code)
466{ 455{
467 regs->psw.addr -= (error_code >> 16); 456 regs->psw.addr -= (error_code >> 16);
468 do_exception(regs, 4, 1); 457 do_exception(regs, 4, 1);
469} 458}
470 459
471void do_dat_exception(struct pt_regs *regs, unsigned long error_code) 460void __kprobes do_dat_exception(struct pt_regs *regs, unsigned long error_code)
472{ 461{
473 do_exception(regs, error_code & 0xff, 0); 462 do_exception(regs, error_code & 0xff, 0);
474} 463}