MdePkg/BaseLib: add PatchInstructionX86()
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / Ia32 / SmiException.S
1 #------------------------------------------------------------------------------
2 #
3 # Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
4 # This program and the accompanying materials
5 # are licensed and made available under the terms and conditions of the BSD License
6 # which accompanies this distribution. The full text of the license may be found at
7 # http://opensource.org/licenses/bsd-license.php.
8 #
9 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 #
12 # Module Name:
13 #
14 # SmiException.S
15 #
16 # Abstract:
17 #
18 # Exception handlers used in SM mode
19 #
20 #------------------------------------------------------------------------------
21
22 ASM_GLOBAL ASM_PFX(SmiPFHandler)
23 ASM_GLOBAL ASM_PFX(PageFaultStubFunction)
24 ASM_GLOBAL ASM_PFX(gcSmiIdtr)
25 ASM_GLOBAL ASM_PFX(gcSmiGdtr)
26 ASM_GLOBAL ASM_PFX(gTaskGateDescriptor)
27 ASM_GLOBAL ASM_PFX(gcPsd)
28 ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
29
30 .data
31
32 NullSeg: .quad 0 # reserved by architecture
33 CodeSeg32:
34 .word -1 # LimitLow
35 .word 0 # BaseLow
36 .byte 0 # BaseMid
37 .byte 0x9b
38 .byte 0xcf # LimitHigh
39 .byte 0 # BaseHigh
40 ProtModeCodeSeg32:
41 .word -1 # LimitLow
42 .word 0 # BaseLow
43 .byte 0 # BaseMid
44 .byte 0x9b
45 .byte 0xcf # LimitHigh
46 .byte 0 # BaseHigh
47 ProtModeSsSeg32:
48 .word -1 # LimitLow
49 .word 0 # BaseLow
50 .byte 0 # BaseMid
51 .byte 0x93
52 .byte 0xcf # LimitHigh
53 .byte 0 # BaseHigh
54 DataSeg32:
55 .word -1 # LimitLow
56 .word 0 # BaseLow
57 .byte 0 # BaseMid
58 .byte 0x93
59 .byte 0xcf # LimitHigh
60 .byte 0 # BaseHigh
61 CodeSeg16:
62 .word -1
63 .word 0
64 .byte 0
65 .byte 0x9b
66 .byte 0x8f
67 .byte 0
68 DataSeg16:
69 .word -1
70 .word 0
71 .byte 0
72 .byte 0x93
73 .byte 0x8f
74 .byte 0
75 CodeSeg64:
76 .word -1 # LimitLow
77 .word 0 # BaseLow
78 .byte 0 # BaseMid
79 .byte 0x9b
80 .byte 0xaf # LimitHigh
81 .byte 0 # BaseHigh
82 .equ GDT_SIZE, .- NullSeg
83
84 TssSeg:
85 .word TSS_DESC_SIZE -1 # LimitLow
86 .word 0 # BaseLow
87 .byte 0 # BaseMid
88 .byte 0x89
89 .byte 0x00 # LimitHigh
90 .byte 0 # BaseHigh
91 ExceptionTssSeg:
92 .word TSS_DESC_SIZE - 1 # LimitLow
93 .word 0 # BaseLow
94 .byte 0 # BaseMid
95 .byte 0x89
96 .byte 0x00 # LimitHigh
97 .byte 0 # BaseHigh
98
99 .equ CODE_SEL, CodeSeg32 - NullSeg
100 .equ DATA_SEL, DataSeg32 - NullSeg
101 .equ TSS_SEL, TssSeg - NullSeg
102 .equ EXCEPTION_TSS_SEL, ExceptionTssSeg - NullSeg
103
104 # IA32 TSS fields
105 .equ TSS_ESP0, 4
106 .equ TSS_SS0, 8
107 .equ TSS_ESP1, 12
108 .equ TSS_SS1, 16
109 .equ TSS_ESP2, 20
110 .equ TSS_SS2, 24
111 .equ TSS_CR3, 28
112 .equ TSS_EIP, 32
113 .equ TSS_EFLAGS, 36
114 .equ TSS_EAX, 40
115 .equ TSS_ECX, 44
116 .equ TSS_EDX, 48
117 .equ TSS_EBX, 52
118 .equ TSS_ESP, 56
119 .equ TSS_EBP, 60
120 .equ TSS_ESI, 64
121 .equ TSS_EDI, 68
122 .equ TSS_ES, 72
123 .equ TSS_CS, 76
124 .equ TSS_SS, 80
125 .equ TSS_DS, 84
126 .equ TSS_FS, 88
127 .equ TSS_GS, 92
128 .equ TSS_LDT, 96
129
130 # Create 2 TSS segments just after GDT
131 TssDescriptor:
132 .word 0 # PreviousTaskLink
133 .word 0 # Reserved
134 .long 0 # ESP0
135 .word 0 # SS0
136 .word 0 # Reserved
137 .long 0 # ESP1
138 .word 0 # SS1
139 .word 0 # Reserved
140 .long 0 # ESP2
141 .word 0 # SS2
142 .word 0 # Reserved
143 .long 0 # CR3
144 .long 0 # EIP
145 .long 0 # EFLAGS
146 .long 0 # EAX
147 .long 0 # ECX
148 .long 0 # EDX
149 .long 0 # EBX
150 .long 0 # ESP
151 .long 0 # EBP
152 .long 0 # ESI
153 .long 0 # EDI
154 .word 0 # ES
155 .word 0 # Reserved
156 .word 0 # CS
157 .word 0 # Reserved
158 .word 0 # SS
159 .word 0 # Reserved
160 .word 0 # DS
161 .word 0 # Reserved
162 .word 0 # FS
163 .word 0 # Reserved
164 .word 0 # GS
165 .word 0 # Reserved
166 .word 0 # LDT Selector
167 .word 0 # Reserved
168 .word 0 # T
169 .word 0 # I/O Map Base
170 .equ TSS_DESC_SIZE, . - TssDescriptor
171
172 ExceptionTssDescriptor:
173 .word 0 # PreviousTaskLink
174 .word 0 # Reserved
175 .long 0 # ESP0
176 .word 0 # SS0
177 .word 0 # Reserved
178 .long 0 # ESP1
179 .word 0 # SS1
180 .word 0 # Reserved
181 .long 0 # ESP2
182 .word 0 # SS2
183 .word 0 # Reserved
184 .long 0 # CR3
185 .long PFHandlerEntry # EIP
186 .long 00000002 # EFLAGS
187 .long 0 # EAX
188 .long 0 # ECX
189 .long 0 # EDX
190 .long 0 # EBX
191 .long 0 # ESP
192 .long 0 # EBP
193 .long 0 # ESI
194 .long 0 # EDI
195 .word DATA_SEL # ES
196 .word 0 # Reserved
197 .word CODE_SEL # CS
198 .word 0 # Reserved
199 .word DATA_SEL # SS
200 .word 0 # Reserved
201 .word DATA_SEL # DS
202 .word 0 # Reserved
203 .word DATA_SEL # FS
204 .word 0 # Reserved
205 .word DATA_SEL # GS
206 .word 0 # Reserved
207 .word 0 # LDT Selector
208 .word 0 # Reserved
209 .word 0 # T
210 .word 0 # I/O Map Base
211
212 ASM_PFX(gcPsd):
213 .ascii "PSDSIG "
214 .word PSD_SIZE
215 .word 2
216 .word 1 << 2
217 .word CODE_SEL
218 .word DATA_SEL
219 .word DATA_SEL
220 .word DATA_SEL
221 .word 0
222 .long 0
223 .long 0
224 .long 0
225 .long 0
226 .quad 0
227 .long NullSeg
228 .long 0
229 .long GDT_SIZE
230 .long 0
231 .space 24, 0
232 .long 0
233 .long 0
234 .equ PSD_SIZE, . - ASM_PFX(gcPsd)
235
236 ASM_PFX(gcSmiGdtr): .word GDT_SIZE - 1
237 .long NullSeg
238
239 ASM_PFX(gcSmiIdtr): .word 0
240 .long 0
241
242 ASM_PFX(gTaskGateDescriptor):
243 .word 0 # Reserved
244 .word EXCEPTION_TSS_SEL # TSS Segment selector
245 .byte 0 # Reserved
246 .byte 0x85 # Task Gate, present, DPL = 0
247 .word 0 # Reserved
248
249 .text
250
251 #------------------------------------------------------------------------------
252 # PageFaultIdtHandlerSmmProfile is the entry point for all exceptions
253 #
254 # Stack:
255 #+---------------------+
256 #+ EFlags +
257 #+---------------------+
258 #+ CS +
259 #+---------------------+
260 #+ EIP +
261 #+---------------------+
262 #+ Error Code +
263 #+---------------------+
264 #+ Vector Number +
265 #+---------------------+
266 #+ EBP +
267 #+---------------------+ <-- EBP
268 #
269 # RSP set to odd multiple of 8 means ErrCode PRESENT
270 #------------------------------------------------------------------------------
271 ASM_GLOBAL ASM_PFX(PageFaultIdtHandlerSmmProfile)
272 ASM_PFX(PageFaultIdtHandlerSmmProfile):
273 pushl $0x0e # Page Fault
274 pushl %ebp
275 movl %esp, %ebp
276
277
278 #
279 # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
280 # is 16-byte aligned
281 #
282 andl $0xfffffff0, %esp
283 subl $12, %esp
284
285 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
286 pushl %eax
287 pushl %ecx
288 pushl %edx
289 pushl %ebx
290 leal (6*4)(%ebp), %ecx
291 pushl %ecx # ESP
292 pushl (%ebp) # EBP
293 pushl %esi
294 pushl %edi
295
296 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
297 movl %ss, %eax
298 pushl %eax
299 movzwl (4*4)(%ebp), %eax
300 pushl %eax
301 movl %ds, %eax
302 pushl %eax
303 movl %es, %eax
304 pushl %eax
305 movl %fs, %eax
306 pushl %eax
307 movl %gs, %eax
308 pushl %eax
309
310 ## UINT32 Eip;
311 movl (3*4)(%ebp), %eax
312 pushl %eax
313
314 ## UINT32 Gdtr[2], Idtr[2];
315 subl $8, %esp
316 sidt (%esp)
317 movl 2(%esp), %eax
318 xchgl (%esp), %eax
319 andl $0xffff, %eax
320 movl %eax, 4(%esp)
321
322 subl $8, %esp
323 sgdt (%esp)
324 movl 2(%esp), %eax
325 xchgl (%esp), %eax
326 andl $0xffff, %eax
327 movl %eax, 4(%esp)
328
329 ## UINT32 Ldtr, Tr;
330 xorl %eax, %eax
331 strw %ax
332 pushl %eax
333 sldtw %ax
334 pushl %eax
335
336 ## UINT32 EFlags;
337 movl (5*4)(%ebp), %eax
338 pushl %eax
339
340 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
341 movl %cr4, %eax
342 orl $0x208, %eax
343 movl %eax, %cr4
344 pushl %eax
345 movl %cr3, %eax
346 pushl %eax
347 movl %cr2, %eax
348 pushl %eax
349 xorl %eax, %eax
350 pushl %eax
351 movl %cr0, %eax
352 pushl %eax
353
354 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
355 movl %dr7, %eax
356 pushl %eax
357 movl %dr6, %eax
358 pushl %eax
359 movl %dr3, %eax
360 pushl %eax
361 movl %dr2, %eax
362 pushl %eax
363 movl %dr1, %eax
364 pushl %eax
365 movl %dr0, %eax
366 pushl %eax
367
368 ## FX_SAVE_STATE_IA32 FxSaveState;
369 subl $512, %esp
370 movl %esp, %edi
371 .byte 0x0f, 0xae, 0x07 #fxsave [edi]
372
373 # UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
374 cld
375
376 ## UINT32 ExceptionData;
377 pushl (2*4)(%ebp)
378
379 ## call into exception handler
380
381 ## Prepare parameter and call
382 movl %esp, %edx
383 pushl %edx
384 movl (1*4)(%ebp), %edx
385 pushl %edx
386
387 #
388 # Call External Exception Handler
389 #
390 movl $ASM_PFX(SmiPFHandler), %eax
391 call *%eax
392 addl $8, %esp
393 jmp L4
394
395 L4:
396 ## UINT32 ExceptionData;
397 addl $4, %esp
398
399 ## FX_SAVE_STATE_IA32 FxSaveState;
400 movl %esp, %esi
401 .byte 0xf, 0xae, 0xe # fxrstor [esi]
402 addl $512, %esp
403
404 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
405 ## Skip restoration of DRx registers to support debuggers
406 ## that set breakpoints in interrupt/exception context
407 addl $4*6, %esp
408
409 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
410 popl %eax
411 movl %eax, %cr0
412 addl $4, %esp # not for Cr1
413 popl %eax
414 movl %eax, %cr2
415 popl %eax
416 movl %eax, %cr3
417 popl %eax
418 movl %eax, %cr4
419
420 ## UINT32 EFlags;
421 popl (5*4)(%ebp)
422
423 ## UINT32 Ldtr, Tr;
424 ## UINT32 Gdtr[2], Idtr[2];
425 ## Best not let anyone mess with these particular registers...
426 addl $24, %esp
427
428 ## UINT32 Eip;
429 popl (3*4)(%ebp)
430
431 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
432 ## NOTE - modified segment registers could hang the debugger... We
433 ## could attempt to insulate ourselves against this possibility,
434 ## but that poses risks as well.
435 ##
436 popl %gs
437 popl %fs
438 popl %es
439 popl %ds
440 popl (4*4)(%ebp)
441 popl %ss
442
443 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
444 popl %edi
445 popl %esi
446 addl $4, %esp # not for ebp
447 addl $4, %esp # not for esp
448 popl %ebx
449 popl %edx
450 popl %ecx
451 popl %eax
452
453 movl %ebp, %esp
454 popl %ebp
455
456 # Enable TF bit after page fault handler runs
457 btsl $8, 16(%esp) # EFLAGS
458
459 addl $8, %esp # skip INT# & ErrCode
460 Return:
461 iret
462 #
463 # Page Fault Exception Handler entry when SMM Stack Guard is enabled
464 # Executiot starts here after a task switch
465 #
466 PFHandlerEntry:
467 #
468 # Get this processor's TSS
469 #
470 subl $8, %esp
471 sgdt 2(%esp)
472 movl 4(%esp), %eax # GDT base
473 addl $8, %esp
474 movl (TSS_SEL+2)(%eax), %ecx
475 shll $8, %ecx
476 movb (TSS_SEL+7)(%eax), %cl
477 rorl $8, %ecx # ecx = TSS base
478
479 movl %esp, %ebp
480
481 #
482 # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
483 # is 16-byte aligned
484 #
485 andl $0xfffffff0, %esp
486 subl $12, %esp
487
488 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
489 pushl TSS_EAX(%ecx)
490 pushl TSS_ECX(%ecx)
491 pushl TSS_EDX(%ecx)
492 pushl TSS_EBX(%ecx)
493 pushl TSS_ESP(%ecx)
494 pushl TSS_EBP(%ecx)
495 pushl TSS_ESI(%ecx)
496 pushl TSS_EDI(%ecx)
497
498 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
499 movzwl TSS_SS(%ecx), %eax
500 pushl %eax
501 movzwl TSS_CS(%ecx), %eax
502 pushl %eax
503 movzwl TSS_DS(%ecx), %eax
504 pushl %eax
505 movzwl TSS_ES(%ecx), %eax
506 pushl %eax
507 movzwl TSS_FS(%ecx), %eax
508 pushl %eax
509 movzwl TSS_GS(%ecx), %eax
510 pushl %eax
511
512 ## UINT32 Eip;
513 pushl TSS_EIP(%ecx)
514
515 ## UINT32 Gdtr[2], Idtr[2];
516 subl $8, %esp
517 sidt (%esp)
518 movl 2(%esp), %eax
519 xchgl (%esp), %eax
520 andl $0xFFFF, %eax
521 movl %eax, 4(%esp)
522
523 subl $8, %esp
524 sgdt (%esp)
525 movl 2(%esp), %eax
526 xchgl (%esp), %eax
527 andl $0xFFFF, %eax
528 movl %eax, 4(%esp)
529
530 ## UINT32 Ldtr, Tr;
531 movl $TSS_SEL, %eax
532 pushl %eax
533 movzwl TSS_LDT(%ecx), %eax
534 pushl %eax
535
536 ## UINT32 EFlags;
537 pushl TSS_EFLAGS(%ecx)
538
539 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
540 movl %cr4, %eax
541 orl $0x208, %eax
542 movl %eax, %cr4
543 pushl %eax
544 movl %cr3, %eax
545 pushl %eax
546 movl %cr2, %eax
547 pushl %eax
548 xorl %eax, %eax
549 pushl %eax
550 movl %cr0, %eax
551 pushl %eax
552
553 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
554 movl %dr7, %eax
555 pushl %eax
556 movl %dr6, %eax
557 pushl %eax
558 movl %dr3, %eax
559 pushl %eax
560 movl %dr2, %eax
561 pushl %eax
562 movl %dr1, %eax
563 pushl %eax
564 movl %dr0, %eax
565 pushl %eax
566
567 ## FX_SAVE_STATE_IA32 FxSaveState;
568 ## Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
569 ## when executing fxsave/fxrstor instruction
570 clts
571 subl $512, %esp
572 movl %esp, %edi
573 .byte 0x0f, 0xae, 0x07 #fxsave [edi]
574
575 # UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
576 cld
577
578 ## UINT32 ExceptionData;
579 pushl (%ebp)
580
581 ## call into exception handler
582 movl %ecx, %ebx
583 movl $ASM_PFX(SmiPFHandler), %eax
584
585 ## Prepare parameter and call
586 movl %esp, %edx
587 pushl %edx
588 movl $14, %edx
589 pushl %edx
590
591 #
592 # Call External Exception Handler
593 #
594 call *%eax
595 addl $8, %esp
596
597 movl %ebx, %ecx
598 ## UINT32 ExceptionData;
599 addl $4, %esp
600
601 ## FX_SAVE_STATE_IA32 FxSaveState;
602 movl %esp, %esi
603 .byte 0xf, 0xae, 0xe # fxrstor [esi]
604 addl $512, %esp
605
606 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
607 ## Skip restoration of DRx registers to support debuggers
608 ## that set breakpoints in interrupt/exception context
609 addl $4*6, %esp
610
611 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
612 popl %eax
613 movl %eax, %cr0
614 addl $4, %esp # not for Cr1
615 popl %eax
616 movl %eax, %cr2
617 popl %eax
618 movl %eax, TSS_CR3(%ecx)
619 popl %eax
620 movl %eax, %cr4
621
622 ## UINT32 EFlags;
623 popl TSS_EFLAGS(%ecx)
624
625 ## UINT32 Ldtr, Tr;
626 ## UINT32 Gdtr[2], Idtr[2];
627 ## Best not let anyone mess with these particular registers...
628 addl $24, %esp
629
630 ## UINT32 Eip;
631 popl TSS_EIP(%ecx)
632
633 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
634 ## NOTE - modified segment registers could hang the debugger... We
635 ## could attempt to insulate ourselves against this possibility,
636 ## but that poses risks as well.
637 ##
638 popl %eax
639 movw %ax, TSS_GS(%ecx)
640 popl %eax
641 movw %ax, TSS_FS(%ecx)
642 popl %eax
643 movw %ax, TSS_ES(%ecx)
644 popl %eax
645 movw %ax, TSS_DS(%ecx)
646 popl %eax
647 movw %ax, TSS_CS(%ecx)
648 popl %eax
649 movw %ax, TSS_SS(%ecx)
650
651 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
652 popl TSS_EDI(%ecx)
653 popl TSS_ESI(%ecx)
654 addl $4, %esp # not for ebp
655 addl $4, %esp # not for esp
656 popl TSS_EBX(%ecx)
657 popl TSS_EDX(%ecx)
658 popl TSS_ECX(%ecx)
659 popl TSS_EAX(%ecx)
660
661 movl %ebp, %esp
662
663 # Set single step DB# if SMM profile is enabled and page fault exception happens
664 cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
665 jz Done2
666 # Create return context for iret in stub function
667 movl TSS_ESP(%ecx), %eax # Get old stack pointer
668 movl TSS_EIP(%ecx), %ebx
669 movl %ebx, -0xc(%eax) # create EIP in old stack
670 movzwl TSS_CS(%ecx), %ebx
671 movl %ebx, -0x8(%eax) # create CS in old stack
672 movl TSS_EFLAGS(%ecx), %ebx
673 btsl $8,%ebx
674 movl %ebx, -0x4(%eax) # create eflags in old stack
675 movl TSS_ESP(%ecx), %eax # Get old stack pointer
676 subl $12, %eax # minus 12 byte
677 movl %eax, TSS_ESP(%ecx) # Set new stack pointer
678
679 # Replace the EIP of interrupted task with stub function
680 movl $ASM_PFX(PageFaultStubFunction), %eax
681 movl %eax, TSS_EIP(%ecx)
682 # Jump to the iret so next page fault handler as a task will start again after iret.
683
684 Done2:
685
686 addl $4, %esp # skip ErrCode
687
688 jmp Return
689
690 ASM_PFX(PageFaultStubFunction):
691 #
692 # we need clean TS bit in CR0 to execute
693 # x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
694 #
695 clts
696 iret