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