fault.c 16.5 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
7
8
9
10
/*
 *  linux/arch/arm/mm/fault.c
 *
 *  Copyright (C) 1995  Linus Torvalds
 *  Modifications for ARM processor (c) 1995-2004 Russell King
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
11
#include <linux/extable.h>
Linus Torvalds's avatar
Linus Torvalds committed
12
13
#include <linux/signal.h>
#include <linux/mm.h>
14
#include <linux/hardirq.h>
Linus Torvalds's avatar
Linus Torvalds committed
15
#include <linux/init.h>
16
#include <linux/kprobes.h>
17
#include <linux/uaccess.h>
18
#include <linux/page-flags.h>
19
#include <linux/sched/signal.h>
20
#include <linux/sched/debug.h>
Russell King's avatar
Russell King committed
21
#include <linux/highmem.h>
22
#include <linux/perf_event.h>
Linus Torvalds's avatar
Linus Torvalds committed
23
24

#include <asm/pgtable.h>
25
26
#include <asm/system_misc.h>
#include <asm/system_info.h>
Linus Torvalds's avatar
Linus Torvalds committed
27
28
29
30
#include <asm/tlbflush.h>

#include "fault.h"

31
#ifdef CONFIG_MMU
32

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#ifdef CONFIG_IPIPE

static inline unsigned long ipipe_fault_entry(void)
{
	unsigned long flags;
	int s;

	flags = hard_local_irq_save();
	s = __test_and_set_bit(IPIPE_STALL_FLAG, &__ipipe_root_status);
	hard_local_irq_enable();

	return arch_mangle_irq_bits(s, flags);
}

static inline void ipipe_fault_exit(unsigned long x)
{
	if (!arch_demangle_irq_bits(&x))
		local_irq_enable();
	else
		hard_local_irq_restore(x);
}

#else

static inline unsigned long ipipe_fault_entry(void)
{
	return 0;
}

static inline void ipipe_fault_exit(unsigned long x) { }

#endif

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#ifdef CONFIG_KPROBES
static inline int notify_page_fault(struct pt_regs *regs, unsigned int fsr)
{
	int ret = 0;

	if (!user_mode(regs)) {
		/* kprobe_running() needs smp_processor_id() */
		preempt_disable();
		if (kprobe_running() && kprobe_fault_handler(regs, fsr))
			ret = 1;
		preempt_enable();
	}

	return ret;
}
#else
static inline int notify_page_fault(struct pt_regs *regs, unsigned int fsr)
{
	return 0;
}
#endif

Linus Torvalds's avatar
Linus Torvalds committed
88
89
90
91
92
93
94
95
96
97
98
/*
 * This is useful to dump out the page tables associated with
 * 'addr' in mm 'mm'.
 */
void show_pte(struct mm_struct *mm, unsigned long addr)
{
	pgd_t *pgd;

	if (!mm)
		mm = &init_mm;

99
	pr_alert("pgd = %p\n", mm->pgd);
Linus Torvalds's avatar
Linus Torvalds committed
100
	pgd = pgd_offset(mm, addr);
101
	pr_alert("[%08lx] *pgd=%08llx",
102
			addr, (long long)pgd_val(*pgd));
Linus Torvalds's avatar
Linus Torvalds committed
103
104

	do {
105
		pud_t *pud;
Linus Torvalds's avatar
Linus Torvalds committed
106
107
108
109
110
111
112
		pmd_t *pmd;
		pte_t *pte;

		if (pgd_none(*pgd))
			break;

		if (pgd_bad(*pgd)) {
113
			pr_cont("(bad)");
Linus Torvalds's avatar
Linus Torvalds committed
114
115
116
			break;
		}

117
118
		pud = pud_offset(pgd, addr);
		if (PTRS_PER_PUD != 1)
119
			pr_cont(", *pud=%08llx", (long long)pud_val(*pud));
120
121
122
123
124

		if (pud_none(*pud))
			break;

		if (pud_bad(*pud)) {
125
			pr_cont("(bad)");
126
127
128
129
			break;
		}

		pmd = pmd_offset(pud, addr);
130
		if (PTRS_PER_PMD != 1)
131
			pr_cont(", *pmd=%08llx", (long long)pmd_val(*pmd));
Linus Torvalds's avatar
Linus Torvalds committed
132
133
134
135
136

		if (pmd_none(*pmd))
			break;

		if (pmd_bad(*pmd)) {
137
			pr_cont("(bad)");
Linus Torvalds's avatar
Linus Torvalds committed
138
139
140
141
			break;
		}

		/* We must not map this if we have highmem enabled */
142
143
144
		if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT)))
			break;

