]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/idt.s
xnu-2050.7.9.tar.gz
[apple/xnu.git] / osfmk / i386 / idt.s
1 /*
2 * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990 Carnegie Mellon University
34 * All Rights Reserved.
35 *
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.
41 *
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.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56 /*
57 */
58 #include <i386/asm.h>
59 #include <assym.s>
60 #include <i386/eflags.h>
61 #include <i386/trap.h>
62 #include <i386/rtclock_asm.h>
63 #define _ARCH_I386_ASM_HELP_H_ /* Prevent inclusion of user header */
64 #include <mach/i386/syscall_sw.h>
65 #include <i386/postcode.h>
66 #include <i386/proc_reg.h>
67 #include <mach/exception_types.h>
68
69 /*
70 * Low-memory handlers.
71 */
72 #define LO_ALLINTRS EXT(lo_allintrs32)
73 #define LO_ALLTRAPS EXT(lo_alltraps32)
74 #define LO_SYSENTER EXT(lo_sysenter32)
75 #define LO_UNIX_SCALL EXT(lo_unix_scall32)
76 #define LO_MACH_SCALL EXT(lo_mach_scall32)
77 #define LO_MDEP_SCALL EXT(lo_mdep_scall32)
78
79 #define HI_DATA(lo_addr) ( (EXT(lo_addr) - EXT(hi_remap_data)) + HIGH_IDT_BASE )
80 #define HI_TEXT(lo_text) ( (EXT(lo_text) - EXT(hi_remap_text)) + HIGH_MEM_BASE )
81
82 /*
83 * Interrupt descriptor table and code vectors for it.
84 */
85 #define IDT_BASE_ENTRY(vec,seg,type) \
86 .data ;\
87 .long EXT(vec) - EXT(hi_remap_text) + HIGH_MEM_BASE ; \
88 .word seg ;\
89 .byte 0 ;\
90 .byte type ;\
91 .text
92
93 #define IDT_BASE_ENTRY_INT(vec,seg,type) \
94 .data ;\
95 .long vec - EXT(hi_remap_text) + HIGH_MEM_BASE ; \
96 .word seg ;\
97 .byte 0 ;\
98 .byte type ;\
99 .text
100
101 #define IDT_BASE_ENTRY_TG(vec,seg,type) \
102 .data ;\
103 .long 0 ; \
104 .word seg ;\
105 .byte 0 ;\
106 .byte type ;\
107 .text
108
109 #define IDT_ENTRY(vec,type) IDT_BASE_ENTRY(vec,KERNEL32_CS,type)
110 #define IDT_ENTRY_INT(vec,type) IDT_BASE_ENTRY_INT(vec,KERNEL32_CS,type)
111
112 /*
113 * No error code. Clear error code and push trap number.
114 */
115 #define EXCEPTION(n,name) \
116 IDT_ENTRY(name,K_INTR_GATE);\
117 Entry(name) ;\
118 pushl $0 ;\
119 pushl $(n) ;\
120 pusha ;\
121 movl $(LO_ALLTRAPS),%ebx ;\
122 jmp enter_lohandler
123
124
125 /*
126 * Interrupt from user. Clear error code and push trap number.
127 */
128 #define EXCEP_USR(n,name) \
129 IDT_ENTRY(name,U_INTR_GATE);\
130 Entry(name) ;\
131 pushl $0 ;\
132 pushl $(n) ;\
133 pusha ;\
134 movl $(LO_ALLTRAPS),%ebx ;\
135 jmp enter_lohandler
136
137
138 /*
139 * Special interrupt code.
140 */
141 #define EXCEP_SPC(n,name) \
142 IDT_ENTRY(name,K_INTR_GATE)
143
144 /*
145 * Special interrupt code from user.
146 */
147 #define EXCEP_SPC_USR(n,name) \
148 IDT_ENTRY(name,U_INTR_GATE)
149
150
151 /*
152 * Extra-special interrupt code. Note that no offset may be
153 * specified in a task gate descriptor, so name is ignored.
154 */
155
156 /* Double-fault fatal handler */
157 #define DF_FATAL_TASK(n,name) \
158 IDT_BASE_ENTRY_TG(0,DF_TSS,K_TASK_GATE)
159
160 /* machine-check handler */
161 #define MC_FATAL_TASK(n,name) \
162 IDT_BASE_ENTRY_TG(0,MC_TSS,K_TASK_GATE)
163
164 /*
165 * Error code has been pushed. Push trap number.
166 */
167 #define EXCEP_ERR(n,name) \
168 IDT_ENTRY(name,K_INTR_GATE) ;\
169 Entry(name) ;\
170 pushl $(n) ;\
171 pusha ;\
172 movl $(LO_ALLTRAPS),%ebx ;\
173 jmp enter_lohandler
174
175
176 /*
177 * Interrupt.
178 */
179 #define INTERRUPT(n) \
180 IDT_ENTRY_INT(L_ ## n,K_INTR_GATE) ;\
181 .align FALIGN ;\
182 L_ ## n: ;\
183 pushl $0 ;\
184 pushl $(n) ;\
185 pusha ;\
186 movl $(LO_ALLINTRS),%ebx ;\
187 jmp enter_lohandler
188
189
190 .data
191 .align 12
192 Entry(master_idt)
193 Entry(hi_remap_data)
194 .text
195 .align 12
196 Entry(hi_remap_text)
197
198 EXCEPTION(0x00,t_zero_div)
199 EXCEP_SPC(0x01,hi_debug)
200 INTERRUPT(0x02) /* NMI */
201 EXCEP_USR(0x03,t_int3)
202 EXCEP_USR(0x04,t_into)
203 EXCEP_USR(0x05,t_bounds)
204 EXCEPTION(0x06,t_invop)
205 EXCEPTION(0x07,t_nofpu)
206 DF_FATAL_TASK(0x08,df_task_start)
207 EXCEPTION(0x09,a_fpu_over)
208 EXCEPTION(0x0a,a_inv_tss)
209 EXCEP_SPC(0x0b,hi_segnp)
210 EXCEP_ERR(0x0c,t_stack_fault)
211 EXCEP_SPC(0x0d,hi_gen_prot)
212 EXCEP_SPC(0x0e,hi_page_fault)
213 EXCEPTION(0x0f,t_trap_0f)
214 EXCEPTION(0x10,t_fpu_err)
215 EXCEPTION(0x11,t_trap_11)
216 MC_FATAL_TASK(0x12,mc_task_start)
217 EXCEPTION(0x13,t_sse_err)
218 EXCEPTION(0x14,t_trap_14)
219 EXCEPTION(0x15,t_trap_15)
220 EXCEPTION(0x16,t_trap_16)
221 EXCEPTION(0x17,t_trap_17)
222 EXCEPTION(0x18,t_trap_18)
223 EXCEPTION(0x19,t_trap_19)
224 EXCEPTION(0x1a,t_trap_1a)
225 EXCEPTION(0x1b,t_trap_1b)
226 EXCEPTION(0x1c,t_trap_1c)
227 EXCEPTION(0x1d,t_trap_1d)
228 EXCEPTION(0x1e,t_trap_1e)
229 EXCEPTION(0x1f,t_trap_1f)
230
231 INTERRUPT(0x20)
232 INTERRUPT(0x21)
233 INTERRUPT(0x22)
234 INTERRUPT(0x23)
235 INTERRUPT(0x24)
236 INTERRUPT(0x25)
237 INTERRUPT(0x26)
238 INTERRUPT(0x27)
239 INTERRUPT(0x28)
240 INTERRUPT(0x29)
241 INTERRUPT(0x2a)
242 INTERRUPT(0x2b)
243 INTERRUPT(0x2c)
244 INTERRUPT(0x2d)
245 INTERRUPT(0x2e)
246 INTERRUPT(0x2f)
247
248 INTERRUPT(0x30)
249 INTERRUPT(0x31)
250 INTERRUPT(0x32)
251 INTERRUPT(0x33)
252 INTERRUPT(0x34)
253 INTERRUPT(0x35)
254 INTERRUPT(0x36)
255 INTERRUPT(0x37)
256 INTERRUPT(0x38)
257 INTERRUPT(0x39)
258 INTERRUPT(0x3a)
259 INTERRUPT(0x3b)
260 INTERRUPT(0x3c)
261 INTERRUPT(0x3d)
262 INTERRUPT(0x3e)
263 INTERRUPT(0x3f)
264
265 INTERRUPT(0x40)
266 INTERRUPT(0x41)
267 INTERRUPT(0x42)
268 INTERRUPT(0x43)
269 INTERRUPT(0x44)
270 INTERRUPT(0x45)
271 INTERRUPT(0x46)
272 INTERRUPT(0x47)
273 INTERRUPT(0x48)
274 INTERRUPT(0x49)
275 INTERRUPT(0x4a)
276 INTERRUPT(0x4b)
277 INTERRUPT(0x4c)
278 INTERRUPT(0x4d)
279 INTERRUPT(0x4e)
280 INTERRUPT(0x4f)
281
282 INTERRUPT(0x50)
283 INTERRUPT(0x51)
284 INTERRUPT(0x52)
285 INTERRUPT(0x53)
286 INTERRUPT(0x54)
287 INTERRUPT(0x55)
288 INTERRUPT(0x56)
289 INTERRUPT(0x57)
290 INTERRUPT(0x58)
291 INTERRUPT(0x59)
292 INTERRUPT(0x5a)
293 INTERRUPT(0x5b)
294 INTERRUPT(0x5c)
295 INTERRUPT(0x5d)
296 INTERRUPT(0x5e)
297 INTERRUPT(0x5f)
298
299 INTERRUPT(0x60)
300 INTERRUPT(0x61)
301 INTERRUPT(0x62)
302 INTERRUPT(0x63)
303 INTERRUPT(0x64)
304 INTERRUPT(0x65)
305 INTERRUPT(0x66)
306 INTERRUPT(0x67)
307 INTERRUPT(0x68)
308 INTERRUPT(0x69)
309 INTERRUPT(0x6a)
310 INTERRUPT(0x6b)
311 INTERRUPT(0x6c)
312 INTERRUPT(0x6d)
313 INTERRUPT(0x6e)
314 INTERRUPT(0x6f)
315
316 INTERRUPT(0x70)
317 INTERRUPT(0x71)
318 INTERRUPT(0x72)
319 INTERRUPT(0x73)
320 INTERRUPT(0x74)
321 INTERRUPT(0x75)
322 INTERRUPT(0x76)
323 INTERRUPT(0x77)
324 INTERRUPT(0x78)
325 INTERRUPT(0x79)
326 INTERRUPT(0x7a)
327 INTERRUPT(0x7b)
328 INTERRUPT(0x7c)
329 INTERRUPT(0x7d)
330 INTERRUPT(0x7e)
331 EXCEP_USR(0x7f, t_dtrace_ret)
332
333 EXCEP_SPC_USR(0x80,hi_unix_scall)
334 EXCEP_SPC_USR(0x81,hi_mach_scall)
335 EXCEP_SPC_USR(0x82,hi_mdep_scall)
336 INTERRUPT(0x83)
337 INTERRUPT(0x84)
338 INTERRUPT(0x85)
339 INTERRUPT(0x86)
340 INTERRUPT(0x87)
341 INTERRUPT(0x88)
342 INTERRUPT(0x89)
343 INTERRUPT(0x8a)
344 INTERRUPT(0x8b)
345 INTERRUPT(0x8c)
346 INTERRUPT(0x8d)
347 INTERRUPT(0x8e)
348 INTERRUPT(0x8f)
349
350 INTERRUPT(0x90)
351 INTERRUPT(0x91)
352 INTERRUPT(0x92)
353 INTERRUPT(0x93)
354 INTERRUPT(0x94)
355 INTERRUPT(0x95)
356 INTERRUPT(0x96)
357 INTERRUPT(0x97)
358 INTERRUPT(0x98)
359 INTERRUPT(0x99)
360 INTERRUPT(0x9a)
361 INTERRUPT(0x9b)
362 INTERRUPT(0x9c)
363 INTERRUPT(0x9d)
364 INTERRUPT(0x9e)
365 INTERRUPT(0x9f)
366
367 INTERRUPT(0xa0)
368 INTERRUPT(0xa1)
369 INTERRUPT(0xa2)
370 INTERRUPT(0xa3)
371 INTERRUPT(0xa4)
372 INTERRUPT(0xa5)
373 INTERRUPT(0xa6)
374 INTERRUPT(0xa7)
375 INTERRUPT(0xa8)
376 INTERRUPT(0xa9)
377 INTERRUPT(0xaa)
378 INTERRUPT(0xab)
379 INTERRUPT(0xac)
380 INTERRUPT(0xad)
381 INTERRUPT(0xae)
382 INTERRUPT(0xaf)
383
384 INTERRUPT(0xb0)
385 INTERRUPT(0xb1)
386 INTERRUPT(0xb2)
387 INTERRUPT(0xb3)
388 INTERRUPT(0xb4)
389 INTERRUPT(0xb5)
390 INTERRUPT(0xb6)
391 INTERRUPT(0xb7)
392 INTERRUPT(0xb8)
393 INTERRUPT(0xb9)
394 INTERRUPT(0xba)
395 INTERRUPT(0xbb)
396 INTERRUPT(0xbc)
397 INTERRUPT(0xbd)
398 INTERRUPT(0xbe)
399 INTERRUPT(0xbf)
400
401 INTERRUPT(0xc0)
402 INTERRUPT(0xc1)
403 INTERRUPT(0xc2)
404 INTERRUPT(0xc3)
405 INTERRUPT(0xc4)
406 INTERRUPT(0xc5)
407 INTERRUPT(0xc6)
408 INTERRUPT(0xc7)
409 INTERRUPT(0xc8)
410 INTERRUPT(0xc9)
411 INTERRUPT(0xca)
412 INTERRUPT(0xcb)
413 INTERRUPT(0xcc)
414 INTERRUPT(0xcd)
415 INTERRUPT(0xce)
416 INTERRUPT(0xcf)
417
418 INTERRUPT(0xd0)
419 INTERRUPT(0xd1)
420 INTERRUPT(0xd2)
421 INTERRUPT(0xd3)
422 INTERRUPT(0xd4)
423 INTERRUPT(0xd5)
424 INTERRUPT(0xd6)
425 INTERRUPT(0xd7)
426 INTERRUPT(0xd8)
427 INTERRUPT(0xd9)
428 INTERRUPT(0xda)
429 INTERRUPT(0xdb)
430 INTERRUPT(0xdc)
431 INTERRUPT(0xdd)
432 INTERRUPT(0xde)
433 INTERRUPT(0xdf)
434
435 INTERRUPT(0xe0)
436 INTERRUPT(0xe1)
437 INTERRUPT(0xe2)
438 INTERRUPT(0xe3)
439 INTERRUPT(0xe4)
440 INTERRUPT(0xe5)
441 INTERRUPT(0xe6)
442 INTERRUPT(0xe7)
443 INTERRUPT(0xe8)
444 INTERRUPT(0xe9)
445 INTERRUPT(0xea)
446 INTERRUPT(0xeb)
447 INTERRUPT(0xec)
448 INTERRUPT(0xed)
449 INTERRUPT(0xee)
450 INTERRUPT(0xef)
451
452 INTERRUPT(0xf0)
453 INTERRUPT(0xf1)
454 INTERRUPT(0xf2)
455 INTERRUPT(0xf3)
456 INTERRUPT(0xf4)
457 INTERRUPT(0xf5)
458 INTERRUPT(0xf6)
459 INTERRUPT(0xf7)
460 INTERRUPT(0xf8)
461 INTERRUPT(0xf9)
462 INTERRUPT(0xfa)
463 INTERRUPT(0xfb)
464 INTERRUPT(0xfc)
465 INTERRUPT(0xfd)
466 INTERRUPT(0xfe)
467 EXCEPTION(0xff,t_preempt)
468
469
470 .data
471 Entry(lo_kernel_cr3)
472 .long 0
473 .long 0
474
475 .text
476
477
478 /*
479 * Trap/interrupt entry points.
480 *
481 * All traps must create the following save area on the PCB "stack":
482 *
483 * gs
484 * fs
485 * es
486 * ds
487 * edi
488 * esi
489 * ebp
490 * cr2 if page fault - otherwise unused
491 * ebx
492 * edx
493 * ecx
494 * eax
495 * trap number
496 * error code
497 * eip
498 * cs
499 * eflags
500 * user esp - if from user
501 * user ss - if from user
502 */
503
504 ret_to_kernel:
505 jmp *1f
506 1: .long HI_TEXT(hi_ret_to_kernel)
507
508 ret_to_user:
509 jmp *1f
510 1: .long HI_TEXT(hi_ret_to_user)
511
512 Entry(hi_ret_to_user)
513 movl %esp,%ebx
514 movl %gs:CPU_ACTIVE_THREAD,%ecx
515 subl TH_PCB_ISS(%ecx),%ebx
516 movl $(WINDOWS_CLEAN),TH_COPYIO_STATE(%ecx)
517
518 movl TH_PCB_IDS(%ecx),%eax /* get debug state struct */
519 cmpl $0,%eax /* is there a debug state */
520 je 1f /* branch if not */
521 movl DS_DR0(%eax), %ecx /* Load the 32 bit debug registers */
522 movl %ecx, %db0
523 movl DS_DR1(%eax), %ecx
524 movl %ecx, %db1
525 movl DS_DR2(%eax), %ecx
526 movl %ecx, %db2
527 movl DS_DR3(%eax), %ecx
528 movl %ecx, %db3
529 movl DS_DR7(%eax), %eax
530 1:
531 addl %gs:CPU_HI_ISS,%ebx /* rebase PCB save area to high addr */
532 movl %gs:CPU_TASK_CR3,%ecx
533 movl %ecx,%gs:CPU_ACTIVE_CR3
534 movl %ebx,%esp /* switch to hi based PCB stack */
535 movl %ecx,%cr3 /* switch to user's address space */
536
537 cmpl $0,%eax /* is dr7 set to something? */
538 je 2f /* branch if not */
539 movl %eax,%db7 /* Set dr7 */
540 2:
541
542 Entry(hi_ret_to_kernel)
543
544 popl %eax /* ignore flavor of saved state */
545 EXT(ret_popl_gs):
546 popl %gs /* restore segment registers */
547 EXT(ret_popl_fs):
548 popl %fs
549 EXT(ret_popl_es):
550 popl %es
551 EXT(ret_popl_ds):
552 popl %ds
553
554 popa /* restore general registers */
555 addl $8,%esp /* discard trap number and error code */
556
557 cmpl $(SYSENTER_CS),4(%esp) /* test for fast entry/exit */
558 je fast_exit
559 EXT(ret_iret):
560 iret /* return from interrupt */
561 fast_exit:
562 popl %edx /* user return eip */
563 popl %ecx /* pop and toss cs */
564 andl $(~EFL_IF),(%esp) /* clear intrs enabled, see sti below */
565 popf /* flags - carry denotes failure */
566 popl %ecx /* user return esp */
567 sti /* interrupts enabled after sysexit */
568 sysexit
569
570
571 Entry(hi_unix_scall)
572 pushl %eax /* save system call number */
573 pushl $0 /* clear trap number slot */
574 pusha /* save the general registers */
575 movl $(LO_UNIX_SCALL),%ebx
576 jmp enter_lohandler
577
578
579 Entry(hi_mach_scall)
580 pushl %eax /* save system call number */
581 pushl $0 /* clear trap number slot */
582 pusha /* save the general registers */
583 movl $(LO_MACH_SCALL),%ebx
584 jmp enter_lohandler
585
586
587 Entry(hi_mdep_scall)
588 pushl %eax /* save system call number */
589 pushl $0 /* clear trap number slot */
590 pusha /* save the general registers */
591 movl $(LO_MDEP_SCALL),%ebx
592 jmp enter_lohandler
593
594
595 /*
596 * sysenter entry point
597 * Requires user code to set up:
598 * edx: user instruction pointer (return address)
599 * ecx: user stack pointer
600 * on which is pushed stub ret addr and saved ebx
601 * Return to user-space is made using sysexit.
602 * Note: sysenter/sysexit cannot be used for calls returning a value in edx,
603 * or requiring ecx to be preserved.
604 */
605 Entry(hi_sysenter)
606 movl (%esp), %esp /* switch from intr stack to pcb */
607 /*
608 * Push values on to the PCB stack
609 * to cons up the saved state.
610 */
611 pushl $(USER_DS) /* ss */
612 pushl %ecx /* uesp */
613 pushf /* flags */
614 /*
615 * Clear, among others, the Nested Task (NT) flags bit;
616 * This is cleared by INT, but not by SYSENTER.
617 */
618 pushl $0
619 popfl
620 pushl $(SYSENTER_CS) /* cs */
621 hi_sysenter_2:
622 pushl %edx /* eip */
623 pushl %eax /* err/eax - syscall code */
624 pushl $0 /* clear trap number slot */
625 pusha /* save the general registers */
626 orl $(EFL_IF),R32_EFLAGS-R32_EDI(%esp) /* (edi was last reg pushed) */
627 movl $(LO_SYSENTER),%ebx
628 enter_lohandler:
629 pushl %ds
630 pushl %es
631 pushl %fs
632 pushl %gs
633 pushl $(SS_32) /* 32-bit state flavor */
634 enter_lohandler1:
635 mov %ss,%eax
636 mov %eax,%ds
637 mov %eax,%fs
638 mov %eax,%es /* switch to kernel data seg */
639 mov $(CPU_DATA_GS),%eax
640 mov %eax,%gs
641 cld /* clear direction flag */
642 /*
643 * Switch to kernel's address space if necessary
644 */
645 movl HI_DATA(lo_kernel_cr3),%ecx
646 movl %cr3,%eax
647 cmpl %eax,%ecx
648 je 1f
649 movl %ecx,%cr3
650 movl %ecx,%gs:CPU_ACTIVE_CR3
651 1:
652 testb $3,R32_CS(%esp)
653 jz 2f
654 movl %esp,%edx /* came from user mode */
655 xor %ebp, %ebp
656 subl %gs:CPU_HI_ISS,%edx
657 movl %gs:CPU_ACTIVE_THREAD,%ecx
658 addl TH_PCB_ISS(%ecx),%edx /* rebase the high stack to a low address */
659 movl %edx,%esp
660 cmpl $0, TH_PCB_IDS(%ecx) /* Is there a debug register state? */
661 je 2f
662 movl $0, %ecx /* If so, reset DR7 (the control) */
663 movl %ecx, %dr7
664 2:
665 movl R32_TRAPNO(%esp),%ecx // Get the interrupt vector
666 addl $1,%gs:hwIntCnt(,%ecx,4) // Bump the count
667 jmp *%ebx
668
669
670 /*
671 * Page fault traps save cr2.
672 */
673 Entry(hi_page_fault)
674 pushl $(T_PAGE_FAULT) /* mark a page fault trap */
675 pusha /* save the general registers */
676 movl %cr2,%eax /* get the faulting address */
677 movl %eax,R32_CR2-R32_EDI(%esp)/* save in esp save slot */
678
679 movl $(LO_ALLTRAPS),%ebx
680 jmp enter_lohandler
681
682
683
684 /*
685 * Debug trap. Check for single-stepping across system call into
686 * kernel. If this is the case, taking the debug trap has turned
687 * off single-stepping - save the flags register with the trace
688 * bit set.
689 */
690 Entry(hi_debug)
691 testb $3,4(%esp)
692 jnz hi_debug_trap
693 /* trap came from kernel mode */
694 cmpl $(HI_TEXT(hi_mach_scall)),(%esp)
695 jne 6f
696 addl $12,%esp /* remove eip/cs/eflags from debug_trap */
697 jmp EXT(hi_mach_scall) /* continue system call entry */
698 6:
699 cmpl $(HI_TEXT(hi_mdep_scall)),(%esp)
700 jne 5f
701 addl $12,%esp /* remove eip/cs/eflags from debug_trap */
702 jmp EXT(hi_mdep_scall) /* continue system call entry */
703 5:
704 cmpl $(HI_TEXT(hi_unix_scall)),(%esp)
705 jne 4f
706 addl $12,%esp /* remove eip/cs/eflags from debug_trap */
707 jmp EXT(hi_unix_scall) /* continue system call entry */
708 4:
709 cmpl $(HI_TEXT(hi_sysenter)),(%esp)
710 jne hi_debug_trap
711 /*
712 * eip/cs/flags have been pushed on intr stack
713 * We have to switch to pcb stack and copy eflags.
714 * Note: setting the cs selector to SYSENTER_TF_CS
715 * will cause the return to user path to take the iret path so
716 * that eflags (containing the trap bit) is set atomically.
717 * In unix_syscall this is tested so that we'll rewind the pc
718 * to account for with sysenter or int entry.
719 */
720 addl $8,%esp /* remove eip/cs */
721 pushl %ecx /* save %ecx */
722 movl 8(%esp),%ecx /* top of intr stack -> pcb stack */
723 xchgl %ecx,%esp /* switch to pcb stack */
724 pushl $(USER_DS) /* ss */
725 pushl %ss:(%ecx) /* %ecx into uesp slot */
726 pushl %ss:4(%ecx) /* eflags */
727 movl %ss:(%ecx),%ecx /* restore %ecx */
728 pushl $(SYSENTER_TF_CS) /* cs - not SYSENTER_CS for iret path */
729 jmp hi_sysenter_2 /* continue sysenter entry */
730 hi_debug_trap:
731 pushl $0
732 pushl $(T_DEBUG) /* handle as user trap */
733 pusha /* save the general registers */
734 movl $(LO_ALLTRAPS),%ebx
735 jmp enter_lohandler
736
737
738
739 /*
740 * General protection or segment-not-present fault.
741 * Check for a GP/NP fault in the kernel_return
742 * sequence; if there, report it as a GP/NP fault on the user's instruction.
743 *
744 * esp-> 0: trap code (NP or GP)
745 * 4: segment number in error
746 * 8 eip
747 * 12 cs
748 * 16 eflags
749 * 20 old registers (trap is from kernel)
750 */
751 Entry(hi_gen_prot)
752 pushl $(T_GENERAL_PROTECTION) /* indicate fault type */
753 jmp trap_check_kernel_exit /* check for kernel exit sequence */
754
755 Entry(hi_segnp)
756 pushl $(T_SEGMENT_NOT_PRESENT)
757 /* indicate fault type */
758 trap_check_kernel_exit:
759 testb $3,12(%esp)
760 jnz hi_take_trap
761 /* trap was from kernel mode, so */
762 /* check for the kernel exit sequence */
763 cmpl $(HI_TEXT(ret_iret)),8(%esp) /* on IRET? */
764 je fault_iret
765 cmpl $(HI_TEXT(ret_popl_ds)),8(%esp) /* popping DS? */
766 je fault_popl_ds
767 cmpl $(HI_TEXT(ret_popl_es)),8(%esp) /* popping ES? */
768 je fault_popl_es
769 cmpl $(HI_TEXT(ret_popl_fs)),8(%esp) /* popping FS? */
770 je fault_popl_fs
771 cmpl $(HI_TEXT(ret_popl_gs)),8(%esp) /* popping GS? */
772 je fault_popl_gs
773 hi_take_trap:
774 pusha /* save the general registers */
775 movl $(LO_ALLTRAPS),%ebx
776 jmp enter_lohandler
777
778
779 /*
780 * GP/NP fault on IRET: CS or SS is in error.
781 * All registers contain the user's values.
782 *
783 * on SP is
784 * 0 trap number
785 * 4 errcode
786 * 8 eip
787 * 12 cs --> trapno
788 * 16 efl --> errcode
789 * 20 user eip
790 * 24 user cs
791 * 28 user eflags
792 * 32 user esp
793 * 36 user ss
794 */
795 fault_iret:
796 movl %eax,8(%esp) /* save eax (we don`t need saved eip) */
797 popl %eax /* get trap number */
798 movl %eax,12-4(%esp) /* put in user trap number */
799 popl %eax /* get error code */
800 movl %eax,16-8(%esp) /* put in user errcode */
801 popl %eax /* restore eax */
802 /* now treat as fault from user */
803 pusha /* save the general registers */
804 movl $(LO_ALLTRAPS),%ebx
805 jmp enter_lohandler
806
807 /*
808 * Fault restoring a segment register. The user's registers are still
809 * saved on the stack. The offending segment register has not been
810 * popped.
811 */
812 fault_popl_ds:
813 popl %eax /* get trap number */
814 popl %edx /* get error code */
815 addl $12,%esp /* pop stack to user regs */
816 jmp push_es /* (DS on top of stack) */
817 fault_popl_es:
818 popl %eax /* get trap number */
819 popl %edx /* get error code */
820 addl $12,%esp /* pop stack to user regs */
821 jmp push_fs /* (ES on top of stack) */
822 fault_popl_fs:
823 popl %eax /* get trap number */
824 popl %edx /* get error code */
825 addl $12,%esp /* pop stack to user regs */
826 jmp push_gs /* (FS on top of stack) */
827 fault_popl_gs:
828 popl %eax /* get trap number */
829 popl %edx /* get error code */
830 addl $12,%esp /* pop stack to user regs */
831 jmp push_none /* (GS on top of stack) */
832
833 push_es:
834 pushl %es /* restore es, */
835 push_fs:
836 pushl %fs /* restore fs, */
837 push_gs:
838 pushl %gs /* restore gs. */
839 push_none:
840 pushl $(SS_32) /* 32-bit state flavor */
841 movl %eax,R32_TRAPNO(%esp) /* set trap number */
842 movl %edx,R32_ERR(%esp) /* set error code */
843 /* now treat as fault from user */
844 /* except that segment registers are */
845 /* already pushed */
846 movl $(LO_ALLTRAPS),%ebx
847 jmp enter_lohandler1
848
849
850 .text
851
852
853 Entry(hi_remap_etext)
854
855
856 /*
857 * All 32 bit task 'exceptions' enter lo_alltraps:
858 * esp -> x86_saved_state_t
859 *
860 * The rest of the state is set up as:
861 * cr3 -> kernel directory
862 * esp -> low based stack
863 * gs -> CPU_DATA_GS
864 * cs -> KERNEL32_CS
865 * ss/ds/es -> KERNEL_DS
866 *
867 * interrupts disabled
868 * direction flag cleared
869 */
870 Entry(lo_alltraps32)
871 movl R32_CS(%esp),%eax /* assume 32-bit state */
872 cmpl $(SS_64),SS_FLAVOR(%esp)/* 64-bit? */
873 jne 1f
874 movl R64_CS(%esp),%eax /* 64-bit user mode */
875 1:
876 testb $3,%al
877 jz trap_from_kernel
878 /* user mode trap */
879 TIME_TRAP_UENTRY
880
881 movl %gs:CPU_ACTIVE_THREAD,%ecx
882 movl TH_TASK(%ecx),%ebx
883
884 /* Check for active vtimers in the current task */
885 TASK_VTIMER_CHECK(%ebx, %ecx)
886
887 movl %gs:CPU_KERNEL_STACK,%ebx
888 xchgl %ebx,%esp /* switch to kernel stack */
889
890 CCALL1(user_trap, %ebx) /* call user trap routine */
891 /* user_trap() unmasks interrupts */
892 cli /* hold off intrs - critical section */
893 xorl %ecx,%ecx /* don't check if we're in the PFZ */
894
895 /*
896 * Return from trap or system call, checking for ASTs.
897 * On lowbase PCB stack with intrs disabled
898 */
899 Entry(return_from_trap32)
900 movl %gs:CPU_ACTIVE_THREAD, %esp
901 movl TH_PCB_ISS(%esp), %esp /* switch back to PCB stack */
902 movl %gs:CPU_PENDING_AST, %eax
903 testl %eax, %eax
904 je EXT(return_to_user) /* branch if no AST */
905 LEXT(return_from_trap_with_ast)
906 movl %gs:CPU_KERNEL_STACK, %ebx
907 xchgl %ebx, %esp /* switch to kernel stack */
908
909 testl %ecx, %ecx /* see if we need to check for an EIP in the PFZ */
910 je 2f /* no, go handle the AST */
911 cmpl $(SS_64), SS_FLAVOR(%ebx) /* are we a 64-bit task? */
912 je 1f
913 /* no... 32-bit user mode */
914 movl R32_EIP(%ebx), %eax
915 pushl %ebx /* save PCB stack */
916 xorl %ebp, %ebp /* clear frame pointer */
917 CCALL1(commpage_is_in_pfz32, %eax)
918 popl %ebx /* retrieve pointer to PCB stack */
919 testl %eax, %eax
920 je 2f /* not in the PFZ... go service AST */
921 movl %eax, R32_EBX(%ebx) /* let the PFZ know we've pended an AST */
922 xchgl %ebx, %esp /* switch back to PCB stack */
923 jmp EXT(return_to_user)
924 1: /* 64-bit user mode */
925 movl R64_RIP(%ebx), %ecx
926 movl R64_RIP+4(%ebx), %eax
927 pushl %ebx /* save PCB stack */
928 xorl %ebp, %ebp /* clear frame pointer */
929 CCALL2(commpage_is_in_pfz64, %ecx, %eax)
930 popl %ebx /* retrieve pointer to PCB stack */
931 testl %eax, %eax
932 je 2f /* not in the PFZ... go service AST */
933 movl %eax, R64_RBX(%ebx) /* let the PFZ know we've pended an AST */
934 xchgl %ebx, %esp /* switch back to PCB stack */
935 jmp EXT(return_to_user)
936 2:
937 sti /* interrupts always enabled on return to user mode */
938 xorl %ebp, %ebp /* Clear framepointer */
939 CCALL1(i386_astintr, $0) /* take the AST */
940 cli
941 xorl %ecx, %ecx /* don't check if we're in the PFZ */
942 jmp EXT(return_from_trap32) /* and check again (rare) */
943
944
945 /*
946 * Trap from kernel mode. No need to switch stacks.
947 * Interrupts must be off here - we will set them to state at time of trap
948 * as soon as it's safe for us to do so and not recurse doing preemption
949 */
950 trap_from_kernel:
951 movl %esp, %eax /* saved state addr */
952 pushl R32_EIP(%esp) /* Simulate a CALL from fault point */
953 pushl %ebp /* Extend framepointer chain */
954 movl %esp, %ebp
955 CCALL1WITHSP(kernel_trap, %eax) /* Call kernel trap handler */
956 popl %ebp
957 addl $4, %esp
958 cli
959
960 movl %gs:CPU_PENDING_AST,%eax /* get pending asts */
961 testl $ AST_URGENT,%eax /* any urgent preemption? */
962 je ret_to_kernel /* no, nothing to do */
963 cmpl $ T_PREEMPT,R32_TRAPNO(%esp)
964 je ret_to_kernel /* T_PREEMPT handled in kernel_trap() */
965 testl $ EFL_IF,R32_EFLAGS(%esp) /* interrupts disabled? */
966 je ret_to_kernel
967 cmpl $0,%gs:CPU_PREEMPTION_LEVEL /* preemption disabled? */
968 jne ret_to_kernel
969 movl %gs:CPU_KERNEL_STACK,%eax
970 movl %esp,%ecx
971 xorl %eax,%ecx
972 and EXT(kernel_stack_mask),%ecx
973 testl %ecx,%ecx /* are we on the kernel stack? */
974 jne ret_to_kernel /* no, skip it */
975
976 CCALL1(i386_astintr, $1) /* take the AST */
977
978 jmp ret_to_kernel
979
980
981 /*
982 * All interrupts on all tasks enter here with:
983 * esp-> -> x86_saved_state_t
984 *
985 * cr3 -> kernel directory
986 * esp -> low based stack
987 * gs -> CPU_DATA_GS
988 * cs -> KERNEL32_CS
989 * ss/ds/es -> KERNEL_DS
990 *
991 * interrupts disabled
992 * direction flag cleared
993 */
994 Entry(lo_allintrs32)
995 /*
996 * test whether already on interrupt stack
997 */
998 movl %gs:CPU_INT_STACK_TOP,%ecx
999 cmpl %esp,%ecx
1000 jb 1f
1001 leal -INTSTACK_SIZE(%ecx),%edx
1002 cmpl %esp,%edx
1003 jb int_from_intstack
1004 1:
1005 xchgl %ecx,%esp /* switch to interrupt stack */
1006
1007 movl %cr0,%eax /* get cr0 */
1008 orl $(CR0_TS),%eax /* or in TS bit */
1009 movl %eax,%cr0 /* set cr0 */
1010
1011 subl $8, %esp /* for 16-byte stack alignment */
1012 pushl %ecx /* save pointer to old stack */
1013 movl %ecx,%gs:CPU_INT_STATE /* save intr state */
1014
1015 TIME_INT_ENTRY /* do timing */
1016
1017 movl %gs:CPU_ACTIVE_THREAD,%ecx
1018 movl TH_TASK(%ecx),%ebx
1019
1020 /* Check for active vtimers in the current task */
1021 TASK_VTIMER_CHECK(%ebx, %ecx)
1022
1023 incl %gs:CPU_PREEMPTION_LEVEL
1024 incl %gs:CPU_INTERRUPT_LEVEL
1025
1026 movl %gs:CPU_INT_STATE, %eax
1027 CCALL1(interrupt, %eax) /* call generic interrupt routine */
1028
1029 cli /* just in case we returned with intrs enabled */
1030 xorl %eax,%eax
1031 movl %eax,%gs:CPU_INT_STATE /* clear intr state pointer */
1032
1033 decl %gs:CPU_INTERRUPT_LEVEL
1034 decl %gs:CPU_PREEMPTION_LEVEL
1035
1036 TIME_INT_EXIT /* do timing */
1037
1038 movl %gs:CPU_ACTIVE_THREAD,%eax
1039 movl TH_PCB_FPS(%eax),%eax /* get pcb's ifps */
1040 testl %eax, %eax /* Is there a context */
1041 je 1f /* Branch if not */
1042 cmpl $0, FP_VALID(%eax) /* Check fp_valid */
1043 jne 1f /* Branch if valid */
1044 clts /* Clear TS */
1045 jmp 2f
1046 1:
1047 movl %cr0,%eax /* get cr0 */
1048 orl $(CR0_TS),%eax /* or in TS bit */
1049 movl %eax,%cr0 /* set cr0 */
1050 2:
1051 popl %esp /* switch back to old stack */
1052
1053 /* Load interrupted code segment into %eax */
1054 movl R32_CS(%esp),%eax /* assume 32-bit state */
1055 cmpl $(SS_64),SS_FLAVOR(%esp)/* 64-bit? */
1056 jne 3f
1057 movl R64_CS(%esp),%eax /* 64-bit user mode */
1058 3:
1059 testb $3,%al /* user mode, */
1060 jnz ast_from_interrupt_user /* go handle potential ASTs */
1061 /*
1062 * we only want to handle preemption requests if
1063 * the interrupt fell in the kernel context
1064 * and preemption isn't disabled
1065 */
1066 movl %gs:CPU_PENDING_AST,%eax
1067 testl $ AST_URGENT,%eax /* any urgent requests? */
1068 je ret_to_kernel /* no, nothing to do */
1069
1070 cmpl $0,%gs:CPU_PREEMPTION_LEVEL /* preemption disabled? */
1071 jne ret_to_kernel /* yes, skip it */
1072
1073 movl %gs:CPU_KERNEL_STACK,%eax
1074 movl %esp,%ecx
1075 xorl %eax,%ecx
1076 and EXT(kernel_stack_mask),%ecx
1077 testl %ecx,%ecx /* are we on the kernel stack? */
1078 jne ret_to_kernel /* no, skip it */
1079
1080 /*
1081 * Take an AST from kernel space. We don't need (and don't want)
1082 * to do as much as the case where the interrupt came from user
1083 * space.
1084 */
1085 CCALL1(i386_astintr, $1)
1086
1087 jmp ret_to_kernel
1088
1089
1090 /*
1091 * nested int - simple path, can't preempt etc on way out
1092 */
1093 int_from_intstack:
1094 incl %gs:CPU_PREEMPTION_LEVEL
1095 incl %gs:CPU_INTERRUPT_LEVEL
1096
1097 movl %esp, %edx /* x86_saved_state */
1098 CCALL1(interrupt, %edx)
1099
1100 decl %gs:CPU_INTERRUPT_LEVEL
1101 decl %gs:CPU_PREEMPTION_LEVEL
1102
1103 jmp ret_to_kernel
1104
1105 /*
1106 * Take an AST from an interrupted user
1107 */
1108 ast_from_interrupt_user:
1109 movl %gs:CPU_PENDING_AST,%eax
1110 testl %eax,%eax /* pending ASTs? */
1111 je ret_to_user /* no, nothing to do */
1112
1113 TIME_TRAP_UENTRY
1114
1115 movl $1, %ecx /* check if we're in the PFZ */
1116 jmp EXT(return_from_trap_with_ast) /* return */
1117
1118
1119 /*
1120 * 32bit Tasks
1121 * System call entries via INTR_GATE or sysenter:
1122 *
1123 * esp -> x86_saved_state32_t
1124 * cr3 -> kernel directory
1125 * esp -> low based stack
1126 * gs -> CPU_DATA_GS
1127 * cs -> KERNEL32_CS
1128 * ss/ds/es -> KERNEL_DS
1129 *
1130 * interrupts disabled
1131 * direction flag cleared
1132 */
1133
1134 Entry(lo_sysenter32)
1135 /*
1136 * We can be here either for a mach syscall or a unix syscall,
1137 * as indicated by the sign of the code:
1138 */
1139 movl R32_EAX(%esp),%eax
1140 testl %eax,%eax
1141 js EXT(lo_mach_scall32) /* < 0 => mach */
1142 /* > 0 => unix */
1143
1144 Entry(lo_unix_scall32)
1145 TIME_TRAP_UENTRY
1146
1147 movl %gs:CPU_KERNEL_STACK,%edi
1148 xchgl %edi,%esp /* switch to kernel stack */
1149 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
1150 movl TH_TASK(%ecx),%ebx /* point to current task */
1151 incl TH_SYSCALLS_UNIX(%ecx) /* increment call count */
1152
1153 /* Check for active vtimers in the current task */
1154 TASK_VTIMER_CHECK(%ebx, %ecx)
1155
1156 sti
1157
1158 CCALL1(unix_syscall, %edi)
1159 /*
1160 * always returns through thread_exception_return
1161 */
1162
1163
1164 Entry(lo_mach_scall32)
1165 TIME_TRAP_UENTRY
1166
1167 movl %gs:CPU_KERNEL_STACK,%edi
1168 xchgl %edi,%esp /* switch to kernel stack */
1169 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
1170 movl TH_TASK(%ecx),%ebx /* point to current task */
1171 incl TH_SYSCALLS_MACH(%ecx) /* increment call count */
1172
1173 /* Check for active vtimers in the current task */
1174 TASK_VTIMER_CHECK(%ebx, %ecx)
1175
1176 sti
1177
1178 CCALL1(mach_call_munger, %edi)
1179 /*
1180 * always returns through thread_exception_return
1181 */
1182
1183
1184 Entry(lo_mdep_scall32)
1185 TIME_TRAP_UENTRY
1186
1187 movl %gs:CPU_KERNEL_STACK,%edi
1188 xchgl %edi,%esp /* switch to kernel stack */
1189 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
1190 movl TH_TASK(%ecx),%ebx /* point to current task */
1191
1192 /* Check for active vtimers in the current task */
1193 TASK_VTIMER_CHECK(%ebx, %ecx)
1194
1195 sti
1196
1197 CCALL1(machdep_syscall, %edi)
1198 /*
1199 * always returns through thread_exception_return
1200 */
1201
1202
1203 LEXT(return_to_user)
1204 TIME_TRAP_UEXIT
1205 jmp ret_to_user
1206
1207
1208 /*
1209 * Double-fault exception handler task. The last gasp...
1210 */
1211 Entry(df_task_start)
1212 CCALL1(panic_double_fault32, $(T_DOUBLE_FAULT))
1213 hlt
1214
1215
1216 /*
1217 * machine-check handler task. The last gasp...
1218 */
1219 Entry(mc_task_start)
1220 CCALL1(panic_machine_check32, $(T_MACHINE_CHECK))
1221 hlt