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