OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [m68k/] [mm/] [fault.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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
 
13
#include <asm/setup.h>
14
#include <asm/traps.h>
15
#include <asm/system.h>
16
#include <asm/uaccess.h>
17
#include <asm/pgalloc.h>
18
 
19
extern void die_if_kernel(char *, struct pt_regs *, long);
20
extern const int frame_extra_sizes[]; /* in m68k/kernel/signal.c */
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
                unsigned long fixup;
38
 
39
                /* Are we prepared to handle this kernel fault? */
40
                if ((fixup = search_exception_table(regs->pc))) {
41
                        struct pt_regs *tregs;
42
                        /* Create a new four word stack frame, discarding the old
43
                           one.  */
44
                        regs->stkadj = frame_extra_sizes[regs->format];
45
                        tregs = (struct pt_regs *)((ulong)regs + regs->stkadj);
46
                        tregs->vector = regs->vector;
47
                        tregs->format = 0;
48
                        tregs->pc = fixup;
49
                        tregs->sr = regs->sr;
50
                        return -1;
51
                }
52
 
53
                //if (siginfo.si_signo == SIGBUS)
54
                //      force_sig_info(siginfo.si_signo,
55
                //                     &siginfo, current);
56
 
57
                /*
58
                 * Oops. The kernel tried to access some bad page. We'll have to
59
                 * terminate things with extreme prejudice.
60
                 */
61
                if ((unsigned long)siginfo.si_addr < PAGE_SIZE)
62
                        printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
63
                else
64
                        printk(KERN_ALERT "Unable to handle kernel access");
65
                printk(" at virtual address %p\n", siginfo.si_addr);
66
                die_if_kernel("Oops", regs, 0 /*error_code*/);
67
                do_exit(SIGKILL);
68
        }
69
 
70
        return 1;
71
}
72
 
73
/*
74
 * This routine handles page faults.  It determines the problem, and
75
 * then passes it off to one of the appropriate routines.
76
 *
77
 * error_code:
78
 *      bit 0 == 0 means no page found, 1 means protection fault
79
 *      bit 1 == 0 means read, 1 means write
80
 *
81
 * If this routine detects a bad access, it returns 1, otherwise it
82
 * returns 0.
83
 */
84
int do_page_fault(struct pt_regs *regs, unsigned long address,
85
                              unsigned long error_code)
86
{
87
        struct mm_struct *mm = current->mm;
88
        struct vm_area_struct * vma;
89
        int write, fault;
90
 
91
#ifdef DEBUG
92
        printk ("do page fault:\nregs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
93
                regs->sr, regs->pc, address, error_code,
94
                current->mm->pgd);
95
#endif
96
 
97
        /*
98
         * If we're in an interrupt or have no user
99
         * context, we must not take the fault..
100
         */
101
        if (in_interrupt() || !mm)
102
                goto no_context;
103
 
104
        down_read(&mm->mmap_sem);
105
 
106
        vma = find_vma(mm, address);
107
        if (!vma)
108
                goto map_err;
109
        if (vma->vm_flags & VM_IO)
110
                goto acc_err;
111
        if (vma->vm_start <= address)
112
                goto good_area;
113
        if (!(vma->vm_flags & VM_GROWSDOWN))
114
                goto map_err;
115
        if (user_mode(regs)) {
116
                /* Accessing the stack below usp is always a bug.  The
117
                   "+ 256" is there due to some instructions doing
118
                   pre-decrement on the stack and that doesn't show up
119
                   until later.  */
120
                if (address + 256 < rdusp())
121
                        goto map_err;
122
        }
123
        if (expand_stack(vma, address))
124
                goto map_err;
125
 
126
/*
127
 * Ok, we have a good vm_area for this memory access, so
128
 * we can handle it..
129
 */
130
good_area:
131
#ifdef DEBUG
132
        printk("do_page_fault: good_area\n");
133
#endif
134
        write = 0;
135
        switch (error_code & 3) {
136
                default:        /* 3: write, present */
137
                        /* fall through */
138
                case 2:         /* write, not present */
139
                        if (!(vma->vm_flags & VM_WRITE))
140
                                goto acc_err;
141
                        write++;
142
                        break;
143
                case 1:         /* read, present */
144
                        goto acc_err;
145
                case 0:          /* read, not present */
146
                        if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
147
                                goto acc_err;
148
        }
149
 
150
        /*
151
         * If for any reason at all we couldn't handle the fault,
152
         * make sure we exit gracefully rather than endlessly redo
153
         * the fault.
154
         */
155
 
156
 survive:
157
        fault = handle_mm_fault(mm, vma, address, write);
158
#ifdef DEBUG
159
        printk("handle_mm_fault returns %d\n",fault);
160
#endif
161
        switch (fault) {
162
        case 1:
163
                current->min_flt++;
164
                break;
165
        case 2:
166
                current->maj_flt++;
167
                break;
168
        case 0:
169
                goto bus_err;
170
        default:
171
                goto out_of_memory;
172
        }
173
 
174
        up_read(&mm->mmap_sem);
175
        return 0;
176
 
177
/*
178
 * We ran out of memory, or some other thing happened to us that made
179
 * us unable to handle the page fault gracefully.
180
 */
181
out_of_memory:
182
        if (current->pid == 1) {
183
                yield();
184
                goto survive;
185
        }
186
 
187
        up_read(&mm->mmap_sem);
188
        printk("VM: killing process %s\n", current->comm);
189
        if (user_mode(regs))
190
                do_exit(SIGKILL);
191
 
192
no_context:
193
        current->thread.signo = SIGBUS;
194
        current->thread.faddr = address;
195
        return send_fault_sig(regs);
196
 
197
bus_err:
198
        current->thread.signo = SIGBUS;
199
        current->thread.code = BUS_ADRERR;
200
        current->thread.faddr = address;
201
        goto send_sig;
202
 
203
map_err:
204
        current->thread.signo = SIGSEGV;
205
        current->thread.code = SEGV_MAPERR;
206
        current->thread.faddr = address;
207
        goto send_sig;
208
 
209
acc_err:
210
        current->thread.signo = SIGSEGV;
211
        current->thread.code = SEGV_ACCERR;
212
        current->thread.faddr = address;
213
 
214
send_sig:
215
        up_read(&mm->mmap_sem);
216
        return send_fault_sig(regs);
217
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.