The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/locore.s

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* 
    2  * Mach Operating System
    3  * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
    4  * Copyright (c) 1991 IBM Corporation 
    5  * All Rights Reserved.
    6  * 
    7  * Permission to use, copy, modify and distribute this software and its
    8  * documentation is hereby granted, provided that both the copyright
    9  * notice and this permission notice appear in all copies of the
   10  * software, derivative works or modified versions, and any portions
   11  * thereof, and that both notices appear in supporting documentation,
   12  * and that the nema IBM not be used in advertising or publicity 
   13  * pertaining to distribution of the software without specific, written
   14  * prior permission.
   15  * 
   16  * CARNEGIE MELLON AND IBM ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   17  * CONDITION.  CARNEGIE MELLON AND IBM DISCLAIM ANY LIABILITY OF ANY KIND FOR
   18  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   19  * 
   20  * Carnegie Mellon requests users of this software to return to
   21  * 
   22  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   23  *  School of Computer Science
   24  *  Carnegie Mellon University
   25  *  Pittsburgh PA 15213-3890
   26  * 
   27  * any improvements or extensions that they make and grant Carnegie Mellon
   28  * the rights to redistribute these changes.
   29  */
   30 
   31 /*
   32  * HISTORY
   33  * $Log:        locore.s,v $
   34  * Revision 2.25  93/05/10  23:23:41  rvb
   35  *      Checkin for MK80 branch.
   36  *      [93/05/10  15:11:52  grm]
   37  * 
   38  * Revision 2.23.1.1  93/03/01  15:22:47  grm
   39  *      Added TTD teledebug code to setup trampoline upon entry.  The
   40  *      code mirrors ddb.
   41  *      [93/03/01            grm]
   42  * 
   43  * Revision 2.24  93/05/10  17:46:24  rvb
   44  *      Use C comments
   45  *      [93/05/04  17:16:38  rvb]
   46  * 
   47  * Revision 2.23  93/02/04  07:56:32  danner
   48  *      Added special case of TIME_TRAP_UENTRY for system calls:
   49  *      TIME_TRAP_SENTRY.  It needs to save and restore %eax around the
   50  *      call to timer_normalize.  Fix from OSF Grenoble.
   51  *      [93/01/20            dbg]
   52  *      Integrate PS2 code from IBM.
   53  *      [93/01/18            prithvi]
   54  * 
   55  * Revision 2.22  93/01/28  18:40:56  danner
   56  *      Make tenmicrosec() generally available.  Clean up comment.
   57  *      [93/01/25            rvb]
   58  * 
   59  * Revision 2.21  92/04/06  01:15:57  rpd
   60  *      Converted from #-style to /-style comments, for ANSI preprocessors.
   61  *      [92/04/05            rpd]
   62  * 
   63  * Revision 2.20  92/02/19  16:29:23  elf
   64  *      Add some MD debugger support.
   65  *      [92/02/07            rvb]
   66  * 
   67  * Revision 2.19  92/01/03  20:07:57  dbg
   68  *      Generalize retryable faults.  Add inst_fetch to fetch
   69  *      instruction when segments are in use.
   70  *      [91/12/06            dbg]
   71  * 
   72  *      Remove fixed lower bound for emulated system call table.
   73  *      [91/10/31            dbg]
   74  * 
   75  *      Segment-not-present may also occur during kernel exit sequence.
   76  *      Call i386_ast_taken to handle delayed floating-point exceptions.
   77  *      [91/10/29            dbg]
   78  * 
   79  * Revision 2.18  91/10/07  17:24:53  af
   80  *      tenmicrosec() was all wrong has been expunged, since noone uses
   81  *      it.
   82  *      [91/09/04            rvb]
   83  * 
   84  * Revision 2.17  91/08/28  21:39:05  jsb
   85  *      Add tests for V86 mode in trace and GP fault checks.  Clear
   86  *      direction flag at all kernel entry points.
   87  *      [91/08/20            dbg]
   88  * 
   89  * Revision 2.16  91/07/31  17:38:38  dbg
   90  *      Add microsecond timing.
   91  * 
   92  *      Save user regs directly in PCB on trap, and switch to separate
   93  *      kernel stack.
   94  * 
   95  *      Make copyin and copyout use longword move if possible.
   96  *      [91/07/30  16:53:39  dbg]
   97  * 
   98  * Revision 2.15  91/06/19  11:55:16  rvb
   99  *      cputypes.h->platforms.h
  100  *      [91/06/12  13:44:59  rvb]
  101  * 
  102  * Revision 2.14  91/05/14  16:11:15  mrt
  103  *      Correcting copyright
  104  * 
  105  * Revision 2.13  91/05/08  12:39:21  dbg
  106  *      Put parentheses around substituted immediate expressions, so
  107  *      that they will pass through the GNU preprocessor.
  108  * 
  109  *      Handle multiple CPUS.
  110  *      [91/04/26  14:36:46  dbg]
  111  * 
  112  * Revision 2.12  91/03/16  14:44:37  rpd
  113  *      Changed call_continuation to not change spl.
  114  *      [91/02/17            rpd]
  115  *      Added call_continuation.
  116  *      Changed the AST interface.
  117  *      [91/01/18            rpd]
  118  * 
  119  * Revision 2.11  91/02/05  17:12:59  mrt
  120  *      Changed to new Mach copyright
  121  *      [91/02/01  17:35:44  mrt]
  122  * 
  123  * Revision 2.10  91/01/09  22:41:32  rpd
  124  *      Removed k_user_regs.
  125  *      [91/01/09            rpd]
  126  * 
  127  * Revision 2.9  91/01/08  17:32:10  rpd
  128  *      interrupt_returns must check for EFL_VM.
  129  *      [90/12/21  14:37:44  rvb]
  130  * 
  131  *      Add trapv86 for VM thread.
  132  *      [90/12/19  17:00:56  rvb]
  133  * 
  134  * Revision 2.8  91/01/08  15:10:49  rpd
  135  *      Replaced thread_bootstrap_user, thread_bootstrap_kernel
  136  *      with thread_exception_return, thread_syscall_return.
  137  *      Updated mach_trap_table indexing for new layout.
  138  *      [90/12/17            rpd]
  139  * 
  140  *      Renamed thread_bootstrap to thread_bootstrap_user.
  141  *      Added thread_bootstrap_kernel.
  142  *      [90/12/14            rpd]
  143  * 
  144  *      Reorganized the pcb.
  145  *      Added copyinmsg, copyoutmsg synonyms for copyin, copyout.
  146  *      [90/12/11            rpd]
  147  * 
  148  * Revision 2.7  90/12/20  16:36:21  jeffreyh
  149  *      Changes for __STDC__
  150  *      [90/12/07  15:43:29  jeffreyh]
  151  * 
  152  *
  153  * Revision 2.6  90/12/04  14:46:11  jsb
  154  *      iPSC2 -> iPSC386.
  155  *      [90/12/04  11:17:03  jsb]
  156  * 
  157  * Revision 2.5  90/09/23  17:45:16  jsb
  158  *      Added support for iPSC386.
  159  *      [90/09/21  16:40:55  jsb]
  160  * 
  161  * Revision 2.4  90/08/27  21:57:24  dbg
  162  *      Remove interrupt/trap vectors - get from idt.s.
  163  *      Fix copyout to check user address on each page boundary.
  164  *      [90/07/25            dbg]
  165  * 
  166  * Revision 2.3  90/05/21  13:26:44  dbg
  167  *      Add inl, outl.
  168  *      [90/05/17            dbg]
  169  * 
  170  * Revision 2.2  90/05/03  15:33:45  dbg
  171  *      Created.
  172  *      [90/02/14            dbg]
  173  * 
  174  */
  175 
  176 #include <cpus.h>
  177 #include <platforms.h>
  178 #include <mach_kdb.h>
  179 #include <mach_ttd.h>
  180 #include <stat_time.h>
  181 
  182 #include <i386/asm.h>
  183 #include <i386/eflags.h>
  184 #include <i386/proc_reg.h>
  185 #include <i386/trap.h>
  186 #include <assym.s>
  187 
  188 #if     NCPUS > 1
  189 
  190 #ifdef  SYMMETRY
  191 #include <sqt/asm_macros.h>
  192 #endif
  193 
  194 #define CX(addr,reg)    addr(,reg,4)
  195 
  196 #else
  197 #define CPU_NUMBER(reg)
  198 #define CX(addr,reg)    addr
  199 
  200 #endif  NCPUS > 1
  201 
  202 /*
  203  * Fault recovery.
  204  */
  205 #define RECOVER_TABLE_START     \
  206         .text   2               ;\
  207         .globl  _recover_table  ;\
  208 _recover_table:                 ;\
  209         .text
  210 
  211 #define RECOVER(addr)           \
  212         .text   2               ;\
  213         .long   9f              ;\
  214         .long   addr            ;\
  215         .text                   ;\
  216 9:
  217 
  218 #define RECOVER_TABLE_END               \
  219         .text   2                       ;\
  220         .globl  _recover_table_end      ;\
  221 _recover_table_end:                     ;\
  222         .text
  223 
  224 /*
  225  * Retry table for certain successful faults.
  226  */
  227 #define RETRY_TABLE_START       \
  228         .text   3               ;\
  229         .globl  _retry_table    ;\
  230 _retry_table:                   ;\
  231         .text
  232 
  233 #define RETRY(addr)             \
  234         .text   3               ;\
  235         .long   9f              ;\
  236         .long   addr            ;\
  237         .text                   ;\
  238 9:
  239 
  240 #define RETRY_TABLE_END                 \
  241         .text   3                       ;\
  242         .globl  _retry_table_end        ;\
  243 _retry_table_end:                       ;\
  244         .text
  245 
  246 /*
  247  * Allocate recovery and retry tables.
  248  */
  249         RECOVER_TABLE_START
  250         RETRY_TABLE_START
  251 
  252 /*
  253  * Timing routines.
  254  */
  255 #if     STAT_TIME
  256 
  257 #define TIME_TRAP_UENTRY
  258 #define TIME_TRAP_SENTRY
  259 #define TIME_TRAP_UEXIT
  260 #define TIME_INT_ENTRY
  261 #define TIME_INT_EXIT
  262 
  263 #else   /* microsecond timing */
  264 
  265 /*
  266  * Microsecond timing.
  267  * Assumes a free-running microsecond counter.
  268  * no TIMER_MAX check needed.
  269  */
  270 
  271 /*
  272  * There is only one current time-stamp per CPU, since only
  273  * the time-stamp in the current timer is used.
  274  * To save time, we allocate the current time-stamps here.
  275  */
  276         .comm   _current_tstamp, 4*NCPUS
  277 
  278 /*
  279  * Update time on user trap entry.
  280  * 11 instructions (including cli on entry)
  281  * Assumes CPU number in %edx.
  282  * Uses %eax, %ebx, %ecx.
  283  */
  284 #define TIME_TRAP_UENTRY \
  285         cli                                     /* block interrupts */  ;\
  286         movl    VA_ETC,%ebx                     /* get timer value */   ;\
  287         movl    CX(_current_tstamp,%edx),%ecx   /* get old time stamp */;\
  288         movl    %ebx,CX(_current_tstamp,%edx)   /* set new time stamp */;\
  289         subl    %ecx,%ebx                       /* elapsed = new-old */ ;\
  290         movl    CX(_current_timer,%edx),%ecx    /* get current timer */ ;\
  291         addl    %ebx,LOW_BITS(%ecx)             /* add to low bits */   ;\
  292         jns     0f                              /* if overflow, */      ;\
  293         call    timer_normalize                 /* normalize timer */   ;\
  294 0:      addl    $(TH_SYS_TIMER-TH_USER_TIMER),%ecx                      ;\
  295                                                 /* switch to sys timer */;\
  296         movl    %ecx,CX(_current_timer,%edx)    /* make it current */   ;\
  297         sti                                     /* allow interrupts */
  298 
  299 /*
  300  * Update time on system call entry.
  301  * 11 instructions (including cli on entry)
  302  * Assumes CPU number in %edx.
  303  * Uses %ebx, %ecx.
  304  * Same as TIME_TRAP_UENTRY, but preserves %eax.
  305  */
  306 #define TIME_TRAP_SENTRY \
  307         cli                                     /* block interrupts */  ;\
  308         movl    VA_ETC,%ebx                     /* get timer value */   ;\
  309         movl    CX(_current_tstamp,%edx),%ecx   /* get old time stamp */;\
  310         movl    %ebx,CX(_current_tstamp,%edx)   /* set new time stamp */;\
  311         subl    %ecx,%ebx                       /* elapsed = new-old */ ;\
  312         movl    CX(_current_timer,%edx),%ecx    /* get current timer */ ;\
  313         addl    %ebx,LOW_BITS(%ecx)             /* add to low bits */   ;\
  314         jns     0f                              /* if overflow, */      ;\
  315         pushl   %eax                            /* save %eax */         ;\
  316         call    timer_normalize                 /* normalize timer */   ;\
  317         popl    %eax                            /* restore %eax */      ;\
  318 0:      addl    $(TH_SYS_TIMER-TH_USER_TIMER),%ecx                      ;\
  319                                                 /* switch to sys timer */;\
  320         movl    %ecx,CX(_current_timer,%edx)    /* make it current */   ;\
  321         sti                                     /* allow interrupts */
  322 
  323 /*
  324  * update time on user trap exit.
  325  * 10 instructions.
  326  * Assumes CPU number in %edx.
  327  * Uses %ebx, %ecx.
  328  */
  329 #define TIME_TRAP_UEXIT \
  330         cli                                     /* block interrupts */  ;\
  331         movl    VA_ETC,%ebx                     /* get timer */         ;\
  332         movl    CX(_current_tstamp,%edx),%ecx   /* get old time stamp */;\
  333         movl    %ebx,CX(_current_tstamp,%edx)   /* set new time stamp */;\
  334         subl    %ecx,%ebx                       /* elapsed = new-old */ ;\
  335         movl    CX(_current_timer,%edx),%ecx    /* get current timer */ ;\
  336         addl    %ebx,LOW_BITS(%ecx)             /* add to low bits */   ;\
  337         jns     0f                              /* if overflow, */      ;\
  338         call    timer_normalize                 /* normalize timer */   ;\
  339 0:      addl    $(TH_USER_TIMER-TH_SYS_TIMER),%ecx                      ;\
  340                                                 /* switch to user timer */;\
  341         movl    %ecx,CX(_current_timer,%edx)    /* make it current */
  342 
  343 /*
  344  * update time on interrupt entry.
  345  * 9 instructions.
  346  * Assumes CPU number in %edx.
  347  * Leaves old timer in %ebx.
  348  * Uses %ecx.
  349  */
  350 #define TIME_INT_ENTRY \
  351         movl    VA_ETC,%ecx                     /* get timer */         ;\
  352         movl    CX(_current_tstamp,%edx),%ebx   /* get old time stamp */;\
  353         movl    %ecx,CX(_current_tstamp,%edx)   /* set new time stamp */;\
  354         subl    %ebx,%ecx                       /* elapsed = new-old */ ;\
  355         movl    CX(_current_timer,%edx),%ebx    /* get current timer */ ;\
  356         addl    %ecx,LOW_BITS(%ebx)             /* add to low bits */   ;\
  357         leal    CX(0,%edx),%ecx                 /* timer is 16 bytes */ ;\
  358         lea     CX(_kernel_timer,%edx),%ecx     /* get interrupt timer*/;\
  359         movl    %ecx,CX(_current_timer,%edx)    /* set timer
  360 
  361 /*
  362  * update time on interrupt exit.
  363  * 11 instructions
  364  * Assumes CPU number in %edx, old timer in %ebx.
  365  * Uses %eax, %ecx.
  366  */
  367 #define TIME_INT_EXIT \
  368         movl    VA_ETC,%eax                     /* get timer */         ;\
  369         movl    CX(_current_tstamp,%edx),%ecx   /* get old time stamp */;\
  370         movl    %eax,CX(_current_tstamp,%edx)   /* set new time stamp */;\
  371         subl    %ecx,%eax                       /* elapsed = new-old */ ;\
  372         movl    CX(_current_timer,%edx),%ecx    /* get current timer */ ;\
  373         addl    %eax,LOW_BITS(%ecx)             /* add to low bits */   ;\
  374         jns     0f                              /* if overflow, */      ;\
  375         call    timer_normalize                 /* normalize timer */   ;\
  376 0:      testb   $0x80,LOW_BITS+3(%ebx)          /* old timer overflow? */;\
  377         jz      0f                              /* if overflow, */      ;\
  378         movl    %ebx,%ecx                       /* get old timer */     ;\
  379         call    timer_normalize                 /* normalize timer */   ;\
  380 0:      movl    %ebx,CX(_current_timer,%edx)    /* set timer */
  381 
  382 
  383 /*
  384  * Normalize timer in ecx.
  385  * Preserves edx; clobbers eax.
  386  */
  387         .align  2
  388 timer_high_unit:
  389         .long   TIMER_HIGH_UNIT                 /* div has no immediate opnd */
  390 
  391 timer_normalize:
  392         pushl   %edx                            /* save register */
  393         xorl    %edx,%edx                       /* clear divisor high */
  394         movl    LOW_BITS(%ecx),%eax             /* get divisor low */
  395         divl    timer_high_unit,%eax            /* quotient in eax */
  396                                                 /* remainder in edx */
  397         addl    %eax,HIGH_BITS_CHECK(%ecx)      /* add high_inc to check  */
  398         movl    %edx,LOW_BITS(%ecx)             /* remainder to low_bits  */
  399         addl    %eax,HIGH_BITS(%ecx)            /* add high_inc to high bits */
  400         popl    %edx                            /* restore register  */
  401         ret
  402 
  403 /*
  404  * Switch to a new timer.
  405  */
  406 ENTRY(timer_switch)
  407         CPU_NUMBER(%edx)                        /* get this CPU  */
  408         movl    VA_ETC,%ecx                     /* get timer */
  409         movl    CX(_current_tstamp,%edx),%eax   /* get old time stamp  */
  410         movl    %ecx,CX(_current_tstamp,%edx)   /* set new time stamp */
  411         subl    %ecx,%eax                       /* elapsed = new - old */
  412         movl    CX(_current_timer,%edx),%ecx    /* get current timer */
  413         addl    %eax,LOW_BITS(%ecx)             /* add to low bits */
  414         jns     0f                              /* if overflow, */
  415         call    timer_normalize                 /* normalize timer */
  416 0:
  417         movl    S_ARG0,%ecx                     /* get new timer */
  418         movl    %ecx,CX(_current_timer,%edx)    /* set timer */
  419         ret
  420 
  421 /*
  422  * Initialize the first timer for a CPU.
  423  */
  424 ENTRY(start_timer)
  425         CPU_NUMBER(%edx)                        /* get this CPU */
  426         movl    VA_ETC,%ecx                     /* get timer */
  427         movl    %ecx,CX(_current_tstamp,%edx)   /* set initial time stamp */
  428         movl    S_ARG0,%ecx                     /* get timer */
  429         movl    %ecx,CX(_current_timer,%edx)    /* set initial timer */
  430         ret
  431 
  432 #endif  /* accurate timing */
  433 
  434 /**/
  435 
  436 /*
  437  * Trap/interrupt entry points.
  438  *
  439  * All traps must create the following save area on the kernel stack:
  440  *
  441  *      gs
  442  *      fs
  443  *      es
  444  *      ds
  445  *      edi
  446  *      esi
  447  *      ebp
  448  *      cr2 if page fault - otherwise unused
  449  *      ebx
  450  *      edx
  451  *      ecx
  452  *      eax
  453  *      trap number
  454  *      error code
  455  *      eip
  456  *      cs
  457  *      eflags
  458  *      user esp - if from user
  459  *      user ss  - if from user
  460  *      es       - if from V86 thread
  461  *      ds       - if from V86 thread
  462  *      fs       - if from V86 thread
  463  *      gs       - if from V86 thread
  464  *
  465  */
  466 
  467 /*
  468  * General protection or segment-not-present fault.
  469  * Check for a GP/NP fault in the kernel_return
  470  * sequence; if there, report it as a GP/NP fault on the user's instruction.
  471  *
  472  * esp->     0: trap code (NP or GP)
  473  *           4: segment number in error
  474  *           8  eip
  475  *          12  cs
  476  *          16  eflags
  477  *          20  old registers (trap is from kernel)
  478  */
  479 ENTRY(t_gen_prot)
  480         pushl   $(T_GENERAL_PROTECTION) /* indicate fault type  */
  481         jmp     trap_check_kernel_exit  /* check for kernel exit sequence */
  482 
  483 ENTRY(t_segnp)
  484         pushl   $(T_SEGMENT_NOT_PRESENT)
  485                                         /* indicate fault type */
  486 
  487 trap_check_kernel_exit:
  488         testl   $(EFL_VM),16(%esp)      /* is trap from V86 mode? */
  489         jnz     _alltraps               /* isn`t kernel trap if so */
  490         testl   $3,12(%esp)             /* is trap from kernel mode? */
  491         jne     _alltraps               /* if so:  */
  492                                         /* check for the kernel exit sequence */
  493         cmpl    $_kret_iret,8(%esp)     /* on IRET? */
  494         je      fault_iret
  495         cmpl    $_kret_popl_ds,8(%esp)  /* popping DS? */
  496         je      fault_popl_ds   
  497         cmpl    $_kret_popl_es,8(%esp)  /* popping ES? */
  498         je      fault_popl_es
  499         cmpl    $_kret_popl_fs,8(%esp)  /* popping FS? */
  500         je      fault_popl_fs
  501         cmpl    $_kret_popl_gs,8(%esp)  /* popping GS? */
  502         je      fault_popl_gs
  503 take_fault:                             /* if none of the above: */
  504         jmp     _alltraps               /* treat as normal trap. */
  505 
  506 /*
  507  * GP/NP fault on IRET: CS or SS is in error.
  508  * All registers contain the user's values.
  509  *
  510  * on SP is
  511  *  0   trap number
  512  *  4   errcode
  513  *  8   eip
  514  * 12   cs              --> trapno
  515  * 16   efl             --> errcode
  516  * 20   user eip
  517  * 24   user cs
  518  * 28   user eflags
  519  * 32   user esp
  520  * 36   user ss
  521  */
  522 fault_iret:
  523         movl    %eax,8(%esp)            /* save eax (we don`t need saved eip) */
  524         popl    %eax                    /* get trap number */
  525         movl    %eax,12-4(%esp)         /* put in user trap number */
  526         popl    %eax                    /* get error code */
  527         movl    %eax,16-8(%esp)         /* put in user errcode */
  528         popl    %eax                    /* restore eax */
  529         jmp     _alltraps               /* take fault */
  530 
  531 /*
  532  * Fault restoring a segment register.  The user's registers are still
  533  * saved on the stack.  The offending segment register has not been
  534  * popped.
  535  */
  536 fault_popl_ds:
  537         popl    %eax                    /* get trap number  */
  538         popl    %edx                    /* get error code */
  539         addl    $12,%esp                /* pop stack to user regs */
  540         jmp     push_es                 /* (DS on top of stack) */
  541 fault_popl_es:
  542         popl    %eax                    /* get trap number */
  543         popl    %edx                    /* get error code */
  544         addl    $12,%esp                /* pop stack to user regs */
  545         jmp     push_fs                 /* (ES on top of stack) */
  546 fault_popl_fs:
  547         popl    %eax                    /* get trap number */
  548         popl    %edx                    /* get error code */
  549         addl    $12,%esp                /* pop stack to user regs */
  550         jmp     push_gs                 /* (FS on top of stack) */
  551 fault_popl_gs:
  552         popl    %eax                    /* get trap number */
  553         popl    %edx                    /* get error code */
  554         addl    $12,%esp                /* pop stack to user regs */
  555         jmp     push_segregs            /* (GS on top of stack) */
  556 
  557 push_es:
  558         pushl   %es                     /* restore es, */
  559 push_fs:
  560         pushl   %fs                     /* restore fs, */
  561 push_gs:
  562         pushl   %gs                     /* restore gs. */
  563 push_segregs:
  564         movl    %eax,R_TRAPNO(%esp)     /* set trap number */
  565         movl    %edx,R_ERR(%esp)        /* set error code */
  566         jmp     trap_set_segs           /* take trap */
  567 
  568 /*
  569  * Debug trap.  Check for single-stepping across system call into
  570  * kernel.  If this is the case, taking the debug trap has turned
  571  * off single-stepping - save the flags register with the trace
  572  * bit set.
  573  */
  574 ENTRY(t_debug)
  575         testl   $(EFL_VM),8(%esp)       /* is trap from V86 mode? */
  576         jnz     0f                      /* isn`t kernel trap if so */
  577         testl   $3,4(%esp)              /* is trap from kernel mode? */
  578         jnz     0f                      /* if so: */
  579         cmpl    $syscall_entry,(%esp)   /* system call entry? */
  580         jne     0f                      /* if so: */
  581                                         /* flags are sitting where syscall */
  582                                         /* wants them */
  583         addl    $8,%esp                 /* remove eip/cs */
  584         jmp     syscall_entry_2         /* continue system call entry */
  585 
  586 0:      pushl   $0                      /* otherwise: */
  587         pushl   $(T_DEBUG)              /* handle as normal */
  588         jmp     _alltraps               /* debug fault */
  589 
  590 /*
  591  * Page fault traps save cr2.
  592  */
  593 ENTRY(t_page_fault)
  594         pushl   $(T_PAGE_FAULT)         /* mark a page fault trap */
  595         pusha                           /* save the general registers */
  596         movl    %cr2,%eax               /* get the faulting address */
  597         movl    %eax,12(%esp)           /* save in esp save slot */
  598         jmp     trap_push_segs          /* continue fault */
  599 
  600 /*
  601  * All 'exceptions' enter here with:
  602  *      esp->   trap number
  603  *              error code
  604  *              old eip
  605  *              old cs
  606  *              old eflags
  607  *              old esp         if trapped from user
  608  *              old ss          if trapped from user
  609  */
  610 ENTRY(alltraps)
  611         pusha                           /* save the general registers */
  612 trap_push_segs:
  613         pushl   %ds                     /* and the segment registers */
  614         pushl   %es
  615         pushl   %fs
  616         pushl   %gs
  617 
  618 trap_set_segs:
  619         cld                             /* clear direction flag */
  620         testl   $(EFL_VM),R_EFLAGS(%esp) /* in V86 mode? */
  621         jnz     trap_from_user          /* user mode trap if so */
  622         testb   $3,R_CS(%esp)           /* user mode trap? */
  623         jz      trap_from_kernel        /* kernel trap if not */
  624 trap_from_user:
  625         mov     %ss,%ax                 /* switch to kernel data segment */
  626         mov     %ax,%ds                 /* (same as kernel stack segment) */
  627         mov     %ax,%es
  628 
  629         CPU_NUMBER(%edx)
  630         TIME_TRAP_UENTRY
  631 
  632         movl    CX(_kernel_stack,%edx),%ebx
  633         xchgl   %ebx,%esp               /* switch to kernel stack */
  634                                         /* user regs pointer already set */
  635 _take_trap:
  636         pushl   %ebx                    /* pass register save area to trap */
  637         call    _user_trap              /* call user trap routine */
  638         movl    4(%esp),%esp            /* switch back to PCB stack */
  639 
  640 /*
  641  * Return from trap or system call, checking for ASTs.
  642  * On PCB stack.
  643  */
  644 
  645 _return_from_trap:
  646         CPU_NUMBER(%edx)
  647         cmpl    $0,CX(_need_ast,%edx)
  648         jz      _return_to_user         /* if we need an AST: */
  649 
  650         movl    CX(_kernel_stack,%edx),%esp
  651                                         /* switch to kernel stack */
  652         call    _i386_astintr           /* take the AST */
  653         popl    %esp                    /* switch back to PCB stack */
  654         jmp     _return_from_trap       /* and check again (rare) */
  655                                         /* ASTs after this point will */
  656                                         /* have to wait */
  657 
  658 _return_to_user:
  659         TIME_TRAP_UEXIT
  660 
  661 /*
  662  * Return from kernel mode to interrupted thread.
  663  */
  664 
  665 _return_from_kernel:
  666 _kret_popl_gs:
  667         popl    %gs                     /* restore segment registers */
  668 _kret_popl_fs:
  669         popl    %fs
  670 _kret_popl_es:
  671         popl    %es
  672 _kret_popl_ds:
  673         popl    %ds
  674         popa                            /* restore general registers */
  675         addl    $8,%esp                 /* discard trap number and error code */
  676 _kret_iret:
  677         iret                            /* return from interrupt */
  678 
  679 
  680 /*
  681  * Trap from kernel mode.  No need to switch stacks or load segment registers.
  682  */
  683 trap_from_kernel:
  684 #if     MACH_KDB || MACH_TTD
  685         movl    %ss,%ax
  686         movl    %ax,%ds
  687         movl    %ax,%es                 /* switch to kernel data seg */
  688         movl    %esp,%ebx               /* save current stack */
  689         
  690         cmpl    _int_stack_high,%esp    /* on an interrupt stack? */
  691         jb      1f                      /* OK if so */
  692 
  693         CPU_NUMBER(%edx)                /* get CPU number */
  694         cmpl    CX(_kernel_stack,%edx),%esp
  695                                         /* already on kernel stack? */
  696         ja      0f
  697         cmpl    CX(_active_stacks,%edx),%esp
  698         ja      1f                      /* switch if not */
  699 0:
  700         movl    CX(_kernel_stack,%edx),%esp
  701 1:
  702         pushl   %ebx                    /* save old stack */
  703         pushl   %ebx                    /* pass as parameter */
  704         call    _kernel_trap            /* to kernel trap routine */
  705         addl    $4,%esp                 /* pop parameter */
  706         popl    %esp                    /* return to old stack */
  707 #else   /* MACH_KDB || MACH_TTD */
  708         pushl   %esp                    /* pass parameter */
  709         call    _kernel_trap            /* to kernel trap routine */
  710         addl    $4,%esp                 /* pop parameter */
  711 #endif  /* MACH_KDB || MACH_TTD */
  712         jmp     _return_from_kernel
  713 
  714 
  715 /*
  716  *      Called as a function, makes the current thread
  717  *      return from the kernel as if from an exception.
  718  */
  719 
  720         .globl  _thread_exception_return
  721         .globl  _thread_bootstrap_return
  722 _thread_exception_return:
  723 _thread_bootstrap_return:
  724         movl    %esp,%ecx                       /* get kernel stack */
  725         or      $(KERNEL_STACK_SIZE-1),%ecx
  726         movl    -3-IKS_SIZE(%ecx),%esp          /* switch back to PCB stack */
  727         jmp     _return_from_trap
  728 
  729 /*
  730  *      Called as a function, makes the current thread
  731  *      return from the kernel as if from a syscall.
  732  *      Takes the syscall's return code as an argument.
  733  */
  734 
  735 ENTRY(thread_syscall_return)
  736         movl    S_ARG0,%eax                     /* get return value */
  737         movl    %esp,%ecx                       /* get kernel stack */
  738         or      $(KERNEL_STACK_SIZE-1),%ecx
  739         movl    -3-IKS_SIZE(%ecx),%esp          /* switch back to PCB stack */
  740         movl    %eax,R_EAX(%esp)                /* save return value */
  741         jmp     _return_from_trap
  742 
  743 ENTRY(call_continuation)
  744         movl    S_ARG0,%eax                     /* get continuation */
  745         movl    %esp,%ecx                       /* get kernel stack */
  746         or      $(KERNEL_STACK_SIZE-1),%ecx
  747         addl    $(-3-IKS_SIZE),%ecx
  748         movl    %ecx,%esp                       /* pop the stack */
  749         xorl    %ebp,%ebp                       /* zero frame pointer */
  750         jmp     *%eax                           /* goto continuation */
  751 
  752 /*
  753  * All interrupts enter here.
  754  * old %eax on stack; interrupt number in %eax.
  755  */
  756 ENTRY(all_intrs)
  757         pushl   %ecx                    /* save registers */
  758         pushl   %edx
  759         cld                             /* clear direction flag */
  760 
  761         cmpl    %ss:_int_stack_high,%esp /* on an interrupt stack? */
  762         jb      int_from_intstack       /* if not: */
  763 
  764         pushl   %ds                     /* save segment registers */
  765         pushl   %es
  766         mov     %ss,%dx                 /* switch to kernel segments */
  767         mov     %dx,%ds
  768         mov     %dx,%es
  769 
  770         CPU_NUMBER(%edx)
  771 
  772         movl    CX(_int_stack_top,%edx),%ecx
  773         xchgl   %ecx,%esp               /* switch to interrupt stack */
  774 
  775 #if     STAT_TIME
  776         pushl   %ecx                    /* save pointer to old stack */
  777 #else
  778         pushl   %ebx                    /* save %ebx - out of the way */
  779                                         /* so stack looks the same */
  780         pushl   %ecx                    /* save pointer to old stack */
  781         TIME_INT_ENTRY                  /* do timing */
  782 #endif
  783 
  784         call    _interrupt              /* call generic interrupt routine */
  785 
  786         .globl  _return_to_iret
  787 _return_to_iret:                        /* ( label for kdb_kintr and hardclock) */
  788 
  789         CPU_NUMBER(%edx)
  790 #if     STAT_TIME
  791 #else
  792         TIME_INT_EXIT                   /* do timing */
  793         movl    4(%esp),%ebx            /* restore the extra reg we saved */
  794 #endif
  795 
  796         popl    %esp                    /* switch back to old stack */
  797 
  798         testl   $(EFL_VM),I_EFL(%esp)   /* if in V86 */
  799         jnz     0f                      /* or */
  800         testb   $3,I_CS(%esp)           /* user mode, */
  801         jz      1f                      /* check for ASTs */
  802 0:
  803         cmpl    $0,CX(_need_ast,%edx)
  804         jnz     ast_from_interrupt      /* take it if so */
  805 1:
  806         pop     %es                     /* restore segment regs */
  807         pop     %ds
  808         pop     %edx
  809         pop     %ecx
  810         pop     %eax
  811         iret                            /* return to caller */
  812 
  813 int_from_intstack:
  814         call    _interrupt              /* call interrupt routine */
  815 _return_to_iret_i:                      /* ( label for kdb_kintr) */
  816         pop     %edx                    /* must have been on kernel segs */
  817         pop     %ecx
  818         pop     %eax                    /* no ASTs */
  819         iret
  820 
  821 /*
  822  *      Take an AST from an interrupt.
  823  *      On PCB stack.
  824  * sp-> es      -> edx
  825  *      ds      -> ecx
  826  *      edx     -> eax
  827  *      ecx     -> trapno
  828  *      eax     -> code
  829  *      eip
  830  *      cs
  831  *      efl
  832  *      esp
  833  *      ss
  834  */
  835 ast_from_interrupt:
  836         pop     %es                     /* restore all registers ... */
  837         pop     %ds
  838         popl    %edx
  839         popl    %ecx
  840         popl    %eax
  841         pushl   $0                      /* zero code */
  842         pushl   $0                      /* zero trap number */
  843         pusha                           /* save general registers */
  844         push    %ds                     /* save segment registers */
  845         push    %es
  846         push    %fs
  847         push    %gs
  848         mov     %ss,%dx                 /* switch to kernel segments */
  849         mov     %dx,%ds
  850         mov     %dx,%es
  851 
  852         CPU_NUMBER(%edx)
  853         TIME_TRAP_UENTRY
  854 
  855         movl    CX(_kernel_stack,%edx),%esp
  856                                         /* switch to kernel stack */
  857         call    _i386_astintr           /* take the AST */
  858         popl    %esp                    /* back to PCB stack */
  859         jmp     _return_from_trap       /* return */
  860 
  861 #if     MACH_KDB
  862 /*
  863  * kdb_kintr:   enter kdb from keyboard interrupt.
  864  * Chase down the stack frames until we find one whose return
  865  * address is the interrupt handler.   At that point, we have:
  866  *
  867  * frame->      saved %ebp
  868  *              return address in interrupt handler
  869  *              iunit
  870  * [ PS2 - saved interrupt number ]
  871  *              saved SPL
  872  *              return address == return_to_iret_i
  873  *              saved %edx
  874  *              saved %ecx
  875  *              saved %eax
  876  *              saved %eip
  877  *              saved %cs
  878  *              saved %efl
  879  *
  880  * OR:
  881  * frame->      saved %ebp
  882  *              return address in interrupt handler
  883  *              iunit
  884  * [ PS2 - saved interrupt number ]
  885  *              saved SPL
  886  *              return address == return_to_iret
  887  *              pointer to save area on old stack
  888  *            [ saved %ebx, if accurate timing ]
  889  *
  890  * old stack:   saved %es
  891  *              saved %ds
  892  *              saved %edx
  893  *              saved %ecx
  894  *              saved %eax
  895  *              saved %eip
  896  *              saved %cs
  897  *              saved %efl
  898  *
  899  * Call kdb, passing it that register save area.
  900  */
  901 
  902 #ifdef  PS2
  903 #define RET_OFFSET      20
  904 #else   /* not PS2 */
  905 #define RET_OFFSET      16
  906 #endif  /* PS2 */
  907 
  908 ENTRY(kdb_kintr)
  909         movl    %ebp,%eax               /* save caller`s frame pointer */
  910         movl    $_return_to_iret,%ecx   /* interrupt return address 1 */
  911         movl    $_return_to_iret_i,%edx /* interrupt return address 2 */
  912 
  913 0:      cmpl    RET_OFFSET(%eax),%ecx   /* does this frame return to */
  914                                         /* interrupt handler (1)? */
  915         je      1f
  916         cmpl    RET_OFFSET(%eax),%edx   /* interrupt handler (2)? */
  917         je      2f                      /* if not: */
  918         movl    (%eax),%eax             /* try next frame */
  919         jmp     0b
  920 
  921 1:      movl    $kdb_from_iret,RET_OFFSET(%eax)
  922         ret                             /* returns to kernel/user stack */
  923 
  924 2:      movl    $kdb_from_iret_i,RET_OFFSET(%eax)
  925                                         /* returns to interrupt stack */
  926         ret
  927 
  928 /*
  929  * On return from keyboard interrupt, we will execute
  930  * kdb_from_iret_i
  931  *      if returning to an interrupt on the interrupt stack
  932  * kdb_from_iret
  933  *      if returning to an interrupt on the user or kernel stack
  934  */
  935 kdb_from_iret:
  936                                         /* save regs in known locations */
  937 #if     STAT_TIME
  938         pushl   %ebx                    /* caller`s %ebx is in reg */
  939 #else
  940         movl    4(%esp),%eax            /* get caller`s %ebx */
  941         pushl   %eax                    /* push on stack */
  942 #endif
  943         pushl   %ebp
  944         pushl   %esi
  945         pushl   %edi
  946         push    %fs
  947         push    %gs
  948         pushl   %esp                    /* pass regs */
  949         call    _kdb_kentry             /* to kdb */
  950         addl    $4,%esp                 /* pop parameters */
  951         pop     %gs                     /* restore registers */
  952         pop     %fs
  953         popl    %edi
  954         popl    %esi
  955         popl    %ebp
  956 #if     STAT_TIME
  957         popl    %ebx
  958 #else
  959         popl    %eax
  960         movl    %eax,4(%esp)
  961 #endif
  962         jmp     _return_to_iret         /* normal interrupt return */
  963 
  964 kdb_from_iret_i:                        /* on interrupt stack */
  965         pop     %edx                    /* restore saved registers */
  966         pop     %ecx
  967         pop     %eax
  968         pushl   $0                      /* zero error code */
  969         pushl   $0                      /* zero trap number */
  970         pusha                           /* save general registers */
  971         push    %ds                     /* save segment registers */
  972         push    %es
  973         push    %fs
  974         push    %gs
  975         pushl   %esp                    /* pass regs, */
  976         pushl   $0                      /* code, */
  977         pushl   $-1                     /* type to kdb */
  978         call    _kdb_trap
  979         addl    $12,%esp                /* remove parameters */
  980         pop     %gs                     /* restore segment registers */
  981         pop     %fs
  982         pop     %es
  983         pop     %ds
  984         popa                            /* restore general registers */
  985         addl    $8,%esp
  986         iret
  987 
  988 #endif  MACH_KDB
  989 
  990 #if     MACH_TTD
  991 /*
  992  * Same code as that above for the keyboard entry into kdb.
  993  */
  994 ENTRY(kttd_intr)
  995         movl    %ebp,%eax               /* save caller`s frame pointer */
  996         movl    $_return_to_iret,%ecx   /* interrupt return address 1 */
  997         movl    $_return_to_iret_i,%edx /* interrupt return address 2 */
  998 
  999 0:      cmpl    16(%eax),%ecx           /* does this frame return to */
 1000                                         /* interrupt handler (1)? */
 1001         je      1f
 1002         cmpl    16(%eax),%edx           /* interrupt handler (2)? */
 1003         je      2f                      /* if not: */
 1004         movl    (%eax),%eax             /* try next frame */
 1005         jmp     0b
 1006 
 1007 1:      movl    $ttd_from_iret,16(%eax) /* returns to kernel/user stack */
 1008         ret
 1009 
 1010 2:      movl    $ttd_from_iret_i,16(%eax)
 1011                                         /* returns to interrupt stack */
 1012         ret
 1013 
 1014 /*
 1015  * On return from keyboard interrupt, we will execute
 1016  * ttd_from_iret_i
 1017  *      if returning to an interrupt on the interrupt stack
 1018  * ttd_from_iret
 1019  *      if returning to an interrupt on the user or kernel stack
 1020  */
 1021 ttd_from_iret:
 1022                                         /* save regs in known locations */
 1023 #if     STAT_TIME
 1024         pushl   %ebx                    /* caller`s %ebx is in reg */
 1025 #else
 1026         movl    4(%esp),%eax            /* get caller`s %ebx */
 1027         pushl   %eax                    /* push on stack */
 1028 #endif
 1029         pushl   %ebp
 1030         pushl   %esi
 1031         pushl   %edi
 1032         push    %fs
 1033         push    %gs
 1034         pushl   %esp                    /* pass regs */
 1035         call    _kttd_netentry          /* to kdb */
 1036         addl    $4,%esp                 /* pop parameters */
 1037         pop     %gs                     /* restore registers */
 1038         pop     %fs
 1039         popl    %edi
 1040         popl    %esi
 1041         popl    %ebp
 1042 #if     STAT_TIME
 1043         popl    %ebx
 1044 #else
 1045         popl    %eax
 1046         movl    %eax,4(%esp)
 1047 #endif
 1048         jmp     _return_to_iret         /* normal interrupt return */
 1049 
 1050 ttd_from_iret_i:                        /* on interrupt stack */
 1051         pop     %edx                    /* restore saved registers */
 1052         pop     %ecx
 1053         pop     %eax
 1054         pushl   $0                      /* zero error code */
 1055         pushl   $0                      /* zero trap number */
 1056         pusha                           /* save general registers */
 1057         push    %ds                     /* save segment registers */
 1058         push    %es
 1059         push    %fs
 1060         push    %gs
 1061         pushl   %esp                    /* pass regs, */
 1062         pushl   $0                      /* code, */
 1063         pushl   $-1                     /* type to kdb */
 1064         call    _kttd_trap
 1065         addl    $12,%esp                /* remove parameters */
 1066         pop     %gs                     /* restore segment registers */
 1067         pop     %fs
 1068         pop     %es
 1069         pop     %ds
 1070         popa                            /* restore general registers */
 1071         addl    $8,%esp
 1072         iret
 1073 
 1074 #endif  /* MACH_TTD */
 1075 
 1076 /*
 1077  * System call enters through a call gate.  Flags are not saved -
 1078  * we must shuffle stack to look like trap save area.
 1079  *
 1080  * esp->        old eip
 1081  *              old cs
 1082  *              old esp
 1083  *              old ss
 1084  *
 1085  * eax contains system call number.
 1086  */
 1087 ENTRY(syscall)
 1088 syscall_entry:
 1089         pushf                           /* save flags as soon as possible */
 1090 syscall_entry_2:
 1091         pushl   %eax                    /* save system call number */
 1092         pushl   $0                      /* clear trap number slot */
 1093                 
 1094         pusha                           /* save the general registers */
 1095         pushl   %ds                     /* and the segment registers */
 1096         pushl   %es
 1097         pushl   %fs
 1098         pushl   %gs
 1099 
 1100         mov     %ss,%dx                 /* switch to kernel data segment */
 1101         mov     %dx,%ds
 1102         mov     %dx,%es
 1103 
 1104 /*
 1105  * Shuffle eflags,eip,cs into proper places
 1106  */
 1107 
 1108         movl    R_EIP(%esp),%ebx        /* eflags are in EIP slot */
 1109         movl    R_CS(%esp),%ecx         /* eip is in CS slot */
 1110         movl    R_EFLAGS(%esp),%edx     /* cs is in EFLAGS slot */
 1111         movl    %ecx,R_EIP(%esp)        /* fix eip */
 1112         movl    %edx,R_CS(%esp)         /* fix cs */
 1113         movl    %ebx,R_EFLAGS(%esp)     /* fix eflags */
 1114 
 1115         CPU_NUMBER(%edx)
 1116         TIME_TRAP_SENTRY
 1117 
 1118         movl    CX(_kernel_stack,%edx),%ebx
 1119                                         /* get current kernel stack */
 1120         xchgl   %ebx,%esp               /* switch stacks - %ebx points to */
 1121                                         /* user registers. */
 1122                                         /* user regs pointer already set */
 1123 
 1124 /*
 1125  * Check for MACH or emulated system call
 1126  */
 1127 
 1128         movl    CX(_active_threads,%edx),%edx
 1129                                         /* point to current thread */
 1130         movl    TH_TASK(%edx),%edx      /* point to task */
 1131         movl    TASK_EMUL(%edx),%edx    /* get emulation vector */
 1132         orl     %edx,%edx               /* if none, */
 1133         je      syscall_native          /*    do native system call */
 1134         movl    %eax,%ecx               /* copy system call number */
 1135         subl    DISP_MIN(%edx),%ecx     /* get displacement into syscall */
 1136                                         /* vector table */
 1137         jl      syscall_native          /* too low - native system call */
 1138         cmpl    DISP_COUNT(%edx),%ecx   /* check range */
 1139         jnl     syscall_native          /* too high - native system call */
 1140         movl    DISP_VECTOR(%edx,%ecx,4),%edx
 1141                                         /* get the emulation vector */
 1142         orl     %edx,%edx               /* emulated system call if not zero */
 1143         jnz     syscall_emul
 1144 
 1145 /*
 1146  * Native system call.
 1147  */
 1148 syscall_native:
 1149         negl    %eax                    /* get system call number */
 1150         jl      mach_call_range         /* out of range if it was positive */
 1151         cmpl    _mach_trap_count,%eax   /* check system call table bounds */
 1152         jg      mach_call_range         /* error if out of range */
 1153         shll    $4,%eax                 /* manual indexing */
 1154         movl    _mach_trap_table(%eax),%ecx
 1155                                         /* get number of arguments */
 1156         jecxz   mach_call_call          /* skip argument copy if none */
 1157 
 1158         movl    R_UESP(%ebx),%esi       /* get user stack pointer */
 1159         lea     4(%esi,%ecx,4),%esi     /* skip user return address, */
 1160                                         /* and point past last argument */
 1161         cmpl    $(VM_MAX_ADDRESS),%esi  /* in user space? */
 1162         ja      mach_call_addr          /* address error if not */
 1163         movl    %esp,%edx               /* save kernel ESP for error recovery */
 1164 
 1165 0:      subl    $4,%esi
 1166         RECOVER(mach_call_addr_push)
 1167         pushl   (%esi)                  /* push argument on stack */
 1168         loop    0b                      /* loop for all arguments */
 1169 
 1170 mach_call_call:
 1171         call    *_mach_trap_table+4(%eax)
 1172                                         /* call procedure */
 1173         movl    %esp,%ecx               /* get kernel stack */
 1174         or      $(KERNEL_STACK_SIZE-1),%ecx
 1175         movl    -3-IKS_SIZE(%ecx),%esp  /* switch back to PCB stack */
 1176         movl    %eax,R_EAX(%esp)        /* save return value */
 1177         jmp     _return_from_trap       /* return to user */
 1178 
 1179 /*
 1180  * Address out of range.  Change to page fault.
 1181  * %esi holds failing address.
 1182  */
 1183 mach_call_addr_push:
 1184         movl    %edx,%esp               /* clean parameters from stack */
 1185 mach_call_addr:
 1186         movl    %esi,R_CR2(%ebx)        /* set fault address */
 1187         movl    $(T_PAGE_FAULT),R_TRAPNO(%ebx)
 1188                                         /* set page-fault trap */
 1189         movl    $(T_PF_USER),R_ERR(%ebx)
 1190                                         /* set error code - read user space */
 1191         jmp     _take_trap              /* treat as a trap */
 1192 
 1193 /*
 1194  * System call out of range.  Treat as invalid-instruction trap.
 1195  * (? general protection?)
 1196  */
 1197 mach_call_range:
 1198         movl    $(T_INVALID_OPCODE),R_TRAPNO(%ebx)
 1199                                         /* set invalid-operation trap */
 1200         movl    $0,R_ERR(%ebx)          /* clear error code */
 1201         jmp     _take_trap              /* treat as a trap */
 1202 
 1203 /*
 1204  * User space emulation of system calls.
 1205  * edx - user address to handle syscall
 1206  *
 1207  * User stack will become:
 1208  * uesp->       eflags
 1209  *              eip
 1210  * eax still contains syscall number.
 1211  */
 1212 syscall_emul:
 1213         movl    R_UESP(%ebx),%edi       /* get user stack pointer */
 1214         cmpl    $(VM_MAX_ADDRESS),%edi  /* in user space? */
 1215         ja      syscall_addr            /* address error if not */
 1216         subl    $8,%edi                 /* push space for new arguments */
 1217         cmpl    $(VM_MIN_ADDRESS),%edi  /* still in user space? */
 1218         jb      syscall_addr            /* error if not */
 1219         movl    R_EFLAGS(%ebx),%eax     /* move flags */
 1220         RECOVER(syscall_addr)
 1221         movl    %eax,0(%edi)            /* to user stack */
 1222         movl    R_EIP(%ebx),%eax        /* move eip */
 1223         RECOVER(syscall_addr)
 1224         movl    %eax,4(%edi)            /* to user stack */
 1225         movl    %edi,R_UESP(%ebx)       /* set new user stack pointer */
 1226         movl    %edx,R_EIP(%ebx)        /* change return address to trap */
 1227         movl    %ebx,%esp               /* back to PCB stack */
 1228         jmp     _return_from_trap       /* return to user */
 1229 
 1230 /*
 1231  * Address error - address is in %edi.
 1232  */
 1233 syscall_addr:
 1234         movl    %edi,R_CR2(%ebx)        /* set fault address */
 1235         movl    $(T_PAGE_FAULT),R_TRAPNO(%ebx)
 1236                                         /* set page-fault trap */
 1237         movl    $(T_PF_USER),R_ERR(%ebx)
 1238                                         /* set error code - read user space */
 1239         jmp     _take_trap              /* treat as a trap */
 1240 
 1241 /**/
 1242 /*
 1243  * Utility routines.
 1244  */
 1245 
 1246 /*
 1247  * Copy from user address space.
 1248  * arg0:        user address
 1249  * arg1:        kernel address
 1250  * arg2:        byte count
 1251  */
 1252 ENTRY(copyin)
 1253 Entry(copyinmsg)
 1254         pushl   %esi
 1255         pushl   %edi                    /* save registers */
 1256 
 1257         movl    8+S_ARG0,%esi           /* get user start address */
 1258         movl    8+S_ARG1,%edi           /* get kernel destination address */
 1259         movl    8+S_ARG2,%edx           /* get count */
 1260 
 1261 #if     (VM_MIN_ADDRESS != 0)
 1262         cmpl    $(VM_MIN_ADDRESS),%esi  /* is start within user space? */
 1263         jb      copy_fail
 1264 #endif
 1265         lea     0(%esi,%edx),%eax       /* get user end address + 1 */
 1266         cmpl    %esi,%eax
 1267         jb      copy_fail               /* fail if wrap-around */
 1268         cmpl    $(VM_MAX_ADDRESS),%eax
 1269         ja      copy_fail               /* or above user range */
 1270         
 1271         cld                             /* count up */
 1272         movl    %edx,%ecx               /* move by longwords first */
 1273         shrl    $2,%ecx
 1274         RECOVER(copy_fail)
 1275         rep
 1276         movsl                           /* move longwords */
 1277         movl    %edx,%ecx               /* now move remaining bytes */
 1278         andl    $3,%ecx
 1279         RECOVER(copy_fail)
 1280         rep
 1281         movsb
 1282         xorl    %eax,%eax               /* return 0 for success */
 1283 copy_ret:
 1284         popl    %edi                    /* restore registers */
 1285         popl    %esi
 1286         ret                             /* and return */
 1287 
 1288 copy_fail:
 1289         movl    $1,%eax                 /* return 1 for failure */
 1290         jmp     copy_ret                /* pop frame and return */
 1291 
 1292 /*
 1293  * Copy to user address space.
 1294  * arg0:        kernel address
 1295  * arg1:        user address
 1296  * arg2:        byte count
 1297  */
 1298 ENTRY(copyout)
 1299 Entry(copyoutmsg)
 1300         pushl   %esi
 1301         pushl   %edi                    /* save registers */
 1302 
 1303         movl    8+S_ARG0,%esi           /* get kernel start address */
 1304         movl    8+S_ARG1,%edi           /* get user start address */
 1305         movl    8+S_ARG2,%edx           /* get count */
 1306 
 1307 #if     (VM_MIN_ADDRESS != 0)
 1308         cmpl    $(VM_MIN_ADDRESS),%edi  /* within user space? */
 1309         jb      copy_fail
 1310 #endif
 1311         leal    0(%edi,%edx),%eax       /* get user end address + 1 */
 1312         cmpl    %edi,%eax
 1313         jb      copy_fail               /* fail if wrap-around */
 1314         cmpl    $(VM_MAX_ADDRESS),%eax
 1315         ja      copy_fail               /* or above user range */
 1316         
 1317 /*
 1318  * Check whether user address space is writable
 1319  * before writing to it - hardware is broken.
 1320  */
 1321 copyout_retry:
 1322         movl    %cr3,%ecx               /* point to page directory */
 1323         movl    %edi,%eax               /* get page directory bits */
 1324         shrl    $(PDESHIFT),%eax        /* from user address */
 1325         movl    KERNELBASE(%ecx,%eax,4),%ecx
 1326                                         /* get page directory pointer */
 1327         testl   $(PTE_V),%ecx           /* present? */
 1328         jz      0f                      /* if not, fault is OK */
 1329         andl    $(PTE_PFN),%ecx         /* isolate page frame address */
 1330         movl    %edi,%eax               /* get page table bits */
 1331         shrl    $(PTESHIFT),%eax
 1332         andl    $(PTEMASK),%eax         /* from user address */
 1333         leal    KERNELBASE(%ecx,%eax,4),%ecx
 1334                                         /* point to page table entry */
 1335         movl    (%ecx),%eax             /* get it */
 1336         testl   $(PTE_V),%eax           /* present? */
 1337         jz      0f                      /* if not, fault is OK */
 1338         testl   $(PTE_W),%eax           /* writable? */
 1339         jnz     0f                      /* OK if so */
 1340 /*
 1341  * Not writable - must fake a fault.  Turn off access to the page.
 1342  */
 1343         andl    $(PTE_INVALID),(%ecx)   /* turn off valid bit */
 1344         movl    %cr3,%eax               /* invalidate TLB */
 1345         movl    %eax,%cr3
 1346 0:
 1347 /*
 1348  * Copy only what fits on the current destination page.
 1349  * Check for write-fault again on the next page.
 1350  */
 1351         leal    NBPG(%edi),%eax         /* point to */
 1352         andl    $(-NBPG),%eax           /* start of next page */
 1353         subl    %edi,%eax               /* get number of bytes to that point */
 1354         cmpl    %edx,%eax               /* bigger than count? */
 1355         jle     1f                      /* if so, */
 1356         movl    %edx,%eax               /* use count */
 1357 1:
 1358         cld                             /* count up */
 1359         movl    %eax,%ecx               /* move by longwords first */
 1360         shrl    $2,%ecx
 1361         RECOVER(copy_fail)
 1362         RETRY(copyout_retry)
 1363         rep
 1364         movsl
 1365         movl    %eax,%ecx               /* now move remaining bytes */
 1366         andl    $3,%ecx
 1367         RECOVER(copy_fail)
 1368         RETRY(copyout_retry)
 1369         rep
 1370         movsb                           /* move */
 1371         subl    %eax,%edx               /* decrement count */
 1372         jg      copyout_retry           /* restart on next page if not done */
 1373         xorl    %eax,%eax               /* return 0 for success */
 1374         popl    %edi                    /* restore registers */
 1375         popl    %esi
 1376         ret                             /* and return */
 1377 
 1378 /*
 1379  * FPU routines.
 1380  */
 1381 
 1382 /*
 1383  * Initialize FPU.
 1384  */
 1385 ENTRY(_fninit)
 1386         fninit
 1387         ret
 1388 
 1389 /*
 1390  * Read control word
 1391  */
 1392 ENTRY(_fstcw)
 1393         pushl   %eax            /* get stack space */
 1394         fstcw   (%esp)
 1395         popl    %eax
 1396         ret
 1397 
 1398 /*
 1399  * Set control word
 1400  */
 1401 ENTRY(_fldcw)
 1402         fldcw   4(%esp)
 1403         ret
 1404 
 1405 /*
 1406  * Read status word
 1407  */
 1408 ENTRY(_fnstsw)
 1409         xor     %eax,%eax               /* clear high 16 bits of eax */
 1410         fnstsw  %ax                     /* read FP status */
 1411         ret
 1412 
 1413 /*
 1414  * Clear FPU exceptions
 1415  */
 1416 ENTRY(_fnclex)
 1417         fnclex
 1418         ret
 1419 
 1420 /*
 1421  * Clear task-switched flag.
 1422  */
 1423 ENTRY(_clts)
 1424         clts
 1425         ret
 1426 
 1427 /*
 1428  * Save complete FPU state.  Save error for later.
 1429  */
 1430 ENTRY(_fpsave)
 1431         movl    4(%esp),%eax            /* get save area pointer */
 1432         fnsave  (%eax)                  /* save complete state, including */
 1433                                         /* errors */
 1434         ret
 1435 
 1436 /*
 1437  * Restore FPU state.
 1438  */
 1439 ENTRY(_fprestore)
 1440         movl    4(%esp),%eax            /* get save area pointer */
 1441         frstor  (%eax)                  /* restore complete state */
 1442         ret
 1443 
 1444 /*
 1445  * Set cr3
 1446  */
 1447 ENTRY(set_cr3)
 1448         movl    4(%esp),%eax            /* get new cr3 value */
 1449         movl    %eax,%cr3               /* load it */
 1450         ret
 1451 
 1452 /*
 1453  * Read cr3
 1454  */
 1455 ENTRY(get_cr3)
 1456         movl    %cr3,%eax
 1457         ret
 1458 
 1459 /*
 1460  * Flush TLB
 1461  */
 1462 ENTRY(flush_tlb)
 1463         movl    %cr3,%eax               /* flush tlb by reloading CR3 */
 1464         movl    %eax,%cr3               /* with itself */
 1465         ret
 1466 
 1467 /*
 1468  * Read cr2
 1469  */
 1470 ENTRY(get_cr2)
 1471         movl    %cr2,%eax
 1472         ret
 1473 
 1474 /*
 1475  * Read ldtr
 1476  */
 1477 ENTRY(get_ldt)
 1478         xorl    %eax,%eax
 1479         sldt    %ax
 1480         ret
 1481 
 1482 /*
 1483  * Set ldtr
 1484  */
 1485 ENTRY(set_ldt)
 1486         lldt    4(%esp)
 1487         ret
 1488 
 1489 /*
 1490  * Read task register.
 1491  */
 1492 ENTRY(get_tr)
 1493         xorl    %eax,%eax
 1494         str     %ax
 1495         ret
 1496 
 1497 /*
 1498  * Set task register.  Also clears busy bit of task descriptor.
 1499  */
 1500 ENTRY(set_tr)
 1501         movl    S_ARG0,%eax             /* get task segment number */
 1502         subl    $8,%esp                 /* push space for SGDT */
 1503         sgdt    2(%esp)                 /* store GDT limit and base (linear) */
 1504         movl    4(%esp),%edx            /* address GDT */
 1505         movb    $(K_TSS),5(%edx,%eax)   /* fix access byte in task descriptor */
 1506         ltr     %ax                     /* load task register */
 1507         addl    $8,%esp                 /* clear stack */
 1508         ret                             /* and return */
 1509 
 1510 /*
 1511  * Set task-switched flag.
 1512  */
 1513 ENTRY(_setts)
 1514         movl    %cr0,%eax               /* get cr0 */
 1515         orl     $(CR0_TS),%eax          /* or in TS bit */
 1516         movl    %eax,%cr0               /* set cr0 */
 1517         ret
 1518 
 1519 /*
 1520  * void outb(unsigned char *io_port,
 1521  *           unsigned char byte)
 1522  *
 1523  * Output a byte to an IO port.
 1524  */
 1525 ENTRY(outb)
 1526         movl    S_ARG0,%edx             /* IO port address */
 1527         movl    S_ARG1,%eax             /* data to output */
 1528         outb    %al,%dx                 /* send it out */
 1529 #ifdef  iPSC386
 1530         mull    %ecx                    /* Delay a little to make H/W happy */
 1531 #endif  iPSC386
 1532         ret
 1533 
 1534 /*
 1535  * unsigned char inb(unsigned char *io_port)
 1536  *
 1537  * Input a byte from an IO port.
 1538  */
 1539 ENTRY(inb)
 1540         movl    S_ARG0,%edx             /* IO port address */
 1541         xor     %eax,%eax               /* clear high bits of register */
 1542         inb     %dx,%al                 /* get the byte */
 1543 #ifdef  iPSC386
 1544 / Do a long multiply to delay a little to make H/W happy.  Must
 1545 / save and restore EAX which is used to hold result of multiply
 1546         pushl   %eax
 1547         mull    %ecx
 1548         popl    %eax
 1549 #endif  iPSC386
 1550         ret
 1551 
 1552 /*
 1553  * void outw(unsigned short *io_port,
 1554  *           unsigned short word)
 1555  *
 1556  * Output a word to an IO port.
 1557  */
 1558 ENTRY(outw)
 1559         movl    S_ARG0,%edx             /* IO port address */
 1560         movl    S_ARG1,%eax             /* data to output */
 1561         outw    %ax,%dx                 /* send it out */
 1562         ret
 1563 
 1564 /*
 1565  * unsigned short inw(unsigned short *io_port)
 1566  *
 1567  * Input a word from an IO port.
 1568  */
 1569 ENTRY(inw)
 1570         movl    S_ARG0,%edx             /* IO port address */
 1571         xor     %eax,%eax               /* clear high bits of register */
 1572         inw     %dx,%ax                 /* get the word */
 1573         ret
 1574 
 1575 /*
 1576  * void outl(unsigned int *io_port,
 1577  *           unsigned int byte)
 1578  *
 1579  * Output an int to an IO port.
 1580  */
 1581 ENTRY(outl)
 1582         movl    S_ARG0,%edx             /* IO port address */
 1583         movl    S_ARG1,%eax             /* data to output */
 1584         outl    %eax,%dx                /* send it out */
 1585         ret
 1586 
 1587 /*
 1588  * unsigned int inl(unsigned int *io_port)
 1589  *
 1590  * Input an int from an IO port.
 1591  */
 1592 ENTRY(inl)
 1593         movl    S_ARG0,%edx             /* IO port address */
 1594         inl     %dx,%eax                /* get the int */
 1595         ret
 1596 
 1597 /*
 1598  * void loutb(unsigned byte *io_port,
 1599  *            unsigned byte *data,
 1600  *            unsigned int count)
 1601  *
 1602  * Output an array of bytes to an IO port.
 1603  */
 1604 ENTRY(loutb)
 1605         movl    %esi,%eax               /* save register */
 1606         movl    S_ARG0,%edx             /* get io port number */
 1607         movl    S_ARG1,%esi             /* get data address */
 1608         movl    S_ARG2,%ecx             /* get count */
 1609 
 1610         cld                             /* count up */
 1611 
 1612         rep
 1613         outsb                           /* output */
 1614 
 1615         movl    %eax,%esi               /* restore register */
 1616         ret                             /* exit */
 1617 
 1618 
 1619 /*
 1620  * void loutw(unsigned short *io_port,
 1621  *            unsigned short *data,
 1622  *            unsigned int count)
 1623  *
 1624  * Output an array of shorts to an IO port.
 1625  */
 1626 ENTRY(loutw)
 1627         movl    %esi,%eax               /* save register */
 1628         movl    S_ARG0,%edx             /* get io port number */
 1629         movl    S_ARG1,%esi             /* get data address */
 1630         movl    S_ARG2,%ecx             /* get count */
 1631 
 1632         cld                             /* count up */
 1633 
 1634         rep
 1635         outsw                           /* output */
 1636 
 1637         movl    %eax,%esi               /* restore register */
 1638         ret                             /* exit */
 1639 
 1640 
 1641 /*
 1642  * void linb(unsigned char *io_port,
 1643  *           unsigned char *data,
 1644  *           unsigned int count)
 1645  *
 1646  * Input an array of bytes from an IO port.
 1647  */
 1648 ENTRY(linb)
 1649         movl    %edi,%eax               /* save register */
 1650         movl    S_ARG0,%edx             /* get io port number */
 1651         movl    S_ARG1,%edi             /* get data address */
 1652         movl    S_ARG2,%ecx             /* get count */
 1653 
 1654         cld                             /* count up */
 1655 
 1656         rep
 1657         insb                            /* input */
 1658 
 1659         movl    %eax,%edi               /* restore register */
 1660         ret                             /* exit */
 1661 
 1662 
 1663 /*
 1664  * void linw(unsigned short *io_port,
 1665  *           unsigned short *data,
 1666  *           unsigned int count)
 1667  *
 1668  * Input an array of shorts from an IO port.
 1669  */
 1670 ENTRY(linw)
 1671         movl    %edi,%eax               /* save register */
 1672         movl    S_ARG0,%edx             /* get io port number */
 1673         movl    S_ARG1,%edi             /* get data address */
 1674         movl    S_ARG2,%ecx             /* get count */
 1675 
 1676         cld                             /* count up */
 1677 
 1678         rep
 1679         insw                            /* input */
 1680 
 1681         movl    %eax,%edi               /* restore register */
 1682         ret                             /* exit */
 1683 
 1684 
 1685 /*
 1686  * int inst_fetch(int eip, int cs);
 1687  *
 1688  * Fetch instruction byte.  Return -1 if invalid address.
 1689  */
 1690         .globl  _inst_fetch
 1691 _inst_fetch:
 1692         movl    S_ARG1, %eax            /* get segment */
 1693         movw    %ax,%fs                 /* into FS */
 1694         movl    S_ARG0, %eax            /* get offset */
 1695         RETRY(_inst_fetch)              /* re-load FS on retry */
 1696         RECOVER(_inst_fetch_fault)
 1697         movzbl  %fs:(%eax),%eax         /* load instruction byte */
 1698         ret
 1699 
 1700 _inst_fetch_fault:
 1701         movl    $-1,%eax                /* return -1 if error */
 1702         ret
 1703 
 1704 
 1705 /*
 1706  * Done with recovery and retry tables.
 1707  */
 1708         RECOVER_TABLE_END
 1709         RETRY_TABLE_END
 1710 
 1711 
 1712 
 1713 ENTRY(dr6)
 1714         movl    %db6, %eax
 1715         ret
 1716 
 1717 /*      dr<i>(address, type, len, persistence)
 1718  */
 1719 ENTRY(dr0)
 1720         movl    S_ARG0, %eax
 1721         movl    %eax,_dr_addr
 1722         movl    %eax, %db0
 1723         movl    $0, %ecx
 1724         jmp     0f
 1725 ENTRY(dr1)
 1726         movl    S_ARG0, %eax
 1727         movl    %eax,_dr_addr+1*4
 1728         movl    %eax, %db1
 1729         movl    $2, %ecx
 1730         jmp     0f
 1731 ENTRY(dr2)
 1732         movl    S_ARG0, %eax
 1733         movl    %eax,_dr_addr+2*4
 1734         movl    %eax, %db2
 1735         movl    $4, %ecx
 1736         jmp     0f
 1737 
 1738 ENTRY(dr3)
 1739         movl    S_ARG0, %eax
 1740         movl    %eax,_dr_addr+3*4
 1741         movl    %eax, %db3
 1742         movl    $6, %ecx
 1743 
 1744 0:
 1745         pushl   %ebp
 1746         movl    %esp, %ebp
 1747 
 1748         movl    %db7, %edx
 1749         movl    %edx,_dr_addr+4*4
 1750         andl    dr_msk(,%ecx,2),%edx    /* clear out new entry */
 1751         movl    %edx,_dr_addr+5*4
 1752         movzbl  B_ARG3, %eax
 1753         andb    $3, %al
 1754         shll    %cl, %eax
 1755         orl     %eax, %edx
 1756 
 1757         movzbl  B_ARG1, %eax
 1758         andb    $3, %al
 1759         addb    $0x10, %ecx
 1760         shll    %cl, %eax
 1761         orl     %eax, %edx
 1762 
 1763         movzbl  B_ARG2, %eax
 1764         andb    $3, %al
 1765         addb    $0x2, %ecx
 1766         shll    %cl, %eax
 1767         orl     %eax, %edx
 1768 
 1769         movl    %edx, %db7
 1770         movl    %edx,_dr_addr+7*4
 1771         movl    %edx, %eax
 1772         leave
 1773         ret
 1774 
 1775         .data
 1776 dr_msk:
 1777         .long   ~0x000f0003
 1778         .long   ~0x00f0000c
 1779         .long   ~0x0f000030
 1780         .long   ~0xf00000c0
 1781 ENTRY(dr_addr)
 1782         .long   0,0,0,0
 1783         .long   0,0,0,0
 1784         .text
 1785 
 1786 /*
 1787  * Waste 10 microseconds.
 1788  */
 1789 ENTRY(tenmicrosec)
 1790         movl    _microdata,%ecx         /* cycle count for 10 microsecond loop */
 1791 tenmicroloop:
 1792         loop    tenmicroloop
 1793         ret
 1794 

Cache object: 5c578a6c67c5c94f3e8e9f84ebe76b71


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.