patch-1.3.48 linux/arch/mips/kernel/entry.S

Next file: linux/arch/mips/kernel/gdb-low.S
Previous file: linux/arch/mips/kernel/cache.S
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.47/linux/arch/mips/kernel/entry.S linux/arch/mips/kernel/entry.S
@@ -1,25 +1,31 @@
 /*
- * arch/mips/kernel/entry.S
+ * Low level exception handling
  *
- * Copyright (C) 1994, 1995 Waldorf Electronics
- * written by Ralf Baechle
+ * 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) 1994, 1995 by Ralf Baechle
  */
 
 /*
  * entry.S contains the system-call and fault low-level handling routines.
  * This also contains the timer-interrupt handler, as well as all interrupts
- * and faults that can result in a task-switch.
+ * and faults that can result in a task-switch. The ISA dependend TLB
+ * code is in arch/mips/kernel/<cputype>.S
  */
-
 #include <linux/sys.h>
-#include <linux/autoconf.h>
+
+#include <asm/asm.h>
+#include <asm/errno.h>
 #include <asm/segment.h>
 #include <asm/mipsregs.h>
 #include <asm/mipsconfig.h>
 #include <asm/page.h>
+#include <asm/pgtable.h>
 #include <asm/stackframe.h>
-#include <asm/regdef.h>
 #include <asm/processor.h>
+#include <asm/unistd.h>
 
 /*
  * These are offsets into the task-struct.
@@ -30,944 +36,276 @@
 signal		= 12
 blocked		= 16
 flags		= 20
-errno		= 24			#/* MIPS OK */
-exec_domain	= 60			#/* ??? */
-
-ENOSYS		= 38
+errno		= 24
+exec_domain	= 60
 
-		.globl	ret_from_sys_call
-		.globl	_sys_call_table
+#ifdef __SMP__
+#error "Fix this for SMP"
+#else
+#define current current_set
+#endif
 
+/*
+ * Heia ...  The %lo, %hi and %HI stuff is too strong for the ELF assembler
+ * and the ABI to cope with ...
+ */
 		.text
 		.set	noreorder
 		.align 4
 handle_bottom_half:
-		/*
-		 * If your assembler breaks on the next line it's
-		 * time to update!
-		 */
-		lui	s0,%hi(_intr_count)
-		lw	s1,%lo(_intr_count)(s0)
-		mfc0	s3,CP0_STATUS			# Enable IRQs
+		lui	s0,%hi(intr_count)
+		lw	s1,%lo(intr_count)(s0)
+		mfc0	s3,CP0_STATUS		# Enable IRQs
 		addiu	s2,s1,1
-		sw	s2,%lo(_intr_count)(s0)
+		sw	s2,%lo(intr_count)(s0)
 		ori	t0,s3,0x1f
-		xori	t0,t0,0x1e
-		jal	_do_bottom_half
-		mtc0	t0,CP0_STATUS			# delay slot
-		mtc0	s3,CP0_STATUS			# Restore old IRQ state
-		j	9f
-		sw	s1,%lo(_intr_count)(s0)		# delay slot
-
-		.set	reorder
-reschedule:
-		la	ra,ret_from_sys_call
-		j	_schedule
-		nop
-
-		.align	5
-		.globl	_handle_sys
-_handle_sys:
-		.set	noreorder
-		.set	noat
-		SAVE_ALL
-		.set	at
-		STI
-		/*
-		 * Compute return address. For now we assume that syscalls never
-		 * appear in branch delay slots. For the Linux/MIPS standard
-		 * libraries this assumption is always try.
-		 */
-		lw	t3,FR_EPC(sp)
-		lw	s1,FR_REG2(sp)
-		li	t0,-ENOSYS
-		addiu	t3,t3,4
-		sw	t3,FR_EPC(sp)
-		li	t2,NR_syscalls
-		bge	s1,t2,ret_from_sys_call
-		sw	t0,FR_REG2(sp)		# delay slot
-		sll	s1,s1,2
-		lw	s1,_sys_call_table(s1)
-		lw	s0,_current
-
-		beqz	s1,ret_from_sys_call
-		lw	t0,flags(s0)
-		sll	t0,t0,2			# PF_TRACESYS
-		bltz	t0,1f
-		sw	zero,errno(s0)		# delay slot
-
-		lw	a0,FR_REG4(sp)
-		lw	a1,FR_REG5(sp)
-		lw	a2,FR_REG6(sp)
-		lw	a3,FR_REG7(sp)
-		lw	t0,FR_REG3(sp)
-		jalr	s1			# do the real work
-		sw	t0,16(sp)		# delay slot
-
-		lw	t0,errno(s0)
-		sw	v0,FR_REG2(sp)		# save the return value
-		subu	t0,zero,t0		# t0 = -t0
-		beqz	t0,ret_from_sys_call
-		nop
-		/*
-		 * Fixme: should set error flag
-		 */
-		j	ret_from_sys_call
-		sw	t0,FR_REG2(sp)		# delay slot
-
-		.align	4
-1:		jal	_syscall_trace
-		nop				# delay slot
-
-		lw	a0,FR_REG4(sp)
-		lw	a1,FR_REG5(sp)
-		lw	a2,FR_REG6(sp)
-		lw	a3,FR_REG7(sp)
-		lw	t0,FR_REG3(sp)
-		jalr	s1			# do the real work
-		sw	t0,16(sp)		# delay slot
-
-		lw	t0,errno(s0)
-		sw	v0,FR_REG2(sp)		# save the return value
-		subu	t0,zero,t0
-		beqz	t0,1f
-		nop				# delay slot
-		sw	t1,FR_REG2(sp)
-		/*
-		 * Fixme: should set error flag
-		 */
-1:		jal	_syscall_trace
-		nop
+		xori	t0,0x1e
+		jal	do_bottom_half
+		mtc0	t0,CP0_STATUS		# delay slot
+		mtc0	s3,CP0_STATUS		# Restore old IRQ state
+		b	9f
+		sw	s1,%lo(intr_count)(s0)	# delay slot
+
+reschedule:	jal	schedule 
+		nop				# delay slot
+EXPORT(ret_from_sys_call)
+		lw	t0,intr_count		# bottom half
+		bnez	t0,return
 
