Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | /* $Id: r2300_misc.S,v 1.8 1999/12/08 22:05:10 harald Exp $ * misc.S: Misc. exception handling code for R3000/R2000. * * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse * * Multi-CPU abstraction reworking: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * * Further modifications to make this work: * Copyright (c) 1998 Harald Koerfgen * Copyright (c) 1998, 1999 Gleb Raiko & Vladimir Roganov */ #include <asm/asm.h> #include <asm/current.h> #include <asm/bootinfo.h> #include <asm/cachectl.h> #include <asm/fpregdef.h> #include <asm/mipsregs.h> #include <asm/page.h> #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/regdef.h> #include <asm/segment.h> #include <asm/stackframe.h> .text .set mips1 .set noreorder #undef NOTLB_OPTIMIZE /* If you are paranoid, define this. */ /* ABUSE of CPP macros 101. */ /* After this macro runs, the pte faulted on is * in register PTE, a ptr into the table in which * the pte belongs is in PTR. */ #define LOAD_PTE(pte, ptr) \ mfc0 pte, CP0_BADVADDR; \ lw ptr, current_pgd; \ srl pte, pte, 22; \ sll pte, pte, 2; \ addu ptr, ptr, pte; \ mfc0 pte, CP0_CONTEXT; \ lw ptr, (ptr); \ andi pte, pte, 0xffc; \ addu ptr, ptr, pte; \ lw pte, (ptr); \ nop; /* This places the even/odd pte pair in the page * table at PTR into ENTRYLO0 and ENTRYLO1 using * TMP as a scratch register. */ #define PTE_RELOAD(ptr) \ lw ptr, (ptr) ; \ nop ; \ mtc0 ptr, CP0_ENTRYLO0; \ nop; #define DO_FAULT(write) \ .set noat; \ .set macro; \ SAVE_ALL; \ mfc0 a2, CP0_BADVADDR; \ STI; \ .set at; \ move a0, sp; \ jal do_page_fault; \ li a1, write; \ j ret_from_sys_call; \ nop; \ .set noat; \ .set nomacro; /* Check is PTE is present, if not then jump to LABEL. * PTR points to the page table where this PTE is located, * when the macro is done executing PTE will be restored * with it's original value. */ #define PTE_PRESENT(pte, ptr, label) \ andi pte, pte, (_PAGE_PRESENT | _PAGE_READ); \ xori pte, pte, (_PAGE_PRESENT | _PAGE_READ); \ bnez pte, label; \ .set push; \ .set reorder; \ lw pte, (ptr); \ .set pop; /* Make PTE valid, store result in PTR. */ #define PTE_MAKEVALID(pte, ptr) \ ori pte, pte, (_PAGE_VALID | _PAGE_ACCESSED); \ sw pte, (ptr); /* Check if PTE can be written to, if not branch to LABEL. * Regardless restore PTE with value from PTR when done. */ #define PTE_WRITABLE(pte, ptr, label) \ andi pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \ xori pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \ bnez pte, label; \ .set push; \ .set reorder; \ lw pte, (ptr); \ .set pop; /* Make PTE writable, update software status bits as well, * then store at PTR. */ #define PTE_MAKEWRITE(pte, ptr) \ ori pte, pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | \ _PAGE_VALID | _PAGE_DIRTY); \ sw pte, (ptr); /* * The index register may have the probe fail bit set, * because we would trap on access kseg2, i.e. without refill. */ #define TLB_WRITE(reg) \ mfc0 reg, CP0_INDEX; \ nop; \ bltz reg, 1f; \ nop; \ tlbwi; \ j 2f; \ nop; \ 1: tlbwr; \ 2: #define RET(reg) \ mfc0 reg, CP0_EPC; \ nop; \ jr reg; \ rfe .set noreorder .align 5 NESTED(handle_tlbl, PT_SIZE, sp) .set noat #ifndef NOTLB_OPTIMIZE /* Test present bit in entry. */ LOAD_PTE(k0, k1) tlbp PTE_PRESENT(k0, k1, nopage_tlbl) PTE_MAKEVALID(k0, k1) PTE_RELOAD(k1) TLB_WRITE(k0) RET(k0) nopage_tlbl: #endif DO_FAULT(0) END(handle_tlbl) NESTED(handle_tlbs, PT_SIZE, sp) .set noat #ifndef NOTLB_OPTIMIZE LOAD_PTE(k0, k1) tlbp # find faulting entry PTE_WRITABLE(k0, k1, nopage_tlbs) PTE_MAKEWRITE(k0, k1) PTE_RELOAD(k1) TLB_WRITE(k0) RET(k0) nopage_tlbs: #endif DO_FAULT(1) END(handle_tlbs) .align 5 NESTED(handle_mod, PT_SIZE, sp) .set noat #ifndef NOTLB_OPTIMIZE LOAD_PTE(k0, k1) tlbp # find faulting entry andi k0, k0, _PAGE_WRITE beqz k0, nowrite_mod .set push .set reorder lw k0, (k1) .set pop /* Present and writable bits set, set accessed and dirty bits. */ PTE_MAKEWRITE(k0, k1) /* Now reload the entry into the tlb. */ PTE_RELOAD(k1) tlbwi RET(k0) #endif nowrite_mod: DO_FAULT(1) END(handle_mod) |