xref: /openbmc/linux/arch/s390/mm/fault.c (revision 61365e13)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  arch/s390/mm/fault.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  S390 version
51da177e4SLinus Torvalds  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
61da177e4SLinus Torvalds  *    Author(s): Hartmut Penner (hp@de.ibm.com)
71da177e4SLinus Torvalds  *               Ulrich Weigand (uweigand@de.ibm.com)
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *  Derived from "arch/i386/mm/fault.c"
101da177e4SLinus Torvalds  *    Copyright (C) 1995  Linus Torvalds
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds 
13cdd6c482SIngo Molnar #include <linux/perf_event.h>
141da177e4SLinus Torvalds #include <linux/signal.h>
151da177e4SLinus Torvalds #include <linux/sched.h>
161da177e4SLinus Torvalds #include <linux/kernel.h>
171da177e4SLinus Torvalds #include <linux/errno.h>
181da177e4SLinus Torvalds #include <linux/string.h>
191da177e4SLinus Torvalds #include <linux/types.h>
201da177e4SLinus Torvalds #include <linux/ptrace.h>
211da177e4SLinus Torvalds #include <linux/mman.h>
221da177e4SLinus Torvalds #include <linux/mm.h>
237757591aSHeiko Carstens #include <linux/compat.h>
241da177e4SLinus Torvalds #include <linux/smp.h>
251eeb66a1SChristoph Hellwig #include <linux/kdebug.h>
261da177e4SLinus Torvalds #include <linux/init.h>
271da177e4SLinus Torvalds #include <linux/console.h>
281da177e4SLinus Torvalds #include <linux/module.h>
291da177e4SLinus Torvalds #include <linux/hardirq.h>
304ba069b8SMichael Grundy #include <linux/kprobes.h>
31be5ec363SMartin Schwidefsky #include <linux/uaccess.h>
3253492b1dSGerald Schaefer #include <linux/hugetlb.h>
331da177e4SLinus Torvalds #include <asm/system.h>
341da177e4SLinus Torvalds #include <asm/pgtable.h>
3529b08d2bSHeiko Carstens #include <asm/s390_ext.h>
366252d702SMartin Schwidefsky #include <asm/mmu_context.h>
37a806170eSHeiko Carstens #include "../kernel/entry.h"
381da177e4SLinus Torvalds 
39347a8dc3SMartin Schwidefsky #ifndef CONFIG_64BIT
401da177e4SLinus Torvalds #define __FAIL_ADDR_MASK 0x7ffff000
411da177e4SLinus Torvalds #define __FIXUP_MASK 0x7fffffff
421da177e4SLinus Torvalds #define __SUBCODE_MASK 0x0200
431da177e4SLinus Torvalds #define __PF_RES_FIELD 0ULL
44347a8dc3SMartin Schwidefsky #else /* CONFIG_64BIT */
451da177e4SLinus Torvalds #define __FAIL_ADDR_MASK -4096L
461da177e4SLinus Torvalds #define __FIXUP_MASK ~0L
471da177e4SLinus Torvalds #define __SUBCODE_MASK 0x0600
481da177e4SLinus Torvalds #define __PF_RES_FIELD 0x8000000000000000ULL
49347a8dc3SMartin Schwidefsky #endif /* CONFIG_64BIT */
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL
521da177e4SLinus Torvalds extern int sysctl_userprocess_debug;
531da177e4SLinus Torvalds #endif
541da177e4SLinus Torvalds 
554ba069b8SMichael Grundy #ifdef CONFIG_KPROBES
5610c1031fSMartin Schwidefsky static inline int notify_page_fault(struct pt_regs *regs, long err)
5710c1031fSMartin Schwidefsky {
5833464e3bSChristoph Hellwig 	int ret = 0;
5933464e3bSChristoph Hellwig 
6033464e3bSChristoph Hellwig 	/* kprobe_running() needs smp_processor_id() */
6133464e3bSChristoph Hellwig 	if (!user_mode(regs)) {
6233464e3bSChristoph Hellwig 		preempt_disable();
6333464e3bSChristoph Hellwig 		if (kprobe_running() && kprobe_fault_handler(regs, 14))
6433464e3bSChristoph Hellwig 			ret = 1;
6533464e3bSChristoph Hellwig 		preempt_enable();
6633464e3bSChristoph Hellwig 	}
6733464e3bSChristoph Hellwig 
6833464e3bSChristoph Hellwig 	return ret;
694ba069b8SMichael Grundy }
704ba069b8SMichael Grundy #else
7110c1031fSMartin Schwidefsky static inline int notify_page_fault(struct pt_regs *regs, long err)
724ba069b8SMichael Grundy {
7333464e3bSChristoph Hellwig 	return 0;
744ba069b8SMichael Grundy }
754ba069b8SMichael Grundy #endif
764ba069b8SMichael Grundy 
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds /*
791da177e4SLinus Torvalds  * Unlock any spinlocks which will prevent us from getting the
80cefc8be8SKirill Korotaev  * message out.
811da177e4SLinus Torvalds  */
821da177e4SLinus Torvalds void bust_spinlocks(int yes)
831da177e4SLinus Torvalds {
841da177e4SLinus Torvalds 	if (yes) {
851da177e4SLinus Torvalds 		oops_in_progress = 1;
861da177e4SLinus Torvalds 	} else {
871da177e4SLinus Torvalds 		int loglevel_save = console_loglevel;
881da177e4SLinus Torvalds 		console_unblank();
891da177e4SLinus Torvalds 		oops_in_progress = 0;
901da177e4SLinus Torvalds 		/*
911da177e4SLinus Torvalds 		 * OK, the message is on the console.  Now we call printk()
921da177e4SLinus Torvalds 		 * without oops_in_progress set so that printk will give klogd
931da177e4SLinus Torvalds 		 * a poke.  Hold onto your hats...
941da177e4SLinus Torvalds 		 */
951da177e4SLinus Torvalds 		console_loglevel = 15;
961da177e4SLinus Torvalds 		printk(" ");
971da177e4SLinus Torvalds 		console_loglevel = loglevel_save;
981da177e4SLinus Torvalds 	}
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds /*
102482b05ddSGerald Schaefer  * Returns the address space associated with the fault.
10361365e13SMartin Schwidefsky  * Returns 0 for kernel space and 1 for user space.
1041da177e4SLinus Torvalds  */
10561365e13SMartin Schwidefsky static inline int user_space_fault(unsigned long trans_exc_code)
1061da177e4SLinus Torvalds {
1071da177e4SLinus Torvalds 	/*
10861365e13SMartin Schwidefsky 	 * The lowest two bits of the translation exception
10961365e13SMartin Schwidefsky 	 * identification indicate which paging table was used.
1101da177e4SLinus Torvalds 	 */
11161365e13SMartin Schwidefsky 	trans_exc_code &= 3;
11261365e13SMartin Schwidefsky 	if (trans_exc_code == 2)
11361365e13SMartin Schwidefsky 		/* Access via secondary space, set_fs setting decides */
11461365e13SMartin Schwidefsky 		return current->thread.mm_segment.ar4;
11561365e13SMartin Schwidefsky 	if (!switch_amode)
11661365e13SMartin Schwidefsky 		/* User space if the access has been done via home space. */
11761365e13SMartin Schwidefsky 		return trans_exc_code == 3;
118482b05ddSGerald Schaefer 	/*
11961365e13SMartin Schwidefsky 	 * If the user space is not the home space the kernel runs in home
12061365e13SMartin Schwidefsky 	 * space. Access via secondary space has already been covered,
12161365e13SMartin Schwidefsky 	 * access via primary space or access register is from user space
12261365e13SMartin Schwidefsky 	 * and access via home space is from the kernel.
123482b05ddSGerald Schaefer 	 */
12461365e13SMartin Schwidefsky 	return trans_exc_code != 3;
1251da177e4SLinus Torvalds }
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds /*
1281da177e4SLinus Torvalds  * Send SIGSEGV to task.  This is an external routine
1291da177e4SLinus Torvalds  * to keep the stack usage of do_page_fault small.
1301da177e4SLinus Torvalds  */
1311da177e4SLinus Torvalds static void do_sigsegv(struct pt_regs *regs, unsigned long error_code,
1321da177e4SLinus Torvalds 		       int si_code, unsigned long address)
1331da177e4SLinus Torvalds {
1341da177e4SLinus Torvalds 	struct siginfo si;
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds #if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG)
1371da177e4SLinus Torvalds #if defined(CONFIG_SYSCTL)
1381da177e4SLinus Torvalds 	if (sysctl_userprocess_debug)
1391da177e4SLinus Torvalds #endif
1401da177e4SLinus Torvalds 	{
1411da177e4SLinus Torvalds 		printk("User process fault: interruption code 0x%lX\n",
1421da177e4SLinus Torvalds 		       error_code);
1431da177e4SLinus Torvalds 		printk("failing address: %lX\n", address);
1441da177e4SLinus Torvalds 		show_regs(regs);
1451da177e4SLinus Torvalds 	}
1461da177e4SLinus Torvalds #endif
1471da177e4SLinus Torvalds 	si.si_signo = SIGSEGV;
1481da177e4SLinus Torvalds 	si.si_code = si_code;
149d2c993d8SHeiko Carstens 	si.si_addr = (void __user *) address;
1501da177e4SLinus Torvalds 	force_sig_info(SIGSEGV, &si, current);
1511da177e4SLinus Torvalds }
1521da177e4SLinus Torvalds 
15310c1031fSMartin Schwidefsky static void do_no_context(struct pt_regs *regs, unsigned long error_code,
15461365e13SMartin Schwidefsky 			  unsigned long trans_exc_code)
15510c1031fSMartin Schwidefsky {
15610c1031fSMartin Schwidefsky 	const struct exception_table_entry *fixup;
15761365e13SMartin Schwidefsky 	unsigned long address;
15810c1031fSMartin Schwidefsky 
15910c1031fSMartin Schwidefsky 	/* Are we prepared to handle this kernel fault?  */
16010c1031fSMartin Schwidefsky 	fixup = search_exception_tables(regs->psw.addr & __FIXUP_MASK);
16110c1031fSMartin Schwidefsky 	if (fixup) {
16210c1031fSMartin Schwidefsky 		regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
16310c1031fSMartin Schwidefsky 		return;
16410c1031fSMartin Schwidefsky 	}
16510c1031fSMartin Schwidefsky 
16610c1031fSMartin Schwidefsky 	/*
16710c1031fSMartin Schwidefsky 	 * Oops. The kernel tried to access some bad page. We'll have to
16810c1031fSMartin Schwidefsky 	 * terminate things with extreme prejudice.
16910c1031fSMartin Schwidefsky 	 */
17061365e13SMartin Schwidefsky 	address = trans_exc_code & __FAIL_ADDR_MASK;
17161365e13SMartin Schwidefsky 	if (user_space_fault(trans_exc_code) == 0)
17210c1031fSMartin Schwidefsky 		printk(KERN_ALERT "Unable to handle kernel pointer dereference"
17310c1031fSMartin Schwidefsky 		       " at virtual kernel address %p\n", (void *)address);
17410c1031fSMartin Schwidefsky 	else
17510c1031fSMartin Schwidefsky 		printk(KERN_ALERT "Unable to handle kernel paging request"
17610c1031fSMartin Schwidefsky 		       " at virtual user address %p\n", (void *)address);
17710c1031fSMartin Schwidefsky 
17810c1031fSMartin Schwidefsky 	die("Oops", regs, error_code);
17910c1031fSMartin Schwidefsky 	do_exit(SIGKILL);
18010c1031fSMartin Schwidefsky }
18110c1031fSMartin Schwidefsky 
18261365e13SMartin Schwidefsky static void do_low_address(struct pt_regs *regs, unsigned long error_code,
18361365e13SMartin Schwidefsky 			   unsigned long trans_exc_code)
18410c1031fSMartin Schwidefsky {
18510c1031fSMartin Schwidefsky 	/* Low-address protection hit in kernel mode means
18610c1031fSMartin Schwidefsky 	   NULL pointer write access in kernel mode.  */
18710c1031fSMartin Schwidefsky 	if (regs->psw.mask & PSW_MASK_PSTATE) {
18810c1031fSMartin Schwidefsky 		/* Low-address protection hit in user mode 'cannot happen'. */
18910c1031fSMartin Schwidefsky 		die ("Low-address protection", regs, error_code);
19010c1031fSMartin Schwidefsky 		do_exit(SIGKILL);
19110c1031fSMartin Schwidefsky 	}
19210c1031fSMartin Schwidefsky 
19361365e13SMartin Schwidefsky 	do_no_context(regs, error_code, trans_exc_code);
19410c1031fSMartin Schwidefsky }
19510c1031fSMartin Schwidefsky 
19610c1031fSMartin Schwidefsky static void do_sigbus(struct pt_regs *regs, unsigned long error_code,
19761365e13SMartin Schwidefsky 		      unsigned long trans_exc_code)
19810c1031fSMartin Schwidefsky {
19910c1031fSMartin Schwidefsky 	struct task_struct *tsk = current;
20010c1031fSMartin Schwidefsky 	struct mm_struct *mm = tsk->mm;
20110c1031fSMartin Schwidefsky 
20210c1031fSMartin Schwidefsky 	up_read(&mm->mmap_sem);
20310c1031fSMartin Schwidefsky 	/*
20410c1031fSMartin Schwidefsky 	 * Send a sigbus, regardless of whether we were in kernel
20510c1031fSMartin Schwidefsky 	 * or user mode.
20610c1031fSMartin Schwidefsky 	 */
20761365e13SMartin Schwidefsky 	tsk->thread.prot_addr = trans_exc_code & __FAIL_ADDR_MASK;
20810c1031fSMartin Schwidefsky 	tsk->thread.trap_no = error_code;
20910c1031fSMartin Schwidefsky 	force_sig(SIGBUS, tsk);
21010c1031fSMartin Schwidefsky 
21110c1031fSMartin Schwidefsky 	/* Kernel mode? Handle exceptions or die */
21210c1031fSMartin Schwidefsky 	if (!(regs->psw.mask & PSW_MASK_PSTATE))
21361365e13SMartin Schwidefsky 		do_no_context(regs, error_code, trans_exc_code);
21410c1031fSMartin Schwidefsky }
21510c1031fSMartin Schwidefsky 
216c1821c2eSGerald Schaefer #ifdef CONFIG_S390_EXEC_PROTECT
217c1821c2eSGerald Schaefer static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
218c1821c2eSGerald Schaefer 			 unsigned long address, unsigned long error_code)
219c1821c2eSGerald Schaefer {
220be5ec363SMartin Schwidefsky 	u16 instruction;
221490f03d6SHeiko Carstens 	int rc;
222490f03d6SHeiko Carstens #ifdef CONFIG_COMPAT
223490f03d6SHeiko Carstens 	int compat;
224490f03d6SHeiko Carstens #endif
225c1821c2eSGerald Schaefer 
226be5ec363SMartin Schwidefsky 	pagefault_disable();
227be5ec363SMartin Schwidefsky 	rc = __get_user(instruction, (u16 __user *) regs->psw.addr);
228be5ec363SMartin Schwidefsky 	pagefault_enable();
229be5ec363SMartin Schwidefsky 	if (rc)
230be5ec363SMartin Schwidefsky 		return -EFAULT;
231c1821c2eSGerald Schaefer 
232c1821c2eSGerald Schaefer 	up_read(&mm->mmap_sem);
233be5ec363SMartin Schwidefsky 	clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
234be5ec363SMartin Schwidefsky #ifdef CONFIG_COMPAT
2357757591aSHeiko Carstens 	compat = is_compat_task();
236be5ec363SMartin Schwidefsky 	if (compat && instruction == 0x0a77)
237c2e8b853SHeiko Carstens 		sys32_sigreturn();
238be5ec363SMartin Schwidefsky 	else if (compat && instruction == 0x0aad)
239c2e8b853SHeiko Carstens 		sys32_rt_sigreturn();
240be5ec363SMartin Schwidefsky 	else
241be5ec363SMartin Schwidefsky #endif
242be5ec363SMartin Schwidefsky 	if (instruction == 0x0a77)
243c2e8b853SHeiko Carstens 		sys_sigreturn();
244be5ec363SMartin Schwidefsky 	else if (instruction == 0x0aad)
245c2e8b853SHeiko Carstens 		sys_rt_sigreturn();
246be5ec363SMartin Schwidefsky 	else {
247c1821c2eSGerald Schaefer 		current->thread.prot_addr = address;
248c1821c2eSGerald Schaefer 		current->thread.trap_no = error_code;
249c1821c2eSGerald Schaefer 		do_sigsegv(regs, error_code, SEGV_MAPERR, address);
250c1821c2eSGerald Schaefer 	}
251c1821c2eSGerald Schaefer 	return 0;
252c1821c2eSGerald Schaefer }
253c1821c2eSGerald Schaefer #endif /* CONFIG_S390_EXEC_PROTECT */
254c1821c2eSGerald Schaefer 
2551da177e4SLinus Torvalds /*
2561da177e4SLinus Torvalds  * This routine handles page faults.  It determines the address,
2571da177e4SLinus Torvalds  * and the problem, and then passes it off to one of the appropriate
2581da177e4SLinus Torvalds  * routines.
2591da177e4SLinus Torvalds  *
2601da177e4SLinus Torvalds  * error_code:
2611da177e4SLinus Torvalds  *   04       Protection           ->  Write-Protection  (suprression)
2621da177e4SLinus Torvalds  *   10       Segment translation  ->  Not present       (nullification)
2631da177e4SLinus Torvalds  *   11       Page translation     ->  Not present       (nullification)
2641da177e4SLinus Torvalds  *   3b       Region third trans.  ->  Not present       (nullification)
2651da177e4SLinus Torvalds  */
266482b05ddSGerald Schaefer static inline void
26761365e13SMartin Schwidefsky do_exception(struct pt_regs *regs, unsigned long error_code, int write,
26861365e13SMartin Schwidefsky 	     unsigned long trans_exc_code)
2691da177e4SLinus Torvalds {
2701da177e4SLinus Torvalds 	struct task_struct *tsk;
2711da177e4SLinus Torvalds 	struct mm_struct *mm;
2721da177e4SLinus Torvalds 	struct vm_area_struct *vma;
2731da177e4SLinus Torvalds 	unsigned long address;
27410c1031fSMartin Schwidefsky 	int si_code;
27583c54070SNick Piggin 	int fault;
27610c1031fSMartin Schwidefsky 
27733464e3bSChristoph Hellwig 	if (notify_page_fault(regs, error_code))
27810c1031fSMartin Schwidefsky 		return;
2791da177e4SLinus Torvalds 
2801da177e4SLinus Torvalds 	tsk = current;
2811da177e4SLinus Torvalds 	mm = tsk->mm;
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 	/*
2841da177e4SLinus Torvalds 	 * Verify that the fault happened in user space, that
2851da177e4SLinus Torvalds 	 * we are not in an interrupt and that there is a
2861da177e4SLinus Torvalds 	 * user context.
2871da177e4SLinus Torvalds 	 */
28861365e13SMartin Schwidefsky 	if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
2891da177e4SLinus Torvalds 		goto no_context;
2901da177e4SLinus Torvalds 
29161365e13SMartin Schwidefsky 	address = trans_exc_code & __FAIL_ADDR_MASK;
2921da177e4SLinus Torvalds 	/*
2931da177e4SLinus Torvalds 	 * When we get here, the fault happened in the current
2941da177e4SLinus Torvalds 	 * task's user address space, so we can switch on the
2951da177e4SLinus Torvalds 	 * interrupts again and then search the VMAs
2961da177e4SLinus Torvalds 	 */
2971da177e4SLinus Torvalds 	local_irq_enable();
298cdd6c482SIngo Molnar 	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
2991da177e4SLinus Torvalds 	down_read(&mm->mmap_sem);
3001da177e4SLinus Torvalds 
301482b05ddSGerald Schaefer 	si_code = SEGV_MAPERR;
3021da177e4SLinus Torvalds 	vma = find_vma(mm, address);
3031da177e4SLinus Torvalds 	if (!vma)
3041da177e4SLinus Torvalds 		goto bad_area;
305c1821c2eSGerald Schaefer 
306c1821c2eSGerald Schaefer #ifdef CONFIG_S390_EXEC_PROTECT
30761365e13SMartin Schwidefsky 	if (unlikely((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
30861365e13SMartin Schwidefsky 		     (trans_exc_code & 3) == 0 && !(vma->vm_flags & VM_EXEC)))
309c1821c2eSGerald Schaefer 		if (!signal_return(mm, regs, address, error_code))
310c1821c2eSGerald Schaefer 			/*
311c1821c2eSGerald Schaefer 			 * signal_return() has done an up_read(&mm->mmap_sem)
312c1821c2eSGerald Schaefer 			 * if it returns 0.
313c1821c2eSGerald Schaefer 			 */
314c1821c2eSGerald Schaefer 			return;
315c1821c2eSGerald Schaefer #endif
316c1821c2eSGerald Schaefer 
3171da177e4SLinus Torvalds 	if (vma->vm_start <= address)
3181da177e4SLinus Torvalds 		goto good_area;
3191da177e4SLinus Torvalds 	if (!(vma->vm_flags & VM_GROWSDOWN))
3201da177e4SLinus Torvalds 		goto bad_area;
3211da177e4SLinus Torvalds 	if (expand_stack(vma, address))
3221da177e4SLinus Torvalds 		goto bad_area;
3231da177e4SLinus Torvalds /*
3241da177e4SLinus Torvalds  * Ok, we have a good vm_area for this memory access, so
3251da177e4SLinus Torvalds  * we can handle it..
3261da177e4SLinus Torvalds  */
3271da177e4SLinus Torvalds good_area:
3281da177e4SLinus Torvalds 	si_code = SEGV_ACCERR;
32910c1031fSMartin Schwidefsky 	if (!write) {
3301da177e4SLinus Torvalds 		/* page not present, check vm flags */
3311da177e4SLinus Torvalds 		if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
3321da177e4SLinus Torvalds 			goto bad_area;
3331da177e4SLinus Torvalds 	} else {
3341da177e4SLinus Torvalds 		if (!(vma->vm_flags & VM_WRITE))
3351da177e4SLinus Torvalds 			goto bad_area;
3361da177e4SLinus Torvalds 	}
3371da177e4SLinus Torvalds 
33853492b1dSGerald Schaefer 	if (is_vm_hugetlb_page(vma))
33953492b1dSGerald Schaefer 		address &= HPAGE_MASK;
3401da177e4SLinus Torvalds 	/*
3411da177e4SLinus Torvalds 	 * If for any reason at all we couldn't handle the fault,
3421da177e4SLinus Torvalds 	 * make sure we exit gracefully rather than endlessly redo
3431da177e4SLinus Torvalds 	 * the fault.
3441da177e4SLinus Torvalds 	 */
345d06063ccSLinus Torvalds 	fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);
34683c54070SNick Piggin 	if (unlikely(fault & VM_FAULT_ERROR)) {
34783c54070SNick Piggin 		if (fault & VM_FAULT_OOM) {
34859fa4392SHeiko Carstens 			up_read(&mm->mmap_sem);
34959fa4392SHeiko Carstens 			pagefault_out_of_memory();
35010c1031fSMartin Schwidefsky 			return;
35183c54070SNick Piggin 		} else if (fault & VM_FAULT_SIGBUS) {
35283c54070SNick Piggin 			do_sigbus(regs, error_code, address);
35383c54070SNick Piggin 			return;
35483c54070SNick Piggin 		}
3551da177e4SLinus Torvalds 		BUG();
3561da177e4SLinus Torvalds 	}
357bde69af2SHeiko Carstens 	if (fault & VM_FAULT_MAJOR) {
35883c54070SNick Piggin 		tsk->maj_flt++;
359cdd6c482SIngo Molnar 		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
360bde69af2SHeiko Carstens 				     regs, address);
361bde69af2SHeiko Carstens 	} else {
36283c54070SNick Piggin 		tsk->min_flt++;
363cdd6c482SIngo Molnar 		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
364bde69af2SHeiko Carstens 				     regs, address);
365bde69af2SHeiko Carstens 	}
3661da177e4SLinus Torvalds         up_read(&mm->mmap_sem);
3671da177e4SLinus Torvalds 	/*
3681da177e4SLinus Torvalds 	 * The instruction that caused the program check will
3691da177e4SLinus Torvalds 	 * be repeated. Don't signal single step via SIGTRAP.
3701da177e4SLinus Torvalds 	 */
371482b05ddSGerald Schaefer 	clear_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
3721da177e4SLinus Torvalds         return;
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds /*
3751da177e4SLinus Torvalds  * Something tried to access memory that isn't in our memory map..
3761da177e4SLinus Torvalds  * Fix it, but check if it's kernel or user first..
3771da177e4SLinus Torvalds  */
3781da177e4SLinus Torvalds bad_area:
3791da177e4SLinus Torvalds 	up_read(&mm->mmap_sem);
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds 	/* User mode accesses just cause a SIGSEGV */
3821da177e4SLinus Torvalds 	if (regs->psw.mask & PSW_MASK_PSTATE) {
3831da177e4SLinus Torvalds 		tsk->thread.prot_addr = address;
3841da177e4SLinus Torvalds 		tsk->thread.trap_no = error_code;
3851da177e4SLinus Torvalds 		do_sigsegv(regs, error_code, si_code, address);
3861da177e4SLinus Torvalds 		return;
3871da177e4SLinus Torvalds 	}
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds no_context:
39061365e13SMartin Schwidefsky 	do_no_context(regs, error_code, trans_exc_code);
3911da177e4SLinus Torvalds }
3921da177e4SLinus Torvalds 
393482b05ddSGerald Schaefer void __kprobes do_protection_exception(struct pt_regs *regs,
394a806170eSHeiko Carstens 				       long error_code)
3951da177e4SLinus Torvalds {
39661365e13SMartin Schwidefsky 	unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
39761365e13SMartin Schwidefsky 
39810c1031fSMartin Schwidefsky 	/* Protection exception is supressing, decrement psw address. */
3991da177e4SLinus Torvalds 	regs->psw.addr -= (error_code >> 16);
40010c1031fSMartin Schwidefsky 	/*
40110c1031fSMartin Schwidefsky 	 * Check for low-address protection.  This needs to be treated
40210c1031fSMartin Schwidefsky 	 * as a special case because the translation exception code
40310c1031fSMartin Schwidefsky 	 * field is not guaranteed to contain valid data in this case.
40410c1031fSMartin Schwidefsky 	 */
40561365e13SMartin Schwidefsky 	if (unlikely(!(trans_exc_code & 4))) {
40661365e13SMartin Schwidefsky 		do_low_address(regs, error_code, trans_exc_code);
40710c1031fSMartin Schwidefsky 		return;
40810c1031fSMartin Schwidefsky 	}
40961365e13SMartin Schwidefsky 	do_exception(regs, 4, 1, trans_exc_code);
4101da177e4SLinus Torvalds }
4111da177e4SLinus Torvalds 
412a806170eSHeiko Carstens void __kprobes do_dat_exception(struct pt_regs *regs, long error_code)
4131da177e4SLinus Torvalds {
41461365e13SMartin Schwidefsky 	do_exception(regs, error_code & 0xff, 0, S390_lowcore.trans_exc_code);
4151da177e4SLinus Torvalds }
4161da177e4SLinus Torvalds 
4176252d702SMartin Schwidefsky #ifdef CONFIG_64BIT
4186252d702SMartin Schwidefsky void __kprobes do_asce_exception(struct pt_regs *regs, unsigned long error_code)
4196252d702SMartin Schwidefsky {
42061365e13SMartin Schwidefsky 	unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
4216252d702SMartin Schwidefsky 	struct mm_struct *mm;
4226252d702SMartin Schwidefsky 	struct vm_area_struct *vma;
4236252d702SMartin Schwidefsky 	unsigned long address;
4246252d702SMartin Schwidefsky 
4256252d702SMartin Schwidefsky 	mm = current->mm;
42661365e13SMartin Schwidefsky 	address = trans_exc_code & __FAIL_ADDR_MASK;
4276252d702SMartin Schwidefsky 
42861365e13SMartin Schwidefsky 	if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
4296252d702SMartin Schwidefsky 		goto no_context;
4306252d702SMartin Schwidefsky 
4316252d702SMartin Schwidefsky 	local_irq_enable();
4326252d702SMartin Schwidefsky 
4336252d702SMartin Schwidefsky 	down_read(&mm->mmap_sem);
4346252d702SMartin Schwidefsky 	vma = find_vma(mm, address);
4356252d702SMartin Schwidefsky 	up_read(&mm->mmap_sem);
4366252d702SMartin Schwidefsky 
4376252d702SMartin Schwidefsky 	if (vma) {
4386252d702SMartin Schwidefsky 		update_mm(mm, current);
4396252d702SMartin Schwidefsky 		return;
4406252d702SMartin Schwidefsky 	}
4416252d702SMartin Schwidefsky 
4426252d702SMartin Schwidefsky 	/* User mode accesses just cause a SIGSEGV */
4436252d702SMartin Schwidefsky 	if (regs->psw.mask & PSW_MASK_PSTATE) {
4446252d702SMartin Schwidefsky 		current->thread.prot_addr = address;
4456252d702SMartin Schwidefsky 		current->thread.trap_no = error_code;
4466252d702SMartin Schwidefsky 		do_sigsegv(regs, error_code, SEGV_MAPERR, address);
4476252d702SMartin Schwidefsky 		return;
4486252d702SMartin Schwidefsky 	}
4496252d702SMartin Schwidefsky 
4506252d702SMartin Schwidefsky no_context:
45161365e13SMartin Schwidefsky 	do_no_context(regs, error_code, trans_exc_code);
4526252d702SMartin Schwidefsky }
4536252d702SMartin Schwidefsky #endif
4546252d702SMartin Schwidefsky 
4551da177e4SLinus Torvalds #ifdef CONFIG_PFAULT
4561da177e4SLinus Torvalds /*
4571da177e4SLinus Torvalds  * 'pfault' pseudo page faults routines.
4581da177e4SLinus Torvalds  */
45929b08d2bSHeiko Carstens static ext_int_info_t ext_int_pfault;
4601da177e4SLinus Torvalds static int pfault_disable = 0;
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds static int __init nopfault(char *str)
4631da177e4SLinus Torvalds {
4641da177e4SLinus Torvalds 	pfault_disable = 1;
4651da177e4SLinus Torvalds 	return 1;
4661da177e4SLinus Torvalds }
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds __setup("nopfault", nopfault);
4691da177e4SLinus Torvalds 
4701da177e4SLinus Torvalds typedef struct {
4711da177e4SLinus Torvalds 	__u16 refdiagc;
4721da177e4SLinus Torvalds 	__u16 reffcode;
4731da177e4SLinus Torvalds 	__u16 refdwlen;
4741da177e4SLinus Torvalds 	__u16 refversn;
4751da177e4SLinus Torvalds 	__u64 refgaddr;
4761da177e4SLinus Torvalds 	__u64 refselmk;
4771da177e4SLinus Torvalds 	__u64 refcmpmk;
4781da177e4SLinus Torvalds 	__u64 reserved;
479c41fbc69SHeiko Carstens } __attribute__ ((packed, aligned(8))) pfault_refbk_t;
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds int pfault_init(void)
4821da177e4SLinus Torvalds {
4831da177e4SLinus Torvalds 	pfault_refbk_t refbk =
4841da177e4SLinus Torvalds 		{ 0x258, 0, 5, 2, __LC_CURRENT, 1ULL << 48, 1ULL << 48,
4851da177e4SLinus Torvalds 		  __PF_RES_FIELD };
4861da177e4SLinus Torvalds         int rc;
4871da177e4SLinus Torvalds 
48829b08d2bSHeiko Carstens 	if (!MACHINE_IS_VM || pfault_disable)
4891da177e4SLinus Torvalds 		return -1;
49094c12cc7SMartin Schwidefsky 	asm volatile(
4911da177e4SLinus Torvalds 		"	diag	%1,%0,0x258\n"
4921da177e4SLinus Torvalds 		"0:	j	2f\n"
4931da177e4SLinus Torvalds 		"1:	la	%0,8\n"
4941da177e4SLinus Torvalds 		"2:\n"
49594c12cc7SMartin Schwidefsky 		EX_TABLE(0b,1b)
496d4b68996SMartin Schwidefsky 		: "=d" (rc) : "a" (&refbk), "m" (refbk) : "cc");
4971da177e4SLinus Torvalds         __ctl_set_bit(0, 9);
4981da177e4SLinus Torvalds         return rc;
4991da177e4SLinus Torvalds }
5001da177e4SLinus Torvalds 
5011da177e4SLinus Torvalds void pfault_fini(void)
5021da177e4SLinus Torvalds {
5031da177e4SLinus Torvalds 	pfault_refbk_t refbk =
5041da177e4SLinus Torvalds 	{ 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL };
5051da177e4SLinus Torvalds 
50629b08d2bSHeiko Carstens 	if (!MACHINE_IS_VM || pfault_disable)
5071da177e4SLinus Torvalds 		return;
5081da177e4SLinus Torvalds 	__ctl_clear_bit(0,9);
50994c12cc7SMartin Schwidefsky 	asm volatile(
5101da177e4SLinus Torvalds 		"	diag	%0,0,0x258\n"
5111da177e4SLinus Torvalds 		"0:\n"
51294c12cc7SMartin Schwidefsky 		EX_TABLE(0b,0b)
513d4b68996SMartin Schwidefsky 		: : "a" (&refbk), "m" (refbk) : "cc");
5141da177e4SLinus Torvalds }
5151da177e4SLinus Torvalds 
5162b67fc46SHeiko Carstens static void pfault_interrupt(__u16 error_code)
5171da177e4SLinus Torvalds {
5181da177e4SLinus Torvalds 	struct task_struct *tsk;
5191da177e4SLinus Torvalds 	__u16 subcode;
5201da177e4SLinus Torvalds 
5211da177e4SLinus Torvalds 	/*
5221da177e4SLinus Torvalds 	 * Get the external interruption subcode & pfault
5231da177e4SLinus Torvalds 	 * initial/completion signal bit. VM stores this
5241da177e4SLinus Torvalds 	 * in the 'cpu address' field associated with the
5251da177e4SLinus Torvalds          * external interrupt.
5261da177e4SLinus Torvalds 	 */
5271da177e4SLinus Torvalds 	subcode = S390_lowcore.cpu_addr;
5281da177e4SLinus Torvalds 	if ((subcode & 0xff00) != __SUBCODE_MASK)
5291da177e4SLinus Torvalds 		return;
5301da177e4SLinus Torvalds 
5311da177e4SLinus Torvalds 	/*
5321da177e4SLinus Torvalds 	 * Get the token (= address of the task structure of the affected task).
5331da177e4SLinus Torvalds 	 */
5341da177e4SLinus Torvalds 	tsk = *(struct task_struct **) __LC_PFAULT_INTPARM;
5351da177e4SLinus Torvalds 
5361da177e4SLinus Torvalds 	if (subcode & 0x0080) {
5371da177e4SLinus Torvalds 		/* signal bit is set -> a page has been swapped in by VM */
5381da177e4SLinus Torvalds 		if (xchg(&tsk->thread.pfault_wait, -1) != 0) {
5391da177e4SLinus Torvalds 			/* Initial interrupt was faster than the completion
5401da177e4SLinus Torvalds 			 * interrupt. pfault_wait is valid. Set pfault_wait
5411da177e4SLinus Torvalds 			 * back to zero and wake up the process. This can
5421da177e4SLinus Torvalds 			 * safely be done because the task is still sleeping
543b6d09449SMartin Schwidefsky 			 * and can't produce new pfaults. */
5441da177e4SLinus Torvalds 			tsk->thread.pfault_wait = 0;
5451da177e4SLinus Torvalds 			wake_up_process(tsk);
546b6d09449SMartin Schwidefsky 			put_task_struct(tsk);
5471da177e4SLinus Torvalds 		}
5481da177e4SLinus Torvalds 	} else {
5491da177e4SLinus Torvalds 		/* signal bit not set -> a real page is missing. */
550b6d09449SMartin Schwidefsky 		get_task_struct(tsk);
5511da177e4SLinus Torvalds 		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
5521da177e4SLinus Torvalds 		if (xchg(&tsk->thread.pfault_wait, 1) != 0) {
5531da177e4SLinus Torvalds 			/* Completion interrupt was faster than the initial
5541da177e4SLinus Torvalds 			 * interrupt (swapped in a -1 for pfault_wait). Set
5551da177e4SLinus Torvalds 			 * pfault_wait back to zero and exit. This can be
5561da177e4SLinus Torvalds 			 * done safely because tsk is running in kernel
5571da177e4SLinus Torvalds 			 * mode and can't produce new pfaults. */
5581da177e4SLinus Torvalds 			tsk->thread.pfault_wait = 0;
5591da177e4SLinus Torvalds 			set_task_state(tsk, TASK_RUNNING);
560b6d09449SMartin Schwidefsky 			put_task_struct(tsk);
5611da177e4SLinus Torvalds 		} else
5621da177e4SLinus Torvalds 			set_tsk_need_resched(tsk);
5631da177e4SLinus Torvalds 	}
5641da177e4SLinus Torvalds }
5651da177e4SLinus Torvalds 
56629b08d2bSHeiko Carstens void __init pfault_irq_init(void)
56729b08d2bSHeiko Carstens {
56829b08d2bSHeiko Carstens 	if (!MACHINE_IS_VM)
56929b08d2bSHeiko Carstens 		return;
57029b08d2bSHeiko Carstens 
57129b08d2bSHeiko Carstens 	/*
57229b08d2bSHeiko Carstens 	 * Try to get pfault pseudo page faults going.
57329b08d2bSHeiko Carstens 	 */
57429b08d2bSHeiko Carstens 	if (register_early_external_interrupt(0x2603, pfault_interrupt,
57529b08d2bSHeiko Carstens 					      &ext_int_pfault) != 0)
57629b08d2bSHeiko Carstens 		panic("Couldn't request external interrupt 0x2603");
57729b08d2bSHeiko Carstens 
57829b08d2bSHeiko Carstens 	if (pfault_init() == 0)
57929b08d2bSHeiko Carstens 		return;
58029b08d2bSHeiko Carstens 
58129b08d2bSHeiko Carstens 	/* Tough luck, no pfault. */
58229b08d2bSHeiko Carstens 	pfault_disable = 1;
58329b08d2bSHeiko Carstens 	unregister_early_external_interrupt(0x2603, pfault_interrupt,
58429b08d2bSHeiko Carstens 					    &ext_int_pfault);
58529b08d2bSHeiko Carstens }
58629b08d2bSHeiko Carstens #endif
587