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