]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.S
1. Separated DxeSmmCpuExceptionHandlerLib.inf into 2 instance DxeCpuExceptionHandlerL...
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / X64 / ExceptionHandlerAsm.S
1 #------------------------------------------------------------------------------ ;
2 # Copyright (c) 2012 - 2013, 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.S
14 #
15 # Abstract:
16 #
17 # x64 CPU Exception Handler
18 #
19 # Notes:
20 #
21 #------------------------------------------------------------------------------
22
23
24
25 ASM_GLOBAL ASM_PFX(CommonExceptionHandler)
26 ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
27 ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
28
29 #EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions
30 #EXTRN ASM_PFX(mDoFarReturnFlag):QWORD # Do far return flag
31 .text
32
33 #
34 # exception handler stub table
35 #
36 Exception0Handle:
37 .byte 0x6a # push #VectorNum
38 .byte 0
39 pushq %rax
40 .byte 0x48, 0xB8
41 .quad ASM_PFX(CommonInterruptEntry)
42 jmp *%rax
43 Exception1Handle:
44 .byte 0x6a # push #VectorNum
45 .byte 1
46 pushq %rax
47 .byte 0x48, 0xB8
48 .quad ASM_PFX(CommonInterruptEntry)
49 jmp *%rax
50 Exception2Handle:
51 .byte 0x6a # push #VectorNum
52 .byte 2
53 pushq %rax
54 .byte 0x48, 0xB8
55 .quad ASM_PFX(CommonInterruptEntry)
56 jmp *%rax
57 Exception3Handle:
58 .byte 0x6a # push #VectorNum
59 .byte 3
60 pushq %rax
61 .byte 0x48, 0xB8
62 .quad ASM_PFX(CommonInterruptEntry)
63 jmp *%rax
64 Exception4Handle:
65 .byte 0x6a # push #VectorNum
66 .byte 4
67 pushq %rax
68 .byte 0x48, 0xB8
69 .quad ASM_PFX(CommonInterruptEntry)
70 jmp *%rax
71 Exception5Handle:
72 .byte 0x6a # push #VectorNum
73 .byte 5
74 pushq %rax
75 .byte 0x48, 0xB8
76 .quad ASM_PFX(CommonInterruptEntry)
77 jmp *%rax
78 Exception6Handle:
79 .byte 0x6a # push #VectorNum
80 .byte 6
81 pushq %rax
82 .byte 0x48, 0xB8
83 .quad ASM_PFX(CommonInterruptEntry)
84 jmp *%rax
85 Exception7Handle:
86 .byte 0x6a # push #VectorNum
87 .byte 7
88 pushq %rax
89 .byte 0x48, 0xB8
90 .quad ASM_PFX(CommonInterruptEntry)
91 jmp *%rax
92 Exception8Handle:
93 .byte 0x6a # push #VectorNum
94 .byte 8
95 pushq %rax
96 .byte 0x48, 0xB8
97 .quad ASM_PFX(CommonInterruptEntry)
98 jmp *%rax
99 Exception9Handle:
100 .byte 0x6a # push #VectorNum
101 .byte 9
102 pushq %rax
103 .byte 0x48, 0xB8
104 .quad ASM_PFX(CommonInterruptEntry)
105 jmp *%rax
106 Exception10Handle:
107 .byte 0x6a # push #VectorNum
108 .byte 10
109 pushq %rax
110 .byte 0x48, 0xB8
111 .quad ASM_PFX(CommonInterruptEntry)
112 jmp *%rax
113 Exception11Handle:
114 .byte 0x6a # push #VectorNum
115 .byte 11
116 pushq %rax
117 .byte 0x48, 0xB8
118 .quad ASM_PFX(CommonInterruptEntry)
119 jmp *%rax
120 Exception12Handle:
121 .byte 0x6a # push #VectorNum
122 .byte 12
123 pushq %rax
124 .byte 0x48, 0xB8
125 .quad ASM_PFX(CommonInterruptEntry)
126 jmp *%rax
127 Exception13Handle:
128 .byte 0x6a # push #VectorNum
129 .byte 13
130 pushq %rax
131 .byte 0x48, 0xB8
132 .quad ASM_PFX(CommonInterruptEntry)
133 jmp *%rax
134 Exception14Handle:
135 .byte 0x6a # push #VectorNum
136 .byte 14
137 pushq %rax
138 .byte 0x48, 0xB8
139 .quad ASM_PFX(CommonInterruptEntry)
140 jmp *%rax
141 Exception15Handle:
142 .byte 0x6a # push #VectorNum
143 .byte 15
144 pushq %rax
145 .byte 0x48, 0xB8
146 .quad ASM_PFX(CommonInterruptEntry)
147 jmp *%rax
148 Exception16Handle:
149 .byte 0x6a # push #VectorNum
150 .byte 16
151 pushq %rax
152 .byte 0x48, 0xB8
153 .quad ASM_PFX(CommonInterruptEntry)
154 jmp *%rax
155 Exception17Handle:
156 .byte 0x6a # push #VectorNum
157 .byte 17
158 pushq %rax
159 .byte 0x48, 0xB8
160 .quad ASM_PFX(CommonInterruptEntry)
161 jmp *%rax
162 Exception18Handle:
163 .byte 0x6a # push #VectorNum
164 .byte 18
165 pushq %rax
166 .byte 0x48, 0xB8
167 .quad ASM_PFX(CommonInterruptEntry)
168 jmp *%rax
169 Exception19Handle:
170 .byte 0x6a # push #VectorNum
171 .byte 19
172 pushq %rax
173 .byte 0x48, 0xB8
174 .quad ASM_PFX(CommonInterruptEntry)
175 jmp *%rax
176 Exception20Handle:
177 .byte 0x6a # push #VectorNum
178 .byte 20
179 pushq %rax
180 .byte 0x48, 0xB8
181 .quad ASM_PFX(CommonInterruptEntry)
182 jmp *%rax
183 Exception21Handle:
184 .byte 0x6a # push #VectorNum
185 .byte 21
186 pushq %rax
187 .byte 0x48, 0xB8
188 .quad ASM_PFX(CommonInterruptEntry)
189 jmp *%rax
190 Exception22Handle:
191 .byte 0x6a # push #VectorNum
192 .byte 22
193 pushq %rax
194 .byte 0x48, 0xB8
195 .quad ASM_PFX(CommonInterruptEntry)
196 jmp *%rax
197 Exception23Handle:
198 .byte 0x6a # push #VectorNum
199 .byte 23
200 pushq %rax
201 .byte 0x48, 0xB8
202 .quad ASM_PFX(CommonInterruptEntry)
203 jmp *%rax
204 Exception24Handle:
205 .byte 0x6a # push #VectorNum
206 .byte 24
207 pushq %rax
208 .byte 0x48, 0xB8
209 .quad ASM_PFX(CommonInterruptEntry)
210 jmp *%rax
211 Exception25Handle:
212 .byte 0x6a # push #VectorNum
213 .byte 25
214 pushq %rax
215 .byte 0x48, 0xB8
216 .quad ASM_PFX(CommonInterruptEntry)
217 jmp *%rax
218 Exception26Handle:
219 .byte 0x6a # push #VectorNum
220 .byte 26
221 pushq %rax
222 .byte 0x48, 0xB8
223 .quad ASM_PFX(CommonInterruptEntry)
224 jmp *%rax
225 Exception27Handle:
226 .byte 0x6a # push #VectorNum
227 .byte 27
228 pushq %rax
229 .byte 0x48, 0xB8
230 .quad ASM_PFX(CommonInterruptEntry)
231 jmp *%rax
232 Exception28Handle:
233 .byte 0x6a # push #VectorNum
234 .byte 28
235 pushq %rax
236 .byte 0x48, 0xB8
237 .quad ASM_PFX(CommonInterruptEntry)
238 jmp *%rax
239 Exception29Handle:
240 .byte 0x6a # push #VectorNum
241 .byte 29
242 pushq %rax
243 .byte 0x48, 0xB8
244 .quad ASM_PFX(CommonInterruptEntry)
245 jmp *%rax
246 Exception30Handle:
247 .byte 0x6a # push #VectorNum
248 .byte 30
249 pushq %rax
250 .byte 0x48, 0xB8
251 .quad ASM_PFX(CommonInterruptEntry)
252 jmp *%rax
253 Exception31Handle:
254 .byte 0x6a # push #VectorNum
255 .byte 31
256 pushq %rax
257 .byte 0x48, 0xB8
258 .quad ASM_PFX(CommonInterruptEntry)
259 jmp *%rax
260
261 HookAfterStubHeaderBegin:
262 .byte 0x6a # push
263 VectorNum:
264 .byte 0 # 0 will be fixed
265 pushq %rax
266 .byte 0x48, 0xB8 # movq ASM_PFX(HookAfterStubHeaderEnd), %rax
267 .quad ASM_PFX(HookAfterStubHeaderEnd)
268 jmp *%rax
269 ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
270 ASM_PFX(HookAfterStubHeaderEnd):
271 movq %rsp, %rax
272 subq $8, %rsp
273 andl $0x0fffffff0, %esp
274 pushq %rcx
275 movq 8(%rax), %rcx
276 bt %ecx, ASM_PFX(mErrorCodeFlag)
277 jc NoErrorData
278 pushq (%rsp) # push additional rcx to make stack alignment
279 NoErrorData:
280 xchgq (%rsp), %rcx # restore rcx, save Exception Number in stack
281 pushq (%rax) # push rax into stack to keep code consistence
282
283 #---------------------------------------;
284 # CommonInterruptEntry ;
285 #---------------------------------------;
286 # The follow algorithm is used for the common interrupt routine.
287
288 ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
289 ASM_PFX(CommonInterruptEntry):
290 cli
291 popq %rax
292 #
293 # All interrupt handlers are invoked through interrupt gates, so
294 # IF flag automatically cleared at the entry point
295 #
296 #
297 # Calculate vector number
298 #
299 xchgq (%rsp), %rcx # get the return address of call, actually, it is the address of vector number.
300 andq $0x0FF, %rcx
301 cmp $32, %ecx # Intel reserved vector for exceptions?
302 jae NoErrorCode
303 pushq %rax
304 leaq ASM_PFX(mErrorCodeFlag)(%rip), %rax
305 bt %ecx, (%rax)
306 popq %rax
307 jc CommonInterruptEntry_al_0000
308
309 NoErrorCode:
310
311 #
312 # Push a dummy error code on the stack
313 # to maintain coherent stack map
314 #
315 pushq (%rsp)
316 movq $0, 8(%rsp)
317 CommonInterruptEntry_al_0000:
318 pushq %rbp
319 movq %rsp, %rbp
320 pushq $0 # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
321 pushq $0 # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
322
323 #
324 # Stack:
325 # +---------------------+ <-- 16-byte aligned ensured by processor
326 # + Old SS +
327 # +---------------------+
328 # + Old RSP +
329 # +---------------------+
330 # + RFlags +
331 # +---------------------+
332 # + CS +
333 # +---------------------+
334 # + RIP +
335 # +---------------------+
336 # + Error Code +
337 # +---------------------+
338 # + RCX / Vector Number +
339 # +---------------------+
340 # + RBP +
341 # +---------------------+ <-- RBP, 16-byte aligned
342 #
343
344
345 #
346 # Since here the stack pointer is 16-byte aligned, so
347 # EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
348 # is 16-byte aligned
349 #
350
351 #; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
352 #; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
353 pushq %r15
354 pushq %r14
355 pushq %r13
356 pushq %r12
357 pushq %r11
358 pushq %r10
359 pushq %r9
360 pushq %r8
361 pushq %rax
362 pushq 8(%rbp) # RCX
363 pushq %rdx
364 pushq %rbx
365 pushq 48(%rbp) # RSP
366 pushq (%rbp) # RBP
367 pushq %rsi
368 pushq %rdi
369
370 #; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
371 movzwq 56(%rbp), %rax
372 pushq %rax # for ss
373 movzwq 32(%rbp), %rax
374 pushq %rax # for cs
375 movl %ds, %eax
376 pushq %rax
377 movl %es, %eax
378 pushq %rax
379 movl %fs, %eax
380 pushq %rax
381 movl %gs, %eax
382 pushq %rax
383
384 movq %rcx, 8(%rbp) # save vector number
385
386 #; UINT64 Rip;
387 pushq 24(%rbp)
388
389 #; UINT64 Gdtr[2], Idtr[2];
390 xorq %rax, %rax
391 pushq %rax
392 pushq %rax
393 sidt (%rsp)
394 xchgq 2(%rsp), %rax
395 xchgq (%rsp), %rax
396 xchgq 8(%rsp), %rax
397
398 xorq %rax, %rax
399 pushq %rax
400 pushq %rax
401 sgdt (%rsp)
402 xchgq 2(%rsp), %rax
403 xchgq (%rsp), %rax
404 xchgq 8(%rsp), %rax
405
406 #; UINT64 Ldtr, Tr;
407 xorq %rax, %rax
408 str %ax
409 pushq %rax
410 sldt %ax
411 pushq %rax
412
413 #; UINT64 RFlags;
414 pushq 40(%rbp)
415
416 #; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
417 movq %cr8, %rax
418 pushq %rax
419 movq %cr4, %rax
420 orq $0x208, %rax
421 movq %rax, %cr4
422 pushq %rax
423 mov %cr3, %rax
424 pushq %rax
425 mov %cr2, %rax
426 pushq %rax
427 xorq %rax, %rax
428 pushq %rax
429 mov %cr0, %rax
430 pushq %rax
431
432 #; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
433 movq %dr7, %rax
434 pushq %rax
435 movq %dr6, %rax
436 pushq %rax
437 movq %dr3, %rax
438 pushq %rax
439 movq %dr2, %rax
440 pushq %rax
441 movq %dr1, %rax
442 pushq %rax
443 movq %dr0, %rax
444 pushq %rax
445
446 #; FX_SAVE_STATE_X64 FxSaveState;
447 subq $512, %rsp
448 movq %rsp, %rdi
449 .byte 0x0f, 0x0ae, 0x07 #fxsave [rdi]
450
451 #; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
452 cld
453
454 #; UINT32 ExceptionData;
455 pushq 16(%rbp)
456
457 #; Prepare parameter and call
458 mov 8(%rbp), %rcx
459 mov %rsp, %rdx
460 #
461 # Per X64 calling convention, allocate maximum parameter stack space
462 # and make sure RSP is 16-byte aligned
463 #
464 subq $40, %rsp
465 call ASM_PFX(CommonExceptionHandler)
466 addq $40, %rsp
467
468 cli
469 #; UINT64 ExceptionData;
470 addq $8, %rsp
471
472 #; FX_SAVE_STATE_X64 FxSaveState;
473
474 movq %rsp, %rsi
475 .byte 0x0f, 0x0ae, 0x0E # fxrstor [rsi]
476 addq $512, %rsp
477
478 #; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
479 #; Skip restoration of DRx registers to support in-circuit emualators
480 #; or debuggers set breakpoint in interrupt/exception context
481 addq $48, %rsp
482
483 #; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
484 popq %rax
485 movq %rax, %cr0
486 addq $8, %rsp # not for Cr1
487 popq %rax
488 movq %rax, %cr2
489 popq %rax
490 movq %rax, %cr3
491 popq %rax
492 movq %rax, %cr4
493 popq %rax
494 movq %rax, %cr8
495
496 #; UINT64 RFlags;
497 popq 40(%rbp)
498
499 #; UINT64 Ldtr, Tr;
500 #; UINT64 Gdtr[2], Idtr[2];
501 #; Best not let anyone mess with these particular registers...
502 addq $48, %rsp
503
504 #; UINT64 Rip;
505 popq 24(%rbp)
506
507 #; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
508 popq %rax
509 # mov %rax, %gs ; not for gs
510 popq %rax
511 # mov %rax, %fs ; not for fs
512 # (X64 will not use fs and gs, so we do not restore it)
513 popq %rax
514 movl %eax, %es
515 popq %rax
516 movl %eax, %ds
517 popq 32(%rbp) # for cs
518 popq 56(%rbp) # for ss
519
520 #; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
521 #; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
522 popq %rdi
523 popq %rsi
524 addq $8, %rsp # not for rbp
525 popq 48(%rbp) # for rsp
526 popq %rbx
527 popq %rdx
528 popq %rcx
529 popq %rax
530 popq %r8
531 popq %r9
532 popq %r10
533 popq %r11
534 popq %r12
535 popq %r13
536 popq %r14
537 popq %r15
538
539 movq %rbp, %rsp
540 popq %rbp
541 addq $16, %rsp
542 cmpq $0, -32(%rsp) # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
543 jz DoReturn # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
544 cmpb $1, -40(%rsp)
545 jz ErrorCode
546 jmp *-32(%rsp)
547 ErrorCode:
548 subq $8, %rsp
549 jmp *-24(%rsp)
550
551 DoReturn:
552 cmpq $0, ASM_PFX(mDoFarReturnFlag) # Check if need to do far return instead of IRET
553 jz DoIret
554 pushq %rax
555 movq %rsp, %rax # save old RSP to rax
556 movq 0x20(%rsp), %rsp
557 pushq 0x10(%rax) # save CS in new location
558 pushq 0x8(%rax) # save EIP in new location
559 pushq 0x18(%rax) # save EFLAGS in new location
560 movq (%rax), %rax # restore rax
561 popfq # restore EFLAGS
562 .byte 0x48 # prefix to composite "retq" with next "retf"
563 retf # far return
564 DoIret:
565 iretq
566
567
568 #-------------------------------------------------------------------------------------
569 # AsmGetTemplateAddressMap (&AddressMap);
570 #-------------------------------------------------------------------------------------
571 # comments here for definition of address map
572 ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap)
573 ASM_PFX(AsmGetTemplateAddressMap):
574
575 movabsq $Exception0Handle, %rax
576 movq %rax, (%rcx)
577 movq $(Exception1Handle - Exception0Handle), 0x08(%rcx)
578 movabsq $HookAfterStubHeaderBegin, %rax
579 movq %rax, 0x10(%rcx)
580 ret
581
582 #-------------------------------------------------------------------------------------
583 # AsmVectorNumFixup (*VectorBase, VectorNum);
584 #-------------------------------------------------------------------------------------
585 ASM_GLOBAL ASM_PFX(AsmVectorNumFixup)
586 ASM_PFX(AsmVectorNumFixup):
587 movq %rdx, %rax
588 movb %al, (VectorNum - HookAfterStubHeaderBegin)(%rcx)
589 ret
590
591 #END
592
593