-		.align	4
-ret_from_sys_call:
-		lw	t0,_intr_count		# bottom half
-		bnez	t0,2f
-9:
-		lw	t0,_bh_mask		# delay slot
-		lw	t1,_bh_active		# unused delay slot
+9:		lw	t0,bh_mask		# delay slot
+		lw	t1,bh_active		# unused delay slot
 		and	t0,t1
 		bnez	t0,handle_bottom_half
 
-		lw	t0,FR_STATUS(sp)	# returning to supervisor ?
+		lw	t0,FR_STATUS(sp)	# returning to kernel mode?
 		andi	t1,t0,0x10
-		beqz	t1,2f
+		beqz	t1,return		# -> yes
 
 		mfc0	t0,CP0_STATUS		# delay slot
-		lw	t1,_need_resched
+		lw	t1,need_resched
 		ori	t0,0x1f			# enable irqs
 		xori	t0,0x1e
 		bnez	t1,reschedule
 		mtc0	t0,CP0_STATUS		# delay slot
 
-		lw	s0,_current
-		lw	t0,_task
-		lw	t1,state(s0)		# state
-		beq	s0,t0,2f		# task[0] cannot have signals
-		lw	t0,counter(s0)		# counter
-		bnez	t1,reschedule		# state == 0 ?
+		lw	s0,current
+		lw	t0,task
 		lw	a0,blocked(s0)
+		beq	s0,t0,return		# task[0] cannot have signals
 						# save blocked in a0 for
 						# signal handling
-		beqz	t0,reschedule		# counter == 0 ?
 		lw	t0,signal(s0)
 		nor	t1,zero,a0
 		and	t1,t0,t1
-		beqz	t1,skip_signal_return
+		beqz	t1,return
 		nop
 
-		jal	_do_signal
+		jal	do_signal
 		move	a1,sp			# delay slot
 		
-skip_signal_return:
-		.set	noreorder
 		.set	noat
-2:
-return:		RESTORE_ALL
-		.set	at
-
-#ifdef CONFIG_DESKSTATION_TYNE
-/*
- * Deskstation Tyne interrupt handler
- */
-		.text
-		.set	noreorder
-		.set	noat
-		.globl	_deskstation_tyne_handle_int
-		.align	5
-_deskstation_tyne_handle_int:
-		SAVE_ALL
+EXPORT(return)	RESTORE_ALL
+		ERET
 		.set	at
