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