This commit was manufactured by cvs2svn to create branch 'vserver'.
[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         .text
28         .set    mips1
29         .set    noreorder
30
31         __INIT
32
33         /* TLB refill, R[23]00 version */
34         LEAF(except_vec0_r2300)
35         .set    noat
36         .set    mips1
37         mfc0    k0, CP0_BADVADDR
38         lw      k1, pgd_current                 # get pgd pointer
39         srl     k0, k0, 22
40         sll     k0, k0, 2
41         addu    k1, k1, k0
42         mfc0    k0, CP0_CONTEXT
43         lw      k1, (k1)
44         and     k0, k0, 0xffc
45         addu    k1, k1, k0
46         lw      k0, (k1)
47         nop
48         mtc0    k0, CP0_ENTRYLO0
49         mfc0    k1, CP0_EPC
50         tlbwr
51         jr      k1
52         rfe
53         END(except_vec0_r2300)
54
55         __FINIT
56
57         /* ABUSE of CPP macros 101. */
58
59         /* After this macro runs, the pte faulted on is
60          * in register PTE, a ptr into the table in which
61          * the pte belongs is in PTR.
62          */
63 #define LOAD_PTE(pte, ptr) \
64         mfc0    pte, CP0_BADVADDR; \
65         lw      ptr, pgd_current; \
66         srl     pte, pte, 22; \
67         sll     pte, pte, 2; \
68         addu    ptr, ptr, pte; \
69         mfc0    pte, CP0_CONTEXT; \
70         lw      ptr, (ptr); \
71         andi    pte, pte, 0xffc; \
72         addu    ptr, ptr, pte; \
73         lw      pte, (ptr); \
74         nop;
75
76         /* This places the even/odd pte pair in the page
77          * table at PTR into ENTRYLO0 and ENTRYLO1 using
78          * TMP as a scratch register.
79          */
80 #define PTE_RELOAD(ptr) \
81         lw      ptr, (ptr)      ; \
82         nop                     ; \
83         mtc0    ptr, CP0_ENTRYLO0; \
84         nop;
85
86 #define DO_FAULT(write) \
87         .set    noat; \
88         .set    macro; \
89         SAVE_ALL; \
90         mfc0    a2, CP0_BADVADDR; \
91         KMODE; \
92         .set    at; \
93         move    a0, sp; \
94         jal     do_page_fault; \
95          li     a1, write; \
96         j       ret_from_exception; \
97          nop; \
98         .set    noat; \
99         .set    nomacro;
100
101         /* Check is PTE is present, if not then jump to LABEL.
102          * PTR points to the page table where this PTE is located,
103          * when the macro is done executing PTE will be restored
104          * with it's original value.
105          */
106 #define PTE_PRESENT(pte, ptr, label) \
107         andi    pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
108         xori    pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
109         bnez    pte, label; \
110         .set    push;       \
111         .set    reorder;    \
112          lw     pte, (ptr); \
113         .set    pop;
114
115         /* Make PTE valid, store result in PTR. */
116 #define PTE_MAKEVALID(pte, ptr) \
117         ori     pte, pte, (_PAGE_VALID | _PAGE_ACCESSED); \
118         sw      pte, (ptr);
119
120         /* Check if PTE can be written to, if not branch to LABEL.
121          * Regardless restore PTE with value from PTR when done.
122          */
123 #define PTE_WRITABLE(pte, ptr, label) \
124         andi    pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
125         xori    pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
126         bnez    pte, label; \
127         .set    push;       \
128         .set    reorder;    \
129         lw      pte, (ptr); \
130         .set    pop;
131
132
133         /* Make PTE writable, update software status bits as well,
134          * then store at PTR.
135          */
136 #define PTE_MAKEWRITE(pte, ptr) \
137         ori     pte, pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | \
138                            _PAGE_VALID | _PAGE_DIRTY); \
139         sw      pte, (ptr);
140
141 /*
142  * The index register may have the probe fail bit set,
143  * because we would trap on access kseg2, i.e. without refill.
144  */
145 #define TLB_WRITE(reg) \
146         mfc0    reg, CP0_INDEX; \
147         nop; \
148         bltz    reg, 1f; \
149          nop; \
150         tlbwi; \
151         j       2f; \
152          nop; \
153 1:      tlbwr; \
154 2:
155
156 #define RET(reg) \
157         mfc0    reg, CP0_EPC; \
158         nop; \
159         jr      reg; \
160          rfe
161
162         .set    noreorder
163
164         .align  5
165 NESTED(handle_tlbl, PT_SIZE, sp)
166         .set    noat
167
168 #ifdef TLB_OPTIMIZE
169         /* Test present bit in entry. */
170         LOAD_PTE(k0, k1)
171         tlbp
172         PTE_PRESENT(k0, k1, nopage_tlbl)
173         PTE_MAKEVALID(k0, k1)
174         PTE_RELOAD(k1)
175         TLB_WRITE(k0)
176         RET(k0)
177 nopage_tlbl:
178 #endif
179
180         DO_FAULT(0)
181 END(handle_tlbl)
182
183 NESTED(handle_tlbs, PT_SIZE, sp)
184         .set    noat
185
186 #ifdef TLB_OPTIMIZE
187         LOAD_PTE(k0, k1)
188         tlbp                            # find faulting entry
189         PTE_WRITABLE(k0, k1, nopage_tlbs)
190         PTE_MAKEWRITE(k0, k1)
191         PTE_RELOAD(k1)
192         TLB_WRITE(k0)
193         RET(k0)
194 nopage_tlbs:
195 #endif
196
197         DO_FAULT(1)
198 END(handle_tlbs)
199
200         .align  5
201 NESTED(handle_mod, PT_SIZE, sp)
202         .set    noat
203 #ifdef TLB_OPTIMIZE
204         LOAD_PTE(k0, k1)
205         tlbp                                    # find faulting entry
206         andi    k0, k0, _PAGE_WRITE
207         beqz    k0, nowrite_mod
208         .set    push
209         .set    reorder
210         lw      k0, (k1)
211         .set    pop
212
213         /* Present and writable bits set, set accessed and dirty bits. */
214         PTE_MAKEWRITE(k0, k1)
215
216         /* Now reload the entry into the tlb. */
217         PTE_RELOAD(k1)
218         tlbwi
219         RET(k0)
220 #endif
221
222 nowrite_mod:
223         DO_FAULT(1)
224 END(handle_mod)