]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.S
6e80d848fef2033f77cb5afa203d862e83639374
[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 pushq %rax
277 movabsl ASM_PFX(mErrorCodeFlag), %eax
278 bt %ecx, %eax
279 popq %rax
280 jc NoErrorData
281 pushq (%rsp) # push additional rcx to make stack alignment
282 NoErrorData:
283 xchgq (%rsp), %rcx # restore rcx, save Exception Number in stack
284 pushq (%rax) # push rax into stack to keep code consistence
285
286 #---------------------------------------;
287 # CommonInterruptEntry ;
288 #---------------------------------------;
289 # The follow algorithm is used for the common interrupt routine.
290
291 ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
292 ASM_PFX(CommonInterruptEntry):
293 cli
294 popq %rax
295 #
296 # All interrupt handlers are invoked through interrupt gates, so
297 # IF flag automatically cleared at the entry point
298 #
299 #
300 # Calculate vector number
301 #
302 xchgq (%rsp), %rcx # get the return address of call, actually, it is the address of vector number.
303 andq $0x0FF, %rcx
304 cmp $32, %ecx # Intel reserved vector for exceptions?
305 jae NoErrorCode
306 pushq %rax
307 movabsl ASM_PFX(mErrorCodeFlag), %eax
308 bt %ecx, %eax
309 popq %rax
310 jc CommonInterruptEntry_al_0000
311
312 NoErrorCode:
313
314 #
315 # Push a dummy error code on the stack
316 # to maintain coherent stack map
317 #
318 pushq (%rsp)
319 movq $0, 8(%rsp)
320 CommonInterruptEntry_al_0000:
321 pushq %rbp
322 movq %rsp, %rbp
323 pushq $0 # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
324 pushq $0 # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
325
326 #
327 # Stack:
328 # +---------------------+ <-- 16-byte aligned ensured by processor
329 # + Old SS +
330 # +---------------------+
331 # + Old RSP +
332 # +---------------------+
333 # + RFlags +
334 # +---------------------+
335 # + CS +
336 # +---------------------+
337 # + RIP +
338 # +---------------------+
339 # + Error Code +
340 # +---------------------+
341 # + RCX / Vector Number +
342 # +---------------------+
343 # + RBP +
344 # +---------------------+ <-- RBP, 16-byte aligned
345 #
346
347
348 #
349 # Since here the stack pointer is 16-byte aligned, so
350 # EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
351 # is 16-byte aligned
352 #
353
354 #; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
355 #; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
356 pushq %r15
357 pushq %r14
358 pushq %r13
359 pushq %r12
360 pushq %r11
361 pushq %r10
362 pushq %r9
363 pushq %r8
364 pushq %rax
365 pushq 8(%rbp) # RCX
366 pushq %rdx
367 pushq %rbx
368 pushq 48(%rbp) # RSP
369 pushq (%rbp) # RBP
370 pushq %rsi
371 pushq %rdi
372
373 #; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
374 movzwq 56(%rbp), %rax
375 pushq %rax # for ss
376 movzwq 32(%rbp), %rax
377 pushq %rax # for cs
378 movl %ds, %eax
379 pushq %rax
380 movl %es, %eax
381 pushq %rax
382 movl %fs, %eax
383 pushq %rax
384 movl %gs, %eax
385 pushq %rax
386
387 movq %rcx, 8(%rbp) # save vector number
388
389 #; UINT64 Rip;
390 pushq 24(%rbp)
391
392 #; UINT64 Gdtr[2], Idtr[2];
393 xorq %rax, %rax
394 pushq %rax
395 pushq %rax
396 sidt (%rsp)
397 xchgq 2(%rsp), %rax
398 xchgq (%rsp), %rax
399 xchgq 8(%rsp), %rax
400
401 xorq %rax, %rax
402 pushq %rax
403 pushq %rax
404 sgdt (%rsp)
405 xchgq 2(%rsp), %rax
406 xchgq (%rsp), %rax
407 xchgq 8(%rsp), %rax
408
409 #; UINT64 Ldtr, Tr;
410 xorq %rax, %rax
411 str %ax
412 pushq %rax
413 sldt %ax
414 pushq %rax
415
416 #; UINT64 RFlags;
417 pushq 40(%rbp)
418
419 #; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
420 movq %cr8, %rax
421 pushq %rax
422 movq %cr4, %rax
423 orq $0x208, %rax
424 movq %rax, %cr4
425 pushq %rax
426 mov %cr3, %rax
427 pushq %rax
428 mov %cr2, %rax
429 pushq %rax
430 xorq %rax, %rax
431 pushq %rax
432 mov %cr0, %rax
433 pushq %rax
434
435 #; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
436 movq %dr7, %rax
437 pushq %rax
438 movq %dr6, %rax
439 pushq %rax
440 movq %dr3, %rax
441 pushq %rax
442 movq %dr2, %rax
443 pushq %rax
444 movq %dr1, %rax
445 pushq %rax
446 movq %dr0, %rax
447 pushq %rax
448
449 #; FX_SAVE_STATE_X64 FxSaveState;
450 subq $512, %rsp
451 movq %rsp, %rdi
452 .byte 0x0f, 0x0ae, 0x07 #fxsave [rdi]
453
454 #; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
455 cld
456
457 #; UINT32 ExceptionData;
458 pushq 16(%rbp)
459
460 #; Prepare parameter and call
461 mov 8(%rbp), %rcx
462 mov %rsp, %rdx
463 #
464 # Per X64 calling convention, allocate maximum parameter stack space
465 # and make sure RSP is 16-byte aligned
466 #
467 subq $40, %rsp
468 call ASM_PFX(CommonExceptionHandler)
469 addq $40, %rsp
470
471 cli
472 #; UINT64 ExceptionData;
473 addq $8, %rsp
474
475 #; FX_SAVE_STATE_X64 FxSaveState;
476
477 movq %rsp, %rsi
478 .byte 0x0f, 0x0ae, 0x0E # fxrstor [rsi]
479 addq $512, %rsp
480
481 #; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
482 #; Skip restoration of DRx registers to support in-circuit emualators
483 #; or debuggers set breakpoint in interrupt/exception context
484 addq $48, %rsp
485
486 #; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
487 popq %rax
488 movq %rax, %cr0
489 addq $8, %rsp # not for Cr1
490 popq %rax
491 movq %rax, %cr2
492 popq %rax
493 movq %rax, %cr3
494 popq %rax
495 movq %rax, %cr4
496 popq %rax
497 movq %rax, %cr8
498
499 #; UINT64 RFlags;
500 popq 40(%rbp)
501
502 #; UINT64 Ldtr, Tr;
503 #; UINT64 Gdtr[2], Idtr[2];
504 #; Best not let anyone mess with these particular registers...
505 addq $48, %rsp
506
507 #; UINT64 Rip;
508 popq 24(%rbp)
509
510 #; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
511 popq %rax
512 # mov %rax, %gs ; not for gs
513 popq %rax
514 # mov %rax, %fs ; not for fs
515 # (X64 will not use fs and gs, so we do not restore it)
516 popq %rax
517 movl %eax, %es
518 popq %rax
519 movl %eax, %ds
520 popq 32(%rbp) # for cs
521 popq 56(%rbp) # for ss
522
523 #; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
524 #; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
525 popq %rdi
526 popq %rsi
527 addq $8, %rsp # not for rbp
528 popq 48(%rbp) # for rsp
529 popq %rbx
530 popq %rdx
531 popq %rcx
532 popq %rax
533 popq %r8
534 popq %r9
535 popq %r10
536 popq %r11
537 popq %r12
538 popq %r13
539 popq %r14
540 popq %r15
541
542 movq %rbp, %rsp
543 popq %rbp
544 addq $16, %rsp
545 cmpq $0, -32(%rsp) # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
546 jz DoReturn # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
547 cmpb $1, -40(%rsp)
548 jz ErrorCode
549 jmp *-32(%rsp)
550 ErrorCode:
551 subq $8, %rsp
552 jmp *-24(%rsp)
553
554 DoReturn:
555 pushq %rax
556 movabsq ASM_PFX(mDoFarReturnFlag), %rax
557 cmpq $0, %rax # Check if need to do far return instead of IRET
558 popq %rax
559 jz DoIret
560 pushq %rax
561 movq %rsp, %rax # save old RSP to rax
562 movq 0x20(%rsp), %rsp
563 pushq 0x10(%rax) # save CS in new location
564 pushq 0x8(%rax) # save EIP in new location
565 pushq 0x18(%rax) # save EFLAGS in new location
566 movq (%rax), %rax # restore rax
567 popfq # restore EFLAGS
568 .byte 0x48 # prefix to composite "retq" with next "retf"
569 retf # far return
570 DoIret:
571 iretq
572
573
574 #-------------------------------------------------------------------------------------
575 # AsmGetTemplateAddressMap (&AddressMap);
576 #-------------------------------------------------------------------------------------
577 # comments here for definition of address map
578 ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap)
579 ASM_PFX(AsmGetTemplateAddressMap):
580
581 movabsq $Exception0Handle, %rax
582 movq %rax, (%rcx)
583 movq $(Exception1Handle - Exception0Handle), 0x08(%rcx)
584 movabsq $HookAfterStubHeaderBegin, %rax
585 movq %rax, 0x10(%rcx)
586 ret
587
588 #-------------------------------------------------------------------------------------
589 # AsmVectorNumFixup (*VectorBase, VectorNum);
590 #-------------------------------------------------------------------------------------
591 ASM_GLOBAL ASM_PFX(AsmVectorNumFixup)
592 ASM_PFX(AsmVectorNumFixup):
593 movq %rdx, %rax
594 movb %al, (VectorNum - HookAfterStubHeaderBegin)(%rcx)
595 ret
596
597 #END
598
599