diff options
Diffstat (limited to 'usr/src/uts/i86pc/ml/syscall_asm.s')
-rw-r--r-- | usr/src/uts/i86pc/ml/syscall_asm.s | 744 |
1 files changed, 0 insertions, 744 deletions
diff --git a/usr/src/uts/i86pc/ml/syscall_asm.s b/usr/src/uts/i86pc/ml/syscall_asm.s deleted file mode 100644 index 5bb6bdea31..0000000000 --- a/usr/src/uts/i86pc/ml/syscall_asm.s +++ /dev/null @@ -1,744 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016 by Delphix. All rights reserved. - */ - -/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ -/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ -/* All Rights Reserved */ - -/* Copyright (c) 1987, 1988 Microsoft Corporation */ -/* All Rights Reserved */ - -#include <sys/asm_linkage.h> -#include <sys/asm_misc.h> -#include <sys/regset.h> -#include <sys/psw.h> -#include <sys/x86_archext.h> -#include <sys/machbrand.h> -#include <sys/privregs.h> - -#if defined(__lint) - -#include <sys/types.h> -#include <sys/thread.h> -#include <sys/systm.h> - -#else /* __lint */ - -#include <sys/segments.h> -#include <sys/pcb.h> -#include <sys/trap.h> -#include <sys/ftrace.h> -#include <sys/traptrace.h> -#include <sys/clock.h> -#include <sys/panic.h> -#include "assym.h" - -#endif /* __lint */ - -/* - * We implement two flavours of system call entry points - * - * - {int,lcall}/iret (i386) - * - sysenter/sysexit (Pentium II and beyond) - * - * The basic pattern used in the handlers is to check to see if we can - * do fast (simple) version of the system call; if we can't we use various - * C routines that handle corner cases and debugging. - * - * To reduce the amount of assembler replication, yet keep the system call - * implementations vaguely comprehensible, the common code in the body - * of the handlers is broken up into a set of preprocessor definitions - * below. - */ - -/* - * When we have SYSCALLTRACE defined, we sneak an extra - * predicate into a couple of tests. - */ -#if defined(SYSCALLTRACE) -#define ORL_SYSCALLTRACE(r32) \ - orl syscalltrace, r32 -#else -#define ORL_SYSCALLTRACE(r32) -#endif - -/* - * This check is false whenever we want to go fast i.e. - * - * if (code >= NSYSCALL || - * t->t_pre_sys || (t->t_proc_flag & TP_WATCHPT) != 0) - * do full version - * #ifdef SYSCALLTRACE - * if (syscalltrace) - * do full version - * #endif - * - * Preconditions: - * - t curthread - * - code contains the syscall number - * Postconditions: - * - %ecx and %edi are smashed - * - condition code flag ZF is cleared if pre-sys is too complex - */ -#define CHECK_PRESYS_NE(t, code) \ - movzbl T_PRE_SYS(t), %edi; \ - movzwl T_PROC_FLAG(t), %ecx; \ - andl $TP_WATCHPT, %ecx; \ - orl %ecx, %edi; \ - cmpl $NSYSCALL, code; \ - setae %cl; \ - movzbl %cl, %ecx; \ - orl %ecx, %edi; \ - ORL_SYSCALLTRACE(%edi) - -/* - * Check if a brand_mach_ops callback is defined for the specified callback_id - * type. If so invoke it with the user's %gs value loaded and the following - * data on the stack: - * -------------------------------------- - * | user's %ss | - * | | user's %esp | - * | | EFLAGS register | - * | | user's %cs | - * | | user's %eip (user return address) | - * | | 'scratch space' | - * | | user's %ebx | - * | | user's %gs selector | - * v | lwp pointer | - * | callback wrapper return addr | - * -------------------------------------- - * - * If the brand code returns, we assume that we are meant to execute the - * normal system call path. - * - * The interface to the brand callbacks on the 32-bit kernel assumes %ebx - * is available as a scratch register within the callback. If the callback - * returns within the kernel then this macro will restore %ebx. If the - * callback is going to return directly to userland then it should restore - * %ebx before returning to userland. - */ -#define BRAND_CALLBACK(callback_id) \ - subl $4, %esp /* save some scratch space */ ;\ - pushl %ebx /* save %ebx to use for scratch */ ;\ - pushl %gs /* save the user %gs */ ;\ - movl $KGS_SEL, %ebx ;\ - movw %bx, %gs /* switch to the kernel's %gs */ ;\ - movl %gs:CPU_THREAD, %ebx /* load the thread pointer */ ;\ - movl T_LWP(%ebx), %ebx /* load the lwp pointer */ ;\ - pushl %ebx /* push the lwp pointer */ ;\ - movl LWP_PROCP(%ebx), %ebx /* load the proc pointer */ ;\ - movl P_BRAND(%ebx), %ebx /* load the brand pointer */ ;\ - movl B_MACHOPS(%ebx), %ebx /* load the machops pointer */ ;\ - movl _CONST(_MUL(callback_id, CPTRSIZE))(%ebx), %ebx ;\ - cmpl $0, %ebx ;\ - je 1f ;\ - movl %ebx, 12(%esp) /* save callback to scratch */ ;\ - movl 4(%esp), %ebx /* grab the user %gs */ ;\ - movw %bx, %gs /* restore the user %gs */ ;\ - call *12(%esp) /* call callback in scratch */ ;\ -1: movl 4(%esp), %ebx /* restore user %gs (re-do if */ ;\ - movw %bx, %gs /* branch due to no callback) */ ;\ - movl 8(%esp), %ebx /* restore user's %ebx */ ;\ - addl $16, %esp /* restore stack ptr */ - -#define MSTATE_TRANSITION(from, to) \ - pushl $to; \ - pushl $from; \ - call syscall_mstate; \ - addl $0x8, %esp - -/* - * aka CPU_STATS_ADDQ(CPU, sys.syscall, 1) - * This must be called with interrupts or preemption disabled. - */ -#define CPU_STATS_SYS_SYSCALL_INC \ - addl $1, %gs:CPU_STATS_SYS_SYSCALL; \ - adcl $0, %gs:CPU_STATS_SYS_SYSCALL+4; - -#if !defined(__lint) - -/* - * ASSERT(lwptoregs(lwp) == rp); - * - * this may seem obvious, but very odd things happen if this - * assertion is false - * - * Preconditions: - * -none- - * Postconditions (if assertion is true): - * %esi and %edi are smashed - */ -#if defined(DEBUG) - -__lwptoregs_msg: - .string "syscall_asm.s:%d lwptoregs(%p) [%p] != rp [%p]" - -#define ASSERT_LWPTOREGS(t, rp) \ - movl T_LWP(t), %esi; \ - movl LWP_REGS(%esi), %edi; \ - cmpl rp, %edi; \ - je 7f; \ - pushl rp; \ - pushl %edi; \ - pushl %esi; \ - pushl $__LINE__; \ - pushl $__lwptoregs_msg; \ - call panic; \ -7: -#else -#define ASSERT_LWPTOREGS(t, rp) -#endif - -#endif /* __lint */ - -/* - * This is an assembler version of this fragment: - * - * lwp->lwp_state = LWP_SYS; - * lwp->lwp_ru.sysc++; - * lwp->lwp_eosys = NORMALRETURN; - * lwp->lwp_ap = argp; - * - * Preconditions: - * -none- - * Postconditions: - * -none- - */ -#define SET_LWP(lwp, argp) \ - movb $LWP_SYS, LWP_STATE(lwp); \ - addl $1, LWP_RU_SYSC(lwp); \ - adcl $0, LWP_RU_SYSC+4(lwp); \ - movb $NORMALRETURN, LWP_EOSYS(lwp); \ - movl argp, LWP_AP(lwp) - -/* - * Set up the thread, lwp, find the handler, and copy - * in the arguments from userland to the kernel stack. - * - * Preconditions: - * - %eax contains the syscall number - * Postconditions: - * - %eax contains a pointer to the sysent structure - * - %ecx is zeroed - * - %esi, %edi are smashed - * - %esp is SYS_DROPped ready for the syscall - */ -#define SIMPLE_SYSCALL_PRESYS(t, faultlabel) \ - movl T_LWP(t), %esi; \ - movw %ax, T_SYSNUM(t); \ - subl $SYS_DROP, %esp; \ - shll $SYSENT_SIZE_SHIFT, %eax; \ - SET_LWP(%esi, %esp); \ - leal sysent(%eax), %eax; \ - movzbl SY_NARG(%eax), %ecx; \ - testl %ecx, %ecx; \ - jz 4f; \ - movl %esp, %edi; \ - movl SYS_DROP + REGOFF_UESP(%esp), %esi; \ - movl $faultlabel, T_LOFAULT(t); \ - addl $4, %esi; \ - rep; \ - smovl; \ - movl %ecx, T_LOFAULT(t); \ -4: - -/* - * Check to see if a simple return is possible i.e. - * - * if ((t->t_post_sys_ast | syscalltrace) != 0) - * do full version; - * - * Preconditions: - * - t is curthread - * Postconditions: - * - condition code NE is set if post-sys is too complex - * - rtmp is zeroed if it isn't (we rely on this!) - */ -#define CHECK_POSTSYS_NE(t, rtmp) \ - xorl rtmp, rtmp; \ - ORL_SYSCALLTRACE(rtmp); \ - orl T_POST_SYS_AST(t), rtmp; \ - cmpl $0, rtmp - -/* - * Fix up the lwp, thread, and eflags for a successful return - * - * Preconditions: - * - zwreg contains zero - * Postconditions: - * - %esp has been unSYS_DROPped - * - %esi is smashed (points to lwp) - */ -#define SIMPLE_SYSCALL_POSTSYS(t, zwreg) \ - movl T_LWP(t), %esi; \ - addl $SYS_DROP, %esp; \ - movw zwreg, T_SYSNUM(t); \ - movb $LWP_USER, LWP_STATE(%esi); \ - andb $_CONST(0xffff - PS_C), REGOFF_EFL(%esp) - -/* - * System call handler. This is the destination of both the call - * gate (lcall 0x27) _and_ the interrupt gate (int 0x91). For our purposes, - * there are two significant differences between an interrupt gate and a call - * gate: - * - * 1) An interrupt gate runs the handler with interrupts disabled, whereas a - * call gate runs the handler with whatever EFLAGS settings were in effect at - * the time of the call. - * - * 2) An interrupt gate pushes the contents of the EFLAGS register at the time - * of the interrupt onto the stack, whereas a call gate does not. - * - * Because we use the following code sequence to handle system calls made from - * _both_ a call gate _and_ an interrupt gate, these two differences must be - * respected. In regards to number 1) above, the handler must ensure that a sane - * EFLAGS snapshot is stored on the stack so that when the kernel returns back - * to the user via iret (which returns to user with the EFLAGS value saved on - * the stack), interrupts are re-enabled. - * - * In regards to number 2) above, the handler must always put a current snapshot - * of EFLAGS onto the stack in the appropriate place. If we came in via an - * interrupt gate, we will be clobbering the EFLAGS value that was pushed by - * the interrupt gate. This is OK, as the only bit that was changed by the - * hardware was the IE (interrupt enable) bit, which for an interrupt gate is - * now off. If we were to do nothing, the stack would contain an EFLAGS with - * IE off, resulting in us eventually returning back to the user with interrupts - * disabled. The solution is to turn on the IE bit in the EFLAGS value saved on - * the stack. - * - * Another subtlety which deserves mention is the difference between the two - * descriptors. The call gate descriptor is set to instruct the hardware to copy - * one parameter from the user stack to the kernel stack, whereas the interrupt - * gate descriptor doesn't use the parameter passing mechanism at all. The - * kernel doesn't actually use the parameter that is copied by the hardware; the - * only reason it does this is so that there is a space on the stack large - * enough to hold an EFLAGS register value, which happens to be in the correct - * place for use by iret when we go back to userland. How convenient. - * - * Stack frame description in syscall() and callees. - * - * |------------| - * | regs | +(8*4)+4 registers - * |------------| - * | 8 args | <- %esp MAXSYSARGS (currently 8) arguments - * |------------| - * - */ -#define SYS_DROP _CONST(_MUL(MAXSYSARGS, 4)) - -#if defined(__lint) - -/*ARGSUSED*/ -void -sys_call() -{} - -void -_allsyscalls() -{} - -size_t _allsyscalls_size; - -#else /* __lint */ - - ENTRY_NP2(brand_sys_call, _allsyscalls) - BRAND_CALLBACK(BRAND_CB_SYSCALL) - - ALTENTRY(sys_call) - / on entry eax = system call number - - / set up the stack to look as in reg.h - subl $8, %esp / pad the stack with ERRCODE and TRAPNO - - SYSCALL_PUSH - -#ifdef TRAPTRACE - TRACE_PTR(%edi, %ebx, %ebx, %ecx, $TT_SYSCALL) / Uses labels "8" and "9" - TRACE_REGS(%edi, %esp, %ebx, %ecx) / Uses label "9" - pushl %eax - TRACE_STAMP(%edi) / Clobbers %eax, %edx, uses "9" - popl %eax - movl %eax, TTR_SYSNUM(%edi) -#endif - -_watch_do_syscall: - movl %esp, %ebp - - / Interrupts may be enabled here, so we must make sure this thread - / doesn't migrate off the CPU while it updates the CPU stats. - / - / XXX This is only true if we got here via call gate thru the LDT for - / old style syscalls. Perhaps this preempt++-- will go away soon? - movl %gs:CPU_THREAD, %ebx - addb $1, T_PREEMPT(%ebx) - CPU_STATS_SYS_SYSCALL_INC - subb $1, T_PREEMPT(%ebx) - - ENABLE_INTR_FLAGS - - pushl %eax / preserve across mstate call - MSTATE_TRANSITION(LMS_USER, LMS_SYSTEM) - popl %eax - - movl %gs:CPU_THREAD, %ebx - - ASSERT_LWPTOREGS(%ebx, %esp) - - CHECK_PRESYS_NE(%ebx, %eax) - jne _full_syscall_presys - SIMPLE_SYSCALL_PRESYS(%ebx, _syscall_fault) - -_syslcall_call: - call *SY_CALLC(%eax) - -_syslcall_done: - CHECK_POSTSYS_NE(%ebx, %ecx) - jne _full_syscall_postsys - SIMPLE_SYSCALL_POSTSYS(%ebx, %cx) - movl %eax, REGOFF_EAX(%esp) - movl %edx, REGOFF_EDX(%esp) - - MSTATE_TRANSITION(LMS_SYSTEM, LMS_USER) - - / - / get back via iret - / - CLI(%edx) - jmp sys_rtt_syscall - -_full_syscall_presys: - movl T_LWP(%ebx), %esi - subl $SYS_DROP, %esp - movb $LWP_SYS, LWP_STATE(%esi) - pushl %esp - pushl %ebx - call syscall_entry - addl $8, %esp - jmp _syslcall_call - -_full_syscall_postsys: - addl $SYS_DROP, %esp - pushl %edx - pushl %eax - pushl %ebx - call syscall_exit - addl $12, %esp - MSTATE_TRANSITION(LMS_SYSTEM, LMS_USER) - jmp _sys_rtt - -_syscall_fault: - push $0xe / EFAULT - call set_errno - addl $4, %esp - xorl %eax, %eax / fake syscall_err() - xorl %edx, %edx - jmp _syslcall_done - SET_SIZE(sys_call) - SET_SIZE(brand_sys_call) - -#endif /* __lint */ - -/* - * System call handler via the sysenter instruction - * - * Here's how syscall entry usually works (see sys_call for details). - * - * There, the caller (lcall or int) in userland has arranged that: - * - * - %eax contains the syscall number - * - the user stack contains the args to the syscall - * - * Normally the lcall instruction into the call gate causes the processor - * to push %ss, %esp, <top-of-stack>, %cs, %eip onto the kernel stack. - * The sys_call handler then leaves space for r_trapno and r_err, and - * pusha's {%eax, %ecx, %edx, %ebx, %esp, %ebp, %esi, %edi}, followed - * by %ds, %es, %fs and %gs to capture a 'struct regs' on the stack. - * Then the kernel sets %ds, %es and %gs to kernel selectors, and finally - * extracts %efl and puts it into r_efl (which happens to live at the offset - * that <top-of-stack> was copied into). Note that the value in r_efl has - * the IF (interrupt enable) flag turned on. (The int instruction into the - * interrupt gate does essentially the same thing, only instead of - * <top-of-stack> we get eflags - see comment above.) - * - * In the sysenter case, things are a lot more primitive. - * - * The caller in userland has arranged that: - * - * - %eax contains the syscall number - * - %ecx contains the user %esp - * - %edx contains the return %eip - * - the user stack contains the args to the syscall - * - * e.g. - * <args on the stack> - * mov $SYS_callnum, %eax - * mov $1f, %edx / return %eip - * mov %esp, %ecx / return %esp - * sysenter - * 1: - * - * Hardware and (privileged) initialization code have arranged that by - * the time the sysenter instructions completes: - * - * - %eip is pointing to sys_sysenter (below). - * - %cs and %ss are set to kernel text and stack (data) selectors. - * - %esp is pointing at the lwp's stack - * - Interrupts have been disabled. - * - * The task for the sysenter handler is: - * - * - recreate the same regs structure on the stack and the same - * kernel state as if we'd come in on an lcall - * - do the normal work of a syscall - * - execute the system call epilogue, use sysexit to return to userland. - * - * Note that we are unable to return both "rvals" to userland with this - * call, as %edx is used by the sysexit instruction. - * - * One final complication in this routine is its interaction with - * single-stepping in a debugger. For most of the system call mechanisms, - * the CPU automatically clears the single-step flag before we enter the - * kernel. The sysenter mechanism does not clear the flag, so a user - * single-stepping through a libc routine may suddenly find themself - * single-stepping through the kernel. To detect this, kmdb compares the - * trap %pc to the [brand_]sys_enter addresses on each single-step trap. - * If it finds that we have single-stepped to a sysenter entry point, it - * explicitly clears the flag and executes the sys_sysenter routine. - * - * One final complication in this final complication is the fact that we - * have two different entry points for sysenter: brand_sys_sysenter and - * sys_sysenter. If we enter at brand_sys_sysenter and start single-stepping - * through the kernel with kmdb, we will eventually hit the instruction at - * sys_sysenter. kmdb cannot distinguish between that valid single-step - * and the undesirable one mentioned above. To avoid this situation, we - * simply add a jump over the instruction at sys_sysenter to make it - * impossible to single-step to it. - */ -#if defined(__lint) - -void -sys_sysenter() -{} - -#else /* __lint */ - - ENTRY_NP(brand_sys_sysenter) - pushl %edx - BRAND_CALLBACK(BRAND_CB_SYSENTER) - popl %edx - /* - * Jump over sys_sysenter to allow single-stepping as described - * above. - */ - ja 1f - - ALTENTRY(sys_sysenter) - nop -1: - / - / do what the call gate would've done to the stack .. - / - pushl $UDS_SEL / (really %ss, but it's the same ..) - pushl %ecx / userland makes this a copy of %esp - pushfl - orl $PS_IE, (%esp) / turn interrupts on when we return to user - pushl $UCS_SEL - pushl %edx / userland makes this a copy of %eip - / - / done. finish building the stack frame - / - subl $8, %esp / leave space for ERR and TRAPNO - - SYSENTER_PUSH - -#ifdef TRAPTRACE - TRACE_PTR(%edi, %ebx, %ebx, %ecx, $TT_SYSENTER) / uses labels 8 and 9 - TRACE_REGS(%edi, %esp, %ebx, %ecx) / uses label 9 - pushl %eax - TRACE_STAMP(%edi) / clobbers %eax, %edx, uses label 9 - popl %eax - movl %eax, TTR_SYSNUM(%edi) -#endif - movl %esp, %ebp - - CPU_STATS_SYS_SYSCALL_INC - - ENABLE_INTR_FLAGS - - pushl %eax / preserve across mstate call - MSTATE_TRANSITION(LMS_USER, LMS_SYSTEM) - popl %eax - - movl %gs:CPU_THREAD, %ebx - - ASSERT_LWPTOREGS(%ebx, %esp) - - CHECK_PRESYS_NE(%ebx, %eax) - jne _full_syscall_presys - SIMPLE_SYSCALL_PRESYS(%ebx, _syscall_fault) - -_sysenter_call: - call *SY_CALLC(%eax) - -_sysenter_done: - CHECK_POSTSYS_NE(%ebx, %ecx) - jne _full_syscall_postsys - SIMPLE_SYSCALL_POSTSYS(%ebx, %cx) - / - / sysexit uses %edx to restore %eip, so we can't use it - / to return a value, sigh. - / - movl %eax, REGOFF_EAX(%esp) - / movl %edx, REGOFF_EDX(%esp) - - / Interrupts will be turned on by the 'sti' executed just before - / sysexit. The following ensures that restoring the user's EFLAGS - / doesn't enable interrupts too soon. - andl $_BITNOT(PS_IE), REGOFF_EFL(%esp) - - MSTATE_TRANSITION(LMS_SYSTEM, LMS_USER) - - cli - - SYSCALL_POP - - popl %edx / sysexit: %edx -> %eip - addl $4, %esp / get CS off the stack - popfl / EFL - popl %ecx / sysexit: %ecx -> %esp - sti - sysexit - SET_SIZE(sys_sysenter) - SET_SIZE(brand_sys_sysenter) -#endif /* __lint */ - -#if defined(__lint) -/* - * System call via an int80. This entry point is only used by the Linux - * application environment. Unlike the sysenter path, there is no default - * action to take if no callback is registered for this process. - */ -void -sys_int80() -{} - -#else /* __lint */ - - ENTRY_NP(brand_sys_int80) - BRAND_CALLBACK(BRAND_CB_INT80) - - ALTENTRY(sys_int80) - /* - * We hit an int80, but this process isn't of a brand with an int80 - * handler. Bad process! Make it look as if the INT failed. - * Modify %eip to point before the INT, push the expected error - * code and fake a GP fault. - * - */ - subl $2, (%esp) /* int insn 2-bytes */ - pushl $_CONST(_MUL(T_INT80, GATE_DESC_SIZE) + 2) - jmp gptrap / GP fault - SET_SIZE(sys_int80) - SET_SIZE(brand_sys_int80) - -/* - * Declare a uintptr_t which covers the entire pc range of syscall - * handlers for the stack walkers that need this. - */ - .align CPTRSIZE - .globl _allsyscalls_size - .type _allsyscalls_size, @object -_allsyscalls_size: - .NWORD . - _allsyscalls - SET_SIZE(_allsyscalls_size) - -#endif /* __lint */ - -/* - * These are the thread context handlers for lwps using sysenter/sysexit. - */ - -#if defined(__lint) - -/*ARGSUSED*/ -void -sep_save(void *ksp) -{} - -/*ARGSUSED*/ -void -sep_restore(void *ksp) -{} - -#else /* __lint */ - - /* - * setting this value to zero as we switch away causes the - * stack-pointer-on-sysenter to be NULL, ensuring that we - * don't silently corrupt another (preempted) thread stack - * when running an lwp that (somehow) didn't get sep_restore'd - */ - ENTRY_NP(sep_save) - xorl %edx, %edx - xorl %eax, %eax - movl $MSR_INTC_SEP_ESP, %ecx - wrmsr - ret - SET_SIZE(sep_save) - - /* - * Update the kernel stack pointer as we resume onto this cpu. - */ - ENTRY_NP(sep_restore) - movl 4(%esp), %eax /* per-lwp kernel sp */ - xorl %edx, %edx - movl $MSR_INTC_SEP_ESP, %ecx - wrmsr - ret - SET_SIZE(sep_restore) - -#endif /* __lint */ - -/* - * Call syscall(). Called from trap() on watchpoint at lcall 0,7 - */ - -#if defined(__lint) - -void -watch_syscall(void) -{} - -#else /* __lint */ - - ENTRY_NP(watch_syscall) - CLI(%eax) - movl %gs:CPU_THREAD, %ebx - movl T_STACK(%ebx), %esp / switch to the thread stack - movl REGOFF_EAX(%esp), %eax / recover original syscall# - jmp _watch_do_syscall - SET_SIZE(watch_syscall) - -#endif /* __lint */ |