diff options
Diffstat (limited to 'arch/mips/kernel/entry.S')
-rw-r--r-- | arch/mips/kernel/entry.S | 661 |
1 files changed, 181 insertions, 480 deletions
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index 787e2bbf4..6072afae2 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -1,28 +1,31 @@ /* - * arch/mips/kernel/entry.S + * Low level exception handling * - * Copyright (C) 1994, 1995 Waldorf Electronics - * written by Ralf Baechle and Andreas Busse + * 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. The ISA dependend TLB - * code is in arch/mips/kernel/tlb.S + * and faults that can result in a task-switch. The ISA dependent TLB + * code is in arch/mips/<ISA-level>/<cputype>.S */ - #include <linux/sys.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/processor.h> +#include <asm/regdef.h> +#include <asm/fpregdef.h> +#include <asm/unistd.h> /* * These are offsets into the task-struct. @@ -36,6 +39,16 @@ flags = 20 errno = 24 exec_domain = 60 +#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 @@ -50,126 +63,16 @@ handle_bottom_half: jal do_bottom_half mtc0 t0,CP0_STATUS # delay slot mtc0 s3,CP0_STATUS # Restore old IRQ state - j 9f + b 9f sw s1,%lo(intr_count)(s0) # delay slot -reschedule: - lui ra,%hi(ret_from_sys_call) - j schedule - addiu ra,%lo(ret_from_sys_call) # delay slot - - .align 5 - NESTED(handle_sys, FR_SIZE, sp) - .set noat - SAVE_ALL - STI - .set at - /* - * Compute return address. We assume that syscalls never - * appear in delay slots. For the Linux/MIPS libc this - * assumption is always true. - */ - lw t3,FR_EPC(sp) - lw s1,FR_REG2(sp) - li t0,-ENOSYS - addiu 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,PTRLOG - lw s1,sys_call_table(s1) - lw s0,current - - beqz s1,ret_from_sys_call - lw t0,flags(s0) # delay slot - sll t0,26 # PF_TRACESYS - bltz t0,1f - sw zero,errno(s0) # delay slot - -#if 0 - lw t0,FR_ORIG_REG2(sp) - beq t0,4,1f - nop - la t0,sys_call_names - lw t1,FR_ORIG_REG2(sp) - sll t1,2 - addu t0,t1 - lw a1,(t0) - PRINT("%s(") - lw a1,FR_REG4(sp) - lw a2,FR_REG5(sp) - lw a3,FR_REG6(sp) - PRINT("%08lx, %08lx, %08lx, ") - lw a1,FR_REG7(sp) - lw a2,FR_EPC(sp) - lw a3,FR_REG31(sp) - PRINT("%08lx) epc %08lx ra %08lx ") -1: -#endif - 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,PTRSIZE*4(sp) # delay slot - -#if 0 - lw t0,FR_ORIG_REG2(sp) - beq t0,4,1f - nop - sw v0,xxx - lw a1,xxx - PRINT("res %08lx\n") - lw v0,xxx - .data -xxx: .word 0 - .text -1: -#endif - - lw t0,errno(s0) - sw v0,FR_REG2(sp) # save return value - subu t0,zero,t0 - beqz t0,ret_from_sys_call +reschedule: jal schedule nop # delay slot - /* - * 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,PTRSIZE*4(sp) # delay slot - - lw t0,errno(s0) - sw v0,FR_REG2(sp) - subu t0,zero,t0 # delay slot - beqz t0,1f - nop # delay slot - /* - * Fixme: should set error flag - */ -1: jal syscall_trace - sw t0,FR_REG2(sp) # delay slot - - .align 4 - .globl ret_from_sys_call -ret_from_sys_call: +EXPORT(ret_from_sys_call) lw t0,intr_count # bottom half bnez t0,return -9: - lw t0,bh_mask # delay slot + +9: lw t0,bh_mask # delay slot lw t1,bh_active # unused delay slot and t0,t1 bnez t0,handle_bottom_half @@ -187,15 +90,11 @@ ret_from_sys_call: lw s0,current lw t0,task - lw t1,state(s0) # state - beq s0,t0,return # task[0] cannot have signals - lw t0,counter(s0) # counter - bnez t1,reschedule # state == 0 ? 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) + lw t0,signal(s0) # delay slot nor t1,zero,a0 and t1,t0,t1 beqz t1,return @@ -203,423 +102,225 @@ ret_from_sys_call: jal do_signal move a1,sp # delay slot - + .set noat - .globl return -return: RESTORE_ALL +EXPORT(return) + RESTORE_ALL ERET .set at - END(handle_sys) /* - * Beware: interrupt, fast_interrupt and bad_interrupt have unusal - * calling conventions! + * Beware: timer_interrupt, interrupt, fast_interrupt and bad_interrupt + * have unusual calling conventions to speedup the mess. * - * t1 - interrupt number + * a0 - interrupt number * s2 - destroyed * return values: * v0 - return routine + * + * The timer interrupt is handled specially to insure that the jiffies + * variable is updated at all times. Specifically, the timer interrupt is + * just like the complete handlers except that it is invoked with interrupts + * disabled and should never re-enable them. If other interrupts were + * allowed to be processed while the timer interrupt is active, then the + * other interrupts would have to avoid using the jiffies variable for delay + * and interval timing operations to avoid hanging the system. */ .text .set at .align 5 - NESTED(interrupt, FR_SIZE, sp) +NESTED(timer_interrupt, FR_SIZE, sp) + move s2,ra + jal do_IRQ + move a1,sp # delay slot + .set reorder + la v0,ret_from_sys_call + jr s2 + .set noreorder + END(timer_interrupt) + + .align 5 +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 move a1,sp # delay slot mfc0 t0,CP0_STATUS # disable IRQs ori t0,1 xori t0,1 + mtc0 t0,CP0_STATUS + .set reorder la v0,ret_from_sys_call jr s2 - mtc0 t0,CP0_STATUS # delay slot + .set noreorder END(interrupt) .align 5 - NESTED(fast_interrupt, FR_SIZE, sp) +NESTED(fast_interrupt, FR_SIZE, sp) + .set reorder move s2,ra - move a0,t1 jal do_fast_IRQ - move a1,sp # delay slot - lui v0,%hi(return) + la v0,return jr s2 - addiu v0,%lo(return) # delay slot + .set noreorder END(fast_interrupt) - LEAF(bad_interrupt) /* * Don't return & unblock the pic */ +LEAF(bad_interrupt) + .set reorder + lw t0,%lo(intr_count)(s3) + subu t0,1 + .set noreorder j return - nop + sw t0,%lo(intr_count)(s3) # delay slot END(bad_interrupt) - .align 5 - LEAF(spurious_interrupt) + .text + .align 5 +LEAF(spurious_interrupt) /* - * Nothing happened... (whistle) + * Someone tried to fool us by sending an interrupt but we + * couldn't find a cause for it. */ - lui t1,%hi(spurious_count) - lw t0,%lo(spurious_count)(t1) - la v0,return - addiu t0,1 - jr ra - sw t0,%lo(spurious_count)(t1) + lui t1,%hi(spurious_count) + lw t0,%lo(spurious_count)(t1) + la v0,return + addiu t0,1 + jr ra + sw t0,%lo(spurious_count)(t1) END(spurious_interrupt) - - /* - * Build a default exception handler for the other R4x00 exceptions + * 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_HANDLER(exception) \ +#define __BUILD_clear_none(exception) \ + REG_S sp,FR_ORIG_REG2(sp); /* sp < 0 */ +#define __BUILD_clear_sys(exception) \ + REG_S v0,FR_ORIG_REG2(sp); \ + REG_S a3,FR_ORIG_REG7(sp); +#define __BUILD_clear_fpe(exception) \ + REG_S sp,FR_ORIG_REG2(sp); /* sp < 0 */ \ + cfc1 a1,fcr31; \ + li a2,~(0x3f<<12); \ + and a2,a1; \ + ctc1 a2,fcr31; +#define __BUILD_clear_watch(exception) \ + REG_S sp,FR_ORIG_REG2(sp); /* sp < 0 */ \ + mtc0 zero,CP0_WATCHLO; \ + mtc0 zero,CP0_WATCHHI +#define __BUILD_clear_ade(exception) \ + REG_S sp,FR_ORIG_REG2(sp); /* sp < 0 */ \ + MFC0 t0,CP0_BADVADDR; \ + REG_S t0,FR_BADVADDR(sp); +#define __BUILD_silent(exception) +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) +#define fmt "Got %s at %08x.\n" +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) +#define fmt "Got %s at %016Lx.\n" +#endif +#define __BUILD_verbose(exception) \ + la a1,8f; \ + TEXT (#exception); \ + REG_L a2,FR_EPC(sp); \ + PRINT(fmt) +#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,handler,clear,verbose) \ + .text; \ .align 5; \ NESTED(handle_##exception, FR_SIZE, sp); \ .set noat; \ SAVE_ALL; \ + __BUILD_clear_##clear(exception); \ STI; \ .set at; \ - la a1,8f; \ - TEXT (#exception); \ - lw a2,FR_EPC(sp); \ - PRINT("Got %s at %08x.\n"); \ - li a0,0; \ - li t0,-1; /* not a sys call */ \ - sw t0,FR_ORIG_REG2(sp); \ - jal do_##exception; \ + __BUILD_##verbose(exception); \ + REG_S sp,FR_ORIG_REG2(sp); /* not a sys call */ \ + jal do_##handler; \ move a0,sp; /* delay slot */ \ j ret_from_sys_call; \ nop; /* delay slot */ \ END(handle_##exception) - BUILD_HANDLER(adel) - BUILD_HANDLER(ades) - BUILD_HANDLER(ibe) - BUILD_HANDLER(dbe) - BUILD_HANDLER(ov) - BUILD_HANDLER(fpe) - BUILD_HANDLER(bp) - BUILD_HANDLER(tr) - BUILD_HANDLER(ri) - BUILD_HANDLER(cpu) - BUILD_HANDLER(vcei) - BUILD_HANDLER(vced) - BUILD_HANDLER(watch) - BUILD_HANDLER(reserved) - + BUILD_HANDLER(adel,ade,ade,silent) /* #4 */ + BUILD_HANDLER(ades,ade,ade,silent) /* #5 */ + BUILD_HANDLER(ibe,ibe,none,verbose) /* #6 */ + BUILD_HANDLER(dbe,dbe,none,verbose) /* #7 */ + BUILD_HANDLER(sys,sys,none,silent) /* #8 */ + BUILD_HANDLER(bp,bp,none,silent) /* #9 */ + BUILD_HANDLER(ri,ri,none,silent) /* #10 */ + BUILD_HANDLER(cpu,cpu,none,silent) /* #11 */ + BUILD_HANDLER(ov,ov,none,silent) /* #12 */ + BUILD_HANDLER(tr,tr,none,silent) /* #13 */ + BUILD_HANDLER(vcei,vcei,none,verbose) /* #14 */ + BUILD_HANDLER(fpe,fpe,fpe,silent) /* #15 */ + BUILD_HANDLER(watch,watch,watch,verbose) /* #23 */ + BUILD_HANDLER(vced,vced,none,verbose) /* #31 */ + BUILD_HANDLER(reserved,reserved,none,verbose) /* others */ /* * Exception handler table with 32 entries. * This might be extended to handle software exceptions */ .bss - .align 2 - EXPORT(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 - EXPORT(sys_call_table) - PTR sys_setup /* 0 */ - PTR sys_exit - PTR sys_fork - PTR sys_read - PTR sys_write - PTR sys_open /* 5 */ - PTR sys_close - PTR sys_waitpid - PTR sys_creat - PTR sys_link - PTR sys_unlink /* 10 */ - PTR sys_execve - PTR sys_chdir - PTR sys_time - PTR sys_mknod - PTR sys_chmod /* 15 */ - PTR sys_chown - PTR sys_break - PTR sys_stat - PTR sys_lseek - PTR sys_getpid /* 20 */ - PTR sys_mount - PTR sys_umount - PTR sys_setuid - PTR sys_getuid - PTR sys_stime /* 25 */ - PTR sys_ptrace - PTR sys_alarm - PTR sys_fstat - PTR sys_pause - PTR sys_utime /* 30 */ - PTR sys_stty - PTR sys_gtty - PTR sys_access - PTR sys_nice - PTR sys_ftime /* 35 */ - PTR sys_sync - PTR sys_kill - PTR sys_rename - PTR sys_mkdir - PTR sys_rmdir /* 40 */ - PTR sys_dup - PTR sys_pipe - PTR sys_times - PTR sys_prof - PTR sys_brk /* 45 */ - PTR sys_setgid - PTR sys_getgid - PTR sys_signal - PTR sys_geteuid - PTR sys_getegid /* 50 */ - PTR sys_acct - PTR sys_phys - PTR sys_lock - PTR sys_ioctl - PTR sys_fcntl /* 55 */ - PTR sys_mpx - PTR sys_setpgid - PTR sys_ulimit - PTR sys_olduname - PTR sys_umask /* 60 */ - PTR sys_chroot - PTR sys_ustat - PTR sys_dup2 - PTR sys_getppid - PTR sys_getpgrp /* 65 */ - PTR sys_setsid - PTR sys_sigaction - PTR sys_sgetmask - PTR sys_ssetmask - PTR sys_setreuid /* 70 */ - PTR sys_setregid - PTR sys_sigsuspend - PTR sys_sigpending - PTR sys_sethostname - PTR sys_setrlimit /* 75 */ - PTR sys_getrlimit - PTR sys_getrusage - PTR sys_gettimeofday - PTR sys_settimeofday - PTR sys_getgroups /* 80 */ - PTR sys_setgroups - PTR sys_select - PTR sys_symlink - PTR sys_lstat - PTR sys_readlink /* 85 */ - PTR sys_uselib - PTR sys_swapon - PTR sys_reboot - PTR old_readdir - PTR sys_mmap /* 90 */ - PTR sys_munmap - PTR sys_truncate - PTR sys_ftruncate - PTR sys_fchmod - PTR sys_fchown /* 95 */ - PTR sys_getpriority - PTR sys_setpriority - PTR sys_profil - PTR sys_statfs - PTR sys_fstatfs /* 100 */ - PTR sys_ioperm - PTR sys_socketcall - PTR sys_syslog - PTR sys_setitimer - PTR sys_getitimer /* 105 */ - PTR sys_newstat - PTR sys_newlstat - PTR sys_newfstat - PTR sys_uname - PTR sys_iopl /* 110 */ - PTR sys_vhangup - PTR sys_idle - PTR sys_vm86 - PTR sys_wait4 - PTR sys_swapoff /* 115 */ - PTR sys_sysinfo - PTR sys_ipc - PTR sys_fsync - PTR sys_sigreturn - PTR sys_clone /* 120 */ - PTR sys_setdomainname - PTR sys_newuname - PTR 0 #sys_modify_ldt - PTR sys_adjtimex - PTR sys_mprotect /* 125 */ - PTR sys_sigprocmask - PTR sys_create_module - PTR sys_init_module - PTR sys_delete_module - PTR sys_get_kernel_syms /* 130 */ - PTR sys_quotactl - PTR sys_getpgid - PTR sys_fchdir - PTR sys_bdflush - PTR sys_sysfs /* 135 */ - PTR sys_personality - PTR 0 /* for afs_syscall */ - PTR sys_setfsuid - PTR sys_setfsgid - PTR sys_llseek /* 140 */ - PTR sys_getdents - PTR sys_select - PTR sys_flock - .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 - EXPORT(IRQ_vectors) - .fill 16,4,0 + /* + * Linux flavoured syscalls. + */ +#define SYS(call, narg) PTR call +#include "syscalls.h" - .text -sys_call_names: - TTABLE ("setup") - TTABLE ("exit") - TTABLE ("fork") - TTABLE ("read") - TTABLE ("write") - TTABLE ("open") - TTABLE ("close") - TTABLE ("waitpid") - TTABLE ("creat") - TTABLE ("link") - TTABLE ("unlink") - TTABLE ("execve") - TTABLE ("chdir") - TTABLE ("time") - TTABLE ("mknod") - TTABLE ("chmod") - TTABLE ("chown") - TTABLE ("break") - TTABLE ("stat") - TTABLE ("lseek") - TTABLE ("getpid") - TTABLE ("mount") - TTABLE ("umount") - TTABLE ("setuid") - TTABLE ("getuid") - TTABLE ("stime") - TTABLE ("ptrace") - TTABLE ("alarm") - TTABLE ("fstat") - TTABLE ("pause") - TTABLE ("utime") - TTABLE ("stty") - TTABLE ("gtty") - TTABLE ("access") - TTABLE ("nice") - TTABLE ("ftime") - TTABLE ("sync") - TTABLE ("kill") - TTABLE ("rename") - TTABLE ("mkdir") - TTABLE ("rmdir") - TTABLE ("dup") - TTABLE ("pipe") - TTABLE ("times") - TTABLE ("prof") - TTABLE ("brk") - TTABLE ("setgid") - TTABLE ("getgid") - TTABLE ("signal") - TTABLE ("geteuid") - TTABLE ("getegid") - TTABLE ("acct") - TTABLE ("phys") - TTABLE ("lock") - TTABLE ("ioctl") - TTABLE ("fcntl") - TTABLE ("mpx") - TTABLE ("setpgid") - TTABLE ("ulimit") - TTABLE ("olduname") - TTABLE ("umask") - TTABLE ("chroot") - TTABLE ("ustat") - TTABLE ("dup2") - TTABLE ("getppid") - TTABLE ("getpgrp") - TTABLE ("setsid") - TTABLE ("sigaction") - TTABLE ("sgetmask") - TTABLE ("ssetmask") - TTABLE ("setreuid") - TTABLE ("setregid") - TTABLE ("sigsuspend") - TTABLE ("sigpending") - TTABLE ("sethostname") - TTABLE ("setrlimit") - TTABLE ("getrlimit") - TTABLE ("getrusage") - TTABLE ("gettimeofday") - TTABLE ("settimeofday") - TTABLE ("getgroups") - TTABLE ("setgroups") - TTABLE ("select") - TTABLE ("symlink") - TTABLE ("lstat") - TTABLE ("readlink") - TTABLE ("uselib") - TTABLE ("swapon") - TTABLE ("reboot") - TTABLE ("readdir") - TTABLE ("mmap") - TTABLE ("munmap") - TTABLE ("truncate") - TTABLE ("ftruncate") - TTABLE ("fchmod") - TTABLE ("fchown") - TTABLE ("getpriority") - TTABLE ("setpriority") - TTABLE ("profil") - TTABLE ("statfs") - TTABLE ("fstatfs") - TTABLE ("ioperm") - TTABLE ("socketcall") - TTABLE ("syslog") - TTABLE ("setitimer") - TTABLE ("getitimer") - TTABLE ("newstat") - TTABLE ("newlstat") - TTABLE ("newfstat") - TTABLE ("uname") - TTABLE ("iopl") - TTABLE ("vhangup") - TTABLE ("idle") - TTABLE ("vm86") - TTABLE ("wait4") - TTABLE ("swapoff") - TTABLE ("sysinfo") - TTABLE ("ipc") - TTABLE ("fsync") - TTABLE ("sigreturn") - TTABLE ("clone") - TTABLE ("setdomainname") - TTABLE ("newuname") - TTABLE ("modify_ldt (unused)") - TTABLE ("adjtimex") - TTABLE ("mprotect") - TTABLE ("sigprocmask") - TTABLE ("create_module") - TTABLE ("init_module") - TTABLE ("delete_module") - TTABLE ("get_kernel_syms") - TTABLE ("quotactl") - TTABLE ("getpgid") - TTABLE ("fchdir") - TTABLE ("bdflush") - TTABLE ("sysfs") - TTABLE ("personality") - TTABLE ("afs_syscall") /* for afs_syscall */ - TTABLE ("setfsuid") - TTABLE ("setfsgid") - TTABLE ("llseek") - TTABLE ("sys_getdents") - TTABLE ("sys_select") - TTABLE ("sys_flock") +/* + * Number of arguments of each syscall + * FIXME: This table contains huge empty areas wasting memory. + */ +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" |