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. do_sparc_winfault

   1 /* $Id: fault.c,v 1.42 1995/11/25 00:59:20 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 *,long);
  32 
  33 struct linux_romvec *romvec;
  34 
  35 /* foo */
  36 
  37 int tbase_needs_unmapping;
  38 
  39 /* At boot time we determine these two values necessary for setting
  40  * up the segment maps and page table entries (pte's).
  41  */
  42 
  43 int num_segmaps, num_contexts;
  44 int invalid_segment;
  45 
  46 /* various Virtual Address Cache parameters we find at boot time... */
  47 
  48 int vac_size, vac_linesize, vac_do_hw_vac_flushes;
  49 int vac_entries_per_context, vac_entries_per_segment;
  50 int vac_entries_per_page;
  51 
  52 /*
  53  * Define this if things work differently on a i386 and a i486:
  54  * it will (on a i486) warn about kernel memory accesses that are
  55  * done without a 'verify_area(VERIFY_WRITE,..)'
  56  */
  57 #undef CONFIG_TEST_VERIFY_AREA
  58 
  59 /* Nice, simple, prom library does all the sweating for us. ;) */
  60 int prom_probe_memory (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62         register struct linux_mlist_v0 *mlist;
  63         register unsigned long bytes, base_paddr, tally;
  64         register int i;
  65 
  66         i = 0;
  67         mlist= *prom_meminfo()->v0_available;
  68         bytes = tally = mlist->num_bytes;
  69         base_paddr = (unsigned long) mlist->start_adr;
  70   
  71         sp_banks[0].base_addr = base_paddr;
  72         sp_banks[0].num_bytes = bytes;
  73 
  74         while (mlist->theres_more != (void *) 0){
  75                 i++;
  76                 mlist = mlist->theres_more;
  77                 bytes = mlist->num_bytes;
  78                 tally += bytes;
  79                 if (i >= SPARC_PHYS_BANKS-1) {
  80                         printk ("The machine has more banks that this kernel can support\n"
  81                                 "Increase the SPARC_PHYS_BANKS setting (currently %d)\n",
  82                                 SPARC_PHYS_BANKS);
  83                         i = SPARC_PHYS_BANKS-1;
  84                         break;
  85                 }
  86     
  87                 sp_banks[i].base_addr = (unsigned long) mlist->start_adr;
  88                 sp_banks[i].num_bytes = mlist->num_bytes;
  89         }
  90 
  91         i++;
  92         sp_banks[i].base_addr = 0xdeadbeef;
  93         sp_banks[i].num_bytes = 0;
  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 /* Whee, a level 15 NMI interrupt memory error.  Let's have fun... */
 113 asmlinkage void sparc_lvl15_nmi(struct pt_regs *regs, unsigned long serr,
     /* [previous][next][first][last][top][bottom][index][help] */
 114                                 unsigned long svaddr, unsigned long aerr,
 115                                 unsigned long avaddr)
 116 {
 117         printk("FAULT: NMI received\n");
 118         printk("SREGS: Synchronous Error %08lx\n", serr);
 119         printk("       Synchronous Vaddr %08lx\n", svaddr);
 120         printk("      Asynchronous Error %08lx\n", aerr);
 121         printk("      Asynchronous Vaddr %08lx\n", avaddr);
 122         printk("REGISTER DUMP:\n");
 123         show_regs(regs);
 124         prom_halt();
 125 }
 126 
 127 /* Whee, looks like an i386 to me ;-) */
 128 asmlinkage void do_sparc_fault(struct pt_regs *regs, unsigned long tbr)
     /* [previous][next][first][last][top][bottom][index][help] */
 129 {
 130         struct vm_area_struct *vma;
 131         unsigned long address, error_code, trap_type;
 132         unsigned long from_user;
 133 
 134         from_user = (((regs->psr & PSR_PS) >> 4) ^ FAULT_CODE_USER);
 135         if(get_fault_info(&address, &error_code, from_user))
 136                 goto bad_area;
 137         trap_type = ((tbr>>4)&0xff);
 138         if(trap_type == SP_TRAP_TFLT) {
 139                 /* We play it 'safe'... */
 140                 address = regs->pc;
 141                 error_code = (from_user); /* no page, read */
 142         } else if(trap_type != SP_TRAP_DFLT)
 143                 panic("Bad sparc trap, trap_type not data or text fault...");
 144 
 145         /* Now actually handle the fault.  Do kernel faults special,
 146          * because on the sun4c we could have faulted trying to read
 147          * the vma area of the task and without the following code
 148          * we'd fault recursively until all our stack is gone. ;-(
 149          *
 150          * XXX I think there are races with this maneuver. XXX
 151          */
 152         if(!from_user && address >= KERNBASE) {
 153                 update_mmu_cache(0, address, __pte(0));
 154                 return;
 155         }
 156 
 157         vma = find_vma(current, address);
 158         if(!vma)
 159                 goto bad_area;
 160         if(vma->vm_start <= address)
 161                 goto good_area;
 162         if(!(vma->vm_flags & VM_GROWSDOWN))
 163                 goto bad_area;
 164         if(expand_stack(vma, address))
 165                 goto bad_area;
 166         /*
 167          * Ok, we have a good vm_area for this memory access, so
 168          * we can handle it..
 169          */
 170 good_area:
 171         if(error_code & FAULT_CODE_WRITE) {
 172                 if(!(vma->vm_flags & VM_WRITE))
 173                         goto bad_area;
 174         } else {
 175                 /* Allow reads even for write-only mappings */
 176                 if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
 177                         goto bad_area;
 178         }
 179         handle_mm_fault(vma, address, error_code & FAULT_CODE_WRITE);
 180         return;
 181         /*
 182          * Something tried to access memory that isn't in our memory map..
 183          * Fix it, but check if it's kernel or user first..
 184          */
 185 bad_area:
 186         if(error_code & FAULT_CODE_USER) {
 187                 current->tss.sig_address = address;
 188                 current->tss.sig_desc = SUBSIG_NOMAPPING;
 189                 send_sig(SIGSEGV, current, 1);
 190                 return;
 191         }
 192         /* Uh oh, a kernel fault.  Check for bootup wp_test... */
 193         if (wp_works_ok < 0 && address == 0x0) {
 194                 wp_works_ok = 1;
 195                 printk("This Sparc honours the WP bit even when in supervisor mode. "
 196                        "Good.\n");
 197                 /* Advance program counter over the store. */
 198                 regs->pc = regs->npc;
 199                 regs->npc += 4;
 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("At PC %08lx nPC %08lx\n", (unsigned long) regs->pc,
 208                (unsigned long) regs->npc);
 209         printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n",
 210                (unsigned long) current->tss.pgd_ptr);
 211         show_regs(regs);
 212         panic("KERNAL FAULT");
 213 }
 214 
 215 /* When the user does not have a mapped stack and we either
 216  * need to read the users register window from that stack or
 217  * we need to save a window to that stack, control flow
 218  * ends up here to investigate the situation.  This is a
 219  * very odd situation where a 'user fault' happens from
 220  * kernel space.
 221  */
 222 
 223 /* #define DEBUG_WINFAULT */
 224 extern void show_regwindow(struct reg_window *);
 225 asmlinkage void do_sparc_winfault(struct pt_regs *regs, int push)
     /* [previous][next][first][last][top][bottom][index][help] */
 226 {
 227         int wincount = 0;
 228         int signal = 0;
 229         struct thread_struct *tsp = &current->tss;
 230 
 231         flush_user_windows();
 232 #ifdef DEBUG_WINFAULT
 233         {
 234                 int i;
 235                 printk("%s[%d]wfault<%d>: WINDOW DUMP --> ", current->comm,
 236                        current->pid, push);
 237                 if(push==1)
 238                         for(i = 0; i < tsp->w_saved; i++)
 239                                 printk("w[%d]sp<%08lx>, ",
 240                                        i, tsp->rwbuf_stkptrs[i]);
 241                 else
 242                         printk("w[0]sp<%08lx>", regs->u_regs[UREG_FP]);
 243                 if(push!=2)
 244                         printk("\n");
 245         }
 246 #endif
 247         if(push==1) {
 248                 /* We failed to push a window to users stack. */
 249                 while(wincount < tsp->w_saved) {
 250                         if ((tsp->rwbuf_stkptrs[wincount] & 7) ||
 251                             (tsp->rwbuf_stkptrs[wincount] > KERNBASE) ||
 252                             verify_area(VERIFY_WRITE,
 253                                         (char *) tsp->rwbuf_stkptrs[wincount],
 254                                         sizeof(struct reg_window))) {
 255                                 signal = SIGILL;
 256                                 break;
 257                         }                       
 258                         /* Do it! */
 259                         memcpy((char *) tsp->rwbuf_stkptrs[wincount],
 260                                (char *)&tsp->reg_window[wincount],
 261                                sizeof(struct reg_window));
 262                         wincount++;
 263                 }
 264         } else {
 265                 /* We failed to pull a window from users stack.
 266                  * For a window underflow from userland we need
 267                  * to verify two stacks, for a return from trap
 268                  * we need only inspect the one at UREG_FP.
 269                  */
 270                 if((regs->u_regs[UREG_FP] & 7) ||
 271                    (regs->u_regs[UREG_FP] > KERNBASE) ||
 272                    verify_area(VERIFY_READ,
 273                                (char *) regs->u_regs[UREG_FP],
 274                                sizeof(struct reg_window)))
 275                         signal = SIGILL;
 276                 else
 277                         memcpy((char *)&tsp->reg_window[0],
 278                                (char *) regs->u_regs[UREG_FP],
 279                                sizeof(struct reg_window));
 280                 if(push==2 && !signal) {
 281                         unsigned long sp = tsp->reg_window[0].ins[6];
 282 #ifdef DEBUG_WINFAULT
 283                         printk(", w[1]sp<%08lx>\n", sp);
 284                         show_regwindow(&tsp->reg_window[0]);
 285 #endif
 286                         if((sp & 7) || (sp > KERNBASE) ||
 287                            verify_area(VERIFY_READ, (char *) sp,
 288                                        sizeof(struct reg_window)))
 289                                 signal = SIGILL;
 290                         else
 291                                 memcpy((char *)&tsp->reg_window[1],
 292                                        (char *) sp, sizeof(struct reg_window));
 293                 }
 294         }
 295         if(signal) {
 296                 printk("%s[%d]: User has trashed stack pointer pc<%08lx>sp<%08lx>\n",
 297                        current->comm, current->pid, regs->pc, regs->u_regs[UREG_FP]);
 298                 tsp->sig_address = regs->pc;
 299                 tsp->sig_desc = SUBSIG_STACK;
 300                 send_sig(signal, current, 1);
 301         } else
 302                 tsp->w_saved = 0;
 303 }

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