1 ;------------------------------------------------------------------------------ ; 2 ; Copyright (c) 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 ; ExceptionHandlerAsm.Asm 14 ; 15 ; Abstract: 16 ; 17 ; IA32 CPU Exception Handler 18 ; 19 ; Notes: 20 ; 21 ;------------------------------------------------------------------------------ 22 23 ; 24 ; CommonExceptionHandler() 25 ; 26 extern ASM_PFX(CommonExceptionHandler) 27 28 SECTION .data 29 30 extern ASM_PFX(mErrorCodeFlag) ; Error code flags for exceptions 31 extern ASM_PFX(mDoFarReturnFlag) ; Do far return flag 32 33 SECTION .text 34 35 ALIGN 8 36 37 ; 38 ; exception handler stub table 39 ; 40 AsmIdtVectorBegin: 41 %rep 32 42 db 0x6a ; push #VectorNum 43 db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum 44 push eax 45 mov eax, ASM_PFX(CommonInterruptEntry) 46 jmp eax 47 %endrep 48 AsmIdtVectorEnd: 49 50 HookAfterStubBegin: 51 db 0x6a ; push 52 VectorNum: 53 db 0 ; 0 will be fixed 54 push eax 55 mov eax, HookAfterStubHeaderEnd 56 jmp eax 57 HookAfterStubHeaderEnd: 58 pop eax 59 sub esp, 8 ; reserve room for filling exception data later 60 push dword [esp + 8] 61 xchg ecx, [esp] ; get vector number 62 bt [ASM_PFX(mErrorCodeFlag)], ecx 63 jnc .0 64 push dword [esp] ; addition push if exception data needed 65 .0: 66 xchg ecx, [esp] ; restore ecx 67 push eax 68 69 ;----------------------------------------------------------------------------; 70 ; CommonInterruptEntry ; 71 ;----------------------------------------------------------------------------; 72 ; The follow algorithm is used for the common interrupt routine. 73 ; Entry from each interrupt with a push eax and eax=interrupt number 74 ; Stack: 75 ; +---------------------+ 76 ; + EFlags + 77 ; +---------------------+ 78 ; + CS + 79 ; +---------------------+ 80 ; + EIP + 81 ; +---------------------+ 82 ; + Error Code + 83 ; +---------------------+ 84 ; + Vector Number + 85 ; +---------------------+ 86 ; + EBP + 87 ; +---------------------+ <-- EBP 88 global ASM_PFX(CommonInterruptEntry) 89 ASM_PFX(CommonInterruptEntry): 90 cli 91 pop eax 92 ; 93 ; All interrupt handlers are invoked through interrupt gates, so 94 ; IF flag automatically cleared at the entry point 95 ; 96 97 ; 98 ; Get vector number from top of stack 99 ; 100 xchg ecx, [esp] 101 and ecx, 0xFF ; Vector number should be less than 256 102 cmp ecx, 32 ; Intel reserved vector for exceptions? 103 jae NoErrorCode 104 bt [ASM_PFX(mErrorCodeFlag)], ecx 105 jc HasErrorCode 106 107 NoErrorCode: 108 109 ; 110 ; Stack: 111 ; +---------------------+ 112 ; + EFlags + 113 ; +---------------------+ 114 ; + CS + 115 ; +---------------------+ 116 ; + EIP + 117 ; +---------------------+ 118 ; + ECX + 119 ; +---------------------+ <-- ESP 120 ; 121 ; Registers: 122 ; ECX - Vector Number 123 ; 124 125 ; 126 ; Put Vector Number on stack 127 ; 128 push ecx 129 130 ; 131 ; Put 0 (dummy) error code on stack, and restore ECX 132 ; 133 xor ecx, ecx ; ECX = 0 134 xchg ecx, [esp+4] 135 136 jmp ErrorCodeAndVectorOnStack 137 138 HasErrorCode: 139 140 ; 141 ; Stack: 142 ; +---------------------+ 143 ; + EFlags + 144 ; +---------------------+ 145 ; + CS + 146 ; +---------------------+ 147 ; + EIP + 148 ; +---------------------+ 149 ; + Error Code + 150 ; +---------------------+ 151 ; + ECX + 152 ; +---------------------+ <-- ESP 153 ; 154 ; Registers: 155 ; ECX - Vector Number 156 ; 157 158 ; 159 ; Put Vector Number on stack and restore ECX 160 ; 161 xchg ecx, [esp] 162 163 ErrorCodeAndVectorOnStack: 164 push ebp 165 mov ebp, esp 166 167 ; 168 ; Stack: 169 ; +---------------------+ 170 ; + EFlags + 171 ; +---------------------+ 172 ; + CS + 173 ; +---------------------+ 174 ; + EIP + 175 ; +---------------------+ 176 ; + Error Code + 177 ; +---------------------+ 178 ; + Vector Number + 179 ; +---------------------+ 180 ; + EBP + 181 ; +---------------------+ <-- EBP 182 ; 183 184 ; 185 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 186 ; is 16-byte aligned 187 ; 188 and esp, 0xfffffff0 189 sub esp, 12 190 191 sub esp, 8 192 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler 193 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag 194 195 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 196 push eax 197 push ecx 198 push edx 199 push ebx 200 lea ecx, [ebp + 6 * 4] 201 push ecx ; ESP 202 push dword [ebp] ; EBP 203 push esi 204 push edi 205 206 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; 207 mov eax, ss 208 push eax 209 movzx eax, word [ebp + 4 * 4] 210 push eax 211 mov eax, ds 212 push eax 213 mov eax, es 214 push eax 215 mov eax, fs 216 push eax 217 mov eax, gs 218 push eax 219 220 ;; UINT32 Eip; 221 mov eax, [ebp + 3 * 4] 222 push eax 223 224 ;; UINT32 Gdtr[2], Idtr[2]; 225 sub esp, 8 226 sidt [esp] 227 mov eax, [esp + 2] 228 xchg eax, [esp] 229 and eax, 0xFFFF 230 mov [esp+4], eax 231 232 sub esp, 8 233 sgdt [esp] 234 mov eax, [esp + 2] 235 xchg eax, [esp] 236 and eax, 0xFFFF 237 mov [esp+4], eax 238 239 ;; UINT32 Ldtr, Tr; 240 xor eax, eax 241 str ax 242 push eax 243 sldt ax 244 push eax 245 246 ;; UINT32 EFlags; 247 mov eax, [ebp + 5 * 4] 248 push eax 249 250 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; 251 mov eax, 1 252 push ebx ; temporarily save value of ebx on stack 253 cpuid ; use CPUID to determine if FXSAVE/FXRESTOR and DE 254 ; are supported 255 pop ebx ; retore value of ebx that was overwritten by CPUID 256 mov eax, cr4 257 push eax ; push cr4 firstly 258 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support 259 jz .1 260 or eax, BIT9 ; Set CR4.OSFXSR 261 .1: 262 test edx, BIT2 ; Test for Debugging Extensions support 263 jz .2 264 or eax, BIT3 ; Set CR4.DE 265 .2: 266 mov cr4, eax 267 mov eax, cr3 268 push eax 269 mov eax, cr2 270 push eax 271 xor eax, eax 272 push eax 273 mov eax, cr0 274 push eax 275 276 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 277 mov eax, dr7 278 push eax 279 mov eax, dr6 280 push eax 281 mov eax, dr3 282 push eax 283 mov eax, dr2 284 push eax 285 mov eax, dr1 286 push eax 287 mov eax, dr0 288 push eax 289 290 ;; FX_SAVE_STATE_IA32 FxSaveState; 291 sub esp, 512 292 mov edi, esp 293 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support. 294 ; edx still contains result from CPUID above 295 jz .3 296 db 0xf, 0xae, 0x7 ;fxsave [edi] 297 .3: 298 299 ;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear 300 cld 301 302 ;; UINT32 ExceptionData; 303 push dword [ebp + 2 * 4] 304 305 ;; Prepare parameter and call 306 mov edx, esp 307 push edx 308 mov edx, dword [ebp + 1 * 4] 309 push edx 310 311 ; 312 ; Call External Exception Handler 313 ; 314 mov eax, ASM_PFX(CommonExceptionHandler) 315 call eax 316 add esp, 8 317 318 cli 319 ;; UINT32 ExceptionData; 320 add esp, 4 321 322 ;; FX_SAVE_STATE_IA32 FxSaveState; 323 mov esi, esp 324 mov eax, 1 325 cpuid ; use CPUID to determine if FXSAVE/FXRESTOR 326 ; are supported 327 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support 328 jz .4 329 db 0xf, 0xae, 0xe ; fxrstor [esi] 330 .4: 331 add esp, 512 332 333 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 334 ;; Skip restoration of DRx registers to support in-circuit emualators 335 ;; or debuggers set breakpoint in interrupt/exception context 336 add esp, 4 * 6 337 338 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; 339 pop eax 340 mov cr0, eax 341 add esp, 4 ; not for Cr1 342 pop eax 343 mov cr2, eax 344 pop eax 345 mov cr3, eax 346 pop eax 347 mov cr4, eax 348 349 ;; UINT32 EFlags; 350 pop dword [ebp + 5 * 4] 351 352 ;; UINT32 Ldtr, Tr; 353 ;; UINT32 Gdtr[2], Idtr[2]; 354 ;; Best not let anyone mess with these particular registers... 355 add esp, 24 356 357 ;; UINT32 Eip; 358 pop dword [ebp + 3 * 4] 359 360 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; 361 ;; NOTE - modified segment registers could hang the debugger... We 362 ;; could attempt to insulate ourselves against this possibility, 363 ;; but that poses risks as well. 364 ;; 365 pop gs 366 pop fs 367 pop es 368 pop ds 369 pop dword [ebp + 4 * 4] 370 pop ss 371 372 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; 373 pop edi 374 pop esi 375 add esp, 4 ; not for ebp 376 add esp, 4 ; not for esp 377 pop ebx 378 pop edx 379 pop ecx 380 pop eax 381 382 pop dword [ebp - 8] 383 pop dword [ebp - 4] 384 mov esp, ebp 385 pop ebp 386 add esp, 8 387 cmp dword [esp - 16], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler 388 jz DoReturn 389 cmp dword [esp - 20], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag 390 jz ErrorCode 391 jmp dword [esp - 16] 392 ErrorCode: 393 sub esp, 4 394 jmp dword [esp - 12] 395 396 DoReturn: 397 cmp dword [ASM_PFX(mDoFarReturnFlag)], 0 ; Check if need to do far return instead of IRET 398 jz DoIret 399 push dword [esp + 8] ; save EFLAGS 400 add esp, 16 401 push dword [esp - 8] ; save CS in new location 402 push dword [esp - 8] ; save EIP in new location 403 push dword [esp - 8] ; save EFLAGS in new location 404 popfd ; restore EFLAGS 405 retf ; far return 406 407 DoIret: 408 iretd 409 410 ;---------------------------------------; 411 ; _AsmGetTemplateAddressMap ; 412 ;----------------------------------------------------------------------------; 413 ; 414 ; Protocol prototype 415 ; AsmGetTemplateAddressMap ( 416 ; EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap 417 ; ); 418 ; 419 ; Routine Description: 420 ; 421 ; Return address map of interrupt handler template so that C code can generate 422 ; interrupt table. 423 ; 424 ; Arguments: 425 ; 426 ; 427 ; Returns: 428 ; 429 ; Nothing 430 ; 431 ; 432 ; Input: [ebp][0] = Original ebp 433 ; [ebp][4] = Return address 434 ; 435 ; Output: Nothing 436 ; 437 ; Destroys: Nothing 438 ;-----------------------------------------------------------------------------; 439 global ASM_PFX(AsmGetTemplateAddressMap) 440 ASM_PFX(AsmGetTemplateAddressMap): 441 push ebp ; C prolog 442 mov ebp, esp 443 pushad 444 445 mov ebx, dword [ebp + 0x8] 446 mov dword [ebx], AsmIdtVectorBegin 447 mov dword [ebx + 0x4], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32 448 mov dword [ebx + 0x8], HookAfterStubBegin 449 450 popad 451 pop ebp 452 ret 453 454 ;------------------------------------------------------------------------------------- 455 ; AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr); 456 ;------------------------------------------------------------------------------------- 457 global ASM_PFX(AsmVectorNumFixup) 458 ASM_PFX(AsmVectorNumFixup): 459 mov eax, dword [esp + 8] 460 mov ecx, [esp + 4] 461 mov [ecx + (VectorNum - HookAfterStubBegin)], al 462 ret 463