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

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