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
- Lines: 1181
- Date:
Wed Dec 13 12:39:43 1995
- Orig file:
v1.3.47/linux/arch/mips/kernel/entry.S
- Orig date:
Wed Jan 25 08:54:22 1995
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