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