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 23ENTRY(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 701: 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 1012: 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 ldi r2, #-4096 154 beqz r3, 3f ; pmd_none(*pmd) ? 155 156 ; pte = pte_offset(pmd, address); 157 and r2, r3 ; r2: pte base addr 158 srl3 r3, r0, #10 159 and3 r3, r3, #0xffc ; r3: pte offset 160 or r3, r2 161 seth r2, #0x8000 162 or r3, r2 ; r3: pte addr 163 164 ; pte_data = (unsigned long)pte_val(*pte); 165 ld r2, @r3 ; r2: pte data 166 and3 r3, r2, #2 ; _PAGE_PRESENT(=2) check 167 beqz r3, 3f 168 169 .fillinsn 1705: 171;; set tlb 172;; input 173;; r0: PFN + ASID 174;; r1: TLB entry address 175;; r2: pte_data 176;; r3: free 177 st r0, @r1 ; set_tlb_tag(entry++, address); 178 st r2, @+r1 ; set_tlb_data(entry, pte_data); 179 180 .fillinsn 1816: 182 ld r3, @sp+ 183 ld r2, @sp+ 184 ld r1, @sp+ 185 ld r0, @sp+ 186 rte 187 188 .fillinsn 1893: 190;; error 191;; input 192;; r0: PFN + ASID 193;; r1: TLB entry address 194;; r2, r3: free 195;; output 196;; r0: PFN + ASID 197;; r1: TLB entry address 198;; r2: pte_data 199;; r3: free 200#ifdef CONFIG_ISA_DUAL_ISSUE 201 bra 5b || ldi r2, #2 202#else 203 ldi r2, #2 ; r2: pte_data = 0 | _PAGE_PRESENT(=2) 204 bra 5b 205#endif 206 207#elif defined (CONFIG_ISA_M32R) 208 209 st sp, @-sp 210 st r0, @-sp 211 st r1, @-sp 212 st r2, @-sp 213 st r3, @-sp 214 st r4, @-sp 215 216 seth r3, #high(MMU_REG_BASE) 217 ld r0, @(MDEVA_offset,r3) ; r0: address (MDEVA reg.) 218 mvfc r2, bpc ; r2: bpc 219 ld r1, @(MESTS_offset,r3) ; r1: status (MESTS reg.) 220 st r1, @(MESTS_offset,r3) ; clear status (MESTS reg.) 221 and3 r1, r1, #(MESTS_IT) 222 beqz r1, 1f ; data TLB miss? 223 224;; instrucntion TLB miss 225 mv r0, r2 ; address = bpc; 226 ; entry = (unsigned long *)ITLB_BASE+tlb_entry_i*2; 227 seth r3, #shigh(tlb_entry_i_dat) 228 ld r4, @(low(tlb_entry_i_dat),r3) 229 sll3 r2, r4, #3 230 seth r1, #high(ITLB_BASE) 231 or3 r1, r1, #low(ITLB_BASE) 232 add r2, r1 ; r2: entry 233 addi r4, #1 ; tlb_entry_i++; 234 and3 r4, r4, #(NR_TLB_ENTRIES-1) 235 st r4, @(low(tlb_entry_i_dat),r3) 236 bra 2f 237 .fillinsn 2381: 239;; data TLB miss 240 ; entry = (unsigned long *)DTLB_BASE+tlb_entry_d*2; 241 seth r3, #shigh(tlb_entry_d_dat) 242 ld r4, @(low(tlb_entry_d_dat),r3) 243 sll3 r2, r4, #3 244 seth r1, #high(DTLB_BASE) 245 or3 r1, r1, #low(DTLB_BASE) 246 add r2, r1 ; r2: entry 247 addi r4, #1 ; tlb_entry_d++; 248 and3 r4, r4, #(NR_TLB_ENTRIES-1) 249 st r4, @(low(tlb_entry_d_dat),r3) 250 .fillinsn 2512: 252;; load pte 253; r0: address, r2: entry 254; r1,r3,r4: (free) 255 ; pgd = *(unsigned long *)MPTB; 256 ld24 r1, #(-MPTB-1) 257 not r1, r1 258 ld r1, @r1 259 srl3 r4, r0, #22 260 sll3 r3, r4, #2 261 add r3, r1 ; r3: pgd 262 ; pmd = pmd_offset(pgd, address); 263 ld r1, @r3 ; r1: pmd 264 beqz r1, 3f ; pmd_none(*pmd) ? 265; 266 and3 r1, r1, #0xeff 267 ldi r4, #611 ; _KERNPG_TABLE(=611) 268 bne r1, r4, 3f ; !pmd_bad(*pmd) ? 269 270 .fillinsn 2714: 272 ; pte = pte_offset(pmd, address); 273 ld r4, @r3 ; r4: pte 274 ldi r3, #-4096 275 and r4, r3 276 srl3 r3, r0, #10 277 and3 r3, r3, #0xffc 278 add r4, r3 279 seth r3, #0x8000 280 add r4, r3 ; r4: pte 281 ; pte_data = (unsigned long)pte_val(*pte); 282 ld r1, @r4 ; r1: pte_data 283 and3 r3, r1, #2 ; _PAGE_PRESENT(=2) check 284 beqz r3, 3f 285 286 .fillinsn 287;; set tlb 288; r0: address, r1: pte_data, r2: entry 289; r3,r4: (free) 2905: 291 ldi r3, #-4096 ; set_tlb_tag(entry++, address); 292 and r3, r0 293 seth r4, #shigh(MASID) 294 ld r4, @(low(MASID),r4) ; r4: MASID 295 and3 r4, r4, #(MMU_CONTEXT_ASID_MASK) 296 or r3, r4 297 st r3, @r2 298 st r1, @(4,r2) ; set_tlb_data(entry, pte_data); 299 300 ld r4, @sp+ 301 ld r3, @sp+ 302 ld r2, @sp+ 303 ld r1, @sp+ 304 ld r0, @sp+ 305 ld sp, @sp+ 306 rte 307 308 .fillinsn 3093: 310 ldi r1, #2 ; r1: pte_data = 0 | _PAGE_PRESENT(=2) 311 bra 5b 312 313#else 314#error unknown isa configuration 315#endif 316 317ENTRY(init_tlb) 318;; Set MMU Register 319 seth r0, #high(MMU_REG_BASE) ; Set MMU_REG_BASE higher 320 or3 r0, r0, #low(MMU_REG_BASE) ; Set MMU_REG_BASE lower 321 ldi r1, #0 322 st r1, @(MPSZ_offset,r0) ; Set MPSZ Reg(Page size 4KB:0 16KB:1 64KB:2) 323 ldi r1, #0 324 st r1, @(MASID_offset,r0) ; Set ASID Zero 325 326;; Set TLB 327 seth r0, #high(ITLB_BASE) ; Set ITLB_BASE higher 328 or3 r0, r0, #low(ITLB_BASE) ; Set ITLB_BASE lower 329 seth r1, #high(DTLB_BASE) ; Set DTLB_BASE higher 330 or3 r1, r1, #low(DTLB_BASE) ; Set DTLB_BASE lower 331 ldi r2, #0 332 ldi r3, #NR_TLB_ENTRIES 333 addi r0, #-4 334 addi r1, #-4 335clear_tlb: 336 st r2, @+r0 ; VPA <- 0 337 st r2, @+r0 ; PPA <- 0 338 st r2, @+r1 ; VPA <- 0 339 st r2, @+r1 ; PPA <- 0 340 addi r3, #-1 341 bnez r3, clear_tlb 342;; 343 jmp r14 344 345ENTRY(m32r_itlb_entrys) 346ENTRY(m32r_otlb_entrys) 347 348#endif /* CONFIG_MMU */ 349 350 .end 351