VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c

Last change on this file was 101291, checked in by vboxsync, 19 months ago

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

  • Property svn:eol-style set to native
File size: 6.7 KB
Line 
1/** @file
2 SMM CPU misc functions for Ia32 arch specific.
3
4Copyright (c) 2015 - 2023, Intel Corporation. All rights reserved.<BR>
5SPDX-License-Identifier: BSD-2-Clause-Patent
6
7**/
8
9#include "PiSmmCpuDxeSmm.h"
10
11extern UINT64 gTaskGateDescriptor;
12
13EFI_PHYSICAL_ADDRESS mGdtBuffer;
14UINTN mGdtBufferSize;
15
16extern BOOLEAN mCetSupported;
17
18X86_ASSEMBLY_PATCH_LABEL mPatchCetPl0Ssp;
19X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSsp;
20UINT32 mCetPl0Ssp;
21UINT32 mCetInterruptSsp;
22
23/**
24 Initialize IDT for SMM Stack Guard.
25
26**/
27VOID
28EFIAPI
29InitializeIDTSmmStackGuard (
30 VOID
31 )
32{
33 IA32_IDT_GATE_DESCRIPTOR *IdtGate;
34
35 //
36 // If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
37 // is a Task Gate Descriptor so that when a Page Fault Exception occurs,
38 // the processors can use a known good stack in case stack is ran out.
39 //
40 IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;
41 IdtGate += EXCEPT_IA32_PAGE_FAULT;
42 IdtGate->Uint64 = gTaskGateDescriptor;
43}
44
45/**
46 Initialize Gdt for all processors.
47
48 @param[in] Cr3 CR3 value.
49 @param[out] GdtStepSize The step size for GDT table.
50
51 @return GdtBase for processor 0.
52 GdtBase for processor X is: GdtBase + (GdtStepSize * X)
53**/
54VOID *
55InitGdt (
56 IN UINTN Cr3,
57 OUT UINTN *GdtStepSize
58 )
59{
60 UINTN Index;
61 IA32_SEGMENT_DESCRIPTOR *GdtDescriptor;
62 UINTN TssBase;
63 UINTN GdtTssTableSize;
64 UINT8 *GdtTssTables;
65 UINTN GdtTableStepSize;
66 UINTN InterruptShadowStack;
67
68 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
69 //
70 // For IA32 SMM, if SMM Stack Guard feature is enabled, we use 2 TSS.
71 // in this case, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention
72 // on each SMI entry.
73 //
74
75 //
76 // Enlarge GDT to contain 2 TSS descriptors
77 //
78 gcSmiGdtr.Limit += (UINT16)(2 * sizeof (IA32_SEGMENT_DESCRIPTOR));
79
80 GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + EXCEPTION_TSS_SIZE + 7) & ~7; // 8 bytes aligned
81 mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
82 //
83 // IA32 Stack Guard need use task switch to switch stack that need
84 // write GDT and TSS, so AllocateCodePages() could not be used here
85 // as code pages will be set to RO.
86 //
87 GdtTssTables = (UINT8 *)AllocatePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));
88 ASSERT (GdtTssTables != NULL);
89 mGdtBuffer = (UINTN)GdtTssTables;
90 GdtTableStepSize = GdtTssTableSize;
91
92 for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
93 CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID *)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE + EXCEPTION_TSS_SIZE);
94 //
95 // Fixup TSS descriptors
96 //
97 TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);
98 GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;
99 GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
100 GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
101 GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
102
103 TssBase += TSS_SIZE;
104 GdtDescriptor++;
105 GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
106 GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
107 GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
108 //
109 // Fixup TSS segments
110 //
111 // ESP as known good stack
112 //
113 *(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) = mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize;
114 *(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = Cr3;
115
116 //
117 // Setup ShadowStack for stack switch
118 //
119 if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {
120 InterruptShadowStack = (UINTN)(mSmmStackArrayBase + mSmmStackSize + EFI_PAGES_TO_SIZE (1) - sizeof (UINT64) + (mSmmStackSize + mSmmShadowStackSize) * Index);
121 *(UINT32 *)(TssBase + TSS_IA32_SSP_OFFSET) = (UINT32)InterruptShadowStack;
122 }
123 }
124 } else {
125 //
126 // Just use original table, AllocatePage and copy them here to make sure GDTs are covered in page memory.
127 //
128 GdtTssTableSize = gcSmiGdtr.Limit + 1;
129 mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
130 GdtTssTables = (UINT8 *)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));
131 ASSERT (GdtTssTables != NULL);
132 mGdtBuffer = (UINTN)GdtTssTables;
133 GdtTableStepSize = GdtTssTableSize;
134
135 for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
136 CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID *)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1);
137 }
138 }
139
140 *GdtStepSize = GdtTableStepSize;
141 return GdtTssTables;
142}
143
144/**
145 Transfer AP to safe hlt-loop after it finished restore CPU features on S3 patch.
146
147 @param[in] ApHltLoopCode The address of the safe hlt-loop function.
148 @param[in] TopOfStack A pointer to the new stack to use for the ApHltLoopCode.
149 @param[in] NumberToFinishAddress Address of Semaphore of APs finish count.
150
151**/
152VOID
153TransferApToSafeState (
154 IN UINTN ApHltLoopCode,
155 IN UINTN TopOfStack,
156 IN UINTN NumberToFinishAddress
157 )
158{
159 SwitchStack (
160 (SWITCH_STACK_ENTRY_POINT)ApHltLoopCode,
161 (VOID *)NumberToFinishAddress,
162 NULL,
163 (VOID *)TopOfStack
164 );
165 //
166 // It should never reach here
167 //
168 ASSERT (FALSE);
169}
170
171/**
172 Initialize the shadow stack related data structure.
173
174 @param CpuIndex The index of CPU.
175 @param ShadowStack The bottom of the shadow stack for this CPU.
176**/
177VOID
178InitShadowStack (
179 IN UINTN CpuIndex,
180 IN VOID *ShadowStack
181 )
182{
183 UINTN SmmShadowStackSize;
184
185 if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {
186 SmmShadowStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize)));
187 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
188 SmmShadowStackSize += EFI_PAGES_TO_SIZE (2);
189 }
190
191 mCetPl0Ssp = (UINT32)((UINTN)ShadowStack + SmmShadowStackSize - sizeof (UINT64));
192 PatchInstructionX86 (mPatchCetPl0Ssp, mCetPl0Ssp, 4);
193 DEBUG ((DEBUG_INFO, "mCetPl0Ssp - 0x%x\n", mCetPl0Ssp));
194 DEBUG ((DEBUG_INFO, "ShadowStack - 0x%x\n", ShadowStack));
195 DEBUG ((DEBUG_INFO, " SmmShadowStackSize - 0x%x\n", SmmShadowStackSize));
196
197 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
198 mCetInterruptSsp = (UINT32)((UINTN)ShadowStack + EFI_PAGES_TO_SIZE (1) - sizeof (UINT64));
199 PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4);
200 DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp));
201 }
202 }
203}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette