diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-04-28 01:09:25 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-04-28 01:09:25 +0000 |
commit | b9ba7aeb165cffecdffb60aec8c3fa8d590d9ca9 (patch) | |
tree | 42d07b0c7246ae2536a702e7c5de9e2732341116 /arch/sh/kernel | |
parent | 7406b0a326f2d70ade2671c37d1beef62249db97 (diff) |
Merge with 2.3.99-pre6.
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r-- | arch/sh/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/sh/kernel/entry.S | 442 | ||||
-rw-r--r-- | arch/sh/kernel/fpu.c | 49 | ||||
-rw-r--r-- | arch/sh/kernel/head.S | 16 | ||||
-rw-r--r-- | arch/sh/kernel/irq.c | 2 | ||||
-rw-r--r-- | arch/sh/kernel/irq_imask.c | 12 | ||||
-rw-r--r-- | arch/sh/kernel/irq_onchip.c | 4 | ||||
-rw-r--r-- | arch/sh/kernel/process.c | 31 | ||||
-rw-r--r-- | arch/sh/kernel/setup.c | 19 | ||||
-rw-r--r-- | arch/sh/kernel/signal.c | 30 | ||||
-rw-r--r-- | arch/sh/kernel/time.c | 41 | ||||
-rw-r--r-- | arch/sh/kernel/traps.c | 10 |
12 files changed, 391 insertions, 266 deletions
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 8996a13dc..266aafe1f 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -29,7 +29,6 @@ all: kernel.o head.o init_task.o entry.o: entry.S head.o: head.S - $(CC) $(AFLAGS) -traditional -c $*.S -o $*.o clean: diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S index 46ad20f53..00372811c 100644 --- a/arch/sh/kernel/entry.S +++ b/arch/sh/kernel/entry.S @@ -14,6 +14,8 @@ #include <linux/linkage.h> #include <linux/config.h> +#define COMPAT_OLD_SYSCALL_ABI 1 + ! NOTE: ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address ! to be jumped is too far, but it causes illegal slot exception. @@ -31,26 +33,24 @@ * if the order here is changed, it needs to be * updated in ptrace.c and ptrace.h * - * syscall # - * ssr - * r0 + * $r0 * ... - * r15 = stack pointer - * gbr - * mach - * macl - * pr - * spc + * $r15 = stack pointer + * $spc + * $pr + * $ssr + * $gbr + * $mach + * $macl + * syscall # * */ /* * These are offsets into the task-struct. */ -state = 0 flags = 4 sigpending = 8 -addr_limit = 12 need_resched = 20 PF_TRACESYS = 0x00000020 @@ -75,30 +75,35 @@ MMU_TEA = 0xff00000c ! TLB Exception Address Register #endif /* Offsets to the stack */ -SYSCALL_NR = 0 -SR = 4 -R0 = 8 -SP = (8+15*4) +R0 = 0 /* Return value */ +SP = (15*4) +SR = (16*4+8) +SYSCALL_NR = (16*4+6*4) + #define k0 r0 #define k1 r1 #define k2 r2 #define k3 r3 +#define k4 r4 -#define kernel_sp r4 /* r4_bank1 */ -#define ksp r4_bank /* r4_bank1 */ +#define current r7 /* r7_bank1 */ +#define g_imask r6 /* r6_bank1 */ +#define k_current r7_bank /* r7_bank1 */ +#define k_g_imask r6_bank /* r6_bank1 */ #define k_ex_code r2_bank /* r2_bank1 */ -/* Kernel mode register usage: - k0 scratch - k1 scratch - k2 scratch (Exception code) - k3 scratch (Return address) - k4 Stack base = current+8192 - k5 Global Interrupt Mask (0--15) - k6 reserved - k7 reserved -*/ +/* + * Kernel mode register usage: + * k0 scratch + * k1 scratch + * k2 scratch (Exception code) + * k3 scratch (Return address) + * k4 scratch + * k5 reserved + * k6 Global Interrupt Mask (0--15 << 4) + * k7 CURRENT (pointer to current task) + */ ! ! TLB Miss / Initial Page write exception handling @@ -114,42 +119,60 @@ SP = (8+15*4) ! this first version depends *much* on C implementation. ! -#define RESTORE_FLAGS() \ - mov.l @(SR,$r15), $r0; \ - and #0xf0, $r0; \ - shlr8 $r0; \ - cmp/eq #0x0f, $r0; \ - bt 9f; \ - mov.l __INV_IMASK, $r1; \ - stc $sr, $r0; \ - and $r1, $r0; \ - stc $r5_bank, $r1; \ - or $r1, $r0; \ - ldc $r0, $sr +#define STI() \ + mov.l __INV_IMASK, $r11; \ + stc $sr, $r10; \ + and $r11, $r10; \ + stc $k_g_imask, $r11; \ + or $r11, $r10; \ + ldc $r10, $sr .balign 4 -tlb_protection_violation_load: tlb_miss_load: - mov #-1, $r0 - mov.l $r0, @$r15 ! syscall nr = -1 mov.l 2f, $r0 mov.l @$r0, $r6 - RESTORE_FLAGS() -9: mov $r15, $r4 + STI() + mov $r15, $r4 mov.l 1f, $r0 jmp @$r0 mov #0, $r5 .balign 4 -tlb_protection_violation_store: tlb_miss_store: + mov.l 2f, $r0 + mov.l @$r0, $r6 + STI() + mov $r15, $r4 + mov.l 1f, $r0 + jmp @$r0 + mov #1, $r5 + + .balign 4 initial_page_write: - mov #-1, $r0 - mov.l $r0, @$r15 ! syscall nr = -1 mov.l 2f, $r0 mov.l @$r0, $r6 - RESTORE_FLAGS() -9: mov $r15, $r4 + STI() + mov $r15, $r4 + mov.l 1f, $r0 + jmp @$r0 + mov #1, $r5 + + .balign 4 +tlb_protection_violation_load: + mov.l 2f, $r0 + mov.l @$r0, $r6 + STI() + mov $r15, $r4 + mov.l 1f, $r0 + jmp @$r0 + mov #0, $r5 + + .balign 4 +tlb_protection_violation_store: + mov.l 2f, $r0 + mov.l @$r0, $r6 + STI() + mov $r15, $r4 mov.l 1f, $r0 jmp @$r0 mov #1, $r5 @@ -162,8 +185,6 @@ initial_page_write: .balign 4 /* Unwind the stack and jmp to the debug entry */ debug: - add #4, $r15 ! skip syscall number - mov.l @$r15+, $r11 ! SSR mov.l @$r15+, $r0 mov.l @$r15+, $r1 mov.l @$r15+, $r2 @@ -172,11 +193,10 @@ debug: mov.l @$r15+, $r5 mov.l @$r15+, $r6 mov.l @$r15+, $r7 - stc $sr, $r14 - mov.l 1f, $r9 ! BL =1, RB=1 - or $r9, $r14 - ldc $r14, $sr ! here, change the register bank - mov $r11, $k1 + stc $sr, $r8 + mov.l 1f, $r9 ! BL =1, RB=1, IMASK=0x0F + or $r9, $r8 + ldc $r8, $sr ! here, change the register bank mov.l @$r15+, $r8 mov.l @$r15+, $r9 mov.l @$r15+, $r10 @@ -185,11 +205,12 @@ debug: mov.l @$r15+, $r13 mov.l @$r15+, $r14 mov.l @$r15+, $k0 + ldc.l @$r15+, $spc + lds.l @$r15+, $pr + mov.l @$r15+, $k1 ldc.l @$r15+, $gbr lds.l @$r15+, $mach lds.l @$r15+, $macl - lds.l @$r15+, $pr - ldc.l @$r15+, $spc mov $k0, $r15 ! mov.l 2f, $k0 @@ -203,11 +224,10 @@ debug: .balign 4 error: ! - RESTORE_FLAGS() -9: mov.l 1f, $r1 - mov #-1, $r0 - jmp @$r1 - mov.l $r0, @$r15 ! syscall nr = -1 + STI() + mov.l 1f, $r0 + jmp @$r0 + nop .balign 4 1: .long SYMBOL_NAME(do_exception_error) @@ -222,76 +242,106 @@ ENTRY(ret_from_fork) bra SYMBOL_NAME(ret_from_syscall) add #4, $r15 ! pop down bogus r0 (see switch_to MACRO) -! -! The immediate value of "trapa" indicates the number of arguments -! placed on the stack. -! -! Note that TRA register contains the value = Imm x 4. -! +/* + * Old syscall interface: + * + * Syscall #: R0 + * Arguments #0 to #3: R4--R7 + * more arguments: On the stack + * TRA: (number of arguments on the stack) x 4 + * + * New syscall interface: + * + * Syscall #: R3 + * Arguments #0 to #3: R4--R7 + * Arguments #4 to #6: R0, R1, R2 + * TRA: (number of arguments + 0x10) x 4 + * + */ + system_call: - mov.l 1f, $r2 - mov.l @$r2, $r8 - ! - ! DEBUG DEBUG - ! mov.l led, $r1 - ! mov $r0, $r2 - ! mov.b $r2, @$r1 + mov.l 1f, $r9 + mov.l @$r9, $r8 ! #ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB - mov #0x20, $r1 - extu.b $r1, $r1 - shll2 $r1 - cmp/hs $r1, $r8 + mov #0x20, $r9 + extu.b $r9, $r9 + shll2 $r9 + cmp/hs $r9, $r8 bt debug #endif ! - mov $r0, $r2 - RESTORE_FLAGS() -9: mov.l __n_sys, $r1 - cmp/hs $r1, $r2 + mov #SYSCALL_NR, $r14 + add $r15, $r14 + ! + mov #0x40, $r9 +#ifdef COMPAT_OLD_SYSCALL_ABI + cmp/hs $r9, $r8 + mov $r0, $r10 + bf/s 0f + mov $r0, $r9 +#endif + ! New Syscall ABI + sub $r9, $r8 + shlr2 $r8 + shll8 $r8 + shll8 $r8 + mov $r3, $r10 + or $r8, $r10 ! Encode syscall # and # of arguments + ! + mov $r3, $r9 + mov #0, $r8 +0: + mov.l $r10, @$r14 ! set syscall_nr + STI() + mov.l __n_sys, $r10 + cmp/hs $r10, $r9 bt badsys ! - stc $ksp, $r1 - mov.l __tsk_flags, $r0 - add $r0, $r1 ! - mov.l @$r1, $r0 ! Is it trace? - tst #PF_TRACESYS, $r0 +#ifdef COMPAT_OLD_SYSCALL_ABI + ! Build the stack frame if TRA > 0 + mov $r8, $r10 + cmp/pl $r10 + bf 0f + mov.l @(SP,$r15), $r0 ! get original stack +7: add #-4, $r10 +4: mov.l @($r0,$r10), $r1 ! May cause address error exception.. + mov.l $r1, @-$r15 + cmp/pl $r10 + bt 7b +#endif +0: stc $k_current, $r11 + mov.l @(flags,$r11), $r10 ! Is it trace? + mov #PF_TRACESYS, $r11 + tst $r11, $r10 bt 5f ! Trace system call - mov #-ENOSYS, $r1 - mov.l $r1, @(R0,$r15) - mov.l 3f, $r1 - jsr @$r1 + mov #-ENOSYS, $r11 + mov.l $r11, @(R0,$r15) + mov.l 2f, $r11 + jsr @$r11 nop - mova 3f, $r0 + mov.l __syscall_ret_trace, $r10 bra 6f - lds $r0, $pr + lds $r10, $pr ! -5: mova syscall_ret, $r0 - lds $r0, $pr - ! Build the stack frame if TRA > 0 -6: mov $r2, $r3 - mov $r8, $r2 - cmp/pl $r8 - bf 0f - mov #SP, $r0 - mov.l @($r0,$r15), $r0 ! get original stack -7: add #-4, $r8 -4: mov.l @($r0,$r8), $r1 ! May cause address error exception.. - mov.l $r1, @-$r15 - cmp/pl $r8 - bt 7b +5: mov.l __syscall_ret, $r10 + lds $r10, $pr ! -0: mov $r3, $r0 - shll2 $r0 ! x4 - mov.l __sct, $r1 - add $r1, $r0 - mov.l @$r0, $r1 - jmp @$r1 - mov $r2, $r8 +6: mov $r9, $r10 + shll2 $r10 ! x4 + mov.l __sct, $r11 + add $r11, $r10 + mov.l @$r10, $r11 + jmp @$r11 + nop + ! In case of trace .balign 4 -3: add $r8, $r15 ! pop off the arguments +3: +#ifdef COMPAT_OLD_SYSCALL_ABI + add $r8, $r15 ! pop off the arguments +#endif mov.l $r0, @(R0,$r15) ! save the return value mov.l 2f, $r1 mova SYMBOL_NAME(ret_from_syscall), $r0 @@ -302,9 +352,12 @@ system_call: 2: .long SYMBOL_NAME(syscall_trace) __n_sys: .long NR_syscalls __sct: .long SYMBOL_NAME(sys_call_table) -__tsk_flags: .long flags-8192 ! offset from stackbase to tsk->flags -led: .long 0xa8000000 ! For my board -- gN +__syscall_ret_trace: + .long 3b +__syscall_ret: + .long SYMBOL_NAME(syscall_ret) +#ifdef COMPAT_OLD_SYSCALL_ABI .section .fixup,"ax" fixup_syscall_argerr: rts @@ -316,6 +369,7 @@ fixup_syscall_argerr: .balign 4 .long 4b,fixup_syscall_argerr .previous +#endif .balign 4 reschedule: @@ -327,23 +381,25 @@ reschedule: 1: .long SYMBOL_NAME(schedule) ENTRY(ret_from_irq) - mov.l @(SR,$r15), $r0 ! get status register + mov #SR, $r0 + mov.l @($r0,$r15), $r0 ! get status register shll $r0 shll $r0 ! kernel space? bt restore_all ! Yes, it's from kernel, go back soon ! - RESTORE_FLAGS() -9: bra ret_with_reschedule + STI() + bra ret_with_reschedule nop ENTRY(ret_from_exception) - mov.l @(SR,$r15), $r0 ! get status register + mov #SR, $r0 + mov.l @($r0,$r15), $r0 ! get status register shll $r0 shll $r0 ! kernel space? bt restore_all ! Yes, it's from kernel, go back soon ! - RESTORE_FLAGS() -9: bra ret_from_syscall + STI() + bra ret_from_syscall nop .balign 4 __INV_IMASK: @@ -351,7 +407,9 @@ __INV_IMASK: .balign 4 syscall_ret: +#ifdef COMPAT_OLD_SYSCALL_ABI add $r8, $r15 ! pop off the arguments +#endif mov.l $r0, @(R0,$r15) ! save the return value /* fall through */ @@ -366,9 +424,7 @@ handle_softirq: jsr @$r0 nop ret_with_reschedule: - stc $ksp, $r1 - mov.l __minus8192, $r0 - add $r0, $r1 + stc $k_current, $r1 mov.l @(need_resched,$r1), $r0 tst #0xff, $r0 bf reschedule @@ -389,30 +445,14 @@ __softirq_state: .long SYMBOL_NAME(softirq_state) __do_softirq: .long SYMBOL_NAME(do_softirq) -__minus8192: - .long -8192 ! offset from stackbase to tsk .balign 4 restore_all: #if defined(__SH4__) - mov.l __fpu_prepare_fd, $r1 - jsr @$r1 + mov.l __fpu_prepare_fd, $r0 + jsr @$r0 stc $sr, $r4 #endif - add #4, $r15 ! Skip syscall number - mov.l @$r15+, $r11 ! Got SSR into R11 -#if defined(__SH4__) - mov $r11, $r12 -#endif - ! - mov.l 1f, $r1 - stc $sr, $r0 - and $r1, $r0 ! Get FD - mov.l 2f, $r1 - and $r1, $r11 - or $r0, $r11 ! Inherit the FD value of SR - stc $r5_bank, $r0 - or $r0, $r11 ! Inherit the IMASK value ! mov.l @$r15+, $r0 mov.l @$r15+, $r1 @@ -422,14 +462,12 @@ restore_all: mov.l @$r15+, $r5 mov.l @$r15+, $r6 mov.l @$r15+, $r7 - stc $sr, $r14 + ! + stc $sr, $r8 mov.l __blrb_flags, $r9 ! BL =1, RB=1 - or $r9, $r14 - ldc $r14, $sr ! here, change the register bank - mov $r11, $k1 -#if defined(__SH4__) - mov $r12, $k2 -#endif + or $r9, $r8 + ldc $r8, $sr ! here, change the register bank + ! mov.l @$r15+, $r8 mov.l @$r15+, $r9 mov.l @$r15+, $r10 @@ -437,20 +475,33 @@ restore_all: mov.l @$r15+, $r12 mov.l @$r15+, $r13 mov.l @$r15+, $r14 - mov.l @$r15+, $k0 ! original stack + mov.l @$r15+, $k4 ! original stack pointer + ldc.l @$r15+, $spc + lds.l @$r15+, $pr + mov.l @$r15+, $k3 ! original SR ldc.l @$r15+, $gbr lds.l @$r15+, $mach lds.l @$r15+, $macl - lds.l @$r15+, $pr - ldc.l @$r15+, $spc - ldc $k1, $ssr + add #4, $r15 ! Skip syscall number + ! + ! Calculate new SR value + mov $k3, $k2 ! original SR value + mov.l 1f, $k1 + stc $sr, $k0 + and $k1, $k0 ! Get current FD-bit + mov.l 2f, $k1 + and $k1, $k2 ! Mask orignal SR value + or $k0, $k2 ! Inherit current FD-bit + or $g_imask, $k2 ! Inherit the IMASK-bits + ldc $k2, $ssr + ! #if defined(__SH4__) - shll $k1 - shll $k1 + shll $k2 + shll $k2 bf 9f ! user mode /* Kernel to kernel transition */ mov.l 1f, $k1 - tst $k1, $k2 + tst $k1, $k3 bf 9f ! it hadn't FPU ! Kernel to kernel and FPU was used ! There's the case we don't get FPU now @@ -462,14 +513,15 @@ restore_all: ldc $k2, $sr ! Grab FPU mov.l __init_task_flags, $k1 mov.l @$k1, $k2 - mov.l __PF_USEDFPU, $k1 - or $k1, $k2 - mov.l __init_task_flags, $k1 + mov.l __PF_USEDFPU, $k0 + or $k0, $k2 mov.l $k2, @$k1 ! Set init_task.flags |= PF_USEDFPU ! ! Restoring FPU... ! -7: fmov.s @$r15+, $fr0 +7: mov.l 3f, $k1 + lds $k1, $fpscr + fmov.s @$r15+, $fr0 fmov.s @$r15+, $fr1 fmov.s @$r15+, $fr2 fmov.s @$r15+, $fr3 @@ -489,7 +541,7 @@ restore_all: lds.l @$r15+, $fpul 9: #endif - mov $k0, $r15 + mov $k4, $r15 rte nop @@ -505,6 +557,7 @@ __PF_USEDFPU: #endif 1: .long 0x00008000 ! FD 2: .long 0xffff7f0f ! ~(IMASK+FD) +3: .long 0x00080000 ! SZ=0, PR=1 ! Exception Vector Base ! @@ -569,6 +622,9 @@ handle_exception: ! /* Currently it's not the case for GCC (only udivsi3_i4, divsi3_i4) */ sts.l $fpul, @-$r15 sts.l $fpscr, @-$r15 + mov.l 6f, $k1 + lds $k1, $fpscr + mov.l 3f, $k1 fmov.s $fr15, @-$r15 fmov.s $fr14, @-$r15 fmov.s $fr13, @-$r15 @@ -584,40 +640,47 @@ handle_exception: fmov.s $fr3, @-$r15 fmov.s $fr2, @-$r15 fmov.s $fr1, @-$r15 - fmov.s $fr0, @-$r15 bra 9f - mov.l 3f, $k1 + fmov.s $fr0, @-$r15 #else mov.l 3f, $k1 bt/s 9f ! it's from kernel to kernel transition mov $r15, $k0 ! save original stack to k0 anyway #endif 8: /* User space to kernel */ - mov $kernel_sp, $r15 ! change to kernel stack - mov.l 4f, $k1 ! let kernel release FPU -9: stc.l $spc, @-$r15 - sts.l $pr, @-$r15 + mov #0x20, $k1 + shll8 $k1 ! $k1 <= 8192 + add $current, $k1 + mov $k1, $r15 ! change to kernel stack ! - lds $k3, $pr ! Set the return address to pr + mov.l 4f, $k1 ! let kernel release FPU +9: mov #-1, $k4 + mov.l $k4, @-$r15 ! syscall_nr (default: -1) ! sts.l $macl, @-$r15 sts.l $mach, @-$r15 stc.l $gbr, @-$r15 - mov.l $k0, @-$r15 ! save orignal stack - mov.l $r14, @-$r15 + stc.l $ssr, @-$r15 + sts.l $pr, @-$r15 + stc.l $spc, @-$r15 ! - stc $sr, $r14 ! Back to normal register bank, and - or $k1, $r14 ! Block all interrupts, may release FPU - mov.l 5f, $k1 - and $k1, $r14 ! ... - ldc $r14, $sr ! ...changed here. + lds $k3, $pr ! Set the return address to pr ! + mov.l $k0, @-$r15 ! save orignal stack + mov.l $r14, @-$r15 mov.l $r13, @-$r15 mov.l $r12, @-$r15 mov.l $r11, @-$r15 mov.l $r10, @-$r15 mov.l $r9, @-$r15 mov.l $r8, @-$r15 + ! + stc $sr, $r8 ! Back to normal register bank, and + or $k1, $r8 ! Block all interrupts, may release FPU + mov.l 5f, $k1 + and $k1, $r8 ! ... + ldc $r8, $sr ! ...changed here. + ! mov.l $r7, @-$r15 mov.l $r6, @-$r15 mov.l $r5, @-$r15 @@ -626,23 +689,22 @@ handle_exception: mov.l $r2, @-$r15 mov.l $r1, @-$r15 mov.l $r0, @-$r15 - stc.l $ssr, @-$r15 - mov.l $r0, @-$r15 ! push $r0 again (for syscall number) - ! Then, dispatch to the handler, according to the excepiton code. - stc $k_ex_code, $r1 - shlr2 $r1 - shlr $r1 - mov.l 1f, $r0 - add $r1, $r0 - mov.l @$r0, $r0 - jmp @$r0 - mov.l @$r15, $r0 ! recovering $r0.. + ! Then, dispatch to the handler, according to the exception code. + stc $k_ex_code, $r8 + shlr2 $r8 + shlr $r8 + mov.l 1f, $r9 + add $r8, $r9 + mov.l @$r9, $r9 + jmp @$r9 + nop .balign 4 1: .long SYMBOL_NAME(exception_handling_table) 2: .long 0x00008000 ! FD=1 3: .long 0x000000f0 ! FD=0, IMASK=15 4: .long 0x000080f0 ! FD=1, IMASK=15 5: .long 0xcfffffff ! RB=0, BL=0 +6: .long 0x00080000 ! SZ=0, PR=1 none: rts diff --git a/arch/sh/kernel/fpu.c b/arch/sh/kernel/fpu.c index 5301a1333..cbeb60d31 100644 --- a/arch/sh/kernel/fpu.c +++ b/arch/sh/kernel/fpu.c @@ -23,6 +23,7 @@ save_fpu(struct task_struct *tsk) { asm volatile("sts.l $fpul, @-%0\n\t" "sts.l $fpscr, @-%0\n\t" + "lds %1, $fpscr\n\t" "frchg\n\t" "fmov.s $fr15, @-%0\n\t" "fmov.s $fr14, @-%0\n\t" @@ -58,7 +59,8 @@ save_fpu(struct task_struct *tsk) "fmov.s $fr1, @-%0\n\t" "fmov.s $fr0, @-%0" : /* no output */ - : "r" ((char *)(&tsk->thread.fpu.hard.status)) + : "r" ((char *)(&tsk->thread.fpu.hard.status)), + "r" (FPSCR_INIT) : "memory"); tsk->flags &= ~PF_USEDFPU; @@ -68,7 +70,8 @@ save_fpu(struct task_struct *tsk) static void restore_fpu(struct task_struct *tsk) { - asm volatile("fmov.s @%0+, $fr0\n\t" + asm volatile("lds %1, $fpscr\n\t" + "fmov.s @%0+, $fr0\n\t" "fmov.s @%0+, $fr1\n\t" "fmov.s @%0+, $fr2\n\t" "fmov.s @%0+, $fr3\n\t" @@ -105,7 +108,7 @@ restore_fpu(struct task_struct *tsk) "lds.l @%0+, $fpscr\n\t" "lds.l @%0+, $fpul\n\t" : /* no output */ - : "r" (&tsk->thread.fpu) + : "r" (&tsk->thread.fpu), "r" (FPSCR_INIT) : "memory"); } @@ -163,7 +166,6 @@ do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long { struct task_struct *tsk = current; - regs.syscall_nr = -1; regs.pc += 2; grab_fpu(); @@ -179,15 +181,34 @@ do_fpu_state_restore(unsigned long r4, unsigned long r5, unsigned long r6, { struct task_struct *tsk = current; - regs.syscall_nr = -1; - if (!user_mode(®s)) { if (tsk != &init_task) { unlazy_fpu(tsk); } tsk = &init_task; - if (tsk->flags & PF_USEDFPU) - BUG(); + if (tsk->flags & PF_USEDFPU) { + /* + * This weird situation can be occurred. + * + * There's race condition in __cli: + * + * (1) $SR --> register + * (2) Set IMASK of register + * (3) $SR <-- register + * + * Between (1) and (2), or (2) and (3) getting + * interrupt, and interrupt handler (or + * softirq) may use FPU. + * + * Then, SR.FD is overwritten by (3). + * + * This results init_task.PF_USEDFPU is on, + * with SR.FD == 1. + * + */ + release_fpu(); + return; + } } grab_fpu(); @@ -216,8 +237,8 @@ fpu_prepare_fd(unsigned long sr, unsigned long r5, unsigned long r6, grab_fpu(); else { if (!(sr & SR_FD)) { - release_fpu(); BUG(); + release_fpu(); } } return; @@ -228,16 +249,20 @@ fpu_prepare_fd(unsigned long sr, unsigned long r5, unsigned long r6, grab_fpu(); else { if (init_task.flags & PF_USEDFPU) { - init_task.flags &= ~PF_USEDFPU; - BUG(); + /* + * This weird situation can be occurred. + * See the comment in do_fpu_state_restore. + */ + grab_fpu(); + save_fpu(&init_task); } } } else { if (init_task.flags & PF_USEDFPU) save_fpu(&init_task); else { - release_fpu(); BUG(); + release_fpu(); } } } diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S index ae406d22d..db3e8b0a3 100644 --- a/arch/sh/kernel/head.S +++ b/arch/sh/kernel/head.S @@ -41,12 +41,21 @@ ENTRY(_stext) ldc $r0, $sr ! Initialize global interrupt mask mov #0, $r0 - ldc $r0, $r5_bank + ldc $r0, $r6_bank ! mov.l 2f, $r0 mov $r0, $r15 ! Set initial r15 (stack pointer) - ldc $r0, $r4_bank ! and stack base + mov #0x20, $r1 ! + shll8 $r1 ! $r1 = 8192 + sub $r1, $r0 ! + ldc $r0, $r7_bank ! ... and init_task ! +#if defined(__SH4__) + ! Initialize fpu + mov.l 7f, $r0 + jsr @$r0 + nop +#endif ! Enable cache mov.l 6f, $r0 jsr @$r0 @@ -71,3 +80,6 @@ ENTRY(_stext) 4: .long SYMBOL_NAME(_end) 5: .long SYMBOL_NAME(start_kernel) 6: .long SYMBOL_NAME(cache_init) +#if defined(__SH4__) +7: .long SYMBOL_NAME(fpu_init) +#endif diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index af03ef46d..c989796d7 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -235,8 +235,6 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, struct irqaction * action; unsigned int status; - regs.syscall_nr = -1; /* It's not system call */ - /* Get IRQ number */ asm volatile("stc $r2_bank, %0\n\t" "shlr2 %0\n\t" diff --git a/arch/sh/kernel/irq_imask.c b/arch/sh/kernel/irq_imask.c index 380acf405..7237ba3b5 100644 --- a/arch/sh/kernel/irq_imask.c +++ b/arch/sh/kernel/irq_imask.c @@ -43,7 +43,7 @@ static unsigned int startup_imask_irq(unsigned int irq) } static struct hw_interrupt_type imask_irq_type = { - "Interrupt using IMASK of SR register", + "SR.IMASK", startup_imask_irq, shutdown_imask_irq, enable_imask_irq, @@ -56,13 +56,13 @@ void static inline set_interrupt_registers(int ip) { unsigned long __dummy; - asm volatile("ldc %2, $r5_bank\n\t" + asm volatile("ldc %2, $r6_bank\n\t" "stc $sr, %0\n\t" "and #0xf0, %0\n\t" - "shlr8 %0\n\t" - "cmp/eq #0x0f, %0\n\t" - "bt 1f ! CLI-ed\n\t" - "stc $sr, %0\n\t" + "shlr2 %0\n\t" + "cmp/eq #0x3c, %0\n\t" + "bt/s 1f ! CLI-ed\n\t" + " stc $sr, %0\n\t" "and %1, %0\n\t" "or %2, %0\n\t" "ldc %0, $sr\n" diff --git a/arch/sh/kernel/irq_onchip.c b/arch/sh/kernel/irq_onchip.c index 10c48fd38..36dce33fb 100644 --- a/arch/sh/kernel/irq_onchip.c +++ b/arch/sh/kernel/irq_onchip.c @@ -61,7 +61,7 @@ static unsigned int startup_onChip_irq(unsigned int irq) } static struct hw_interrupt_type onChip_irq_type = { - "On-Chip Supporting Module", + "On-Chip-IPR", startup_onChip_irq, shutdown_onChip_irq, enable_onChip_irq, @@ -193,7 +193,7 @@ static unsigned int startup_onChip2_irq(unsigned int irq) } static struct hw_interrupt_type onChip2_irq_type = { - "SH7709 Extended On-Chip Supporting Module", + "Extended-IPR", startup_onChip2_irq, shutdown_onChip2_irq, enable_onChip2_irq, diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 97cd1fe0c..2d0f5e18a 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -136,20 +136,20 @@ void free_task_struct(struct task_struct *p) */ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { /* Don't use this in BL=1(cli). Or else, CPU resets! */ - register unsigned long __sc0 __asm__ ("$r0") = __NR_clone; + register unsigned long __sc0 __asm__ ("$r3") = __NR_clone; register unsigned long __sc4 __asm__ ("$r4") = (long) flags | CLONE_VM; register unsigned long __sc5 __asm__ ("$r5") = 0; register unsigned long __sc8 __asm__ ("$r8") = (long) arg; register unsigned long __sc9 __asm__ ("$r9") = (long) fn; - __asm__("trapa #0\n\t" /* Linux/SH system call */ + __asm__("trapa #0x12\n\t" /* Linux/SH system call */ "tst #0xff, $r0\n\t" /* child or parent? */ "bf 1f\n\t" /* parent - jump */ "jsr @$r9\n\t" /* call fn */ " mov $r8, $r4\n\t" /* push argument */ "mov $r0, $r4\n\t" /* return value to arg of exit */ - "mov %2, $r0\n\t" /* exit */ - "trapa #0\n" + "mov %2, $r3\n\t" /* exit */ + "trapa #0x11\n" "1:" : "=z" (__sc0) : "0" (__sc0), "i" (__NR_exit), @@ -194,7 +194,11 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) fpvalid = tsk->used_math; if (fpvalid) { + unsigned long flags; + + save_and_cli(flags); unlazy_fpu(tsk); + restore_flags(flags); memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu)); } @@ -214,7 +218,11 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, struct task_struct *tsk = current; if (tsk != &init_task) { + unsigned long flags; + + save_and_cli(flags); unlazy_fpu(tsk); + restore_flags(flags); p->thread.fpu = current->thread.fpu; p->used_math = tsk->used_math; } @@ -263,16 +271,21 @@ void dump_thread(struct pt_regs * regs, struct user * dump) void __switch_to(struct task_struct *prev, struct task_struct *next) { #if defined(__SH4__) - if (prev != &init_task) + if (prev != &init_task) { + unsigned long flags; + + save_and_cli(flags); unlazy_fpu(prev); + restore_flags(flags); + } #endif /* - * Restore the kernel stack onto kernel mode register - * k4 (r4_bank1) + * Restore the kernel mode register + * k7 (r7_bank1) */ - asm volatile("ldc %0, $r4_bank" + asm volatile("ldc %0, $r7_bank" : /* no output */ - :"r" ((unsigned long)next+8192)); + :"r" (next)); } asmlinkage int sys_fork(unsigned long r4, unsigned long r5, diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 154283571..49179f08f 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -244,7 +244,7 @@ void __init setup_arch(char **cmdline_p) /* * Reserve the kernel text and - * Reserve the bootmem bitmap.We do this in two steps (first step + * Reserve the bootmem bitmap. We do this in two steps (first step * was init_bootmem()), because this catches the (definitely buggy) * case of us accidentally initializing the bootmem allocator with * an invalid RAM area. @@ -262,17 +262,17 @@ void __init setup_arch(char **cmdline_p) if (LOADER_TYPE && INITRD_START) { if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { reserve_bootmem(INITRD_START+__MEMORY_START, INITRD_SIZE); - initrd_start = - INITRD_START ? INITRD_START + PAGE_OFFSET + __MEMORY_START : 0; + initrd_start = + INITRD_START ? INITRD_START + PAGE_OFFSET + __MEMORY_START : 0; initrd_end = initrd_start + INITRD_SIZE; } else { - printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", INITRD_START + INITRD_SIZE, max_low_pfn << PAGE_SHIFT); - initrd_start = 0; - } - } + initrd_start = 0; + } + } #endif #if 0 @@ -301,10 +301,9 @@ void __init setup_arch(char **cmdline_p) #endif #if defined(__SH4__) + /* We already grab/initialized FPU in head.S. Make it consisitent. */ init_task.used_math = 1; init_task.flags |= PF_USEDFPU; - grab_fpu(); - fpu_init(); #endif paging_init(); } diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index 4b11100ae..8751d45f5 100644 --- a/arch/sh/kernel/signal.c +++ b/arch/sh/kernel/signal.c @@ -152,30 +152,36 @@ struct rt_sigframe #if defined(__SH4__) static inline int restore_sigcontext_fpu(struct sigcontext *sc) { - current->used_math = 1; + struct task_struct *tsk = current; + + tsk->used_math = 1; return __copy_from_user(&tsk->thread.fpu.hard, &sc->sc_fpregs[0], - sizeof(long)*(NUM_FPU_REGS*2+2)); + sizeof(long)*(16*2+2)); } static inline int save_sigcontext_fpu(struct sigcontext *sc) { struct task_struct *tsk = current; + unsigned long flags; if (!tsk->used_math) { - sc->owend_fp = 0; + sc->sc_ownedfp = 0; return 0; } - sc->owend_fp = 1; + sc->sc_ownedfp = 1; /* This will cause a "finit" to be triggered by the next attempted FPU operation by the 'current' process. */ tsk->used_math = 0; + save_and_cli(flags); unlazy_fpu(tsk); + restore_flags(flags); + return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.fpu.hard, - sizeof(long)*(NUM_FPU_REGS*2+2)); + sizeof(long)*(16*2+2)); } #endif @@ -206,7 +212,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *r0_p) regs->sr |= SR_FD; /* Release FPU */ clear_fpu(tsk); current->used_math = 0; - __get_user (owned_fp, &context->sc_ownedfp); + __get_user (owned_fp, &sc->sc_ownedfp); if (owned_fp) err |= restore_sigcontext_fpu(sc); } @@ -363,11 +369,11 @@ static void setup_frame(int sig, struct k_sigaction *ka, if (ka->sa.sa_flags & SA_RESTORER) { regs->pr = (unsigned long) ka->sa.sa_restorer; } else { - /* This is : mov #__NR_sigreturn,r0 ; trapa #0 */ + /* This is : mov #__NR_sigreturn,r3 ; trapa #0x10 */ #ifdef __LITTLE_ENDIAN__ - unsigned long code = 0xc300e000 | (__NR_sigreturn); + unsigned long code = 0xc310e300 | (__NR_sigreturn); #else - unsigned long code = 0xe000c300 | (__NR_sigreturn << 16); + unsigned long code = 0xe300c310 | (__NR_sigreturn << 16); #endif regs->pr = (unsigned long) frame->retcode; @@ -437,11 +443,11 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, if (ka->sa.sa_flags & SA_RESTORER) { regs->pr = (unsigned long) ka->sa.sa_restorer; } else { - /* This is : mov #__NR_rt_sigreturn,r0 ; trapa #0 */ + /* This is : mov #__NR_rt_sigreturn,r3 ; trapa #0x10 */ #ifdef __LITTLE_ENDIAN__ - unsigned long code = 0xc300e000 | (__NR_rt_sigreturn); + unsigned long code = 0xc310e300 | (__NR_rt_sigreturn); #else - unsigned long code = 0xe000c300 | (__NR_rt_sigreturn << 16); + unsigned long code = 0xe300c310 | (__NR_rt_sigreturn << 16); #endif regs->pr = (unsigned long) frame->retcode; diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index fad3a8145..3e9cd8d28 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c @@ -33,6 +33,23 @@ #define TMU0_TCR_INIT 0x0020 #define TMU_TSTR_INIT 1 +/* RCR1 Bits */ +#define RCR1_CF 0x80 /* Carry Flag */ +#define RCR1_CIE 0x10 /* Carry Interrupt Enable */ +#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */ +#define RCR1_AF 0x01 /* Alarm Flag */ + +/* RCR2 Bits */ +#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */ +#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */ +#define RCR2_RTCEN 0x08 /* ENable RTC */ +#define RCR2_ADJ 0x04 /* ADJustment (30-second) */ +#define RCR2_RESET 0x02 /* Reset bit */ +#define RCR2_START 0x01 /* Start bit */ + +#define RTC_IRQ 22 +#define RTC_IPR_OFFSET 0 + #if defined(__sh3__) #define TMU_TOCR 0xfffffe90 /* Byte access */ #define TMU_TSTR 0xfffffe92 /* Byte access */ @@ -43,9 +60,6 @@ #define FRQCR 0xffffff80 -#define RTC_IRQ 22 -#define RTC_IPR_OFFSET 0 - /* SH-3 RTC */ #define R64CNT 0xfffffec0 #define RSECCNT 0xfffffec2 @@ -74,9 +88,6 @@ #define FRQCR 0xffc00000 -#define RTC_IRQ 22 -#define RTC_IPR_OFFSET 0 - /* SH-4 RTC */ #define R64CNT 0xffc80000 #define RSECCNT 0xffc80004 @@ -149,7 +160,7 @@ static int set_rtc_time(unsigned long nowtime) int retval = 0; int real_seconds, real_minutes, cmos_minutes; - ctrl_outb(0x02, RCR2); /* reset pre-scaler & stop RTC */ + ctrl_outb(RCR2_RESET, RCR2); /* Reset pre-scaler & stop RTC */ cmos_minutes = ctrl_inb(RMINCNT); BCD_TO_BIN(cmos_minutes); @@ -178,7 +189,7 @@ static int set_rtc_time(unsigned long nowtime) retval = -1; } - ctrl_outb(0x01, RCR2); /* start RTC */ + ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start RTC */ return retval; } @@ -283,8 +294,8 @@ static unsigned long get_rtc_time(void) unsigned int sec, min, hr, wk, day, mon, yr, yr100; again: - ctrl_outb(0x01, RCR1); /* clear CF bit */ do { + ctrl_outb(0, RCR1); /* Clear CF-bit */ sec = ctrl_inb(RSECCNT); min = ctrl_inb(RMINCNT); hr = ctrl_inb(RHRCNT); @@ -299,7 +310,7 @@ static unsigned long get_rtc_time(void) yr = ctrl_inb(RYRCNT); yr100 = (yr == 0x99) ? 0x19 : 0x20; #endif - } while ((ctrl_inb(RCR1) & 0x80) != 0); + } while ((ctrl_inb(RCR1) & RCR1_CF) != 0); BCD_TO_BIN(yr100); BCD_TO_BIN(yr); @@ -313,7 +324,7 @@ static unsigned long get_rtc_time(void) hr > 23 || min > 59 || sec > 59) { printk(KERN_ERR "SH RTC: invalid value, resetting to 1 Jan 2000\n"); - ctrl_outb(0x02, RCR2); /* reset, stop */ + ctrl_outb(RCR2_RESET, RCR2); /* Reset & Stop */ ctrl_outb(0, RSECCNT); ctrl_outb(0, RMINCNT); ctrl_outb(0, RHRCNT); @@ -325,7 +336,7 @@ static unsigned long get_rtc_time(void) #else ctrl_outb(0, RYRCNT); #endif - ctrl_outb(0x01, RCR2); /* start */ + ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start */ goto again; } @@ -339,13 +350,13 @@ static __init unsigned int get_cpu_mhz(void) sti(); do {} while (ctrl_inb(R64CNT) != 0); - ctrl_outb(0x11, RCR1); + ctrl_outb(RCR1_CIE, RCR1); /* Enable carry interrupt */ asm volatile( "1:\t" "tst %1,%1\n\t" "bt/s 1b\n\t" " add #1,%0" - : "=&r"(count), "=&z" (__dummy) + : "=r"(count), "=z" (__dummy) : "0" (0), "1" (0)); cli(); /* @@ -373,7 +384,7 @@ static __init unsigned int get_cpu_mhz(void) static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - ctrl_outb(0x01, RCR1); + ctrl_outb(0, RCR1); /* Disable Carry Interrupts */ regs->regs[0] = 1; } diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index 98431cb36..a9775f306 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -43,7 +43,6 @@ asmlinkage void do_##name(unsigned long r4, unsigned long r5, \ \ asm volatile("stc $r2_bank, %0": "=r" (error_code)); \ sti(); \ - regs.syscall_nr = -1; \ tsk->thread.error_code = error_code; \ tsk->thread.trap_no = trapnr; \ force_sig(signr, tsk); \ @@ -95,9 +94,9 @@ DO_ERROR( 8, SIGSEGV, "address error (store)", address_error_store, current) DO_ERROR(12, SIGILL, "reserved instruction", reserved_inst, current) DO_ERROR(13, SIGILL, "illegal slot instruction", illegal_slot_inst, current) -asmlinkage void do_exception_error (unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, - struct pt_regs regs) +asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs regs) { long ex; asm volatile("stc $r2_bank, %0" : "=r" (ex)); @@ -131,7 +130,8 @@ void dump_stack(void) unsigned long *p; asm("mov $r15, %0" : "=r" (start)); - asm("stc $r4_bank, %0" : "=r" (end)); + asm("stc $r7_bank, %0" : "=r" (end)); + end += 8192; printk("%08lx:%08lx\n", (unsigned long)start, (unsigned long)end); for (p=start; p < end; p++) |