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