]> git.saurik.com Git - apple/xnu.git/blame_incremental - osfmk/i386/locore.s
xnu-344.23.tar.gz
[apple/xnu.git] / osfmk / i386 / locore.s
... / ...
CommitLineData
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * @OSF_COPYRIGHT@
24 */
25/*
26 * Mach Operating System
27 * Copyright (c) 1991,1990 Carnegie Mellon University
28 * All Rights Reserved.
29 *
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.
35 *
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.
39 *
40 * Carnegie Mellon requests users of this software to return to
41 *
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
46 *
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
49 */
50
51#include <cpus.h>
52#include <etap.h>
53#include <etap_event_monitor.h>
54#include <mach_rt.h>
55#include <platforms.h>
56#include <mach_kdb.h>
57#include <mach_kgdb.h>
58#include <mach_kdp.h>
59#include <stat_time.h>
60#include <mach_assert.h>
61
62#include <sys/errno.h>
63#include <i386/asm.h>
64#include <i386/cpuid.h>
65#include <i386/eflags.h>
66#include <i386/proc_reg.h>
67#include <i386/trap.h>
68#include <assym.s>
69#include <mach/exception_types.h>
70
71#include <i386/AT386/mp/mp.h>
72
73#define PREEMPT_DEBUG_LOG 0
74
75#if __MACHO__
76/* Under Mach-O, etext is a variable which contains
77 * the last text address
78 */
79#define ETEXT_ADDR (EXT(etext))
80#else
81/* Under ELF and other non-Mach-O formats, the address of
82 * etext represents the last text address
83 */
84#define ETEXT_ADDR $ EXT(etext)
85#endif
86
87#if NCPUS > 1
88
89#define CX(addr,reg) addr(,reg,4)
90
91#else
92#define CPU_NUMBER(reg)
93#define CX(addr,reg) addr
94
95#endif /* NCPUS > 1 */
96
97 .text
98locore_start:
99
100/*
101 * Fault recovery.
102 */
103
104#ifdef __MACHO__
105#define RECOVERY_SECTION .section __VECTORS, __recover
106#define RETRY_SECTION .section __VECTORS, __retries
107#else
108#define RECOVERY_SECTION .text
109#define RECOVERY_SECTION .text
110#endif
111
112#define RECOVER_TABLE_START \
113 .align 2 ; \
114 .globl EXT(recover_table) ;\
115LEXT(recover_table) ;\
116 .text
117
118#define RECOVER(addr) \
119 .align 2; \
120 .long 9f ;\
121 .long addr ;\
122 .text ;\
1239:
124
125#define RECOVER_TABLE_END \
126 .align 2 ;\
127 .globl EXT(recover_table_end) ;\
128LEXT(recover_table_end) ;\
129 .text
130
131/*
132 * Retry table for certain successful faults.
133 */
134#define RETRY_TABLE_START \
135 .align 3; \
136 .globl EXT(retry_table) ;\
137LEXT(retry_table) ;\
138 .text
139
140#define RETRY(addr) \
141 .align 3 ;\
142 .long 9f ;\
143 .long addr ;\
144 .text ;\
1459:
146
147#define RETRY_TABLE_END \
148 .align 3; \
149 .globl EXT(retry_table_end) ;\
150LEXT(retry_table_end) ;\
151 .text
152
153/*
154 * Allocate recovery and retry tables.
155 */
156 RECOVERY_SECTION
157 RECOVER_TABLE_START
158 RETRY_SECTION
159 RETRY_TABLE_START
160
161/*
162 * Timing routines.
163 */
164#if STAT_TIME
165
166#define TIME_TRAP_UENTRY
167#define TIME_TRAP_UEXIT
168#define TIME_INT_ENTRY
169#define TIME_INT_EXIT
170
171#else /* microsecond timing */
172
173/*
174 * Microsecond timing.
175 * Assumes a free-running microsecond counter.
176 * no TIMER_MAX check needed.
177 */
178
179/*
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.
183 */
184 .comm EXT(current_tstamp), 4*NCPUS
185
186/*
187 * Update time on user trap entry.
188 * 11 instructions (including cli on entry)
189 * Assumes CPU number in %edx.
190 * Uses %ebx, %ecx.
191 */
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 */ ;\
2020: 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 */
206
207/*
208 * update time on user trap exit.
209 * 10 instructions.
210 * Assumes CPU number in %edx.
211 * Uses %ebx, %ecx.
212 */
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 */ ;\
2230: addl $(TH_USER_TIMER-TH_SYS_TIMER),%ecx ;\
224 /* switch to user timer */;\
225 movl %ecx,CX(EXT(current_timer),%edx) /* make it current */
226
227/*
228 * update time on interrupt entry.
229 * 9 instructions.
230 * Assumes CPU number in %edx.
231 * Leaves old timer in %ebx.
232 * Uses %ecx.
233 */
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 */
244
245/*
246 * update time on interrupt exit.
247 * 11 instructions
248 * Assumes CPU number in %edx, old timer in %ebx.
249 * Uses %eax, %ecx.
250 */
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 */ ;\
2600: 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 */ ;\
2640: movl %ebx,CX(EXT(current_timer),%edx) /* set timer */
265
266
267/*
268 * Normalize timer in ecx.
269 * Preserves edx; clobbers eax.
270 */
271 .align ALIGN
272timer_high_unit:
273 .long TIMER_HIGH_UNIT /* div has no immediate opnd */
274
275timer_normalize:
276 pushl %edx /* save registersz */
277 pushl %eax
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 */
286 popl %edx
287 ret
288
289/*
290 * Switch to a new timer.
291 */
292Entry(timer_switch)
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 */
3020:
303 movl S_ARG0,%ecx /* get new timer */
304 movl %ecx,CX(EXT(current_timer),%edx) /* set timer */
305 ret
306
307/*
308 * Initialize the first timer for a CPU.
309 */
310Entry(start_timer)
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 */
316 ret
317
318#endif /* accurate timing */
319
320/*
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).
326 */
327
328/*
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).
332 *
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).
337 *
338 * Must be called on kernel stack.
339 */
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 */ ;\
345 movl $ R_UESP,%ecx ;\
346 sarl $2,%ecx /* word count for transfer */ ;\
347 cld /* we`re incrementing */ ;\
348 rep ;\
349 movsl /* transfer the frame */ ;\
350 addl $ R_UESP,stkp /* derive true "user" esp */ ;\
351 movl stkp,R_UESP(thread) /* store in PCB */ ;\
352 movl $0,%ecx ;\
353 mov %ss,%cx /* get current ss */ ;\
354 movl %ecx,R_SS(thread) /* store in PCB */
355
356/*
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).
360 *
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).
365 *
366 * Must be called on kernel stack.
367 */
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 */;\
377 mov %cx,%es ;\
3781: ;\
379 movl $ R_UESP,%ecx ;\
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 */ ;\
384 rep ;\
385 movsl /* transfer the frame */ ;\
386 mov %ss,%cx /* restore kernel segments */ ;\
387 mov %cx,%es
388
389#undef PDEBUG
390
391#ifdef PDEBUG
392
393/*
394 * Traditional, not ANSI.
395 */
396#define CAH(label) \
397 .data ;\
398 .globl label/**/count ;\
399label/**/count: ;\
400 .long 0 ;\
401 .globl label/**/limit ;\
402label/**/limit: ;\
403 .long 0 ;\
404 .text ;\
405 addl $1,%ss:label/**/count ;\
406 cmpl $0,label/**/limit ;\
407 jz label/**/exit ;\
408 pushl %eax ;\
409label/**/loop: ;\
410 movl %ss:label/**/count,%eax ;\
411 cmpl %eax,%ss:label/**/limit ;\
412 je label/**/loop ;\
413 popl %eax ;\
414label/**/exit:
415
416#else /* PDEBUG */
417
418#define CAH(label)
419
420#endif /* PDEBUG */
421
422#if MACH_KDB
423/*
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.
429 *
430 * In case of a double-fault, our only recourse is to switch
431 * hardware "tasks", so that we avoid using the current stack.
432 *
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.
437 */
438#if 0
439/*
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.
446 */
447/*
448 * Double fault (Murphy's point) - error code (0) on stack
449 */
450Entry(db_task_dbl_fault)
451 popl %eax
452 movl $(T_DOUBLE_FAULT),%ebx
453 jmp db_task_start
454/*
455 * Segment not present - error code on stack
456 */
457Entry(db_task_seg_np)
458 popl %eax
459 movl $(T_SEGMENT_NOT_PRESENT),%ebx
460 jmp db_task_start
461/*
462 * Stack fault - error code on (current) stack
463 */
464Entry(db_task_stk_fault)
465 popl %eax
466 movl $(T_STACK_FAULT),%ebx
467 jmp db_task_start
468/*
469 * General protection fault - error code on stack
470 */
471Entry(db_task_gen_prot)
472 popl %eax
473 movl $(T_GENERAL_PROTECTION),%ebx
474 jmp db_task_start
475#endif /* 0 */
476/*
477 * The entry point where execution resumes after last-ditch debugger task
478 * switch.
479 */
480Entry(db_task_start)
481 movl %esp,%edx
482 subl $ISS_SIZE,%edx
483 movl %edx,%esp /* allocate i386_saved_state on stack */
484 movl %eax,R_ERR(%esp)
485 movl %ebx,R_TRAPNO(%esp)
486 pushl %edx
487#if NCPUS > 1
488 CPU_NUMBER(%edx)
489 movl CX(EXT(mp_dbtss),%edx),%edx
490 movl TSS_LINK(%edx),%eax
491#else
492 movl EXT(dbtss)+TSS_LINK,%eax
493#endif
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)
498 addl $0x4,%esp
499 /*
500 * And now...?
501 */
502 iret /* ha, ha, ha... */
503#endif /* MACH_KDB */
504
505/*
506 * Trap/interrupt entry points.
507 *
508 * All traps must create the following save area on the PCB "stack":
509 *
510 * gs
511 * fs
512 * es
513 * ds
514 * edi
515 * esi
516 * ebp
517 * cr2 if page fault - otherwise unused
518 * ebx
519 * edx
520 * ecx
521 * eax
522 * trap number
523 * error code
524 * eip
525 * cs
526 * eflags
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
533 *
534 */
535
536/*
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.
540 *
541 * esp-> 0: trap code (NP or GP)
542 * 4: segment number in error
543 * 8 eip
544 * 12 cs
545 * 16 eflags
546 * 20 old registers (trap is from kernel)
547 */
548Entry(t_gen_prot)
549 pushl $(T_GENERAL_PROTECTION) /* indicate fault type */
550 jmp trap_check_kernel_exit /* check for kernel exit sequence */
551
552Entry(t_segnp)
553 pushl $(T_SEGMENT_NOT_PRESENT)
554 /* indicate fault type */
555
556trap_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? */
563 je fault_iret
564 cmpl $ EXT(kret_popl_ds),8(%esp) /* popping DS? */
565 je fault_popl_ds
566 cmpl $ EXT(kret_popl_es),8(%esp) /* popping ES? */
567 je fault_popl_es
568 cmpl $ EXT(kret_popl_fs),8(%esp) /* popping FS? */
569 je fault_popl_fs
570 cmpl $ EXT(kret_popl_gs),8(%esp) /* popping GS? */
571 je fault_popl_gs
572take_fault: /* if none of the above: */
573 jmp EXT(alltraps) /* treat as normal trap. */
574
575/*
576 * GP/NP fault on IRET: CS or SS is in error.
577 * All registers contain the user's values.
578 *
579 * on SP is
580 * 0 trap number
581 * 4 errcode
582 * 8 eip
583 * 12 cs --> trapno
584 * 16 efl --> errcode
585 * 20 user eip
586 * 24 user cs
587 * 28 user eflags
588 * 32 user esp
589 * 36 user ss
590 */
591fault_iret:
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 */
598 CAH(fltir)
599 jmp EXT(alltraps) /* take fault */
600
601/*
602 * Fault restoring a segment register. The user's registers are still
603 * saved on the stack. The offending segment register has not been
604 * popped.
605 */
606fault_popl_ds:
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) */
611fault_popl_es:
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) */
616fault_popl_fs:
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) */
621fault_popl_gs:
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) */
626
627push_es:
628 pushl %es /* restore es, */
629push_fs:
630 pushl %fs /* restore fs, */
631push_gs:
632 pushl %gs /* restore gs. */
633push_segregs:
634 movl %eax,R_TRAPNO(%esp) /* set trap number */
635 movl %edx,R_ERR(%esp) /* set error code */
636 CAH(fltpp)
637 jmp trap_set_segs /* take trap */
638
639/*
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
643 * bit set.
644 */
645Entry(t_debug)
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? */
649 jnz 0f /* if so: */
650 cmpl $syscall_entry,(%esp) /* system call entry? */
651 jne 0f /* if so: */
652 /* flags are sitting where syscall */
653 /* wants them */
654 addl $8,%esp /* remove eip/cs */
655 jmp syscall_entry_2 /* continue system call entry */
656
6570: pushl $0 /* otherwise: */
658 pushl $(T_DEBUG) /* handle as normal */
659 jmp EXT(alltraps) /* debug fault */
660
661/*
662 * Page fault traps save cr2.
663 */
664Entry(t_page_fault)
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 */
670
671/*
672 * All 'exceptions' enter here with:
673 * esp-> trap number
674 * error code
675 * old eip
676 * old cs
677 * old eflags
678 * old esp if trapped from user
679 * old ss if trapped from user
680 *
681 * NB: below use of CPU_NUMBER assumes that macro will use correct
682 * segment register for any kernel data accesses.
683 */
684Entry(alltraps)
685 pusha /* save the general registers */
686trap_push_segs:
687 pushl %ds /* save the segment registers */
688 pushl %es
689 pushl %fs
690 pushl %gs
691
692trap_set_segs:
693 movl %ss,%ax
694 movl %ax,%ds
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? */
700 jnz trap_from_user
701 CPU_NUMBER(%edx)
702 cmpl $0,CX(EXT(active_kloaded),%edx)
703 je trap_from_kernel /* if clear, truly in kernel */
704#ifdef FIXME
705 cmpl ETEXT_ADDR,R_EIP(%esp) /* pc within kernel? */
706 jb trap_from_kernel
707#endif
708trap_from_kloaded:
709 /*
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
714 * frame.
715 */
716 mov $ CPU_DATA,%dx
717 mov %dx,%gs
718 CAH(atstart)
719 CPU_NUMBER(%edx)
720 movl CX(EXT(active_kloaded),%edx),%ebx
721 movl CX(EXT(kernel_stack),%edx),%eax
722 xchgl %esp,%eax
723 FRAME_STACK_TO_PCB(%ebx,%eax)
724 CAH(atend)
725 jmp EXT(take_trap)
726
727trap_from_user:
728 mov $ CPU_DATA,%ax
729 mov %ax,%gs
730
731 CPU_NUMBER(%edx)
732 TIME_TRAP_UENTRY
733
734 movl CX(EXT(kernel_stack),%edx),%ebx
735 xchgl %ebx,%esp /* switch to kernel stack */
736 /* user regs pointer already set */
737LEXT(take_trap)
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 */
742
743/*
744 * Return from trap or system call, checking for ASTs.
745 * On PCB stack.
746 */
747
748LEXT(return_from_trap)
749 CPU_NUMBER(%edx)
750 cmpl $0,CX(EXT(need_ast),%edx)
751 je EXT(return_to_user) /* if we need an AST: */
752
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 */
761 /* have to wait */
762
763/*
764 * Arrange the checks needed for kernel-loaded (or kernel-loading)
765 * threads so that branch is taken in kernel-loaded case.
766 */
767LEXT(return_to_user)
768 TIME_TRAP_UEXIT
769 CPU_NUMBER(%eax)
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)
777
778#if MACH_RT
779#if MACH_ASSERT
780 movl $ CPD_PREEMPTION_LEVEL,%ebx
781 cmpl $0,%gs:(%ebx)
782 je EXT(return_from_kernel)
783 int $3
784#endif /* MACH_ASSERT */
785#endif /* MACH_RT */
786
787/*
788 * Return from kernel mode to interrupted thread.
789 */
790
791LEXT(return_from_kernel)
792LEXT(kret_popl_gs)
793 popl %gs /* restore segment registers */
794LEXT(kret_popl_fs)
795 popl %fs
796LEXT(kret_popl_es)
797 popl %es
798LEXT(kret_popl_ds)
799 popl %ds
800 popa /* restore general registers */
801 addl $8,%esp /* discard trap number and error code */
802
803LEXT(kret_iret)
804 iret /* return from interrupt */
805
806
807LEXT(return_xfer_stack)
808 /*
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
812 * to do so for us.
813 */
814 CAH(rxsstart)
815 CPU_NUMBER(%eax)
816 movl CX(EXT(kernel_stack),%eax),%esp
817 movl CX(EXT(active_kloaded),%eax),%eax
818 FRAME_PCB_TO_STACK(%eax)
819 movl %eax,%esp
820 CAH(rxsend)
821 jmp EXT(return_from_kernel)
822
823/*
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.
830 */
831/*
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
835 * stack pointer.
836 */
837LEXT(return_kernel_loading)
838 CPU_NUMBER(%eax)
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)
850
851/*
852 * Trap from kernel mode. No need to switch stacks or load segment registers.
853 */
854trap_from_kernel:
855#if MACH_KDB || MACH_KGDB
856 mov $ CPU_DATA,%ax
857 mov %ax,%gs
858 movl %esp,%ebx /* save current stack */
859
860 cmpl EXT(int_stack_high),%esp /* on an interrupt stack? */
861 jb 6f /* OK if so */
862
863#if MACH_KGDB
864 cmpl $0,EXT(kgdb_active) /* Unexpected trap in kgdb */
865 je 0f /* no */
866
867 pushl %esp /* Already on kgdb stack */
868 cli
869 call EXT(kgdb_trap)
870 addl $4,%esp
871 jmp EXT(return_from_kernel)
8720: /* should kgdb handle this exception? */
873 cmpl $(T_NO_FPU),R_TRAPNO(%esp) /* FPU disabled? */
874 je 2f /* yes */
875 cmpl $(T_PAGE_FAULT),R_TRAPNO(%esp) /* page fault? */
876 je 2f /* yes */
8771:
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)
8862:
887#endif /* MACH_KGDB */
888
889#if MACH_KDB
890 cmpl $0,EXT(db_active) /* could trap be from ddb? */
891 je 3f /* no */
892#if NCPUS > 1
893 CPU_NUMBER(%edx) /* see if this CPU is in ddb */
894 cmpl $0,CX(EXT(kdb_active),%edx)
895 je 3f /* no */
896#endif /* NCPUS > 1 */
897 pushl %esp
898 call EXT(db_trap_from_asm)
899 addl $0x4,%esp
900 jmp EXT(return_from_kernel)
901
9023:
903 /*
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
911 * bogus fault.
912 */
913 movl R_TRAPNO(%esp),%edx
914 cmpl $(T_PAGE_FAULT),%edx
915 je 4f
916 cmpl $(T_NO_FPU),%edx
917 je 4f
918 cmpl $(T_FPU_FAULT),%edx
919 je 4f
920 cmpl $(T_FLOATING_POINT_ERROR),%edx
921 je 4f
922 cmpl $(T_PREEMPT),%edx
923 jne 7f
9244:
925#endif /* MACH_KDB */
926
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 */
9335:
934 movl CX(EXT(kernel_stack),%edx),%esp
9356:
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 */
940 testl %eax,%eax
941 jne 8f
942 /*
943 * If kernel_trap returns false, trap wasn't handled.
944 */
9457:
946#if MACH_KDB
947 CPU_NUMBER(%edx)
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 */
952#if MACH_KGDB
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 */
960 testl %eax,%eax
961 jne 8f
962 /*
963 * Likewise, if kdb_trap/kgdb_from_kernel returns false, trap
964 * wasn't handled.
965 */
966 pushl %ebx /* pass old stack as parameter */
967 call EXT(panic_trap)
968 addl $4,%esp /* pop parameter */
9698:
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 */
976
977#if MACH_RT
978 CPU_NUMBER(%edx)
979
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
988 movl %esp,%ecx
989 xorl %eax,%ecx
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 */
993
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 */
998 pushl $0f
999 call EXT(log_thread_action)
1000 addl $16, %esp
1001 .data
10020: String "trap preempt eip"
1003 .text
1004#endif /* PREEMPT_DEBUG_LOG */
1005
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 */
1010
1011 jmp EXT(return_from_kernel)
1012
1013/*
1014 * Called as a function, makes the current thread
1015 * return from the kernel as if from an exception.
1016 */
1017
1018 .globl EXT(thread_exception_return)
1019 .globl EXT(thread_bootstrap_return)
1020LEXT(thread_exception_return)
1021LEXT(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)
1026
1027Entry(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 */
1035
1036#if 0
1037#define LOG_INTERRUPT(info,msg) \
1038 pushal ; \
1039 pushl msg ; \
1040 pushl info ; \
1041 call EXT(log_thread_action) ; \
1042 add $8,%esp ; \
1043 popal
1044#define CHECK_INTERRUPT_TIME(n) \
1045 pushal ; \
1046 pushl $n ; \
1047 call EXT(check_thread_time) ; \
1048 add $4,%esp ; \
1049 popal
1050#else
1051#define LOG_INTERRUPT(info,msg)
1052#define CHECK_INTERRUPT_TIME(n)
1053#endif
1054
1055imsg_start:
1056 String "interrupt start"
1057imsg_end:
1058 String "interrupt end"
1059
1060/*
1061 * All interrupts enter here.
1062 * old %eax on stack; interrupt number in %eax.
1063 */
1064Entry(all_intrs)
1065 pushl %ecx /* save registers */
1066 pushl %edx
1067 cld /* clear direction flag */
1068
1069 cmpl %ss:EXT(int_stack_high),%esp /* on an interrupt stack? */
1070 jb int_from_intstack /* if not: */
1071
1072 pushl %ds /* save segment registers */
1073 pushl %es
1074 mov %ss,%dx /* switch to kernel segments */
1075 mov %dx,%ds
1076 mov %dx,%es
1077 mov $ CPU_DATA,%dx
1078 mov %dx,%gs
1079
1080 CPU_NUMBER(%edx)
1081
1082 movl CX(EXT(int_stack_top),%edx),%ecx
1083 movl 20(%esp),%edx /* get eip */
1084 xchgl %ecx,%esp /* switch to interrupt stack */
1085
1086#if STAT_TIME
1087 pushl %ecx /* save pointer to old stack */
1088#else
1089 pushl %ebx /* save %ebx - out of the way */
1090 /* so stack looks the same */
1091 pushl %ecx /* save pointer to old stack */
1092 TIME_INT_ENTRY /* do timing */
1093#endif
1094
1095 pushl %edx /* pass eip to pe_incoming_interrupt */
1096
1097#if MACH_RT
1098 movl $ CPD_PREEMPTION_LEVEL,%edx
1099 incl %gs:(%edx)
1100#endif /* MACH_RT */
1101
1102 movl $ CPD_INTERRUPT_LEVEL,%edx
1103 incl %gs:(%edx)
1104
1105 pushl %eax /* Push trap number */
1106 call EXT(PE_incoming_interrupt) /* call generic interrupt routine */
1107 addl $8,%esp /* Pop trap number and eip */
1108
1109 .globl EXT(return_to_iret)
1110LEXT(return_to_iret) /* (label for kdb_kintr and hardclock) */
1111
1112 movl $ CPD_INTERRUPT_LEVEL,%edx
1113 decl %gs:(%edx)
1114
1115#if MACH_RT
1116 movl $ CPD_PREEMPTION_LEVEL,%edx
1117 decl %gs:(%edx)
1118#endif /* MACH_RT */
1119
1120#if STAT_TIME
1121#else
1122 TIME_INT_EXIT /* do timing */
1123 movl 4(%esp),%ebx /* restore the extra reg we saved */
1124#endif
1125
1126 popl %esp /* switch back to old stack */
1127
1128 CPU_NUMBER(%edx)
1129 movl CX(EXT(need_ast),%edx),%eax
1130 testl %eax,%eax /* any pending asts? */
1131 je 1f /* no, nothing to do */
1132 testl $(EFL_VM),I_EFL(%esp) /* if in V86 */
1133 jnz ast_from_interrupt /* take it */
1134 testb $3,I_CS(%esp) /* user mode, */
1135 jnz ast_from_interrupt /* take it */
1136#ifdef FIXME
1137 cmpl ETEXT_ADDR,I_EIP(%esp) /* if within kernel-loaded task, */
1138 jnb ast_from_interrupt /* take it */
1139#endif
1140
1141#if MACH_RT
1142 cmpl $0,EXT(preemptable) /* kernel-mode, preemption enabled? */
1143 je 1f /* no, skip it */
1144 movl $ CPD_PREEMPTION_LEVEL,%ecx
1145 cmpl $0,%gs:(%ecx) /* preemption masked? */
1146 jne 1f /* yes, skip it */
1147 testl $ AST_URGENT,%eax /* any urgent requests? */
1148 je 1f /* no, skip it */
1149 cmpl $ EXT(locore_end),I_EIP(%esp) /* are we in locore code? */
1150 jb 1f /* yes, skip it */
1151 movl CX(EXT(kernel_stack),%edx),%eax
1152 movl %esp,%ecx
1153 xorl %eax,%ecx
1154 andl $(-KERNEL_STACK_SIZE),%ecx
1155 testl %ecx,%ecx /* are we on the kernel stack? */
1156 jne 1f /* no, skip it */
1157
1158/*
1159 * Take an AST from kernel space. We don't need (and don't want)
1160 * to do as much as the case where the interrupt came from user
1161 * space.
1162 */
1163#if PREEMPT_DEBUG_LOG
1164 pushl $0
1165 pushl $0
1166 pushl I_EIP+8(%esp)
1167 pushl $0f
1168 call EXT(log_thread_action)
1169 addl $16, %esp
1170 .data
11710: String "intr preempt eip"
1172 .text
1173#endif /* PREEMPT_DEBUG_LOG */
1174
1175 sti
1176 pushl $1 /* push preemption flag */
1177 call EXT(i386_astintr) /* take the AST */
1178 addl $4,%esp /* pop preemption flag */
1179#endif /* MACH_RT */
1180
11811:
1182 pop %es /* restore segment regs */
1183 pop %ds
1184 pop %edx
1185 pop %ecx
1186 pop %eax
1187 iret /* return to caller */
1188
1189int_from_intstack:
1190#if MACH_RT
1191 movl $ CPD_PREEMPTION_LEVEL,%edx
1192 incl %gs:(%edx)
1193#endif /* MACH_RT */
1194
1195 movl $ CPD_INTERRUPT_LEVEL,%edx
1196 incl %gs:(%edx)
1197
1198 movl 12(%esp),%edx
1199 pushl %edx /* push eip */
1200
1201 pushl %eax /* Push trap number */
1202
1203 call EXT(PE_incoming_interrupt)
1204 addl $4,%esp /* pop eip */
1205
1206LEXT(return_to_iret_i) /* ( label for kdb_kintr) */
1207
1208 addl $4,%esp /* pop trap number */
1209
1210 movl $ CPD_INTERRUPT_LEVEL,%edx
1211 decl %gs:(%edx)
1212
1213#if MACH_RT
1214 movl $ CPD_PREEMPTION_LEVEL,%edx
1215 decl %gs:(%edx)
1216#endif /* MACH_RT */
1217
1218 pop %edx /* must have been on kernel segs */
1219 pop %ecx
1220 pop %eax /* no ASTs */
1221 iret
1222
1223/*
1224 * Take an AST from an interrupt.
1225 * On PCB stack.
1226 * sp-> es -> edx
1227 * ds -> ecx
1228 * edx -> eax
1229 * ecx -> trapno
1230 * eax -> code
1231 * eip
1232 * cs
1233 * efl
1234 * esp
1235 * ss
1236 */
1237ast_from_interrupt:
1238 pop %es /* restore all registers ... */
1239 pop %ds
1240 popl %edx
1241 popl %ecx
1242 popl %eax
1243 sti /* Reenable interrupts */
1244 pushl $0 /* zero code */
1245 pushl $0 /* zero trap number */
1246 pusha /* save general registers */
1247 push %ds /* save segment registers */
1248 push %es
1249 push %fs
1250 push %gs
1251 mov %ss,%dx /* switch to kernel segments */
1252 mov %dx,%ds
1253 mov %dx,%es
1254 mov $ CPU_DATA,%dx
1255 mov %dx,%gs
1256
1257 /*
1258 * See if we interrupted a kernel-loaded thread executing
1259 * in its own task.
1260 */
1261 CPU_NUMBER(%edx)
1262 testl $(EFL_VM),R_EFLAGS(%esp) /* in V86 mode? */
1263 jnz 0f /* user mode trap if so */
1264 testb $3,R_CS(%esp)
1265 jnz 0f /* user mode, back to normal */
1266#ifdef FIXME
1267 cmpl ETEXT_ADDR,R_EIP(%esp)
1268 jb 0f /* not kernel-loaded, back to normal */
1269#endif
1270
1271 /*
1272 * Transfer the current stack frame by hand into the PCB.
1273 */
1274 CAH(afistart)
1275 movl CX(EXT(active_kloaded),%edx),%eax
1276 movl CX(EXT(kernel_stack),%edx),%ebx
1277 xchgl %ebx,%esp
1278 FRAME_STACK_TO_PCB(%eax,%ebx)
1279 CAH(afiend)
1280 TIME_TRAP_UENTRY
1281 jmp 3f
12820:
1283 TIME_TRAP_UENTRY
1284
1285 movl CX(EXT(kernel_stack),%edx),%eax
1286 /* switch to kernel stack */
1287 xchgl %eax,%esp
12883:
1289 pushl %eax
1290 pushl $0 /* push preemption flag */
1291 call EXT(i386_astintr) /* take the AST */
1292 addl $4,%esp /* pop preemption flag */
1293 popl %esp /* back to PCB stack */
1294 jmp EXT(return_from_trap) /* return */
1295
1296#if MACH_KDB || MACH_KGDB
1297/*
1298 * kdb_kintr: enter kdb from keyboard interrupt.
1299 * Chase down the stack frames until we find one whose return
1300 * address is the interrupt handler. At that point, we have:
1301 *
1302 * frame-> saved %ebp
1303 * return address in interrupt handler
1304 * ivect
1305 * saved SPL
1306 * return address == return_to_iret_i
1307 * saved %edx
1308 * saved %ecx
1309 * saved %eax
1310 * saved %eip
1311 * saved %cs
1312 * saved %efl
1313 *
1314 * OR:
1315 * frame-> saved %ebp
1316 * return address in interrupt handler
1317 * ivect
1318 * saved SPL
1319 * return address == return_to_iret
1320 * pointer to save area on old stack
1321 * [ saved %ebx, if accurate timing ]
1322 *
1323 * old stack: saved %es
1324 * saved %ds
1325 * saved %edx
1326 * saved %ecx
1327 * saved %eax
1328 * saved %eip
1329 * saved %cs
1330 * saved %efl
1331 *
1332 * Call kdb, passing it that register save area.
1333 */
1334
1335#if MACH_KGDB
1336Entry(kgdb_kintr)
1337#endif /* MACH_KGDB */
1338#if MACH_KDB
1339Entry(kdb_kintr)
1340#endif /* MACH_KDB */
1341 movl %ebp,%eax /* save caller`s frame pointer */
1342 movl $ EXT(return_to_iret),%ecx /* interrupt return address 1 */
1343 movl $ EXT(return_to_iret_i),%edx /* interrupt return address 2 */
1344
13450: cmpl 16(%eax),%ecx /* does this frame return to */
1346 /* interrupt handler (1)? */
1347 je 1f
1348 cmpl $kdb_from_iret,16(%eax)
1349 je 1f
1350 cmpl 16(%eax),%edx /* interrupt handler (2)? */
1351 je 2f /* if not: */
1352 cmpl $kdb_from_iret_i,16(%eax)
1353 je 2f
1354 movl (%eax),%eax /* try next frame */
1355 jmp 0b
1356
13571: movl $kdb_from_iret,16(%eax) /* returns to kernel/user stack */
1358 ret
1359
13602: movl $kdb_from_iret_i,16(%eax)
1361 /* returns to interrupt stack */
1362 ret
1363
1364/*
1365 * On return from keyboard interrupt, we will execute
1366 * kdb_from_iret_i
1367 * if returning to an interrupt on the interrupt stack
1368 * kdb_from_iret
1369 * if returning to an interrupt on the user or kernel stack
1370 */
1371kdb_from_iret:
1372 /* save regs in known locations */
1373#if STAT_TIME
1374 pushl %ebx /* caller`s %ebx is in reg */
1375#else
1376 movl 4(%esp),%eax /* get caller`s %ebx */
1377 pushl %eax /* push on stack */
1378#endif
1379 pushl %ebp
1380 pushl %esi
1381 pushl %edi
1382 push %fs
1383 push %gs
1384#if MACH_KGDB
1385 cli
1386 pushl %esp /* pass regs */
1387 call EXT(kgdb_kentry) /* to kgdb */
1388 addl $4,%esp /* pop parameters */
1389#endif /* MACH_KGDB */
1390#if MACH_KDB
1391 pushl %esp /* pass regs */
1392 call EXT(kdb_kentry) /* to kdb */
1393 addl $4,%esp /* pop parameters */
1394#endif /* MACH_KDB */
1395 pop %gs /* restore registers */
1396 pop %fs
1397 popl %edi
1398 popl %esi
1399 popl %ebp
1400#if STAT_TIME
1401 popl %ebx
1402#else
1403 popl %eax
1404 movl %eax,4(%esp)
1405#endif
1406 jmp EXT(return_to_iret) /* normal interrupt return */
1407
1408kdb_from_iret_i: /* on interrupt stack */
1409 pop %edx /* restore saved registers */
1410 pop %ecx
1411 pop %eax
1412 pushl $0 /* zero error code */
1413 pushl $0 /* zero trap number */
1414 pusha /* save general registers */
1415 push %ds /* save segment registers */
1416 push %es
1417 push %fs
1418 push %gs
1419#if MACH_KGDB
1420 cli /* disable interrupts */
1421 CPU_NUMBER(%edx) /* get CPU number */
1422 movl CX(EXT(kgdb_stacks),%edx),%ebx
1423 xchgl %ebx,%esp /* switch to kgdb stack */
1424 pushl %ebx /* pass old sp as an arg */
1425 call EXT(kgdb_from_kernel)
1426 popl %esp /* switch back to interrupt stack */
1427#endif /* MACH_KGDB */
1428#if MACH_KDB
1429 pushl %esp /* pass regs, */
1430 pushl $0 /* code, */
1431 pushl $-1 /* type to kdb */
1432 call EXT(kdb_trap)
1433 addl $12,%esp
1434#endif /* MACH_KDB */
1435 pop %gs /* restore segment registers */
1436 pop %fs
1437 pop %es
1438 pop %ds
1439 popa /* restore general registers */
1440 addl $8,%esp
1441 iret
1442
1443#endif /* MACH_KDB || MACH_KGDB */
1444
1445
1446/*
1447 * Mach RPC enters through a call gate, like a system call.
1448 */
1449
1450Entry(mach_rpc)
1451 pushf /* save flags as soon as possible */
1452 pushl %eax /* save system call number */
1453 pushl $0 /* clear trap number slot */
1454
1455 pusha /* save the general registers */
1456 pushl %ds /* and the segment registers */
1457 pushl %es
1458 pushl %fs
1459 pushl %gs
1460
1461 mov %ss,%dx /* switch to kernel data segment */
1462 mov %dx,%ds
1463 mov %dx,%es
1464 mov $ CPU_DATA,%dx
1465 mov %dx,%gs
1466
1467/*
1468 * Shuffle eflags,eip,cs into proper places
1469 */
1470
1471 movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
1472 movl R_CS(%esp),%ecx /* eip is in CS slot */
1473 movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
1474 movl %ecx,R_EIP(%esp) /* fix eip */
1475 movl %edx,R_CS(%esp) /* fix cs */
1476 movl %ebx,R_EFLAGS(%esp) /* fix eflags */
1477
1478 CPU_NUMBER(%edx)
1479 TIME_TRAP_UENTRY
1480
1481 negl %eax /* get system call number */
1482 shll $4,%eax /* manual indexing */
1483
1484/*
1485 * Check here for mach_rpc from kernel-loaded task --
1486 * - Note that kernel-loaded task returns via real return.
1487 * We didn't enter here "through" PCB (i.e., using ring 0 stack),
1488 * so transfer the stack frame into the PCB explicitly, then
1489 * start running on resulting "PCB stack". We have to set
1490 * up a simulated "uesp" manually, since there's none in the
1491 * frame.
1492 */
1493 cmpl $0,CX(EXT(active_kloaded),%edx)
1494 jz 2f
1495 CAH(mrstart)
1496 movl CX(EXT(active_kloaded),%edx),%ebx
1497 movl CX(EXT(kernel_stack),%edx),%edx
1498 xchgl %edx,%esp
1499
1500 FRAME_STACK_TO_PCB(%ebx,%edx)
1501 CAH(mrend)
1502
1503 CPU_NUMBER(%edx)
1504 jmp 3f
1505
15062:
1507 CPU_NUMBER(%edx)
1508 movl CX(EXT(kernel_stack),%edx),%ebx
1509 /* get current kernel stack */
1510 xchgl %ebx,%esp /* switch stacks - %ebx points to */
1511 /* user registers. */
1512
15133:
1514
1515/*
1516 * Register use on entry:
1517 * eax contains syscall number
1518 * ebx contains user regs pointer
1519 */
1520#undef RPC_TRAP_REGISTERS
1521#ifdef RPC_TRAP_REGISTERS
1522 pushl R_ESI(%ebx)
1523 pushl R_EDI(%ebx)
1524 pushl R_ECX(%ebx)
1525 pushl R_EDX(%ebx)
1526#else
1527 movl EXT(mach_trap_table)(%eax),%ecx
1528 /* get number of arguments */
1529 jecxz 2f /* skip argument copy if none */
1530 movl R_UESP(%ebx),%esi /* get user stack pointer */
1531 lea 4(%esi,%ecx,4),%esi /* skip user return address, */
1532 /* and point past last argument */
1533 /* edx holds cpu number from above */
1534 movl CX(EXT(active_kloaded),%edx),%edx
1535 /* point to current thread */
1536 orl %edx,%edx /* if ! kernel-loaded, check addr */
1537 jz 4f /* else */
1538 mov %ds,%dx /* kernel data segment access */
1539 jmp 5f
15404:
1541 cmpl $(VM_MAX_ADDRESS),%esi /* in user space? */
1542 ja mach_call_addr /* address error if not */
1543 movl $ USER_DS,%edx /* user data segment access */
15445:
1545 mov %dx,%fs
1546 movl %esp,%edx /* save kernel ESP for error recovery */
15471:
1548 subl $4,%esi
1549 RECOVERY_SECTION
1550 RECOVER(mach_call_addr_push)
1551 pushl %fs:(%esi) /* push argument on stack */
1552 loop 1b /* loop for all arguments */
1553#endif
1554
1555/*
1556 * Register use on entry:
1557 * eax contains syscall number
1558 * ebx contains user regs pointer
1559 */
15602:
1561 CAH(call_call)
1562 call *EXT(mach_trap_table)+4(%eax)
1563 /* call procedure */
1564 movl %esp,%ecx /* get kernel stack */
1565 or $(KERNEL_STACK_SIZE-1),%ecx
1566 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
1567 movl %eax,R_EAX(%esp) /* save return value */
1568 jmp EXT(return_from_trap) /* return to user */
1569
1570
1571/*
1572 * Special system call entry for "int 0x80", which has the "eflags"
1573 * register saved at the right place already.
1574 * Fall back to the common syscall path after saving the registers.
1575 *
1576 * esp -> old eip
1577 * old cs
1578 * old eflags
1579 * old esp if trapped from user
1580 * old ss if trapped from user
1581 *
1582 * XXX: for the moment, we don't check for int 0x80 from kernel mode.
1583 */
1584Entry(syscall_int80)
1585 pushl %eax /* save system call number */
1586 pushl $0 /* clear trap number slot */
1587
1588 pusha /* save the general registers */
1589 pushl %ds /* and the segment registers */
1590 pushl %es
1591 pushl %fs
1592 pushl %gs
1593
1594 mov %ss,%dx /* switch to kernel data segment */
1595 mov %dx,%ds
1596 mov %dx,%es
1597 mov $ CPU_DATA,%dx
1598 mov %dx,%gs
1599
1600 jmp syscall_entry_3
1601
1602/*
1603 * System call enters through a call gate. Flags are not saved -
1604 * we must shuffle stack to look like trap save area.
1605 *
1606 * esp-> old eip
1607 * old cs
1608 * old esp
1609 * old ss
1610 *
1611 * eax contains system call number.
1612 *
1613 * NB: below use of CPU_NUMBER assumes that macro will use correct
1614 * correct segment register for any kernel data accesses.
1615 */
1616Entry(syscall)
1617syscall_entry:
1618 pushf /* save flags as soon as possible */
1619syscall_entry_2:
1620 pushl %eax /* save system call number */
1621 pushl $0 /* clear trap number slot */
1622
1623 pusha /* save the general registers */
1624 pushl %ds /* and the segment registers */
1625 pushl %es
1626 pushl %fs
1627 pushl %gs
1628
1629 mov %ss,%dx /* switch to kernel data segment */
1630 mov %dx,%ds
1631 mov %dx,%es
1632 mov $ CPU_DATA,%dx
1633 mov %dx,%gs
1634
1635/*
1636 * Shuffle eflags,eip,cs into proper places
1637 */
1638
1639 movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
1640 movl R_CS(%esp),%ecx /* eip is in CS slot */
1641 movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
1642 movl %ecx,R_EIP(%esp) /* fix eip */
1643 movl %edx,R_CS(%esp) /* fix cs */
1644 movl %ebx,R_EFLAGS(%esp) /* fix eflags */
1645
1646syscall_entry_3:
1647 CPU_NUMBER(%edx)
1648/*
1649 * Check here for syscall from kernel-loaded task --
1650 * We didn't enter here "through" PCB (i.e., using ring 0 stack),
1651 * so transfer the stack frame into the PCB explicitly, then
1652 * start running on resulting "PCB stack". We have to set
1653 * up a simulated "uesp" manually, since there's none in the
1654 * frame.
1655 */
1656 cmpl $0,CX(EXT(active_kloaded),%edx)
1657 jz 0f
1658 CAH(scstart)
1659 movl CX(EXT(active_kloaded),%edx),%ebx
1660 movl CX(EXT(kernel_stack),%edx),%edx
1661 xchgl %edx,%esp
1662 FRAME_STACK_TO_PCB(%ebx,%edx)
1663 CAH(scend)
1664 TIME_TRAP_UENTRY
1665 CPU_NUMBER(%edx)
1666 jmp 1f
1667
16680:
1669 TIME_TRAP_UENTRY
1670
1671 CPU_NUMBER(%edx)
1672 movl CX(EXT(kernel_stack),%edx),%ebx
1673 /* get current kernel stack */
1674 xchgl %ebx,%esp /* switch stacks - %ebx points to */
1675 /* user registers. */
1676 /* user regs pointer already set */
1677
1678/*
1679 * Check for MACH or emulated system call
1680 * Register use (from here till we begin processing call):
1681 * eax contains system call number
1682 * ebx points to user regs
1683 */
16841:
1685 movl $ CPD_ACTIVE_THREAD,%edx
1686 movl %gs:(%edx),%edx /* get active thread */
1687 /* point to current thread */
1688 movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */
1689 movl ACT_TASK(%edx),%edx /* point to task */
1690 movl TASK_EMUL(%edx),%edx /* get emulation vector */
1691 orl %edx,%edx /* if none, */
1692 je syscall_native /* do native system call */
1693 movl %eax,%ecx /* copy system call number */
1694 subl DISP_MIN(%edx),%ecx /* get displacement into syscall */
1695 /* vector table */
1696 jl syscall_native /* too low - native system call */
1697 cmpl DISP_COUNT(%edx),%ecx /* check range */
1698 jnl syscall_native /* too high - native system call */
1699 movl DISP_VECTOR(%edx,%ecx,4),%edx
1700 /* get the emulation vector */
1701 orl %edx,%edx /* emulated system call if not zero */
1702 jnz syscall_emul
1703
1704/*
1705 * Native system call.
1706 * Register use on entry:
1707 * eax contains syscall number
1708 * ebx points to user regs
1709 */
1710syscall_native:
1711 negl %eax /* get system call number */
1712 jl mach_call_range /* out of range if it was positive */
1713
1714 cmpl EXT(mach_trap_count),%eax /* check system call table bounds */
1715 jg mach_call_range /* error if out of range */
1716 shll $4,%eax /* manual indexing */
1717
1718 movl EXT(mach_trap_table)+4(%eax),%edx
1719 /* get procedure */
1720 cmpl $ EXT(kern_invalid),%edx /* if not "kern_invalid" */
1721 jne do_native_call /* go on with Mach syscall */
1722
1723 movl $ CPD_ACTIVE_THREAD,%edx
1724 movl %gs:(%edx),%edx /* get active thread */
1725 /* point to current thread */
1726 movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */
1727 movl ACT_TASK(%edx),%edx /* point to task */
1728 movl TASK_EMUL(%edx),%edx /* get emulation vector */
1729 orl %edx,%edx /* if it exists, */
1730 jne do_native_call /* do native system call */
1731 shrl $4,%eax /* restore syscall number */
1732 jmp mach_call_range /* try it as a "server" syscall */
1733
1734/*
1735 * Register use on entry:
1736 * eax contains syscall number
1737 * ebx contains user regs pointer
1738 */
1739do_native_call:
1740 movl EXT(mach_trap_table)(%eax),%ecx
1741 /* get number of arguments */
1742 jecxz mach_call_call /* skip argument copy if none */
1743 movl R_UESP(%ebx),%esi /* get user stack pointer */
1744 lea 4(%esi,%ecx,4),%esi /* skip user return address, */
1745 /* and point past last argument */
1746 CPU_NUMBER(%edx)
1747 movl CX(EXT(active_kloaded),%edx),%edx
1748 /* point to current thread */
1749 orl %edx,%edx /* if kernel-loaded, skip addr check */
1750 jz 0f /* else */
1751 mov %ds,%dx /* kernel data segment access */
1752 jmp 1f
17530:
1754 cmpl $(VM_MAX_ADDRESS),%esi /* in user space? */
1755 ja mach_call_addr /* address error if not */
1756 movl $ USER_DS,%edx /* user data segment access */
17571:
1758 mov %dx,%fs
1759 movl %esp,%edx /* save kernel ESP for error recovery */
17602:
1761 subl $4,%esi
1762 RECOVERY_SECTION
1763 RECOVER(mach_call_addr_push)
1764 pushl %fs:(%esi) /* push argument on stack */
1765 loop 2b /* loop for all arguments */
1766
1767/*
1768 * Register use on entry:
1769 * eax contains syscall number
1770 * ebx contains user regs pointer
1771 */
1772mach_call_call:
1773
1774 CAH(call_call)
1775
1776#if ETAP_EVENT_MONITOR
1777 cmpl $0x200, %eax /* is this mach_msg? */
1778 jz make_syscall /* if yes, don't record event */
1779
1780 pushal /* Otherwise: save registers */
1781 pushl %eax /* push syscall number on stack*/
1782 call EXT(etap_machcall_probe1) /* call event begin probe */
1783 add $4,%esp /* restore stack */
1784 popal /* restore registers */
1785
1786 call *EXT(mach_trap_table)+4(%eax) /* call procedure */
1787 pushal
1788 call EXT(etap_machcall_probe2) /* call event end probe */
1789 popal
1790 jmp skip_syscall /* syscall already made */
1791#endif /* ETAP_EVENT_MONITOR */
1792
1793make_syscall:
1794 call *EXT(mach_trap_table)+4(%eax) /* call procedure */
1795skip_syscall:
1796
1797 movl %esp,%ecx /* get kernel stack */
1798 or $(KERNEL_STACK_SIZE-1),%ecx
1799 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
1800 movl %eax,R_EAX(%esp) /* save return value */
1801 jmp EXT(return_from_trap) /* return to user */
1802
1803/*
1804 * Address out of range. Change to page fault.
1805 * %esi holds failing address.
1806 * Register use on entry:
1807 * ebx contains user regs pointer
1808 */
1809mach_call_addr_push:
1810 movl %edx,%esp /* clean parameters from stack */
1811mach_call_addr:
1812 movl %esi,R_CR2(%ebx) /* set fault address */
1813 movl $(T_PAGE_FAULT),R_TRAPNO(%ebx)
1814 /* set page-fault trap */
1815 movl $(T_PF_USER),R_ERR(%ebx)
1816 /* set error code - read user space */
1817 CAH(call_addr)
1818 jmp EXT(take_trap) /* treat as a trap */
1819
1820/*
1821 * System call out of range. Treat as invalid-instruction trap.
1822 * (? general protection?)
1823 * Register use on entry:
1824 * eax contains syscall number
1825 */
1826mach_call_range:
1827 movl $ CPD_ACTIVE_THREAD,%edx
1828 movl %gs:(%edx),%edx /* get active thread */
1829
1830 movl TH_TOP_ACT(%edx),%edx /* get thread->top_act */
1831 movl ACT_TASK(%edx),%edx /* point to task */
1832 movl TASK_EMUL(%edx),%edx /* get emulation vector */
1833 orl %edx,%edx /* if emulator, */
1834 jne EXT(syscall_failed) /* handle as illegal instruction */
1835 /* else generate syscall exception: */
1836 push %eax
1837 movl %esp,%edx
1838 push $1 /* code_cnt = 1 */
1839 push %edx /* exception_type_t (see i/f docky) */
1840 push $ EXC_SYSCALL
1841 CAH(call_range)
1842 call EXT(exception)
1843 /* no return */
1844
1845 .globl EXT(syscall_failed)
1846LEXT(syscall_failed)
1847 movl %esp,%ecx /* get kernel stack */
1848 or $(KERNEL_STACK_SIZE-1),%ecx
1849 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
1850 CPU_NUMBER(%edx)
1851 movl CX(EXT(kernel_stack),%edx),%ebx
1852 /* get current kernel stack */
1853 xchgl %ebx,%esp /* switch stacks - %ebx points to */
1854 /* user registers. */
1855 /* user regs pointer already set */
1856
1857 movl $(T_INVALID_OPCODE),R_TRAPNO(%ebx)
1858 /* set invalid-operation trap */
1859 movl $0,R_ERR(%ebx) /* clear error code */
1860 CAH(failed)
1861 jmp EXT(take_trap) /* treat as a trap */
1862
1863/*
1864 * User space emulation of system calls.
1865 * edx - user address to handle syscall
1866 *
1867 * User stack will become:
1868 * uesp-> eflags
1869 * eip
1870 * Register use on entry:
1871 * ebx contains user regs pointer
1872 * edx contains emulator vector address
1873 */
1874syscall_emul:
1875 movl R_UESP(%ebx),%edi /* get user stack pointer */
1876 CPU_NUMBER(%eax)
1877 movl CX(EXT(active_kloaded),%eax),%eax
1878 orl %eax,%eax /* if thread not kernel-loaded, */
1879 jz 0f /* do address checks */
1880 subl $8,%edi
1881 mov %ds,%ax /* kernel data segment access */
1882 jmp 1f /* otherwise, skip them */
18830:
1884 cmpl $(VM_MAX_ADDRESS),%edi /* in user space? */
1885 ja syscall_addr /* address error if not */
1886 subl $8,%edi /* push space for new arguments */
1887 cmpl $(VM_MIN_ADDRESS),%edi /* still in user space? */
1888 jb syscall_addr /* error if not */
1889 movl $ USER_DS,%ax /* user data segment access */
18901:
1891 mov %ax,%fs
1892 movl R_EFLAGS(%ebx),%eax /* move flags */
1893 RECOVERY_SECTION
1894 RECOVER(syscall_addr)
1895 movl %eax,%fs:0(%edi) /* to user stack */
1896 movl R_EIP(%ebx),%eax /* move eip */
1897 RECOVERY_SECTION
1898 RECOVER(syscall_addr)
1899 movl %eax,%fs:4(%edi) /* to user stack */
1900 movl %edi,R_UESP(%ebx) /* set new user stack pointer */
1901 movl %edx,R_EIP(%ebx) /* change return address to trap */
1902 movl %ebx,%esp /* back to PCB stack */
1903 CAH(emul)
1904 jmp EXT(return_from_trap) /* return to user */
1905
1906
1907/*
1908 * Address error - address is in %edi.
1909 * Register use on entry:
1910 * ebx contains user regs pointer
1911 */
1912syscall_addr:
1913 movl %edi,R_CR2(%ebx) /* set fault address */
1914 movl $(T_PAGE_FAULT),R_TRAPNO(%ebx)
1915 /* set page-fault trap */
1916 movl $(T_PF_USER),R_ERR(%ebx)
1917 /* set error code - read user space */
1918 CAH(addr)
1919 jmp EXT(take_trap) /* treat as a trap */
1920
1921/*\f*/
1922/*
1923 * Utility routines.
1924 */
1925
1926
1927/*
1928 * Copy from user address space.
1929 * arg0: user address
1930 * arg1: kernel address
1931 * arg2: byte count
1932 */
1933Entry(copyinmsg)
1934ENTRY(copyin)
1935 pushl %esi
1936 pushl %edi /* save registers */
1937
1938 movl 8+S_ARG0,%esi /* get user start address */
1939 movl 8+S_ARG1,%edi /* get kernel destination address */
1940 movl 8+S_ARG2,%edx /* get count */
1941
1942 lea 0(%esi,%edx),%eax /* get user end address + 1 */
1943
1944 movl $ CPD_ACTIVE_THREAD,%ecx
1945 movl %gs:(%ecx),%ecx /* get active thread */
1946 movl TH_TOP_ACT(%ecx),%ecx /* get thread->top_act */
1947 movl ACT_MAP(%ecx),%ecx /* get act->map */
1948 movl MAP_PMAP(%ecx),%ecx /* get map->pmap */
1949 cmpl EXT(kernel_pmap), %ecx
1950 jz 1f
1951 movl $ USER_DS,%cx /* user data segment access */
1952 mov %cx,%ds
19531:
1954 cmpl %esi,%eax
1955 jb copyin_fail /* fail if wrap-around */
1956 cld /* count up */
1957 movl %edx,%ecx /* move by longwords first */
1958 shrl $2,%ecx
1959 RECOVERY_SECTION
1960 RECOVER(copyin_fail)
1961 rep
1962 movsl /* move longwords */
1963 movl %edx,%ecx /* now move remaining bytes */
1964 andl $3,%ecx
1965 RECOVERY_SECTION
1966 RECOVER(copyin_fail)
1967 rep
1968 movsb
1969 xorl %eax,%eax /* return 0 for success */
1970copy_ret:
1971 mov %ss,%di /* restore kernel data segment */
1972 mov %di,%ds
1973
1974 popl %edi /* restore registers */
1975 popl %esi
1976 ret /* and return */
1977
1978copyin_fail:
1979 movl $ EFAULT,%eax /* return error for failure */
1980 jmp copy_ret /* pop frame and return */
1981
1982/*
1983 * Copy string from user address space.
1984 * arg0: user address
1985 * arg1: kernel address
1986 * arg2: max byte count
1987 * arg3: actual byte count (OUT)
1988 */
1989Entry(copyinstr)
1990 pushl %esi
1991 pushl %edi /* save registers */
1992
1993 movl 8+S_ARG0,%esi /* get user start address */
1994 movl 8+S_ARG1,%edi /* get kernel destination address */
1995 movl 8+S_ARG2,%edx /* get count */
1996
1997 lea 0(%esi,%edx),%eax /* get user end address + 1 */
1998
1999 movl $ CPD_ACTIVE_THREAD,%ecx
2000 movl %gs:(%ecx),%ecx /* get active thread */
2001 movl TH_TOP_ACT(%ecx),%ecx /* get thread->top_act */
2002 movl ACT_MAP(%ecx),%ecx /* get act->map */
2003 movl MAP_PMAP(%ecx),%ecx /* get map->pmap */
2004 cmpl EXT(kernel_pmap), %ecx
2005 jne 0f
2006 mov %ds,%cx /* kernel data segment access */
2007 jmp 1f
20080:
2009 movl $ USER_DS,%cx /* user data segment access */
20101:
2011 mov %cx,%fs
2012 xorl %eax,%eax
2013 cmpl $0,%edx
2014 je 4f
20152:
2016 RECOVERY_SECTION
2017 RECOVER(copystr_fail) /* copy bytes... */
2018 movb %fs:(%esi),%eax
2019 incl %esi
2020 testl %edi,%edi /* if kernel address is ... */
2021 jz 3f /* not NULL */
2022 movb %eax,(%edi) /* copy the byte */
2023 incl %edi
20243:
2025 decl %edx
2026 je 5f /* Zero count.. error out */
2027 cmpl $0,%eax
2028 jne 2b /* .. a NUL found? */
2029 jmp 4f
20305:
2031 movl $ ENAMETOOLONG,%eax /* String is too long.. */
20324:
2033 xorl %eax,%eax /* return zero for success */
2034 movl 8+S_ARG3,%edi /* get OUT len ptr */
2035 cmpl $0,%edi
2036 jz copystr_ret /* if null, just return */
2037 subl 8+S_ARG0,%esi
2038 movl %esi,(%edi) /* else set OUT arg to xfer len */
2039copystr_ret:
2040 popl %edi /* restore registers */
2041 popl %esi
2042 ret /* and return */
2043
2044copystr_fail:
2045 movl $ EFAULT,%eax /* return error for failure */
2046 jmp copy_ret /* pop frame and return */
2047
2048/*
2049 * Copy to user address space.
2050 * arg0: kernel address
2051 * arg1: user address
2052 * arg2: byte count
2053 */
2054Entry(copyoutmsg)
2055ENTRY(copyout)
2056 pushl %esi
2057 pushl %edi /* save registers */
2058 pushl %ebx
2059
2060 movl 12+S_ARG0,%esi /* get kernel start address */
2061 movl 12+S_ARG1,%edi /* get user start address */
2062 movl 12+S_ARG2,%edx /* get count */
2063
2064 leal 0(%edi,%edx),%eax /* get user end address + 1 */
2065
2066 movl $ CPD_ACTIVE_THREAD,%ecx
2067 movl %gs:(%ecx),%ecx /* get active thread */
2068 movl TH_TOP_ACT(%ecx),%ecx /* get thread->top_act */
2069 movl ACT_MAP(%ecx),%ecx /* get act->map */
2070 movl MAP_PMAP(%ecx),%ecx /* get map->pmap */
2071 cmpl EXT(kernel_pmap), %ecx
2072 jne 0f
2073 mov %ds,%cx /* else kernel data segment access */
2074 jmp 1f
20750:
2076 movl $ USER_DS,%cx
20771:
2078 mov %cx,%es
2079
2080/*
2081 * Check whether user address space is writable
2082 * before writing to it - hardware is broken.
2083 *
2084 * Skip check if "user" address is really in
2085 * kernel space (i.e., if it's in a kernel-loaded
2086 * task).
2087 *
2088 * Register usage:
2089 * esi/edi source/dest pointers for rep/mov
2090 * ecx counter for rep/mov
2091 * edx counts down from 3rd arg
2092 * eax count of bytes for each (partial) page copy
2093 * ebx shadows edi, used to adjust edx
2094 */
2095 movl %edi,%ebx /* copy edi for syncing up */
2096copyout_retry:
2097 /* if restarting after a partial copy, put edx back in sync, */
2098 addl %ebx,%edx /* edx -= (edi - ebx); */
2099 subl %edi,%edx /
2100 movl %edi,%ebx /* ebx = edi; */
2101
2102 mov %es,%cx
2103 cmpl $ USER_DS,%cx /* If kernel data segment */
2104 jnz 0f /* skip check */
2105
2106 cmpb $(CPUID_FAMILY_386), EXT(cpuid_family)
2107 ja 0f
2108
2109 movl %cr3,%ecx /* point to page directory */
2110#if NCPUS > 1
2111 andl $(~0x7), %ecx /* remove cpu number */
2112#endif /* NCPUS > 1 && AT386 */
2113 movl %edi,%eax /* get page directory bits */
2114 shrl $(PDESHIFT),%eax /* from user address */
2115 movl KERNELBASE(%ecx,%eax,4),%ecx
2116 /* get page directory pointer */
2117 testl $(PTE_V),%ecx /* present? */
2118 jz 0f /* if not, fault is OK */
2119 andl $(PTE_PFN),%ecx /* isolate page frame address */
2120 movl %edi,%eax /* get page table bits */
2121 shrl $(PTESHIFT),%eax
2122 andl $(PTEMASK),%eax /* from user address */
2123 leal KERNELBASE(%ecx,%eax,4),%ecx
2124 /* point to page table entry */
2125 movl (%ecx),%eax /* get it */
2126 testl $(PTE_V),%eax /* present? */
2127 jz 0f /* if not, fault is OK */
2128 testl $(PTE_W),%eax /* writable? */
2129 jnz 0f /* OK if so */
2130/*
2131 * Not writable - must fake a fault. Turn off access to the page.
2132 */
2133 andl $(PTE_INVALID),(%ecx) /* turn off valid bit */
2134 movl %cr3,%eax /* invalidate TLB */
2135 movl %eax,%cr3
21360:
2137/*
2138 * Copy only what fits on the current destination page.
2139 * Check for write-fault again on the next page.
2140 */
2141 leal NBPG(%edi),%eax /* point to */
2142 andl $(-NBPG),%eax /* start of next page */
2143 subl %edi,%eax /* get number of bytes to that point */
2144 cmpl %edx,%eax /* bigger than count? */
2145 jle 1f /* if so, */
2146 movl %edx,%eax /* use count */
21471:
2148 cld /* count up */
2149 movl %eax,%ecx /* move by longwords first */
2150 shrl $2,%ecx
2151 RECOVERY_SECTION
2152 RECOVER(copyout_fail)
2153 RETRY_SECTION
2154 RETRY(copyout_retry)
2155 rep
2156 movsl
2157 movl %eax,%ecx /* now move remaining bytes */
2158 andl $3,%ecx
2159 RECOVERY_SECTION
2160 RECOVER(copyout_fail)
2161 RETRY_SECTION
2162 RETRY(copyout_retry)
2163 rep
2164 movsb /* move */
2165 movl %edi,%ebx /* copy edi for syncing up */
2166 subl %eax,%edx /* and decrement count */
2167 jg copyout_retry /* restart on next page if not done */
2168 xorl %eax,%eax /* return 0 for success */
2169copyout_ret:
2170 mov %ss,%di /* restore kernel segment */
2171 mov %di,%es
2172
2173 popl %ebx
2174 popl %edi /* restore registers */
2175 popl %esi
2176 ret /* and return */
2177
2178copyout_fail:
2179 movl $ EFAULT,%eax /* return error for failure */
2180 jmp copyout_ret /* pop frame and return */
2181
2182/*
2183 * FPU routines.
2184 */
2185
2186/*
2187 * Initialize FPU.
2188 */
2189ENTRY(_fninit)
2190 fninit
2191 ret
2192
2193/*
2194 * Read control word
2195 */
2196ENTRY(_fstcw)
2197 pushl %eax /* get stack space */
2198 fstcw (%esp)
2199 popl %eax
2200 ret
2201
2202/*
2203 * Set control word
2204 */
2205ENTRY(_fldcw)
2206 fldcw 4(%esp)
2207 ret
2208
2209/*
2210 * Read status word
2211 */
2212ENTRY(_fnstsw)
2213 xor %eax,%eax /* clear high 16 bits of eax */
2214 fnstsw %ax /* read FP status */
2215 ret
2216
2217/*
2218 * Clear FPU exceptions
2219 */
2220ENTRY(_fnclex)
2221 fnclex
2222 ret
2223
2224/*
2225 * Clear task-switched flag.
2226 */
2227ENTRY(_clts)
2228 clts
2229 ret
2230
2231/*
2232 * Save complete FPU state. Save error for later.
2233 */
2234ENTRY(_fpsave)
2235 movl 4(%esp),%eax /* get save area pointer */
2236 fnsave (%eax) /* save complete state, including */
2237 /* errors */
2238 ret
2239
2240/*
2241 * Restore FPU state.
2242 */
2243ENTRY(_fprestore)
2244 movl 4(%esp),%eax /* get save area pointer */
2245 frstor (%eax) /* restore complete state */
2246 ret
2247
2248/*
2249 * Set cr3
2250 */
2251ENTRY(set_cr3)
2252#if NCPUS > 1
2253 CPU_NUMBER(%eax)
2254 orl 4(%esp), %eax
2255#else /* NCPUS > 1 && AT386 */
2256 movl 4(%esp),%eax /* get new cr3 value */
2257#endif /* NCPUS > 1 && AT386 */
2258 /*
2259 * Don't set PDBR to a new value (hence invalidating the
2260 * "paging cache") if the new value matches the current one.
2261 */
2262 movl %cr3,%edx /* get current cr3 value */
2263 cmpl %eax,%edx
2264 je 0f /* if two are equal, don't set */
2265 movl %eax,%cr3 /* load it (and flush cache) */
22660:
2267 ret
2268
2269/*
2270 * Read cr3
2271 */
2272ENTRY(get_cr3)
2273 movl %cr3,%eax
2274#if NCPUS > 1
2275 andl $(~0x7), %eax /* remove cpu number */
2276#endif /* NCPUS > 1 && AT386 */
2277 ret
2278
2279/*
2280 * Flush TLB
2281 */
2282ENTRY(flush_tlb)
2283 movl %cr3,%eax /* flush tlb by reloading CR3 */
2284 movl %eax,%cr3 /* with itself */
2285 ret
2286
2287/*
2288 * Read cr2
2289 */
2290ENTRY(get_cr2)
2291 movl %cr2,%eax
2292 ret
2293
2294/*
2295 * Read cr4
2296 */
2297ENTRY(get_cr4)
2298 .byte 0x0f,0x20,0xe0 /* movl %cr4, %eax */
2299 ret
2300
2301/*
2302 * Write cr4
2303 */
2304ENTRY(set_cr4)
2305 movl 4(%esp), %eax
2306 .byte 0x0f,0x22,0xe0 /* movl %eax, %cr4 */
2307 ret
2308
2309/*
2310 * Read ldtr
2311 */
2312Entry(get_ldt)
2313 xorl %eax,%eax
2314 sldt %ax
2315 ret
2316
2317/*
2318 * Set ldtr
2319 */
2320Entry(set_ldt)
2321 lldt 4(%esp)
2322 ret
2323
2324/*
2325 * Read task register.
2326 */
2327ENTRY(get_tr)
2328 xorl %eax,%eax
2329 str %ax
2330 ret
2331
2332/*
2333 * Set task register. Also clears busy bit of task descriptor.
2334 */
2335ENTRY(set_tr)
2336 movl S_ARG0,%eax /* get task segment number */
2337 subl $8,%esp /* push space for SGDT */
2338 sgdt 2(%esp) /* store GDT limit and base (linear) */
2339 movl 4(%esp),%edx /* address GDT */
2340 movb $(K_TSS),5(%edx,%eax) /* fix access byte in task descriptor */
2341 ltr %ax /* load task register */
2342 addl $8,%esp /* clear stack */
2343 ret /* and return */
2344
2345/*
2346 * Set task-switched flag.
2347 */
2348ENTRY(_setts)
2349 movl %cr0,%eax /* get cr0 */
2350 orl $(CR0_TS),%eax /* or in TS bit */
2351 movl %eax,%cr0 /* set cr0 */
2352 ret
2353
2354/*
2355 * io register must not be used on slaves (no AT bus)
2356 */
2357#define ILL_ON_SLAVE
2358
2359
2360#if MACH_ASSERT
2361
2362#define ARG0 B_ARG0
2363#define ARG1 B_ARG1
2364#define ARG2 B_ARG2
2365#define PUSH_FRAME FRAME
2366#define POP_FRAME EMARF
2367
2368#else /* MACH_ASSERT */
2369
2370#define ARG0 S_ARG0
2371#define ARG1 S_ARG1
2372#define ARG2 S_ARG2
2373#define PUSH_FRAME
2374#define POP_FRAME
2375
2376#endif /* MACH_ASSERT */
2377
2378
2379#if MACH_KDB || MACH_ASSERT
2380
2381/*
2382 * Following routines are also defined as macros in i386/pio.h
2383 * Compile then when MACH_KDB is configured so that they
2384 * can be invoked from the debugger.
2385 */
2386
2387/*
2388 * void outb(unsigned char *io_port,
2389 * unsigned char byte)
2390 *
2391 * Output a byte to an IO port.
2392 */
2393ENTRY(outb)
2394 PUSH_FRAME
2395 ILL_ON_SLAVE
2396 movl ARG0,%edx /* IO port address */
2397 movl ARG1,%eax /* data to output */
2398 outb %al,%dx /* send it out */
2399 POP_FRAME
2400 ret
2401
2402/*
2403 * unsigned char inb(unsigned char *io_port)
2404 *
2405 * Input a byte from an IO port.
2406 */
2407ENTRY(inb)
2408 PUSH_FRAME
2409 ILL_ON_SLAVE
2410 movl ARG0,%edx /* IO port address */
2411 xor %eax,%eax /* clear high bits of register */
2412 inb %dx,%al /* get the byte */
2413 POP_FRAME
2414 ret
2415
2416/*
2417 * void outw(unsigned short *io_port,
2418 * unsigned short word)
2419 *
2420 * Output a word to an IO port.
2421 */
2422ENTRY(outw)
2423 PUSH_FRAME
2424 ILL_ON_SLAVE
2425 movl ARG0,%edx /* IO port address */
2426 movl ARG1,%eax /* data to output */
2427 outw %ax,%dx /* send it out */
2428 POP_FRAME
2429 ret
2430
2431/*
2432 * unsigned short inw(unsigned short *io_port)
2433 *
2434 * Input a word from an IO port.
2435 */
2436ENTRY(inw)
2437 PUSH_FRAME
2438 ILL_ON_SLAVE
2439 movl ARG0,%edx /* IO port address */
2440 xor %eax,%eax /* clear high bits of register */
2441 inw %dx,%ax /* get the word */
2442 POP_FRAME
2443 ret
2444
2445/*
2446 * void outl(unsigned int *io_port,
2447 * unsigned int byte)
2448 *
2449 * Output an int to an IO port.
2450 */
2451ENTRY(outl)
2452 PUSH_FRAME
2453 ILL_ON_SLAVE
2454 movl ARG0,%edx /* IO port address*/
2455 movl ARG1,%eax /* data to output */
2456 outl %eax,%dx /* send it out */
2457 POP_FRAME
2458 ret
2459
2460/*
2461 * unsigned int inl(unsigned int *io_port)
2462 *
2463 * Input an int from an IO port.
2464 */
2465ENTRY(inl)
2466 PUSH_FRAME
2467 ILL_ON_SLAVE
2468 movl ARG0,%edx /* IO port address */
2469 inl %dx,%eax /* get the int */
2470 POP_FRAME
2471 ret
2472
2473#endif /* MACH_KDB || MACH_ASSERT*/
2474
2475/*
2476 * void loutb(unsigned byte *io_port,
2477 * unsigned byte *data,
2478 * unsigned int count)
2479 *
2480 * Output an array of bytes to an IO port.
2481 */
2482ENTRY(loutb)
2483ENTRY(outsb)
2484 PUSH_FRAME
2485 ILL_ON_SLAVE
2486 movl %esi,%eax /* save register */
2487 movl ARG0,%edx /* get io port number */
2488 movl ARG1,%esi /* get data address */
2489 movl ARG2,%ecx /* get count */
2490 cld /* count up */
2491 rep
2492 outsb /* output */
2493 movl %eax,%esi /* restore register */
2494 POP_FRAME
2495 ret
2496
2497
2498/*
2499 * void loutw(unsigned short *io_port,
2500 * unsigned short *data,
2501 * unsigned int count)
2502 *
2503 * Output an array of shorts to an IO port.
2504 */
2505ENTRY(loutw)
2506ENTRY(outsw)
2507 PUSH_FRAME
2508 ILL_ON_SLAVE
2509 movl %esi,%eax /* save register */
2510 movl ARG0,%edx /* get io port number */
2511 movl ARG1,%esi /* get data address */
2512 movl ARG2,%ecx /* get count */
2513 cld /* count up */
2514 rep
2515 outsw /* output */
2516 movl %eax,%esi /* restore register */
2517 POP_FRAME
2518 ret
2519
2520/*
2521 * void loutw(unsigned short io_port,
2522 * unsigned int *data,
2523 * unsigned int count)
2524 *
2525 * Output an array of longs to an IO port.
2526 */
2527ENTRY(loutl)
2528ENTRY(outsl)
2529 PUSH_FRAME
2530 ILL_ON_SLAVE
2531 movl %esi,%eax /* save register */
2532 movl ARG0,%edx /* get io port number */
2533 movl ARG1,%esi /* get data address */
2534 movl ARG2,%ecx /* get count */
2535 cld /* count up */
2536 rep
2537 outsl /* output */
2538 movl %eax,%esi /* restore register */
2539 POP_FRAME
2540 ret
2541
2542
2543/*
2544 * void linb(unsigned char *io_port,
2545 * unsigned char *data,
2546 * unsigned int count)
2547 *
2548 * Input an array of bytes from an IO port.
2549 */
2550ENTRY(linb)
2551ENTRY(insb)
2552 PUSH_FRAME
2553 ILL_ON_SLAVE
2554 movl %edi,%eax /* save register */
2555 movl ARG0,%edx /* get io port number */
2556 movl ARG1,%edi /* get data address */
2557 movl ARG2,%ecx /* get count */
2558 cld /* count up */
2559 rep
2560 insb /* input */
2561 movl %eax,%edi /* restore register */
2562 POP_FRAME
2563 ret
2564
2565
2566/*
2567 * void linw(unsigned short *io_port,
2568 * unsigned short *data,
2569 * unsigned int count)
2570 *
2571 * Input an array of shorts from an IO port.
2572 */
2573ENTRY(linw)
2574ENTRY(insw)
2575 PUSH_FRAME
2576 ILL_ON_SLAVE
2577 movl %edi,%eax /* save register */
2578 movl ARG0,%edx /* get io port number */
2579 movl ARG1,%edi /* get data address */
2580 movl ARG2,%ecx /* get count */
2581 cld /* count up */
2582 rep
2583 insw /* input */
2584 movl %eax,%edi /* restore register */
2585 POP_FRAME
2586 ret
2587
2588
2589/*
2590 * void linl(unsigned short io_port,
2591 * unsigned int *data,
2592 * unsigned int count)
2593 *
2594 * Input an array of longs from an IO port.
2595 */
2596ENTRY(linl)
2597ENTRY(insl)
2598 PUSH_FRAME
2599 ILL_ON_SLAVE
2600 movl %edi,%eax /* save register */
2601 movl ARG0,%edx /* get io port number */
2602 movl ARG1,%edi /* get data address */
2603 movl ARG2,%ecx /* get count */
2604 cld /* count up */
2605 rep
2606 insl /* input */
2607 movl %eax,%edi /* restore register */
2608 POP_FRAME
2609 ret
2610
2611
2612/*
2613 * int inst_fetch(int eip, int cs);
2614 *
2615 * Fetch instruction byte. Return -1 if invalid address.
2616 */
2617 .globl EXT(inst_fetch)
2618LEXT(inst_fetch)
2619 movl S_ARG1, %eax /* get segment */
2620 movw %ax,%fs /* into FS */
2621 movl S_ARG0, %eax /* get offset */
2622 RETRY_SECTION
2623 RETRY(EXT(inst_fetch)) /* re-load FS on retry */
2624 RECOVERY_SECTION
2625 RECOVER(EXT(inst_fetch_fault))
2626 movzbl %fs:(%eax),%eax /* load instruction byte */
2627 ret
2628
2629LEXT(inst_fetch_fault)
2630 movl $-1,%eax /* return -1 if error */
2631 ret
2632
2633
2634#if MACH_KDP
2635/*
2636 * kdp_copy_kmem(char *src, char *dst, int count)
2637 *
2638 * Similar to copyin except that both addresses are kernel addresses.
2639 */
2640
2641ENTRY(kdp_copy_kmem)
2642 pushl %esi
2643 pushl %edi /* save registers */
2644
2645 movl 8+S_ARG0,%esi /* get kernel start address */
2646 movl 8+S_ARG1,%edi /* get kernel destination address */
2647
2648 movl 8+S_ARG2,%edx /* get count */
2649
2650 lea 0(%esi,%edx),%eax /* get kernel end address + 1 */
2651
2652 cmpl %esi,%eax
2653 jb kdp_vm_read_fail /* fail if wrap-around */
2654 cld /* count up */
2655 movl %edx,%ecx /* move by longwords first */
2656 shrl $2,%ecx
2657 RECOVERY_SECTION
2658 RECOVER(kdp_vm_read_fail)
2659 rep
2660 movsl /* move longwords */
2661 movl %edx,%ecx /* now move remaining bytes */
2662 andl $3,%ecx
2663 RECOVERY_SECTION
2664 RECOVER(kdp_vm_read_fail)
2665 rep
2666 movsb
2667kdp_vm_read_done:
2668 movl 8+S_ARG2,%edx /* get count */
2669 subl %ecx,%edx /* Return number of bytes transfered */
2670 movl %edx,%eax
2671
2672 popl %edi /* restore registers */
2673 popl %esi
2674 ret /* and return */
2675
2676kdp_vm_read_fail:
2677 xorl %eax,%eax /* didn't copy a thing. */
2678
2679 popl %edi
2680 popl %esi
2681 ret
2682#endif
2683
2684
2685/*
2686 * Done with recovery and retry tables.
2687 */
2688 RECOVERY_SECTION
2689 RECOVER_TABLE_END
2690 RETRY_SECTION
2691 RETRY_TABLE_END
2692
2693
2694
2695ENTRY(dr6)
2696 movl %db6, %eax
2697 ret
2698
2699/* dr<i>(address, type, len, persistence)
2700 */
2701ENTRY(dr0)
2702 movl S_ARG0, %eax
2703 movl %eax,EXT(dr_addr)
2704 movl %eax, %db0
2705 movl $0, %ecx
2706 jmp 0f
2707ENTRY(dr1)
2708 movl S_ARG0, %eax
2709 movl %eax,EXT(dr_addr)+1*4
2710 movl %eax, %db1
2711 movl $2, %ecx
2712 jmp 0f
2713ENTRY(dr2)
2714 movl S_ARG0, %eax
2715 movl %eax,EXT(dr_addr)+2*4
2716 movl %eax, %db2
2717 movl $4, %ecx
2718 jmp 0f
2719
2720ENTRY(dr3)
2721 movl S_ARG0, %eax
2722 movl %eax,EXT(dr_addr)+3*4
2723 movl %eax, %db3
2724 movl $6, %ecx
2725
27260:
2727 pushl %ebp
2728 movl %esp, %ebp
2729
2730 movl %db7, %edx
2731 movl %edx,EXT(dr_addr)+4*4
2732 andl dr_msk(,%ecx,2),%edx /* clear out new entry */
2733 movl %edx,EXT(dr_addr)+5*4
2734 movzbl B_ARG3, %eax
2735 andb $3, %al
2736 shll %cl, %eax
2737 orl %eax, %edx
2738
2739 movzbl B_ARG1, %eax
2740 andb $3, %al
2741 addb $0x10, %ecx
2742 shll %cl, %eax
2743 orl %eax, %edx
2744
2745 movzbl B_ARG2, %eax
2746 andb $3, %al
2747 addb $0x2, %ecx
2748 shll %cl, %eax
2749 orl %eax, %edx
2750
2751 movl %edx, %db7
2752 movl %edx,EXT(dr_addr)+7*4
2753 movl %edx, %eax
2754 leave
2755 ret
2756
2757 .data
2758
2759DATA(preemptable) /* Not on an MP (makes cpu_number() usage unsafe) */
2760#if MACH_RT && (NCPUS == 1)
2761 .long 0 /* FIXME -- Currently disabled */
2762#else
2763 .long 0 /* FIX ME -- Currently disabled */
2764#endif /* MACH_RT && (NCPUS == 1) */
2765
2766dr_msk:
2767 .long ~0x000f0003
2768 .long ~0x00f0000c
2769 .long ~0x0f000030
2770 .long ~0xf00000c0
2771ENTRY(dr_addr)
2772 .long 0,0,0,0
2773 .long 0,0,0,0
2774 .text
2775
2776/*
2777 * Determine cpu model and set global cpuid_xxx variables
2778 *
2779 * Relies on 386 eflags bit 18 (AC) always being zero & 486 preserving it.
2780 * Relies on 486 eflags bit 21 (ID) always being zero & 586 preserving it.
2781 * Relies on CPUID instruction for next x86 generations
2782 * (assumes cpuid-family-homogenous MPs; else convert to per-cpu array)
2783 */
2784
2785ENTRY(set_cpu_model)
2786 FRAME
2787 pushl %ebx /* save ebx */
2788 andl $~0x3,%esp /* Align stack to avoid AC fault */
2789 pushfl /* push EFLAGS */
2790 popl %eax /* pop into eax */
2791 movl %eax,%ecx /* Save original EFLAGS */
2792 xorl $(EFL_AC+EFL_ID),%eax /* toggle ID,AC bits */
2793 pushl %eax /* push new value */
2794 popfl /* through the EFLAGS register */
2795 pushfl /* and back */
2796 popl %eax /* into eax */
2797 movb $(CPUID_FAMILY_386),EXT(cpuid_family)
2798 pushl %ecx /* push original EFLAGS */
2799 popfl /* restore EFLAGS */
2800 xorl %ecx,%eax /* see what changed */
2801 testl $ EFL_AC,%eax /* test AC bit */
2802 jz 0f /* if AC toggled (486 or higher) */
2803
2804 movb $(CPUID_FAMILY_486),EXT(cpuid_family)
2805 testl $ EFL_ID,%eax /* test ID bit */
2806 jz 0f /* if ID toggled use cpuid instruction */
2807
2808 xorl %eax,%eax /* get vendor identification string */
2809 .word 0xA20F /* cpuid instruction */
2810 movl %eax,EXT(cpuid_value) /* Store high value */
2811 movl %ebx,EXT(cpuid_vid) /* Store byte 0-3 of Vendor ID */
2812 movl %edx,EXT(cpuid_vid)+4 /* Store byte 4-7 of Vendor ID */
2813 movl %ecx,EXT(cpuid_vid)+8 /* Store byte 8-B of Vendor ID */
2814 movl $1,%eax /* get processor signature */
2815 .word 0xA20F /* cpuid instruction */
2816 movl %edx,EXT(cpuid_feature) /* Store feature flags */
2817 movl %eax,%ecx /* Save original signature */
2818 andb $0xF,%al /* Get Stepping ID */
2819 movb %al,EXT(cpuid_stepping) /* Save Stepping ID */
2820 movl %ecx,%eax /* Get original signature */
2821 shrl $4,%eax /* Shift Stepping ID */
2822 movl %eax,%ecx /* Save original signature */
2823 andb $0xF,%al /* Get Model */
2824 movb %al,EXT(cpuid_model) /* Save Model */
2825 movl %ecx,%eax /* Get original signature */
2826 shrl $4,%eax /* Shift Stepping ID */
2827 movl %eax,%ecx /* Save original signature */
2828 andb $0xF,%al /* Get Family */
2829 movb %al,EXT(cpuid_family) /* Save Family */
2830 movl %ecx,%eax /* Get original signature */
2831 shrl $4,%eax /* Shift Stepping ID */
2832 andb $0x3,%al /* Get Type */
2833 movb %al,EXT(cpuid_type) /* Save Type */
2834
2835 movl EXT(cpuid_value),%eax /* Get high value */
2836 cmpl $2,%eax /* Test if processor configuration */
2837 jle 0f /* is present */
2838 movl $2,%eax /* get processor configuration */
2839 .word 0xA20F /* cpuid instruction */
2840 movl %eax,EXT(cpuid_cache) /* Store byte 0-3 of configuration */
2841 movl %ebx,EXT(cpuid_cache)+4 /* Store byte 4-7 of configuration */
2842 movl %ecx,EXT(cpuid_cache)+8 /* Store byte 8-B of configuration */
2843 movl %edx,EXT(cpuid_cache)+12 /* Store byte C-F of configuration */
28440:
2845 popl %ebx /* restore ebx */
2846 EMARF
2847 ret /* return */
2848
2849ENTRY(get_cr0)
2850 movl %cr0, %eax
2851 ret
2852
2853ENTRY(set_cr0)
2854 movl 4(%esp), %eax
2855 movl %eax, %cr0
2856 ret
2857
2858#ifndef SYMMETRY
2859
2860/*
2861 * ffs(mask)
2862 */
2863ENTRY(ffs)
2864 bsfl S_ARG0, %eax
2865 jz 0f
2866 incl %eax
2867 ret
28680: xorl %eax, %eax
2869 ret
2870
2871/*
2872 * cpu_shutdown()
2873 * Force reboot
2874 */
2875
2876null_idtr:
2877 .word 0
2878 .long 0
2879
2880Entry(cpu_shutdown)
2881 lidt null_idtr /* disable the interrupt handler */
2882 xor %ecx,%ecx /* generate a divide by zero */
2883 div %ecx,%eax /* reboot now */
2884 ret /* this will "never" be executed */
2885
2886#endif /* SYMMETRY */
2887
2888
2889/*
2890 * setbit(int bitno, int *s) - set bit in bit string
2891 */
2892ENTRY(setbit)
2893 movl S_ARG0, %ecx /* bit number */
2894 movl S_ARG1, %eax /* address */
2895 btsl %ecx, (%eax) /* set bit */
2896 ret
2897
2898/*
2899 * clrbit(int bitno, int *s) - clear bit in bit string
2900 */
2901ENTRY(clrbit)
2902 movl S_ARG0, %ecx /* bit number */
2903 movl S_ARG1, %eax /* address */
2904 btrl %ecx, (%eax) /* clear bit */
2905 ret
2906
2907/*
2908 * ffsbit(int *s) - find first set bit in bit string
2909 */
2910ENTRY(ffsbit)
2911 movl S_ARG0, %ecx /* address */
2912 movl $0, %edx /* base offset */
29130:
2914 bsfl (%ecx), %eax /* check argument bits */
2915 jnz 1f /* found bit, return */
2916 addl $4, %ecx /* increment address */
2917 addl $32, %edx /* increment offset */
2918 jmp 0b /* try again */
29191:
2920 addl %edx, %eax /* return offset */
2921 ret
2922
2923/*
2924 * testbit(int nr, volatile void *array)
2925 *
2926 * Test to see if the bit is set within the bit string
2927 */
2928
2929ENTRY(testbit)
2930 movl S_ARG0,%eax /* Get the bit to test */
2931 movl S_ARG1,%ecx /* get the array string */
2932 btl %eax,(%ecx)
2933 sbbl %eax,%eax
2934 ret
2935
2936ENTRY(get_pc)
2937 movl 4(%ebp),%eax
2938 ret
2939
2940#if ETAP
2941
2942ENTRY(etap_get_pc)
2943 movl 4(%ebp), %eax /* fetch pc of caller */
2944 ret
2945
2946ENTRY(tvals_to_etap)
2947 movl S_ARG0, %eax
2948 movl $1000000000, %ecx
2949 mull %ecx
2950 addl S_ARG1, %eax
2951 adc $0, %edx
2952 ret
2953
2954/* etap_time_t
2955 * etap_time_sub(etap_time_t stop, etap_time_t start)
2956 *
2957 * 64bit subtract, returns stop - start
2958 */
2959ENTRY(etap_time_sub)
2960 movl S_ARG0, %eax /* stop.low */
2961 movl S_ARG1, %edx /* stop.hi */
2962 subl S_ARG2, %eax /* stop.lo - start.lo */
2963 sbbl S_ARG3, %edx /* stop.hi - start.hi */
2964 ret
2965
2966#endif /* ETAP */
2967
2968#if NCPUS > 1
2969
2970ENTRY(minsecurity)
2971 pushl %ebp
2972 movl %esp,%ebp
2973/*
2974 * jail: set the EIP to "jail" to block a kernel thread.
2975 * Useful to debug synchronization problems on MPs.
2976 */
2977ENTRY(jail)
2978 jmp EXT(jail)
2979
2980#endif /* NCPUS > 1 */
2981
2982/*
2983 * delay(microseconds)
2984 */
2985
2986ENTRY(delay)
2987 movl 4(%esp),%eax
2988 testl %eax, %eax
2989 jle 3f
2990 movl EXT(delaycount), %ecx
29911:
2992 movl %ecx, %edx
29932:
2994 decl %edx
2995 jne 2b
2996 decl %eax
2997 jne 1b
29983:
2999 ret
3000
3001/*
3002 * unsigned int
3003 * div_scale(unsigned int dividend,
3004 * unsigned int divisor,
3005 * unsigned int *scale)
3006 *
3007 * This function returns (dividend << *scale) //divisor where *scale
3008 * is the largest possible value before overflow. This is used in
3009 * computation where precision must be achieved in order to avoid
3010 * floating point usage.
3011 *
3012 * Algorithm:
3013 * *scale = 0;
3014 * while (((dividend >> *scale) >= divisor))
3015 * (*scale)++;
3016 * *scale = 32 - *scale;
3017 * return ((dividend << *scale) / divisor);
3018 */
3019ENTRY(div_scale)
3020 PUSH_FRAME
3021 xorl %ecx, %ecx /* *scale = 0 */
3022 xorl %eax, %eax
3023 movl ARG0, %edx /* get dividend */
30240:
3025 cmpl ARG1, %edx /* if (divisor > dividend) */
3026 jle 1f /* goto 1f */
3027 addl $1, %ecx /* (*scale)++ */
3028 shrdl $1, %edx, %eax /* dividend >> 1 */
3029 shrl $1, %edx /* dividend >> 1 */
3030 jmp 0b /* goto 0b */
30311:
3032 divl ARG1 /* (dividend << (32 - *scale)) / divisor */
3033 movl ARG2, %edx /* get scale */
3034 movl $32, (%edx) /* *scale = 32 */
3035 subl %ecx, (%edx) /* *scale -= %ecx */
3036 POP_FRAME
3037 ret
3038
3039/*
3040 * unsigned int
3041 * mul_scale(unsigned int multiplicand,
3042 * unsigned int multiplier,
3043 * unsigned int *scale)
3044 *
3045 * This function returns ((multiplicand * multiplier) >> *scale) where
3046 * scale is the largest possible value before overflow. This is used in
3047 * computation where precision must be achieved in order to avoid
3048 * floating point usage.
3049 *
3050 * Algorithm:
3051 * *scale = 0;
3052 * while (overflow((multiplicand * multiplier) >> *scale))
3053 * (*scale)++;
3054 * return ((multiplicand * multiplier) >> *scale);
3055 */
3056ENTRY(mul_scale)
3057 PUSH_FRAME
3058 xorl %ecx, %ecx /* *scale = 0 */
3059 movl ARG0, %eax /* get multiplicand */
3060 mull ARG1 /* multiplicand * multiplier */
30610:
3062 cmpl $0, %edx /* if (!overflow()) */
3063 je 1f /* goto 1 */
3064 addl $1, %ecx /* (*scale)++ */
3065 shrdl $1, %edx, %eax /* (multiplicand * multiplier) >> 1 */
3066 shrl $1, %edx /* (multiplicand * multiplier) >> 1 */
3067 jmp 0b
30681:
3069 movl ARG2, %edx /* get scale */
3070 movl %ecx, (%edx) /* set *scale */
3071 POP_FRAME
3072 ret
3073
3074#if NCPUS > 1
3075ENTRY(_cpu_number)
3076 CPU_NUMBER(%eax)
3077 ret
3078#endif /* NCPUS > 1 */
3079
3080#ifdef MACH_BSD
3081/*
3082 * BSD System call entry point..
3083 */
3084
3085Entry(trap_unix_syscall)
3086 pushf /* save flags as soon as possible */
3087 pushl %eax /* save system call number */
3088 pushl $0 /* clear trap number slot */
3089
3090 pusha /* save the general registers */
3091 pushl %ds /* and the segment registers */
3092 pushl %es
3093 pushl %fs
3094 pushl %gs
3095
3096 mov %ss,%dx /* switch to kernel data segment */
3097 mov %dx,%ds
3098 mov %dx,%es
3099 mov $ CPU_DATA,%dx
3100 mov %dx,%gs
3101
3102/*
3103 * Shuffle eflags,eip,cs into proper places
3104 */
3105
3106 movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
3107 movl R_CS(%esp),%ecx /* eip is in CS slot */
3108 movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
3109 movl %ecx,R_EIP(%esp) /* fix eip */
3110 movl %edx,R_CS(%esp) /* fix cs */
3111 movl %ebx,R_EFLAGS(%esp) /* fix eflags */
3112
3113 CPU_NUMBER(%edx)
3114 TIME_TRAP_UENTRY
3115
3116 negl %eax /* get system call number */
3117 shll $4,%eax /* manual indexing */
3118
3119 CPU_NUMBER(%edx)
3120 movl CX(EXT(kernel_stack),%edx),%ebx
3121 /* get current kernel stack */
3122 xchgl %ebx,%esp /* switch stacks - %ebx points to */
3123 /* user registers. */
3124
3125/*
3126 * Register use on entry:
3127 * eax contains syscall number
3128 * ebx contains user regs pointer
3129 */
3130 CAH(call_call)
3131 pushl %ebx /* Push the regs set onto stack */
3132 call EXT(unix_syscall)
3133 popl %ebx
3134 movl %esp,%ecx /* get kernel stack */
3135 or $(KERNEL_STACK_SIZE-1),%ecx
3136 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
3137 movl %eax,R_EAX(%esp) /* save return value */
3138 jmp EXT(return_from_trap) /* return to user */
3139
3140/*
3141 * Entry point for machdep system calls..
3142 */
3143
3144Entry(trap_machdep_syscall)
3145 pushf /* save flags as soon as possible */
3146 pushl %eax /* save system call number */
3147 pushl $0 /* clear trap number slot */
3148
3149 pusha /* save the general registers */
3150 pushl %ds /* and the segment registers */
3151 pushl %es
3152 pushl %fs
3153 pushl %gs
3154
3155 mov %ss,%dx /* switch to kernel data segment */
3156 mov %dx,%ds
3157 mov %dx,%es
3158 mov $ CPU_DATA,%dx
3159 mov %dx,%gs
3160
3161/*
3162 * Shuffle eflags,eip,cs into proper places
3163 */
3164
3165 movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
3166 movl R_CS(%esp),%ecx /* eip is in CS slot */
3167 movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
3168 movl %ecx,R_EIP(%esp) /* fix eip */
3169 movl %edx,R_CS(%esp) /* fix cs */
3170 movl %ebx,R_EFLAGS(%esp) /* fix eflags */
3171
3172 CPU_NUMBER(%edx)
3173 TIME_TRAP_UENTRY
3174
3175 negl %eax /* get system call number */
3176 shll $4,%eax /* manual indexing */
3177
3178 CPU_NUMBER(%edx)
3179 movl CX(EXT(kernel_stack),%edx),%ebx
3180 /* get current kernel stack */
3181 xchgl %ebx,%esp /* switch stacks - %ebx points to */
3182 /* user registers. */
3183
3184/*
3185 * Register use on entry:
3186 * eax contains syscall number
3187 * ebx contains user regs pointer
3188 */
3189 CAH(call_call)
3190 pushl %ebx
3191 call EXT(machdep_syscall)
3192 popl %ebx
3193 movl %esp,%ecx /* get kernel stack */
3194 or $(KERNEL_STACK_SIZE-1),%ecx
3195 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
3196 movl %eax,R_EAX(%esp) /* save return value */
3197 jmp EXT(return_from_trap) /* return to user */
3198
3199Entry(trap_mach25_syscall)
3200 pushf /* save flags as soon as possible */
3201 pushl %eax /* save system call number */
3202 pushl $0 /* clear trap number slot */
3203
3204 pusha /* save the general registers */
3205 pushl %ds /* and the segment registers */
3206 pushl %es
3207 pushl %fs
3208 pushl %gs
3209
3210 mov %ss,%dx /* switch to kernel data segment */
3211 mov %dx,%ds
3212 mov %dx,%es
3213 mov $ CPU_DATA,%dx
3214 mov %dx,%gs
3215
3216/*
3217 * Shuffle eflags,eip,cs into proper places
3218 */
3219
3220 movl R_EIP(%esp),%ebx /* eflags are in EIP slot */
3221 movl R_CS(%esp),%ecx /* eip is in CS slot */
3222 movl R_EFLAGS(%esp),%edx /* cs is in EFLAGS slot */
3223 movl %ecx,R_EIP(%esp) /* fix eip */
3224 movl %edx,R_CS(%esp) /* fix cs */
3225 movl %ebx,R_EFLAGS(%esp) /* fix eflags */
3226
3227 CPU_NUMBER(%edx)
3228 TIME_TRAP_UENTRY
3229
3230 negl %eax /* get system call number */
3231 shll $4,%eax /* manual indexing */
3232
3233 CPU_NUMBER(%edx)
3234 movl CX(EXT(kernel_stack),%edx),%ebx
3235 /* get current kernel stack */
3236 xchgl %ebx,%esp /* switch stacks - %ebx points to */
3237 /* user registers. */
3238
3239/*
3240 * Register use on entry:
3241 * eax contains syscall number
3242 * ebx contains user regs pointer
3243 */
3244 CAH(call_call)
3245 pushl %ebx
3246 call EXT(mach25_syscall)
3247 popl %ebx
3248 movl %esp,%ecx /* get kernel stack */
3249 or $(KERNEL_STACK_SIZE-1),%ecx
3250 movl -3-IKS_SIZE(%ecx),%esp /* switch back to PCB stack */
3251 movl %eax,R_EAX(%esp) /* save return value */
3252 jmp EXT(return_from_trap) /* return to user */
3253
3254#endif