Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vm_fault.c
Go to the documentation of this file.
1 /*
2  * Memory fault handling for Hexagon
3  *
4  * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 and
8  * only version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301, USA.
19  */
20 
21 /*
22  * Page fault handling for the Hexagon Virtual Machine.
23  * Can also be called by a native port emulating the HVM
24  * execptions.
25  */
26 
27 #include <asm/pgtable.h>
28 #include <asm/traps.h>
29 #include <asm/uaccess.h>
30 #include <linux/mm.h>
31 #include <linux/signal.h>
32 #include <linux/module.h>
33 #include <linux/hardirq.h>
34 
35 /*
36  * Decode of hardware exception sends us to one of several
37  * entry points. At each, we generate canonical arguments
38  * for handling by the abstract memory management code.
39  */
40 #define FLT_IFETCH -1
41 #define FLT_LOAD 0
42 #define FLT_STORE 1
43 
44 
45 /*
46  * Canonical page fault handler
47  */
48 void do_page_fault(unsigned long address, long cause, struct pt_regs *regs)
49 {
50  struct vm_area_struct *vma;
51  struct mm_struct *mm = current->mm;
53  int si_code = SEGV_MAPERR;
54  int fault;
55  const struct exception_table_entry *fixup;
56  unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
57  (cause > 0 ? FAULT_FLAG_WRITE : 0);
58 
59  /*
60  * If we're in an interrupt or have no user context,
61  * then must not take the fault.
62  */
63  if (unlikely(in_interrupt() || !mm))
64  goto no_context;
65 
67 
68 retry:
69  down_read(&mm->mmap_sem);
70  vma = find_vma(mm, address);
71  if (!vma)
72  goto bad_area;
73 
74  if (vma->vm_start <= address)
75  goto good_area;
76 
77  if (!(vma->vm_flags & VM_GROWSDOWN))
78  goto bad_area;
79 
80  if (expand_stack(vma, address))
81  goto bad_area;
82 
83 good_area:
84  /* Address space is OK. Now check access rights. */
85  si_code = SEGV_ACCERR;
86 
87  switch (cause) {
88  case FLT_IFETCH:
89  if (!(vma->vm_flags & VM_EXEC))
90  goto bad_area;
91  break;
92  case FLT_LOAD:
93  if (!(vma->vm_flags & VM_READ))
94  goto bad_area;
95  break;
96  case FLT_STORE:
97  if (!(vma->vm_flags & VM_WRITE))
98  goto bad_area;
99  break;
100  }
101 
102  fault = handle_mm_fault(mm, vma, address, flags);
103 
104  if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
105  return;
106 
107  /* The most common case -- we are done. */
108  if (likely(!(fault & VM_FAULT_ERROR))) {
109  if (flags & FAULT_FLAG_ALLOW_RETRY) {
110  if (fault & VM_FAULT_MAJOR)
111  current->maj_flt++;
112  else
113  current->min_flt++;
114  if (fault & VM_FAULT_RETRY) {
115  flags &= ~FAULT_FLAG_ALLOW_RETRY;
116  flags |= FAULT_FLAG_TRIED;
117  goto retry;
118  }
119  }
120 
121  up_read(&mm->mmap_sem);
122  return;
123  }
124 
125  up_read(&mm->mmap_sem);
126 
127  /* Handle copyin/out exception cases */
128  if (!user_mode(regs))
129  goto no_context;
130 
131  if (fault & VM_FAULT_OOM) {
133  return;
134  }
135 
136  /* User-mode address is in the memory map, but we are
137  * unable to fix up the page fault.
138  */
139  if (fault & VM_FAULT_SIGBUS) {
140  info.si_signo = SIGBUS;
141  info.si_code = BUS_ADRERR;
142  }
143  /* Address is not in the memory map */
144  else {
145  info.si_signo = SIGSEGV;
146  info.si_code = SEGV_ACCERR;
147  }
148  info.si_errno = 0;
149  info.si_addr = (void __user *)address;
150  force_sig_info(info.si_code, &info, current);
151  return;
152 
153 bad_area:
154  up_read(&mm->mmap_sem);
155 
156  if (user_mode(regs)) {
157  info.si_signo = SIGSEGV;
158  info.si_errno = 0;
159  info.si_code = si_code;
160  info.si_addr = (void *)address;
161  force_sig_info(SIGSEGV, &info, current);
162  return;
163  }
164  /* Kernel-mode fault falls through */
165 
166 no_context:
167  fixup = search_exception_tables(pt_elr(regs));
168  if (fixup) {
169  pt_set_elr(regs, fixup->fixup);
170  return;
171  }
172 
173  /* Things are looking very, very bad now */
174  bust_spinlocks(1);
175  printk(KERN_EMERG "Unable to handle kernel paging request at "
176  "virtual address 0x%08lx, regs %p\n", address, regs);
177  die("Bad Kernel VA", regs, SIGKILL);
178 }
179 
180 
182 {
183  unsigned long badvadr = pt_badva(regs);
184 
185  do_page_fault(badvadr, FLT_LOAD, regs);
186 }
187 
189 {
190  unsigned long badvadr = pt_badva(regs);
191 
192  do_page_fault(badvadr, FLT_STORE, regs);
193 }
194 
196 {
197  unsigned long badvadr = pt_badva(regs);
198 
199  do_page_fault(badvadr, FLT_IFETCH, regs);
200 }