TianoCore EDK2 master
Loading...
Searching...
No Matches
Smbase.c
Go to the documentation of this file.
1
9#include <Base.h> // BASE_1MB
10#include <Library/BaseLib.h> // CpuPause()
11#include <Library/BaseMemoryLib.h> // CopyMem()
12#include <Library/DebugLib.h> // DEBUG()
13#include <Library/LocalApicLib.h> // SendInitSipiSipi()
14#include <Library/SynchronizationLib.h> // InterlockedCompareExchange64()
15#include <Register/Intel/SmramSaveStateMap.h> // SMM_DEFAULT_SMBASE
16
17#include "FirstSmiHandlerContext.h" // FIRST_SMI_HANDLER_CONTEXT
18
19#include "Smbase.h"
20
21extern CONST UINT8 mPostSmmPen[];
22extern CONST UINT16 mPostSmmPenSize;
23extern CONST UINT8 mFirstSmiHandler[];
24extern CONST UINT16 mFirstSmiHandlerSize;
25
49 OUT UINT32 *PenAddress,
50 IN CONST EFI_BOOT_SERVICES *BootServices
51 )
52{
53 EFI_STATUS Status;
55
56 //
57 // The pen code must fit in one page, and the last byte must remain free for
58 // signaling the SMM Monarch.
59 //
60 if (mPostSmmPenSize >= EFI_PAGE_SIZE) {
61 Status = EFI_BAD_BUFFER_SIZE;
62 DEBUG ((
63 DEBUG_ERROR,
64 "%a: mPostSmmPenSize=%u: %r\n",
65 __func__,
66 mPostSmmPenSize,
67 Status
68 ));
69 return Status;
70 }
71
72 Address = BASE_1MB - 1;
73 Status = BootServices->AllocatePages (
76 1,
77 &Address
78 );
79 if (EFI_ERROR (Status)) {
80 DEBUG ((DEBUG_ERROR, "%a: AllocatePages(): %r\n", __func__, Status));
81 return Status;
82 }
83
84 DEBUG ((DEBUG_INFO, "%a: Post-SMM Pen at 0x%Lx\n", __func__, Address));
85 *PenAddress = (UINT32)Address;
86 return EFI_SUCCESS;
87}
88
100VOID
102 IN UINT32 PenAddress
103 )
104{
105 CopyMem ((VOID *)(UINTN)PenAddress, mPostSmmPen, mPostSmmPenSize);
106}
107
120VOID
122 IN UINT32 PenAddress,
123 IN CONST EFI_BOOT_SERVICES *BootServices
124 )
125{
126 BootServices->FreePages (PenAddress, 1);
127}
128
140VOID
142 VOID
143 )
144{
146
147 CopyMem (
149 mFirstSmiHandler,
150 mFirstSmiHandlerSize
151 );
152
153 Context = (VOID *)(UINTN)SMM_DEFAULT_SMBASE;
154 Context->ApicIdGate = MAX_UINT64;
155}
156
199 IN APIC_ID ApicId,
200 IN UINTN Smbase,
201 IN UINT32 PenAddress
202 )
203{
204 EFI_STATUS Status;
205 volatile UINT8 *SmmVacated;
206 volatile FIRST_SMI_HANDLER_CONTEXT *Context;
207 UINT64 ExchangeResult;
208
209 if (Smbase > MAX_UINT32) {
210 Status = EFI_INVALID_PARAMETER;
211 DEBUG ((
212 DEBUG_ERROR,
213 "%a: ApicId=" FMT_APIC_ID " Smbase=0x%Lx: %r\n",
214 __func__,
215 ApicId,
216 (UINT64)Smbase,
217 Status
218 ));
219 return Status;
220 }
221
222 SmmVacated = (UINT8 *)(UINTN)PenAddress + (EFI_PAGE_SIZE - 1);
223 Context = (VOID *)(UINTN)SMM_DEFAULT_SMBASE;
224
225 //
226 // Clear AboutToLeaveSmm, so we notice when the hot-added CPU is just about
227 // to reach RSM, and we can proceed to polling the last byte of the reserved
228 // page (which could be attacked by the OS).
229 //
230 Context->AboutToLeaveSmm = 0;
231
232 //
233 // Clear the last byte of the reserved page, so we notice when the hot-added
234 // CPU checks back in from the pen.
235 //
236 *SmmVacated = 0;
237
238 //
239 // Boot the hot-added CPU.
240 //
241 // There are 2*2 cases to consider:
242 //
243 // (1) The CPU was hot-added before the SMI was broadcast.
244 //
245 // (1.1) The OS is benign.
246 //
247 // The hot-added CPU is in RESET state, with the broadcast SMI pending
248 // for it. The directed SMI below will be ignored (it's idempotent),
249 // and the INIT-SIPI-SIPI will launch the CPU directly into SMM.
250 //
251 // (1.2) The OS is malicious.
252 //
253 // The hot-added CPU has been booted, by the OS. Thus, the hot-added
254 // CPU is spinning on the APIC ID gate. In that case, both the SMI and
255 // the INIT-SIPI-SIPI below will be ignored.
256 //
257 // (2) The CPU was hot-added after the SMI was broadcast.
258 //
259 // (2.1) The OS is benign.
260 //
261 // The hot-added CPU is in RESET state, with no SMI pending for it. The
262 // directed SMI will latch the SMI for the CPU. Then the INIT-SIPI-SIPI
263 // will launch the CPU into SMM.
264 //
265 // (2.2) The OS is malicious.
266 //
267 // The hot-added CPU is executing OS code. The directed SMI will pull
268 // the hot-added CPU into SMM, where it will start spinning on the APIC
269 // ID gate. The INIT-SIPI-SIPI will be ignored.
270 //
271 SendSmiIpi (ApicId);
272 SendInitSipiSipi (ApicId, PenAddress);
273
274 //
275 // Expose the desired new SMBASE value to the hot-added CPU.
276 //
277 Context->NewSmbase = (UINT32)Smbase;
278
279 //
280 // Un-gate SMBASE relocation for the hot-added CPU whose APIC ID is ApicId.
281 //
282 ExchangeResult = InterlockedCompareExchange64 (
283 &Context->ApicIdGate,
284 MAX_UINT64,
285 ApicId
286 );
287 if (ExchangeResult != MAX_UINT64) {
288 Status = EFI_PROTOCOL_ERROR;
289 DEBUG ((
290 DEBUG_ERROR,
291 "%a: ApicId=" FMT_APIC_ID " ApicIdGate=0x%Lx: %r\n",
292 __func__,
293 ApicId,
294 ExchangeResult,
295 Status
296 ));
297 return Status;
298 }
299
300 //
301 // Wait until the hot-added CPU is just about to execute RSM.
302 //
303 while (Context->AboutToLeaveSmm == 0) {
304 CpuPause ();
305 }
306
307 //
308 // Now wait until the hot-added CPU reports back from the pen (or the OS
309 // attacks the last byte of the reserved page).
310 //
311 while (*SmmVacated == 0) {
312 CpuPause ();
313 }
314
315 Status = EFI_SUCCESS;
316 return Status;
317}
UINT64 UINTN
VOID EFIAPI CpuPause(VOID)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID EFIAPI SendSmiIpi(IN UINT32 ApicId)
Definition: BaseXApicLib.c:427
VOID EFIAPI SendInitSipiSipi(IN UINT32 ApicId, IN UINT32 StartupRoutine)
Definition: BaseXApicLib.c:541
#define CONST
Definition: Base.h:259
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define SMM_HANDLER_OFFSET
#define SMM_DEFAULT_SMBASE
EFI_STATUS SmbaseAllocatePostSmmPen(OUT UINT32 *PenAddress, IN CONST EFI_BOOT_SERVICES *BootServices)
Definition: Smbase.c:48
VOID SmbaseInstallFirstSmiHandler(VOID)
Definition: Smbase.c:141
VOID SmbaseReinstallPostSmmPen(IN UINT32 PenAddress)
Definition: Smbase.c:101
VOID SmbaseReleasePostSmmPen(IN UINT32 PenAddress, IN CONST EFI_BOOT_SERVICES *BootServices)
Definition: Smbase.c:121
EFI_STATUS SmbaseRelocate(IN APIC_ID ApicId, IN UINTN Smbase, IN UINT32 PenAddress)
Definition: Smbase.c:198
UINT64 EFIAPI InterlockedCompareExchange64(IN OUT volatile UINT64 *Value, IN UINT64 CompareValue, IN UINT64 ExchangeValue)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
@ EfiReservedMemoryType
@ AllocateMaxAddress
Definition: UefiSpec.h:38