-		CLI
-		lui	s0,%hi(PORT_BASE)
-		li	t1,0x0f
-		sb	t1,%lo(PORT_BASE+0x20)(s0)	# poll command
-		lb	t1,%lo(PORT_BASE+0x20)(s0)	# read result
-		li	s1,1
-		bgtz	t1,Lpoll_second
-		andi	t1,t1,7
-		/*
-		 * Acknowledge first pic
-		 */
-		lb	t2,%lo(PORT_BASE+0x21)(s0)
-		lui	s4,%hi(_cache_21)
-		lb	t0,%lo(_cache_21)(s4)
-		sllv	s1,s1,t1
-		or	t0,t0,s1
-		sb	t0,%lo(_cache_21)(s4)
-		sb	t0,%lo(PORT_BASE+0x21)(s0)
-		lui	s3,%hi(_intr_count)
-		lw	t0,%lo(_intr_count)(s3)
-		li	t2,0x20
-		sb	t2,%lo(PORT_BASE+0x20)(s0)
-		/*
-		 * Now call the real handler
-		 */
-		la	t3,_IRQ_vectors
-		sll	t2,t1,2
-		addu	t3,t3,t2
-		lw	t3,(t3)
-		addiu	t0,t0,1
-		jalr	t3
-		sw	t0,%lo(_intr_count)(s3)		# delay slot
-		lw	t0,%lo(_intr_count)(s3)
-		/*
-		 * Unblock first pic
-		 */
-		lbu	t1,%lo(PORT_BASE+0x21)(s0)
-		lb	t1,%lo(_cache_21)(s4)
-		subu	t0,t0,1
-		sw	t0,%lo(_intr_count)(s3)
-		nor	s1,zero,s1
-		and	t1,t1,s1
-		sb	t1,%lo(_cache_21)(s4)
-		jr	v0
-		sb	t1,%lo(PORT_BASE+0x21)(s0)	# delay slot
-
-		.align	5
-Lpoll_second:	li	t1,0x0f
-		sb	t1,%lo(PORT_BASE+0xa0)(s0)	# poll command
-		lb	t1,%lo(PORT_BASE+0xa0)(s0)	# read result
-		lui	s4,%hi(_cache_A1)
-		bgtz	t1,Lspurious_interrupt
-		andi	t1,t1,7
-		/*
-		 * Acknowledge second pic
-		 */
-		lbu	t2,%lo(PORT_BASE+0xa1)(s0)
-		lb	t3,%lo(_cache_A1)(s4)
-		sllv	s1,s1,t1
-		or	t3,t3,s1
-		sb	t3,%lo(_cache_A1)(s4)
-		sb	t3,%lo(PORT_BASE+0xa1)(s0)
-		li	t3,0x20
-		sb	t3,%lo(PORT_BASE+0xa0)(s0)
-		lui	s3,%hi(_intr_count)
-		lw	t0,%lo(_intr_count)(s3)
-		sb	t3,%lo(PORT_BASE+0x20)(s0)
-		/*
-		 * Now call the real handler
-		 */
-		la	t0,_IRQ_vectors
-		sll	t2,t1,2
-		addu	t0,t0,t2
-		lw	t0,32(t0)
-		addiu	t0,t0,1
-		jalr	t0
-		sw	t0,%lo(_intr_count)(s3)		# delay slot
-		lw	t0,%lo(_intr_count)(s3)
-		/*
-		 * Unblock second pic
-		 */
-		lb	t1,%lo(PORT_BASE+0xa1)(s0)
-		lb	t1,%lo(_cache_A1)(s4)
-		subu	t0,t0,1
-		lw	t0,%lo(_intr_count)(s3)
-		nor	s1,zero,s1
-		and	t1,t1,s1
-		sb	t1,%lo(_cache_A1)(s4)
-		jr	v0
-		sb	t1,%lo(PORT_BASE+0xa1)(s0)	# delay slot
 
-		.align	5
-Lspurious_interrupt:
-		/*
-		 * Nothing happened... (whistle)
-		 */
-		lui	t1,%hi(_spurious_count)
-		lw	t0,%lo(_spurious_count)(t1)
-		la	v0,return
-		addiu	t0,t0,1
-		jr	ra
-		sw	t0,%lo(_spurious_count)(t1)
-#endif /* CONFIG_DESKSTATION_TYNE */
-		
-#ifdef CONFIG_ACER_PICA_61
 /*
- * Acer PICA interrupt handler dummy
+ * Beware: interrupt, fast_interrupt and bad_interrupt have unusal
+ * calling conventions to speedup the mess.
+ *
+ * t1 - interrupt number
+ * s2 - destroyed
+ * return values:
+ * v0 - return routine
  */
-		.set	noreorder
-		.set	noat
-		.globl	_acer_pica_61_handle_int
-		.align	5
-_acer_pica_61_handle_int:
-		la	a0,acer_text
-		jal	_panic
-		nop
-1:		b	1b
-		nop
-acer_text:	.asciz	"Interrupt handler for Acer PICA not written yet"
-		.align	2
-#endif /* CONFIG_ACER_PICA_61 */
-
 		.text
-		.set	noreorder
 		.set	at
-		.globl	_interrupt
 		.align	5
-_interrupt:	move	s2,ra
-		mfc0	t0,CP0_STATUS
-		ori	t0,t0,0x1f
-		xori	t0,t0,0x1e
+NESTED(interrupt, FR_SIZE, sp)
+		move	s2,ra
+		mfc0	t0,CP0_STATUS			# enable IRQs
+		ori	t0,0x1f
+		xori	t0,0x1e
 		mtc0	t0,CP0_STATUS
 		move	a0,t1
-		jal	_do_IRQ
+		jal	do_IRQ
 		move	a1,sp				# delay slot
-		mfc0	t0,CP0_STATUS
-		ori	t0,t0,1
-		xori	t0,t0,1
+		mfc0	t0,CP0_STATUS			# disable IRQs
+		ori	t0,1
+		xori	t0,1
 		la	v0,ret_from_sys_call
 		jr	s2
 		mtc0	t0,CP0_STATUS			# delay slot
+		END(interrupt)
 
-		.globl	_fast_interrupt
 		.align	5
-_fast_interrupt:
+NESTED(fast_interrupt, FR_SIZE, sp)
 		move	s2,ra
 		move	a0,t1
-		jal	_do_fast_IRQ
+		jal	do_fast_IRQ
 		move	a1,sp				# delay slot
-		la	v0,return
+		lui	v0,%hi(return)
 		jr	s2
-		nop					# delay slot
+		addiu	v0,%lo(return)			# delay slot
+		END(fast_interrupt)
 
