diff options
author | Ulf Carlsson <md1ulfc@mdstud.chalmers.se> | 2000-05-25 19:33:16 +0000 |
---|---|---|
committer | Ulf Carlsson <md1ulfc@mdstud.chalmers.se> | 2000-05-25 19:33:16 +0000 |
commit | e3f4987b05b99df724313e4906971e0c2392e9d5 (patch) | |
tree | 045335cf3c152e6d43e590662217c2cdb4bf0a74 /arch | |
parent | 243287e7620e395edf940f61c5dcc6fa606a150f (diff) |
First cut of TLB handlers in assembler. I'm not using
the context register as it should be used, but let's look
into that later.
If there is a problem with the code it will crash after
right after freeing unused kernel memery. I have this code
tested on both UP and SMP though.
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips64/kernel/r4k_tlb.S | 217 | ||||
-rw-r--r-- | arch/mips64/kernel/traps.c | 20 |
2 files changed, 227 insertions, 10 deletions
diff --git a/arch/mips64/kernel/r4k_tlb.S b/arch/mips64/kernel/r4k_tlb.S new file mode 100644 index 000000000..a8ea18523 --- /dev/null +++ b/arch/mips64/kernel/r4k_tlb.S @@ -0,0 +1,217 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000 Silicon Graphics, Inc. + * Written by Ulf Carlsson (ulfc@engr.sgi.com) + */ +#include <linux/threads.h> +#include <asm/asm.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> +#include <asm/pgtable.h> +#include <asm/stackframe.h> + + .data + .comm pgd_current, NR_CPUS * 8, 8 + + /* + * After this macro runs we have a pointer to the pte of the address + * that caused the fault in in PTR. + */ + .macro LOAD_PTE, ptr, tmp +#ifdef CONFIG_SMP + mfc0 \tmp, CP0_CONTEXT + dla \ptr, pgd_current + dsrl \tmp, 23 + daddu \ptr, \tmp +#else + dla \ptr, pgd_current +#endif + dmfc0 \tmp, CP0_BADVADDR + ld \ptr, (\ptr) + dsrl \tmp, 28 # get pgd offset + andi \tmp, 0x1ff8 + daddu \ptr, \tmp # add in pgd offset + dmfc0 \tmp, CP0_BADVADDR + ld \ptr, (\ptr) # get pmd pointer + dsrl \tmp, 18 # get pmd offset + andi \tmp, 0x1ff8 + daddu \ptr, \tmp # add in pmd offset + dmfc0 \tmp, CP0_BADVADDR + ld \ptr, (\ptr) # get pte pointer + dsrl \tmp, 9 + andi \tmp, 0xff8 # get pte offset + daddu \ptr, \tmp + .endm + + .macro LOAD_PTE2, ptr, tmp +#ifdef CONFIG_SMP + mfc0 \tmp, CP0_CONTEXT + dla \ptr, pgd_current + dsrl \tmp, 23 + daddu \ptr, \tmp +#else + dla \ptr, pgd_current +#endif + dmfc0 \tmp, CP0_BADVADDR + ld \ptr, (\ptr) + dsrl \tmp, 28 # get pgd offset + andi \tmp, 0x1ff8 + daddu \ptr, \tmp # add in pgd offset + dmfc0 \tmp, CP0_BADVADDR + ld \ptr, (\ptr) # get pmd pointer + dsrl \tmp, 18 # get pmd offset + andi \tmp, 0x1ff8 + daddu \ptr, \tmp # add in pmd offset + dmfc0 \tmp, CP0_XCONTEXT + ld \ptr, (\ptr) # get pte pointer + andi \tmp, 0xff0 # get pte offset + daddu \ptr, \tmp + .endm + + /* + * This places the even/odd pte pair in the page table at the pte + * entry pointed to by PTE into ENTRYLO0 and ENTRYLO1. + */ + .macro PTE_RELOAD, pte0, pte1 + dsrl \pte0, 6 # convert to entrylo0 + dmtc0 \pte0, CP0_ENTRYLO0 # load it + dsrl \pte1, 6 # convert to entrylo1 + dmtc0 \pte1, CP0_ENTRYLO1 # load it + .endm + + .macro DO_FAULT, write + SAVE_ALL + dmfc0 a2, CP0_BADVADDR + STI + .set at + move a0, sp + jal do_page_fault + li a1, \write + j ret_from_sys_call + nop + .set noat + .endm + + /* Check if PTE is present, if not jump to LABEL. */ + .macro PTE_PRESENT, pte, ptr, label + andi \pte, (_PAGE_PRESENT | _PAGE_READ) + xori \pte, (_PAGE_PRESENT | _PAGE_READ) + bnez \pte, \label + nop + ld \pte, (\ptr) + .endm + + /* Mark PTE as valid, and save in PTR. */ + .macro PTE_MAKEVALID, pte, ptr + ori \pte, (_PAGE_VALID | _PAGE_ACCESSED) + sd \pte, (\ptr) + .endm + + /* Check if PTE is writable, if not jump to LABEL. */ + .macro PTE_WRITEABLE, pte, ptr, label + andi \pte, (_PAGE_PRESENT | _PAGE_WRITE) + xori \pte, (_PAGE_PRESENT | _PAGE_WRITE) + bnez \pte, \label + nop + ld \pte, (\ptr) + .endm + + /* Mark PTE as writable, and save in PTR. */ + .macro PTE_MAKEWRITE, pte, ptr + ori \pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | \ + _PAGE_DIRTY) + sd \pte, (\ptr) + .endm + + .text + .set noreorder + .set mips3 + + .align 5 +FEXPORT(except_vec0) + .set noat +1: b 1b + nop + + /* TLB refill handler for the R10000. + * Attention: We may only use 32 instructions. + */ + + .align 5 +FEXPORT(except_vec1_r10k) + .set noat + LOAD_PTE2 k1 k0 + ld k0, 0(k1) # get even pte + ld k1, 8(k1) # get odd pte + PTE_RELOAD k0 k1 + nop + tlbwr + eret + + .align 5 +FEXPORT(handle_tlbl) + .set noat + LOAD_PTE k1 k0 + nop + tlbp + ld k0, 0(k1) + PTE_PRESENT k0 k1 nopage_tlbl + PTE_MAKEVALID k0 k1 + ori k1, 0xf + xori k1, 0xf + ld k0, 0(k1) + ld k1, 8(k1) + PTE_RELOAD k0 k1 + nop + tlbwi + nop + eret + +nopage_tlbl: + DO_FAULT 0 + + .align 5 +FEXPORT(handle_tlbs) + .set noat + LOAD_PTE k1 k0 + nop + tlbp + ld k0, 0(k1) + PTE_WRITEABLE k0 k1 nopage_tlbs + PTE_MAKEWRITE k0 k1 + ori k1, 0xf + xori k1, 0xf + ld k0, 0(k1) + ld k1, 8(k1) + PTE_RELOAD k0 k1 + nop + tlbwi + eret + +nopage_tlbs: + DO_FAULT 1 + + .align 5 +FEXPORT(handle_mod) + .set noat + LOAD_PTE k1 k0 + nop + tlbp + ld k0, 0(k1) + PTE_WRITEABLE k0 k1 nowrite_mod + PTE_MAKEWRITE k0 k1 + ori k1, 0xf + xori k1, 0xf + ld k0, 0(k1) + ld k1, 8(k1) + PTE_RELOAD k0 k1 + nop + tlbwi + eret + +nowrite_mod: + DO_FAULT 1 diff --git a/arch/mips64/kernel/traps.c b/arch/mips64/kernel/traps.c index fa58017cf..d9213757f 100644 --- a/arch/mips64/kernel/traps.c +++ b/arch/mips64/kernel/traps.c @@ -41,9 +41,9 @@ static inline void console_verbose(void) console_loglevel = 15; } -extern asmlinkage void __xtlb_mod_debug(void); -extern asmlinkage void __xtlb_tlbl_debug(void); -extern asmlinkage void __xtlb_tlbs_debug(void); +extern asmlinkage void handle_mod(void); +extern asmlinkage void handle_tlbl(void); +extern asmlinkage void handle_tlbs(void); extern asmlinkage void handle_adel(void); extern asmlinkage void handle_ades(void); extern asmlinkage void handle_ibe(void); @@ -471,8 +471,8 @@ static inline void go_64(void) void __init trap_init(void) { - extern char __tlb_refill_debug_tramp; - extern char __xtlb_refill_debug_tramp; + extern char except_vec0; + extern char except_vec1_r10k; extern char except_vec2_generic; extern char except_vec3_generic, except_vec3_r4000; extern void bus_error_init(void); @@ -528,8 +528,8 @@ void __init trap_init(void) case CPU_NEVADA: r4k: /* Debug TLB refill handler. */ - memcpy((void *)KSEG0, &__tlb_refill_debug_tramp, 0x80); - memcpy((void *)KSEG0 + 0x080, &__xtlb_refill_debug_tramp, 0x80); + memcpy((void *)KSEG0, &except_vec0, 0x80); + memcpy((void *)KSEG0 + 0x080, &except_vec1_r10k, 0x80); /* Cache error vector */ memcpy((void *)(KSEG0 + 0x100), (void *) KSEG0, 0x80); @@ -542,9 +542,9 @@ r4k: 0x100); } - set_except_vector(1, __xtlb_mod_debug); - set_except_vector(2, __xtlb_tlbl_debug); - set_except_vector(3, __xtlb_tlbs_debug); + set_except_vector(1, handle_mod); + set_except_vector(2, handle_tlbl); + set_except_vector(3, handle_tlbs); set_except_vector(4, handle_adel); set_except_vector(5, handle_ades); |