Linus Torvalds's avatar
Linus Torvalds committed
145
		pte = pte_offset_map(pmd, addr);
146
		pr_cont(", *pte=%08llx", (long long)pte_val(*pte));
147
#ifndef CONFIG_ARM_LPAE
148
		pr_cont(", *ppte=%08llx",
149
		       (long long)pte_val(pte[PTE_HWTABLE_PTRS]));
150
#endif
Linus Torvalds's avatar
Linus Torvalds committed
151
152
153
		pte_unmap(pte);
	} while(0);

154
	pr_cont("\n");
Linus Torvalds's avatar
Linus Torvalds committed
155
}
156
157
158
159
#else					/* CONFIG_MMU */
void show_pte(struct mm_struct *mm, unsigned long addr)
{ }
#endif					/* CONFIG_MMU */
Linus Torvalds's avatar
Linus Torvalds committed
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

/*
 * Oops.  The kernel tried to access some page that wasn't present.
 */
static void
__do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
		  struct pt_regs *regs)
{
	/*
	 * Are we prepared to handle this kernel fault?
	 */
	if (fixup_exception(regs))
		return;

	/*
	 * No handler, we'll have to terminate things with extreme prejudice.
	 */
	bust_spinlocks(1);
178
179
180
	pr_alert("Unable to handle kernel %s at virtual address %08lx\n",
		 (addr < PAGE_SIZE) ? "NULL pointer dereference" :
		 "paging request", addr);
Linus Torvalds's avatar
Linus Torvalds committed
181
182
183
184
185
186
187
188
189
190
191
192
193

	show_pte(mm, addr);
	die("Oops", regs, fsr);
	bust_spinlocks(0);
	do_exit(SIGKILL);
}

/*
 * Something tried to access memory that isn't in our memory map..
 * User mode accesses just cause a SIGSEGV
 */
static void
__do_user_fault(struct task_struct *tsk, unsigned long addr,
194
195
		unsigned int fsr, unsigned int sig, int code,
		struct pt_regs *regs)
Linus Torvalds's avatar
Linus Torvalds committed
196
197
198
{
	struct siginfo si;

199
200
201
	if (addr > TASK_SIZE)
		harden_branch_predictor();

202
203
	clear_siginfo(&si);

Linus Torvalds's avatar
Linus Torvalds committed
204
#ifdef CONFIG_DEBUG_USER
205
206
	if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
	    ((user_debug & UDBG_BUS)  && (sig == SIGBUS))) {
207
208
		printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n",
		       tsk->comm, sig, addr, fsr);
Linus Torvalds's avatar
Linus Torvalds committed
209
210
211
212
213
214
215
216
		show_pte(tsk->mm, addr);
		show_regs(regs);
	}
#endif

	tsk->thread.address = addr;
	tsk->thread.error_code = fsr;
	tsk->thread.trap_no = 14;
217
	si.si_signo = sig;
Linus Torvalds's avatar
Linus Torvalds committed
218
219
220
	si.si_errno = 0;
	si.si_code = code;
	si.si_addr = (void __user *)addr;
221
	force_sig_info(sig, &si, tsk);
Linus Torvalds's avatar
Linus Torvalds committed
222
223
}