-		.globl	_bad_interrupt
-_bad_interrupt:
+LEAF(bad_interrupt)
 		/*
 		 * Don't return & unblock the pic
 		 */
 		j	return
 		nop
+		END(bad_interrupt)
 
-		.globl	_handle_tlbl
-		.align	5
-_handle_tlbl:
+/*
+ * do_syscall calls the function in a1 with upto 7 arguments.  If over
+ * four arguments are being requested, the additional arguments will
+ * be copied from the user stack pointed to by a0->reg29.
+ * Note that this routine relies on the GNU assemblers weak instruction
+ * scheduling abilities to generate the best possible code for all MIPS CPUs.
+ *
+ * a0 (struct pt_regs *)  pointer to user registers
+ * a1 (syscall_t)         pointer to syscall to do
+ * a2 (int)               number of arguments to syscall
+ */
 		.set	noreorder
-		.set	noat
-		/*
-		 * Check whether this is a refill or an invalid exception
-		 *
-		 * NOTE: Some MIPS manuals say that the R4x00 sets the
-		 * BadVAddr only when EXL == 0. This is wrong - BadVaddr
-		 * is being set for all Reload, Invalid and Modified
-		 * exceptions.
-		 */
-		mfc0	k0,CP0_BADVADDR
-		mfc0	k1,CP0_ENTRYHI
-		ori	k0,k0,0x1fff
-		xori	k0,k0,0x1fff
-		andi	k1,k1,0xff
-		or	k0,k0,k1
-		mfc0	k1,CP0_ENTRYHI
-		mtc0	k0,CP0_ENTRYHI
-		nop					# for R4[04]00 pipeline
-		nop
-		nop
-		tlbp
-		nop					# for R4[04]00 pipeline
-		nop
-		mfc0	k0,CP0_INDEX
-		srl	k0,k0,31
-		beqz	k0,invalid_tlbl
-		mtc0	k1,CP0_ENTRYHI			# delay slot
-		/*
-		 * Not in tlb -> nested refill exception
-		 * Load the missing entry and return. This is the most
-		 * efficient way to regain the faulting address.
-		 */
-		dmfc0	k1,CP0_CONTEXT
-		dsra	k1,k1,1
-		lwu	k0,(k1)			# Never causes another exception
-		lwu	k1,4(k1)
-		dsrl	k0,k0,6			# Convert to EntryLo format
-		dsrl	k1,k1,6			# Convert to EntryLo format
-		dmtc0	k0,CP0_ENTRYLO0
-		dmtc0	k1,CP0_ENTRYLO1
-		nop				# for R4[04]00 pipeline
-		tlbwr
-		eret
-
-		/*
-		 * Handle invalid exception
-		 *
-		 * There are two possible causes for an invalid (tlbl)
-		 * exception:
-		 * 1) pages that have the present bit set but the valid bit
-		 *    unset.
-		 * 2) pages that don't exist
-		 * Case one needs fast handling, therefore don't save
-		 * registers yet.
-		 *
-		 * k0 now contains the bad virtual address.
-		 */
-invalid_tlbl:
-		/*
-		 * Remove entry so we don't need to care later
-		 */
-		mfc0	k0,CP0_INDEX
-		lui	k1,0x0008
-		or	k0,k0,k1
-		dsll	k0,k0,13
-		dmtc0	k0,CP0_ENTRYHI
-		dmtc0	zero,CP0_ENTRYLO0
-		dmtc0	zero,CP0_ENTRYLO1
-		/*
-		 * Test whether present bit in entry is set
-		 */
-		dmfc0	k0,CP0_BADVADDR
-		tlbwi						# delayed, for R4[04]00 pipeline
-		srl	k0,k0,10
-		lui	k1,%HI(TLBMAP)
-		addu	k0,k0,k1
-		ori	k0,k0,3
-		xori	k0,k0,3
-		lw	k1,(k0)
-		andi	k1,k1,_PAGE_PRESENT
-		beqz	k1,nopage_tlbl
-		/*
-		 * Present bit is set -> set valid and accessed bits
-		 */
-		lw	k1,(k0)				# delay slot
-		ori	k1,k1,_PAGE_ACCESSED
-		sw	k1,(k0)
-		eret
-
-		/*
-		 * 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
-		.set	at
-		STI
-		/*
-		 * Create a Intel-style errorcode
-		 * Bit 0: P Present
-		 *        0 == Page not in memory
-		 *        1 == privilege violation
-		 * Bit 1: R/W Read/Write
-		 *        0 == ReadAccess
-		 *        1 == WriteAccess
-		 * Bit 2: U/S User/Supervisor
-		 *        0 == User mode
-		 *        1 == Kernel mode
-		 *
-		 * a0 (struct pt_regs *) regs
-		 * a1 (unsigned long)    error_code
-		 */
-		lw	a1,FR_STATUS(sp)
-		move	a0,sp
-		srl	a1,a1,4
-		andi	a1,a1,1
-		jal	_do_page_fault
-		xori	a1,a1,1				# delay slot
-		j	ret_from_sys_call
-		nop					# delay slot
-
 		.text
