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