224
void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
Linus Torvalds's avatar
Linus Torvalds committed
225
{
226
227
228
	struct task_struct *tsk = current;
	struct mm_struct *mm = tsk->active_mm;

Linus Torvalds's avatar
Linus Torvalds committed
229
230
231
232
233
	/*
	 * If we are in kernel mode at this point, we
	 * have no context to handle this fault with.
	 */
	if (user_mode(regs))
234
		__do_user_fault(tsk, addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
Linus Torvalds's avatar
Linus Torvalds committed
235
236
237
238
	else
		__do_kernel_fault(mm, addr, fsr, regs);
}

239
#ifdef CONFIG_MMU
240
241
#define VM_FAULT_BADMAP		0x010000
#define VM_FAULT_BADACCESS	0x020000
Linus Torvalds's avatar
Linus Torvalds committed
242

243
244
245
246
247
248
249
250
251
/*
 * Check that the permissions on the VMA allow for the fault which occurred.
 * If we encountered a write fault, we must have write permission, otherwise
 * we allow any permission.
 */
static inline bool access_error(unsigned int fsr, struct vm_area_struct *vma)
{
	unsigned int mask = VM_READ | VM_WRITE | VM_EXEC;

252
	if ((fsr & FSR_WRITE) && !(fsr & FSR_CM))
253
		mask = VM_WRITE;
254
255
	if (fsr & FSR_LNX_PF)
		mask = VM_EXEC;
256
257
258
259

	return vma->vm_flags & mask ? false : true;
}

260
static vm_fault_t __kprobes
Linus Torvalds's avatar
Linus Torvalds committed
261
__do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
262
		unsigned int flags, struct task_struct *tsk)
Linus Torvalds's avatar
Linus Torvalds committed
263
264
{
	struct vm_area_struct *vma;
265
	vm_fault_t fault;
Linus Torvalds's avatar
Linus Torvalds committed
266
267
268

	vma = find_vma(mm, addr);
	fault = VM_FAULT_BADMAP;
269
	if (unlikely(!vma))
Linus Torvalds's avatar
Linus Torvalds committed
270
		goto out;
271
	if (unlikely(vma->vm_start > addr))
Linus Torvalds's avatar
Linus Torvalds committed
272
273
274
275
276
277
278
		goto check_stack;

	/*
	 * Ok, we have a good vm_area for this
	 * memory access, so we can handle it.
	 */
good_area:
279
280
	if (access_error(fsr, vma)) {
		fault = VM_FAULT_BADACCESS;
Linus Torvalds's avatar
Linus Torvalds committed
281
		goto out;
282
	}
Linus Torvalds's avatar
Linus Torvalds committed
283

284
	return handle_mm_fault(vma, addr & PAGE_MASK, flags);
Linus Torvalds's avatar
Linus Torvalds committed
285
286

check_stack:
287
288
289
	/* Don't allow expansion below FIRST_USER_ADDRESS */
	if (vma->vm_flags & VM_GROWSDOWN &&
	    addr >= FIRST_USER_ADDRESS && !expand_stack(vma, addr))
Linus Torvalds's avatar
Linus Torvalds committed
290
291
292
293
294
		goto good_area;
out:
	return fault;
}

295
static int __kprobes
Linus Torvalds's avatar
Linus Torvalds committed
296
297
298
299
do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
	struct task_struct *tsk;
	struct mm_struct *mm;
300
301
	int sig, code;
	vm_fault_t fault;
302
	unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
303
	unsigned long irqflags;
Linus Torvalds's avatar
Linus Torvalds committed
304

305
	if (__ipipe_report_trap(IPIPE_TRAP_ACCESS, regs))
306
307
		return 0;

308
309
310
311
312
	irqflags = ipipe_fault_entry();

	if (notify_page_fault(regs, fsr))
		goto out;

Linus Torvalds's avatar
Linus Torvalds committed
313
314
315
	tsk = current;
	mm  = tsk->mm;