-		.globl	_handle_tlbs
-		.align	5
-_handle_tlbs:
-		.set	noreorder
-		.set	noat
-		/*
-		 * It is impossible that is a nested reload exception.
-		 * Therefore this must be a invalid exception.
-		 * Two possible cases:
-		 * 1) Page not used yet
-		 * 2) Page doesn't exist yet. Let the kernel handle the trouble.
-		 *
-		 * Test whether present bit in entry is set
-		 */
-		dmfc0	k0,CP0_BADVADDR
-		srl	k0,k0,10
-		lui	k1,%HI(TLBMAP)
-		addu	k0,k0,k1
-		ori	k0,k0,3
-		xori	k0,k0,3
-		lw	k1,(k0)
-		andi	k1,k1,(_PAGE_PRESENT|_PAGE_RW)
-		beqz	k1,nopage_tlbs
-		/*
-		 * Present and writable bits set -> set accessed and dirty bits.
-		 */
-		lw	k1,(k0)				# delay slot
-		ori	k1,k1,(_PAGE_ACCESSED|_PAGE_DIRTY)
-		sw	k1,(k0)
-		/*
-		 * Now reload the entry into the tlb
-		 */
-		ori	k0,k0,0x1000
-		xori	k0,k0,0x1000
-		lw	k1,4(k0)
-		lw	k0,(k0)
-		srl	k0,k0,6
-		srl	k1,k1,6
-		dmtc0	k0,CP0_ENTRYLO0
-		dmtc0	k1,CP0_ENTRYLO1
-		tlbwi
-		eret
-
-		/*
-		 * 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:
-		/*
-		 * Remove entry so we don't need to care later
-		 */
-		mfc0	k0,CP0_INDEX
-		lui	k1,0x0008
-		or	k0,k0,k1
-		dsll	k0,k0,13
-		dmtc0	k0,CP0_ENTRYHI
-		dmtc0	zero,CP0_ENTRYLO0
-		dmtc0	zero,CP0_ENTRYLO1
-		tlbwi
-		SAVE_ALL
-		.set	at
-		STI
-		/*
-		 * Create a Intel-style errorcode
-		 * Bit 0: P Present
-		 *        0 == Page not in memory
-		 *        1 == privilege violation
-		 * Bit 1: R/W Read/Write
-		 *        0 == ReadAccess
-		 *        1 == WriteAccess
-		 * Bit 2: U/S User/Supervisor
-		 *        0 == User mode
-		 *        1 == Kernel mode
-		 *
-		 * a0 (struct pt_regs *) regs
-		 * a1 (unsigned long)    error_code
-		 */
-		lw	a1,FR_STATUS(sp)
-		move	a0,sp
-		srl	a1,a1,4
-		andi	a1,a1,1
-		jal	_do_page_fault
-		xori	a1,a1,3				# branch delay slot
-		j	ret_from_sys_call
-		nop					# branch delay slot
-
-		.globl	_handle_mod
-		.align	5
-_handle_mod:
-		.set	noreorder
-		.set	noat
-		/*
-		 * Two possible cases:
-		 * 1) Page is rw but not dirty -> set dirty and return
-		 * 2) Page is not rw -> call C handler
-		 */
-		dmfc0	k0,CP0_BADVADDR
-		srl	k0,k0,10
-		lui	k1,%HI(TLBMAP)
-		addu	k0,k0,k1
-		ori	k0,k0,3
-		xori	k0,k0,3
-		lw	k1,(k0)
-		andi	k1,k1,_PAGE_RW
-		beqz	k1,nopage_tlbs
-		/*
-		 * Present and writable bits set -> set accessed and dirty bits.
-		 */
-		lw	k1,(k0)				# delay slot
-		ori	k1,k1,(_PAGE_ACCESSED|_PAGE_DIRTY)
-		sw	k1,(k0)
-		/*
-		 * Now reload the entry into the tlb
-		 */
-		ori	k0,k0,0x1000
-		xori	k0,k0,0x1000
-		lw	k1,4(k0)
-		lw	k0,(k0)
-		srl	k0,k0,6
-		srl	k1,k1,6
-		dmtc0	k0,CP0_ENTRYLO0
-		dmtc0	k1,CP0_ENTRYLO1
-		tlbwi
-		eret
-
-		.globl	_handle_adel
-		.align	5
-_handle_adel:
-		.set	noreorder
-		.set	noat
-		SAVE_ALL
-		STI
-		li	t0,-1
-		sw	t0,FR_ORIG_REG2(sp)
-		jal	_do_adel
-		move	a0,sp			# delay slot
-		j	ret_from_sys_call
-		nop				# delay slot
-
-		.globl	_handle_ades
-		.align	5
-_handle_ades:
-		.set	noreorder
-		.set	noat
-		SAVE_ALL
-		STI
-		li	t0,-1
-		sw	t0,FR_ORIG_REG2(sp)
-		jal	_do_ades
-		move	a0,sp			# delay slot
-		j	ret_from_sys_call
-		nop				# delay slot
-
-		.globl	_handle_ibe
-		.align	5
-_handle_ibe:
-		.set	noreorder
-		.set	noat
-		SAVE_ALL
-		STI
-		li	t0,-1
-		sw	t0,FR_ORIG_REG2(sp)
-		jal	_do_ibe
-		move	a0,sp			# delay slot
-		j	ret_from_sys_call
-		nop				# delay slot
-
-		.globl	_handle_dbe
-		.align	5
-_handle_dbe:
-		.set	noreorder
-		.set	noat
-		SAVE_ALL
-		STI
-		li	t0,-1
-		sw	t0,FR_ORIG_REG2(sp)
-		jal	_do_dbe
-		move	a0,sp			# delay slot
-		j	ret_from_sys_call
-		nop				# delay slot
-
-		.globl	_handle_ov
-		.align	5
-_handle_ov:
-		.set	noreorder
-		.set	noat
-		SAVE_ALL
-		STI
-		li	t0,-1
-		sw	t0,FR_ORIG_REG2(sp)
-		jal	_do_ov
-		move	a0,sp			# delay slot
-		j	ret_from_sys_call
-		nop				# delay slot
-
-		.globl	_handle_fpe
-		.align	5
-_handle_fpe:
-		.set	noreorder
-		.set	noat
-		SAVE_ALL
-		STI
-		li	t0,-1
-		sw	t0,FR_ORIG_REG2(sp)
-		jal	_do_fpe
-		move	a0,sp			# delay slot
-		j	ret_from_sys_call
-		nop				# delay slot
-
-		.globl	_handle_bp
-		.align	5
-_handle_bp:
-		.set	noreorder
-		.set	noat
-		SAVE_ALL
-		STI
-		li	t0,-1
-		sw	t0,FR_ORIG_REG2(sp)
-		jal	_do_bp
-		move	a0,sp			# delay slot
-		j	ret_from_sys_call
-		nop				# delay slot
-
-		.globl	_handle_tr
-		.align	5
-_handle_tr:
-		.set	noreorder
-		.set	noat
-		SAVE_ALL
-		STI
-		li	t0,-1
-		sw	t0,FR_ORIG_REG2(sp)
-		jal	_do_tr
-		move	a0,sp			# delay slot
-		j	ret_from_sys_call
-		nop				# delay slot
-
-		.globl	_handle_ri
-		.align	5
-_handle_ri:
-		.set	noreorder
-		.set	noat
-		SAVE_ALL
-		STI
-		li	t0,-1
-		sw	t0,FR_ORIG_REG2(sp)
-		jal	_do_ri
-		move	a0,sp			# delay slot
-		j	ret_from_sys_call
-		nop				# delay slot
-
-		.globl	_handle_cpu
-		.align	5
-_handle_cpu:
-		.set	noreorder
-		.set	noat
-		SAVE_ALL
-		STI
-		li	t0,-1
-		sw	t0,FR_ORIG_REG2(sp)
-		jal	_do_cpu
-		move	a0,sp			# delay slot
-		j	ret_from_sys_call
-		nop				# delay slot
+NESTED(do_syscalls, 32, sp)
+		subu	sp,32
+		sw	ra,28(sp)
+		sll	a2,a2,PTRLOG
+		lw	t0,dst(a2)
+		move	t2,a1
+		jalr	t0
+		lw	t0,FR_REG29(a0)		# get old user stack pointer
 
