Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
fault.c
Go to the documentation of this file.
1 /*
2  * linux/arch/cris/mm/fault.c
3  *
4  * Low level bus fault handler
5  *
6  *
7  * Copyright (C) 2000-2007 Axis Communications AB
8  *
9  * Authors: Bjorn Wesen
10  *
11  */
12 
13 #include <linux/mm.h>
14 #include <asm/uaccess.h>
15 #include <asm/pgtable.h>
16 #include <arch/svinto.h>
17 #include <asm/mmu_context.h>
18 
19 /* debug of low-level TLB reload */
20 #undef DEBUG
21 
22 #ifdef DEBUG
23 #define D(x) x
24 #else
25 #define D(x)
26 #endif
27 
28 extern const struct exception_table_entry
29  *search_exception_tables(unsigned long addr);
30 
31 asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs,
32  int protection, int writeaccess);
33 
34 /* fast TLB-fill fault handler
35  * this is called from entry.S with interrupts disabled
36  */
37 
38 void
40 {
41  int cause;
42  int select;
43 #ifdef DEBUG
44  int index;
45  int page_id;
46  int acc, inv;
47 #endif
49  pmd_t *pmd;
50  pte_t pte;
51  int miss, we, writeac;
52  unsigned long address;
53  unsigned long flags;
54 
55  cause = *R_MMU_CAUSE;
56 
57  address = cause & PAGE_MASK; /* get faulting address */
58  select = *R_TLB_SELECT;
59 
60 #ifdef DEBUG
61  page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause);
62  acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause);
63  inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause);
64  index = IO_EXTRACT(R_TLB_SELECT, index, select);
65 #endif
66  miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause);
67  we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause);
68  writeac = IO_EXTRACT(R_MMU_CAUSE, wr_rd, cause);
69 
70  D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n",
71  regs->irp, address, miss, inv, we, acc, index, page_id));
72 
73  /* leave it to the MM system fault handler */
74  if (miss)
75  do_page_fault(address, regs, 0, writeac);
76  else
77  do_page_fault(address, regs, 1, we);
78 
79  /* Reload TLB with new entry to avoid an extra miss exception.
80  * do_page_fault may have flushed the TLB so we have to restore
81  * the MMU registers.
82  */
83  local_irq_save(flags);
84  pmd = (pmd_t *)(pgd + pgd_index(address));
85  if (pmd_none(*pmd))
86  goto exit;
87  pte = *pte_offset_kernel(pmd, address);
88  if (!pte_present(pte))
89  goto exit;
90  *R_TLB_SELECT = select;
91  *R_TLB_HI = cause;
92  *R_TLB_LO = pte_val(pte);
93 exit:
94  local_irq_restore(flags);
95 }