📄 windalib.s
字号:
/* windALib.s - I80x86 internal VxWorks kernel assembly library *//* Copyright 1984-2001 Wind River Systems, Inc. *//*modification history--------------------01q,05dec01,hdn added PAUSE instruction for Pentium401p,13nov01,ahm Added AutoHalt mode for idling kenel (SPR#32599)01o,26sep01,hdn added the interrupt stack switch support01n,23aug01,hdn added FUNC/FUNC_LABEL, replaced .align with .balign replaced sysCodeSelector with sysCsSuper01m,28aug98,hdn replaced sysIntLevel() with "movl INT29(%edi),%eax"01l,10aug98,pr replaced evtsched with function pointer _func_evtLogTSched01k,29apr98,cjtc fix WV instrumentation in idle01j,16apr98,pr cleanup.01i,17feb98,pr added WindView 2.0 code.01h,29jul96,sbs Made windview conditionally compile.01g,14jun95,hdn changed CODE_SELECTOR to sysCodeSelector.01f,08aug94,hdn added support for WindView.01e,02jun93,hdn updated to 5.1. - fixed #else and #endif - changed VOID to void - changed ASMLANGUAGE to _ASMLANGUAGE - changed copyright notice01d,15oct92,hdn supported nested interrupt.01c,13oct92,hdn debugged.01b,07apr92,hdn written optimized codes.01a,28feb92,hdn written based on TRON, 68k version.*//*DESCRIPTIONThis module contains internals to the VxWorks kernel.These routines have been coded in assembler because they are eitherspecific to this processor, or they have been optimized for performance.*/#define _ASMLANGUAGE#include "vxWorks.h"#include "asm.h"#include "regs.h"#include "esf.h"#include "private/eventP.h"#include "private/trgLibP.h"#include "private/taskLibP.h"#include "private/semLibP.h"#include "private/workQLibP.h"/* defines */#define INT_STACK_USE#define X86_POWER_MANAGEMENT .data .globl FUNC(copyright_wind_river) .long FUNC(copyright_wind_river) /* internals */ .globl GTEXT(windExit) /* routine to exit mutual exclusion */ .globl GTEXT(windIntStackSet) /* interrupt stack set routine */ .globl GTEXT(vxTaskEntry) /* task entry wrapper */ .globl GTEXT(intEnt) /* interrupt entrance routine */ .globl GTEXT(intExit) /* interrupt exit routine */ .globl GTEXT(intStackEnable) /* interrupt stack usage enabler */#ifdef X86_POWER_MANAGEMENT .globl GTEXT(vxIdleAutoHalt) /* put cpu in AutoHalt when idle */#endif /* X86_POWER_MANAGEMENT */#ifdef PORTABLE .globl GTEXT(windLoadContext) /* needed by portable reschedule () */#else .globl GTEXT(reschedule) /* optimized reschedule () routine */#endif /* PORTABLE */ .globl GDATA(vxIntStackPtr) /* interrupt stack pointer */ .globl GDATA(vxIntStackEnabled) /* interrupt stack enabled */FUNC_LABEL(vxIntStackPtr) /* interrupt stack pointer */ .long 0x00000000FUNC_LABEL(vxIntStackEnabled) /* TRUE if interrupt stack is enabled */ .long 0x00000000FUNC_LABEL(intNest) /* interrupt stack nest counter */ .long 0x00000000 .text .balign 16/********************************************************************************* windExitInt - exit kernel routine from interrupt level** windExit branches here if exiting kernel routine from int level* No rescheduling is necessary because the ISR will exit via intExit, and* intExit does the necessary rescheduling.*/windExitIntWork: popfl /* pop original level */ call FUNC(workQDoWork) /* empty the work queue */windExitInt: pushfl /* push interrupt level to stack */ cli /* LOCK INTERRUPTS */ cmpl $0,FUNC(workQIsEmpty) /* test for work to do */ je windExitIntWork /* workQ is not empty */#ifdef WV_INSTRUMENTATION /* windview instrumentation - BEGIN * exit windExit with no dispatch; point 1 in the windExit diagram. */ cmpl $0,FUNC(evtAction) /* is WindView on? */ je noInst1 movl $ WV_CLASS_1_ON,%eax andl FUNC(wvEvtClass),%eax /* is event collection on? */ cmpl $ WV_CLASS_1_ON,%eax /* is event collection on? */ jne trgCheckInst1 movl FUNC(_func_evtLogTSched),%edx /* event log routine */ cmpl $0,%edx je trgCheckInst1 movl FUNC(taskIdCurrent),%eax /* current task */ movl WIND_TCB_PRIORITY(%eax),%ecx pushl %ecx /* WIND_TCB_PRIORITY */ pushl %eax /* taskIdCurrent */ /* Here we try to determine if the task is running at an * inherited priority, if so a different event is generated. */ cmpl WIND_TCB_PRI_NORMAL(%eax),%ecx jge noInst1Inheritance /* no inheritance */ pushl $ EVENT_WIND_EXIT_NODISPATCH_PI jmp inst1Inheritance /* no inheritance */noInst1Inheritance: pushl $ EVENT_WIND_EXIT_NODISPATCH /* event id */inst1Inheritance: call *%edx /* call evtsched routine */ addl $12,%esptrgCheckInst1: movl $ TRG_CLASS_1,%eax orl $ TRG_ON,%eax cmpl FUNC(trgEvtClass),%eax /* any trigger? */ jne noInst1 movl FUNC(_func_trgCheck),%edx /* triggering routine */ cmpl $0,%edx je noInst1 movl FUNC(taskIdCurrent),%eax /* current task */ movl WIND_TCB_PRIORITY(%eax),%ecx pushl $ 0 /* 0 */ pushl $ 0 /* 0 */ pushl $ 0 /* 0 */ pushl %ecx /* WIND_TCB_PRIORITY */ pushl %eax /* taskIdCurrent */ pushl $ 0 /* obj */ pushl $ 0 /* TRG_CLASS1_INDEX */ /* Here we try to determine if the task is running at an * inherited priority, if so a different event is generated. */ cmpl WIND_TCB_PRI_NORMAL(%eax),%ecx jge noTrgInst1Inheritance /* no inheritance */ pushl $ EVENT_WIND_EXIT_NODISPATCH_PI jmp trgInst1Inheritance /* no inheritance */noTrgInst1Inheritance: pushl $ EVENT_WIND_EXIT_NODISPATCH /* event id */trgInst1Inheritance: call *%edx /* call triggering routine */ addl $32,%espnoInst1: /* windview instrumentation - END */#endif /* WV_INSTRUMENTATION */ movl $0,FUNC(kernelState) /* release mutual exclusion to kernel */ popfl /* pop original level */ xorl %eax,%eax /* return OK */ ret /* intExit will do rescheduling *//********************************************************************************* checkTaskReady - check that taskIdCurrent is ready to run** This code branched to by windExit when it finds preemption is disabled.* It is possible that even though preemption is disabled, a context switch* must occur. This situation arrises when a task block during a preemption* lock. So this routine checks if taskIdCurrent is ready to run, if not it* branches to save the context of taskIdCurrent, otherwise it falls thru to* check the work queue for any pending work.*/ .balign 16,0x90checkTaskReady: cmpl $0,WIND_TCB_STATUS(%edx) /* is task ready to run */ jne saveTaskContext /* if no, we blocked with preempt off */ /* FALL THRU TO CHECK WORK QUEUE *//********************************************************************************* checkWorkQ - check the work queue for any work to do** This code is branched to by windExit. Currently taskIdCurrent is highest* priority ready task, but before we can return to it we must check the work* queue. If there is work we empty it via doWorkPreSave, otherwise we unlock* interrupts, clear d0, and return to taskIdCurrent.*/checkWorkQ: cli /* LOCK INTERRUPTS */ cmpl $0,FUNC(workQIsEmpty) /* test for work to do */ je doWorkPreSave /* workQueue is not empty */#ifdef WV_INSTRUMENTATION /* windview instrumentation - BEGIN * exit windExit with no dispatch; point 4 in the windExit diagram. */ cmpl $0,FUNC(evtAction) /* is WindView on? */ je noInst4 movl $ WV_CLASS_1_ON,%eax andl FUNC(wvEvtClass),%eax /* is event collection on? */ cmpl $ WV_CLASS_1_ON,%eax /* is event collection on? */ jne trgCheckInst4 movl FUNC(_func_evtLogTSched),%edx /* event log routine */ cmpl $0,%edx je trgCheckInst4 movl FUNC(taskIdCurrent),%eax /* current task */ movl WIND_TCB_PRIORITY(%eax),%ecx pushl %ecx /* WIND_TCB_PRIORITY */ pushl %eax /* taskIdCurrent */ /* Here we try to determine if the task is running at an * inherited priority, if so a different event is generated. */ cmpl WIND_TCB_PRI_NORMAL(%eax),%ecx jge noInst4Inheritance /* no inheritance */ pushl $ EVENT_WIND_EXIT_NODISPATCH_PI jmp inst4Inheritance /* no inheritance */noInst4Inheritance: pushl $ EVENT_WIND_EXIT_NODISPATCH /* event id */inst4Inheritance: call *%edx /* call evtsched routine */ addl $12,%esptrgCheckInst4: movl $ TRG_CLASS_1,%eax orl $ TRG_ON,%eax cmpl FUNC(trgEvtClass),%eax /* any trigger? */ jne noInst4 movl FUNC(_func_trgCheck),%edx /* triggering routine */ cmpl $0,%edx je noInst4 movl FUNC(taskIdCurrent),%eax /* current task */ movl WIND_TCB_PRIORITY(%eax),%ecx pushl $ 0 /* 0 */ pushl $ 0 /* 0 */ pushl $ 0 /* 0 */ pushl %ecx /* WIND_TCB_PRIORITY */ pushl %eax /* taskIdCurrent */ pushl $ 0 /* obj */ pushl $ 0 /* TRG_CLASS1_INDEX */ /* Here we try to determine if the task is running at an * inherited priority, if so a different event is generated. */ cmpl WIND_TCB_PRI_NORMAL(%eax),%ecx jge noTrgInst4Inheritance /* no inheritance */ pushl $ EVENT_WIND_EXIT_NODISPATCH_PI jmp trgInst4Inheritance /* no inheritance */noTrgInst4Inheritance: pushl $ EVENT_WIND_EXIT_NODISPATCH /* event id */trgInst4Inheritance: call *%edx /* call triggering routine */ addl $32,%espnoInst4: /* windview instrumentation - END */#endif /* WV_INSTRUMENTATION */ movl $0,FUNC(kernelState) /* else release exclusion */ sti /* UNLOCK INTERRUPTS */ xorl %eax,%eax /* return OK */ ret /* back to calling task *//********************************************************************************* doWorkPreSave - empty the work queue with current context not saved** We try to empty the work queue here, rather than let reschedule* perform the work because there is a strong chance that the* work we do will not preempt the calling task. If this is the case, then* saving the entire context just to restore it in reschedule is a waste of* time. Once the work has been emptied, the ready queue must be checked to* see if reschedule must be called, the check of the ready queue is done by* branching back up to checkTaskCode.*/ .balign 16,0x90doWorkPreSave: sti /* UNLOCK INTERRUPTS */ call FUNC(workQDoWork) /* empty the work queue */ jmp checkTaskSwitch /* back up to test if tasks switched *//******************************************************************************** windExit - task level exit from kernel** Release kernel mutual exclusion (kernelState) and dispatch any new task if* necessary. If a higher priority task than the current task has been made* ready, then we invoke the rescheduler. Before releasing mutual exclusion,* the work queue is checked and emptied if necessary.** If rescheduling is necessary, the context of the calling task is saved in its* associated TCB with the PC pointing at the next instruction after the jsr to* this routine. The SP in the tcb is modified to ignore the return address* on the stack. Thus the context saved is as if this routine was never called.** Only the volatile registers e[adc]x are safe to use until the context* is saved in saveTaskContext.** At the call to reschedule the value of taskIdCurrent must be in edx.** RETURNS: OK or* ERROR if semaphore timeout occurs.** NOMANUAL* STATUS windExit ()*/ .balign 16,0x90FUNC_LABEL(windExit) cmpl $0,FUNC(intCnt) /* if intCnt == 0 we're from task */ jne windExitInt /* else we're exiting interrupt code */ /* FALL THRU TO CHECK THAT CURRENT TASK IS STILL HIGHEST *//********************************************************************************* checkTaskSwitch - check to see if taskIdCurrent is still highest task** We arrive at this code either as the result of falling thru from windExit,* or if we have finished emptying the work queue. We compare taskIdCurrent* with the highest ready task on the ready queue. If they are same we* go to a routine to check the work queue. If they are different and preemption* is allowed we branch to a routine to make sure that taskIdCurrent is really* ready (it may have blocked with preemption disabled). If they are different* we save the context of taskIdCurrent and fall thru to reschedule.*/checkTaskSwitch: movl FUNC(taskIdCurrent),%edx /* move taskIdCurrent to edx */ cmpl FUNC(readyQHead),%edx /* compare highest ready task */ je checkWorkQ /* if same then time to leave */ cmpl $0,WIND_TCB_LOCK_CNT(%edx) /* is task preemption allowed */ jne checkTaskReady /* if no, check task is ready */saveTaskContext: movl (%esp),%eax /* save return address as PC */ movl %eax,WIND_TCB_PC(%edx) pushfl /* save a eflags */ popl WIND_TCB_EFLAGS(%edx) bts $9,WIND_TCB_EFLAGS(%edx) /* set IF to enable INT */ movl %ebx,WIND_TCB_EBX(%edx) /* e[adc]x are volatile */ movl %esi,WIND_TCB_ESI(%edx) movl %edi,WIND_TCB_EDI(%edx) movl %ebp,WIND_TCB_EBP(%edx) movl %esp,WIND_TCB_ESP(%edx) movl $0,WIND_TCB_EAX(%edx) /* clear saved eax for return */ addl $4,WIND_TCB_ESP(%edx) /* fix up SP for no ret adrs */ pushl FUNC(errno) /* save errno */ popl WIND_TCB_ERRNO(%edx)#ifdef PORTABLE call FUNC(reschedule)#else /* FALL THRU TO RESCHEDULE *//********************************************************************************* reschedule - rescheduler for VxWorks kernel** This routine is called when either intExit, or windExit, thinks the* context might change. All of the contexts of all of the tasks are* accurately stored in the task control blocks when entering this function.* The status register is 0x800f0000. (Supervisor, Stack0, Interrupts UNLOCKED)** The register %edx must contain the value of _taskIdCurrent at the entrance to* this routine.** At the conclusion of this routine, taskIdCurrent will equal the highest* priority task eligible to run, and the kernel work queue will be empty.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -