linux/arch/m32r/mm/mmu.S
<<
>>
Prefs
   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