2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990 Carnegie Mellon University
34 * All Rights Reserved.
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
58 #include <platforms.h>
60 #include <mach_kgdb.h>
62 #include <stat_time.h>
63 #include <mach_assert.h>
65 #include <sys/errno.h>
67 #include <i386/cpuid.h>
68 #include <i386/eflags.h>
69 #include <i386/proc_reg.h>
70 #include <i386/trap.h>
72 #include <mach/exception_types.h>
74 #define _ARCH_I386_ASM_HELP_H_ /* Prevent inclusion of user header */
75 #include <mach/i386/syscall_sw.h>
80 * PTmap is recursive pagemap at top of virtual address space.
81 * Within PTmap, the page directory can be found (third indirection).
83 .globl _PTmap,_PTD,_PTDpde
84 .set _PTmap,(PTDPTDI << PDESHIFT)
85 .set _PTD,_PTmap + (PTDPTDI * NBPG)
86 .set _PTDpde,_PTD + (PTDPTDI * PDESIZE)
89 * APTmap, APTD is the alternate recursive pagemap.
90 * It's used when modifying another process's page tables.
92 .globl _APTmap,_APTD,_APTDpde
93 .set _APTmap,(APTDPTDI << PDESHIFT)
94 .set _APTD,_APTmap + (APTDPTDI * NBPG)
95 .set _APTDpde,_PTD + (APTDPTDI * PDESIZE)
98 /* Under Mach-O, etext is a variable which contains
99 * the last text address
101 #define ETEXT_ADDR (EXT(etext))
103 /* Under ELF and other non-Mach-O formats, the address of
104 * etext represents the last text address
106 #define ETEXT_ADDR $ EXT(etext)
109 #define CX(addr,reg) addr(,reg,4)
112 * The following macros make calls into C code.
113 * They dynamically align the stack to 16 bytes.
114 * Arguments are moved (not pushed) onto the correctly aligned stack.
115 * NOTE: EDI is destroyed in the process, and hence cannot
116 * be directly used as a parameter. Users of this macro must
117 * independently preserve EDI (a non-volatile) if the routine is
118 * intended to be called from C, for instance.
123 andl $0xFFFFFFF0, %esp ;\
127 #define CCALL1(fn, arg1) \
130 andl $0xFFFFFFF0, %esp ;\
131 movl arg1, 0(%esp) ;\
135 #define CCALL2(fn, arg1, arg2) \
138 andl $0xFFFFFFF0, %esp ;\
139 movl arg2, 4(%esp) ;\
140 movl arg1, 0(%esp) ;\
144 #define CCALL3(fn, arg1, arg2, arg3) \
147 andl $0xFFFFFFF0, %esp ;\
148 movl arg3, 8(%esp) ;\
149 movl arg2, 4(%esp) ;\
150 movl arg1, 0(%esp) ;\
162 #define RECOVERY_SECTION .section __VECTORS, __recover
164 #define RECOVERY_SECTION .text
165 #define RECOVERY_SECTION .text
168 #define RECOVER_TABLE_START \
170 .globl EXT(recover_table) ;\
171 LEXT(recover_table) ;\
174 #define RECOVER(addr) \
181 #define RECOVER_TABLE_END \
183 .globl EXT(recover_table_end) ;\
184 LEXT(recover_table_end) ;\
188 * Allocate recovery and table.
200 movl %eax,TIMER_HIGHCHK(%ecx)
201 movl %edx,TIMER_LOW(%ecx)
202 movl %eax,TIMER_HIGH(%ecx)
207 0: movl TIMER_HIGH(%ecx),%edx
208 movl TIMER_LOW(%ecx),%eax
209 cmpl TIMER_HIGHCHK(%ecx),%edx
215 #define TIME_TRAP_UENTRY
216 #define TIME_TRAP_UEXIT
217 #define TIME_INT_ENTRY
218 #define TIME_INT_EXIT
226 * Nanotime returned in %edx:%eax.
227 * Computed from tsc based on the scale factor
228 * and an implicit 32 bit shift.
229 * This code must match what _rtc_nanotime_read does in
230 * i386/machine_routines_asm.s. Failure to do so can
231 * result in "weird" timing results.
233 * Uses %eax, %ebx, %ecx, %edx, %esi, %edi.
235 #define RNT_INFO _rtc_nanotime_info
237 lea RNT_INFO,%edi ; \
239 movl RNT_GENERATION(%edi),%esi /* being updated? */ ; \
241 jz 0b /* wait until done */ ; \
243 subl RNT_TSC_BASE(%edi),%eax ; \
244 sbbl RNT_TSC_BASE+4(%edi),%edx /* tsc - tsc_base */ ; \
245 movl RNT_SCALE(%edi),%ecx /* * scale factor */ ; \
253 addl RNT_NS_BASE(%edi),%eax /* + ns_base */ ; \
254 adcl RNT_NS_BASE+4(%edi),%edx ; \
255 cmpl RNT_GENERATION(%edi),%esi /* check for update */ ; \
256 jne 0b /* do it all again */
260 * Add 64-bit delta in register dreg : areg to timer pointed to by register treg.
262 #define TIMER_UPDATE(treg,dreg,areg) \
263 addl TIMER_LOW(treg),areg /* add low bits */ ; \
264 adcl dreg,TIMER_HIGH(treg) /* add carry high bits */ ; \
265 movl areg,TIMER_LOW(treg) /* store updated low bit */ ; \
266 movl TIMER_HIGH(treg),dreg /* copy high bits */ ; \
267 movl dreg,TIMER_HIGHCHK(treg) /* to high check */
270 * Add time delta to old timer and start new.
272 #define TIMER_EVENT(old,new) \
273 NANOTIME /* edx:eax nanosecs */ ; \
274 movl %eax,%esi /* save timestamp */ ; \
275 movl %edx,%edi /* save timestamp */ ; \
276 movl %gs:CPU_PROCESSOR,%ebx /* get current processor */ ; \
277 movl THREAD_TIMER(%ebx),%ecx /* get current timer */ ; \
278 subl TIMER_TSTAMP(%ecx),%eax /* compute elapsed time */ ; \
279 sbbl TIMER_TSTAMP+4(%ecx),%edx /* compute elapsed time */ ; \
280 TIMER_UPDATE(%ecx,%edx,%eax) /* update timer */ ; \
281 addl $(new##_TIMER-old##_TIMER),%ecx /* point to new timer */ ; \
282 movl %esi,TIMER_TSTAMP(%ecx) /* set timestamp */ ; \
283 movl %edi,TIMER_TSTAMP+4(%ecx) /* set timestamp */ ; \
284 movl %ecx,THREAD_TIMER(%ebx) /* set current timer */ ; \
285 movl %esi,%eax /* restore timestamp */ ; \
286 movl %edi,%edx /* restore timestamp */ ; \
287 movl CURRENT_STATE(%ebx),%ecx /* current state */ ; \
288 subl TIMER_TSTAMP(%ecx),%eax /* compute elapsed time */ ; \
289 sbbl TIMER_TSTAMP+4(%ecx),%edx /* compute elapsed time */ ; \
290 TIMER_UPDATE(%ecx,%edx,%eax) /* update timer */ ; \
291 addl $(new##_STATE-old##_STATE),%ecx /* point to new state */ ; \
292 movl %ecx,CURRENT_STATE(%ebx) /* set current state */ ; \
293 movl %esi,TIMER_TSTAMP(%ecx) /* set timestamp */ ; \
294 movl %edi,TIMER_TSTAMP+4(%ecx) /* set timestamp */
297 * Update time on user trap entry.
298 * Uses %eax,%ebx,%ecx,%edx,%esi,%edi.
300 #define TIME_TRAP_UENTRY TIMER_EVENT(USER,SYSTEM)
303 * update time on user trap exit.
304 * Uses %eax,%ebx,%ecx,%edx,%esi,%edi.
306 #define TIME_TRAP_UEXIT TIMER_EVENT(SYSTEM,USER)
309 * update time on interrupt entry.
310 * Uses %eax,%ebx,%ecx,%edx,%esi,%edi.
311 * Saves processor state info on stack.
313 #define TIME_INT_ENTRY \
314 NANOTIME /* edx:eax nanosecs */ ; \
315 movl %eax,%gs:CPU_INT_EVENT_TIME /* save in cpu data */ ; \
316 movl %edx,%gs:CPU_INT_EVENT_TIME+4 /* save in cpu data */ ; \
317 movl %eax,%esi /* save timestamp */ ; \
318 movl %edx,%edi /* save timestamp */ ; \
319 movl %gs:CPU_PROCESSOR,%ebx /* get current processor */ ; \
320 movl THREAD_TIMER(%ebx),%ecx /* get current timer */ ; \
321 subl TIMER_TSTAMP(%ecx),%eax /* compute elapsed time */ ; \
322 sbbl TIMER_TSTAMP+4(%ecx),%edx /* compute elapsed time */ ; \
323 TIMER_UPDATE(%ecx,%edx,%eax) /* update timer */ ; \
324 movl KERNEL_TIMER(%ebx),%ecx /* point to kernel timer */ ; \
325 movl %esi,TIMER_TSTAMP(%ecx) /* set timestamp */ ; \
326 movl %edi,TIMER_TSTAMP+4(%ecx) /* set timestamp */ ; \
327 movl %esi,%eax /* restore timestamp */ ; \
328 movl %edi,%edx /* restore timestamp */ ; \
329 movl CURRENT_STATE(%ebx),%ecx /* get current state */ ; \
330 pushl %ecx /* save state */ ; \
331 subl TIMER_TSTAMP(%ecx),%eax /* compute elapsed time */ ; \
332 sbbl TIMER_TSTAMP+4(%ecx),%edx /* compute elapsed time */ ; \
333 TIMER_UPDATE(%ecx,%edx,%eax) /* update timer */ ; \
334 leal IDLE_STATE(%ebx),%eax /* get idle state */ ; \
335 cmpl %eax,%ecx /* compare current state */ ; \
336 je 0f /* skip if equal */ ; \
337 leal SYSTEM_STATE(%ebx),%ecx /* get system state */ ; \
338 movl %ecx,CURRENT_STATE(%ebx) /* set current state */ ; \
339 0: movl %esi,TIMER_TSTAMP(%ecx) /* set timestamp */ ; \
340 movl %edi,TIMER_TSTAMP+4(%ecx) /* set timestamp */
343 * update time on interrupt exit.
344 * Uses %eax,%ebx,%ecx,%edx,%esi,%edi.
345 * Restores processor state info from stack.
347 #define TIME_INT_EXIT \
348 NANOTIME /* edx:eax nanosecs */ ; \
349 movl %eax,%gs:CPU_INT_EVENT_TIME /* save in cpu data */ ; \
350 movl %edx,%gs:CPU_INT_EVENT_TIME+4 /* save in cpu data */ ; \
351 movl %eax,%esi /* save timestamp */ ; \
352 movl %edx,%edi /* save timestamp */ ; \
353 movl %gs:CPU_PROCESSOR,%ebx /* get current processor */ ; \
354 movl KERNEL_TIMER(%ebx),%ecx /* point to kernel timer */ ; \
355 subl TIMER_TSTAMP(%ecx),%eax /* compute elapsed time */ ; \
356 sbbl TIMER_TSTAMP+4(%ecx),%edx /* compute elapsed time */ ; \
357 TIMER_UPDATE(%ecx,%edx,%eax) /* update timer */ ; \
358 movl THREAD_TIMER(%ebx),%ecx /* interrupted timer */ ; \
359 movl %esi,TIMER_TSTAMP(%ecx) /* set timestamp */ ; \
360 movl %edi,TIMER_TSTAMP+4(%ecx) /* set timestamp */ ; \
361 movl %esi,%eax /* restore timestamp */ ; \
362 movl %edi,%edx /* restore timestamp */ ; \
363 movl CURRENT_STATE(%ebx),%ecx /* get current state */ ; \
364 subl TIMER_TSTAMP(%ecx),%eax /* compute elapsed time */ ; \
365 sbbl TIMER_TSTAMP+4(%ecx),%edx /* compute elapsed time */ ; \
366 TIMER_UPDATE(%ecx,%edx,%eax) /* update timer */ ; \
367 popl %ecx /* restore state */ ; \
368 movl %ecx,CURRENT_STATE(%ebx) /* set current state */ ; \
369 movl %esi,TIMER_TSTAMP(%ecx) /* set timestamp */ ; \
370 movl %edi,TIMER_TSTAMP+4(%ecx) /* set timestamp */
372 #endif /* STAT_TIME */
379 * Traditional, not ANSI.
383 .globl label/**/count ;\
386 .globl label/**/limit ;\
390 addl $1,%ss:label/**/count ;\
391 cmpl $0,label/**/limit ;\
395 movl %ss:label/**/count,%eax ;\
396 cmpl %eax,%ss:label/**/limit ;\
409 * Last-ditch debug code to handle faults that might result
410 * from entering kernel (from collocated server) on an invalid
411 * stack. On collocated entry, there's no hardware-initiated
412 * stack switch, so a valid stack must be in place when an
413 * exception occurs, or we may double-fault.
415 * In case of a double-fault, our only recourse is to switch
416 * hardware "tasks", so that we avoid using the current stack.
418 * The idea here is just to get the processor into the debugger,
419 * post-haste. No attempt is made to fix up whatever error got
420 * us here, so presumably continuing from the debugger will
421 * simply land us here again -- at best.
425 * Note that the per-fault entry points are not currently
426 * functional. The only way to make them work would be to
427 * set up separate TSS's for each fault type, which doesn't
428 * currently seem worthwhile. (The offset part of a task
429 * gate is always ignored.) So all faults that task switch
430 * currently resume at db_task_start.
433 * Double fault (Murphy's point) - error code (0) on stack
435 Entry(db_task_dbl_fault)
437 movl $(T_DOUBLE_FAULT),%ebx
440 * Segment not present - error code on stack
442 Entry(db_task_seg_np)
444 movl $(T_SEGMENT_NOT_PRESENT),%ebx
447 * Stack fault - error code on (current) stack
449 Entry(db_task_stk_fault)
451 movl $(T_STACK_FAULT),%ebx
454 * General protection fault - error code on stack
456 Entry(db_task_gen_prot)
458 movl $(T_GENERAL_PROTECTION),%ebx
462 * The entry point where execution resumes after last-ditch debugger task
467 subl $(ISS32_SIZE),%edx
468 movl %edx,%esp /* allocate x86_saved_state on stack */
469 movl %eax,R_ERR(%esp)
470 movl %ebx,R_TRAPNO(%esp)
473 movl CX(EXT(master_dbtss),%edx),%edx
474 movl TSS_LINK(%edx),%eax
475 pushl %eax /* pass along selector of previous TSS */
476 call EXT(db_tss_to_frame)
477 popl %eax /* get rid of TSS selector */
478 call EXT(db_trap_from_asm)
483 iret /* ha, ha, ha... */
484 #endif /* MACH_KDB */
487 * Called as a function, makes the current thread
488 * return from the kernel as if from an exception.
491 .globl EXT(thread_exception_return)
492 .globl EXT(thread_bootstrap_return)
493 LEXT(thread_exception_return)
494 LEXT(thread_bootstrap_return)
496 movl %gs:CPU_KERNEL_STACK,%ecx
497 movl (%ecx),%esp /* switch back to PCB stack */
498 jmp EXT(return_from_trap)
500 Entry(call_continuation)
501 movl S_ARG0,%eax /* get continuation */
502 movl S_ARG1,%edx /* continuation param */
503 movl S_ARG2,%ecx /* wait result */
504 movl %gs:CPU_KERNEL_STACK,%esp /* pop the stack */
505 xorl %ebp,%ebp /* zero frame pointer */
506 subl $8,%esp /* align the stack */
509 call *%eax /* call continuation */
511 movl %gs:CPU_ACTIVE_THREAD,%eax
513 call EXT(thread_terminate)
517 /*******************************************************************************************************
519 * All 64 bit task 'exceptions' enter lo_alltraps:
520 * esp -> x86_saved_state_t
522 * The rest of the state is set up as:
523 * cr3 -> kernel directory
524 * esp -> low based stack
527 * ss/ds/es -> KERNEL_DS
529 * interrupts disabled
530 * direction flag cleared
533 movl R_CS(%esp),%eax /* assume 32-bit state */
534 cmpl $(SS_64),SS_FLAVOR(%esp)/* 64-bit? */
536 movl R64_CS(%esp),%eax /* 64-bit user mode */
543 movl %gs:CPU_ACTIVE_THREAD,%ecx
544 movl ACT_TASK(%ecx),%ebx
546 /* Check for active vtimers in the current task */
547 cmpl $0,TASK_VTIMERS(%ebx)
550 /* Set a pending AST */
551 orl $(AST_BSD),%gs:CPU_PENDING_AST
553 /* Set a thread AST (atomic) */
555 orl $(AST_BSD),ACT_AST(%ecx)
558 movl %gs:CPU_KERNEL_STACK,%ebx
559 xchgl %ebx,%esp /* switch to kernel stack */
562 CCALL1(user_trap, %ebx) /* call user trap routine */
563 cli /* hold off intrs - critical section */
564 popl %esp /* switch back to PCB stack */
567 * Return from trap or system call, checking for ASTs.
568 * On lowbase PCB stack with intrs disabled
570 LEXT(return_from_trap)
571 movl %gs:CPU_PENDING_AST,%eax
573 je EXT(return_to_user) /* branch if no AST */
575 movl %gs:CPU_KERNEL_STACK,%ebx
576 xchgl %ebx,%esp /* switch to kernel stack */
577 sti /* interrupts always enabled on return to user mode */
579 pushl %ebx /* save PCB stack */
580 xorl %ebp,%ebp /* Clear framepointer */
581 CCALL1(i386_astintr, $0) /* take the AST */
583 popl %esp /* switch back to PCB stack (w/exc link) */
584 jmp EXT(return_from_trap) /* and check again (rare) */
590 cmpl $0, %gs:CPU_IS64BIT
591 je EXT(lo_ret_to_user)
592 jmp EXT(lo64_ret_to_user)
597 * Trap from kernel mode. No need to switch stacks.
598 * Interrupts must be off here - we will set them to state at time of trap
599 * as soon as it's safe for us to do so and not recurse doing preemption
602 movl %esp, %eax /* saved state addr */
603 pushl R_EIP(%esp) /* Simulate a CALL from fault point */
604 pushl %ebp /* Extend framepointer chain */
606 CCALL1(kernel_trap, %eax) /* Call kernel trap handler */
611 movl %gs:CPU_PENDING_AST,%eax /* get pending asts */
612 testl $ AST_URGENT,%eax /* any urgent preemption? */
613 je ret_to_kernel /* no, nothing to do */
614 cmpl $ T_PREEMPT,R_TRAPNO(%esp)
615 je ret_to_kernel /* T_PREEMPT handled in kernel_trap() */
616 testl $ EFL_IF,R_EFLAGS(%esp) /* interrupts disabled? */
618 cmpl $0,%gs:CPU_PREEMPTION_LEVEL /* preemption disabled? */
620 movl %gs:CPU_KERNEL_STACK,%eax
623 andl $(-KERNEL_STACK_SIZE),%ecx
624 testl %ecx,%ecx /* are we on the kernel stack? */
625 jne ret_to_kernel /* no, skip it */
627 CCALL1(i386_astintr, $1) /* take the AST */
630 cmpl $0, %gs:CPU_IS64BIT
631 je EXT(lo_ret_to_kernel)
632 jmp EXT(lo64_ret_to_kernel)
636 /*******************************************************************************************************
638 * All interrupts on all tasks enter here with:
639 * esp-> -> x86_saved_state_t
641 * cr3 -> kernel directory
642 * esp -> low based stack
645 * ss/ds/es -> KERNEL_DS
647 * interrupts disabled
648 * direction flag cleared
652 * test whether already on interrupt stack
654 movl %gs:CPU_INT_STACK_TOP,%ecx
657 leal -INTSTACK_SIZE(%ecx),%edx
661 xchgl %ecx,%esp /* switch to interrupt stack */
663 movl %cr0,%eax /* get cr0 */
664 orl $(CR0_TS),%eax /* or in TS bit */
665 movl %eax,%cr0 /* set cr0 */
667 subl $8, %esp /* for 16-byte stack alignment */
668 pushl %ecx /* save pointer to old stack */
669 movl %ecx,%gs:CPU_INT_STATE /* save intr state */
671 TIME_INT_ENTRY /* do timing */
673 movl %gs:CPU_ACTIVE_THREAD,%ecx
674 movl ACT_TASK(%ecx),%ebx
676 /* Check for active vtimers in the current task */
677 cmpl $0,TASK_VTIMERS(%ebx)
680 /* Set a pending AST */
681 orl $(AST_BSD),%gs:CPU_PENDING_AST
683 /* Set a thread AST (atomic) */
685 orl $(AST_BSD),ACT_AST(%ecx)
688 incl %gs:CPU_PREEMPTION_LEVEL
689 incl %gs:CPU_INTERRUPT_LEVEL
691 movl %gs:CPU_INT_STATE, %eax
692 CCALL1(PE_incoming_interrupt, %eax) /* call generic interrupt routine */
694 cli /* just in case we returned with intrs enabled */
696 movl %eax,%gs:CPU_INT_STATE /* clear intr state pointer */
698 decl %gs:CPU_INTERRUPT_LEVEL
699 decl %gs:CPU_PREEMPTION_LEVEL
701 TIME_INT_EXIT /* do timing */
703 movl %gs:CPU_ACTIVE_THREAD,%eax
704 movl ACT_PCB(%eax),%eax /* get act`s PCB */
705 movl PCB_FPS(%eax),%eax /* get pcb's ims.ifps */
706 cmpl $0,%eax /* Is there a context */
707 je 1f /* Branch if not */
708 movl FP_VALID(%eax),%eax /* Load fp_valid */
709 cmpl $0,%eax /* Check if valid */
710 jne 1f /* Branch if valid */
714 movl %cr0,%eax /* get cr0 */
715 orl $(CR0_TS),%eax /* or in TS bit */
716 movl %eax,%cr0 /* set cr0 */
718 popl %esp /* switch back to old stack */
720 /* Load interrupted code segment into %eax */
721 movl R_CS(%esp),%eax /* assume 32-bit state */
722 cmpl $(SS_64),SS_FLAVOR(%esp)/* 64-bit? */
724 movl R64_CS(%esp),%eax /* 64-bit user mode */
726 testb $3,%al /* user mode, */
727 jnz ast_from_interrupt_user /* go handle potential ASTs */
729 * we only want to handle preemption requests if
730 * the interrupt fell in the kernel context
731 * and preemption isn't disabled
733 movl %gs:CPU_PENDING_AST,%eax
734 testl $ AST_URGENT,%eax /* any urgent requests? */
735 je ret_to_kernel /* no, nothing to do */
737 cmpl $0,%gs:CPU_PREEMPTION_LEVEL /* preemption disabled? */
738 jne ret_to_kernel /* yes, skip it */
740 movl %gs:CPU_KERNEL_STACK,%eax
743 andl $(-KERNEL_STACK_SIZE),%ecx
744 testl %ecx,%ecx /* are we on the kernel stack? */
745 jne ret_to_kernel /* no, skip it */
748 * Take an AST from kernel space. We don't need (and don't want)
749 * to do as much as the case where the interrupt came from user
752 CCALL1(i386_astintr, $1)
758 * nested int - simple path, can't preempt etc on way out
761 incl %gs:CPU_PREEMPTION_LEVEL
762 incl %gs:CPU_INTERRUPT_LEVEL
764 movl %esp, %edx /* x86_saved_state */
765 CCALL1(PE_incoming_interrupt, %edx)
767 decl %gs:CPU_INTERRUPT_LEVEL
768 decl %gs:CPU_PREEMPTION_LEVEL
773 * Take an AST from an interrupted user
775 ast_from_interrupt_user:
776 movl %gs:CPU_PENDING_AST,%eax
777 testl %eax,%eax /* pending ASTs? */
778 je EXT(ret_to_user) /* no, nothing to do */
782 jmp EXT(return_from_trap) /* return */
785 /*******************************************************************************************************
788 * System call entries via INTR_GATE or sysenter:
790 * esp -> x86_saved_state32_t
791 * cr3 -> kernel directory
792 * esp -> low based stack
795 * ss/ds/es -> KERNEL_DS
797 * interrupts disabled
798 * direction flag cleared
803 * We can be here either for a mach syscall or a unix syscall,
804 * as indicated by the sign of the code:
806 movl R_EAX(%esp),%eax
808 js EXT(lo_mach_scall) /* < 0 => mach */
814 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
815 movl ACT_TASK(%ecx),%ebx /* point to current task */
816 addl $1,TASK_SYSCALLS_UNIX(%ebx) /* increment call count */
818 /* Check for active vtimers in the current task */
819 cmpl $0,TASK_VTIMERS(%ebx)
822 /* Set a pending AST */
823 orl $(AST_BSD),%gs:CPU_PENDING_AST
825 /* Set a thread AST (atomic) */
827 orl $(AST_BSD),ACT_AST(%ecx)
830 movl %gs:CPU_KERNEL_STACK,%ebx
831 xchgl %ebx,%esp /* switch to kernel stack */
835 CCALL1(unix_syscall, %ebx)
837 * always returns through thread_exception_return
844 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
845 movl ACT_TASK(%ecx),%ebx /* point to current task */
846 addl $1,TASK_SYSCALLS_MACH(%ebx) /* increment call count */
848 /* Check for active vtimers in the current task */
849 cmpl $0,TASK_VTIMERS(%ebx)
852 /* Set a pending AST */
853 orl $(AST_BSD),%gs:CPU_PENDING_AST
855 /* Set a thread AST (atomic) */
857 orl $(AST_BSD),ACT_AST(%ecx)
860 movl %gs:CPU_KERNEL_STACK,%ebx
861 xchgl %ebx,%esp /* switch to kernel stack */
865 CCALL1(mach_call_munger, %ebx)
867 * always returns through thread_exception_return
874 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
875 movl ACT_TASK(%ecx),%ebx /* point to current task */
877 /* Check for active vtimers in the current task */
878 cmpl $0,TASK_VTIMERS(%ebx)
881 /* Set a pending AST */
882 orl $(AST_BSD),%gs:CPU_PENDING_AST
884 /* Set a thread AST (atomic) */
886 orl $(AST_BSD),ACT_AST(%ecx)
889 movl %gs:CPU_KERNEL_STACK,%ebx
890 xchgl %ebx,%esp /* switch to kernel stack */
894 CCALL1(machdep_syscall, %ebx)
896 * always returns through thread_exception_return
903 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
904 movl ACT_TASK(%ecx),%ebx /* point to current task */
906 /* Check for active vtimers in the current task */
907 cmpl $0,TASK_VTIMERS(%ebx)
910 /* Set a pending AST */
911 orl $(AST_BSD),%gs:CPU_PENDING_AST
913 /* Set a thread AST (atomic) */
915 orl $(AST_BSD),ACT_AST(%ecx)
918 movl %gs:CPU_KERNEL_STACK,%ebx // Get the address of the kernel stack
919 xchgl %ebx,%esp // Switch to it, saving the previous
921 CCALL1(diagCall, %ebx) // Call diagnostics
923 cmpl $0,%eax // What kind of return is this?
925 cli // Disable interruptions just in case they were enabled
926 popl %esp // Get back the original stack
927 jmp EXT(return_to_user) // Normal return, do not check asts...
929 CCALL3(i386_exception, $EXC_SYSCALL, $0x6000, $1)
930 // pass what would be the diag syscall
931 // error return - cause an exception
936 /*******************************************************************************************************
939 * System call entries via syscall only:
941 * esp -> x86_saved_state64_t
942 * cr3 -> kernel directory
943 * esp -> low based stack
946 * ss/ds/es -> KERNEL_DS
948 * interrupts disabled
949 * direction flag cleared
954 * We can be here either for a mach, unix machdep or diag syscall,
955 * as indicated by the syscall class:
957 movl R64_RAX(%esp), %eax /* syscall number/class */
959 andl $(SYSCALL_CLASS_MASK), %ebx /* syscall class */
960 cmpl $(SYSCALL_CLASS_MACH<<SYSCALL_CLASS_SHIFT), %ebx
961 je EXT(lo64_mach_scall)
962 cmpl $(SYSCALL_CLASS_UNIX<<SYSCALL_CLASS_SHIFT), %ebx
963 je EXT(lo64_unix_scall)
964 cmpl $(SYSCALL_CLASS_MDEP<<SYSCALL_CLASS_SHIFT), %ebx
965 je EXT(lo64_mdep_scall)
966 cmpl $(SYSCALL_CLASS_DIAG<<SYSCALL_CLASS_SHIFT), %ebx
967 je EXT(lo64_diag_scall)
969 movl %gs:CPU_KERNEL_STACK,%ebx
970 xchgl %ebx,%esp /* switch to kernel stack */
974 /* Syscall class unknown */
975 CCALL3(i386_exception, $(EXC_SYSCALL), %eax, $1)
979 Entry(lo64_unix_scall)
982 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
983 movl ACT_TASK(%ecx),%ebx /* point to current task */
984 addl $1,TASK_SYSCALLS_UNIX(%ebx) /* increment call count */
986 /* Check for active vtimers in the current task */
987 cmpl $0,TASK_VTIMERS(%ebx)
990 /* Set a pending AST */
991 orl $(AST_BSD),%gs:CPU_PENDING_AST
993 /* Set a thread AST (atomic) */
995 orl $(AST_BSD),ACT_AST(%ecx)
998 movl %gs:CPU_KERNEL_STACK,%ebx
999 xchgl %ebx,%esp /* switch to kernel stack */
1003 CCALL1(unix_syscall64, %ebx)
1005 * always returns through thread_exception_return
1009 Entry(lo64_mach_scall)
1012 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
1013 movl ACT_TASK(%ecx),%ebx /* point to current task */
1014 addl $1,TASK_SYSCALLS_MACH(%ebx) /* increment call count */
1016 /* Check for active vtimers in the current task */
1017 cmpl $0,TASK_VTIMERS(%ebx)
1020 /* Set a pending AST */
1021 orl $(AST_BSD),%gs:CPU_PENDING_AST
1024 orl $(AST_BSD),ACT_AST(%ecx)
1027 movl %gs:CPU_KERNEL_STACK,%ebx
1028 xchgl %ebx,%esp /* switch to kernel stack */
1032 CCALL1(mach_call_munger64, %ebx)
1034 * always returns through thread_exception_return
1039 Entry(lo64_mdep_scall)
1042 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
1043 movl ACT_TASK(%ecx),%ebx /* point to current task */
1045 /* Check for active vtimers in the current task */
1046 cmpl $0,TASK_VTIMERS(%ebx)
1049 /* Set a pending AST */
1050 orl $(AST_BSD),%gs:CPU_PENDING_AST
1052 /* Set a thread AST (atomic) */
1054 orl $(AST_BSD),ACT_AST(%ecx)
1057 movl %gs:CPU_KERNEL_STACK,%ebx
1058 xchgl %ebx,%esp /* switch to kernel stack */
1062 CCALL1(machdep_syscall64, %ebx)
1064 * always returns through thread_exception_return
1068 Entry(lo64_diag_scall)
1071 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
1072 movl ACT_TASK(%ecx),%ebx /* point to current task */
1074 /* Check for active vtimers in the current task */
1075 cmpl $0,TASK_VTIMERS(%ebx)
1078 /* Set a pending AST */
1079 orl $(AST_BSD),%gs:CPU_PENDING_AST
1081 /* Set a thread AST (atomic) */
1083 orl $(AST_BSD),ACT_AST(%ecx)
1086 movl %gs:CPU_KERNEL_STACK,%ebx // Get the address of the kernel stack
1087 xchgl %ebx,%esp // Switch to it, saving the previous
1089 CCALL1(diagCall64, %ebx) // Call diagnostics
1091 cmpl $0,%eax // What kind of return is this?
1093 cli // Disable interruptions just in case they were enabled
1094 popl %esp // Get back the original stack
1095 jmp EXT(return_to_user) // Normal return, do not check asts...
1097 CCALL3(i386_exception, $EXC_SYSCALL, $0x6000, $1)
1098 // pass what would be the diag syscall
1099 // error return - cause an exception
1109 * Copy from user/kernel address space.
1110 * arg0: window offset or kernel address
1111 * arg1: kernel address
1114 Entry(copyinphys_user)
1115 movl $(USER_WINDOW_SEL),%ecx /* user data segment access through kernel window */
1118 Entry(copyinphys_kern)
1119 movl $(PHYS_WINDOW_SEL),%ecx /* physical access through kernel window */
1124 movl $(USER_WINDOW_SEL),%ecx /* user data segment access through kernel window */
1131 pushl %edi /* save registers */
1133 movl 8+S_ARG0,%esi /* get source - window offset or kernel address */
1134 movl 8+S_ARG1,%edi /* get destination - kernel address */
1135 movl 8+S_ARG2,%edx /* get count */
1138 movl %edx,%ecx /* move by longwords first */
1141 RECOVER(copyin_fail)
1143 movsl /* move longwords */
1144 movl %edx,%ecx /* now move remaining bytes */
1147 RECOVER(copyin_fail)
1150 xorl %eax,%eax /* return 0 for success */
1152 mov %ss,%cx /* restore kernel data and extended segments */
1156 popl %edi /* restore registers */
1158 ret /* and return */
1161 movl $(EFAULT),%eax /* return error for failure */
1162 jmp copyin_ret /* pop frame and return */
1167 * Copy string from user/kern address space.
1168 * arg0: window offset or kernel address
1169 * arg1: kernel address
1170 * arg2: max byte count
1171 * arg3: actual byte count (OUT)
1173 Entry(copyinstr_kern)
1175 jmp copyinstr_common
1177 Entry(copyinstr_user)
1178 movl $(USER_WINDOW_SEL),%ecx /* user data segment access through kernel window */
1184 pushl %edi /* save registers */
1186 movl 8+S_ARG0,%esi /* get source - window offset or kernel address */
1187 movl 8+S_ARG1,%edi /* get destination - kernel address */
1188 movl 8+S_ARG2,%edx /* get count */
1190 xorl %eax,%eax /* set to 0 here so that the high 24 bits */
1191 /* are 0 for the cmpl against 0 */
1194 RECOVER(copystr_fail) /* copy bytes... */
1197 testl %edi,%edi /* if kernel address is ... */
1198 jz 3f /* not NULL */
1199 movb %al,(%edi) /* copy the byte */
1202 testl %eax,%eax /* did we just stuff the 0-byte? */
1203 jz 4f /* yes, return 0 status already in %eax */
1204 decl %edx /* decrement #bytes left in buffer */
1205 jnz 2b /* buffer not full so copy in another byte */
1206 movl $(ENAMETOOLONG),%eax /* buffer full but no 0-byte: ENAMETOOLONG */
1208 movl 8+S_ARG3,%edi /* get OUT len ptr */
1210 jz copystr_ret /* if null, just return */
1212 movl %esi,(%edi) /* else set OUT arg to xfer len */
1214 popl %edi /* restore registers */
1216 ret /* and return */
1219 movl $(EFAULT),%eax /* return error for failure */
1220 jmp copystr_ret /* pop frame and return */
1224 * Copy to user/kern address space.
1225 * arg0: kernel address
1226 * arg1: window offset or kernel address
1229 ENTRY(copyoutphys_user)
1230 movl $(USER_WINDOW_SEL),%ecx /* user data segment access through kernel window */
1233 ENTRY(copyoutphys_kern)
1234 movl $(PHYS_WINDOW_SEL),%ecx /* physical access through kernel window */
1239 movl $(USER_WINDOW_SEL),%ecx /* user data segment access through kernel window */
1246 pushl %edi /* save registers */
1248 movl 8+S_ARG0,%esi /* get source - kernel address */
1249 movl 8+S_ARG1,%edi /* get destination - window offset or kernel address */
1250 movl 8+S_ARG2,%edx /* get count */
1253 movl %edx,%ecx /* move by longwords first */
1256 RECOVER(copyout_fail)
1259 movl %edx,%ecx /* now move remaining bytes */
1262 RECOVER(copyout_fail)
1265 xorl %eax,%eax /* return 0 for success */
1267 mov %ss,%cx /* restore kernel segment */
1271 popl %edi /* restore registers */
1273 ret /* and return */
1276 movl $(EFAULT),%eax /* return error for failure */
1277 jmp copyout_ret /* pop frame and return */
1280 * io register must not be used on slaves (no AT bus)
1282 #define ILL_ON_SLAVE
1290 #define PUSH_FRAME FRAME
1291 #define POP_FRAME EMARF
1293 #else /* MACH_ASSERT */
1301 #endif /* MACH_ASSERT */
1304 #if MACH_KDB || MACH_ASSERT
1307 * Following routines are also defined as macros in i386/pio.h
1308 * Compile then when MACH_KDB is configured so that they
1309 * can be invoked from the debugger.
1313 * void outb(unsigned char *io_port,
1314 * unsigned char byte)
1316 * Output a byte to an IO port.
1321 movl ARG0,%edx /* IO port address */
1322 movl ARG1,%eax /* data to output */
1323 outb %al,%dx /* send it out */
1328 * unsigned char inb(unsigned char *io_port)
1330 * Input a byte from an IO port.
1335 movl ARG0,%edx /* IO port address */
1336 xor %eax,%eax /* clear high bits of register */
1337 inb %dx,%al /* get the byte */
1342 * void outw(unsigned short *io_port,
1343 * unsigned short word)
1345 * Output a word to an IO port.
1350 movl ARG0,%edx /* IO port address */
1351 movl ARG1,%eax /* data to output */
1352 outw %ax,%dx /* send it out */
1357 * unsigned short inw(unsigned short *io_port)
1359 * Input a word from an IO port.
1364 movl ARG0,%edx /* IO port address */
1365 xor %eax,%eax /* clear high bits of register */
1366 inw %dx,%ax /* get the word */
1371 * void outl(unsigned int *io_port,
1372 * unsigned int byte)
1374 * Output an int to an IO port.
1379 movl ARG0,%edx /* IO port address*/
1380 movl ARG1,%eax /* data to output */
1381 outl %eax,%dx /* send it out */
1386 * unsigned int inl(unsigned int *io_port)
1388 * Input an int from an IO port.
1393 movl ARG0,%edx /* IO port address */
1394 inl %dx,%eax /* get the int */
1398 #endif /* MACH_KDB || MACH_ASSERT*/
1401 * void loutb(unsigned byte *io_port,
1402 * unsigned byte *data,
1403 * unsigned int count)
1405 * Output an array of bytes to an IO port.
1411 movl %esi,%eax /* save register */
1412 movl ARG0,%edx /* get io port number */
1413 movl ARG1,%esi /* get data address */
1414 movl ARG2,%ecx /* get count */
1418 movl %eax,%esi /* restore register */
1424 * void loutw(unsigned short *io_port,
1425 * unsigned short *data,
1426 * unsigned int count)
1428 * Output an array of shorts to an IO port.
1434 movl %esi,%eax /* save register */
1435 movl ARG0,%edx /* get io port number */
1436 movl ARG1,%esi /* get data address */
1437 movl ARG2,%ecx /* get count */
1441 movl %eax,%esi /* restore register */
1446 * void loutw(unsigned short io_port,
1447 * unsigned int *data,
1448 * unsigned int count)
1450 * Output an array of longs to an IO port.
1456 movl %esi,%eax /* save register */
1457 movl ARG0,%edx /* get io port number */
1458 movl ARG1,%esi /* get data address */
1459 movl ARG2,%ecx /* get count */
1463 movl %eax,%esi /* restore register */
1469 * void linb(unsigned char *io_port,
1470 * unsigned char *data,
1471 * unsigned int count)
1473 * Input an array of bytes from an IO port.
1479 movl %edi,%eax /* save register */
1480 movl ARG0,%edx /* get io port number */
1481 movl ARG1,%edi /* get data address */
1482 movl ARG2,%ecx /* get count */
1486 movl %eax,%edi /* restore register */
1492 * void linw(unsigned short *io_port,
1493 * unsigned short *data,
1494 * unsigned int count)
1496 * Input an array of shorts from an IO port.
1502 movl %edi,%eax /* save register */
1503 movl ARG0,%edx /* get io port number */
1504 movl ARG1,%edi /* get data address */
1505 movl ARG2,%ecx /* get count */
1509 movl %eax,%edi /* restore register */
1515 * void linl(unsigned short io_port,
1516 * unsigned int *data,
1517 * unsigned int count)
1519 * Input an array of longs from an IO port.
1525 movl %edi,%eax /* save register */
1526 movl ARG0,%edx /* get io port number */
1527 movl ARG1,%edi /* get data address */
1528 movl ARG2,%ecx /* get count */
1532 movl %eax,%edi /* restore register */
1537 * int rdmsr_carefully(uint32_t msr, uint32_t *lo, uint32_t *hi)
1539 ENTRY(rdmsr_carefully)
1556 * Done with recovery table.
1596 lidt null_idtr /* disable the interrupt handler */
1597 xor %ecx,%ecx /* generate a divide by zero */
1598 div %ecx,%eax /* reboot now */
1599 ret /* this will "never" be executed */
1601 #endif /* SYMMETRY */
1605 * setbit(int bitno, int *s) - set bit in bit string
1608 movl S_ARG0, %ecx /* bit number */
1609 movl S_ARG1, %eax /* address */
1610 btsl %ecx, (%eax) /* set bit */
1614 * clrbit(int bitno, int *s) - clear bit in bit string
1617 movl S_ARG0, %ecx /* bit number */
1618 movl S_ARG1, %eax /* address */
1619 btrl %ecx, (%eax) /* clear bit */
1623 * ffsbit(int *s) - find first set bit in bit string
1626 movl S_ARG0, %ecx /* address */
1627 movl $0, %edx /* base offset */
1629 bsfl (%ecx), %eax /* check argument bits */
1630 jnz 1f /* found bit, return */
1631 addl $4, %ecx /* increment address */
1632 addl $32, %edx /* increment offset */
1633 jmp 0b /* try again */
1635 addl %edx, %eax /* return offset */
1639 * testbit(int nr, volatile void *array)
1641 * Test to see if the bit is set within the bit string
1645 movl S_ARG0,%eax /* Get the bit to test */
1646 movl S_ARG1,%ecx /* get the array string */
1659 * jail: set the EIP to "jail" to block a kernel thread.
1660 * Useful to debug synchronization problems on MPs.
1667 * div_scale(unsigned int dividend,
1668 * unsigned int divisor,
1669 * unsigned int *scale)
1671 * This function returns (dividend << *scale) //divisor where *scale
1672 * is the largest possible value before overflow. This is used in
1673 * computation where precision must be achieved in order to avoid
1674 * floating point usage.
1678 * while (((dividend >> *scale) >= divisor))
1680 * *scale = 32 - *scale;
1681 * return ((dividend << *scale) / divisor);
1685 xorl %ecx, %ecx /* *scale = 0 */
1687 movl ARG0, %edx /* get dividend */
1689 cmpl ARG1, %edx /* if (divisor > dividend) */
1690 jle 1f /* goto 1f */
1691 addl $1, %ecx /* (*scale)++ */
1692 shrdl $1, %edx, %eax /* dividend >> 1 */
1693 shrl $1, %edx /* dividend >> 1 */
1694 jmp 0b /* goto 0b */
1696 divl ARG1 /* (dividend << (32 - *scale)) / divisor */
1697 movl ARG2, %edx /* get scale */
1698 movl $32, (%edx) /* *scale = 32 */
1699 subl %ecx, (%edx) /* *scale -= %ecx */
1705 * mul_scale(unsigned int multiplicand,
1706 * unsigned int multiplier,
1707 * unsigned int *scale)
1709 * This function returns ((multiplicand * multiplier) >> *scale) where
1710 * scale is the largest possible value before overflow. This is used in
1711 * computation where precision must be achieved in order to avoid
1712 * floating point usage.
1716 * while (overflow((multiplicand * multiplier) >> *scale))
1718 * return ((multiplicand * multiplier) >> *scale);
1722 xorl %ecx, %ecx /* *scale = 0 */
1723 movl ARG0, %eax /* get multiplicand */
1724 mull ARG1 /* multiplicand * multiplier */
1726 cmpl $0, %edx /* if (!overflow()) */
1728 addl $1, %ecx /* (*scale)++ */
1729 shrdl $1, %edx, %eax /* (multiplicand * multiplier) >> 1 */
1730 shrl $1, %edx /* (multiplicand * multiplier) >> 1 */
1733 movl ARG2, %edx /* get scale */
1734 movl %ecx, (%edx) /* set *scale */
1741 * Double-fault exception handler task. The last gasp...
1743 Entry(df_task_start)
1744 CCALL1(panic_double_fault, $(T_DOUBLE_FAULT))
1749 * machine-check handler task. The last gasp...
1751 Entry(mc_task_start)
1752 CCALL1(panic_machine_check, $(T_MACHINE_CHECK))
1756 * Compatibility mode's last gasp...
1760 CCALL1(panic_double_fault64, %eax)
1765 CCALL1(panic_machine_check64, %eax)