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 KiGpfFatal 399 400DispatchAccessViolation: 401 402 /* Dispatch access violation */ 403 DispatchException eax, 2, 0, -1, 0 404 405KiGpfFatal: 406 407 /* Bugcheck */ 408 mov ecx, UNEXPECTED_KERNEL_MODE_TRAP 409 mov rdx, HEX(000D) // EXCEPTION_GP_FAULT 410 xor r8, r8 411 mov r9, [rbp + KTRAP_FRAME_ErrorCode] // error code 412 sub rsp, 8 413 mov [rsp + KTRAP_FRAME_P5+8], rbp // trap frame 414 call KeBugCheckWithTf 415 416KiGpfExit: 417 /* Return */ 418 /* Return */ 419 ExitTrap TF_SAVE_ALL 420ENDFUNC 421 422 423PUBLIC KiPageFault 424FUNC KiPageFault 425 /* We have an error code */ 426 EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL) 427 428 /* Save page fault address */ 429 mov rdx, cr2 430 mov [rbp + KTRAP_FRAME_FaultAddress], rdx 431 432 /* If interrupts are off, treat this as an access violation */ 433 test dword ptr [rbp + KTRAP_FRAME_EFlags], EFLAGS_IF_MASK 434 jz AccessViolation 435 436 /* Enable interrupts for the page fault handler */ 437 sti 438 439 /* Call page fault handler */ 440 mov ecx, [rbp + KTRAP_FRAME_ErrorCode] // FaultCode 441 // rdx == Address 442 mov r8b, [rbp + KTRAP_FRAME_SegCs] // Mode 443 and r8b, 1 444 mov r9, rbp // TrapInformation 445 call MmAccessFault 446 447 /* Check for success */ 448 test eax, eax 449 jl PageFaultError 450 451 /* Check whether the kernel debugger has owed breakpoints to be inserted */ 452 call KdSetOwedBreakpoints 453 /* We succeeded, return */ 454 jmp PageFaultReturn 455 456PageFaultError: 457 458 /* Disable interrupts again for the debugger */ 459 cli 460 461 /* Set parameter 1 to error code */ 462 mov r9d, [rbp + KTRAP_FRAME_ErrorCode] 463 464 /* Set parameter2 to faulting address */ 465 mov r10, cr2 // Param2 = faulting address 466 467 cmp eax, STATUS_ACCESS_VIOLATION 468 je AccessViolation 469 cmp eax, STATUS_GUARD_PAGE_VIOLATION 470 je SpecialCode 471 cmp eax, STATUS_STACK_OVERFLOW 472 je SpecialCode 473 474InPageException: 475 /* Dispatch in-page exception */ 476 mov r11d, eax // Param3 = Status 477 mov eax, STATUS_IN_PAGE_ERROR // ExceptionCode 478 mov edx, 3 // ParamCount 479 call InternalDispatchException 480 jmp PageFaultReturn 481 482AccessViolation: 483 /* Use more proper status code */ 484 mov eax, KI_EXCEPTION_ACCESS_VIOLATION 485 486SpecialCode: 487 /* Setup a normal page fault exception */ 488 mov edx, 2 // ParamCount 489 call InternalDispatchException 490 491PageFaultReturn: 492 /* Return */ 493 ExitTrap (TF_SAVE_ALL or TF_CHECKUSERAPC) 494ENDFUNC 495 496 497PUBLIC KiFloatingErrorFault 498FUNC KiFloatingErrorFault 499 /* Push pseudo error code */ 500 EnterTrap TF_SAVE_ALL 501 502 UNIMPLEMENTED KiFloatingErrorFault 503 int 3 504 505 /* Return */ 506 ExitTrap TF_SAVE_ALL 507ENDFUNC 508 509 510PUBLIC KiAlignmentFault 511FUNC KiAlignmentFault 512 /* We have an error code */ 513 EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL) 514 515 /* Bugcheck */ 516 Fatal EXCEPTION_ALIGNMENT_CHECK 517 jmp $ 518ENDFUNC 519 520 521PUBLIC KiMcheckAbort 522FUNC KiMcheckAbort 523 /* Push pseudo error code */ 524 EnterTrap TF_SAVE_ALL 525 526 /* Bugcheck */ 527 Fatal HEX(12) 528 jmp $ 529ENDFUNC 530 531 532PUBLIC KiXmmException 533FUNC KiXmmException 534 /* Push pseudo error code */ 535 EnterTrap TF_SAVE_ALL 536 537 /* Call the C handler */ 538 mov rcx, rbp 539 call KiXmmExceptionHandler 540 541 /* Check for success */ 542 test eax, eax 543 jge KiXmmExit 544 545 /* Dispatch the exception */ 546 DispatchException eax, 2, 0, [rbp+KTRAP_FRAME_MxCsr], 0 547 548 // FIXME: STATUS_FLOAT_MULTIPLE_TRAPS / STATUS_FLOAT_MULTIPLE_FAULTS 549 550KiXmmExit: 551 /* Return */ 552 ExitTrap TF_SAVE_ALL 553ENDFUNC 554 555 556/* SOFTWARE INTERRUPT SERVICES ***********************************************/ 557 558PUBLIC KiRaiseAssertion 559FUNC KiRaiseAssertion 560 /* We have an error code */ 561 EnterTrap (TF_SAVE_ALL) 562 563 /* Decrement RIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */ 564 sub qword ptr [rbp + KTRAP_FRAME_Rip], 2 565 566 /* Dispatch the exception */ 567 DispatchException STATUS_ASSERTION_FAILURE, 0, 0, 0, 0 568 569 /* Return */ 570 ExitTrap TF_SAVE_ALL 571ENDFUNC 572 573 574PUBLIC KiDebugServiceTrap 575FUNC KiDebugServiceTrap 576 /* No error code */ 577 EnterTrap TF_SAVE_ALL 578 579 /* Increase Rip to skip the int3 */ 580 inc qword ptr [rbp + KTRAP_FRAME_Rip] 581 582 /* Dispatch the exception (Params = service, buffer, legth) */ 583 DispatchException STATUS_BREAKPOINT, 3, [rbp+KTRAP_FRAME_Rax], [rbp+KTRAP_FRAME_Rcx], [rbp+KTRAP_FRAME_Rdx] 584 585 /* Return */ 586 ExitTrap TF_SAVE_ALL 587ENDFUNC 588 589 590PUBLIC KiApcInterrupt 591.PROC KiApcInterrupt 592 /* No error code */ 593 EnterTrap (TF_VOLATILES or TF_IRQL) 594 595 /* Raise to APC_LEVEL */ 596 mov rax, APC_LEVEL 597 mov cr8, rax 598 599 /* End the interrupt */ 600 mov dword ptr [APIC_EOI], 0 601 602 /* Enable interrupts */ 603 sti 604 605 /* Call the worker routine */ 606 mov cl, [rbp + KTRAP_FRAME_SegCs] // ProcessorMode 607 and cl, 1 608 mov rdx, 0 // ExceptionFrame 609 mov r8, rbp // TrapFrame 610 call KiDeliverApc 611 612 /* Disable interrupts */ 613 cli 614 615 /* Lower IRQL back to PASSIVE */ 616 mov rax, PASSIVE_LEVEL 617 mov cr8, rax 618 619 /* Return */ 620 ExitTrap (TF_VOLATILES or TF_IRQL) 621.ENDP 622 623/* 624 * VOID 625 * KiRetireDpcList( 626 * PKPRCB Prcb); 627 */ 628EXTERN KiRetireDpcList:PROC 629 630/* 631 * VOID 632 * KiRetireDpcListInDpcStack( 633 * PKPRCB Prcb, 634 * PVOID DpcStack); 635 */ 636PUBLIC KiRetireDpcListInDpcStack 637.PROC KiRetireDpcListInDpcStack 638 push rbp 639 .pushreg rbp 640 mov rbp, rsp 641 .setframe rbp, 0 642 .endprolog 643 644 /* Switch to the DpcStack */ 645 mov rsp, rdx 646 647 /* The stack is 16 byte aligned, allocate 32 bytes home space */ 648 sub rsp, 32 649 650 /* Call KiRetireDpcList on the given stack */ 651 call KiRetireDpcList 652 653 /* Restore stack, cleanup and return */ 654 mov rsp, rbp 655 pop rbp 656 ret 657.ENDP 658 659PUBLIC KiDpcInterrupt 660.PROC KiDpcInterrupt 661 /* No error code */ 662 EnterTrap (TF_VOLATILES or TF_IRQL) 663 664 /* Call the worker routine */ 665 call KiDpcInterruptHandler 666 667 /* Return, but don't send an EOI! */ 668 ExitTrap (TF_VOLATILES or TF_IRQL) 669.ENDP 670 671 672PUBLIC KiIpiInterrupt 673.PROC KiIpiInterrupt 674 /* No error code */ 675 EnterTrap (TF_VOLATILES or TF_IRQL) 676 677 /* Raise to IPI_LEVEL */ 678 mov rax, IPI_LEVEL 679 mov cr8, rax 680 681 /* End the interrupt */ 682 mov dword ptr [APIC_EOI], 0 683 684 int 3 685 686 /* Return */ 687 ExitTrap (TF_VOLATILES or TF_IRQL) 688.ENDP 689 690 691PUBLIC KiUnexpectedInterrupt 692FUNC KiUnexpectedInterrupt 693 /* The error code is the vector */ 694 EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL) 695 696#if 0 697 /* Set bugcheck parameters */ 698 mov ecx, TRAP_CAUSE_UNKNOWN 699 mov rdx, [rbp + KTRAP_FRAME_ErrorCode] // the vector 700 mov r8, 0 // The unknown floating-point exception 701 mov r9, 0 // The enabled and asserted status bits 702 sub rsp, 8 703 mov [rbp + KTRAP_FRAME_P5 + 8], rbp // trap frame 704 call KeBugCheckWithTf 705 jmp $ 706#endif 707 /* Return */ 708 ExitTrap TF_SAVE_ALL 709ENDFUNC 710 711PUBLIC KiInterruptDispatch 712FUNC KiInterruptDispatch 713 /* The error code is a pointer to the interrupt object's code */ 714 EnterTrap (TF_HAS_ERROR_CODE or TF_SAVE_ALL or TF_IRQL) 715 716 /* Increase interrupt count */ 717 inc dword ptr gs:[PcInterruptCount]; 718 719 /* Save rbx and rsi in the trap frame */ 720 mov [rbp + KTRAP_FRAME_Rbx], rbx 721 mov [rbp + KTRAP_FRAME_Rsi], rsi 722 723 /* Load the address of the dispatch code into rbx */ 724 mov rbx, [rbp + KTRAP_FRAME_ErrorCode] 725 726 /* Substract offset of the DispatchCode member plus 6 for the call instruction */ 727 sub rbx, KINTERRUPT_DispatchCode + 6 728 729 /* Save the address of the InterruptListEntry in rsi */ 730 lea rsi, [rbx + KINTERRUPT_InterruptListEntry] 731 732.DoDispatchInterrupt: 733 /* Raise IRQL to SynchronizeIrql */ 734 movzx rax, byte ptr [rbx + KINTERRUPT_SynchronizeIrql] 735 mov cr8, rax 736 737#ifdef CONFIG_SMP 738 /* Acquire interrupt lock */ 739 mov r8, [rbx + KINTERRUPT_ActualLock] 740 741 //KxAcquireSpinLock(Interrupt->ActualLock); 742#endif 743 744 /* Call the ISR */ 745 mov rcx, rbx 746 mov rdx, [rbx + KINTERRUPT_ServiceContext] 747 call qword ptr [rbx + KINTERRUPT_ServiceRoutine] 748 749#ifdef CONFIG_SMP 750 /* Release interrupt lock */ 751 //KxReleaseSpinLock(Interrupt->ActualLock); 752#endif 753 754 /* Go back to old irql */ 755 movzx rax, byte ptr [rbp + KTRAP_FRAME_PreviousIrql] 756 mov cr8, rax 757 758 /* Check for chained interrupts */ 759 mov rax, [rbx + KINTERRUPT_InterruptListEntry] 760 cmp rax, rsi 761 je .Done 762 763 /* Load the next interrupt object into rbx and repeat */ 764 lea rbx, [rax - KINTERRUPT_InterruptListEntry] 765 jmp .DoDispatchInterrupt 766 767.Done: 768 /* Restore rbx and rsi */ 769 mov rbx, [rbp + KTRAP_FRAME_Rbx] 770 mov rsi, [rbp + KTRAP_FRAME_Rsi] 771 772 /* Return */ 773 ExitTrap (TF_SAVE_ALL or TF_SEND_EOI) 774ENDFUNC 775 776EXTERN KiSystemCallHandler:PROC 777 778/*! \name KiSystemCallEntry64 779 * 780 * \brief This is the entrypoint for syscalls from 64bit user mode 781 * 782 * \param rax - The system call number 783 * \param rcx - User mode return address, set by the syscall instruction 784 * \param rdx,r8,r9 - Parameters 2-4 to the service function 785 * \param r10 - Parameter 1 to the service function 786 * \param r11 - RFLAGS saved by the syscall instruction 787 *--*/ 788PUBLIC KiSystemCallEntry64 789.PROC KiSystemCallEntry64 790 /* The unwind info pretends we have a machine frame */ 791 .PUSHFRAME 792 .ALLOCSTACK (KTRAP_FRAME_LENGTH + MAX_SYSCALL_PARAM_SIZE - MachineFrameLength) 793 .ENDPROLOG 794 795 /* Swap gs to kernel, so we can access the PCR */ 796 swapgs 797 798 /* Save the user mode rsp in the PCR */ 799 mov gs:[PcUserRsp], rsp 800 801 /* Get the kernel stack from the PCR */ 802 mov rsp, gs:[PcRspBase] 803 804 /* Allocate a TRAP_FRAME and space for parameters */ 805 sub rsp, (KTRAP_FRAME_LENGTH + MAX_SYSCALL_PARAM_SIZE) 806 807 /* Save volatile registers in the trap frame */ 808 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rax], rax 809 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rip], rcx 810 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rdx], rdx 811 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R8], r8 812 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R9], r9 813 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx], r10 814 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags], r11 815 816 /* Store user stack pointer in the trap frame */ 817 mov rax, gs:[PcUserRsp] 818 mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rsp], rax 819 820 /* Set sane segments */ 821 mov ax, (KGDT64_R3_DATA or RPL_MASK) 822 mov ds, ax 823 mov es, ax 824 825 /* Save MCXSR and set kernel value */ 826 stmxcsr [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_MxCsr] 827 ldmxcsr gs:[PcMxCsr] 828 829#if DBG 830 /* Check IRQL */ 831 mov rax, cr8 832 test eax, eax 833 jz KiSystemCall64Again 834 int HEX(2C) 835#endif 836 837GLOBAL_LABEL KiSystemCall64Again 838 839 /* Call the C-handler (will enable interrupts) */ 840 call KiSystemCallHandler 841 842 /* The return value from KiSystemCallHandler is the address of the Nt-function */ 843 mov rcx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx] 844 mov rdx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rdx] 845 mov r8, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R8] 846 mov r9, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R9] 847 call rax 848 849GLOBAL_LABEL KiSystemServiceExit 850 851#if DBG 852 test dword ptr [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags], HEX(200) 853 jnz IntsEnabled 854 int 3 855IntsEnabled: 856#endif 857 858 /* Check for pending user APC */ 859 mov rcx, gs:qword ptr [PcCurrentThread] 860 cmp byte ptr [rcx + ThApcState + AsUserApcPending], 0 861 jz no_user_apc_pending 862 call KiInitiateUserApc 863no_user_apc_pending: 864 865 /* Disable interrupts for return */ 866 cli 867 868 /* Restore MCXSR */ 869 ldmxcsr [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_MxCsr] 870 871 /* Restore old trap frame */ 872 mov rcx, gs:[PcCurrentThread] 873 mov rdx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_TrapFrame] 874 mov [rcx + KTHREAD_TrapFrame], rdx 875 876 /* Prepare user mode return address (rcx) and eflags (r11) for sysret */ 877 mov rcx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rip] 878 mov r11, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags] 879 880 /* Load user mode stack (It was copied to the trap frame) */ 881 mov rsp, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rsp] 882 883 /* r8 points to the user stack */ 884 mov r8, rsp 885 886 /* r9 matches rbp */ 887 mov r9, rbp 888 889 /* Swap gs back to user */ 890 swapgs 891 892 /* Zero out volatiles */ 893 pxor xmm0, xmm0 894 pxor xmm1, xmm1 895 pxor xmm2, xmm2 896 pxor xmm3, xmm3 897 pxor xmm4, xmm4 898 pxor xmm5, xmm5 899 xor rdx, rdx 900 xor r10, r10 901 902 /* return to user mode */ 903 .byte HEX(48) // REX prefix to return to long mode 904 sysretq 905 906.ENDP 907 908 909/*! 910 * VOID 911 * DECLSPEC_NORETURN 912 * KiServiceExit(IN PKTRAP_FRAME TrapFrame, IN NTSTATUS Status)); 913 */ 914PUBLIC KiServiceExit 915.PROC KiServiceExit 916 .endprolog 917 918 lea rsp, [rcx - MAX_SYSCALL_PARAM_SIZE] 919 jmp KiSystemServiceExit 920 921.ENDP 922 923 924/*! 925 * VOID 926 * DECLSPEC_NORETURN 927 * KiServiceExit2(IN PKTRAP_FRAME TrapFrame); 928 */ 929PUBLIC KiServiceExit2 930.PROC KiServiceExit2 931 .ENDPROLOG 932 933 // FIXME: this should probably also restore an exception frame 934 935 mov rsp, rcx 936.ENDP 937 938PUBLIC KiServiceExit3 939.PROC KiServiceExit3 940 .PUSHFRAME 941 .ALLOCSTACK (KTRAP_FRAME_LENGTH - MachineFrameLength) 942 .ENDPROLOG 943 944#if DBG 945 /* Get the current IRQL and compare it to the trap frame */ 946 mov rax, cr8 947 cmp byte ptr [rsp + KTRAP_FRAME_PreviousIrql], al 948 je KiServiceExit2_ok1 949 int HEX(2C) 950 951KiServiceExit2_ok1: 952 /* Check if this is a user mode exit */ 953 mov ah, byte ptr [rsp + KTRAP_FRAME_SegCs] 954 test ah, 1 955 jz KiServiceExit2_kernel 956 957 /* Validate that we are at PASSIVE_LEVEL */ 958 test al, al 959 jz KiServiceExit2_kernel 960 int HEX(2C) 961 962KiServiceExit2_kernel: 963#endif 964 965 /* Return */ 966 mov rbp, rsp 967 ExitTrap TF_SAVE_ALL 968.ENDP 969 970 971PUBLIC KiSystemCallEntry32 972KiSystemCallEntry32: 973 swapgs 974 int 3 975 976 977PUBLIC KiZwSystemService 978FUNC KiZwSystemService 979 push rbp 980 .pushreg rbp 981 sub rsp, KTRAP_FRAME_LENGTH 982 .allocstack KTRAP_FRAME_LENGTH 983 mov [rsp + KTRAP_FRAME_Rsi], rsi 984 .savereg rsi, KTRAP_FRAME_Rsi 985 mov [rsp + KTRAP_FRAME_Rdi], rdi 986 .savereg rdi, KTRAP_FRAME_Rdi 987 mov rbp, rsp 988 .setframe rbp, 0 989 .endprolog 990 991 /* Get current thread */ 992 mov r11, gs:[PcCurrentThread] 993 994 /* Save PreviousMode in the trap frame */ 995 mov dil, byte ptr [r11 + KTHREAD_PreviousMode] 996 mov byte ptr [rbp + KTRAP_FRAME_PreviousMode], dil 997 998 /* Save the old trap frame in TrapFrame.Rdx */ 999 mov rdi, [r11 + KTHREAD_TrapFrame] 1000 mov [rbp + KTRAP_FRAME_Rdx], rdi 1001 1002 /* Set the new trap frame and previous mode */ 1003 mov [r11 + ThTrapFrame], rbp 1004 mov byte ptr [r11 + KTHREAD_PreviousMode], 0 1005 1006 /* allocate space for parameters */ 1007 sub rsp, r10 1008 and rsp, HEX(0fffffffffffffff0) 1009 1010 /* Save rcx */ 1011 mov [rbp + KTRAP_FRAME_Rcx], rcx 1012 1013 /* copy parameters to the new location */ 1014 lea rsi, [rbp + KTRAP_FRAME_LENGTH + 16] 1015 lea rdi, [rsp] 1016 mov rcx, r10 1017 shr rcx, 3 1018 rep movsq 1019 1020 /* Restore rcx */ 1021 mov rcx, [rbp + KTRAP_FRAME_Rcx] 1022 1023 /* Call the service function */ 1024 call rax 1025 1026 /* Restore the old trap frame */ 1027 mov r11, gs:[PcCurrentThread] 1028 mov rsi, [rbp + KTRAP_FRAME_Rdx] 1029 mov [r11 + KTHREAD_TrapFrame], rsi 1030 1031 /* Restore PreviousMode from the trap frame */ 1032 mov dil, byte ptr [rbp + KTRAP_FRAME_PreviousMode] 1033 mov byte ptr [r11 + KTHREAD_PreviousMode], dil 1034 1035 /* Restore rdi and rsi */ 1036 mov rsi, [rbp + KTRAP_FRAME_Rsi] 1037 mov rdi, [rbp + KTRAP_FRAME_Rdi] 1038 1039 /* Cleanup the stack and return */ 1040 lea rsp, [rbp + KTRAP_FRAME_LENGTH] 1041 pop rbp 1042 ret 1043 1044ENDFUNC 1045 1046PUBLIC KiConvertToGuiThread 1047FUNC KiConvertToGuiThread 1048 1049 sub rsp, 40 1050 .allocstack 40 1051 .endprolog 1052 1053 // NewStack = (ULONG_PTR)MmCreateKernelStack(TRUE, 0); 1054 mov cl, 1 1055 xor rdx, rdx 1056 call MmCreateKernelStack 1057 1058 /* Check for failure */ 1059 test rax, rax 1060 jz KiConvertToGuiThreadFailed 1061 1062 /* OldStack = KeSwitchKernelStack((PVOID)NewStack, (PVOID)(NewStack - KERNEL_STACK_SIZE)); */ 1063 mov rcx, rax 1064 mov rdx, rax 1065 sub rdx, KERNEL_STACK_SIZE 1066 call KeSwitchKernelStack 1067 1068 // MmDeleteKernelStack(OldStack, FALSE); 1069 mov rcx, rax 1070 xor rdx, rdx 1071 call MmDeleteKernelStack 1072 1073 /* Call the worker function */ 1074 call PsConvertToGuiThread 1075 1076 /* Check for failure */ 1077 test rax, rax 1078 js KiConvertToGuiThreadFailed 1079 1080 /* Disable interrupts for return */ 1081 cli 1082 1083 // FIXME: should just do the trap frame switch in KiSystemCallHandler64 1084 /* Restore old trap frame */ 1085 mov rcx, gs:[PcCurrentThread] 1086 mov rdx, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_TrapFrame] 1087 mov [rcx + KTHREAD_TrapFrame], rdx 1088 1089 // Restore register parameters 1090 mov rcx, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rip] 1091 mov rdx, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rdx] 1092 mov r8, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R8] 1093 mov r9, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R9] 1094 1095 /* Run KiSystemCallHandler again */ 1096 add rsp, 48 1097 jmp KiSystemCall64Again 1098 1099KiConvertToGuiThreadFailed: 1100 1101 /* Clean up the stack and return failure */ 1102 add rsp, 40 1103 mov eax, HEX(C0000017) // STATUS_NO_MEMORY 1104 ret 1105 1106ENDFUNC 1107 1108 1109EXTERN KiSetTrapContextInternal:PROC 1110 1111/* 1112 * VOID 1113 * KiSetTrapContext( 1114 * _Out_ PKTRAP_FRAME TrapFrame, 1115 * _In_ PCONTEXT Context, 1116 * _In_ KPROCESSOR_MODE RequestorMode); 1117 */ 1118PUBLIC KiSetTrapContext 1119.PROC KiSetTrapContext 1120 1121 /* Generate a KEXCEPTION_FRAME on the stack */ 1122 GENERATE_EXCEPTION_FRAME 1123 1124 call KiSetTrapContextInternal 1125 1126 /* Restore the registers from the KEXCEPTION_FRAME */ 1127 RESTORE_EXCEPTION_STATE 1128 1129 /* Return */ 1130 ret 1131 1132.ENDP 1133 1134 1135/* 1136 * VOID 1137 * KiDeliverApc( 1138 * _In_ KPROCESSOR_MODE DeliveryMode, 1139 * _In_ PKEXCEPTION_FRAME ExceptionFrame, 1140 * _In_ PKTRAP_FRAME TrapFrame); 1141 * 1142 */ 1143EXTERN KiDeliverApc:PROC 1144 1145PUBLIC KiInitiateUserApc 1146.PROC KiInitiateUserApc 1147 1148 /* Generate a KEXCEPTION_FRAME on the stack */ 1149 GENERATE_EXCEPTION_FRAME 1150 1151 /* Raise IRQL to APC_LEVEL */ 1152 mov rax, APC_LEVEL 1153 mov cr8, rax 1154 1155 /* Enable interrupts */ 1156 sti 1157 1158 /* Get the current trap frame */ 1159 mov rax, gs:[PcCurrentThread] 1160 mov r8, [rax + KTHREAD_TrapFrame] 1161 1162 /* Call the C function */ 1163 mov ecx, 1 1164 mov rdx, rsp 1165 call KiDeliverApc 1166 1167 /* Disable interrupts again */ 1168 cli 1169 1170 /* Go back to PASSIVE_LEVEL */ 1171 mov rax, PASSIVE_LEVEL 1172 mov cr8, rax 1173 1174 /* Restore the registers from the KEXCEPTION_FRAME */ 1175 RESTORE_EXCEPTION_STATE 1176 1177 /* Return */ 1178 ret 1179 1180.ENDP 1181 1182 1183PUBLIC KiInitializeSegments 1184KiInitializeSegments: 1185 mov ax, KGDT64_R3_DATA or RPL_MASK 1186 mov gs, ax 1187 swapgs 1188 mov gs, ax 1189 ret 1190 1191/*! 1192 * VOID 1193 * KiSwitchKernelStackHelper( 1194 * LONG_PTR StackOffset, 1195 * PVOID OldStackBase); 1196 */ 1197PUBLIC KiSwitchKernelStackHelper 1198KiSwitchKernelStackHelper: 1199 1200 /* Pop return address from the current stack */ 1201 pop rax 1202 1203 /* Switch to new stack */ 1204 lea rsp, [rsp + rcx] 1205 1206 /* Push return address on the new stack */ 1207 push rax 1208 1209 /* Return on new stack */ 1210 mov rax, rdx 1211 ret 1212 1213EXTERN KiSwitchKernelStack:PROC 1214 1215PUBLIC KeSwitchKernelStack 1216FUNC KeSwitchKernelStack 1217 1218 sub rsp, 40 1219 .allocstack 40 1220 1221 /* Save rcx */ 1222 mov [rsp], rcx 1223 .savereg rcx, 0 1224 .endprolog 1225 1226 /* Call the C handler, which returns the old stack in rax */ 1227 call KiSwitchKernelStack 1228 1229 /* Restore rcx (StackBase) */ 1230 mov rcx, [rsp] 1231 1232 /* Switch to new stack: RSP += (StackBase - OldStackBase) */ 1233 sub rcx, rax 1234 add rsp, rcx 1235 1236 /* Deallocate the home frame */ 1237 add rsp, 40 1238 ret 1239 1240ENDFUNC 1241 1242 1243 1244 1245#ifdef _MSC_VER 1246#undef lgdt 1247#undef lidt 1248 1249//void __lgdt(void *Source); 1250PUBLIC __lgdt 1251__lgdt: 1252 lgdt fword ptr [rcx] 1253 ret 1254 1255//void __sgdt(void *Destination); 1256PUBLIC __sgdt 1257__sgdt: 1258 sgdt fword ptr [rcx] 1259 ret 1260 1261// void __lldt(unsigned short Value) 1262PUBLIC __lldt 1263__lldt: 1264 lldt cx 1265 ret 1266 1267//void __sldt(void *Destination); 1268PUBLIC __sldt 1269__sldt: 1270 sldt word ptr [rcx] 1271 ret 1272 1273//void __ltr(unsigned short Source); 1274PUBLIC __ltr 1275__ltr: 1276 ltr cx 1277 ret 1278 1279//void __str(unsigned short *Destination); 1280PUBLIC __str 1281__str: 1282 str word ptr [rcx] 1283 ret 1284 1285PUBLIC __swapgs 1286__swapgs: 1287 swapgs 1288 ret 1289 1290#endif 1291 1292END 1293