[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [microblaze-uclinux] Interrupts disabled in RETURN macro



Diff attached.


On Tuesday 18 April 2006 13:38, John Williams wrote:
> Hi Alejandro,
>
> Can you please post a diff?  Much easier to scan quickly than the whole
> file :)
>
> Thanks,
>
> John
>
> Alejandro Lucero wrote:
> > Hi John,
> >
> > I'm looking at the RETURN macro (entry.S) and I'd like to ask you why
> > interrupts are disabled immediately. I think it's possible to delay it
> > just until before POP_STATE since is here when the problematic r14
> > register is modified. In the current way scheduling is called without
> > interrupts, the same with do_signal.
> >
> > Delaying disabling interrupts would improve interrupts latency since less
> > code would be executed with interrupts disabled.
> >
> > I have tested this approach and it works even with high interrupts
> > frequency. Perhaps I'm forgetting something and in this way some race
> > condition can happen and it's hard to reproduce in my tests.
> >
> > With the ret_from_trap happens the same problem. BIPSET is used before
> > RETURN so a lot of code is executed without interrupts when it could do
> > it with them. To improve latencies the BIPSET could be delayed just until
> > before POP_STATE and this BIPSET could be used by interrupts return too,
> > instead of ENTRY_CLI. Some updates to IRQ RETURN, now rtbd instead of
> > rtid, and adding interrupts enabled when saving PSW in
> > SAVE_SYS_REGS_FOR_IRQ.
> >
> > The entry.S modified is attached.
> >
> > Can you (or someone else) see what I'm forgetting?
> >
> >
> >
> > ------------------------------------------------------------------------
> >
> > /*
> >  * arch/microblaze/kernel/entry.S -- Low-level system-call handling, trap
> > handlers, *	and context-switching
> >  *
> >  *  Copyright (C) 2003	     John Williams <jwilliams@xxxxxxxxxxxxxx>
> >  *  Copyright (C) 2001,2002  NEC Corporation
> >  *  Copyright (C) 2001,2002  Miles Bader <miles@xxxxxxx>
> >  *
> >  * 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.
> >  *
> >  * Written by Miles Bader <miles@xxxxxxx>
> >  * Heavily modified by John Williams for Microblaze
> >  */
> >
> > #include <linux/sys.h>
> >
> > #include <asm/entry.h>
> > #include <asm/clinkage.h>
> > #include <asm/current.h>
> > #include <asm/processor.h>
> > #include <asm/irq.h>
> > #include <linux/config.h>
> > #include <asm/exceptions.h>
> >
> > #include "microblaze_defs.h"
> >
> >
> > /* Make a slightly more convenient alias for C_SYMBOL_NAME.  */
> > #define CSYM	C_SYMBOL_NAME
> >
> > /* The offset of the struct pt_regs in a `state save frame' on the stack.
> >  */ #define PTO	STATE_SAVE_PT_OFFSET
> >
> > /* Standard way of enabling and disabling interrupts in entry.S */
> > #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
> > #define ENTRY_CLI(scratch_reg)                                           
> >     \ msrclr scratch_reg, 0x2;					      \
> > 	nop;
> >
> > #define ENTRY_EI(scratch_reg)                                            
> >     \ msrset scratch_reg, 0x2;					      \
> > 	nop;
> >
> > #else
> >
> > #define ENTRY_CLI(scratch_reg)                                           
> >     \ mfs     scratch_reg, rmsr;                                         
> >   \ andi    scratch_reg, scratch_reg, ~2;                                
> > \ mts     rmsr, scratch_reg;					      \
> > 	nop;
> >
> > #define ENTRY_EI(scratch_reg)                                            
> >     \ mfs     scratch_reg, rmsr;                                         
> >   \ ori     scratch_reg, scratch_reg, 2;                                 
> > \ mts     rmsr, scratch_reg;					      \
> > 	nop;
> > #endif
> >
> > /* Various ways of setting and clearing BIP in flags reg.  This is mucky,
> > but necessary */
> > //#ifdef CONFIG_MICROBLAZE_BIPDIRECT
> > #if 1
> >   /* using microblaze version that allows msr ops to write to BIP */
> >   #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
> > 	#define BIPCLR(scratch_reg)					      \
> > 		msrclr 	scratch_reg, 0x8;				      \
> > 		nop;
> >
> > 	#define BIPSET(scratch_reg)					      \
> > 		msrset	scratch_reg, 0x8;				      \
> > 		nop;
> >   #else
> > 	#define BIPCLR(scratch_reg)					      \
> > 		mfs	scratch_reg, rmsr;				      \
> > 		andi	scratch_reg, scratch_reg, ~0x8;			      \
> > 		mts	rmsr, scratch_reg;				      \
> > 		nop;
> >
> > 	#define BIPSET(scratch_reg)					      \
> > 		mfs	scratch_reg, rmsr;				      \
> > 		ori	scratch_reg, scratch_reg, 0x8;			      \
> > 		mts	rmsr, scratch_reg;				      \
> > 		nop;
> >   #endif
> > #else
> >   /* Older microblaze version that prevents direct access to BIP bit
> >      We hack around it using the rtbd and brki instructions */
> > 	#define BIPCLR(scratch_reg)					      \
> > 		rtbd	r0, 1f;						      \
> > 		nop;							      \
> > 	   1:
> >
> > 	#define BIPSET(scratch_reg)					      \
> > 		brki	r0, 1f;						      \
> > 	   1:
> > #endif
> >
> > /* Standard macros to save and restore regs in the pt_regs struct pointed
> >    to by the stack pointer (r1) */
> > #define SAVE_REG(reg_num) \
> > 	swi	macrology_paste(r,reg_num), r1, PTO+PT_GPR(reg_num);
> >
> > #define RESTORE_REG(reg_num) \
> > 	lwi	macrology_paste(r,reg_num), r1, PTO+PT_GPR(reg_num);
> >
> > /* Save argument registers to the struct pt_regs pointed to by EP.  */
> > #define SAVE_ARG_REGS							      \
> > 	SAVE_REG(5);							      \
> > 	SAVE_REG(6);							      \
> > 	SAVE_REG(7);							      \
> > 	SAVE_REG(8);							      \
> > 	SAVE_REG(9);							      \
> > 	SAVE_REG(10);
> >
> > /* Restore argument registers from the struct pt_regs pointed to by EP. 
> > */ #define RESTORE_ARG_REGS						      \
> > 	RESTORE_REG(5);							      \
> > 	RESTORE_REG(6);							      \
> > 	RESTORE_REG(7);							      \
> > 	RESTORE_REG(8);							      \
> > 	RESTORE_REG(9);							      \
> > 	RESTORE_REG(10);
> >
> > /* Save value return registers to the struct pt_regs pointed to by EP. 
> > */ #define SAVE_RVAL_REGS							      \
> > 	SAVE_REG(3);							      \
> > 	SAVE_REG(4);
> >
> > /* Restore value return registers from the struct pt_regs pointed to by
> > EP.  */ #define RESTORE_RVAL_REGS						      \
> > 	RESTORE_REG(3);							      \
> > 	RESTORE_REG(4);
> >
> > #define SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS
> >
> > #define SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL				      \
> > 	SAVE_REG(11);							      \
> > 	SAVE_REG(12);
> >
> > #define RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS
> >
> > #define RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL				      \
> > 	RESTORE_REG(11);						      \
> > 	RESTORE_REG(12);
> >
> > /* Save `call clobbered' registers to the struct pt_regs pointed to by
> > EP.  */ #define SAVE_CALL_CLOBBERED_REGS					      \
> > 	SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS;				      \
> > 	SAVE_RVAL_REGS;							      \
> > 	SAVE_ARG_REGS;							      \
> > 	SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL;
> > /* Restore `call clobbered' registers from the struct pt_regs pointed to
> >    by EP.  */
> > #define RESTORE_CALL_CLOBBERED_REGS					      \
> > 	RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS;			      \
> > 	RESTORE_RVAL_REGS;						      \
> > 	RESTORE_ARG_REGS;						      \
> > 	RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL;
> >
> > /* Save `call clobbered' registers except for the return-value registers
> >    to the struct pt_regs pointed to by EP.  */
> > #define SAVE_CALL_CLOBBERED_REGS_NO_RVAL				      \
> > 	SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS;				      \
> > 	SAVE_ARG_REGS;							      \
> > 	SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL;
> > /* Restore `call clobbered' registers except for the return-value
> > registers from the struct pt_regs pointed to by EP.  */
> > #define RESTORE_CALL_CLOBBERED_REGS_NO_RVAL				      \
> > 	RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS;			      \
> > 	RESTORE_ARG_REGS;						      \
> > 	RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL;
> >
> > #define ZERO_REG(reg_num)						      \
> > 	add	r ## reg_num, r0, r0;
> >
> > /* Zero `call clobbered' registers except for the return-value registers.
> >  */ #define ZERO_CALL_CLOBBERED_REGS_NO_RVAL				      \
> > 	ZERO_REG(11); ZERO_REG(12);
> >
> > /* Save `call saved' registers to the struct pt_regs pointed to by EP. 
> > */ #define SAVE_CALL_SAVED_REGS						      \
> > 	SAVE_REG(19);							      \
> > 	SAVE_REG(20);							      \
> > 	SAVE_REG(21);							      \
> > 	SAVE_REG(22);							      \
> > 	SAVE_REG(23);							      \
> > 	SAVE_REG(24);							      \
> > 	SAVE_REG(25);							      \
> > 	SAVE_REG(26);							      \
> > 	SAVE_REG(27);							      \
> > 	SAVE_REG(28);							      \
> > 	SAVE_REG(29);							      \
> > 	SAVE_REG(30);							      \
> >  	SAVE_REG(31);
> >
> > /* Restore `call saved' registers from the struct pt_regs pointed to by
> > EP.  */ #define RESTORE_CALL_SAVED_REGS						      \
> > 	RESTORE_REG(19);						      \
> > 	RESTORE_REG(20);						      \
> > 	RESTORE_REG(21);						      \
> > 	RESTORE_REG(22);						      \
> > 	RESTORE_REG(23);						      \
> > 	RESTORE_REG(24);						      \
> > 	RESTORE_REG(25);						      \
> > 	RESTORE_REG(26);						      \
> > 	RESTORE_REG(27);						      \
> > 	RESTORE_REG(28);						      \
> > 	RESTORE_REG(29);						      \
> > 	RESTORE_REG(30);						      \
> > 	RESTORE_REG(31);
> >
> >
> > /* Save link register into state save frame */
> > #define SAVE_LINK(linkreg)						      \
> > 	swi	linkreg, r1, PTO+PT_PC;		/* PC, before IRQ/trap /*
> >
> > /* Restore saved PC into desired return link register */
> > #define RESTORE_LINK(linkreg)						      \
> > 	lwi	linkreg, r1, PTO+PT_PC;		/* PC, before IRQ/trap /*
> >
> > /* Save a special reg into saved state frame */
> > #define SAVE_SPECIAL(reg,OFFS)						      \
> > 	mfs	r11, r ## reg;						      \
> > 	swi	r11, r1, PTO+PT_ ## OFFS;
> >
> > /* Restore a special reg from saved state frame */
> > #define RESTORE_SPECIAL(reg,OFFS)					      \
> > 	lwi	r11, r1, PTO+PT_ ## OFFS;				      \
> > 	mts	r ## reg , r11;
> >
> > /* Save processor status word into saved state frame */
> > #define SAVE_PSW							      \
> > 	SAVE_SPECIAL(msr,PSW)
> >
> > /* Restore processor status word from saved state frame */
> > #define RESTORE_PSW							      \
> > 	RESTORE_SPECIAL(msr,PSW)
> >
> > /* Save system registers to the struct pt_regs pointed to by REG.
> >    r11 is clobbered.  */
> > #define SAVE_SYS_REGS_FOR_IRQ						      \
> > 	SAVE_REG(17); 							      \
> > 	SAVE_LINK(r14);							      \
> >         mfs     r11, rmsr;                                               
> >     \ ori     r11, r11, 0xa;   /* Needed for RTLinux */                  
> >     \ swi     r11, r1, PTO+PT_PSW;
> >
> > /* Restore system registers from the struct pt_regs pointed to by EP.
> >    clobber r14 to restore status register, it gets fixed immediately */
> > #define RESTORE_SYS_REGS_FOR_IRQ					      \
> > 	RESTORE_REG(17); 						      \
> > 	RESTORE_PSW;							      \
> > 	RESTORE_LINK(r14);
> >
> > /* Save system registers to the struct pt_regs pointed to by REG.
> >    r11 is clobbered.  */
> > #define SAVE_SYS_REGS_FOR_TRAP						      \
> > 	SAVE_REG(17); 							      \
> > 	SAVE_LINK(r14);							      \
> >         mfs     r11, rmsr;                                               
> >     \ ori     r11, r11, 0xa;   /* Needed for RTLinux */                  
> >     \ swi     r11, r1, PTO+PT_PSW;
> >
> >
> > /* Restore system registers from the struct pt_regs pointed to by EP.
> >    clobber r11 to restore status register */
> > #define RESTORE_SYS_REGS_FOR_TRAP					      \
> > 	RESTORE_REG(17);						      \
> > 	RESTORE_PSW;							      \
> > 	RESTORE_LINK(r14);
> >
> > /* Save system registers to the struct pt_regs pointed to by REG.
> >    r11 is clobbered.  */
> > #define SAVE_SYS_REGS_FOR_DBTRAP					      \
> > 	SAVE_REG(17);							      \
> > 	SAVE_LINK(r14);							      \
> > 	SAVE_PSW;
> >
> > /* Restore system registers from the struct pt_regs pointed to by EP.
> >    clobber r11 to restore status register */
> > #define RESTORE_SYS_REGS_FOR_DBTRAP					      \
> > 	RESTORE_REG(17);						      \
> > 	RESTORE_PSW;							      \
> > 	RESTORE_LINK(r14);
> >
> > /* Save system registers to the struct pt_regs pointed to by REG.  This
> > is a NMI-specific version, because NMIs save the PC/PSW in a different
> > place than other interrupt requests.  r11 is clobbered.  */
> > #define SAVE_SYS_REGS_FOR_NMI						      \
> > 	SAVE_LINK(r16);							      \
> > 	SAVE_PSW;
> >
> > /* Restore system registers from the struct pt_regs pointed to by EP. 
> > This is a NMI-specific version, because NMIs save the PC/PSW in a
> > different place than other interrupt requests.  r11 is clobbered (it is
> > used as a scratch register because the POP_STATE macro restores it, and
> > this macro is usually used inside POP_STATE).  */
> > #define RESTORE_SYS_REGS_FOR_NMI					      \
> > 	RESTORE_PSW;							      \
> > 	RESTORE_LINK(r16);
> >
> > /* Push register state, except for the stack pointer, on the stack in the
> > form of a struct pt_regs, in preparation for a system call.  This macro
> > makes sure that `special' registers, system registers; TYPE identifies
> > the set of extra registers to be saved as well.  EP is clobbered.
> >    Uses add(i)k to prevent corrupting carry flags prior to them being
> > saved */ #ifdef CONFIG_REGISTER_TASK_PTR
> > #define PUSH_STATE(type)						      \
> > 	addik	r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */      \
> > 	SAVE_REG(2);				/* Save SDA */		      \
> > 	SAVE_REG(13);				/* Save SDA2 */		      \
> > 	SAVE_REG(15);				/* Save LP */		      \
> > 	SAVE_REG(18);				/* Save asm scratch reg */    \
> > 	SAVE_REG(CURRENT_TASK_REGNUM);		/* Save current task reg */   \
> > 	type ## _STATE_SAVER;
> > #else
> > #define PUSH_STATE(type)						      \
> > 	addik	r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */      \
> > 	SAVE_REG(2);				/* Save SDA */		      \
> > 	SAVE_REG(13);				/* Save SDA2 */		      \
> > 	SAVE_REG(15);				/* Save LP */		      \
> > 	SAVE_REG(18);				/* Save asm scratch reg */    \
> > 	type ## _STATE_SAVER;
> > #endif
> >
> > /* Pop a register state, except for the stack pointer, from the struct
> > pt_regs on the stack.  */
> > #ifdef CONFIG_REGISTER_TASK_PTR
> > #define POP_STATE(type)							      \
> > 	type ## _STATE_RESTORER;					      \
> > 	RESTORE_REG(2);				/* Restore SDA */	      \
> > 	RESTORE_REG(13);			/* Restore SDA2 */	      \
> > 	RESTORE_REG(15);			/* Restore LP */	      \
> > 	RESTORE_REG(18);			/* Restore asm scratch reg */ \
> > 	RESTORE_REG(CURRENT_TASK_REGNUM);	/* Restore cur task reg */    \
> > 	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */
> > #else
> > #define POP_STATE(type)							      \
> > 	type ## _STATE_RESTORER;					      \
> > 	RESTORE_REG(2);				/* Restore SDA */	      \
> > 	RESTORE_REG(13);			/* Restore SDA2 */	      \
> > 	RESTORE_REG(15);			/* Restore LP */	      \
> > 	RESTORE_REG(18);			/* Restore asm scratch reg */ \
> > 	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */
> > #endif
> >
> >
> > /* Switch to the kernel stack if necessary, and push register state on
> >    the stack in the form of a struct pt_regs.  Also load the current
> >    task pointer if switching from user mode.  The stack-pointer (r3)
> >    should have already been saved to the memory location SP_SAVE_LOC
> >    (the reason for this is that the interrupt vectors may be beyond a
> >    22-bit signed offset jump from the actual interrupt handler, and this
> >    allows them to save the stack-pointer and use that register to do an
> >    indirect jump).  This macro makes sure that `special' registers,
> >    system registers, and the stack pointer are saved; TYPE identifies
> >    the set of extra registers to be saved as well.  SYSCALL_NUM is the
> >    register in which the system-call number this state is for is stored
> >    (r0 if this isn't a system call).  Interrupts should already be
> >    disabled when calling this.  */
> > #define SAVE_STATE(type, syscall_num, sp_save_loc)			      \
> > 	swi	r11, r0, R11_SAVE;	/* Save r11 */			      \
> >         lwi	r11, r0, KM;		/* See if already in kernel mode.  */ \
> > 	beqi	r11, 1f;		/* Jump ahead if coming from user */  \
> > 	lwi	r11, r0, R11_SAVE;	/* restore r11 */		      \
> >         /* Kernel-mode state save.  */					      \
> > 	lwi	r1, r0, sp_save_loc;	/* Reload kernel stack-pointer.  */   \
> > 	swi	r1, r1, (PT_GPR(GPR_SP)-PT_SIZE); /* Save original SP. */     \
> >         PUSH_STATE(type);						      \
> > 	addi	r11, r0, 1; 		/* Was in kernel-mode.  */	      \
> >         swi	r11, r1, PTO+PT_KERNEL_MODE; 	 			      \
> >         brid	2f;							      \
> > 	nop;				/* Fill delay slot */		      \
> > 1:      /* User-mode state save.  */					      \
> > 	lwi	r11, r0, R11_SAVE;	/* restore r11 */		      \
> >         lwi	r1, r0, KSP;		/* Switch to kernel stack.  */	      \
> >         PUSH_STATE(type);						      \
> > 	swi	r0, r1, PTO+PT_KERNEL_MODE; /* Was in user-mode.  */	      \
> > 	lwi	r11, r0, sp_save_loc;					      \
> > 	swi	r11, r1, PTO+PT_GPR(GPR_SP); /* Store user SP.  */	      \
> > 	addi	r11, r0, 1;						      \
> > 	swi	r11, r0, KM;		/* Now we're in kernel-mode.  */      \
> > 	GET_CURRENT_TASK(CURRENT_TASK);	/* Update the current task pointer.*/ \
> > 2:      /* Save away the syscall number.  */				      \
> >         swi	syscall_num, r1, PTO+PT_SYSCALL
> >
> >
> > /* Save register state not normally saved by PUSH_STATE for TYPE.  */
> > #define SAVE_EXTRA_STATE(type)						      \
> > 	type ## _EXTRA_STATE_SAVER;
> >
> > /* Restore register state not normally restored by POP_STATE for TYPE. 
> > */ #define RESTORE_EXTRA_STATE(type)					      \
> > 	type ## _EXTRA_STATE_RESTORER;
> >
> > /* Save any call-clobbered registers not normally saved by PUSH_STATE
> >    for TYPE.  */
> > #define SAVE_EXTRA_STATE_FOR_FUNCALL(type)				      \
> > 	type ## _FUNCALL_EXTRA_STATE_SAVER;
> >
> > /* Restore any call-clobbered registers not normally restored by
> > POP_STATE for TYPE.  */
> > #define RESTORE_EXTRA_STATE_FOR_FUNCALL(type)				      \
> > 	type ## _FUNCALL_EXTRA_STATE_RESTORER;
> >
> >
> > /* These are extra_state_saver/restorer values for a user trap.  Note
> > that we save the argument registers so that restarted syscalls will
> > function properly (otherwise it wouldn't be necessary), and we must _not_
> > restore the return-value registers (so that traps can return a value!),
> > but there are various options for what happens to other call-clobbered
> > registers, selected by preprocessor conditionals.  */
> >
> > #if TRAPS_PRESERVE_CALL_CLOBBERED_REGS
> >
> > /* Traps save/restore all call-clobbered registers (except for rval
> > regs).  */ #define TRAP_STATE_SAVER						      \
> >      SAVE_CALL_CLOBBERED_REGS_NO_RVAL;					      \
> >      SAVE_SYS_REGS_FOR_TRAP
> >
> > #define TRAP_STATE_RESTORER						      \
> >      RESTORE_CALL_CLOBBERED_REGS_NO_RVAL;				      \
> >      RESTORE_SYS_REGS_FOR_TRAP
> >
> > #else /* !TRAPS_PRESERVE_CALL_CLOBBERED_REGS */
> >
> > /* Traps don't save call-clobbered registers (but do still save arg
> > regs).  */ #define TRAP_STATE_SAVER						      \
> >      SAVE_ARG_REGS;							      \
> >      SAVE_SYS_REGS_FOR_TRAP
> >
> > #if TRAPS_ZERO_CALL_CLOBBERED_REGS
> >
> > /* Traps zero call-clobbered registers (except for arg/rval regs) before
> >    returning from a system call, to avoid any internal values from
> > leaking out of the kernel.  */
> > #define TRAP_STATE_RESTORER						      \
> >      ZERO_CALL_CLOBBERED_REGS_NO_ARGS_NO_RVAL;				      \
> >      RESTORE_ARG_REGS;							      \
> >      RESTORE_SYS_REGS_FOR_TRAP
> >
> > #else /* !TRAPS_ZERO_CALL_CLOBBERED_REGS */
> >
> > /* When traps return, they just leave call-clobbered registers (except
> > for arg regs) with whatever value they have from the kernel.  */
> > #define TRAP_STATE_RESTORER						      \
> >      RESTORE_ARG_REGS;							      \
> >      RESTORE_SYS_REGS_FOR_TRAP
> >
> > #endif /* TRAPS_ZERO_CALL_CLOBBERED_REGS */
> > #endif /* TRAPS_PRESERVE_CALL_CLOBBERED_REGS */
> >
> > /* Save registers not normally saved by traps.  */
> > #define TRAP_EXTRA_STATE_SAVER						      \
> >    SAVE_RVAL_REGS;							      \
> >    SAVE_CALL_SAVED_REGS
> > #define TRAP_EXTRA_STATE_RESTORER					      \
> >    RESTORE_RVAL_REGS;							      \
> >    RESTORE_CALL_SAVED_REGS
> > #define TRAP_FUNCALL_EXTRA_STATE_SAVER					      \
> >    SAVE_RVAL_REGS
> > #define TRAP_FUNCALL_EXTRA_STATE_RESTORER				      \
> >    RESTORE_RVAL_REGS
> >
> > /* Save registers not normally saved by traps.  */
> > /* DBTRAP saves everything on entry, so nothing "extra" to save */
> > #define DBTRAP_EXTRA_STATE_SAVER
> > #define DBTRAP_EXTRA_STATE_RESTORER
> >
> > #define DBTRAP_FUNCALL_EXTRA_STATE_SAVER
> > #define DBTRAP_FUNCALL_EXTRA_STATE_RESTORER
> >
> > /* The PTRACE syscall expects the entire PT_REGS struct to be correct, so
> > no optimisations allows - we must save all registers immediately upon
> > entry */ #define DBTRAP_STATE_SAVER						      \
> >      SAVE_CALL_SAVED_REGS;						      \
> >      SAVE_CALL_CLOBBERED_REGS;						      \
> >      SAVE_SYS_REGS_FOR_DBTRAP
> >
> > #define DBTRAP_STATE_RESTORER						      \
> >      RESTORE_CALL_SAVED_REGS;						      \
> >      RESTORE_SYS_REGS_FOR_DBTRAP;					      \
> >      RESTORE_CALL_CLOBBERED_REGS
> >
> >
> > /* Register saving/restoring for maskable interrupts.  */
> > #define IRQ_STATE_SAVER							      \
> >    SAVE_CALL_CLOBBERED_REGS;						      \
> >    SAVE_SYS_REGS_FOR_IRQ
> >
> > #define IRQ_STATE_RESTORER						      \
> >    RESTORE_SYS_REGS_FOR_IRQ						      \
> >    RESTORE_CALL_CLOBBERED_REGS;
> >
> > #define IRQ_EXTRA_STATE_SAVER						      \
> >    SAVE_CALL_SAVED_REGS
> >
> > #define IRQ_EXTRA_STATE_RESTORER					      \
> >    RESTORE_CALL_SAVED_REGS
> >
> > #define IRQ_FUNCALL_EXTRA_STATE_SAVER       /* nothing */
> >
> > #define IRQ_FUNCALL_EXTRA_STATE_RESTORER    /* nothing */
> >
> > /* Register saving/restoring for non-maskable interrupts.  */
> > #define NMI_STATE_SAVER							      \
> >    SAVE_CALL_CLOBBERED_REGS;						      \
> >    SAVE_SYS_REGS_FOR_NMI
> >
> > #define NMI_STATE_RESTORER						      \
> >    RESTORE_CALL_CLOBBERED_REGS;						      \
> >    RESTORE_SYS_REGS_FOR_NMI
> >
> > #define NMI_EXTRA_STATE_SAVER						      \
> >    SAVE_CALL_SAVED_REGS
> >
> > #define NMI_EXTRA_STATE_RESTORER					      \
> >    RESTORE_CALL_SAVED_REGS
> >
> > #define NMI_FUNCALL_EXTRA_STATE_SAVER       /* nothing */
> >
> > #define NMI_FUNCALL_EXTRA_STATE_RESTORER    /* nothing */
> >
> > /* Register saving/restoring for a context switch.  We don't need to save
> > too many registers, because context-switching looks like a function call
> > (via the function `switch_thread'), so callers will save any
> > call-clobbered registers themselves.  The stack pointer and return value
> > are handled by switch_thread itself.  */
> > #define SWITCH_STATE_SAVER						      \
> >    SAVE_CALL_SAVED_REGS							      \
> >    SAVE_PSW
> >
> > #define SWITCH_STATE_RESTORER						      \
> >    RESTORE_CALL_SAVED_REGS						      \
> >    RESTORE_PSW
> >
> > /* Instructions to return from an IRQ */
> > #define IRQ_RETURN_INST							      \
> > 	rtbd	r14, 0;		/* Follow interrupt link pointer back to */   \
> > 				/* next insn after interrupt occured */       \
> > 	nop;			/* Delay slot */
> >
> > /* Instructions to return from a trap */
> > /* Note we use rtbd to clear BIP bit on way out */
> > /* Return offset is 4, to execute instruction after syscall brki insn*/
> > #define TRAP_RETURN_INST						      \
> > 	rtbd	r14, 4;		/* r14 used as trap link register */	      \
> > 	nop;
> >
> > /* Instructions to return from a debug trap */
> > /* Note we use rtbd to clear BIP bit on exit */
> > /* Return offset is zero, to ensure trapped instruction is re-executed */
> > #define DBTRAP_RETURN_INST						      \
> > 	rtbd	r14, 0;		/* r14 used as trap link register */	      \
> > 	nop;
> >
> > /* Code fragment to return from NMI */
> > #define NMI_RETURN_INST							      \
> > 	rtbd	r16, 8;		/* r16 is NMI (brk) link register */	      \
> > 	nop;
> >
> > /* Restore register state from the struct pt_regs on the stack, switch
> > back to the user stack if necessary, and return from the trap/interrupt.
> > EXTRA_STATE_RESTORER is a sequence of assembly language statements to
> > restore anything not restored by this macro.  Only registers not saved by
> > the C compiler are restored (that is, R1(sp), R2(gp), R15(lp), and
> > anything restored by EXTRA_STATE_RESTORER).  */
> > #define RETURN(type)							      \
> >         lwi	r11, r1, PTO+PT_KERNEL_MODE;				      \
> > 	bnei	r11, 2f;		/* See if returning to kernel mode, */\
> > 					/* ... if so, skip resched &c.  */    \
> > 									      \
> > 	/* We're returning to user mode, so check for various conditions that \
> > 	   trigger rescheduling. */					      \
> > 	/* Get current task ptr into r11 */				      \
> > 	RETRIEVE_CURRENT_TASK(r11);					      \
> > 	lwi	r11, r11, TASK_NEED_RESCHED;				      \
> > 	bnei	r11, 3f;		/* Call the scheduler */	      \
> > 									      \
> > 	/* XXX Is PT_DTRACE handling needed here? */			      \
> > 	/* XXX m68knommu also checks TASK_STATE & TASK_COUNTER here.  */      \
> > 									      \
> > 	/* Maybe handle a signal */					      \
> > 5:	RETRIEVE_CURRENT_TASK(r11);					      \
> > 	lwi	r11, r11, TASK_SIGPENDING;				      \
> > 	bnei	r11, 4f;		/* Signals to handle, handle them */  \
> > 									      \
> > 	RETRIEVE_CURRENT_TASK(r11);					      \
> > 	lwi	r11, r11, TASK_PTRACE;					      \
> > 	bnei	r11, 4f;		/* Signals to handle, handle them */  \
> > 									      \
> > /* Finally, return to user state.  */					      \
> > 1:	BIPSET(r11);							      \
> > 	swi	r0, r0, KM;		/* Now officially in user state. */   \
> > 	POP_STATE(type);						      \
> > 	swi	r1, r0, KSP;		/* Save the kernel stack pointer. */  \
> > 	lwi	r1, r1, PT_GPR(GPR_SP)-PT_SIZE;				      \
> > 					/* Restore user stack pointer. */     \
> > 	bri	6f;							      \
> > 									      \
> > /* Return to kernel state.  */						      \
> > 2:	BIPSET(r11);							      \
> > 	POP_STATE(type);						      \
> > 6:									      \
> > type ## _return:		/* Make global symbol for debugging */	      \
> > 	type ## _RETURN_INST						      \
> > 									      \
> > /* Call the scheduler before returning from a syscall/trap. */		      \
> > 3:	SAVE_EXTRA_STATE_FOR_FUNCALL(type); /* Prepare for funcall. */	      \
> > 	bralid	r15, CSYM(schedule);	/* Call scheduler */		      \
> > 	nop;				/* delay slot */		      \
> > 	RESTORE_EXTRA_STATE_FOR_FUNCALL(type);				      \
> > 	brid	5b;		/* Back to continue return processing */      \
> > 	nop;								      \
> > 									      \
> > /* Handle a signal return; Pending signals should be in r18.  */	      \
> > 4:      /* Not all registers are saved by the normal trap/interrupt entry
> >     \ points (for instance, call-saved registers (because the normal    
> > \ C-compiler calling sequence in the kernel makes sure they're	      \
> > preserved), and call-clobbered registers in the case of	      \ traps),
> > but signal handlers may want to examine or change the      \ complete
> > register state.  Here we save anything not saved by	      \ the normal
> > entry sequence, so that it may be safely restored	      \ (in a possibly
> > modified form) after do_signal returns.  */	      \
> > SAVE_EXTRA_STATE(type)		/* Save state not saved by entry. */  \ la	r5,
> > r1, PTO;		/* Arg 1: struct pt_regs *regs */     \
> > 	add	r6, r0, r0;		/* Arg 2: sigset_t *oldset */	      \
> > 	bralid	r15, CSYM(do_signal);	/* Handle any signals */	      \
> > 	nop;								      \
> >         RESTORE_EXTRA_STATE(type);	/* Restore extra regs.  */	      \
> > 	brid	1b;							      \
> > 	nop;
> >
> >
> > /* Jump to the appropriate function for the system call number in r12
> >    (r12 is not preserved), or return an error if r12 is not valid.  The
> >    LP register should point to the location where the called function
> >    should return.  [note that MAKE_SYS_CALL uses label 1]  */
> > #define MAKE_SYS_CALL							      \
> > 	/* See if the system call number is valid.  */			      \
> > 	addi	r11, r12, -NR_syscalls;					      \
> > 	bgei	r11,1f;							      \
> > 	/* Figure out which function to use for this system call.  */	      \
> > 	/* Note Microblaze barrel shift is optional, so don't rely on it */   \
> > 	add	r12, r12, r12;			/* convert num -> ptr */      \
> > 	add	r12, r12, r12;						      \
> > 	lwi	r12, r12, CSYM(sys_call_table);	/* Get function pointer */    \
> > 	/* Make the system call.  */					      \
> > 	bra	r12;							      \
> > 	/* The syscall number is invalid, return an error.  */		      \
> > 1:	addi	r3, r0, -ENOSYS;					      \
> > 	rtsd	r15,8;		/* looks like a normal subroutine return */
> >
> >
> > 	// Ugly kludge to get around some Xilinx mb-gcc wierdness
> > 	.data
> > 	.globl CSYM(_shift_temp_loc)
> > CSYM(_shift_temp_loc):
> > 	.long	0
> >
> > 	.text
> >
> > /*
> >  * User trap.
> >  *
> >  * System calls are handled here.
> >  *
> >  * Syscall protocol:
> >  *   Syscall number in r12, args in r5-r10
> >  *   Return value in r3
> >  *
> >  * Trap entered via brki instruction, so BIP bit is set, and interrupts
> >  * are masked.  This is nice, means we don't have to CLI before state
> > save */
> > G_ENTRY(trap):
> > 	swi	r1, r0, ENTRY_SP;	// save stack (emulate v850)
> > 	SAVE_STATE (TRAP, r12, ENTRY_SP) // Save registers.
> > 	BIPCLR(r11);			// Clear BIP
> > 					// BIP now cleared, interrupts enabled
> > 	la	r15, r0, ret_from_trap-8// where the trap should return
> > 					// need -8 to adjust for rtsd r15, 8
> > 	MAKE_SYS_CALL			// Jump to the syscall function.
> > END(trap)
> >
> > /* This is just like ret_from_trap, but first restores extra registers
> >    saved by some wrappers.  */
> > L_ENTRY(restore_extra_regs_and_ret_from_trap):
> > 	RESTORE_EXTRA_STATE(TRAP)
> > 	// fall through
> > END(restore_extra_regs_and_ret_from_trap)
> >
> > /* Entry point used to return from a syscall/trap.  */
> > /* We re-enable BIP bit before state restore */
> > L_ENTRY(ret_from_trap):
> > 	RETURN(TRAP)
> > END(ret_from_trap)
> >
> > /* This the initial entry point for a new child thread, with an
> > appropriate stack in place that makes it look the the child is in the
> > middle of an syscall.  This function is actually `returned to' from
> > switch_thread (copy_thread makes ret_from_fork the return address in each
> > new thread's saved context).  */
> > C_ENTRY(ret_from_fork):
> > 	bralid	r15, CSYM(schedule_tail); // ...which is schedule_tail's arg
> > 	add	r3, r5, r0;		// switch_thread returns the prev task.
> > 					// ( in the delay slot )
> > 	add	r3, r0, r0;		// Child's fork call should return 0.
> > 	brid	ret_from_trap		// Do normal trap return.
> > 	nop;
> > C_END(ret_from_fork)
> >
> >
> > #if !TRAPS_PRESERVE_CALL_CLOBBERED_REGS
> > 	// Make sure r13 and r14 are preserved, in case we have to restart a
> > 	// system call because of a signal (ep has already been set by caller).
> > 	//st.w	r13, PTO+PT_GPR(13)[sp]
> > 	//st.w	r14, PTO+PT_GPR(13)[sp]
> > 	la	r15, r0, ret_from_long_syscall-8
> > #endif /* !TRAPS_PRESERVE_CALL_CLOBBERED_REGS */
> >
> > 	MAKE_SYS_CALL			// Jump to the syscall function.
> > END(syscall_long)
> >
> > #if !TRAPS_PRESERVE_CALL_CLOBBERED_REGS
> > /* Entry point used to return from a long syscall.  Only needed to
> > restore r13/r14 if the general trap mechanism doesnt' do so.  */
> > L_ENTRY(ret_from_long_syscall):
> > 	//ld.w	PTO+PT_GPR(13)[sp], r13 // Restore the extra registers
> > 	//ld.w	PTO+PT_GPR(13)[sp], r14
> > 	brid	ret_from_trap;		// The rest is the same as other traps
> > 	nop;
> > END(ret_from_long_syscall)
> > #endif /* !TRAPS_PRESERVE_CALL_CLOBBERED_REGS */
> >
> >
> > /* These syscalls need access to the struct pt_regs on the stack, so we
> >    implement them in assembly (they're basically all wrappers anyway). 
> > */
> >
> > L_ENTRY(sys_fork_wrapper):
> > #ifdef NO_MM
> > 	// fork almost works, enough to trick you into looking elsewhere :-(
> > 	addi	r3, r0, -EINVAL
> > 	rtsd	r15, 8;
> > #else
> > 	// Save state not saved by entry.  This is actually slight overkill;
> > 	// it's actually only necessary to save any state restored by
> > 	// switch_thread that's not saved by the trap entry.
> > 	SAVE_EXTRA_STATE(TRAP)		// Save state not saved by entry.
> > 	addi	r5, r0, SIGCHLD		// Arg 0: flags
> > 	lwi	r6, r1, PTO+PT_GPR(GPR_SP) // Arg 1: child SP (use parent's)
> > 	la	r7, r1, PTO;		// Arg 2: parent context
> > 	add	r9. r0, r0;		// Arg 3: (unused)
> > 	brid	CSYM(do_fork)		// Do real work (tail-call).
> > 	nop;
> > #endif
> > END(sys_fork_wrapper)
> >
> > L_ENTRY(sys_vfork_wrapper):
> > 	// Save state not saved by entry.  This is actually slight overkill;
> > 	// it's actually only necessary to save any state restored by
> > 	// switch_thread that's not saved by the trap entry.
> > 	SAVE_EXTRA_STATE(TRAP)		// Save state not saved by entry.
> > 	addi	r5, r0, CLONE_VFORK | CLONE_VM | SIGCHLD // Arg 0: flags
> > 	lwi	r6, r1, PTO+PT_GPR(GPR_SP) // Arg 1: child SP (use parent's)
> > 	la	r7, r1, PTO;		// Arg 2: parent context
> > 	add	r8, r0, r0;			// Arg 3: (unused)
> > 	brid	CSYM(do_fork)		// Do real work (tail-call).
> > 	nop
> > END(sys_vfork_wrapper)
> >
> > L_ENTRY(sys_clone_wrapper):
> > 	// Save state not saved by entry.  This is actually slight overkill;
> > 	// it's actually only necessary to save any state restored by
> > 	// switch_thread that's not saved by the trap entry.
> > 	SAVE_EXTRA_STATE(TRAP)		// Save state not saved by entry.
> > 	bnei	r6, 1f; 		// See if child SP arg (arg 1) is 0.
> > 	lwi	r6, r1, PTO+PT_GPR(GPR_SP);	// If so, use paret's stack ptr
> > 1:	la	r7, r1, PTO;		// Arg 2: parent context
> > 	add	r8, r0, r0;		// Arg 3: (unused)
> > 	brid	CSYM(do_fork)		// Do real work (tail-call).
> > 	nop;
> > END(sys_clone_wrapper)
> >
> > L_ENTRY(sys_execve_wrapper):
> > 	la	r8, r1, PTO;		// add user context as 4th arg
> > 	brid	CSYM(sys_execve);	// Do real work (tail-call).
> > 	nop;
> > END(sys_execve_wrapper)
> >
> > L_ENTRY(sys_sigsuspend_wrapper):
> >         SAVE_EXTRA_STATE(TRAP)		// Save state not saved by entry.
> > 	la	r6, r1, PTO;		// add user context as 2nd arg
> > 	bralid	r15, CSYM(sys_sigsuspend); // Do real work.
> > 	nop;
> > 	brid	restore_extra_regs_and_ret_from_trap;
> > 	nop;
> > END(sys_sigsuspend_wrapper)
> >
> > L_ENTRY(sys_rt_sigsuspend_wrapper):
> >         SAVE_EXTRA_STATE(TRAP)		// Save state not saved by entry.
> > 	la	r7, r1, PTO;		// add user context as 3rd arg
> > 	brlid	r15, CSYM(sys_rt_sigsuspend);	// Do real work.
> > 	nop;
> > 	brid	restore_extra_regs_and_ret_from_trap;
> > 	nop;
> > END(sys_rt_sigsuspend_wrapper)
> >
> > L_ENTRY(sys_sigreturn_wrapper):
> >         SAVE_EXTRA_STATE(TRAP)		// Save state not saved by entry.
> > 	la	r5, r1, PTO;		// add user context as 1st arg
> > 	brlid	r15, CSYM(sys_sigreturn);	// Do real work.
> > 	nop;
> > 	brid	restore_extra_regs_and_ret_from_trap;
> > 	nop;
> > END(sys_sigreturn_wrapper)
> >
> > L_ENTRY(sys_rt_sigreturn_wrapper):
> >         SAVE_EXTRA_STATE(TRAP)		// Save state not saved by entry.
> > 	la	r5, r1, PTO;		// add user context as 1st arg
> > 	brlid	r15, CSYM(sys_rt_sigreturn)	// Do real work.
> > 	nop;
> > 	brid	restore_extra_regs_and_ret_from_trap;
> > 	nop;
> > END(sys_rt_sigreturn_wrapper)
> >
> >
> > /*
> >  * Hardware maskable interrupts.
> >  *
> >  * The stack-pointer (r1) should have already been saved to the memory
> >  * location ENTRY_SP.
> >  * Currently this is just because the v850 code does it.  This should
> >  * be removed at some point to streamline things
> >  */
> > G_ENTRY(irq):
> > 	swi	r1, r0, ENTRY_SP;	// save stack (emulate v850)
> >        swi     r11, r0, 0x554;
> >         swi     r12, r0, 0x558;
> >         lwi     r11, r0, 0x41200018;    // first param irq number
> >         bgti    r11, 4f;
> >         lwi     r11, r0, 0x41c00008;
> >         lwi     r12, r0, 0x41c00004;
> >         rsub    r11, r12, r11;
> >         swi     r11, r0, 0x570;
> >         lwi     r12, r0, 0x574;
> >         rsub    r11, r11, r12;
> >         bgti    r11, 4f;
> >         lwi     r11, r0, 0x570;
> >         swi     r11, r0, 0x574;
> >         4:
> >         lwi     r12, r0, 0x558;
> >         lwi     r11, r0, 0x554;
> >
> > 	SAVE_STATE (IRQ, r0, ENTRY_SP)	// Save registers.
> >
> > 	add	r5, r0, r0;		// Clear first param
> > 	la	r6, r1, PTO;		// User regs are arg2
> >
> > 	// It's up to the high level handler to query the
> > 	// interrupt controller and get the IRQ number etc
> >
> > 	// Call the high-level interrupt handling code.
> > 	bralid r15, CSYM(handle_irq);
> > 	nop;
> >
> > 	// fall through
> >
> > /* Entry point used to return from an interrupt (also used by exception
> >    handle
> > s, below).  */
> > ret_from_irq:
> > 	RETURN(IRQ)
> > END(irq)
> >
> >
> > /*
> >  * Hardware non-maskable interrupts.
> >  *
> >  * The stack-pointer (r1) should have already been saved to the memory
> >  * location ENTRY_SP (the reason for this is that the interrupt vectors
> > may be * beyond a 22-bit signed offset jump from the actual interrupt
> > handler, and * this allows them to save the stack-pointer and use that
> > register to do an * indirect jump).
> >  */
> > G_ENTRY(nmi):
> > 	swi	r1, r0, NMI_ENTRY_SP;		/* Save state (emulate v850) */
> > 	SAVE_STATE (NMI, r0, NMI_ENTRY_SP); /* Save registers.  */
> >
> > 	add	r5, r0, r0;
> > 	la	r6, r1, PTO;	/* User regs are arg2.  */
> >
> > 	/* Non-maskable interrupts always lie right after maskable interrupts.
> > 	   Call the generic IRQ handler, with two arguments, the IRQ number,
> > 	   and a pointer to the user registers, to handle the specifics.
> > 	   (we subtract one because the first NMI has code 1).  */
> > 	bralid 	r15, CSYM(handle_irq);
> > 	nop;
> >
> > 	RETURN(NMI)
> > END(nmi0)
> >
> >
> > /*
> >  * Illegal instruction trap.
> >  *
> >  * The stack-pointer (r3) should have already been saved to the memory
> >  * location ENTRY_SP (the reason for this is that the interrupt vectors
> > may be * beyond a 22-bit signed offset jump from the actual interrupt
> > handler, and * this allows them to save the stack-pointer and use that
> > register to do an * indirect jump).
> >  */
> > G_ENTRY(illegal_instruction):
> > 	swi	r1, r0, ENTRY_SP;	// Save stack (emulate v850)
> > 	SAVE_STATE (IRQ, r0, ENTRY_SP)	// Save registers.
> > 	ENTRY_EI(r11);
> > 	addi	r5, r0, SIGILL;		// Arg 0: signal number
> > 	RETRIEVE_CURRENT_TASK(r6);	// Arg 1: task
> > 	la	r15, r0, ret_from_irq-8	// where the handler should return
> > 	brid	CSYM(force_sig);
> > 	nop;
> >
> > END(illegal_instruction)
> >
> >
> > /*
> >  * `Debug' trap
> >  *  We enter dbtrap in "BIP" (breakpoint) mode.
> >  *  So we exit the breakpoint mode with an 'rtbd' and proceed with the
> >  *  original dbtrap.
> >  *  however, wait to save state first
> >  */
> > G_ENTRY(dbtrap):
> > 	/* BIP bit is set on entry, no interrupts can occur */
> > 	swi	r1, r0, ENTRY_SP;	// Save stack (emulate v850)
> > 	SAVE_STATE (DBTRAP, r0, ENTRY_SP)   // Save registers.
> > 	BIPCLR(r11);
> > 	/* BIP bit now clear, interrupts can occur */
> > 	// Should insert code to detect illegal traps etc
> >
> > 	addi	r5, r0, SIGTRAP;	// send the trap signal
> > 	RETRIEVE_CURRENT_TASK(r6);	// to the current task
> > 	brlid	r15, CSYM(send_sig);
> > 	add	r7, r0, r0;		// 3rd param zero (delay slot)
> >
> > 	BIPSET(r11);		/* Set BIP again, ready for state restore */
> > 	RETURN(DBTRAP);
> >
> > END(dbtrap)
> >
> > G_ENTRY(reset_trap):
> >
> > 	/* BIP bit is set on entry, no interrupts can occur */
> > 	swi	r1, r0, ENTRY_SP;	// Save stack (emulate v850)
> > 	SAVE_STATE (DBTRAP, r0, ENTRY_SP)   // Save registers.
> > 	BIPCLR(r11);
> >
> > 	// For now, call into kernel for debugging
> > 	brlid	r15, CSYM(debug_trap);
> > 	la	r5, r1, PTO
> > 	// And loop forever! */
> > foo:	brid foo
> > 	nop
> > END(reset_trap)
> >
> > /*
> >  * Trap with no handler
> >  */
> > L_ENTRY(bad_trap_wrapper):
> > 	add	r5, r0, r19; 		// Arg 0: trap number
> > 	la	r6, r1, PTO;		// Arg 1: user regs
> > 	brid	CSYM(bad_trap);		// tail call handler
> > 	nop;
> >
> > END(bad_trap_wrapper)
> >
> > /*
> >  * This is where we switch between two threads.  The arguments are:
> >  *   r5 -- pointer to the struct thread for the `current' process
> >  *   r6 -- pointer to the struct thread for the `new' process.
> >  * when this function returns, it will return to the new thread.
> >  */
> > C_ENTRY(switch_thread):
> >
> > 	// Return the previous task
> > 	// Do this before push_state, so that return value is on stack
> > 	// Update the current task pointer
> > 	//GET_CURRENT_TASK(CURRENT_TASK)
> > 	RETRIEVE_CURRENT_TASK(r3);
> >
> > 	// First, push the current processor state on the stack
> > 	PUSH_STATE(SWITCH)
> >
> > 	// Now save the location of the kernel stack pointer for this thread;
> > 	// since we've pushed all other state on the stack, this is enough to
> > 	// restore it all later.
> > 	swi	r1, r5, THREAD_KSP;
> > 	// Now restore the stack pointer from the new process
> > 	lwi	r1, r6, THREAD_KSP;
> > 	// ... and restore all state from that
> > 	POP_STATE(SWITCH)
> > 	// Update the current task pointer
> > 	GET_CURRENT_TASK(CURRENT_TASK)
> > 	// Now return into the new thread
> > 	rtsd	r15,8;
> > 	nop;
> > C_END(switch_thread)
> >
> > 	.section .rodata
> >
> > 	.align 4
> > 	.globl CSYM(sys_call_table)
> > CSYM(sys_call_table):
> > 	.long CSYM(sys_ni_syscall)	// 0  -  old "setup()" system call
> > 	.long CSYM(sys_exit)
> > 	.long sys_fork_wrapper
> > 	.long CSYM(sys_read)
> > 	.long CSYM(sys_write)
> > 	.long CSYM(sys_open)		// 5
> > 	.long CSYM(sys_close)
> > 	.long CSYM(sys_waitpid)
> > 	.long CSYM(sys_creat)
> > 	.long CSYM(sys_link)
> > 	.long CSYM(sys_unlink)		// 10
> > 	.long sys_execve_wrapper
> > 	.long CSYM(sys_chdir)
> > 	.long CSYM(sys_time)
> > 	.long CSYM(sys_mknod)
> > 	.long CSYM(sys_chmod)		// 15
> > 	.long CSYM(sys_chown16)
> > 	.long CSYM(sys_ni_syscall)	// was: break
> > 	.long CSYM(sys_ni_syscall)	// was: oldstat (aka stat)
> > 	.long CSYM(sys_lseek)
> > 	.long CSYM(sys_getpid)		// 20
> > 	.long CSYM(sys_mount)
> > 	.long CSYM(sys_oldumount)
> > 	.long CSYM(sys_setuid16)
> > 	.long CSYM(sys_getuid16)
> > 	.long CSYM(sys_stime)		// 25
> > 	.long CSYM(sys_ptrace)
> > 	.long CSYM(sys_alarm)
> > 	.long CSYM(sys_ni_syscall)	// was: oldfstat (aka fstat)
> > 	.long CSYM(sys_pause)
> > 	.long CSYM(sys_utime)		// 30
> > 	.long CSYM(sys_ni_syscall)	// was: stty
> > 	.long CSYM(sys_ni_syscall)	// was: gtty
> > 	.long CSYM(sys_access)
> > 	.long CSYM(sys_nice)
> > 	.long CSYM(sys_ni_syscall)	// 35, was: ftime
> > 	.long CSYM(sys_sync)
> > 	.long CSYM(sys_kill)
> > 	.long CSYM(sys_rename)
> > 	.long CSYM(sys_mkdir)
> > 	.long CSYM(sys_rmdir)		// 40
> > 	.long CSYM(sys_dup)
> > 	.long CSYM(sys_pipe)
> > 	.long CSYM(sys_times)
> > 	.long CSYM(sys_ni_syscall)	// was: prof
> > 	.long CSYM(sys_brk)		// 45
> > 	.long CSYM(sys_setgid16)
> > 	.long CSYM(sys_getgid16)
> > 	.long CSYM(sys_signal)
> > 	.long CSYM(sys_geteuid16)
> > 	.long CSYM(sys_getegid16)	// 50
> > 	.long CSYM(sys_acct)
> > 	.long CSYM(sys_umount)		// recycled never used phys()
> > 	.long CSYM(sys_ni_syscall)	// was: lock
> > 	.long CSYM(sys_ioctl)
> > 	.long CSYM(sys_fcntl)		// 55
> > 	.long CSYM(sys_ni_syscall)	// was: mpx
> > 	.long CSYM(sys_setpgid)
> > 	.long CSYM(sys_ni_syscall) 	// was: ulimit
> > 	.long CSYM(sys_ni_syscall)
> > 	.long CSYM(sys_umask)		// 60
> > 	.long CSYM(sys_chroot)
> > 	.long CSYM(sys_ustat)
> > 	.long CSYM(sys_dup2)
> > 	.long CSYM(sys_getppid)
> > 	.long CSYM(sys_getpgrp)		// 65
> > 	.long CSYM(sys_setsid)
> > 	.long CSYM(sys_sigaction)
> > 	.long CSYM(sys_sgetmask)
> > 	.long CSYM(sys_ssetmask)
> > 	.long CSYM(sys_setreuid16)	// 70
> > 	.long CSYM(sys_setregid16)
> > 	.long sys_sigsuspend_wrapper
> > 	.long CSYM(sys_sigpending)
> > 	.long CSYM(sys_sethostname)
> > 	.long CSYM(sys_setrlimit)	// 75
> > 	.long CSYM(sys_old_getrlimit)
> > 	.long CSYM(sys_getrusage)
> > 	.long CSYM(sys_gettimeofday)
> > 	.long CSYM(sys_settimeofday)
> > 	.long CSYM(sys_getgroups16)	// 80
> > 	.long CSYM(sys_setgroups16)
> > 	.long CSYM(sys_ni_syscall)	// was: old_select
> > 	.long CSYM(sys_symlink)
> > 	.long CSYM(sys_ni_syscall)	// was: oldlstat (aka lstat)
> > 	.long CSYM(sys_readlink)	// 85
> > 	.long CSYM(sys_uselib)
> > 	.long CSYM(sys_swapon)
> > 	.long CSYM(sys_reboot)
> > 	.long CSYM(old_readdir)
> > 	.long CSYM(sys_mmap)		// 90
> > 	.long CSYM(sys_munmap)
> > 	.long CSYM(sys_truncate)
> > 	.long CSYM(sys_ftruncate)
> > 	.long CSYM(sys_fchmod)
> > 	.long CSYM(sys_fchown16)	// 95
> > 	.long CSYM(sys_getpriority)
> > 	.long CSYM(sys_setpriority)
> > 	.long CSYM(sys_ni_syscall) 	// was: profil
> > 	.long CSYM(sys_statfs)
> > 	.long CSYM(sys_fstatfs)		// 100
> > 	.long CSYM(sys_ni_syscall)	// i386: ioperm
> > 	.long CSYM(sys_socketcall)
> > 	.long CSYM(sys_syslog)
> > 	.long CSYM(sys_setitimer)
> > 	.long CSYM(sys_getitimer)	// 105
> > 	.long CSYM(sys_newstat)
> > 	.long CSYM(sys_newlstat)
> > 	.long CSYM(sys_newfstat)
> > 	.long CSYM(sys_ni_syscall)	// was: olduname (aka uname)
> > 	.long CSYM(sys_ni_syscall)	// 110, i386: iopl
> > 	.long CSYM(sys_vhangup)
> > 	.long CSYM(sys_ni_syscall)	// was: idle
> > 	.long CSYM(sys_ni_syscall)	// i386: vm86old
> > 	.long CSYM(sys_wait4)
> > 	.long CSYM(sys_swapoff)		// 115
> > 	.long CSYM(sys_sysinfo)
> > 	.long CSYM(sys_ipc)
> > 	.long CSYM(sys_fsync)
> > 	.long sys_sigreturn_wrapper
> > 	.long sys_clone_wrapper		// 120
> > 	.long CSYM(sys_setdomainname)
> > 	.long CSYM(sys_newuname)
> > 	.long CSYM(sys_ni_syscall)	// i386: modify_ldt, m68k: cacheflush
> > 	.long CSYM(sys_adjtimex)
> > 	.long CSYM(sys_mprotect)	// 125
> > 	.long CSYM(sys_sigprocmask)
> > 	.long CSYM(sys_create_module)
> > 	.long CSYM(sys_init_module)
> > 	.long CSYM(sys_delete_module)
> > 	.long CSYM(sys_get_kernel_syms) // 130
> > 	.long CSYM(sys_quotactl)
> > 	.long CSYM(sys_getpgid)
> > 	.long CSYM(sys_fchdir)
> > 	.long CSYM(sys_bdflush)
> > 	.long CSYM(sys_sysfs)		// 135
> > 	.long CSYM(sys_personality)
> > 	.long CSYM(sys_ni_syscall)	// for afs_syscall
> > 	.long CSYM(sys_setfsuid16)
> > 	.long CSYM(sys_setfsgid16)
> > 	.long CSYM(sys_llseek)		// 140
> > 	.long CSYM(sys_getdents)
> > 	.long CSYM(sys_select)
> > 	.long CSYM(sys_flock)
> > 	.long CSYM(sys_msync)
> > 	.long CSYM(sys_readv)		// 145
> > 	.long CSYM(sys_writev)
> > 	.long CSYM(sys_getsid)
> > 	.long CSYM(sys_fdatasync)
> > 	.long CSYM(sys_sysctl)
> > 	.long CSYM(sys_mlock)		// 150
> > 	.long CSYM(sys_munlock)
> > 	.long CSYM(sys_mlockall)
> > 	.long CSYM(sys_munlockall)
> > 	.long CSYM(sys_sched_setparam)
> > 	.long CSYM(sys_sched_getparam)	// 155
> > 	.long CSYM(sys_sched_setscheduler)
> > 	.long CSYM(sys_sched_getscheduler)
> > 	.long CSYM(sys_sched_yield)
> > 	.long CSYM(sys_sched_get_priority_max)
> > 	.long CSYM(sys_sched_get_priority_min)  // 160
> > 	.long CSYM(sys_sched_rr_get_interval)
> > 	.long CSYM(sys_nanosleep)
> > 	.long CSYM(sys_mremap)
> > 	.long CSYM(sys_setresuid16)
> > 	.long CSYM(sys_getresuid16)	// 165
> > 	.long CSYM(sys_ni_syscall)	// for vm86
> > 	.long CSYM(sys_query_module)
> > 	.long CSYM(sys_poll)
> > 	.long CSYM(sys_nfsservctl)
> > 	.long CSYM(sys_setresgid16)	// 170
> > 	.long CSYM(sys_getresgid16)
> > 	.long CSYM(sys_prctl)
> > 	.long sys_rt_sigreturn_wrapper
> > 	.long CSYM(sys_rt_sigaction)
> > 	.long CSYM(sys_rt_sigprocmask)	// 175
> > 	.long CSYM(sys_rt_sigpending)
> > 	.long CSYM(sys_rt_sigtimedwait)
> > 	.long CSYM(sys_rt_sigqueueinfo)
> > 	.long sys_rt_sigsuspend_wrapper
> > 	.long CSYM(sys_pread)		// 180
> > 	.long CSYM(sys_pwrite)
> > 	.long CSYM(sys_lchown16);
> > 	.long CSYM(sys_getcwd)
> > 	.long CSYM(sys_capget)
> > 	.long CSYM(sys_capset)		// 185
> > 	.long CSYM(sys_sigaltstack)
> > 	.long CSYM(sys_sendfile)
> > 	.long CSYM(sys_ni_syscall)	// streams1
> > 	.long CSYM(sys_ni_syscall)	// streams2
> > 	.long sys_vfork_wrapper		// 190
> > 	.long CSYM(sys_getrlimit)
> > 	.long CSYM(sys_mmap2)
> > 	.long CSYM(sys_truncate64)
> > 	.long CSYM(sys_ftruncate64)
> > 	.long CSYM(sys_stat64)		// 195
> > 	.long CSYM(sys_lstat64)
> > 	.long CSYM(sys_fstat64)
> > 	.long CSYM(sys_chown)
> > 	.long CSYM(sys_getuid)
> > 	.long CSYM(sys_getgid)		// 200
> > 	.long CSYM(sys_geteuid)
> > 	.long CSYM(sys_getegid)
> > 	.long CSYM(sys_setreuid)
> > 	.long CSYM(sys_setregid)
> > 	.long CSYM(sys_getgroups)	// 205
> > 	.long CSYM(sys_setgroups)
> > 	.long CSYM(sys_fchown)
> > 	.long CSYM(sys_setresuid)
> > 	.long CSYM(sys_getresuid)
> > 	.long CSYM(sys_setresgid)	// 210
> > 	.long CSYM(sys_getresgid)
> > 	.long CSYM(sys_lchown)
> > 	.long CSYM(sys_setuid)
> > 	.long CSYM(sys_setgid)
> > 	.long CSYM(sys_setfsuid)	// 215
> > 	.long CSYM(sys_setfsgid)
> > 	.long CSYM(sys_pivot_root)
> > 	.long CSYM(sys_mincore)		// just returns ENOSYS without MMU
> > 	.long CSYM(sys_madvise)		// just returns ENOSYS without MMU
> > 	.long CSYM(sys_getdents64)	// 220
> > 	.long CSYM(sys_fcntl64)
> > 	.long CSYM(sys_ni_syscall)	// Reserved for TUX
> > 	.long CSYM(sys_ni_syscall)	// Reserved for `security'
> > 	.long CSYM(sys_gettid)
> > 	.long CSYM(sys_ni_syscall)	// 225, sys_readahead on i386
> >
> > 	.space (NR_syscalls-225)*4
>
> ___________________________
> microblaze-uclinux mailing list
> microblaze-uclinux@xxxxxxxxxxxxxx
> Project Home Page : http://www.itee.uq.edu.au/~jwilliams/mblaze-uclinux
> Mailing List Archive :
> http://www.itee.uq.edu.au/~listarch/microblaze-uclinux/

