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 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 1745: 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 1856: 186 ld r3, @sp+ 187 ld r2, @sp+ 188 ld r1, @sp+ 189 ld r0, @sp+ 190 rte 191 192 .fillinsn 1933: 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 2421: 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 2552: 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 2754: 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) 2945: 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 3133: 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 321ENTRY(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 339clear_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 349ENTRY(m32r_itlb_entrys) 350ENTRY(m32r_otlb_entrys) 351 352#endif /* CONFIG_MMU */ 353 354 .end 355