xref: /freebsd/sys/amd64/amd64/cpu_switch.S (revision 0967373e)
10967373eSDavid Greenman/*-
20967373eSDavid Greenman * Copyright (c) 1990 The Regents of the University of California.
30967373eSDavid Greenman * All rights reserved.
40967373eSDavid Greenman *
50967373eSDavid Greenman * This code is derived from software contributed to Berkeley by
60967373eSDavid Greenman * William Jolitz.
70967373eSDavid Greenman *
80967373eSDavid Greenman * Redistribution and use in source and binary forms, with or without
90967373eSDavid Greenman * modification, are permitted provided that the following conditions
100967373eSDavid Greenman * are met:
110967373eSDavid Greenman * 1. Redistributions of source code must retain the above copyright
120967373eSDavid Greenman *    notice, this list of conditions and the following disclaimer.
130967373eSDavid Greenman * 2. Redistributions in binary form must reproduce the above copyright
140967373eSDavid Greenman *    notice, this list of conditions and the following disclaimer in the
150967373eSDavid Greenman *    documentation and/or other materials provided with the distribution.
160967373eSDavid Greenman * 3. All advertising materials mentioning features or use of this software
170967373eSDavid Greenman *    must display the following acknowledgement:
180967373eSDavid Greenman *	This product includes software developed by the University of
190967373eSDavid Greenman *	California, Berkeley and its contributors.
200967373eSDavid Greenman * 4. Neither the name of the University nor the names of its contributors
210967373eSDavid Greenman *    may be used to endorse or promote products derived from this software
220967373eSDavid Greenman *    without specific prior written permission.
230967373eSDavid Greenman *
240967373eSDavid Greenman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
250967373eSDavid Greenman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
260967373eSDavid Greenman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
270967373eSDavid Greenman * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
280967373eSDavid Greenman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
290967373eSDavid Greenman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
300967373eSDavid Greenman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
310967373eSDavid Greenman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
320967373eSDavid Greenman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
330967373eSDavid Greenman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
340967373eSDavid Greenman * SUCH DAMAGE.
350967373eSDavid Greenman *
360967373eSDavid Greenman *	$Id$
370967373eSDavid Greenman */
380967373eSDavid Greenman
390967373eSDavid Greenman#include "npx.h"	/* for NNPX */
400967373eSDavid Greenman#include "assym.s"	/* for preprocessor defines */
410967373eSDavid Greenman#include "errno.h"	/* for error codes */
420967373eSDavid Greenman
430967373eSDavid Greenman#include "i386/isa/debug.h"	/* for SHOW macros */
440967373eSDavid Greenman#include "machine/asmacros.h"	/* for miscellaneous assembly macros */
450967373eSDavid Greenman
460967373eSDavid Greenman/*****************************************************************************/
470967373eSDavid Greenman/* Scheduling                                                                */
480967373eSDavid Greenman/*****************************************************************************/
490967373eSDavid Greenman
500967373eSDavid Greenman/*
510967373eSDavid Greenman * The following primitives manipulate the run queues.
520967373eSDavid Greenman * _whichqs tells which of the 32 queues _qs
530967373eSDavid Greenman * have processes in them.  Setrq puts processes into queues, Remrq
540967373eSDavid Greenman * removes them from queues.  The running process is on no queue,
550967373eSDavid Greenman * other processes are on a queue related to p->p_pri, divided by 4
560967373eSDavid Greenman * actually to shrink the 0-127 range of priorities into the 32 available
570967373eSDavid Greenman * queues.
580967373eSDavid Greenman */
590967373eSDavid Greenman	.data
600967373eSDavid Greenman	.globl	_curpcb, _whichqs
610967373eSDavid Greenman_curpcb:	.long	0			/* pointer to curproc's PCB area */
620967373eSDavid Greenman_whichqs:	.long	0			/* which run queues have data */
630967373eSDavid Greenman
640967373eSDavid Greenman	.globl	_qs,_cnt,_panic
650967373eSDavid Greenman	.comm	_noproc,4
660967373eSDavid Greenman	.comm	_runrun,4
670967373eSDavid Greenman
680967373eSDavid Greenman	.globl	_want_resched
690967373eSDavid Greenman_want_resched:	.long	0			/* we need to re-run the scheduler */
700967373eSDavid Greenman
710967373eSDavid Greenman	.text
720967373eSDavid Greenman/*
730967373eSDavid Greenman * Setrq(p)
740967373eSDavid Greenman *
750967373eSDavid Greenman * Call should be made at spl6(), and p->p_stat should be SRUN
760967373eSDavid Greenman */
770967373eSDavid GreenmanENTRY(setrq)
780967373eSDavid Greenman	movl	4(%esp),%eax
790967373eSDavid Greenman	cmpl	$0,P_RLINK(%eax)		/* should not be on q already */
800967373eSDavid Greenman	je	set1
810967373eSDavid Greenman	pushl	$set2
820967373eSDavid Greenman	call	_panic
830967373eSDavid Greenmanset1:
840967373eSDavid Greenman	movzbl	P_PRI(%eax),%edx
850967373eSDavid Greenman	shrl	$2,%edx
860967373eSDavid Greenman	btsl	%edx,_whichqs			/* set q full bit */
870967373eSDavid Greenman	shll	$3,%edx
880967373eSDavid Greenman	addl	$_qs,%edx			/* locate q hdr */
890967373eSDavid Greenman	movl	%edx,P_LINK(%eax)		/* link process on tail of q */
900967373eSDavid Greenman	movl	P_RLINK(%edx),%ecx
910967373eSDavid Greenman	movl	%ecx,P_RLINK(%eax)
920967373eSDavid Greenman	movl	%eax,P_RLINK(%edx)
930967373eSDavid Greenman	movl	%eax,P_LINK(%ecx)
940967373eSDavid Greenman	ret
950967373eSDavid Greenman
960967373eSDavid Greenmanset2:	.asciz	"setrq"
970967373eSDavid Greenman
980967373eSDavid Greenman/*
990967373eSDavid Greenman * Remrq(p)
1000967373eSDavid Greenman *
1010967373eSDavid Greenman * Call should be made at spl6().
1020967373eSDavid Greenman */
1030967373eSDavid GreenmanENTRY(remrq)
1040967373eSDavid Greenman	movl	4(%esp),%eax
1050967373eSDavid Greenman	movzbl	P_PRI(%eax),%edx
1060967373eSDavid Greenman	shrl	$2,%edx
1070967373eSDavid Greenman	btrl	%edx,_whichqs			/* clear full bit, panic if clear already */
1080967373eSDavid Greenman	jb	rem1
1090967373eSDavid Greenman	pushl	$rem3
1100967373eSDavid Greenman	call	_panic
1110967373eSDavid Greenmanrem1:
1120967373eSDavid Greenman	pushl	%edx
1130967373eSDavid Greenman	movl	P_LINK(%eax),%ecx		/* unlink process */
1140967373eSDavid Greenman	movl	P_RLINK(%eax),%edx
1150967373eSDavid Greenman	movl	%edx,P_RLINK(%ecx)
1160967373eSDavid Greenman	movl	P_RLINK(%eax),%ecx
1170967373eSDavid Greenman	movl	P_LINK(%eax),%edx
1180967373eSDavid Greenman	movl	%edx,P_LINK(%ecx)
1190967373eSDavid Greenman	popl	%edx
1200967373eSDavid Greenman	movl	$_qs,%ecx
1210967373eSDavid Greenman	shll	$3,%edx
1220967373eSDavid Greenman	addl	%edx,%ecx
1230967373eSDavid Greenman	cmpl	P_LINK(%ecx),%ecx		/* q still has something? */
1240967373eSDavid Greenman	je	rem2
1250967373eSDavid Greenman	shrl	$3,%edx				/* yes, set bit as still full */
1260967373eSDavid Greenman	btsl	%edx,_whichqs
1270967373eSDavid Greenmanrem2:
1280967373eSDavid Greenman	movl	$0,P_RLINK(%eax)		/* zap reverse link to indicate off list */
1290967373eSDavid Greenman	ret
1300967373eSDavid Greenman
1310967373eSDavid Greenmanrem3:	.asciz	"remrq"
1320967373eSDavid Greenmansw0:	.asciz	"swtch"
1330967373eSDavid Greenman
1340967373eSDavid Greenman/*
1350967373eSDavid Greenman * When no processes are on the runq, Swtch branches to idle
1360967373eSDavid Greenman * to wait for something to come ready.
1370967373eSDavid Greenman */
1380967373eSDavid Greenman	ALIGN_TEXT
1390967373eSDavid GreenmanIdle:
1400967373eSDavid Greenman	sti
1410967373eSDavid Greenman	SHOW_STI
1420967373eSDavid Greenman
1430967373eSDavid Greenman	ALIGN_TEXT
1440967373eSDavid Greenmanidle_loop:
1450967373eSDavid Greenman	call	_spl0
1460967373eSDavid Greenman	cmpl	$0,_whichqs
1470967373eSDavid Greenman	jne	sw1
1480967373eSDavid Greenman	hlt					/* wait for interrupt */
1490967373eSDavid Greenman	jmp	idle_loop
1500967373eSDavid Greenman
1510967373eSDavid Greenmanbadsw:
1520967373eSDavid Greenman	pushl	$sw0
1530967373eSDavid Greenman	call	_panic
1540967373eSDavid Greenman	/*NOTREACHED*/
1550967373eSDavid Greenman
1560967373eSDavid Greenman/*
1570967373eSDavid Greenman * Swtch()
1580967373eSDavid Greenman */
1590967373eSDavid Greenman	SUPERALIGN_TEXT	/* so profiling doesn't lump Idle with swtch().. */
1600967373eSDavid GreenmanENTRY(swtch)
1610967373eSDavid Greenman
1620967373eSDavid Greenman	incl	_cnt+V_SWTCH
1630967373eSDavid Greenman
1640967373eSDavid Greenman	/* switch to new process. first, save context as needed */
1650967373eSDavid Greenman
1660967373eSDavid Greenman	movl	_curproc,%ecx
1670967373eSDavid Greenman
1680967373eSDavid Greenman	/* if no process to save, don't bother */
1690967373eSDavid Greenman	testl	%ecx,%ecx
1700967373eSDavid Greenman	je	sw1
1710967373eSDavid Greenman
1720967373eSDavid Greenman	movl	P_ADDR(%ecx),%ecx
1730967373eSDavid Greenman
1740967373eSDavid Greenman	movl	(%esp),%eax			/* Hardware registers */
1750967373eSDavid Greenman	movl	%eax,PCB_EIP(%ecx)
1760967373eSDavid Greenman	movl	%ebx,PCB_EBX(%ecx)
1770967373eSDavid Greenman	movl	%esp,PCB_ESP(%ecx)
1780967373eSDavid Greenman	movl	%ebp,PCB_EBP(%ecx)
1790967373eSDavid Greenman	movl	%esi,PCB_ESI(%ecx)
1800967373eSDavid Greenman	movl	%edi,PCB_EDI(%ecx)
1810967373eSDavid Greenman
1820967373eSDavid Greenman#if NNPX > 0
1830967373eSDavid Greenman	/* have we used fp, and need a save? */
1840967373eSDavid Greenman	mov	_curproc,%eax
1850967373eSDavid Greenman	cmp	%eax,_npxproc
1860967373eSDavid Greenman	jne	1f
1870967373eSDavid Greenman	pushl	%ecx				/* h/w bugs make saving complicated */
1880967373eSDavid Greenman	leal	PCB_SAVEFPU(%ecx),%eax
1890967373eSDavid Greenman	pushl	%eax
1900967373eSDavid Greenman	call	_npxsave			/* do it in a big C function */
1910967373eSDavid Greenman	popl	%eax
1920967373eSDavid Greenman	popl	%ecx
1930967373eSDavid Greenman1:
1940967373eSDavid Greenman#endif	/* NNPX > 0 */
1950967373eSDavid Greenman
1960967373eSDavid Greenman	movl	_CMAP2,%eax			/* save temporary map PTE */
1970967373eSDavid Greenman	movl	%eax,PCB_CMAP2(%ecx)		/* in our context */
1980967373eSDavid Greenman	movl	$0,_curproc			/*  out of process */
1990967373eSDavid Greenman
2000967373eSDavid Greenman#	movw	_cpl,%ax
2010967373eSDavid Greenman#	movw	%ax,PCB_IML(%ecx)		/* save ipl */
2020967373eSDavid Greenman
2030967373eSDavid Greenman	/* save is done, now choose a new process or idle */
2040967373eSDavid Greenmansw1:
2050967373eSDavid Greenman	cli
2060967373eSDavid Greenman	SHOW_CLI
2070967373eSDavid Greenman	movl	_whichqs,%edi
2080967373eSDavid Greenman2:
2090967373eSDavid Greenman	/* XXX - bsf is sloow */
2100967373eSDavid Greenman	bsfl	%edi,%eax			/* find a full q */
2110967373eSDavid Greenman	je	Idle				/* if none, idle */
2120967373eSDavid Greenman	/* XX update whichqs? */
2130967373eSDavid Greenmanswfnd:
2140967373eSDavid Greenman	btrl	%eax,%edi			/* clear q full status */
2150967373eSDavid Greenman	jnb	2b				/* if it was clear, look for another */
2160967373eSDavid Greenman	movl	%eax,%ebx			/* save which one we are using */
2170967373eSDavid Greenman
2180967373eSDavid Greenman	shll	$3,%eax
2190967373eSDavid Greenman	addl	$_qs,%eax			/* select q */
2200967373eSDavid Greenman	movl	%eax,%esi
2210967373eSDavid Greenman
2220967373eSDavid Greenman#ifdef	DIAGNOSTIC
2230967373eSDavid Greenman	cmpl	P_LINK(%eax),%eax 		/* linked to self? (e.g. not on list) */
2240967373eSDavid Greenman	je	badsw				/* not possible */
2250967373eSDavid Greenman#endif
2260967373eSDavid Greenman
2270967373eSDavid Greenman	movl	P_LINK(%eax),%ecx		/* unlink from front of process q */
2280967373eSDavid Greenman	movl	P_LINK(%ecx),%edx
2290967373eSDavid Greenman	movl	%edx,P_LINK(%eax)
2300967373eSDavid Greenman	movl	P_RLINK(%ecx),%eax
2310967373eSDavid Greenman	movl	%eax,P_RLINK(%edx)
2320967373eSDavid Greenman
2330967373eSDavid Greenman	cmpl	P_LINK(%ecx),%esi		/* q empty */
2340967373eSDavid Greenman	je	3f
2350967373eSDavid Greenman	btsl	%ebx,%edi			/* nope, set to indicate full */
2360967373eSDavid Greenman3:
2370967373eSDavid Greenman	movl	%edi,_whichqs			/* update q status */
2380967373eSDavid Greenman
2390967373eSDavid Greenman	movl	$0,%eax
2400967373eSDavid Greenman	movl	%eax,_want_resched
2410967373eSDavid Greenman
2420967373eSDavid Greenman#ifdef	DIAGNOSTIC
2430967373eSDavid Greenman	cmpl	%eax,P_WCHAN(%ecx)
2440967373eSDavid Greenman	jne	badsw
2450967373eSDavid Greenman	cmpb	$SRUN,P_STAT(%ecx)
2460967373eSDavid Greenman	jne	badsw
2470967373eSDavid Greenman#endif
2480967373eSDavid Greenman
2490967373eSDavid Greenman	movl	%eax,P_RLINK(%ecx) 		/* isolate process to run */
2500967373eSDavid Greenman	movl	P_ADDR(%ecx),%edx
2510967373eSDavid Greenman	movl	PCB_CR3(%edx),%ebx
2520967373eSDavid Greenman
2530967373eSDavid Greenman	/* switch address space */
2540967373eSDavid Greenman	movl	%ebx,%cr3
2550967373eSDavid Greenman
2560967373eSDavid Greenman	/* restore context */
2570967373eSDavid Greenman	movl	PCB_EBX(%edx),%ebx
2580967373eSDavid Greenman	movl	PCB_ESP(%edx),%esp
2590967373eSDavid Greenman	movl	PCB_EBP(%edx),%ebp
2600967373eSDavid Greenman	movl	PCB_ESI(%edx),%esi
2610967373eSDavid Greenman	movl	PCB_EDI(%edx),%edi
2620967373eSDavid Greenman	movl	PCB_EIP(%edx),%eax
2630967373eSDavid Greenman	movl	%eax,(%esp)
2640967373eSDavid Greenman
2650967373eSDavid Greenman	movl	PCB_CMAP2(%edx),%eax		/* get temporary map */
2660967373eSDavid Greenman	movl	%eax,_CMAP2			/* reload temporary map PTE */
2670967373eSDavid Greenman
2680967373eSDavid Greenman	movl	%ecx,_curproc			/* into next process */
2690967373eSDavid Greenman	movl	%edx,_curpcb
2700967373eSDavid Greenman
2710967373eSDavid Greenman	pushl	%edx				/* save p to return */
2720967373eSDavid Greenman/*
2730967373eSDavid Greenman * XXX - 0.0 forgot to save it - is that why this was commented out in 0.1?
2740967373eSDavid Greenman * I think restoring the cpl is unnecessary, but we must turn off the cli
2750967373eSDavid Greenman * now that spl*() don't do it as a side affect.
2760967373eSDavid Greenman */
2770967373eSDavid Greenman	pushl	PCB_IML(%edx)
2780967373eSDavid Greenman	sti
2790967373eSDavid Greenman	SHOW_STI
2800967373eSDavid Greenman#if 0
2810967373eSDavid Greenman	call	_splx
2820967373eSDavid Greenman#endif
2830967373eSDavid Greenman	addl	$4,%esp
2840967373eSDavid Greenman/*
2850967373eSDavid Greenman * XXX - 0.0 gets here via swtch_to_inactive().  I think 0.1 gets here in the
2860967373eSDavid Greenman * same way.  Better return a value.
2870967373eSDavid Greenman */
2880967373eSDavid Greenman	popl	%eax				/* return(p); */
2890967373eSDavid Greenman	ret
2900967373eSDavid Greenman
2910967373eSDavid GreenmanENTRY(mvesp)
2920967373eSDavid Greenman	movl	%esp,%eax
2930967373eSDavid Greenman	ret
2940967373eSDavid Greenman/*
2950967373eSDavid Greenman * struct proc *swtch_to_inactive(p) ; struct proc *p;
2960967373eSDavid Greenman *
2970967373eSDavid Greenman * At exit of a process, move off the address space of the
2980967373eSDavid Greenman * process and onto a "safe" one. Then, on a temporary stack
2990967373eSDavid Greenman * return and run code that disposes of the old state.
3000967373eSDavid Greenman * Since this code requires a parameter from the "old" stack,
3010967373eSDavid Greenman * pass it back as a return value.
3020967373eSDavid Greenman */
3030967373eSDavid GreenmanENTRY(swtch_to_inactive)
3040967373eSDavid Greenman	popl	%edx				/* old pc */
3050967373eSDavid Greenman	popl	%eax				/* arg, our return value */
3060967373eSDavid Greenman	movl	_IdlePTD,%ecx
3070967373eSDavid Greenman	movl	%ecx,%cr3			/* good bye address space */
3080967373eSDavid Greenman #write buffer?
3090967373eSDavid Greenman	movl	$tmpstk-4,%esp			/* temporary stack, compensated for call */
3100967373eSDavid Greenman	jmp	%edx				/* return, execute remainder of cleanup */
3110967373eSDavid Greenman
3120967373eSDavid Greenman/*
3130967373eSDavid Greenman * savectx(pcb, altreturn)
3140967373eSDavid Greenman * Update pcb, saving current processor state and arranging
3150967373eSDavid Greenman * for alternate return ala longjmp in swtch if altreturn is true.
3160967373eSDavid Greenman */
3170967373eSDavid GreenmanENTRY(savectx)
3180967373eSDavid Greenman	movl	4(%esp),%ecx
3190967373eSDavid Greenman	movw	_cpl,%ax
3200967373eSDavid Greenman	movw	%ax,PCB_IML(%ecx)
3210967373eSDavid Greenman	movl	(%esp),%eax
3220967373eSDavid Greenman	movl	%eax,PCB_EIP(%ecx)
3230967373eSDavid Greenman	movl	%ebx,PCB_EBX(%ecx)
3240967373eSDavid Greenman	movl	%esp,PCB_ESP(%ecx)
3250967373eSDavid Greenman	movl	%ebp,PCB_EBP(%ecx)
3260967373eSDavid Greenman	movl	%esi,PCB_ESI(%ecx)
3270967373eSDavid Greenman	movl	%edi,PCB_EDI(%ecx)
3280967373eSDavid Greenman
3290967373eSDavid Greenman#if NNPX > 0
3300967373eSDavid Greenman	/*
3310967373eSDavid Greenman	 * If npxproc == NULL, then the npx h/w state is irrelevant and the
3320967373eSDavid Greenman	 * state had better already be in the pcb.  This is true for forks
3330967373eSDavid Greenman	 * but not for dumps (the old book-keeping with FP flags in the pcb
3340967373eSDavid Greenman	 * always lost for dumps because the dump pcb has 0 flags).
3350967373eSDavid Greenman	 *
3360967373eSDavid Greenman	 * If npxproc != NULL, then we have to save the npx h/w state to
3370967373eSDavid Greenman	 * npxproc's pcb and copy it to the requested pcb, or save to the
3380967373eSDavid Greenman	 * requested pcb and reload.  Copying is easier because we would
3390967373eSDavid Greenman	 * have to handle h/w bugs for reloading.  We used to lose the
3400967373eSDavid Greenman	 * parent's npx state for forks by forgetting to reload.
3410967373eSDavid Greenman	 */
3420967373eSDavid Greenman	mov	_npxproc,%eax
3430967373eSDavid Greenman	testl	%eax,%eax
3440967373eSDavid Greenman	je	1f
3450967373eSDavid Greenman
3460967373eSDavid Greenman	pushl	%ecx
3470967373eSDavid Greenman	movl	P_ADDR(%eax),%eax
3480967373eSDavid Greenman	leal	PCB_SAVEFPU(%eax),%eax
3490967373eSDavid Greenman	pushl	%eax
3500967373eSDavid Greenman	pushl	%eax
3510967373eSDavid Greenman	call	_npxsave
3520967373eSDavid Greenman	popl	%eax
3530967373eSDavid Greenman	popl	%eax
3540967373eSDavid Greenman	popl	%ecx
3550967373eSDavid Greenman
3560967373eSDavid Greenman	pushl	%ecx
3570967373eSDavid Greenman	pushl	$108+8*2			/* XXX h/w state size + padding */
3580967373eSDavid Greenman	leal	PCB_SAVEFPU(%ecx),%ecx
3590967373eSDavid Greenman	pushl	%ecx
3600967373eSDavid Greenman	pushl	%eax
3610967373eSDavid Greenman	call	_bcopy
3620967373eSDavid Greenman	addl	$12,%esp
3630967373eSDavid Greenman	popl	%ecx
3640967373eSDavid Greenman1:
3650967373eSDavid Greenman#endif	/* NNPX > 0 */
3660967373eSDavid Greenman
3670967373eSDavid Greenman	movl	_CMAP2,%edx			/* save temporary map PTE */
3680967373eSDavid Greenman	movl	%edx,PCB_CMAP2(%ecx)		/* in our context */
3690967373eSDavid Greenman
3700967373eSDavid Greenman	cmpl	$0,8(%esp)
3710967373eSDavid Greenman	je	1f
3720967373eSDavid Greenman	movl	%esp,%edx			/* relocate current sp relative to pcb */
3730967373eSDavid Greenman	subl	$_kstack,%edx			/*   (sp is relative to kstack): */
3740967373eSDavid Greenman	addl	%edx,%ecx			/*   pcb += sp - kstack; */
3750967373eSDavid Greenman	movl	%eax,(%ecx)			/* write return pc at (relocated) sp@ */
3760967373eSDavid Greenman
3770967373eSDavid Greenman/* this mess deals with replicating register state gcc hides */
3780967373eSDavid Greenman	movl	12(%esp),%eax
3790967373eSDavid Greenman	movl	%eax,12(%ecx)
3800967373eSDavid Greenman	movl	16(%esp),%eax
3810967373eSDavid Greenman	movl	%eax,16(%ecx)
3820967373eSDavid Greenman	movl	20(%esp),%eax
3830967373eSDavid Greenman	movl	%eax,20(%ecx)
3840967373eSDavid Greenman	movl	24(%esp),%eax
3850967373eSDavid Greenman	movl	%eax,24(%ecx)
3860967373eSDavid Greenman1:
3870967373eSDavid Greenman	xorl	%eax,%eax			/* return 0 */
3880967373eSDavid Greenman	ret
3890967373eSDavid Greenman
3900967373eSDavid Greenman/*
3910967373eSDavid Greenman * addupc(int pc, struct uprof *up, int ticks):
3920967373eSDavid Greenman * update profiling information for the user process.
3930967373eSDavid Greenman */
3940967373eSDavid GreenmanENTRY(addupc)
3950967373eSDavid Greenman	pushl %ebp
3960967373eSDavid Greenman	movl %esp,%ebp
3970967373eSDavid Greenman	movl 12(%ebp),%edx			/* up */
3980967373eSDavid Greenman	movl 8(%ebp),%eax			/* pc */
3990967373eSDavid Greenman
4000967373eSDavid Greenman	subl PR_OFF(%edx),%eax			/* pc -= up->pr_off */
4010967373eSDavid Greenman	jl L1					/* if (pc < 0) return */
4020967373eSDavid Greenman
4030967373eSDavid Greenman	shrl $1,%eax				/* praddr = pc >> 1 */
4040967373eSDavid Greenman	imull PR_SCALE(%edx),%eax		/* praddr *= up->pr_scale */
4050967373eSDavid Greenman	shrl $15,%eax				/* praddr = praddr << 15 */
4060967373eSDavid Greenman	andl $-2,%eax				/* praddr &= ~1 */
4070967373eSDavid Greenman
4080967373eSDavid Greenman	cmpl PR_SIZE(%edx),%eax			/* if (praddr > up->pr_size) return */
4090967373eSDavid Greenman	ja L1
4100967373eSDavid Greenman
4110967373eSDavid Greenman/*	addl %eax,%eax				/* praddr -> word offset */
4120967373eSDavid Greenman	addl PR_BASE(%edx),%eax			/* praddr += up-> pr_base */
4130967373eSDavid Greenman	movl 16(%ebp),%ecx			/* ticks */
4140967373eSDavid Greenman
4150967373eSDavid Greenman	movl _curpcb,%edx
4160967373eSDavid Greenman	movl $proffault,PCB_ONFAULT(%edx)
4170967373eSDavid Greenman	addl %ecx,(%eax)			/* storage location += ticks */
4180967373eSDavid Greenman	movl $0,PCB_ONFAULT(%edx)
4190967373eSDavid GreenmanL1:
4200967373eSDavid Greenman	leave
4210967373eSDavid Greenman	ret
4220967373eSDavid Greenman
4230967373eSDavid Greenman	ALIGN_TEXT
4240967373eSDavid Greenmanproffault:
4250967373eSDavid Greenman	/* if we get a fault, then kill profiling all together */
4260967373eSDavid Greenman	movl $0,PCB_ONFAULT(%edx)		/* squish the fault handler */
4270967373eSDavid Greenman	movl 12(%ebp),%ecx
4280967373eSDavid Greenman	movl $0,PR_SCALE(%ecx)			/* up->pr_scale = 0 */
4290967373eSDavid Greenman	leave
4300967373eSDavid Greenman	ret
4310967373eSDavid Greenman
4320967373eSDavid Greenman/* To be done: */
4330967373eSDavid GreenmanENTRY(astoff)
4340967373eSDavid Greenman	ret
4350967373eSDavid Greenman
436