Annotation of XNU/osfmk/i386/locore.s, revision 1.1

1.1     ! root        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  [email protected]
        !            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
        !            98: locore_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) ;\
        !           115: LEXT(recover_table)            ;\
        !           116:        .text
        !           117: 
        !           118: #define        RECOVER(addr)           \
        !           119:        .align  2;              \
        !           120:        .long   9f              ;\
        !           121:        .long   addr            ;\
        !           122:        .text                   ;\
        !           123: 9:
        !           124: 
        !           125: #define        RECOVER_TABLE_END               \
        !           126:        .align  2                       ;\
        !           127:        .globl  EXT(recover_table_end)  ;\
        !           128: LEXT(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) ;\
        !           137: LEXT(retry_table)              ;\
        !           138:        .text
        !           139: 
        !           140: #define        RETRY(addr)             \
        !           141:        .align 3                ;\
        !           142:        .long   9f              ;\
        !           143:        .long   addr            ;\
        !           144:        .text                   ;\
        !           145: 9:
        !           146: 
        !           147: #define        RETRY_TABLE_END                 \
        !           148:        .align 3;                       \
        !           149:        .globl  EXT(retry_table_end)    ;\
        !           150: LEXT(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 */   ;\
        !           202: 0:     addl    $(TH_SYS_TIMER-TH_USER_TIMER),%ecx                      ;\
        !           203:                                                /* switch to sys timer */;\
        !           204:        movl    %ecx,CX(EXT(current_timer),%edx) /* make it current */  ;\
        !           205:        sti                                     /* allow interrupts */
        !           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 */   ;\
        !           223: 0:     addl    $(TH_USER_TIMER-TH_SYS_TIMER),%ecx                      ;\
        !           224:                                                /* switch to user timer */;\
        !           225:        movl    %ecx,CX(EXT(current_timer),%edx) /* make it current */
        !           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 */   ;\
        !           260: 0:     testb   $0x80,LOW_BITS+3(%ebx)          /* old timer overflow? */;\
        !           261:        jz      0f                              /* if overflow, */      ;\
        !           262:        movl    %ebx,%ecx                       /* get old timer */     ;\
        !           263:        call    timer_normalize                 /* normalize timer */   ;\
        !           264: 0:     movl    %ebx,CX(EXT(current_timer),%edx) /* set timer */
        !           265: 
        !           266: 
        !           267: /*
        !           268:  * Normalize timer in ecx.
        !           269:  * Preserves edx; clobbers eax.
        !           270:  */
        !           271:        .align  ALIGN
        !           272: timer_high_unit:
        !           273:        .long   TIMER_HIGH_UNIT                 /* div has no immediate opnd */
        !           274: 
        !           275: timer_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:  */
        !           292: Entry(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 */
        !           302: 0:
        !           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:  */
        !           310: Entry(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                                                 ;\
        !           378: 1:                                                                     ;\
        !           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 ;\
        !           399: label/**/count: ;\
        !           400:        .long   0 ;\
        !           401:        .globl label/**/limit ;\
        !           402: label/**/limit: ;\
        !           403:        .long   0 ;\
        !           404:        .text ;\
        !           405:        addl    $1,%ss:label/**/count ;\
        !           406:        cmpl    $0,label/**/limit ;\
        !           407:        jz      label/**/exit ;\
        !           408:        pushl   %eax ;\
        !           409: label/**/loop: ;\
        !           410:        movl    %ss:label/**/count,%eax ;\
        !           411:        cmpl    %eax,%ss:label/**/limit ;\
        !           412:        je      label/**/loop ;\
        !           413:        popl    %eax ;\
        !           414: label/**/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:  */
        !           450: Entry(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:  */
        !           457: Entry(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:  */
        !           464: Entry(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:  */
        !           471: Entry(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:  */
        !           480: Entry(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:  */
        !           548: Entry(t_gen_prot)
        !           549:        pushl   $(T_GENERAL_PROTECTION) /* indicate fault type */
        !           550:        jmp     trap_check_kernel_exit  /* check for kernel exit sequence */
        !           551: 
        !           552: Entry(t_segnp)
        !           553:        pushl   $(T_SEGMENT_NOT_PRESENT)
        !           554:                                        /* indicate fault type */
        !           555: 
        !           556: trap_check_kernel_exit:
        !           557:        testl   $(EFL_VM),16(%esp)      /* is trap from V86 mode? */
        !           558:        jnz     EXT(alltraps)           /* isn`t kernel trap if so */
        !           559:        testl   $3,12(%esp)             /* is trap from kernel mode? */
        !           560:        jne     EXT(alltraps)           /* if so: */
        !           561:                                        /* check for the kernel exit sequence */
        !           562:        cmpl    $EXT(kret_iret),8(%esp) /* on IRET? */
        !           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
        !           572: take_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:  */
        !           591: fault_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:  */
        !           606: fault_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) */
        !           611: fault_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) */
        !           616: fault_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) */
        !           621: fault_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: 
        !           627: push_es:
        !           628:        pushl   %es                     /* restore es, */
        !           629: push_fs:
        !           630:        pushl   %fs                     /* restore fs, */
        !           631: push_gs:
        !           632:        pushl   %gs                     /* restore gs. */
        !           633: push_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:  */
        !           645: Entry(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: 
        !           657: 0:     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:  */
        !           664: Entry(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:  */
        !           684: Entry(alltraps)
        !           685:        pusha                           /* save the general registers */
        !           686: trap_push_segs:
        !           687:        pushl   %ds                     /* save the segment registers */
        !           688:        pushl   %es
        !           689:        pushl   %fs
        !           690:        pushl   %gs
        !           691: 
        !           692: trap_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
        !           708: trap_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: 
        !           727: trap_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 */
        !           737: LEXT(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: 
        !           748: LEXT(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:  */
        !           767: LEXT(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: 
        !           791: LEXT(return_from_kernel)
        !           792: LEXT(kret_popl_gs)
        !           793:        popl    %gs                     /* restore segment registers */
        !           794: LEXT(kret_popl_fs)
        !           795:        popl    %fs
        !           796: LEXT(kret_popl_es)
        !           797:        popl    %es
        !           798: LEXT(kret_popl_ds)
        !           799:        popl    %ds
        !           800:        popa                            /* restore general registers */
        !           801:        addl    $8,%esp                 /* discard trap number and error code */
        !           802: 
        !           803: LEXT(kret_iret)
        !           804:        iret                            /* return from interrupt */
        !           805: 
        !           806: 
        !           807: LEXT(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:  */
        !           837: LEXT(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:  */
        !           854: trap_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)
        !           872: 0:                                      /* 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 */
        !           877: 1:
        !           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)
        !           886: 2:
        !           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: 
        !           902: 3:
        !           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
        !           924: 4:
        !           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 */
        !           933: 5:
        !           934:        movl    CX(EXT(kernel_stack),%edx),%esp
        !           935: 6:
        !           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:         */
        !           945: 7:
        !           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 */
        !           969: 8:
        !           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
        !          1002: 0:      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)
        !          1020: LEXT(thread_exception_return)
        !          1021: LEXT(thread_bootstrap_return)
        !          1022:        movl    %esp,%ecx                       /* get kernel stack */
        !          1023:        or      $(KERNEL_STACK_SIZE-1),%ecx
        !          1024:        movl    -3-IKS_SIZE(%ecx),%esp          /* switch back to PCB stack */
        !          1025:        jmp     EXT(return_from_trap)
        !          1026: 
        !          1027: Entry(call_continuation)
        !          1028:        movl    S_ARG0,%eax                     /* get continuation */
        !          1029:        movl    %esp,%ecx                       /* get kernel stack */
        !          1030:        or      $(KERNEL_STACK_SIZE-1),%ecx
        !          1031:        addl    $(-3-IKS_SIZE),%ecx
        !          1032:        movl    %ecx,%esp                       /* pop the stack */
        !          1033:        xorl    %ebp,%ebp                       /* zero frame pointer */
        !          1034:        jmp     *%eax                           /* goto continuation */
        !          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:         
        !          1055: imsg_start:
        !          1056:        String  "interrupt start"
        !          1057: imsg_end:
        !          1058:        String  "interrupt end"
        !          1059: 
        !          1060: /*
        !          1061:  * All interrupts enter here.
        !          1062:  * old %eax on stack; interrupt number in %eax.
        !          1063:  */
        !          1064: Entry(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:        xchgl   %ecx,%esp               /* switch to interrupt stack */
        !          1084: 
        !          1085: #if    STAT_TIME
        !          1086:        pushl   %ecx                    /* save pointer to old stack */
        !          1087: #else
        !          1088:        pushl   %ebx                    /* save %ebx - out of the way */
        !          1089:                                        /* so stack looks the same */
        !          1090:        pushl   %ecx                    /* save pointer to old stack */
        !          1091:        TIME_INT_ENTRY                  /* do timing */
        !          1092: #endif
        !          1093: 
        !          1094: #if    MACH_RT
        !          1095:        movl    $CPD_PREEMPTION_LEVEL,%edx
        !          1096:        incl    %gs:(%edx)
        !          1097: #endif /* MACH_RT */
        !          1098: 
        !          1099:        movl    $CPD_INTERRUPT_LEVEL,%edx
        !          1100:        incl    %gs:(%edx)
        !          1101: 
        !          1102:        pushl   %eax                            /* Push trap number */
        !          1103:        call    EXT(PE_incoming_interrupt)              /* call generic interrupt routine */
        !          1104:        addl    $4,%esp                 /* Pop trap number */
        !          1105: 
        !          1106:        .globl  EXT(return_to_iret)
        !          1107: LEXT(return_to_iret)                   /* (label for kdb_kintr and hardclock) */
        !          1108: 
        !          1109:        movl    $CPD_INTERRUPT_LEVEL,%edx
        !          1110:        decl    %gs:(%edx)
        !          1111: 
        !          1112: #if    MACH_RT
        !          1113:        movl    $CPD_PREEMPTION_LEVEL,%edx
        !          1114:        decl    %gs:(%edx)
        !          1115: #endif /* MACH_RT */
        !          1116: 
        !          1117: #if    STAT_TIME
        !          1118: #else
        !          1119:        TIME_INT_EXIT                   /* do timing */
        !          1120:        movl    4(%esp),%ebx            /* restore the extra reg we saved */
        !          1121: #endif
        !          1122: 
        !          1123:        popl    %esp                    /* switch back to old stack */
        !          1124: 
        !          1125:        CPU_NUMBER(%edx)
        !          1126:        movl    CX(EXT(need_ast),%edx),%eax
        !          1127:        testl   %eax,%eax               /* any pending asts? */
        !          1128:        je      1f                      /* no, nothing to do */
        !          1129:        testl   $(EFL_VM),I_EFL(%esp)   /* if in V86 */
        !          1130:        jnz     ast_from_interrupt      /* take it */
        !          1131:        testb   $3,I_CS(%esp)           /* user mode, */
        !          1132:        jnz     ast_from_interrupt      /* take it */
        !          1133: #ifdef FIXME
        !          1134:        cmpl    ETEXT_ADDR,I_EIP(%esp) /* if within kernel-loaded task, */
        !          1135:        jnb     ast_from_interrupt      /* take it */
        !          1136: #endif
        !          1137: 
        !          1138: #if    MACH_RT
        !          1139:        cmpl    $0,EXT(preemptable)     /* kernel-mode, preemption enabled? */
        !          1140:        je      1f                      /* no, skip it */
        !          1141:        movl    $CPD_PREEMPTION_LEVEL,%ecx
        !          1142:        cmpl    $0,%gs:(%ecx)           /* preemption masked? */
        !          1143:        jne     1f                      /* yes, skip it */
        !          1144:        testl   $AST_URGENT,%eax        /* any urgent requests? */
        !          1145:        je      1f                      /* no, skip it */
        !          1146:        cmpl    $LEXT(locore_end),I_EIP(%esp)   /* are we in locore code? */
        !          1147:        jb      1f                      /* yes, skip it */
        !          1148:        movl    CX(EXT(kernel_stack),%edx),%eax
        !          1149:        movl    %esp,%ecx
        !          1150:        xorl    %eax,%ecx
        !          1151:        andl    $(-KERNEL_STACK_SIZE),%ecx
        !          1152:        testl   %ecx,%ecx               /* are we on the kernel stack? */
        !          1153:        jne     1f                      /* no, skip it */
        !          1154: 
        !          1155: /*
        !          1156:  * Take an AST from kernel space.  We don't need (and don't want)
        !          1157:  * to do as much as the case where the interrupt came from user
        !          1158:  * space.
        !          1159:  */
        !          1160: #if    PREEMPT_DEBUG_LOG
        !          1161:        pushl   $0
        !          1162:        pushl   $0
        !          1163:        pushl   I_EIP+8(%esp)
        !          1164:        pushl   $0f
        !          1165:        call    EXT(log_thread_action)
        !          1166:        addl    $16, %esp
        !          1167:        .data
        !          1168: 0:     String  "intr preempt eip"
        !          1169:        .text
        !          1170: #endif /* PREEMPT_DEBUG_LOG */
        !          1171: 
        !          1172:        sti
        !          1173:        pushl   $1                      /* push preemption flag */
        !          1174:        call    EXT(i386_astintr)       /* take the AST */
        !          1175:        addl    $4,%esp                 /* pop preemption flag */
        !          1176: #endif /* MACH_RT */
        !          1177: 
        !          1178: 1:
        !          1179:        pop     %es                     /* restore segment regs */
        !          1180:        pop     %ds
        !          1181:        pop     %edx
        !          1182:        pop     %ecx
        !          1183:        pop     %eax
        !          1184:        iret                            /* return to caller */
        !          1185: 
        !          1186: int_from_intstack:
        !          1187: #if    MACH_RT
        !          1188:        movl    $CPD_PREEMPTION_LEVEL,%edx
        !          1189:        incl    %gs:(%edx)
        !          1190: #endif /* MACH_RT */
        !          1191: 
        !          1192:        movl    $CPD_INTERRUPT_LEVEL,%edx
        !          1193:        incl    %gs:(%edx)
        !          1194: 
        !          1195:        pushl   %eax                    /* Push trap number */
        !          1196: 
        !          1197:        call    EXT(PE_incoming_interrupt)
        !          1198: 
        !          1199: LEXT(return_to_iret_i)                 /* ( label for kdb_kintr) */
        !          1200: 
        !          1201:        addl    $4,%esp                 /* pop trap number */
        !          1202: 
        !          1203:        movl    $CPD_INTERRUPT_LEVEL,%edx
        !          1204:        decl    %gs:(%edx)
        !          1205: 
        !          1206: #if    MACH_RT
        !          1207:        movl    $CPD_PREEMPTION_LEVEL,%edx
        !          1208:        decl    %gs:(%edx)
        !          1209: #endif /* MACH_RT */
        !          1210: 
        !          1211:        pop     %edx                    /* must have been on kernel segs */
        !          1212:        pop     %ecx
        !          1213:        pop     %eax                    /* no ASTs */
        !          1214:        iret
        !          1215: 
        !          1216: /*
        !          1217:  *     Take an AST from an interrupt.
        !          1218:  *     On PCB stack.
        !          1219:  * sp->        es      -> edx
        !          1220:  *     ds      -> ecx
        !          1221:  *     edx     -> eax
        !          1222:  *     ecx     -> trapno
        !          1223:  *     eax     -> code
        !          1224:  *     eip
        !          1225:  *     cs
        !          1226:  *     efl
        !          1227:  *     esp
        !          1228:  *     ss
        !          1229:  */
        !          1230: ast_from_interrupt:
        !          1231:        pop     %es                     /* restore all registers ... */
        !          1232:        pop     %ds
        !          1233:        popl    %edx
        !          1234:        popl    %ecx
        !          1235:        popl    %eax
        !          1236:        sti                             /* Reenable interrupts */
        !          1237:        pushl   $0                      /* zero code */
        !          1238:        pushl   $0                      /* zero trap number */
        !          1239:        pusha                           /* save general registers */
        !          1240:        push    %ds                     /* save segment registers */
        !          1241:        push    %es
        !          1242:        push    %fs
        !          1243:        push    %gs
        !          1244:        mov     %ss,%dx                 /* switch to kernel segments */
        !          1245:        mov     %dx,%ds
        !          1246:        mov     %dx,%es
        !          1247:        mov     $CPU_DATA,%dx
        !          1248:        mov     %dx,%gs
        !          1249: 
        !          1250:        /*
        !          1251:         * See if we interrupted a kernel-loaded thread executing
        !          1252:         * in its own task.
        !          1253:         */
        !          1254:        CPU_NUMBER(%edx)
        !          1255:        testl   $(EFL_VM),R_EFLAGS(%esp) /* in V86 mode? */
        !          1256:        jnz     0f                      /* user mode trap if so */
        !          1257:        testb   $3,R_CS(%esp)           
        !          1258:        jnz     0f                      /* user mode, back to normal */
        !          1259: #ifdef FIXME
        !          1260:        cmpl    ETEXT_ADDR,R_EIP(%esp)
        !          1261:        jb      0f                      /* not kernel-loaded, back to normal */
        !          1262: #endif
        !          1263: 
        !          1264:        /*
        !          1265:         * Transfer the current stack frame by hand into the PCB.
        !          1266:         */
        !          1267:        CAH(afistart)
        !          1268:        movl    CX(EXT(active_kloaded),%edx),%eax
        !          1269:        movl    CX(EXT(kernel_stack),%edx),%ebx
        !          1270:        xchgl   %ebx,%esp
        !          1271:        FRAME_STACK_TO_PCB(%eax,%ebx)
        !          1272:        CAH(afiend)
        !          1273:        TIME_TRAP_UENTRY
        !          1274:        jmp     3f
        !          1275: 0:
        !          1276:        TIME_TRAP_UENTRY
        !          1277: 
        !          1278:        movl    CX(EXT(kernel_stack),%edx),%eax
        !          1279:                                        /* switch to kernel stack */
        !          1280:        xchgl   %eax,%esp
        !          1281: 3:
        !          1282:        pushl   %eax
        !          1283:        pushl   $0                      /* push preemption flag */
        !          1284:        call    EXT(i386_astintr)       /* take the AST */
        !          1285:        addl    $4,%esp                 /* pop preemption flag */
        !          1286:        popl    %esp                    /* back to PCB stack */
        !          1287:        jmp     EXT(return_from_trap)   /* return */
        !          1288: 
        !          1289: #if    MACH_KDB || MACH_KGDB 
        !          1290: /*
        !          1291:  * kdb_kintr:  enter kdb from keyboard interrupt.
        !          1292:  * Chase down the stack frames until we find one whose return
        !          1293:  * address is the interrupt handler.   At that point, we have:
        !          1294:  *
        !          1295:  * frame->     saved %ebp
        !          1296:  *             return address in interrupt handler
        !          1297:  *             ivect
        !          1298:  *             saved SPL
        !          1299:  *             return address == return_to_iret_i
        !          1300:  *             saved %edx
        !          1301:  *             saved %ecx
        !          1302:  *             saved %eax
        !          1303:  *             saved %eip
        !          1304:  *             saved %cs
        !          1305:  *             saved %efl
        !          1306:  *
        !          1307:  * OR:
        !          1308:  * frame->     saved %ebp
        !          1309:  *             return address in interrupt handler
        !          1310:  *             ivect
        !          1311:  *             saved SPL
        !          1312:  *             return address == return_to_iret
        !          1313:  *             pointer to save area on old stack
        !          1314:  *           [ saved %ebx, if accurate timing ]
        !          1315:  *
        !          1316:  * old stack:  saved %es
        !          1317:  *             saved %ds
        !          1318:  *             saved %edx
        !          1319:  *             saved %ecx
        !          1320:  *             saved %eax
        !          1321:  *             saved %eip
        !          1322:  *             saved %cs
        !          1323:  *             saved %efl
        !          1324:  *
        !          1325:  * Call kdb, passing it that register save area.
        !          1326:  */
        !          1327: 
        !          1328: #if MACH_KGDB
        !          1329: Entry(kgdb_kintr)
        !          1330: #endif /* MACH_KGDB */
        !          1331: #if MACH_KDB
        !          1332: Entry(kdb_kintr)
        !          1333: #endif /* MACH_KDB */
        !          1334:        movl    %ebp,%eax               /* save caller`s frame pointer */
        !          1335:        movl    $EXT(return_to_iret),%ecx /* interrupt return address 1 */
        !          1336:        movl    $EXT(return_to_iret_i),%edx /* interrupt return address 2 */
        !          1337: 
        !          1338: 0:     cmpl    16(%eax),%ecx           /* does this frame return to */
        !          1339:                                        /* interrupt handler (1)? */
        !          1340:        je      1f
        !          1341:        cmpl    $kdb_from_iret,16(%eax)
        !          1342:        je      1f
        !          1343:        cmpl    16(%eax),%edx           /* interrupt handler (2)? */
        !          1344:        je      2f                      /* if not: */
        !          1345:        cmpl    $kdb_from_iret_i,16(%eax)
        !          1346:        je      2f
        !          1347:        movl    (%eax),%eax             /* try next frame */
        !          1348:        jmp     0b
        !          1349: 
        !          1350: 1:     movl    $kdb_from_iret,16(%eax) /* returns to kernel/user stack */
        !          1351:        ret
        !          1352: 
        !          1353: 2:     movl    $kdb_from_iret_i,16(%eax)
        !          1354:                                        /* returns to interrupt stack */
        !          1355:        ret
        !          1356: 
        !          1357: /*
        !          1358:  * On return from keyboard interrupt, we will execute
        !          1359:  * kdb_from_iret_i
        !          1360:  *     if returning to an interrupt on the interrupt stack
        !          1361:  * kdb_from_iret
        !          1362:  *     if returning to an interrupt on the user or kernel stack
        !          1363:  */
        !          1364: kdb_from_iret:
        !          1365:                                        /* save regs in known locations */
        !          1366: #if    STAT_TIME
        !          1367:        pushl   %ebx                    /* caller`s %ebx is in reg */
        !          1368: #else
        !          1369:        movl    4(%esp),%eax            /* get caller`s %ebx */
        !          1370:        pushl   %eax                    /* push on stack */
        !          1371: #endif
        !          1372:        pushl   %ebp
        !          1373:        pushl   %esi
        !          1374:        pushl   %edi
        !          1375:        push    %fs
        !          1376:        push    %gs
        !          1377: #if MACH_KGDB
        !          1378:        cli
        !          1379:         pushl   %esp                    /* pass regs */
        !          1380:         call    EXT(kgdb_kentry)        /* to kgdb */
        !          1381:         addl    $4,%esp                 /* pop parameters */
        !          1382: #endif /* MACH_KGDB */
        !          1383: #if MACH_KDB
        !          1384:        pushl   %esp                    /* pass regs */
        !          1385:         call    EXT(kdb_kentry)                /* to kdb */
        !          1386:        addl    $4,%esp                 /* pop parameters */
        !          1387: #endif /* MACH_KDB */
        !          1388:        pop     %gs                     /* restore registers */
        !          1389:        pop     %fs
        !          1390:        popl    %edi
        !          1391:        popl    %esi
        !          1392:        popl    %ebp
        !          1393: #if    STAT_TIME
        !          1394:        popl    %ebx
        !          1395: #else
        !          1396:        popl    %eax
        !          1397:        movl    %eax,4(%esp)
        !          1398: #endif
        !          1399:        jmp     EXT(return_to_iret)     /* normal interrupt return */
        !          1400: 
        !          1401: kdb_from_iret_i:                       /* on interrupt stack */
        !          1402:        pop     %edx                    /* restore saved registers */
        !          1403:        pop     %ecx
        !          1404:        pop     %eax
        !          1405:        pushl   $0                      /* zero error code */
        !          1406:        pushl   $0                      /* zero trap number */
        !          1407:        pusha                           /* save general registers */
        !          1408:        push    %ds                     /* save segment registers */
        !          1409:        push    %es
        !          1410:        push    %fs
        !          1411:        push    %gs
        !          1412: #if MACH_KGDB
        !          1413:        cli                             /* disable interrupts */
        !          1414:         CPU_NUMBER(%edx)                /* get CPU number */
        !          1415:         movl    CX(EXT(kgdb_stacks),%edx),%ebx
        !          1416:         xchgl   %ebx,%esp               /* switch to kgdb stack */
        !          1417:         pushl   %ebx                    /* pass old sp as an arg */
        !          1418:         call    EXT(kgdb_from_kernel)
        !          1419:         popl    %esp                    /* switch back to interrupt stack */
        !          1420: #endif /* MACH_KGDB */
        !          1421: #if MACH_KDB
        !          1422:         pushl   %esp                    /* pass regs, */
        !          1423:         pushl   $0                      /* code, */
        !          1424:         pushl   $-1                     /* type to kdb */
        !          1425:         call    EXT(kdb_trap)
        !          1426:         addl    $12,%esp
        !          1427: #endif /* MACH_KDB */
        !          1428:        pop     %gs                     /* restore segment registers */
        !          1429:        pop     %fs
        !          1430:        pop     %es
        !          1431:        pop     %ds
        !          1432:        popa                            /* restore general registers */
        !          1433:        addl    $8,%esp
        !          1434:        iret
        !          1435: 
        !          1436: #endif /* MACH_KDB || MACH_KGDB */
        !          1437: 
        !          1438: 
        !          1439: /*
        !          1440:  * Mach RPC enters through a call gate, like a system call.
        !          1441:  */
        !          1442: 
        !          1443: Entry(mach_rpc)
        !          1444:        pushf                           /* save flags as soon as possible */
        !          1445:        pushl   %eax                    /* save system call number */
        !          1446:        pushl   $0                      /* clear trap number slot */
        !          1447: 
        !          1448:        pusha                           /* save the general registers */
        !          1449:        pushl   %ds                     /* and the segment registers */
        !          1450:        pushl   %es
        !          1451:        pushl   %fs
        !          1452:        pushl   %gs
        !          1453: 
        !          1454:        mov     %ss,%dx                 /* switch to kernel data segment */
        !          1455:        mov     %dx,%ds
        !          1456:        mov     %dx,%es
        !          1457:        mov     $CPU_DATA,%dx
        !          1458:        mov     %dx,%gs
        !          1459: 
        !          1460: /*
        !          1461:  * Shuffle eflags,eip,cs into proper places
        !          1462:  */
        !          1463: 
        !          1464:        movl    R_EIP(%esp),%ebx        /* eflags are in EIP slot */
        !          1465:        movl    R_CS(%esp),%ecx         /* eip is in CS slot */
        !          1466:        movl    R_EFLAGS(%esp),%edx     /* cs is in EFLAGS slot */
        !          1467:        movl    %ecx,R_EIP(%esp)        /* fix eip */
        !          1468:        movl    %edx,R_CS(%esp)         /* fix cs */
        !          1469:        movl    %ebx,R_EFLAGS(%esp)     /* fix eflags */
        !          1470: 
        !          1471:        CPU_NUMBER(%edx)
        !          1472:         TIME_TRAP_UENTRY
        !          1473: 
        !          1474:         negl    %eax                    /* get system call number */
        !          1475:         shll    $4,%eax                 /* manual indexing */
        !          1476: 
        !          1477: /*
        !          1478:  * Check here for mach_rpc from kernel-loaded task --
        !          1479:  *  - Note that kernel-loaded task returns via real return.
        !          1480:  * We didn't enter here "through" PCB (i.e., using ring 0 stack),
        !          1481:  * so transfer the stack frame into the PCB explicitly, then
        !          1482:  * start running on resulting "PCB stack".  We have to set
        !          1483:  * up a simulated "uesp" manually, since there's none in the
        !          1484:  * frame.
        !          1485:  */
        !          1486:         cmpl    $0,CX(EXT(active_kloaded),%edx)
        !          1487:         jz      2f
        !          1488:         CAH(mrstart)
        !          1489:         movl    CX(EXT(active_kloaded),%edx),%ebx
        !          1490:         movl    CX(EXT(kernel_stack),%edx),%edx
        !          1491:         xchgl   %edx,%esp
        !          1492: 
        !          1493:         FRAME_STACK_TO_PCB(%ebx,%edx)
        !          1494:         CAH(mrend)
        !          1495: 
        !          1496:         CPU_NUMBER(%edx)
        !          1497:         jmp     3f
        !          1498: 
        !          1499: 2:
        !          1500:        CPU_NUMBER(%edx)
        !          1501:        movl    CX(EXT(kernel_stack),%edx),%ebx
        !          1502:                                        /* get current kernel stack */
        !          1503:        xchgl   %ebx,%esp               /* switch stacks - %ebx points to */
        !          1504:                                        /* user registers. */
        !          1505: 
        !          1506: 3:
        !          1507: 
        !          1508: /*
        !          1509:  * Register use on entry:
        !          1510:  *   eax contains syscall number
        !          1511:  *   ebx contains user regs pointer
        !          1512:  */
        !          1513: #undef         RPC_TRAP_REGISTERS
        !          1514: #ifdef RPC_TRAP_REGISTERS
        !          1515:        pushl   R_ESI(%ebx)
        !          1516:        pushl   R_EDI(%ebx)
        !          1517:        pushl   R_ECX(%ebx)
        !          1518:        pushl   R_EDX(%ebx)
        !          1519: #else
        !          1520:        movl    EXT(mach_trap_table)(%eax),%ecx
        !          1521:                                        /* get number of arguments */
        !          1522:        jecxz   2f                      /* skip argument copy if none */
        !          1523:        movl    R_UESP(%ebx),%esi       /* get user stack pointer */
        !          1524:        lea     4(%esi,%ecx,4),%esi     /* skip user return address, */
        !          1525:                                        /* and point past last argument */
        !          1526:        /* edx holds cpu number from above */
        !          1527:        movl    CX(EXT(active_kloaded),%edx),%edx
        !          1528:                                        /* point to current thread */
        !          1529:        orl     %edx,%edx               /* if ! kernel-loaded, check addr */
        !          1530:        jz      4f                      /* else */
        !          1531:        mov     %ds,%dx                 /* kernel data segment access */
        !          1532:        jmp     5f
        !          1533: 4:
        !          1534:        cmpl    $(VM_MAX_ADDRESS),%esi  /* in user space? */
        !          1535:        ja      mach_call_addr          /* address error if not */
        !          1536:        movl    $USER_DS,%edx           /* user data segment access */
        !          1537: 5:
        !          1538:        mov     %dx,%fs
        !          1539:        movl    %esp,%edx               /* save kernel ESP for error recovery */
        !          1540: 1:
        !          1541:        subl    $4,%esi
        !          1542:        RECOVERY_SECTION
        !          1543:        RECOVER(mach_call_addr_push)
        !          1544:        pushl   %fs:(%esi)              /* push argument on stack */
        !          1545:        loop    1b                      /* loop for all arguments */
        !          1546: #endif
        !          1547: 
        !          1548: /*
        !          1549:  * Register use on entry:
        !          1550:  *   eax contains syscall number
        !          1551:  *   ebx contains user regs pointer
        !          1552:  */
        !          1553: 2:
        !          1554:        CAH(call_call)
        !          1555:        call    *EXT(mach_trap_table)+4(%eax)
        !          1556:                                        /* call procedure */
        !          1557:        movl    %esp,%ecx               /* get kernel stack */
        !          1558:        or      $(KERNEL_STACK_SIZE-1),%ecx
        !          1559:        movl    -3-IKS_SIZE(%ecx),%esp  /* switch back to PCB stack */
        !          1560:        movl    %eax,R_EAX(%esp)        /* save return value */
        !          1561:        jmp     EXT(return_from_trap)   /* return to user */
        !          1562: 
        !          1563: 
        !          1564: /*
        !          1565:  * Special system call entry for "int 0x80", which has the "eflags"
        !          1566:  * register saved at the right place already.
        !          1567:  * Fall back to the common syscall path after saving the registers.
        !          1568:  *
        !          1569:  * esp ->      old eip
        !          1570:  *             old cs
        !          1571:  *             old eflags
        !          1572:  *             old esp         if trapped from user
        !          1573:  *             old ss          if trapped from user
        !          1574:  *
        !          1575:  * XXX:        for the moment, we don't check for int 0x80 from kernel mode.
        !          1576:  */
        !          1577: Entry(syscall_int80)
        !          1578:        pushl   %eax                    /* save system call number */
        !          1579:        pushl   $0                      /* clear trap number slot */
        !          1580: 
        !          1581:        pusha                           /* save the general registers */
        !          1582:        pushl   %ds                     /* and the segment registers */
        !          1583:        pushl   %es
        !          1584:        pushl   %fs
        !          1585:        pushl   %gs
        !          1586: 
        !          1587:        mov     %ss,%dx                 /* switch to kernel data segment */
        !          1588:        mov     %dx,%ds
        !          1589:        mov     %dx,%es
        !          1590:        mov     $CPU_DATA,%dx
        !          1591:        mov     %dx,%gs
        !          1592: 
        !          1593:        jmp     syscall_entry_3
        !          1594: 
        !          1595: /*
        !          1596:  * System call enters through a call gate.  Flags are not saved -
        !          1597:  * we must shuffle stack to look like trap save area.
        !          1598:  *
        !          1599:  * esp->       old eip
        !          1600:  *             old cs
        !          1601:  *             old esp
        !          1602:  *             old ss
        !          1603:  *
        !          1604:  * eax contains system call number.
        !          1605:  *
        !          1606:  * NB: below use of CPU_NUMBER assumes that macro will use correct
        !          1607:  * correct segment register for any kernel data accesses.
        !          1608:  */
        !          1609: Entry(syscall)
        !          1610: syscall_entry:
        !          1611:        pushf                           /* save flags as soon as possible */
        !          1612: syscall_entry_2:
        !          1613:        pushl   %eax                    /* save system call number */
        !          1614:        pushl   $0                      /* clear trap number slot */
        !          1615: 
        !          1616:        pusha                           /* save the general registers */
        !          1617:        pushl   %ds                     /* and the segment registers */
        !          1618:        pushl   %es
        !          1619:        pushl   %fs
        !          1620:        pushl   %gs
        !          1621: 
        !          1622:        mov     %ss,%dx                 /* switch to kernel data segment */
        !          1623:        mov     %dx,%ds
        !          1624:        mov     %dx,%es
        !          1625:        mov     $CPU_DATA,%dx
        !          1626:        mov     %dx,%gs
        !          1627: 
        !          1628: /*
        !          1629:  * Shuffle eflags,eip,cs into proper places
        !          1630:  */
        !          1631: 
        !          1632:        movl    R_EIP(%esp),%ebx        /* eflags are in EIP slot */
        !          1633:        movl    R_CS(%esp),%ecx         /* eip is in CS slot */
        !          1634:        movl    R_EFLAGS(%esp),%edx     /* cs is in EFLAGS slot */
        !          1635:        movl    %ecx,R_EIP(%esp)        /* fix eip */
        !          1636:        movl    %edx,R_CS(%esp)         /* fix cs */
        !          1637:        movl    %ebx,R_EFLAGS(%esp)     /* fix eflags */
        !          1638: 
        !          1639: syscall_entry_3:
        !          1640:        CPU_NUMBER(%edx)
        !          1641: /*
        !          1642:  * Check here for syscall from kernel-loaded task --
        !          1643:  * We didn't enter here "through" PCB (i.e., using ring 0 stack),
        !          1644:  * so transfer the stack frame into the PCB explicitly, then
        !          1645:  * start running on resulting "PCB stack".  We have to set
        !          1646:  * up a simulated "uesp" manually, since there's none in the
        !          1647:  * frame.
        !          1648:  */
        !          1649:        cmpl    $0,CX(EXT(active_kloaded),%edx)
        !          1650:        jz      0f
        !          1651:        CAH(scstart)
        !          1652:        movl    CX(EXT(active_kloaded),%edx),%ebx
        !          1653:        movl    CX(EXT(kernel_stack),%edx),%edx
        !          1654:        xchgl   %edx,%esp
        !          1655:        FRAME_STACK_TO_PCB(%ebx,%edx)
        !          1656:        CAH(scend)
        !          1657:        TIME_TRAP_UENTRY
        !          1658:        CPU_NUMBER(%edx)
        !          1659:        jmp     1f
        !          1660: 
        !          1661: 0:
        !          1662:        TIME_TRAP_UENTRY
        !          1663: 
        !          1664:        CPU_NUMBER(%edx)
        !          1665:        movl    CX(EXT(kernel_stack),%edx),%ebx
        !          1666:                                        /* get current kernel stack */
        !          1667:        xchgl   %ebx,%esp               /* switch stacks - %ebx points to */
        !          1668:                                        /* user registers. */
        !          1669:                                        /* user regs pointer already set */
        !          1670: 
        !          1671: /*
        !          1672:  * Check for MACH or emulated system call
        !          1673:  * Register use (from here till we begin processing call):
        !          1674:  *   eax contains system call number
        !          1675:  *   ebx points to user regs
        !          1676:  */
        !          1677: 1:
        !          1678:        movl    $CPD_ACTIVE_THREAD,%edx
        !          1679:        movl    %gs:(%edx),%edx                 /* get active thread */
        !          1680:                                        /* point to current thread */
        !          1681:        movl    TH_TOP_ACT(%edx),%edx   /* get thread->top_act */
        !          1682:        movl    ACT_TASK(%edx),%edx     /* point to task */
        !          1683:        movl    TASK_EMUL(%edx),%edx    /* get emulation vector */
        !          1684:        orl     %edx,%edx               /* if none, */
        !          1685:        je      syscall_native          /*    do native system call */
        !          1686:        movl    %eax,%ecx               /* copy system call number */
        !          1687:        subl    DISP_MIN(%edx),%ecx     /* get displacement into syscall */
        !          1688:                                        /* vector table */
        !          1689:        jl      syscall_native          /* too low - native system call */
        !          1690:        cmpl    DISP_COUNT(%edx),%ecx   /* check range */
        !          1691:        jnl     syscall_native          /* too high - native system call */
        !          1692:        movl    DISP_VECTOR(%edx,%ecx,4),%edx
        !          1693:                                        /* get the emulation vector */
        !          1694:        orl     %edx,%edx               /* emulated system call if not zero */
        !          1695:        jnz     syscall_emul
        !          1696: 
        !          1697: /*
        !          1698:  * Native system call.
        !          1699:  * Register use on entry:
        !          1700:  *   eax contains syscall number
        !          1701:  *   ebx points to user regs
        !          1702:  */
        !          1703: syscall_native:
        !          1704:        negl    %eax                    /* get system call number */
        !          1705:        jl      mach_call_range         /* out of range if it was positive */
        !          1706: 
        !          1707:        cmpl    EXT(mach_trap_count),%eax /* check system call table bounds */
        !          1708:        jg      mach_call_range         /* error if out of range */
        !          1709:        shll    $4,%eax                 /* manual indexing */
        !          1710: 
        !          1711:        movl    EXT(mach_trap_table)+4(%eax),%edx
        !          1712:                                        /* get procedure */
        !          1713:        cmpl    $EXT(kern_invalid),%edx /* if not "kern_invalid" */
        !          1714:        jne     mach_syscall_native     /*      go on with Mach syscall */
        !          1715: 
        !          1716:        movl    $CPD_ACTIVE_THREAD,%edx
        !          1717:        movl    %gs:(%edx),%edx                 /* get active thread */
        !          1718:                                        /* point to current thread */
        !          1719:        movl    TH_TOP_ACT(%edx),%edx   /* get thread->top_act */
        !          1720:        movl    ACT_TASK(%edx),%edx     /* point to task */
        !          1721:        movl    TASK_EMUL(%edx),%edx    /* get emulation vector */
        !          1722:        orl     %edx,%edx               /* if it exists, */
        !          1723:        jne     mach_syscall_native     /*    do native system call */
        !          1724:        shrl    $4,%eax                 /* restore syscall number */
        !          1725:        jmp     mach_call_range         /* try it as a "server" syscall */
        !          1726: 
        !          1727: mach_syscall_native:
        !          1728:        movl    $CPD_ACTIVE_THREAD,%edx
        !          1729:        movl    %gs:(%edx),%edx         /* get active thread */
        !          1730: 
        !          1731:        movl    TH_TOP_ACT(%edx),%edx   /* get thread->top_act */
        !          1732:        movl    ACT_MACH_EXC_PORT(%edx),%edx
        !          1733:        movl    $EXT(realhost),%ecx
        !          1734:        movl    HOST_NAME(%ecx),%ecx
        !          1735:        cmpl    %edx,%ecx               /* act->mach_exc_port = host_name ? */
        !          1736:        je      do_native_call          /* -> send to kernel, do not collect $200 */
        !          1737:        cmpl    $0,%edx                 /* thread->mach_exc_port = null ? */
        !          1738:        je      try_task                /* try task */
        !          1739:        jmp     mach_syscall_exception
        !          1740:         /* NOT REACHED */
        !          1741: 
        !          1742: try_task:
        !          1743:        movl    $CPD_ACTIVE_THREAD,%edx
        !          1744:        movl    %gs:(%edx),%edx         /* get active thread */
        !          1745: 
        !          1746:        movl    TH_TOP_ACT(%edx),%edx   /* get thread->top_act */
        !          1747:        movl    ACT_TASK(%edx),%edx     /* point to task */
        !          1748:        movl    TASK_MACH_EXC_PORT(%edx),%edx
        !          1749:        movl    $EXT(realhost),%ecx
        !          1750:        movl    HOST_NAME(%ecx),%ecx
        !          1751:        cmpl    %edx,%ecx               /* thread->mach_exc_port = host_name ? */
        !          1752:        je      do_native_call          /* -> send to kernel */
        !          1753:        cmpl    $0,%edx                 /* thread->mach_exc_port = null ? */
        !          1754:        je      EXT(syscall_failed)     /* try task */
        !          1755:        jmp     mach_syscall_exception
        !          1756:        /* NOT REACHED */
        !          1757: 
        !          1758: /*
        !          1759:  * Register use on entry:
        !          1760:  *   eax contains syscall number
        !          1761:  *   ebx contains user regs pointer
        !          1762:  */
        !          1763: do_native_call:
        !          1764:        movl    EXT(mach_trap_table)(%eax),%ecx
        !          1765:                                        /* get number of arguments */
        !          1766:        jecxz   mach_call_call          /* skip argument copy if none */
        !          1767:        movl    R_UESP(%ebx),%esi       /* get user stack pointer */
        !          1768:        lea     4(%esi,%ecx,4),%esi     /* skip user return address, */
        !          1769:                                        /* and point past last argument */
        !          1770:        CPU_NUMBER(%edx)
        !          1771:        movl    CX(EXT(active_kloaded),%edx),%edx
        !          1772:                                        /* point to current thread */
        !          1773:        orl     %edx,%edx               /* if kernel-loaded, skip addr check */
        !          1774:        jz      0f                      /* else */
        !          1775:        mov     %ds,%dx                 /* kernel data segment access  */
        !          1776:        jmp     1f
        !          1777: 0:
        !          1778:        cmpl    $(VM_MAX_ADDRESS),%esi  /* in user space? */
        !          1779:        ja      mach_call_addr          /* address error if not */
        !          1780:        movl    $USER_DS,%edx           /* user data segment access */
        !          1781: 1:
        !          1782:        mov     %dx,%fs
        !          1783:        movl    %esp,%edx               /* save kernel ESP for error recovery */
        !          1784: 2:
        !          1785:        subl    $4,%esi
        !          1786:        RECOVERY_SECTION
        !          1787:        RECOVER(mach_call_addr_push)
        !          1788:        pushl   %fs:(%esi)              /* push argument on stack */
        !          1789:        loop    2b                      /* loop for all arguments */
        !          1790: 
        !          1791: /*
        !          1792:  * Register use on entry:
        !          1793:  *   eax contains syscall number
        !          1794:  *   ebx contains user regs pointer
        !          1795:  */
        !          1796: mach_call_call:
        !          1797: 
        !          1798:        CAH(call_call)
        !          1799: 
        !          1800: #if    ETAP_EVENT_MONITOR
        !          1801:        cmpl    $0x200, %eax                    /* is this mach_msg? */
        !          1802:        jz      make_syscall                    /* if yes, don't record event */
        !          1803: 
        !          1804:         pushal                                 /* Otherwise: save registers */
        !          1805:         pushl  %eax                            /*   push syscall number on stack*/
        !          1806:         call   EXT(etap_machcall_probe1)       /*   call event begin probe */
        !          1807:         add    $4,%esp                         /*   restore stack */
        !          1808:         popal                                  /*   restore registers */
        !          1809: 
        !          1810:        call    *EXT(mach_trap_table)+4(%eax)   /* call procedure */
        !          1811:         pushal
        !          1812:         call   EXT(etap_machcall_probe2)       /* call event end probe */
        !          1813:         popal
        !          1814:        jmp     skip_syscall                    /* syscall already made */
        !          1815: #endif /* ETAP_EVENT_MONITOR */
        !          1816: 
        !          1817: make_syscall:
        !          1818:        call    *EXT(mach_trap_table)+4(%eax)   /* call procedure */
        !          1819: skip_syscall:
        !          1820: 
        !          1821:        movl    %esp,%ecx               /* get kernel stack */
        !          1822:        or      $(KERNEL_STACK_SIZE-1),%ecx
        !          1823:        movl    -3-IKS_SIZE(%ecx),%esp  /* switch back to PCB stack */
        !          1824:        movl    %eax,R_EAX(%esp)        /* save return value */
        !          1825:        jmp     EXT(return_from_trap)   /* return to user */
        !          1826: 
        !          1827: /*
        !          1828:  * Address out of range.  Change to page fault.
        !          1829:  * %esi holds failing address.
        !          1830:  * Register use on entry:
        !          1831:  *   ebx contains user regs pointer
        !          1832:  */
        !          1833: mach_call_addr_push:
        !          1834:        movl    %edx,%esp               /* clean parameters from stack */
        !          1835: mach_call_addr:
        !          1836:        movl    %esi,R_CR2(%ebx)        /* set fault address */
        !          1837:        movl    $(T_PAGE_FAULT),R_TRAPNO(%ebx)
        !          1838:                                        /* set page-fault trap */
        !          1839:        movl    $(T_PF_USER),R_ERR(%ebx)
        !          1840:                                        /* set error code - read user space */
        !          1841:        CAH(call_addr)
        !          1842:        jmp     EXT(take_trap)          /* treat as a trap */
        !          1843: 
        !          1844: /*
        !          1845:  * try sending mach system call exception to server
        !          1846:  * Register use on entry:
        !          1847:  *   eax contains syscall number
        !          1848:  */
        !          1849: mach_syscall_exception:
        !          1850:        push    %eax                    /* code (syscall no.) */
        !          1851:        movl    %esp,%edx
        !          1852:        push    $1                      /* code_cnt = 1 */
        !          1853:        push    %edx                    /* exception_type_t (see i/f docky) */
        !          1854:        push    $EXC_MACH_SYSCALL       /* exception */
        !          1855: 
        !          1856:        CAH(exception)
        !          1857:        call    EXT(exception)
        !          1858:        /* no return */
        !          1859: 
        !          1860: /*
        !          1861:  * System call out of range.  Treat as invalid-instruction trap.
        !          1862:  * (? general protection?)
        !          1863:  * Register use on entry:
        !          1864:  *   eax contains syscall number
        !          1865:  */
        !          1866: mach_call_range:
        !          1867:        movl    $CPD_ACTIVE_THREAD,%edx
        !          1868:        movl    %gs:(%edx),%edx         /* get active thread */
        !          1869: 
        !          1870:        movl    TH_TOP_ACT(%edx),%edx   /* get thread->top_act */
        !          1871:        movl    ACT_TASK(%edx),%edx     /* point to task */
        !          1872:        movl    TASK_EMUL(%edx),%edx    /* get emulation vector */
        !          1873:        orl     %edx,%edx               /* if emulator, */
        !          1874:        jne     EXT(syscall_failed)     /*    handle as illegal instruction */
        !          1875:                                        /* else generate syscall exception: */
        !          1876:        push    %eax
        !          1877:        movl    %esp,%edx
        !          1878:        push    $1                      /* code_cnt = 1 */
        !          1879:        push    %edx                    /* exception_type_t (see i/f docky) */
        !          1880:        push    $EXC_SYSCALL
        !          1881:        CAH(call_range)
        !          1882:        call    EXT(exception)
        !          1883:        /* no return */
        !          1884: 
        !          1885: /*
        !          1886:  * Restart a mach system call after raising an exception.
        !          1887:  */
        !          1888:        .globl  EXT(restart_mach_syscall)
        !          1889: LEXT(restart_mach_syscall)
        !          1890:        movl    %esp,%ecx               /* get kernel stack */
        !          1891:        or      $(KERNEL_STACK_SIZE-1),%ecx
        !          1892:        movl    -3-IKS_SIZE(%ecx),%ebx  /* get user PCB */
        !          1893:        movl    R_EAX(%ebx),%eax        /* syscall number, */
        !          1894:        negl    %eax                    /* negate it and */
        !          1895:        shll    $4,%eax                 /* change to syscall table index */
        !          1896:        CAH(restart)
        !          1897:        jmp     do_native_call          /* try native system call */
        !          1898: 
        !          1899:        .globl  EXT(syscall_failed)
        !          1900: LEXT(syscall_failed)
        !          1901:        movl    %esp,%ecx               /* get kernel stack */
        !          1902:        or      $(KERNEL_STACK_SIZE-1),%ecx
        !          1903:        movl    -3-IKS_SIZE(%ecx),%esp  /* switch back to PCB stack */
        !          1904:        CPU_NUMBER(%edx)
        !          1905:        movl    CX(EXT(kernel_stack),%edx),%ebx
        !          1906:                                        /* get current kernel stack */
        !          1907:        xchgl   %ebx,%esp               /* switch stacks - %ebx points to */
        !          1908:                                        /* user registers. */
        !          1909:                                        /* user regs pointer already set */
        !          1910: 
        !          1911:        movl    $(T_INVALID_OPCODE),R_TRAPNO(%ebx)
        !          1912:                                        /* set invalid-operation trap */
        !          1913:        movl    $0,R_ERR(%ebx)          /* clear error code */
        !          1914:        CAH(failed)
        !          1915:        jmp     EXT(take_trap)          /* treat as a trap */
        !          1916: 
        !          1917: /*
        !          1918:  * User space emulation of system calls.
        !          1919:  * edx - user address to handle syscall
        !          1920:  *
        !          1921:  * User stack will become:
        !          1922:  * uesp->      eflags
        !          1923:  *             eip
        !          1924:  * Register use on entry:
        !          1925:  *   ebx contains user regs pointer
        !          1926:  *   edx contains emulator vector address
        !          1927:  */
        !          1928: syscall_emul:
        !          1929:        movl    R_UESP(%ebx),%edi       /* get user stack pointer */
        !          1930:        CPU_NUMBER(%eax)
        !          1931:        movl    CX(EXT(active_kloaded),%eax),%eax
        !          1932:        orl     %eax,%eax               /* if thread not kernel-loaded, */
        !          1933:        jz      0f                      /*   do address checks */
        !          1934:        subl    $8,%edi
        !          1935:        mov     %ds,%ax                 /* kernel data segment access */
        !          1936:        jmp     1f                      /* otherwise, skip them */
        !          1937: 0:
        !          1938:        cmpl    $(VM_MAX_ADDRESS),%edi  /* in user space? */
        !          1939:        ja      syscall_addr            /* address error if not */
        !          1940:        subl    $8,%edi                 /* push space for new arguments */
        !          1941:        cmpl    $(VM_MIN_ADDRESS),%edi  /* still in user space? */
        !          1942:        jb      syscall_addr            /* error if not */
        !          1943:        movl    $USER_DS,%ax            /* user data segment access */
        !          1944: 1:
        !          1945:        mov     %ax,%fs
        !          1946:        movl    R_EFLAGS(%ebx),%eax     /* move flags */
        !          1947:        RECOVERY_SECTION
        !          1948:        RECOVER(syscall_addr)
        !          1949:        movl    %eax,%fs:0(%edi)        /* to user stack */
        !          1950:        movl    R_EIP(%ebx),%eax        /* move eip */
        !          1951:        RECOVERY_SECTION
        !          1952:        RECOVER(syscall_addr)
        !          1953:        movl    %eax,%fs:4(%edi)        /* to user stack */
        !          1954:        movl    %edi,R_UESP(%ebx)       /* set new user stack pointer */
        !          1955:        movl    %edx,R_EIP(%ebx)        /* change return address to trap */
        !          1956:        movl    %ebx,%esp               /* back to PCB stack */
        !          1957:        CAH(emul)
        !          1958:        jmp     EXT(return_from_trap)   /* return to user */
        !          1959: 
        !          1960: 
        !          1961: /*
        !          1962:  * Address error - address is in %edi.
        !          1963:  * Register use on entry:
        !          1964:  *   ebx contains user regs pointer
        !          1965:  */
        !          1966: syscall_addr:
        !          1967:        movl    %edi,R_CR2(%ebx)        /* set fault address */
        !          1968:        movl    $(T_PAGE_FAULT),R_TRAPNO(%ebx)
        !          1969:                                        /* set page-fault trap */
        !          1970:        movl    $(T_PF_USER),R_ERR(%ebx)
        !          1971:                                        /* set error code - read user space */
        !          1972:        CAH(addr)
        !          1973:        jmp     EXT(take_trap)          /* treat as a trap */
        !          1974: 
        !          1975: /**/
        !          1976: /*
        !          1977:  * Utility routines.
        !          1978:  */
        !          1979: 
        !          1980: 
        !          1981: /*
        !          1982:  * Copy from user address space.
        !          1983:  * arg0:       user address
        !          1984:  * arg1:       kernel address
        !          1985:  * arg2:       byte count
        !          1986:  */
        !          1987: Entry(copyinmsg)
        !          1988: ENTRY(copyin)
        !          1989:        pushl   %esi
        !          1990:        pushl   %edi                    /* save registers */
        !          1991: 
        !          1992:        movl    8+S_ARG0,%esi           /* get user start address */
        !          1993:        movl    8+S_ARG1,%edi           /* get kernel destination address */
        !          1994:        movl    8+S_ARG2,%edx           /* get count */
        !          1995: 
        !          1996:        lea     0(%esi,%edx),%eax       /* get user end address + 1 */
        !          1997: 
        !          1998:        movl    $CPD_ACTIVE_THREAD,%ecx
        !          1999:        movl    %gs:(%ecx),%ecx                 /* get active thread */
        !          2000:        movl    TH_TOP_ACT(%ecx),%ecx           /* get thread->top_act */
        !          2001:        movl    ACT_MAP(%ecx),%ecx              /* get act->map */
        !          2002:        movl    MAP_PMAP(%ecx),%ecx             /* get map->pmap */
        !          2003:        cmpl    EXT(kernel_pmap), %ecx
        !          2004:        jz      1f
        !          2005:        movl    $USER_DS,%cx            /* user data segment access */
        !          2006:        mov     %cx,%ds
        !          2007: 1:
        !          2008:        cmpl    %esi,%eax
        !          2009:        jb      copyin_fail             /* fail if wrap-around */
        !          2010:        cld                             /* count up */
        !          2011:        movl    %edx,%ecx               /* move by longwords first */
        !          2012:        shrl    $2,%ecx
        !          2013:        RECOVERY_SECTION
        !          2014:        RECOVER(copyin_fail)
        !          2015:        rep
        !          2016:        movsl                           /* move longwords */
        !          2017:        movl    %edx,%ecx               /* now move remaining bytes */
        !          2018:        andl    $3,%ecx
        !          2019:        RECOVERY_SECTION
        !          2020:        RECOVER(copyin_fail)
        !          2021:        rep
        !          2022:        movsb
        !          2023:        xorl    %eax,%eax               /* return 0 for success */
        !          2024: copy_ret:
        !          2025:        mov     %ss,%di                 /* restore kernel data segment */
        !          2026:        mov     %di,%ds
        !          2027: 
        !          2028:        popl    %edi                    /* restore registers */
        !          2029:        popl    %esi
        !          2030:        ret                             /* and return */
        !          2031: 
        !          2032: copyin_fail:
        !          2033:        movl    $EFAULT,%eax                    /* return error for failure */
        !          2034:        jmp     copy_ret                /* pop frame and return */
        !          2035: 
        !          2036: /*
        !          2037:  * Copy string from user address space.
        !          2038:  * arg0:       user address
        !          2039:  * arg1:       kernel address
        !          2040:  * arg2:       max byte count
        !          2041:  * arg3:       actual byte count (OUT)
        !          2042:  */
        !          2043: Entry(copyinstr)
        !          2044:        pushl   %esi
        !          2045:        pushl   %edi                    /* save registers */
        !          2046: 
        !          2047:        movl    8+S_ARG0,%esi           /* get user start address */
        !          2048:        movl    8+S_ARG1,%edi           /* get kernel destination address */
        !          2049:        movl    8+S_ARG2,%edx           /* get count */
        !          2050: 
        !          2051:        lea     0(%esi,%edx),%eax       /* get user end address + 1 */
        !          2052: 
        !          2053:        movl    $CPD_ACTIVE_THREAD,%ecx
        !          2054:        movl    %gs:(%ecx),%ecx                 /* get active thread */
        !          2055:        movl    TH_TOP_ACT(%ecx),%ecx           /* get thread->top_act */
        !          2056:        movl    ACT_MAP(%ecx),%ecx              /* get act->map */
        !          2057:        movl    MAP_PMAP(%ecx),%ecx             /* get map->pmap */
        !          2058:        cmpl    EXT(kernel_pmap), %ecx
        !          2059:        jne     0f
        !          2060:        mov     %ds,%cx                 /* kernel data segment access  */
        !          2061:        jmp     1f
        !          2062: 0:
        !          2063:        movl    $USER_DS,%cx            /* user data segment access */
        !          2064: 1:
        !          2065:        mov     %cx,%fs
        !          2066:        xorl    %eax,%eax
        !          2067:        cmpl    $0,%edx
        !          2068:        je      4f
        !          2069: 2:
        !          2070:        RECOVERY_SECTION
        !          2071:        RECOVER(copystr_fail)           /* copy bytes... */
        !          2072:        movb    %fs:(%esi),%eax
        !          2073:        incl    %esi
        !          2074:        testl   %edi,%edi               /* if kernel address is ... */
        !          2075:        jz      3f                      /* not NULL */
        !          2076:        movb    %eax,(%edi)             /* copy the byte */
        !          2077:        incl    %edi
        !          2078: 3:
        !          2079:        decl    %edx
        !          2080:        je      5f                      /* Zero count.. error out */
        !          2081:        cmpl    $0,%eax
        !          2082:        jne     2b                      /* .. a NUL found? */
        !          2083:        jmp     4f
        !          2084: 5:
        !          2085:        movl    $ENAMETOOLONG,%eax      /* String is too long.. */
        !          2086: 4:
        !          2087:        xorl    %eax,%eax               /* return zero for success */
        !          2088:        movl    8+S_ARG3,%edi           /* get OUT len ptr */
        !          2089:        cmpl    $0,%edi
        !          2090:        jz      copystr_ret             /* if null, just return */
        !          2091:        subl    8+S_ARG0,%esi
        !          2092:        movl    %esi,(%edi)             /* else set OUT arg to xfer len */
        !          2093: copystr_ret:
        !          2094:        popl    %edi                    /* restore registers */
        !          2095:        popl    %esi
        !          2096:        ret                             /* and return */
        !          2097: 
        !          2098: copystr_fail:
        !          2099:        movl    $EFAULT,%eax            /* return error for failure */
        !          2100:        jmp     copy_ret                /* pop frame and return */
        !          2101: 
        !          2102: /*
        !          2103:  * Copy to user address space.
        !          2104:  * arg0:       kernel address
        !          2105:  * arg1:       user address
        !          2106:  * arg2:       byte count
        !          2107:  */
        !          2108: Entry(copyoutmsg)
        !          2109: ENTRY(copyout)
        !          2110:        pushl   %esi
        !          2111:        pushl   %edi                    /* save registers */
        !          2112:        pushl   %ebx
        !          2113: 
        !          2114:        movl    12+S_ARG0,%esi          /* get kernel start address */
        !          2115:        movl    12+S_ARG1,%edi          /* get user start address */
        !          2116:        movl    12+S_ARG2,%edx          /* get count */
        !          2117: 
        !          2118:        leal    0(%edi,%edx),%eax       /* get user end address + 1 */
        !          2119: 
        !          2120:        movl    $CPD_ACTIVE_THREAD,%ecx
        !          2121:        movl    %gs:(%ecx),%ecx                 /* get active thread */
        !          2122:        movl    TH_TOP_ACT(%ecx),%ecx           /* get thread->top_act */
        !          2123:        movl    ACT_MAP(%ecx),%ecx              /* get act->map */
        !          2124:        movl    MAP_PMAP(%ecx),%ecx             /* get map->pmap */
        !          2125:        cmpl    EXT(kernel_pmap), %ecx
        !          2126:        jne     0f
        !          2127:        mov     %ds,%cx                 /* else kernel data segment access  */
        !          2128:        jmp     1f
        !          2129: 0:
        !          2130:        movl    $USER_DS,%cx
        !          2131: 1:
        !          2132:        mov     %cx,%es
        !          2133: 
        !          2134: /*
        !          2135:  * Check whether user address space is writable
        !          2136:  * before writing to it - hardware is broken.
        !          2137:  *
        !          2138:  * Skip check if "user" address is really in
        !          2139:  * kernel space (i.e., if it's in a kernel-loaded
        !          2140:  * task).
        !          2141:  *
        !          2142:  * Register usage:
        !          2143:  *     esi/edi source/dest pointers for rep/mov
        !          2144:  *     ecx     counter for rep/mov
        !          2145:  *     edx     counts down from 3rd arg
        !          2146:  *     eax     count of bytes for each (partial) page copy
        !          2147:  *     ebx     shadows edi, used to adjust edx
        !          2148:  */
        !          2149:        movl    %edi,%ebx               /* copy edi for syncing up */
        !          2150: copyout_retry:
        !          2151:        /* if restarting after a partial copy, put edx back in sync, */
        !          2152:        addl    %ebx,%edx               /* edx -= (edi - ebx); */
        !          2153:        subl    %edi,%edx               /
        !          2154:        movl    %edi,%ebx               /* ebx = edi; */
        !          2155: 
        !          2156:        mov     %es,%cx         
        !          2157:        cmpl    $USER_DS,%cx            /* If kernel data segment */
        !          2158:        jnz     0f                      /* skip check */
        !          2159: 
        !          2160:        cmpb    $(CPUID_FAMILY_386), EXT(cpuid_family)
        !          2161:        ja      0f
        !          2162: 
        !          2163:        movl    %cr3,%ecx               /* point to page directory */
        !          2164: #if    NCPUS > 1
        !          2165:        andl    $(~0x7), %ecx           /* remove cpu number */
        !          2166: #endif /* NCPUS > 1 && AT386 */
        !          2167:        movl    %edi,%eax               /* get page directory bits */
        !          2168:        shrl    $(PDESHIFT),%eax        /* from user address */
        !          2169:        movl    KERNELBASE(%ecx,%eax,4),%ecx
        !          2170:                                        /* get page directory pointer */
        !          2171:        testl   $(PTE_V),%ecx           /* present? */
        !          2172:        jz      0f                      /* if not, fault is OK */
        !          2173:        andl    $(PTE_PFN),%ecx         /* isolate page frame address */
        !          2174:        movl    %edi,%eax               /* get page table bits */
        !          2175:        shrl    $(PTESHIFT),%eax
        !          2176:        andl    $(PTEMASK),%eax         /* from user address */
        !          2177:        leal    KERNELBASE(%ecx,%eax,4),%ecx
        !          2178:                                        /* point to page table entry */
        !          2179:        movl    (%ecx),%eax             /* get it */
        !          2180:        testl   $(PTE_V),%eax           /* present? */
        !          2181:        jz      0f                      /* if not, fault is OK */
        !          2182:        testl   $(PTE_W),%eax           /* writable? */
        !          2183:        jnz     0f                      /* OK if so */
        !          2184: /*
        !          2185:  * Not writable - must fake a fault.  Turn off access to the page.
        !          2186:  */
        !          2187:        andl    $(PTE_INVALID),(%ecx)   /* turn off valid bit */
        !          2188:        movl    %cr3,%eax               /* invalidate TLB */
        !          2189:        movl    %eax,%cr3
        !          2190: 0:
        !          2191: /*
        !          2192:  * Copy only what fits on the current destination page.
        !          2193:  * Check for write-fault again on the next page.
        !          2194:  */
        !          2195:        leal    NBPG(%edi),%eax         /* point to */
        !          2196:        andl    $(-NBPG),%eax           /* start of next page */
        !          2197:        subl    %edi,%eax               /* get number of bytes to that point */
        !          2198:        cmpl    %edx,%eax               /* bigger than count? */
        !          2199:        jle     1f                      /* if so, */
        !          2200:        movl    %edx,%eax               /* use count */
        !          2201: 1:
        !          2202:        cld                             /* count up */
        !          2203:        movl    %eax,%ecx               /* move by longwords first */
        !          2204:        shrl    $2,%ecx
        !          2205:        RECOVERY_SECTION
        !          2206:        RECOVER(copyout_fail)
        !          2207:        RETRY_SECTION
        !          2208:        RETRY(copyout_retry)
        !          2209:        rep
        !          2210:        movsl
        !          2211:        movl    %eax,%ecx               /* now move remaining bytes */
        !          2212:        andl    $3,%ecx
        !          2213:        RECOVERY_SECTION
        !          2214:        RECOVER(copyout_fail)
        !          2215:        RETRY_SECTION
        !          2216:        RETRY(copyout_retry)
        !          2217:        rep
        !          2218:        movsb                           /* move */
        !          2219:        movl    %edi,%ebx               /* copy edi for syncing up */
        !          2220:        subl    %eax,%edx               /* and decrement count */
        !          2221:        jg      copyout_retry           /* restart on next page if not done */
        !          2222:        xorl    %eax,%eax               /* return 0 for success */
        !          2223: copyout_ret:
        !          2224:        mov     %ss,%di                 /* restore kernel segment */
        !          2225:        mov     %di,%es
        !          2226: 
        !          2227:        popl    %ebx
        !          2228:        popl    %edi                    /* restore registers */
        !          2229:        popl    %esi
        !          2230:        ret                             /* and return */
        !          2231: 
        !          2232: copyout_fail:
        !          2233:        movl    $EFAULT,%eax            /* return error for failure */
        !          2234:        jmp     copyout_ret             /* pop frame and return */
        !          2235: 
        !          2236: /*
        !          2237:  * FPU routines.
        !          2238:  */
        !          2239: 
        !          2240: /*
        !          2241:  * Initialize FPU.
        !          2242:  */
        !          2243: ENTRY(_fninit)
        !          2244:        fninit
        !          2245:        ret
        !          2246: 
        !          2247: /*
        !          2248:  * Read control word
        !          2249:  */
        !          2250: ENTRY(_fstcw)
        !          2251:        pushl   %eax            /* get stack space */
        !          2252:        fstcw   (%esp)
        !          2253:        popl    %eax
        !          2254:        ret
        !          2255: 
        !          2256: /*
        !          2257:  * Set control word
        !          2258:  */
        !          2259: ENTRY(_fldcw)
        !          2260:        fldcw   4(%esp)
        !          2261:        ret
        !          2262: 
        !          2263: /*
        !          2264:  * Read status word
        !          2265:  */
        !          2266: ENTRY(_fnstsw)
        !          2267:        xor     %eax,%eax               /* clear high 16 bits of eax */
        !          2268:        fnstsw  %ax                     /* read FP status */
        !          2269:        ret
        !          2270: 
        !          2271: /*
        !          2272:  * Clear FPU exceptions
        !          2273:  */
        !          2274: ENTRY(_fnclex)
        !          2275:        fnclex
        !          2276:        ret
        !          2277: 
        !          2278: /*
        !          2279:  * Clear task-switched flag.
        !          2280:  */
        !          2281: ENTRY(_clts)
        !          2282:        clts
        !          2283:        ret
        !          2284: 
        !          2285: /*
        !          2286:  * Save complete FPU state.  Save error for later.
        !          2287:  */
        !          2288: ENTRY(_fpsave)
        !          2289:        movl    4(%esp),%eax            /* get save area pointer */
        !          2290:        fnsave  (%eax)                  /* save complete state, including */
        !          2291:                                        /* errors */
        !          2292:        ret
        !          2293: 
        !          2294: /*
        !          2295:  * Restore FPU state.
        !          2296:  */
        !          2297: ENTRY(_fprestore)
        !          2298:        movl    4(%esp),%eax            /* get save area pointer */
        !          2299:        frstor  (%eax)                  /* restore complete state */
        !          2300:        ret
        !          2301: 
        !          2302: /*
        !          2303:  * Set cr3
        !          2304:  */
        !          2305: ENTRY(set_cr3)
        !          2306: #if    NCPUS > 1
        !          2307:        CPU_NUMBER(%eax)
        !          2308:        orl     4(%esp), %eax
        !          2309: #else  /* NCPUS > 1 && AT386 */
        !          2310:        movl    4(%esp),%eax            /* get new cr3 value */
        !          2311: #endif /* NCPUS > 1 && AT386 */
        !          2312:        /*
        !          2313:         * Don't set PDBR to a new value (hence invalidating the
        !          2314:         * "paging cache") if the new value matches the current one.
        !          2315:         */
        !          2316:        movl    %cr3,%edx               /* get current cr3 value */
        !          2317:        cmpl    %eax,%edx
        !          2318:        je      0f                      /* if two are equal, don't set */
        !          2319:        movl    %eax,%cr3               /* load it (and flush cache) */
        !          2320: 0:
        !          2321:        ret
        !          2322: 
        !          2323: /*
        !          2324:  * Read cr3
        !          2325:  */
        !          2326: ENTRY(get_cr3)
        !          2327:        movl    %cr3,%eax
        !          2328: #if    NCPUS > 1
        !          2329:        andl    $(~0x7), %eax           /* remove cpu number */
        !          2330: #endif /* NCPUS > 1 && AT386 */
        !          2331:        ret
        !          2332: 
        !          2333: /*
        !          2334:  * Flush TLB
        !          2335:  */
        !          2336: ENTRY(flush_tlb)
        !          2337:        movl    %cr3,%eax               /* flush tlb by reloading CR3 */
        !          2338:        movl    %eax,%cr3               /* with itself */
        !          2339:        ret
        !          2340: 
        !          2341: /*
        !          2342:  * Read cr2
        !          2343:  */
        !          2344: ENTRY(get_cr2)
        !          2345:        movl    %cr2,%eax
        !          2346:        ret
        !          2347: 
        !          2348: /*
        !          2349:  * Read cr4
        !          2350:  */
        !          2351: ENTRY(get_cr4)
        !          2352:        .byte   0x0f,0x20,0xe0          /* movl %cr4, %eax */
        !          2353:        ret
        !          2354: 
        !          2355: /*
        !          2356:  * Write cr4
        !          2357:  */
        !          2358: ENTRY(set_cr4)
        !          2359:        movl    4(%esp), %eax
        !          2360:        .byte   0x0f,0x22,0xe0          /* movl %eax, %cr4 */
        !          2361:        ret
        !          2362: 
        !          2363: /*
        !          2364:  * Read ldtr
        !          2365:  */
        !          2366: Entry(get_ldt)
        !          2367:        xorl    %eax,%eax
        !          2368:        sldt    %ax
        !          2369:        ret
        !          2370: 
        !          2371: /*
        !          2372:  * Set ldtr
        !          2373:  */
        !          2374: Entry(set_ldt)
        !          2375:        lldt    4(%esp)
        !          2376:        ret
        !          2377: 
        !          2378: /*
        !          2379:  * Read task register.
        !          2380:  */
        !          2381: ENTRY(get_tr)
        !          2382:        xorl    %eax,%eax
        !          2383:        str     %ax
        !          2384:        ret
        !          2385: 
        !          2386: /*
        !          2387:  * Set task register.  Also clears busy bit of task descriptor.
        !          2388:  */
        !          2389: ENTRY(set_tr)
        !          2390:        movl    S_ARG0,%eax             /* get task segment number */
        !          2391:        subl    $8,%esp                 /* push space for SGDT */
        !          2392:        sgdt    2(%esp)                 /* store GDT limit and base (linear) */
        !          2393:        movl    4(%esp),%edx            /* address GDT */
        !          2394:        movb    $(K_TSS),5(%edx,%eax)   /* fix access byte in task descriptor */
        !          2395:        ltr     %ax                     /* load task register */
        !          2396:        addl    $8,%esp                 /* clear stack */
        !          2397:        ret                             /* and return */
        !          2398: 
        !          2399: /*
        !          2400:  * Set task-switched flag.
        !          2401:  */
        !          2402: ENTRY(_setts)
        !          2403:        movl    %cr0,%eax               /* get cr0 */
        !          2404:        orl     $(CR0_TS),%eax          /* or in TS bit */
        !          2405:        movl    %eax,%cr0               /* set cr0 */
        !          2406:        ret
        !          2407: 
        !          2408: /*
        !          2409:  * io register must not be used on slaves (no AT bus)
        !          2410:  */
        !          2411: #define        ILL_ON_SLAVE
        !          2412: 
        !          2413: 
        !          2414: #if    MACH_ASSERT
        !          2415: 
        !          2416: #define ARG0           B_ARG0
        !          2417: #define ARG1           B_ARG1
        !          2418: #define ARG2           B_ARG2
        !          2419: #define PUSH_FRAME     FRAME
        !          2420: #define POP_FRAME      EMARF
        !          2421: 
        !          2422: #else  /* MACH_ASSERT */
        !          2423: 
        !          2424: #define ARG0           S_ARG0
        !          2425: #define ARG1           S_ARG1
        !          2426: #define ARG2           S_ARG2
        !          2427: #define PUSH_FRAME     
        !          2428: #define POP_FRAME      
        !          2429: 
        !          2430: #endif /* MACH_ASSERT */
        !          2431: 
        !          2432: 
        !          2433: #if    MACH_KDB || MACH_ASSERT
        !          2434: 
        !          2435: /*
        !          2436:  * Following routines are also defined as macros in i386/pio.h
        !          2437:  * Compile then when MACH_KDB is configured so that they
        !          2438:  * can be invoked from the debugger.
        !          2439:  */
        !          2440: 
        !          2441: /*
        !          2442:  * void outb(unsigned char *io_port,
        !          2443:  *          unsigned char byte)
        !          2444:  *
        !          2445:  * Output a byte to an IO port.
        !          2446:  */
        !          2447: ENTRY(outb)
        !          2448:        PUSH_FRAME
        !          2449:        ILL_ON_SLAVE
        !          2450:        movl    ARG0,%edx               /* IO port address */
        !          2451:        movl    ARG1,%eax               /* data to output */
        !          2452:        outb    %al,%dx                 /* send it out */
        !          2453:        POP_FRAME
        !          2454:        ret
        !          2455: 
        !          2456: /*
        !          2457:  * unsigned char inb(unsigned char *io_port)
        !          2458:  *
        !          2459:  * Input a byte from an IO port.
        !          2460:  */
        !          2461: ENTRY(inb)
        !          2462:        PUSH_FRAME
        !          2463:        ILL_ON_SLAVE
        !          2464:        movl    ARG0,%edx               /* IO port address */
        !          2465:        xor     %eax,%eax               /* clear high bits of register */
        !          2466:        inb     %dx,%al                 /* get the byte */
        !          2467:        POP_FRAME
        !          2468:        ret
        !          2469: 
        !          2470: /*
        !          2471:  * void outw(unsigned short *io_port,
        !          2472:  *          unsigned short word)
        !          2473:  *
        !          2474:  * Output a word to an IO port.
        !          2475:  */
        !          2476: ENTRY(outw)
        !          2477:        PUSH_FRAME
        !          2478:        ILL_ON_SLAVE
        !          2479:        movl    ARG0,%edx               /* IO port address */
        !          2480:        movl    ARG1,%eax               /* data to output */
        !          2481:        outw    %ax,%dx                 /* send it out */
        !          2482:        POP_FRAME
        !          2483:        ret
        !          2484: 
        !          2485: /*
        !          2486:  * unsigned short inw(unsigned short *io_port)
        !          2487:  *
        !          2488:  * Input a word from an IO port.
        !          2489:  */
        !          2490: ENTRY(inw)
        !          2491:        PUSH_FRAME
        !          2492:        ILL_ON_SLAVE
        !          2493:        movl    ARG0,%edx               /* IO port address */
        !          2494:        xor     %eax,%eax               /* clear high bits of register */
        !          2495:        inw     %dx,%ax                 /* get the word */
        !          2496:        POP_FRAME
        !          2497:        ret
        !          2498: 
        !          2499: /*
        !          2500:  * void outl(unsigned int *io_port,
        !          2501:  *          unsigned int byte)
        !          2502:  *
        !          2503:  * Output an int to an IO port.
        !          2504:  */
        !          2505: ENTRY(outl)
        !          2506:        PUSH_FRAME
        !          2507:        ILL_ON_SLAVE
        !          2508:        movl    ARG0,%edx               /* IO port address*/
        !          2509:        movl    ARG1,%eax               /* data to output */
        !          2510:        outl    %eax,%dx                /* send it out */
        !          2511:        POP_FRAME
        !          2512:        ret
        !          2513: 
        !          2514: /*
        !          2515:  * unsigned int inl(unsigned int *io_port)
        !          2516:  *
        !          2517:  * Input an int from an IO port.
        !          2518:  */
        !          2519: ENTRY(inl)
        !          2520:        PUSH_FRAME
        !          2521:        ILL_ON_SLAVE
        !          2522:        movl    ARG0,%edx               /* IO port address */
        !          2523:        inl     %dx,%eax                /* get the int */
        !          2524:        POP_FRAME
        !          2525:        ret
        !          2526: 
        !          2527: #endif /* MACH_KDB  || MACH_ASSERT*/
        !          2528: 
        !          2529: /*
        !          2530:  * void loutb(unsigned byte *io_port,
        !          2531:  *           unsigned byte *data,
        !          2532:  *           unsigned int count)
        !          2533:  *
        !          2534:  * Output an array of bytes to an IO port.
        !          2535:  */
        !          2536: ENTRY(loutb)
        !          2537: ENTRY(outsb)
        !          2538:        PUSH_FRAME
        !          2539:        ILL_ON_SLAVE
        !          2540:        movl    %esi,%eax               /* save register */
        !          2541:        movl    ARG0,%edx               /* get io port number */
        !          2542:        movl    ARG1,%esi               /* get data address */
        !          2543:        movl    ARG2,%ecx               /* get count */
        !          2544:        cld                             /* count up */
        !          2545:        rep
        !          2546:        outsb                           /* output */
        !          2547:        movl    %eax,%esi               /* restore register */
        !          2548:        POP_FRAME
        !          2549:        ret     
        !          2550: 
        !          2551: 
        !          2552: /*
        !          2553:  * void loutw(unsigned short *io_port,
        !          2554:  *           unsigned short *data,
        !          2555:  *           unsigned int count)
        !          2556:  *
        !          2557:  * Output an array of shorts to an IO port.
        !          2558:  */
        !          2559: ENTRY(loutw)
        !          2560: ENTRY(outsw)
        !          2561:        PUSH_FRAME
        !          2562:        ILL_ON_SLAVE
        !          2563:        movl    %esi,%eax               /* save register */
        !          2564:        movl    ARG0,%edx               /* get io port number */
        !          2565:        movl    ARG1,%esi               /* get data address */
        !          2566:        movl    ARG2,%ecx               /* get count */
        !          2567:        cld                             /* count up */
        !          2568:        rep
        !          2569:        outsw                           /* output */
        !          2570:        movl    %eax,%esi               /* restore register */
        !          2571:        POP_FRAME
        !          2572:        ret
        !          2573: 
        !          2574: /*
        !          2575:  * void loutw(unsigned short io_port,
        !          2576:  *           unsigned int *data,
        !          2577:  *           unsigned int count)
        !          2578:  *
        !          2579:  * Output an array of longs to an IO port.
        !          2580:  */
        !          2581: ENTRY(loutl)
        !          2582: ENTRY(outsl)
        !          2583:        PUSH_FRAME
        !          2584:        ILL_ON_SLAVE
        !          2585:        movl    %esi,%eax               /* save register */
        !          2586:        movl    ARG0,%edx               /* get io port number */
        !          2587:        movl    ARG1,%esi               /* get data address */
        !          2588:        movl    ARG2,%ecx               /* get count */
        !          2589:        cld                             /* count up */
        !          2590:        rep
        !          2591:        outsl                           /* output */
        !          2592:        movl    %eax,%esi               /* restore register */
        !          2593:        POP_FRAME
        !          2594:        ret
        !          2595: 
        !          2596: 
        !          2597: /*
        !          2598:  * void linb(unsigned char *io_port,
        !          2599:  *          unsigned char *data,
        !          2600:  *          unsigned int count)
        !          2601:  *
        !          2602:  * Input an array of bytes from an IO port.
        !          2603:  */
        !          2604: ENTRY(linb)
        !          2605: ENTRY(insb)
        !          2606:        PUSH_FRAME
        !          2607:        ILL_ON_SLAVE
        !          2608:        movl    %edi,%eax               /* save register */
        !          2609:        movl    ARG0,%edx               /* get io port number */
        !          2610:        movl    ARG1,%edi               /* get data address */
        !          2611:        movl    ARG2,%ecx               /* get count */
        !          2612:        cld                             /* count up */
        !          2613:        rep
        !          2614:        insb                            /* input */
        !          2615:        movl    %eax,%edi               /* restore register */
        !          2616:        POP_FRAME
        !          2617:        ret
        !          2618: 
        !          2619: 
        !          2620: /*
        !          2621:  * void linw(unsigned short *io_port,
        !          2622:  *          unsigned short *data,
        !          2623:  *          unsigned int count)
        !          2624:  *
        !          2625:  * Input an array of shorts from an IO port.
        !          2626:  */
        !          2627: ENTRY(linw)
        !          2628: ENTRY(insw)
        !          2629:        PUSH_FRAME
        !          2630:        ILL_ON_SLAVE
        !          2631:        movl    %edi,%eax               /* save register */
        !          2632:        movl    ARG0,%edx               /* get io port number */
        !          2633:        movl    ARG1,%edi               /* get data address */
        !          2634:        movl    ARG2,%ecx               /* get count */
        !          2635:        cld                             /* count up */
        !          2636:        rep
        !          2637:        insw                            /* input */
        !          2638:        movl    %eax,%edi               /* restore register */
        !          2639:        POP_FRAME
        !          2640:        ret
        !          2641: 
        !          2642: 
        !          2643: /*
        !          2644:  * void linl(unsigned short io_port,
        !          2645:  *          unsigned int *data,
        !          2646:  *          unsigned int count)
        !          2647:  *
        !          2648:  * Input an array of longs from an IO port.
        !          2649:  */
        !          2650: ENTRY(linl)
        !          2651: ENTRY(insl)
        !          2652:        PUSH_FRAME
        !          2653:        ILL_ON_SLAVE
        !          2654:        movl    %edi,%eax               /* save register */
        !          2655:        movl    ARG0,%edx               /* get io port number */
        !          2656:        movl    ARG1,%edi               /* get data address */
        !          2657:        movl    ARG2,%ecx               /* get count */
        !          2658:        cld                             /* count up */
        !          2659:        rep
        !          2660:        insl                            /* input */
        !          2661:        movl    %eax,%edi               /* restore register */
        !          2662:        POP_FRAME
        !          2663:        ret
        !          2664: 
        !          2665: 
        !          2666: /*
        !          2667:  * int inst_fetch(int eip, int cs);
        !          2668:  *
        !          2669:  * Fetch instruction byte.  Return -1 if invalid address.
        !          2670:  */
        !          2671:        .globl  EXT(inst_fetch)
        !          2672: LEXT(inst_fetch)
        !          2673:        movl    S_ARG1, %eax            /* get segment */
        !          2674:        movw    %ax,%fs                 /* into FS */
        !          2675:        movl    S_ARG0, %eax            /* get offset */
        !          2676:        RETRY_SECTION
        !          2677:        RETRY(EXT(inst_fetch))          /* re-load FS on retry */
        !          2678:        RECOVERY_SECTION
        !          2679:        RECOVER(EXT(inst_fetch_fault))
        !          2680:        movzbl  %fs:(%eax),%eax         /* load instruction byte */
        !          2681:        ret
        !          2682: 
        !          2683: LEXT(inst_fetch_fault)
        !          2684:        movl    $-1,%eax                /* return -1 if error */
        !          2685:        ret
        !          2686: 
        !          2687: 
        !          2688: #if MACH_KDP
        !          2689: /*
        !          2690:  * kdp_copy_kmem(char *src, char *dst, int count)
        !          2691:  *
        !          2692:  * Similar to copyin except that both addresses are kernel addresses.
        !          2693:  */
        !          2694: 
        !          2695: ENTRY(kdp_copy_kmem)
        !          2696:        pushl   %esi
        !          2697:        pushl   %edi                    /* save registers */
        !          2698: 
        !          2699:        movl    8+S_ARG0,%esi           /* get kernel start address */
        !          2700:        movl    8+S_ARG1,%edi           /* get kernel destination address */
        !          2701: 
        !          2702:        movl    8+S_ARG2,%edx           /* get count */
        !          2703: 
        !          2704:        lea     0(%esi,%edx),%eax       /* get kernel end address + 1 */
        !          2705: 
        !          2706:        cmpl    %esi,%eax
        !          2707:        jb      kdp_vm_read_fail        /* fail if wrap-around */
        !          2708:        cld                             /* count up */
        !          2709:        movl    %edx,%ecx               /* move by longwords first */
        !          2710:        shrl    $2,%ecx
        !          2711:        RECOVERY_SECTION
        !          2712:        RECOVER(kdp_vm_read_fail)
        !          2713:        rep
        !          2714:        movsl                           /* move longwords */
        !          2715:        movl    %edx,%ecx               /* now move remaining bytes */
        !          2716:        andl    $3,%ecx
        !          2717:        RECOVERY_SECTION
        !          2718:        RECOVER(kdp_vm_read_fail)
        !          2719:        rep
        !          2720:        movsb
        !          2721: kdp_vm_read_done:
        !          2722:        movl    8+S_ARG2,%edx           /* get count */
        !          2723:        subl    %ecx,%edx               /* Return number of bytes transfered */
        !          2724:        movl    %edx,%eax
        !          2725: 
        !          2726:        popl    %edi                    /* restore registers */
        !          2727:        popl    %esi
        !          2728:        ret                             /* and return */
        !          2729: 
        !          2730: kdp_vm_read_fail:
        !          2731:        xorl    %eax,%eax       /* didn't copy a thing. */
        !          2732: 
        !          2733:        popl    %edi
        !          2734:        popl    %esi
        !          2735:        ret
        !          2736: #endif
        !          2737: 
        !          2738: 
        !          2739: /*
        !          2740:  * Done with recovery and retry tables.
        !          2741:  */
        !          2742:        RECOVERY_SECTION
        !          2743:        RECOVER_TABLE_END
        !          2744:        RETRY_SECTION
        !          2745:        RETRY_TABLE_END
        !          2746: 
        !          2747: 
        !          2748: 
        !          2749: ENTRY(dr6)
        !          2750:        movl    %db6, %eax
        !          2751:        ret
        !          2752: 
        !          2753: /*     dr<i>(address, type, len, persistence)
        !          2754:  */
        !          2755: ENTRY(dr0)
        !          2756:        movl    S_ARG0, %eax
        !          2757:        movl    %eax,EXT(dr_addr)
        !          2758:        movl    %eax, %db0
        !          2759:        movl    $0, %ecx
        !          2760:        jmp     0f
        !          2761: ENTRY(dr1)
        !          2762:        movl    S_ARG0, %eax
        !          2763:        movl    %eax,EXT(dr_addr)+1*4
        !          2764:        movl    %eax, %db1
        !          2765:        movl    $2, %ecx
        !          2766:        jmp     0f
        !          2767: ENTRY(dr2)
        !          2768:        movl    S_ARG0, %eax
        !          2769:        movl    %eax,EXT(dr_addr)+2*4
        !          2770:        movl    %eax, %db2
        !          2771:        movl    $4, %ecx
        !          2772:        jmp     0f
        !          2773: 
        !          2774: ENTRY(dr3)
        !          2775:        movl    S_ARG0, %eax
        !          2776:        movl    %eax,EXT(dr_addr)+3*4
        !          2777:        movl    %eax, %db3
        !          2778:        movl    $6, %ecx
        !          2779: 
        !          2780: 0:
        !          2781:        pushl   %ebp
        !          2782:        movl    %esp, %ebp
        !          2783: 
        !          2784:        movl    %db7, %edx
        !          2785:        movl    %edx,EXT(dr_addr)+4*4
        !          2786:        andl    dr_msk(,%ecx,2),%edx    /* clear out new entry */
        !          2787:        movl    %edx,EXT(dr_addr)+5*4
        !          2788:        movzbl  B_ARG3, %eax
        !          2789:        andb    $3, %al
        !          2790:        shll    %cl, %eax
        !          2791:        orl     %eax, %edx
        !          2792: 
        !          2793:        movzbl  B_ARG1, %eax
        !          2794:        andb    $3, %al
        !          2795:        addb    $0x10, %ecx
        !          2796:        shll    %cl, %eax
        !          2797:        orl     %eax, %edx
        !          2798: 
        !          2799:        movzbl  B_ARG2, %eax
        !          2800:        andb    $3, %al
        !          2801:        addb    $0x2, %ecx
        !          2802:        shll    %cl, %eax
        !          2803:        orl     %eax, %edx
        !          2804: 
        !          2805:        movl    %edx, %db7
        !          2806:        movl    %edx,EXT(dr_addr)+7*4
        !          2807:        movl    %edx, %eax
        !          2808:        leave
        !          2809:        ret
        !          2810: 
        !          2811:        .data
        !          2812: 
        !          2813: DATA(preemptable)      /* Not on an MP (makes cpu_number() usage unsafe) */
        !          2814: #if    MACH_RT && (NCPUS == 1)
        !          2815:        .long   0       /* FIXME -- Currently disabled */
        !          2816: #else
        !          2817:        .long   0       /* FIX ME -- Currently disabled */
        !          2818: #endif /* MACH_RT && (NCPUS == 1) */
        !          2819: 
        !          2820: dr_msk:
        !          2821:        .long   ~0x000f0003
        !          2822:        .long   ~0x00f0000c
        !          2823:        .long   ~0x0f000030
        !          2824:        .long   ~0xf00000c0
        !          2825: ENTRY(dr_addr)
        !          2826:        .long   0,0,0,0
        !          2827:        .long   0,0,0,0
        !          2828:        .text
        !          2829: 
        !          2830: /*
        !          2831:  * Determine cpu model and set global cpuid_xxx variables
        !          2832:  *
        !          2833:  * Relies on 386 eflags bit 18 (AC) always being zero & 486 preserving it.
        !          2834:  * Relies on 486 eflags bit 21 (ID) always being zero & 586 preserving it.
        !          2835:  * Relies on CPUID instruction for next x86 generations
        !          2836:  * (assumes cpuid-family-homogenous MPs; else convert to per-cpu array)
        !          2837:  */
        !          2838: 
        !          2839: ENTRY(set_cpu_model)
        !          2840:        FRAME
        !          2841:        pushl   %ebx                    /* save ebx */
        !          2842:        andl    $~0x3,%esp              /* Align stack to avoid AC fault */
        !          2843:        pushfl                          /* push EFLAGS */
        !          2844:        popl    %eax                    /* pop into eax */
        !          2845:        movl    %eax,%ecx               /* Save original EFLAGS */
        !          2846:        xorl    $(EFL_AC+EFL_ID),%eax   /* toggle ID,AC bits */
        !          2847:        pushl   %eax                    /* push new value */
        !          2848:        popfl                           /* through the EFLAGS register */
        !          2849:        pushfl                          /* and back */
        !          2850:        popl    %eax                    /* into eax */
        !          2851:        movb    $(CPUID_FAMILY_386),EXT(cpuid_family)
        !          2852:        pushl   %ecx                    /* push original EFLAGS */
        !          2853:        popfl                           /* restore EFLAGS */
        !          2854:        xorl    %ecx,%eax               /* see what changed */
        !          2855:        testl   $EFL_AC,%eax            /* test AC bit */
        !          2856:        jz      0f                      /* if AC toggled (486 or higher) */
        !          2857:        
        !          2858:        movb    $(CPUID_FAMILY_486),EXT(cpuid_family)
        !          2859:        testl   $EFL_ID,%eax            /* test ID bit */
        !          2860:        jz      0f                      /* if ID toggled use cpuid instruction */
        !          2861:        
        !          2862:        xorl    %eax,%eax               /* get vendor identification string */
        !          2863:        .word   0xA20F                  /* cpuid instruction */
        !          2864:        movl    %eax,EXT(cpuid_value)   /* Store high value */ 
        !          2865:        movl    %ebx,EXT(cpuid_vid)     /* Store byte 0-3 of Vendor ID */
        !          2866:        movl    %edx,EXT(cpuid_vid)+4   /* Store byte 4-7 of Vendor ID */
        !          2867:        movl    %ecx,EXT(cpuid_vid)+8   /* Store byte 8-B of Vendor ID */
        !          2868:        movl    $1,%eax                 /* get processor signature */
        !          2869:        .word   0xA20F                  /* cpuid instruction */
        !          2870:        movl    %edx,EXT(cpuid_feature) /* Store feature flags */
        !          2871:        movl    %eax,%ecx               /* Save original signature */
        !          2872:        andb    $0xF,%al                /* Get Stepping ID */
        !          2873:        movb    %al,EXT(cpuid_stepping) /* Save Stepping ID */
        !          2874:        movl    %ecx,%eax               /* Get original signature */
        !          2875:        shrl    $4,%eax                 /* Shift Stepping ID */
        !          2876:        movl    %eax,%ecx               /* Save original signature */
        !          2877:        andb    $0xF,%al                /* Get Model */
        !          2878:        movb    %al,EXT(cpuid_model)    /* Save Model */
        !          2879:        movl    %ecx,%eax               /* Get original signature */
        !          2880:        shrl    $4,%eax                 /* Shift Stepping ID */
        !          2881:        movl    %eax,%ecx               /* Save original signature */
        !          2882:        andb    $0xF,%al                /* Get Family */
        !          2883:        movb    %al,EXT(cpuid_family)   /* Save Family */
        !          2884:        movl    %ecx,%eax               /* Get original signature */
        !          2885:        shrl    $4,%eax                 /* Shift Stepping ID */
        !          2886:        andb    $0x3,%al                /* Get Type */
        !          2887:        movb    %al,EXT(cpuid_type)     /* Save Type */
        !          2888: 
        !          2889:        movl    EXT(cpuid_value),%eax   /* Get high value */
        !          2890:        cmpl    $2,%eax                 /* Test if processor configuration */
        !          2891:        jle     0f                      /* is present */
        !          2892:        movl    $2,%eax                 /* get processor configuration */
        !          2893:        .word   0xA20F                  /* cpuid instruction */
        !          2894:        movl    %eax,EXT(cpuid_cache)   /* Store byte 0-3 of configuration */
        !          2895:        movl    %ebx,EXT(cpuid_cache)+4 /* Store byte 4-7 of configuration */
        !          2896:        movl    %ecx,EXT(cpuid_cache)+8 /* Store byte 8-B of configuration */
        !          2897:        movl    %edx,EXT(cpuid_cache)+12 /* Store byte C-F of configuration */
        !          2898: 0:
        !          2899:        popl    %ebx                    /* restore ebx */
        !          2900:        EMARF
        !          2901:        ret                             /* return */
        !          2902: 
        !          2903: ENTRY(get_cr0)
        !          2904:        movl    %cr0, %eax
        !          2905:        ret
        !          2906: 
        !          2907: ENTRY(set_cr0)
        !          2908:        movl    4(%esp), %eax
        !          2909:        movl    %eax, %cr0
        !          2910:        ret
        !          2911: 
        !          2912: #ifndef        SYMMETRY
        !          2913: 
        !          2914: /*
        !          2915:  * ffs(mask)
        !          2916:  */
        !          2917: ENTRY(ffs)
        !          2918:        bsfl    S_ARG0, %eax
        !          2919:        jz      0f
        !          2920:        incl    %eax
        !          2921:        ret
        !          2922: 0:     xorl    %eax, %eax
        !          2923:        ret
        !          2924: 
        !          2925: /*
        !          2926:  * cpu_shutdown()
        !          2927:  * Force reboot
        !          2928:  */
        !          2929: 
        !          2930: null_idtr:
        !          2931:        .word   0
        !          2932:        .long   0
        !          2933: 
        !          2934: Entry(cpu_shutdown)
        !          2935:         lidt    null_idtr       /* disable the interrupt handler */
        !          2936:         xor     %ecx,%ecx       /* generate a divide by zero */
        !          2937:         div     %ecx,%eax       /* reboot now */
        !          2938:         ret                     /* this will "never" be executed */
        !          2939: 
        !          2940: #endif /* SYMMETRY */
        !          2941: 
        !          2942: 
        !          2943: /*
        !          2944:  * setbit(int bitno, int *s) - set bit in bit string
        !          2945:  */
        !          2946: ENTRY(setbit)
        !          2947:        movl    S_ARG0, %ecx            /* bit number */
        !          2948:        movl    S_ARG1, %eax            /* address */
        !          2949:        btsl    %ecx, (%eax)            /* set bit */
        !          2950:        ret
        !          2951: 
        !          2952: /*
        !          2953:  * clrbit(int bitno, int *s) - clear bit in bit string
        !          2954:  */
        !          2955: ENTRY(clrbit)
        !          2956:        movl    S_ARG0, %ecx            /* bit number */
        !          2957:        movl    S_ARG1, %eax            /* address */
        !          2958:        btrl    %ecx, (%eax)            /* clear bit */
        !          2959:        ret
        !          2960: 
        !          2961: /*
        !          2962:  * ffsbit(int *s) - find first set bit in bit string
        !          2963:  */
        !          2964: ENTRY(ffsbit)
        !          2965:        movl    S_ARG0, %ecx            /* address */
        !          2966:        movl    $0, %edx                /* base offset */
        !          2967: 0:
        !          2968:        bsfl    (%ecx), %eax            /* check argument bits */
        !          2969:        jnz     1f                      /* found bit, return */
        !          2970:        addl    $4, %ecx                /* increment address */
        !          2971:        addl    $32, %edx               /* increment offset */
        !          2972:        jmp     0b                      /* try again */
        !          2973: 1:
        !          2974:        addl    %edx, %eax              /* return offset */
        !          2975:        ret
        !          2976: 
        !          2977: /*
        !          2978:  * testbit(int nr, volatile void *array)
        !          2979:  *
        !          2980:  * Test to see if the bit is set within the bit string
        !          2981:  */
        !          2982: 
        !          2983: ENTRY(testbit)
        !          2984:        movl    S_ARG0,%eax     /* Get the bit to test */
        !          2985:        movl    S_ARG1,%ecx     /* get the array string */
        !          2986:        btl     %eax,(%ecx)
        !          2987:        sbbl    %eax,%eax
        !          2988:        ret
        !          2989: 
        !          2990: ENTRY(get_pc)
        !          2991:        movl    4(%ebp),%eax
        !          2992:        ret
        !          2993: 
        !          2994: #if    ETAP
        !          2995: 
        !          2996: ENTRY(etap_get_pc)
        !          2997:        movl    4(%ebp), %eax           /* fetch pc of caller */
        !          2998:        ret
        !          2999: 
        !          3000: ENTRY(tvals_to_etap)
        !          3001:         movl   S_ARG0, %eax
        !          3002:        movl    $1000000000, %ecx
        !          3003:        mull    %ecx
        !          3004:        addl    S_ARG1, %eax
        !          3005:         adc     $0, %edx
        !          3006:                ret
        !          3007: 
        !          3008: /* etap_time_t
        !          3009:  * etap_time_sub(etap_time_t stop, etap_time_t start)
        !          3010:  *     
        !          3011:  *     64bit subtract, returns stop - start
        !          3012:  */                    
        !          3013: ENTRY(etap_time_sub)
        !          3014:        movl    S_ARG0, %eax            /* stop.low */
        !          3015:        movl    S_ARG1, %edx            /* stop.hi */
        !          3016:        subl    S_ARG2, %eax            /* stop.lo - start.lo */
        !          3017:        sbbl    S_ARG3, %edx            /* stop.hi - start.hi */
        !          3018:        ret
        !          3019:                
        !          3020: #endif /* ETAP */
        !          3021:        
        !          3022: #if    NCPUS > 1
        !          3023: 
        !          3024: ENTRY(minsecurity)
        !          3025:        pushl   %ebp
        !          3026:        movl    %esp,%ebp
        !          3027: /*
        !          3028:  * jail: set the EIP to "jail" to block a kernel thread.
        !          3029:  * Useful to debug synchronization problems on MPs.
        !          3030:  */
        !          3031: ENTRY(jail)
        !          3032:        jmp     EXT(jail)
        !          3033: 
        !          3034: #endif /* NCPUS > 1 */
        !          3035: 
        !          3036: /*
        !          3037:  * delay(microseconds)
        !          3038:  */
        !          3039: 
        !          3040: ENTRY(delay)
        !          3041:        movl    4(%esp),%eax
        !          3042:        testl   %eax, %eax
        !          3043:        jle     3f
        !          3044:        movl    EXT(delaycount), %ecx
        !          3045: 1:
        !          3046:        movl    %ecx, %edx
        !          3047: 2:
        !          3048:        decl    %edx
        !          3049:        jne     2b
        !          3050:        decl    %eax
        !          3051:        jne     1b
        !          3052: 3:
        !          3053:        ret
        !          3054: 
        !          3055: /*
        !          3056:  * unsigned int
        !          3057:  * div_scale(unsigned int dividend,
        !          3058:  *          unsigned int divisor,
        !          3059:  *          unsigned int *scale)
        !          3060:  *
        !          3061:  * This function returns (dividend << *scale) //divisor where *scale
        !          3062:  * is the largest possible value before overflow. This is used in
        !          3063:  * computation where precision must be achieved in order to avoid
        !          3064:  * floating point usage.
        !          3065:  *
        !          3066:  * Algorithm:
        !          3067:  *     *scale = 0;
        !          3068:  *     while (((dividend >> *scale) >= divisor))
        !          3069:  *             (*scale)++;
        !          3070:  *     *scale = 32 - *scale;
        !          3071:  *     return ((dividend << *scale) / divisor);  
        !          3072:  */
        !          3073: ENTRY(div_scale)
        !          3074:        PUSH_FRAME
        !          3075:        xorl    %ecx, %ecx              /* *scale = 0 */
        !          3076:        xorl    %eax, %eax
        !          3077:        movl    ARG0, %edx              /* get dividend */
        !          3078: 0:
        !          3079:        cmpl    ARG1, %edx              /* if (divisor > dividend) */
        !          3080:        jle     1f                      /* goto 1f */
        !          3081:        addl    $1, %ecx                /* (*scale)++ */
        !          3082:        shrdl   $1, %edx, %eax          /* dividend >> 1 */
        !          3083:        shrl    $1, %edx                /* dividend >> 1 */
        !          3084:        jmp     0b                      /* goto 0b */
        !          3085: 1:     
        !          3086:        divl    ARG1                    /* (dividend << (32 - *scale)) / divisor */
        !          3087:        movl    ARG2, %edx              /* get scale */
        !          3088:        movl    $32, (%edx)             /* *scale = 32 */
        !          3089:        subl    %ecx, (%edx)            /* *scale -= %ecx */
        !          3090:        POP_FRAME
        !          3091:        ret
        !          3092: 
        !          3093: /*
        !          3094:  * unsigned int
        !          3095:  * mul_scale(unsigned int multiplicand,
        !          3096:  *          unsigned int multiplier,
        !          3097:  *          unsigned int *scale)
        !          3098:  *
        !          3099:  * This function returns ((multiplicand * multiplier) >> *scale) where
        !          3100:  * scale is the largest possible value before overflow. This is used in
        !          3101:  * computation where precision must be achieved in order to avoid
        !          3102:  * floating point usage.
        !          3103:  *
        !          3104:  * Algorithm:
        !          3105:  *     *scale = 0;
        !          3106:  *     while (overflow((multiplicand * multiplier) >> *scale))
        !          3107:  *             (*scale)++;
        !          3108:  *     return ((multiplicand * multiplier) >> *scale);
        !          3109:  */
        !          3110: ENTRY(mul_scale)
        !          3111:        PUSH_FRAME
        !          3112:        xorl    %ecx, %ecx              /* *scale = 0 */
        !          3113:        movl    ARG0, %eax              /* get multiplicand */
        !          3114:        mull    ARG1                    /* multiplicand * multiplier */
        !          3115: 0:
        !          3116:        cmpl    $0, %edx                /* if (!overflow()) */
        !          3117:        je      1f                      /* goto 1 */
        !          3118:        addl    $1, %ecx                /* (*scale)++ */
        !          3119:        shrdl   $1, %edx, %eax          /* (multiplicand * multiplier) >> 1 */
        !          3120:        shrl    $1, %edx                /* (multiplicand * multiplier) >> 1 */
        !          3121:        jmp     0b
        !          3122: 1:
        !          3123:        movl    ARG2, %edx              /* get scale */
        !          3124:        movl    %ecx, (%edx)            /* set *scale */
        !          3125:        POP_FRAME
        !          3126:        ret
        !          3127: 
        !          3128: #if    NCPUS > 1
        !          3129: ENTRY(_cpu_number)
        !          3130:        CPU_NUMBER(%eax)
        !          3131:        ret
        !          3132: #endif /* NCPUS > 1 */
        !          3133: 
        !          3134: #ifdef MACH_BSD
        !          3135: /*
        !          3136:  * BSD System call entry point.. 
        !          3137:  */
        !          3138: 
        !          3139: Entry(trap_unix_syscall)
        !          3140:        pushf                           /* save flags as soon as possible */
        !          3141:        pushl   %eax                    /* save system call number */
        !          3142:        pushl   $0                      /* clear trap number slot */
        !          3143: 
        !          3144:        pusha                           /* save the general registers */
        !          3145:        pushl   %ds                     /* and the segment registers */
        !          3146:        pushl   %es
        !          3147:        pushl   %fs
        !          3148:        pushl   %gs
        !          3149: 
        !          3150:        mov     %ss,%dx                 /* switch to kernel data segment */
        !          3151:        mov     %dx,%ds
        !          3152:        mov     %dx,%es
        !          3153:        mov     $CPU_DATA,%dx
        !          3154:        mov     %dx,%gs
        !          3155: 
        !          3156: /*
        !          3157:  * Shuffle eflags,eip,cs into proper places
        !          3158:  */
        !          3159: 
        !          3160:        movl    R_EIP(%esp),%ebx        /* eflags are in EIP slot */
        !          3161:        movl    R_CS(%esp),%ecx         /* eip is in CS slot */
        !          3162:        movl    R_EFLAGS(%esp),%edx     /* cs is in EFLAGS slot */
        !          3163:        movl    %ecx,R_EIP(%esp)        /* fix eip */
        !          3164:        movl    %edx,R_CS(%esp)         /* fix cs */
        !          3165:        movl    %ebx,R_EFLAGS(%esp)     /* fix eflags */
        !          3166: 
        !          3167:        CPU_NUMBER(%edx)
        !          3168:         TIME_TRAP_UENTRY
        !          3169: 
        !          3170:         negl    %eax                    /* get system call number */
        !          3171:         shll    $4,%eax                 /* manual indexing */
        !          3172: 
        !          3173:        CPU_NUMBER(%edx)
        !          3174:        movl    CX(EXT(kernel_stack),%edx),%ebx
        !          3175:                                        /* get current kernel stack */
        !          3176:        xchgl   %ebx,%esp               /* switch stacks - %ebx points to */
        !          3177:                                        /* user registers. */
        !          3178: 
        !          3179: /*
        !          3180:  * Register use on entry:
        !          3181:  *   eax contains syscall number
        !          3182:  *   ebx contains user regs pointer
        !          3183:  */
        !          3184:        CAH(call_call)
        !          3185:        pushl   %ebx                    /* Push the regs set onto stack */
        !          3186:        call    EXT(unix_syscall)
        !          3187:        popl    %ebx
        !          3188:        movl    %esp,%ecx               /* get kernel stack */
        !          3189:        or      $(KERNEL_STACK_SIZE-1),%ecx
        !          3190:        movl    -3-IKS_SIZE(%ecx),%esp  /* switch back to PCB stack */
        !          3191:        movl    %eax,R_EAX(%esp)        /* save return value */
        !          3192:        jmp     EXT(return_from_trap)   /* return to user */
        !          3193: 
        !          3194: /*
        !          3195:  * Entry point for machdep system calls..
        !          3196:  */
        !          3197: 
        !          3198: Entry(trap_machdep_syscall)
        !          3199:        pushf                           /* save flags as soon as possible */
        !          3200:        pushl   %eax                    /* save system call number */
        !          3201:        pushl   $0                      /* clear trap number slot */
        !          3202: 
        !          3203:        pusha                           /* save the general registers */
        !          3204:        pushl   %ds                     /* and the segment registers */
        !          3205:        pushl   %es
        !          3206:        pushl   %fs
        !          3207:        pushl   %gs
        !          3208: 
        !          3209:        mov     %ss,%dx                 /* switch to kernel data segment */
        !          3210:        mov     %dx,%ds
        !          3211:        mov     %dx,%es
        !          3212:        mov     $CPU_DATA,%dx
        !          3213:        mov     %dx,%gs
        !          3214: 
        !          3215: /*
        !          3216:  * Shuffle eflags,eip,cs into proper places
        !          3217:  */
        !          3218: 
        !          3219:        movl    R_EIP(%esp),%ebx        /* eflags are in EIP slot */
        !          3220:        movl    R_CS(%esp),%ecx         /* eip is in CS slot */
        !          3221:        movl    R_EFLAGS(%esp),%edx     /* cs is in EFLAGS slot */
        !          3222:        movl    %ecx,R_EIP(%esp)        /* fix eip */
        !          3223:        movl    %edx,R_CS(%esp)         /* fix cs */
        !          3224:        movl    %ebx,R_EFLAGS(%esp)     /* fix eflags */
        !          3225: 
        !          3226:        CPU_NUMBER(%edx)
        !          3227:         TIME_TRAP_UENTRY
        !          3228: 
        !          3229:         negl    %eax                    /* get system call number */
        !          3230:         shll    $4,%eax                 /* manual indexing */
        !          3231: 
        !          3232:        CPU_NUMBER(%edx)
        !          3233:        movl    CX(EXT(kernel_stack),%edx),%ebx
        !          3234:                                        /* get current kernel stack */
        !          3235:        xchgl   %ebx,%esp               /* switch stacks - %ebx points to */
        !          3236:                                        /* user registers. */
        !          3237: 
        !          3238: /*
        !          3239:  * Register use on entry:
        !          3240:  *   eax contains syscall number
        !          3241:  *   ebx contains user regs pointer
        !          3242:  */
        !          3243:        CAH(call_call)
        !          3244:        pushl   %ebx
        !          3245:        call    EXT(machdep_syscall)
        !          3246:        popl    %ebx
        !          3247:        movl    %esp,%ecx               /* get kernel stack */
        !          3248:        or      $(KERNEL_STACK_SIZE-1),%ecx
        !          3249:        movl    -3-IKS_SIZE(%ecx),%esp  /* switch back to PCB stack */
        !          3250:        movl    %eax,R_EAX(%esp)        /* save return value */
        !          3251:        jmp     EXT(return_from_trap)   /* return to user */
        !          3252: 
        !          3253: Entry(trap_mach25_syscall)
        !          3254:        pushf                           /* save flags as soon as possible */
        !          3255:        pushl   %eax                    /* save system call number */
        !          3256:        pushl   $0                      /* clear trap number slot */
        !          3257: 
        !          3258:        pusha                           /* save the general registers */
        !          3259:        pushl   %ds                     /* and the segment registers */
        !          3260:        pushl   %es
        !          3261:        pushl   %fs
        !          3262:        pushl   %gs
        !          3263: 
        !          3264:        mov     %ss,%dx                 /* switch to kernel data segment */
        !          3265:        mov     %dx,%ds
        !          3266:        mov     %dx,%es
        !          3267:        mov     $CPU_DATA,%dx
        !          3268:        mov     %dx,%gs
        !          3269: 
        !          3270: /*
        !          3271:  * Shuffle eflags,eip,cs into proper places
        !          3272:  */
        !          3273: 
        !          3274:        movl    R_EIP(%esp),%ebx        /* eflags are in EIP slot */
        !          3275:        movl    R_CS(%esp),%ecx         /* eip is in CS slot */
        !          3276:        movl    R_EFLAGS(%esp),%edx     /* cs is in EFLAGS slot */
        !          3277:        movl    %ecx,R_EIP(%esp)        /* fix eip */
        !          3278:        movl    %edx,R_CS(%esp)         /* fix cs */
        !          3279:        movl    %ebx,R_EFLAGS(%esp)     /* fix eflags */
        !          3280: 
        !          3281:        CPU_NUMBER(%edx)
        !          3282:         TIME_TRAP_UENTRY
        !          3283: 
        !          3284:         negl    %eax                    /* get system call number */
        !          3285:         shll    $4,%eax                 /* manual indexing */
        !          3286: 
        !          3287:        CPU_NUMBER(%edx)
        !          3288:        movl    CX(EXT(kernel_stack),%edx),%ebx
        !          3289:                                        /* get current kernel stack */
        !          3290:        xchgl   %ebx,%esp               /* switch stacks - %ebx points to */
        !          3291:                                        /* user registers. */
        !          3292: 
        !          3293: /*
        !          3294:  * Register use on entry:
        !          3295:  *   eax contains syscall number
        !          3296:  *   ebx contains user regs pointer
        !          3297:  */
        !          3298:        CAH(call_call)
        !          3299:        pushl   %ebx
        !          3300:        call    EXT(mach25_syscall)
        !          3301:        popl    %ebx
        !          3302:        movl    %esp,%ecx               /* get kernel stack */
        !          3303:        or      $(KERNEL_STACK_SIZE-1),%ecx
        !          3304:        movl    -3-IKS_SIZE(%ecx),%esp  /* switch back to PCB stack */
        !          3305:        movl    %eax,R_EAX(%esp)        /* save return value */
        !          3306:        jmp     EXT(return_from_trap)   /* return to user */
        !          3307: 
        !          3308: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.