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