1/* 2 * FILE: ntoskrnl/ke/amd64/trap.S 3 * COPYRIGHT: See COPYING in the top level directory 4 * PURPOSE: System Traps, Entrypoints and Exitpoints 5 * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) 6 */ 7 8/* INCLUDES ******************************************************************/ 9 10#include <asm.inc> 11#include <ksamd64.inc> 12#include <trapamd64.inc> 13 14EXTERN KiDispatchException:PROC 15EXTERN KeBugCheckWithTf:PROC 16EXTERN MmAccessFault:PROC 17EXTERN KiSystemFatalException:PROC 18EXTERN KiNpxNotAvailableFaultHandler:PROC 19EXTERN KiGeneralProtectionFaultHandler:PROC 20EXTERN KiXmmExceptionHandler:PROC 21EXTERN KiDeliverApc:PROC 22EXTERN KiDpcInterruptHandler:PROC 23EXTERN PsConvertToGuiThread:PROC 24EXTERN MmCreateKernelStack:PROC 25EXTERN MmDeleteKernelStack:PROC 26 27EXTERN KdSetOwedBreakpoints:PROC 28 29 30/* Helper Macros *************************************************************/ 31 32MACRO(DispatchException, Status, Number, P1, P2, P3) 33 mov eax, Status 34 mov edx, Number 35 mov r9, P1 36 mov r10, P2 37 mov r11, P3 38 call InternalDispatchException 39ENDM 40 41MACRO(Fatal, BugcheckCode) 42 /* Bugcheck */ 43 mov ecx, BugcheckCode 44 mov rdx, rbp 45 call KiSystemFatalException 46ENDM 47 48 49/* FUNCTIONS *****************************************************************/ 50 51.code64 52 53ALIGN 8 54 55MACRO(UnexpectedVectorStub, Vector) 56 /* This nop is to make the relative jmp address 4 bytes aligned and to 57 make the whole code 8 bytes long */ 58 nop 59 /* This is a push instruction with 8bit operand. Since the instruction 60 sign extends the value to 32 bits, we need to offset it */ 61PUBLIC KxUnexpectedInterrupt&Vector 62KxUnexpectedInterrupt&Vector: 63 push (Vector - 128) 64 jmp KiUnexpectedInterrupt 65ENDM 66 67PUBLIC KiUnexpectedRange 68KiUnexpectedRange: 69Vector = 0 70REPEAT 256 71 UnexpectedVectorStub %Vector 72 Vector = Vector+1 73ENDR 74PUBLIC KiUnexpectedRangeEnd 75KiUnexpectedRangeEnd: 76 77PUBLIC KiInterruptDispatchTemplate 78KiInterruptDispatchTemplate: 79 /* This instruction pushes the return address on the stack, which is the 80 address of the interrupt object's DispatchCode member, then jumps 81 to the address stored in the interrupt object's DispatchAddress member */ 82 call qword ptr KiInterruptDispatchTemplate[rip - KINTERRUPT_DispatchCode + KINTERRUPT_DispatchAddress] 83 84 85// rbp = TrapFrame, eax = ExceptionCode, edx = NumParams, r9,r10,r11 = params 86FUNC InternalDispatchException 87 88 /* Allocate stack space for EXCEPTION_RECORD and KEXCEPTION_FRAME */ 89 sub rsp, EXCEPTION_RECORD_LENGTH + KEXCEPTION_FRAME_LENGTH 90 .allocstack (EXCEPTION_RECORD_LENGTH + KEXCEPTION_FRAME_LENGTH) 91 .endprolog 92 93 /* Set up EXCEPTION_RECORD */ 94 lea rcx, [rsp + KEXCEPTION_FRAME_LENGTH] 95 mov [rcx + EXCEPTION_RECORD_ExceptionCode], eax 96 xor rax, rax 97 mov [rcx + EXCEPTION_RECORD_ExceptionFlags], eax 98 mov [rcx + EXCEPTION_RECORD_ExceptionRecord], rax 99 mov rax, [rbp + KTRAP_FRAME_Rip] 100 mov [rcx + EXCEPTION_RECORD_ExceptionAddress], rax 101 mov [rcx + EXCEPTION_RECORD_NumberParameters], edx 102 mov [rcx + EXCEPTION_RECORD_ExceptionInformation + HEX(00)], r9 103 mov [rcx + EXCEPTION_RECORD_ExceptionInformation + HEX(08)], r10 104 mov [rcx + EXCEPTION_RECORD_ExceptionInformation + HEX(10)], r11 105 106 /* Set up KEXCEPTION_FRAME */ 107 mov rax, [rbp + KTRAP_FRAME_Rbp] 108 mov [rsp + KEXCEPTION_FRAME_Rbp], rax 109 mov [rsp + KEXCEPTION_FRAME_Rbx], rbx 110 mov [rsp + KEXCEPTION_FRAME_Rdi], rdi 111 mov [rsp + KEXCEPTION_FRAME_Rsi], rsi 112 mov [rsp + KEXCEPTION_FRAME_R12], r12 113 mov [rsp + KEXCEPTION_FRAME_R13], r13 114 mov [rsp + KEXCEPTION_FRAME_R14], r14 115 mov [rsp + KEXCEPTION_FRAME_R15], r15 116 movdqa [rsp + KEXCEPTION_FRAME_Xmm6], xmm6 117 movdqa [rsp + KEXCEPTION_FRAME_Xmm7], xmm7 118 movdqa [rsp + KEXCEPTION_FRAME_Xmm8], xmm8 119 movdqa [rsp + KEXCEPTION_FRAME_Xmm9], xmm9 120 movdqa [rsp + KEXCEPTION_FRAME_Xmm10], xmm10 121 movdqa [rsp + KEXCEPTION_FRAME_Xmm11], xmm11 122 movdqa [rsp + KEXCEPTION_FRAME_Xmm12], xmm12 123 movdqa [rsp + KEXCEPTION_FRAME_Xmm13], xmm13 124 movdqa [rsp + KEXCEPTION_FRAME_Xmm14], xmm14 125 movdqa [rsp + KEXCEPTION_FRAME_Xmm15], xmm15 126 mov qword ptr [rsp + KEXCEPTION_FRAME_Return], 0 127 128 /* Call KiDispatchException */ 129 // rcx already points to ExceptionRecord 130 mov rdx, rsp // ExceptionFrame 131 mov r8, rbp // TrapFrame 132 mov r9b, [r8 + KTRAP_FRAME_PreviousMode] // PreviousMode 133 mov byte ptr [rsp + KEXCEPTION_FRAME_P5], 1 // FirstChance 134 call KiDispatchException 135 136 /* Restore registers */ 137 mov r12, [rsp + KEXCEPTION_FRAME_R12] 138 mov r13, [rsp + KEXCEPTION_FRAME_R13] 139 mov r14, [rsp + KEXCEPTION_FRAME_R14] 140 mov r15, [rsp + KEXCEPTION_FRAME_R15] 141 movdqa xmm6, [rsp + KEXCEPTION_FRAME_Xmm6] 142 movdqa xmm7, [rsp + KEXCEPTION_FRAME_Xmm7] 143 movdqa xmm8, [rsp + KEXCEPTION_FRAME_Xmm8] 144 movdqa xmm9, [rsp + KEXCEPTION_FRAME_Xmm9] 145 movdqa xmm10, [rsp + KEXCEPTION_FRAME_Xmm10] 146 movdqa xmm11, [rsp + KEXCEPTION_FRAME_Xmm11] 147 movdqa xmm12, [rsp + KEXCEPTION_FRAME_Xmm12] 148 movdqa xmm13, [rsp + KEXCEPTION_FRAME_Xmm13] 149 movdqa xmm14, [rsp + KEXCEPTION_FRAME_Xmm14] 150 movdqa xmm15, [rsp + KEXCEPTION_FRAME_Xmm15] 151 152 add rsp, EXCEPTION_RECORD_LENGTH + KEXCEPTION_FRAME_LENGTH 153 ret 154ENDFUNC 155 156 157/* CPU EXCEPTION HANDLERS ****************************************************/ 158 159PUBLIC KiDivideErrorFault 160FUNC KiDivideErrorFault 161 /* Push pseudo error code */ 162 EnterTrap TF_SAVE_ALL 163 164 /* Enable interrupts */ 165 sti 166 167 /* Dispatch the exception */ 168 DispatchException STATUS_INTEGER_DIVIDE_BY_ZERO, 0, 0, 0, 0 169 170 /* Return */ 171 ExitTrap TF_SAVE_ALL 172ENDFUNC 173 174 175PUBLIC KiDebugTrapOrFault 176FUNC KiDebugTrapOrFault 177 /* Push pseudo error code */ 178 EnterTrap TF_SAVE_ALL 179 180 /* Check if the frame was from kernelmode */ 181 test word ptr [rbp + KTRAP_FRAME_SegCs], 3 182 jz KiDebugTrapOrFaultKMode 183 184 /* Enable interrupts for user-mode */ 185 sti 186 187KiDebugTrapOrFaultKMode: 188 /* Dispatch the exception */ 189 DispatchException STATUS_SINGLE_STEP, 0, 0, 0, 0 190 191 /* Return */ 192 ExitTrap TF_SAVE_ALL 193ENDFUNC 194 195 196PUBLIC KiNmiInterrupt 197FUNC KiNmiInterrupt 198 /* Push pseudo error code */ 199 EnterTrap TF_SAVE_ALL 200 201 UNIMPLEMENTED KiNmiInterrupt 202 int 3 203 204 /* Return */ 205 ExitTrap TF_SAVE_ALL 206ENDFUNC 207 208 209PUBLIC KiBreakpointTrap 210FUNC KiBreakpointTrap 211 /* Push pseudo error code */ 212 EnterTrap TF_SAVE_ALL 213 214 /* Check if the frame was from kernelmode */ 215 test word ptr [rbp + KTRAP_FRAME_SegCs], 3 216 jz KiBreakpointTrapKMode 217 218 /* Enable interrupts for user-mode */ 219 sti 220 221KiBreakpointTrapKMode: 222 /* Dispatch the exception */ 223 DispatchException STATUS_BREAKPOINT, 3, BREAKPOINT_BREAK, 0, 0 224 225 /* Return */ 226 ExitTrap TF_SAVE_ALL 227ENDFUNC 228 229 230PUBLIC KiOverflowTrap 231FUNC KiOverflowTrap 232 /* Push pseudo error code */ 233 EnterTrap TF_SAVE_ALL 234 235 /* Enable interrupts */ 236 sti 237 238 /* Dispatch the exception */ 239 DispatchException STATUS_INTEGER_OVERFLOW, 3, 0, 0, 0 240 241 /* Return */ 242 ExitTrap TF_SAVE_ALL 243ENDFUNC 244 245 246PUBLIC KiBoundFault 247FUNC KiBoundFault 248 /* Push pseudo error code */ 249 EnterTrap TF_SAVE_ALL 250 251 /* Check if the frame was from kernelmode */ 252 test word ptr [rbp + KTRAP_FRAME_SegCs], 3 253 jnz KiBoundFaultUserMode 254 255 /* Bugcheck */ 256 Fatal EXCEPTION_BOUND_CHECK 257 258KiBoundFaultUserMode: 259 /* Enable interrupts for user-mode */ 260 sti 261 262 /* Dispatch the exception */ 263 DispatchException STATUS_ARRAY_BOUNDS_EXCEEDED, 0, 0, 0, 0 264 265 /* Return */ 266 ExitTrap TF_SAVE_ALL 267ENDFUNC 268 269 270PUBLIC KiInvalidOpcodeFault 271FUNC KiInvalidOpcodeFault 272 /* Push pseudo error code */ 273 EnterTrap TF_SAVE_ALL 274 275 /* Enable interrupts */ 276 sti 277 278 /* Check if the frame was from kernelmode */ 279 test word ptr [rbp + KTRAP_FRAME_SegCs], 3 280 jz KiInvalidOpcodeKernel 281 282 // FIXME: handle STATUS_INVALID_LOCK_SEQUENCE 283 284KiInvalidOpcodeKernel: 285 /* Kernel mode fault */ 286 287 /* Dispatch the exception */ 288 DispatchException STATUS_ILLEGAL_INSTRUCTION, 0, 0, 0, 0 289 290 /* Return */ 291 ExitTrap TF_SAVE_ALL 292ENDFUNC 293 294 295PUBLIC KiNpxNotAvailableFault 296FUNC KiNpxNotAvailableFault 297 /* Push pseudo error code */ 298 EnterTrap TF_SAVE_ALL 299 300 /* Call the C handler */ 301 mov rcx, rbp 302 call KiNpxNotAvailableFaultHandler 303 304 /* Check the return status code */ 305 test eax, eax 306 jz KiNpxNotAvailableFaultExit 307 308 /* Dispatch the exception */ 309 DispatchException eax, 3, 0, 0, 0 310 311KiNpxNotAvailableFaultExit: 312 /* Return */ 313 ExitTrap TF_SAVE_ALL 314ENDFUNC 315 316 317PUBLIC KiDoubleFaultAbort 318FUNC KiDoubleFaultAbort 319 320 /* Hack for VBox, which "forgets" to push an error code on the stack! */ 321 and rsp, HEX(FFFFFFFFFFFFFFF0) 322 323 /* A zero error code is pushed */ 324 EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL) 325 326 int 3 327 328 /* Bugcheck */ 329 Fatal 8 // EXCEPTION_DOUBLE_FAULT 330 jmp $ 331ENDFUNC 332 333 334PUBLIC KiNpxSegmentOverrunAbort 335FUNC KiNpxSegmentOverrunAbort 336 /* Push pseudo error code */ 337 EnterTrap TF_SAVE_ALL 338 339 /* Bugcheck */ 340 Fatal EXCEPTION_NPX_OVERRUN 341 342 jmp $ 343ENDFUNC 344 345 346PUBLIC KiInvalidTssFault 347FUNC KiInvalidTssFault 348 /* We have an error code */ 349 EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL) 350 351 /* Bugcheck */ 352 Fatal EXCEPTION_INVALID_TSS 353 jmp $ 354ENDFUNC 355 356 357PUBLIC KiSegmentNotPresentFault 358FUNC KiSegmentNotPresentFault 359 /* We have an error code */ 360 EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL) 361 362 /* Bugcheck */ 363 Fatal EXCEPTION_SEGMENT_NOT_PRESENT 364 jmp $ 365ENDFUNC 366 367 368PUBLIC KiStackFault 369FUNC KiStackFault 370 /* We have an error code */ 371 EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL) 372 373 /* Bugcheck */ 374 Fatal EXCEPTION_STACK_FAULT 375 jmp $ 376ENDFUNC 377 378 379PUBLIC KiGeneralProtectionFault 380FUNC KiGeneralProtectionFault 381 /* We have an error code */ 382 EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL) 383 384 /* Call the C handler */ 385 mov rcx, rbp 386 call KiGeneralProtectionFaultHandler 387 388 /* Check for success */ 389 test eax, eax 390 jge KiGpfExit 391 392 /* Check for access violation */ 393 cmp eax, STATUS_ACCESS_VIOLATION 394 je DispatchAccessViolation 395 396 /* Dispatch privileged instruction fault */ 397 DispatchException eax, 0, 0, 0, 0 398 jmp KiGpfExit 399 400DispatchAccessViolation: 401 402 /* Dispatch access violation */ 403 DispatchException eax, 2, 0, -1, 0 404 405KiGpfExit: 406 /* Return */ 407 ExitTrap TF_SAVE_ALL 408ENDFUNC 409 410 411PUBLIC KiPageFault 412FUNC KiPageFault 413 /* We have an error code */ 414 EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL) 415 416 /* Save page fault address */ 417 mov rdx, cr2 418 mov [rbp + KTRAP_FRAME_FaultAddress], rdx 419 420 /* If interrupts are off, do not enable them */ 421 test dword ptr [rbp + KTRAP_FRAME_EFlags], EFLAGS_IF_MASK 422 jz IntsDisabled 423 424 /* Enable interrupts for the page fault handler */ 425 sti 426 427IntsDisabled: 428 429 /* Call page fault handler */ 430 mov ecx, [rbp + KTRAP_FRAME_ErrorCode] // FaultCode 431 // rdx == Address 432 mov r8b, [rbp + KTRAP_FRAME_SegCs] // Mode 433 and r8b, 1 434 mov r9, rbp // TrapInformation 435 call MmAccessFault 436 437 /* Check for success */ 438 test eax, eax 439 jl PageFaultError 440 441 /* Check whether the kernel debugger has owed breakpoints to be inserted */ 442 call KdSetOwedBreakpoints 443 /* We succeeded, return */ 444 jmp PageFaultReturn 445 446PageFaultError: 447 448 /* Set parameter 1 to error code */ 449 mov r9d, [rbp + KTRAP_FRAME_ErrorCode] 450 451 /* Set parameter 2 to faulting address */ 452 mov r10, cr2 // Param2 = faulting address 453 454 cmp eax, STATUS_ACCESS_VIOLATION 455 je AccessViolation 456 cmp eax, STATUS_GUARD_PAGE_VIOLATION 457 je SpecialCode 458 cmp eax, STATUS_STACK_OVERFLOW 459 je SpecialCode 460 461InPageException: 462 /* Dispatch in-page exception */ 463 mov r11d, eax // Param3 = Status 464 mov eax, STATUS_IN_PAGE_ERROR // ExceptionCode 465 mov edx, 3 // ParamCount 466 call InternalDispatchException 467 jmp PageFaultReturn 468 469AccessViolation: 470 /* Use more proper status code */ 471 mov eax, KI_EXCEPTION_ACCESS_VIOLATION 472 473SpecialCode: 474 /* Setup a normal page fault exception */ 475 mov edx, 2 // ParamCount 476 call InternalDispatchException 477 478PageFaultReturn: 479 480 /* Disable interrupts for the return */ 481 cli 482 483 /* Return */ 484 ExitTrap (TF_SAVE_ALL or TF_CHECKUSERAPC) 485ENDFUNC 486 487 488PUBLIC KiFloatingErrorFault 489FUNC KiFloatingErrorFault 490 /* Push pseudo error code */ 491 EnterTrap TF_SAVE_ALL 492 493 UNIMPLEMENTED KiFloatingErrorFault 494 int 3 495 496 /* Return */ 497 ExitTrap TF_SAVE_ALL 498ENDFUNC 499 500 501PUBLIC KiAlignmentFault 502FUNC KiAlignmentFault 503 /* We have an error code */ 504 EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL) 505 506 /* Bugcheck */ 507 Fatal EXCEPTION_ALIGNMENT_CHECK 508 jmp $ 509ENDFUNC 510 511 512PUBLIC KiMcheckAbort 513FUNC KiMcheckAbort 514 /* Push pseudo error code */ 515 EnterTrap TF_SAVE_ALL 516 517 /* Bugcheck */ 518 Fatal HEX(12) 519 jmp $ 520ENDFUNC 521 522 523PUBLIC KiXmmException 524FUNC KiXmmException 525 /* Push pseudo error code */ 526 EnterTrap TF_SAVE_ALL 527 528 /* Call the C handler */ 529 mov rcx, rbp 530 call KiXmmExceptionHandler 531 532 /* Check for success */ 533 test eax, eax 534 jge KiXmmExit 535 536 /* Dispatch the exception */ 537 DispatchException eax, 2, 0, [rbp+KTRAP_FRAME_MxCsr], 0 538 539 // FIXME: STATUS_FLOAT_MULTIPLE_TRAPS / STATUS_FLOAT_MULTIPLE_FAULTS 540 541KiXmmExit: 542 /* Return */ 543 ExitTrap TF_SAVE_ALL 544ENDFUNC 545 546 547/* SOFTWARE INTERRUPT SERVICES ***********************************************/ 548 549PUBLIC KiRaiseAssertion 550FUNC KiRaiseAssertion 551 /* We have an error code */ 552 EnterTrap (TF_SAVE_ALL) 553 554 /* Decrement RIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */ 555 sub qword ptr [rbp + KTRAP_FRAME_Rip], 2 556 557 /* Dispatch the exception */ 558 DispatchException STATUS_ASSERTION_FAILURE, 0, 0, 0, 0 559 560 /* Return */ 561 ExitTrap TF_SAVE_ALL 562ENDFUNC 563 564 565PUBLIC KiDebugServiceTrap 566FUNC KiDebugServiceTrap 567 /* No error code */ 568 EnterTrap TF_SAVE_ALL 569 570 /* Increase Rip to skip the int3 */ 571 inc qword ptr [rbp + KTRAP_FRAME_Rip] 572 573 /* Dispatch the exception (Params = service, buffer, legth) */ 574 DispatchException STATUS_BREAKPOINT, 3, [rbp+KTRAP_FRAME_Rax], [rbp+KTRAP_FRAME_Rcx], [rbp+KTRAP_FRAME_Rdx] 575 576 /* Return */ 577 ExitTrap TF_SAVE_ALL 578ENDFUNC 579 580 581PUBLIC KiApcInterrupt 582.PROC KiApcInterrupt 583 /* No error code */ 584 EnterTrap (TF_SAVE_ALL or TF_IRQL) 585 586 /* Raise to APC_LEVEL */ 587 mov rax, APC_LEVEL 588 mov cr8, rax 589 590 /* End the interrupt */ 591 mov dword ptr [APIC_EOI], 0 592 593 /* Enable interrupts */ 594 sti 595 596 /* Call the worker routine */ 597 mov cl, [rbp + KTRAP_FRAME_SegCs] // ProcessorMode 598 and cl, 1 599 mov rdx, 0 // ExceptionFrame 600 mov r8, rbp // TrapFrame 601 call KiDeliverApc 602 603 /* Disable interrupts */ 604 cli 605 606 /* Lower IRQL back to PASSIVE */ 607 mov rax, PASSIVE_LEVEL 608 mov cr8, rax 609 610 /* Return */ 611 ExitTrap (TF_SAVE_ALL or TF_IRQL) 612.ENDP 613 614/* 615 * VOID 616 * KiRetireDpcList( 617 * PKPRCB Prcb); 618 */ 619EXTERN KiRetireDpcList:PROC 620 621/* 622 * VOID 623 * KiRetireDpcListInDpcStack( 624 * PKPRCB Prcb, 625 * PVOID DpcStack); 626 */ 627PUBLIC KiRetireDpcListInDpcStack 628.PROC KiRetireDpcListInDpcStack 629 push rbp 630 .pushreg rbp 631 mov rbp, rsp 632 .setframe rbp, 0 633 .endprolog 634 635 /* Switch to the DpcStack */ 636 mov rsp, rdx 637 638 /* The stack is 16 byte aligned, allocate 32 bytes home space */ 639 sub rsp, 32 640 641 /* Call KiRetireDpcList on the given stack */ 642 call KiRetireDpcList 643 644 /* Restore stack, cleanup and return */ 645 mov rsp, rbp 646 pop rbp 647 ret 648.ENDP 649 650PUBLIC KiDpcInterrupt 651.PROC KiDpcInterrupt 652 /* No error code */ 653 EnterTrap (TF_SAVE_ALL or TF_IRQL) 654 655 /* Call the worker routine */ 656 call KiDpcInterruptHandler 657 658 /* Return, but don't send an EOI! */ 659 ExitTrap (TF_SAVE_ALL or TF_IRQL) 660.ENDP 661 662 663PUBLIC KiIpiInterrupt 664.PROC KiIpiInterrupt 665 /* No error code */ 666 EnterTrap (TF_SAVE_ALL or TF_IRQL) 667 668 /* Raise to IPI_LEVEL */ 669 mov rax, IPI_LEVEL 670 mov cr8, rax 671 672 /* End the interrupt */ 673 mov dword ptr [APIC_EOI], 0 674 675 int 3 676 677 /* Return */ 678 ExitTrap (TF_SAVE_ALL or TF_IRQL) 679.ENDP 680 681 682PUBLIC KiUnexpectedInterrupt 683FUNC KiUnexpectedInterrupt 684 /* The error code is the vector */ 685 EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL) 686 687#if 0 688 /* Set bugcheck parameters */ 689 mov ecx, TRAP_CAUSE_UNKNOWN 690 mov rdx, [rbp + KTRAP_FRAME_ErrorCode] // the vector 691 mov r8, 0 // The unknown floating-point exception 692 mov r9, 0 // The enabled and asserted status bits 693 sub rsp, 8 694 mov [rbp + KTRAP_FRAME_P5 + 8], rbp // trap frame 695 call KeBugCheckWithTf 696 jmp $ 697#endif 698 /* Return */ 699 ExitTrap TF_SAVE_ALL 700ENDFUNC 701 702PUBLIC KiInterruptDispatch 703FUNC KiInterruptDispatch 704 /* The error code is a pointer to the interrupt object's code */ 705 EnterTrap (TF_HAS_ERROR_CODE or TF_SAVE_ALL or TF_IRQL) 706 707 /* Increase interrupt count */ 708 inc dword ptr gs:[PcInterruptCount]; 709 710 /* Save rbx and rsi in the trap frame */ 711 mov [rbp + KTRAP_FRAME_Rbx], rbx 712 mov [rbp + KTRAP_FRAME_Rsi], rsi 713 714 /* Load the address of the dispatch code into rbx */ 715 mov rbx, [rbp + KTRAP_FRAME_ErrorCode] 716 717 /* Substract offset of the DispatchCode member plus 6 for the call instruction */ 718 sub rbx, KINTERRUPT_DispatchCode + 6 719 720 /* Save the address of the InterruptListEntry in rsi */ 721 lea rsi, [rbx + KINTERRUPT_InterruptListEntry] 722 723.DoDispatchInterrupt: 724 /* Raise IRQL to SynchronizeIrql */ 725 movzx rax, byte ptr [rbx + KINTERRUPT_SynchronizeIrql] 726 mov cr8, rax 727 728#ifdef CONFIG_SMP 729 /* Acquire interrupt lock */ 730 mov r8, [rbx + KINTERRUPT_ActualLock] 731 732 //KxAcquireSpinLock(Interrupt->ActualLock); 733#endif 734 735 /* Call the ISR */ 736 mov rcx, rbx 737 mov rdx, [rbx + KINTERRUPT_ServiceContext] 738 call qword ptr [rbx + KINTERRUPT_ServiceRoutine] 739 740#ifdef CONFIG_SMP 741 /* Release interrupt lock */ 742 //KxReleaseSpinLock(Interrupt->ActualLock); 743#endif 744 745 /* Go back to old irql */ 746 movzx rax, byte ptr [rbp + KTRAP_FRAME_PreviousIrql] 747 mov cr8, rax 748 749 /* Check for chained interrupts */ 750 mov rax, [rbx + KINTERRUPT_InterruptListEntry] 751 cmp rax, rsi 752 je .Done 753 754 /* Load the next interrupt object into rbx and repeat */ 755 lea rbx, [rax - KINTERRUPT_InterruptListEntry] 756 jmp .DoDispatchInterrupt 757 758.Done: 759 /* Restore rbx and rsi */ 760 mov rbx, [rbp + KTRAP_FRAME_Rbx] 761 mov rsi, [rbp + KTRAP_FRAME_Rsi] 762 763 /* Return */ 764 ExitTrap (TF_SAVE_ALL or TF_SEND_EOI) 765ENDFUNC 766 767EXTERN KiSystemCallHandler:PROC 768 769/*! \name KiSystemCallEntry64 770 * 771 * \brief This is the entrypoint for syscalls from 64bit user mode 772 * 773 * \param rax - The system call number 774 * \param rcx - User mode return address, set by the syscall instruction 775 * \param rdx,r8,r9 - Parameters 2-4 to the service function 776 * \param r10 - Parameter 1 to the service function 777 * \param r11 - RFLAGS saved by the syscall instruction 778 *--*/ 779PUBLIC KiSystemCallEntry64 780.PROC KiSystemCallEntry64 781 /* The unwind info pretends we have a machine frame */ 782 .PUSHFRAME 783 .ALLOCSTACK (KTRAP_FRAME_LENGTH + MAX_SYSCALL_PARAM_SIZE - MachineFrameLength) 784 .ENDPROLOG 785 786 /* Swap gs to kernel, so we can access the PCR */ 787 swapgs 788 789 /* Save the user mode rsp in the PCR */ 790 mov gs:[PcUserRsp], rsp 791 792 /* Get the kernel stack from the PCR */ 793 mov rsp, gs:[PcRspBase] 794 795 /* Allocate a TRAP_FRAME and space for parameters */ 796 sub rsp, (KTRAP_FRAME_LENGTH + MAX_SYSCALL_PARAM_SIZE) 797 798 /* Save volatile registers in the trap frame */ 799 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rax], rax 800 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rip], rcx 801 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rdx], rdx 802 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R8], r8 803 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R9], r9 804 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx], r10 805 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags], r11 806 807 /* Store user stack pointer in the trap frame */ 808 mov rax, gs:[PcUserRsp] 809 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rsp], rax 810 811 /* Set sane segments */ 812 mov ax, (KGDT64_R3_DATA or RPL_MASK) 813 mov ds, ax 814 mov es, ax 815 816 /* Save MCXSR and set kernel value */ 817 stmxcsr [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_MxCsr] 818 ldmxcsr gs:[PcMxCsr] 819 820#if DBG 821 /* Check IRQL */ 822 mov rax, cr8 823 test eax, eax 824 jz KiSystemCall64Again 825 int HEX(2C) 826#endif 827 828GLOBAL_LABEL KiSystemCall64Again 829 830 /* Call the C-handler (will enable interrupts) */ 831 call KiSystemCallHandler 832 833 /* The return value from KiSystemCallHandler is the address of the Nt-function */ 834 mov rcx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx] 835 mov rdx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rdx] 836 mov r8, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R8] 837 mov r9, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R9] 838 call rax 839 840GLOBAL_LABEL KiSystemServiceExit 841 842#if DBG 843 test dword ptr [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags], HEX(200) 844 jnz IntsEnabled 845 int 3 846IntsEnabled: 847#endif 848 849 /* Check for pending user APC */ 850 mov rcx, gs:qword ptr [PcCurrentThread] 851 cmp byte ptr [rcx + ThApcState + AsUserApcPending], 0 852 jz no_user_apc_pending 853 call KiInitiateUserApc 854no_user_apc_pending: 855 856 /* Disable interrupts for return */ 857 cli 858 859 /* Restore MCXSR */ 860 ldmxcsr [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_MxCsr] 861 862 /* Restore old trap frame */ 863 mov rcx, gs:[PcCurrentThread] 864 mov rdx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_TrapFrame] 865 mov [rcx + KTHREAD_TrapFrame], rdx 866 867 /* Prepare user mode return address (rcx) and eflags (r11) for sysret */ 868 mov rcx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rip] 869 mov r11, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags] 870 871 /* Load user mode stack (It was copied to the trap frame) */ 872 mov rsp, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rsp] 873 874 /* r8 points to the user stack */ 875 mov r8, rsp 876 877 /* r9 matches rbp */ 878 mov r9, rbp 879 880 /* Swap gs back to user */ 881 swapgs 882 883 /* Zero out volatiles */ 884 pxor xmm0, xmm0 885 pxor xmm1, xmm1 886 pxor xmm2, xmm2 887 pxor xmm3, xmm3 888 pxor xmm4, xmm4 889 pxor xmm5, xmm5 890 xor rdx, rdx 891 xor r10, r10 892 893 /* return to user mode */ 894 .byte HEX(48) // REX prefix to return to long mode 895 sysretq 896 897.ENDP 898 899 900/*! 901 * VOID 902 * DECLSPEC_NORETURN 903 * KiServiceExit(IN PKTRAP_FRAME TrapFrame, IN NTSTATUS Status)); 904 */ 905PUBLIC KiServiceExit 906.PROC KiServiceExit 907 .endprolog 908 909 lea rsp, [rcx - MAX_SYSCALL_PARAM_SIZE] 910 jmp KiSystemServiceExit 911 912.ENDP 913 914 915/*! 916 * VOID 917 * DECLSPEC_NORETURN 918 * KiServiceExit2(IN PKTRAP_FRAME TrapFrame); 919 */ 920PUBLIC KiServiceExit2 921.PROC KiServiceExit2 922 .ENDPROLOG 923 924 // FIXME: this should probably also restore an exception frame 925 926 mov rsp, rcx 927.ENDP 928 929PUBLIC KiServiceExit3 930.PROC KiServiceExit3 931 .PUSHFRAME 932 .ALLOCSTACK (KTRAP_FRAME_LENGTH - MachineFrameLength) 933 .ENDPROLOG 934 935#if DBG 936 /* Get the current IRQL and compare it to the trap frame */ 937 mov rax, cr8 938 cmp byte ptr [rsp + KTRAP_FRAME_PreviousIrql], al 939 je KiServiceExit2_ok1 940 int HEX(2C) 941 942KiServiceExit2_ok1: 943 /* Check if this is a user mode exit */ 944 mov ah, byte ptr [rsp + KTRAP_FRAME_SegCs] 945 test ah, 1 946 jz KiServiceExit2_kernel 947 948 /* Validate that we are at PASSIVE_LEVEL */ 949 test al, al 950 jz KiServiceExit2_kernel 951 int HEX(2C) 952 953KiServiceExit2_kernel: 954#endif 955 956 /* Return */ 957 mov rbp, rsp 958 ExitTrap TF_SAVE_ALL 959.ENDP 960 961 962PUBLIC KiSystemCallEntry32 963KiSystemCallEntry32: 964 swapgs 965 int 3 966 967 968PUBLIC KiZwSystemService 969FUNC KiZwSystemService 970 push rbp 971 .pushreg rbp 972 sub rsp, KTRAP_FRAME_LENGTH 973 .allocstack KTRAP_FRAME_LENGTH 974 mov [rsp + KTRAP_FRAME_Rsi], rsi 975 .savereg rsi, KTRAP_FRAME_Rsi 976 mov [rsp + KTRAP_FRAME_Rdi], rdi 977 .savereg rdi, KTRAP_FRAME_Rdi 978 mov rbp, rsp 979 .setframe rbp, 0 980 .endprolog 981 982 /* Get current thread */ 983 mov r11, gs:[PcCurrentThread] 984 985 /* Save PreviousMode in the trap frame */ 986 mov dil, byte ptr [r11 + KTHREAD_PreviousMode] 987 mov byte ptr [rbp + KTRAP_FRAME_PreviousMode], dil 988 989 /* Save the old trap frame in TrapFrame.Rdx */ 990 mov rdi, [r11 + KTHREAD_TrapFrame] 991 mov [rbp + KTRAP_FRAME_Rdx], rdi 992 993 /* Set the new trap frame and previous mode */ 994 mov [r11 + ThTrapFrame], rbp 995 mov byte ptr [r11 + KTHREAD_PreviousMode], 0 996 997 /* allocate space for parameters */ 998 sub rsp, r10 999 and rsp, HEX(0fffffffffffffff0) 1000 1001 /* Save rcx */ 1002 mov [rbp + KTRAP_FRAME_Rcx], rcx 1003 1004 /* copy parameters to the new location */ 1005 lea rsi, [rbp + KTRAP_FRAME_LENGTH + 16] 1006 lea rdi, [rsp] 1007 mov rcx, r10 1008 shr rcx, 3 1009 rep movsq 1010 1011 /* Restore rcx */ 1012 mov rcx, [rbp + KTRAP_FRAME_Rcx] 1013 1014 /* Call the service function */ 1015 call rax 1016 1017 /* Restore the old trap frame */ 1018 mov r11, gs:[PcCurrentThread] 1019 mov rsi, [rbp + KTRAP_FRAME_Rdx] 1020 mov [r11 + KTHREAD_TrapFrame], rsi 1021 1022 /* Restore PreviousMode from the trap frame */ 1023 mov dil, byte ptr [rbp + KTRAP_FRAME_PreviousMode] 1024 mov byte ptr [r11 + KTHREAD_PreviousMode], dil 1025 1026 /* Restore rdi and rsi */ 1027 mov rsi, [rbp + KTRAP_FRAME_Rsi] 1028 mov rdi, [rbp + KTRAP_FRAME_Rdi] 1029 1030 /* Cleanup the stack and return */ 1031 lea rsp, [rbp + KTRAP_FRAME_LENGTH] 1032 pop rbp 1033 ret 1034 1035ENDFUNC 1036 1037PUBLIC KiConvertToGuiThread 1038FUNC KiConvertToGuiThread 1039 1040 sub rsp, 40 1041 .allocstack 40 1042 .endprolog 1043 1044 /* Check if we already have a large stack */ 1045 mov rax, gs:[PcCurrentThread] 1046 cmp byte ptr [rax + KTHREAD_LargeStack], 0 1047 jnz AlreadyLargeStack 1048 1049 // NewStack = (ULONG_PTR)MmCreateKernelStack(TRUE, 0); 1050 mov cl, 1 1051 xor rdx, rdx 1052 call MmCreateKernelStack 1053 1054 /* Check for failure */ 1055 test rax, rax 1056 jz KiConvertToGuiThreadFailed 1057 1058 /* OldStack = KeSwitchKernelStack((PVOID)NewStack, (PVOID)(NewStack - KERNEL_LARGE_STACK_COMMIT )); */ 1059 mov rcx, rax 1060 mov rdx, rax 1061 sub rdx, KERNEL_LARGE_STACK_COMMIT 1062 call KeSwitchKernelStack 1063 1064 // MmDeleteKernelStack(OldStack, FALSE); 1065 mov rcx, rax 1066 xor rdx, rdx 1067 call MmDeleteKernelStack 1068 1069AlreadyLargeStack: 1070 1071 /* Call the worker function */ 1072 call PsConvertToGuiThread 1073 1074 /* Check for failure */ 1075 test eax, eax 1076 js KiConvertToGuiThreadFailed 1077 1078 /* Disable interrupts for return */ 1079 cli 1080 1081 // FIXME: should just do the trap frame switch in KiSystemCallHandler64 1082 /* Restore old trap frame */ 1083 mov rcx, gs:[PcCurrentThread] 1084 mov rdx, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_TrapFrame] 1085 mov [rcx + KTHREAD_TrapFrame], rdx 1086 1087 // Restore register parameters 1088 mov rcx, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rip] 1089 mov rdx, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rdx] 1090 mov r8, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R8] 1091 mov r9, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R9] 1092 1093 /* Run KiSystemCallHandler again */ 1094 add rsp, 48 1095 jmp KiSystemCall64Again 1096 1097KiConvertToGuiThreadFailed: 1098 1099 /* Clean up the stack and return failure */ 1100 add rsp, 40 1101 mov eax, HEX(C0000017) // STATUS_NO_MEMORY 1102 ret 1103 1104ENDFUNC 1105 1106 1107EXTERN KiSetTrapContextInternal:PROC 1108 1109/* 1110 * VOID 1111 * KiSetTrapContext( 1112 * _Out_ PKTRAP_FRAME TrapFrame, 1113 * _In_ PCONTEXT Context, 1114 * _In_ KPROCESSOR_MODE RequestorMode); 1115 */ 1116PUBLIC KiSetTrapContext 1117.PROC KiSetTrapContext 1118 1119 /* Generate a KEXCEPTION_FRAME on the stack */ 1120 GENERATE_EXCEPTION_FRAME 1121 1122 call KiSetTrapContextInternal 1123 1124 /* Restore the registers from the KEXCEPTION_FRAME */ 1125 RESTORE_EXCEPTION_STATE 1126 1127 /* Return */ 1128 ret 1129 1130.ENDP 1131 1132 1133/* 1134 * VOID 1135 * KiDeliverApc( 1136 * _In_ KPROCESSOR_MODE DeliveryMode, 1137 * _In_ PKEXCEPTION_FRAME ExceptionFrame, 1138 * _In_ PKTRAP_FRAME TrapFrame); 1139 * 1140 */ 1141EXTERN KiDeliverApc:PROC 1142 1143PUBLIC KiInitiateUserApc 1144.PROC KiInitiateUserApc 1145 1146 /* Generate a KEXCEPTION_FRAME on the stack */ 1147 GENERATE_EXCEPTION_FRAME 1148 1149 /* Raise IRQL to APC_LEVEL */ 1150 mov rax, APC_LEVEL 1151 mov cr8, rax 1152 1153 /* Enable interrupts */ 1154 sti 1155 1156 /* Get the current trap frame */ 1157 mov rax, gs:[PcCurrentThread] 1158 mov r8, [rax + KTHREAD_TrapFrame] 1159 1160 /* Call the C function */ 1161 mov ecx, 1 1162 mov rdx, rsp 1163 call KiDeliverApc 1164 1165 /* Disable interrupts again */ 1166 cli 1167 1168 /* Go back to PASSIVE_LEVEL */ 1169 mov rax, PASSIVE_LEVEL 1170 mov cr8, rax 1171 1172 /* Restore the registers from the KEXCEPTION_FRAME */ 1173 RESTORE_EXCEPTION_STATE 1174 1175 /* Return */ 1176 ret 1177 1178.ENDP 1179 1180 1181PUBLIC KiInitializeSegments 1182KiInitializeSegments: 1183 mov ax, KGDT64_R3_DATA or RPL_MASK 1184 mov gs, ax 1185 swapgs 1186 mov gs, ax 1187 ret 1188 1189/*! 1190 * VOID 1191 * KiSwitchKernelStackHelper( 1192 * LONG_PTR StackOffset, 1193 * PVOID OldStackBase); 1194 */ 1195PUBLIC KiSwitchKernelStackHelper 1196KiSwitchKernelStackHelper: 1197 1198 /* Pop return address from the current stack */ 1199 pop rax 1200 1201 /* Switch to new stack */ 1202 lea rsp, [rsp + rcx] 1203 1204 /* Push return address on the new stack */ 1205 push rax 1206 1207 /* Return on new stack */ 1208 mov rax, rdx 1209 ret 1210 1211EXTERN KiSwitchKernelStack:PROC 1212 1213PUBLIC KeSwitchKernelStack 1214FUNC KeSwitchKernelStack 1215 1216 /* Save rcx and allocate callee home space */ 1217 mov [rsp + P1Home], rcx 1218 .savereg rcx, P1Home 1219 sub rsp, 40 1220 .allocstack 40 1221 .endprolog 1222 1223 /* Call the C handler, which returns the old stack in rax */ 1224 call KiSwitchKernelStack 1225 1226 /* Restore rcx (StackBase) */ 1227 mov rcx, [rsp + 40 + P1Home] 1228 1229 /* Switch to new stack: RSP += (StackBase - OldStackBase) */ 1230 sub rcx, rax 1231 add rsp, rcx 1232 1233 /* Deallocate the home frame */ 1234 add rsp, 40 1235 ret 1236 1237ENDFUNC 1238 1239 1240 1241 1242#ifdef _MSC_VER 1243#undef lgdt 1244#undef lidt 1245 1246//void __lgdt(void *Source); 1247PUBLIC __lgdt 1248__lgdt: 1249 lgdt fword ptr [rcx] 1250 ret 1251 1252//void __sgdt(void *Destination); 1253PUBLIC __sgdt 1254__sgdt: 1255 sgdt fword ptr [rcx] 1256 ret 1257 1258// void __lldt(unsigned short Value) 1259PUBLIC __lldt 1260__lldt: 1261 lldt cx 1262 ret 1263 1264//void __sldt(void *Destination); 1265PUBLIC __sldt 1266__sldt: 1267 sldt word ptr [rcx] 1268 ret 1269 1270//void __ltr(unsigned short Source); 1271PUBLIC __ltr 1272__ltr: 1273 ltr cx 1274 ret 1275 1276//void __str(unsigned short *Destination); 1277PUBLIC __str 1278__str: 1279 str word ptr [rcx] 1280 ret 1281 1282PUBLIC __swapgs 1283__swapgs: 1284 swapgs 1285 ret 1286 1287#endif 1288 1289END 1290