316
317
318
319
	/* Enable interrupts if they were enabled in the parent context. */
	if (interrupts_enabled(regs))
		local_irq_enable();

Linus Torvalds's avatar
Linus Torvalds committed
320
321
322
323
	/*
	 * If we're in an interrupt or have no user
	 * context, we must not take the fault..
	 */
324
	if (faulthandler_disabled() || !mm)
Linus Torvalds's avatar
Linus Torvalds committed
325
326
		goto no_context;

327
328
	if (user_mode(regs))
		flags |= FAULT_FLAG_USER;
329
	if ((fsr & FSR_WRITE) && !(fsr & FSR_CM))
330
331
		flags |= FAULT_FLAG_WRITE;

332
333
334
335
336
337
338
339
	/*
	 * As per x86, we may deadlock here.  However, since the kernel only
	 * validly references user space from well defined areas of the code,
	 * we can bug out early if this is from code which shouldn't.
	 */
	if (!down_read_trylock(&mm->mmap_sem)) {
		if (!user_mode(regs) && !search_exception_tables(regs->ARM_pc))
			goto no_context;
340
retry:
341
		down_read(&mm->mmap_sem);
342
343
344
345
346
347
348
	} else {
		/*
		 * The above down_read_trylock() might have succeeded in
		 * which case, we'll have missed the might_sleep() from
		 * down_read()
		 */
		might_sleep();
349
350
351
352
353
#ifdef CONFIG_DEBUG_VM
		if (!user_mode(regs) &&
		    !search_exception_tables(regs->ARM_pc))
			goto no_context;
#endif
354
355
	}

356
357
358
359
360
361
	fault = __do_page_fault(mm, addr, fsr, flags, tsk);

	/* If we need to retry but a fatal signal is pending, handle the
	 * signal first. We do not need to release the mmap_sem because
	 * it would already be released in __lock_page_or_retry in
	 * mm/filemap.c. */
362
363
364
	if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
		if (!user_mode(regs))
			goto no_context;
365
		goto out;
366
	}
367
368
369
370
371
372

	/*
	 * Major/minor page fault accounting is only done on the
	 * initial attempt. If we go through a retry, it is extremely
	 * likely that the page will be found in page cache at that point.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
373

374
	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr);
375
	if (!(fault & VM_FAULT_ERROR) && flags & FAULT_FLAG_ALLOW_RETRY) {
376
377
378
379
380
381
382
383
384
385
386
387
388
		if (fault & VM_FAULT_MAJOR) {
			tsk->maj_flt++;
			perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
					regs, addr);
		} else {
			tsk->min_flt++;
			perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
					regs, addr);
		}
		if (fault & VM_FAULT_RETRY) {
			/* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
			* of starvation. */
			flags &= ~FAULT_FLAG_ALLOW_RETRY;
389
			flags |= FAULT_FLAG_TRIED;
390
391
392
393
394
			goto retry;
		}
	}

	up_read(&mm->mmap_sem);
395

Linus Torvalds's avatar
Linus Torvalds committed
396
	/*
Jan Kara's avatar
Jan Kara committed
397
	 * Handle the "normal" case first - VM_FAULT_MAJOR
Linus Torvalds's avatar
Linus Torvalds committed
398
	 */
399
	if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS))))
400
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
401

402
403
404
405
406
407
408
	/*
	 * If we are in kernel mode at this point, we
	 * have no context to handle this fault with.
	 */
	if (!user_mode(regs))
		goto no_context;

409
410
411
412
413
414
415
	if (fault & VM_FAULT_OOM) {
		/*
		 * We ran out of memory, call the OOM killer, and return to
		 * userspace (which will retry the fault, or kill us if we
		 * got oom-killed)
		 */
		pagefault_out_of_memory();
416
		goto out;
417
418
	}

