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