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