Nick Piggin's avatar
Nick Piggin committed
419
	if (fault & VM_FAULT_SIGBUS) {
420
421
422
423
424
425
		/*
		 * We had some memory, but were unable to
		 * successfully fix up this page fault.
		 */
		sig = SIGBUS;
		code = BUS_ADRERR;
Nick Piggin's avatar
Nick Piggin committed
426
	} else {
427
428
429
430
431
432
433
		/*
		 * Something tried to access memory that
		 * isn't in our memory map..
		 */
		sig = SIGSEGV;
		code = fault == VM_FAULT_BADACCESS ?
			SEGV_ACCERR : SEGV_MAPERR;
Linus Torvalds's avatar
Linus Torvalds committed
434
435
	}

436
	__do_user_fault(tsk, addr, fsr, sig, code, regs);
437
	goto out;
Linus Torvalds's avatar
Linus Torvalds committed
438
439
440

no_context:
	__do_kernel_fault(mm, addr, fsr, regs);
441
442
443
out:
	ipipe_fault_exit(irqflags);

Linus Torvalds's avatar
Linus Torvalds committed
444
445
	return 0;
}
446
447
448
449
450
451
452
#else					/* CONFIG_MMU */
static int
do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
	return 0;
}
#endif					/* CONFIG_MMU */
Linus Torvalds's avatar
Linus Torvalds committed
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470

/*
 * First Level Translation Fault Handler
 *
 * We enter here because the first level page table doesn't contain
 * a valid entry for the address.
 *
 * If the address is in kernel space (>= TASK_SIZE), then we are
 * probably faulting in the vmalloc() area.
 *
 * If the init_task's first level page tables contains the relevant
 * entry, we copy the it to this task.  If not, we send the process
 * a signal, fixup the exception, or oops the kernel.
 *
 * NOTE! We MUST NOT take any locks for this case. We may be in an
 * interrupt or a critical region, and should only copy the information
 * from the master page table, nothing more.
 */
471
#ifdef CONFIG_MMU
472
static int __kprobes
Linus Torvalds's avatar
Linus Torvalds committed
473
474
475
do_translation_fault(unsigned long addr, unsigned int fsr,
		     struct pt_regs *regs)
{
476
	unsigned long irqflags;
Linus Torvalds's avatar
Linus Torvalds committed
477
478
	unsigned int index;
	pgd_t *pgd, *pgd_k;
479
	pud_t *pud, *pud_k;
Linus Torvalds's avatar
Linus Torvalds committed
480
481
	pmd_t *pmd, *pmd_k;

482
483
	IPIPE_BUG_ON(!hard_irqs_disabled());

Linus Torvalds's avatar
Linus Torvalds committed
484
485
486
	if (addr < TASK_SIZE)
		return do_page_fault(addr, fsr, regs);

487
488
489
	if (user_mode(regs))
		goto bad_area;

Linus Torvalds's avatar
Linus Torvalds committed
490
491
492
493
494
495
496
497
498
499
	index = pgd_index(addr);

	pgd = cpu_get_pgd() + index;
	pgd_k = init_mm.pgd + index;

	if (pgd_none(*pgd_k))
		goto bad_area;
	if (!pgd_present(*pgd))
		set_pgd(pgd, *pgd_k);

500
501
502
503
504
505
506
507
508
509
	pud = pud_offset(pgd, addr);
	pud_k = pud_offset(pgd_k, addr);

	if (pud_none(*pud_k))
		goto bad_area;
	if (!pud_present(*pud))
		set_pud(pud, *pud_k);

