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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [ppc/] [mm/] [fault.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1624 jcastillo
/*
2
 *  ARCH/ppc/mm/fault.c
3
 *
4
 *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
5
 *  Ported to PPC by Gary Thomas
6
 */
7
 
8
#include <linux/signal.h>
9
#include <linux/sched.h>
10
#include <linux/head.h>
11
#include <linux/kernel.h>
12
#include <linux/errno.h>
13
#include <linux/string.h>
14
#include <linux/types.h>
15
#include <linux/ptrace.h>
16
#include <linux/mman.h>
17
#include <linux/mm.h>
18
 
19
#include <asm/page.h>
20
#include <asm/pgtable.h>
21
 
22
extern void die_if_kernel(char *, struct pt_regs *, long);
23
extern void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
24
 
25
#undef SHOW_FAULTS
26
#undef NOISY_INSTRFAULT
27
#undef NOISY_DATAFAULT
28
 
29
#define NEWMM 1
30
 
31
void
32
DataAccessException(struct pt_regs *regs)
33
{
34
  pgd_t *dir;
35
  pmd_t *pmd;
36
  pte_t *pte;
37
  int tries, mode = 0;
38
 
39
#ifdef NOISY_DATAFAULT
40
  printk("Data fault on %x\n",regs->dar);
41
#endif
42
 
43
  if (user_mode(regs)) mode |= 0x04;
44
  if (regs->dsisr & 0x02000000) mode |= 0x02;  /* Load/store */
45
  if (regs->dsisr & 0x08000000) mode |= 0x01;  /* Protection violation */
46
  if (mode & 0x01)
47
  {
48
#ifdef NOISY_DATAFAULT
49
    printk("Write Protect fault\n ");
50
#endif
51
    do_page_fault(regs, regs->dar, mode);
52
#ifdef NOISY_DATAFAULT    
53
    printk("Write Protect fault handled\n");
54
#endif
55
    return;
56
  }
57
 
58
 
59
  for (tries = 0;  tries < 1;  tries++)
60
  {
61
    dir = pgd_offset(current->mm, regs->dar & PAGE_MASK);
62
    if (dir)
63
    {
64
      pmd = pmd_offset(dir, regs->dar & PAGE_MASK);
65
      if (pmd && pmd_present(*pmd))
66
      {
67
        pte = pte_offset(pmd, regs->dar & PAGE_MASK);
68
        if (pte && pte_present(*pte))
69
        {
70
#if NOISY_DATAFAULT
71
          printk("Page mapped - PTE: %x[%x]\n", pte, *(long *)pte);
72
#endif
73
          MMU_hash_page(&current->tss, regs->dar & PAGE_MASK, pte);
74
          /*MMU_hash_page2(current->mm, regs->dar & PAGE_MASK, pte);*/
75
          return;
76
        }
77
      }
78
    } else
79
    {
80
#if NOISY_DATAFAULT
81
      printk("No PGD\n");
82
#endif 
83
    }
84
    do_page_fault(regs, regs->dar, mode);
85
  }
86
}
87
 
88
void
89
InstructionAccessException(struct pt_regs *regs)
90
{
91
  pgd_t *dir;
92
  pmd_t *pmd;
93
  pte_t *pte;
94
  int tries, mode = 0;
95
 
96
#if NOISY_INSTRFAULT
97
  printk("Instr fault on %x\n",regs->dar);
98
#endif
99
 
100
#ifdef NEWMM
101
  if (!user_mode(regs))
102
  {
103
 
104
    panic("InstructionAcessException in kernel mode. PC %x addr %x",
105
          regs->nip, regs->dar);
106
  }
107
#endif
108
  if (user_mode(regs)) mode |= 0x04;
109
  if (regs->dsisr & 0x02000000) mode |= 0x02;  /* Load/store */
110
  if (regs->dsisr & 0x08000000) mode |= 0x01;  /* Protection violation */
111
 
112
  if (mode & 0x01)
113
  {
114
    do_page_fault(regs, regs->dar, mode);
115
    return;
116
  }
117
  for (tries = 0;  tries < 1;  tries++)
118
  {
119
    dir = pgd_offset(current->mm, regs->dar & PAGE_MASK);
120
    if (dir)
121
    {
122
      pmd = pmd_offset(dir, regs->dar & PAGE_MASK);
123
      if (pmd && pmd_present(*pmd))
124
      {
125
        pte = pte_offset(pmd, regs->dar & PAGE_MASK);
126
        if (pte && pte_present(*pte))
127
          {
128
 
129
            MMU_hash_page(&current->tss, regs->dar & PAGE_MASK, pte);
130
            /*    MMU_hash_page2(current->mm, regs->dar & PAGE_MASK, pte);*/
131
            return;
132
          }
133
      }
134
    } else
135
      {
136
      }
137
    do_page_fault(regs, regs->dar, mode);
138
  }
139
}
140
 
141
 
142
/*
143
 * This routine handles page faults.  It determines the address,
144
 * and the problem, and then passes it off to one of the appropriate
145
 * routines.
146
 *
147
 * The error_code parameter just the same as in the i386 version:
148
 *
149
 *      bit 0 == 0 means no page found, 1 means protection fault
150
 *      bit 1 == 0 means read, 1 means write
151
 *      bit 2 == 0 means kernel, 1 means user-mode
152
 */
153
void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code)
154
{
155
  struct vm_area_struct * vma;
156
  unsigned long page;
157
 
158
  vma = find_vma(current, address);
159
  if (!vma)
160
  {
161
    goto bad_area;
162
  }
163
 
164
  if (vma->vm_start <= address){
165
    goto good_area;
166
  }
167
  if (!(vma->vm_flags & VM_GROWSDOWN))
168
  {
169
    goto bad_area;
170
  }
171
  if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
172
  {
173
    goto bad_area;
174
  }
175
  vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
176
 
177
  vma->vm_start = (address & PAGE_MASK);
178
 
179
good_area:
180
  /* a write */
181
  if (error_code & 2) {
182
    if (!(vma->vm_flags & VM_WRITE))
183
    {
184
      goto bad_area;
185
    }
186
  /* a read */
187
  } else {
188
    /* protection fault */
189
    if (error_code & 1)
190
    {
191
      goto bad_area;
192
    }
193
    if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
194
    {
195
      goto bad_area;
196
    }
197
  }
198
  handle_mm_fault(vma, address, error_code & 2);
199
  flush_page(address);  /* Flush & Invalidate cache - note: address is OK now */
200
  return;
201
 
202
bad_area:
203
  if (user_mode(regs))
204
  {
205
/*    printk("Bad User Area: Addr %x PC %x Task %x pid %d %s\n",
206
           address,regs->nip, current,current->pid,current->comm);*/
207
    send_sig(SIGSEGV, current, 1);
208
    return;
209
  }
210
  panic("KERNEL access of bad area PC %x address %x vm_flags %x\n",
211
        regs->nip,address,vma->vm_flags);
212
}
213
 
