|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.