diff options
Diffstat (limited to 'arch/m32r/mm/mmu.S')
-rw-r--r-- | arch/m32r/mm/mmu.S | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/arch/m32r/mm/mmu.S b/arch/m32r/mm/mmu.S new file mode 100644 index 000000000000..0c28f11d6677 --- /dev/null +++ b/arch/m32r/mm/mmu.S | |||
@@ -0,0 +1,350 @@ | |||
1 | /* | ||
2 | * linux/arch/m32r/mm/mmu.S | ||
3 | * | ||
4 | * Copyright (C) 2001 by Hiroyuki Kondo | ||
5 | */ | ||
6 | |||
7 | /* $Id: mmu.S,v 1.15 2004/03/16 02:56:27 takata Exp $ */ | ||
8 | |||
9 | #include <linux/config.h> /* CONFIG_MMU */ | ||
10 | #include <linux/linkage.h> | ||
11 | #include <asm/assembler.h> | ||
12 | #include <asm/smp.h> | ||
13 | |||
14 | .text | ||
15 | #ifdef CONFIG_MMU | ||
16 | |||
17 | #include <asm/mmu_context.h> | ||
18 | #include <asm/page.h> | ||
19 | #include <asm/pgtable.h> | ||
20 | #include <asm/m32r.h> | ||
21 | |||
22 | /* | ||
23 | * TLB Miss Exception handler | ||
24 | */ | ||
25 | .balign 16 | ||
26 | ENTRY(tme_handler) | ||
27 | .global tlb_entry_i_dat | ||
28 | .global tlb_entry_d_dat | ||
29 | |||
30 | SWITCH_TO_KERNEL_STACK | ||
31 | |||
32 | #if defined(CONFIG_ISA_M32R2) | ||
33 | st r0, @-sp | ||
34 | st r1, @-sp | ||
35 | st r2, @-sp | ||
36 | st r3, @-sp | ||
37 | |||
38 | seth r3, #high(MMU_REG_BASE) | ||
39 | ld r1, @(MESTS_offset, r3) ; r1: status (MESTS reg.) | ||
40 | ld r0, @(MDEVP_offset, r3) ; r0: PFN + ASID (MDEVP reg.) | ||
41 | st r1, @(MESTS_offset, r3) ; clear status (MESTS reg.) | ||
42 | and3 r1, r1, #(MESTS_IT) | ||
43 | bnez r1, 1f ; instruction TLB miss? | ||
44 | |||
45 | ;; data TLB miss | ||
46 | ;; input | ||
47 | ;; r0: PFN + ASID (MDEVP reg.) | ||
48 | ;; r1 - r3: free | ||
49 | ;; output | ||
50 | ;; r0: PFN + ASID | ||
51 | ;; r1: TLB entry base address | ||
52 | ;; r2: &tlb_entry_{i|d}_dat | ||
53 | ;; r3: free | ||
54 | |||
55 | #ifndef CONFIG_SMP | ||
56 | seth r2, #high(tlb_entry_d_dat) | ||
57 | or3 r2, r2, #low(tlb_entry_d_dat) | ||
58 | #else /* CONFIG_SMP */ | ||
59 | ldi r1, #-8192 | ||
60 | seth r2, #high(tlb_entry_d_dat) | ||
61 | or3 r2, r2, #low(tlb_entry_d_dat) | ||
62 | and r1, sp | ||
63 | ld r1, @(16, r1) ; current_thread_info->cpu | ||
64 | slli r1, #2 | ||
65 | add r2, r1 | ||
66 | #endif /* !CONFIG_SMP */ | ||
67 | seth r1, #high(DTLB_BASE) | ||
68 | or3 r1, r1, #low(DTLB_BASE) | ||
69 | bra 2f | ||
70 | |||
71 | .balign 16 | ||
72 | .fillinsn | ||
73 | 1: | ||
74 | ;; instrucntion TLB miss | ||
75 | ;; input | ||
76 | ;; r0: MDEVP reg. (included ASID) | ||
77 | ;; r1 - r3: free | ||
78 | ;; output | ||
79 | ;; r0: PFN + ASID | ||
80 | ;; r1: TLB entry base address | ||
81 | ;; r2: &tlb_entry_{i|d}_dat | ||
82 | ;; r3: free | ||
83 | ldi r3, #-4096 | ||
84 | and3 r0, r0, #(MMU_CONTEXT_ASID_MASK) | ||
85 | mvfc r1, bpc | ||
86 | and r1, r3 | ||
87 | or r0, r1 ; r0: PFN + ASID | ||
88 | #ifndef CONFIG_SMP | ||
89 | seth r2, #high(tlb_entry_i_dat) | ||
90 | or3 r2, r2, #low(tlb_entry_i_dat) | ||
91 | #else /* CONFIG_SMP */ | ||
92 | ldi r1, #-8192 | ||
93 | seth r2, #high(tlb_entry_i_dat) | ||
94 | or3 r2, r2, #low(tlb_entry_i_dat) | ||
95 | and r1, sp | ||
96 | ld r1, @(16, r1) ; current_thread_info->cpu | ||
97 | slli r1, #2 | ||
98 | add r2, r1 | ||
99 | #endif /* !CONFIG_SMP */ | ||
100 | seth r1, #high(ITLB_BASE) | ||
101 | or3 r1, r1, #low(ITLB_BASE) | ||
102 | |||
103 | .fillinsn | ||
104 | 2: | ||
105 | ;; select TLB entry | ||
106 | ;; input | ||
107 | ;; r0: PFN + ASID | ||
108 | ;; r1: TLB entry base address | ||
109 | ;; r2: &tlb_entry_{i|d}_dat | ||
110 | ;; r3: free | ||
111 | ;; output | ||
112 | ;; r0: PFN + ASID | ||
113 | ;; r1: TLB entry address | ||
114 | ;; r2, r3: free | ||
115 | #ifdef CONFIG_ISA_DUAL_ISSUE | ||
116 | ld r3, @r2 || srli r1, #3 | ||
117 | #else | ||
118 | ld r3, @r2 | ||
119 | srli r1, #3 | ||
120 | #endif | ||
121 | add r1, r3 | ||
122 | ; tlb_entry_{d|i}_dat++; | ||
123 | addi r3, #1 | ||
124 | and3 r3, r3, #(NR_TLB_ENTRIES - 1) | ||
125 | #ifdef CONFIG_ISA_DUAL_ISSUE | ||
126 | st r3, @r2 || slli r1, #3 | ||
127 | #else | ||
128 | st r3, @r2 | ||
129 | slli r1, #3 | ||
130 | #endif | ||
131 | |||
132 | ;; load pte | ||
133 | ;; input | ||
134 | ;; r0: PFN + ASID | ||
135 | ;; r1: TLB entry address | ||
136 | ;; r2, r3: free | ||
137 | ;; output | ||
138 | ;; r0: PFN + ASID | ||
139 | ;; r1: TLB entry address | ||
140 | ;; r2: pte_data | ||
141 | ;; r3: free | ||
142 | ; pgd = *(unsigned long *)MPTB; | ||
143 | ld24 r2, #(-MPTB - 1) | ||
144 | srl3 r3, r0, #22 | ||
145 | #ifdef CONFIG_ISA_DUAL_ISSUE | ||
146 | not r2, r2 || slli r3, #2 ; r3: pgd offset | ||
147 | #else | ||
148 | not r2, r2 | ||
149 | slli r3, #2 | ||
150 | #endif | ||
151 | ld r2, @r2 ; r2: pgd base addr (MPTB reg.) | ||
152 | or r3, r2 ; r3: pmd addr | ||
153 | |||
154 | ; pmd = pmd_offset(pgd, address); | ||
155 | ld r3, @r3 ; r3: pmd data | ||
156 | ldi r2, #-4096 | ||
157 | beqz r3, 3f ; pmd_none(*pmd) ? | ||
158 | |||
159 | ; pte = pte_offset(pmd, address); | ||
160 | and r2, r3 ; r2: pte base addr | ||
161 | srl3 r3, r0, #10 | ||
162 | and3 r3, r3, #0xffc ; r3: pte offset | ||
163 | or r3, r2 | ||
164 | seth r2, #0x8000 | ||
165 | or r3, r2 ; r3: pte addr | ||
166 | |||
167 | ; pte_data = (unsigned long)pte_val(*pte); | ||
168 | ld r2, @r3 ; r2: pte data | ||
169 | or3 r2, r2, #2 ; _PAGE_PRESENT(=2) | ||
170 | |||
171 | .fillinsn | ||
172 | 5: | ||
173 | ;; set tlb | ||
174 | ;; input | ||
175 | ;; r0: PFN + ASID | ||
176 | ;; r1: TLB entry address | ||
177 | ;; r2: pte_data | ||
178 | ;; r3: free | ||
179 | st r0, @r1 ; set_tlb_tag(entry++, address); | ||
180 | st r2, @+r1 ; set_tlb_data(entry, pte_data); | ||
181 | |||
182 | .fillinsn | ||
183 | 6: | ||
184 | ld r3, @sp+ | ||
185 | ld r2, @sp+ | ||
186 | ld r1, @sp+ | ||
187 | ld r0, @sp+ | ||
188 | rte | ||
189 | |||
190 | .fillinsn | ||
191 | 3: | ||
192 | ;; error | ||
193 | ;; input | ||
194 | ;; r0: PFN + ASID | ||
195 | ;; r1: TLB entry address | ||
196 | ;; r2, r3: free | ||
197 | ;; output | ||
198 | ;; r0: PFN + ASID | ||
199 | ;; r1: TLB entry address | ||
200 | ;; r2: pte_data | ||
201 | ;; r3: free | ||
202 | #ifdef CONFIG_ISA_DUAL_ISSUE | ||
203 | bra 5b || ldi r2, #2 | ||
204 | #else | ||
205 | ldi r2, #2 ; r2: pte_data = 0 | _PAGE_PRESENT(=2) | ||
206 | bra 5b | ||
207 | #endif | ||
208 | |||
209 | #elif defined (CONFIG_ISA_M32R) | ||
210 | |||
211 | st sp, @-sp | ||
212 | st r0, @-sp | ||
213 | st r1, @-sp | ||
214 | st r2, @-sp | ||
215 | st r3, @-sp | ||
216 | st r4, @-sp | ||
217 | |||
218 | seth r3, #high(MMU_REG_BASE) | ||
219 | ld r0, @(MDEVA_offset,r3) ; r0: address (MDEVA reg.) | ||
220 | mvfc r2, bpc ; r2: bpc | ||
221 | ld r1, @(MESTS_offset,r3) ; r1: status (MESTS reg.) | ||
222 | st r1, @(MESTS_offset,r3) ; clear status (MESTS reg.) | ||
223 | and3 r1, r1, #(MESTS_IT) | ||
224 | beqz r1, 1f ; data TLB miss? | ||
225 | |||
226 | ;; instrucntion TLB miss | ||
227 | mv r0, r2 ; address = bpc; | ||
228 | ; entry = (unsigned long *)ITLB_BASE+tlb_entry_i*2; | ||
229 | seth r3, #shigh(tlb_entry_i_dat) | ||
230 | ld r4, @(low(tlb_entry_i_dat),r3) | ||
231 | sll3 r2, r4, #3 | ||
232 | seth r1, #high(ITLB_BASE) | ||
233 | or3 r1, r1, #low(ITLB_BASE) | ||
234 | add r2, r1 ; r2: entry | ||
235 | addi r4, #1 ; tlb_entry_i++; | ||
236 | and3 r4, r4, #(NR_TLB_ENTRIES-1) | ||
237 | st r4, @(low(tlb_entry_i_dat),r3) | ||
238 | bra 2f | ||
239 | .fillinsn | ||
240 | 1: | ||
241 | ;; data TLB miss | ||
242 | ; entry = (unsigned long *)DTLB_BASE+tlb_entry_d*2; | ||
243 | seth r3, #shigh(tlb_entry_d_dat) | ||
244 | ld r4, @(low(tlb_entry_d_dat),r3) | ||
245 | sll3 r2, r4, #3 | ||
246 | seth r1, #high(DTLB_BASE) | ||
247 | or3 r1, r1, #low(DTLB_BASE) | ||
248 | add r2, r1 ; r2: entry | ||
249 | addi r4, #1 ; tlb_entry_d++; | ||
250 | and3 r4, r4, #(NR_TLB_ENTRIES-1) | ||
251 | st r4, @(low(tlb_entry_d_dat),r3) | ||
252 | .fillinsn | ||
253 | 2: | ||
254 | ;; load pte | ||
255 | ; r0: address, r2: entry | ||
256 | ; r1,r3,r4: (free) | ||
257 | ; pgd = *(unsigned long *)MPTB; | ||
258 | ld24 r1, #(-MPTB-1) | ||
259 | not r1, r1 | ||
260 | ld r1, @r1 | ||
261 | srl3 r4, r0, #22 | ||
262 | sll3 r3, r4, #2 | ||
263 | add r3, r1 ; r3: pgd | ||
264 | ; pmd = pmd_offset(pgd, address); | ||
265 | ld r1, @r3 ; r1: pmd | ||
266 | beqz r1, 3f ; pmd_none(*pmd) ? | ||
267 | ; | ||
268 | and3 r1, r1, #0xeff | ||
269 | ldi r4, #611 ; _KERNPG_TABLE(=611) | ||
270 | beq r1, r4, 4f ; !pmd_bad(*pmd) ? | ||
271 | .fillinsn | ||
272 | 3: | ||
273 | ldi r1, #0 ; r1: pte_data = 0 | ||
274 | bra 5f | ||
275 | .fillinsn | ||
276 | 4: | ||
277 | ; pte = pte_offset(pmd, address); | ||
278 | ld r4, @r3 ; r4: pte | ||
279 | ldi r3, #-4096 | ||
280 | and r4, r3 | ||
281 | srl3 r3, r0, #10 | ||
282 | and3 r3, r3, #0xffc | ||
283 | add r4, r3 | ||
284 | seth r3, #0x8000 | ||
285 | add r4, r3 ; r4: pte | ||
286 | ; pte_data = (unsigned long)pte_val(*pte); | ||
287 | ld r1, @r4 ; r1: pte_data | ||
288 | .fillinsn | ||
289 | |||
290 | ;; set tlb | ||
291 | ; r0: address, r1: pte_data, r2: entry | ||
292 | ; r3,r4: (free) | ||
293 | 5: | ||
294 | ldi r3, #-4096 ; set_tlb_tag(entry++, address); | ||
295 | and r3, r0 | ||
296 | seth r4, #shigh(MASID) | ||
297 | ld r4, @(low(MASID),r4) ; r4: MASID | ||
298 | and3 r4, r4, #(MMU_CONTEXT_ASID_MASK) | ||
299 | or r3, r4 | ||
300 | st r3, @r2 | ||
301 | or3 r4, r1, #2 ; _PAGE_PRESENT(=2) | ||
302 | st r4, @(4,r2) ; set_tlb_data(entry, pte_data); | ||
303 | |||
304 | ld r4, @sp+ | ||
305 | ld r3, @sp+ | ||
306 | ld r2, @sp+ | ||
307 | ld r1, @sp+ | ||
308 | ld r0, @sp+ | ||
309 | ld sp, @sp+ | ||
310 | rte | ||
311 | |||
312 | #else | ||
313 | #error unknown isa configuration | ||
314 | #endif | ||
315 | |||
316 | ENTRY(init_tlb) | ||
317 | ;; Set MMU Register | ||
318 | seth r0, #high(MMU_REG_BASE) ; Set MMU_REG_BASE higher | ||
319 | or3 r0, r0, #low(MMU_REG_BASE) ; Set MMU_REG_BASE lower | ||
320 | ldi r1, #0 | ||
321 | st r1, @(MPSZ_offset,r0) ; Set MPSZ Reg(Page size 4KB:0 16KB:1 64KB:2) | ||
322 | ldi r1, #0 | ||
323 | st r1, @(MASID_offset,r0) ; Set ASID Zero | ||
324 | |||
325 | ;; Set TLB | ||
326 | seth r0, #high(ITLB_BASE) ; Set ITLB_BASE higher | ||
327 | or3 r0, r0, #low(ITLB_BASE) ; Set ITLB_BASE lower | ||
328 | seth r1, #high(DTLB_BASE) ; Set DTLB_BASE higher | ||
329 | or3 r1, r1, #low(DTLB_BASE) ; Set DTLB_BASE lower | ||
330 | ldi r2, #0 | ||
331 | ldi r3, #NR_TLB_ENTRIES | ||
332 | addi r0, #-4 | ||
333 | addi r1, #-4 | ||
334 | clear_tlb: | ||
335 | st r2, @+r0 ; VPA <- 0 | ||
336 | st r2, @+r0 ; PPA <- 0 | ||
337 | st r2, @+r1 ; VPA <- 0 | ||
338 | st r2, @+r1 ; PPA <- 0 | ||
339 | addi r3, #-1 | ||
340 | bnez r3, clear_tlb | ||
341 | ;; | ||
342 | jmp r14 | ||
343 | |||
344 | ENTRY(m32r_itlb_entrys) | ||
345 | ENTRY(m32r_otlb_entrys) | ||
346 | |||
347 | #endif /* CONFIG_MMU */ | ||
348 | |||
349 | .end | ||
350 | |||