Source to machdep/i386/locore.s


Enter a symbol's name here to quickly find it.

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.0 (the 'License').  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License."
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

/*
 * Copyright (c) 1992 NeXT Computer, Inc.
 *
 * Locore module for NEXTSTEP/Intel Kernel.
 *
 * HISTORY
 *
 * 17 July 1994 ? at NeXT
 *	Major mods for user state save optimizations.
 * 29 August 1992 ? at NeXT
 *	Created.
 */

#import <architecture/i386/asm_help.h>

#import <assym.h>

	TEXT

#define EXCEPTION(name, number)						\
LEAF(_##name, 0)			;				\
		pushl	$0x00		;				\
		pushl	$##number	;				\
		jmp	trap_handler

#define EXCEPTERR(name, number)						\
LEAF(_##name, 0)			;				\
		pushl	$##number	;				\
		jmp	trap_handler

#define INTERRUPT(name, number)						\
LEAF(_##name, 0)			;				\
		pushl	$0x00		;				\
		pushl	$##number	;				\
		jmp	interrupt

#define		RETURN			 				\
		popl	%gs		;				\
		popl	%fs		;				\
		popl	%es		;				\
		popl	%ds		;				\
		popa			;				\
		addl	$8, %esp	;				\
		iret

EXCEPTION(trp_divr,0x00)
EXCEPTION(trp_debg,0x01)
EXCEPTION(int__nmi,0x02)
EXCEPTION(trp_brpt,0x03)
EXCEPTION(trp_over,0x04)
EXCEPTION(flt_bnds,0x05)
EXCEPTION(flt_opcd,0x06)
EXCEPTION(flt_ncpr,0x07)
EXCEPTERR(abt_dblf,0x08)
EXCEPTION(abt_over,0x09)
EXCEPTERR(flt_btss,0x0A)
EXCEPTERR(flt_bseg,0x0B)
EXCEPTERR(flt_bstk,0x0C)
EXCEPTERR(flt_prot,0x0D)
EXCEPTERR(flt_page,0x0E)
EXCEPTION(trp_0x0F,0x0F)
EXCEPTION(flt_bcpr,0x10)
EXCEPTION(trp_0x11,0x11)
EXCEPTION(trp_0x12,0x12)
EXCEPTION(trp_0x13,0x13)
EXCEPTION(trp_0x14,0x14)
EXCEPTION(trp_0x15,0x15)
EXCEPTION(trp_0x16,0x16)
EXCEPTION(trp_0x17,0x17)
EXCEPTION(trp_0x18,0x18)
EXCEPTION(trp_0x19,0x19)
EXCEPTION(trp_0x1A,0x1A)
EXCEPTION(trp_0x1B,0x1B)
EXCEPTION(trp_0x1C,0x1C)
EXCEPTION(trp_0x1D,0x1D)
EXCEPTION(trp_0x1E,0x1E)
EXCEPTION(trp_0x1F,0x1F)
EXCEPTION(trp_0x20,0x20)
EXCEPTION(trp_0x21,0x21)
EXCEPTION(trp_0x22,0x22)
EXCEPTION(trp_0x23,0x23)
EXCEPTION(trp_0x24,0x24)
EXCEPTION(trp_0x25,0x25)
EXCEPTION(trp_0x26,0x26)
EXCEPTION(trp_0x27,0x27)
EXCEPTION(trp_0x28,0x28)
EXCEPTION(trp_0x29,0x29)
EXCEPTION(trp_0x2A,0x2A)
EXCEPTION(trp_0x2B,0x2B)
EXCEPTION(trp_0x2C,0x2C)
EXCEPTION(trp_0x2D,0x2D)
EXCEPTION(trp_0x2E,0x2E)
EXCEPTION(trp_0x2F,0x2F)
EXCEPTION(trp_0x30,0x30)
EXCEPTION(trp_0x31,0x31)
EXCEPTION(trp_0x32,0x32)
EXCEPTION(trp_0x33,0x33)
EXCEPTION(trp_0x34,0x34)
EXCEPTION(trp_0x35,0x35)
EXCEPTION(trp_0x36,0x36)
EXCEPTION(trp_0x37,0x37)
EXCEPTION(trp_0x38,0x38)
EXCEPTION(trp_0x39,0x39)
EXCEPTION(trp_0x3A,0x3A)
EXCEPTION(trp_0x3B,0x3B)
EXCEPTION(trp_0x3C,0x3C)
EXCEPTION(trp_0x3D,0x3D)
EXCEPTION(trp_0x3E,0x3E)
EXCEPTION(trp_0x3F,0x3F)
//
INTERRUPT(int_0x40,0x40)
INTERRUPT(int_0x41,0x41)
INTERRUPT(int_0x42,0x42)
INTERRUPT(int_0x43,0x43)
INTERRUPT(int_0x44,0x44)
INTERRUPT(int_0x45,0x45)
INTERRUPT(int_0x46,0x46)
INTERRUPT(int_0x47,0x47)
INTERRUPT(int_0x48,0x48)
INTERRUPT(int_0x49,0x49)
INTERRUPT(int_0x4A,0x4A)
INTERRUPT(int_0x4B,0x4B)
INTERRUPT(int_0x4C,0x4C)
INTERRUPT(int_0x4D,0x4D)
INTERRUPT(int_0x4E,0x4E)
INTERRUPT(int_0x4F,0x4F)
INTERRUPT(int_0x50,0x50)
INTERRUPT(int_0x51,0x51)
INTERRUPT(int_0x52,0x52)
INTERRUPT(int_0x53,0x53)
INTERRUPT(int_0x54,0x54)
INTERRUPT(int_0x55,0x55)
INTERRUPT(int_0x56,0x56)
INTERRUPT(int_0x57,0x57)
INTERRUPT(int_0x58,0x58)
INTERRUPT(int_0x59,0x59)
INTERRUPT(int_0x5A,0x5A)
INTERRUPT(int_0x5B,0x5B)
INTERRUPT(int_0x5C,0x5C)
INTERRUPT(int_0x5D,0x5D)
INTERRUPT(int_0x5E,0x5E)
INTERRUPT(int_0x5F,0x5F)
INTERRUPT(int_0x60,0x60)
INTERRUPT(int_0x61,0x61)
INTERRUPT(int_0x62,0x62)
INTERRUPT(int_0x63,0x63)
INTERRUPT(int_0x64,0x64)
INTERRUPT(int_0x65,0x65)
INTERRUPT(int_0x66,0x66)
INTERRUPT(int_0x67,0x67)
INTERRUPT(int_0x68,0x68)
INTERRUPT(int_0x69,0x69)
INTERRUPT(int_0x6A,0x6A)
INTERRUPT(int_0x6B,0x6B)
INTERRUPT(int_0x6C,0x6C)
INTERRUPT(int_0x6D,0x6D)
INTERRUPT(int_0x6E,0x6E)
INTERRUPT(int_0x6F,0x6F)
INTERRUPT(int_0x70,0x70)
INTERRUPT(int_0x71,0x71)
INTERRUPT(int_0x72,0x72)
INTERRUPT(int_0x73,0x73)
INTERRUPT(int_0x74,0x74)
INTERRUPT(int_0x75,0x75)
INTERRUPT(int_0x76,0x76)
INTERRUPT(int_0x77,0x77)
INTERRUPT(int_0x78,0x78)
INTERRUPT(int_0x79,0x79)
INTERRUPT(int_0x7A,0x7A)
INTERRUPT(int_0x7B,0x7B)
INTERRUPT(int_0x7C,0x7C)
INTERRUPT(int_0x7D,0x7D)
INTERRUPT(int_0x7E,0x7E)
INTERRUPT(int_0x7F,0x7F)
INTERRUPT(int_0x80,0x80)
INTERRUPT(int_0x81,0x81)
INTERRUPT(int_0x82,0x82)
INTERRUPT(int_0x83,0x83)
INTERRUPT(int_0x84,0x84)
INTERRUPT(int_0x85,0x85)
INTERRUPT(int_0x86,0x86)
INTERRUPT(int_0x87,0x87)
INTERRUPT(int_0x88,0x88)
INTERRUPT(int_0x89,0x89)
INTERRUPT(int_0x8A,0x8A)
INTERRUPT(int_0x8B,0x8B)
INTERRUPT(int_0x8C,0x8C)
INTERRUPT(int_0x8D,0x8D)
INTERRUPT(int_0x8E,0x8E)
INTERRUPT(int_0x8F,0x8F)
INTERRUPT(int_0x90,0x90)
INTERRUPT(int_0x91,0x91)
INTERRUPT(int_0x92,0x92)
INTERRUPT(int_0x93,0x93)
INTERRUPT(int_0x94,0x94)
INTERRUPT(int_0x95,0x95)
INTERRUPT(int_0x96,0x96)
INTERRUPT(int_0x97,0x97)
INTERRUPT(int_0x98,0x98)
INTERRUPT(int_0x99,0x99)
INTERRUPT(int_0x9A,0x9A)
INTERRUPT(int_0x9B,0x9B)
INTERRUPT(int_0x9C,0x9C)
INTERRUPT(int_0x9D,0x9D)
INTERRUPT(int_0x9E,0x9E)
INTERRUPT(int_0x9F,0x9F)
INTERRUPT(int_0xA0,0xA0)
INTERRUPT(int_0xA1,0xA1)
INTERRUPT(int_0xA2,0xA2)
INTERRUPT(int_0xA3,0xA3)
INTERRUPT(int_0xA4,0xA4)
INTERRUPT(int_0xA5,0xA5)
INTERRUPT(int_0xA6,0xA6)
INTERRUPT(int_0xA7,0xA7)
INTERRUPT(int_0xA8,0xA8)
INTERRUPT(int_0xA9,0xA9)
INTERRUPT(int_0xAA,0xAA)
INTERRUPT(int_0xAB,0xAB)
INTERRUPT(int_0xAC,0xAC)
INTERRUPT(int_0xAD,0xAD)
INTERRUPT(int_0xAE,0xAE)
INTERRUPT(int_0xAF,0xAF)
INTERRUPT(int_0xB0,0xB0)
INTERRUPT(int_0xB1,0xB1)
INTERRUPT(int_0xB2,0xB2)
INTERRUPT(int_0xB3,0xB3)
INTERRUPT(int_0xB4,0xB4)
INTERRUPT(int_0xB5,0xB5)
INTERRUPT(int_0xB6,0xB6)
INTERRUPT(int_0xB7,0xB7)
INTERRUPT(int_0xB8,0xB8)
INTERRUPT(int_0xB9,0xB9)
INTERRUPT(int_0xBA,0xBA)
INTERRUPT(int_0xBB,0xBB)
INTERRUPT(int_0xBC,0xBC)
INTERRUPT(int_0xBD,0xBD)
INTERRUPT(int_0xBE,0xBE)
INTERRUPT(int_0xBF,0xBF)
INTERRUPT(int_0xC0,0xC0)
INTERRUPT(int_0xC1,0xC1)
INTERRUPT(int_0xC2,0xC2)
INTERRUPT(int_0xC3,0xC3)
INTERRUPT(int_0xC4,0xC4)
INTERRUPT(int_0xC5,0xC5)
INTERRUPT(int_0xC6,0xC6)
INTERRUPT(int_0xC7,0xC7)
INTERRUPT(int_0xC8,0xC8)
INTERRUPT(int_0xC9,0xC9)
INTERRUPT(int_0xCA,0xCA)
INTERRUPT(int_0xCB,0xCB)
INTERRUPT(int_0xCC,0xCC)
INTERRUPT(int_0xCD,0xCD)
INTERRUPT(int_0xCE,0xCE)
INTERRUPT(int_0xCF,0xCF)
INTERRUPT(int_0xD0,0xD0)
INTERRUPT(int_0xD1,0xD1)
INTERRUPT(int_0xD2,0xD2)
INTERRUPT(int_0xD3,0xD3)
INTERRUPT(int_0xD4,0xD4)
INTERRUPT(int_0xD5,0xD5)
INTERRUPT(int_0xD6,0xD6)
INTERRUPT(int_0xD7,0xD7)
INTERRUPT(int_0xD8,0xD8)
INTERRUPT(int_0xD9,0xD9)
INTERRUPT(int_0xDA,0xDA)
INTERRUPT(int_0xDB,0xDB)
INTERRUPT(int_0xDC,0xDC)
INTERRUPT(int_0xDD,0xDD)
INTERRUPT(int_0xDE,0xDE)
INTERRUPT(int_0xDF,0xDF)
INTERRUPT(int_0xE0,0xE0)
INTERRUPT(int_0xE1,0xE1)
INTERRUPT(int_0xE2,0xE2)
INTERRUPT(int_0xE3,0xE3)
INTERRUPT(int_0xE4,0xE4)
INTERRUPT(int_0xE5,0xE5)
INTERRUPT(int_0xE6,0xE6)
INTERRUPT(int_0xE7,0xE7)
INTERRUPT(int_0xE8,0xE8)
INTERRUPT(int_0xE9,0xE9)
INTERRUPT(int_0xEA,0xEA)
INTERRUPT(int_0xEB,0xEB)
INTERRUPT(int_0xEC,0xEC)
INTERRUPT(int_0xED,0xED)
INTERRUPT(int_0xEE,0xEE)
INTERRUPT(int_0xEF,0xEF)
INTERRUPT(int_0xF0,0xF0)
INTERRUPT(int_0xF1,0xF1)
INTERRUPT(int_0xF2,0xF2)
INTERRUPT(int_0xF3,0xF3)
INTERRUPT(int_0xF4,0xF4)
INTERRUPT(int_0xF5,0xF5)
INTERRUPT(int_0xF6,0xF6)
INTERRUPT(int_0xF7,0xF7)
INTERRUPT(int_0xF8,0xF8)
INTERRUPT(int_0xF9,0xF9)
INTERRUPT(int_0xFA,0xFA)
INTERRUPT(int_0xFB,0xFB)
INTERRUPT(int_0xFC,0xFC)
INTERRUPT(int_0xFD,0xFD)
INTERRUPT(int_0xFE,0xFE)
INTERRUPT(int_0xFF,0xFF)

	ALIGN
trap_handler:
	// save general registers
	pusha

	// save segment registers
	pushl	%ds
	pushl	%es
	pushl	%fs
	pushl	%gs

	// reinitialize segment registers
	movw	$ KDSSEL,%ax
	movw	%ax,%ds
	movw	%ax,%es
	movw	$ LDATASEL,%ax
	movw	%ax,%fs
	movw	$ NULLSEL,%ax
	movw	%ax,%gs

	// clear direction flag
	cld

	// set frame pointer
	lea	EBP(%esp),%ebp

	// is our stack the save area?
	movl	_empty_stacks,%esi
	movl	%esp,%ebx
	andl	%esi,%esi
	je	0f
	// yes, switch to kernel stack
	// need to do this atomically
	cli
	movl	_stack_pointers,%esp
	movl	$0,_empty_stacks
	sti
0:
	// ptr to saved state
	pushl	%ebx

	call	_catch_trap
	// user mode trap never returns
	// kernel mode trap always returns

	// restore old stack pointer
	// and old value of _empty_stacks
	// need to do this atomically
	cli
	movl	%ebx,%esp
	movl	%esi,_empty_stacks
	sti

	RETURN

	ALIGN
interrupt:
	// save general registers
	pusha

	// save segment registers
	pushl	%ds
	pushl	%es
	pushl	%fs
	pushl	%gs

	// reinitialize segment registers
	movw	$ KDSSEL,%ax
	movw	%ax,%ds
	movw	%ax,%es
	movw	$ LDATASEL,%ax
	movw	%ax,%fs
	movw	$ NULLSEL,%ax
	movw	%ax,%gs

	// clear direction flag
	cld

	// set frame pointer
	lea	EBP(%esp),%ebp

	// is our stack the save area?
	movl	_empty_stacks,%esi
	movl	%esp,%ebx
	andl	%esi,%esi
	je	0f
	// yes, switch to kernel stack
	// interrupts are already disabled
	movl	_stack_pointers,%esp
	movl	$0,_empty_stacks
0:
	// ptr to saved state
	pushl	%ebx

	call	_catch_interrupt
	// user mode interrupt may not return
	// kernel mode interrupt always returns

	// restore old stack pointer	
	movl	%ebx,%esp
	
	// restore old value of _empty_stacks
	movl	%esi,_empty_stacks

	RETURN
	
LEAF(_machdep_call_, 0)
	// save eflags
	pushf
	
	// dummy trapno
	pushl	$0
	
	// save general registers
	pusha
	
	// save segment registers
	pushl	%ds
	pushl	%es
	pushl	%fs
	pushl	%gs

	// copy eflags to correct offset
	movl	ERR(%esp),%eax
	movl	%eax,EFL(%esp)

	// reinitialize segment registers
	movw	$ KDSSEL,%ax
	movw	%ax,%ds
	movw	%ax,%es
	movw	$ LDATASEL,%ax
	movw	%ax,%fs
	movw	$ NULLSEL,%ax
	movw	%ax,%gs
	
	// clear direction flag
	cld

	// set frame pointer
	lea	EBP(%esp),%ebp

	// is our stack the save area?
	movl	_empty_stacks,%esi
	movl	%esp,%ebx
	andl	%esi,%esi
	je	0f
	// yes, switch to kernel stack
	// need to do this atomically
	cli
	movl	_stack_pointers,%esp
	movl	$0,_empty_stacks
	sti
0:
	// ptr to saved state
	pushl	%ebx

	call	_machdep_call
	// call from user mode never returns
	// call from kernel mode always returns (error)

	movl	%ebx,%esp
	
	RETURN
	
LEAF(_mach_kernel_trap_, 0)
	// save eflags
	pushf
	
	// dummy trapno
	pushl	$0
	
	// save general registers
	pusha
	
	// save segment registers
	pushl	%ds
	pushl	%es
	pushl	%fs
	pushl	%gs

	// copy eflags to correct offset
	movl	ERR(%esp),%eax
	movl	%eax,EFL(%esp)

	// reinitialize segment registers
	movw	$ KDSSEL,%ax
	movw	%ax,%ds
	movw	%ax,%es
	movw	$ LDATASEL,%ax
	movw	%ax,%fs
	movw	$ NULLSEL,%ax
	movw	%ax,%gs
	
	// clear direction flag
	cld

	// set frame pointer
	lea	EBP(%esp),%ebp

	// is our stack the save area?
	movl	_empty_stacks,%esi
	movl	%esp,%ebx
	andl	%esi,%esi
	je	0f
	// yes, switch to kernel stack
	// need to do this atomically
	cli
	movl	_stack_pointers,%esp
	movl	$0,_empty_stacks
	sti
0:
	// ptr to saved state
	pushl	%ebx

	call	_mach_kernel_trap
	// call from user mode never returns
	// call from kernel mode always returns (error)

	movl	%ebx,%esp
	
	RETURN
	
LEAF(_unix_syscall_, 0)
	// save eflags
	pushf
	
	// dummy trapno
	pushl	$0
	
	// save general registers
	pusha
	
	// save segment registers
	pushl	%ds
	pushl	%es
	pushl	%fs
	pushl	%gs

	// copy eflags to correct offset
	movl	ERR(%esp),%eax
	movl	%eax,EFL(%esp)

	// reinitialize segment registers
	movw	$ KDSSEL,%ax
	movw	%ax,%ds
	movw	%ax,%es
	movw	$ LDATASEL,%ax
	movw	%ax,%fs
	movw	$ NULLSEL,%ax
	movw	%ax,%gs
	
	// clear direction flag
	cld

	// set frame pointer
	lea	EBP(%esp),%ebp

	// is our stack the save area?
	movl	_empty_stacks,%esi
	movl	%esp,%ebx
	andl	%esi,%esi
	je	0f
	// yes, switch to kernel stack
	// need to do this atomically
	cli
	movl	_stack_pointers,%esp
	movl	$0,_empty_stacks
	sti
0:
	// ptr to saved state
	pushl	%ebx

	call	_unix_syscall
	// call from user mode never returns
	// call from kernel mode always returns (error)

	movl	%ebx,%esp
	
	RETURN
	
LEAF(_dbf_handler_, 0)
0:	call	_dbf_handler
	jmp	0b

	/*
	 * Return directly to
	 * a *user* context
	 * using a specific return
	 * frame.  Typically, the
	 * frame is in the thread
	 * save area, but it can
	 * also be somewhere on the
	 * kernel stack.  N.B. If the
	 * resumed context is executing
	 * in kernel mode, the system
	 * will crash and burn.
	 */
LEAF(__return_with_state, 0)
	// discard return address
	popl	%eax
	
	// retrieve state ptr
	popl	%ebx

	// switch stack back to save area
	// need to do this atomically
	cli
	movl	%ebx,%esp
	movl	$1,_empty_stacks
	sti
	
	RETURN

	/*
	 * Perform a coroutine
	 * switch between threads.
	 */
LEAF(__switch_tss, 0)
	movl	4(%esp),%eax
	andl	%eax,%eax
	je	0f
	movl	%edi,0x44(%eax)
	movl	%esi,0x40(%eax)
	movl	%ebx,0x34(%eax)
	movl	%ebp,0x3c(%eax)
	popl	%edx
	movl	%edx,0x20(%eax)
	movl	%esp,0x38(%eax)

	movl	4(%esp),%edx
	movl	0x44(%edx),%edi
	movl	0x40(%edx),%esi
	movl	0x34(%edx),%ebx
	movl	0x3c(%edx),%ebp
	movl	8(%esp),%eax
	movl	0x38(%edx),%esp
	movl	0x20(%edx),%edx
	jmp	*%edx

0:
	popl	%edx
	
	movl	4(%esp),%edx
	movl	0x44(%edx),%edi
	movl	0x40(%edx),%esi
	movl	0x34(%edx),%ebx
	movl	0x3c(%edx),%ebp
	movl	8(%esp),%eax
	movl	0x38(%edx),%esp
	movl	0x20(%edx),%edx
	jmp	*%edx
	
LEAF(__stack_attach, 0)
	pushl	%eax
	call	*%ebx
0:	hlt
	jmp	0b
	
LEAF(__call_with_stack, 0)
	movl	4(%esp),%eax
	movl	8(%esp),%esp
	movl	%esp,%ebp
	call	*%eax	
0:	hlt
	jmp	0b

#ifdef	GPROF
LEAF(mcount, 0)
	movl	0(%esp),%eax		// fetch self address
	pushl	%eax
	movl	4(%ebp),%eax		// fetch parent address
	pushl	%eax
	pushf
	popl	%eax
	andl	$0x200,%eax
	je	0f
	cli
	call	_mcount
	sti
	addl	$8,%esp
	ret
	
0:	call	_mcount
	addl	$8,%esp
	ret
#endif	GPROF

#define	O_EDI	0
#define	O_ESI	4
#define	O_EBX	8
#define	O_EBP	12
#define	O_ESP	16
#define O_EIP	20
#define	O_IPL	24

LEAF(_setjmp, 0)
X_LEAF(_set_label, _setjmp)
	call	_curipl
	movl	4(%esp),%edx		// address of save area
	movl	%eax,O_IPL(%edx)	// save ipl level for longjmp
	movl	%edi,O_EDI(%edx)
	movl	%esi,O_ESI(%edx)
	movl	%ebx,O_EBX(%edx)
	movl	%ebp,O_EBP(%edx)
	movl	%esp,O_ESP(%edx)
	movl	0(%esp),%eax		// %eip (return address)
	movl	%eax,O_EIP(%edx)
	xorl	%eax,%eax		// retval <- 0
	ret

LEAF(_longjmp, 0)
X_LEAF(_jump_label, _longjmp)
	movl	4(%esp),%edx		// address of save area
	movl	O_EDI(%edx),%edi
	movl	O_ESI(%edx),%esi
	movl	O_EBX(%edx),%ebx
	movl	O_EBP(%edx),%ebp
	movl	O_ESP(%edx),%esp
	movl	O_EIP(%edx),%eax	// %eip (return address)
	movl	%eax,0(%esp)
	pushl	O_IPL(%edx)
	call	_splx			// restore ipl level
	addl	$4,%esp
	movl	$1,%eax
	ret