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