[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)