-		.globl	_handle_vcei
-		.align	5
-_handle_vcei:
+		.set	reorder			# for sake of R3000
+7:		lw	t1,24(t0)		# parameter #7 from usp
+		sw	t1,24(t0)
+6:		lw	t1,20(t0)		# parameter #6 from usp
+		sw	t1,20(t0)
+5:		lw	t1,16(t0)		# parameter #5 from usp
+		sw	t1,16(t0)
+		.set	noreorder
+4:		lw	a3,FR_REG7(a0)		# 4 args
+3:		lw	a2,FR_REG6(a0)		# 3 args
+2:		lw	a1,FR_REG5(a0)		# 2 args
+1:		jalr	t2			# 1 args
+		lw	a0,FR_REG4(a0)		# delay slot
+		.set	reorder
+		lw	ra,28(sp)
+		addiu	sp,32
+		jr	ra
+0:		jalr	t2			# 0 args, just pass a0
+		lw	ra,28(sp)
+		addiu	sp,32
+		jr	ra
+		END(do_syscalls)
 		.set	noreorder
-		.set	noat
-		SAVE_ALL
-		STI
-		li	t0,-1
-		sw	t0,FR_ORIG_REG2(sp)
-		jal	_do_vcei
-		move	a0,sp			# delay slot
-		j	ret_from_sys_call
-		nop				# delay slot
 
-		.globl	_handle_vced
-		.align	5
-_handle_vced:
-		.set	noreorder
-		.set	noat
-		SAVE_ALL
-		STI
-		li	t0,-1
-		sw	t0,FR_ORIG_REG2(sp)
-		jal	_do_vced
-		move	a0,sp			# delay slot
-		j	ret_from_sys_call
-		nop				# delay slot
+		.rdata
+		.align	PTRLOG
+dst:		PTR	0b, 1b, 2b, 3b, 4b, 5b, 6b, 7b
 
