]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm
6a328289a8af5e60ee7df5d13b61a40be86176de
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / Ia32 / SmiException.nasm
1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2009 - 2015, 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(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 ASM_PFX(gSmiMtrrs)
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 IDT_SIZE - 1
254 DD _SmiIDT
255
256 _SmiIDT:
257 %rep 32
258 DW 0 ; Offset 0:15
259 DW CODE_SEL ; Segment selector
260 DB 0 ; Unused
261 DB 0x8e ; Interrupt Gate, Present
262 DW 0 ; Offset 16:31
263 %endrep
264
265 IDT_SIZE equ $ - _SmiIDT
266
267 TaskGateDescriptor:
268 DW 0 ; Reserved
269 DW EXCEPTION_TSS_SEL ; TSS Segment selector
270 DB 0 ; Reserved
271 DB 0x85 ; Task Gate, present, DPL = 0
272 DW 0 ; Reserved
273
274 SECTION .text
275 ;------------------------------------------------------------------------------
276 ; PageFaultIdtHandlerSmmProfile is the entry point page fault only
277 ;
278 ;
279 ; Stack:
280 ; +---------------------+
281 ; + EFlags +
282 ; +---------------------+
283 ; + CS +
284 ; +---------------------+
285 ; + EIP +
286 ; +---------------------+
287 ; + Error Code +
288 ; +---------------------+
289 ; + Vector Number +
290 ; +---------------------+
291 ; + EBP +
292 ; +---------------------+ <-- EBP
293 ;
294 ;
295 ;------------------------------------------------------------------------------
296 global ASM_PFX(PageFaultIdtHandlerSmmProfile)
297 ASM_PFX(PageFaultIdtHandlerSmmProfile):
298 push 0xe ; Page Fault
299
300 push ebp
301 mov ebp, esp
302
303 ;
304 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
305 ; is 16-byte aligned
306 ;
307 and esp, 0xfffffff0
308 sub esp, 12
309
310 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
311 push eax
312 push ecx
313 push edx
314 push ebx
315 lea ecx, [ebp + 6 * 4]
316 push ecx ; ESP
317 push dword [ebp] ; EBP
318 push esi
319 push edi
320
321 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
322 mov eax, ss
323 push eax
324 movzx eax, word [ebp + 4 * 4]
325 push eax
326 mov eax, ds
327 push eax
328 mov eax, es
329 push eax
330 mov eax, fs
331 push eax
332 mov eax, gs
333 push eax
334
335 ;; UINT32 Eip;
336 mov eax, [ebp + 3 * 4]
337 push eax
338
339 ;; UINT32 Gdtr[2], Idtr[2];
340 sub esp, 8
341 sidt [esp]
342 mov eax, [esp + 2]
343 xchg eax, [esp]
344 and eax, 0xFFFF
345 mov [esp+4], eax
346
347 sub esp, 8
348 sgdt [esp]
349 mov eax, [esp + 2]
350 xchg eax, [esp]
351 and eax, 0xFFFF
352 mov [esp+4], eax
353
354 ;; UINT32 Ldtr, Tr;
355 xor eax, eax
356 str ax
357 push eax
358 sldt ax
359 push eax
360
361 ;; UINT32 EFlags;
362 mov eax, [ebp + 5 * 4]
363 push eax
364
365 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
366 mov eax, cr4
367 or eax, 0x208
368 mov cr4, eax
369 push eax
370 mov eax, cr3
371 push eax
372 mov eax, cr2
373 push eax
374 xor eax, eax
375 push eax
376 mov eax, cr0
377 push eax
378
379 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
380 mov eax, dr7
381 push eax
382 mov eax, dr6
383 push eax
384 mov eax, dr3
385 push eax
386 mov eax, dr2
387 push eax
388 mov eax, dr1
389 push eax
390 mov eax, dr0
391 push eax
392
393 ;; FX_SAVE_STATE_IA32 FxSaveState;
394 sub esp, 512
395 mov edi, esp
396 db 0xf, 0xae, 0x7 ;fxsave [edi]
397
398 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
399 cld
400
401 ;; UINT32 ExceptionData;
402 push dword [ebp + 2 * 4]
403
404 ;; call into exception handler
405
406 ;; Prepare parameter and call
407 mov edx, esp
408 push edx
409 mov edx, dword [ebp + 1 * 4]
410 push edx
411
412 ;
413 ; Call External Exception Handler
414 ;
415 mov eax, ASM_PFX(SmiPFHandler)
416 call eax
417 add esp, 8
418
419 ;; UINT32 ExceptionData;
420 add esp, 4
421
422 ;; FX_SAVE_STATE_IA32 FxSaveState;
423 mov esi, esp
424 db 0xf, 0xae, 0xe ; fxrstor [esi]
425 add esp, 512
426
427 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
428 ;; Skip restoration of DRx registers to support debuggers
429 ;; that set breakpoint in interrupt/exception context
430 add esp, 4 * 6
431
432 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
433 pop eax
434 mov cr0, eax
435 add esp, 4 ; not for Cr1
436 pop eax
437 mov cr2, eax
438 pop eax
439 mov cr3, eax
440 pop eax
441 mov cr4, eax
442
443 ;; UINT32 EFlags;
444 pop dword [ebp + 5 * 4]
445
446 ;; UINT32 Ldtr, Tr;
447 ;; UINT32 Gdtr[2], Idtr[2];
448 ;; Best not let anyone mess with these particular registers...
449 add esp, 24
450
451 ;; UINT32 Eip;
452 pop dword [ebp + 3 * 4]
453
454 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
455 ;; NOTE - modified segment registers could hang the debugger... We
456 ;; could attempt to insulate ourselves against this possibility,
457 ;; but that poses risks as well.
458 ;;
459 pop gs
460 pop fs
461 pop es
462 pop ds
463 pop dword [ebp + 4 * 4]
464 pop ss
465
466 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
467 pop edi
468 pop esi
469 add esp, 4 ; not for ebp
470 add esp, 4 ; not for esp
471 pop ebx
472 pop edx
473 pop ecx
474 pop eax
475
476 mov esp, ebp
477 pop ebp
478
479 ; Enable TF bit after page fault handler runs
480 bts dword [esp + 16], 8 ; EFLAGS
481
482 add esp, 8 ; skip INT# & ErrCode
483 Return:
484 iretd
485 ;
486 ; Page Fault Exception Handler entry when SMM Stack Guard is enabled
487 ; Executiot starts here after a task switch
488 ;
489 PFHandlerEntry:
490 ;
491 ; Get this processor's TSS
492 ;
493 sub esp, 8
494 sgdt [esp + 2]
495 mov eax, [esp + 4] ; GDT base
496 add esp, 8
497 mov ecx, [eax + TSS_SEL + 2]
498 shl ecx, 8
499 mov cl, [eax + TSS_SEL + 7]
500 ror ecx, 8 ; ecx = TSS base
501
502 mov ebp, esp
503
504 ;
505 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
506 ; is 16-byte aligned
507 ;
508 and esp, 0xfffffff0
509 sub esp, 12
510
511 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
512 push dword [ecx + IA32_TSS._EAX]
513 push dword [ecx + IA32_TSS._ECX]
514 push dword [ecx + IA32_TSS._EDX]
515 push dword [ecx + IA32_TSS._EBX]
516 push dword [ecx + IA32_TSS._ESP]
517 push dword [ecx + IA32_TSS._EBP]
518 push dword [ecx + IA32_TSS._ESI]
519 push dword [ecx + IA32_TSS._EDI]
520
521 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
522 movzx eax, word [ecx + IA32_TSS._SS]
523 push eax
524 movzx eax, word [ecx + IA32_TSS._CS]
525 push eax
526 movzx eax, word [ecx + IA32_TSS._DS]
527 push eax
528 movzx eax, word [ecx + IA32_TSS._ES]
529 push eax
530 movzx eax, word [ecx + IA32_TSS._FS]
531 push eax
532 movzx eax, word [ecx + IA32_TSS._GS]
533 push eax
534
535 ;; UINT32 Eip;
536 push dword [ecx + IA32_TSS.EIP]
537
538 ;; UINT32 Gdtr[2], Idtr[2];
539 sub esp, 8
540 sidt [esp]
541 mov eax, [esp + 2]
542 xchg eax, [esp]
543 and eax, 0xFFFF
544 mov [esp+4], eax
545
546 sub esp, 8
547 sgdt [esp]
548 mov eax, [esp + 2]
549 xchg eax, [esp]
550 and eax, 0xFFFF
551 mov [esp+4], eax
552
553 ;; UINT32 Ldtr, Tr;
554 mov eax, TSS_SEL
555 push eax
556 movzx eax, word [ecx + IA32_TSS.LDT]
557 push eax
558
559 ;; UINT32 EFlags;
560 push dword [ecx + IA32_TSS.EFLAGS]
561
562 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
563 mov eax, cr4
564 or eax, 0x208
565 mov cr4, eax
566 push eax
567 mov eax, cr3
568 push eax
569 mov eax, cr2
570 push eax
571 xor eax, eax
572 push eax
573 mov eax, cr0
574 push eax
575
576 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
577 mov eax, dr7
578 push eax
579 mov eax, dr6
580 push eax
581 mov eax, dr3
582 push eax
583 mov eax, dr2
584 push eax
585 mov eax, dr1
586 push eax
587 mov eax, dr0
588 push eax
589
590 ;; FX_SAVE_STATE_IA32 FxSaveState;
591 ;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
592 ;; when executing fxsave/fxrstor instruction
593 clts
594 sub esp, 512
595 mov edi, esp
596 db 0xf, 0xae, 0x7 ;fxsave [edi]
597
598 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
599 cld
600
601 ;; UINT32 ExceptionData;
602 push dword [ebp]
603
604 ;; call into exception handler
605 mov ebx, ecx
606 mov eax, ASM_PFX(SmiPFHandler)
607
608 ;; Prepare parameter and call
609 mov edx, esp
610 push edx
611 mov edx, 14
612 push edx
613
614 ;
615 ; Call External Exception Handler
616 ;
617 call eax
618 add esp, 8
619
620 mov ecx, ebx
621 ;; UINT32 ExceptionData;
622 add esp, 4
623
624 ;; FX_SAVE_STATE_IA32 FxSaveState;
625 mov esi, esp
626 db 0xf, 0xae, 0xe ; fxrstor [esi]
627 add esp, 512
628
629 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
630 ;; Skip restoration of DRx registers to support debuggers
631 ;; that set breakpoints in interrupt/exception context
632 add esp, 4 * 6
633
634 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
635 pop eax
636 mov cr0, eax
637 add esp, 4 ; not for Cr1
638 pop eax
639 mov cr2, eax
640 pop eax
641 mov dword [ecx + IA32_TSS._CR3], eax
642 pop eax
643 mov cr4, eax
644
645 ;; UINT32 EFlags;
646 pop dword [ecx + IA32_TSS.EFLAGS]
647
648 ;; UINT32 Ldtr, Tr;
649 ;; UINT32 Gdtr[2], Idtr[2];
650 ;; Best not let anyone mess with these particular registers...
651 add esp, 24
652
653 ;; UINT32 Eip;
654 pop dword [ecx + IA32_TSS.EIP]
655
656 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
657 ;; NOTE - modified segment registers could hang the debugger... We
658 ;; could attempt to insulate ourselves against this possibility,
659 ;; but that poses risks as well.
660 ;;
661 pop eax
662 o16 mov [ecx + IA32_TSS._GS], ax
663 pop eax
664 o16 mov [ecx + IA32_TSS._FS], ax
665 pop eax
666 o16 mov [ecx + IA32_TSS._ES], ax
667 pop eax
668 o16 mov [ecx + IA32_TSS._DS], ax
669 pop eax
670 o16 mov [ecx + IA32_TSS._CS], ax
671 pop eax
672 o16 mov [ecx + IA32_TSS._SS], ax
673
674 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
675 pop dword [ecx + IA32_TSS._EDI]
676 pop dword [ecx + IA32_TSS._ESI]
677 add esp, 4 ; not for ebp
678 add esp, 4 ; not for esp
679 pop dword [ecx + IA32_TSS._EBX]
680 pop dword [ecx + IA32_TSS._EDX]
681 pop dword [ecx + IA32_TSS._ECX]
682 pop dword [ecx + IA32_TSS._EAX]
683
684 mov esp, ebp
685
686 ; Set single step DB# if SMM profile is enabled and page fault exception happens
687 cmp byte [dword ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))], 0
688 jz @Done2
689
690 ; Create return context for iretd in stub function
691 mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
692 mov ebx, dword [ecx + IA32_TSS.EIP]
693 mov [eax - 0xc], ebx ; create EIP in old stack
694 movzx ebx, word [ecx + IA32_TSS._CS]
695 mov [eax - 0x8], ebx ; create CS in old stack
696 mov ebx, dword [ecx + IA32_TSS.EFLAGS]
697 bts ebx, 8
698 mov [eax - 0x4], ebx ; create eflags in old stack
699 mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
700 sub eax, 0xc ; minus 12 byte
701 mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer
702 ; Replace the EIP of interrupted task with stub function
703 mov eax, ASM_PFX(PageFaultStubFunction)
704 mov dword [ecx + IA32_TSS.EIP], eax
705 ; Jump to the iretd so next page fault handler as a task will start again after iretd.
706 @Done2:
707 add esp, 4 ; skip ErrCode
708
709 jmp Return
710
711 global ASM_PFX(PageFaultStubFunction)
712 ASM_PFX(PageFaultStubFunction):
713 ;
714 ; we need clean TS bit in CR0 to execute
715 ; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
716 ;
717 clts
718 iretd
719
720 global ASM_PFX(InitializeIDTSmmStackGuard)
721 ASM_PFX(InitializeIDTSmmStackGuard):
722 push ebx
723 ;
724 ; If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
725 ; is a Task Gate Descriptor so that when a Page Fault Exception occurrs,
726 ; the processors can use a known good stack in case stack is ran out.
727 ;
728 lea ebx, [_SmiIDT + 14 * 8]
729 lea edx, [TaskGateDescriptor]
730 mov eax, [edx]
731 mov [ebx], eax
732 mov eax, [edx + 4]
733 mov [ebx + 4], eax
734 pop ebx
735 ret