linux-bk/arch/cris/arch-v10/mm/fault.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/cris/mm/fault.c
   3 *
   4 *  Low level bus fault handler
   5 *
   6 *
   7 *  Copyright (C) 2000, 2001  Axis Communications AB
   8 *
   9 *  Authors:  Bjorn Wesen 
  10 * 
  11 */
  12
  13#include <linux/mm.h>
  14#include <asm/uaccess.h>
  15#include <asm/pgtable.h>
  16#include <asm/arch/svinto.h>
  17
  18/* debug of low-level TLB reload */
  19#undef DEBUG
  20
  21#ifdef DEBUG
  22#define D(x) x
  23#else
  24#define D(x)
  25#endif
  26
  27extern volatile pgd_t *current_pgd;
  28
  29extern const struct exception_table_entry
  30        *search_exception_tables(unsigned long addr);
  31
  32asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs,
  33                              int protection, int writeaccess);
  34
  35/* fast TLB-fill fault handler
  36 * this is called from entry.S with interrupts disabled
  37 */
  38
  39void
  40handle_mmu_bus_fault(struct pt_regs *regs)
  41{
  42        int cause;
  43#ifdef DEBUG
  44        int select;
  45        int index;
  46        int page_id;
  47        int acc, inv;
  48#endif
  49        int miss, we, writeac;
  50        pmd_t *pmd;
  51        pte_t pte;
  52        unsigned long address;
  53
  54        cause = *R_MMU_CAUSE;
  55
  56        address = cause & PAGE_MASK; /* get faulting address */
  57
  58#ifdef DEBUG
  59        select = *R_TLB_SELECT;
  60        page_id = IO_EXTRACT(R_MMU_CAUSE,  page_id,   cause);
  61        acc     = IO_EXTRACT(R_MMU_CAUSE,  acc_excp,  cause);
  62        inv     = IO_EXTRACT(R_MMU_CAUSE,  inv_excp,  cause);  
  63        index   = IO_EXTRACT(R_TLB_SELECT, index,     select);
  64#endif
  65        miss    = IO_EXTRACT(R_MMU_CAUSE,  miss_excp, cause);
  66        we      = IO_EXTRACT(R_MMU_CAUSE,  we_excp,   cause);
  67        writeac = IO_EXTRACT(R_MMU_CAUSE,  wr_rd,     cause);
  68
  69        /* ETRAX 100LX TR89 bugfix: if the second half of an unaligned
  70         * write causes a MMU-fault, it will not be restarted correctly.
  71         * This could happen if a write crosses a page-boundary and the
  72         * second page is not yet COW'ed or even loaded. The workaround
  73         * is to clear the unaligned bit in the CPU status record, so 
  74         * that the CPU will rerun both the first and second halves of
  75         * the instruction. This will not have any sideeffects unless
  76         * the first half goes to any device or memory that can't be
  77         * written twice, and which is mapped through the MMU.
  78         *
  79         * We only need to do this for writes.
  80         */
  81
  82        if(writeac)
  83                regs->csrinstr &= ~(1 << 5);
  84        
  85        D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n",
  86                 regs->irp, address, miss, inv, we, acc, index, page_id));
  87
  88        /* for a miss, we need to reload the TLB entry */
  89
  90        if (miss) {
  91                /* see if the pte exists at all
  92                 * refer through current_pgd, dont use mm->pgd
  93                 */
  94
  95                pmd = (pmd_t *)(current_pgd + pgd_index(address));
  96                if (pmd_none(*pmd)) {
  97                        do_page_fault(address, regs, 0, writeac);
  98                        return;
  99                }
 100                if (pmd_bad(*pmd)) {
 101                        printk("bad pgdir entry 0x%lx at 0x%p\n", *(unsigned long*)pmd, pmd);
 102                        pmd_clear(pmd);
 103                        return;
 104                }
 105                pte = *pte_offset_kernel(pmd, address);
 106                if (!pte_present(pte)) {
 107                        do_page_fault(address, regs, 0, writeac);
 108                        return;
 109                }
 110
 111#ifdef DEBUG
 112                printk(" found pte %lx pg %p ", pte_val(pte), pte_page(pte));
 113                if (pte_val(pte) & _PAGE_SILENT_WRITE)
 114                        printk("Silent-W ");
 115                if (pte_val(pte) & _PAGE_KERNEL)
 116                        printk("Kernel ");
 117                if (pte_val(pte) & _PAGE_SILENT_READ)
 118                        printk("Silent-R ");
 119                if (pte_val(pte) & _PAGE_GLOBAL)
 120                        printk("Global ");
 121                if (pte_val(pte) & _PAGE_PRESENT)
 122                        printk("Present ");
 123                if (pte_val(pte) & _PAGE_ACCESSED)
 124                        printk("Accessed ");
 125                if (pte_val(pte) & _PAGE_MODIFIED)
 126                        printk("Modified ");
 127                if (pte_val(pte) & _PAGE_READ)
 128                        printk("Readable ");
 129                if (pte_val(pte) & _PAGE_WRITE)
 130                        printk("Writeable ");
 131                printk("\n");
 132#endif
 133
 134                /* load up the chosen TLB entry
 135                 * this assumes the pte format is the same as the TLB_LO layout.
 136                 *
 137                 * the write to R_TLB_LO also writes the vpn and page_id fields from
 138                 * R_MMU_CAUSE, which we in this case obviously want to keep
 139                 */
 140
 141                *R_TLB_LO = pte_val(pte);
 142
 143                return;
 144        }
 145
 146        /* leave it to the MM system fault handler */
 147        do_page_fault(address, regs, 1, we);
 148}
 149
 150/* Called from arch/cris/mm/fault.c to find fixup code. */
 151int
 152find_fixup_code(struct pt_regs *regs)
 153{
 154        const struct exception_table_entry *fixup;
 155
 156        if ((fixup = search_exception_tables(regs->irp)) != 0) {
 157                /* Adjust the instruction pointer in the stackframe. */
 158                regs->irp = fixup->fixup;
 159                
 160                /* 
 161                 * Don't return by restoring the CPU state, so switch
 162                 * frame-type. 
 163                 */
 164                regs->frametype = CRIS_FRAME_NORMAL;
 165                return 1;
 166        }
 167
 168        return 0;
 169}
 170
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.