	pmd = pmd_offset(pud, addr);
	pmd_k = pmd_offset(pud_k, addr);
Linus Torvalds's avatar
Linus Torvalds committed
510

511
512
513
514
515
516
#ifdef CONFIG_ARM_LPAE
	/*
	 * Only one hardware entry per PMD with LPAE.
	 */
	index = 0;
#else
517
518
519
520
521
522
523
524
525
	/*
	 * On ARM one Linux PGD entry contains two hardware entries (see page
	 * tables layout in pgtable.h). We normally guarantee that we always
	 * fill both L1 entries. But create_mapping() doesn't follow the rule.
	 * It can create inidividual L1 entries, so here we have to call
	 * pmd_none() check for the entry really corresponded to address, not
	 * for the first of pair.
	 */
	index = (addr >> SECTION_SHIFT) & 1;
526
#endif
527
	if (pmd_none(pmd_k[index]))
Linus Torvalds's avatar
Linus Torvalds committed
528
529
530
		goto bad_area;

	copy_pmd(pmd, pmd_k);
531

Linus Torvalds's avatar
Linus Torvalds committed
532
533
534
	return 0;

bad_area:
535
536
537
538
539
	if (__ipipe_report_trap(IPIPE_TRAP_ACCESS, regs))
		return 0;

	irqflags = ipipe_fault_entry();

540
	do_bad_area(addr, fsr, regs);
541
542
543

	ipipe_fault_exit(irqflags);

Linus Torvalds's avatar
Linus Torvalds committed
544
545
	return 0;
}
546
547
548
549
550
551
552
553
#else					/* CONFIG_MMU */
static int
do_translation_fault(unsigned long addr, unsigned int fsr,
		     struct pt_regs *regs)
{
	return 0;
}
#endif					/* CONFIG_MMU */
Linus Torvalds's avatar
Linus Torvalds committed
554
555
556
557
558

/*
 * Some section permission faults need to be handled gracefully.
 * They can happen due to a __{get,put}_user during an oops.
 */
559
#ifndef CONFIG_ARM_LPAE
Linus Torvalds's avatar
Linus Torvalds committed
560
561
562
static int
do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
563
564
565
566
567
568
569
	unsigned long irqflags;

	if (__ipipe_report_trap(IPIPE_TRAP_SECTION, regs))
		return 0;

	irqflags = ipipe_fault_entry();

570
	do_bad_area(addr, fsr, regs);
571
572
573

	ipipe_fault_exit(irqflags);

Linus Torvalds's avatar
Linus Torvalds committed
574
575
	return 0;
}
576
#endif /* CONFIG_ARM_LPAE */
Linus Torvalds's avatar
Linus Torvalds committed
577
578
579
580
581
582
583

/*
 * This abort handler always returns "fault".
 */
static int
do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
584
585
586
	if (__ipipe_report_trap(IPIPE_TRAP_DABT,regs))
		return 0;

Linus Torvalds's avatar
Linus Torvalds committed
587
588
589
	return 1;
}

590
struct fsr_info {
Linus Torvalds's avatar
Linus Torvalds committed
591
592
	int	(*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
	int	sig;
593
	int	code;
Linus Torvalds's avatar
Linus Torvalds committed
594
595
596
	const char *name;
};

597
/* FSR definition */
598
599
600
#ifdef CONFIG_ARM_LPAE
#include "fsr-3level.c"
#else
601
#include "fsr-2level.c"
602
#endif
603

Linus Torvalds's avatar
Linus Torvalds committed
604
605
void __init
hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
606
		int sig, int code, const char *name)
Linus Torvalds's avatar
Linus Torvalds committed
607
{
608
609
610
611
612
613
614
	if (nr < 0 || nr >= ARRAY_SIZE(fsr_info))
		BUG();

	fsr_info[nr].fn   = fn;
	fsr_info[nr].sig  = sig;
	fsr_info[nr].code = code;
	fsr_info[nr].name = name;
Linus Torvalds's avatar
Linus Torvalds committed
615
616
617
618
619
}

/*
 * Dispatch a data abort to the relevant handler.
 */
620
asmlinkage void
Linus Torvalds's avatar
Linus Torvalds committed
621
622
do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
623
	const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
624
	unsigned long irqflags;
625
	struct siginfo info;
Linus Torvalds's avatar
Linus Torvalds committed
626

627
	if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