-- 
Alejandro Lucero
Technical Director
+34 665 68 71 68
Valencia (SPAIN)
www.os3sl.com
--- entry.S.orig	2006-04-18 16:44:19.000000000 +0200
+++ entry.S	2006-04-18 16:47:20.000000000 +0200
@@ -243,7 +243,9 @@
 #define SAVE_SYS_REGS_FOR_IRQ						      \
 	SAVE_REG(17); 							      \
 	SAVE_LINK(r14);							      \
-	SAVE_PSW;
+        mfs     r11, rmsr;                                                    \
+        ori     r11, r11, 0xa;  			                      \
+        swi     r11, r1, PTO+PT_PSW;
 
 /* Restore system registers from the struct pt_regs pointed to by EP.         
    clobber r14 to restore status register, it gets fixed immediately */    
@@ -257,7 +259,10 @@
 #define SAVE_SYS_REGS_FOR_TRAP						      \
 	SAVE_REG(17); 							      \
 	SAVE_LINK(r14);							      \
-	SAVE_PSW;
+        mfs     r11, rmsr;                                                    \
+        ori     r11, r11, 0xa;  			                      \
+        swi     r11, r1, PTO+PT_PSW;
+
 
 /* Restore system registers from the struct pt_regs pointed to by EP.         
    clobber r11 to restore status register */
