1 /** @file
2 
3   AMD Sev Dxe driver. This driver is dispatched early in DXE, due to being list
4   in APRIORI. It clears C-bit from MMIO and NonExistent Memory space when SEV
5   is enabled.
6 
7   Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
8 
9   SPDX-License-Identifier: BSD-2-Clause-Patent
10 
11 **/
12 
13 #include <Library/BaseLib.h>
14 #include <Library/BaseMemoryLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/DxeServicesTableLib.h>
17 #include <Library/MemEncryptSevLib.h>
18 #include <Library/MemoryAllocationLib.h>
19 #include <Library/PcdLib.h>
20 
21 EFI_STATUS
22 EFIAPI
AmdSevDxeEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)23 AmdSevDxeEntryPoint (
24   IN EFI_HANDLE         ImageHandle,
25   IN EFI_SYSTEM_TABLE   *SystemTable
26   )
27 {
28   EFI_STATUS                       Status;
29   EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *AllDescMap;
30   UINTN                            NumEntries;
31   UINTN                            Index;
32 
33   //
34   // Do nothing when SEV is not enabled
35   //
36   if (!MemEncryptSevIsEnabled ()) {
37     return EFI_UNSUPPORTED;
38   }
39 
40   //
41   // Iterate through the GCD map and clear the C-bit from MMIO and NonExistent
42   // memory space. The NonExistent memory space will be used for mapping the
43   // MMIO space added later (eg PciRootBridge). By clearing both known MMIO and
44   // NonExistent memory space can gurantee that current and furture MMIO adds
45   // will have C-bit cleared.
46   //
47   Status = gDS->GetMemorySpaceMap (&NumEntries, &AllDescMap);
48   if (!EFI_ERROR (Status)) {
49     for (Index = 0; Index < NumEntries; Index++) {
50       CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;
51 
52       Desc = &AllDescMap[Index];
53       if (Desc->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo ||
54           Desc->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
55         Status = MemEncryptSevClearPageEncMask (
56                    0,
57                    Desc->BaseAddress,
58                    EFI_SIZE_TO_PAGES (Desc->Length),
59                    FALSE
60                    );
61         ASSERT_EFI_ERROR (Status);
62       }
63     }
64 
65     FreePool (AllDescMap);
66   }
67 
68   //
69   // When SMM is enabled, clear the C-bit from SMM Saved State Area
70   //
71   // NOTES: The SavedStateArea address cleared here is before SMBASE
72   // relocation. Currently, we do not clear the SavedStateArea address after
73   // SMBASE is relocated due to the following reasons:
74   //
75   // 1) Guest BIOS never access the relocated SavedStateArea.
76   //
77   // 2) The C-bit works on page-aligned address, but the SavedStateArea
78   // address is not a page-aligned. Theoretically, we could roundup the address
79   // and clear the C-bit of aligned address but looking carefully we found
80   // that some portion of the page contains code -- which will causes a bigger
81   // issues for SEV guest. When SEV is enabled, all the code must be encrypted
82   // otherwise hardware will cause trap.
83   //
84   // We restore the C-bit for this SMM Saved State Area after SMBASE relocation
85   // is completed (See OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c).
86   //
87   if (FeaturePcdGet (PcdSmmSmramRequire)) {
88     UINTN MapPagesBase;
89     UINTN MapPagesCount;
90 
91     Status = MemEncryptSevLocateInitialSmramSaveStateMapPages (
92                &MapPagesBase,
93                &MapPagesCount
94                );
95     ASSERT_EFI_ERROR (Status);
96 
97     //
98     // Although these pages were set aside (i.e., allocated) by PlatformPei, we
99     // could be after a warm reboot from the OS. Don't leak any stale OS data
100     // to the hypervisor.
101     //
102     ZeroMem ((VOID *)MapPagesBase, EFI_PAGES_TO_SIZE (MapPagesCount));
103 
104     Status = MemEncryptSevClearPageEncMask (
105                0,             // Cr3BaseAddress -- use current CR3
106                MapPagesBase,  // BaseAddress
107                MapPagesCount, // NumPages
108                TRUE           // Flush
109                );
110     if (EFI_ERROR (Status)) {
111       DEBUG ((DEBUG_ERROR, "%a: MemEncryptSevClearPageEncMask(): %r\n",
112         __FUNCTION__, Status));
113       ASSERT (FALSE);
114       CpuDeadLoop ();
115     }
116   }
117 
118   return EFI_SUCCESS;
119 }
120