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