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