]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/SmmMemLib/SmmMemLib.c
MdePkg: Apply uncrustify changes
[mirror_edk2.git] / MdePkg / Library / SmmMemLib / SmmMemLib.c
CommitLineData
d425764e
JY
1/** @file\r
2 Instance of SMM memory check library.\r
3\r
4 SMM memory check library library implementation. This library consumes SMM_ACCESS2_PROTOCOL\r
5 to get SMRAM information. In order to use this library instance, the platform should produce\r
6 all SMRAM range via SMM_ACCESS2_PROTOCOL, including the range for firmware (like SMM Core\r
7 and SMM driver) and/or specific dedicated hardware.\r
8\r
9095d37b 9 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
9344f092 10 SPDX-License-Identifier: BSD-2-Clause-Patent\r
d425764e
JY
11\r
12**/\r
13\r
d425764e
JY
14#include <PiSmm.h>\r
15\r
16#include <Library/BaseLib.h>\r
17#include <Library/BaseMemoryLib.h>\r
18#include <Library/DebugLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/UefiBootServicesTableLib.h>\r
233ffa90 21#include <Library/DxeServicesTableLib.h>\r
d425764e 22#include <Library/SmmServicesTableLib.h>\r
68096272 23#include <Library/UefiLib.h>\r
d425764e
JY
24#include <Library/HobLib.h>\r
25#include <Protocol/SmmAccess2.h>\r
91f51fcc
JY
26#include <Protocol/SmmReadyToLock.h>\r
27#include <Protocol/SmmEndOfDxe.h>\r
68096272 28#include <Guid/MemoryAttributesTable.h>\r
91f51fcc 29\r
233ffa90
JY
30//\r
31// attributes for reserved memory before it is promoted to system memory\r
32//\r
33#define EFI_MEMORY_PRESENT 0x0100000000000000ULL\r
34#define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL\r
35#define EFI_MEMORY_TESTED 0x0400000000000000ULL\r
36\r
2f88bd3a
MK
37EFI_SMRAM_DESCRIPTOR *mSmmMemLibInternalSmramRanges;\r
38UINTN mSmmMemLibInternalSmramCount;\r
d425764e
JY
39\r
40//\r
41// Maximum support address used to check input buffer\r
42//\r
43EFI_PHYSICAL_ADDRESS mSmmMemLibInternalMaximumSupportAddress = 0;\r
44\r
2f88bd3a
MK
45UINTN mMemoryMapEntryCount;\r
46EFI_MEMORY_DESCRIPTOR *mMemoryMap;\r
47UINTN mDescriptorSize;\r
91f51fcc 48\r
2f88bd3a
MK
49EFI_GCD_MEMORY_SPACE_DESCRIPTOR *mSmmMemLibGcdMemSpace = NULL;\r
50UINTN mSmmMemLibGcdMemNumberOfDesc = 0;\r
233ffa90 51\r
68096272
JY
52EFI_MEMORY_ATTRIBUTES_TABLE *mSmmMemLibMemoryAttributesTable = NULL;\r
53\r
2f88bd3a
MK
54VOID *mRegistrationEndOfDxe;\r
55VOID *mRegistrationReadyToLock;\r
91f51fcc 56\r
2f88bd3a 57BOOLEAN mSmmMemLibSmmReadyToLock = FALSE;\r
91f51fcc 58\r
d425764e 59/**\r
2a93f2c3 60 Calculate and save the maximum support address.\r
d425764e
JY
61\r
62**/\r
63VOID\r
2a93f2c3 64SmmMemLibInternalCalculateMaximumSupportAddress (\r
d425764e
JY
65 VOID\r
66 )\r
67{\r
2f88bd3a
MK
68 VOID *Hob;\r
69 UINT32 RegEax;\r
70 UINT8 PhysicalAddressBits;\r
d425764e
JY
71\r
72 //\r
73 // Get physical address bits supported.\r
74 //\r
75 Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
76 if (Hob != NULL) {\r
2f88bd3a 77 PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;\r
d425764e
JY
78 } else {\r
79 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
80 if (RegEax >= 0x80000008) {\r
81 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
2f88bd3a 82 PhysicalAddressBits = (UINT8)RegEax;\r
d425764e
JY
83 } else {\r
84 PhysicalAddressBits = 36;\r
85 }\r
86 }\r
2f88bd3a 87\r
d425764e
JY
88 //\r
89 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.\r
90 //\r
91 ASSERT (PhysicalAddressBits <= 52);\r
92 if (PhysicalAddressBits > 48) {\r
93 PhysicalAddressBits = 48;\r
94 }\r
9095d37b 95\r
d425764e 96 //\r
9095d37b 97 // Save the maximum support address in one global variable\r
d425764e
JY
98 //\r
99 mSmmMemLibInternalMaximumSupportAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)(LShiftU64 (1, PhysicalAddressBits) - 1);\r
5f289f3a 100 DEBUG ((DEBUG_INFO, "mSmmMemLibInternalMaximumSupportAddress = 0x%lx\n", mSmmMemLibInternalMaximumSupportAddress));\r
d425764e
JY
101}\r
102\r
103/**\r
104 This function check if the buffer is valid per processor architecture and not overlap with SMRAM.\r
105\r
106 @param Buffer The buffer start address to be checked.\r
107 @param Length The buffer length to be checked.\r
108\r
109 @retval TRUE This buffer is valid per processor architecture and not overlap with SMRAM.\r
110 @retval FALSE This buffer is not valid per processor architecture or overlap with SMRAM.\r
111**/\r
112BOOLEAN\r
113EFIAPI\r
114SmmIsBufferOutsideSmmValid (\r
115 IN EFI_PHYSICAL_ADDRESS Buffer,\r
116 IN UINT64 Length\r
117 )\r
118{\r
119 UINTN Index;\r
9095d37b 120\r
d425764e
JY
121 //\r
122 // Check override.\r
123 // NOTE: (B:0->L:4G) is invalid for IA32, but (B:1->L:4G-1)/(B:4G-1->L:1) is valid.\r
124 //\r
125 if ((Length > mSmmMemLibInternalMaximumSupportAddress) ||\r
126 (Buffer > mSmmMemLibInternalMaximumSupportAddress) ||\r
2f88bd3a
MK
127 ((Length != 0) && (Buffer > (mSmmMemLibInternalMaximumSupportAddress - (Length - 1)))))\r
128 {\r
d425764e
JY
129 //\r
130 // Overflow happen\r
131 //\r
132 DEBUG ((\r
5f289f3a 133 DEBUG_ERROR,\r
d425764e
JY
134 "SmmIsBufferOutsideSmmValid: Overflow: Buffer (0x%lx) - Length (0x%lx), MaximumSupportAddress (0x%lx)\n",\r
135 Buffer,\r
136 Length,\r
137 mSmmMemLibInternalMaximumSupportAddress\r
138 ));\r
139 return FALSE;\r
140 }\r
9095d37b 141\r
2f88bd3a 142 for (Index = 0; Index < mSmmMemLibInternalSmramCount; Index++) {\r
d425764e 143 if (((Buffer >= mSmmMemLibInternalSmramRanges[Index].CpuStart) && (Buffer < mSmmMemLibInternalSmramRanges[Index].CpuStart + mSmmMemLibInternalSmramRanges[Index].PhysicalSize)) ||\r
2f88bd3a
MK
144 ((mSmmMemLibInternalSmramRanges[Index].CpuStart >= Buffer) && (mSmmMemLibInternalSmramRanges[Index].CpuStart < Buffer + Length)))\r
145 {\r
d425764e 146 DEBUG ((\r
5f289f3a 147 DEBUG_ERROR,\r
d425764e
JY
148 "SmmIsBufferOutsideSmmValid: Overlap: Buffer (0x%lx) - Length (0x%lx), ",\r
149 Buffer,\r
150 Length\r
151 ));\r
152 DEBUG ((\r
5f289f3a 153 DEBUG_ERROR,\r
d425764e
JY
154 "CpuStart (0x%lx) - PhysicalSize (0x%lx)\n",\r
155 mSmmMemLibInternalSmramRanges[Index].CpuStart,\r
156 mSmmMemLibInternalSmramRanges[Index].PhysicalSize\r
157 ));\r
158 return FALSE;\r
159 }\r
160 }\r
161\r
91f51fcc
JY
162 //\r
163 // Check override for Valid Communication Region\r
164 //\r
233ffa90 165 if (mSmmMemLibSmmReadyToLock) {\r
2f88bd3a
MK
166 EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
167 BOOLEAN InValidCommunicationRegion;\r
9095d37b 168\r
91f51fcc 169 InValidCommunicationRegion = FALSE;\r
2f88bd3a 170 MemoryMap = mMemoryMap;\r
91f51fcc
JY
171 for (Index = 0; Index < mMemoryMapEntryCount; Index++) {\r
172 if ((Buffer >= MemoryMap->PhysicalStart) &&\r
2f88bd3a
MK
173 (Buffer + Length <= MemoryMap->PhysicalStart + LShiftU64 (MemoryMap->NumberOfPages, EFI_PAGE_SHIFT)))\r
174 {\r
91f51fcc
JY
175 InValidCommunicationRegion = TRUE;\r
176 }\r
2f88bd3a
MK
177\r
178 MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, mDescriptorSize);\r
91f51fcc
JY
179 }\r
180\r
181 if (!InValidCommunicationRegion) {\r
182 DEBUG ((\r
5f289f3a 183 DEBUG_ERROR,\r
233ffa90 184 "SmmIsBufferOutsideSmmValid: Not in ValidCommunicationRegion: Buffer (0x%lx) - Length (0x%lx)\n",\r
91f51fcc
JY
185 Buffer,\r
186 Length\r
187 ));\r
91f51fcc
JY
188 return FALSE;\r
189 }\r
233ffa90
JY
190\r
191 //\r
192 // Check untested memory as invalid communication buffer.\r
193 //\r
194 for (Index = 0; Index < mSmmMemLibGcdMemNumberOfDesc; Index++) {\r
195 if (((Buffer >= mSmmMemLibGcdMemSpace[Index].BaseAddress) && (Buffer < mSmmMemLibGcdMemSpace[Index].BaseAddress + mSmmMemLibGcdMemSpace[Index].Length)) ||\r
2f88bd3a
MK
196 ((mSmmMemLibGcdMemSpace[Index].BaseAddress >= Buffer) && (mSmmMemLibGcdMemSpace[Index].BaseAddress < Buffer + Length)))\r
197 {\r
233ffa90 198 DEBUG ((\r
5f289f3a 199 DEBUG_ERROR,\r
233ffa90
JY
200 "SmmIsBufferOutsideSmmValid: In Untested Memory Region: Buffer (0x%lx) - Length (0x%lx)\n",\r
201 Buffer,\r
202 Length\r
203 ));\r
204 return FALSE;\r
205 }\r
206 }\r
68096272
JY
207\r
208 //\r
209 // Check UEFI runtime memory with EFI_MEMORY_RO as invalid communication buffer.\r
210 //\r
211 if (mSmmMemLibMemoryAttributesTable != NULL) {\r
2f88bd3a 212 EFI_MEMORY_DESCRIPTOR *Entry;\r
68096272
JY
213\r
214 Entry = (EFI_MEMORY_DESCRIPTOR *)(mSmmMemLibMemoryAttributesTable + 1);\r
215 for (Index = 0; Index < mSmmMemLibMemoryAttributesTable->NumberOfEntries; Index++) {\r
2f88bd3a 216 if ((Entry->Type == EfiRuntimeServicesCode) || (Entry->Type == EfiRuntimeServicesData)) {\r
68096272
JY
217 if ((Entry->Attribute & EFI_MEMORY_RO) != 0) {\r
218 if (((Buffer >= Entry->PhysicalStart) && (Buffer < Entry->PhysicalStart + LShiftU64 (Entry->NumberOfPages, EFI_PAGE_SHIFT))) ||\r
2f88bd3a
MK
219 ((Entry->PhysicalStart >= Buffer) && (Entry->PhysicalStart < Buffer + Length)))\r
220 {\r
68096272 221 DEBUG ((\r
5f289f3a 222 DEBUG_ERROR,\r
68096272
JY
223 "SmmIsBufferOutsideSmmValid: In RuntimeCode Region: Buffer (0x%lx) - Length (0x%lx)\n",\r
224 Buffer,\r
225 Length\r
226 ));\r
227 return FALSE;\r
228 }\r
229 }\r
230 }\r
2f88bd3a 231\r
68096272
JY
232 Entry = NEXT_MEMORY_DESCRIPTOR (Entry, mSmmMemLibMemoryAttributesTable->DescriptorSize);\r
233 }\r
234 }\r
91f51fcc 235 }\r
2f88bd3a 236\r
d425764e
JY
237 return TRUE;\r
238}\r
239\r
240/**\r
241 Copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).\r
242\r
243 This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).\r
244 It checks if source buffer is valid per processor architecture and not overlap with SMRAM.\r
245 If the check passes, it copies memory and returns EFI_SUCCESS.\r
246 If the check fails, it return EFI_SECURITY_VIOLATION.\r
247 The implementation must be reentrant.\r
248\r
249 @param DestinationBuffer The pointer to the destination buffer of the memory copy.\r
250 @param SourceBuffer The pointer to the source buffer of the memory copy.\r
251 @param Length The number of bytes to copy from SourceBuffer to DestinationBuffer.\r
252\r
253 @retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with SMRAM.\r
254 @retval EFI_SUCCESS Memory is copied.\r
255\r
256**/\r
257EFI_STATUS\r
258EFIAPI\r
259SmmCopyMemToSmram (\r
260 OUT VOID *DestinationBuffer,\r
261 IN CONST VOID *SourceBuffer,\r
262 IN UINTN Length\r
263 )\r
264{\r
265 if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) {\r
5f289f3a 266 DEBUG ((DEBUG_ERROR, "SmmCopyMemToSmram: Security Violation: Source (0x%x), Length (0x%x)\n", SourceBuffer, Length));\r
d425764e
JY
267 return EFI_SECURITY_VIOLATION;\r
268 }\r
2f88bd3a 269\r
d425764e
JY
270 CopyMem (DestinationBuffer, SourceBuffer, Length);\r
271 return EFI_SUCCESS;\r
272}\r
273\r
274/**\r
275 Copies a source buffer (SMRAM) to a destination buffer (NON-SMRAM).\r
276\r
277 This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).\r
278 It checks if destination buffer is valid per processor architecture and not overlap with SMRAM.\r
279 If the check passes, it copies memory and returns EFI_SUCCESS.\r
280 If the check fails, it returns EFI_SECURITY_VIOLATION.\r
281 The implementation must be reentrant.\r
9095d37b 282\r
d425764e
JY
283 @param DestinationBuffer The pointer to the destination buffer of the memory copy.\r
284 @param SourceBuffer The pointer to the source buffer of the memory copy.\r
285 @param Length The number of bytes to copy from SourceBuffer to DestinationBuffer.\r
286\r
fae43d06 287 @retval EFI_SECURITY_VIOLATION The DestinationBuffer is invalid per processor architecture or overlap with SMRAM.\r
d425764e
JY
288 @retval EFI_SUCCESS Memory is copied.\r
289\r
290**/\r
291EFI_STATUS\r
292EFIAPI\r
293SmmCopyMemFromSmram (\r
294 OUT VOID *DestinationBuffer,\r
295 IN CONST VOID *SourceBuffer,\r
296 IN UINTN Length\r
297 )\r
298{\r
299 if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) {\r
5f289f3a 300 DEBUG ((DEBUG_ERROR, "SmmCopyMemFromSmram: Security Violation: Destination (0x%x), Length (0x%x)\n", DestinationBuffer, Length));\r
d425764e
JY
301 return EFI_SECURITY_VIOLATION;\r
302 }\r
2f88bd3a 303\r
d425764e
JY
304 CopyMem (DestinationBuffer, SourceBuffer, Length);\r
305 return EFI_SUCCESS;\r
306}\r
307\r
308/**\r
309 Copies a source buffer (NON-SMRAM) to a destination buffer (NON-SMRAM).\r
310\r
311 This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).\r
312 It checks if source buffer and destination buffer are valid per processor architecture and not overlap with SMRAM.\r
313 If the check passes, it copies memory and returns EFI_SUCCESS.\r
314 If the check fails, it returns EFI_SECURITY_VIOLATION.\r
315 The implementation must be reentrant, and it must handle the case where source buffer overlaps destination buffer.\r
9095d37b 316\r
d425764e
JY
317 @param DestinationBuffer The pointer to the destination buffer of the memory copy.\r
318 @param SourceBuffer The pointer to the source buffer of the memory copy.\r
319 @param Length The number of bytes to copy from SourceBuffer to DestinationBuffer.\r
320\r
fae43d06 321 @retval EFI_SECURITY_VIOLATION The DestinationBuffer is invalid per processor architecture or overlap with SMRAM.\r
d425764e
JY
322 @retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with SMRAM.\r
323 @retval EFI_SUCCESS Memory is copied.\r
324\r
325**/\r
326EFI_STATUS\r
327EFIAPI\r
328SmmCopyMem (\r
329 OUT VOID *DestinationBuffer,\r
330 IN CONST VOID *SourceBuffer,\r
331 IN UINTN Length\r
332 )\r
333{\r
334 if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) {\r
5f289f3a 335 DEBUG ((DEBUG_ERROR, "SmmCopyMem: Security Violation: Destination (0x%x), Length (0x%x)\n", DestinationBuffer, Length));\r
d425764e
JY
336 return EFI_SECURITY_VIOLATION;\r
337 }\r
2f88bd3a 338\r
d425764e 339 if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) {\r
5f289f3a 340 DEBUG ((DEBUG_ERROR, "SmmCopyMem: Security Violation: Source (0x%x), Length (0x%x)\n", SourceBuffer, Length));\r
d425764e
JY
341 return EFI_SECURITY_VIOLATION;\r
342 }\r
2f88bd3a 343\r
d425764e
JY
344 CopyMem (DestinationBuffer, SourceBuffer, Length);\r
345 return EFI_SUCCESS;\r
346}\r
347\r
348/**\r
349 Fills a target buffer (NON-SMRAM) with a byte value.\r
350\r
351 This function fills a target buffer (non-SMRAM) with a byte value.\r
352 It checks if target buffer is valid per processor architecture and not overlap with SMRAM.\r
353 If the check passes, it fills memory and returns EFI_SUCCESS.\r
354 If the check fails, it returns EFI_SECURITY_VIOLATION.\r
9095d37b 355\r
d425764e
JY
356 @param Buffer The memory to set.\r
357 @param Length The number of bytes to set.\r
358 @param Value The value with which to fill Length bytes of Buffer.\r
9095d37b 359\r
d425764e
JY
360 @retval EFI_SECURITY_VIOLATION The Buffer is invalid per processor architecture or overlap with SMRAM.\r
361 @retval EFI_SUCCESS Memory is set.\r
362\r
363**/\r
364EFI_STATUS\r
365EFIAPI\r
366SmmSetMem (\r
367 OUT VOID *Buffer,\r
368 IN UINTN Length,\r
369 IN UINT8 Value\r
370 )\r
371{\r
372 if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, Length)) {\r
5f289f3a 373 DEBUG ((DEBUG_ERROR, "SmmSetMem: Security Violation: Source (0x%x), Length (0x%x)\n", Buffer, Length));\r
d425764e
JY
374 return EFI_SECURITY_VIOLATION;\r
375 }\r
2f88bd3a 376\r
d425764e
JY
377 SetMem (Buffer, Length, Value);\r
378 return EFI_SUCCESS;\r
379}\r
380\r
233ffa90
JY
381/**\r
382 Get GCD memory map.\r
383 Only record untested memory as invalid communication buffer.\r
384**/\r
385VOID\r
386SmmMemLibInternalGetGcdMemoryMap (\r
387 VOID\r
388 )\r
389{\r
390 UINTN NumberOfDescriptors;\r
391 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemSpaceMap;\r
392 EFI_STATUS Status;\r
393 UINTN Index;\r
394\r
395 Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemSpaceMap);\r
396 if (EFI_ERROR (Status)) {\r
2f88bd3a 397 return;\r
233ffa90
JY
398 }\r
399\r
400 mSmmMemLibGcdMemNumberOfDesc = 0;\r
401 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
2f88bd3a
MK
402 if ((MemSpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved) &&\r
403 ((MemSpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==\r
404 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED))\r
405 )\r
406 {\r
233ffa90
JY
407 mSmmMemLibGcdMemNumberOfDesc++;\r
408 }\r
409 }\r
410\r
411 mSmmMemLibGcdMemSpace = AllocateZeroPool (mSmmMemLibGcdMemNumberOfDesc * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));\r
412 ASSERT (mSmmMemLibGcdMemSpace != NULL);\r
413 if (mSmmMemLibGcdMemSpace == NULL) {\r
414 mSmmMemLibGcdMemNumberOfDesc = 0;\r
415 gBS->FreePool (MemSpaceMap);\r
2f88bd3a 416 return;\r
233ffa90
JY
417 }\r
418\r
419 mSmmMemLibGcdMemNumberOfDesc = 0;\r
420 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
2f88bd3a
MK
421 if ((MemSpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved) &&\r
422 ((MemSpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==\r
423 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED))\r
424 )\r
425 {\r
233ffa90
JY
426 CopyMem (\r
427 &mSmmMemLibGcdMemSpace[mSmmMemLibGcdMemNumberOfDesc],\r
428 &MemSpaceMap[Index],\r
2f88bd3a 429 sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR)\r
233ffa90
JY
430 );\r
431 mSmmMemLibGcdMemNumberOfDesc++;\r
432 }\r
433 }\r
434\r
435 gBS->FreePool (MemSpaceMap);\r
436}\r
437\r
68096272
JY
438/**\r
439 Get UEFI MemoryAttributesTable.\r
440**/\r
441VOID\r
442SmmMemLibInternalGetUefiMemoryAttributesTable (\r
443 VOID\r
444 )\r
445{\r
446 EFI_STATUS Status;\r
447 EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;\r
448 UINTN MemoryAttributesTableSize;\r
449\r
450 Status = EfiGetSystemConfigurationTable (&gEfiMemoryAttributesTableGuid, (VOID **)&MemoryAttributesTable);\r
264914a5 451 if (!EFI_ERROR (Status) && (MemoryAttributesTable != NULL)) {\r
2f88bd3a 452 MemoryAttributesTableSize = sizeof (EFI_MEMORY_ATTRIBUTES_TABLE) + MemoryAttributesTable->DescriptorSize * MemoryAttributesTable->NumberOfEntries;\r
68096272
JY
453 mSmmMemLibMemoryAttributesTable = AllocateCopyPool (MemoryAttributesTableSize, MemoryAttributesTable);\r
454 ASSERT (mSmmMemLibMemoryAttributesTable != NULL);\r
455 }\r
456}\r
457\r
91f51fcc
JY
458/**\r
459 Notification for SMM EndOfDxe protocol.\r
460\r
461 @param[in] Protocol Points to the protocol's unique identifier.\r
462 @param[in] Interface Points to the interface instance.\r
463 @param[in] Handle The handle on which the interface was installed.\r
464\r
465 @retval EFI_SUCCESS Notification runs successfully.\r
466**/\r
467EFI_STATUS\r
468EFIAPI\r
469SmmLibInternalEndOfDxeNotify (\r
470 IN CONST EFI_GUID *Protocol,\r
471 IN VOID *Interface,\r
472 IN EFI_HANDLE Handle\r
473 )\r
474{\r
2f88bd3a
MK
475 EFI_STATUS Status;\r
476 UINTN MapKey;\r
477 UINTN MemoryMapSize;\r
478 EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
479 EFI_MEMORY_DESCRIPTOR *MemoryMapStart;\r
480 EFI_MEMORY_DESCRIPTOR *SmmMemoryMapStart;\r
481 UINTN MemoryMapEntryCount;\r
482 UINTN DescriptorSize;\r
483 UINT32 DescriptorVersion;\r
484 UINTN Index;\r
91f51fcc
JY
485\r
486 MemoryMapSize = 0;\r
2f88bd3a
MK
487 MemoryMap = NULL;\r
488 Status = gBS->GetMemoryMap (\r
489 &MemoryMapSize,\r
490 MemoryMap,\r
491 &MapKey,\r
492 &DescriptorSize,\r
493 &DescriptorVersion\r
494 );\r
91f51fcc
JY
495 ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
496\r
497 do {\r
498 Status = gBS->AllocatePool (EfiBootServicesData, MemoryMapSize, (VOID **)&MemoryMap);\r
499 ASSERT (MemoryMap != NULL);\r
9095d37b 500\r
91f51fcc 501 Status = gBS->GetMemoryMap (\r
2f88bd3a
MK
502 &MemoryMapSize,\r
503 MemoryMap,\r
504 &MapKey,\r
505 &DescriptorSize,\r
506 &DescriptorVersion\r
507 );\r
91f51fcc
JY
508 if (EFI_ERROR (Status)) {\r
509 gBS->FreePool (MemoryMap);\r
510 }\r
511 } while (Status == EFI_BUFFER_TOO_SMALL);\r
512\r
513 //\r
514 // Get Count\r
515 //\r
2f88bd3a
MK
516 mDescriptorSize = DescriptorSize;\r
517 MemoryMapEntryCount = MemoryMapSize/DescriptorSize;\r
518 MemoryMapStart = MemoryMap;\r
91f51fcc
JY
519 mMemoryMapEntryCount = 0;\r
520 for (Index = 0; Index < MemoryMapEntryCount; Index++) {\r
521 switch (MemoryMap->Type) {\r
2f88bd3a
MK
522 case EfiReservedMemoryType:\r
523 case EfiRuntimeServicesCode:\r
524 case EfiRuntimeServicesData:\r
525 case EfiACPIMemoryNVS:\r
526 mMemoryMapEntryCount++;\r
527 break;\r
91f51fcc 528 }\r
2f88bd3a
MK
529\r
530 MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize);\r
91f51fcc 531 }\r
2f88bd3a 532\r
91f51fcc 533 MemoryMap = MemoryMapStart;\r
9095d37b 534\r
91f51fcc
JY
535 //\r
536 // Get Data\r
537 //\r
538 mMemoryMap = AllocatePool (mMemoryMapEntryCount*DescriptorSize);\r
539 ASSERT (mMemoryMap != NULL);\r
540 SmmMemoryMapStart = mMemoryMap;\r
541 for (Index = 0; Index < MemoryMapEntryCount; Index++) {\r
542 switch (MemoryMap->Type) {\r
2f88bd3a
MK
543 case EfiReservedMemoryType:\r
544 case EfiRuntimeServicesCode:\r
545 case EfiRuntimeServicesData:\r
546 case EfiACPIMemoryNVS:\r
547 CopyMem (mMemoryMap, MemoryMap, DescriptorSize);\r
548 mMemoryMap = NEXT_MEMORY_DESCRIPTOR (mMemoryMap, DescriptorSize);\r
549 break;\r
91f51fcc 550 }\r
2f88bd3a
MK
551\r
552 MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize);\r
91f51fcc 553 }\r
2f88bd3a 554\r
91f51fcc 555 mMemoryMap = SmmMemoryMapStart;\r
2f88bd3a 556 MemoryMap = MemoryMapStart;\r
9095d37b 557\r
91f51fcc
JY
558 gBS->FreePool (MemoryMap);\r
559\r
233ffa90
JY
560 //\r
561 // Get additional information from GCD memory map.\r
562 //\r
563 SmmMemLibInternalGetGcdMemoryMap ();\r
564\r
68096272
JY
565 //\r
566 // Get UEFI memory attributes table.\r
567 //\r
568 SmmMemLibInternalGetUefiMemoryAttributesTable ();\r
569\r
91f51fcc
JY
570 return EFI_SUCCESS;\r
571}\r
572\r
91f51fcc
JY
573/**\r
574 Notification for SMM ReadyToLock protocol.\r
575\r
576 @param[in] Protocol Points to the protocol's unique identifier.\r
577 @param[in] Interface Points to the interface instance.\r
578 @param[in] Handle The handle on which the interface was installed.\r
579\r
580 @retval EFI_SUCCESS Notification runs successfully.\r
581**/\r
582EFI_STATUS\r
583EFIAPI\r
584SmmLibInternalReadyToLockNotify (\r
585 IN CONST EFI_GUID *Protocol,\r
586 IN VOID *Interface,\r
587 IN EFI_HANDLE Handle\r
588 )\r
589{\r
233ffa90 590 mSmmMemLibSmmReadyToLock = TRUE;\r
91f51fcc
JY
591 return EFI_SUCCESS;\r
592}\r
2f88bd3a 593\r
d425764e
JY
594/**\r
595 The constructor function initializes the Smm Mem library\r
596\r
597 @param ImageHandle The firmware allocated handle for the EFI image.\r
598 @param SystemTable A pointer to the EFI System Table.\r
599\r
600 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
601\r
602**/\r
603EFI_STATUS\r
604EFIAPI\r
605SmmMemLibConstructor (\r
606 IN EFI_HANDLE ImageHandle,\r
607 IN EFI_SYSTEM_TABLE *SystemTable\r
608 )\r
609{\r
2f88bd3a
MK
610 EFI_STATUS Status;\r
611 EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;\r
612 UINTN Size;\r
9095d37b 613\r
d425764e
JY
614 //\r
615 // Get SMRAM information\r
616 //\r
617 Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);\r
618 ASSERT_EFI_ERROR (Status);\r
619\r
2f88bd3a 620 Size = 0;\r
d425764e
JY
621 Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);\r
622 ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
623\r
624 mSmmMemLibInternalSmramRanges = AllocatePool (Size);\r
625 ASSERT (mSmmMemLibInternalSmramRanges != NULL);\r
626\r
627 Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmmMemLibInternalSmramRanges);\r
628 ASSERT_EFI_ERROR (Status);\r
629\r
630 mSmmMemLibInternalSmramCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);\r
631\r
632 //\r
2a93f2c3 633 // Calculate and save maximum support address\r
d425764e 634 //\r
2a93f2c3 635 SmmMemLibInternalCalculateMaximumSupportAddress ();\r
d425764e 636\r
91f51fcc
JY
637 //\r
638 // Register EndOfDxe to get UEFI memory map\r
639 //\r
640 Status = gSmst->SmmRegisterProtocolNotify (&gEfiSmmEndOfDxeProtocolGuid, SmmLibInternalEndOfDxeNotify, &mRegistrationEndOfDxe);\r
641 ASSERT_EFI_ERROR (Status);\r
642\r
643 //\r
644 // Register ready to lock so that we can know when to check valid SMRAM region\r
645 //\r
646 Status = gSmst->SmmRegisterProtocolNotify (&gEfiSmmReadyToLockProtocolGuid, SmmLibInternalReadyToLockNotify, &mRegistrationReadyToLock);\r
647 ASSERT_EFI_ERROR (Status);\r
648\r
d425764e
JY
649 return EFI_SUCCESS;\r
650}\r
651\r
652/**\r
653 The destructor function frees resource used in the Smm Mem library\r
654\r
655 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
656 @param[in] SystemTable A pointer to the EFI System Table.\r
657\r
658 @retval EFI_SUCCESS The deconstructor always returns EFI_SUCCESS.\r
659**/\r
660EFI_STATUS\r
661EFIAPI\r
662SmmMemLibDestructor (\r
663 IN EFI_HANDLE ImageHandle,\r
664 IN EFI_SYSTEM_TABLE *SystemTable\r
665 )\r
666{\r
667 FreePool (mSmmMemLibInternalSmramRanges);\r
668\r
91f51fcc
JY
669 gSmst->SmmRegisterProtocolNotify (&gEfiSmmEndOfDxeProtocolGuid, NULL, &mRegistrationEndOfDxe);\r
670 gSmst->SmmRegisterProtocolNotify (&gEfiSmmReadyToLockProtocolGuid, NULL, &mRegistrationReadyToLock);\r
d425764e
JY
671 return EFI_SUCCESS;\r
672}\r