root/arch/sparc/mm/fault.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. prom_probe_memory
  2. probe_memory
  3. sparc_lvl15_nmi
  4. do_sparc_fault
  5. force_user_fault
  6. window_overflow_fault
  7. window_underflow_fault
  8. window_ret_fault

   1 /* $Id: fault.c,v 1.61 1996/04/12 06:52:35 davem Exp $
   2  * fault.c:  Page fault handlers for the Sparc.
   3  *
   4  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
   5  */
   6 
   7 #include <asm/head.h>
   8 
   9 #include <linux/string.h>
  10 #include <linux/types.h>
  11 #include <linux/ptrace.h>
  12 #include <linux/mman.h>
  13 #include <linux/tasks.h>
  14 #include <linux/smp.h>
  15 #include <linux/signal.h>
  16 #include <linux/mm.h>
  17 
  18 #include <asm/system.h>
  19 #include <asm/segment.h>
  20 #include <asm/openprom.h>
  21 #include <asm/idprom.h>
  22 #include <asm/page.h>
  23 #include <asm/pgtable.h>
  24 #include <asm/memreg.h>
  25 #include <asm/openprom.h>
  26 #include <asm/oplib.h>
  27 #include <asm/smp.h>
  28 #include <asm/traps.h>
  29 #include <asm/kdebug.h>
  30 
  31 #define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))
  32 
  33 extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
  34 extern int prom_node_root;
  35 
  36 extern void die_if_kernel(char *,struct pt_regs *);
  37 
  38 struct linux_romvec *romvec;
  39 
  40 /* At boot time we determine these two values necessary for setting
  41  * up the segment maps and page table entries (pte's).
  42  */
  43 
  44 int num_segmaps, num_contexts;
  45 int invalid_segment;
  46 
  47 /* various Virtual Address Cache parameters we find at boot time... */
  48 
  49 int vac_size, vac_linesize, vac_do_hw_vac_flushes;
  50 int vac_entries_per_context, vac_entries_per_segment;
  51 int vac_entries_per_page;
  52 
  53 /* Nice, simple, prom library does all the sweating for us. ;) */
  54 int prom_probe_memory (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56         register struct linux_mlist_v0 *mlist;
  57         register unsigned long bytes, base_paddr, tally;
  58         register int i;
  59 
  60         i = 0;
  61         mlist= *prom_meminfo()->v0_available;
  62         bytes = tally = mlist->num_bytes;
  63         base_paddr = (unsigned long) mlist->start_adr;
  64   
  65         sp_banks[0].base_addr = base_paddr;
  66         sp_banks[0].num_bytes = bytes;
  67 
  68         while (mlist->theres_more != (void *) 0){
  69                 i++;
  70                 mlist = mlist->theres_more;
  71                 bytes = mlist->num_bytes;
  72                 tally += bytes;
  73                 if (i >= SPARC_PHYS_BANKS-1) {
  74                         printk ("The machine has more banks that this kernel can support\n"
  75                                 "Increase the SPARC_PHYS_BANKS setting (currently %d)\n",
  76                                 SPARC_PHYS_BANKS);
  77                         i = SPARC_PHYS_BANKS-1;
  78                         break;
  79                 }
  80     
  81                 sp_banks[i].base_addr = (unsigned long) mlist->start_adr;
  82                 sp_banks[i].num_bytes = mlist->num_bytes;
  83         }
  84 
  85         i++;
  86         sp_banks[i].base_addr = 0xdeadbeef;
  87         sp_banks[i].num_bytes = 0;
  88 
  89         /* Now mask all bank sizes on a page boundary, it is all we can
  90          * use anyways.
  91          */
  92         for(i=0; sp_banks[i].num_bytes != 0; i++)
  93                 sp_banks[i].num_bytes &= PAGE_MASK;
  94 
  95         return tally;
  96 }
  97 
  98 /* Traverse the memory lists in the prom to see how much physical we
  99  * have.
 100  */
 101 unsigned long
 102 probe_memory(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104         int total;
 105 
 106         total = prom_probe_memory();
 107 
 108         /* Oh man, much nicer, keep the dirt in promlib. */
 109         return total;
 110 }
 111 
 112 extern void sun4c_complete_all_stores(void);
 113 
 114 /* Whee, a level 15 NMI interrupt memory error.  Let's have fun... */
 115 asmlinkage void sparc_lvl15_nmi(struct pt_regs *regs, unsigned long serr,
     /* [previous][next][first][last][top][bottom][index][help] */
 116                                 unsigned long svaddr, unsigned long aerr,
 117                                 unsigned long avaddr)
 118 {
 119         sun4c_complete_all_stores();
 120         printk("FAULT: NMI received\n");
 121         printk("SREGS: Synchronous Error %08lx\n", serr);
 122         printk("       Synchronous Vaddr %08lx\n", svaddr);
 123         printk("      Asynchronous Error %08lx\n", aerr);
 124         printk("      Asynchronous Vaddr %08lx\n", avaddr);
 125         printk("REGISTER DUMP:\n");
 126         show_regs(regs);
 127         prom_halt();
 128 }
 129 
 130 asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
     /* [previous][next][first][last][top][bottom][index][help] */
 131                                unsigned long address)
 132 {
 133         struct vm_area_struct *vma;
 134         int from_user = !(regs->psr & PSR_PS);
 135 
 136 #if 0
 137         printk("CPU[%d]: f<pid=%d,tf=%d,wr=%d,addr=%08lx",
 138                smp_processor_id(), current->pid, text_fault,
 139                write, address);
 140         printk(",pc=%08lx> ", regs->pc);
 141 #endif
 142 
 143         if(text_fault)
 144                 address = regs->pc;
 145 
 146         /* Now actually handle the fault.  Do kernel faults special,
 147          * because on the sun4c we could have faulted trying to read
 148          * the vma area of the task and without the following code
 149          * we'd fault recursively until all our stack is gone. ;-(
 150          */
 151         if(!from_user && address >= KERNBASE) {
 152 #ifdef __SMP__
 153                 printk("CPU[%d]: Kernel faults at addr=%08lx\n",
 154                        smp_processor_id(), address);
 155                 while(1)
 156                         ;
 157 #else
 158                 quick_kernel_fault(address);
 159                 return;
 160 #endif
 161         }
 162 
 163         vma = find_vma(current, address);
 164         if(!vma)
 165                 goto bad_area;
 166         if(vma->vm_start <= address)
 167                 goto good_area;
 168         if(!(vma->vm_flags & VM_GROWSDOWN))
 169                 goto bad_area;
 170         if(expand_stack(vma, address))
 171                 goto bad_area;
 172         /*
 173          * Ok, we have a good vm_area for this memory access, so
 174          * we can handle it..
 175          */
 176 good_area:
 177         if(write) {
 178                 if(!(vma->vm_flags & VM_WRITE))
 179                         goto bad_area;
 180         } else {
 181                 /* Allow reads even for write-only mappings */
 182                 if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
 183                         goto bad_area;
 184         }
 185         handle_mm_fault(vma, address, write);
 186         return;
 187         /*
 188          * Something tried to access memory that isn't in our memory map..
 189          * Fix it, but check if it's kernel or user first..
 190          */
 191 bad_area:
 192         if(from_user) {
 193 #if 0
 194                 printk("%s [%d]: segfaults at %08lx pc=%08lx\n",
 195                        current->comm, current->pid, address, regs->pc);
 196 #endif
 197                 current->tss.sig_address = address;
 198                 current->tss.sig_desc = SUBSIG_NOMAPPING;
 199                 send_sig(SIGSEGV, current, 1);
 200                 return;
 201         }
 202         if((unsigned long) address < PAGE_SIZE) {
 203                 printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
 204         } else
 205                 printk(KERN_ALERT "Unable to handle kernel paging request");
 206         printk(" at virtual address %08lx\n",address);
 207         printk(KERN_ALERT "current->mm->context = %08lx\n",
 208                (unsigned long) current->mm->context);
 209         printk(KERN_ALERT "current->mm->pgd = %08lx\n",
 210                (unsigned long) current->mm->pgd);
 211         die_if_kernel("Oops", regs);
 212 }
 213 
 214 /* This always deals with user addresses. */
 215 inline void force_user_fault(unsigned long address, int write)
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217         struct vm_area_struct *vma;
 218 
 219         vma = find_vma(current, address);
 220         if(!vma)
 221                 goto bad_area;
 222         if(vma->vm_start <= address)
 223                 goto good_area;
 224         if(!(vma->vm_flags & VM_GROWSDOWN))
 225                 goto bad_area;
 226         if(expand_stack(vma, address))
 227                 goto bad_area;
 228 good_area:
 229         if(write)
 230                 if(!(vma->vm_flags & VM_WRITE))
 231                         goto bad_area;
 232         else
 233                 if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
 234                         goto bad_area;
 235         handle_mm_fault(vma, address, write);
 236         return;
 237 bad_area:
 238         current->tss.sig_address = address;
 239         current->tss.sig_desc = SUBSIG_NOMAPPING;
 240         send_sig(SIGSEGV, current, 1);
 241         return;
 242 }
 243 
 244 void window_overflow_fault(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 245 {
 246         unsigned long sp = current->tss.rwbuf_stkptrs[0];
 247 
 248         if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
 249                 force_user_fault(sp + 0x38, 1);
 250         force_user_fault(sp, 1);
 251 }
 252 
 253 void window_underflow_fault(unsigned long sp)
     /* [previous][next][first][last][top][bottom][index][help] */
 254 {
 255         if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
 256                 force_user_fault(sp + 0x38, 0);
 257         force_user_fault(sp, 0);
 258 }
 259 
 260 void window_ret_fault(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 261 {
 262         unsigned long sp = regs->u_regs[UREG_FP];
 263 
 264         if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
 265                 force_user_fault(sp + 0x38, 0);
 266         force_user_fault(sp, 0);
 267 }

/* [previous][next][first][last][top][bottom][index][help] */