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