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