/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
- *
- * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* 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 2.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.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ 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
* Please see the License for the specific language governing rights and
* limitations under the License.
*
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* @OSF_COPYRIGHT@
* the rights to redistribute these changes.
*/
-#include <cpus.h>
-#include <etap.h>
-#include <etap_event_monitor.h>
#include <mach_rt.h>
#include <platforms.h>
-#include <mach_kdb.h>
-#include <mach_kgdb.h>
#include <mach_kdp.h>
-#include <stat_time.h>
#include <mach_assert.h>
#include <sys/errno.h>
#include <i386/proc_reg.h>
#include <i386/trap.h>
#include <assym.s>
-#include <mach/exception_types.h>
-#include <i386/AT386/mp/mp.h>
+#include <config_dtrace.h>
-#define PREEMPT_DEBUG_LOG 0
+/*
+ * PTmap is recursive pagemap at top of virtual address space.
+ * Within PTmap, the page directory can be found (third indirection).
+*/
+ .globl _PTmap,_PTD,_PTDpde
+ .set _PTmap,(PTDPTDI << PDESHIFT)
+ .set _PTD,_PTmap + (PTDPTDI * NBPG)
+ .set _PTDpde,_PTD + (PTDPTDI * PDESIZE)
#if __MACHO__
/* Under Mach-O, etext is a variable which contains
#define ETEXT_ADDR $ EXT(etext)
#endif
-#if NCPUS > 1
-
-#define CX(addr,reg) addr(,reg,4)
-
-#else
-#define CPU_NUMBER(reg)
-#define CX(addr,reg) addr
-
-#endif /* NCPUS > 1 */
.text
locore_start:
#ifdef __MACHO__
#define RECOVERY_SECTION .section __VECTORS, __recover
-#define RETRY_SECTION .section __VECTORS, __retries
#else
#define RECOVERY_SECTION .text
#define RECOVERY_SECTION .text
.align 2 ;\
.globl EXT(recover_table_end) ;\
LEXT(recover_table_end) ;\
- .text
+ .long 0 /* workaround see comment below */ ;\
+ .text ;
-/*
- * Retry table for certain successful faults.
+/* TODO FIXME
+ * the .long 0 is to work around a linker bug (insert radar# here)
+ * basically recover_table_end has zero size and bumps up right against saved_esp in acpi_wakeup.s
+ * recover_table_end is in __RECOVER,__vectors and saved_esp is in __SLEEP,__data, but they're right next to each
+ * other and so the linker combines them and incorrectly relocates everything referencing recover_table_end to point
+ * into the SLEEP section
*/
-#define RETRY_TABLE_START \
- .align 3; \
- .globl EXT(retry_table) ;\
-LEXT(retry_table) ;\
- .text
-
-#define RETRY(addr) \
- .align 3 ;\
- .long 9f ;\
- .long addr ;\
- .text ;\
-9:
-
-#define RETRY_TABLE_END \
- .align 3; \
- .globl EXT(retry_table_end) ;\
-LEXT(retry_table_end) ;\
- .text
/*
- * Allocate recovery and retry tables.
+ * Allocate recovery and table.
*/
RECOVERY_SECTION
RECOVER_TABLE_START
- RETRY_SECTION
- RETRY_TABLE_START
-
-/*
- * Timing routines.
- */
-#if STAT_TIME
-
-#define TIME_TRAP_UENTRY
-#define TIME_TRAP_UEXIT
-#define TIME_INT_ENTRY
-#define TIME_INT_EXIT
-
-#else /* microsecond timing */
-
-/*
- * Microsecond timing.
- * Assumes a free-running microsecond counter.
- * no TIMER_MAX check needed.
- */
-
-/*
- * There is only one current time-stamp per CPU, since only
- * the time-stamp in the current timer is used.
- * To save time, we allocate the current time-stamps here.
- */
- .comm EXT(current_tstamp), 4*NCPUS
-
-/*
- * Update time on user trap entry.
- * 11 instructions (including cli on entry)
- * Assumes CPU number in %edx.
- * Uses %ebx, %ecx.
- */
-#define TIME_TRAP_UENTRY \
- cli /* block interrupts */ ;\
- movl VA_ETC,%ebx /* get timer value */ ;\
- movl CX(EXT(current_tstamp),%edx),%ecx /* get old time stamp */;\
- movl %ebx,CX(EXT(current_tstamp),%edx) /* set new time stamp */;\
- subl %ecx,%ebx /* elapsed = new-old */ ;\
- movl CX(EXT(current_timer),%edx),%ecx /* get current timer */;\
- addl %ebx,LOW_BITS(%ecx) /* add to low bits */ ;\
- jns 0f /* if overflow, */ ;\
- call timer_normalize /* normalize timer */ ;\
-0: addl $(TH_SYS_TIMER-TH_USER_TIMER),%ecx ;\
- /* switch to sys timer */;\
- movl %ecx,CX(EXT(current_timer),%edx) /* make it current */ ;\
- sti /* allow interrupts */
-
-/*
- * update time on user trap exit.
- * 10 instructions.
- * Assumes CPU number in %edx.
- * Uses %ebx, %ecx.
- */
-#define TIME_TRAP_UEXIT \
- cli /* block interrupts */ ;\
- movl VA_ETC,%ebx /* get timer */ ;\
- movl CX(EXT(current_tstamp),%edx),%ecx /* get old time stamp */;\
- movl %ebx,CX(EXT(current_tstamp),%edx) /* set new time stamp */;\
- subl %ecx,%ebx /* elapsed = new-old */ ;\
- movl CX(EXT(current_timer),%edx),%ecx /* get current timer */;\
- addl %ebx,LOW_BITS(%ecx) /* add to low bits */ ;\
- jns 0f /* if overflow, */ ;\
- call timer_normalize /* normalize timer */ ;\
-0: addl $(TH_USER_TIMER-TH_SYS_TIMER),%ecx ;\
- /* switch to user timer */;\
- movl %ecx,CX(EXT(current_timer),%edx) /* make it current */
-
-/*
- * update time on interrupt entry.
- * 9 instructions.
- * Assumes CPU number in %edx.
- * Leaves old timer in %ebx.
- * Uses %ecx.
- */
-#define TIME_INT_ENTRY \
- movl VA_ETC,%ecx /* get timer */ ;\
- movl CX(EXT(current_tstamp),%edx),%ebx /* get old time stamp */;\
- movl %ecx,CX(EXT(current_tstamp),%edx) /* set new time stamp */;\
- subl %ebx,%ecx /* elapsed = new-old */ ;\
- movl CX(EXT(current_timer),%edx),%ebx /* get current timer */;\
- addl %ecx,LOW_BITS(%ebx) /* add to low bits */ ;\
- leal CX(0,%edx),%ecx /* timer is 16 bytes */ ;\
- lea CX(EXT(kernel_timer),%edx),%ecx /* get interrupt timer*/;\
- movl %ecx,CX(EXT(current_timer),%edx) /* set timer */
-
-/*
- * update time on interrupt exit.
- * 11 instructions
- * Assumes CPU number in %edx, old timer in %ebx.
- * Uses %eax, %ecx.
- */
-#define TIME_INT_EXIT \
- 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.
+ * Called as a function, makes the current thread
+ * return from the kernel as if from an exception.
+ * We will consult with DTrace if this is a
+ * newly created thread and we need to fire a probe.
*/
- .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
+ .globl EXT(thread_exception_return)
+ .globl EXT(thread_bootstrap_return)
+LEXT(thread_bootstrap_return)
+#if CONFIG_DTRACE
+ call EXT(dtrace_thread_bootstrap)
+#endif
-/*
- * 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
+LEXT(thread_exception_return)
+ cli
+ xorl %ecx,%ecx /* don't check if in the PFZ */
+ cmpl $0, %gs:CPU_IS64BIT
+ je EXT(return_from_trap32)
+ jmp EXT(return_from_trap)
-#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).
+ * Utility routines.
*/
/*
- * 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.
+ * Copy from user/kernel address space.
+ * arg0: window offset or kernel address
+ * arg1: kernel address
+ * arg2: byte count
*/
-#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 */
+Entry(copyinphys_user)
+ movl $(USER_WINDOW_SEL),%ecx /* user data segment access through kernel window */
+ mov %cx,%ds
-/*
- * 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
-
-#undef PDEBUG
-
-#ifdef PDEBUG
+Entry(copyinphys_kern)
+ movl $(PHYS_WINDOW_SEL),%ecx /* physical access through kernel window */
+ mov %cx,%es
+ jmp copyin_common
-/*
- * Traditional, not ANSI.
- */
-#define CAH(label) \
- .data ;\
- .globl label/**/count ;\
-label/**/count: ;\
- .long 0 ;\
- .globl label/**/limit ;\
-label/**/limit: ;\
- .long 0 ;\
- .text ;\
- addl $1,%ss:label/**/count ;\
- cmpl $0,label/**/limit ;\
- jz label/**/exit ;\
- pushl %eax ;\
-label/**/loop: ;\
- movl %ss:label/**/count,%eax ;\
- cmpl %eax,%ss:label/**/limit ;\
- je label/**/loop ;\
- popl %eax ;\
-label/**/exit:
-
-#else /* PDEBUG */
-
-#define CAH(label)
-
-#endif /* PDEBUG */
-
-#if MACH_KDB
-/*
- * Last-ditch debug code to handle faults that might result
- * from entering kernel (from collocated server) on an invalid
- * stack. On collocated entry, there's no hardware-initiated
- * stack switch, so a valid stack must be in place when an
- * exception occurs, or we may double-fault.
- *
- * In case of a double-fault, our only recourse is to switch
- * hardware "tasks", so that we avoid using the current stack.
- *
- * The idea here is just to get the processor into the debugger,
- * post-haste. No attempt is made to fix up whatever error got
- * us here, so presumably continuing from the debugger will
- * simply land us here again -- at best.
- */
-#if 0
-/*
- * Note that the per-fault entry points are not currently
- * functional. The only way to make them work would be to
- * set up separate TSS's for each fault type, which doesn't
- * currently seem worthwhile. (The offset part of a task
- * gate is always ignored.) So all faults that task switch
- * currently resume at db_task_start.
- */
-/*
- * Double fault (Murphy's point) - error code (0) on stack
- */
-Entry(db_task_dbl_fault)
- popl %eax
- movl $(T_DOUBLE_FAULT),%ebx
- jmp db_task_start
-/*
- * Segment not present - error code on stack
- */
-Entry(db_task_seg_np)
- popl %eax
- movl $(T_SEGMENT_NOT_PRESENT),%ebx
- jmp db_task_start
-/*
- * Stack fault - error code on (current) stack
- */
-Entry(db_task_stk_fault)
- popl %eax
- movl $(T_STACK_FAULT),%ebx
- jmp db_task_start
-/*
- * General protection fault - error code on stack
- */
-Entry(db_task_gen_prot)
- popl %eax
- movl $(T_GENERAL_PROTECTION),%ebx
- jmp db_task_start
-#endif /* 0 */
-/*
- * The entry point where execution resumes after last-ditch debugger task
- * switch.
- */
-Entry(db_task_start)
- movl %esp,%edx
- subl $ISS_SIZE,%edx
- movl %edx,%esp /* allocate i386_saved_state on stack */
- movl %eax,R_ERR(%esp)
- movl %ebx,R_TRAPNO(%esp)
- pushl %edx
-#if NCPUS > 1
- CPU_NUMBER(%edx)
- movl CX(EXT(mp_dbtss),%edx),%edx
- movl TSS_LINK(%edx),%eax
-#else
- movl EXT(dbtss)+TSS_LINK,%eax
-#endif
- pushl %eax /* pass along selector of previous TSS */
- call EXT(db_tss_to_frame)
- popl %eax /* get rid of TSS selector */
- call EXT(db_trap_from_asm)
- addl $0x4,%esp
- /*
- * And now...?
- */
- iret /* ha, ha, ha... */
-#endif /* MACH_KDB */
+Entry(copyin_user)
+ movl $(USER_WINDOW_SEL),%ecx /* user data segment access through kernel window */
+ mov %cx,%ds
-/*
- * Trap/interrupt entry points.
- *
- * All traps must create the following save area on the PCB "stack":
- *
- * gs
- * fs
- * es
- * ds
- * edi
- * esi
- * ebp
- * cr2 if page fault - otherwise unused
- * ebx
- * edx
- * ecx
- * eax
- * trap number
- * error code
- * eip
- * cs
- * eflags
- * user esp - if from user
- * user ss - if from user
- * es - if from V86 thread
- * ds - if from V86 thread
- * fs - if from V86 thread
- * gs - if from V86 thread
- *
- */
+Entry(copyin_kern)
-/*
- * General protection or segment-not-present fault.
- * Check for a GP/NP fault in the kernel_return
- * sequence; if there, report it as a GP/NP fault on the user's instruction.
- *
- * esp-> 0: trap code (NP or GP)
- * 4: segment number in error
- * 8 eip
- * 12 cs
- * 16 eflags
- * 20 old registers (trap is from kernel)
- */
-Entry(t_gen_prot)
- pushl $(T_GENERAL_PROTECTION) /* indicate fault type */
- jmp trap_check_kernel_exit /* check for kernel exit sequence */
-
-Entry(t_segnp)
- pushl $(T_SEGMENT_NOT_PRESENT)
- /* indicate fault type */
-
-trap_check_kernel_exit:
- testl $(EFL_VM),16(%esp) /* is trap from V86 mode? */
- jnz EXT(alltraps) /* isn`t kernel trap if so */
- testl $3,12(%esp) /* is trap from kernel mode? */
- jne EXT(alltraps) /* if so: */
- /* check for the kernel exit sequence */
- cmpl $ EXT(kret_iret),8(%esp) /* on IRET? */
- je fault_iret
- cmpl $ EXT(kret_popl_ds),8(%esp) /* popping DS? */
- je fault_popl_ds
- cmpl $ EXT(kret_popl_es),8(%esp) /* popping ES? */
- je fault_popl_es
- cmpl $ EXT(kret_popl_fs),8(%esp) /* popping FS? */
- je fault_popl_fs
- cmpl $ EXT(kret_popl_gs),8(%esp) /* popping GS? */
- je fault_popl_gs
-take_fault: /* if none of the above: */
- jmp EXT(alltraps) /* treat as normal trap. */
+copyin_common:
+ pushl %esi
+ pushl %edi /* save registers */
-/*
- * GP/NP fault on IRET: CS or SS is in error.
- * All registers contain the user's values.
- *
- * on SP is
- * 0 trap number
- * 4 errcode
- * 8 eip
- * 12 cs --> trapno
- * 16 efl --> errcode
- * 20 user eip
- * 24 user cs
- * 28 user eflags
- * 32 user esp
- * 36 user ss
- */
-fault_iret:
- movl %eax,8(%esp) /* save eax (we don`t need saved eip) */
- popl %eax /* get trap number */
- movl %eax,12-4(%esp) /* put in user trap number */
- popl %eax /* get error code */
- movl %eax,16-8(%esp) /* put in user errcode */
- popl %eax /* restore eax */
- CAH(fltir)
- jmp EXT(alltraps) /* take fault */
+ movl 8+S_ARG0,%esi /* get source - window offset or kernel address */
+ movl 8+S_ARG1,%edi /* get destination - kernel address */
+ movl 8+S_ARG2,%edx /* get count */
-/*
- * Fault restoring a segment register. The user's registers are still
- * saved on the stack. The offending segment register has not been
- * popped.
- */
-fault_popl_ds:
- popl %eax /* get trap number */
- popl %edx /* get error code */
- addl $12,%esp /* pop stack to user regs */
- jmp push_es /* (DS on top of stack) */
-fault_popl_es:
- popl %eax /* get trap number */
- popl %edx /* get error code */
- addl $12,%esp /* pop stack to user regs */
- jmp push_fs /* (ES on top of stack) */
-fault_popl_fs:
- popl %eax /* get trap number */
- popl %edx /* get error code */
- addl $12,%esp /* pop stack to user regs */
- jmp push_gs /* (FS on top of stack) */
-fault_popl_gs:
- popl %eax /* get trap number */
- popl %edx /* get error code */
- addl $12,%esp /* pop stack to user regs */
- jmp push_segregs /* (GS on top of stack) */
-
-push_es:
- pushl %es /* restore es, */
-push_fs:
- pushl %fs /* restore fs, */
-push_gs:
- pushl %gs /* restore gs. */
-push_segregs:
- movl %eax,R_TRAPNO(%esp) /* set trap number */
- movl %edx,R_ERR(%esp) /* set error code */
- CAH(fltpp)
- jmp trap_set_segs /* take trap */
+ cld /* count up */
+ movl %edx,%ecx /* move by longwords first */
+ shrl $2,%ecx
+ RECOVERY_SECTION
+ RECOVER(copyin_fail)
+ rep
+ movsl /* move longwords */
+ movl %edx,%ecx /* now move remaining bytes */
+ andl $3,%ecx
+ RECOVERY_SECTION
+ RECOVER(copyin_fail)
+ rep
+ movsb
+ xorl %eax,%eax /* return 0 for success */
+copyin_ret:
+ mov %ss,%cx /* restore kernel data and extended segments */
+ mov %cx,%ds
+ mov %cx,%es
-/*
- * Debug trap. Check for single-stepping across system call into
- * kernel. If this is the case, taking the debug trap has turned
- * off single-stepping - save the flags register with the trace
- * bit set.
- */
-Entry(t_debug)
- testl $(EFL_VM),8(%esp) /* is trap from V86 mode? */
- jnz 0f /* isn`t kernel trap if so */
- testl $3,4(%esp) /* is trap from kernel mode? */
- jnz 0f /* if so: */
- cmpl $syscall_entry,(%esp) /* system call entry? */
- jne 0f /* if so: */
- /* flags are sitting where syscall */
- /* wants them */
- addl $8,%esp /* remove eip/cs */
- jmp syscall_entry_2 /* continue system call entry */
-
-0: pushl $0 /* otherwise: */
- pushl $(T_DEBUG) /* handle as normal */
- jmp EXT(alltraps) /* debug fault */
+ popl %edi /* restore registers */
+ popl %esi
+ ret /* and return */
-/*
- * Page fault traps save cr2.
- */
-Entry(t_page_fault)
- pushl $(T_PAGE_FAULT) /* mark a page fault trap */
- pusha /* save the general registers */
- movl %cr2,%eax /* get the faulting address */
- movl %eax,12(%esp) /* save in esp save slot */
- jmp trap_push_segs /* continue fault */
+copyin_fail:
+ movl $(EFAULT),%eax /* return error for failure */
+ jmp copyin_ret /* pop frame and return */
-/*
- * All 'exceptions' enter here with:
- * esp-> trap number
- * error code
- * old eip
- * old cs
- * old eflags
- * old esp if trapped from user
- * old ss if trapped from user
- *
- * NB: below use of CPU_NUMBER assumes that macro will use correct
- * segment register for any kernel data accesses.
- */
-Entry(alltraps)
- pusha /* save the general registers */
-trap_push_segs:
- pushl %ds /* save the segment registers */
- pushl %es
- pushl %fs
- pushl %gs
-
-trap_set_segs:
- movl %ss,%ax
- movl %ax,%ds
- movl %ax,%es /* switch to kernel data seg */
- cld /* clear direction flag */
- testl $(EFL_VM),R_EFLAGS(%esp) /* in V86 mode? */
- jnz trap_from_user /* user mode trap if so */
- testb $3,R_CS(%esp) /* user mode trap? */
- jnz trap_from_user
- CPU_NUMBER(%edx)
- cmpl $0,CX(EXT(active_kloaded),%edx)
- je trap_from_kernel /* if clear, truly in kernel */
-#ifdef FIXME
- cmpl ETEXT_ADDR,R_EIP(%esp) /* pc within kernel? */
- jb trap_from_kernel
-#endif
-trap_from_kloaded:
- /*
- * We didn't enter here "through" PCB (i.e., using ring 0 stack),
- * so transfer the stack frame into the PCB explicitly, then
- * start running on resulting "PCB stack". We have to set
- * up a simulated "uesp" manually, since there's none in the
- * frame.
- */
- mov $ CPU_DATA,%dx
- mov %dx,%gs
- CAH(atstart)
- CPU_NUMBER(%edx)
- movl CX(EXT(active_kloaded),%edx),%ebx
- movl CX(EXT(kernel_stack),%edx),%eax
- xchgl %esp,%eax
- FRAME_STACK_TO_PCB(%ebx,%eax)
- CAH(atend)
- jmp EXT(take_trap)
-
-trap_from_user:
- mov $ CPU_DATA,%ax
- mov %ax,%gs
-
- CPU_NUMBER(%edx)
- TIME_TRAP_UENTRY
-
- movl CX(EXT(kernel_stack),%edx),%ebx
- xchgl %ebx,%esp /* switch to kernel stack */
- /* user regs pointer already set */
-LEXT(take_trap)
- pushl %ebx /* record register save area */
- pushl %ebx /* pass register save area to trap */
- call EXT(user_trap) /* call user trap routine */
- movl 4(%esp),%esp /* switch back to PCB stack */
+
/*
- * Return from trap or system call, checking for ASTs.
- * On PCB stack.
+ * Copy string from user/kern address space.
+ * arg0: window offset or kernel address
+ * arg1: kernel address
+ * arg2: max byte count
+ * arg3: actual byte count (OUT)
*/
+Entry(copyinstr_kern)
+ mov %ds,%cx
+ jmp copyinstr_common
-LEXT(return_from_trap)
- CPU_NUMBER(%edx)
- cmpl $0,CX(EXT(need_ast),%edx)
- je EXT(return_to_user) /* if we need an AST: */
-
- movl CX(EXT(kernel_stack),%edx),%esp
- /* switch to kernel stack */
- pushl $0 /* push preemption flag */
- call EXT(i386_astintr) /* take the AST */
- addl $4,%esp /* pop preemption flag */
- popl %esp /* switch back to PCB stack (w/exc link) */
- jmp EXT(return_from_trap) /* and check again (rare) */
- /* ASTs after this point will */
- /* have to wait */
-
-/*
- * Arrange the checks needed for kernel-loaded (or kernel-loading)
- * threads so that branch is taken in kernel-loaded case.
- */
-LEXT(return_to_user)
- TIME_TRAP_UEXIT
- CPU_NUMBER(%eax)
- cmpl $0,CX(EXT(active_kloaded),%eax)
- jnz EXT(return_xfer_stack)
- movl $ CPD_ACTIVE_THREAD,%ebx
- movl %gs:(%ebx),%ebx /* get active thread */
- movl TH_TOP_ACT(%ebx),%ebx /* get thread->top_act */
- cmpl $0,ACT_KLOADING(%ebx) /* check if kernel-loading */
- jnz EXT(return_kernel_loading)
-
-#if MACH_RT
-#if MACH_ASSERT
- movl $ CPD_PREEMPTION_LEVEL,%ebx
- cmpl $0,%gs:(%ebx)
- je EXT(return_from_kernel)
- int $3
-#endif /* MACH_ASSERT */
-#endif /* MACH_RT */
+Entry(copyinstr_user)
+ movl $(USER_WINDOW_SEL),%ecx /* user data segment access through kernel window */
-/*
- * Return from kernel mode to interrupted thread.
- */
+copyinstr_common:
+ mov %cx,%fs
-LEXT(return_from_kernel)
-LEXT(kret_popl_gs)
- popl %gs /* restore segment registers */
-LEXT(kret_popl_fs)
- popl %fs
-LEXT(kret_popl_es)
- popl %es
-LEXT(kret_popl_ds)
- popl %ds
- popa /* restore general registers */
- addl $8,%esp /* discard trap number and error code */
-
-LEXT(kret_iret)
- iret /* return from interrupt */
-
-
-LEXT(return_xfer_stack)
- /*
- * If we're on PCB stack in a kernel-loaded task, we have
- * to transfer saved state back to thread stack and swap
- * stack pointers here, because the hardware's not going
- * to do so for us.
- */
- CAH(rxsstart)
- CPU_NUMBER(%eax)
- movl CX(EXT(kernel_stack),%eax),%esp
- movl CX(EXT(active_kloaded),%eax),%eax
- FRAME_PCB_TO_STACK(%eax)
- movl %eax,%esp
- CAH(rxsend)
- jmp EXT(return_from_kernel)
+ pushl %esi
+ pushl %edi /* save registers */
-/*
- * Hate to put this here, but setting up a separate swap_func for
- * kernel-loaded threads no longer works, since thread executes
- * "for a while" (i.e., until it reaches glue code) when first
- * created, even if it's nominally suspended. Hence we can't
- * transfer the PCB when the thread first resumes, because we
- * haven't initialized it yet.
- */
-/*
- * Have to force transfer to new stack "manually". Use a string
- * move to transfer all of our saved state to the stack pointed
- * to by iss.uesp, then install a pointer to it as our current
- * stack pointer.
- */
-LEXT(return_kernel_loading)
- CPU_NUMBER(%eax)
- movl CX(EXT(kernel_stack),%eax),%esp
- movl $ CPD_ACTIVE_THREAD,%ebx
- movl %gs:(%ebx),%ebx /* get active thread */
- movl TH_TOP_ACT(%ebx),%ebx /* get thread->top_act */
- movl %ebx,%edx /* save for later */
- movl $0,ACT_KLOADING(%edx) /* clear kernel-loading bit */
- FRAME_PCB_TO_STACK(%ebx)
- movl %ebx,%esp /* start running on new stack */
- movl $1,ACT_KLOADED(%edx) /* set kernel-loaded bit */
- movl %edx,CX(EXT(active_kloaded),%eax) /* set cached indicator */
- jmp EXT(return_from_kernel)
+ movl 8+S_ARG0,%esi /* get source - window offset or kernel address */
+ movl 8+S_ARG1,%edi /* get destination - kernel address */
+ movl 8+S_ARG2,%edx /* get count */
-/*
- * Trap from kernel mode. No need to switch stacks or load segment registers.
- */
-trap_from_kernel:
-#if MACH_KDB || MACH_KGDB
- mov $ CPU_DATA,%ax
- mov %ax,%gs
- movl %esp,%ebx /* save current stack */
-
- cmpl EXT(int_stack_high),%esp /* on an interrupt stack? */
- jb 6f /* OK if so */
-
-#if MACH_KGDB
- cmpl $0,EXT(kgdb_active) /* Unexpected trap in kgdb */
- je 0f /* no */
-
- pushl %esp /* Already on kgdb stack */
- cli
- call EXT(kgdb_trap)
- addl $4,%esp
- jmp EXT(return_from_kernel)
-0: /* should kgdb handle this exception? */
- cmpl $(T_NO_FPU),R_TRAPNO(%esp) /* FPU disabled? */
- je 2f /* yes */
- cmpl $(T_PAGE_FAULT),R_TRAPNO(%esp) /* page fault? */
- je 2f /* yes */
-1:
- cli /* disable interrupts */
- CPU_NUMBER(%edx) /* get CPU number */
- movl CX(EXT(kgdb_stacks),%edx),%ebx
- xchgl %ebx,%esp /* switch to kgdb stack */
- pushl %ebx /* pass old sp as an arg */
- call EXT(kgdb_from_kernel)
- popl %esp /* switch back to kernel stack */
- jmp EXT(return_from_kernel)
+ xorl %eax,%eax /* set to 0 here so that the high 24 bits */
+ /* are 0 for the cmpl against 0 */
2:
-#endif /* MACH_KGDB */
-
-#if MACH_KDB
- cmpl $0,EXT(db_active) /* could trap be from ddb? */
- je 3f /* no */
-#if NCPUS > 1
- CPU_NUMBER(%edx) /* see if this CPU is in ddb */
- cmpl $0,CX(EXT(kdb_active),%edx)
- je 3f /* no */
-#endif /* NCPUS > 1 */
- pushl %esp
- call EXT(db_trap_from_asm)
- addl $0x4,%esp
- jmp EXT(return_from_kernel)
-
+ RECOVERY_SECTION
+ RECOVER(copystr_fail) /* copy bytes... */
+ movb %fs:(%esi),%al
+ incl %esi
+ testl %edi,%edi /* if kernel address is ... */
+ jz 3f /* not NULL */
+ movb %al,(%edi) /* copy the byte */
+ incl %edi
3:
- /*
- * Dilemma: don't want to switch to kernel_stack if trap
- * "belongs" to ddb; don't want to switch to db_stack if
- * trap "belongs" to kernel. So have to duplicate here the
- * set of trap types that kernel_trap() handles. Note that
- * "unexpected" page faults will not be handled by kernel_trap().
- * In this panic-worthy case, we fall into the debugger with
- * kernel_stack containing the call chain that led to the
- * bogus fault.
- */
- movl R_TRAPNO(%esp),%edx
- cmpl $(T_PAGE_FAULT),%edx
- je 4f
- cmpl $(T_NO_FPU),%edx
- je 4f
- cmpl $(T_FPU_FAULT),%edx
- je 4f
- cmpl $(T_FLOATING_POINT_ERROR),%edx
- je 4f
- cmpl $(T_PREEMPT),%edx
- jne 7f
+ testl %eax,%eax /* did we just stuff the 0-byte? */
+ jz 4f /* yes, return 0 status already in %eax */
+ decl %edx /* decrement #bytes left in buffer */
+ jnz 2b /* buffer not full so copy in another byte */
+ movl $(ENAMETOOLONG),%eax /* buffer full but no 0-byte: ENAMETOOLONG */
4:
-#endif /* MACH_KDB */
-
- CPU_NUMBER(%edx) /* get CPU number */
- cmpl CX(EXT(kernel_stack),%edx),%esp
- /* if not already on kernel stack, */
- ja 5f /* check some more */
- cmpl CX(EXT(active_stacks),%edx),%esp
- ja 6f /* on kernel stack: no switch */
-5:
- movl CX(EXT(kernel_stack),%edx),%esp
-6:
- pushl %ebx /* save old stack */
- pushl %ebx /* pass as parameter */
- call EXT(kernel_trap) /* to kernel trap routine */
- addl $4,%esp /* pop parameter */
- testl %eax,%eax
- jne 8f
- /*
- * If kernel_trap returns false, trap wasn't handled.
- */
-7:
-#if MACH_KDB
- CPU_NUMBER(%edx)
- movl CX(EXT(db_stacks),%edx),%esp
- pushl %ebx /* pass old stack as parameter */
- call EXT(db_trap_from_asm)
-#endif /* MACH_KDB */
-#if MACH_KGDB
- cli /* disable interrupts */
- CPU_NUMBER(%edx) /* get CPU number */
- movl CX(EXT(kgdb_stacks),%edx),%esp
- pushl %ebx /* pass old stack as parameter */
- call EXT(kgdb_from_kernel)
-#endif /* MACH_KGDB */
- addl $4,%esp /* pop parameter */
- testl %eax,%eax
- jne 8f
- /*
- * Likewise, if kdb_trap/kgdb_from_kernel returns false, trap
- * wasn't handled.
- */
- pushl %ebx /* pass old stack as parameter */
- call EXT(panic_trap)
- addl $4,%esp /* pop parameter */
-8:
- movl %ebx,%esp /* get old stack (from callee-saves reg) */
-#else /* MACH_KDB || MACH_KGDB */
- pushl %esp /* pass parameter */
- call EXT(kernel_trap) /* to kernel trap routine */
- addl $4,%esp /* pop parameter */
-#endif /* MACH_KDB || MACH_KGDB */
-
-#if MACH_RT
- CPU_NUMBER(%edx)
-
- movl CX(EXT(need_ast),%edx),%eax /* get pending asts */
- testl $ AST_URGENT,%eax /* any urgent preemption? */
- je EXT(return_from_kernel) /* no, nothing to do */
- cmpl $0,EXT(preemptable) /* kernel-mode, preemption enabled? */
- je EXT(return_from_kernel) /* no, skip it */
- cmpl $ T_PREEMPT,48(%esp) /* preempt request? */
- jne EXT(return_from_kernel) /* no, nothing to do */
- movl CX(EXT(kernel_stack),%edx),%eax
- movl %esp,%ecx
- xorl %eax,%ecx
- andl $(-KERNEL_STACK_SIZE),%ecx
- testl %ecx,%ecx /* are we on the kernel stack? */
- jne EXT(return_from_kernel) /* no, skip it */
-
-#if PREEMPT_DEBUG_LOG
- pushl 28(%esp) /* stack pointer */
- pushl 24+4(%esp) /* frame pointer */
- pushl 56+8(%esp) /* stack pointer */
- pushl $0f
- call EXT(log_thread_action)
- addl $16, %esp
- .data
-0: String "trap preempt eip"
- .text
-#endif /* PREEMPT_DEBUG_LOG */
-
- pushl $1 /* push preemption flag */
- call EXT(i386_astintr) /* take the AST */
- addl $4,%esp /* pop preemption flag */
-#endif /* MACH_RT */
-
- jmp EXT(return_from_kernel)
-
-/*
- * Called as a function, makes the current thread
- * return from the kernel as if from an exception.
- */
+ movl 8+S_ARG3,%edi /* get OUT len ptr */
+ cmpl $0,%edi
+ jz copystr_ret /* if null, just return */
+ subl 8+S_ARG0,%esi
+ movl %esi,(%edi) /* else set OUT arg to xfer len */
+copystr_ret:
+ popl %edi /* restore registers */
+ popl %esi
+ ret /* and return */
- .globl EXT(thread_exception_return)
- .globl EXT(thread_bootstrap_return)
-LEXT(thread_exception_return)
-LEXT(thread_bootstrap_return)
- movl %esp,%ecx /* get kernel stack */
- or $(KERNEL_STACK_SIZE-1),%ecx
- movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
- jmp EXT(return_from_trap)
+copystr_fail:
+ movl $(EFAULT),%eax /* return error for failure */
+ jmp copystr_ret /* pop frame and return */
-Entry(call_continuation)
- movl S_ARG0,%eax /* get continuation */
- movl %esp,%ecx /* get kernel stack */
- or $(KERNEL_STACK_SIZE-1),%ecx
- addl $(-3-IKS_SIZE),%ecx
- movl %ecx,%esp /* pop the stack */
- xorl %ebp,%ebp /* zero frame pointer */
- jmp *%eax /* goto continuation */
-
-#if 0
-#define LOG_INTERRUPT(info,msg) \
- pushal ; \
- pushl msg ; \
- pushl info ; \
- call EXT(log_thread_action) ; \
- add $8,%esp ; \
- popal
-#define CHECK_INTERRUPT_TIME(n) \
- pushal ; \
- pushl $n ; \
- call EXT(check_thread_time) ; \
- add $4,%esp ; \
- popal
-#else
-#define LOG_INTERRUPT(info,msg)
-#define CHECK_INTERRUPT_TIME(n)
-#endif
-
-imsg_start:
- String "interrupt start"
-imsg_end:
- String "interrupt end"
/*
- * All interrupts enter here.
- * old %eax on stack; interrupt number in %eax.
+ * Copy to user/kern address space.
+ * arg0: kernel address
+ * arg1: window offset or kernel address
+ * arg2: byte count
*/
-Entry(all_intrs)
- pushl %ecx /* save registers */
- pushl %edx
- cld /* clear direction flag */
-
- cmpl %ss:EXT(int_stack_high),%esp /* on an interrupt stack? */
- jb int_from_intstack /* if not: */
-
- pushl %ds /* save segment registers */
- pushl %es
- mov %ss,%dx /* switch to kernel segments */
- mov %dx,%ds
- mov %dx,%es
- mov $ CPU_DATA,%dx
- mov %dx,%gs
-
- CPU_NUMBER(%edx)
-
- movl CX(EXT(int_stack_top),%edx),%ecx
- movl 20(%esp),%edx /* get eip */
- xchgl %ecx,%esp /* switch to interrupt stack */
-
-#if STAT_TIME
- pushl %ecx /* save pointer to old stack */
-#else
- pushl %ebx /* save %ebx - out of the way */
- /* so stack looks the same */
- pushl %ecx /* save pointer to old stack */
- TIME_INT_ENTRY /* do timing */
-#endif
+ENTRY(copyoutphys_user)
+ movl $(USER_WINDOW_SEL),%ecx /* user data segment access through kernel window */
+ mov %cx,%es
- pushl %edx /* pass eip to pe_incoming_interrupt */
-
-#if MACH_RT
- movl $ CPD_PREEMPTION_LEVEL,%edx
- incl %gs:(%edx)
-#endif /* MACH_RT */
+ENTRY(copyoutphys_kern)
+ movl $(PHYS_WINDOW_SEL),%ecx /* physical access through kernel window */
+ mov %cx,%ds
+ jmp copyout_common
- movl $ CPD_INTERRUPT_LEVEL,%edx
- incl %gs:(%edx)
+ENTRY(copyout_user)
+ movl $(USER_WINDOW_SEL),%ecx /* user data segment access through kernel window */
+ mov %cx,%es
- pushl %eax /* Push trap number */
- call EXT(PE_incoming_interrupt) /* call generic interrupt routine */
- addl $8,%esp /* Pop trap number and eip */
+ENTRY(copyout_kern)
- .globl EXT(return_to_iret)
-LEXT(return_to_iret) /* (label for kdb_kintr and hardclock) */
+copyout_common:
+ pushl %esi
+ pushl %edi /* save registers */
- movl $ CPD_INTERRUPT_LEVEL,%edx
- decl %gs:(%edx)
+ movl 8+S_ARG0,%esi /* get source - kernel address */
+ movl 8+S_ARG1,%edi /* get destination - window offset or kernel address */
+ movl 8+S_ARG2,%edx /* get count */
-#if MACH_RT
- movl $ CPD_PREEMPTION_LEVEL,%edx
- decl %gs:(%edx)
-#endif /* MACH_RT */
+ cld /* count up */
+ movl %edx,%ecx /* move by longwords first */
+ shrl $2,%ecx
+ RECOVERY_SECTION
+ RECOVER(copyout_fail)
+ rep
+ movsl
+ movl %edx,%ecx /* now move remaining bytes */
+ andl $3,%ecx
+ RECOVERY_SECTION
+ RECOVER(copyout_fail)
+ rep
+ movsb /* move */
+ xorl %eax,%eax /* return 0 for success */
+copyout_ret:
+ mov %ss,%cx /* restore kernel segment */
+ mov %cx,%es
+ mov %cx,%ds
-#if STAT_TIME
-#else
- TIME_INT_EXIT /* do timing */
- movl 4(%esp),%ebx /* restore the extra reg we saved */
-#endif
+ popl %edi /* restore registers */
+ popl %esi
+ ret /* and return */
- popl %esp /* switch back to old stack */
-
- CPU_NUMBER(%edx)
- movl CX(EXT(need_ast),%edx),%eax
- testl %eax,%eax /* any pending asts? */
- je 1f /* no, nothing to do */
- testl $(EFL_VM),I_EFL(%esp) /* if in V86 */
- jnz ast_from_interrupt /* take it */
- testb $3,I_CS(%esp) /* user mode, */
- jnz ast_from_interrupt /* take it */
-#ifdef FIXME
- cmpl ETEXT_ADDR,I_EIP(%esp) /* if within kernel-loaded task, */
- jnb ast_from_interrupt /* take it */
-#endif
+copyout_fail:
+ movl $(EFAULT),%eax /* return error for failure */
+ jmp copyout_ret /* pop frame and return */
-#if MACH_RT
- cmpl $0,EXT(preemptable) /* kernel-mode, preemption enabled? */
- je 1f /* no, skip it */
- movl $ CPD_PREEMPTION_LEVEL,%ecx
- cmpl $0,%gs:(%ecx) /* preemption masked? */
- jne 1f /* yes, skip it */
- testl $ AST_URGENT,%eax /* any urgent requests? */
- je 1f /* no, skip it */
- cmpl $ EXT(locore_end),I_EIP(%esp) /* are we in locore code? */
- jb 1f /* yes, skip it */
- movl CX(EXT(kernel_stack),%edx),%eax
- movl %esp,%ecx
- xorl %eax,%ecx
- andl $(-KERNEL_STACK_SIZE),%ecx
- testl %ecx,%ecx /* are we on the kernel stack? */
- jne 1f /* no, skip it */
/*
- * Take an AST from kernel space. We don't need (and don't want)
- * to do as much as the case where the interrupt came from user
- * space.
+ * io register must not be used on slaves (no AT bus)
*/
-#if PREEMPT_DEBUG_LOG
- pushl $0
- pushl $0
- pushl I_EIP+8(%esp)
- pushl $0f
- call EXT(log_thread_action)
- addl $16, %esp
- .data
-0: String "intr preempt eip"
- .text
-#endif /* PREEMPT_DEBUG_LOG */
-
- sti
- pushl $1 /* push preemption flag */
- call EXT(i386_astintr) /* take the AST */
- addl $4,%esp /* pop preemption flag */
-#endif /* MACH_RT */
+#define ILL_ON_SLAVE
-1:
- pop %es /* restore segment regs */
- pop %ds
- pop %edx
- pop %ecx
- pop %eax
- iret /* return to caller */
-
-int_from_intstack:
-#if MACH_RT
- movl $ CPD_PREEMPTION_LEVEL,%edx
- incl %gs:(%edx)
-#endif /* MACH_RT */
-
- movl $ CPD_INTERRUPT_LEVEL,%edx
- incl %gs:(%edx)
-
- movl 12(%esp),%edx
- pushl %edx /* push eip */
-
- pushl %eax /* Push trap number */
- call EXT(PE_incoming_interrupt)
- addl $4,%esp /* pop eip */
+#if MACH_ASSERT
-LEXT(return_to_iret_i) /* ( label for kdb_kintr) */
+#define ARG0 B_ARG0
+#define ARG1 B_ARG1
+#define ARG2 B_ARG2
+#define PUSH_FRAME FRAME
+#define POP_FRAME EMARF
- addl $4,%esp /* pop trap number */
+#else /* MACH_ASSERT */
- movl $ CPD_INTERRUPT_LEVEL,%edx
- decl %gs:(%edx)
+#define ARG0 S_ARG0
+#define ARG1 S_ARG1
+#define ARG2 S_ARG2
+#define PUSH_FRAME
+#define POP_FRAME
-#if MACH_RT
- movl $ CPD_PREEMPTION_LEVEL,%edx
- decl %gs:(%edx)
-#endif /* MACH_RT */
+#endif /* MACH_ASSERT */
- pop %edx /* must have been on kernel segs */
- pop %ecx
- pop %eax /* no ASTs */
- iret
/*
- * Take an AST from an interrupt.
- * On PCB stack.
- * sp-> es -> edx
- * ds -> ecx
- * edx -> eax
- * ecx -> trapno
- * eax -> code
- * eip
- * cs
- * efl
- * esp
- * ss
+ * int rdmsr_carefully(uint32_t msr, uint32_t *lo, uint32_t *hi)
*/
-ast_from_interrupt:
- pop %es /* restore all registers ... */
- pop %ds
- popl %edx
- popl %ecx
- popl %eax
- sti /* Reenable interrupts */
- pushl $0 /* zero code */
- pushl $0 /* zero trap number */
- pusha /* save general registers */
- push %ds /* save segment registers */
- push %es
- push %fs
- push %gs
- mov %ss,%dx /* switch to kernel segments */
- mov %dx,%ds
- mov %dx,%es
- mov $ CPU_DATA,%dx
- mov %dx,%gs
-
- /*
- * See if we interrupted a kernel-loaded thread executing
- * in its own task.
- */
- CPU_NUMBER(%edx)
- testl $(EFL_VM),R_EFLAGS(%esp) /* in V86 mode? */
- jnz 0f /* user mode trap if so */
- testb $3,R_CS(%esp)
- jnz 0f /* user mode, back to normal */
-#ifdef FIXME
- cmpl ETEXT_ADDR,R_EIP(%esp)
- jb 0f /* not kernel-loaded, back to normal */
-#endif
+ENTRY(rdmsr_carefully)
+ movl S_ARG0, %ecx
+ RECOVERY_SECTION
+ RECOVER(rdmsr_fail)
+ rdmsr
+ movl S_ARG1, %ecx
+ movl %eax, (%ecx)
+ movl S_ARG2, %ecx
+ movl %edx, (%ecx)
+ movl $0, %eax
+ ret
- /*
- * Transfer the current stack frame by hand into the PCB.
- */
- CAH(afistart)
- movl CX(EXT(active_kloaded),%edx),%eax
- movl CX(EXT(kernel_stack),%edx),%ebx
- xchgl %ebx,%esp
- FRAME_STACK_TO_PCB(%eax,%ebx)
- CAH(afiend)
- TIME_TRAP_UENTRY
- jmp 3f
-0:
- TIME_TRAP_UENTRY
+rdmsr_fail:
+ movl $1, %eax
+ ret
- movl CX(EXT(kernel_stack),%edx),%eax
- /* switch to kernel stack */
- xchgl %eax,%esp
-3:
- pushl %eax
- pushl $0 /* push preemption flag */
- call EXT(i386_astintr) /* take the AST */
- addl $4,%esp /* pop preemption flag */
- popl %esp /* back to PCB stack */
- jmp EXT(return_from_trap) /* return */
-
-#if MACH_KDB || MACH_KGDB
/*
- * kdb_kintr: enter kdb from keyboard interrupt.
- * Chase down the stack frames until we find one whose return
- * address is the interrupt handler. At that point, we have:
- *
- * frame-> saved %ebp
- * return address in interrupt handler
- * ivect
- * saved SPL
- * return address == return_to_iret_i
- * saved %edx
- * saved %ecx
- * saved %eax
- * saved %eip
- * saved %cs
- * saved %efl
- *
- * OR:
- * frame-> saved %ebp
- * return address in interrupt handler
- * ivect
- * saved SPL
- * return address == return_to_iret
- * pointer to save area on old stack
- * [ saved %ebx, if accurate timing ]
- *
- * old stack: saved %es
- * saved %ds
- * saved %edx
- * saved %ecx
- * saved %eax
- * saved %eip
- * saved %cs
- * saved %efl
- *
- * Call kdb, passing it that register save area.
+ * Done with recovery table.
*/
-
-#if MACH_KGDB
-Entry(kgdb_kintr)
-#endif /* MACH_KGDB */
-#if MACH_KDB
-Entry(kdb_kintr)
-#endif /* MACH_KDB */
- movl %ebp,%eax /* save caller`s frame pointer */
- movl $ EXT(return_to_iret),%ecx /* interrupt return address 1 */
- movl $ EXT(return_to_iret_i),%edx /* interrupt return address 2 */
-
-0: cmpl 16(%eax),%ecx /* does this frame return to */
- /* interrupt handler (1)? */
- je 1f
- cmpl $kdb_from_iret,16(%eax)
- je 1f
- cmpl 16(%eax),%edx /* interrupt handler (2)? */
- je 2f /* if not: */
- cmpl $kdb_from_iret_i,16(%eax)
- je 2f
- movl (%eax),%eax /* try next frame */
- jmp 0b
-
-1: movl $kdb_from_iret,16(%eax) /* returns to kernel/user stack */
- ret
-
-2: movl $kdb_from_iret_i,16(%eax)
- /* returns to interrupt stack */
- ret
+ RECOVERY_SECTION
+ RECOVER_TABLE_END
/*
- * On return from keyboard interrupt, we will execute
- * kdb_from_iret_i
- * if returning to an interrupt on the interrupt stack
- * kdb_from_iret
- * if returning to an interrupt on the user or kernel stack
- */
-kdb_from_iret:
- /* save regs in known locations */
-#if STAT_TIME
- pushl %ebx /* caller`s %ebx is in reg */
-#else
- movl 4(%esp),%eax /* get caller`s %ebx */
- pushl %eax /* push on stack */
-#endif
- pushl %ebp
- pushl %esi
- pushl %edi
- push %fs
- push %gs
-#if MACH_KGDB
- cli
- pushl %esp /* pass regs */
- call EXT(kgdb_kentry) /* to kgdb */
- addl $4,%esp /* pop parameters */
-#endif /* MACH_KGDB */
-#if MACH_KDB
- pushl %esp /* pass regs */
- call EXT(kdb_kentry) /* to kdb */
- addl $4,%esp /* pop parameters */
-#endif /* MACH_KDB */
- pop %gs /* restore registers */
- pop %fs
- popl %edi
- popl %esi
- popl %ebp
-#if STAT_TIME
- popl %ebx
-#else
- popl %eax
- movl %eax,4(%esp)
-#endif
- jmp EXT(return_to_iret) /* normal interrupt return */
-
-kdb_from_iret_i: /* on interrupt stack */
- pop %edx /* restore saved registers */
- pop %ecx
- pop %eax
- pushl $0 /* zero error code */
- pushl $0 /* zero trap number */
- pusha /* save general registers */
- push %ds /* save segment registers */
- push %es
- push %fs
- push %gs
-#if MACH_KGDB
- cli /* disable interrupts */
- CPU_NUMBER(%edx) /* get CPU number */
- movl CX(EXT(kgdb_stacks),%edx),%ebx
- xchgl %ebx,%esp /* switch to kgdb stack */
- pushl %ebx /* pass old sp as an arg */
- call EXT(kgdb_from_kernel)
- popl %esp /* switch back to interrupt stack */
-#endif /* MACH_KGDB */
-#if MACH_KDB
- pushl %esp /* pass regs, */
- pushl $0 /* code, */
- pushl $-1 /* type to kdb */
- call EXT(kdb_trap)
- addl $12,%esp
-#endif /* MACH_KDB */
- pop %gs /* restore segment registers */
- pop %fs
- pop %es
- pop %ds
- popa /* restore general registers */
- addl $8,%esp
- iret
-
-#endif /* MACH_KDB || MACH_KGDB */
-
-
-/*
- * Mach RPC enters through a call gate, like a system call.
- */
-
-Entry(mach_rpc)
- pushf /* save flags as soon as possible */
- pushl %eax /* save system call number */
- pushl $0 /* clear trap number slot */
-
- pusha /* save the general registers */
- pushl %ds /* and the segment registers */
- pushl %es
- pushl %fs
- pushl %gs
-
- mov %ss,%dx /* switch to kernel data segment */
- mov %dx,%ds
- mov %dx,%es
- mov $ CPU_DATA,%dx
- mov %dx,%gs
-
-/*
- * Shuffle eflags,eip,cs into proper places
- */
-
- movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
- movl R_CS(%esp),%ecx /* eip is in CS slot */
- movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
- movl %ecx,R_EIP(%esp) /* fix eip */
- movl %edx,R_CS(%esp) /* fix cs */
- movl %ebx,R_EFLAGS(%esp) /* fix eflags */
-
- CPU_NUMBER(%edx)
- TIME_TRAP_UENTRY
-
- negl %eax /* get system call number */
- shll $4,%eax /* manual indexing */
-
-/*
- * Check here for mach_rpc from kernel-loaded task --
- * - Note that kernel-loaded task returns via real return.
- * We didn't enter here "through" PCB (i.e., using ring 0 stack),
- * so transfer the stack frame into the PCB explicitly, then
- * start running on resulting "PCB stack". We have to set
- * up a simulated "uesp" manually, since there's none in the
- * frame.
- */
- cmpl $0,CX(EXT(active_kloaded),%edx)
- jz 2f
- CAH(mrstart)
- movl CX(EXT(active_kloaded),%edx),%ebx
- movl CX(EXT(kernel_stack),%edx),%edx
- xchgl %edx,%esp
-
- FRAME_STACK_TO_PCB(%ebx,%edx)
- CAH(mrend)
-
- CPU_NUMBER(%edx)
- jmp 3f
-
-2:
- CPU_NUMBER(%edx)
- movl CX(EXT(kernel_stack),%edx),%ebx
- /* get current kernel stack */
- xchgl %ebx,%esp /* switch stacks - %ebx points to */
- /* user registers. */
-
-3:
-
-/*
- * Register use on entry:
- * eax contains syscall number
- * ebx contains user regs pointer
- */
-#undef RPC_TRAP_REGISTERS
-#ifdef RPC_TRAP_REGISTERS
- pushl R_ESI(%ebx)
- pushl R_EDI(%ebx)
- pushl R_ECX(%ebx)
- pushl R_EDX(%ebx)
-#else
- movl EXT(mach_trap_table)(%eax),%ecx
- /* get number of arguments */
- jecxz 2f /* skip argument copy if none */
- movl R_UESP(%ebx),%esi /* get user stack pointer */
- lea 4(%esi,%ecx,4),%esi /* skip user return address, */
- /* and point past last argument */
- /* edx holds cpu number from above */
- movl CX(EXT(active_kloaded),%edx),%edx
- /* point to current thread */
- orl %edx,%edx /* if ! kernel-loaded, check addr */
- jz 4f /* else */
- mov %ds,%dx /* kernel data segment access */
- jmp 5f
-4:
- cmpl $(VM_MAX_ADDRESS),%esi /* in user space? */
- ja mach_call_addr /* address error if not */
- movl $ USER_DS,%edx /* user data segment access */
-5:
- mov %dx,%fs
- movl %esp,%edx /* save kernel ESP for error recovery */
-1:
- subl $4,%esi
- RECOVERY_SECTION
- RECOVER(mach_call_addr_push)
- pushl %fs:(%esi) /* push argument on stack */
- loop 1b /* loop for all arguments */
-#endif
-
-/*
- * Register use on entry:
- * eax contains syscall number
- * ebx contains user regs pointer
- */
-2:
- CAH(call_call)
- call *EXT(mach_trap_table)+4(%eax)
- /* call procedure */
- movl %esp,%ecx /* get kernel stack */
- or $(KERNEL_STACK_SIZE-1),%ecx
- movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
- movl %eax,R_EAX(%esp) /* save return value */
- jmp EXT(return_from_trap) /* return to user */
-
-
-/*
- * Special system call entry for "int 0x80", which has the "eflags"
- * register saved at the right place already.
- * Fall back to the common syscall path after saving the registers.
- *
- * esp -> old eip
- * old cs
- * old eflags
- * old esp if trapped from user
- * old ss if trapped from user
- *
- * XXX: for the moment, we don't check for int 0x80 from kernel mode.
- */
-Entry(syscall_int80)
- pushl %eax /* save system call number */
- pushl $0 /* clear trap number slot */
-
- pusha /* save the general registers */
- pushl %ds /* and the segment registers */
- pushl %es
- pushl %fs
- pushl %gs
-
- mov %ss,%dx /* switch to kernel data segment */
- mov %dx,%ds
- mov %dx,%es
- mov $ CPU_DATA,%dx
- mov %dx,%gs
-
- jmp syscall_entry_3
-
-/*
- * System call enters through a call gate. Flags are not saved -
- * we must shuffle stack to look like trap save area.
- *
- * esp-> old eip
- * old cs
- * old esp
- * old ss
- *
- * eax contains system call number.
- *
- * NB: below use of CPU_NUMBER assumes that macro will use correct
- * correct segment register for any kernel data accesses.
- */
-Entry(syscall)
-syscall_entry:
- pushf /* save flags as soon as possible */
-syscall_entry_2:
- pushl %eax /* save system call number */
- pushl $0 /* clear trap number slot */
-
- pusha /* save the general registers */
- pushl %ds /* and the segment registers */
- pushl %es
- pushl %fs
- pushl %gs
-
- mov %ss,%dx /* switch to kernel data segment */
- mov %dx,%ds
- mov %dx,%es
- mov $ CPU_DATA,%dx
- mov %dx,%gs
-
-/*
- * Shuffle eflags,eip,cs into proper places
- */
-
- movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
- movl R_CS(%esp),%ecx /* eip is in CS slot */
- movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
- movl %ecx,R_EIP(%esp) /* fix eip */
- movl %edx,R_CS(%esp) /* fix cs */
- movl %ebx,R_EFLAGS(%esp) /* fix eflags */
-
-syscall_entry_3:
- CPU_NUMBER(%edx)
-/*
- * Check here for syscall from kernel-loaded task --
- * We didn't enter here "through" PCB (i.e., using ring 0 stack),
- * so transfer the stack frame into the PCB explicitly, then
- * start running on resulting "PCB stack". We have to set
- * up a simulated "uesp" manually, since there's none in the
- * frame.
- */
- cmpl $0,CX(EXT(active_kloaded),%edx)
- jz 0f
- CAH(scstart)
- movl CX(EXT(active_kloaded),%edx),%ebx
- movl CX(EXT(kernel_stack),%edx),%edx
- xchgl %edx,%esp
- FRAME_STACK_TO_PCB(%ebx,%edx)
- CAH(scend)
- TIME_TRAP_UENTRY
- CPU_NUMBER(%edx)
- jmp 1f
-
-0:
- TIME_TRAP_UENTRY
-
- CPU_NUMBER(%edx)
- movl CX(EXT(kernel_stack),%edx),%ebx
- /* get current kernel stack */
- xchgl %ebx,%esp /* switch stacks - %ebx points to */
- /* user registers. */
- /* user regs pointer already set */
-
-/*
- * Check for MACH or emulated system call
- * Register use (from here till we begin processing call):
- * eax contains system call number
- * ebx points to user regs
- */
-1:
- movl $ CPD_ACTIVE_THREAD,%edx
- movl %gs:(%edx),%edx /* get active thread */
- /* point to current thread */
- movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */
- movl ACT_TASK(%edx),%edx /* point to task */
- movl TASK_EMUL(%edx),%edx /* get emulation vector */
- orl %edx,%edx /* if none, */
- je syscall_native /* do native system call */
- movl %eax,%ecx /* copy system call number */
- subl DISP_MIN(%edx),%ecx /* get displacement into syscall */
- /* vector table */
- jl syscall_native /* too low - native system call */
- cmpl DISP_COUNT(%edx),%ecx /* check range */
- jnl syscall_native /* too high - native system call */
- movl DISP_VECTOR(%edx,%ecx,4),%edx
- /* get the emulation vector */
- orl %edx,%edx /* emulated system call if not zero */
- jnz syscall_emul
-
-/*
- * Native system call.
- * Register use on entry:
- * eax contains syscall number
- * ebx points to user regs
- */
-syscall_native:
- negl %eax /* get system call number */
- jl mach_call_range /* out of range if it was positive */
-
- cmpl EXT(mach_trap_count),%eax /* check system call table bounds */
- jg mach_call_range /* error if out of range */
- shll $4,%eax /* manual indexing */
-
- movl EXT(mach_trap_table)+4(%eax),%edx
- /* get procedure */
- cmpl $ EXT(kern_invalid),%edx /* if not "kern_invalid" */
- jne do_native_call /* go on with Mach syscall */
-
- movl $ CPD_ACTIVE_THREAD,%edx
- movl %gs:(%edx),%edx /* get active thread */
- /* point to current thread */
- movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */
- movl ACT_TASK(%edx),%edx /* point to task */
- movl TASK_EMUL(%edx),%edx /* get emulation vector */
- orl %edx,%edx /* if it exists, */
- jne do_native_call /* do native system call */
- shrl $4,%eax /* restore syscall number */
- jmp mach_call_range /* try it as a "server" syscall */
-
-/*
- * Register use on entry:
- * eax contains syscall number
- * ebx contains user regs pointer
- */
-do_native_call:
- movl EXT(mach_trap_table)(%eax),%ecx
- /* get number of arguments */
- jecxz mach_call_call /* skip argument copy if none */
- movl R_UESP(%ebx),%esi /* get user stack pointer */
- lea 4(%esi,%ecx,4),%esi /* skip user return address, */
- /* and point past last argument */
- CPU_NUMBER(%edx)
- movl CX(EXT(active_kloaded),%edx),%edx
- /* point to current thread */
- orl %edx,%edx /* if kernel-loaded, skip addr check */
- jz 0f /* else */
- mov %ds,%dx /* kernel data segment access */
- jmp 1f
-0:
- cmpl $(VM_MAX_ADDRESS),%esi /* in user space? */
- ja mach_call_addr /* address error if not */
- movl $ USER_DS,%edx /* user data segment access */
-1:
- mov %dx,%fs
- movl %esp,%edx /* save kernel ESP for error recovery */
-2:
- subl $4,%esi
- RECOVERY_SECTION
- RECOVER(mach_call_addr_push)
- pushl %fs:(%esi) /* push argument on stack */
- loop 2b /* loop for all arguments */
-
-/*
- * Register use on entry:
- * eax contains syscall number
- * ebx contains user regs pointer
- */
-mach_call_call:
-
- CAH(call_call)
-
-#if ETAP_EVENT_MONITOR
- cmpl $0x200, %eax /* is this mach_msg? */
- jz make_syscall /* if yes, don't record event */
-
- pushal /* Otherwise: save registers */
- pushl %eax /* push syscall number on stack*/
- call EXT(etap_machcall_probe1) /* call event begin probe */
- add $4,%esp /* restore stack */
- popal /* restore registers */
-
- call *EXT(mach_trap_table)+4(%eax) /* call procedure */
- pushal
- call EXT(etap_machcall_probe2) /* call event end probe */
- popal
- jmp skip_syscall /* syscall already made */
-#endif /* ETAP_EVENT_MONITOR */
-
-make_syscall:
- call *EXT(mach_trap_table)+4(%eax) /* call procedure */
-skip_syscall:
-
- movl %esp,%ecx /* get kernel stack */
- or $(KERNEL_STACK_SIZE-1),%ecx
- movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
- movl %eax,R_EAX(%esp) /* save return value */
- jmp EXT(return_from_trap) /* return to user */
-
-/*
- * Address out of range. Change to page fault.
- * %esi holds failing address.
- * Register use on entry:
- * ebx contains user regs pointer
- */
-mach_call_addr_push:
- movl %edx,%esp /* clean parameters from stack */
-mach_call_addr:
- movl %esi,R_CR2(%ebx) /* set fault address */
- movl $(T_PAGE_FAULT),R_TRAPNO(%ebx)
- /* set page-fault trap */
- movl $(T_PF_USER),R_ERR(%ebx)
- /* set error code - read user space */
- CAH(call_addr)
- jmp EXT(take_trap) /* treat as a trap */
-
-/*
- * System call out of range. Treat as invalid-instruction trap.
- * (? general protection?)
- * Register use on entry:
- * eax contains syscall number
- */
-mach_call_range:
- movl $ CPD_ACTIVE_THREAD,%edx
- movl %gs:(%edx),%edx /* get active thread */
-
- movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */
- movl ACT_TASK(%edx),%edx /* point to task */
- movl TASK_EMUL(%edx),%edx /* get emulation vector */
- orl %edx,%edx /* if emulator, */
- jne EXT(syscall_failed) /* handle as illegal instruction */
- /* else generate syscall exception: */
- push %eax
- movl %esp,%edx
- push $1 /* code_cnt = 1 */
- push %edx /* exception_type_t (see i/f docky) */
- push $ EXC_SYSCALL
- CAH(call_range)
- call EXT(exception)
- /* no return */
-
- .globl EXT(syscall_failed)
-LEXT(syscall_failed)
- movl %esp,%ecx /* get kernel stack */
- or $(KERNEL_STACK_SIZE-1),%ecx
- movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
- CPU_NUMBER(%edx)
- movl CX(EXT(kernel_stack),%edx),%ebx
- /* get current kernel stack */
- xchgl %ebx,%esp /* switch stacks - %ebx points to */
- /* user registers. */
- /* user regs pointer already set */
-
- movl $(T_INVALID_OPCODE),R_TRAPNO(%ebx)
- /* set invalid-operation trap */
- movl $0,R_ERR(%ebx) /* clear error code */
- CAH(failed)
- jmp EXT(take_trap) /* treat as a trap */
-
-/*
- * User space emulation of system calls.
- * edx - user address to handle syscall
- *
- * User stack will become:
- * uesp-> eflags
- * eip
- * Register use on entry:
- * ebx contains user regs pointer
- * edx contains emulator vector address
- */
-syscall_emul:
- movl R_UESP(%ebx),%edi /* get user stack pointer */
- CPU_NUMBER(%eax)
- movl CX(EXT(active_kloaded),%eax),%eax
- orl %eax,%eax /* if thread not kernel-loaded, */
- jz 0f /* do address checks */
- subl $8,%edi
- mov %ds,%ax /* kernel data segment access */
- jmp 1f /* otherwise, skip them */
-0:
- cmpl $(VM_MAX_ADDRESS),%edi /* in user space? */
- ja syscall_addr /* address error if not */
- subl $8,%edi /* push space for new arguments */
- cmpl $(VM_MIN_ADDRESS),%edi /* still in user space? */
- jb syscall_addr /* error if not */
- movl $ USER_DS,%ax /* user data segment access */
-1:
- mov %ax,%fs
- movl R_EFLAGS(%ebx),%eax /* move flags */
- RECOVERY_SECTION
- RECOVER(syscall_addr)
- movl %eax,%fs:0(%edi) /* to user stack */
- movl R_EIP(%ebx),%eax /* move eip */
- RECOVERY_SECTION
- RECOVER(syscall_addr)
- movl %eax,%fs:4(%edi) /* to user stack */
- movl %edi,R_UESP(%ebx) /* set new user stack pointer */
- movl %edx,R_EIP(%ebx) /* change return address to trap */
- movl %ebx,%esp /* back to PCB stack */
- CAH(emul)
- jmp EXT(return_from_trap) /* return to user */
-
-
-/*
- * Address error - address is in %edi.
- * Register use on entry:
- * ebx contains user regs pointer
- */
-syscall_addr:
- movl %edi,R_CR2(%ebx) /* set fault address */
- movl $(T_PAGE_FAULT),R_TRAPNO(%ebx)
- /* set page-fault trap */
- movl $(T_PF_USER),R_ERR(%ebx)
- /* set error code - read user space */
- CAH(addr)
- jmp EXT(take_trap) /* treat as a trap */
-
-/*\f*/
-/*
- * Utility routines.
- */
-
-
-/*
- * Copy from user address space.
- * arg0: user address
- * arg1: kernel address
- * arg2: byte count
- */
-Entry(copyinmsg)
-ENTRY(copyin)
- pushl %esi
- pushl %edi /* save registers */
-
- movl 8+S_ARG0,%esi /* get user start address */
- movl 8+S_ARG1,%edi /* get kernel destination address */
- movl 8+S_ARG2,%edx /* get count */
-
- lea 0(%esi,%edx),%eax /* get user end address + 1 */
-
- movl $ CPD_ACTIVE_THREAD,%ecx
- movl %gs:(%ecx),%ecx /* get active thread */
- movl TH_TOP_ACT(%ecx),%ecx /* get thread->top_act */
- movl ACT_MAP(%ecx),%ecx /* get act->map */
- movl MAP_PMAP(%ecx),%ecx /* get map->pmap */
- cmpl EXT(kernel_pmap), %ecx
- jz 1f
- movl $ USER_DS,%cx /* user data segment access */
- mov %cx,%ds
-1:
- cmpl %esi,%eax
- jb copyin_fail /* fail if wrap-around */
- cld /* count up */
- movl %edx,%ecx /* move by longwords first */
- shrl $2,%ecx
- RECOVERY_SECTION
- RECOVER(copyin_fail)
- rep
- movsl /* move longwords */
- movl %edx,%ecx /* now move remaining bytes */
- andl $3,%ecx
- RECOVERY_SECTION
- RECOVER(copyin_fail)
- rep
- movsb
- xorl %eax,%eax /* return 0 for success */
-copy_ret:
- mov %ss,%di /* restore kernel data segment */
- mov %di,%ds
-
- popl %edi /* restore registers */
- popl %esi
- ret /* and return */
-
-copyin_fail:
- movl $ EFAULT,%eax /* return error for failure */
- jmp copy_ret /* pop frame and return */
-
-/*
- * Copy string from user address space.
- * arg0: user address
- * arg1: kernel address
- * arg2: max byte count
- * arg3: actual byte count (OUT)
- */
-Entry(copyinstr)
- pushl %esi
- pushl %edi /* save registers */
-
- movl 8+S_ARG0,%esi /* get user start address */
- movl 8+S_ARG1,%edi /* get kernel destination address */
- movl 8+S_ARG2,%edx /* get count */
-
- lea 0(%esi,%edx),%eax /* get user end address + 1 */
-
- movl $ CPD_ACTIVE_THREAD,%ecx
- movl %gs:(%ecx),%ecx /* get active thread */
- movl TH_TOP_ACT(%ecx),%ecx /* get thread->top_act */
- movl ACT_MAP(%ecx),%ecx /* get act->map */
- movl MAP_PMAP(%ecx),%ecx /* get map->pmap */
- cmpl EXT(kernel_pmap), %ecx
- jne 0f
- mov %ds,%cx /* kernel data segment access */
- jmp 1f
-0:
- movl $ USER_DS,%cx /* user data segment access */
-1:
- mov %cx,%fs
- xorl %eax,%eax
- cmpl $0,%edx
- je 4f
-2:
- RECOVERY_SECTION
- RECOVER(copystr_fail) /* copy bytes... */
- movb %fs:(%esi),%eax
- incl %esi
- testl %edi,%edi /* if kernel address is ... */
- jz 3f /* not NULL */
- movb %eax,(%edi) /* copy the byte */
- incl %edi
-3:
- decl %edx
- je 5f /* Zero count.. error out */
- cmpl $0,%eax
- jne 2b /* .. a NUL found? */
- jmp 4f
-5:
- movl $ ENAMETOOLONG,%eax /* String is too long.. */
-4:
- xorl %eax,%eax /* return zero for success */
- movl 8+S_ARG3,%edi /* get OUT len ptr */
- cmpl $0,%edi
- jz copystr_ret /* if null, just return */
- subl 8+S_ARG0,%esi
- movl %esi,(%edi) /* else set OUT arg to xfer len */
-copystr_ret:
- popl %edi /* restore registers */
- popl %esi
- ret /* and return */
-
-copystr_fail:
- movl $ EFAULT,%eax /* return error for failure */
- jmp copy_ret /* pop frame and return */
-
-/*
- * Copy to user address space.
- * arg0: kernel address
- * arg1: user address
- * arg2: byte count
- */
-Entry(copyoutmsg)
-ENTRY(copyout)
- pushl %esi
- pushl %edi /* save registers */
- pushl %ebx
-
- movl 12+S_ARG0,%esi /* get kernel start address */
- movl 12+S_ARG1,%edi /* get user start address */
- movl 12+S_ARG2,%edx /* get count */
-
- leal 0(%edi,%edx),%eax /* get user end address + 1 */
-
- movl $ CPD_ACTIVE_THREAD,%ecx
- movl %gs:(%ecx),%ecx /* get active thread */
- movl TH_TOP_ACT(%ecx),%ecx /* get thread->top_act */
- movl ACT_MAP(%ecx),%ecx /* get act->map */
- movl MAP_PMAP(%ecx),%ecx /* get map->pmap */
- cmpl EXT(kernel_pmap), %ecx
- jne 0f
- mov %ds,%cx /* else kernel data segment access */
- jmp 1f
-0:
- movl $ USER_DS,%cx
-1:
- mov %cx,%es
-
-/*
- * Check whether user address space is writable
- * before writing to it - hardware is broken.
- *
- * Skip check if "user" address is really in
- * kernel space (i.e., if it's in a kernel-loaded
- * task).
- *
- * Register usage:
- * esi/edi source/dest pointers for rep/mov
- * ecx counter for rep/mov
- * edx counts down from 3rd arg
- * eax count of bytes for each (partial) page copy
- * ebx shadows edi, used to adjust edx
- */
- movl %edi,%ebx /* copy edi for syncing up */
-copyout_retry:
- /* if restarting after a partial copy, put edx back in sync, */
- addl %ebx,%edx /* edx -= (edi - ebx); */
- subl %edi,%edx /
- movl %edi,%ebx /* ebx = edi; */
-
- mov %es,%cx
- cmpl $ USER_DS,%cx /* If kernel data segment */
- jnz 0f /* skip check */
-
- cmpb $(CPUID_FAMILY_386), EXT(cpuid_family)
- ja 0f
-
- movl %cr3,%ecx /* point to page directory */
-#if NCPUS > 1
- andl $(~0x7), %ecx /* remove cpu number */
-#endif /* NCPUS > 1 && AT386 */
- movl %edi,%eax /* get page directory bits */
- shrl $(PDESHIFT),%eax /* from user address */
- movl KERNELBASE(%ecx,%eax,4),%ecx
- /* get page directory pointer */
- testl $(PTE_V),%ecx /* present? */
- jz 0f /* if not, fault is OK */
- andl $(PTE_PFN),%ecx /* isolate page frame address */
- movl %edi,%eax /* get page table bits */
- shrl $(PTESHIFT),%eax
- andl $(PTEMASK),%eax /* from user address */
- leal KERNELBASE(%ecx,%eax,4),%ecx
- /* point to page table entry */
- movl (%ecx),%eax /* get it */
- testl $(PTE_V),%eax /* present? */
- jz 0f /* if not, fault is OK */
- testl $(PTE_W),%eax /* writable? */
- jnz 0f /* OK if so */
-/*
- * Not writable - must fake a fault. Turn off access to the page.
- */
- andl $(PTE_INVALID),(%ecx) /* turn off valid bit */
- movl %cr3,%eax /* invalidate TLB */
- movl %eax,%cr3
-0:
-/*
- * Copy only what fits on the current destination page.
- * Check for write-fault again on the next page.
- */
- leal NBPG(%edi),%eax /* point to */
- andl $(-NBPG),%eax /* start of next page */
- subl %edi,%eax /* get number of bytes to that point */
- cmpl %edx,%eax /* bigger than count? */
- jle 1f /* if so, */
- movl %edx,%eax /* use count */
-1:
- cld /* count up */
- movl %eax,%ecx /* move by longwords first */
- shrl $2,%ecx
- RECOVERY_SECTION
- RECOVER(copyout_fail)
- RETRY_SECTION
- RETRY(copyout_retry)
- rep
- movsl
- movl %eax,%ecx /* now move remaining bytes */
- andl $3,%ecx
- RECOVERY_SECTION
- RECOVER(copyout_fail)
- RETRY_SECTION
- RETRY(copyout_retry)
- rep
- movsb /* move */
- movl %edi,%ebx /* copy edi for syncing up */
- subl %eax,%edx /* and decrement count */
- jg copyout_retry /* restart on next page if not done */
- xorl %eax,%eax /* return 0 for success */
-copyout_ret:
- mov %ss,%di /* restore kernel segment */
- mov %di,%es
-
- popl %ebx
- popl %edi /* restore registers */
- popl %esi
- ret /* and return */
-
-copyout_fail:
- movl $ EFAULT,%eax /* return error for failure */
- jmp copyout_ret /* pop frame and return */
-
-/*
- * FPU routines.
- */
-
-/*
- * Initialize FPU.
- */
-ENTRY(_fninit)
- fninit
- ret
-
-/*
- * Read control word
- */
-ENTRY(_fstcw)
- pushl %eax /* get stack space */
- fstcw (%esp)
- popl %eax
- ret
-
-/*
- * Set control word
- */
-ENTRY(_fldcw)
- fldcw 4(%esp)
- ret
-
-/*
- * Read status word
- */
-ENTRY(_fnstsw)
- xor %eax,%eax /* clear high 16 bits of eax */
- fnstsw %ax /* read FP status */
- ret
-
-/*
- * Clear FPU exceptions
- */
-ENTRY(_fnclex)
- fnclex
- ret
-
-/*
- * Clear task-switched flag.
- */
-ENTRY(_clts)
- clts
- ret
-
-/*
- * Save complete FPU state. Save error for later.
- */
-ENTRY(_fpsave)
- movl 4(%esp),%eax /* get save area pointer */
- fnsave (%eax) /* save complete state, including */
- /* errors */
- ret
-
-/*
- * Restore FPU state.
- */
-ENTRY(_fprestore)
- movl 4(%esp),%eax /* get save area pointer */
- frstor (%eax) /* restore complete state */
- ret
-
-/*
- * Set cr3
- */
-ENTRY(set_cr3)
-#if NCPUS > 1
- CPU_NUMBER(%eax)
- orl 4(%esp), %eax
-#else /* NCPUS > 1 && AT386 */
- movl 4(%esp),%eax /* get new cr3 value */
-#endif /* NCPUS > 1 && AT386 */
- /*
- * Don't set PDBR to a new value (hence invalidating the
- * "paging cache") if the new value matches the current one.
- */
- movl %cr3,%edx /* get current cr3 value */
- cmpl %eax,%edx
- je 0f /* if two are equal, don't set */
- movl %eax,%cr3 /* load it (and flush cache) */
-0:
- ret
-
-/*
- * Read cr3
- */
-ENTRY(get_cr3)
- movl %cr3,%eax
-#if NCPUS > 1
- andl $(~0x7), %eax /* remove cpu number */
-#endif /* NCPUS > 1 && AT386 */
- ret
-
-/*
- * Flush TLB
- */
-ENTRY(flush_tlb)
- movl %cr3,%eax /* flush tlb by reloading CR3 */
- movl %eax,%cr3 /* with itself */
- ret
-
-/*
- * Read cr2
- */
-ENTRY(get_cr2)
- movl %cr2,%eax
- ret
-
-/*
- * Read cr4
- */
-ENTRY(get_cr4)
- .byte 0x0f,0x20,0xe0 /* movl %cr4, %eax */
- ret
-
-/*
- * Write cr4
- */
-ENTRY(set_cr4)
- movl 4(%esp), %eax
- .byte 0x0f,0x22,0xe0 /* movl %eax, %cr4 */
- ret
-
-/*
- * Read ldtr
- */
-Entry(get_ldt)
- xorl %eax,%eax
- sldt %ax
- ret
-
-/*
- * Set ldtr
- */
-Entry(set_ldt)
- lldt 4(%esp)
- ret
-
-/*
- * Read task register.
- */
-ENTRY(get_tr)
- xorl %eax,%eax
- str %ax
- ret
-
-/*
- * Set task register. Also clears busy bit of task descriptor.
- */
-ENTRY(set_tr)
- movl S_ARG0,%eax /* get task segment number */
- subl $8,%esp /* push space for SGDT */
- sgdt 2(%esp) /* store GDT limit and base (linear) */
- movl 4(%esp),%edx /* address GDT */
- movb $(K_TSS),5(%edx,%eax) /* fix access byte in task descriptor */
- ltr %ax /* load task register */
- addl $8,%esp /* clear stack */
- ret /* and return */
-
-/*
- * Set task-switched flag.
- */
-ENTRY(_setts)
- movl %cr0,%eax /* get cr0 */
- orl $(CR0_TS),%eax /* or in TS bit */
- movl %eax,%cr0 /* set cr0 */
- ret
-
-/*
- * io register must not be used on slaves (no AT bus)
- */
-#define ILL_ON_SLAVE
-
-
-#if MACH_ASSERT
-
-#define ARG0 B_ARG0
-#define ARG1 B_ARG1
-#define ARG2 B_ARG2
-#define PUSH_FRAME FRAME
-#define POP_FRAME EMARF
-
-#else /* MACH_ASSERT */
-
-#define ARG0 S_ARG0
-#define ARG1 S_ARG1
-#define ARG2 S_ARG2
-#define PUSH_FRAME
-#define POP_FRAME
-
-#endif /* MACH_ASSERT */
-
-
-#if MACH_KDB || MACH_ASSERT
-
-/*
- * Following routines are also defined as macros in i386/pio.h
- * Compile then when MACH_KDB is configured so that they
- * can be invoked from the debugger.
- */
-
-/*
- * void outb(unsigned char *io_port,
- * unsigned char byte)
- *
- * Output a byte to an IO port.
- */
-ENTRY(outb)
- PUSH_FRAME
- ILL_ON_SLAVE
- movl ARG0,%edx /* IO port address */
- movl ARG1,%eax /* data to output */
- outb %al,%dx /* send it out */
- POP_FRAME
- ret
-
-/*
- * unsigned char inb(unsigned char *io_port)
- *
- * Input a byte from an IO port.
- */
-ENTRY(inb)
- PUSH_FRAME
- ILL_ON_SLAVE
- movl ARG0,%edx /* IO port address */
- xor %eax,%eax /* clear high bits of register */
- inb %dx,%al /* get the byte */
- POP_FRAME
- ret
-
-/*
- * void outw(unsigned short *io_port,
- * unsigned short word)
- *
- * Output a word to an IO port.
- */
-ENTRY(outw)
- PUSH_FRAME
- ILL_ON_SLAVE
- movl ARG0,%edx /* IO port address */
- movl ARG1,%eax /* data to output */
- outw %ax,%dx /* send it out */
- POP_FRAME
- ret
-
-/*
- * unsigned short inw(unsigned short *io_port)
- *
- * Input a word from an IO port.
- */
-ENTRY(inw)
- PUSH_FRAME
- ILL_ON_SLAVE
- movl ARG0,%edx /* IO port address */
- xor %eax,%eax /* clear high bits of register */
- inw %dx,%ax /* get the word */
- POP_FRAME
- ret
-
-/*
- * void outl(unsigned int *io_port,
- * unsigned int byte)
- *
- * Output an int to an IO port.
- */
-ENTRY(outl)
- PUSH_FRAME
- ILL_ON_SLAVE
- movl ARG0,%edx /* IO port address*/
- movl ARG1,%eax /* data to output */
- outl %eax,%dx /* send it out */
- POP_FRAME
- ret
-
-/*
- * unsigned int inl(unsigned int *io_port)
- *
- * Input an int from an IO port.
- */
-ENTRY(inl)
- PUSH_FRAME
- ILL_ON_SLAVE
- movl ARG0,%edx /* IO port address */
- inl %dx,%eax /* get the int */
- POP_FRAME
- ret
-
-#endif /* MACH_KDB || MACH_ASSERT*/
-
-/*
- * void loutb(unsigned byte *io_port,
- * unsigned byte *data,
- * unsigned int count)
- *
- * Output an array of bytes to an IO port.
- */
-ENTRY(loutb)
-ENTRY(outsb)
- PUSH_FRAME
- ILL_ON_SLAVE
- movl %esi,%eax /* save register */
- movl ARG0,%edx /* get io port number */
- movl ARG1,%esi /* get data address */
- movl ARG2,%ecx /* get count */
- cld /* count up */
- rep
- outsb /* output */
- movl %eax,%esi /* restore register */
- POP_FRAME
- ret
-
-
-/*
- * void loutw(unsigned short *io_port,
- * unsigned short *data,
- * unsigned int count)
- *
- * Output an array of shorts to an IO port.
- */
-ENTRY(loutw)
-ENTRY(outsw)
- PUSH_FRAME
- ILL_ON_SLAVE
- movl %esi,%eax /* save register */
- movl ARG0,%edx /* get io port number */
- movl ARG1,%esi /* get data address */
- movl ARG2,%ecx /* get count */
- cld /* count up */
- rep
- outsw /* output */
- movl %eax,%esi /* restore register */
- POP_FRAME
- ret
-
-/*
- * void loutw(unsigned short io_port,
- * unsigned int *data,
- * unsigned int count)
- *
- * Output an array of longs to an IO port.
- */
-ENTRY(loutl)
-ENTRY(outsl)
- PUSH_FRAME
- ILL_ON_SLAVE
- movl %esi,%eax /* save register */
- movl ARG0,%edx /* get io port number */
- movl ARG1,%esi /* get data address */
- movl ARG2,%ecx /* get count */
- cld /* count up */
- rep
- outsl /* output */
- movl %eax,%esi /* restore register */
- POP_FRAME
- ret
-
-
-/*
- * void linb(unsigned char *io_port,
- * unsigned char *data,
- * unsigned int count)
- *
- * Input an array of bytes from an IO port.
- */
-ENTRY(linb)
-ENTRY(insb)
- PUSH_FRAME
- ILL_ON_SLAVE
- movl %edi,%eax /* save register */
- movl ARG0,%edx /* get io port number */
- movl ARG1,%edi /* get data address */
- movl ARG2,%ecx /* get count */
- cld /* count up */
- rep
- insb /* input */
- movl %eax,%edi /* restore register */
- POP_FRAME
- ret
-
-
-/*
- * void linw(unsigned short *io_port,
- * unsigned short *data,
- * unsigned int count)
- *
- * Input an array of shorts from an IO port.
- */
-ENTRY(linw)
-ENTRY(insw)
- PUSH_FRAME
- ILL_ON_SLAVE
- movl %edi,%eax /* save register */
- movl ARG0,%edx /* get io port number */
- movl ARG1,%edi /* get data address */
- movl ARG2,%ecx /* get count */
- cld /* count up */
- rep
- insw /* input */
- movl %eax,%edi /* restore register */
- POP_FRAME
- ret
-
-
-/*
- * void linl(unsigned short io_port,
- * unsigned int *data,
- * unsigned int count)
- *
- * Input an array of longs from an IO port.
- */
-ENTRY(linl)
-ENTRY(insl)
- PUSH_FRAME
- ILL_ON_SLAVE
- movl %edi,%eax /* save register */
- movl ARG0,%edx /* get io port number */
- movl ARG1,%edi /* get data address */
- movl ARG2,%ecx /* get count */
- cld /* count up */
- rep
- insl /* input */
- movl %eax,%edi /* restore register */
- POP_FRAME
- ret
-
-
-/*
- * int inst_fetch(int eip, int cs);
- *
- * Fetch instruction byte. Return -1 if invalid address.
- */
- .globl EXT(inst_fetch)
-LEXT(inst_fetch)
- movl S_ARG1, %eax /* get segment */
- movw %ax,%fs /* into FS */
- movl S_ARG0, %eax /* get offset */
- RETRY_SECTION
- RETRY(EXT(inst_fetch)) /* re-load FS on retry */
- RECOVERY_SECTION
- RECOVER(EXT(inst_fetch_fault))
- movzbl %fs:(%eax),%eax /* load instruction byte */
- ret
-
-LEXT(inst_fetch_fault)
- movl $-1,%eax /* return -1 if error */
- ret
-
-
-#if MACH_KDP
-/*
- * kdp_copy_kmem(char *src, char *dst, int count)
- *
- * Similar to copyin except that both addresses are kernel addresses.
- */
-
-ENTRY(kdp_copy_kmem)
- pushl %esi
- pushl %edi /* save registers */
-
- movl 8+S_ARG0,%esi /* get kernel start address */
- movl 8+S_ARG1,%edi /* get kernel destination address */
-
- movl 8+S_ARG2,%edx /* get count */
-
- lea 0(%esi,%edx),%eax /* get kernel end address + 1 */
-
- cmpl %esi,%eax
- jb kdp_vm_read_fail /* fail if wrap-around */
- cld /* count up */
- movl %edx,%ecx /* move by longwords first */
- shrl $2,%ecx
- RECOVERY_SECTION
- RECOVER(kdp_vm_read_fail)
- rep
- movsl /* move longwords */
- movl %edx,%ecx /* now move remaining bytes */
- andl $3,%ecx
- RECOVERY_SECTION
- RECOVER(kdp_vm_read_fail)
- rep
- movsb
-kdp_vm_read_done:
- movl 8+S_ARG2,%edx /* get count */
- subl %ecx,%edx /* Return number of bytes transfered */
- movl %edx,%eax
-
- popl %edi /* restore registers */
- popl %esi
- ret /* and return */
-
-kdp_vm_read_fail:
- xorl %eax,%eax /* didn't copy a thing. */
-
- popl %edi
- popl %esi
- ret
-#endif
-
-
-/*
- * Done with recovery and retry tables.
- */
- RECOVERY_SECTION
- RECOVER_TABLE_END
- RETRY_SECTION
- RETRY_TABLE_END
-
-
-
-ENTRY(dr6)
- movl %db6, %eax
- ret
-
-/* dr<i>(address, type, len, persistence)
- */
-ENTRY(dr0)
- movl S_ARG0, %eax
- movl %eax,EXT(dr_addr)
- movl %eax, %db0
- movl $0, %ecx
- jmp 0f
-ENTRY(dr1)
- movl S_ARG0, %eax
- movl %eax,EXT(dr_addr)+1*4
- movl %eax, %db1
- movl $2, %ecx
- jmp 0f
-ENTRY(dr2)
- movl S_ARG0, %eax
- movl %eax,EXT(dr_addr)+2*4
- movl %eax, %db2
- movl $4, %ecx
- jmp 0f
-
-ENTRY(dr3)
- movl S_ARG0, %eax
- movl %eax,EXT(dr_addr)+3*4
- movl %eax, %db3
- movl $6, %ecx
-
-0:
- pushl %ebp
- movl %esp, %ebp
-
- movl %db7, %edx
- movl %edx,EXT(dr_addr)+4*4
- andl dr_msk(,%ecx,2),%edx /* clear out new entry */
- movl %edx,EXT(dr_addr)+5*4
- movzbl B_ARG3, %eax
- andb $3, %al
- shll %cl, %eax
- orl %eax, %edx
-
- movzbl B_ARG1, %eax
- andb $3, %al
- addb $0x10, %ecx
- shll %cl, %eax
- orl %eax, %edx
-
- movzbl B_ARG2, %eax
- andb $3, %al
- addb $0x2, %ecx
- shll %cl, %eax
- orl %eax, %edx
-
- movl %edx, %db7
- movl %edx,EXT(dr_addr)+7*4
- movl %edx, %eax
- leave
- ret
-
- .data
-
-DATA(preemptable) /* Not on an MP (makes cpu_number() usage unsafe) */
-#if MACH_RT && (NCPUS == 1)
- .long 0 /* FIXME -- Currently disabled */
-#else
- .long 0 /* FIX ME -- Currently disabled */
-#endif /* MACH_RT && (NCPUS == 1) */
-
-dr_msk:
- .long ~0x000f0003
- .long ~0x00f0000c
- .long ~0x0f000030
- .long ~0xf00000c0
-ENTRY(dr_addr)
- .long 0,0,0,0
- .long 0,0,0,0
- .text
-
-ENTRY(get_cr0)
- movl %cr0, %eax
- ret
-
-ENTRY(set_cr0)
- movl 4(%esp), %eax
- movl %eax, %cr0
- ret
-
-#ifndef SYMMETRY
-
-/*
- * ffs(mask)
+ * ffs(mask)
*/
ENTRY(ffs)
bsfl S_ARG0, %eax
div %ecx,%eax /* reboot now */
ret /* this will "never" be executed */
-#endif /* SYMMETRY */
-
/*
* setbit(int bitno, int *s) - set bit in bit string
sbbl %eax,%eax
ret
-ENTRY(get_pc)
- movl 4(%ebp),%eax
- ret
-
-#if ETAP
-
-ENTRY(etap_get_pc)
- movl 4(%ebp), %eax /* fetch pc of caller */
- ret
-
-ENTRY(tvals_to_etap)
- movl S_ARG0, %eax
- movl $1000000000, %ecx
- mull %ecx
- addl S_ARG1, %eax
- adc $0, %edx
- ret
-
-/* etap_time_t
- * etap_time_sub(etap_time_t stop, etap_time_t start)
- *
- * 64bit subtract, returns stop - start
- */
-ENTRY(etap_time_sub)
- movl S_ARG0, %eax /* stop.low */
- movl S_ARG1, %edx /* stop.hi */
- subl S_ARG2, %eax /* stop.lo - start.lo */
- sbbl S_ARG3, %edx /* stop.hi - start.hi */
- ret
-
-#endif /* ETAP */
-
-#if NCPUS > 1
-
-ENTRY(minsecurity)
- pushl %ebp
- movl %esp,%ebp
-/*
- * jail: set the EIP to "jail" to block a kernel thread.
- * Useful to debug synchronization problems on MPs.
- */
-ENTRY(jail)
- jmp EXT(jail)
-
-#endif /* NCPUS > 1 */
-
-/*
- * delay(microseconds)
- */
-
-ENTRY(delay)
- movl 4(%esp),%eax
- testl %eax, %eax
- jle 3f
- movl EXT(delaycount), %ecx
-1:
- movl %ecx, %edx
-2:
- decl %edx
- jne 2b
- decl %eax
- jne 1b
-3:
- ret
-
-/*
- * unsigned int
- * div_scale(unsigned int dividend,
- * unsigned int divisor,
- * unsigned int *scale)
- *
- * This function returns (dividend << *scale) //divisor where *scale
- * is the largest possible value before overflow. This is used in
- * computation where precision must be achieved in order to avoid
- * floating point usage.
- *
- * Algorithm:
- * *scale = 0;
- * while (((dividend >> *scale) >= divisor))
- * (*scale)++;
- * *scale = 32 - *scale;
- * return ((dividend << *scale) / divisor);
- */
-ENTRY(div_scale)
- PUSH_FRAME
- xorl %ecx, %ecx /* *scale = 0 */
- xorl %eax, %eax
- movl ARG0, %edx /* get dividend */
-0:
- cmpl ARG1, %edx /* if (divisor > dividend) */
- jle 1f /* goto 1f */
- addl $1, %ecx /* (*scale)++ */
- shrdl $1, %edx, %eax /* dividend >> 1 */
- shrl $1, %edx /* dividend >> 1 */
- jmp 0b /* goto 0b */
-1:
- divl ARG1 /* (dividend << (32 - *scale)) / divisor */
- movl ARG2, %edx /* get scale */
- movl $32, (%edx) /* *scale = 32 */
- subl %ecx, (%edx) /* *scale -= %ecx */
- POP_FRAME
- ret
-
-/*
- * unsigned int
- * mul_scale(unsigned int multiplicand,
- * unsigned int multiplier,
- * unsigned int *scale)
- *
- * This function returns ((multiplicand * multiplier) >> *scale) where
- * scale is the largest possible value before overflow. This is used in
- * computation where precision must be achieved in order to avoid
- * floating point usage.
- *
- * Algorithm:
- * *scale = 0;
- * while (overflow((multiplicand * multiplier) >> *scale))
- * (*scale)++;
- * return ((multiplicand * multiplier) >> *scale);
- */
-ENTRY(mul_scale)
- PUSH_FRAME
- xorl %ecx, %ecx /* *scale = 0 */
- movl ARG0, %eax /* get multiplicand */
- mull ARG1 /* multiplicand * multiplier */
-0:
- cmpl $0, %edx /* if (!overflow()) */
- je 1f /* goto 1 */
- addl $1, %ecx /* (*scale)++ */
- shrdl $1, %edx, %eax /* (multiplicand * multiplier) >> 1 */
- shrl $1, %edx /* (multiplicand * multiplier) >> 1 */
- jmp 0b
-1:
- movl ARG2, %edx /* get scale */
- movl %ecx, (%edx) /* set *scale */
- POP_FRAME
- ret
-
-#if NCPUS > 1
-ENTRY(_cpu_number)
- CPU_NUMBER(%eax)
- ret
-#endif /* NCPUS > 1 */
-
-#ifdef MACH_BSD
-/*
- * BSD System call entry point..
- */
-
-Entry(trap_unix_syscall)
- pushf /* save flags as soon as possible */
- pushl %eax /* save system call number */
- pushl $0 /* clear trap number slot */
-
- pusha /* save the general registers */
- pushl %ds /* and the segment registers */
- pushl %es
- pushl %fs
- pushl %gs
-
- mov %ss,%dx /* switch to kernel data segment */
- mov %dx,%ds
- mov %dx,%es
- mov $ CPU_DATA,%dx
- mov %dx,%gs
-
-/*
- * Shuffle eflags,eip,cs into proper places
- */
-
- movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
- movl R_CS(%esp),%ecx /* eip is in CS slot */
- movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
- movl %ecx,R_EIP(%esp) /* fix eip */
- movl %edx,R_CS(%esp) /* fix cs */
- movl %ebx,R_EFLAGS(%esp) /* fix eflags */
-
- CPU_NUMBER(%edx)
- TIME_TRAP_UENTRY
-
- negl %eax /* get system call number */
- shll $4,%eax /* manual indexing */
-
- CPU_NUMBER(%edx)
- movl CX(EXT(kernel_stack),%edx),%ebx
- /* get current kernel stack */
- xchgl %ebx,%esp /* switch stacks - %ebx points to */
- /* user registers. */
-
-/*
- * Register use on entry:
- * eax contains syscall number
- * ebx contains user regs pointer
- */
- CAH(call_call)
- pushl %ebx /* Push the regs set onto stack */
- call EXT(unix_syscall)
- popl %ebx
- movl %esp,%ecx /* get kernel stack */
- or $(KERNEL_STACK_SIZE-1),%ecx
- movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
- movl %eax,R_EAX(%esp) /* save return value */
- jmp EXT(return_from_trap) /* return to user */
-
-/*
- * Entry point for machdep system calls..
- */
-
-Entry(trap_machdep_syscall)
- pushf /* save flags as soon as possible */
- pushl %eax /* save system call number */
- pushl $0 /* clear trap number slot */
-
- pusha /* save the general registers */
- pushl %ds /* and the segment registers */
- pushl %es
- pushl %fs
- pushl %gs
-
- mov %ss,%dx /* switch to kernel data segment */
- mov %dx,%ds
- mov %dx,%es
- mov $ CPU_DATA,%dx
- mov %dx,%gs
-
-/*
- * Shuffle eflags,eip,cs into proper places
- */
-
- movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
- movl R_CS(%esp),%ecx /* eip is in CS slot */
- movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
- movl %ecx,R_EIP(%esp) /* fix eip */
- movl %edx,R_CS(%esp) /* fix cs */
- movl %ebx,R_EFLAGS(%esp) /* fix eflags */
-
- CPU_NUMBER(%edx)
- TIME_TRAP_UENTRY
-
- negl %eax /* get system call number */
- shll $4,%eax /* manual indexing */
-
- CPU_NUMBER(%edx)
- movl CX(EXT(kernel_stack),%edx),%ebx
- /* get current kernel stack */
- xchgl %ebx,%esp /* switch stacks - %ebx points to */
- /* user registers. */
-
-/*
- * Register use on entry:
- * eax contains syscall number
- * ebx contains user regs pointer
- */
- CAH(call_call)
- pushl %ebx
- call EXT(machdep_syscall)
- popl %ebx
- movl %esp,%ecx /* get kernel stack */
- or $(KERNEL_STACK_SIZE-1),%ecx
- movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
- movl %eax,R_EAX(%esp) /* save return value */
- jmp EXT(return_from_trap) /* return to user */
-
-Entry(trap_mach25_syscall)
- pushf /* save flags as soon as possible */
- pushl %eax /* save system call number */
- pushl $0 /* clear trap number slot */
-
- pusha /* save the general registers */
- pushl %ds /* and the segment registers */
- pushl %es
- pushl %fs
- pushl %gs
-
- mov %ss,%dx /* switch to kernel data segment */
- mov %dx,%ds
- mov %dx,%es
- mov $ CPU_DATA,%dx
- mov %dx,%gs
-
-/*
- * Shuffle eflags,eip,cs into proper places
- */
-
- movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
- movl R_CS(%esp),%ecx /* eip is in CS slot */
- movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
- movl %ecx,R_EIP(%esp) /* fix eip */
- movl %edx,R_CS(%esp) /* fix cs */
- movl %ebx,R_EFLAGS(%esp) /* fix eflags */
-
- CPU_NUMBER(%edx)
- TIME_TRAP_UENTRY
-
- negl %eax /* get system call number */
- shll $4,%eax /* manual indexing */
-
- CPU_NUMBER(%edx)
- movl CX(EXT(kernel_stack),%edx),%ebx
- /* get current kernel stack */
- xchgl %ebx,%esp /* switch stacks - %ebx points to */
- /* user registers. */
-
-/*
- * Register use on entry:
- * eax contains syscall number
- * ebx contains user regs pointer
- */
- CAH(call_call)
- pushl %ebx
- call EXT(mach25_syscall)
- popl %ebx
- movl %esp,%ecx /* get kernel stack */
- or $(KERNEL_STACK_SIZE-1),%ecx
- movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
- movl %eax,R_EAX(%esp) /* save return value */
- jmp EXT(return_from_trap) /* return to user */
-
-#endif