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