]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Misc / MemoryAttributesTable.c
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
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
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
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
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
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 }