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