Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/m68k/mm/fault.c
10817 views
1
/*
2
* linux/arch/m68k/mm/fault.c
3
*
4
* Copyright (C) 1995 Hamish Macdonald
5
*/
6
7
#include <linux/mman.h>
8
#include <linux/mm.h>
9
#include <linux/kernel.h>
10
#include <linux/ptrace.h>
11
#include <linux/interrupt.h>
12
#include <linux/module.h>
13
14
#include <asm/setup.h>
15
#include <asm/traps.h>
16
#include <asm/system.h>
17
#include <asm/uaccess.h>
18
#include <asm/pgalloc.h>
19
20
extern void die_if_kernel(char *, struct pt_regs *, long);
21
22
int send_fault_sig(struct pt_regs *regs)
23
{
24
siginfo_t siginfo = { 0, 0, 0, };
25
26
siginfo.si_signo = current->thread.signo;
27
siginfo.si_code = current->thread.code;
28
siginfo.si_addr = (void *)current->thread.faddr;
29
#ifdef DEBUG
30
printk("send_fault_sig: %p,%d,%d\n", siginfo.si_addr, siginfo.si_signo, siginfo.si_code);
31
#endif
32
33
if (user_mode(regs)) {
34
force_sig_info(siginfo.si_signo,
35
&siginfo, current);
36
} else {
37
if (handle_kernel_fault(regs))
38
return -1;
39
40
//if (siginfo.si_signo == SIGBUS)
41
// force_sig_info(siginfo.si_signo,
42
// &siginfo, current);
43
44
/*
45
* Oops. The kernel tried to access some bad page. We'll have to
46
* terminate things with extreme prejudice.
47
*/
48
if ((unsigned long)siginfo.si_addr < PAGE_SIZE)
49
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
50
else
51
printk(KERN_ALERT "Unable to handle kernel access");
52
printk(" at virtual address %p\n", siginfo.si_addr);
53
die_if_kernel("Oops", regs, 0 /*error_code*/);
54
do_exit(SIGKILL);
55
}
56
57
return 1;
58
}
59
60
/*
61
* This routine handles page faults. It determines the problem, and
62
* then passes it off to one of the appropriate routines.
63
*
64
* error_code:
65
* bit 0 == 0 means no page found, 1 means protection fault
66
* bit 1 == 0 means read, 1 means write
67
*
68
* If this routine detects a bad access, it returns 1, otherwise it
69
* returns 0.
70
*/
71
int do_page_fault(struct pt_regs *regs, unsigned long address,
72
unsigned long error_code)
73
{
74
struct mm_struct *mm = current->mm;
75
struct vm_area_struct * vma;
76
int write, fault;
77
78
#ifdef DEBUG
79
printk ("do page fault:\nregs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
80
regs->sr, regs->pc, address, error_code,
81
current->mm->pgd);
82
#endif
83
84
/*
85
* If we're in an interrupt or have no user
86
* context, we must not take the fault..
87
*/
88
if (in_atomic() || !mm)
89
goto no_context;
90
91
down_read(&mm->mmap_sem);
92
93
vma = find_vma(mm, address);
94
if (!vma)
95
goto map_err;
96
if (vma->vm_flags & VM_IO)
97
goto acc_err;
98
if (vma->vm_start <= address)
99
goto good_area;
100
if (!(vma->vm_flags & VM_GROWSDOWN))
101
goto map_err;
102
if (user_mode(regs)) {
103
/* Accessing the stack below usp is always a bug. The
104
"+ 256" is there due to some instructions doing
105
pre-decrement on the stack and that doesn't show up
106
until later. */
107
if (address + 256 < rdusp())
108
goto map_err;
109
}
110
if (expand_stack(vma, address))
111
goto map_err;
112
113
/*
114
* Ok, we have a good vm_area for this memory access, so
115
* we can handle it..
116
*/
117
good_area:
118
#ifdef DEBUG
119
printk("do_page_fault: good_area\n");
120
#endif
121
write = 0;
122
switch (error_code & 3) {
123
default: /* 3: write, present */
124
/* fall through */
125
case 2: /* write, not present */
126
if (!(vma->vm_flags & VM_WRITE))
127
goto acc_err;
128
write++;
129
break;
130
case 1: /* read, present */
131
goto acc_err;
132
case 0: /* read, not present */
133
if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
134
goto acc_err;
135
}
136
137
/*
138
* If for any reason at all we couldn't handle the fault,
139
* make sure we exit gracefully rather than endlessly redo
140
* the fault.
141
*/
142
143
fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);
144
#ifdef DEBUG
145
printk("handle_mm_fault returns %d\n",fault);
146
#endif
147
if (unlikely(fault & VM_FAULT_ERROR)) {
148
if (fault & VM_FAULT_OOM)
149
goto out_of_memory;
150
else if (fault & VM_FAULT_SIGBUS)
151
goto bus_err;
152
BUG();
153
}
154
if (fault & VM_FAULT_MAJOR)
155
current->maj_flt++;
156
else
157
current->min_flt++;
158
159
up_read(&mm->mmap_sem);
160
return 0;
161
162
/*
163
* We ran out of memory, or some other thing happened to us that made
164
* us unable to handle the page fault gracefully.
165
*/
166
out_of_memory:
167
up_read(&mm->mmap_sem);
168
if (!user_mode(regs))
169
goto no_context;
170
pagefault_out_of_memory();
171
return 0;
172
173
no_context:
174
current->thread.signo = SIGBUS;
175
current->thread.faddr = address;
176
return send_fault_sig(regs);
177
178
bus_err:
179
current->thread.signo = SIGBUS;
180
current->thread.code = BUS_ADRERR;
181
current->thread.faddr = address;
182
goto send_sig;
183
184
map_err:
185
current->thread.signo = SIGSEGV;
186
current->thread.code = SEGV_MAPERR;
187
current->thread.faddr = address;
188
goto send_sig;
189
190
acc_err:
191
current->thread.signo = SIGSEGV;
192
current->thread.code = SEGV_ACCERR;
193
current->thread.faddr = address;
194
195
send_sig:
196
up_read(&mm->mmap_sem);
197
return send_fault_sig(regs);
198
}
199
200