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        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