aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm/fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/mm/fault.c')
-rw-r--r--arch/s390/mm/fault.c53
1 files changed, 16 insertions, 37 deletions
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 88cef505453b..19f623f1f21c 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -106,21 +106,24 @@ void bust_spinlocks(int yes)
106 * Returns the address space associated with the fault. 106 * Returns the address space associated with the fault.
107 * Returns 0 for kernel space and 1 for user space. 107 * Returns 0 for kernel space and 1 for user space.
108 */ 108 */
109static inline int user_space_fault(unsigned long trans_exc_code) 109static inline int user_space_fault(struct pt_regs *regs)
110{ 110{
111 unsigned long trans_exc_code;
112
111 /* 113 /*
112 * The lowest two bits of the translation exception 114 * The lowest two bits of the translation exception
113 * identification indicate which paging table was used. 115 * identification indicate which paging table was used.
114 */ 116 */
115 trans_exc_code &= 3; 117 trans_exc_code = regs->int_parm_long & 3;
116 if (trans_exc_code == 2) 118 if (trans_exc_code == 3) /* home space -> kernel */
117 /* Access via secondary space, set_fs setting decides */ 119 return 0;
120 if (user_mode(regs))
121 return 1;
122 if (trans_exc_code == 2) /* secondary space -> set_fs */
118 return current->thread.mm_segment.ar4; 123 return current->thread.mm_segment.ar4;
119 /* 124 if (current->flags & PF_VCPU)
120 * Access via primary space or access register is from user space 125 return 1;
121 * and access via home space is from the kernel. 126 return 0;
122 */
123 return trans_exc_code != 3;
124} 127}
125 128
126static inline void report_user_fault(struct pt_regs *regs, long signr) 129static inline void report_user_fault(struct pt_regs *regs, long signr)
@@ -172,7 +175,7 @@ static noinline void do_no_context(struct pt_regs *regs)
172 * terminate things with extreme prejudice. 175 * terminate things with extreme prejudice.
173 */ 176 */
174 address = regs->int_parm_long & __FAIL_ADDR_MASK; 177 address = regs->int_parm_long & __FAIL_ADDR_MASK;
175 if (!user_space_fault(regs->int_parm_long)) 178 if (!user_space_fault(regs))
176 printk(KERN_ALERT "Unable to handle kernel pointer dereference" 179 printk(KERN_ALERT "Unable to handle kernel pointer dereference"
177 " at virtual kernel address %p\n", (void *)address); 180 " at virtual kernel address %p\n", (void *)address);
178 else 181 else
@@ -296,7 +299,7 @@ static inline int do_exception(struct pt_regs *regs, int access)
296 * user context. 299 * user context.
297 */ 300 */
298 fault = VM_FAULT_BADCONTEXT; 301 fault = VM_FAULT_BADCONTEXT;
299 if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm)) 302 if (unlikely(!user_space_fault(regs) || in_atomic() || !mm))
300 goto out; 303 goto out;
301 304
302 address = trans_exc_code & __FAIL_ADDR_MASK; 305 address = trans_exc_code & __FAIL_ADDR_MASK;
@@ -441,30 +444,6 @@ void __kprobes do_dat_exception(struct pt_regs *regs)
441 do_fault_error(regs, fault); 444 do_fault_error(regs, fault);
442} 445}
443 446
444int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
445{
446 struct pt_regs regs;
447 int access, fault;
448
449 /* Emulate a uaccess fault from kernel mode. */
450 regs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_DAT | PSW_MASK_MCHECK;
451 if (!irqs_disabled())
452 regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT;
453 regs.psw.addr = (unsigned long) __builtin_return_address(0);
454 regs.psw.addr |= PSW_ADDR_AMODE;
455 regs.int_code = pgm_int_code;
456 regs.int_parm_long = (uaddr & PAGE_MASK) | 2;
457 access = write ? VM_WRITE : VM_READ;
458 fault = do_exception(&regs, access);
459 /*
460 * Since the fault happened in kernel mode while performing a uaccess
461 * all we need to do now is emulating a fixup in case "fault" is not
462 * zero.
463 * For the calling uaccess functions this results always in -EFAULT.
464 */
465 return fault ? -EFAULT : 0;
466}
467
468#ifdef CONFIG_PFAULT 447#ifdef CONFIG_PFAULT
469/* 448/*
470 * 'pfault' pseudo page faults routines. 449 * 'pfault' pseudo page faults routines.
@@ -645,7 +624,7 @@ static int __init pfault_irq_init(void)
645{ 624{
646 int rc; 625 int rc;
647 626
648 rc = register_external_interrupt(0x2603, pfault_interrupt); 627 rc = register_external_irq(EXT_IRQ_CP_SERVICE, pfault_interrupt);
649 if (rc) 628 if (rc)
650 goto out_extint; 629 goto out_extint;
651 rc = pfault_init() == 0 ? 0 : -EOPNOTSUPP; 630 rc = pfault_init() == 0 ? 0 : -EOPNOTSUPP;
@@ -656,7 +635,7 @@ static int __init pfault_irq_init(void)
656 return 0; 635 return 0;
657 636
658out_pfault: 637out_pfault:
659 unregister_external_interrupt(0x2603, pfault_interrupt); 638 unregister_external_irq(EXT_IRQ_CP_SERVICE, pfault_interrupt);
660out_extint: 639out_extint:
661 pfault_disable = 1; 640 pfault_disable = 1;
662 return rc; 641 return rc;