VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c@ 89977

Last change on this file since 89977 was 85718, checked in by vboxsync, 5 years ago

Devices/EFI: Merge edk-stable202005 and make it build, bugref:4643

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