]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / Library / SmmCpuFeaturesLib / SmmCpuFeaturesLib.c
1 /** @file
2 The CPU specific programming for PiSmmCpuDxeSmm module.
3
4 Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8
9 #include <IndustryStandard/Q35MchIch9.h>
10 #include <Library/BaseLib.h>
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/MemEncryptSevLib.h>
14 #include <Library/MemoryAllocationLib.h>
15 #include <Library/PcdLib.h>
16 #include <Library/SafeIntLib.h>
17 #include <Library/SmmCpuFeaturesLib.h>
18 #include <Library/SmmServicesTableLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Pcd/CpuHotEjectData.h>
21 #include <PiSmm.h>
22 #include <Register/Intel/SmramSaveStateMap.h>
23 #include <Register/QemuSmramSaveStateMap.h>
24
25 //
26 // EFER register LMA bit
27 //
28 #define LMA BIT10
29
30 /**
31 The constructor function
32
33 @param[in] ImageHandle The firmware allocated handle for the EFI image.
34 @param[in] SystemTable A pointer to the EFI System Table.
35
36 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
37
38 **/
39 EFI_STATUS
40 EFIAPI
41 SmmCpuFeaturesLibConstructor (
42 IN EFI_HANDLE ImageHandle,
43 IN EFI_SYSTEM_TABLE *SystemTable
44 )
45 {
46 //
47 // No need to program SMRRs on our virtual platform.
48 //
49 return EFI_SUCCESS;
50 }
51
52 /**
53 Called during the very first SMI into System Management Mode to initialize
54 CPU features, including SMBASE, for the currently executing CPU. Since this
55 is the first SMI, the SMRAM Save State Map is at the default address of
56 SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET. The currently executing
57 CPU is specified by CpuIndex and CpuIndex can be used to access information
58 about the currently executing CPU in the ProcessorInfo array and the
59 HotPlugCpuData data structure.
60
61 @param[in] CpuIndex The index of the CPU to initialize. The value
62 must be between 0 and the NumberOfCpus field in
63 the System Management System Table (SMST).
64 @param[in] IsMonarch TRUE if the CpuIndex is the index of the CPU that
65 was elected as monarch during System Management
66 Mode initialization.
67 FALSE if the CpuIndex is not the index of the CPU
68 that was elected as monarch during System
69 Management Mode initialization.
70 @param[in] ProcessorInfo Pointer to an array of EFI_PROCESSOR_INFORMATION
71 structures. ProcessorInfo[CpuIndex] contains the
72 information for the currently executing CPU.
73 @param[in] CpuHotPlugData Pointer to the CPU_HOT_PLUG_DATA structure that
74 contains the ApidId and SmBase arrays.
75 **/
76 VOID
77 EFIAPI
78 SmmCpuFeaturesInitializeProcessor (
79 IN UINTN CpuIndex,
80 IN BOOLEAN IsMonarch,
81 IN EFI_PROCESSOR_INFORMATION *ProcessorInfo,
82 IN CPU_HOT_PLUG_DATA *CpuHotPlugData
83 )
84 {
85 QEMU_SMRAM_SAVE_STATE_MAP *CpuState;
86
87 //
88 // Configure SMBASE.
89 //
90 CpuState = (QEMU_SMRAM_SAVE_STATE_MAP *)(UINTN)(
91 SMM_DEFAULT_SMBASE +
92 SMRAM_SAVE_STATE_MAP_OFFSET
93 );
94 if ((CpuState->x86.SMMRevId & 0xFFFF) == 0) {
95 CpuState->x86.SMBASE = (UINT32)CpuHotPlugData->SmBase[CpuIndex];
96 } else {
97 CpuState->x64.SMBASE = (UINT32)CpuHotPlugData->SmBase[CpuIndex];
98 }
99
100 //
101 // No need to program SMRRs on our virtual platform.
102 //
103 }
104
105 /**
106 This function updates the SMRAM save state on the currently executing CPU
107 to resume execution at a specific address after an RSM instruction. This
108 function must evaluate the SMRAM save state to determine the execution mode
109 the RSM instruction resumes and update the resume execution address with
110 either NewInstructionPointer32 or NewInstructionPoint. The auto HALT restart
111 flag in the SMRAM save state must always be cleared. This function returns
112 the value of the instruction pointer from the SMRAM save state that was
113 replaced. If this function returns 0, then the SMRAM save state was not
114 modified.
115
116 This function is called during the very first SMI on each CPU after
117 SmmCpuFeaturesInitializeProcessor() to set a flag in normal execution mode
118 to signal that the SMBASE of each CPU has been updated before the default
119 SMBASE address is used for the first SMI to the next CPU.
120
121 @param[in] CpuIndex The index of the CPU to hook. The value
122 must be between 0 and the NumberOfCpus
123 field in the System Management System
124 Table (SMST).
125 @param[in] CpuState Pointer to SMRAM Save State Map for the
126 currently executing CPU.
127 @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to
128 32-bit execution mode from 64-bit SMM.
129 @param[in] NewInstructionPointer Instruction pointer to use if resuming to
130 same execution mode as SMM.
131
132 @retval 0 This function did modify the SMRAM save state.
133 @retval > 0 The original instruction pointer value from the SMRAM save state
134 before it was replaced.
135 **/
136 UINT64
137 EFIAPI
138 SmmCpuFeaturesHookReturnFromSmm (
139 IN UINTN CpuIndex,
140 IN SMRAM_SAVE_STATE_MAP *CpuState,
141 IN UINT64 NewInstructionPointer32,
142 IN UINT64 NewInstructionPointer
143 )
144 {
145 UINT64 OriginalInstructionPointer;
146 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;
147
148 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)CpuState;
149 if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) {
150 OriginalInstructionPointer = (UINT64)CpuSaveState->x86._EIP;
151 CpuSaveState->x86._EIP = (UINT32)NewInstructionPointer;
152 //
153 // Clear the auto HALT restart flag so the RSM instruction returns
154 // program control to the instruction following the HLT instruction.
155 //
156 if ((CpuSaveState->x86.AutoHALTRestart & BIT0) != 0) {
157 CpuSaveState->x86.AutoHALTRestart &= ~BIT0;
158 }
159 } else {
160 OriginalInstructionPointer = CpuSaveState->x64._RIP;
161 if ((CpuSaveState->x64.IA32_EFER & LMA) == 0) {
162 CpuSaveState->x64._RIP = (UINT32)NewInstructionPointer32;
163 } else {
164 CpuSaveState->x64._RIP = (UINT32)NewInstructionPointer;
165 }
166
167 //
168 // Clear the auto HALT restart flag so the RSM instruction returns
169 // program control to the instruction following the HLT instruction.
170 //
171 if ((CpuSaveState->x64.AutoHALTRestart & BIT0) != 0) {
172 CpuSaveState->x64.AutoHALTRestart &= ~BIT0;
173 }
174 }
175
176 return OriginalInstructionPointer;
177 }
178
179 STATIC CPU_HOT_EJECT_DATA *mCpuHotEjectData = NULL;
180
181 /**
182 Initialize mCpuHotEjectData if PcdCpuMaxLogicalProcessorNumber > 1.
183
184 Also setup the corresponding PcdCpuHotEjectDataAddress.
185 **/
186 STATIC
187 VOID
188 InitCpuHotEjectData (
189 VOID
190 )
191 {
192 UINTN Size;
193 UINT32 Idx;
194 UINT32 MaxNumberOfCpus;
195 RETURN_STATUS PcdStatus;
196
197 MaxNumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
198 if (MaxNumberOfCpus == 1) {
199 return;
200 }
201
202 //
203 // We allocate CPU_HOT_EJECT_DATA and CPU_HOT_EJECT_DATA->QemuSelectorMap[]
204 // in a single allocation, and explicitly align the QemuSelectorMap[] (which
205 // is a UINT64 array) at its natural boundary.
206 // Accordingly, allocate:
207 // sizeof(*mCpuHotEjectData) + (MaxNumberOfCpus * sizeof(UINT64))
208 // and, add sizeof(UINT64) - 1 to use as padding if needed.
209 //
210
211 if (RETURN_ERROR (SafeUintnMult (MaxNumberOfCpus, sizeof (UINT64), &Size)) ||
212 RETURN_ERROR (SafeUintnAdd (Size, sizeof (*mCpuHotEjectData), &Size)) ||
213 RETURN_ERROR (SafeUintnAdd (Size, sizeof (UINT64) - 1, &Size)))
214 {
215 DEBUG ((DEBUG_ERROR, "%a: invalid CPU_HOT_EJECT_DATA\n", __FUNCTION__));
216 goto Fatal;
217 }
218
219 mCpuHotEjectData = AllocatePool (Size);
220 if (mCpuHotEjectData == NULL) {
221 ASSERT (mCpuHotEjectData != NULL);
222 goto Fatal;
223 }
224
225 mCpuHotEjectData->Handler = NULL;
226 mCpuHotEjectData->ArrayLength = MaxNumberOfCpus;
227
228 mCpuHotEjectData->QemuSelectorMap = ALIGN_POINTER (
229 mCpuHotEjectData + 1,
230 sizeof (UINT64)
231 );
232 //
233 // We use mCpuHotEjectData->QemuSelectorMap to map
234 // ProcessorNum -> QemuSelector. Initialize to invalid values.
235 //
236 for (Idx = 0; Idx < mCpuHotEjectData->ArrayLength; Idx++) {
237 mCpuHotEjectData->QemuSelectorMap[Idx] = CPU_EJECT_QEMU_SELECTOR_INVALID;
238 }
239
240 //
241 // Expose address of CPU Hot eject Data structure
242 //
243 PcdStatus = PcdSet64S (
244 PcdCpuHotEjectDataAddress,
245 (UINTN)(VOID *)mCpuHotEjectData
246 );
247 ASSERT_RETURN_ERROR (PcdStatus);
248
249 return;
250
251 Fatal:
252 CpuDeadLoop ();
253 }
254
255 /**
256 Hook point in normal execution mode that allows the one CPU that was elected
257 as monarch during System Management Mode initialization to perform additional
258 initialization actions immediately after all of the CPUs have processed their
259 first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE
260 into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm().
261 **/
262 VOID
263 EFIAPI
264 SmmCpuFeaturesSmmRelocationComplete (
265 VOID
266 )
267 {
268 EFI_STATUS Status;
269 UINTN MapPagesBase;
270 UINTN MapPagesCount;
271
272 InitCpuHotEjectData ();
273
274 if (!MemEncryptSevIsEnabled ()) {
275 return;
276 }
277
278 //
279 // Now that SMBASE relocation is complete, re-encrypt the original SMRAM save
280 // state map's container pages, and release the pages to DXE. (The pages were
281 // allocated in PlatformPei.)
282 //
283 Status = MemEncryptSevLocateInitialSmramSaveStateMapPages (
284 &MapPagesBase,
285 &MapPagesCount
286 );
287 ASSERT_EFI_ERROR (Status);
288
289 Status = MemEncryptSevSetPageEncMask (
290 0, // Cr3BaseAddress -- use current CR3
291 MapPagesBase, // BaseAddress
292 MapPagesCount // NumPages
293 );
294 if (EFI_ERROR (Status)) {
295 DEBUG ((
296 DEBUG_ERROR,
297 "%a: MemEncryptSevSetPageEncMask(): %r\n",
298 __FUNCTION__,
299 Status
300 ));
301 ASSERT (FALSE);
302 CpuDeadLoop ();
303 }
304
305 ZeroMem ((VOID *)MapPagesBase, EFI_PAGES_TO_SIZE (MapPagesCount));
306
307 if (PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {
308 //
309 // The initial SMRAM Save State Map has been covered as part of a larger
310 // reserved memory allocation in PlatformPei's InitializeRamRegions(). That
311 // allocation is supposed to survive into OS runtime; we must not release
312 // any part of it. Only re-assert the containment here.
313 //
314 ASSERT (SMM_DEFAULT_SMBASE <= MapPagesBase);
315 ASSERT (
316 (MapPagesBase + EFI_PAGES_TO_SIZE (MapPagesCount) <=
317 SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE)
318 );
319 } else {
320 Status = gBS->FreePages (MapPagesBase, MapPagesCount);
321 ASSERT_EFI_ERROR (Status);
322 }
323 }
324
325 /**
326 Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
327 returned, then a custom SMI handler is not provided by this library,
328 and the default SMI handler must be used.
329
330 @retval 0 Use the default SMI handler.
331 @retval > 0 Use the SMI handler installed by
332 SmmCpuFeaturesInstallSmiHandler(). The caller is required to
333 allocate enough SMRAM for each CPU to support the size of the
334 custom SMI handler.
335 **/
336 UINTN
337 EFIAPI
338 SmmCpuFeaturesGetSmiHandlerSize (
339 VOID
340 )
341 {
342 return 0;
343 }
344
345 /**
346 Install a custom SMI handler for the CPU specified by CpuIndex. This
347 function is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size
348 is greater than zero and is called by the CPU that was elected as monarch
349 during System Management Mode initialization.
350
351 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
352 The value must be between 0 and the NumberOfCpus field
353 in the System Management System Table (SMST).
354 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
355 @param[in] SmiStack The stack to use when an SMI is processed by the
356 the CPU specified by CpuIndex.
357 @param[in] StackSize The size, in bytes, if the stack used when an SMI is
358 processed by the CPU specified by CpuIndex.
359 @param[in] GdtBase The base address of the GDT to use when an SMI is
360 processed by the CPU specified by CpuIndex.
361 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
362 processed by the CPU specified by CpuIndex.
363 @param[in] IdtBase The base address of the IDT to use when an SMI is
364 processed by the CPU specified by CpuIndex.
365 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
366 processed by the CPU specified by CpuIndex.
367 @param[in] Cr3 The base address of the page tables to use when an SMI
368 is processed by the CPU specified by CpuIndex.
369 **/
370 VOID
371 EFIAPI
372 SmmCpuFeaturesInstallSmiHandler (
373 IN UINTN CpuIndex,
374 IN UINT32 SmBase,
375 IN VOID *SmiStack,
376 IN UINTN StackSize,
377 IN UINTN GdtBase,
378 IN UINTN GdtSize,
379 IN UINTN IdtBase,
380 IN UINTN IdtSize,
381 IN UINT32 Cr3
382 )
383 {
384 }
385
386 /**
387 Determines if MTRR registers must be configured to set SMRAM cache-ability
388 when executing in System Management Mode.
389
390 @retval TRUE MTRR registers must be configured to set SMRAM cache-ability.
391 @retval FALSE MTRR registers do not need to be configured to set SMRAM
392 cache-ability.
393 **/
394 BOOLEAN
395 EFIAPI
396 SmmCpuFeaturesNeedConfigureMtrrs (
397 VOID
398 )
399 {
400 return FALSE;
401 }
402
403 /**
404 Disable SMRR register if SMRR is supported and
405 SmmCpuFeaturesNeedConfigureMtrrs() returns TRUE.
406 **/
407 VOID
408 EFIAPI
409 SmmCpuFeaturesDisableSmrr (
410 VOID
411 )
412 {
413 //
414 // No SMRR support, nothing to do
415 //
416 }
417
418 /**
419 Enable SMRR register if SMRR is supported and
420 SmmCpuFeaturesNeedConfigureMtrrs() returns TRUE.
421 **/
422 VOID
423 EFIAPI
424 SmmCpuFeaturesReenableSmrr (
425 VOID
426 )
427 {
428 //
429 // No SMRR support, nothing to do
430 //
431 }
432
433 /**
434 Processor specific hook point each time a CPU enters System Management Mode.
435
436 @param[in] CpuIndex The index of the CPU that has entered SMM. The value
437 must be between 0 and the NumberOfCpus field in the
438 System Management System Table (SMST).
439 **/
440 VOID
441 EFIAPI
442 SmmCpuFeaturesRendezvousEntry (
443 IN UINTN CpuIndex
444 )
445 {
446 //
447 // No SMRR support, nothing to do
448 //
449 }
450
451 /**
452 Processor specific hook point each time a CPU exits System Management Mode.
453
454 @param[in] CpuIndex The index of the CPU that is exiting SMM. The value
455 must be between 0 and the NumberOfCpus field in the
456 System Management System Table (SMST).
457 **/
458 VOID
459 EFIAPI
460 SmmCpuFeaturesRendezvousExit (
461 IN UINTN CpuIndex
462 )
463 {
464 //
465 // We only call the Handler if CPU hot-eject is enabled
466 // (PcdCpuMaxLogicalProcessorNumber > 1), and hot-eject is needed
467 // in this SMI exit (otherwise mCpuHotEjectData->Handler is not armed.)
468 //
469
470 if (mCpuHotEjectData != NULL) {
471 CPU_HOT_EJECT_HANDLER Handler;
472
473 //
474 // As the comment above mentions, mCpuHotEjectData->Handler might be
475 // written to on the BSP as part of handling of the CPU-ejection.
476 //
477 // We know that any initial assignment to mCpuHotEjectData->Handler
478 // (on the BSP, in the CpuHotplugMmi() context) is ordered-before the
479 // load below, since it is guaranteed to happen before the
480 // control-dependency of the BSP's SMI exit signal -- by way of a store
481 // to AllCpusInSync (on the BSP, in BspHandler()) and the corresponding
482 // AllCpusInSync loop (on the APs, in SmiRendezvous()) which depends on
483 // that store.
484 //
485 // This guarantees that these pieces of code can never execute
486 // simultaneously. In addition, we ensure that the following load is
487 // ordered-after the AllCpusInSync loop by using a MemoryFence() with
488 // acquire semantics.
489 //
490 MemoryFence ();
491
492 Handler = mCpuHotEjectData->Handler;
493
494 if (Handler != NULL) {
495 Handler (CpuIndex);
496 }
497 }
498 }
499
500 /**
501 Check to see if an SMM register is supported by a specified CPU.
502
503 @param[in] CpuIndex The index of the CPU to check for SMM register support.
504 The value must be between 0 and the NumberOfCpus field
505 in the System Management System Table (SMST).
506 @param[in] RegName Identifies the SMM register to check for support.
507
508 @retval TRUE The SMM register specified by RegName is supported by the CPU
509 specified by CpuIndex.
510 @retval FALSE The SMM register specified by RegName is not supported by the
511 CPU specified by CpuIndex.
512 **/
513 BOOLEAN
514 EFIAPI
515 SmmCpuFeaturesIsSmmRegisterSupported (
516 IN UINTN CpuIndex,
517 IN SMM_REG_NAME RegName
518 )
519 {
520 ASSERT (RegName == SmmRegFeatureControl);
521 return FALSE;
522 }
523
524 /**
525 Returns the current value of the SMM register for the specified CPU.
526 If the SMM register is not supported, then 0 is returned.
527
528 @param[in] CpuIndex The index of the CPU to read the SMM register. The
529 value must be between 0 and the NumberOfCpus field in
530 the System Management System Table (SMST).
531 @param[in] RegName Identifies the SMM register to read.
532
533 @return The value of the SMM register specified by RegName from the CPU
534 specified by CpuIndex.
535 **/
536 UINT64
537 EFIAPI
538 SmmCpuFeaturesGetSmmRegister (
539 IN UINTN CpuIndex,
540 IN SMM_REG_NAME RegName
541 )
542 {
543 //
544 // This is called for SmmRegSmmDelayed, SmmRegSmmBlocked, SmmRegSmmEnable.
545 // The last of these should actually be SmmRegSmmDisable, so we can just
546 // return FALSE.
547 //
548 return 0;
549 }
550
551 /**
552 Sets the value of an SMM register on a specified CPU.
553 If the SMM register is not supported, then no action is performed.
554
555 @param[in] CpuIndex The index of the CPU to write the SMM register. The
556 value must be between 0 and the NumberOfCpus field in
557 the System Management System Table (SMST).
558 @param[in] RegName Identifies the SMM register to write.
559 registers are read-only.
560 @param[in] Value The value to write to the SMM register.
561 **/
562 VOID
563 EFIAPI
564 SmmCpuFeaturesSetSmmRegister (
565 IN UINTN CpuIndex,
566 IN SMM_REG_NAME RegName,
567 IN UINT64 Value
568 )
569 {
570 ASSERT (FALSE);
571 }
572
573 ///
574 /// Macro used to simplify the lookup table entries of type
575 /// CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
576 ///
577 #define SMM_CPU_OFFSET(Field) OFFSET_OF (QEMU_SMRAM_SAVE_STATE_MAP, Field)
578
579 ///
580 /// Macro used to simplify the lookup table entries of type
581 /// CPU_SMM_SAVE_STATE_REGISTER_RANGE
582 ///
583 #define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }
584
585 ///
586 /// Structure used to describe a range of registers
587 ///
588 typedef struct {
589 EFI_SMM_SAVE_STATE_REGISTER Start;
590 EFI_SMM_SAVE_STATE_REGISTER End;
591 UINTN Length;
592 } CPU_SMM_SAVE_STATE_REGISTER_RANGE;
593
594 ///
595 /// Structure used to build a lookup table to retrieve the widths and offsets
596 /// associated with each supported EFI_SMM_SAVE_STATE_REGISTER value
597 ///
598
599 #define SMM_SAVE_STATE_REGISTER_FIRST_INDEX 1
600
601 typedef struct {
602 UINT8 Width32;
603 UINT8 Width64;
604 UINT16 Offset32;
605 UINT16 Offset64Lo;
606 UINT16 Offset64Hi;
607 BOOLEAN Writeable;
608 } CPU_SMM_SAVE_STATE_LOOKUP_ENTRY;
609
610 ///
611 /// Table used by GetRegisterIndex() to convert an EFI_SMM_SAVE_STATE_REGISTER
612 /// value to an index into a table of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
613 ///
614 STATIC CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges[] = {
615 SMM_REGISTER_RANGE (
616 EFI_SMM_SAVE_STATE_REGISTER_GDTBASE,
617 EFI_SMM_SAVE_STATE_REGISTER_LDTINFO
618 ),
619 SMM_REGISTER_RANGE (
620 EFI_SMM_SAVE_STATE_REGISTER_ES,
621 EFI_SMM_SAVE_STATE_REGISTER_RIP
622 ),
623 SMM_REGISTER_RANGE (
624 EFI_SMM_SAVE_STATE_REGISTER_RFLAGS,
625 EFI_SMM_SAVE_STATE_REGISTER_CR4
626 ),
627 { (EFI_SMM_SAVE_STATE_REGISTER)0, (EFI_SMM_SAVE_STATE_REGISTER)0,0 }
628 };
629
630 ///
631 /// Lookup table used to retrieve the widths and offsets associated with each
632 /// supported EFI_SMM_SAVE_STATE_REGISTER value
633 ///
634 STATIC CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset[] = {
635 {
636 0, // Width32
637 0, // Width64
638 0, // Offset32
639 0, // Offset64Lo
640 0, // Offset64Hi
641 FALSE // Writeable
642 }, // Reserved
643
644 //
645 // CPU Save State registers defined in PI SMM CPU Protocol.
646 //
647 {
648 0, // Width32
649 8, // Width64
650 0, // Offset32
651 SMM_CPU_OFFSET (x64._GDTRBase), // Offset64Lo
652 SMM_CPU_OFFSET (x64._GDTRBase) + 4, // Offset64Hi
653 FALSE // Writeable
654 }, // EFI_SMM_SAVE_STATE_REGISTER_GDTBASE = 4
655
656 {
657 0, // Width32
658 8, // Width64
659 0, // Offset32
660 SMM_CPU_OFFSET (x64._IDTRBase), // Offset64Lo
661 SMM_CPU_OFFSET (x64._IDTRBase) + 4, // Offset64Hi
662 FALSE // Writeable
663 }, // EFI_SMM_SAVE_STATE_REGISTER_IDTBASE = 5
664
665 {
666 0, // Width32
667 8, // Width64
668 0, // Offset32
669 SMM_CPU_OFFSET (x64._LDTRBase), // Offset64Lo
670 SMM_CPU_OFFSET (x64._LDTRBase) + 4, // Offset64Hi
671 FALSE // Writeable
672 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTBASE = 6
673
674 {
675 0, // Width32
676 0, // Width64
677 0, // Offset32
678 SMM_CPU_OFFSET (x64._GDTRLimit), // Offset64Lo
679 SMM_CPU_OFFSET (x64._GDTRLimit) + 4, // Offset64Hi
680 FALSE // Writeable
681 }, // EFI_SMM_SAVE_STATE_REGISTER_GDTLIMIT = 7
682
683 {
684 0, // Width32
685 0, // Width64
686 0, // Offset32
687 SMM_CPU_OFFSET (x64._IDTRLimit), // Offset64Lo
688 SMM_CPU_OFFSET (x64._IDTRLimit) + 4, // Offset64Hi
689 FALSE // Writeable
690 }, // EFI_SMM_SAVE_STATE_REGISTER_IDTLIMIT = 8
691
692 {
693 0, // Width32
694 0, // Width64
695 0, // Offset32
696 SMM_CPU_OFFSET (x64._LDTRLimit), // Offset64Lo
697 SMM_CPU_OFFSET (x64._LDTRLimit) + 4, // Offset64Hi
698 FALSE // Writeable
699 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTLIMIT = 9
700
701 {
702 0, // Width32
703 0, // Width64
704 0, // Offset32
705 0, // Offset64Lo
706 0 + 4, // Offset64Hi
707 FALSE // Writeable
708 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTINFO = 10
709
710 {
711 4, // Width32
712 4, // Width64
713 SMM_CPU_OFFSET (x86._ES), // Offset32
714 SMM_CPU_OFFSET (x64._ES), // Offset64Lo
715 0, // Offset64Hi
716 FALSE // Writeable
717 }, // EFI_SMM_SAVE_STATE_REGISTER_ES = 20
718
719 {
720 4, // Width32
721 4, // Width64
722 SMM_CPU_OFFSET (x86._CS), // Offset32
723 SMM_CPU_OFFSET (x64._CS), // Offset64Lo
724 0, // Offset64Hi
725 FALSE // Writeable
726 }, // EFI_SMM_SAVE_STATE_REGISTER_CS = 21
727
728 {
729 4, // Width32
730 4, // Width64
731 SMM_CPU_OFFSET (x86._SS), // Offset32
732 SMM_CPU_OFFSET (x64._SS), // Offset64Lo
733 0, // Offset64Hi
734 FALSE // Writeable
735 }, // EFI_SMM_SAVE_STATE_REGISTER_SS = 22
736
737 {
738 4, // Width32
739 4, // Width64
740 SMM_CPU_OFFSET (x86._DS), // Offset32
741 SMM_CPU_OFFSET (x64._DS), // Offset64Lo
742 0, // Offset64Hi
743 FALSE // Writeable
744 }, // EFI_SMM_SAVE_STATE_REGISTER_DS = 23
745
746 {
747 4, // Width32
748 4, // Width64
749 SMM_CPU_OFFSET (x86._FS), // Offset32
750 SMM_CPU_OFFSET (x64._FS), // Offset64Lo
751 0, // Offset64Hi
752 FALSE // Writeable
753 }, // EFI_SMM_SAVE_STATE_REGISTER_FS = 24
754
755 {
756 4, // Width32
757 4, // Width64
758 SMM_CPU_OFFSET (x86._GS), // Offset32
759 SMM_CPU_OFFSET (x64._GS), // Offset64Lo
760 0, // Offset64Hi
761 FALSE // Writeable
762 }, // EFI_SMM_SAVE_STATE_REGISTER_GS = 25
763
764 {
765 0, // Width32
766 4, // Width64
767 0, // Offset32
768 SMM_CPU_OFFSET (x64._LDTR), // Offset64Lo
769 0, // Offset64Hi
770 FALSE // Writeable
771 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTR_SEL = 26
772
773 {
774 4, // Width32
775 4, // Width64
776 SMM_CPU_OFFSET (x86._TR), // Offset32
777 SMM_CPU_OFFSET (x64._TR), // Offset64Lo
778 0, // Offset64Hi
779 FALSE // Writeable
780 }, // EFI_SMM_SAVE_STATE_REGISTER_TR_SEL = 27
781
782 {
783 4, // Width32
784 8, // Width64
785 SMM_CPU_OFFSET (x86._DR7), // Offset32
786 SMM_CPU_OFFSET (x64._DR7), // Offset64Lo
787 SMM_CPU_OFFSET (x64._DR7) + 4, // Offset64Hi
788 FALSE // Writeable
789 }, // EFI_SMM_SAVE_STATE_REGISTER_DR7 = 28
790
791 {
792 4, // Width32
793 8, // Width64
794 SMM_CPU_OFFSET (x86._DR6), // Offset32
795 SMM_CPU_OFFSET (x64._DR6), // Offset64Lo
796 SMM_CPU_OFFSET (x64._DR6) + 4, // Offset64Hi
797 FALSE // Writeable
798 }, // EFI_SMM_SAVE_STATE_REGISTER_DR6 = 29
799
800 {
801 0, // Width32
802 8, // Width64
803 0, // Offset32
804 SMM_CPU_OFFSET (x64._R8), // Offset64Lo
805 SMM_CPU_OFFSET (x64._R8) + 4, // Offset64Hi
806 TRUE // Writeable
807 }, // EFI_SMM_SAVE_STATE_REGISTER_R8 = 30
808
809 {
810 0, // Width32
811 8, // Width64
812 0, // Offset32
813 SMM_CPU_OFFSET (x64._R9), // Offset64Lo
814 SMM_CPU_OFFSET (x64._R9) + 4, // Offset64Hi
815 TRUE // Writeable
816 }, // EFI_SMM_SAVE_STATE_REGISTER_R9 = 31
817
818 {
819 0, // Width32
820 8, // Width64
821 0, // Offset32
822 SMM_CPU_OFFSET (x64._R10), // Offset64Lo
823 SMM_CPU_OFFSET (x64._R10) + 4, // Offset64Hi
824 TRUE // Writeable
825 }, // EFI_SMM_SAVE_STATE_REGISTER_R10 = 32
826
827 {
828 0, // Width32
829 8, // Width64
830 0, // Offset32
831 SMM_CPU_OFFSET (x64._R11), // Offset64Lo
832 SMM_CPU_OFFSET (x64._R11) + 4, // Offset64Hi
833 TRUE // Writeable
834 }, // EFI_SMM_SAVE_STATE_REGISTER_R11 = 33
835
836 {
837 0, // Width32
838 8, // Width64
839 0, // Offset32
840 SMM_CPU_OFFSET (x64._R12), // Offset64Lo
841 SMM_CPU_OFFSET (x64._R12) + 4, // Offset64Hi
842 TRUE // Writeable
843 }, // EFI_SMM_SAVE_STATE_REGISTER_R12 = 34
844
845 {
846 0, // Width32
847 8, // Width64
848 0, // Offset32
849 SMM_CPU_OFFSET (x64._R13), // Offset64Lo
850 SMM_CPU_OFFSET (x64._R13) + 4, // Offset64Hi
851 TRUE // Writeable
852 }, // EFI_SMM_SAVE_STATE_REGISTER_R13 = 35
853
854 {
855 0, // Width32
856 8, // Width64
857 0, // Offset32
858 SMM_CPU_OFFSET (x64._R14), // Offset64Lo
859 SMM_CPU_OFFSET (x64._R14) + 4, // Offset64Hi
860 TRUE // Writeable
861 }, // EFI_SMM_SAVE_STATE_REGISTER_R14 = 36
862
863 {
864 0, // Width32
865 8, // Width64
866 0, // Offset32
867 SMM_CPU_OFFSET (x64._R15), // Offset64Lo
868 SMM_CPU_OFFSET (x64._R15) + 4, // Offset64Hi
869 TRUE // Writeable
870 }, // EFI_SMM_SAVE_STATE_REGISTER_R15 = 37
871
872 {
873 4, // Width32
874 8, // Width64
875 SMM_CPU_OFFSET (x86._EAX), // Offset32
876 SMM_CPU_OFFSET (x64._RAX), // Offset64Lo
877 SMM_CPU_OFFSET (x64._RAX) + 4, // Offset64Hi
878 TRUE // Writeable
879 }, // EFI_SMM_SAVE_STATE_REGISTER_RAX = 38
880
881 {
882 4, // Width32
883 8, // Width64
884 SMM_CPU_OFFSET (x86._EBX), // Offset32
885 SMM_CPU_OFFSET (x64._RBX), // Offset64Lo
886 SMM_CPU_OFFSET (x64._RBX) + 4, // Offset64Hi
887 TRUE // Writeable
888 }, // EFI_SMM_SAVE_STATE_REGISTER_RBX = 39
889
890 {
891 4, // Width32
892 8, // Width64
893 SMM_CPU_OFFSET (x86._ECX), // Offset32
894 SMM_CPU_OFFSET (x64._RCX), // Offset64Lo
895 SMM_CPU_OFFSET (x64._RCX) + 4, // Offset64Hi
896 TRUE // Writeable
897 }, // EFI_SMM_SAVE_STATE_REGISTER_RCX = 40
898
899 {
900 4, // Width32
901 8, // Width64
902 SMM_CPU_OFFSET (x86._EDX), // Offset32
903 SMM_CPU_OFFSET (x64._RDX), // Offset64Lo
904 SMM_CPU_OFFSET (x64._RDX) + 4, // Offset64Hi
905 TRUE // Writeable
906 }, // EFI_SMM_SAVE_STATE_REGISTER_RDX = 41
907
908 {
909 4, // Width32
910 8, // Width64
911 SMM_CPU_OFFSET (x86._ESP), // Offset32
912 SMM_CPU_OFFSET (x64._RSP), // Offset64Lo
913 SMM_CPU_OFFSET (x64._RSP) + 4, // Offset64Hi
914 TRUE // Writeable
915 }, // EFI_SMM_SAVE_STATE_REGISTER_RSP = 42
916
917 {
918 4, // Width32
919 8, // Width64
920 SMM_CPU_OFFSET (x86._EBP), // Offset32
921 SMM_CPU_OFFSET (x64._RBP), // Offset64Lo
922 SMM_CPU_OFFSET (x64._RBP) + 4, // Offset64Hi
923 TRUE // Writeable
924 }, // EFI_SMM_SAVE_STATE_REGISTER_RBP = 43
925
926 {
927 4, // Width32
928 8, // Width64
929 SMM_CPU_OFFSET (x86._ESI), // Offset32
930 SMM_CPU_OFFSET (x64._RSI), // Offset64Lo
931 SMM_CPU_OFFSET (x64._RSI) + 4, // Offset64Hi
932 TRUE // Writeable
933 }, // EFI_SMM_SAVE_STATE_REGISTER_RSI = 44
934
935 {
936 4, // Width32
937 8, // Width64
938 SMM_CPU_OFFSET (x86._EDI), // Offset32
939 SMM_CPU_OFFSET (x64._RDI), // Offset64Lo
940 SMM_CPU_OFFSET (x64._RDI) + 4, // Offset64Hi
941 TRUE // Writeable
942 }, // EFI_SMM_SAVE_STATE_REGISTER_RDI = 45
943
944 {
945 4, // Width32
946 8, // Width64
947 SMM_CPU_OFFSET (x86._EIP), // Offset32
948 SMM_CPU_OFFSET (x64._RIP), // Offset64Lo
949 SMM_CPU_OFFSET (x64._RIP) + 4, // Offset64Hi
950 TRUE // Writeable
951 }, // EFI_SMM_SAVE_STATE_REGISTER_RIP = 46
952
953 {
954 4, // Width32
955 8, // Width64
956 SMM_CPU_OFFSET (x86._EFLAGS), // Offset32
957 SMM_CPU_OFFSET (x64._RFLAGS), // Offset64Lo
958 SMM_CPU_OFFSET (x64._RFLAGS) + 4, // Offset64Hi
959 TRUE // Writeable
960 }, // EFI_SMM_SAVE_STATE_REGISTER_RFLAGS = 51
961
962 {
963 4, // Width32
964 8, // Width64
965 SMM_CPU_OFFSET (x86._CR0), // Offset32
966 SMM_CPU_OFFSET (x64._CR0), // Offset64Lo
967 SMM_CPU_OFFSET (x64._CR0) + 4, // Offset64Hi
968 FALSE // Writeable
969 }, // EFI_SMM_SAVE_STATE_REGISTER_CR0 = 52
970
971 {
972 4, // Width32
973 8, // Width64
974 SMM_CPU_OFFSET (x86._CR3), // Offset32
975 SMM_CPU_OFFSET (x64._CR3), // Offset64Lo
976 SMM_CPU_OFFSET (x64._CR3) + 4, // Offset64Hi
977 FALSE // Writeable
978 }, // EFI_SMM_SAVE_STATE_REGISTER_CR3 = 53
979
980 {
981 0, // Width32
982 4, // Width64
983 0, // Offset32
984 SMM_CPU_OFFSET (x64._CR4), // Offset64Lo
985 SMM_CPU_OFFSET (x64._CR4) + 4, // Offset64Hi
986 FALSE // Writeable
987 }, // EFI_SMM_SAVE_STATE_REGISTER_CR4 = 54
988 };
989
990 //
991 // No support for I/O restart
992 //
993
994 /**
995 Read information from the CPU save state.
996
997 @param Register Specifies the CPU register to read form the save state.
998
999 @retval 0 Register is not valid
1000 @retval >0 Index into mSmmCpuWidthOffset[] associated with Register
1001
1002 **/
1003 STATIC
1004 UINTN
1005 GetRegisterIndex (
1006 IN EFI_SMM_SAVE_STATE_REGISTER Register
1007 )
1008 {
1009 UINTN Index;
1010 UINTN Offset;
1011
1012 for (Index = 0, Offset = SMM_SAVE_STATE_REGISTER_FIRST_INDEX;
1013 mSmmCpuRegisterRanges[Index].Length != 0;
1014 Index++)
1015 {
1016 if ((Register >= mSmmCpuRegisterRanges[Index].Start) &&
1017 (Register <= mSmmCpuRegisterRanges[Index].End))
1018 {
1019 return Register - mSmmCpuRegisterRanges[Index].Start + Offset;
1020 }
1021
1022 Offset += mSmmCpuRegisterRanges[Index].Length;
1023 }
1024
1025 return 0;
1026 }
1027
1028 /**
1029 Read a CPU Save State register on the target processor.
1030
1031 This function abstracts the differences that whether the CPU Save State
1032 register is in the IA32 CPU Save State Map or X64 CPU Save State Map.
1033
1034 This function supports reading a CPU Save State register in SMBase relocation
1035 handler.
1036
1037 @param[in] CpuIndex Specifies the zero-based index of the CPU save
1038 state.
1039 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
1040 @param[in] Width The number of bytes to read from the CPU save
1041 state.
1042 @param[out] Buffer Upon return, this holds the CPU register value
1043 read from the save state.
1044
1045 @retval EFI_SUCCESS The register was read from Save State.
1046 @retval EFI_NOT_FOUND The register is not defined for the Save State
1047 of Processor.
1048 @retval EFI_INVALID_PARAMTER This or Buffer is NULL.
1049
1050 **/
1051 STATIC
1052 EFI_STATUS
1053 ReadSaveStateRegisterByIndex (
1054 IN UINTN CpuIndex,
1055 IN UINTN RegisterIndex,
1056 IN UINTN Width,
1057 OUT VOID *Buffer
1058 )
1059 {
1060 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;
1061
1062 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex];
1063
1064 if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) {
1065 //
1066 // If 32-bit mode width is zero, then the specified register can not be
1067 // accessed
1068 //
1069 if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {
1070 return EFI_NOT_FOUND;
1071 }
1072
1073 //
1074 // If Width is bigger than the 32-bit mode width, then the specified
1075 // register can not be accessed
1076 //
1077 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {
1078 return EFI_INVALID_PARAMETER;
1079 }
1080
1081 //
1082 // Write return buffer
1083 //
1084 ASSERT (CpuSaveState != NULL);
1085 CopyMem (
1086 Buffer,
1087 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32,
1088 Width
1089 );
1090 } else {
1091 //
1092 // If 64-bit mode width is zero, then the specified register can not be
1093 // accessed
1094 //
1095 if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {
1096 return EFI_NOT_FOUND;
1097 }
1098
1099 //
1100 // If Width is bigger than the 64-bit mode width, then the specified
1101 // register can not be accessed
1102 //
1103 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {
1104 return EFI_INVALID_PARAMETER;
1105 }
1106
1107 //
1108 // Write lower 32-bits of return buffer
1109 //
1110 CopyMem (
1111 Buffer,
1112 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo,
1113 MIN (4, Width)
1114 );
1115 if (Width >= 4) {
1116 //
1117 // Write upper 32-bits of return buffer
1118 //
1119 CopyMem (
1120 (UINT8 *)Buffer + 4,
1121 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi,
1122 Width - 4
1123 );
1124 }
1125 }
1126
1127 return EFI_SUCCESS;
1128 }
1129
1130 /**
1131 Read an SMM Save State register on the target processor. If this function
1132 returns EFI_UNSUPPORTED, then the caller is responsible for reading the
1133 SMM Save Sate register.
1134
1135 @param[in] CpuIndex The index of the CPU to read the SMM Save State. The
1136 value must be between 0 and the NumberOfCpus field in
1137 the System Management System Table (SMST).
1138 @param[in] Register The SMM Save State register to read.
1139 @param[in] Width The number of bytes to read from the CPU save state.
1140 @param[out] Buffer Upon return, this holds the CPU register value read
1141 from the save state.
1142
1143 @retval EFI_SUCCESS The register was read from Save State.
1144 @retval EFI_INVALID_PARAMTER Buffer is NULL.
1145 @retval EFI_UNSUPPORTED This function does not support reading
1146 Register.
1147 **/
1148 EFI_STATUS
1149 EFIAPI
1150 SmmCpuFeaturesReadSaveStateRegister (
1151 IN UINTN CpuIndex,
1152 IN EFI_SMM_SAVE_STATE_REGISTER Register,
1153 IN UINTN Width,
1154 OUT VOID *Buffer
1155 )
1156 {
1157 UINTN RegisterIndex;
1158 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;
1159
1160 //
1161 // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA
1162 //
1163 if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {
1164 //
1165 // Only byte access is supported for this register
1166 //
1167 if (Width != 1) {
1168 return EFI_INVALID_PARAMETER;
1169 }
1170
1171 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex];
1172
1173 //
1174 // Check CPU mode
1175 //
1176 if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) {
1177 *(UINT8 *)Buffer = 32;
1178 } else {
1179 *(UINT8 *)Buffer = 64;
1180 }
1181
1182 return EFI_SUCCESS;
1183 }
1184
1185 //
1186 // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO
1187 //
1188 if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {
1189 return EFI_NOT_FOUND;
1190 }
1191
1192 //
1193 // Convert Register to a register lookup table index. Let
1194 // PiSmmCpuDxeSmm implement other special registers (currently
1195 // there is only EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID).
1196 //
1197 RegisterIndex = GetRegisterIndex (Register);
1198 if (RegisterIndex == 0) {
1199 return (Register < EFI_SMM_SAVE_STATE_REGISTER_IO ?
1200 EFI_NOT_FOUND :
1201 EFI_UNSUPPORTED);
1202 }
1203
1204 return ReadSaveStateRegisterByIndex (CpuIndex, RegisterIndex, Width, Buffer);
1205 }
1206
1207 /**
1208 Writes an SMM Save State register on the target processor. If this function
1209 returns EFI_UNSUPPORTED, then the caller is responsible for writing the
1210 SMM Save Sate register.
1211
1212 @param[in] CpuIndex The index of the CPU to write the SMM Save State. The
1213 value must be between 0 and the NumberOfCpus field in
1214 the System Management System Table (SMST).
1215 @param[in] Register The SMM Save State register to write.
1216 @param[in] Width The number of bytes to write to the CPU save state.
1217 @param[in] Buffer Upon entry, this holds the new CPU register value.
1218
1219 @retval EFI_SUCCESS The register was written to Save State.
1220 @retval EFI_INVALID_PARAMTER Buffer is NULL.
1221 @retval EFI_UNSUPPORTED This function does not support writing
1222 Register.
1223 **/
1224 EFI_STATUS
1225 EFIAPI
1226 SmmCpuFeaturesWriteSaveStateRegister (
1227 IN UINTN CpuIndex,
1228 IN EFI_SMM_SAVE_STATE_REGISTER Register,
1229 IN UINTN Width,
1230 IN CONST VOID *Buffer
1231 )
1232 {
1233 UINTN RegisterIndex;
1234 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;
1235
1236 //
1237 // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored
1238 //
1239 if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {
1240 return EFI_SUCCESS;
1241 }
1242
1243 //
1244 // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported
1245 //
1246 if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {
1247 return EFI_NOT_FOUND;
1248 }
1249
1250 //
1251 // Convert Register to a register lookup table index. Let
1252 // PiSmmCpuDxeSmm implement other special registers (currently
1253 // there is only EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID).
1254 //
1255 RegisterIndex = GetRegisterIndex (Register);
1256 if (RegisterIndex == 0) {
1257 return (Register < EFI_SMM_SAVE_STATE_REGISTER_IO ?
1258 EFI_NOT_FOUND :
1259 EFI_UNSUPPORTED);
1260 }
1261
1262 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex];
1263
1264 //
1265 // Do not write non-writable SaveState, because it will cause exception.
1266 //
1267 if (!mSmmCpuWidthOffset[RegisterIndex].Writeable) {
1268 return EFI_UNSUPPORTED;
1269 }
1270
1271 //
1272 // Check CPU mode
1273 //
1274 if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) {
1275 //
1276 // If 32-bit mode width is zero, then the specified register can not be
1277 // accessed
1278 //
1279 if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {
1280 return EFI_NOT_FOUND;
1281 }
1282
1283 //
1284 // If Width is bigger than the 32-bit mode width, then the specified
1285 // register can not be accessed
1286 //
1287 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {
1288 return EFI_INVALID_PARAMETER;
1289 }
1290
1291 //
1292 // Write SMM State register
1293 //
1294 ASSERT (CpuSaveState != NULL);
1295 CopyMem (
1296 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32,
1297 Buffer,
1298 Width
1299 );
1300 } else {
1301 //
1302 // If 64-bit mode width is zero, then the specified register can not be
1303 // accessed
1304 //
1305 if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {
1306 return EFI_NOT_FOUND;
1307 }
1308
1309 //
1310 // If Width is bigger than the 64-bit mode width, then the specified
1311 // register can not be accessed
1312 //
1313 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {
1314 return EFI_INVALID_PARAMETER;
1315 }
1316
1317 //
1318 // Write lower 32-bits of SMM State register
1319 //
1320 CopyMem (
1321 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo,
1322 Buffer,
1323 MIN (4, Width)
1324 );
1325 if (Width >= 4) {
1326 //
1327 // Write upper 32-bits of SMM State register
1328 //
1329 CopyMem (
1330 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi,
1331 (UINT8 *)Buffer + 4,
1332 Width - 4
1333 );
1334 }
1335 }
1336
1337 return EFI_SUCCESS;
1338 }
1339
1340 /**
1341 This function is hook point called after the gEfiSmmReadyToLockProtocolGuid
1342 notification is completely processed.
1343 **/
1344 VOID
1345 EFIAPI
1346 SmmCpuFeaturesCompleteSmmReadyToLock (
1347 VOID
1348 )
1349 {
1350 }
1351
1352 /**
1353 This API provides a method for a CPU to allocate a specific region for
1354 storing page tables.
1355
1356 This API can be called more once to allocate memory for page tables.
1357
1358 Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns
1359 a pointer to the allocated buffer. The buffer returned is aligned on a 4KB
1360 boundary. If Pages is 0, then NULL is returned. If there is not enough
1361 memory remaining to satisfy the request, then NULL is returned.
1362
1363 This function can also return NULL if there is no preference on where the
1364 page tables are allocated in SMRAM.
1365
1366 @param Pages The number of 4 KB pages to allocate.
1367
1368 @return A pointer to the allocated buffer for page tables.
1369 @retval NULL Fail to allocate a specific region for storing page tables,
1370 Or there is no preference on where the page tables are
1371 allocated in SMRAM.
1372
1373 **/
1374 VOID *
1375 EFIAPI
1376 SmmCpuFeaturesAllocatePageTableMemory (
1377 IN UINTN Pages
1378 )
1379 {
1380 return NULL;
1381 }