1;------------------------------------------------------------------------------ ; 2; Copyright (c) 2012 - 2014, 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; x64 CPU Exception Handler 18; 19; Notes: 20; 21;------------------------------------------------------------------------------ 22 23; 24; CommonExceptionHandler() 25; 26externdef CommonExceptionHandler:near 27 28EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions 29EXTRN mDoFarReturnFlag:QWORD ; Do far return flag 30 31data SEGMENT 32 33.code 34 35ALIGN 8 36 37AsmIdtVectorBegin: 38REPEAT 32 39 db 6ah ; push #VectorNum 40 db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum 41 push rax 42 mov rax, CommonInterruptEntry 43 jmp rax 44ENDM 45AsmIdtVectorEnd: 46 47HookAfterStubHeaderBegin: 48 db 6ah ; push 49@VectorNum: 50 db 0 ; 0 will be fixed 51 push rax 52 mov rax, HookAfterStubHeaderEnd 53 jmp rax 54HookAfterStubHeaderEnd: 55 mov rax, rsp 56 and sp, 0fff0h ; make sure 16-byte aligned for exception context 57 sub rsp, 18h ; reserve room for filling exception data later 58 push rcx 59 mov rcx, [rax + 8] 60 bt mErrorCodeFlag, ecx 61 jnc @F 62 push [rsp] ; push additional rcx to make stack alignment 63@@: 64 xchg rcx, [rsp] ; restore rcx, save Exception Number in stack 65 push [rax] ; push rax into stack to keep code consistence 66 67;---------------------------------------; 68; CommonInterruptEntry ; 69;---------------------------------------; 70; The follow algorithm is used for the common interrupt routine. 71; Entry from each interrupt with a push eax and eax=interrupt number 72; Stack frame would be as follows as specified in IA32 manuals: 73; 74; +---------------------+ <-- 16-byte aligned ensured by processor 75; + Old SS + 76; +---------------------+ 77; + Old RSP + 78; +---------------------+ 79; + RFlags + 80; +---------------------+ 81; + CS + 82; +---------------------+ 83; + RIP + 84; +---------------------+ 85; + Error Code + 86; +---------------------+ 87; + Vector Number + 88; +---------------------+ 89; + RBP + 90; +---------------------+ <-- RBP, 16-byte aligned 91; The follow algorithm is used for the common interrupt routine. 92CommonInterruptEntry PROC PUBLIC 93 cli 94 pop rax 95 ; 96 ; All interrupt handlers are invoked through interrupt gates, so 97 ; IF flag automatically cleared at the entry point 98 ; 99 xchg rcx, [rsp] ; Save rcx into stack and save vector number into rcx 100 and rcx, 0FFh 101 cmp ecx, 32 ; Intel reserved vector for exceptions? 102 jae NoErrorCode 103 bt mErrorCodeFlag, ecx 104 jc @F 105 106NoErrorCode: 107 108 ; 109 ; Push a dummy error code on the stack 110 ; to maintain coherent stack map 111 ; 112 push [rsp] 113 mov qword ptr [rsp + 8], 0 114@@: 115 push rbp 116 mov rbp, rsp 117 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler 118 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag 119 120 ; 121 ; Stack: 122 ; +---------------------+ <-- 16-byte aligned ensured by processor 123 ; + Old SS + 124 ; +---------------------+ 125 ; + Old RSP + 126 ; +---------------------+ 127 ; + RFlags + 128 ; +---------------------+ 129 ; + CS + 130 ; +---------------------+ 131 ; + RIP + 132 ; +---------------------+ 133 ; + Error Code + 134 ; +---------------------+ 135 ; + RCX / Vector Number + 136 ; +---------------------+ 137 ; + RBP + 138 ; +---------------------+ <-- RBP, 16-byte aligned 139 ; 140 141 142 ; 143 ; Since here the stack pointer is 16-byte aligned, so 144 ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64 145 ; is 16-byte aligned 146 ; 147 148;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; 149;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; 150 push r15 151 push r14 152 push r13 153 push r12 154 push r11 155 push r10 156 push r9 157 push r8 158 push rax 159 push qword ptr [rbp + 8] ; RCX 160 push rdx 161 push rbx 162 push qword ptr [rbp + 48] ; RSP 163 push qword ptr [rbp] ; RBP 164 push rsi 165 push rdi 166 167;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero 168 movzx rax, word ptr [rbp + 56] 169 push rax ; for ss 170 movzx rax, word ptr [rbp + 32] 171 push rax ; for cs 172 mov rax, ds 173 push rax 174 mov rax, es 175 push rax 176 mov rax, fs 177 push rax 178 mov rax, gs 179 push rax 180 181 mov [rbp + 8], rcx ; save vector number 182 183;; UINT64 Rip; 184 push qword ptr [rbp + 24] 185 186;; UINT64 Gdtr[2], Idtr[2]; 187 xor rax, rax 188 push rax 189 push rax 190 sidt [rsp] 191 xchg rax, [rsp + 2] 192 xchg rax, [rsp] 193 xchg rax, [rsp + 8] 194 195 xor rax, rax 196 push rax 197 push rax 198 sgdt [rsp] 199 xchg rax, [rsp + 2] 200 xchg rax, [rsp] 201 xchg rax, [rsp + 8] 202 203;; UINT64 Ldtr, Tr; 204 xor rax, rax 205 str ax 206 push rax 207 sldt ax 208 push rax 209 210;; UINT64 RFlags; 211 push qword ptr [rbp + 40] 212 213;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; 214 mov rax, cr8 215 push rax 216 mov rax, cr4 217 or rax, 208h 218 mov cr4, rax 219 push rax 220 mov rax, cr3 221 push rax 222 mov rax, cr2 223 push rax 224 xor rax, rax 225 push rax 226 mov rax, cr0 227 push rax 228 229;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 230 mov rax, dr7 231 push rax 232 mov rax, dr6 233 push rax 234 mov rax, dr3 235 push rax 236 mov rax, dr2 237 push rax 238 mov rax, dr1 239 push rax 240 mov rax, dr0 241 push rax 242 243;; FX_SAVE_STATE_X64 FxSaveState; 244 sub rsp, 512 245 mov rdi, rsp 246 db 0fh, 0aeh, 07h ;fxsave [rdi] 247 248;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear 249 cld 250 251;; UINT32 ExceptionData; 252 push qword ptr [rbp + 16] 253 254;; Prepare parameter and call 255 mov rcx, [rbp + 8] 256 mov rdx, rsp 257 ; 258 ; Per X64 calling convention, allocate maximum parameter stack space 259 ; and make sure RSP is 16-byte aligned 260 ; 261 sub rsp, 4 * 8 + 8 262 mov rax, CommonExceptionHandler 263 call rax 264 add rsp, 4 * 8 + 8 265 266 cli 267;; UINT64 ExceptionData; 268 add rsp, 8 269 270;; FX_SAVE_STATE_X64 FxSaveState; 271 272 mov rsi, rsp 273 db 0fh, 0aeh, 0Eh ; fxrstor [rsi] 274 add rsp, 512 275 276;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 277;; Skip restoration of DRx registers to support in-circuit emualators 278;; or debuggers set breakpoint in interrupt/exception context 279 add rsp, 8 * 6 280 281;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; 282 pop rax 283 mov cr0, rax 284 add rsp, 8 ; not for Cr1 285 pop rax 286 mov cr2, rax 287 pop rax 288 mov cr3, rax 289 pop rax 290 mov cr4, rax 291 pop rax 292 mov cr8, rax 293 294;; UINT64 RFlags; 295 pop qword ptr [rbp + 40] 296 297;; UINT64 Ldtr, Tr; 298;; UINT64 Gdtr[2], Idtr[2]; 299;; Best not let anyone mess with these particular registers... 300 add rsp, 48 301 302;; UINT64 Rip; 303 pop qword ptr [rbp + 24] 304 305;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; 306 pop rax 307 ; mov gs, rax ; not for gs 308 pop rax 309 ; mov fs, rax ; not for fs 310 ; (X64 will not use fs and gs, so we do not restore it) 311 pop rax 312 mov es, rax 313 pop rax 314 mov ds, rax 315 pop qword ptr [rbp + 32] ; for cs 316 pop qword ptr [rbp + 56] ; for ss 317 318;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; 319;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; 320 pop rdi 321 pop rsi 322 add rsp, 8 ; not for rbp 323 pop qword ptr [rbp + 48] ; for rsp 324 pop rbx 325 pop rdx 326 pop rcx 327 pop rax 328 pop r8 329 pop r9 330 pop r10 331 pop r11 332 pop r12 333 pop r13 334 pop r14 335 pop r15 336 337 mov rsp, rbp 338 pop rbp 339 add rsp, 16 340 cmp qword ptr [rsp - 32], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler 341 jz DoReturn 342 cmp qword ptr [rsp - 40], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag 343 jz ErrorCode 344 jmp qword ptr [rsp - 32] 345ErrorCode: 346 sub rsp, 8 347 jmp qword ptr [rsp - 24] 348 349DoReturn: 350 cmp mDoFarReturnFlag, 0 ; Check if need to do far return instead of IRET 351 jz DoIret 352 push rax 353 mov rax, rsp ; save old RSP to rax 354 mov rsp, [rsp + 20h] 355 push [rax + 10h] ; save CS in new location 356 push [rax + 8h] ; save EIP in new location 357 push [rax + 18h] ; save EFLAGS in new location 358 mov rax, [rax] ; restore rax 359 popfq ; restore EFLAGS 360 DB 48h ; prefix to composite "retq" with next "retf" 361 retf ; far return 362DoIret: 363 iretq 364 365CommonInterruptEntry ENDP 366 367;------------------------------------------------------------------------------------- 368; GetTemplateAddressMap (&AddressMap); 369;------------------------------------------------------------------------------------- 370; comments here for definition of address map 371AsmGetTemplateAddressMap PROC 372 mov rax, offset AsmIdtVectorBegin 373 mov qword ptr [rcx], rax 374 mov qword ptr [rcx + 8h], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32 375 mov rax, offset HookAfterStubHeaderBegin 376 mov qword ptr [rcx + 10h], rax 377 ret 378AsmGetTemplateAddressMap ENDP 379 380;------------------------------------------------------------------------------------- 381; AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr); 382;------------------------------------------------------------------------------------- 383AsmVectorNumFixup PROC 384 mov rax, rdx 385 mov [rcx + (@VectorNum - HookAfterStubHeaderBegin)], al 386 ret 387AsmVectorNumFixup ENDP 388 389END 390