Linus Torvalds's avatar
Linus Torvalds committed
628
629
		return;

630
631
632
633
634
	if (__ipipe_report_trap(IPIPE_TRAP_UNKNOWN, regs))
		return;

	irqflags = ipipe_fault_entry();

635
	pr_alert("Unhandled fault: %s (0x%03x) at 0x%08lx\n",
Linus Torvalds's avatar
Linus Torvalds committed
636
		inf->name, fsr, addr);
637
	show_pte(current->mm, addr);
638

639
	clear_siginfo(&info);
640
641
642
643
	info.si_signo = inf->sig;
	info.si_errno = 0;
	info.si_code  = inf->code;
	info.si_addr  = (void __user *)addr;
644
	arm_notify_die("", regs, &info, fsr, 0);
645
646

	ipipe_fault_exit(irqflags);
Linus Torvalds's avatar
Linus Torvalds committed
647
648
}

649
650
651
652
653
654
655
656
657
658
659
660
661
void __init
hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
		 int sig, int code, const char *name)
{
	if (nr < 0 || nr >= ARRAY_SIZE(ifsr_info))
		BUG();

	ifsr_info[nr].fn   = fn;
	ifsr_info[nr].sig  = sig;
	ifsr_info[nr].code = code;
	ifsr_info[nr].name = name;
}

662
asmlinkage void
663
do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
Linus Torvalds's avatar
Linus Torvalds committed
664
{
665
	const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr);
666
	unsigned long irqflags;
667
668
669
670
671
	struct siginfo info;

	if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
		return;

672
673
674
675
676
	if (__ipipe_report_trap(IPIPE_TRAP_UNKNOWN, regs))
		return;

	irqflags = ipipe_fault_entry();

677
	pr_alert("Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n",
678
679
		inf->name, ifsr, addr);

680
	clear_siginfo(&info);
681
682
683
684
685
	info.si_signo = inf->sig;
	info.si_errno = 0;
	info.si_code  = inf->code;
	info.si_addr  = (void __user *)addr;
	arm_notify_die("", regs, &info, ifsr, 0);
686
687

	ipipe_fault_exit(irqflags);
Linus Torvalds's avatar
Linus Torvalds committed
688
689
}

690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
/*
 * Abort handler to be used only during first unmasking of asynchronous aborts
 * on the boot CPU. This makes sure that the machine will not die if the
 * firmware/bootloader left an imprecise abort pending for us to trip over.
 */
static int __init early_abort_handler(unsigned long addr, unsigned int fsr,
				      struct pt_regs *regs)
{
	pr_warn("Hit pending asynchronous external abort (FSR=0x%08x) during "
		"first unmask, this is most likely caused by a "
		"firmware/bootloader bug.\n", fsr);

	return 0;
}

void __init early_abt_enable(void)
{
707
	fsr_info[FSR_FS_AEA].fn = early_abort_handler;
708
	local_abt_enable();
709
	fsr_info[FSR_FS_AEA].fn = do_bad;
710
711
}

712
#ifndef CONFIG_ARM_LPAE
713
714
715
716
717
718
719
static int __init exceptions_init(void)
{
	if (cpu_architecture() >= CPU_ARCH_ARMv6) {
		hook_fault_code(4, do_translation_fault, SIGSEGV, SEGV_MAPERR,
				"I-cache maintenance fault");
	}

720
721
722
723
724
725
726
727
728
729
730
	if (cpu_architecture() >= CPU_ARCH_ARMv7) {
		/*
		 * TODO: Access flag faults introduced in ARMv6K.
		 * Runtime check for 'K' extension is needed
		 */
		hook_fault_code(3, do_bad, SIGSEGV, SEGV_MAPERR,
				"section access flag fault");
		hook_fault_code(6, do_bad, SIGSEGV, SEGV_MAPERR,
				"section access flag fault");
	}

731
732
733
734
	return 0;
}

arch_initcall(exceptions_init);
735
#endif