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.asm 14 ; 15 ; Abstract: 16 ; 17 ; Exception handlers used in SM mode 18 ; 19 ;------------------------------------------------------------------------------- 20 21 .686p 22 .model flat,C 23 24 EXTERNDEF SmiPFHandler:PROC 25 EXTERNDEF PageFaultStubFunction:PROC 26 EXTERNDEF gcSmiIdtr:FWORD 27 EXTERNDEF gcSmiGdtr:FWORD 28 EXTERNDEF gTaskGateDescriptor:QWORD 29 EXTERNDEF gcPsd:BYTE 30 EXTERNDEF FeaturePcdGet (PcdCpuSmmProfileEnable):BYTE 31 32 33 .data 34 35 NullSeg DQ 0 ; reserved by architecture 36 CodeSeg32 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 43 ProtModeCodeSeg32 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 50 ProtModeSsSeg32 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 57 DataSeg32 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 64 CodeSeg16 LABEL QWORD 65 DW -1 66 DW 0 67 DB 0 68 DB 9bh 69 DB 8fh 70 DB 0 71 DataSeg16 LABEL QWORD 72 DW -1 73 DW 0 74 DB 0 75 DB 93h 76 DB 8fh 77 DB 0 78 CodeSeg64 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 85 GDT_SIZE = $ - offset NullSeg 86 87 TssSeg 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 94 ExceptionTssSeg 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 102 CODE_SEL = offset CodeSeg32 - offset NullSeg 103 DATA_SEL = offset DataSeg32 - offset NullSeg 104 TSS_SEL = offset TssSeg - offset NullSeg 105 EXCEPTION_TSS_SEL = offset ExceptionTssSeg - offset NullSeg 106 107 IA32_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 ? 146 IA32_TSS ENDS 147 148 ; Create 2 TSS segments just after GDT 149 TssDescriptor 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 188 TSS_DESC_SIZE = $ - offset TssDescriptor 189 190 ExceptionTssDescriptor 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 230 gcPsd 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 0 248 PSD_SIZE = $ - offset gcPsd 249 250 gcSmiGdtr LABEL FWORD 251 DW GDT_SIZE - 1 252 DD offset NullSeg 253 254 gcSmiIdtr LABEL FWORD 255 DW 0 256 DD 0 257 258 gTaskGateDescriptor LABEL QWORD 259 DW 0 ; Reserved 260 DW EXCEPTION_TSS_SEL ; TSS Segment selector 261 DB 0 ; Reserved 262 DB 85h ; Task Gate, present, DPL = 0 263 DW 0 ; Reserved 264 265 266 .code 267 ;------------------------------------------------------------------------------ 268 ; PageFaultIdtHandlerSmmProfile is the entry point page fault only 269 ; 270 ; 271 ; Stack: 272 ; +---------------------+ 273 ; + EFlags + 274 ; +---------------------+ 275 ; + CS + 276 ; +---------------------+ 277 ; + EIP + 278 ; +---------------------+ 279 ; + Error Code + 280 ; +---------------------+ 281 ; + Vector Number + 282 ; +---------------------+ 283 ; + EBP + 284 ; +---------------------+ <-- EBP 285 ; 286 ; 287 ;------------------------------------------------------------------------------ 288 PageFaultIdtHandlerSmmProfile PROC 289 push 0eh ; Page Fault 290 291 push ebp 292 mov ebp, esp 293 294 295 ; 296 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 297 ; is 16-byte aligned 298 ; 299 and esp, 0fffffff0h 300 sub esp, 12 301 302 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 303 push eax 304 push ecx 305 push edx 306 push ebx 307 lea ecx, [ebp + 6 * 4] 308 push ecx ; ESP 309 push dword ptr [ebp] ; EBP 310 push esi 311 push edi 312 313 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; 314 mov eax, ss 315 push eax 316 movzx eax, word ptr [ebp + 4 * 4] 317 push eax 318 mov eax, ds 319 push eax 320 mov eax, es 321 push eax 322 mov eax, fs 323 push eax 324 mov eax, gs 325 push eax 326 327 ;; UINT32 Eip; 328 mov eax, [ebp + 3 * 4] 329 push eax 330 331 ;; UINT32 Gdtr[2], Idtr[2]; 332 sub esp, 8 333 sidt [esp] 334 mov eax, [esp + 2] 335 xchg eax, [esp] 336 and eax, 0FFFFh 337 mov [esp+4], eax 338 339 sub esp, 8 340 sgdt [esp] 341 mov eax, [esp + 2] 342 xchg eax, [esp] 343 and eax, 0FFFFh 344 mov [esp+4], eax 345 346 ;; UINT32 Ldtr, Tr; 347 xor eax, eax 348 str ax 349 push eax 350 sldt ax 351 push eax 352 353 ;; UINT32 EFlags; 354 mov eax, [ebp + 5 * 4] 355 push eax 356 357 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; 358 mov eax, cr4 359 or eax, 208h 360 mov cr4, eax 361 push eax 362 mov eax, cr3 363 push eax 364 mov eax, cr2 365 push eax 366 xor eax, eax 367 push eax 368 mov eax, cr0 369 push eax 370 371 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 372 mov eax, dr7 373 push eax 374 mov eax, dr6 375 push eax 376 mov eax, dr3 377 push eax 378 mov eax, dr2 379 push eax 380 mov eax, dr1 381 push eax 382 mov eax, dr0 383 push eax 384 385 ;; FX_SAVE_STATE_IA32 FxSaveState; 386 sub esp, 512 387 mov edi, esp 388 db 0fh, 0aeh, 07h ;fxsave [edi] 389 390 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear 391 cld 392 393 ;; UINT32 ExceptionData; 394 push dword ptr [ebp + 2 * 4] 395 396 ;; call into exception handler 397 398 ;; Prepare parameter and call 399 mov edx, esp 400 push edx 401 mov edx, dword ptr [ebp + 1 * 4] 402 push edx 403 404 ; 405 ; Call External Exception Handler 406 ; 407 mov eax, SmiPFHandler 408 call eax 409 add esp, 8 410 411 ;; UINT32 ExceptionData; 412 add esp, 4 413 414 ;; FX_SAVE_STATE_IA32 FxSaveState; 415 mov esi, esp 416 db 0fh, 0aeh, 0eh ; fxrstor [esi] 417 add esp, 512 418 419 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 420 ;; Skip restoration of DRx registers to support debuggers 421 ;; that set breakpoint in interrupt/exception context 422 add esp, 4 * 6 423 424 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; 425 pop eax 426 mov cr0, eax 427 add esp, 4 ; not for Cr1 428 pop eax 429 mov cr2, eax 430 pop eax 431 mov cr3, eax 432 pop eax 433 mov cr4, eax 434 435 ;; UINT32 EFlags; 436 pop dword ptr [ebp + 5 * 4] 437 438 ;; UINT32 Ldtr, Tr; 439 ;; UINT32 Gdtr[2], Idtr[2]; 440 ;; Best not let anyone mess with these particular registers... 441 add esp, 24 442 443 ;; UINT32 Eip; 444 pop dword ptr [ebp + 3 * 4] 445 446 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; 447 ;; NOTE - modified segment registers could hang the debugger... We 448 ;; could attempt to insulate ourselves against this possibility, 449 ;; but that poses risks as well. 450 ;; 451 pop gs 452 pop fs 453 pop es 454 pop ds 455 pop dword ptr [ebp + 4 * 4] 456 pop ss 457 458 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 459 pop edi 460 pop esi 461 add esp, 4 ; not for ebp 462 add esp, 4 ; not for esp 463 pop ebx 464 pop edx 465 pop ecx 466 pop eax 467 468 mov esp, ebp 469 pop ebp 470 471 ; Enable TF bit after page fault handler runs 472 bts dword ptr [esp + 16], 8 ; EFLAGS 473 474 add esp, 8 ; skip INT# & ErrCode 475 Return: 476 iretd 477 ; 478 ; Page Fault Exception Handler entry when SMM Stack Guard is enabled 479 ; Executiot starts here after a task switch 480 ; 481 PFHandlerEntry:: 482 ; 483 ; Get this processor's TSS 484 ; 485 sub esp, 8 486 sgdt [esp + 2] 487 mov eax, [esp + 4] ; GDT base 488 add esp, 8 489 mov ecx, [eax + TSS_SEL + 2] 490 shl ecx, 8 491 mov cl, [eax + TSS_SEL + 7] 492 ror ecx, 8 ; ecx = TSS base 493 494 mov ebp, esp 495 496 ; 497 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 498 ; is 16-byte aligned 499 ; 500 and esp, 0fffffff0h 501 sub esp, 12 502 503 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 504 push (IA32_TSS ptr [ecx])._EAX 505 push (IA32_TSS ptr [ecx])._ECX 506 push (IA32_TSS ptr [ecx])._EDX 507 push (IA32_TSS ptr [ecx])._EBX 508 push (IA32_TSS ptr [ecx])._ESP 509 push (IA32_TSS ptr [ecx])._EBP 510 push (IA32_TSS ptr [ecx])._ESI 511 push (IA32_TSS ptr [ecx])._EDI 512 513 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; 514 movzx eax, (IA32_TSS ptr [ecx])._SS 515 push eax 516 movzx eax, (IA32_TSS ptr [ecx])._CS 517 push eax 518 movzx eax, (IA32_TSS ptr [ecx])._DS 519 push eax 520 movzx eax, (IA32_TSS ptr [ecx])._ES 521 push eax 522 movzx eax, (IA32_TSS ptr [ecx])._FS 523 push eax 524 movzx eax, (IA32_TSS ptr [ecx])._GS 525 push eax 526 527 ;; UINT32 Eip; 528 push (IA32_TSS ptr [ecx]).EIP 529 530 ;; UINT32 Gdtr[2], Idtr[2]; 531 sub esp, 8 532 sidt [esp] 533 mov eax, [esp + 2] 534 xchg eax, [esp] 535 and eax, 0FFFFh 536 mov [esp+4], eax 537 538 sub esp, 8 539 sgdt [esp] 540 mov eax, [esp + 2] 541 xchg eax, [esp] 542 and eax, 0FFFFh 543 mov [esp+4], eax 544 545 ;; UINT32 Ldtr, Tr; 546 mov eax, TSS_SEL 547 push eax 548 movzx eax, (IA32_TSS ptr [ecx]).LDT 549 push eax 550 551 ;; UINT32 EFlags; 552 push (IA32_TSS ptr [ecx]).EFLAGS 553 554 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; 555 mov eax, cr4 556 or eax, 208h 557 mov cr4, eax 558 push eax 559 mov eax, cr3 560 push eax 561 mov eax, cr2 562 push eax 563 xor eax, eax 564 push eax 565 mov eax, cr0 566 push eax 567 568 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 569 mov eax, dr7 570 push eax 571 mov eax, dr6 572 push eax 573 mov eax, dr3 574 push eax 575 mov eax, dr2 576 push eax 577 mov eax, dr1 578 push eax 579 mov eax, dr0 580 push eax 581 582 ;; FX_SAVE_STATE_IA32 FxSaveState; 583 ;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM) 584 ;; when executing fxsave/fxrstor instruction 585 clts 586 sub esp, 512 587 mov edi, esp 588 db 0fh, 0aeh, 07h ;fxsave [edi] 589 590 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear 591 cld 592 593 ;; UINT32 ExceptionData; 594 push dword ptr [ebp] 595 596 ;; call into exception handler 597 mov ebx, ecx 598 mov eax, SmiPFHandler 599 600 ;; Prepare parameter and call 601 mov edx, esp 602 push edx 603 mov edx, 14 604 push edx 605 606 ; 607 ; Call External Exception Handler 608 ; 609 call eax 610 add esp, 8 611 612 mov ecx, ebx 613 ;; UINT32 ExceptionData; 614 add esp, 4 615 616 ;; FX_SAVE_STATE_IA32 FxSaveState; 617 mov esi, esp 618 db 0fh, 0aeh, 0eh ; fxrstor [esi] 619 add esp, 512 620 621 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 622 ;; Skip restoration of DRx registers to support debuggers 623 ;; that set breakpoints in interrupt/exception context 624 add esp, 4 * 6 625 626 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; 627 pop eax 628 mov cr0, eax 629 add esp, 4 ; not for Cr1 630 pop eax 631 mov cr2, eax 632 pop eax 633 mov (IA32_TSS ptr [ecx])._CR3, eax 634 pop eax 635 mov cr4, eax 636 637 ;; UINT32 EFlags; 638 pop (IA32_TSS ptr [ecx]).EFLAGS 639 640 ;; UINT32 Ldtr, Tr; 641 ;; UINT32 Gdtr[2], Idtr[2]; 642 ;; Best not let anyone mess with these particular registers... 643 add esp, 24 644 645 ;; UINT32 Eip; 646 pop (IA32_TSS ptr [ecx]).EIP 647 648 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; 649 ;; NOTE - modified segment registers could hang the debugger... We 650 ;; could attempt to insulate ourselves against this possibility, 651 ;; but that poses risks as well. 652 ;; 653 pop eax 654 mov (IA32_TSS ptr [ecx])._GS, ax 655 pop eax 656 mov (IA32_TSS ptr [ecx])._FS, ax 657 pop eax 658 mov (IA32_TSS ptr [ecx])._ES, ax 659 pop eax 660 mov (IA32_TSS ptr [ecx])._DS, ax 661 pop eax 662 mov (IA32_TSS ptr [ecx])._CS, ax 663 pop eax 664 mov (IA32_TSS ptr [ecx])._SS, ax 665 666 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 667 pop (IA32_TSS ptr [ecx])._EDI 668 pop (IA32_TSS ptr [ecx])._ESI 669 add esp, 4 ; not for ebp 670 add esp, 4 ; not for esp 671 pop (IA32_TSS ptr [ecx])._EBX 672 pop (IA32_TSS ptr [ecx])._EDX 673 pop (IA32_TSS ptr [ecx])._ECX 674 pop (IA32_TSS ptr [ecx])._EAX 675 676 mov esp, ebp 677 678 ; Set single step DB# if SMM profile is enabled and page fault exception happens 679 cmp FeaturePcdGet (PcdCpuSmmProfileEnable), 0 680 jz @Done2 681 682 ; Create return context for iretd in stub function 683 mov eax, (IA32_TSS ptr [ecx])._ESP ; Get old stack pointer 684 mov ebx, (IA32_TSS ptr [ecx]).EIP 685 mov [eax - 0ch], ebx ; create EIP in old stack 686 movzx ebx, (IA32_TSS ptr [ecx])._CS 687 mov [eax - 08h], ebx ; create CS in old stack 688 mov ebx, (IA32_TSS ptr [ecx]).EFLAGS 689 bts ebx, 8 690 mov [eax - 04h], ebx ; create eflags in old stack 691 mov eax, (IA32_TSS ptr [ecx])._ESP ; Get old stack pointer 692 sub eax, 0ch ; minus 12 byte 693 mov (IA32_TSS ptr [ecx])._ESP, eax ; Set new stack pointer 694 ; Replace the EIP of interrupted task with stub function 695 mov eax, PageFaultStubFunction 696 mov (IA32_TSS ptr [ecx]).EIP, eax 697 ; Jump to the iretd so next page fault handler as a task will start again after iretd. 698 @Done2: 699 add esp, 4 ; skip ErrCode 700 701 jmp Return 702 PageFaultIdtHandlerSmmProfile ENDP 703 704 PageFaultStubFunction PROC 705 ; 706 ; we need clean TS bit in CR0 to execute 707 ; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions. 708 ; 709 clts 710 iretd 711 PageFaultStubFunction ENDP 712 713 END 714