214
 
215
va_to_phys(unsigned long address)
216
{
217
        pgd_t *dir;
218
        pmd_t *pmd;
219
        pte_t *pte;
220
        dir = pgd_offset(current->mm, address & PAGE_MASK);
221
        if (dir)
222
        {
223
                pmd = pmd_offset(dir, address & PAGE_MASK);
224
                if (pmd && pmd_present(*pmd))
225
                {
226
                        pte = pte_offset(pmd, address & PAGE_MASK);
227
                        if (pte && pte_present(*pte))
228
                        {
229
                                return(pte_page(*pte) | (address & ~(PAGE_MASK-1)));
230
                        }
231
                } else
232
                {
233
                        return (0);
234
                }
235
        } else
236
        {
237
                return (0);
238
        }
239
        return (0);
240
}
241
 
242
 
243
/*
244
 * See if an address should be valid in the current context.
245
 */
246
valid_addr(unsigned long addr)
247
{
248
        struct vm_area_struct * vma;
249
        for (vma = current->mm->mmap ; ; vma = vma->vm_next)
250
        {
251
                if (!vma)
252
                {
253
                        return (0);
254
                }
255
                if (vma->vm_end > addr)
256
                        break;
257
        }
258
        if (vma->vm_start <= addr)
259
        {
260
                return (1);
261
        }
262
        return (0);
263
}

powered by: WebSVN 2.1.0

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