diff options
Diffstat (limited to 'arch/mips/kernel/r2300_switch.S')
-rw-r--r-- | arch/mips/kernel/r2300_switch.S | 186 |
1 files changed, 126 insertions, 60 deletions
diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S index b2b55bf0b..4b8698d3b 100644 --- a/arch/mips/kernel/r2300_switch.S +++ b/arch/mips/kernel/r2300_switch.S @@ -1,12 +1,13 @@ -/* - * r2300_switch.S: R3000/R2000 specific task switching code. +/* $Id: $ + * r2300_switch.S: R2300 specific task switching code. * * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse * * Multi-cpu abstraction and macros for easier reading: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: r2300_switch.S,v 1.3 1998/03/27 04:47:55 ralf Exp $ + * Further modifications to make this work: + * Copyright (c) 1998 Harald Koerfgen */ #include <asm/asm.h> #include <asm/bootinfo.h> @@ -15,6 +16,7 @@ #include <asm/fpregdef.h> #include <asm/mipsconfig.h> #include <asm/mipsregs.h> +#include <asm/offset.h> #include <asm/page.h> #include <asm/pgtable.h> #include <asm/processor.h> @@ -23,68 +25,132 @@ #include <asm/asmmacro.h> -/* XXX The following is fucking losing... find a better way dave. */ -MODE_ALIAS = 0x00e0 # uncachable, dirty, valid - - .text .set mips1 - .set noreorder -/* - * Code necessary to switch tasks on an Linux/MIPS machine. - * FIXME: We don't need to disable interrupts anymore. - */ .align 5 - LEAF(r2300_resume) - mfc0 t1,CP0_STATUS # Save status register - sw t1,THREAD_STATUS($28) - ori t2,t1,0x1f # Disable interrupts - xori t2,0x1e - mtc0 t2,CP0_STATUS + +LEAF(r2300_resume) + .set reorder + mfc0 t1, CP0_STATUS + .set noreorder + sw t1, THREAD_STATUS($28) CPU_SAVE_NONSCRATCH($28) - sll t2,t1,2 # Save floating point state - bgez t2,1f - sw ra,THREAD_REG31($28) - FPU_SAVE($28, t0) -1: + sw ra, THREAD_REG31($28) + + /* + * The order of restoring the registers takes care of the race + * updating $28, $29 and kernelsp without disabling ints. + */ move $28, a0 - lw t0,THREAD_PGDIR($28) # Switch the root pointer - li t1,TLB_ROOT # get PFN - mtc0 t1,CP0_ENTRYHI - mtc0 zero,CP0_INDEX - srl t0,12 # PFN is 12 bits west - ori t0,MODE_ALIAS # want uncachable, dirty, valid - mtc0 t0,CP0_ENTRYLO0 - lw a2,THREAD_STATUS($28) - tlbwi - - /* Flush TLB. */ - mfc0 t3,CP0_STATUS # disable interrupts... - ori t4,t3,1 - xori t4,1 - mtc0 t4,CP0_STATUS - lw t0,mips_tlb_entries - mtc0 zero,CP0_ENTRYLO0 -1: - subu t0,1 - mtc0 t0,CP0_INDEX - lui t1,0x0008 - or t1,t0,t1 - sll t1,12 - mtc0 t1,CP0_ENTRYHI - bne t2,t0,1b - tlbwi - - ori t1,a2,1 # Restore FPU, pipeline magic - xori t1,1 - mtc0 t1,CP0_STATUS - sll t0,a2,2 - bgez t0,1f - lw ra,THREAD_REG31($28) - FPU_RESTORE($28, t0) -1: CPU_RESTORE_NONSCRATCH($28) addiu t0, $28, KERNEL_STACK_SIZE-32 - sw t0,kernelsp + sw t0, kernelsp + mfc0 t1, CP0_STATUS /* Do we really need this? */ + li a3, 0xff00 + and t1, a3 + lw a2, THREAD_STATUS($28) + nor a3, $0, a3 + and a2, a3 + lw a3, TASK_MM($28) + or a2, t1 + lw a3, MM_CONTEXT(a3) + mtc0 a2, CP0_STATUS + andi a3, 0xfc0 jr ra - mtc0 a2,CP0_STATUS # Restore status register + mtc0 a3, CP0_ENTRYHI END(r2300_resume) + +/* + * Do lazy fpu context switch. Saves FPU context to the process in a0 + * and loads the new context of the current process. + */ + +#define ST_OFF (KERNEL_STACK_SIZE - 32 - PT_SIZE + PT_STATUS) + +LEAF(r2300_lazy_fpu_switch) + mfc0 t0, CP0_STATUS # enable cp1 + li t3, 0x20000000 + or t0, t3 + mtc0 t0, CP0_STATUS + + beqz a0, 2f # Save floating point state + nor t3, zero, t3 + .set reorder + lw t1, ST_OFF(a0) # last thread looses fpu + .set noreorder + and t1, t3 + sw t1, ST_OFF(a0) + swc1 $f0, (THREAD_FPU + 0x00)(a0) + FPU_SAVE(a0, t1) # clobbers t1 + +2: + lwc1 $f0, (THREAD_FPU + 0x00)($28) + .set reorder + FPU_RESTORE($28, t0) # clobbers t0 + jr ra + END(r2300_lazy_fpu_switch) + +/* + * Save a thread's fp context. + */ + .set noreorder +LEAF(r2300_save_fp) + FPU_SAVE(a0, t1) # clobbers t1 + jr ra + swc1 $f0, (THREAD_FPU + 0x00)(a0) + END(r2300_save_fp) + +/* + * Load the FPU with signalling NANS. This bit pattern we're using has + * the property that no matter wether considered as single or as double + * precission represents signaling NANS. + * + * We initialize fcr31 to rounding to nearest, no exceptions. + */ + +#define FPU_DEFAULT 0x00000000 + +LEAF(r2300_init_fpu) + mfc0 t0, CP0_STATUS + li t1, 0x20000000 + or t0, t1 + mtc0 t0, CP0_STATUS + + li t1, FPU_DEFAULT + ctc1 t1, fcr31 + + li t0, -1 + + mtc1 t0, $f0 + mtc1 t0, $f1 + mtc1 t0, $f2 + mtc1 t0, $f3 + mtc1 t0, $f4 + mtc1 t0, $f5 + mtc1 t0, $f6 + mtc1 t0, $f7 + mtc1 t0, $f8 + mtc1 t0, $f9 + mtc1 t0, $f10 + mtc1 t0, $f11 + mtc1 t0, $f12 + mtc1 t0, $f13 + mtc1 t0, $f14 + mtc1 t0, $f15 + mtc1 t0, $f16 + mtc1 t0, $f17 + mtc1 t0, $f18 + mtc1 t0, $f19 + mtc1 t0, $f20 + mtc1 t0, $f21 + mtc1 t0, $f22 + mtc1 t0, $f23 + mtc1 t0, $f24 + mtc1 t0, $f25 + mtc1 t0, $f26 + mtc1 t0, $f27 + mtc1 t0, $f28 + mtc1 t0, $f29 + mtc1 t0, $f30 + jr ra + mtc1 t0, $f31 + END(r2300_init_fpu) |