]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
MdeModulePkg/DxeCore: implement memory protection policy
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Misc / MemoryProtection.c
CommitLineData
d0e92aad
JY
1/** @file\r
2 UEFI Memory Protection support.\r
3\r
4 If the UEFI image is page aligned, the image code section is set to read only\r
5 and the image data section is set to non-executable.\r
6\r
7 1) This policy is applied for all UEFI image including boot service driver,\r
8 runtime driver or application.\r
9 2) This policy is applied only if the UEFI image meets the page alignment\r
10 requirement.\r
11 3) This policy is applied only if the Source UEFI image matches the\r
12 PcdImageProtectionPolicy definition.\r
13 4) This policy is not applied to the non-PE image region.\r
14\r
15 The DxeCore calls CpuArchProtocol->SetMemoryAttributes() to protect\r
16 the image. If the CpuArch protocol is not installed yet, the DxeCore\r
17 enqueues the protection request. Once the CpuArch is installed, the\r
18 DxeCore dequeues the protection request and applies policy.\r
19\r
20 Once the image is unloaded, the protection is removed automatically.\r
21\r
22Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
23This program and the accompanying materials\r
24are licensed and made available under the terms and conditions of the BSD License\r
25which accompanies this distribution. The full text of the license may be found at\r
26http://opensource.org/licenses/bsd-license.php\r
27\r
28THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
29WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
30\r
31**/\r
32\r
33#include <PiDxe.h>\r
34#include <Library/BaseLib.h>\r
35#include <Library/BaseMemoryLib.h>\r
36#include <Library/MemoryAllocationLib.h>\r
37#include <Library/UefiBootServicesTableLib.h>\r
38#include <Library/DxeServicesTableLib.h>\r
39#include <Library/DebugLib.h>\r
40#include <Library/UefiLib.h>\r
41\r
42#include <Guid/EventGroup.h>\r
43#include <Guid/MemoryAttributesTable.h>\r
44#include <Guid/PropertiesTable.h>\r
45\r
46#include <Protocol/FirmwareVolume2.h>\r
47#include <Protocol/BlockIo.h>\r
48#include <Protocol/SimpleFileSystem.h>\r
49\r
50#include "DxeMain.h"\r
51\r
52#define CACHE_ATTRIBUTE_MASK (EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP)\r
53#define MEMORY_ATTRIBUTE_MASK (EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RO)\r
54\r
55//\r
56// Image type definitions\r
57//\r
58#define IMAGE_UNKNOWN 0x00000001\r
59#define IMAGE_FROM_FV 0x00000002\r
60\r
61//\r
62// Protection policy bit definition\r
63//\r
64#define DO_NOT_PROTECT 0x00000000\r
65#define PROTECT_IF_ALIGNED_ELSE_ALLOW 0x00000001\r
66\r
7eb927db
AB
67#define MEMORY_TYPE_OS_RESERVED_MIN 0x80000000\r
68#define MEMORY_TYPE_OEM_RESERVED_MIN 0x70000000\r
69\r
70#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \\r
71 ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))\r
72\r
d0e92aad
JY
73UINT32 mImageProtectionPolicy;\r
74\r
7eb927db
AB
75extern LIST_ENTRY mGcdMemorySpaceMap;\r
76\r
d0e92aad
JY
77/**\r
78 Sort code section in image record, based upon CodeSegmentBase from low to high.\r
79\r
80 @param ImageRecord image record to be sorted\r
81**/\r
82VOID\r
83SortImageRecordCodeSection (\r
84 IN IMAGE_PROPERTIES_RECORD *ImageRecord\r
85 );\r
86\r
87/**\r
88 Check if code section in image record is valid.\r
89\r
90 @param ImageRecord image record to be checked\r
91\r
92 @retval TRUE image record is valid\r
93 @retval FALSE image record is invalid\r
94**/\r
95BOOLEAN\r
96IsImageRecordCodeSectionValid (\r
97 IN IMAGE_PROPERTIES_RECORD *ImageRecord\r
98 );\r
99\r
100/**\r
101 Get the image type.\r
102\r
103 @param[in] File This is a pointer to the device path of the file that is\r
104 being dispatched.\r
105\r
106 @return UINT32 Image Type\r
107**/\r
108UINT32\r
109GetImageType (\r
110 IN CONST EFI_DEVICE_PATH_PROTOCOL *File\r
111 )\r
112{\r
113 EFI_STATUS Status;\r
114 EFI_HANDLE DeviceHandle;\r
115 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
116\r
117 if (File == NULL) {\r
118 return IMAGE_UNKNOWN;\r
119 }\r
120\r
121 //\r
122 // First check to see if File is from a Firmware Volume\r
123 //\r
124 DeviceHandle = NULL;\r
125 TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File;\r
126 Status = gBS->LocateDevicePath (\r
127 &gEfiFirmwareVolume2ProtocolGuid,\r
128 &TempDevicePath,\r
129 &DeviceHandle\r
130 );\r
131 if (!EFI_ERROR (Status)) {\r
132 Status = gBS->OpenProtocol (\r
133 DeviceHandle,\r
134 &gEfiFirmwareVolume2ProtocolGuid,\r
135 NULL,\r
136 NULL,\r
137 NULL,\r
138 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
139 );\r
140 if (!EFI_ERROR (Status)) {\r
141 return IMAGE_FROM_FV;\r
142 }\r
143 }\r
144 return IMAGE_UNKNOWN;\r
145}\r
146\r
147/**\r
148 Get UEFI image protection policy based upon image type.\r
149\r
150 @param[in] ImageType The UEFI image type\r
151\r
152 @return UEFI image protection policy\r
153**/\r
154UINT32\r
155GetProtectionPolicyFromImageType (\r
156 IN UINT32 ImageType\r
157 )\r
158{\r
159 if ((ImageType & mImageProtectionPolicy) == 0) {\r
160 return DO_NOT_PROTECT;\r
161 } else {\r
162 return PROTECT_IF_ALIGNED_ELSE_ALLOW;\r
163 }\r
164}\r
165\r
166/**\r
167 Get UEFI image protection policy based upon loaded image device path.\r
168\r
169 @param[in] LoadedImage The loaded image protocol\r
170 @param[in] LoadedImageDevicePath The loaded image device path protocol\r
171\r
172 @return UEFI image protection policy\r
173**/\r
174UINT32\r
175GetUefiImageProtectionPolicy (\r
176 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
177 IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath\r
178 )\r
179{\r
180 BOOLEAN InSmm;\r
181 UINT32 ImageType;\r
182 UINT32 ProtectionPolicy;\r
183\r
184 //\r
185 // Check SMM\r
186 //\r
187 InSmm = FALSE;\r
188 if (gSmmBase2 != NULL) {\r
189 gSmmBase2->InSmm (gSmmBase2, &InSmm);\r
190 }\r
191 if (InSmm) {\r
192 return FALSE;\r
193 }\r
194\r
195 //\r
196 // Check DevicePath\r
197 //\r
198 if (LoadedImage == gDxeCoreLoadedImage) {\r
199 ImageType = IMAGE_FROM_FV;\r
200 } else {\r
201 ImageType = GetImageType (LoadedImageDevicePath);\r
202 }\r
203 ProtectionPolicy = GetProtectionPolicyFromImageType (ImageType);\r
204 return ProtectionPolicy;\r
205}\r
206\r
207\r
208/**\r
209 Set UEFI image memory attributes.\r
210\r
211 @param[in] BaseAddress Specified start address\r
212 @param[in] Length Specified length\r
213 @param[in] Attributes Specified attributes\r
214**/\r
215VOID\r
216SetUefiImageMemoryAttributes (\r
217 IN UINT64 BaseAddress,\r
218 IN UINT64 Length,\r
219 IN UINT64 Attributes\r
220 )\r
221{\r
222 EFI_STATUS Status;\r
223 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
224 UINT64 FinalAttributes;\r
225\r
226 Status = CoreGetMemorySpaceDescriptor(BaseAddress, &Descriptor);\r
227 ASSERT_EFI_ERROR(Status);\r
228\r
229 FinalAttributes = (Descriptor.Attributes & CACHE_ATTRIBUTE_MASK) | (Attributes & MEMORY_ATTRIBUTE_MASK);\r
230\r
231 DEBUG ((DEBUG_INFO, "SetUefiImageMemoryAttributes - 0x%016lx - 0x%016lx (0x%016lx)\n", BaseAddress, Length, FinalAttributes));\r
232\r
233 ASSERT(gCpu != NULL);\r
234 gCpu->SetMemoryAttributes (gCpu, BaseAddress, Length, FinalAttributes);\r
235}\r
236\r
237/**\r
238 Set UEFI image protection attributes.\r
239\r
240 @param[in] ImageRecord A UEFI image record\r
241 @param[in] Protect TRUE: Protect the UEFI image.\r
242 FALSE: Unprotect the UEFI image.\r
243**/\r
244VOID\r
245SetUefiImageProtectionAttributes (\r
246 IN IMAGE_PROPERTIES_RECORD *ImageRecord,\r
247 IN BOOLEAN Protect\r
248 )\r
249{\r
250 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
251 LIST_ENTRY *ImageRecordCodeSectionLink;\r
252 LIST_ENTRY *ImageRecordCodeSectionEndLink;\r
253 LIST_ENTRY *ImageRecordCodeSectionList;\r
254 UINT64 CurrentBase;\r
255 UINT64 ImageEnd;\r
256 UINT64 Attribute;\r
257\r
258 ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;\r
259\r
260 CurrentBase = ImageRecord->ImageBase;\r
261 ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;\r
262\r
263 ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;\r
264 ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;\r
265 while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {\r
266 ImageRecordCodeSection = CR (\r
267 ImageRecordCodeSectionLink,\r
268 IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
269 Link,\r
270 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
271 );\r
272 ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
273\r
274 ASSERT (CurrentBase <= ImageRecordCodeSection->CodeSegmentBase);\r
275 if (CurrentBase < ImageRecordCodeSection->CodeSegmentBase) {\r
276 //\r
277 // DATA\r
278 //\r
279 if (Protect) {\r
280 Attribute = EFI_MEMORY_XP;\r
281 } else {\r
282 Attribute = 0;\r
283 }\r
284 SetUefiImageMemoryAttributes (\r
285 CurrentBase,\r
286 ImageRecordCodeSection->CodeSegmentBase - CurrentBase,\r
287 Attribute\r
288 );\r
289 }\r
290 //\r
291 // CODE\r
292 //\r
293 if (Protect) {\r
294 Attribute = EFI_MEMORY_RO;\r
295 } else {\r
296 Attribute = 0;\r
297 }\r
298 SetUefiImageMemoryAttributes (\r
299 ImageRecordCodeSection->CodeSegmentBase,\r
300 ImageRecordCodeSection->CodeSegmentSize,\r
301 Attribute\r
302 );\r
303 CurrentBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize;\r
304 }\r
305 //\r
306 // Last DATA\r
307 //\r
308 ASSERT (CurrentBase <= ImageEnd);\r
309 if (CurrentBase < ImageEnd) {\r
310 //\r
311 // DATA\r
312 //\r
313 if (Protect) {\r
314 Attribute = EFI_MEMORY_XP;\r
315 } else {\r
316 Attribute = 0;\r
317 }\r
318 SetUefiImageMemoryAttributes (\r
319 CurrentBase,\r
320 ImageEnd - CurrentBase,\r
321 Attribute\r
322 );\r
323 }\r
324 return ;\r
325}\r
326\r
327/**\r
328 Return if the PE image section is aligned.\r
329\r
330 @param[in] SectionAlignment PE/COFF section alignment\r
331 @param[in] MemoryType PE/COFF image memory type\r
332\r
333 @retval TRUE The PE image section is aligned.\r
334 @retval FALSE The PE image section is not aligned.\r
335**/\r
336BOOLEAN\r
337IsMemoryProtectionSectionAligned (\r
338 IN UINT32 SectionAlignment,\r
339 IN EFI_MEMORY_TYPE MemoryType\r
340 )\r
341{\r
342 UINT32 PageAlignment;\r
343\r
344 switch (MemoryType) {\r
345 case EfiRuntimeServicesCode:\r
346 case EfiACPIMemoryNVS:\r
347 PageAlignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
348 break;\r
349 case EfiRuntimeServicesData:\r
350 case EfiACPIReclaimMemory:\r
351 ASSERT (FALSE);\r
352 PageAlignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
353 break;\r
354 case EfiBootServicesCode:\r
355 case EfiLoaderCode:\r
356 case EfiReservedMemoryType:\r
357 PageAlignment = EFI_PAGE_SIZE;\r
358 break;\r
359 default:\r
360 ASSERT (FALSE);\r
361 PageAlignment = EFI_PAGE_SIZE;\r
362 break;\r
363 }\r
364\r
365 if ((SectionAlignment & (PageAlignment - 1)) != 0) {\r
366 return FALSE;\r
367 } else {\r
368 return TRUE;\r
369 }\r
370}\r
371\r
372/**\r
373 Free Image record.\r
374\r
375 @param[in] ImageRecord A UEFI image record\r
376**/\r
377VOID\r
378FreeImageRecord (\r
379 IN IMAGE_PROPERTIES_RECORD *ImageRecord\r
380 )\r
381{\r
382 LIST_ENTRY *CodeSegmentListHead;\r
383 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
384\r
385 CodeSegmentListHead = &ImageRecord->CodeSegmentList;\r
386 while (!IsListEmpty (CodeSegmentListHead)) {\r
387 ImageRecordCodeSection = CR (\r
388 CodeSegmentListHead->ForwardLink,\r
389 IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
390 Link,\r
391 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
392 );\r
393 RemoveEntryList (&ImageRecordCodeSection->Link);\r
394 FreePool (ImageRecordCodeSection);\r
395 }\r
396\r
397 if (ImageRecord->Link.ForwardLink != NULL) {\r
398 RemoveEntryList (&ImageRecord->Link);\r
399 }\r
400 FreePool (ImageRecord);\r
401}\r
402\r
403/**\r
404 Protect or unprotect UEFI image common function.\r
405\r
406 @param[in] LoadedImage The loaded image protocol\r
407 @param[in] LoadedImageDevicePath The loaded image device path protocol\r
408 @param[in] Protect TRUE: Protect the UEFI image.\r
409 FALSE: Unprotect the UEFI image.\r
410**/\r
411VOID\r
412ProtectUefiImageCommon (\r
413 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
414 IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath,\r
415 IN BOOLEAN Protect\r
416 )\r
417{\r
418 VOID *ImageAddress;\r
419 EFI_IMAGE_DOS_HEADER *DosHdr;\r
420 UINT32 PeCoffHeaderOffset;\r
421 UINT32 SectionAlignment;\r
422 EFI_IMAGE_SECTION_HEADER *Section;\r
423 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
424 UINT8 *Name;\r
425 UINTN Index;\r
426 IMAGE_PROPERTIES_RECORD *ImageRecord;\r
427 CHAR8 *PdbPointer;\r
428 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
429 UINT16 Magic;\r
430 BOOLEAN IsAligned;\r
431 UINT32 ProtectionPolicy;\r
432\r
433 DEBUG ((DEBUG_INFO, "ProtectUefiImageCommon - 0x%x\n", LoadedImage));\r
434 DEBUG ((DEBUG_INFO, " - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase, LoadedImage->ImageSize));\r
435\r
436 if (gCpu == NULL) {\r
437 return ;\r
438 }\r
439\r
440 ProtectionPolicy = GetUefiImageProtectionPolicy (LoadedImage, LoadedImageDevicePath);\r
441 switch (ProtectionPolicy) {\r
442 case DO_NOT_PROTECT:\r
443 return ;\r
444 case PROTECT_IF_ALIGNED_ELSE_ALLOW:\r
445 break;\r
446 default:\r
447 ASSERT(FALSE);\r
448 return ;\r
449 }\r
450\r
451 ImageRecord = AllocateZeroPool (sizeof(*ImageRecord));\r
452 if (ImageRecord == NULL) {\r
453 return ;\r
454 }\r
455 ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;\r
456\r
457 //\r
458 // Step 1: record whole region\r
459 //\r
460 ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase;\r
461 ImageRecord->ImageSize = LoadedImage->ImageSize;\r
462\r
463 ImageAddress = LoadedImage->ImageBase;\r
464\r
465 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
466 if (PdbPointer != NULL) {\r
467 DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer));\r
468 }\r
469\r
470 //\r
471 // Check PE/COFF image\r
472 //\r
473 DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;\r
474 PeCoffHeaderOffset = 0;\r
475 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
476 PeCoffHeaderOffset = DosHdr->e_lfanew;\r
477 }\r
478\r
479 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);\r
480 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
481 DEBUG ((DEBUG_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));\r
482 // It might be image in SMM.\r
483 goto Finish;\r
484 }\r
485\r
486 //\r
487 // Get SectionAlignment\r
488 //\r
489 if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
490 //\r
491 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value\r
492 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the\r
493 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
494 // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
495 //\r
496 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
497 } else {\r
498 //\r
499 // Get the magic value from the PE/COFF Optional Header\r
500 //\r
501 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
502 }\r
503 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
504 SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;\r
505 } else {\r
506 SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;\r
507 }\r
508\r
509 IsAligned = IsMemoryProtectionSectionAligned (SectionAlignment, LoadedImage->ImageCodeType);\r
510 if (!IsAligned) {\r
511 DEBUG ((DEBUG_VERBOSE, "!!!!!!!! ProtectUefiImageCommon - Section Alignment(0x%x) is incorrect !!!!!!!!\n",\r
512 SectionAlignment));\r
513 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
514 if (PdbPointer != NULL) {\r
515 DEBUG ((DEBUG_VERBOSE, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));\r
516 }\r
517 goto Finish;\r
518 }\r
519\r
520 Section = (EFI_IMAGE_SECTION_HEADER *) (\r
521 (UINT8 *) (UINTN) ImageAddress +\r
522 PeCoffHeaderOffset +\r
523 sizeof(UINT32) +\r
524 sizeof(EFI_IMAGE_FILE_HEADER) +\r
525 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
526 );\r
527 ImageRecord->CodeSegmentCount = 0;\r
528 InitializeListHead (&ImageRecord->CodeSegmentList);\r
529 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
530 Name = Section[Index].Name;\r
531 DEBUG ((\r
532 DEBUG_VERBOSE,\r
533 " Section - '%c%c%c%c%c%c%c%c'\n",\r
534 Name[0],\r
535 Name[1],\r
536 Name[2],\r
537 Name[3],\r
538 Name[4],\r
539 Name[5],\r
540 Name[6],\r
541 Name[7]\r
542 ));\r
543\r
a2ed40c0
AB
544 //\r
545 // Instead of assuming that a PE/COFF section of type EFI_IMAGE_SCN_CNT_CODE\r
546 // can always be mapped read-only, classify a section as a code section only\r
547 // if it has the executable attribute set and the writable attribute cleared.\r
548 //\r
549 // This adheres more closely to the PE/COFF spec, and avoids issues with\r
550 // Linux OS loaders that may consist of a single read/write/execute section.\r
551 //\r
552 if ((Section[Index].Characteristics & (EFI_IMAGE_SCN_MEM_WRITE | EFI_IMAGE_SCN_MEM_EXECUTE)) == EFI_IMAGE_SCN_MEM_EXECUTE) {\r
d0e92aad
JY
553 DEBUG ((DEBUG_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));\r
554 DEBUG ((DEBUG_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));\r
555 DEBUG ((DEBUG_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));\r
556 DEBUG ((DEBUG_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));\r
557 DEBUG ((DEBUG_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));\r
558 DEBUG ((DEBUG_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));\r
559 DEBUG ((DEBUG_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));\r
560 DEBUG ((DEBUG_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));\r
561 DEBUG ((DEBUG_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics));\r
562\r
563 //\r
564 // Step 2: record code section\r
565 //\r
566 ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection));\r
567 if (ImageRecordCodeSection == NULL) {\r
568 return ;\r
569 }\r
570 ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;\r
571\r
572 ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;\r
573 ImageRecordCodeSection->CodeSegmentSize = ALIGN_VALUE(Section[Index].SizeOfRawData, SectionAlignment);\r
574\r
575 DEBUG ((DEBUG_VERBOSE, "ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));\r
576\r
577 InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);\r
578 ImageRecord->CodeSegmentCount++;\r
579 }\r
580 }\r
581\r
582 if (ImageRecord->CodeSegmentCount == 0) {\r
583 DEBUG ((DEBUG_ERROR, "!!!!!!!! ProtectUefiImageCommon - CodeSegmentCount is 0 !!!!!!!!\n"));\r
584 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
585 if (PdbPointer != NULL) {\r
586 DEBUG ((DEBUG_ERROR, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));\r
587 }\r
588 goto Finish;\r
589 }\r
590\r
591 //\r
592 // Final\r
593 //\r
594 SortImageRecordCodeSection (ImageRecord);\r
595 //\r
596 // Check overlap all section in ImageBase/Size\r
597 //\r
598 if (!IsImageRecordCodeSectionValid (ImageRecord)) {\r
599 DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));\r
600 goto Finish;\r
601 }\r
602\r
603 //\r
604 // Round up the ImageSize, some CPU arch may return EFI_UNSUPPORTED if ImageSize is not aligned.\r
605 // Given that the loader always allocates full pages, we know the space after the image is not used.\r
606 //\r
607 ImageRecord->ImageSize = ALIGN_VALUE(LoadedImage->ImageSize, EFI_PAGE_SIZE);\r
608\r
609 //\r
610 // CPU ARCH present. Update memory attribute directly.\r
611 //\r
612 SetUefiImageProtectionAttributes (ImageRecord, Protect);\r
613\r
614 //\r
615 // Clean up\r
616 //\r
617 FreeImageRecord (ImageRecord);\r
618\r
619Finish:\r
620 return ;\r
621}\r
622\r
623/**\r
624 Protect UEFI image.\r
625\r
626 @param[in] LoadedImage The loaded image protocol\r
627 @param[in] LoadedImageDevicePath The loaded image device path protocol\r
628**/\r
629VOID\r
630ProtectUefiImage (\r
631 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
632 IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath\r
633 )\r
634{\r
635 if (PcdGet32(PcdImageProtectionPolicy) != 0) {\r
636 ProtectUefiImageCommon (LoadedImage, LoadedImageDevicePath, TRUE);\r
637 }\r
638}\r
639\r
640/**\r
641 Unprotect UEFI image.\r
642\r
643 @param[in] LoadedImage The loaded image protocol\r
644 @param[in] LoadedImageDevicePath The loaded image device path protocol\r
645**/\r
646VOID\r
647UnprotectUefiImage (\r
648 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
649 IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath\r
650 )\r
651{\r
652 if (PcdGet32(PcdImageProtectionPolicy) != 0) {\r
653 ProtectUefiImageCommon (LoadedImage, LoadedImageDevicePath, FALSE);\r
654 }\r
655}\r
656\r
7eb927db
AB
657/**\r
658 Return the EFI memory permission attribute associated with memory\r
659 type 'MemoryType' under the configured DXE memory protection policy.\r
660**/\r
661STATIC\r
662UINT64\r
663GetPermissionAttributeForMemoryType (\r
664 IN EFI_MEMORY_TYPE MemoryType\r
665 )\r
666{\r
667 UINT64 TestBit;\r
668\r
669 if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {\r
670 TestBit = BIT63;\r
671 } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {\r
672 TestBit = BIT62;\r
673 } else {\r
674 TestBit = LShiftU64 (1, MemoryType);\r
675 }\r
676\r
677 if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & TestBit) != 0) {\r
678 return EFI_MEMORY_XP;\r
679 } else {\r
680 return 0;\r
681 }\r
682}\r
683\r
684/**\r
685 Sort memory map entries based upon PhysicalStart, from low to high.\r
686\r
687 @param MemoryMap A pointer to the buffer in which firmware places\r
688 the current memory map.\r
689 @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.\r
690 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
691**/\r
692STATIC\r
693VOID\r
694SortMemoryMap (\r
695 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
696 IN UINTN MemoryMapSize,\r
697 IN UINTN DescriptorSize\r
698 )\r
699{\r
700 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
701 EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;\r
702 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
703 EFI_MEMORY_DESCRIPTOR TempMemoryMap;\r
704\r
705 MemoryMapEntry = MemoryMap;\r
706 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
707 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
708 while (MemoryMapEntry < MemoryMapEnd) {\r
709 while (NextMemoryMapEntry < MemoryMapEnd) {\r
710 if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {\r
711 CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
712 CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
713 CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));\r
714 }\r
715\r
716 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
717 }\r
718\r
719 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
720 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
721 }\r
722}\r
723\r
724/**\r
725 Merge adjacent memory map entries if they use the same memory protection policy\r
726\r
727 @param[in, out] MemoryMap A pointer to the buffer in which firmware places\r
728 the current memory map.\r
729 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the\r
730 MemoryMap buffer. On input, this is the size of\r
731 the current memory map. On output,\r
732 it is the size of new memory map after merge.\r
733 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
734**/\r
735STATIC\r
736VOID\r
737MergeMemoryMapForProtectionPolicy (\r
738 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
739 IN OUT UINTN *MemoryMapSize,\r
740 IN UINTN DescriptorSize\r
741 )\r
742{\r
743 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
744 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
745 UINT64 MemoryBlockLength;\r
746 EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;\r
747 EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;\r
748 UINT64 Attributes;\r
749\r
750 SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);\r
751\r
752 MemoryMapEntry = MemoryMap;\r
753 NewMemoryMapEntry = MemoryMap;\r
754 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);\r
755 while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {\r
756 CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
757 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
758\r
759 do {\r
760 MemoryBlockLength = (UINT64) (EFI_PAGES_TO_SIZE((UINTN)MemoryMapEntry->NumberOfPages));\r
761 Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);\r
762\r
763 if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&\r
764 Attributes == GetPermissionAttributeForMemoryType (NextMemoryMapEntry->Type) &&\r
765 ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {\r
766 MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
767 if (NewMemoryMapEntry != MemoryMapEntry) {\r
768 NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
769 }\r
770\r
771 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
772 continue;\r
773 } else {\r
774 MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
775 break;\r
776 }\r
777 } while (TRUE);\r
778\r
779 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
780 NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);\r
781 }\r
782\r
783 *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;\r
784\r
785 return ;\r
786}\r
787\r
788\r
789/**\r
790 Remove exec permissions from all regions whose type is identified by\r
791 PcdDxeNxMemoryProtectionPolicy\r
792**/\r
793STATIC\r
794VOID\r
795InitializeDxeNxMemoryProtectionPolicy (\r
796 VOID\r
797 )\r
798{\r
799 UINTN MemoryMapSize;\r
800 UINTN MapKey;\r
801 UINTN DescriptorSize;\r
802 UINT32 DescriptorVersion;\r
803 EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
804 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
805 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
806 EFI_STATUS Status;\r
807 UINT64 Attributes;\r
808 LIST_ENTRY *Link;\r
809 EFI_GCD_MAP_ENTRY *Entry;\r
810\r
811 //\r
812 // Get the EFI memory map.\r
813 //\r
814 MemoryMapSize = 0;\r
815 MemoryMap = NULL;\r
816\r
817 Status = gBS->GetMemoryMap (\r
818 &MemoryMapSize,\r
819 MemoryMap,\r
820 &MapKey,\r
821 &DescriptorSize,\r
822 &DescriptorVersion\r
823 );\r
824 ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
825 do {\r
826 MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize);\r
827 ASSERT (MemoryMap != NULL);\r
828 Status = gBS->GetMemoryMap (\r
829 &MemoryMapSize,\r
830 MemoryMap,\r
831 &MapKey,\r
832 &DescriptorSize,\r
833 &DescriptorVersion\r
834 );\r
835 if (EFI_ERROR (Status)) {\r
836 FreePool (MemoryMap);\r
837 }\r
838 } while (Status == EFI_BUFFER_TOO_SMALL);\r
839 ASSERT_EFI_ERROR (Status);\r
840\r
841 DEBUG((DEBUG_ERROR, "%a: applying strict permissions to active memory regions\n",\r
842 __FUNCTION__));\r
843\r
844 MergeMemoryMapForProtectionPolicy (MemoryMap, &MemoryMapSize, DescriptorSize);\r
845\r
846 MemoryMapEntry = MemoryMap;\r
847 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
848 while ((UINTN) MemoryMapEntry < (UINTN) MemoryMapEnd) {\r
849\r
850 Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);\r
851 if (Attributes != 0) {\r
852 SetUefiImageMemoryAttributes (\r
853 MemoryMapEntry->PhysicalStart,\r
854 EFI_PAGES_TO_SIZE (MemoryMapEntry->NumberOfPages),\r
855 Attributes);\r
856 }\r
857 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
858 }\r
859 FreePool (MemoryMap);\r
860\r
861 //\r
862 // Apply the policy for RAM regions that we know are present and\r
863 // accessible, but have not been added to the UEFI memory map (yet).\r
864 //\r
865 if (GetPermissionAttributeForMemoryType (EfiConventionalMemory) != 0) {\r
866 DEBUG((DEBUG_ERROR,\r
867 "%a: applying strict permissions to inactive memory regions\n",\r
868 __FUNCTION__));\r
869\r
870 CoreAcquireGcdMemoryLock ();\r
871\r
872 Link = mGcdMemorySpaceMap.ForwardLink;\r
873 while (Link != &mGcdMemorySpaceMap) {\r
874\r
875 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
876\r
877 if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&\r
878 Entry->EndAddress < MAX_ADDRESS &&\r
879 (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==\r
880 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {\r
881\r
882 Attributes = GetPermissionAttributeForMemoryType (EfiConventionalMemory) |\r
883 (Entry->Attributes & CACHE_ATTRIBUTE_MASK);\r
884\r
885 DEBUG ((DEBUG_INFO,\r
886 "Untested GCD memory space region: - 0x%016lx - 0x%016lx (0x%016lx)\n",\r
887 Entry->BaseAddress, Entry->EndAddress - Entry->BaseAddress + 1,\r
888 Attributes));\r
889\r
890 ASSERT(gCpu != NULL);\r
891 gCpu->SetMemoryAttributes (gCpu, Entry->BaseAddress,\r
892 Entry->EndAddress - Entry->BaseAddress + 1, Attributes);\r
893 }\r
894\r
895 Link = Link->ForwardLink;\r
896 }\r
897 CoreReleaseGcdMemoryLock ();\r
898 }\r
899}\r
900\r
901\r
d0e92aad
JY
902/**\r
903 A notification for CPU_ARCH protocol.\r
904\r
905 @param[in] Event Event whose notification function is being invoked.\r
906 @param[in] Context Pointer to the notification function's context,\r
907 which is implementation-dependent.\r
908\r
909**/\r
910VOID\r
911EFIAPI\r
912MemoryProtectionCpuArchProtocolNotify (\r
913 IN EFI_EVENT Event,\r
914 IN VOID *Context\r
915 )\r
916{\r
917 EFI_STATUS Status;\r
918 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
919 EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;\r
920 UINTN NoHandles;\r
921 EFI_HANDLE *HandleBuffer;\r
922 UINTN Index;\r
923\r
924 DEBUG ((DEBUG_INFO, "MemoryProtectionCpuArchProtocolNotify:\n"));\r
925 Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);\r
926 if (EFI_ERROR (Status)) {\r
927 return;\r
928 }\r
929\r
7eb927db
AB
930 //\r
931 // Apply the memory protection policy on non-BScode/RTcode regions.\r
932 //\r
933 if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {\r
934 InitializeDxeNxMemoryProtectionPolicy ();\r
935 }\r
936\r
937 if (mImageProtectionPolicy == 0) {\r
938 return;\r
939 }\r
940\r
d0e92aad
JY
941 Status = gBS->LocateHandleBuffer (\r
942 ByProtocol,\r
943 &gEfiLoadedImageProtocolGuid,\r
944 NULL,\r
945 &NoHandles,\r
946 &HandleBuffer\r
947 );\r
948 if (EFI_ERROR (Status) && (NoHandles == 0)) {\r
949 return ;\r
950 }\r
951\r
952 for (Index = 0; Index < NoHandles; Index++) {\r
953 Status = gBS->HandleProtocol (\r
954 HandleBuffer[Index],\r
955 &gEfiLoadedImageProtocolGuid,\r
956 (VOID **)&LoadedImage\r
957 );\r
958 if (EFI_ERROR(Status)) {\r
959 continue;\r
960 }\r
961 Status = gBS->HandleProtocol (\r
962 HandleBuffer[Index],\r
963 &gEfiLoadedImageDevicePathProtocolGuid,\r
964 (VOID **)&LoadedImageDevicePath\r
965 );\r
966 if (EFI_ERROR(Status)) {\r
967 LoadedImageDevicePath = NULL;\r
968 }\r
969\r
970 ProtectUefiImage (LoadedImage, LoadedImageDevicePath);\r
971 }\r
972\r
973 CoreCloseEvent (Event);\r
974 return;\r
975}\r
976\r
977/**\r
978 ExitBootServices Callback function for memory protection.\r
979**/\r
980VOID\r
981MemoryProtectionExitBootServicesCallback (\r
982 VOID\r
983 )\r
984{\r
985 EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage;\r
986 LIST_ENTRY *Link;\r
987\r
988 //\r
989 // We need remove the RT protection, because RT relocation need write code segment\r
990 // at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time.\r
991 //\r
992 // Firmware does not own page tables after ExitBootServices(), so the OS would\r
993 // have to relax protection of RT code pages across SetVirtualAddressMap(), or\r
994 // delay setting protections on RT code pages until after SetVirtualAddressMap().\r
995 // OS may set protection on RT based upon EFI_MEMORY_ATTRIBUTES_TABLE later.\r
996 //\r
997 if (mImageProtectionPolicy != 0) {\r
998 for (Link = gRuntime->ImageHead.ForwardLink; Link != &gRuntime->ImageHead; Link = Link->ForwardLink) {\r
999 RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);\r
1000 SetUefiImageMemoryAttributes ((UINT64)(UINTN)RuntimeImage->ImageBase, ALIGN_VALUE(RuntimeImage->ImageSize, EFI_PAGE_SIZE), 0);\r
1001 }\r
1002 }\r
1003}\r
1004\r
1005/**\r
1006 Initialize Memory Protection support.\r
1007**/\r
1008VOID\r
1009EFIAPI\r
1010CoreInitializeMemoryProtection (\r
1011 VOID\r
1012 )\r
1013{\r
1014 EFI_STATUS Status;\r
1015 EFI_EVENT Event;\r
1016 VOID *Registration;\r
1017\r
1018 mImageProtectionPolicy = PcdGet32(PcdImageProtectionPolicy);\r
1019\r
7eb927db
AB
1020 //\r
1021 // Sanity check the PcdDxeNxMemoryProtectionPolicy setting:\r
1022 // - code regions should have no EFI_MEMORY_XP attribute\r
1023 // - EfiConventionalMemory and EfiBootServicesData should use the\r
1024 // same attribute\r
1025 //\r
1026 ASSERT ((GetPermissionAttributeForMemoryType (EfiBootServicesCode) & EFI_MEMORY_XP) == 0);\r
1027 ASSERT ((GetPermissionAttributeForMemoryType (EfiRuntimeServicesCode) & EFI_MEMORY_XP) == 0);\r
1028 ASSERT ((GetPermissionAttributeForMemoryType (EfiLoaderCode) & EFI_MEMORY_XP) == 0);\r
1029 ASSERT (GetPermissionAttributeForMemoryType (EfiBootServicesData) ==\r
1030 GetPermissionAttributeForMemoryType (EfiConventionalMemory));\r
1031\r
1032 if (mImageProtectionPolicy != 0 || PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {\r
d0e92aad
JY
1033 Status = CoreCreateEvent (\r
1034 EVT_NOTIFY_SIGNAL,\r
1035 TPL_CALLBACK,\r
1036 MemoryProtectionCpuArchProtocolNotify,\r
1037 NULL,\r
1038 &Event\r
1039 );\r
1040 ASSERT_EFI_ERROR(Status);\r
1041\r
1042 //\r
1043 // Register for protocol notifactions on this event\r
1044 //\r
1045 Status = CoreRegisterProtocolNotify (\r
1046 &gEfiCpuArchProtocolGuid,\r
1047 Event,\r
1048 &Registration\r
1049 );\r
1050 ASSERT_EFI_ERROR(Status);\r
1051 }\r
1052 return ;\r
1053}\r
7eb927db
AB
1054\r
1055/**\r
1056 Returns whether we are currently executing in SMM mode\r
1057**/\r
1058STATIC\r
1059BOOLEAN\r
1060IsInSmm (\r
1061 VOID\r
1062 )\r
1063{\r
1064 BOOLEAN InSmm;\r
1065\r
1066 InSmm = FALSE;\r
1067 if (gSmmBase2 != NULL) {\r
1068 gSmmBase2->InSmm (gSmmBase2, &InSmm);\r
1069 }\r
1070 return InSmm;\r
1071}\r
1072\r
1073/**\r
1074 Manage memory permission attributes on a memory range, according to the\r
1075 configured DXE memory protection policy.\r
1076\r
1077 @param OldType The old memory type of the range\r
1078 @param NewType The new memory type of the range\r
1079 @param Memory The base address of the range\r
1080 @param Length The size of the range (in bytes)\r
1081\r
1082 @return EFI_SUCCESS If we are executing in SMM mode. No permission attributes\r
1083 are updated in this case\r
1084 @return EFI_SUCCESS If the the CPU arch protocol is not installed yet\r
1085 @return EFI_SUCCESS If no DXE memory protection policy has been configured\r
1086 @return EFI_SUCCESS If OldType and NewType use the same permission attributes\r
1087 @return other Return value of gCpu->SetMemoryAttributes()\r
1088\r
1089**/\r
1090EFI_STATUS\r
1091EFIAPI\r
1092ApplyMemoryProtectionPolicy (\r
1093 IN EFI_MEMORY_TYPE OldType,\r
1094 IN EFI_MEMORY_TYPE NewType,\r
1095 IN EFI_PHYSICAL_ADDRESS Memory,\r
1096 IN UINT64 Length\r
1097 )\r
1098{\r
1099 UINT64 OldAttributes;\r
1100 UINT64 NewAttributes;\r
1101\r
1102 //\r
1103 // The policy configured in PcdDxeNxMemoryProtectionPolicy\r
1104 // does not apply to allocations performed in SMM mode.\r
1105 //\r
1106 if (IsInSmm ()) {\r
1107 return EFI_SUCCESS;\r
1108 }\r
1109\r
1110 //\r
1111 // If the CPU arch protocol is not installed yet, we cannot manage memory\r
1112 // permission attributes, and it is the job of the driver that installs this\r
1113 // protocol to set the permissions on existing allocations.\r
1114 //\r
1115 if (gCpu == NULL) {\r
1116 return EFI_SUCCESS;\r
1117 }\r
1118\r
1119 //\r
1120 // Check if a DXE memory protection policy has been configured\r
1121 //\r
1122 if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) == 0) {\r
1123 return EFI_SUCCESS;\r
1124 }\r
1125\r
1126 //\r
1127 // Update the executable permissions according to the DXE memory\r
1128 // protection policy, but only if\r
1129 // - the policy is different between the old and the new type, or\r
1130 // - this is a newly added region (OldType == EfiMaxMemoryType)\r
1131 //\r
1132 NewAttributes = GetPermissionAttributeForMemoryType (NewType);\r
1133\r
1134 if (OldType != EfiMaxMemoryType) {\r
1135 OldAttributes = GetPermissionAttributeForMemoryType (OldType);\r
1136 if (OldAttributes == NewAttributes) {\r
1137 // policy is the same between OldType and NewType\r
1138 return EFI_SUCCESS;\r
1139 }\r
1140 } else if (NewAttributes == 0) {\r
1141 // newly added region of a type that does not require protection\r
1142 return EFI_SUCCESS;\r
1143 }\r
1144\r
1145 return gCpu->SetMemoryAttributes (gCpu, Memory, Length, NewAttributes);\r
1146}\r