home *** CD-ROM | disk | FTP | other *** search
- /*
- * linux/kernel/sys_call.S
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file README.legal in the main directory of this archive
- * for more details.
- *
- * 680x0 support by Hamish Macdonald
- *
- */
-
- /*
- * sys_call.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.
- *
- * NOTE: This code handles signal-recognition, which happens every time
- * after a timer-interrupt and after each system call.
- *
- * Stack layout in '_ret_from_exception':
- * ptrace needs to have all regs on the stack.
- * if the order here is changed, it needs to be
- * updated in fork.c:sys_fork, signal.c:do_signal,
- * ptrace.c and ptrace.h
- *
- * This allows access to the syscall arguments in registers d1-d5
- *
- * 0(sp) - d1
- * 4(sp) - d2
- * 8(sp) - d3
- * C(sp) - d4
- * 10(sp) - d5
- * 14(sp) - d6
- * 18(sp) - d7
- * 1C(sp) - a0
- * 20(sp) - a1
- * 24(sp) - a2
- * 28(sp) - a3
- * 2C(sp) - a4
- * 30(sp) - a5
- * 34(sp) - a6
- * 38(sp) - d0
- * 3C(sp) - usp
- * 40(sp) - orig_d0
- * 44(sp) - stack adjustment
- * 46(sp) - sr
- * 48(sp) - pc
- * 4C(sp) - format & vector
- */
-
- LOFF_D1 = 0x00
- LOFF_D2 = 0x04
- LOFF_D3 = 0x08
- LOFF_D4 = 0x0C
- LOFF_D5 = 0x10
- LOFF_D6 = 0x14
- LOFF_D7 = 0x18
- LOFF_A0 = 0x1C
- LOFF_A1 = 0x20
- LOFF_A2 = 0x24
- LOFF_A3 = 0x28
- LOFF_A4 = 0x2C
- LOFF_A5 = 0x30
- LOFF_A6 = 0x34
- LOFF_D0 = 0x38
- LOFF_USP = 0x3C
- LOFF_ORIG_D0 = 0x40
- LOFF_STKADJ = 0x44
- LOFF_SR = 0x46
- LOFF_PC = 0x48
- LOFF_FORMAT = 0x4C
-
-
- LCF_MASK = 0x0001
-
- LENOSYS = 38
-
- LESP0_OFFSET = 2436
-
- /*
- * these are offsets into the task-struct
- */
- LTS_STATE = 0
- LTS_COUNTER = 4
- LTS_PRIORITY = 8
- LTS_SIGNAL = 12
- LTS_BLOCKED = 16
- LTS_FLAGS = 20
- LTS_ERRNO = 24
-
- .globl _system_call, _buserr, _trap
- .globl _ret_from_exception, _inthandler
-
- .text
- .align 4
- _buserr:
- clrw sp@- | stack adjustment
- subql #8,sp | make room for usp and orig_d0
- movel d0,sp@-
- moveml d1-a6,sp@-
- movec usp,a0
- movel a0,sp@(LOFF_USP)
- moveq #-1,d0
- movel d0,sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
- | signifies that the stack frame
- | is NOT for syscall
-
- | save top of frame
- movel _current,a0
- movel sp,a0@(LESP0_OFFSET)
-
- movel sp,sp@- | stack frame pointer argument
- bsr _buserr_c
- addql #4,sp
- bra _ret_from_exception
-
- .align 4
- _trap:
- clrw sp@- | stack adjustment
- subql #8,sp | make room for usp and orig_d0
- movel d0,sp@-
- moveml d1-a6,sp@-
- movec usp,a0
- movel a0,sp@(LOFF_USP)
- moveq #-1,d0
- movel d0,sp@(LOFF_ORIG_D0) | a -1 in the ORIG_D0 field
- | signifies that the stack frame
- | is NOT for syscall
- | save top of frame
- movel _current,a0
- movel sp,a0@(LESP0_OFFSET)
-
- movel sp,sp@- | stack frame pointer argument
- bsr _trap_c
- addql #4,sp
- bra _ret_from_exception
- .align 4
- reschedule:
- movel #_ret_from_exception,sp@-
- jmp _schedule
-
- .align 4
- _system_call:
- clrw sp@- | stack adjustment
- subql #8,sp | make room for usp and orig_d0
- movel #-LENOSYS,sp@- | default return value in D0
- moveml d1-a6,sp@- | save registers
- movec usp,a0
- movel a0,sp@(LOFF_USP) | save User Stack Pointer
- movel d0,sp@(LOFF_ORIG_D0) | save original D0 (syscall #)
-
- | save top of frame
- movel _current,a0
- movel sp,a0@(LESP0_OFFSET)
-
- cmpl _NR_syscalls,d0
- bgt _ret_from_exception
- andw #~LCF_MASK,sp@(LOFF_SR) | assume syscall success
- clrl a0@(LTS_ERRNO)
- btst #5,a0@(LTS_FLAGS+3) | PF_TRACESYS
- bnes 1f
- lea _sys_call_table,a0
- movel a0@(d0:l:4),a0
- jbsr a0@
- movel d0,sp@(LOFF_D0) | save the return value
- bpl 2f
- orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error
- 2:
- movel _current,a0
- movel a0@(LTS_ERRNO),d1
- negl d1
- beq _ret_from_exception
- movel d1,sp@(LOFF_D0)
- orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error
- bra _ret_from_exception
- 1: jbsr _syscall_trace
- movel sp@(LOFF_ORIG_D0),d0
- lea _sys_call_table,a0
- movel a0@(d0:l:4),a0
- jbsr a0@
- movel d0,sp@(LOFF_D0) | save the return value
- bpl 2f
- orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error
- 2:
- movel _current,a0
- movel a0@(LTS_ERRNO),d1
- negl d1
- beq 2f
- movel d1,sp@(LOFF_D0)
- orw #LCF_MASK,sp@(LOFF_SR) | set carry to indicate error
- 2: jbsr _syscall_trace
-
- _ret_from_exception:
- btst #5,sp@(LOFF_SR) | check if returning to kernel
- bnes 2f | if so, skip resched, signals
- tstl _need_resched
- bne reschedule
- movel _current,a0
- cmpl #_task,a0 | task[0] cannot have signals
- beq 2f
- btst #6,a0@(LTS_FLAGS+3) | check for delayed trace
- beq 1f
- bclr #6,a0@(LTS_FLAGS+3) | clear delayed trace bit
- bclr #7,sp@(LOFF_SR) | clear trace bit in SR
- pea 1 | send SIGTRAP
- movel a0,sp@-
- pea 5
- jbsr _send_sig
- addql #8,sp
- addql #4,sp
- 1:
- moveq #0,d0
- cmpl a0@(LTS_STATE),d0 | state
- bne reschedule
- cmpl a0@(LTS_COUNTER),d0 | counter
- beq reschedule
- movel a0@(LTS_BLOCKED),d0
- movel d0,d1 | save blocked in d1 for signal handling
- notl d0
- andl a0@(LTS_SIGNAL),d0
- bne Lsignal_return
- 2: movel sp@(LOFF_USP),a0
- movec a0,usp
- moveml sp@+,d1-a6
- movel sp@+,d0 | restore d0
- addql #8,sp | skip the usp and orig_d0
- addw sp@+,sp | add the stack adjustment
- rte
- Lsignal_return:
- movel sp,sp@-
- movel d1,sp@-
- bsr _do_signal
- addql #8,sp
- bras 2b
-
-
- /*
- ** This is the main interrupt handler, responsible for calling process_int()
- */
- _inthandler:
- moveml a0-a1/d0-d1,sp@- | save registers
-
- addql #1,_intr_count
- movew sp@(22),d0 | put exception # in d0
- andil #0xfff,d0 | mask out format nybble
-
- subil #0x60,d0 | convert from vector offset...
- lsrl #2,d0 | ...to IRQ number
-
- beq Lspurious | if zero, spurious interrupt
- pea sp@ | push interrupt stack frame address
- movel d0,sp@- | put IRQ # on stack
- jbsr _process_int | process the IRQ
- addql #8,sp | pop parameters off stack
-
- subql #1,_intr_count
-
-
- /* maybe process software interrupts */
- tstl _intr_count
- bne 1f
-
- movel _bh_mask,d0
- andl d0,_bh_active
- beq 1f
-
- movew sr,sp@-
- addql #1,_intr_count
- andiw #0xfbff,sr | allow interrupts
- jbsr _do_bottom_half
- movew sp@+,sr
- subql #1,_intr_count
- 1:
- /*
- * check if returning to user mode.
- * if so, pop stuff off interrupt stack, switch
- * from interrupt mode to master mode, push
- * stack frame on kernel stack and jump to ret_from_exception
- */
- moveb sp@(22),d0 | get format word from int stack
- andb #0xf0,d0 | mask off format
- cmpb #0x10,d0 | check if throwaway frame
- beq Lnotstacked | if, not: interrupts stacked, rte
- moveml sp@+,a0-a1/d0-d1 | restore registers
- rte
- Lnotstacked:
- movec msp,a0 | get the master stack pointer
- btst #0x5,a0@ | supervisor bit set in saved SR?
- moveml sp@+,a0-a1/d0-d1 | restore registers
- beq Lnotkernel | if in kernel, rte
- rte
- Lnotkernel:
- addql #8,sp | throw away throwaway stack frame
- oriw #0x1000,sr | set master bit in SR (sp is now msp)
- andiw #0xfbff,sr | allow interrupts
- clrw sp@- | stack adjustment
- subql #8,sp | make room for usp and orig_d0
- moveml d0,sp@- | save registers as for syscall
- moveml d1-a6,sp@-
- moveq #-1,d0
- movel d0,sp@(LOFF_ORIG_D0) | indicate stack frame not for syscall
- movec usp,a0
- movel a0,sp@(LOFF_USP) | save usp
-
- | save top of frame
- movel _current,a0
- movel sp,a0@(LESP0_OFFSET)
-
- bra _ret_from_exception | deliver signals, reschedule etc..
- Lspurious:
- addql #1,_num_spurious | increment the counter of spurious
- | interrupts.
- subql #1,_intr_count
- moveml sp@+,a0-a1/d0-d1 | restore registers
- rte | return from exception
-