1 /** @file
2   UEFI MemoryAttributesTable support
3 
4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include <PiDxe.h>
10 #include <Library/BaseLib.h>
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/MemoryAllocationLib.h>
13 #include <Library/UefiBootServicesTableLib.h>
14 #include <Library/DxeServicesTableLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/UefiLib.h>
17 
18 #include <Guid/EventGroup.h>
19 
20 #include <Guid/MemoryAttributesTable.h>
21 #include <Guid/PropertiesTable.h>
22 
23 #include "DxeMain.h"
24 
25 /**
26   This function for GetMemoryMap() with properties table capability.
27 
28   It calls original GetMemoryMap() to get the original memory map information. Then
29   plus the additional memory map entries for PE Code/Data seperation.
30 
31   @param  MemoryMapSize          A pointer to the size, in bytes, of the
32                                  MemoryMap buffer. On input, this is the size of
33                                  the buffer allocated by the caller.  On output,
34                                  it is the size of the buffer returned by the
35                                  firmware  if the buffer was large enough, or the
36                                  size of the buffer needed  to contain the map if
37                                  the buffer was too small.
38   @param  MemoryMap              A pointer to the buffer in which firmware places
39                                  the current memory map.
40   @param  MapKey                 A pointer to the location in which firmware
41                                  returns the key for the current memory map.
42   @param  DescriptorSize         A pointer to the location in which firmware
43                                  returns the size, in bytes, of an individual
44                                  EFI_MEMORY_DESCRIPTOR.
45   @param  DescriptorVersion      A pointer to the location in which firmware
46                                  returns the version number associated with the
47                                  EFI_MEMORY_DESCRIPTOR.
48 
49   @retval EFI_SUCCESS            The memory map was returned in the MemoryMap
50                                  buffer.
51   @retval EFI_BUFFER_TOO_SMALL   The MemoryMap buffer was too small. The current
52                                  buffer size needed to hold the memory map is
53                                  returned in MemoryMapSize.
54   @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value.
55 
56 **/
57 EFI_STATUS
58 EFIAPI
59 CoreGetMemoryMapWithSeparatedImageSection (
60   IN OUT UINTN                  *MemoryMapSize,
61   IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
62   OUT UINTN                     *MapKey,
63   OUT UINTN                     *DescriptorSize,
64   OUT UINT32                    *DescriptorVersion
65   );
66 
67 extern EFI_PROPERTIES_TABLE  mPropertiesTable;
68 EFI_MEMORY_ATTRIBUTES_TABLE  *mMemoryAttributesTable = NULL;
69 BOOLEAN                      mMemoryAttributesTableReadyToBoot = FALSE;
70 
71 /**
72   Install MemoryAttributesTable.
73 
74 **/
75 VOID
InstallMemoryAttributesTable(VOID)76 InstallMemoryAttributesTable (
77   VOID
78   )
79 {
80   UINTN                          MemoryMapSize;
81   EFI_MEMORY_DESCRIPTOR          *MemoryMap;
82   EFI_MEMORY_DESCRIPTOR          *MemoryMapStart;
83   UINTN                          MapKey;
84   UINTN                          DescriptorSize;
85   UINT32                         DescriptorVersion;
86   UINTN                          Index;
87   EFI_STATUS                     Status;
88   UINT32                         RuntimeEntryCount;
89   EFI_MEMORY_ATTRIBUTES_TABLE    *MemoryAttributesTable;
90   EFI_MEMORY_DESCRIPTOR          *MemoryAttributesEntry;
91 
92   if (gMemoryMapTerminated) {
93     //
94     // Directly return after MemoryMap terminated.
95     //
96     return;
97   }
98 
99   if ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {
100     DEBUG ((EFI_D_VERBOSE, "MemoryProtectionAttribute NON_EXECUTABLE_PE_DATA is not set, "));
101     DEBUG ((EFI_D_VERBOSE, "because Runtime Driver Section Alignment is not %dK.\n", RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10));
102     return ;
103   }
104 
105   if (mMemoryAttributesTable == NULL) {
106     //
107     // InstallConfigurationTable here to occupy one entry for MemoryAttributesTable
108     // before GetMemoryMap below, as InstallConfigurationTable may allocate runtime
109     // memory for the new entry.
110     //
111     Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, (VOID *) (UINTN) MAX_ADDRESS);
112     ASSERT_EFI_ERROR (Status);
113   }
114 
115   MemoryMapSize = 0;
116   MemoryMap = NULL;
117   Status = CoreGetMemoryMapWithSeparatedImageSection (
118              &MemoryMapSize,
119              MemoryMap,
120              &MapKey,
121              &DescriptorSize,
122              &DescriptorVersion
123              );
124   ASSERT (Status == EFI_BUFFER_TOO_SMALL);
125 
126   do {
127     MemoryMap = AllocatePool (MemoryMapSize);
128     ASSERT (MemoryMap != NULL);
129 
130     Status = CoreGetMemoryMapWithSeparatedImageSection (
131                &MemoryMapSize,
132                MemoryMap,
133                &MapKey,
134                &DescriptorSize,
135                &DescriptorVersion
136                );
137     if (EFI_ERROR (Status)) {
138       FreePool (MemoryMap);
139     }
140   } while (Status == EFI_BUFFER_TOO_SMALL);
141 
142   MemoryMapStart = MemoryMap;
143   RuntimeEntryCount = 0;
144   for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
145     switch (MemoryMap->Type) {
146     case EfiRuntimeServicesCode:
147     case EfiRuntimeServicesData:
148       RuntimeEntryCount ++;
149       break;
150     }
151     MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
152   }
153 
154   //
155   // Allocate MemoryAttributesTable
156   //
157   MemoryAttributesTable = AllocatePool (sizeof(EFI_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount);
158   ASSERT (MemoryAttributesTable != NULL);
159   MemoryAttributesTable->Version         = EFI_MEMORY_ATTRIBUTES_TABLE_VERSION;
160   MemoryAttributesTable->NumberOfEntries = RuntimeEntryCount;
161   MemoryAttributesTable->DescriptorSize  = (UINT32)DescriptorSize;
162   MemoryAttributesTable->Reserved        = 0;
163   DEBUG ((EFI_D_VERBOSE, "MemoryAttributesTable:\n"));
164   DEBUG ((EFI_D_VERBOSE, "  Version              - 0x%08x\n", MemoryAttributesTable->Version));
165   DEBUG ((EFI_D_VERBOSE, "  NumberOfEntries      - 0x%08x\n", MemoryAttributesTable->NumberOfEntries));
166   DEBUG ((EFI_D_VERBOSE, "  DescriptorSize       - 0x%08x\n", MemoryAttributesTable->DescriptorSize));
167   MemoryAttributesEntry = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1);
168   MemoryMap = MemoryMapStart;
169   for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
170     switch (MemoryMap->Type) {
171     case EfiRuntimeServicesCode:
172     case EfiRuntimeServicesData:
173       CopyMem (MemoryAttributesEntry, MemoryMap, DescriptorSize);
174       MemoryAttributesEntry->Attribute &= (EFI_MEMORY_RO|EFI_MEMORY_XP|EFI_MEMORY_RUNTIME);
175       DEBUG ((EFI_D_VERBOSE, "Entry (0x%x)\n", MemoryAttributesEntry));
176       DEBUG ((EFI_D_VERBOSE, "  Type              - 0x%x\n", MemoryAttributesEntry->Type));
177       DEBUG ((EFI_D_VERBOSE, "  PhysicalStart     - 0x%016lx\n", MemoryAttributesEntry->PhysicalStart));
178       DEBUG ((EFI_D_VERBOSE, "  VirtualStart      - 0x%016lx\n", MemoryAttributesEntry->VirtualStart));
179       DEBUG ((EFI_D_VERBOSE, "  NumberOfPages     - 0x%016lx\n", MemoryAttributesEntry->NumberOfPages));
180       DEBUG ((EFI_D_VERBOSE, "  Attribute         - 0x%016lx\n", MemoryAttributesEntry->Attribute));
181       MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR(MemoryAttributesEntry, DescriptorSize);
182       break;
183     }
184     MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
185   }
186   MemoryMap = MemoryMapStart;
187   FreePool (MemoryMap);
188 
189   //
190   // Update configuratoin table for MemoryAttributesTable.
191   //
192   Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, MemoryAttributesTable);
193   ASSERT_EFI_ERROR (Status);
194 
195   if (mMemoryAttributesTable != NULL) {
196     FreePool (mMemoryAttributesTable);
197   }
198   mMemoryAttributesTable = MemoryAttributesTable;
199 }
200 
201 /**
202   Install MemoryAttributesTable on memory allocation.
203 
204   @param[in] MemoryType EFI memory type.
205 **/
206 VOID
InstallMemoryAttributesTableOnMemoryAllocation(IN EFI_MEMORY_TYPE MemoryType)207 InstallMemoryAttributesTableOnMemoryAllocation (
208   IN EFI_MEMORY_TYPE    MemoryType
209   )
210 {
211   //
212   // Install MemoryAttributesTable after ReadyToBoot on runtime memory allocation.
213   //
214   if (mMemoryAttributesTableReadyToBoot &&
215       ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData))) {
216     InstallMemoryAttributesTable ();
217   }
218 }
219 
220 /**
221   Install MemoryAttributesTable on ReadyToBoot.
222 
223   @param[in] Event      The Event this notify function registered to.
224   @param[in] Context    Pointer to the context data registered to the Event.
225 **/
226 VOID
227 EFIAPI
InstallMemoryAttributesTableOnReadyToBoot(IN EFI_EVENT Event,IN VOID * Context)228 InstallMemoryAttributesTableOnReadyToBoot (
229   IN EFI_EVENT          Event,
230   IN VOID               *Context
231   )
232 {
233   InstallMemoryAttributesTable ();
234   mMemoryAttributesTableReadyToBoot = TRUE;
235 }
236 
237 /**
238   Install initial MemoryAttributesTable on EndOfDxe.
239   Then SMM can consume this information.
240 
241   @param[in] Event      The Event this notify function registered to.
242   @param[in] Context    Pointer to the context data registered to the Event.
243 **/
244 VOID
245 EFIAPI
InstallMemoryAttributesTableOnEndOfDxe(IN EFI_EVENT Event,IN VOID * Context)246 InstallMemoryAttributesTableOnEndOfDxe (
247   IN EFI_EVENT          Event,
248   IN VOID               *Context
249   )
250 {
251   InstallMemoryAttributesTable ();
252 }
253 
254 /**
255   Initialize MemoryAttrubutesTable support.
256 **/
257 VOID
258 EFIAPI
CoreInitializeMemoryAttributesTable(VOID)259 CoreInitializeMemoryAttributesTable (
260   VOID
261   )
262 {
263   EFI_STATUS  Status;
264   EFI_EVENT   ReadyToBootEvent;
265   EFI_EVENT   EndOfDxeEvent;
266 
267   //
268   // Construct the table at ReadyToBoot.
269   //
270   Status = CoreCreateEventInternal (
271              EVT_NOTIFY_SIGNAL,
272              TPL_CALLBACK,
273              InstallMemoryAttributesTableOnReadyToBoot,
274              NULL,
275              &gEfiEventReadyToBootGuid,
276              &ReadyToBootEvent
277              );
278   ASSERT_EFI_ERROR (Status);
279 
280   //
281   // Construct the initial table at EndOfDxe,
282   // then SMM can consume this information.
283   // Use TPL_NOTIFY here, as such SMM code (TPL_CALLBACK)
284   // can run after it.
285   //
286   Status = CoreCreateEventInternal (
287              EVT_NOTIFY_SIGNAL,
288              TPL_NOTIFY,
289              InstallMemoryAttributesTableOnEndOfDxe,
290              NULL,
291              &gEfiEndOfDxeEventGroupGuid,
292              &EndOfDxeEvent
293              );
294   ASSERT_EFI_ERROR (Status);
295   return ;
296 }
297