mirror of https://gitee.com/openkylin/linux.git
200 lines
4.0 KiB
ArmAsm
200 lines
4.0 KiB
ArmAsm
|
/*
|
||
|
* arch/score/mm/tlbex.S
|
||
|
*
|
||
|
* Score Processor version.
|
||
|
*
|
||
|
* Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
|
||
|
* Lennox Wu <lennox.wu@sunplusct.com>
|
||
|
* Chen Liqin <liqin.chen@sunplusct.com>
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, see the file COPYING, or write
|
||
|
* to the Free Software Foundation, Inc.,
|
||
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
*/
|
||
|
|
||
|
#include <asm/asmmacro.h>
|
||
|
#include <asm/pgtable-bits.h>
|
||
|
#include <asm/scoreregs.h>
|
||
|
|
||
|
/*
|
||
|
* After this macro runs, the pte faulted on is
|
||
|
* in register PTE, a ptr into the table in which
|
||
|
* the pte belongs is in PTR.
|
||
|
*/
|
||
|
.macro load_pte, pte, ptr
|
||
|
la \ptr, pgd_current
|
||
|
lw \ptr, [\ptr, 0]
|
||
|
mfcr \pte, cr6
|
||
|
srli \pte, \pte, 22
|
||
|
slli \pte, \pte, 2
|
||
|
add \ptr, \ptr, \pte
|
||
|
lw \ptr, [\ptr, 0]
|
||
|
mfcr \pte, cr6
|
||
|
srli \pte, \pte, 10
|
||
|
andi \pte, 0xffc
|
||
|
add \ptr, \ptr, \pte
|
||
|
lw \pte, [\ptr, 0]
|
||
|
.endm
|
||
|
|
||
|
.macro pte_reload, ptr
|
||
|
lw \ptr, [\ptr, 0]
|
||
|
mtcr \ptr, cr12
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
.endm
|
||
|
|
||
|
.macro do_fault, write
|
||
|
SAVE_ALL
|
||
|
mfcr r6, cr6
|
||
|
mv r4, r0
|
||
|
ldi r5, \write
|
||
|
la r8, do_page_fault
|
||
|
brl r8
|
||
|
j ret_from_exception
|
||
|
.endm
|
||
|
|
||
|
.macro pte_writable, pte, ptr, label
|
||
|
andi \pte, 0x280
|
||
|
cmpi.c \pte, 0x280
|
||
|
bne \label
|
||
|
lw \pte, [\ptr, 0] /*reload PTE*/
|
||
|
.endm
|
||
|
|
||
|
/*
|
||
|
* Make PTE writable, update software status bits as well,
|
||
|
* then store at PTR.
|
||
|
*/
|
||
|
.macro pte_makewrite, pte, ptr
|
||
|
ori \pte, 0x426
|
||
|
sw \pte, [\ptr, 0]
|
||
|
.endm
|
||
|
|
||
|
.text
|
||
|
ENTRY(score7_FTLB_refill_Handler)
|
||
|
la r31, pgd_current /* get pgd pointer */
|
||
|
lw r31, [r31, 0] /* get the address of PGD */
|
||
|
mfcr r30, cr6
|
||
|
srli r30, r30, 22 /* PGDIR_SHIFT = 22*/
|
||
|
slli r30, r30, 2
|
||
|
add r31, r31, r30
|
||
|
lw r31, [r31, 0] /* get the address of the start address of PTE table */
|
||
|
|
||
|
mfcr r30, cr9
|
||
|
andi r30, 0xfff /* equivalent to get PET index and right shift 2 bits */
|
||
|
add r31, r31, r30
|
||
|
lw r30, [r31, 0] /* load pte entry */
|
||
|
mtcr r30, cr12
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
mtrtlb
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
rte /* 6 cycles to make sure tlb entry works */
|
||
|
|
||
|
ENTRY(score7_KSEG_refill_Handler)
|
||
|
la r31, pgd_current /* get pgd pointer */
|
||
|
lw r31, [r31, 0] /* get the address of PGD */
|
||
|
mfcr r30, cr6
|
||
|
srli r30, r30, 22 /* PGDIR_SHIFT = 22 */
|
||
|
slli r30, r30, 2
|
||
|
add r31, r31, r30
|
||
|
lw r31, [r31, 0] /* get the address of the start address of PTE table */
|
||
|
|
||
|
mfcr r30, cr6 /* get Bad VPN */
|
||
|
srli r30, r30, 10
|
||
|
andi r30, 0xffc /* PTE VPN mask (bit 11~2) */
|
||
|
|
||
|
add r31, r31, r30
|
||
|
lw r30, [r31, 0] /* load pte entry */
|
||
|
mtcr r30, cr12
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
mtrtlb
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
rte /* 6 cycles to make sure tlb entry works */
|
||
|
|
||
|
nopage_tlbl:
|
||
|
do_fault 0 /* Read */
|
||
|
|
||
|
ENTRY(handle_tlb_refill)
|
||
|
load_pte r30, r31
|
||
|
pte_writable r30, r31, handle_tlb_refill_nopage
|
||
|
pte_makewrite r30, r31 /* Access|Modify|Dirty|Valid */
|
||
|
pte_reload r31
|
||
|
mtrtlb
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
rte
|
||
|
handle_tlb_refill_nopage:
|
||
|
do_fault 0 /* Read */
|
||
|
|
||
|
ENTRY(handle_tlb_invaild)
|
||
|
load_pte r30, r31
|
||
|
stlb /* find faulting entry */
|
||
|
pte_writable r30, r31, handle_tlb_invaild_nopage
|
||
|
pte_makewrite r30, r31 /* Access|Modify|Dirty|Valid */
|
||
|
pte_reload r31
|
||
|
mtptlb
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
rte
|
||
|
handle_tlb_invaild_nopage:
|
||
|
do_fault 0 /* Read */
|
||
|
|
||
|
ENTRY(handle_mod)
|
||
|
load_pte r30, r31
|
||
|
stlb /* find faulting entry */
|
||
|
andi r30, _PAGE_WRITE /* Writable? */
|
||
|
cmpz.c r30
|
||
|
beq nowrite_mod
|
||
|
lw r30, [r31, 0] /* reload into r30 */
|
||
|
|
||
|
/* Present and writable bits set, set accessed and dirty bits. */
|
||
|
pte_makewrite r30, r31
|
||
|
|
||
|
/* Now reload the entry into the tlb. */
|
||
|
pte_reload r31
|
||
|
mtptlb
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
rte
|
||
|
|
||
|
nowrite_mod:
|
||
|
do_fault 1 /* Write */
|