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