@@ -533,7 +538,7 @@
 
 /* Instructions to return from an IRQ */
 #define IRQ_RETURN_INST							      \
-	rtid	r14, 0;		/* Follow interrupt link pointer back to */   \
+	rtbd	r14, 0;		/* Follow interrupt link pointer back to */   \
 				/* next insn after interrupt occured */       \
 	nop;			/* Delay slot */		      
 
@@ -563,7 +568,6 @@
    the C compiler are restored (that is, R1(sp), R2(gp), R15(lp), and
    anything restored by EXTRA_STATE_RESTORER).  */
 #define RETURN(type)							      \
-	ENTRY_CLI(r11);							      \
         lwi	r11, r1, PTO+PT_KERNEL_MODE;				      \
 	bnei	r11, 2f;		/* See if returning to kernel mode, */\
 					/* ... if so, skip resched &c.  */    \
@@ -588,7 +592,8 @@
 	bnei	r11, 4f;		/* Signals to handle, handle them */  \
 									      \
 /* Finally, return to user state.  */					      \
-1:	swi	r0, r0, KM;		/* Now officially in user state. */   \
+1:	BIPSET(r11);							      \
+	swi	r0, r0, KM;		/* Now officially in user state. */   \
 	POP_STATE(type);						      \
 	swi	r1, r0, KSP;		/* Save the kernel stack pointer. */  \
 	lwi	r1, r1, PT_GPR(GPR_SP)-PT_SIZE;				      \
