patch-2.3.9 linux/arch/mips/kernel/r2300_misc.S

Next file: linux/arch/mips/kernel/r2300_switch.S
Previous file: linux/arch/mips/kernel/r2300_fpu.S
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/r2300_misc.S linux/arch/mips/kernel/r2300_misc.S
@@ -1,14 +1,17 @@
-/* $Id: r2300_misc.S,v 1.1.1.1 1997/06/01 03:16:42 ralf Exp $
+/* $Id: r2300_misc.S,v 1.3 1999/05/01 22:40:36 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:
+ * Multi-CPU abstraction reworking:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * Further modifications to make this work:
+ * Copyright (c) 1998 Harald Koerfgen
+ * Copyright (c) 1998 Gleb Raiko & Vladimir Roganov
  */
-#include <linux/config.h>
-
 #include <asm/asm.h>
+#include <asm/current.h>
 #include <asm/bootinfo.h>
 #include <asm/cachectl.h>
 #include <asm/fpregdef.h>
@@ -18,380 +21,175 @@
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/regdef.h>
+#include <asm/segment.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
+#undef NOTLB_OPTIMIZE /* If you are paranoid, define this. */
 
-	jal	dump_tlb_nonwired
-	 nop
+	/* ABUSE of CPP macros 101. */
 
-	mfc0	a0,CP0_BADVADDR
+	/* 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.
+	 */
+#define LOAD_PTE(pte, ptr) \
+	mfc0	pte, CP0_BADVADDR; \
+	_GET_CURRENT(ptr); \
+	srl	pte, pte, 22; \
+	lw	ptr, THREAD_PGDIR(ptr); \
+	sll	pte, pte, 2; \
+	addu	ptr, pte, ptr; \
+	mfc0	pte, CP0_CONTEXT; \
+	lw	ptr, (ptr); \
+	andi	pte, pte, 0xffc; \
+	addu	ptr, ptr, pte; \
+	lw	pte, (ptr); \
+	nop;
+
+	/* This places the even/odd pte pair in the page
+	 * table at PTR into ENTRYLO0 and ENTRYLO1 using
+	 * TMP as a scratch register.
+	 */
+#define PTE_RELOAD(ptr) \
+	lw	ptr, (ptr)	; \
+	nop			; \
+	mtc0	ptr, CP0_ENTRYLO0; \
+	nop;
+
+#define DO_FAULT(write) \
+	.set	noat; \
+	.set	macro; \
+	SAVE_ALL; \
+	mfc0	a2, CP0_BADVADDR; \
+	STI; \
+	.set	at; \
+	move	a0, sp; \
+	jal	do_page_fault; \
+	 li	a1, write; \
+	j	ret_from_sys_call; \
+	 nop; \
+	.set	noat; \
+	.set	nomacro;
+
+	/* Check is PTE is present, if not then jump to LABEL.
+	 * PTR points to the page table where this PTE is located,
+	 * when the macro is done executing PTE will be restored
+	 * with it's original value.
+	 */
+#define PTE_PRESENT(pte, ptr, label) \
+	andi	pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
+	xori	pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
+	bnez	pte, label; \
+	.set	push;       \
+	.set	reorder;    \
+	 lw	pte, (ptr); \
+	.set	pop; 
+
+	/* Make PTE valid, store result in PTR. */
+#define PTE_MAKEVALID(pte, ptr) \
+	ori	pte, pte, (_PAGE_VALID | _PAGE_ACCESSED); \
+	sw	pte, (ptr);
+
+	/* Check if PTE can be written to, if not branch to LABEL.
+	 * Regardless restore PTE with value from PTR when done.
+	 */
+#define PTE_WRITABLE(pte, ptr, label) \
+	andi	pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
+	xori	pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
+	bnez	pte, label; \
+	.set    push;       \
+	.set    reorder;    \
+	lw      pte, (ptr); \
+	.set    pop;
+ 
+
+	/* Make PTE writable, update software status bits as well,
+	 * then store at PTR.
+	 */
+#define PTE_MAKEWRITE(pte, ptr) \
+	ori	pte, pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | \
+			   _PAGE_VALID | _PAGE_DIRTY); \
+	sw	pte, (ptr);
 
-	jal	dump_list_current
-	 nop
+	.set	noreorder
 
+	.align	5
+NESTED(r2300_handle_tlbl, PT_SIZE, sp)
 	.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
+#ifndef NOTLB_OPTIMIZE
+	/* Test present bit in entry. */
+	LOAD_PTE(k0, k1)
+        tlbp
 	nop
+        PTE_PRESENT(k0, k1, nopage_tlbl)
+        PTE_MAKEVALID(k0, k1)
+        PTE_RELOAD(k1)
+	tlbwi
 	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
+	mfc0	k0, CP0_EPC
 	nop
-
-	jr	k1
+	jr	k0
 	 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)
+#endif
 
+	DO_FAULT(0)
+END(r2300_handle_tlbl)
 
-	.text
-	.align	5
-	NESTED(r2300_handle_tlbs, PT_SIZE, sp)
+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
+#ifndef NOTLB_OPTIMIZE
+	LOAD_PTE(k0, k1)
+	tlbp                            # find faulting entry
+	nop
+	PTE_WRITABLE(k0, k1, nopage_tlbs)
+	PTE_MAKEWRITE(k0, k1)
+	PTE_RELOAD(k1)
 	tlbwi
-	nop				# for pipeline
 	nop
+	mfc0	k0, CP0_EPC
 	nop
-
-	jr	k1
+	jr	k0
 	 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)
+#endif
 
+	DO_FAULT(1)
+END(r2300_handle_tlbs)
 
 	.align	5
-	NESTED(r2300_handle_mod, PT_SIZE, sp)
+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)
+#ifndef NOTLB_OPTIMIZE
+	LOAD_PTE(k0, k1)
 	tlbp					# find faulting entry
-	andi	k1,_PAGE_WRITE
+	andi	k0, k0, _PAGE_WRITE
+	beqz	k0, nowrite_mod
+	.set	push
+	.set    reorder
+	lw	k0, (k1)
+	.set    pop
 
-	beqz	k1,nowrite_mod
-	 lw	k1,(k0)
+	/* Present and writable bits set, set accessed and dirty bits. */
+	PTE_MAKEWRITE(k0, k1)
 
-	/* 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
+	/* Now reload the entry into the tlb. */
+	PTE_RELOAD(k1)
 	nop
 	tlbwi
-	nop				# for pipeline
 	nop
+	mfc0	k0, CP0_EPC
 	nop
-
-	jr	k1
+	jr	k0
 	 rfe
-	END(r2300_handle_mod)
-	.set	at
+#endif
+
+nowrite_mod:
+	DO_FAULT(1)
+END(r2300_handle_mod)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)