1#------------------------------------------------------------------------------ 2#* 3#* Copyright (c) 2012 - 2015, 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#* ExceptionHandlerAsm.S 13#* 14#* Abstract: 15#* 16#* IA32 CPU Exception Handler 17# 18#------------------------------------------------------------------------------ 19 20 21#.MMX 22#.XMM 23 24ASM_GLOBAL ASM_PFX(CommonExceptionHandler) 25ASM_GLOBAL ASM_PFX(CommonInterruptEntry) 26ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd) 27 28#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions 29#EXTRN ASM_PFX(mDoFarReturnFlag):DWORD # Do far return flag 30 31.text 32 33# 34# exception handler stub table 35# 36Exception0Handle: 37 .byte 0x6a # push #VectorNum 38 .byte 0 39 pushl %eax 40 .byte 0xB8 41 .long ASM_PFX(CommonInterruptEntry) 42 jmp *%eax 43Exception1Handle: 44 .byte 0x6a # push #VectorNum 45 .byte 1 46 pushl %eax 47 .byte 0xB8 48 .long ASM_PFX(CommonInterruptEntry) 49 jmp *%eax 50Exception2Handle: 51 .byte 0x6a # push #VectorNum 52 .byte 2 53 pushl %eax 54 .byte 0xB8 55 .long ASM_PFX(CommonInterruptEntry) 56 jmp *%eax 57Exception3Handle: 58 .byte 0x6a # push #VectorNum 59 .byte 3 60 pushl %eax 61 .byte 0xB8 62 .long ASM_PFX(CommonInterruptEntry) 63 jmp *%eax 64Exception4Handle: 65 .byte 0x6a # push #VectorNum 66 .byte 4 67 pushl %eax 68 .byte 0xB8 69 .long ASM_PFX(CommonInterruptEntry) 70 jmp *%eax 71Exception5Handle: 72 .byte 0x6a # push #VectorNum 73 .byte 5 74 pushl %eax 75 .byte 0xB8 76 .long ASM_PFX(CommonInterruptEntry) 77 jmp *%eax 78Exception6Handle: 79 .byte 0x6a # push #VectorNum 80 .byte 6 81 pushl %eax 82 .byte 0xB8 83 .long ASM_PFX(CommonInterruptEntry) 84 jmp *%eax 85Exception7Handle: 86 .byte 0x6a # push #VectorNum 87 .byte 7 88 pushl %eax 89 .byte 0xB8 90 .long ASM_PFX(CommonInterruptEntry) 91 jmp *%eax 92Exception8Handle: 93 .byte 0x6a # push #VectorNum 94 .byte 8 95 pushl %eax 96 .byte 0xB8 97 .long ASM_PFX(CommonInterruptEntry) 98 jmp *%eax 99Exception9Handle: 100 .byte 0x6a # push #VectorNum 101 .byte 9 102 pushl %eax 103 .byte 0xB8 104 .long ASM_PFX(CommonInterruptEntry) 105 jmp *%eax 106Exception10Handle: 107 .byte 0x6a # push #VectorNum 108 .byte 10 109 pushl %eax 110 .byte 0xB8 111 .long ASM_PFX(CommonInterruptEntry) 112 jmp *%eax 113Exception11Handle: 114 .byte 0x6a # push #VectorNum 115 .byte 11 116 pushl %eax 117 .byte 0xB8 118 .long ASM_PFX(CommonInterruptEntry) 119 jmp *%eax 120Exception12Handle: 121 .byte 0x6a # push #VectorNum 122 .byte 12 123 pushl %eax 124 .byte 0xB8 125 .long ASM_PFX(CommonInterruptEntry) 126 jmp *%eax 127Exception13Handle: 128 .byte 0x6a # push #VectorNum 129 .byte 13 130 pushl %eax 131 .byte 0xB8 132 .long ASM_PFX(CommonInterruptEntry) 133 jmp *%eax 134Exception14Handle: 135 .byte 0x6a # push #VectorNum 136 .byte 14 137 pushl %eax 138 .byte 0xB8 139 .long ASM_PFX(CommonInterruptEntry) 140 jmp *%eax 141Exception15Handle: 142 .byte 0x6a # push #VectorNum 143 .byte 15 144 pushl %eax 145 .byte 0xB8 146 .long ASM_PFX(CommonInterruptEntry) 147 jmp *%eax 148Exception16Handle: 149 .byte 0x6a # push #VectorNum 150 .byte 16 151 pushl %eax 152 .byte 0xB8 153 .long ASM_PFX(CommonInterruptEntry) 154 jmp *%eax 155Exception17Handle: 156 .byte 0x6a # push #VectorNum 157 .byte 17 158 pushl %eax 159 .byte 0xB8 160 .long ASM_PFX(CommonInterruptEntry) 161 jmp *%eax 162Exception18Handle: 163 .byte 0x6a # push #VectorNum 164 .byte 18 165 pushl %eax 166 .byte 0xB8 167 .long ASM_PFX(CommonInterruptEntry) 168 jmp *%eax 169Exception19Handle: 170 .byte 0x6a # push #VectorNum 171 .byte 19 172 pushl %eax 173 .byte 0xB8 174 .long ASM_PFX(CommonInterruptEntry) 175 jmp *%eax 176Exception20Handle: 177 .byte 0x6a # push #VectorNum 178 .byte 20 179 pushl %eax 180 .byte 0xB8 181 .long ASM_PFX(CommonInterruptEntry) 182 jmp *%eax 183Exception21Handle: 184 .byte 0x6a # push #VectorNum 185 .byte 21 186 pushl %eax 187 .byte 0xB8 188 .long ASM_PFX(CommonInterruptEntry) 189 jmp *%eax 190Exception22Handle: 191 .byte 0x6a # push #VectorNum 192 .byte 22 193 pushl %eax 194 .byte 0xB8 195 .long ASM_PFX(CommonInterruptEntry) 196 jmp *%eax 197Exception23Handle: 198 .byte 0x6a # push #VectorNum 199 .byte 23 200 pushl %eax 201 .byte 0xB8 202 .long ASM_PFX(CommonInterruptEntry) 203 jmp *%eax 204Exception24Handle: 205 .byte 0x6a # push #VectorNum 206 .byte 24 207 pushl %eax 208 .byte 0xB8 209 .long ASM_PFX(CommonInterruptEntry) 210 jmp *%eax 211Exception25Handle: 212 .byte 0x6a # push #VectorNum 213 .byte 25 214 pushl %eax 215 .byte 0xB8 216 .long ASM_PFX(CommonInterruptEntry) 217 jmp *%eax 218Exception26Handle: 219 .byte 0x6a # push #VectorNum 220 .byte 26 221 pushl %eax 222 .byte 0xB8 223 .long ASM_PFX(CommonInterruptEntry) 224 jmp *%eax 225Exception27Handle: 226 .byte 0x6a # push #VectorNum 227 .byte 27 228 pushl %eax 229 .byte 0xB8 230 .long ASM_PFX(CommonInterruptEntry) 231 jmp *%eax 232Exception28Handle: 233 .byte 0x6a # push #VectorNum 234 .byte 28 235 pushl %eax 236 .byte 0xB8 237 .long ASM_PFX(CommonInterruptEntry) 238 jmp *%eax 239Exception29Handle: 240 .byte 0x6a # push #VectorNum 241 .byte 29 242 pushl %eax 243 .byte 0xB8 244 .long ASM_PFX(CommonInterruptEntry) 245 jmp *%eax 246Exception30Handle: 247 .byte 0x6a # push #VectorNum 248 .byte 30 249 pushl %eax 250 .byte 0xB8 251 .long ASM_PFX(CommonInterruptEntry) 252 jmp *%eax 253Exception31Handle: 254 .byte 0x6a # push #VectorNum 255 .byte 31 256 pushl %eax 257 .byte 0xB8 258 .long ASM_PFX(CommonInterruptEntry) 259 jmp *%eax 260 261HookAfterStubBegin: 262 .byte 0x6a # push 263VectorNum: 264 .byte 0 # 0 will be fixed 265 pushl %eax 266 .byte 0xB8 # movl ASM_PFX(HookAfterStubHeaderEnd), %eax 267 .long ASM_PFX(HookAfterStubHeaderEnd) 268 jmp *%eax 269ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd) 270ASM_PFX(HookAfterStubHeaderEnd): 271 popl %eax 272 subl $8, %esp # reserve room for filling exception data later 273 pushl 8(%esp) 274 xchgl (%esp), %ecx # get vector number 275 bt %ecx, ASM_PFX(mErrorCodeFlag) 276 jnc NoErrorData 277 pushl (%esp) # addition push if exception data needed 278NoErrorData: 279 xchg (%esp), %ecx # restore ecx 280 pushl %eax 281 282#---------------------------------------; 283# CommonInterruptEntry ; 284#---------------------------------------; 285# The follow algorithm is used for the common interrupt routine. 286 287ASM_GLOBAL ASM_PFX(CommonInterruptEntry) 288ASM_PFX(CommonInterruptEntry): 289 cli 290 popl %eax 291 # 292 # All interrupt handlers are invoked through interrupt gates, so 293 # IF flag automatically cleared at the entry point 294 # 295 296 # 297 # Get vector number from top of stack 298 # 299 xchgl (%esp), %ecx 300 andl $0x0FF, %ecx # Vector number should be less than 256 301 cmpl $32, %ecx # Intel reserved vector for exceptions? 302 jae NoErrorCode 303 bt %ecx, ASM_PFX(mErrorCodeFlag) 304 jc HasErrorCode 305 306NoErrorCode: 307 308 # 309 # Stack: 310 # +---------------------+ 311 # + EFlags + 312 # +---------------------+ 313 # + CS + 314 # +---------------------+ 315 # + EIP + 316 # +---------------------+ 317 # + ECX + 318 # +---------------------+ <-- ESP 319 # 320 # Registers: 321 # ECX - Vector Number 322 # 323 324 # 325 # Put Vector Number on stack 326 # 327 pushl %ecx 328 329 # 330 # Put 0 (dummy) error code on stack, and restore ECX 331 # 332 xorl %ecx, %ecx # ECX = 0 333 xchgl 4(%esp), %ecx 334 335 jmp ErrorCodeAndVectorOnStack 336 337HasErrorCode: 338 339 # 340 # Stack: 341 # +---------------------+ 342 # + EFlags + 343 # +---------------------+ 344 # + CS + 345 # +---------------------+ 346 # + EIP + 347 # +---------------------+ 348 # + Error Code + 349 # +---------------------+ 350 # + ECX + 351 # +---------------------+ <-- ESP 352 # 353 # Registers: 354 # ECX - Vector Number 355 # 356 357 # 358 # Put Vector Number on stack and restore ECX 359 # 360 xchgl (%esp), %ecx 361 362ErrorCodeAndVectorOnStack: 363 pushl %ebp 364 movl %esp, %ebp 365 366 # 367 # Stack: 368 # +---------------------+ 369 # + EFlags + 370 # +---------------------+ 371 # + CS + 372 # +---------------------+ 373 # + EIP + 374 # +---------------------+ 375 # + Error Code + 376 # +---------------------+ 377 # + Vector Number + 378 # +---------------------+ 379 # + EBP + 380 # +---------------------+ <-- EBP 381 # 382 383 # 384 # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 385 # is 16-byte aligned 386 # 387 andl $0x0fffffff0, %esp 388 subl $12, %esp 389 390 subl $8, %esp 391 pushl $0 # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler 392 pushl $0 # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag 393 394#; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 395 pushl %eax 396 pushl %ecx 397 pushl %edx 398 pushl %ebx 399 leal 24(%ebp), %ecx 400 pushl %ecx # ESP 401 pushl (%ebp) # EBP 402 pushl %esi 403 pushl %edi 404 405#; UINT32 Gs, Fs, Es, Ds, Cs, Ss; 406 movl %ss, %eax 407 pushl %eax 408 movzwl 16(%ebp), %eax 409 pushl %eax 410 movl %ds, %eax 411 pushl %eax 412 movl %es, %eax 413 pushl %eax 414 movl %fs, %eax 415 pushl %eax 416 movl %gs, %eax 417 pushl %eax 418 419#; UINT32 Eip; 420 movl 12(%ebp), %eax 421 pushl %eax 422 423#; UINT32 Gdtr[2], Idtr[2]; 424 subl $8, %esp 425 sidt (%esp) 426 movl 2(%esp), %eax 427 xchgl (%esp), %eax 428 andl $0x0FFFF, %eax 429 movl %eax, 4(%esp) 430 431 subl $8, %esp 432 sgdt (%esp) 433 movl 2(%esp), %eax 434 xchgl (%esp), %eax 435 andl $0x0FFFF, %eax 436 movl %eax, 4(%esp) 437 438#; UINT32 Ldtr, Tr; 439 xorl %eax, %eax 440 str %ax 441 pushl %eax 442 sldt %ax 443 pushl %eax 444 445#; UINT32 EFlags; 446 movl 20(%ebp), %eax 447 pushl %eax 448 449#; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; 450## insure FXSAVE/FXRSTOR is enabled in CR4... 451## ... while we're at it, make sure DE is also enabled... 452 mov $1, %eax 453 pushl %ebx # temporarily save value of ebx on stack 454 cpuid # use CPUID to determine if FXSAVE/FXRESTOR 455 # and DE are supported 456 popl %ebx # retore value of ebx that was overwritten 457 # by CPUID 458 movl %cr4, %eax 459 pushl %eax # push cr4 firstly 460 testl $BIT24, %edx # Test for FXSAVE/FXRESTOR support 461 jz L1 462 orl $BIT9, %eax # Set CR4.OSFXSR 463L1: 464 testl $BIT2, %edx # Test for Debugging Extensions support 465 jz L2 466 orl $BIT3, %eax # Set CR4.DE 467L2: 468 movl %eax, %cr4 469 movl %cr3, %eax 470 pushl %eax 471 movl %cr2, %eax 472 pushl %eax 473 xorl %eax, %eax 474 pushl %eax 475 movl %cr0, %eax 476 pushl %eax 477 478#; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 479 movl %dr7, %eax 480 pushl %eax 481 movl %dr6, %eax 482 pushl %eax 483 movl %dr3, %eax 484 pushl %eax 485 movl %dr2, %eax 486 pushl %eax 487 movl %dr1, %eax 488 pushl %eax 489 movl %dr0, %eax 490 pushl %eax 491 492#; FX_SAVE_STATE_IA32 FxSaveState; 493 subl $512, %esp 494 movl %esp, %edi 495 testl $BIT24, %edx # Test for FXSAVE/FXRESTOR support. 496 # edx still contains result from CPUID above 497 jz L3 498 .byte 0x0f, 0x0ae, 0x07 #fxsave [edi] 499L3: 500 501#; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear 502 cld 503 504#; UINT32 ExceptionData; 505 pushl 8(%ebp) 506 507#; Prepare parameter and call 508 movl %esp, %edx 509 pushl %edx 510 movl 4(%ebp), %edx 511 pushl %edx 512 513 # 514 # Call External Exception Handler 515 # 516 call ASM_PFX(CommonExceptionHandler) 517 addl $8, %esp 518 519 cli 520#; UINT32 ExceptionData; 521 addl $4, %esp 522 523#; FX_SAVE_STATE_IA32 FxSaveState; 524 movl %esp, %esi 525 movl $1, %eax 526 cpuid # use CPUID to determine if FXSAVE/FXRESTOR 527 # are supported 528 testl $BIT24, %edx # Test for FXSAVE/FXRESTOR support 529 jz L4 530 .byte 0x0f, 0x0ae, 0x0e # fxrstor [esi] 531L4: 532 addl $512, %esp 533 534#; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 535#; Skip restoration of DRx registers to support in-circuit emualators 536#; or debuggers set breakpoint in interrupt/exception context 537 addl $24, %esp 538 539#; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; 540 popl %eax 541 movl %eax, %cr0 542 addl $4, %esp # not for Cr1 543 popl %eax 544 movl %eax, %cr2 545 popl %eax 546 movl %eax, %cr3 547 popl %eax 548 movl %eax, %cr4 549 550#; UINT32 EFlags; 551 popl 20(%ebp) 552 553#; UINT32 Ldtr, Tr; 554#; UINT32 Gdtr[2], Idtr[2]; 555#; Best not let anyone mess with these particular registers... 556 addl $24, %esp 557 558#; UINT32 Eip; 559 popl 12(%ebp) 560 561#; UINT32 Gs, Fs, Es, Ds, Cs, Ss; 562#; NOTE - modified segment registers could hang the debugger... We 563#; could attempt to insulate ourselves against this possibility, 564#; but that poses risks as well. 565#; 566 popl %gs 567 popl %fs 568 popl %es 569 popl %ds 570 popl 16(%ebp) 571 popl %ss 572 573#; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 574 popl %edi 575 popl %esi 576 addl $4, %esp # not for ebp 577 addl $4, %esp # not for esp 578 popl %ebx 579 popl %edx 580 popl %ecx 581 popl %eax 582 583 popl -8(%ebp) 584 popl -4(%ebp) 585 movl %ebp, %esp 586 popl %ebp 587 addl $8, %esp 588 cmpl $0, -16(%esp) # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler 589 jz DoReturn 590 cmpl $1, -20(%esp) # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag 591 jz ErrorCode 592 jmp *-16(%esp) 593ErrorCode: 594 subl $4, %esp 595 jmp *-12(%esp) 596 597DoReturn: 598 cmpl $0, ASM_PFX(mDoFarReturnFlag) 599 jz DoIret 600 pushl 8(%esp) # save EFLAGS 601 addl $16, %esp 602 pushl -8(%esp) # save CS in new location 603 pushl -8(%esp) # save EIP in new location 604 pushl -8(%esp) # save EFLAGS in new location 605 popfl # restore EFLAGS 606 lret # far return 607 608DoIret: 609 iretl 610 611 612#---------------------------------------; 613# _AsmGetTemplateAddressMap ; 614#---------------------------------------; 615# 616# Protocol prototype 617# AsmGetTemplateAddressMap ( 618# EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap 619# ); 620# 621# Routine Description: 622# 623# Return address map of interrupt handler template so that C code can generate 624# interrupt table. 625# 626# Arguments: 627# 628# 629# Returns: 630# 631# Nothing 632# 633# 634# Input: [ebp][0] = Original ebp 635# [ebp][4] = Return address 636# 637# Output: Nothing 638# 639# Destroys: Nothing 640#-----------------------------------------------------------------------------; 641#------------------------------------------------------------------------------------- 642# AsmGetAddressMap (&AddressMap); 643#------------------------------------------------------------------------------------- 644ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap) 645ASM_PFX(AsmGetTemplateAddressMap): 646 647 pushl %ebp 648 movl %esp,%ebp 649 pushal 650 651 movl 0x8(%ebp), %ebx 652 movl $Exception0Handle, (%ebx) 653 movl $(Exception1Handle - Exception0Handle), 0x4(%ebx) 654 movl $(HookAfterStubBegin), 0x8(%ebx) 655 656 popal 657 popl %ebp 658 ret 659#------------------------------------------------------------------------------------- 660# AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr); 661#------------------------------------------------------------------------------------- 662ASM_GLOBAL ASM_PFX(AsmVectorNumFixup) 663ASM_PFX(AsmVectorNumFixup): 664 movl 8(%esp), %eax 665 movl 4(%esp), %ecx 666 movb %al, (VectorNum - HookAfterStubBegin)(%ecx) 667 ret 668