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