1;------------------------------------------------------------------------------ ; 2; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR> 3; This program and the accompanying materials 4; are licensed and made available under the terms and conditions of the BSD License 5; which accompanies this distribution. The full text of the license may be found at 6; http://opensource.org/licenses/bsd-license.php. 7; 8; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 9; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 10; 11; Module Name: 12; 13; SmiException.asm 14; 15; Abstract: 16; 17; Exception handlers used in SM mode 18; 19;------------------------------------------------------------------------------- 20 21 .686p 22 .model flat,C 23 24EXTERNDEF SmiPFHandler:PROC 25EXTERNDEF PageFaultStubFunction:PROC 26EXTERNDEF gSmiMtrrs:QWORD 27EXTERNDEF gcSmiIdtr:FWORD 28EXTERNDEF gcSmiGdtr:FWORD 29EXTERNDEF gcPsd:BYTE 30EXTERNDEF FeaturePcdGet (PcdCpuSmmProfileEnable):BYTE 31 32 33 .data 34 35NullSeg DQ 0 ; reserved by architecture 36CodeSeg32 LABEL QWORD 37 DW -1 ; LimitLow 38 DW 0 ; BaseLow 39 DB 0 ; BaseMid 40 DB 9bh 41 DB 0cfh ; LimitHigh 42 DB 0 ; BaseHigh 43ProtModeCodeSeg32 LABEL QWORD 44 DW -1 ; LimitLow 45 DW 0 ; BaseLow 46 DB 0 ; BaseMid 47 DB 9bh 48 DB 0cfh ; LimitHigh 49 DB 0 ; BaseHigh 50ProtModeSsSeg32 LABEL QWORD 51 DW -1 ; LimitLow 52 DW 0 ; BaseLow 53 DB 0 ; BaseMid 54 DB 93h 55 DB 0cfh ; LimitHigh 56 DB 0 ; BaseHigh 57DataSeg32 LABEL QWORD 58 DW -1 ; LimitLow 59 DW 0 ; BaseLow 60 DB 0 ; BaseMid 61 DB 93h 62 DB 0cfh ; LimitHigh 63 DB 0 ; BaseHigh 64CodeSeg16 LABEL QWORD 65 DW -1 66 DW 0 67 DB 0 68 DB 9bh 69 DB 8fh 70 DB 0 71DataSeg16 LABEL QWORD 72 DW -1 73 DW 0 74 DB 0 75 DB 93h 76 DB 8fh 77 DB 0 78CodeSeg64 LABEL QWORD 79 DW -1 ; LimitLow 80 DW 0 ; BaseLow 81 DB 0 ; BaseMid 82 DB 9bh 83 DB 0afh ; LimitHigh 84 DB 0 ; BaseHigh 85GDT_SIZE = $ - offset NullSeg 86 87TssSeg LABEL QWORD 88 DW TSS_DESC_SIZE - 1 ; LimitLow 89 DW 0 ; BaseLow 90 DB 0 ; BaseMid 91 DB 89h 92 DB 00h ; LimitHigh 93 DB 0 ; BaseHigh 94ExceptionTssSeg LABEL QWORD 95 DW TSS_DESC_SIZE - 1 ; LimitLow 96 DW 0 ; BaseLow 97 DB 0 ; BaseMid 98 DB 89h 99 DB 00h ; LimitHigh 100 DB 0 ; BaseHigh 101 102CODE_SEL = offset CodeSeg32 - offset NullSeg 103DATA_SEL = offset DataSeg32 - offset NullSeg 104TSS_SEL = offset TssSeg - offset NullSeg 105EXCEPTION_TSS_SEL = offset ExceptionTssSeg - offset NullSeg 106 107IA32_TSS STRUC 108 DW ? 109 DW ? 110 ESP0 DD ? 111 SS0 DW ? 112 DW ? 113 ESP1 DD ? 114 SS1 DW ? 115 DW ? 116 ESP2 DD ? 117 SS2 DW ? 118 DW ? 119 _CR3 DD ? 120 EIP DD ? 121 EFLAGS DD ? 122 _EAX DD ? 123 _ECX DD ? 124 _EDX DD ? 125 _EBX DD ? 126 _ESP DD ? 127 _EBP DD ? 128 _ESI DD ? 129 _EDI DD ? 130 _ES DW ? 131 DW ? 132 _CS DW ? 133 DW ? 134 _SS DW ? 135 DW ? 136 _DS DW ? 137 DW ? 138 _FS DW ? 139 DW ? 140 _GS DW ? 141 DW ? 142 LDT DW ? 143 DW ? 144 DW ? 145 DW ? 146IA32_TSS ENDS 147 148; Create 2 TSS segments just after GDT 149TssDescriptor LABEL BYTE 150 DW 0 ; PreviousTaskLink 151 DW 0 ; Reserved 152 DD 0 ; ESP0 153 DW 0 ; SS0 154 DW 0 ; Reserved 155 DD 0 ; ESP1 156 DW 0 ; SS1 157 DW 0 ; Reserved 158 DD 0 ; ESP2 159 DW 0 ; SS2 160 DW 0 ; Reserved 161 DD 0 ; CR3 162 DD 0 ; EIP 163 DD 0 ; EFLAGS 164 DD 0 ; EAX 165 DD 0 ; ECX 166 DD 0 ; EDX 167 DD 0 ; EBX 168 DD 0 ; ESP 169 DD 0 ; EBP 170 DD 0 ; ESI 171 DD 0 ; EDI 172 DW 0 ; ES 173 DW 0 ; Reserved 174 DW 0 ; CS 175 DW 0 ; Reserved 176 DW 0 ; SS 177 DW 0 ; Reserved 178 DW 0 ; DS 179 DW 0 ; Reserved 180 DW 0 ; FS 181 DW 0 ; Reserved 182 DW 0 ; GS 183 DW 0 ; Reserved 184 DW 0 ; LDT Selector 185 DW 0 ; Reserved 186 DW 0 ; T 187 DW 0 ; I/O Map Base 188TSS_DESC_SIZE = $ - offset TssDescriptor 189 190ExceptionTssDescriptor LABEL BYTE 191 DW 0 ; PreviousTaskLink 192 DW 0 ; Reserved 193 DD 0 ; ESP0 194 DW 0 ; SS0 195 DW 0 ; Reserved 196 DD 0 ; ESP1 197 DW 0 ; SS1 198 DW 0 ; Reserved 199 DD 0 ; ESP2 200 DW 0 ; SS2 201 DW 0 ; Reserved 202 DD 0 ; CR3 203 DD offset PFHandlerEntry ; EIP 204 DD 00000002 ; EFLAGS 205 DD 0 ; EAX 206 DD 0 ; ECX 207 DD 0 ; EDX 208 DD 0 ; EBX 209 DD 0 ; ESP 210 DD 0 ; EBP 211 DD 0 ; ESI 212 DD 0 ; EDI 213 DW DATA_SEL ; ES 214 DW 0 ; Reserved 215 DW CODE_SEL ; CS 216 DW 0 ; Reserved 217 DW DATA_SEL ; SS 218 DW 0 ; Reserved 219 DW DATA_SEL ; DS 220 DW 0 ; Reserved 221 DW DATA_SEL ; FS 222 DW 0 ; Reserved 223 DW DATA_SEL ; GS 224 DW 0 ; Reserved 225 DW 0 ; LDT Selector 226 DW 0 ; Reserved 227 DW 0 ; T 228 DW 0 ; I/O Map Base 229 230gcPsd LABEL BYTE 231 DB 'PSDSIG ' 232 DW PSD_SIZE 233 DW 2 234 DW 1 SHL 2 235 DW CODE_SEL 236 DW DATA_SEL 237 DW DATA_SEL 238 DW DATA_SEL 239 DW 0 240 DQ 0 241 DQ 0 242 DQ 0 243 DQ offset NullSeg 244 DD GDT_SIZE 245 DD 0 246 DB 24 dup (0) 247 DQ offset gSmiMtrrs 248PSD_SIZE = $ - offset gcPsd 249 250gcSmiGdtr LABEL FWORD 251 DW GDT_SIZE - 1 252 DD offset NullSeg 253 254gcSmiIdtr LABEL FWORD 255 DW IDT_SIZE - 1 256 DD offset _SmiIDT 257 258_SmiIDT LABEL QWORD 259REPEAT 32 260 DW 0 ; Offset 0:15 261 DW CODE_SEL ; Segment selector 262 DB 0 ; Unused 263 DB 8eh ; Interrupt Gate, Present 264 DW 0 ; Offset 16:31 265 ENDM 266IDT_SIZE = $ - offset _SmiIDT 267 268TaskGateDescriptor LABEL DWORD 269 DW 0 ; Reserved 270 DW EXCEPTION_TSS_SEL ; TSS Segment selector 271 DB 0 ; Reserved 272 DB 85h ; Task Gate, present, DPL = 0 273 DW 0 ; Reserved 274 275 276 .code 277;------------------------------------------------------------------------------ 278; PageFaultIdtHandlerSmmProfile is the entry point page fault only 279; 280; 281; Stack: 282; +---------------------+ 283; + EFlags + 284; +---------------------+ 285; + CS + 286; +---------------------+ 287; + EIP + 288; +---------------------+ 289; + Error Code + 290; +---------------------+ 291; + Vector Number + 292; +---------------------+ 293; + EBP + 294; +---------------------+ <-- EBP 295; 296; 297;------------------------------------------------------------------------------ 298PageFaultIdtHandlerSmmProfile PROC 299 push 0eh ; Page Fault 300 301 push ebp 302 mov ebp, esp 303 304 305 ; 306 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 307 ; is 16-byte aligned 308 ; 309 and esp, 0fffffff0h 310 sub esp, 12 311 312;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 313 push eax 314 push ecx 315 push edx 316 push ebx 317 lea ecx, [ebp + 6 * 4] 318 push ecx ; ESP 319 push dword ptr [ebp] ; EBP 320 push esi 321 push edi 322 323;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; 324 mov eax, ss 325 push eax 326 movzx eax, word ptr [ebp + 4 * 4] 327 push eax 328 mov eax, ds 329 push eax 330 mov eax, es 331 push eax 332 mov eax, fs 333 push eax 334 mov eax, gs 335 push eax 336 337;; UINT32 Eip; 338 mov eax, [ebp + 3 * 4] 339 push eax 340 341;; UINT32 Gdtr[2], Idtr[2]; 342 sub esp, 8 343 sidt [esp] 344 mov eax, [esp + 2] 345 xchg eax, [esp] 346 and eax, 0FFFFh 347 mov [esp+4], eax 348 349 sub esp, 8 350 sgdt [esp] 351 mov eax, [esp + 2] 352 xchg eax, [esp] 353 and eax, 0FFFFh 354 mov [esp+4], eax 355 356;; UINT32 Ldtr, Tr; 357 xor eax, eax 358 str ax 359 push eax 360 sldt ax 361 push eax 362 363;; UINT32 EFlags; 364 mov eax, [ebp + 5 * 4] 365 push eax 366 367;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; 368 mov eax, cr4 369 or eax, 208h 370 mov cr4, eax 371 push eax 372 mov eax, cr3 373 push eax 374 mov eax, cr2 375 push eax 376 xor eax, eax 377 push eax 378 mov eax, cr0 379 push eax 380 381;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 382 mov eax, dr7 383 push eax 384 mov eax, dr6 385 push eax 386 mov eax, dr3 387 push eax 388 mov eax, dr2 389 push eax 390 mov eax, dr1 391 push eax 392 mov eax, dr0 393 push eax 394 395;; FX_SAVE_STATE_IA32 FxSaveState; 396 sub esp, 512 397 mov edi, esp 398 db 0fh, 0aeh, 07h ;fxsave [edi] 399 400; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear 401 cld 402 403;; UINT32 ExceptionData; 404 push dword ptr [ebp + 2 * 4] 405 406;; call into exception handler 407 408;; Prepare parameter and call 409 mov edx, esp 410 push edx 411 mov edx, dword ptr [ebp + 1 * 4] 412 push edx 413 414 ; 415 ; Call External Exception Handler 416 ; 417 mov eax, SmiPFHandler 418 call eax 419 add esp, 8 420 421;; UINT32 ExceptionData; 422 add esp, 4 423 424;; FX_SAVE_STATE_IA32 FxSaveState; 425 mov esi, esp 426 db 0fh, 0aeh, 0eh ; fxrstor [esi] 427 add esp, 512 428 429;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 430;; Skip restoration of DRx registers to support debuggers 431;; that set breakpoint in interrupt/exception context 432 add esp, 4 * 6 433 434;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; 435 pop eax 436 mov cr0, eax 437 add esp, 4 ; not for Cr1 438 pop eax 439 mov cr2, eax 440 pop eax 441 mov cr3, eax 442 pop eax 443 mov cr4, eax 444 445;; UINT32 EFlags; 446 pop dword ptr [ebp + 5 * 4] 447 448;; UINT32 Ldtr, Tr; 449;; UINT32 Gdtr[2], Idtr[2]; 450;; Best not let anyone mess with these particular registers... 451 add esp, 24 452 453;; UINT32 Eip; 454 pop dword ptr [ebp + 3 * 4] 455 456;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; 457;; NOTE - modified segment registers could hang the debugger... We 458;; could attempt to insulate ourselves against this possibility, 459;; but that poses risks as well. 460;; 461 pop gs 462 pop fs 463 pop es 464 pop ds 465 pop dword ptr [ebp + 4 * 4] 466 pop ss 467 468;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 469 pop edi 470 pop esi 471 add esp, 4 ; not for ebp 472 add esp, 4 ; not for esp 473 pop ebx 474 pop edx 475 pop ecx 476 pop eax 477 478 mov esp, ebp 479 pop ebp 480 481; Enable TF bit after page fault handler runs 482 bts dword ptr [esp + 16], 8 ; EFLAGS 483 484 add esp, 8 ; skip INT# & ErrCode 485Return: 486 iretd 487; 488; Page Fault Exception Handler entry when SMM Stack Guard is enabled 489; Executiot starts here after a task switch 490; 491PFHandlerEntry:: 492; 493; Get this processor's TSS 494; 495 sub esp, 8 496 sgdt [esp + 2] 497 mov eax, [esp + 4] ; GDT base 498 add esp, 8 499 mov ecx, [eax + TSS_SEL + 2] 500 shl ecx, 8 501 mov cl, [eax + TSS_SEL + 7] 502 ror ecx, 8 ; ecx = TSS base 503 504 mov ebp, esp 505 506 ; 507 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 508 ; is 16-byte aligned 509 ; 510 and esp, 0fffffff0h 511 sub esp, 12 512 513;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 514 push (IA32_TSS ptr [ecx])._EAX 515 push (IA32_TSS ptr [ecx])._ECX 516 push (IA32_TSS ptr [ecx])._EDX 517 push (IA32_TSS ptr [ecx])._EBX 518 push (IA32_TSS ptr [ecx])._ESP 519 push (IA32_TSS ptr [ecx])._EBP 520 push (IA32_TSS ptr [ecx])._ESI 521 push (IA32_TSS ptr [ecx])._EDI 522 523;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; 524 movzx eax, (IA32_TSS ptr [ecx])._SS 525 push eax 526 movzx eax, (IA32_TSS ptr [ecx])._CS 527 push eax 528 movzx eax, (IA32_TSS ptr [ecx])._DS 529 push eax 530 movzx eax, (IA32_TSS ptr [ecx])._ES 531 push eax 532 movzx eax, (IA32_TSS ptr [ecx])._FS 533 push eax 534 movzx eax, (IA32_TSS ptr [ecx])._GS 535 push eax 536 537;; UINT32 Eip; 538 push (IA32_TSS ptr [ecx]).EIP 539 540;; UINT32 Gdtr[2], Idtr[2]; 541 sub esp, 8 542 sidt [esp] 543 mov eax, [esp + 2] 544 xchg eax, [esp] 545 and eax, 0FFFFh 546 mov [esp+4], eax 547 548 sub esp, 8 549 sgdt [esp] 550 mov eax, [esp + 2] 551 xchg eax, [esp] 552 and eax, 0FFFFh 553 mov [esp+4], eax 554 555;; UINT32 Ldtr, Tr; 556 mov eax, TSS_SEL 557 push eax 558 movzx eax, (IA32_TSS ptr [ecx]).LDT 559 push eax 560 561;; UINT32 EFlags; 562 push (IA32_TSS ptr [ecx]).EFLAGS 563 564;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; 565 mov eax, cr4 566 or eax, 208h 567 mov cr4, eax 568 push eax 569 mov eax, cr3 570 push eax 571 mov eax, cr2 572 push eax 573 xor eax, eax 574 push eax 575 mov eax, cr0 576 push eax 577 578;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 579 mov eax, dr7 580 push eax 581 mov eax, dr6 582 push eax 583 mov eax, dr3 584 push eax 585 mov eax, dr2 586 push eax 587 mov eax, dr1 588 push eax 589 mov eax, dr0 590 push eax 591 592;; FX_SAVE_STATE_IA32 FxSaveState; 593;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM) 594;; when executing fxsave/fxrstor instruction 595 clts 596 sub esp, 512 597 mov edi, esp 598 db 0fh, 0aeh, 07h ;fxsave [edi] 599 600; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear 601 cld 602 603;; UINT32 ExceptionData; 604 push dword ptr [ebp] 605 606;; call into exception handler 607 mov ebx, ecx 608 mov eax, SmiPFHandler 609 610;; Prepare parameter and call 611 mov edx, esp 612 push edx 613 mov edx, 14 614 push edx 615 616 ; 617 ; Call External Exception Handler 618 ; 619 call eax 620 add esp, 8 621 622 mov ecx, ebx 623;; UINT32 ExceptionData; 624 add esp, 4 625 626;; FX_SAVE_STATE_IA32 FxSaveState; 627 mov esi, esp 628 db 0fh, 0aeh, 0eh ; fxrstor [esi] 629 add esp, 512 630 631;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 632;; Skip restoration of DRx registers to support debuggers 633;; that set breakpoints in interrupt/exception context 634 add esp, 4 * 6 635 636;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; 637 pop eax 638 mov cr0, eax 639 add esp, 4 ; not for Cr1 640 pop eax 641 mov cr2, eax 642 pop eax 643 mov (IA32_TSS ptr [ecx])._CR3, eax 644 pop eax 645 mov cr4, eax 646 647;; UINT32 EFlags; 648 pop (IA32_TSS ptr [ecx]).EFLAGS 649 650;; UINT32 Ldtr, Tr; 651;; UINT32 Gdtr[2], Idtr[2]; 652;; Best not let anyone mess with these particular registers... 653 add esp, 24 654 655;; UINT32 Eip; 656 pop (IA32_TSS ptr [ecx]).EIP 657 658;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; 659;; NOTE - modified segment registers could hang the debugger... We 660;; could attempt to insulate ourselves against this possibility, 661;; but that poses risks as well. 662;; 663 pop eax 664 mov (IA32_TSS ptr [ecx])._GS, ax 665 pop eax 666 mov (IA32_TSS ptr [ecx])._FS, ax 667 pop eax 668 mov (IA32_TSS ptr [ecx])._ES, ax 669 pop eax 670 mov (IA32_TSS ptr [ecx])._DS, ax 671 pop eax 672 mov (IA32_TSS ptr [ecx])._CS, ax 673 pop eax 674 mov (IA32_TSS ptr [ecx])._SS, ax 675 676;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 677 pop (IA32_TSS ptr [ecx])._EDI 678 pop (IA32_TSS ptr [ecx])._ESI 679 add esp, 4 ; not for ebp 680 add esp, 4 ; not for esp 681 pop (IA32_TSS ptr [ecx])._EBX 682 pop (IA32_TSS ptr [ecx])._EDX 683 pop (IA32_TSS ptr [ecx])._ECX 684 pop (IA32_TSS ptr [ecx])._EAX 685 686 mov esp, ebp 687 688; Set single step DB# if SMM profile is enabled and page fault exception happens 689 cmp FeaturePcdGet (PcdCpuSmmProfileEnable), 0 690 jz @Done2 691 692; Create return context for iretd in stub function 693 mov eax, (IA32_TSS ptr [ecx])._ESP ; Get old stack pointer 694 mov ebx, (IA32_TSS ptr [ecx]).EIP 695 mov [eax - 0ch], ebx ; create EIP in old stack 696 movzx ebx, (IA32_TSS ptr [ecx])._CS 697 mov [eax - 08h], ebx ; create CS in old stack 698 mov ebx, (IA32_TSS ptr [ecx]).EFLAGS 699 bts ebx, 8 700 mov [eax - 04h], ebx ; create eflags in old stack 701 mov eax, (IA32_TSS ptr [ecx])._ESP ; Get old stack pointer 702 sub eax, 0ch ; minus 12 byte 703 mov (IA32_TSS ptr [ecx])._ESP, eax ; Set new stack pointer 704; Replace the EIP of interrupted task with stub function 705 mov eax, PageFaultStubFunction 706 mov (IA32_TSS ptr [ecx]).EIP, eax 707; Jump to the iretd so next page fault handler as a task will start again after iretd. 708@Done2: 709 add esp, 4 ; skip ErrCode 710 711 jmp Return 712PageFaultIdtHandlerSmmProfile ENDP 713 714PageFaultStubFunction PROC 715; 716; we need clean TS bit in CR0 to execute 717; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions. 718; 719 clts 720 iretd 721PageFaultStubFunction ENDP 722 723InitializeIDTSmmStackGuard PROC USES ebx 724; 725; If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT 726; is a Task Gate Descriptor so that when a Page Fault Exception occurs, 727; the processors can use a known good stack in case stack is ran out. 728; 729 lea ebx, _SmiIDT + 14 * 8 730 lea edx, TaskGateDescriptor 731 mov eax, [edx] 732 mov [ebx], eax 733 mov eax, [edx + 4] 734 mov [ebx + 4], eax 735 ret 736InitializeIDTSmmStackGuard ENDP 737 738 END 739