2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
34 * Mach Operating System
35 * Copyright (c) 1991,1990 Carnegie Mellon University
36 * All Rights Reserved.
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48 * Carnegie Mellon requests users of this software to return to
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
60 #include <platforms.h>
62 #include <mach_kgdb.h>
64 #include <stat_time.h>
65 #include <mach_assert.h>
67 #include <sys/errno.h>
69 #include <i386/cpuid.h>
70 #include <i386/eflags.h>
71 #include <i386/proc_reg.h>
72 #include <i386/trap.h>
74 #include <mach/exception_types.h>
78 #define PREEMPT_DEBUG_LOG 0
82 * PTmap is recursive pagemap at top of virtual address space.
83 * Within PTmap, the page directory can be found (third indirection).
85 .globl _PTmap,_PTD,_PTDpde
86 .set _PTmap,(PTDPTDI << PDESHIFT)
87 .set _PTD,_PTmap + (PTDPTDI * NBPG)
88 .set _PTDpde,_PTD + (PTDPTDI * PDESIZE)
91 * APTmap, APTD is the alternate recursive pagemap.
92 * It's used when modifying another process's page tables.
94 .globl _APTmap,_APTD,_APTDpde
95 .set _APTmap,(APTDPTDI << PDESHIFT)
96 .set _APTD,_APTmap + (APTDPTDI * NBPG)
97 .set _APTDpde,_PTD + (APTDPTDI * PDESIZE)
100 /* Under Mach-O, etext is a variable which contains
101 * the last text address
103 #define ETEXT_ADDR (EXT(etext))
105 /* Under ELF and other non-Mach-O formats, the address of
106 * etext represents the last text address
108 #define ETEXT_ADDR $ EXT(etext)
111 #define CX(addr,reg) addr(,reg,4)
121 #define RECOVERY_SECTION .section __VECTORS, __recover
122 #define RETRY_SECTION .section __VECTORS, __retries
124 #define RECOVERY_SECTION .text
125 #define RECOVERY_SECTION .text
128 #define RECOVER_TABLE_START \
130 .globl EXT(recover_table) ;\
131 LEXT(recover_table) ;\
134 #define RECOVER(addr) \
141 #define RECOVER_TABLE_END \
143 .globl EXT(recover_table_end) ;\
144 LEXT(recover_table_end) ;\
148 * Retry table for certain successful faults.
150 #define RETRY_TABLE_START \
152 .globl EXT(retry_table) ;\
156 #define RETRY(addr) \
163 #define RETRY_TABLE_END \
165 .globl EXT(retry_table_end) ;\
166 LEXT(retry_table_end) ;\
170 * Allocate recovery and retry tables.
184 movl %eax,TIMER_HIGHCHK(%ecx)
185 movl %edx,TIMER_LOW(%ecx)
186 movl %eax,TIMER_HIGH(%ecx)
191 0: movl TIMER_HIGH(%ecx),%edx
192 movl TIMER_LOW(%ecx),%eax
193 cmpl TIMER_HIGHCHK(%ecx),%edx
199 #define TIME_TRAP_UENTRY
200 #define TIME_TRAP_UEXIT
201 #define TIME_INT_ENTRY
202 #define TIME_INT_EXIT
210 * Low 32-bits of nanotime returned in %eax.
211 * Computed from tsc using conversion scale/shift from per-cpu data.
212 * Uses %ecx and %edx.
215 pushl %esi /* save %esi */ ;\
216 movl %gs:CPU_THIS,%esi /* per-cpu data ptr */ ;\
217 addl $(CPU_RTC_NANOTIME),%esi /* esi -> per-cpu nanotime*/ ;\
218 rdtsc /* edx:eax = tsc */ ;\
219 subl RTN_TSC(%esi),%eax /* eax = (tsc - base_tsc) */ ;\
220 mull RTN_SCALE(%esi) /* eax *= scale */ ;\
221 movl RTN_SHIFT(%esi),%ecx /* ecx = shift */ ;\
222 shrdl %cl,%edx,%eax /* edx:eax >> shift */ ;\
223 andb $32,%cl /* shift == 32? */ ;\
224 cmovnel %edx,%eax /* %eax = %edx if so */ ;\
225 addl RTN_NANOS(%esi),%eax /* add base ns */ ;\
229 * Add 32-bit ns delta in register dreg to timer pointed to by register treg.
231 #define TIMER_UPDATE(treg,dreg) \
232 addl TIMER_LOW(treg),dreg /* add delta low bits */ ;\
233 adcl $0,TIMER_HIGHCHK(treg) /* add carry check bits */ ;\
234 movl dreg,TIMER_LOW(treg) /* store updated low bit */ ;\
235 movl TIMER_HIGHCHK(treg),dreg /* copy high check bits */ ;\
236 movl dreg,TIMER_HIGH(treg) /* to high bita */
239 * Add time delta to old timer and start new.
241 #define TIMER_EVENT(old,new) \
242 pushl %eax /* must be invariant */ ;\
243 cli /* block interrupts */ ;\
244 NANOTIME32 /* eax low bits nanosecs */ ;\
245 movl %gs:CPU_PROCESSOR,%ecx /* get current processor */ ;\
246 movl CURRENT_TIMER(%ecx),%ecx /* get current timer */ ;\
247 movl %eax,%edx /* save timestamp in %edx */ ;\
248 subl TIMER_TSTAMP(%ecx),%eax /* compute elapsed time */ ;\
249 TIMER_UPDATE(%ecx,%eax) /* update timer struct */ ;\
250 addl $(new##_TIMER-old##_TIMER),%ecx /* point to new timer */ ;\
251 movl %edx,TIMER_TSTAMP(%ecx) /* set timestamp */ ;\
252 movl %gs:CPU_PROCESSOR,%edx /* get current processor */ ;\
253 movl %ecx,CURRENT_TIMER(%edx) /* set current timer */ ;\
254 sti /* interrupts on */ ;\
255 popl %eax /* must be invariant */
258 * Update time on user trap entry.
261 #define TIME_TRAP_UENTRY TIMER_EVENT(USER,SYSTEM)
264 * update time on user trap exit.
267 #define TIME_TRAP_UEXIT TIMER_EVENT(SYSTEM,USER)
270 * update time on interrupt entry.
271 * Uses %eax,%ecx,%edx.
273 #define TIME_INT_ENTRY \
274 NANOTIME32 /* eax low bits nanosecs */ ;\
275 movl %gs:CPU_PROCESSOR,%ecx /* get current processor */ ;\
276 movl CURRENT_TIMER(%ecx),%ecx /* get current timer */ ;\
277 movl %eax,%edx /* save timestamp in %edx */ ;\
278 subl TIMER_TSTAMP(%ecx),%eax /* compute elapsed time */ ;\
279 TIMER_UPDATE(%ecx,%eax) /* update timer struct */ ;\
280 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */ ;\
281 addl $(SYSTEM_TIMER),%ecx /* point to sys timer */ ;\
282 movl %edx,TIMER_TSTAMP(%ecx) /* set timestamp */
285 * update time on interrupt exit.
286 * Uses %eax, %ecx, %edx.
288 #define TIME_INT_EXIT \
289 NANOTIME32 /* eax low bits nanosecs */ ;\
290 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */ ;\
291 addl $(SYSTEM_TIMER),%ecx /* point to sys timer */ ;\
292 movl %eax,%edx /* save timestamp in %edx */ ;\
293 subl TIMER_TSTAMP(%ecx),%eax /* compute elapsed time */ ;\
294 TIMER_UPDATE(%ecx,%eax) /* update timer struct */ ;\
295 movl %gs:CPU_PROCESSOR,%ecx /* get current processor */ ;\
296 movl CURRENT_TIMER(%ecx),%ecx /* interrupted timer */ ;\
297 movl %edx,TIMER_TSTAMP(%ecx) /* set timestamp */
299 #endif /* STAT_TIME */
302 * Encapsulate the transfer of exception stack frames between a PCB
303 * and a thread stack. Since the whole point of these is to emulate
304 * a call or exception that changes privilege level, both macros
305 * assume that there is no user esp or ss stored in the source
306 * frame (because there was no change of privilege to generate them).
310 * Transfer a stack frame from a thread's user stack to its PCB.
311 * We assume the thread and stack addresses have been loaded into
312 * registers (our arguments).
314 * The macro overwrites edi, esi, ecx and whatever registers hold the
315 * thread and stack addresses (which can't be one of the above three).
316 * The thread address is overwritten with the address of its saved state
317 * (where the frame winds up).
319 * Must be called on kernel stack.
321 #define FRAME_STACK_TO_PCB(thread, stkp) ;\
322 movl ACT_PCB(thread),thread /* get act`s PCB */ ;\
323 leal PCB_ISS(thread),%edi /* point to PCB`s saved state */;\
324 movl %edi,thread /* save for later */ ;\
325 movl stkp,%esi /* point to start of frame */ ;\
326 movl $ R_UESP,%ecx ;\
327 sarl $2,%ecx /* word count for transfer */ ;\
328 cld /* we`re incrementing */ ;\
330 movsl /* transfer the frame */ ;\
331 addl $ R_UESP,stkp /* derive true "user" esp */ ;\
332 movl stkp,R_UESP(thread) /* store in PCB */ ;\
334 mov %ss,%cx /* get current ss */ ;\
335 movl %ecx,R_SS(thread) /* store in PCB */
338 * Transfer a stack frame from a thread's PCB to the stack pointed
339 * to by the PCB. We assume the thread address has been loaded into
340 * a register (our argument).
342 * The macro overwrites edi, esi, ecx and whatever register holds the
343 * thread address (which can't be one of the above three). The
344 * thread address is overwritten with the address of its saved state
345 * (where the frame winds up).
347 * Must be called on kernel stack.
349 #define FRAME_PCB_TO_STACK(thread) ;\
350 movl ACT_PCB(thread),%esi /* get act`s PCB */ ;\
351 leal PCB_ISS(%esi),%esi /* point to PCB`s saved state */;\
352 movl R_UESP(%esi),%edi /* point to end of dest frame */;\
353 movl ACT_MAP(thread),%ecx /* get act's map */ ;\
354 movl MAP_PMAP(%ecx),%ecx /* get map's pmap */ ;\
355 cmpl EXT(kernel_pmap), %ecx /* If kernel loaded task */ ;\
356 jz 1f /* use kernel data segment */ ;\
357 movl $ USER_DS,%ecx /* else use user data segment */;\
360 movl $ R_UESP,%ecx ;\
361 subl %ecx,%edi /* derive start of frame */ ;\
362 movl %edi,thread /* save for later */ ;\
363 sarl $2,%ecx /* word count for transfer */ ;\
364 cld /* we`re incrementing */ ;\
366 movsl /* transfer the frame */ ;\
367 mov %ss,%cx /* restore kernel segments */ ;\
375 * Traditional, not ANSI.
379 .globl label/**/count ;\
382 .globl label/**/limit ;\
386 addl $1,%ss:label/**/count ;\
387 cmpl $0,label/**/limit ;\
391 movl %ss:label/**/count,%eax ;\
392 cmpl %eax,%ss:label/**/limit ;\
405 * Last-ditch debug code to handle faults that might result
406 * from entering kernel (from collocated server) on an invalid
407 * stack. On collocated entry, there's no hardware-initiated
408 * stack switch, so a valid stack must be in place when an
409 * exception occurs, or we may double-fault.
411 * In case of a double-fault, our only recourse is to switch
412 * hardware "tasks", so that we avoid using the current stack.
414 * The idea here is just to get the processor into the debugger,
415 * post-haste. No attempt is made to fix up whatever error got
416 * us here, so presumably continuing from the debugger will
417 * simply land us here again -- at best.
421 * Note that the per-fault entry points are not currently
422 * functional. The only way to make them work would be to
423 * set up separate TSS's for each fault type, which doesn't
424 * currently seem worthwhile. (The offset part of a task
425 * gate is always ignored.) So all faults that task switch
426 * currently resume at db_task_start.
429 * Double fault (Murphy's point) - error code (0) on stack
431 Entry(db_task_dbl_fault)
433 movl $(T_DOUBLE_FAULT),%ebx
436 * Segment not present - error code on stack
438 Entry(db_task_seg_np)
440 movl $(T_SEGMENT_NOT_PRESENT),%ebx
443 * Stack fault - error code on (current) stack
445 Entry(db_task_stk_fault)
447 movl $(T_STACK_FAULT),%ebx
450 * General protection fault - error code on stack
452 Entry(db_task_gen_prot)
454 movl $(T_GENERAL_PROTECTION),%ebx
458 * The entry point where execution resumes after last-ditch debugger task
464 movl %edx,%esp /* allocate i386_saved_state on stack */
465 movl %eax,R_ERR(%esp)
466 movl %ebx,R_TRAPNO(%esp)
469 movl CX(EXT(mp_dbtss),%edx),%edx
470 movl TSS_LINK(%edx),%eax
471 pushl %eax /* pass along selector of previous TSS */
472 call EXT(db_tss_to_frame)
473 popl %eax /* get rid of TSS selector */
474 call EXT(db_trap_from_asm)
479 iret /* ha, ha, ha... */
480 #endif /* MACH_KDB */
483 * Trap/interrupt entry points.
485 * All traps must create the following save area on the PCB "stack":
494 * cr2 if page fault - otherwise unused
504 * user esp - if from user
505 * user ss - if from user
506 * es - if from V86 thread
507 * ds - if from V86 thread
508 * fs - if from V86 thread
509 * gs - if from V86 thread
514 * General protection or segment-not-present fault.
515 * Check for a GP/NP fault in the kernel_return
516 * sequence; if there, report it as a GP/NP fault on the user's instruction.
518 * esp-> 0: trap code (NP or GP)
519 * 4: segment number in error
523 * 20 old registers (trap is from kernel)
526 pushl $(T_GENERAL_PROTECTION) /* indicate fault type */
527 jmp trap_check_kernel_exit /* check for kernel exit sequence */
530 pushl $(T_SEGMENT_NOT_PRESENT)
531 /* indicate fault type */
533 trap_check_kernel_exit:
534 testl $(EFL_VM),16(%esp) /* is trap from V86 mode? */
535 jnz EXT(alltraps) /* isn`t kernel trap if so */
536 testl $3,12(%esp) /* is trap from kernel mode? */
537 jne EXT(alltraps) /* if so: */
538 /* check for the kernel exit sequence */
539 cmpl $ EXT(kret_iret),8(%esp) /* on IRET? */
541 cmpl $ EXT(kret_popl_ds),8(%esp) /* popping DS? */
543 cmpl $ EXT(kret_popl_es),8(%esp) /* popping ES? */
545 cmpl $ EXT(kret_popl_fs),8(%esp) /* popping FS? */
547 cmpl $ EXT(kret_popl_gs),8(%esp) /* popping GS? */
549 take_fault: /* if none of the above: */
550 jmp EXT(alltraps) /* treat as normal trap. */
553 * GP/NP fault on IRET: CS or SS is in error.
554 * All registers contain the user's values.
569 movl %eax,8(%esp) /* save eax (we don`t need saved eip) */
570 popl %eax /* get trap number */
571 movl %eax,12-4(%esp) /* put in user trap number */
572 popl %eax /* get error code */
573 movl %eax,16-8(%esp) /* put in user errcode */
574 popl %eax /* restore eax */
576 jmp EXT(alltraps) /* take fault */
579 * Fault restoring a segment register. The user's registers are still
580 * saved on the stack. The offending segment register has not been
584 popl %eax /* get trap number */
585 popl %edx /* get error code */
586 addl $12,%esp /* pop stack to user regs */
587 jmp push_es /* (DS on top of stack) */
589 popl %eax /* get trap number */
590 popl %edx /* get error code */
591 addl $12,%esp /* pop stack to user regs */
592 jmp push_fs /* (ES on top of stack) */
594 popl %eax /* get trap number */
595 popl %edx /* get error code */
596 addl $12,%esp /* pop stack to user regs */
597 jmp push_gs /* (FS on top of stack) */
599 popl %eax /* get trap number */
600 popl %edx /* get error code */
601 addl $12,%esp /* pop stack to user regs */
602 jmp push_segregs /* (GS on top of stack) */
605 pushl %es /* restore es, */
607 pushl %fs /* restore fs, */
609 pushl %gs /* restore gs. */
611 movl %eax,R_TRAPNO(%esp) /* set trap number */
612 movl %edx,R_ERR(%esp) /* set error code */
614 jmp trap_set_segs /* take trap */
617 * Debug trap. Check for single-stepping across system call into
618 * kernel. If this is the case, taking the debug trap has turned
619 * off single-stepping - save the flags register with the trace
623 testl $(EFL_VM),8(%esp) /* is trap from V86 mode? */
624 jnz 0f /* isn`t kernel trap if so */
625 testl $3,4(%esp) /* is trap from kernel mode? */
627 cmpl $syscall_entry,(%esp) /* system call entry? */
629 /* flags are sitting where syscall */
631 addl $8,%esp /* remove eip/cs */
632 jmp syscall_entry_2 /* continue system call entry */
634 1: cmpl $trap_unix_addr,(%esp)
639 0: pushl $0 /* otherwise: */
640 pushl $(T_DEBUG) /* handle as normal */
641 jmp EXT(alltraps) /* debug fault */
644 * Page fault traps save cr2.
647 pushl $(T_PAGE_FAULT) /* mark a page fault trap */
648 pusha /* save the general registers */
649 movl %cr2,%eax /* get the faulting address */
650 movl %eax,12(%esp) /* save in esp save slot */
651 jmp trap_push_segs /* continue fault */
654 * All 'exceptions' enter here with:
660 * old esp if trapped from user
661 * old ss if trapped from user
663 * NB: below use of CPU_NUMBER assumes that macro will use correct
664 * segment register for any kernel data accesses.
667 pusha /* save the general registers */
669 pushl %ds /* save the segment registers */
677 movl %eax,%es /* switch to kernel data seg */
678 cld /* clear direction flag */
679 testl $(EFL_VM),R_EFLAGS(%esp) /* in V86 mode? */
680 jnz trap_from_user /* user mode trap if so */
681 testb $3,R_CS(%esp) /* user mode trap? */
683 cmpl $0,%gs:CPU_ACTIVE_KLOADED
684 je trap_from_kernel /* if clear, truly in kernel */
686 cmpl ETEXT_ADDR,R_EIP(%esp) /* pc within kernel? */
691 * We didn't enter here "through" PCB (i.e., using ring 0 stack),
692 * so transfer the stack frame into the PCB explicitly, then
693 * start running on resulting "PCB stack". We have to set
694 * up a simulated "uesp" manually, since there's none in the
697 mov $ CPU_DATA_GS,%dx
700 movl %gs:CPU_ACTIVE_KLOADED,%ebx
701 movl %gs:CPU_KERNEL_STACK,%eax
703 FRAME_STACK_TO_PCB(%ebx,%eax)
708 mov $ CPU_DATA_GS,%ax
713 movl %gs:CPU_KERNEL_STACK,%ebx
714 xchgl %ebx,%esp /* switch to kernel stack */
715 /* user regs pointer already set */
717 pushl %ebx /* record register save area */
718 pushl %ebx /* pass register save area to trap */
719 call EXT(user_trap) /* call user trap routine */
720 movl 4(%esp),%esp /* switch back to PCB stack */
723 * Return from trap or system call, checking for ASTs.
727 LEXT(return_from_trap)
728 movl %gs:CPU_PENDING_AST,%edx
730 je EXT(return_to_user) /* if we need an AST: */
732 movl %gs:CPU_KERNEL_STACK,%esp
733 /* switch to kernel stack */
734 pushl $0 /* push preemption flag */
735 call EXT(i386_astintr) /* take the AST */
736 addl $4,%esp /* pop preemption flag */
737 popl %esp /* switch back to PCB stack (w/exc link) */
738 jmp EXT(return_from_trap) /* and check again (rare) */
739 /* ASTs after this point will */
743 * Arrange the checks needed for kernel-loaded (or kernel-loading)
744 * threads so that branch is taken in kernel-loaded case.
748 cmpl $0,%gs:CPU_ACTIVE_KLOADED
749 jnz EXT(return_xfer_stack)
750 movl %gs:CPU_ACTIVE_THREAD, %ebx /* get active thread */
754 cmpl $0,%gs:CPU_PREEMPTION_LEVEL
755 je EXT(return_from_kernel)
757 #endif /* MACH_ASSERT */
761 * Return from kernel mode to interrupted thread.
764 LEXT(return_from_kernel)
766 popl %gs /* restore segment registers */
773 popa /* restore general registers */
774 addl $8,%esp /* discard trap number and error code */
777 iret /* return from interrupt */
780 LEXT(return_xfer_stack)
782 * If we're on PCB stack in a kernel-loaded task, we have
783 * to transfer saved state back to thread stack and swap
784 * stack pointers here, because the hardware's not going
788 movl %gs:CPU_KERNEL_STACK,%esp
789 movl %gs:CPU_ACTIVE_KLOADED,%eax
790 FRAME_PCB_TO_STACK(%eax)
793 jmp EXT(return_from_kernel)
796 * Hate to put this here, but setting up a separate swap_func for
797 * kernel-loaded threads no longer works, since thread executes
798 * "for a while" (i.e., until it reaches glue code) when first
799 * created, even if it's nominally suspended. Hence we can't
800 * transfer the PCB when the thread first resumes, because we
801 * haven't initialized it yet.
804 * Have to force transfer to new stack "manually". Use a string
805 * move to transfer all of our saved state to the stack pointed
806 * to by iss.uesp, then install a pointer to it as our current
809 LEXT(return_kernel_loading)
810 movl %gs:CPU_KERNEL_STACK,%esp
811 movl %gs:CPU_ACTIVE_THREAD, %ebx /* get active thread */
812 movl %ebx,%edx /* save for later */
813 FRAME_PCB_TO_STACK(%ebx)
814 movl %ebx,%esp /* start running on new stack */
815 movl $0,%gs:CPU_ACTIVE_KLOADED /* set cached indicator */
816 jmp EXT(return_from_kernel)
819 * Trap from kernel mode. No need to switch stacks or load segment registers.
822 #if MACH_KDB || MACH_KGDB
823 mov $ CPU_DATA_GS,%ax
825 movl %esp,%ebx /* save current stack */
827 cmpl EXT(int_stack_high),%esp /* on an interrupt stack? */
831 cmpl $0,EXT(kgdb_active) /* Unexpected trap in kgdb */
834 pushl %esp /* Already on kgdb stack */
838 jmp EXT(return_from_kernel)
839 0: /* should kgdb handle this exception? */
840 cmpl $(T_NO_FPU),R_TRAPNO(%esp) /* FPU disabled? */
842 cmpl $(T_PAGE_FAULT),R_TRAPNO(%esp) /* page fault? */
845 cli /* disable interrupts */
846 CPU_NUMBER(%edx) /* get CPU number */
847 movl CX(EXT(kgdb_stacks),%edx),%ebx
848 xchgl %ebx,%esp /* switch to kgdb stack */
849 pushl %ebx /* pass old sp as an arg */
850 call EXT(kgdb_from_kernel)
851 popl %esp /* switch back to kernel stack */
852 jmp EXT(return_from_kernel)
854 #endif /* MACH_KGDB */
857 cmpl $0,EXT(db_active) /* could trap be from ddb? */
859 CPU_NUMBER(%edx) /* see if this CPU is in ddb */
860 cmpl $0,CX(EXT(kdb_active),%edx)
863 call EXT(db_trap_from_asm)
865 jmp EXT(return_from_kernel)
869 * Dilemma: don't want to switch to kernel_stack if trap
870 * "belongs" to ddb; don't want to switch to db_stack if
871 * trap "belongs" to kernel. So have to duplicate here the
872 * set of trap types that kernel_trap() handles. Note that
873 * "unexpected" page faults will not be handled by kernel_trap().
874 * In this panic-worthy case, we fall into the debugger with
875 * kernel_stack containing the call chain that led to the
878 movl R_TRAPNO(%esp),%edx
879 cmpl $(T_PAGE_FAULT),%edx
881 cmpl $(T_NO_FPU),%edx
883 cmpl $(T_FPU_FAULT),%edx
885 cmpl $(T_FLOATING_POINT_ERROR),%edx
887 cmpl $(T_PREEMPT),%edx
890 #endif /* MACH_KDB */
892 cmpl %gs:CPU_KERNEL_STACK,%esp
893 /* if not already on kernel stack, */
894 ja 5f /* check some more */
895 cmpl %gs:CPU_ACTIVE_STACK,%esp
896 ja 6f /* on kernel stack: no switch */
898 movl %gs:CPU_KERNEL_STACK,%esp
900 pushl %ebx /* save old stack */
901 pushl %ebx /* pass as parameter */
902 call EXT(kernel_trap) /* to kernel trap routine */
903 addl $4,%esp /* pop parameter */
907 * If kernel_trap returns false, trap wasn't handled.
912 movl CX(EXT(db_stacks),%edx),%esp
913 pushl %ebx /* pass old stack as parameter */
914 call EXT(db_trap_from_asm)
915 #endif /* MACH_KDB */
917 cli /* disable interrupts */
918 CPU_NUMBER(%edx) /* get CPU number */
919 movl CX(EXT(kgdb_stacks),%edx),%esp
920 pushl %ebx /* pass old stack as parameter */
921 call EXT(kgdb_from_kernel)
922 #endif /* MACH_KGDB */
923 addl $4,%esp /* pop parameter */
927 * Likewise, if kdb_trap/kgdb_from_kernel returns false, trap
930 pushl %ebx /* pass old stack as parameter */
932 addl $4,%esp /* pop parameter */
934 movl %ebx,%esp /* get old stack (from callee-saves reg) */
935 #else /* MACH_KDB || MACH_KGDB */
936 pushl %esp /* pass parameter */
937 call EXT(kernel_trap) /* to kernel trap routine */
938 addl $4,%esp /* pop parameter */
939 #endif /* MACH_KDB || MACH_KGDB */
942 movl %gs:CPU_PENDING_AST,%eax /* get pending asts */
943 testl $ AST_URGENT,%eax /* any urgent preemption? */
944 je EXT(return_from_kernel) /* no, nothing to do */
945 cmpl $ T_PREEMPT,48(%esp) /* preempt request? */
946 jne EXT(return_from_kernel) /* no, nothing to do */
947 movl %gs:CPU_KERNEL_STACK,%eax
950 andl $(-KERNEL_STACK_SIZE),%ecx
951 testl %ecx,%ecx /* are we on the kernel stack? */
952 jne EXT(return_from_kernel) /* no, skip it */
954 #if PREEMPT_DEBUG_LOG
955 pushl 28(%esp) /* stack pointer */
956 pushl 24+4(%esp) /* frame pointer */
957 pushl 56+8(%esp) /* stack pointer */
959 call EXT(log_thread_action)
962 0: String "trap preempt eip"
964 #endif /* PREEMPT_DEBUG_LOG */
966 pushl $1 /* push preemption flag */
967 call EXT(i386_astintr) /* take the AST */
968 addl $4,%esp /* pop preemption flag */
971 jmp EXT(return_from_kernel)
974 * Called as a function, makes the current thread
975 * return from the kernel as if from an exception.
978 .globl EXT(thread_exception_return)
979 .globl EXT(thread_bootstrap_return)
980 LEXT(thread_exception_return)
981 LEXT(thread_bootstrap_return)
982 movl %esp,%ecx /* get kernel stack */
983 or $(KERNEL_STACK_SIZE-1),%ecx
984 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
985 jmp EXT(return_from_trap)
987 Entry(call_continuation)
988 movl S_ARG0,%eax /* get continuation */
989 movl S_ARG1,%edx /* continuation param */
990 movl S_ARG2,%ecx /* wait result */
991 movl %esp,%ebp /* get kernel stack */
992 or $(KERNEL_STACK_SIZE-1),%ebp
993 addl $(-3-IKS_SIZE),%ebp
994 movl %ebp,%esp /* pop the stack */
995 xorl %ebp,%ebp /* zero frame pointer */
998 call *%eax /* call continuation */
1000 movl %gs:CPU_ACTIVE_THREAD,%eax
1002 call EXT(thread_terminate)
1005 #define LOG_INTERRUPT(info,msg) \
1009 call EXT(log_thread_action) ; \
1012 #define CHECK_INTERRUPT_TIME(n) \
1015 call EXT(check_thread_time) ; \
1019 #define LOG_INTERRUPT(info,msg)
1020 #define CHECK_INTERRUPT_TIME(n)
1025 String "interrupt start"
1027 String "interrupt end"
1031 * All interrupts enter here.
1032 * old %eax on stack; interrupt number in %eax.
1035 pushl %ecx /* save registers */
1037 cld /* clear direction flag */
1039 pushl %ds /* save segment registers */
1043 mov %ss,%dx /* switch to kernel segments */
1046 mov $ CPU_DATA_GS,%dx
1050 * test whether already on interrupt stack
1052 movl %gs:CPU_INT_STACK_TOP,%ecx
1055 leal -INTSTACK_SIZE(%ecx),%edx
1057 jb int_from_intstack
1059 movl %esp,%edx /* & i386_interrupt_state */
1060 xchgl %ecx,%esp /* switch to interrupt stack */
1062 pushl %ecx /* save pointer to old stack */
1063 pushl %edx /* pass &i386_interrupt_state to pe_incoming_interrupt */
1064 pushl %eax /* push trap number */
1066 TIME_INT_ENTRY /* do timing */
1069 incl %gs:CPU_PREEMPTION_LEVEL
1070 #endif /* MACH_RT */
1071 incl %gs:CPU_INTERRUPT_LEVEL
1073 call EXT(PE_incoming_interrupt) /* call generic interrupt routine */
1074 addl $8,%esp /* Pop trap number and eip */
1076 .globl EXT(return_to_iret)
1077 LEXT(return_to_iret) /* (label for kdb_kintr and hardclock) */
1079 decl %gs:CPU_INTERRUPT_LEVEL
1082 decl %gs:CPU_PREEMPTION_LEVEL
1083 #endif /* MACH_RT */
1085 TIME_INT_EXIT /* do timing */
1087 popl %esp /* switch back to old stack */
1089 movl %gs:CPU_PENDING_AST,%eax
1090 testl %eax,%eax /* any pending asts? */
1091 je 1f /* no, nothing to do */
1092 testl $(EFL_VM),I_EFL(%esp) /* if in V86 */
1093 jnz ast_from_interrupt /* take it */
1094 testb $3,I_CS(%esp) /* user mode, */
1095 jnz ast_from_interrupt /* take it */
1097 cmpl ETEXT_ADDR,I_EIP(%esp) /* if within kernel-loaded task, */
1098 jnb ast_from_interrupt /* take it */
1102 cmpl $0,%gs:CPU_PREEMPTION_LEVEL /* preemption masked? */
1103 jne 1f /* yes, skip it */
1104 testl $ AST_URGENT,%eax /* any urgent requests? */
1105 je 1f /* no, skip it */
1106 cmpl $ EXT(locore_end),I_EIP(%esp) /* are we in locore code? */
1107 jb 1f /* yes, skip it */
1108 movl %gs:CPU_KERNEL_STACK,%eax
1111 andl $(-KERNEL_STACK_SIZE),%ecx
1112 testl %ecx,%ecx /* are we on the kernel stack? */
1113 jne 1f /* no, skip it */
1116 * Take an AST from kernel space. We don't need (and don't want)
1117 * to do as much as the case where the interrupt came from user
1120 #if PREEMPT_DEBUG_LOG
1125 call EXT(log_thread_action)
1128 0: String "intr preempt eip"
1130 #endif /* PREEMPT_DEBUG_LOG */
1133 pushl $1 /* push preemption flag */
1134 call EXT(i386_astintr) /* take the AST */
1135 addl $4,%esp /* pop preemption flag */
1136 #endif /* MACH_RT */
1141 pop %es /* restore segment regs */
1146 iret /* return to caller */
1150 incl %gs:CPU_PREEMPTION_LEVEL
1151 #endif /* MACH_RT */
1153 incl %gs:CPU_INTERRUPT_LEVEL
1155 movl %esp, %edx /* i386_interrupt_state */
1156 pushl %edx /* pass &i386_interrupt_state to PE_incoming_interrupt /*
1158 pushl %eax /* Push trap number */
1160 call EXT(PE_incoming_interrupt)
1161 addl $20,%esp /* pop i386_interrupt_state, gs,fs,es,ds */
1163 LEXT(return_to_iret_i) /* ( label for kdb_kintr) */
1165 addl $4,%esp /* pop trap number */
1167 decl %gs:CPU_INTERRUPT_LEVEL
1170 decl %gs:CPU_PREEMPTION_LEVEL
1171 #endif /* MACH_RT */
1173 pop %edx /* must have been on kernel segs */
1175 pop %eax /* no ASTs */
1179 * Take an AST from an interrupt.
1195 pop %es /* restore all registers ... */
1200 sti /* Reenable interrupts */
1201 pushl $0 /* zero code */
1202 pushl $0 /* zero trap number */
1203 pusha /* save general registers */
1204 push %ds /* save segment registers */
1208 mov %ss,%dx /* switch to kernel segments */
1211 mov $ CPU_DATA_GS,%dx
1215 * See if we interrupted a kernel-loaded thread executing
1219 testl $(EFL_VM),R_EFLAGS(%esp) /* in V86 mode? */
1220 jnz 0f /* user mode trap if so */
1222 jnz 0f /* user mode, back to normal */
1224 cmpl ETEXT_ADDR,R_EIP(%esp)
1225 jb 0f /* not kernel-loaded, back to normal */
1229 * Transfer the current stack frame by hand into the PCB.
1232 movl %gs:CPU_ACTIVE_KLOADED,%eax
1233 movl %gs:CPU_KERNEL_STACK,%ebx
1235 FRAME_STACK_TO_PCB(%eax,%ebx)
1242 movl %gs:CPU_KERNEL_STACK,%eax
1243 /* switch to kernel stack */
1247 pushl $0 /* push preemption flag */
1248 call EXT(i386_astintr) /* take the AST */
1249 addl $4,%esp /* pop preemption flag */
1250 popl %esp /* back to PCB stack */
1251 jmp EXT(return_from_trap) /* return */
1253 #if MACH_KDB || MACH_KGDB
1255 * kdb_kintr: enter kdb from keyboard interrupt.
1256 * Chase down the stack frames until we find one whose return
1257 * address is the interrupt handler. At that point, we have:
1259 * frame-> saved %ebp
1260 * return address in interrupt handler
1263 * return address == return_to_iret_i
1272 * frame-> saved %ebp
1273 * return address in interrupt handler
1276 * return address == return_to_iret
1277 * pointer to save area on old stack
1278 * [ saved %ebx, if accurate timing ]
1280 * old stack: saved %es
1289 * Call kdb, passing it that register save area.
1294 #endif /* MACH_KGDB */
1297 #endif /* MACH_KDB */
1298 movl %ebp,%eax /* save caller`s frame pointer */
1299 movl $ EXT(return_to_iret),%ecx /* interrupt return address 1 */
1300 movl $ EXT(return_to_iret_i),%edx /* interrupt return address 2 */
1302 0: cmpl 16(%eax),%ecx /* does this frame return to */
1303 /* interrupt handler (1)? */
1305 cmpl $kdb_from_iret,16(%eax)
1307 cmpl 16(%eax),%edx /* interrupt handler (2)? */
1309 cmpl $kdb_from_iret_i,16(%eax)
1311 movl (%eax),%eax /* try next frame */
1314 1: movl $kdb_from_iret,16(%eax) /* returns to kernel/user stack */
1317 2: movl $kdb_from_iret_i,16(%eax)
1318 /* returns to interrupt stack */
1322 * On return from keyboard interrupt, we will execute
1324 * if returning to an interrupt on the interrupt stack
1326 * if returning to an interrupt on the user or kernel stack
1329 /* save regs in known locations */
1330 pushl %ebx /* caller`s %ebx is in reg */
1338 pushl %esp /* pass regs */
1339 call EXT(kgdb_kentry) /* to kgdb */
1340 addl $4,%esp /* pop parameters */
1341 #endif /* MACH_KGDB */
1343 pushl %esp /* pass regs */
1344 call EXT(kdb_kentry) /* to kdb */
1345 addl $4,%esp /* pop parameters */
1346 #endif /* MACH_KDB */
1347 pop %gs /* restore registers */
1353 jmp EXT(return_to_iret) /* normal interrupt return */
1355 kdb_from_iret_i: /* on interrupt stack */
1356 pop %edx /* restore saved registers */
1359 pushl $0 /* zero error code */
1360 pushl $0 /* zero trap number */
1361 pusha /* save general registers */
1362 push %ds /* save segment registers */
1367 cli /* disable interrupts */
1368 CPU_NUMBER(%edx) /* get CPU number */
1369 movl CX(EXT(kgdb_stacks),%edx),%ebx
1370 xchgl %ebx,%esp /* switch to kgdb stack */
1371 pushl %ebx /* pass old sp as an arg */
1372 call EXT(kgdb_from_kernel)
1373 popl %esp /* switch back to interrupt stack */
1374 #endif /* MACH_KGDB */
1376 pushl %esp /* pass regs, */
1377 pushl $0 /* code, */
1378 pushl $-1 /* type to kdb */
1381 #endif /* MACH_KDB */
1382 pop %gs /* restore segment registers */
1386 popa /* restore general registers */
1390 #endif /* MACH_KDB || MACH_KGDB */
1394 * Mach RPC enters through a call gate, like a system call.
1398 pushf /* save flags as soon as possible */
1399 pushl %eax /* save system call number */
1400 pushl $0 /* clear trap number slot */
1402 pusha /* save the general registers */
1403 pushl %ds /* and the segment registers */
1408 mov %ss,%dx /* switch to kernel data segment */
1411 mov $ CPU_DATA_GS,%dx
1415 * Shuffle eflags,eip,cs into proper places
1418 movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
1419 movl R_CS(%esp),%ecx /* eip is in CS slot */
1420 movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
1421 movl %ecx,R_EIP(%esp) /* fix eip */
1422 movl %edx,R_CS(%esp) /* fix cs */
1423 movl %ebx,R_EFLAGS(%esp) /* fix eflags */
1427 negl %eax /* get system call number */
1428 shll $4,%eax /* manual indexing */
1431 * Check here for mach_rpc from kernel-loaded task --
1432 * - Note that kernel-loaded task returns via real return.
1433 * We didn't enter here "through" PCB (i.e., using ring 0 stack),
1434 * so transfer the stack frame into the PCB explicitly, then
1435 * start running on resulting "PCB stack". We have to set
1436 * up a simulated "uesp" manually, since there's none in the
1439 cmpl $0,%gs:CPU_ACTIVE_KLOADED
1442 movl %gs:CPU_ACTIVE_KLOADED,%ebx
1443 movl %gs:CPU_KERNEL_STACK,%edx
1446 FRAME_STACK_TO_PCB(%ebx,%edx)
1452 movl %gs:CPU_KERNEL_STACK,%ebx
1453 /* get current kernel stack */
1454 xchgl %ebx,%esp /* switch stacks - %ebx points to */
1455 /* user registers. */
1460 * Register use on entry:
1461 * eax contains syscall number
1462 * ebx contains user regs pointer
1464 #undef RPC_TRAP_REGISTERS
1465 #ifdef RPC_TRAP_REGISTERS
1471 movl EXT(mach_trap_table)(%eax),%ecx
1472 /* get number of arguments */
1473 jecxz 2f /* skip argument copy if none */
1474 movl R_UESP(%ebx),%esi /* get user stack pointer */
1475 lea 4(%esi,%ecx,4),%esi /* skip user return address, */
1476 /* and point past last argument */
1477 movl %gs:CPU_ACTIVE_KLOADED,%edx
1478 /* point to current thread */
1479 orl %edx,%edx /* if ! kernel-loaded, check addr */
1481 mov %ds,%dx /* kernel data segment access */
1484 cmpl $(VM_MAX_ADDRESS),%esi /* in user space? */
1485 ja mach_call_addr /* address error if not */
1486 movl $ USER_DS,%edx /* user data segment access */
1489 movl %esp,%edx /* save kernel ESP for error recovery */
1493 RECOVER(mach_call_addr_push)
1494 pushl %fs:(%esi) /* push argument on stack */
1495 loop 1b /* loop for all arguments */
1499 * Register use on entry:
1500 * eax contains syscall number << 4
1501 * mach_call_munger is declared regparm(1), so the first arg is %eax
1505 call EXT(mach_call_munger)
1507 movl %esp,%ecx /* get kernel stack */
1508 or $(KERNEL_STACK_SIZE-1),%ecx
1509 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
1510 movl %eax,R_EAX(%esp) /* save return value */
1511 jmp EXT(return_from_trap) /* return to user */
1515 * Special system call entry for "int 0x80", which has the "eflags"
1516 * register saved at the right place already.
1517 * Fall back to the common syscall path after saving the registers.
1522 * old esp if trapped from user
1523 * old ss if trapped from user
1525 * XXX: for the moment, we don't check for int 0x80 from kernel mode.
1527 Entry(syscall_int80)
1528 pushl %eax /* save system call number */
1529 pushl $0 /* clear trap number slot */
1531 pusha /* save the general registers */
1532 pushl %ds /* and the segment registers */
1537 mov %ss,%dx /* switch to kernel data segment */
1540 mov $ CPU_DATA_GS,%dx
1546 * System call enters through a call gate. Flags are not saved -
1547 * we must shuffle stack to look like trap save area.
1554 * eax contains system call number.
1556 * NB: below use of CPU_NUMBER assumes that macro will use correct
1557 * correct segment register for any kernel data accesses.
1561 pushf /* save flags as soon as possible */
1563 pushl %eax /* save system call number */
1564 pushl $0 /* clear trap number slot */
1566 pusha /* save the general registers */
1567 pushl %ds /* and the segment registers */
1572 mov %ss,%dx /* switch to kernel data segment */
1575 mov $ CPU_DATA_GS,%dx
1579 * Shuffle eflags,eip,cs into proper places
1582 movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
1583 movl R_CS(%esp),%ecx /* eip is in CS slot */
1584 movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
1585 movl %ecx,R_EIP(%esp) /* fix eip */
1586 movl %edx,R_CS(%esp) /* fix cs */
1587 movl %ebx,R_EFLAGS(%esp) /* fix eflags */
1591 * Check here for syscall from kernel-loaded task --
1592 * We didn't enter here "through" PCB (i.e., using ring 0 stack),
1593 * so transfer the stack frame into the PCB explicitly, then
1594 * start running on resulting "PCB stack". We have to set
1595 * up a simulated "uesp" manually, since there's none in the
1598 cmpl $0,%gs:CPU_ACTIVE_KLOADED
1601 movl %gs:CPU_ACTIVE_KLOADED,%ebx
1602 movl %gs:CPU_KERNEL_STACK,%edx
1604 FRAME_STACK_TO_PCB(%ebx,%edx)
1612 movl %gs:CPU_KERNEL_STACK,%ebx
1613 /* get current kernel stack */
1614 xchgl %ebx,%esp /* switch stacks - %ebx points to */
1615 /* user registers. */
1616 /* user regs pointer already set */
1619 * Native system call.
1620 * Register use on entry:
1621 * eax contains syscall number
1622 * ebx points to user regs
1625 negl %eax /* get system call number */
1626 jl mach_call_range /* out of range if it was positive */
1628 cmpl EXT(mach_trap_count),%eax /* check system call table bounds */
1629 jg mach_call_range /* error if out of range */
1630 shll $4,%eax /* manual indexing */
1632 movl EXT(mach_trap_table)+4(%eax),%edx
1634 cmpl $ EXT(kern_invalid),%edx /* if not "kern_invalid" */
1635 jne do_native_call /* go on with Mach syscall */
1636 shrl $4,%eax /* restore syscall number */
1637 jmp mach_call_range /* try it as a "server" syscall */
1640 * Register use on entry:
1641 * eax contains syscall number
1642 * ebx contains user regs pointer
1645 movl EXT(mach_trap_table)(%eax),%ecx
1646 /* get number of arguments */
1647 jecxz mach_call_call /* skip argument copy if none */
1648 movl R_UESP(%ebx),%esi /* get user stack pointer */
1649 lea 4(%esi,%ecx,4),%esi /* skip user return address, */
1650 /* and point past last argument */
1651 movl %gs:CPU_ACTIVE_KLOADED,%edx
1652 /* point to current thread */
1653 orl %edx,%edx /* if kernel-loaded, skip addr check */
1655 mov %ds,%dx /* kernel data segment access */
1658 cmpl $(VM_MAX_ADDRESS),%esi /* in user space? */
1659 ja mach_call_addr /* address error if not */
1660 movl $ USER_DS,%edx /* user data segment access */
1663 movl %esp,%edx /* save kernel ESP for error recovery */
1667 RECOVER(mach_call_addr_push)
1668 pushl %fs:(%esi) /* push argument on stack */
1669 loop 2b /* loop for all arguments */
1672 * Register use on entry:
1673 * eax contains syscall number
1674 * ebx contains user regs pointer
1680 #if ETAP_EVENT_MONITOR
1681 cmpl $0x200, %eax /* is this mach_msg? */
1682 jz make_syscall /* if yes, don't record event */
1684 pushal /* Otherwise: save registers */
1685 pushl %eax /* push syscall number on stack*/
1686 call EXT(etap_machcall_probe1) /* call event begin probe */
1687 add $4,%esp /* restore stack */
1688 popal /* restore registers */
1690 call *EXT(mach_trap_table)+4(%eax) /* call procedure */
1692 call EXT(etap_machcall_probe2) /* call event end probe */
1694 jmp skip_syscall /* syscall already made */
1695 #endif /* ETAP_EVENT_MONITOR */
1700 * mach_call_munger is declared regparm(1) so the first arg is %eax
1702 call EXT(mach_call_munger)
1706 movl %esp,%ecx /* get kernel stack */
1707 or $(KERNEL_STACK_SIZE-1),%ecx
1708 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
1709 movl %eax,R_EAX(%esp) /* save return value */
1710 jmp EXT(return_from_trap) /* return to user */
1713 * Address out of range. Change to page fault.
1714 * %esi holds failing address.
1715 * Register use on entry:
1716 * ebx contains user regs pointer
1718 mach_call_addr_push:
1719 movl %edx,%esp /* clean parameters from stack */
1721 movl %esi,R_CR2(%ebx) /* set fault address */
1722 movl $(T_PAGE_FAULT),R_TRAPNO(%ebx)
1723 /* set page-fault trap */
1724 movl $(T_PF_USER),R_ERR(%ebx)
1725 /* set error code - read user space */
1727 jmp EXT(take_trap) /* treat as a trap */
1730 * System call out of range. Treat as invalid-instruction trap.
1731 * (? general protection?)
1732 * Register use on entry:
1733 * eax contains syscall number
1738 push $1 /* code_cnt = 1 */
1739 push %edx /* exception_type_t (see i/f docky) */
1742 call EXT(exception_triage)
1745 .globl EXT(syscall_failed)
1746 LEXT(syscall_failed)
1747 movl %esp,%ecx /* get kernel stack */
1748 or $(KERNEL_STACK_SIZE-1),%ecx
1749 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
1750 movl %gs:CPU_KERNEL_STACK,%ebx
1751 /* get current kernel stack */
1752 xchgl %ebx,%esp /* switch stacks - %ebx points to */
1753 /* user registers. */
1754 /* user regs pointer already set */
1756 movl $(T_INVALID_OPCODE),R_TRAPNO(%ebx)
1757 /* set invalid-operation trap */
1758 movl $0,R_ERR(%ebx) /* clear error code */
1760 jmp EXT(take_trap) /* treat as a trap */
1769 * Copy from user address space.
1770 * arg0: user address
1771 * arg1: kernel address
1777 pushl %edi /* save registers */
1779 movl 8+S_ARG0,%esi /* get user start address */
1780 movl 8+S_ARG1,%edi /* get kernel destination address */
1781 movl 8+S_ARG2,%edx /* get count */
1783 lea 0(%esi,%edx),%eax /* get user end address + 1 */
1785 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get active thread */
1786 movl ACT_MAP(%ecx),%ecx /* get act->map */
1787 movl MAP_PMAP(%ecx),%ecx /* get map->pmap */
1788 cmpl EXT(kernel_pmap), %ecx
1790 movl $ USER_DS,%ecx /* user data segment access */
1794 jb copyin_fail /* fail if wrap-around */
1796 movl %edx,%ecx /* move by longwords first */
1799 RECOVER(copyin_fail)
1801 movsl /* move longwords */
1802 movl %edx,%ecx /* now move remaining bytes */
1805 RECOVER(copyin_fail)
1808 xorl %eax,%eax /* return 0 for success */
1810 mov %ss,%di /* restore kernel data segment */
1813 popl %edi /* restore registers */
1815 ret /* and return */
1818 movl $ EFAULT,%eax /* return error for failure */
1819 jmp copy_ret /* pop frame and return */
1822 * Copy string from user address space.
1823 * arg0: user address
1824 * arg1: kernel address
1825 * arg2: max byte count
1826 * arg3: actual byte count (OUT)
1830 pushl %edi /* save registers */
1832 movl 8+S_ARG0,%esi /* get user start address */
1833 movl 8+S_ARG1,%edi /* get kernel destination address */
1834 movl 8+S_ARG2,%edx /* get count */
1836 lea 0(%esi,%edx),%eax /* get user end address + 1 */
1838 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get active thread */
1839 movl ACT_MAP(%ecx),%ecx /* get act->map */
1840 movl MAP_PMAP(%ecx),%ecx /* get map->pmap */
1841 cmpl EXT(kernel_pmap), %ecx
1843 mov %ds,%cx /* kernel data segment access */
1846 movl $ USER_DS,%ecx /* user data segment access */
1854 RECOVER(copystr_fail) /* copy bytes... */
1857 testl %edi,%edi /* if kernel address is ... */
1858 jz 3f /* not NULL */
1859 movb %al,(%edi) /* copy the byte */
1863 je 5f /* Zero count.. error out */
1865 jne 2b /* .. a NUL found? */
1866 jmp 4f /* return zero (%eax) */
1868 movl $ ENAMETOOLONG,%eax /* String is too long.. */
1870 movl 8+S_ARG3,%edi /* get OUT len ptr */
1872 jz copystr_ret /* if null, just return */
1874 movl %esi,(%edi) /* else set OUT arg to xfer len */
1876 popl %edi /* restore registers */
1878 ret /* and return */
1881 movl $ EFAULT,%eax /* return error for failure */
1882 jmp copy_ret /* pop frame and return */
1885 * Copy to user address space.
1886 * arg0: kernel address
1887 * arg1: user address
1893 pushl %edi /* save registers */
1896 movl 12+S_ARG0,%esi /* get kernel start address */
1897 movl 12+S_ARG1,%edi /* get user start address */
1898 movl 12+S_ARG2,%edx /* get count */
1900 leal 0(%edi,%edx),%eax /* get user end address + 1 */
1902 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get active thread */
1903 movl ACT_MAP(%ecx),%ecx /* get act->map */
1904 movl MAP_PMAP(%ecx),%ecx /* get map->pmap */
1905 cmpl EXT(kernel_pmap), %ecx
1907 mov %ds,%cx /* else kernel data segment access */
1915 * Check whether user address space is writable
1916 * before writing to it - hardware is broken.
1918 * Skip check if "user" address is really in
1919 * kernel space (i.e., if it's in a kernel-loaded
1923 * esi/edi source/dest pointers for rep/mov
1924 * ecx counter for rep/mov
1925 * edx counts down from 3rd arg
1926 * eax count of bytes for each (partial) page copy
1927 * ebx shadows edi, used to adjust edx
1929 movl %edi,%ebx /* copy edi for syncing up */
1931 /* if restarting after a partial copy, put edx back in sync, */
1932 addl %ebx,%edx /* edx -= (edi - ebx); */
1934 movl %edi,%ebx /* ebx = edi; */
1937 * Copy only what fits on the current destination page.
1938 * Check for write-fault again on the next page.
1940 leal NBPG(%edi),%eax /* point to */
1941 andl $(-NBPG),%eax /* start of next page */
1942 subl %edi,%eax /* get number of bytes to that point */
1943 cmpl %edx,%eax /* bigger than count? */
1945 movl %edx,%eax /* use count */
1948 movl %eax,%ecx /* move by longwords first */
1951 RECOVER(copyout_fail)
1953 RETRY(copyout_retry)
1956 movl %eax,%ecx /* now move remaining bytes */
1959 RECOVER(copyout_fail)
1961 RETRY(copyout_retry)
1964 movl %edi,%ebx /* copy edi for syncing up */
1965 subl %eax,%edx /* and decrement count */
1966 jg copyout_retry /* restart on next page if not done */
1967 xorl %eax,%eax /* return 0 for success */
1969 mov %ss,%di /* restore kernel segment */
1973 popl %edi /* restore registers */
1975 ret /* and return */
1978 movl $ EFAULT,%eax /* return error for failure */
1979 jmp copyout_ret /* pop frame and return */
1996 pushl %eax /* get stack space */
2012 xor %eax,%eax /* clear high 16 bits of eax */
2013 fnstsw %ax /* read FP status */
2017 * Clear FPU exceptions
2024 * Clear task-switched flag.
2031 * Save complete FPU state. Save error for later.
2034 movl 4(%esp),%eax /* get save area pointer */
2035 fnsave (%eax) /* save complete state, including */
2040 * Restore FPU state.
2043 movl 4(%esp),%eax /* get save area pointer */
2044 frstor (%eax) /* restore complete state */
2054 * Don't set PDBR to a new value (hence invalidating the
2055 * "paging cache") if the new value matches the current one.
2057 movl %cr3,%edx /* get current cr3 value */
2059 je 0f /* if two are equal, don't set */
2060 movl %eax,%cr3 /* load it (and flush cache) */
2069 andl $(~0x7), %eax /* remove cpu number */
2076 movl %cr3,%eax /* flush tlb by reloading CR3 */
2077 movl %eax,%cr3 /* with itself */
2091 .byte 0x0f,0x20,0xe0 /* movl %cr4, %eax */
2099 .byte 0x0f,0x22,0xe0 /* movl %eax, %cr4 */
2118 * Read task register.
2126 * Set task register. Also clears busy bit of task descriptor.
2129 movl S_ARG0,%eax /* get task segment number */
2130 subl $8,%esp /* push space for SGDT */
2131 sgdt 2(%esp) /* store GDT limit and base (linear) */
2132 movl 4(%esp),%edx /* address GDT */
2133 movb $(K_TSS),5(%edx,%eax) /* fix access byte in task descriptor */
2134 ltr %ax /* load task register */
2135 addl $8,%esp /* clear stack */
2136 ret /* and return */
2139 * Set task-switched flag.
2142 movl %cr0,%eax /* get cr0 */
2143 orl $(CR0_TS),%eax /* or in TS bit */
2144 movl %eax,%cr0 /* set cr0 */
2148 * io register must not be used on slaves (no AT bus)
2150 #define ILL_ON_SLAVE
2158 #define PUSH_FRAME FRAME
2159 #define POP_FRAME EMARF
2161 #else /* MACH_ASSERT */
2169 #endif /* MACH_ASSERT */
2172 #if MACH_KDB || MACH_ASSERT
2175 * Following routines are also defined as macros in i386/pio.h
2176 * Compile then when MACH_KDB is configured so that they
2177 * can be invoked from the debugger.
2181 * void outb(unsigned char *io_port,
2182 * unsigned char byte)
2184 * Output a byte to an IO port.
2189 movl ARG0,%edx /* IO port address */
2190 movl ARG1,%eax /* data to output */
2191 outb %al,%dx /* send it out */
2196 * unsigned char inb(unsigned char *io_port)
2198 * Input a byte from an IO port.
2203 movl ARG0,%edx /* IO port address */
2204 xor %eax,%eax /* clear high bits of register */
2205 inb %dx,%al /* get the byte */
2210 * void outw(unsigned short *io_port,
2211 * unsigned short word)
2213 * Output a word to an IO port.
2218 movl ARG0,%edx /* IO port address */
2219 movl ARG1,%eax /* data to output */
2220 outw %ax,%dx /* send it out */
2225 * unsigned short inw(unsigned short *io_port)
2227 * Input a word from an IO port.
2232 movl ARG0,%edx /* IO port address */
2233 xor %eax,%eax /* clear high bits of register */
2234 inw %dx,%ax /* get the word */
2239 * void outl(unsigned int *io_port,
2240 * unsigned int byte)
2242 * Output an int to an IO port.
2247 movl ARG0,%edx /* IO port address*/
2248 movl ARG1,%eax /* data to output */
2249 outl %eax,%dx /* send it out */
2254 * unsigned int inl(unsigned int *io_port)
2256 * Input an int from an IO port.
2261 movl ARG0,%edx /* IO port address */
2262 inl %dx,%eax /* get the int */
2266 #endif /* MACH_KDB || MACH_ASSERT*/
2269 * void loutb(unsigned byte *io_port,
2270 * unsigned byte *data,
2271 * unsigned int count)
2273 * Output an array of bytes to an IO port.
2279 movl %esi,%eax /* save register */
2280 movl ARG0,%edx /* get io port number */
2281 movl ARG1,%esi /* get data address */
2282 movl ARG2,%ecx /* get count */
2286 movl %eax,%esi /* restore register */
2292 * void loutw(unsigned short *io_port,
2293 * unsigned short *data,
2294 * unsigned int count)
2296 * Output an array of shorts to an IO port.
2302 movl %esi,%eax /* save register */
2303 movl ARG0,%edx /* get io port number */
2304 movl ARG1,%esi /* get data address */
2305 movl ARG2,%ecx /* get count */
2309 movl %eax,%esi /* restore register */
2314 * void loutw(unsigned short io_port,
2315 * unsigned int *data,
2316 * unsigned int count)
2318 * Output an array of longs to an IO port.
2324 movl %esi,%eax /* save register */
2325 movl ARG0,%edx /* get io port number */
2326 movl ARG1,%esi /* get data address */
2327 movl ARG2,%ecx /* get count */
2331 movl %eax,%esi /* restore register */
2337 * void linb(unsigned char *io_port,
2338 * unsigned char *data,
2339 * unsigned int count)
2341 * Input an array of bytes from an IO port.
2347 movl %edi,%eax /* save register */
2348 movl ARG0,%edx /* get io port number */
2349 movl ARG1,%edi /* get data address */
2350 movl ARG2,%ecx /* get count */
2354 movl %eax,%edi /* restore register */
2360 * void linw(unsigned short *io_port,
2361 * unsigned short *data,
2362 * unsigned int count)
2364 * Input an array of shorts from an IO port.
2370 movl %edi,%eax /* save register */
2371 movl ARG0,%edx /* get io port number */
2372 movl ARG1,%edi /* get data address */
2373 movl ARG2,%ecx /* get count */
2377 movl %eax,%edi /* restore register */
2383 * void linl(unsigned short io_port,
2384 * unsigned int *data,
2385 * unsigned int count)
2387 * Input an array of longs from an IO port.
2393 movl %edi,%eax /* save register */
2394 movl ARG0,%edx /* get io port number */
2395 movl ARG1,%edi /* get data address */
2396 movl ARG2,%ecx /* get count */
2400 movl %eax,%edi /* restore register */
2406 * int inst_fetch(int eip, int cs);
2408 * Fetch instruction byte. Return -1 if invalid address.
2410 .globl EXT(inst_fetch)
2412 movl S_ARG1, %eax /* get segment */
2413 movw %ax,%fs /* into FS */
2414 movl S_ARG0, %eax /* get offset */
2416 RETRY(EXT(inst_fetch)) /* re-load FS on retry */
2418 RECOVER(EXT(inst_fetch_fault))
2419 movzbl %fs:(%eax),%eax /* load instruction byte */
2422 LEXT(inst_fetch_fault)
2423 movl $-1,%eax /* return -1 if error */
2429 * kdp_copy_kmem(char *src, char *dst, int count)
2431 * Similar to copyin except that both addresses are kernel addresses.
2434 ENTRY(kdp_copy_kmem)
2436 pushl %edi /* save registers */
2438 movl 8+S_ARG0,%esi /* get kernel start address */
2439 movl 8+S_ARG1,%edi /* get kernel destination address */
2441 movl 8+S_ARG2,%edx /* get count */
2443 lea 0(%esi,%edx),%eax /* get kernel end address + 1 */
2446 jb kdp_vm_read_fail /* fail if wrap-around */
2448 movl %edx,%ecx /* move by longwords first */
2451 RECOVER(kdp_vm_read_fail)
2453 movsl /* move longwords */
2454 movl %edx,%ecx /* now move remaining bytes */
2457 RECOVER(kdp_vm_read_fail)
2461 movl 8+S_ARG2,%edx /* get count */
2462 subl %ecx,%edx /* Return number of bytes transfered */
2465 popl %edi /* restore registers */
2467 ret /* and return */
2470 xorl %eax,%eax /* didn't copy a thing. */
2478 * int rdmsr_carefully(uint32_t msr, uint32_t *lo, uint32_t *hi)
2480 ENTRY(rdmsr_carefully)
2497 * Done with recovery and retry tables.
2510 /* dr<i>(address, type, len, persistence)
2514 movl %eax,EXT(dr_addr)
2520 movl %eax,EXT(dr_addr)+1*4
2526 movl %eax,EXT(dr_addr)+2*4
2533 movl %eax,EXT(dr_addr)+3*4
2542 movl %edx,EXT(dr_addr)+4*4
2543 andl dr_msk(,%ecx,2),%edx /* clear out new entry */
2544 movl %edx,EXT(dr_addr)+5*4
2563 movl %edx,EXT(dr_addr)+7*4
2611 lidt null_idtr /* disable the interrupt handler */
2612 xor %ecx,%ecx /* generate a divide by zero */
2613 div %ecx,%eax /* reboot now */
2614 ret /* this will "never" be executed */
2616 #endif /* SYMMETRY */
2620 * setbit(int bitno, int *s) - set bit in bit string
2623 movl S_ARG0, %ecx /* bit number */
2624 movl S_ARG1, %eax /* address */
2625 btsl %ecx, (%eax) /* set bit */
2629 * clrbit(int bitno, int *s) - clear bit in bit string
2632 movl S_ARG0, %ecx /* bit number */
2633 movl S_ARG1, %eax /* address */
2634 btrl %ecx, (%eax) /* clear bit */
2638 * ffsbit(int *s) - find first set bit in bit string
2641 movl S_ARG0, %ecx /* address */
2642 movl $0, %edx /* base offset */
2644 bsfl (%ecx), %eax /* check argument bits */
2645 jnz 1f /* found bit, return */
2646 addl $4, %ecx /* increment address */
2647 addl $32, %edx /* increment offset */
2648 jmp 0b /* try again */
2650 addl %edx, %eax /* return offset */
2654 * testbit(int nr, volatile void *array)
2656 * Test to see if the bit is set within the bit string
2660 movl S_ARG0,%eax /* Get the bit to test */
2661 movl S_ARG1,%ecx /* get the array string */
2673 movl 4(%ebp), %eax /* fetch pc of caller */
2676 ENTRY(tvals_to_etap)
2678 movl $1000000000, %ecx
2685 * etap_time_sub(etap_time_t stop, etap_time_t start)
2687 * 64bit subtract, returns stop - start
2689 ENTRY(etap_time_sub)
2690 movl S_ARG0, %eax /* stop.low */
2691 movl S_ARG1, %edx /* stop.hi */
2692 subl S_ARG2, %eax /* stop.lo - start.lo */
2693 sbbl S_ARG3, %edx /* stop.hi - start.hi */
2702 * jail: set the EIP to "jail" to block a kernel thread.
2703 * Useful to debug synchronization problems on MPs.
2710 * div_scale(unsigned int dividend,
2711 * unsigned int divisor,
2712 * unsigned int *scale)
2714 * This function returns (dividend << *scale) //divisor where *scale
2715 * is the largest possible value before overflow. This is used in
2716 * computation where precision must be achieved in order to avoid
2717 * floating point usage.
2721 * while (((dividend >> *scale) >= divisor))
2723 * *scale = 32 - *scale;
2724 * return ((dividend << *scale) / divisor);
2728 xorl %ecx, %ecx /* *scale = 0 */
2730 movl ARG0, %edx /* get dividend */
2732 cmpl ARG1, %edx /* if (divisor > dividend) */
2733 jle 1f /* goto 1f */
2734 addl $1, %ecx /* (*scale)++ */
2735 shrdl $1, %edx, %eax /* dividend >> 1 */
2736 shrl $1, %edx /* dividend >> 1 */
2737 jmp 0b /* goto 0b */
2739 divl ARG1 /* (dividend << (32 - *scale)) / divisor */
2740 movl ARG2, %edx /* get scale */
2741 movl $32, (%edx) /* *scale = 32 */
2742 subl %ecx, (%edx) /* *scale -= %ecx */
2748 * mul_scale(unsigned int multiplicand,
2749 * unsigned int multiplier,
2750 * unsigned int *scale)
2752 * This function returns ((multiplicand * multiplier) >> *scale) where
2753 * scale is the largest possible value before overflow. This is used in
2754 * computation where precision must be achieved in order to avoid
2755 * floating point usage.
2759 * while (overflow((multiplicand * multiplier) >> *scale))
2761 * return ((multiplicand * multiplier) >> *scale);
2765 xorl %ecx, %ecx /* *scale = 0 */
2766 movl ARG0, %eax /* get multiplicand */
2767 mull ARG1 /* multiplicand * multiplier */
2769 cmpl $0, %edx /* if (!overflow()) */
2771 addl $1, %ecx /* (*scale)++ */
2772 shrdl $1, %edx, %eax /* (multiplicand * multiplier) >> 1 */
2773 shrl $1, %edx /* (multiplicand * multiplier) >> 1 */
2776 movl ARG2, %edx /* get scale */
2777 movl %ecx, (%edx) /* set *scale */
2783 * BSD System call entry point..
2786 Entry(trap_unix_syscall)
2788 pushf /* save flags as soon as possible */
2790 pushl %eax /* save system call number */
2791 pushl $0 /* clear trap number slot */
2793 pusha /* save the general registers */
2794 pushl %ds /* and the segment registers */
2799 mov %ss,%dx /* switch to kernel data segment */
2802 mov $ CPU_DATA_GS,%dx
2806 * Shuffle eflags,eip,cs into proper places
2809 movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
2810 movl R_CS(%esp),%ecx /* eip is in CS slot */
2811 movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
2812 movl %ecx,R_EIP(%esp) /* fix eip */
2813 movl %edx,R_CS(%esp) /* fix cs */
2814 movl %ebx,R_EFLAGS(%esp) /* fix eflags */
2818 negl %eax /* get system call number */
2819 shll $4,%eax /* manual indexing */
2821 movl %gs:CPU_KERNEL_STACK,%ebx
2822 /* get current kernel stack */
2823 xchgl %ebx,%esp /* switch stacks - %ebx points to */
2824 /* user registers. */
2827 * Register use on entry:
2828 * eax contains syscall number
2829 * ebx contains user regs pointer
2832 pushl %ebx /* Push the regs set onto stack */
2833 call EXT(unix_syscall)
2835 movl %esp,%ecx /* get kernel stack */
2836 or $(KERNEL_STACK_SIZE-1),%ecx
2837 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
2838 movl %eax,R_EAX(%esp) /* save return value */
2839 jmp EXT(return_from_trap) /* return to user */
2842 * Entry point for machdep system calls..
2845 Entry(trap_machdep_syscall)
2846 pushf /* save flags as soon as possible */
2847 pushl %eax /* save system call number */
2848 pushl $0 /* clear trap number slot */
2850 pusha /* save the general registers */
2851 pushl %ds /* and the segment registers */
2856 mov %ss,%dx /* switch to kernel data segment */
2859 mov $ CPU_DATA_GS,%dx
2863 * Shuffle eflags,eip,cs into proper places
2866 movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
2867 movl R_CS(%esp),%ecx /* eip is in CS slot */
2868 movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
2869 movl %ecx,R_EIP(%esp) /* fix eip */
2870 movl %edx,R_CS(%esp) /* fix cs */
2871 movl %ebx,R_EFLAGS(%esp) /* fix eflags */
2875 negl %eax /* get system call number */
2876 shll $4,%eax /* manual indexing */
2878 movl %gs:CPU_KERNEL_STACK,%ebx
2879 /* get current kernel stack */
2880 xchgl %ebx,%esp /* switch stacks - %ebx points to */
2881 /* user registers. */
2884 * Register use on entry:
2885 * eax contains syscall number
2886 * ebx contains user regs pointer
2890 call EXT(machdep_syscall)
2892 movl %esp,%ecx /* get kernel stack */
2893 or $(KERNEL_STACK_SIZE-1),%ecx
2894 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
2895 movl %eax,R_EAX(%esp) /* save return value */
2896 jmp EXT(return_from_trap) /* return to user */
2898 Entry(trap_mach25_syscall)
2899 pushf /* save flags as soon as possible */
2900 pushl %eax /* save system call number */
2901 pushl $0 /* clear trap number slot */
2903 pusha /* save the general registers */
2904 pushl %ds /* and the segment registers */
2909 mov %ss,%dx /* switch to kernel data segment */
2912 mov $ CPU_DATA_GS,%dx
2916 * Shuffle eflags,eip,cs into proper places
2919 movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
2920 movl R_CS(%esp),%ecx /* eip is in CS slot */
2921 movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
2922 movl %ecx,R_EIP(%esp) /* fix eip */
2923 movl %edx,R_CS(%esp) /* fix cs */
2924 movl %ebx,R_EFLAGS(%esp) /* fix eflags */
2928 negl %eax /* get system call number */
2929 shll $4,%eax /* manual indexing */
2931 movl %gs:CPU_KERNEL_STACK,%ebx
2932 /* get current kernel stack */
2933 xchgl %ebx,%esp /* switch stacks - %ebx points to */
2934 /* user registers. */
2937 * Register use on entry:
2938 * eax contains syscall number
2939 * ebx contains user regs pointer
2943 call EXT(mach25_syscall)
2945 movl %esp,%ecx /* get kernel stack */
2946 or $(KERNEL_STACK_SIZE-1),%ecx
2947 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
2948 movl %eax,R_EAX(%esp) /* save return value */
2949 jmp EXT(return_from_trap) /* return to user */