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