2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
26 * Mach Operating System
27 * Copyright (c) 1991,1990 Carnegie Mellon University
28 * All Rights Reserved.
30 * Permission to use, copy, modify and distribute this software and its
31 * documentation is hereby granted, provided that both the copyright
32 * notice and this permission notice appear in all copies of the
33 * software, derivative works or modified versions, and any portions
34 * thereof, and that both notices appear in supporting documentation.
36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
40 * Carnegie Mellon requests users of this software to return to
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
53 #include <etap_event_monitor.h>
55 #include <platforms.h>
57 #include <mach_kgdb.h>
59 #include <stat_time.h>
60 #include <mach_assert.h>
62 #include <sys/errno.h>
64 #include <i386/cpuid.h>
65 #include <i386/eflags.h>
66 #include <i386/proc_reg.h>
67 #include <i386/trap.h>
69 #include <mach/exception_types.h>
71 #include <i386/AT386/mp/mp.h>
73 #define PREEMPT_DEBUG_LOG 0
76 /* Under Mach-O, etext is a variable which contains
77 * the last text address
79 #define ETEXT_ADDR (EXT(etext))
81 /* Under ELF and other non-Mach-O formats, the address of
82 * etext represents the last text address
84 #define ETEXT_ADDR $EXT(etext)
89 #define CX(addr,reg) addr(,reg,4)
92 #define CPU_NUMBER(reg)
93 #define CX(addr,reg) addr
95 #endif /* NCPUS > 1 */
105 #define RECOVERY_SECTION .section __VECTORS, __recover
106 #define RETRY_SECTION .section __VECTORS, __retries
108 #define RECOVERY_SECTION .text
109 #define RECOVERY_SECTION .text
112 #define RECOVER_TABLE_START \
114 .globl EXT(recover_table) ;\
115 LEXT(recover_table) ;\
118 #define RECOVER(addr) \
125 #define RECOVER_TABLE_END \
127 .globl EXT(recover_table_end) ;\
128 LEXT(recover_table_end) ;\
132 * Retry table for certain successful faults.
134 #define RETRY_TABLE_START \
136 .globl EXT(retry_table) ;\
140 #define RETRY(addr) \
147 #define RETRY_TABLE_END \
149 .globl EXT(retry_table_end) ;\
150 LEXT(retry_table_end) ;\
154 * Allocate recovery and retry tables.
166 #define TIME_TRAP_UENTRY
167 #define TIME_TRAP_UEXIT
168 #define TIME_INT_ENTRY
169 #define TIME_INT_EXIT
171 #else /* microsecond timing */
174 * Microsecond timing.
175 * Assumes a free-running microsecond counter.
176 * no TIMER_MAX check needed.
180 * There is only one current time-stamp per CPU, since only
181 * the time-stamp in the current timer is used.
182 * To save time, we allocate the current time-stamps here.
184 .comm EXT(current_tstamp), 4*NCPUS
187 * Update time on user trap entry.
188 * 11 instructions (including cli on entry)
189 * Assumes CPU number in %edx.
192 #define TIME_TRAP_UENTRY \
193 cli /* block interrupts */ ;\
194 movl VA_ETC,%ebx /* get timer value */ ;\
195 movl CX(EXT(current_tstamp),%edx),%ecx /* get old time stamp */;\
196 movl %ebx,CX(EXT(current_tstamp),%edx) /* set new time stamp */;\
197 subl %ecx,%ebx /* elapsed = new-old */ ;\
198 movl CX(EXT(current_timer),%edx),%ecx /* get current timer */;\
199 addl %ebx,LOW_BITS(%ecx) /* add to low bits */ ;\
200 jns 0f /* if overflow, */ ;\
201 call timer_normalize /* normalize timer */ ;\
202 0: addl $(TH_SYS_TIMER-TH_USER_TIMER),%ecx ;\
203 /* switch to sys timer */;\
204 movl %ecx,CX(EXT(current_timer),%edx) /* make it current */ ;\
205 sti /* allow interrupts */
208 * update time on user trap exit.
210 * Assumes CPU number in %edx.
213 #define TIME_TRAP_UEXIT \
214 cli /* block interrupts */ ;\
215 movl VA_ETC,%ebx /* get timer */ ;\
216 movl CX(EXT(current_tstamp),%edx),%ecx /* get old time stamp */;\
217 movl %ebx,CX(EXT(current_tstamp),%edx) /* set new time stamp */;\
218 subl %ecx,%ebx /* elapsed = new-old */ ;\
219 movl CX(EXT(current_timer),%edx),%ecx /* get current timer */;\
220 addl %ebx,LOW_BITS(%ecx) /* add to low bits */ ;\
221 jns 0f /* if overflow, */ ;\
222 call timer_normalize /* normalize timer */ ;\
223 0: addl $(TH_USER_TIMER-TH_SYS_TIMER),%ecx ;\
224 /* switch to user timer */;\
225 movl %ecx,CX(EXT(current_timer),%edx) /* make it current */
228 * update time on interrupt entry.
230 * Assumes CPU number in %edx.
231 * Leaves old timer in %ebx.
234 #define TIME_INT_ENTRY \
235 movl VA_ETC,%ecx /* get timer */ ;\
236 movl CX(EXT(current_tstamp),%edx),%ebx /* get old time stamp */;\
237 movl %ecx,CX(EXT(current_tstamp),%edx) /* set new time stamp */;\
238 subl %ebx,%ecx /* elapsed = new-old */ ;\
239 movl CX(EXT(current_timer),%edx),%ebx /* get current timer */;\
240 addl %ecx,LOW_BITS(%ebx) /* add to low bits */ ;\
241 leal CX(0,%edx),%ecx /* timer is 16 bytes */ ;\
242 lea CX(EXT(kernel_timer),%edx),%ecx /* get interrupt timer*/;\
243 movl %ecx,CX(EXT(current_timer),%edx) /* set timer */
246 * update time on interrupt exit.
248 * Assumes CPU number in %edx, old timer in %ebx.
251 #define TIME_INT_EXIT \
252 movl VA_ETC,%eax /* get timer */ ;\
253 movl CX(EXT(current_tstamp),%edx),%ecx /* get old time stamp */;\
254 movl %eax,CX(EXT(current_tstamp),%edx) /* set new time stamp */;\
255 subl %ecx,%eax /* elapsed = new-old */ ;\
256 movl CX(EXT(current_timer),%edx),%ecx /* get current timer */;\
257 addl %eax,LOW_BITS(%ecx) /* add to low bits */ ;\
258 jns 0f /* if overflow, */ ;\
259 call timer_normalize /* normalize timer */ ;\
260 0: testb $0x80,LOW_BITS+3(%ebx) /* old timer overflow? */;\
261 jz 0f /* if overflow, */ ;\
262 movl %ebx,%ecx /* get old timer */ ;\
263 call timer_normalize /* normalize timer */ ;\
264 0: movl %ebx,CX(EXT(current_timer),%edx) /* set timer */
268 * Normalize timer in ecx.
269 * Preserves edx; clobbers eax.
273 .long TIMER_HIGH_UNIT /* div has no immediate opnd */
276 pushl %edx /* save registersz */
278 xorl %edx,%edx /* clear divisor high */
279 movl LOW_BITS(%ecx),%eax /* get divisor low */
280 divl timer_high_unit,%eax /* quotient in eax */
281 /* remainder in edx */
282 addl %eax,HIGH_BITS_CHECK(%ecx) /* add high_inc to check */
283 movl %edx,LOW_BITS(%ecx) /* remainder to low_bits */
284 addl %eax,HIGH_BITS(%ecx) /* add high_inc to high bits */
285 popl %eax /* restore register */
290 * Switch to a new timer.
293 CPU_NUMBER(%edx) /* get this CPU */
294 movl VA_ETC,%ecx /* get timer */
295 movl CX(EXT(current_tstamp),%edx),%eax /* get old time stamp */
296 movl %ecx,CX(EXT(current_tstamp),%edx) /* set new time stamp */
297 subl %ecx,%eax /* elapsed = new - old */
298 movl CX(EXT(current_timer),%edx),%ecx /* get current timer */
299 addl %eax,LOW_BITS(%ecx) /* add to low bits */
300 jns 0f /* if overflow, */
301 call timer_normalize /* normalize timer */
303 movl S_ARG0,%ecx /* get new timer */
304 movl %ecx,CX(EXT(current_timer),%edx) /* set timer */
308 * Initialize the first timer for a CPU.
311 CPU_NUMBER(%edx) /* get this CPU */
312 movl VA_ETC,%ecx /* get timer */
313 movl %ecx,CX(EXT(current_tstamp),%edx) /* set initial time stamp */
314 movl S_ARG0,%ecx /* get timer */
315 movl %ecx,CX(EXT(current_timer),%edx) /* set initial timer */
318 #endif /* accurate timing */
321 * Encapsulate the transfer of exception stack frames between a PCB
322 * and a thread stack. Since the whole point of these is to emulate
323 * a call or exception that changes privilege level, both macros
324 * assume that there is no user esp or ss stored in the source
325 * frame (because there was no change of privilege to generate them).
329 * Transfer a stack frame from a thread's user stack to its PCB.
330 * We assume the thread and stack addresses have been loaded into
331 * registers (our arguments).
333 * The macro overwrites edi, esi, ecx and whatever registers hold the
334 * thread and stack addresses (which can't be one of the above three).
335 * The thread address is overwritten with the address of its saved state
336 * (where the frame winds up).
338 * Must be called on kernel stack.
340 #define FRAME_STACK_TO_PCB(thread, stkp) ;\
341 movl ACT_PCB(thread),thread /* get act`s PCB */ ;\
342 leal PCB_ISS(thread),%edi /* point to PCB`s saved state */;\
343 movl %edi,thread /* save for later */ ;\
344 movl stkp,%esi /* point to start of frame */ ;\
346 sarl $2,%ecx /* word count for transfer */ ;\
347 cld /* we`re incrementing */ ;\
349 movsl /* transfer the frame */ ;\
350 addl $R_UESP,stkp /* derive true "user" esp */ ;\
351 movl stkp,R_UESP(thread) /* store in PCB */ ;\
353 mov %ss,%cx /* get current ss */ ;\
354 movl %ecx,R_SS(thread) /* store in PCB */
357 * Transfer a stack frame from a thread's PCB to the stack pointed
358 * to by the PCB. We assume the thread address has been loaded into
359 * a register (our argument).
361 * The macro overwrites edi, esi, ecx and whatever register holds the
362 * thread address (which can't be one of the above three). The
363 * thread address is overwritten with the address of its saved state
364 * (where the frame winds up).
366 * Must be called on kernel stack.
368 #define FRAME_PCB_TO_STACK(thread) ;\
369 movl ACT_PCB(thread),%esi /* get act`s PCB */ ;\
370 leal PCB_ISS(%esi),%esi /* point to PCB`s saved state */;\
371 movl R_UESP(%esi),%edi /* point to end of dest frame */;\
372 movl ACT_MAP(thread),%ecx /* get act's map */ ;\
373 movl MAP_PMAP(%ecx),%ecx /* get map's pmap */ ;\
374 cmpl EXT(kernel_pmap), %ecx /* If kernel loaded task */ ;\
375 jz 1f /* use kernel data segment */ ;\
376 movl $USER_DS,%cx /* else use user data segment */;\
380 subl %ecx,%edi /* derive start of frame */ ;\
381 movl %edi,thread /* save for later */ ;\
382 sarl $2,%ecx /* word count for transfer */ ;\
383 cld /* we`re incrementing */ ;\
385 movsl /* transfer the frame */ ;\
386 mov %ss,%cx /* restore kernel segments */ ;\
394 * Traditional, not ANSI.
398 .globl label/**/count ;\
401 .globl label/**/limit ;\
405 addl $1,%ss:label/**/count ;\
406 cmpl $0,label/**/limit ;\
410 movl %ss:label/**/count,%eax ;\
411 cmpl %eax,%ss:label/**/limit ;\
424 * Last-ditch debug code to handle faults that might result
425 * from entering kernel (from collocated server) on an invalid
426 * stack. On collocated entry, there's no hardware-initiated
427 * stack switch, so a valid stack must be in place when an
428 * exception occurs, or we may double-fault.
430 * In case of a double-fault, our only recourse is to switch
431 * hardware "tasks", so that we avoid using the current stack.
433 * The idea here is just to get the processor into the debugger,
434 * post-haste. No attempt is made to fix up whatever error got
435 * us here, so presumably continuing from the debugger will
436 * simply land us here again -- at best.
440 * Note that the per-fault entry points are not currently
441 * functional. The only way to make them work would be to
442 * set up separate TSS's for each fault type, which doesn't
443 * currently seem worthwhile. (The offset part of a task
444 * gate is always ignored.) So all faults that task switch
445 * currently resume at db_task_start.
448 * Double fault (Murphy's point) - error code (0) on stack
450 Entry(db_task_dbl_fault)
452 movl $(T_DOUBLE_FAULT),%ebx
455 * Segment not present - error code on stack
457 Entry(db_task_seg_np)
459 movl $(T_SEGMENT_NOT_PRESENT),%ebx
462 * Stack fault - error code on (current) stack
464 Entry(db_task_stk_fault)
466 movl $(T_STACK_FAULT),%ebx
469 * General protection fault - error code on stack
471 Entry(db_task_gen_prot)
473 movl $(T_GENERAL_PROTECTION),%ebx
477 * The entry point where execution resumes after last-ditch debugger task
483 movl %edx,%esp /* allocate i386_saved_state on stack */
484 movl %eax,R_ERR(%esp)
485 movl %ebx,R_TRAPNO(%esp)
489 movl CX(EXT(mp_dbtss),%edx),%edx
490 movl TSS_LINK(%edx),%eax
492 movl EXT(dbtss)+TSS_LINK,%eax
494 pushl %eax /* pass along selector of previous TSS */
495 call EXT(db_tss_to_frame)
496 popl %eax /* get rid of TSS selector */
497 call EXT(db_trap_from_asm)
502 iret /* ha, ha, ha... */
503 #endif /* MACH_KDB */
506 * Trap/interrupt entry points.
508 * All traps must create the following save area on the PCB "stack":
517 * cr2 if page fault - otherwise unused
527 * user esp - if from user
528 * user ss - if from user
529 * es - if from V86 thread
530 * ds - if from V86 thread
531 * fs - if from V86 thread
532 * gs - if from V86 thread
537 * General protection or segment-not-present fault.
538 * Check for a GP/NP fault in the kernel_return
539 * sequence; if there, report it as a GP/NP fault on the user's instruction.
541 * esp-> 0: trap code (NP or GP)
542 * 4: segment number in error
546 * 20 old registers (trap is from kernel)
549 pushl $(T_GENERAL_PROTECTION) /* indicate fault type */
550 jmp trap_check_kernel_exit /* check for kernel exit sequence */
553 pushl $(T_SEGMENT_NOT_PRESENT)
554 /* indicate fault type */
556 trap_check_kernel_exit:
557 testl $(EFL_VM),16(%esp) /* is trap from V86 mode? */
558 jnz EXT(alltraps) /* isn`t kernel trap if so */
559 testl $3,12(%esp) /* is trap from kernel mode? */
560 jne EXT(alltraps) /* if so: */
561 /* check for the kernel exit sequence */
562 cmpl $EXT(kret_iret),8(%esp) /* on IRET? */
564 cmpl $EXT(kret_popl_ds),8(%esp) /* popping DS? */
566 cmpl $EXT(kret_popl_es),8(%esp) /* popping ES? */
568 cmpl $EXT(kret_popl_fs),8(%esp) /* popping FS? */
570 cmpl $EXT(kret_popl_gs),8(%esp) /* popping GS? */
572 take_fault: /* if none of the above: */
573 jmp EXT(alltraps) /* treat as normal trap. */
576 * GP/NP fault on IRET: CS or SS is in error.
577 * All registers contain the user's values.
592 movl %eax,8(%esp) /* save eax (we don`t need saved eip) */
593 popl %eax /* get trap number */
594 movl %eax,12-4(%esp) /* put in user trap number */
595 popl %eax /* get error code */
596 movl %eax,16-8(%esp) /* put in user errcode */
597 popl %eax /* restore eax */
599 jmp EXT(alltraps) /* take fault */
602 * Fault restoring a segment register. The user's registers are still
603 * saved on the stack. The offending segment register has not been
607 popl %eax /* get trap number */
608 popl %edx /* get error code */
609 addl $12,%esp /* pop stack to user regs */
610 jmp push_es /* (DS on top of stack) */
612 popl %eax /* get trap number */
613 popl %edx /* get error code */
614 addl $12,%esp /* pop stack to user regs */
615 jmp push_fs /* (ES on top of stack) */
617 popl %eax /* get trap number */
618 popl %edx /* get error code */
619 addl $12,%esp /* pop stack to user regs */
620 jmp push_gs /* (FS on top of stack) */
622 popl %eax /* get trap number */
623 popl %edx /* get error code */
624 addl $12,%esp /* pop stack to user regs */
625 jmp push_segregs /* (GS on top of stack) */
628 pushl %es /* restore es, */
630 pushl %fs /* restore fs, */
632 pushl %gs /* restore gs. */
634 movl %eax,R_TRAPNO(%esp) /* set trap number */
635 movl %edx,R_ERR(%esp) /* set error code */
637 jmp trap_set_segs /* take trap */
640 * Debug trap. Check for single-stepping across system call into
641 * kernel. If this is the case, taking the debug trap has turned
642 * off single-stepping - save the flags register with the trace
646 testl $(EFL_VM),8(%esp) /* is trap from V86 mode? */
647 jnz 0f /* isn`t kernel trap if so */
648 testl $3,4(%esp) /* is trap from kernel mode? */
650 cmpl $syscall_entry,(%esp) /* system call entry? */
652 /* flags are sitting where syscall */
654 addl $8,%esp /* remove eip/cs */
655 jmp syscall_entry_2 /* continue system call entry */
657 0: pushl $0 /* otherwise: */
658 pushl $(T_DEBUG) /* handle as normal */
659 jmp EXT(alltraps) /* debug fault */
662 * Page fault traps save cr2.
665 pushl $(T_PAGE_FAULT) /* mark a page fault trap */
666 pusha /* save the general registers */
667 movl %cr2,%eax /* get the faulting address */
668 movl %eax,12(%esp) /* save in esp save slot */
669 jmp trap_push_segs /* continue fault */
672 * All 'exceptions' enter here with:
678 * old esp if trapped from user
679 * old ss if trapped from user
681 * NB: below use of CPU_NUMBER assumes that macro will use correct
682 * segment register for any kernel data accesses.
685 pusha /* save the general registers */
687 pushl %ds /* save the segment registers */
695 movl %ax,%es /* switch to kernel data seg */
696 cld /* clear direction flag */
697 testl $(EFL_VM),R_EFLAGS(%esp) /* in V86 mode? */
698 jnz trap_from_user /* user mode trap if so */
699 testb $3,R_CS(%esp) /* user mode trap? */
702 cmpl $0,CX(EXT(active_kloaded),%edx)
703 je trap_from_kernel /* if clear, truly in kernel */
705 cmpl ETEXT_ADDR,R_EIP(%esp) /* pc within kernel? */
710 * We didn't enter here "through" PCB (i.e., using ring 0 stack),
711 * so transfer the stack frame into the PCB explicitly, then
712 * start running on resulting "PCB stack". We have to set
713 * up a simulated "uesp" manually, since there's none in the
720 movl CX(EXT(active_kloaded),%edx),%ebx
721 movl CX(EXT(kernel_stack),%edx),%eax
723 FRAME_STACK_TO_PCB(%ebx,%eax)
734 movl CX(EXT(kernel_stack),%edx),%ebx
735 xchgl %ebx,%esp /* switch to kernel stack */
736 /* user regs pointer already set */
738 pushl %ebx /* record register save area */
739 pushl %ebx /* pass register save area to trap */
740 call EXT(user_trap) /* call user trap routine */
741 movl 4(%esp),%esp /* switch back to PCB stack */
744 * Return from trap or system call, checking for ASTs.
748 LEXT(return_from_trap)
750 cmpl $0,CX(EXT(need_ast),%edx)
751 je EXT(return_to_user) /* if we need an AST: */
753 movl CX(EXT(kernel_stack),%edx),%esp
754 /* switch to kernel stack */
755 pushl $0 /* push preemption flag */
756 call EXT(i386_astintr) /* take the AST */
757 addl $4,%esp /* pop preemption flag */
758 popl %esp /* switch back to PCB stack (w/exc link) */
759 jmp EXT(return_from_trap) /* and check again (rare) */
760 /* ASTs after this point will */
764 * Arrange the checks needed for kernel-loaded (or kernel-loading)
765 * threads so that branch is taken in kernel-loaded case.
770 cmpl $0,CX(EXT(active_kloaded),%eax)
771 jnz EXT(return_xfer_stack)
772 movl $CPD_ACTIVE_THREAD,%ebx
773 movl %gs:(%ebx),%ebx /* get active thread */
774 movl TH_TOP_ACT(%ebx),%ebx /* get thread->top_act */
775 cmpl $0,ACT_KLOADING(%ebx) /* check if kernel-loading */
776 jnz EXT(return_kernel_loading)
780 movl $CPD_PREEMPTION_LEVEL,%ebx
782 je EXT(return_from_kernel)
784 #endif /* MACH_ASSERT */
788 * Return from kernel mode to interrupted thread.
791 LEXT(return_from_kernel)
793 popl %gs /* restore segment registers */
800 popa /* restore general registers */
801 addl $8,%esp /* discard trap number and error code */
804 iret /* return from interrupt */
807 LEXT(return_xfer_stack)
809 * If we're on PCB stack in a kernel-loaded task, we have
810 * to transfer saved state back to thread stack and swap
811 * stack pointers here, because the hardware's not going
816 movl CX(EXT(kernel_stack),%eax),%esp
817 movl CX(EXT(active_kloaded),%eax),%eax
818 FRAME_PCB_TO_STACK(%eax)
821 jmp EXT(return_from_kernel)
824 * Hate to put this here, but setting up a separate swap_func for
825 * kernel-loaded threads no longer works, since thread executes
826 * "for a while" (i.e., until it reaches glue code) when first
827 * created, even if it's nominally suspended. Hence we can't
828 * transfer the PCB when the thread first resumes, because we
829 * haven't initialized it yet.
832 * Have to force transfer to new stack "manually". Use a string
833 * move to transfer all of our saved state to the stack pointed
834 * to by iss.uesp, then install a pointer to it as our current
837 LEXT(return_kernel_loading)
839 movl CX(EXT(kernel_stack),%eax),%esp
840 movl $CPD_ACTIVE_THREAD,%ebx
841 movl %gs:(%ebx),%ebx /* get active thread */
842 movl TH_TOP_ACT(%ebx),%ebx /* get thread->top_act */
843 movl %ebx,%edx /* save for later */
844 movl $0,ACT_KLOADING(%edx) /* clear kernel-loading bit */
845 FRAME_PCB_TO_STACK(%ebx)
846 movl %ebx,%esp /* start running on new stack */
847 movl $1,ACT_KLOADED(%edx) /* set kernel-loaded bit */
848 movl %edx,CX(EXT(active_kloaded),%eax) /* set cached indicator */
849 jmp EXT(return_from_kernel)
852 * Trap from kernel mode. No need to switch stacks or load segment registers.
855 #if MACH_KDB || MACH_KGDB
858 movl %esp,%ebx /* save current stack */
860 cmpl EXT(int_stack_high),%esp /* on an interrupt stack? */
864 cmpl $0,EXT(kgdb_active) /* Unexpected trap in kgdb */
867 pushl %esp /* Already on kgdb stack */
871 jmp EXT(return_from_kernel)
872 0: /* should kgdb handle this exception? */
873 cmpl $(T_NO_FPU),R_TRAPNO(%esp) /* FPU disabled? */
875 cmpl $(T_PAGE_FAULT),R_TRAPNO(%esp) /* page fault? */
878 cli /* disable interrupts */
879 CPU_NUMBER(%edx) /* get CPU number */
880 movl CX(EXT(kgdb_stacks),%edx),%ebx
881 xchgl %ebx,%esp /* switch to kgdb stack */
882 pushl %ebx /* pass old sp as an arg */
883 call EXT(kgdb_from_kernel)
884 popl %esp /* switch back to kernel stack */
885 jmp EXT(return_from_kernel)
887 #endif /* MACH_KGDB */
890 cmpl $0,EXT(db_active) /* could trap be from ddb? */
893 CPU_NUMBER(%edx) /* see if this CPU is in ddb */
894 cmpl $0,CX(EXT(kdb_active),%edx)
896 #endif /* NCPUS > 1 */
898 call EXT(db_trap_from_asm)
900 jmp EXT(return_from_kernel)
904 * Dilemma: don't want to switch to kernel_stack if trap
905 * "belongs" to ddb; don't want to switch to db_stack if
906 * trap "belongs" to kernel. So have to duplicate here the
907 * set of trap types that kernel_trap() handles. Note that
908 * "unexpected" page faults will not be handled by kernel_trap().
909 * In this panic-worthy case, we fall into the debugger with
910 * kernel_stack containing the call chain that led to the
913 movl R_TRAPNO(%esp),%edx
914 cmpl $(T_PAGE_FAULT),%edx
916 cmpl $(T_NO_FPU),%edx
918 cmpl $(T_FPU_FAULT),%edx
920 cmpl $(T_FLOATING_POINT_ERROR),%edx
922 cmpl $(T_PREEMPT),%edx
925 #endif /* MACH_KDB */
927 CPU_NUMBER(%edx) /* get CPU number */
928 cmpl CX(EXT(kernel_stack),%edx),%esp
929 /* if not already on kernel stack, */
930 ja 5f /* check some more */
931 cmpl CX(EXT(active_stacks),%edx),%esp
932 ja 6f /* on kernel stack: no switch */
934 movl CX(EXT(kernel_stack),%edx),%esp
936 pushl %ebx /* save old stack */
937 pushl %ebx /* pass as parameter */
938 call EXT(kernel_trap) /* to kernel trap routine */
939 addl $4,%esp /* pop parameter */
943 * If kernel_trap returns false, trap wasn't handled.
948 movl CX(EXT(db_stacks),%edx),%esp
949 pushl %ebx /* pass old stack as parameter */
950 call EXT(db_trap_from_asm)
951 #endif /* MACH_KDB */
953 cli /* disable interrupts */
954 CPU_NUMBER(%edx) /* get CPU number */
955 movl CX(EXT(kgdb_stacks),%edx),%esp
956 pushl %ebx /* pass old stack as parameter */
957 call EXT(kgdb_from_kernel)
958 #endif /* MACH_KGDB */
959 addl $4,%esp /* pop parameter */
963 * Likewise, if kdb_trap/kgdb_from_kernel returns false, trap
966 pushl %ebx /* pass old stack as parameter */
968 addl $4,%esp /* pop parameter */
970 movl %ebx,%esp /* get old stack (from callee-saves reg) */
971 #else /* MACH_KDB || MACH_KGDB */
972 pushl %esp /* pass parameter */
973 call EXT(kernel_trap) /* to kernel trap routine */
974 addl $4,%esp /* pop parameter */
975 #endif /* MACH_KDB || MACH_KGDB */
980 movl CX(EXT(need_ast),%edx),%eax /* get pending asts */
981 testl $AST_URGENT,%eax /* any urgent preemption? */
982 je EXT(return_from_kernel) /* no, nothing to do */
983 cmpl $0,EXT(preemptable) /* kernel-mode, preemption enabled? */
984 je EXT(return_from_kernel) /* no, skip it */
985 cmpl $T_PREEMPT,48(%esp) /* preempt request? */
986 jne EXT(return_from_kernel) /* no, nothing to do */
987 movl CX(EXT(kernel_stack),%edx),%eax
990 andl $(-KERNEL_STACK_SIZE),%ecx
991 testl %ecx,%ecx /* are we on the kernel stack? */
992 jne EXT(return_from_kernel) /* no, skip it */
994 #if PREEMPT_DEBUG_LOG
995 pushl 28(%esp) /* stack pointer */
996 pushl 24+4(%esp) /* frame pointer */
997 pushl 56+8(%esp) /* stack pointer */
999 call EXT(log_thread_action)
1002 0: String "trap preempt eip"
1004 #endif /* PREEMPT_DEBUG_LOG */
1006 pushl $1 /* push preemption flag */
1007 call EXT(i386_astintr) /* take the AST */
1008 addl $4,%esp /* pop preemption flag */
1009 #endif /* MACH_RT */
1011 jmp EXT(return_from_kernel)
1014 * Called as a function, makes the current thread
1015 * return from the kernel as if from an exception.
1018 .globl EXT(thread_exception_return)
1019 .globl EXT(thread_bootstrap_return)
1020 LEXT(thread_exception_return)
1021 LEXT(thread_bootstrap_return)
1022 movl %esp,%ecx /* get kernel stack */
1023 or $(KERNEL_STACK_SIZE-1),%ecx
1024 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
1025 jmp EXT(return_from_trap)
1027 Entry(call_continuation)
1028 movl S_ARG0,%eax /* get continuation */
1029 movl %esp,%ecx /* get kernel stack */
1030 or $(KERNEL_STACK_SIZE-1),%ecx
1031 addl $(-3-IKS_SIZE),%ecx
1032 movl %ecx,%esp /* pop the stack */
1033 xorl %ebp,%ebp /* zero frame pointer */
1034 jmp *%eax /* goto continuation */
1037 #define LOG_INTERRUPT(info,msg) \
1041 call EXT(log_thread_action) ; \
1044 #define CHECK_INTERRUPT_TIME(n) \
1047 call EXT(check_thread_time) ; \
1051 #define LOG_INTERRUPT(info,msg)
1052 #define CHECK_INTERRUPT_TIME(n)
1056 String "interrupt start"
1058 String "interrupt end"
1061 * All interrupts enter here.
1062 * old %eax on stack; interrupt number in %eax.
1065 pushl %ecx /* save registers */
1067 cld /* clear direction flag */
1069 cmpl %ss:EXT(int_stack_high),%esp /* on an interrupt stack? */
1070 jb int_from_intstack /* if not: */
1072 pushl %ds /* save segment registers */
1074 mov %ss,%dx /* switch to kernel segments */
1082 movl CX(EXT(int_stack_top),%edx),%ecx
1083 xchgl %ecx,%esp /* switch to interrupt stack */
1086 pushl %ecx /* save pointer to old stack */
1088 pushl %ebx /* save %ebx - out of the way */
1089 /* so stack looks the same */
1090 pushl %ecx /* save pointer to old stack */
1091 TIME_INT_ENTRY /* do timing */
1095 movl $CPD_PREEMPTION_LEVEL,%edx
1097 #endif /* MACH_RT */
1099 movl $CPD_INTERRUPT_LEVEL,%edx
1102 pushl %eax /* Push trap number */
1103 call EXT(PE_incoming_interrupt) /* call generic interrupt routine */
1104 addl $4,%esp /* Pop trap number */
1106 .globl EXT(return_to_iret)
1107 LEXT(return_to_iret) /* (label for kdb_kintr and hardclock) */
1109 movl $CPD_INTERRUPT_LEVEL,%edx
1113 movl $CPD_PREEMPTION_LEVEL,%edx
1115 #endif /* MACH_RT */
1119 TIME_INT_EXIT /* do timing */
1120 movl 4(%esp),%ebx /* restore the extra reg we saved */
1123 popl %esp /* switch back to old stack */
1126 movl CX(EXT(need_ast),%edx),%eax
1127 testl %eax,%eax /* any pending asts? */
1128 je 1f /* no, nothing to do */
1129 testl $(EFL_VM),I_EFL(%esp) /* if in V86 */
1130 jnz ast_from_interrupt /* take it */
1131 testb $3,I_CS(%esp) /* user mode, */
1132 jnz ast_from_interrupt /* take it */
1134 cmpl ETEXT_ADDR,I_EIP(%esp) /* if within kernel-loaded task, */
1135 jnb ast_from_interrupt /* take it */
1139 cmpl $0,EXT(preemptable) /* kernel-mode, preemption enabled? */
1140 je 1f /* no, skip it */
1141 movl $CPD_PREEMPTION_LEVEL,%ecx
1142 cmpl $0,%gs:(%ecx) /* preemption masked? */
1143 jne 1f /* yes, skip it */
1144 testl $AST_URGENT,%eax /* any urgent requests? */
1145 je 1f /* no, skip it */
1146 cmpl $LEXT(locore_end),I_EIP(%esp) /* are we in locore code? */
1147 jb 1f /* yes, skip it */
1148 movl CX(EXT(kernel_stack),%edx),%eax
1151 andl $(-KERNEL_STACK_SIZE),%ecx
1152 testl %ecx,%ecx /* are we on the kernel stack? */
1153 jne 1f /* no, skip it */
1156 * Take an AST from kernel space. We don't need (and don't want)
1157 * to do as much as the case where the interrupt came from user
1160 #if PREEMPT_DEBUG_LOG
1165 call EXT(log_thread_action)
1168 0: String "intr preempt eip"
1170 #endif /* PREEMPT_DEBUG_LOG */
1173 pushl $1 /* push preemption flag */
1174 call EXT(i386_astintr) /* take the AST */
1175 addl $4,%esp /* pop preemption flag */
1176 #endif /* MACH_RT */
1179 pop %es /* restore segment regs */
1184 iret /* return to caller */
1188 movl $CPD_PREEMPTION_LEVEL,%edx
1190 #endif /* MACH_RT */
1192 movl $CPD_INTERRUPT_LEVEL,%edx
1195 pushl %eax /* Push trap number */
1197 call EXT(PE_incoming_interrupt)
1199 LEXT(return_to_iret_i) /* ( label for kdb_kintr) */
1201 addl $4,%esp /* pop trap number */
1203 movl $CPD_INTERRUPT_LEVEL,%edx
1207 movl $CPD_PREEMPTION_LEVEL,%edx
1209 #endif /* MACH_RT */
1211 pop %edx /* must have been on kernel segs */
1213 pop %eax /* no ASTs */
1217 * Take an AST from an interrupt.
1231 pop %es /* restore all registers ... */
1236 sti /* Reenable interrupts */
1237 pushl $0 /* zero code */
1238 pushl $0 /* zero trap number */
1239 pusha /* save general registers */
1240 push %ds /* save segment registers */
1244 mov %ss,%dx /* switch to kernel segments */
1251 * See if we interrupted a kernel-loaded thread executing
1255 testl $(EFL_VM),R_EFLAGS(%esp) /* in V86 mode? */
1256 jnz 0f /* user mode trap if so */
1258 jnz 0f /* user mode, back to normal */
1260 cmpl ETEXT_ADDR,R_EIP(%esp)
1261 jb 0f /* not kernel-loaded, back to normal */
1265 * Transfer the current stack frame by hand into the PCB.
1268 movl CX(EXT(active_kloaded),%edx),%eax
1269 movl CX(EXT(kernel_stack),%edx),%ebx
1271 FRAME_STACK_TO_PCB(%eax,%ebx)
1278 movl CX(EXT(kernel_stack),%edx),%eax
1279 /* switch to kernel stack */
1283 pushl $0 /* push preemption flag */
1284 call EXT(i386_astintr) /* take the AST */
1285 addl $4,%esp /* pop preemption flag */
1286 popl %esp /* back to PCB stack */
1287 jmp EXT(return_from_trap) /* return */
1289 #if MACH_KDB || MACH_KGDB
1291 * kdb_kintr: enter kdb from keyboard interrupt.
1292 * Chase down the stack frames until we find one whose return
1293 * address is the interrupt handler. At that point, we have:
1295 * frame-> saved %ebp
1296 * return address in interrupt handler
1299 * return address == return_to_iret_i
1308 * frame-> saved %ebp
1309 * return address in interrupt handler
1312 * return address == return_to_iret
1313 * pointer to save area on old stack
1314 * [ saved %ebx, if accurate timing ]
1316 * old stack: saved %es
1325 * Call kdb, passing it that register save area.
1330 #endif /* MACH_KGDB */
1333 #endif /* MACH_KDB */
1334 movl %ebp,%eax /* save caller`s frame pointer */
1335 movl $EXT(return_to_iret),%ecx /* interrupt return address 1 */
1336 movl $EXT(return_to_iret_i),%edx /* interrupt return address 2 */
1338 0: cmpl 16(%eax),%ecx /* does this frame return to */
1339 /* interrupt handler (1)? */
1341 cmpl $kdb_from_iret,16(%eax)
1343 cmpl 16(%eax),%edx /* interrupt handler (2)? */
1345 cmpl $kdb_from_iret_i,16(%eax)
1347 movl (%eax),%eax /* try next frame */
1350 1: movl $kdb_from_iret,16(%eax) /* returns to kernel/user stack */
1353 2: movl $kdb_from_iret_i,16(%eax)
1354 /* returns to interrupt stack */
1358 * On return from keyboard interrupt, we will execute
1360 * if returning to an interrupt on the interrupt stack
1362 * if returning to an interrupt on the user or kernel stack
1365 /* save regs in known locations */
1367 pushl %ebx /* caller`s %ebx is in reg */
1369 movl 4(%esp),%eax /* get caller`s %ebx */
1370 pushl %eax /* push on stack */
1379 pushl %esp /* pass regs */
1380 call EXT(kgdb_kentry) /* to kgdb */
1381 addl $4,%esp /* pop parameters */
1382 #endif /* MACH_KGDB */
1384 pushl %esp /* pass regs */
1385 call EXT(kdb_kentry) /* to kdb */
1386 addl $4,%esp /* pop parameters */
1387 #endif /* MACH_KDB */
1388 pop %gs /* restore registers */
1399 jmp EXT(return_to_iret) /* normal interrupt return */
1401 kdb_from_iret_i: /* on interrupt stack */
1402 pop %edx /* restore saved registers */
1405 pushl $0 /* zero error code */
1406 pushl $0 /* zero trap number */
1407 pusha /* save general registers */
1408 push %ds /* save segment registers */
1413 cli /* disable interrupts */
1414 CPU_NUMBER(%edx) /* get CPU number */
1415 movl CX(EXT(kgdb_stacks),%edx),%ebx
1416 xchgl %ebx,%esp /* switch to kgdb stack */
1417 pushl %ebx /* pass old sp as an arg */
1418 call EXT(kgdb_from_kernel)
1419 popl %esp /* switch back to interrupt stack */
1420 #endif /* MACH_KGDB */
1422 pushl %esp /* pass regs, */
1423 pushl $0 /* code, */
1424 pushl $-1 /* type to kdb */
1427 #endif /* MACH_KDB */
1428 pop %gs /* restore segment registers */
1432 popa /* restore general registers */
1436 #endif /* MACH_KDB || MACH_KGDB */
1440 * Mach RPC enters through a call gate, like a system call.
1444 pushf /* save flags as soon as possible */
1445 pushl %eax /* save system call number */
1446 pushl $0 /* clear trap number slot */
1448 pusha /* save the general registers */
1449 pushl %ds /* and the segment registers */
1454 mov %ss,%dx /* switch to kernel data segment */
1461 * Shuffle eflags,eip,cs into proper places
1464 movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
1465 movl R_CS(%esp),%ecx /* eip is in CS slot */
1466 movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
1467 movl %ecx,R_EIP(%esp) /* fix eip */
1468 movl %edx,R_CS(%esp) /* fix cs */
1469 movl %ebx,R_EFLAGS(%esp) /* fix eflags */
1474 negl %eax /* get system call number */
1475 shll $4,%eax /* manual indexing */
1478 * Check here for mach_rpc from kernel-loaded task --
1479 * - Note that kernel-loaded task returns via real return.
1480 * We didn't enter here "through" PCB (i.e., using ring 0 stack),
1481 * so transfer the stack frame into the PCB explicitly, then
1482 * start running on resulting "PCB stack". We have to set
1483 * up a simulated "uesp" manually, since there's none in the
1486 cmpl $0,CX(EXT(active_kloaded),%edx)
1489 movl CX(EXT(active_kloaded),%edx),%ebx
1490 movl CX(EXT(kernel_stack),%edx),%edx
1493 FRAME_STACK_TO_PCB(%ebx,%edx)
1501 movl CX(EXT(kernel_stack),%edx),%ebx
1502 /* get current kernel stack */
1503 xchgl %ebx,%esp /* switch stacks - %ebx points to */
1504 /* user registers. */
1509 * Register use on entry:
1510 * eax contains syscall number
1511 * ebx contains user regs pointer
1513 #undef RPC_TRAP_REGISTERS
1514 #ifdef RPC_TRAP_REGISTERS
1520 movl EXT(mach_trap_table)(%eax),%ecx
1521 /* get number of arguments */
1522 jecxz 2f /* skip argument copy if none */
1523 movl R_UESP(%ebx),%esi /* get user stack pointer */
1524 lea 4(%esi,%ecx,4),%esi /* skip user return address, */
1525 /* and point past last argument */
1526 /* edx holds cpu number from above */
1527 movl CX(EXT(active_kloaded),%edx),%edx
1528 /* point to current thread */
1529 orl %edx,%edx /* if ! kernel-loaded, check addr */
1531 mov %ds,%dx /* kernel data segment access */
1534 cmpl $(VM_MAX_ADDRESS),%esi /* in user space? */
1535 ja mach_call_addr /* address error if not */
1536 movl $USER_DS,%edx /* user data segment access */
1539 movl %esp,%edx /* save kernel ESP for error recovery */
1543 RECOVER(mach_call_addr_push)
1544 pushl %fs:(%esi) /* push argument on stack */
1545 loop 1b /* loop for all arguments */
1549 * Register use on entry:
1550 * eax contains syscall number
1551 * ebx contains user regs pointer
1555 call *EXT(mach_trap_table)+4(%eax)
1556 /* call procedure */
1557 movl %esp,%ecx /* get kernel stack */
1558 or $(KERNEL_STACK_SIZE-1),%ecx
1559 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
1560 movl %eax,R_EAX(%esp) /* save return value */
1561 jmp EXT(return_from_trap) /* return to user */
1565 * Special system call entry for "int 0x80", which has the "eflags"
1566 * register saved at the right place already.
1567 * Fall back to the common syscall path after saving the registers.
1572 * old esp if trapped from user
1573 * old ss if trapped from user
1575 * XXX: for the moment, we don't check for int 0x80 from kernel mode.
1577 Entry(syscall_int80)
1578 pushl %eax /* save system call number */
1579 pushl $0 /* clear trap number slot */
1581 pusha /* save the general registers */
1582 pushl %ds /* and the segment registers */
1587 mov %ss,%dx /* switch to kernel data segment */
1596 * System call enters through a call gate. Flags are not saved -
1597 * we must shuffle stack to look like trap save area.
1604 * eax contains system call number.
1606 * NB: below use of CPU_NUMBER assumes that macro will use correct
1607 * correct segment register for any kernel data accesses.
1611 pushf /* save flags as soon as possible */
1613 pushl %eax /* save system call number */
1614 pushl $0 /* clear trap number slot */
1616 pusha /* save the general registers */
1617 pushl %ds /* and the segment registers */
1622 mov %ss,%dx /* switch to kernel data segment */
1629 * Shuffle eflags,eip,cs into proper places
1632 movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
1633 movl R_CS(%esp),%ecx /* eip is in CS slot */
1634 movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
1635 movl %ecx,R_EIP(%esp) /* fix eip */
1636 movl %edx,R_CS(%esp) /* fix cs */
1637 movl %ebx,R_EFLAGS(%esp) /* fix eflags */
1642 * Check here for syscall from kernel-loaded task --
1643 * We didn't enter here "through" PCB (i.e., using ring 0 stack),
1644 * so transfer the stack frame into the PCB explicitly, then
1645 * start running on resulting "PCB stack". We have to set
1646 * up a simulated "uesp" manually, since there's none in the
1649 cmpl $0,CX(EXT(active_kloaded),%edx)
1652 movl CX(EXT(active_kloaded),%edx),%ebx
1653 movl CX(EXT(kernel_stack),%edx),%edx
1655 FRAME_STACK_TO_PCB(%ebx,%edx)
1665 movl CX(EXT(kernel_stack),%edx),%ebx
1666 /* get current kernel stack */
1667 xchgl %ebx,%esp /* switch stacks - %ebx points to */
1668 /* user registers. */
1669 /* user regs pointer already set */
1672 * Check for MACH or emulated system call
1673 * Register use (from here till we begin processing call):
1674 * eax contains system call number
1675 * ebx points to user regs
1678 movl $CPD_ACTIVE_THREAD,%edx
1679 movl %gs:(%edx),%edx /* get active thread */
1680 /* point to current thread */
1681 movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */
1682 movl ACT_TASK(%edx),%edx /* point to task */
1683 movl TASK_EMUL(%edx),%edx /* get emulation vector */
1684 orl %edx,%edx /* if none, */
1685 je syscall_native /* do native system call */
1686 movl %eax,%ecx /* copy system call number */
1687 subl DISP_MIN(%edx),%ecx /* get displacement into syscall */
1689 jl syscall_native /* too low - native system call */
1690 cmpl DISP_COUNT(%edx),%ecx /* check range */
1691 jnl syscall_native /* too high - native system call */
1692 movl DISP_VECTOR(%edx,%ecx,4),%edx
1693 /* get the emulation vector */
1694 orl %edx,%edx /* emulated system call if not zero */
1698 * Native system call.
1699 * Register use on entry:
1700 * eax contains syscall number
1701 * ebx points to user regs
1704 negl %eax /* get system call number */
1705 jl mach_call_range /* out of range if it was positive */
1707 cmpl EXT(mach_trap_count),%eax /* check system call table bounds */
1708 jg mach_call_range /* error if out of range */
1709 shll $4,%eax /* manual indexing */
1711 movl EXT(mach_trap_table)+4(%eax),%edx
1713 cmpl $EXT(kern_invalid),%edx /* if not "kern_invalid" */
1714 jne mach_syscall_native /* go on with Mach syscall */
1716 movl $CPD_ACTIVE_THREAD,%edx
1717 movl %gs:(%edx),%edx /* get active thread */
1718 /* point to current thread */
1719 movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */
1720 movl ACT_TASK(%edx),%edx /* point to task */
1721 movl TASK_EMUL(%edx),%edx /* get emulation vector */
1722 orl %edx,%edx /* if it exists, */
1723 jne mach_syscall_native /* do native system call */
1724 shrl $4,%eax /* restore syscall number */
1725 jmp mach_call_range /* try it as a "server" syscall */
1727 mach_syscall_native:
1728 movl $CPD_ACTIVE_THREAD,%edx
1729 movl %gs:(%edx),%edx /* get active thread */
1731 movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */
1732 movl ACT_MACH_EXC_PORT(%edx),%edx
1733 movl $EXT(realhost),%ecx
1734 movl HOST_NAME(%ecx),%ecx
1735 cmpl %edx,%ecx /* act->mach_exc_port = host_name ? */
1736 je do_native_call /* -> send to kernel, do not collect $200 */
1737 cmpl $0,%edx /* thread->mach_exc_port = null ? */
1738 je try_task /* try task */
1739 jmp mach_syscall_exception
1743 movl $CPD_ACTIVE_THREAD,%edx
1744 movl %gs:(%edx),%edx /* get active thread */
1746 movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */
1747 movl ACT_TASK(%edx),%edx /* point to task */
1748 movl TASK_MACH_EXC_PORT(%edx),%edx
1749 movl $EXT(realhost),%ecx
1750 movl HOST_NAME(%ecx),%ecx
1751 cmpl %edx,%ecx /* thread->mach_exc_port = host_name ? */
1752 je do_native_call /* -> send to kernel */
1753 cmpl $0,%edx /* thread->mach_exc_port = null ? */
1754 je EXT(syscall_failed) /* try task */
1755 jmp mach_syscall_exception
1759 * Register use on entry:
1760 * eax contains syscall number
1761 * ebx contains user regs pointer
1764 movl EXT(mach_trap_table)(%eax),%ecx
1765 /* get number of arguments */
1766 jecxz mach_call_call /* skip argument copy if none */
1767 movl R_UESP(%ebx),%esi /* get user stack pointer */
1768 lea 4(%esi,%ecx,4),%esi /* skip user return address, */
1769 /* and point past last argument */
1771 movl CX(EXT(active_kloaded),%edx),%edx
1772 /* point to current thread */
1773 orl %edx,%edx /* if kernel-loaded, skip addr check */
1775 mov %ds,%dx /* kernel data segment access */
1778 cmpl $(VM_MAX_ADDRESS),%esi /* in user space? */
1779 ja mach_call_addr /* address error if not */
1780 movl $USER_DS,%edx /* user data segment access */
1783 movl %esp,%edx /* save kernel ESP for error recovery */
1787 RECOVER(mach_call_addr_push)
1788 pushl %fs:(%esi) /* push argument on stack */
1789 loop 2b /* loop for all arguments */
1792 * Register use on entry:
1793 * eax contains syscall number
1794 * ebx contains user regs pointer
1800 #if ETAP_EVENT_MONITOR
1801 cmpl $0x200, %eax /* is this mach_msg? */
1802 jz make_syscall /* if yes, don't record event */
1804 pushal /* Otherwise: save registers */
1805 pushl %eax /* push syscall number on stack*/
1806 call EXT(etap_machcall_probe1) /* call event begin probe */
1807 add $4,%esp /* restore stack */
1808 popal /* restore registers */
1810 call *EXT(mach_trap_table)+4(%eax) /* call procedure */
1812 call EXT(etap_machcall_probe2) /* call event end probe */
1814 jmp skip_syscall /* syscall already made */
1815 #endif /* ETAP_EVENT_MONITOR */
1818 call *EXT(mach_trap_table)+4(%eax) /* call procedure */
1821 movl %esp,%ecx /* get kernel stack */
1822 or $(KERNEL_STACK_SIZE-1),%ecx
1823 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
1824 movl %eax,R_EAX(%esp) /* save return value */
1825 jmp EXT(return_from_trap) /* return to user */
1828 * Address out of range. Change to page fault.
1829 * %esi holds failing address.
1830 * Register use on entry:
1831 * ebx contains user regs pointer
1833 mach_call_addr_push:
1834 movl %edx,%esp /* clean parameters from stack */
1836 movl %esi,R_CR2(%ebx) /* set fault address */
1837 movl $(T_PAGE_FAULT),R_TRAPNO(%ebx)
1838 /* set page-fault trap */
1839 movl $(T_PF_USER),R_ERR(%ebx)
1840 /* set error code - read user space */
1842 jmp EXT(take_trap) /* treat as a trap */
1845 * try sending mach system call exception to server
1846 * Register use on entry:
1847 * eax contains syscall number
1849 mach_syscall_exception:
1850 push %eax /* code (syscall no.) */
1852 push $1 /* code_cnt = 1 */
1853 push %edx /* exception_type_t (see i/f docky) */
1854 push $EXC_MACH_SYSCALL /* exception */
1861 * System call out of range. Treat as invalid-instruction trap.
1862 * (? general protection?)
1863 * Register use on entry:
1864 * eax contains syscall number
1867 movl $CPD_ACTIVE_THREAD,%edx
1868 movl %gs:(%edx),%edx /* get active thread */
1870 movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */
1871 movl ACT_TASK(%edx),%edx /* point to task */
1872 movl TASK_EMUL(%edx),%edx /* get emulation vector */
1873 orl %edx,%edx /* if emulator, */
1874 jne EXT(syscall_failed) /* handle as illegal instruction */
1875 /* else generate syscall exception: */
1878 push $1 /* code_cnt = 1 */
1879 push %edx /* exception_type_t (see i/f docky) */
1885 .globl EXT(syscall_failed)
1886 LEXT(syscall_failed)
1887 movl %esp,%ecx /* get kernel stack */
1888 or $(KERNEL_STACK_SIZE-1),%ecx
1889 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
1891 movl CX(EXT(kernel_stack),%edx),%ebx
1892 /* get current kernel stack */
1893 xchgl %ebx,%esp /* switch stacks - %ebx points to */
1894 /* user registers. */
1895 /* user regs pointer already set */
1897 movl $(T_INVALID_OPCODE),R_TRAPNO(%ebx)
1898 /* set invalid-operation trap */
1899 movl $0,R_ERR(%ebx) /* clear error code */
1901 jmp EXT(take_trap) /* treat as a trap */
1904 * User space emulation of system calls.
1905 * edx - user address to handle syscall
1907 * User stack will become:
1910 * Register use on entry:
1911 * ebx contains user regs pointer
1912 * edx contains emulator vector address
1915 movl R_UESP(%ebx),%edi /* get user stack pointer */
1917 movl CX(EXT(active_kloaded),%eax),%eax
1918 orl %eax,%eax /* if thread not kernel-loaded, */
1919 jz 0f /* do address checks */
1921 mov %ds,%ax /* kernel data segment access */
1922 jmp 1f /* otherwise, skip them */
1924 cmpl $(VM_MAX_ADDRESS),%edi /* in user space? */
1925 ja syscall_addr /* address error if not */
1926 subl $8,%edi /* push space for new arguments */
1927 cmpl $(VM_MIN_ADDRESS),%edi /* still in user space? */
1928 jb syscall_addr /* error if not */
1929 movl $USER_DS,%ax /* user data segment access */
1932 movl R_EFLAGS(%ebx),%eax /* move flags */
1934 RECOVER(syscall_addr)
1935 movl %eax,%fs:0(%edi) /* to user stack */
1936 movl R_EIP(%ebx),%eax /* move eip */
1938 RECOVER(syscall_addr)
1939 movl %eax,%fs:4(%edi) /* to user stack */
1940 movl %edi,R_UESP(%ebx) /* set new user stack pointer */
1941 movl %edx,R_EIP(%ebx) /* change return address to trap */
1942 movl %ebx,%esp /* back to PCB stack */
1944 jmp EXT(return_from_trap) /* return to user */
1948 * Address error - address is in %edi.
1949 * Register use on entry:
1950 * ebx contains user regs pointer
1953 movl %edi,R_CR2(%ebx) /* set fault address */
1954 movl $(T_PAGE_FAULT),R_TRAPNO(%ebx)
1955 /* set page-fault trap */
1956 movl $(T_PF_USER),R_ERR(%ebx)
1957 /* set error code - read user space */
1959 jmp EXT(take_trap) /* treat as a trap */
1968 * Copy from user address space.
1969 * arg0: user address
1970 * arg1: kernel address
1976 pushl %edi /* save registers */
1978 movl 8+S_ARG0,%esi /* get user start address */
1979 movl 8+S_ARG1,%edi /* get kernel destination address */
1980 movl 8+S_ARG2,%edx /* get count */
1982 lea 0(%esi,%edx),%eax /* get user end address + 1 */
1984 movl $CPD_ACTIVE_THREAD,%ecx
1985 movl %gs:(%ecx),%ecx /* get active thread */
1986 movl TH_TOP_ACT(%ecx),%ecx /* get thread->top_act */
1987 movl ACT_MAP(%ecx),%ecx /* get act->map */
1988 movl MAP_PMAP(%ecx),%ecx /* get map->pmap */
1989 cmpl EXT(kernel_pmap), %ecx
1991 movl $USER_DS,%cx /* user data segment access */
1995 jb copyin_fail /* fail if wrap-around */
1997 movl %edx,%ecx /* move by longwords first */
2000 RECOVER(copyin_fail)
2002 movsl /* move longwords */
2003 movl %edx,%ecx /* now move remaining bytes */
2006 RECOVER(copyin_fail)
2009 xorl %eax,%eax /* return 0 for success */
2011 mov %ss,%di /* restore kernel data segment */
2014 popl %edi /* restore registers */
2016 ret /* and return */
2019 movl $EFAULT,%eax /* return error for failure */
2020 jmp copy_ret /* pop frame and return */
2023 * Copy string from user address space.
2024 * arg0: user address
2025 * arg1: kernel address
2026 * arg2: max byte count
2027 * arg3: actual byte count (OUT)
2031 pushl %edi /* save registers */
2033 movl 8+S_ARG0,%esi /* get user start address */
2034 movl 8+S_ARG1,%edi /* get kernel destination address */
2035 movl 8+S_ARG2,%edx /* get count */
2037 lea 0(%esi,%edx),%eax /* get user end address + 1 */
2039 movl $CPD_ACTIVE_THREAD,%ecx
2040 movl %gs:(%ecx),%ecx /* get active thread */
2041 movl TH_TOP_ACT(%ecx),%ecx /* get thread->top_act */
2042 movl ACT_MAP(%ecx),%ecx /* get act->map */
2043 movl MAP_PMAP(%ecx),%ecx /* get map->pmap */
2044 cmpl EXT(kernel_pmap), %ecx
2046 mov %ds,%cx /* kernel data segment access */
2049 movl $USER_DS,%cx /* user data segment access */
2057 RECOVER(copystr_fail) /* copy bytes... */
2058 movb %fs:(%esi),%eax
2060 testl %edi,%edi /* if kernel address is ... */
2061 jz 3f /* not NULL */
2062 movb %eax,(%edi) /* copy the byte */
2066 je 5f /* Zero count.. error out */
2068 jne 2b /* .. a NUL found? */
2071 movl $ENAMETOOLONG,%eax /* String is too long.. */
2073 xorl %eax,%eax /* return zero for success */
2074 movl 8+S_ARG3,%edi /* get OUT len ptr */
2076 jz copystr_ret /* if null, just return */
2078 movl %esi,(%edi) /* else set OUT arg to xfer len */
2080 popl %edi /* restore registers */
2082 ret /* and return */
2085 movl $EFAULT,%eax /* return error for failure */
2086 jmp copy_ret /* pop frame and return */
2089 * Copy to user address space.
2090 * arg0: kernel address
2091 * arg1: user address
2097 pushl %edi /* save registers */
2100 movl 12+S_ARG0,%esi /* get kernel start address */
2101 movl 12+S_ARG1,%edi /* get user start address */
2102 movl 12+S_ARG2,%edx /* get count */
2104 leal 0(%edi,%edx),%eax /* get user end address + 1 */
2106 movl $CPD_ACTIVE_THREAD,%ecx
2107 movl %gs:(%ecx),%ecx /* get active thread */
2108 movl TH_TOP_ACT(%ecx),%ecx /* get thread->top_act */
2109 movl ACT_MAP(%ecx),%ecx /* get act->map */
2110 movl MAP_PMAP(%ecx),%ecx /* get map->pmap */
2111 cmpl EXT(kernel_pmap), %ecx
2113 mov %ds,%cx /* else kernel data segment access */
2121 * Check whether user address space is writable
2122 * before writing to it - hardware is broken.
2124 * Skip check if "user" address is really in
2125 * kernel space (i.e., if it's in a kernel-loaded
2129 * esi/edi source/dest pointers for rep/mov
2130 * ecx counter for rep/mov
2131 * edx counts down from 3rd arg
2132 * eax count of bytes for each (partial) page copy
2133 * ebx shadows edi, used to adjust edx
2135 movl %edi,%ebx /* copy edi for syncing up */
2137 /* if restarting after a partial copy, put edx back in sync, */
2138 addl %ebx,%edx /* edx -= (edi - ebx); */
2140 movl %edi,%ebx /* ebx = edi; */
2143 cmpl $USER_DS,%cx /* If kernel data segment */
2144 jnz 0f /* skip check */
2146 cmpb $(CPUID_FAMILY_386), EXT(cpuid_family)
2149 movl %cr3,%ecx /* point to page directory */
2151 andl $(~0x7), %ecx /* remove cpu number */
2152 #endif /* NCPUS > 1 && AT386 */
2153 movl %edi,%eax /* get page directory bits */
2154 shrl $(PDESHIFT),%eax /* from user address */
2155 movl KERNELBASE(%ecx,%eax,4),%ecx
2156 /* get page directory pointer */
2157 testl $(PTE_V),%ecx /* present? */
2158 jz 0f /* if not, fault is OK */
2159 andl $(PTE_PFN),%ecx /* isolate page frame address */
2160 movl %edi,%eax /* get page table bits */
2161 shrl $(PTESHIFT),%eax
2162 andl $(PTEMASK),%eax /* from user address */
2163 leal KERNELBASE(%ecx,%eax,4),%ecx
2164 /* point to page table entry */
2165 movl (%ecx),%eax /* get it */
2166 testl $(PTE_V),%eax /* present? */
2167 jz 0f /* if not, fault is OK */
2168 testl $(PTE_W),%eax /* writable? */
2169 jnz 0f /* OK if so */
2171 * Not writable - must fake a fault. Turn off access to the page.
2173 andl $(PTE_INVALID),(%ecx) /* turn off valid bit */
2174 movl %cr3,%eax /* invalidate TLB */
2178 * Copy only what fits on the current destination page.
2179 * Check for write-fault again on the next page.
2181 leal NBPG(%edi),%eax /* point to */
2182 andl $(-NBPG),%eax /* start of next page */
2183 subl %edi,%eax /* get number of bytes to that point */
2184 cmpl %edx,%eax /* bigger than count? */
2186 movl %edx,%eax /* use count */
2189 movl %eax,%ecx /* move by longwords first */
2192 RECOVER(copyout_fail)
2194 RETRY(copyout_retry)
2197 movl %eax,%ecx /* now move remaining bytes */
2200 RECOVER(copyout_fail)
2202 RETRY(copyout_retry)
2205 movl %edi,%ebx /* copy edi for syncing up */
2206 subl %eax,%edx /* and decrement count */
2207 jg copyout_retry /* restart on next page if not done */
2208 xorl %eax,%eax /* return 0 for success */
2210 mov %ss,%di /* restore kernel segment */
2214 popl %edi /* restore registers */
2216 ret /* and return */
2219 movl $EFAULT,%eax /* return error for failure */
2220 jmp copyout_ret /* pop frame and return */
2237 pushl %eax /* get stack space */
2253 xor %eax,%eax /* clear high 16 bits of eax */
2254 fnstsw %ax /* read FP status */
2258 * Clear FPU exceptions
2265 * Clear task-switched flag.
2272 * Save complete FPU state. Save error for later.
2275 movl 4(%esp),%eax /* get save area pointer */
2276 fnsave (%eax) /* save complete state, including */
2281 * Restore FPU state.
2284 movl 4(%esp),%eax /* get save area pointer */
2285 frstor (%eax) /* restore complete state */
2295 #else /* NCPUS > 1 && AT386 */
2296 movl 4(%esp),%eax /* get new cr3 value */
2297 #endif /* NCPUS > 1 && AT386 */
2299 * Don't set PDBR to a new value (hence invalidating the
2300 * "paging cache") if the new value matches the current one.
2302 movl %cr3,%edx /* get current cr3 value */
2304 je 0f /* if two are equal, don't set */
2305 movl %eax,%cr3 /* load it (and flush cache) */
2315 andl $(~0x7), %eax /* remove cpu number */
2316 #endif /* NCPUS > 1 && AT386 */
2323 movl %cr3,%eax /* flush tlb by reloading CR3 */
2324 movl %eax,%cr3 /* with itself */
2338 .byte 0x0f,0x20,0xe0 /* movl %cr4, %eax */
2346 .byte 0x0f,0x22,0xe0 /* movl %eax, %cr4 */
2365 * Read task register.
2373 * Set task register. Also clears busy bit of task descriptor.
2376 movl S_ARG0,%eax /* get task segment number */
2377 subl $8,%esp /* push space for SGDT */
2378 sgdt 2(%esp) /* store GDT limit and base (linear) */
2379 movl 4(%esp),%edx /* address GDT */
2380 movb $(K_TSS),5(%edx,%eax) /* fix access byte in task descriptor */
2381 ltr %ax /* load task register */
2382 addl $8,%esp /* clear stack */
2383 ret /* and return */
2386 * Set task-switched flag.
2389 movl %cr0,%eax /* get cr0 */
2390 orl $(CR0_TS),%eax /* or in TS bit */
2391 movl %eax,%cr0 /* set cr0 */
2395 * io register must not be used on slaves (no AT bus)
2397 #define ILL_ON_SLAVE
2405 #define PUSH_FRAME FRAME
2406 #define POP_FRAME EMARF
2408 #else /* MACH_ASSERT */
2416 #endif /* MACH_ASSERT */
2419 #if MACH_KDB || MACH_ASSERT
2422 * Following routines are also defined as macros in i386/pio.h
2423 * Compile then when MACH_KDB is configured so that they
2424 * can be invoked from the debugger.
2428 * void outb(unsigned char *io_port,
2429 * unsigned char byte)
2431 * Output a byte to an IO port.
2436 movl ARG0,%edx /* IO port address */
2437 movl ARG1,%eax /* data to output */
2438 outb %al,%dx /* send it out */
2443 * unsigned char inb(unsigned char *io_port)
2445 * Input a byte from an IO port.
2450 movl ARG0,%edx /* IO port address */
2451 xor %eax,%eax /* clear high bits of register */
2452 inb %dx,%al /* get the byte */
2457 * void outw(unsigned short *io_port,
2458 * unsigned short word)
2460 * Output a word to an IO port.
2465 movl ARG0,%edx /* IO port address */
2466 movl ARG1,%eax /* data to output */
2467 outw %ax,%dx /* send it out */
2472 * unsigned short inw(unsigned short *io_port)
2474 * Input a word from an IO port.
2479 movl ARG0,%edx /* IO port address */
2480 xor %eax,%eax /* clear high bits of register */
2481 inw %dx,%ax /* get the word */
2486 * void outl(unsigned int *io_port,
2487 * unsigned int byte)
2489 * Output an int to an IO port.
2494 movl ARG0,%edx /* IO port address*/
2495 movl ARG1,%eax /* data to output */
2496 outl %eax,%dx /* send it out */
2501 * unsigned int inl(unsigned int *io_port)
2503 * Input an int from an IO port.
2508 movl ARG0,%edx /* IO port address */
2509 inl %dx,%eax /* get the int */
2513 #endif /* MACH_KDB || MACH_ASSERT*/
2516 * void loutb(unsigned byte *io_port,
2517 * unsigned byte *data,
2518 * unsigned int count)
2520 * Output an array of bytes to an IO port.
2526 movl %esi,%eax /* save register */
2527 movl ARG0,%edx /* get io port number */
2528 movl ARG1,%esi /* get data address */
2529 movl ARG2,%ecx /* get count */
2533 movl %eax,%esi /* restore register */
2539 * void loutw(unsigned short *io_port,
2540 * unsigned short *data,
2541 * unsigned int count)
2543 * Output an array of shorts to an IO port.
2549 movl %esi,%eax /* save register */
2550 movl ARG0,%edx /* get io port number */
2551 movl ARG1,%esi /* get data address */
2552 movl ARG2,%ecx /* get count */
2556 movl %eax,%esi /* restore register */
2561 * void loutw(unsigned short io_port,
2562 * unsigned int *data,
2563 * unsigned int count)
2565 * Output an array of longs to an IO port.
2571 movl %esi,%eax /* save register */
2572 movl ARG0,%edx /* get io port number */
2573 movl ARG1,%esi /* get data address */
2574 movl ARG2,%ecx /* get count */
2578 movl %eax,%esi /* restore register */
2584 * void linb(unsigned char *io_port,
2585 * unsigned char *data,
2586 * unsigned int count)
2588 * Input an array of bytes from an IO port.
2594 movl %edi,%eax /* save register */
2595 movl ARG0,%edx /* get io port number */
2596 movl ARG1,%edi /* get data address */
2597 movl ARG2,%ecx /* get count */
2601 movl %eax,%edi /* restore register */
2607 * void linw(unsigned short *io_port,
2608 * unsigned short *data,
2609 * unsigned int count)
2611 * Input an array of shorts from an IO port.
2617 movl %edi,%eax /* save register */
2618 movl ARG0,%edx /* get io port number */
2619 movl ARG1,%edi /* get data address */
2620 movl ARG2,%ecx /* get count */
2624 movl %eax,%edi /* restore register */
2630 * void linl(unsigned short io_port,
2631 * unsigned int *data,
2632 * unsigned int count)
2634 * Input an array of longs from an IO port.
2640 movl %edi,%eax /* save register */
2641 movl ARG0,%edx /* get io port number */
2642 movl ARG1,%edi /* get data address */
2643 movl ARG2,%ecx /* get count */
2647 movl %eax,%edi /* restore register */
2653 * int inst_fetch(int eip, int cs);
2655 * Fetch instruction byte. Return -1 if invalid address.
2657 .globl EXT(inst_fetch)
2659 movl S_ARG1, %eax /* get segment */
2660 movw %ax,%fs /* into FS */
2661 movl S_ARG0, %eax /* get offset */
2663 RETRY(EXT(inst_fetch)) /* re-load FS on retry */
2665 RECOVER(EXT(inst_fetch_fault))
2666 movzbl %fs:(%eax),%eax /* load instruction byte */
2669 LEXT(inst_fetch_fault)
2670 movl $-1,%eax /* return -1 if error */
2676 * kdp_copy_kmem(char *src, char *dst, int count)
2678 * Similar to copyin except that both addresses are kernel addresses.
2681 ENTRY(kdp_copy_kmem)
2683 pushl %edi /* save registers */
2685 movl 8+S_ARG0,%esi /* get kernel start address */
2686 movl 8+S_ARG1,%edi /* get kernel destination address */
2688 movl 8+S_ARG2,%edx /* get count */
2690 lea 0(%esi,%edx),%eax /* get kernel end address + 1 */
2693 jb kdp_vm_read_fail /* fail if wrap-around */
2695 movl %edx,%ecx /* move by longwords first */
2698 RECOVER(kdp_vm_read_fail)
2700 movsl /* move longwords */
2701 movl %edx,%ecx /* now move remaining bytes */
2704 RECOVER(kdp_vm_read_fail)
2708 movl 8+S_ARG2,%edx /* get count */
2709 subl %ecx,%edx /* Return number of bytes transfered */
2712 popl %edi /* restore registers */
2714 ret /* and return */
2717 xorl %eax,%eax /* didn't copy a thing. */
2726 * Done with recovery and retry tables.
2739 /* dr<i>(address, type, len, persistence)
2743 movl %eax,EXT(dr_addr)
2749 movl %eax,EXT(dr_addr)+1*4
2755 movl %eax,EXT(dr_addr)+2*4
2762 movl %eax,EXT(dr_addr)+3*4
2771 movl %edx,EXT(dr_addr)+4*4
2772 andl dr_msk(,%ecx,2),%edx /* clear out new entry */
2773 movl %edx,EXT(dr_addr)+5*4
2792 movl %edx,EXT(dr_addr)+7*4
2799 DATA(preemptable) /* Not on an MP (makes cpu_number() usage unsafe) */
2800 #if MACH_RT && (NCPUS == 1)
2801 .long 0 /* FIXME -- Currently disabled */
2803 .long 0 /* FIX ME -- Currently disabled */
2804 #endif /* MACH_RT && (NCPUS == 1) */
2817 * Determine cpu model and set global cpuid_xxx variables
2819 * Relies on 386 eflags bit 18 (AC) always being zero & 486 preserving it.
2820 * Relies on 486 eflags bit 21 (ID) always being zero & 586 preserving it.
2821 * Relies on CPUID instruction for next x86 generations
2822 * (assumes cpuid-family-homogenous MPs; else convert to per-cpu array)
2825 ENTRY(set_cpu_model)
2827 pushl %ebx /* save ebx */
2828 andl $~0x3,%esp /* Align stack to avoid AC fault */
2829 pushfl /* push EFLAGS */
2830 popl %eax /* pop into eax */
2831 movl %eax,%ecx /* Save original EFLAGS */
2832 xorl $(EFL_AC+EFL_ID),%eax /* toggle ID,AC bits */
2833 pushl %eax /* push new value */
2834 popfl /* through the EFLAGS register */
2835 pushfl /* and back */
2836 popl %eax /* into eax */
2837 movb $(CPUID_FAMILY_386),EXT(cpuid_family)
2838 pushl %ecx /* push original EFLAGS */
2839 popfl /* restore EFLAGS */
2840 xorl %ecx,%eax /* see what changed */
2841 testl $EFL_AC,%eax /* test AC bit */
2842 jz 0f /* if AC toggled (486 or higher) */
2844 movb $(CPUID_FAMILY_486),EXT(cpuid_family)
2845 testl $EFL_ID,%eax /* test ID bit */
2846 jz 0f /* if ID toggled use cpuid instruction */
2848 xorl %eax,%eax /* get vendor identification string */
2849 .word 0xA20F /* cpuid instruction */
2850 movl %eax,EXT(cpuid_value) /* Store high value */
2851 movl %ebx,EXT(cpuid_vid) /* Store byte 0-3 of Vendor ID */
2852 movl %edx,EXT(cpuid_vid)+4 /* Store byte 4-7 of Vendor ID */
2853 movl %ecx,EXT(cpuid_vid)+8 /* Store byte 8-B of Vendor ID */
2854 movl $1,%eax /* get processor signature */
2855 .word 0xA20F /* cpuid instruction */
2856 movl %edx,EXT(cpuid_feature) /* Store feature flags */
2857 movl %eax,%ecx /* Save original signature */
2858 andb $0xF,%al /* Get Stepping ID */
2859 movb %al,EXT(cpuid_stepping) /* Save Stepping ID */
2860 movl %ecx,%eax /* Get original signature */
2861 shrl $4,%eax /* Shift Stepping ID */
2862 movl %eax,%ecx /* Save original signature */
2863 andb $0xF,%al /* Get Model */
2864 movb %al,EXT(cpuid_model) /* Save Model */
2865 movl %ecx,%eax /* Get original signature */
2866 shrl $4,%eax /* Shift Stepping ID */
2867 movl %eax,%ecx /* Save original signature */
2868 andb $0xF,%al /* Get Family */
2869 movb %al,EXT(cpuid_family) /* Save Family */
2870 movl %ecx,%eax /* Get original signature */
2871 shrl $4,%eax /* Shift Stepping ID */
2872 andb $0x3,%al /* Get Type */
2873 movb %al,EXT(cpuid_type) /* Save Type */
2875 movl EXT(cpuid_value),%eax /* Get high value */
2876 cmpl $2,%eax /* Test if processor configuration */
2877 jle 0f /* is present */
2878 movl $2,%eax /* get processor configuration */
2879 .word 0xA20F /* cpuid instruction */
2880 movl %eax,EXT(cpuid_cache) /* Store byte 0-3 of configuration */
2881 movl %ebx,EXT(cpuid_cache)+4 /* Store byte 4-7 of configuration */
2882 movl %ecx,EXT(cpuid_cache)+8 /* Store byte 8-B of configuration */
2883 movl %edx,EXT(cpuid_cache)+12 /* Store byte C-F of configuration */
2885 popl %ebx /* restore ebx */
2921 lidt null_idtr /* disable the interrupt handler */
2922 xor %ecx,%ecx /* generate a divide by zero */
2923 div %ecx,%eax /* reboot now */
2924 ret /* this will "never" be executed */
2926 #endif /* SYMMETRY */
2930 * setbit(int bitno, int *s) - set bit in bit string
2933 movl S_ARG0, %ecx /* bit number */
2934 movl S_ARG1, %eax /* address */
2935 btsl %ecx, (%eax) /* set bit */
2939 * clrbit(int bitno, int *s) - clear bit in bit string
2942 movl S_ARG0, %ecx /* bit number */
2943 movl S_ARG1, %eax /* address */
2944 btrl %ecx, (%eax) /* clear bit */
2948 * ffsbit(int *s) - find first set bit in bit string
2951 movl S_ARG0, %ecx /* address */
2952 movl $0, %edx /* base offset */
2954 bsfl (%ecx), %eax /* check argument bits */
2955 jnz 1f /* found bit, return */
2956 addl $4, %ecx /* increment address */
2957 addl $32, %edx /* increment offset */
2958 jmp 0b /* try again */
2960 addl %edx, %eax /* return offset */
2964 * testbit(int nr, volatile void *array)
2966 * Test to see if the bit is set within the bit string
2970 movl S_ARG0,%eax /* Get the bit to test */
2971 movl S_ARG1,%ecx /* get the array string */
2983 movl 4(%ebp), %eax /* fetch pc of caller */
2986 ENTRY(tvals_to_etap)
2988 movl $1000000000, %ecx
2995 * etap_time_sub(etap_time_t stop, etap_time_t start)
2997 * 64bit subtract, returns stop - start
2999 ENTRY(etap_time_sub)
3000 movl S_ARG0, %eax /* stop.low */
3001 movl S_ARG1, %edx /* stop.hi */
3002 subl S_ARG2, %eax /* stop.lo - start.lo */
3003 sbbl S_ARG3, %edx /* stop.hi - start.hi */
3014 * jail: set the EIP to "jail" to block a kernel thread.
3015 * Useful to debug synchronization problems on MPs.
3020 #endif /* NCPUS > 1 */
3023 * delay(microseconds)
3030 movl EXT(delaycount), %ecx
3043 * div_scale(unsigned int dividend,
3044 * unsigned int divisor,
3045 * unsigned int *scale)
3047 * This function returns (dividend << *scale) //divisor where *scale
3048 * is the largest possible value before overflow. This is used in
3049 * computation where precision must be achieved in order to avoid
3050 * floating point usage.
3054 * while (((dividend >> *scale) >= divisor))
3056 * *scale = 32 - *scale;
3057 * return ((dividend << *scale) / divisor);
3061 xorl %ecx, %ecx /* *scale = 0 */
3063 movl ARG0, %edx /* get dividend */
3065 cmpl ARG1, %edx /* if (divisor > dividend) */
3066 jle 1f /* goto 1f */
3067 addl $1, %ecx /* (*scale)++ */
3068 shrdl $1, %edx, %eax /* dividend >> 1 */
3069 shrl $1, %edx /* dividend >> 1 */
3070 jmp 0b /* goto 0b */
3072 divl ARG1 /* (dividend << (32 - *scale)) / divisor */
3073 movl ARG2, %edx /* get scale */
3074 movl $32, (%edx) /* *scale = 32 */
3075 subl %ecx, (%edx) /* *scale -= %ecx */
3081 * mul_scale(unsigned int multiplicand,
3082 * unsigned int multiplier,
3083 * unsigned int *scale)
3085 * This function returns ((multiplicand * multiplier) >> *scale) where
3086 * scale is the largest possible value before overflow. This is used in
3087 * computation where precision must be achieved in order to avoid
3088 * floating point usage.
3092 * while (overflow((multiplicand * multiplier) >> *scale))
3094 * return ((multiplicand * multiplier) >> *scale);
3098 xorl %ecx, %ecx /* *scale = 0 */
3099 movl ARG0, %eax /* get multiplicand */
3100 mull ARG1 /* multiplicand * multiplier */
3102 cmpl $0, %edx /* if (!overflow()) */
3104 addl $1, %ecx /* (*scale)++ */
3105 shrdl $1, %edx, %eax /* (multiplicand * multiplier) >> 1 */
3106 shrl $1, %edx /* (multiplicand * multiplier) >> 1 */
3109 movl ARG2, %edx /* get scale */
3110 movl %ecx, (%edx) /* set *scale */
3118 #endif /* NCPUS > 1 */
3122 * BSD System call entry point..
3125 Entry(trap_unix_syscall)
3126 pushf /* save flags as soon as possible */
3127 pushl %eax /* save system call number */
3128 pushl $0 /* clear trap number slot */
3130 pusha /* save the general registers */
3131 pushl %ds /* and the segment registers */
3136 mov %ss,%dx /* switch to kernel data segment */
3143 * Shuffle eflags,eip,cs into proper places
3146 movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
3147 movl R_CS(%esp),%ecx /* eip is in CS slot */
3148 movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
3149 movl %ecx,R_EIP(%esp) /* fix eip */
3150 movl %edx,R_CS(%esp) /* fix cs */
3151 movl %ebx,R_EFLAGS(%esp) /* fix eflags */
3156 negl %eax /* get system call number */
3157 shll $4,%eax /* manual indexing */
3160 movl CX(EXT(kernel_stack),%edx),%ebx
3161 /* get current kernel stack */
3162 xchgl %ebx,%esp /* switch stacks - %ebx points to */
3163 /* user registers. */
3166 * Register use on entry:
3167 * eax contains syscall number
3168 * ebx contains user regs pointer
3171 pushl %ebx /* Push the regs set onto stack */
3172 call EXT(unix_syscall)
3174 movl %esp,%ecx /* get kernel stack */
3175 or $(KERNEL_STACK_SIZE-1),%ecx
3176 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
3177 movl %eax,R_EAX(%esp) /* save return value */
3178 jmp EXT(return_from_trap) /* return to user */
3181 * Entry point for machdep system calls..
3184 Entry(trap_machdep_syscall)
3185 pushf /* save flags as soon as possible */
3186 pushl %eax /* save system call number */
3187 pushl $0 /* clear trap number slot */
3189 pusha /* save the general registers */
3190 pushl %ds /* and the segment registers */
3195 mov %ss,%dx /* switch to kernel data segment */
3202 * Shuffle eflags,eip,cs into proper places
3205 movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
3206 movl R_CS(%esp),%ecx /* eip is in CS slot */
3207 movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
3208 movl %ecx,R_EIP(%esp) /* fix eip */
3209 movl %edx,R_CS(%esp) /* fix cs */
3210 movl %ebx,R_EFLAGS(%esp) /* fix eflags */
3215 negl %eax /* get system call number */
3216 shll $4,%eax /* manual indexing */
3219 movl CX(EXT(kernel_stack),%edx),%ebx
3220 /* get current kernel stack */
3221 xchgl %ebx,%esp /* switch stacks - %ebx points to */
3222 /* user registers. */
3225 * Register use on entry:
3226 * eax contains syscall number
3227 * ebx contains user regs pointer
3231 call EXT(machdep_syscall)
3233 movl %esp,%ecx /* get kernel stack */
3234 or $(KERNEL_STACK_SIZE-1),%ecx
3235 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
3236 movl %eax,R_EAX(%esp) /* save return value */
3237 jmp EXT(return_from_trap) /* return to user */
3239 Entry(trap_mach25_syscall)
3240 pushf /* save flags as soon as possible */
3241 pushl %eax /* save system call number */
3242 pushl $0 /* clear trap number slot */
3244 pusha /* save the general registers */
3245 pushl %ds /* and the segment registers */
3250 mov %ss,%dx /* switch to kernel data segment */
3257 * Shuffle eflags,eip,cs into proper places
3260 movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
3261 movl R_CS(%esp),%ecx /* eip is in CS slot */
3262 movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
3263 movl %ecx,R_EIP(%esp) /* fix eip */
3264 movl %edx,R_CS(%esp) /* fix cs */
3265 movl %ebx,R_EFLAGS(%esp) /* fix eflags */
3270 negl %eax /* get system call number */
3271 shll $4,%eax /* manual indexing */
3274 movl CX(EXT(kernel_stack),%edx),%ebx
3275 /* get current kernel stack */
3276 xchgl %ebx,%esp /* switch stacks - %ebx points to */
3277 /* user registers. */
3280 * Register use on entry:
3281 * eax contains syscall number
3282 * ebx contains user regs pointer
3286 call EXT(mach25_syscall)
3288 movl %esp,%ecx /* get kernel stack */
3289 or $(KERNEL_STACK_SIZE-1),%ecx
3290 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
3291 movl %eax,R_EAX(%esp) /* save return value */
3292 jmp EXT(return_from_trap) /* return to user */