ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / mips / mm-64 / tlbex-r4k.S
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2000 Silicon Graphics, Inc.
7  * Written by Ulf Carlsson (ulfc@engr.sgi.com)
8  * Copyright (C) 2002  Maciej W. Rozycki
9  */
10 #include <linux/config.h>
11 #include <linux/init.h>
12 #include <linux/threads.h>
13
14 #include <asm/asm.h>
15 #include <asm/hazards.h>
16 #include <asm/regdef.h>
17 #include <asm/mipsregs.h>
18 #include <asm/stackframe.h>
19 #include <asm/war.h>
20
21 #define _VMALLOC_START  0xc000000000000000
22
23         /*
24          * After this macro runs we have a pointer to the pte of the address
25          * that caused the fault in PTR.
26          */
27         .macro  LOAD_PTE2, ptr, tmp, kaddr
28 #ifdef CONFIG_SMP
29         dmfc0   \ptr, CP0_CONTEXT
30         dmfc0   \tmp, CP0_BADVADDR
31         dsra    \ptr, 23                        # get pgd_current[cpu]
32 #else
33         dmfc0   \tmp, CP0_BADVADDR
34         dla     \ptr, pgd_current
35 #endif
36         bltz    \tmp, \kaddr
37          ld     \ptr, (\ptr)
38         dsrl    \tmp, (_PGDIR_SHIFT-3)          # get pgd offset in bytes
39         andi    \tmp, ((_PTRS_PER_PGD - 1)<<3)
40         daddu   \ptr, \tmp                      # add in pgd offset
41         dmfc0   \tmp, CP0_BADVADDR
42         ld      \ptr, (\ptr)                    # get pmd pointer
43         dsrl    \tmp, (_PMD_SHIFT-3)            # get pmd offset in bytes
44         andi    \tmp, ((_PTRS_PER_PMD - 1)<<3)
45         daddu   \ptr, \tmp                      # add in pmd offset
46         dmfc0   \tmp, CP0_XCONTEXT
47         ld      \ptr, (\ptr)                    # get pte pointer
48         andi    \tmp, 0xff0                     # get pte offset
49         daddu   \ptr, \tmp
50         .endm
51
52
53         /*
54          * Ditto for the kernel table.
55          */
56         .macro  LOAD_KPTE2, ptr, tmp, not_vmalloc
57         /*
58          * First, determine that the address is in/above vmalloc range.
59          */
60         dmfc0   \tmp, CP0_BADVADDR
61         dli     \ptr, _VMALLOC_START
62
63         /*
64          * Now find offset into kptbl.
65          */
66         dsubu   \tmp, \tmp, \ptr
67         dla     \ptr, kptbl
68         dsrl    \tmp, (_PAGE_SHIFT+1)           # get vpn2
69         dsll    \tmp, 4                         # byte offset of pte
70         daddu   \ptr, \ptr, \tmp
71
72         /*
73          * Determine that fault address is within vmalloc range.
74          */
75         dla     \tmp, ekptbl
76         slt     \tmp, \ptr, \tmp
77         beqz    \tmp, \not_vmalloc              # not vmalloc
78          nop
79         .endm
80
81
82         /*
83          * This places the even/odd pte pair in the page table at the pte
84          * entry pointed to by PTE into ENTRYLO0 and ENTRYLO1.
85          */
86         .macro  PTE_RELOAD, pte0, pte1
87         dsrl    \pte0, 6                        # convert to entrylo0
88         dmtc0   \pte0, CP0_ENTRYLO0             # load it
89         dsrl    \pte1, 6                        # convert to entrylo1
90         dmtc0   \pte1, CP0_ENTRYLO1             # load it
91         .endm
92
93
94         .text
95         .set    noreorder
96         .set    mips3
97
98         __INIT
99
100         /*
101          * TLB refill handlers for the R4000 and SB1.
102          * Attention:  We may only use 32 instructions / 128 bytes.
103          */
104         .align  5
105 LEAF(except_vec1_r4k)
106         .set    noat
107         dla     k0, handle_vec1_r4k
108         jr      k0
109          nop
110 END(except_vec1_r4k)
111
112 LEAF(except_vec1_sb1)
113 #if BCM1250_M3_WAR
114         dmfc0   k0, CP0_BADVADDR
115         dmfc0   k1, CP0_ENTRYHI
116         xor     k0, k1
117         dsrl    k0, k0, _PAGE_SHIFT+1
118         bnez    k0, 1f
119 #endif
120         .set    noat
121         dla     k0, handle_vec1_r4k
122         jr      k0
123          nop
124
125 1:      eret
126         nop
127 END(except_vec1_sb1)
128
129         __FINIT
130
131         .align  5
132 LEAF(handle_vec1_r4k)
133         .set    noat
134         LOAD_PTE2 k1 k0 9f
135         ld      k0, 0(k1)                       # get even pte
136         ld      k1, 8(k1)                       # get odd pte
137         PTE_RELOAD k0 k1
138         mtc0_tlbw_hazard
139         tlbwr
140         tlbw_eret_hazard
141         eret
142
143 9:                                              # handle the vmalloc range
144         LOAD_KPTE2 k1 k0 invalid_vmalloc_address
145         ld      k0, 0(k1)                       # get even pte
146         ld      k1, 8(k1)                       # get odd pte
147         PTE_RELOAD k0 k1
148         mtc0_tlbw_hazard
149          tlbwr
150         tlbw_eret_hazard
151         eret
152 END(handle_vec1_r4k)
153
154
155         __INIT
156
157         /*
158          * TLB refill handler for the R10000.
159          * Attention:  We may only use 32 instructions / 128 bytes.
160          */
161         .align  5
162 LEAF(except_vec1_r10k)
163         .set    noat
164         dla     k0, handle_vec1_r10k
165         jr      k0
166          nop
167 END(except_vec1_r10k)
168
169         __FINIT
170
171         .align  5
172 LEAF(handle_vec1_r10k)
173         .set    noat
174         LOAD_PTE2 k1 k0 9f
175         ld      k0, 0(k1)                       # get even pte
176         ld      k1, 8(k1)                       # get odd pte
177         PTE_RELOAD k0 k1
178         nop
179         tlbwr
180         eret
181
182 9:                                              # handle the vmalloc range
183         LOAD_KPTE2 k1 k0 invalid_vmalloc_address
184         ld      k0, 0(k1)                       # get even pte
185         ld      k1, 8(k1)                       # get odd pte
186         PTE_RELOAD k0 k1
187         nop
188         tlbwr
189         eret
190 END(handle_vec1_r10k)
191
192
193         .align  5
194 LEAF(invalid_vmalloc_address)
195         .set    noat
196         SAVE_ALL
197         CLI
198         dmfc0   t0, CP0_BADVADDR
199         sd      t0, PT_BVADDR(sp)
200         move    a0, sp
201         jal     show_regs
202         PANIC("Invalid kernel address")
203 END(invalid_vmalloc_address)