patch-2.1.44 linux/arch/mips/kernel/r2300_misc.S
Next file: linux/arch/mips/kernel/r2300_scall.S
Previous file: linux/arch/mips/kernel/r2300_fpu.S
Back to the patch index
Back to the overall index
- Lines: 398
- Date:
Thu Jun 26 12:33:37 1997
- Orig file:
v2.1.43/linux/arch/mips/kernel/r2300_misc.S
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.1.43/linux/arch/mips/kernel/r2300_misc.S linux/arch/mips/kernel/r2300_misc.S
@@ -0,0 +1,397 @@
+/* $Id: r2300_misc.S,v 1.1 1997/06/06 09:32:57 ralf Exp $
+ * r2300_misc.S: Misc. exception handling code for R3000/R2000.
+ *
+ * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
+ *
+ * Multi-cpu abstraction reworking:
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ */
+#include <linux/config.h>
+
+#include <asm/asm.h>
+#include <asm/bootinfo.h>
+#include <asm/cachectl.h>
+#include <asm/fpregdef.h>
+#include <asm/mipsconfig.h>
+#include <asm/mipsregs.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+ .text
+ .set mips1
+ .set noreorder
+
+ .align 5
+ NESTED(r2300_handle_tlbl, PT_SIZE, sp)
+ .set noat
+ /* Check whether this is a refill or an invalid exception */
+ mfc0 k0,CP0_BADVADDR
+ mfc0 k1,CP0_ENTRYHI
+ ori k0,0xfff # clear ASID...
+ xori k0,0xfff # in BadVAddr
+ andi k1,0xfc0 # get current ASID
+ or k0,k1 # make new entryhi
+ mfc0 k1,CP0_ENTRYHI
+ mtc0 k0,CP0_ENTRYHI
+ nop # for pipeline
+ nop
+ nop
+ tlbp
+ nop # for pipeline
+ nop
+ mfc0 k0,CP0_INDEX
+
+ bgez k0,invalid_tlbl # bad addr in c0_badvaddr
+ mtc0 k1,CP0_ENTRYHI
+
+ /* Damn... The next nop is required on the R4400PC V5.0, but
+ * I don't know why - at least there is no documented
+ * reason as for the others :-(
+ * And I haven't tested it as being necessary on R3000 - PMA.
+ * (The R3000 pipeline has only 5 stages, so it's probably not
+ * required -- Ralf)
+ */
+ nop
+
+#ifdef CONF_DEBUG_TLB
+ /* OK, this is a double fault. Let's see whether this is
+ * due to an invalid entry in the page_table.
+ */
+ /* used to be dmfc0 */
+ mfc0 k0,CP0_BADVADDR
+ /* FIXME: This srl/sll sequence is as it is for the R4xx0,
+ * and I suspect that it should be different for
+ * the R[23]000. PMA
+ * (No, it's the assembler way to do
+ * k0 = k0 / PAGE_SIZE;
+ * k0 = k0 * sizeof(pte_t)
+ * Acutally the R4xx0 code will have to change when
+ * switching to 64 bit ... -- Ralf)
+ */
+ srl k0,12 # get PFN?
+ sll k0,2
+ lui k1,%HI(TLBMAP)
+ addu k0,k1
+ lw k1,(k0)
+ andi k1,(_PAGE_PRESENT|_PAGE_ACCESSED)
+ bnez k1,reload_pgd_entries
+ nop
+
+ .set noat
+ SAVE_ALL
+ .set at
+ PRINT("Double fault caused by invalid entries in pgd:\n")
+ mfc0 a1,CP0_BADVADDR
+ PRINT("Double fault address : %08lx\n")
+ mfc0 a1,CP0_EPC
+ PRINT("c0_epc : %08lx\n")
+
+ jal show_regs
+ move a0,sp
+
+ jal dump_tlb_nonwired
+ nop
+
+ mfc0 a0,CP0_BADVADDR
+
+ jal dump_list_current
+ nop
+
+ .set noat
+ STI
+ .set at
+ PANIC("Corrupted pagedir")
+ .set noat
+
+reload_pgd_entries:
+#endif /* CONF_DEBUG_TLB */
+
+ /* Load missing pair of entries from the pgd and return. */
+ mfc0 k1,CP0_CONTEXT
+ lw k0,(k1) # Never causes nested exception
+ mfc0 k1,CP0_EPC # get the return PC
+ srl k0,12 # Convert to EntryLo format
+ mtc0 k0,CP0_ENTRYLO0
+ nop # for pipeline
+ tlbwr
+ nop # for pipeline
+ nop
+ nop
+ /* We don't know whether the original access was read or
+ * write, so return and see what happens...
+ */
+ jr k1
+ rfe
+
+ /* Handle invalid exception
+ *
+ * There are two possible causes for an invalid (tlbl)
+ * exception:
+ * 1) pages with present bit set but the valid bit clear
+ * 2) nonexistant pages
+ * Case one needs fast handling, therefore don't save
+ * registers yet.
+ *
+ * k0 contains c0_index.
+ */
+invalid_tlbl:
+#ifdef CONFIG_TLB_SHUTDOWN
+ /* Remove entry so we don't need to care later
+ * For sake of the pipeline the tlbwi insn has been moved down.
+ * Moving it around is juggling with explosives...
+ */
+ /* FIXME: Why is Ralf setting bit 3 of k1? This may need to
+ * be changed for R[236]000! PMA
+ * (The new ENTRYHI value will then point represent a
+ * inique virtual address outside the 32 bit address
+ * limit. This is just paranoia to avoid a tlb
+ * shutdown. This whole part of the routine is probably
+ * no longer required and can be removed -- Ralf)
+ */
+ lui k1,0x0008
+ or k0,k1
+ sll k0,12 # make it EntryHi format
+ mtc0 k0,CP0_ENTRYHI
+ mtc0 zero,CP0_ENTRYLO0
+#endif
+ /* Test present bit in entry */
+ mfc0 k0,CP0_BADVADDR
+ /* FIXME: This srl/sll sequence is as it is for the R4xx0,
+ * and I suspect that it should be different for
+ * the R[23]000. PMA
+ * (No, it's the assembler way to do
+ * k0 = k0 / PAGE_SIZE;
+ * k0 = k0 * sizeof(pte_t)
+ * Acutally the R4xx0 code will have to change when
+ * switching to 64 bit ... -- Ralf)
+ */
+ srl k0,12
+ sll k0,2
+#ifdef CONFIG_TLB_SHUTDOWN
+ tlbwi # do not move!
+#endif
+ lui k1,%HI(TLBMAP)
+ addu k0,k1
+ lw k1,(k0)
+ andi k1,(_PAGE_PRESENT|_PAGE_READ)
+ xori k1,(_PAGE_PRESENT|_PAGE_READ)
+
+ bnez k1,nopage_tlbl
+ lw k1,(k0)
+
+ /* Present and read bits are set -> set valid and accessed bits */
+ ori k1,(_PAGE_VALID|_PAGE_ACCESSED)
+ sw k1,(k0)
+ mfc0 k1,CP0_EPC
+ nop
+
+ jr k1
+ rfe
+
+ /* Page doesn't exist. Lots of work which is less important
+ * for speed needs to be done, so hand it all over to the
+ * kernel memory management routines.
+ */
+nopage_tlbl:
+ SAVE_ALL
+ mfc0 a2,CP0_BADVADDR
+ STI
+ .set at
+ /* a0 (struct pt_regs *) regs
+ * a1 (unsigned long) 0 for read access
+ * a2 (unsigned long) faulting virtual address
+ */
+ move a0,sp
+ jal do_page_fault
+ li a1,0
+
+ j ret_from_sys_call
+ nop
+ END(r2300_handle_tlbl)
+
+
+ .text
+ .align 5
+ NESTED(r2300_handle_tlbs, PT_SIZE, sp)
+ .set noat
+ /* It is impossible that is a nested reload exception.
+ * Therefore this must be a invalid exception.
+ * Two possible cases:
+ * 1) Page exists but not dirty.
+ * 2) Page doesn't exist yet. Hand over to the kernel.
+ *
+ * Test whether present bit in entry is set
+ */
+ /* used to be dmfc0 */
+ mfc0 k0,CP0_BADVADDR
+ /* FIXME: This srl/sll sequence is as it is for the R4xx0,
+ * and I suspect that it should be different for
+ * the R[23]000. PMA
+ */
+ srl k0,12
+ sll k0,2
+ lui k1,%HI(TLBMAP)
+ addu k0,k1
+ lw k1,(k0)
+ tlbp # find faulting entry
+ andi k1,(_PAGE_PRESENT|_PAGE_WRITE)
+ xori k1,(_PAGE_PRESENT|_PAGE_WRITE)
+
+ bnez k1,nopage_tlbs
+ lw k1,(k0)
+
+ /* Present and writable bits set: set accessed and dirty bits. */
+ ori k1,k1,(_PAGE_ACCESSED|_PAGE_MODIFIED| \
+ _PAGE_VALID|_PAGE_DIRTY)
+ sw k1,(k0)
+ /* Now reload the entry into the TLB */
+ /* FIXME: Why has Ralf set bit 2? Should it be different for
+ * R[23]000? PMA
+ * (The ori/xori combination actually _clears_ bit 2.
+ * This is required for the R4xx0 these CPUs always
+ * map page pairs; a page pair of 4k pages therfore
+ * has always an address with bit 2 set to zero. -- Ralf)
+ */
+ ori k0,0x0004
+ xori k0,0x0004
+ lw k0,(k0)
+ srl k0,12
+ mtc0 k0,CP0_ENTRYLO0
+ mfc0 k1,CP0_EPC
+ nop # for pipeline
+ tlbwi
+ nop # for pipeline
+ nop
+ nop
+
+ jr k1
+ rfe
+
+ /* Page doesn't exist. Lots of work which is less important
+ * for speed needs to be done, so hand it all over to the
+ * kernel memory management routines.
+ */
+nopage_tlbs:
+nowrite_mod:
+#ifdef CONFIG_TLB_SHUTDOWN
+ /* Remove entry so we don't need to care later */
+ mfc0 k0,CP0_INDEX
+#ifdef CONF_DEBUG_TLB
+ bgez k0,2f
+ nop
+ /* We got a tlbs exception but found no matching entry in
+ * the tlb. This should never happen. Paranoia makes us
+ * check it, though.
+ */
+ SAVE_ALL
+ jal show_regs
+ move a0,sp
+ .set at
+ mfc0 a1,CP0_BADVADDR
+ PRINT("c0_badvaddr == %08lx\n")
+ mfc0 a1,CP0_INDEX
+ PRINT("c0_index == %08x\n")
+ mfc0 a1,CP0_ENTRYHI
+ PRINT("c0_entryhi == %08x\n")
+ .set noat
+ STI
+ .set at
+ PANIC("Tlbs or tlbm exception with no matching entry in tlb")
+1:
+ j 1b
+ nop
+2:
+#endif /* CONF_DEBUG_TLB */
+ /* FIXME: Why is Ralf setting bit 3 of k1? This may need to
+ * be changed for R[236]000! PMA
+ * (The new ENTRYHI value will then point represent a
+ * inique virtual address outside the 32 bit address
+ * limit. This is just paranoia to avoid a tlb
+ * shutdown. This whole part of the routine is probably
+ * no longer required and can be removed -- Ralf)
+ */
+ lui k1,0x0008
+ or k0,k1
+ sll k0,12
+ mtc0 k0,CP0_ENTRYHI
+ mtc0 zero,CP0_ENTRYLO0
+ nop # for pipeline
+ nop # R4000 V2.2 requires 4 NOPs
+ nop
+ nop
+ tlbwi
+#endif /* CONFIG_TLB_SHUTDOWN */
+ .set noat
+ SAVE_ALL
+ mfc0 a2,CP0_BADVADDR
+ STI
+ .set at
+ /* a0 (struct pt_regs *) regs
+ * a1 (unsigned long) 1 for write access
+ * a2 (unsigned long) faulting virtual address
+ */
+ move a0,sp
+ jal do_page_fault
+ li a1,1
+
+ j ret_from_sys_call
+ nop
+ END(r2300_handle_tlbs)
+
+
+ .align 5
+ NESTED(r2300_handle_mod, PT_SIZE, sp)
+ .set noat
+ /* Two possible cases:
+ * 1) Page is writable but not dirty -> set dirty and return
+ * 2) Page is not writable -> call C handler
+ */
+ /* used to be dmfc0 */
+ mfc0 k0,CP0_BADVADDR
+ /* FIXME: This srl/sll sequence is as it is for the R4xx0,
+ * and I suspect that it should be different for
+ * the R[23]000. PMA
+ */
+ srl k0,12
+ sll k0,2
+ lui k1,%HI(TLBMAP)
+ addu k0,k1
+ lw k1,(k0)
+ tlbp # find faulting entry
+ andi k1,_PAGE_WRITE
+
+ beqz k1,nowrite_mod
+ lw k1,(k0)
+
+ /* Present and writable bits set: set accessed and dirty bits. */
+ ori k1,(_PAGE_ACCESSED|_PAGE_DIRTY)
+ sw k1,(k0)
+ /* Now reload the entry into the tlb */
+ /* FIXME: Why has Ralf set bit 2? Should it be different for
+ * R[23]000? PMA
+ * (The ori/xori combination actually _clears_ bit 2.
+ * This is required for the R4xx0 these CPUs always
+ * map page pairs; a page pair of 4k pages therfore
+ * has always an address with bit 2 set to zero. -- Ralf)
+ */
+ ori k0,0x0004
+ xori k0,0x0004
+ lw k0,(k0)
+ srl k0,12
+ mtc0 k0,CP0_ENTRYLO0
+ mfc0 k1,CP0_EPC
+ nop # for pipeline
+ nop
+ nop
+ tlbwi
+ nop # for pipeline
+ nop
+ nop
+
+ jr k1
+ rfe
+ END(r2300_handle_mod)
+ .set at
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov