- movl VA_ETC,%eax /* get timer */ ;\
- movl CX(EXT(current_tstamp),%edx),%ecx /* get old time stamp */;\
- movl %eax,CX(EXT(current_tstamp),%edx) /* set new time stamp */;\
- subl %ecx,%eax /* elapsed = new-old */ ;\
- movl CX(EXT(current_timer),%edx),%ecx /* get current timer */;\
- addl %eax,LOW_BITS(%ecx) /* add to low bits */ ;\
- jns 0f /* if overflow, */ ;\
- call timer_normalize /* normalize timer */ ;\
-0: testb $0x80,LOW_BITS+3(%ebx) /* old timer overflow? */;\
- jz 0f /* if overflow, */ ;\
- movl %ebx,%ecx /* get old timer */ ;\
- call timer_normalize /* normalize timer */ ;\
-0: movl %ebx,CX(EXT(current_timer),%edx) /* set timer */
-
-
-/*
- * Normalize timer in ecx.
- * Preserves edx; clobbers eax.
- */
- .align ALIGN
-timer_high_unit:
- .long TIMER_HIGH_UNIT /* div has no immediate opnd */
-
-timer_normalize:
- pushl %edx /* save registersz */
- pushl %eax
- xorl %edx,%edx /* clear divisor high */
- movl LOW_BITS(%ecx),%eax /* get divisor low */
- divl timer_high_unit,%eax /* quotient in eax */
- /* remainder in edx */
- addl %eax,HIGH_BITS_CHECK(%ecx) /* add high_inc to check */
- movl %edx,LOW_BITS(%ecx) /* remainder to low_bits */
- addl %eax,HIGH_BITS(%ecx) /* add high_inc to high bits */
- popl %eax /* restore register */
- popl %edx
- ret
-
-/*
- * Switch to a new timer.
- */
-Entry(timer_switch)
- CPU_NUMBER(%edx) /* get this CPU */
- movl VA_ETC,%ecx /* get timer */
- movl CX(EXT(current_tstamp),%edx),%eax /* get old time stamp */
- movl %ecx,CX(EXT(current_tstamp),%edx) /* set new time stamp */
- subl %ecx,%eax /* elapsed = new - old */
- movl CX(EXT(current_timer),%edx),%ecx /* get current timer */
- addl %eax,LOW_BITS(%ecx) /* add to low bits */
- jns 0f /* if overflow, */
- call timer_normalize /* normalize timer */
-0:
- movl S_ARG0,%ecx /* get new timer */
- movl %ecx,CX(EXT(current_timer),%edx) /* set timer */
- ret
-
-/*
- * Initialize the first timer for a CPU.
- */
-Entry(start_timer)
- CPU_NUMBER(%edx) /* get this CPU */
- movl VA_ETC,%ecx /* get timer */
- movl %ecx,CX(EXT(current_tstamp),%edx) /* set initial time stamp */
- movl S_ARG0,%ecx /* get timer */
- movl %ecx,CX(EXT(current_timer),%edx) /* set initial timer */
- ret
-
-#endif /* accurate timing */
-
-/*
- * Encapsulate the transfer of exception stack frames between a PCB
- * and a thread stack. Since the whole point of these is to emulate
- * a call or exception that changes privilege level, both macros
- * assume that there is no user esp or ss stored in the source
- * frame (because there was no change of privilege to generate them).
- */
-
-/*
- * Transfer a stack frame from a thread's user stack to its PCB.
- * We assume the thread and stack addresses have been loaded into
- * registers (our arguments).
- *
- * The macro overwrites edi, esi, ecx and whatever registers hold the
- * thread and stack addresses (which can't be one of the above three).
- * The thread address is overwritten with the address of its saved state
- * (where the frame winds up).
- *
- * Must be called on kernel stack.
- */
-#define FRAME_STACK_TO_PCB(thread, stkp) ;\
- movl ACT_PCB(thread),thread /* get act`s PCB */ ;\
- leal PCB_ISS(thread),%edi /* point to PCB`s saved state */;\
- movl %edi,thread /* save for later */ ;\
- movl stkp,%esi /* point to start of frame */ ;\
- movl $ R_UESP,%ecx ;\
- sarl $2,%ecx /* word count for transfer */ ;\
- cld /* we`re incrementing */ ;\
- rep ;\
- movsl /* transfer the frame */ ;\
- addl $ R_UESP,stkp /* derive true "user" esp */ ;\
- movl stkp,R_UESP(thread) /* store in PCB */ ;\
- movl $0,%ecx ;\
- mov %ss,%cx /* get current ss */ ;\
- movl %ecx,R_SS(thread) /* store in PCB */
-
-/*
- * Transfer a stack frame from a thread's PCB to the stack pointed
- * to by the PCB. We assume the thread address has been loaded into
- * a register (our argument).
- *
- * The macro overwrites edi, esi, ecx and whatever register holds the
- * thread address (which can't be one of the above three). The
- * thread address is overwritten with the address of its saved state
- * (where the frame winds up).
- *
- * Must be called on kernel stack.
- */
-#define FRAME_PCB_TO_STACK(thread) ;\
- movl ACT_PCB(thread),%esi /* get act`s PCB */ ;\
- leal PCB_ISS(%esi),%esi /* point to PCB`s saved state */;\
- movl R_UESP(%esi),%edi /* point to end of dest frame */;\
- movl ACT_MAP(thread),%ecx /* get act's map */ ;\
- movl MAP_PMAP(%ecx),%ecx /* get map's pmap */ ;\
- cmpl EXT(kernel_pmap), %ecx /* If kernel loaded task */ ;\
- jz 1f /* use kernel data segment */ ;\
- movl $ USER_DS,%cx /* else use user data segment */;\
- mov %cx,%es ;\
-1: ;\
- movl $ R_UESP,%ecx ;\
- subl %ecx,%edi /* derive start of frame */ ;\
- movl %edi,thread /* save for later */ ;\
- sarl $2,%ecx /* word count for transfer */ ;\
- cld /* we`re incrementing */ ;\
- rep ;\
- movsl /* transfer the frame */ ;\
- mov %ss,%cx /* restore kernel segments */ ;\
- mov %cx,%es