-		.globl	_handle_watch
-		.align	5
-_handle_watch:
-		.set	noreorder
-		.set	noat
-		SAVE_ALL
-		STI
-		li	t0,-1
-		sw	t0,FR_ORIG_REG2(sp)
-		jal	_do_watch
-		move	a0,sp			# delay slot
-		j	ret_from_sys_call
-		nop				# delay slot
-
-		.globl	_handle_reserved
-		.align	5
-_handle_reserved:
-		.set	noreorder
-		.set	noat
-		SAVE_ALL
-		STI
-		li	t0,-1
-		sw	t0,FR_ORIG_REG2(sp)
-		jal	_do_reserved
-		move	a0,sp			# delay slot
-		j	ret_from_sys_call
-		nop				# delay slot
+/*
+ * Build a default exception handler for the exceptions that don't need
+ * special handlers.  If you didn't know yet - I *like* playing games with
+ * the C preprocessor ...
+ */
+#define __BUILD_silent(exception)
+#define __BUILD_verbose(exception)                                      \
+		la	a1,8f;                                          \
+		TEXT	(#exception);                                   \
+		lw	a2,FR_EPC(sp);                                  \
+		PRINT("Got %s at %08x.\n")
+#define __BUILD_count(exception)                                        \
+		.set	reorder;                                        \
+		lw	t0,exception_count_##exception;                 \
+		addiu	t0,1;                                           \
+		sw	t0,exception_count_##exception;                 \
+		.set	noreorder;                                      \
+		.data;                                                  \
+EXPORT(exception_count_##exception);                                    \
+		.word	0;                                              \
+		.text;
+#define BUILD_HANDLER(exception,verbose)                                \
+		.text;                                                  \
+		.align	5;                                              \
+		NESTED(handle_##exception, FR_SIZE, sp);                \
+		.set	noat;                                           \
+		SAVE_ALL;                                               \
+		STI;                                                    \
+		.set	at;                                             \
+		__BUILD_##verbose(exception);                           \
+		li	t0,-1;                   /* not a sys call */   \
+		sw	t0,FR_ORIG_REG2(sp);                            \
+		jal	do_##exception;                                 \
+		move	a0,sp;                   /* delay slot */       \
+		j	ret_from_sys_call;                              \
+		nop;                             /* delay slot */       \
+		END(handle_##exception)
+
+		BUILD_HANDLER(adel,verbose)		/* #4  */
+		BUILD_HANDLER(ades,verbose)		/* #5  */
+		BUILD_HANDLER(ibe,verbose)		/* #6  */
+		BUILD_HANDLER(dbe,verbose)		/* #7  */
+		BUILD_HANDLER(sys,silent)		/* #8  */
+		BUILD_HANDLER(bp,verbose)		/* #9  */
+		BUILD_HANDLER(ri,verbose)		/* #10 */
+		BUILD_HANDLER(cpu,silent)		/* #11 */
+		BUILD_HANDLER(ov,verbose)		/* #12 */
+		BUILD_HANDLER(tr,verbose)		/* #13 */
+		BUILD_HANDLER(vcei,verbose)		/* #14 */
+		BUILD_HANDLER(fpe,verbose)		/* #15 */
+		BUILD_HANDLER(watch,verbose)		/* #23 */
+		BUILD_HANDLER(vced,verbose)		/* #31 */
+		BUILD_HANDLER(reserved,verbose)		/* others */
 
 /*
  * Exception handler table with 32 entries.
  * This might be extended to handle software exceptions
  */
 		.bss
-		.globl	_exception_handlers
-		.align	2
-_exception_handlers:
-		.fill	32,4,0
+		.align	PTRLOG
+EXPORT(exception_handlers)
+		.fill	32,PTRSIZE,0
+
+/*
+ * Interrupt handler table with 16 entries.
+ */
+EXPORT(IRQ_vectors)
+		.fill	16,PTRSIZE,0
 
 /*
  * Table of syscalls
  */
 		.data
-_sys_call_table:
-		.word	_sys_setup		/* 0 */
-		.word	_sys_exit
-		.word	_sys_fork
-		.word	_sys_read
-		.word	_sys_write
-		.word	_sys_open		/* 5 */
-		.word	_sys_close
-		.word	_sys_waitpid
-		.word	_sys_creat
-		.word	_sys_link
-		.word	_sys_unlink		/* 10 */
-		.word	_sys_execve
-		.word	_sys_chdir
-		.word	_sys_time
-		.word	_sys_mknod
-		.word	_sys_chmod		/* 15 */
-		.word	_sys_chown
-		.word	_sys_break
-		.word	_sys_stat
-		.word	_sys_lseek
-		.word	_sys_getpid		/* 20 */
-		.word	_sys_mount
-		.word	_sys_umount
-		.word	_sys_setuid
-		.word	_sys_getuid
-		.word	_sys_stime		/* 25 */
-		.word	_sys_ptrace
-		.word	_sys_alarm
-		.word	_sys_fstat
-		.word	_sys_pause
-		.word	_sys_utime		/* 30 */
-		.word	_sys_stty
-		.word	_sys_gtty
-		.word	_sys_access
-		.word	_sys_nice
-		.word	_sys_ftime		/* 35 */
-		.word	_sys_sync
-		.word	_sys_kill
-		.word	_sys_rename
-		.word	_sys_mkdir
-		.word	_sys_rmdir		/* 40 */
-		.word	_sys_dup
-		.word	_sys_pipe
-		.word	_sys_times
-		.word	_sys_prof
-		.word	_sys_brk		/* 45 */
-		.word	_sys_setgid
-		.word	_sys_getgid
-		.word	_sys_signal
-		.word	_sys_geteuid
-		.word	_sys_getegid		/* 50 */
-		.word	_sys_acct
-		.word	_sys_phys
-		.word	_sys_lock
-		.word	_sys_ioctl
-		.word	_sys_fcntl		/* 55 */
-		.word	_sys_mpx
-		.word	_sys_setpgid
-		.word	_sys_ulimit
-		.word	_sys_olduname
-		.word	_sys_umask		/* 60 */
-		.word	_sys_chroot
-		.word	_sys_ustat
-		.word	_sys_dup2
-		.word	_sys_getppid
-		.word	_sys_getpgrp		/* 65 */
-		.word	_sys_setsid
-		.word	_sys_sigaction
-		.word	_sys_sgetmask
-		.word	_sys_ssetmask
-		.word	_sys_setreuid		/* 70 */
-		.word	_sys_setregid
-		.word	_sys_sigsuspend
-		.word	_sys_sigpending
-		.word	_sys_sethostname
-		.word	_sys_setrlimit		/* 75 */
-		.word	_sys_getrlimit
-		.word	_sys_getrusage
-		.word	_sys_gettimeofday
-		.word	_sys_settimeofday
-		.word	_sys_getgroups		/* 80 */
-		.word	_sys_setgroups
-		.word	_sys_select
-		.word	_sys_symlink
-		.word	_sys_lstat
-		.word	_sys_readlink		/* 85 */
-		.word	_sys_uselib
-		.word	_sys_swapon
-		.word	_sys_reboot
-		.word	_sys_readdir
-		.word	_sys_mmap		/* 90 */
-		.word	_sys_munmap
-		.word	_sys_truncate
-		.word	_sys_ftruncate
-		.word	_sys_fchmod
-		.word	_sys_fchown		/* 95 */
-		.word	_sys_getpriority
-		.word	_sys_setpriority
-		.word	_sys_profil
-		.word	_sys_statfs
-		.word	_sys_fstatfs		/* 100 */
-		.word	_sys_ioperm
-		.word	_sys_socketcall
-		.word	_sys_syslog
-		.word	_sys_setitimer
-		.word	_sys_getitimer		/* 105 */
-		.word	_sys_newstat
-		.word	_sys_newlstat
-		.word	_sys_newfstat
-		.word	_sys_uname
-		.word	_sys_iopl		/* 110 */
-		.word	_sys_vhangup
-		.word	_sys_idle
-		.word	0 #_sys_vm86
-		.word	_sys_wait4
-		.word	_sys_swapoff		/* 115 */
-		.word	_sys_sysinfo
-		.word	_sys_ipc
-		.word	_sys_fsync
-		.word	_sys_sigreturn
-		.word	_sys_clone		/* 120 */
-		.word	_sys_setdomainname
-		.word	_sys_newuname
-		.word	0 #_sys_modify_ldt
-		.word	_sys_adjtimex
-		.word	_sys_mprotect		/* 125 */
-		.word	_sys_sigprocmask
-		.word	_sys_create_module
-		.word	_sys_init_module
-		.word	_sys_delete_module
-		.word	_sys_get_kernel_syms	/* 130 */
-		.word	_sys_quotactl
-		.word	_sys_getpgid
-		.word	_sys_fchdir
-		.word	_sys_bdflush
-		.word	_sys_sysfs		/* 135 */
-		.word	_sys_personality
-		.word	0			/* for afs_syscall */
-		.word	_sys_setfsuid
-		.word	_sys_setfsgid
-		.word	_sys_llseek		/* 140 */
-		.space	(NR_syscalls-140)*4
+		.align	PTRLOG
+EXPORT(sys_call_table)
+		/*
+		 * Reserved space for all the SVR4, SVR, BSD43 and POSIX
+		 * flavoured syscalls.
+		 */
+		.space	(__NR_Linux)*PTRSIZE
 
-		.bss
-		.globl	_IRQ_vectors
-_IRQ_vectors:	.fill	16,4,0
+		/*
+		 * Linux flavoured syscalls.
+		 */
+#define SYS(call, narg) PTR call
+#include "syscalls.h"
 
+/*
+ * Number of arguments of each syscall
+ */
+EXPORT(sys_narg_table)
+		/*
+		 * Reserved space for all the SVR4, SVR, BSD43 and POSIX
+		 * flavoured syscalls.
+		 */
+		.space	(__NR_Linux)
+
+		/*
+		 * Linux flavoured syscalls.
+		 */
+#undef SYS
+#define SYS(call, narg) .byte narg
+#include "syscalls.h"

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this