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 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | /* * r4k_misc.S: Misc. exception handling code for r4k. * * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse * * Multi-cpu abstraction and reworking: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * * $Id: r4k_misc.S,v 1.4 1997/12/01 17:57:30 ralf Exp $ */ #include <asm/asm.h> #include <asm/current.h> #include <asm/offset.h> #include <asm/bootinfo.h> #include <asm/cachectl.h> #include <asm/fpregdef.h> #include <asm/mipsconfig.h> #include <asm/mipsregs.h> #include <asm/page.h> #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/regdef.h> #include <asm/stackframe.h> #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; \ srl pte, pte, 22; \ _GET_CURRENT(ptr); \ sll pte, pte, 2; \ lw ptr, THREAD_PGDIR(ptr); \ addu ptr, pte, ptr; \ mfc0 pte, CP0_BADVADDR; \ lw ptr, (ptr); \ srl pte, pte, 10; \ and pte, pte, 0xffc; \ addu ptr, ptr, pte; \ lw pte, (ptr); /* 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, tmp) \ ori ptr, ptr, 0x4; \ xori ptr, ptr, 0x4; \ lw tmp, 4(ptr); \ lw ptr, 0(ptr); \ srl tmp, tmp, 6; \ mtc0 tmp, CP0_ENTRYLO1; \ srl ptr, ptr, 6; \ mtc0 ptr, CP0_ENTRYLO0; #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; \ lw pte, (ptr); /* 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; \ lw pte, (ptr); /* 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); .set noreorder .set mips3 /* * From the IDT errata for the QED RM5230 (Nevada), processor revision 1.0: * 2. A timing hazard exists for the TLBP instruction. * * stalling_instruction * TLBP * * The JTLB is being read for the TLBP throughout the stall generated by the * previous instruction. This is not really correct as the stalling instruction * can modify the address used to access the JTLB. The failure symptom is that * the TLBP instruction will use an address created for the stalling instruction * and not the address held in C0_ENHI and thus report the wrong results. * * The software work-around is to not allow the instruction preceding the TLBP * to stall - make it an NOP or some other instruction guaranteed not to stall. * * Errata 2 will not be fixed. This errata is also on the R5000. * * As if we MIPS hackers wouldn't know how to nop pipelines happy ... */ #define R5K_HAZARD nop /* * Note for many R4k variants tlb probes cannot be executed out * of the instruction cache else you get bogus results. */ .align 5 NESTED(r4k_handle_tlbl, PT_SIZE, sp) .set noat .set nomacro invalid_tlbl: #ifndef NOTLB_OPTIMIZE /* Test present bit in entry. */ LOAD_PTE(k0, k1) R5K_HAZARD tlbp PTE_PRESENT(k0, k1, nopage_tlbl) PTE_MAKEVALID(k0, k1) PTE_RELOAD(k1, k0) nop b 1f tlbwi 1: nop eret #endif nopage_tlbl: DO_FAULT(0) END(r4k_handle_tlbl) .align 5 NESTED(r4k_handle_tlbs, PT_SIZE, sp) .set noat #ifndef NOTLB_OPTIMIZE LOAD_PTE(k0, k1) R5K_HAZARD tlbp # find faulting entry PTE_WRITABLE(k0, k1, nopage_tlbs) PTE_MAKEWRITE(k0, k1) PTE_RELOAD(k1, k0) nop b 1f tlbwi 1: nop eret #endif nopage_tlbs: DO_FAULT(1) END(r4k_handle_tlbs) .align 5 NESTED(r4k_handle_mod, PT_SIZE, sp) .set noat #ifndef NOTLB_OPTIMIZE LOAD_PTE(k0, k1) R5K_HAZARD tlbp # find faulting entry andi k0, k0, _PAGE_WRITE beqz k0, nowrite_mod lw k0, (k1) /* Present and writable bits set, set accessed and dirty bits. */ PTE_MAKEWRITE(k0, k1) #if 0 ori k0, k0, (_PAGE_ACCESSED | _PAGE_DIRTY) sw k0, (k1) #endif /* Now reload the entry into the tlb. */ PTE_RELOAD(k1, k0) nop b 1f tlbwi 1: nop eret #endif nowrite_mod: DO_FAULT(1) END(r4k_handle_mod) |