@@ -596,7 +601,8 @@
 	bri	6f;							      \
 									      \
 /* Return to kernel state.  */						      \
-2:	POP_STATE(type);						      \
+2:	BIPSET(r11);							      \
+	POP_STATE(type);						      \
 6:									      \
 type ## _return:		/* Make global symbol for debugging */	      \
 	type ## _RETURN_INST						      \
@@ -605,7 +611,6 @@
 3:	SAVE_EXTRA_STATE_FOR_FUNCALL(type); /* Prepare for funcall. */	      \
 	bralid	r15, CSYM(schedule);	/* Call scheduler */		      \
 	nop;				/* delay slot */		      \
-	ENTRY_CLI(r11);		/* The scheduler enables interrupts */	      \
 	RESTORE_EXTRA_STATE_FOR_FUNCALL(type);				      \
 	brid	5b;		/* Back to continue return processing */      \
 	nop;								      \
@@ -624,7 +629,6 @@
 	add	r6, r0, r0;		/* Arg 2: sigset_t *oldset */	      \
 	bralid	r15, CSYM(do_signal);	/* Handle any signals */	      \
 	nop;								      \
-	ENTRY_CLI(r11);		/* Sig handling enables interrupts */	      \
         RESTORE_EXTRA_STATE(type);	/* Restore extra regs.  */	      \
 	brid	1b;							      \
 	nop;	
@@ -690,7 +694,6 @@
 /* Entry point used to return from a syscall/trap.  */
 /* We re-enable BIP bit before state restore */
 L_ENTRY(ret_from_trap):
-	BIPSET(r11);			//  Ints masked for state restore
 	RETURN(TRAP)
 END(ret_from_trap)