]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
ArmVirtPkg/HighMemDxe: check new regions against GCD memory space map
[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
d4731a98 347 PageAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
d0e92aad
JY
348 break;\r
349 case EfiRuntimeServicesData:\r
350 case EfiACPIReclaimMemory:\r
351 ASSERT (FALSE);\r
d4731a98 352 PageAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
d0e92aad
JY
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
38b15ebe
LE
583 //\r
584 // If a UEFI executable consists of a single read+write+exec PE/COFF\r
585 // section, that isn't actually an error. The image can be launched\r
586 // alright, only image protection cannot be applied to it fully.\r
587 //\r
588 // One example that elicits this is (some) Linux kernels (with the EFI stub\r
589 // of course).\r
590 //\r
591 DEBUG ((DEBUG_WARN, "!!!!!!!! ProtectUefiImageCommon - CodeSegmentCount is 0 !!!!!!!!\n"));\r
d0e92aad
JY
592 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
593 if (PdbPointer != NULL) {\r
38b15ebe 594 DEBUG ((DEBUG_WARN, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));\r
d0e92aad
JY
595 }\r
596 goto Finish;\r
597 }\r
598\r
599 //\r
600 // Final\r
601 //\r
602 SortImageRecordCodeSection (ImageRecord);\r
603 //\r
604 // Check overlap all section in ImageBase/Size\r
605 //\r
606 if (!IsImageRecordCodeSectionValid (ImageRecord)) {\r
607 DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));\r
608 goto Finish;\r
609 }\r
610\r
611 //\r
612 // Round up the ImageSize, some CPU arch may return EFI_UNSUPPORTED if ImageSize is not aligned.\r
613 // Given that the loader always allocates full pages, we know the space after the image is not used.\r
614 //\r
615 ImageRecord->ImageSize = ALIGN_VALUE(LoadedImage->ImageSize, EFI_PAGE_SIZE);\r
616\r
617 //\r
618 // CPU ARCH present. Update memory attribute directly.\r
619 //\r
620 SetUefiImageProtectionAttributes (ImageRecord, Protect);\r
621\r
622 //\r
623 // Clean up\r
624 //\r
625 FreeImageRecord (ImageRecord);\r
626\r
627Finish:\r
628 return ;\r
629}\r
630\r
631/**\r
632 Protect UEFI image.\r
633\r
634 @param[in] LoadedImage The loaded image protocol\r
635 @param[in] LoadedImageDevicePath The loaded image device path protocol\r
636**/\r
637VOID\r
638ProtectUefiImage (\r
639 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
640 IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath\r
641 )\r
642{\r
643 if (PcdGet32(PcdImageProtectionPolicy) != 0) {\r
644 ProtectUefiImageCommon (LoadedImage, LoadedImageDevicePath, TRUE);\r
645 }\r
646}\r
647\r
648/**\r
649 Unprotect UEFI image.\r
650\r
651 @param[in] LoadedImage The loaded image protocol\r
652 @param[in] LoadedImageDevicePath The loaded image device path protocol\r
653**/\r
654VOID\r
655UnprotectUefiImage (\r
656 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,\r
657 IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath\r
658 )\r
659{\r
660 if (PcdGet32(PcdImageProtectionPolicy) != 0) {\r
661 ProtectUefiImageCommon (LoadedImage, LoadedImageDevicePath, FALSE);\r
662 }\r
663}\r
664\r
7eb927db
AB
665/**\r
666 Return the EFI memory permission attribute associated with memory\r
667 type 'MemoryType' under the configured DXE memory protection policy.\r
7babb437
BD
668\r
669 @param MemoryType Memory type.\r
7eb927db
AB
670**/\r
671STATIC\r
672UINT64\r
673GetPermissionAttributeForMemoryType (\r
674 IN EFI_MEMORY_TYPE MemoryType\r
675 )\r
676{\r
677 UINT64 TestBit;\r
678\r
679 if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {\r
680 TestBit = BIT63;\r
681 } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {\r
682 TestBit = BIT62;\r
683 } else {\r
684 TestBit = LShiftU64 (1, MemoryType);\r
685 }\r
686\r
687 if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & TestBit) != 0) {\r
688 return EFI_MEMORY_XP;\r
689 } else {\r
690 return 0;\r
691 }\r
692}\r
693\r
694/**\r
695 Sort memory map entries based upon PhysicalStart, from low to high.\r
696\r
697 @param MemoryMap A pointer to the buffer in which firmware places\r
698 the current memory map.\r
699 @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.\r
700 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
701**/\r
702STATIC\r
703VOID\r
704SortMemoryMap (\r
705 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
706 IN UINTN MemoryMapSize,\r
707 IN UINTN DescriptorSize\r
708 )\r
709{\r
710 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
711 EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;\r
712 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
713 EFI_MEMORY_DESCRIPTOR TempMemoryMap;\r
714\r
715 MemoryMapEntry = MemoryMap;\r
716 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
717 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
718 while (MemoryMapEntry < MemoryMapEnd) {\r
719 while (NextMemoryMapEntry < MemoryMapEnd) {\r
720 if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {\r
721 CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
722 CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
723 CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));\r
724 }\r
725\r
726 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
727 }\r
728\r
729 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
730 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
731 }\r
732}\r
733\r
734/**\r
735 Merge adjacent memory map entries if they use the same memory protection policy\r
736\r
737 @param[in, out] MemoryMap A pointer to the buffer in which firmware places\r
738 the current memory map.\r
739 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the\r
740 MemoryMap buffer. On input, this is the size of\r
741 the current memory map. On output,\r
742 it is the size of new memory map after merge.\r
743 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
744**/\r
745STATIC\r
746VOID\r
747MergeMemoryMapForProtectionPolicy (\r
748 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
749 IN OUT UINTN *MemoryMapSize,\r
750 IN UINTN DescriptorSize\r
751 )\r
752{\r
753 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
754 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
755 UINT64 MemoryBlockLength;\r
756 EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;\r
757 EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;\r
758 UINT64 Attributes;\r
759\r
760 SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);\r
761\r
762 MemoryMapEntry = MemoryMap;\r
763 NewMemoryMapEntry = MemoryMap;\r
764 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);\r
765 while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {\r
766 CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
767 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
768\r
769 do {\r
770 MemoryBlockLength = (UINT64) (EFI_PAGES_TO_SIZE((UINTN)MemoryMapEntry->NumberOfPages));\r
771 Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);\r
772\r
773 if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&\r
774 Attributes == GetPermissionAttributeForMemoryType (NextMemoryMapEntry->Type) &&\r
775 ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {\r
776 MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
777 if (NewMemoryMapEntry != MemoryMapEntry) {\r
778 NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
779 }\r
780\r
781 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
782 continue;\r
783 } else {\r
784 MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
785 break;\r
786 }\r
787 } while (TRUE);\r
788\r
789 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
790 NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);\r
791 }\r
792\r
793 *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;\r
794\r
795 return ;\r
796}\r
797\r
798\r
799/**\r
800 Remove exec permissions from all regions whose type is identified by\r
7babb437 801 PcdDxeNxMemoryProtectionPolicy.\r
7eb927db
AB
802**/\r
803STATIC\r
804VOID\r
805InitializeDxeNxMemoryProtectionPolicy (\r
806 VOID\r
807 )\r
808{\r
809 UINTN MemoryMapSize;\r
810 UINTN MapKey;\r
811 UINTN DescriptorSize;\r
812 UINT32 DescriptorVersion;\r
813 EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
814 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
815 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
816 EFI_STATUS Status;\r
817 UINT64 Attributes;\r
818 LIST_ENTRY *Link;\r
819 EFI_GCD_MAP_ENTRY *Entry;\r
820\r
821 //\r
822 // Get the EFI memory map.\r
823 //\r
824 MemoryMapSize = 0;\r
825 MemoryMap = NULL;\r
826\r
827 Status = gBS->GetMemoryMap (\r
828 &MemoryMapSize,\r
829 MemoryMap,\r
830 &MapKey,\r
831 &DescriptorSize,\r
832 &DescriptorVersion\r
833 );\r
834 ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
835 do {\r
836 MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize);\r
837 ASSERT (MemoryMap != NULL);\r
838 Status = gBS->GetMemoryMap (\r
839 &MemoryMapSize,\r
840 MemoryMap,\r
841 &MapKey,\r
842 &DescriptorSize,\r
843 &DescriptorVersion\r
844 );\r
845 if (EFI_ERROR (Status)) {\r
846 FreePool (MemoryMap);\r
847 }\r
848 } while (Status == EFI_BUFFER_TOO_SMALL);\r
849 ASSERT_EFI_ERROR (Status);\r
850\r
851 DEBUG((DEBUG_ERROR, "%a: applying strict permissions to active memory regions\n",\r
852 __FUNCTION__));\r
853\r
854 MergeMemoryMapForProtectionPolicy (MemoryMap, &MemoryMapSize, DescriptorSize);\r
855\r
856 MemoryMapEntry = MemoryMap;\r
857 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
858 while ((UINTN) MemoryMapEntry < (UINTN) MemoryMapEnd) {\r
859\r
860 Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);\r
861 if (Attributes != 0) {\r
862 SetUefiImageMemoryAttributes (\r
863 MemoryMapEntry->PhysicalStart,\r
4879e130 864 LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT),\r
7eb927db
AB
865 Attributes);\r
866 }\r
867 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
868 }\r
869 FreePool (MemoryMap);\r
870\r
871 //\r
872 // Apply the policy for RAM regions that we know are present and\r
873 // accessible, but have not been added to the UEFI memory map (yet).\r
874 //\r
875 if (GetPermissionAttributeForMemoryType (EfiConventionalMemory) != 0) {\r
876 DEBUG((DEBUG_ERROR,\r
877 "%a: applying strict permissions to inactive memory regions\n",\r
878 __FUNCTION__));\r
879\r
880 CoreAcquireGcdMemoryLock ();\r
881\r
882 Link = mGcdMemorySpaceMap.ForwardLink;\r
883 while (Link != &mGcdMemorySpaceMap) {\r
884\r
885 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
886\r
887 if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&\r
888 Entry->EndAddress < MAX_ADDRESS &&\r
889 (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==\r
890 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {\r
891\r
892 Attributes = GetPermissionAttributeForMemoryType (EfiConventionalMemory) |\r
893 (Entry->Attributes & CACHE_ATTRIBUTE_MASK);\r
894\r
895 DEBUG ((DEBUG_INFO,\r
896 "Untested GCD memory space region: - 0x%016lx - 0x%016lx (0x%016lx)\n",\r
897 Entry->BaseAddress, Entry->EndAddress - Entry->BaseAddress + 1,\r
898 Attributes));\r
899\r
900 ASSERT(gCpu != NULL);\r
901 gCpu->SetMemoryAttributes (gCpu, Entry->BaseAddress,\r
902 Entry->EndAddress - Entry->BaseAddress + 1, Attributes);\r
903 }\r
904\r
905 Link = Link->ForwardLink;\r
906 }\r
907 CoreReleaseGcdMemoryLock ();\r
908 }\r
909}\r
910\r
911\r
d0e92aad
JY
912/**\r
913 A notification for CPU_ARCH protocol.\r
914\r
915 @param[in] Event Event whose notification function is being invoked.\r
916 @param[in] Context Pointer to the notification function's context,\r
917 which is implementation-dependent.\r
918\r
919**/\r
920VOID\r
921EFIAPI\r
922MemoryProtectionCpuArchProtocolNotify (\r
923 IN EFI_EVENT Event,\r
924 IN VOID *Context\r
925 )\r
926{\r
927 EFI_STATUS Status;\r
928 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
929 EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;\r
930 UINTN NoHandles;\r
931 EFI_HANDLE *HandleBuffer;\r
932 UINTN Index;\r
933\r
934 DEBUG ((DEBUG_INFO, "MemoryProtectionCpuArchProtocolNotify:\n"));\r
935 Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);\r
936 if (EFI_ERROR (Status)) {\r
937 return;\r
938 }\r
939\r
7eb927db
AB
940 //\r
941 // Apply the memory protection policy on non-BScode/RTcode regions.\r
942 //\r
943 if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {\r
944 InitializeDxeNxMemoryProtectionPolicy ();\r
945 }\r
946\r
947 if (mImageProtectionPolicy == 0) {\r
948 return;\r
949 }\r
950\r
d0e92aad
JY
951 Status = gBS->LocateHandleBuffer (\r
952 ByProtocol,\r
953 &gEfiLoadedImageProtocolGuid,\r
954 NULL,\r
955 &NoHandles,\r
956 &HandleBuffer\r
957 );\r
958 if (EFI_ERROR (Status) && (NoHandles == 0)) {\r
959 return ;\r
960 }\r
961\r
962 for (Index = 0; Index < NoHandles; Index++) {\r
963 Status = gBS->HandleProtocol (\r
964 HandleBuffer[Index],\r
965 &gEfiLoadedImageProtocolGuid,\r
966 (VOID **)&LoadedImage\r
967 );\r
968 if (EFI_ERROR(Status)) {\r
969 continue;\r
970 }\r
971 Status = gBS->HandleProtocol (\r
972 HandleBuffer[Index],\r
973 &gEfiLoadedImageDevicePathProtocolGuid,\r
974 (VOID **)&LoadedImageDevicePath\r
975 );\r
976 if (EFI_ERROR(Status)) {\r
977 LoadedImageDevicePath = NULL;\r
978 }\r
979\r
980 ProtectUefiImage (LoadedImage, LoadedImageDevicePath);\r
981 }\r
982\r
983 CoreCloseEvent (Event);\r
984 return;\r
985}\r
986\r
987/**\r
988 ExitBootServices Callback function for memory protection.\r
989**/\r
990VOID\r
991MemoryProtectionExitBootServicesCallback (\r
992 VOID\r
993 )\r
994{\r
995 EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage;\r
996 LIST_ENTRY *Link;\r
997\r
998 //\r
999 // We need remove the RT protection, because RT relocation need write code segment\r
1000 // at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time.\r
1001 //\r
1002 // Firmware does not own page tables after ExitBootServices(), so the OS would\r
1003 // have to relax protection of RT code pages across SetVirtualAddressMap(), or\r
1004 // delay setting protections on RT code pages until after SetVirtualAddressMap().\r
1005 // OS may set protection on RT based upon EFI_MEMORY_ATTRIBUTES_TABLE later.\r
1006 //\r
1007 if (mImageProtectionPolicy != 0) {\r
1008 for (Link = gRuntime->ImageHead.ForwardLink; Link != &gRuntime->ImageHead; Link = Link->ForwardLink) {\r
1009 RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);\r
1010 SetUefiImageMemoryAttributes ((UINT64)(UINTN)RuntimeImage->ImageBase, ALIGN_VALUE(RuntimeImage->ImageSize, EFI_PAGE_SIZE), 0);\r
1011 }\r
1012 }\r
1013}\r
1014\r
1015/**\r
1016 Initialize Memory Protection support.\r
1017**/\r
1018VOID\r
1019EFIAPI\r
1020CoreInitializeMemoryProtection (\r
1021 VOID\r
1022 )\r
1023{\r
1024 EFI_STATUS Status;\r
1025 EFI_EVENT Event;\r
1026 VOID *Registration;\r
1027\r
1028 mImageProtectionPolicy = PcdGet32(PcdImageProtectionPolicy);\r
1029\r
7eb927db
AB
1030 //\r
1031 // Sanity check the PcdDxeNxMemoryProtectionPolicy setting:\r
1032 // - code regions should have no EFI_MEMORY_XP attribute\r
1033 // - EfiConventionalMemory and EfiBootServicesData should use the\r
1034 // same attribute\r
1035 //\r
1036 ASSERT ((GetPermissionAttributeForMemoryType (EfiBootServicesCode) & EFI_MEMORY_XP) == 0);\r
1037 ASSERT ((GetPermissionAttributeForMemoryType (EfiRuntimeServicesCode) & EFI_MEMORY_XP) == 0);\r
1038 ASSERT ((GetPermissionAttributeForMemoryType (EfiLoaderCode) & EFI_MEMORY_XP) == 0);\r
1039 ASSERT (GetPermissionAttributeForMemoryType (EfiBootServicesData) ==\r
1040 GetPermissionAttributeForMemoryType (EfiConventionalMemory));\r
1041\r
1042 if (mImageProtectionPolicy != 0 || PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {\r
d0e92aad
JY
1043 Status = CoreCreateEvent (\r
1044 EVT_NOTIFY_SIGNAL,\r
1045 TPL_CALLBACK,\r
1046 MemoryProtectionCpuArchProtocolNotify,\r
1047 NULL,\r
1048 &Event\r
1049 );\r
1050 ASSERT_EFI_ERROR(Status);\r
1051\r
1052 //\r
1053 // Register for protocol notifactions on this event\r
1054 //\r
1055 Status = CoreRegisterProtocolNotify (\r
1056 &gEfiCpuArchProtocolGuid,\r
1057 Event,\r
1058 &Registration\r
1059 );\r
1060 ASSERT_EFI_ERROR(Status);\r
1061 }\r
1062 return ;\r
1063}\r
7eb927db
AB
1064\r
1065/**\r
7babb437 1066 Returns whether we are currently executing in SMM mode.\r
7eb927db
AB
1067**/\r
1068STATIC\r
1069BOOLEAN\r
1070IsInSmm (\r
1071 VOID\r
1072 )\r
1073{\r
1074 BOOLEAN InSmm;\r
1075\r
1076 InSmm = FALSE;\r
1077 if (gSmmBase2 != NULL) {\r
1078 gSmmBase2->InSmm (gSmmBase2, &InSmm);\r
1079 }\r
1080 return InSmm;\r
1081}\r
1082\r
1083/**\r
1084 Manage memory permission attributes on a memory range, according to the\r
1085 configured DXE memory protection policy.\r
1086\r
1087 @param OldType The old memory type of the range\r
1088 @param NewType The new memory type of the range\r
1089 @param Memory The base address of the range\r
1090 @param Length The size of the range (in bytes)\r
1091\r
1092 @return EFI_SUCCESS If we are executing in SMM mode. No permission attributes\r
1093 are updated in this case\r
1094 @return EFI_SUCCESS If the the CPU arch protocol is not installed yet\r
1095 @return EFI_SUCCESS If no DXE memory protection policy has been configured\r
1096 @return EFI_SUCCESS If OldType and NewType use the same permission attributes\r
1097 @return other Return value of gCpu->SetMemoryAttributes()\r
1098\r
1099**/\r
1100EFI_STATUS\r
1101EFIAPI\r
1102ApplyMemoryProtectionPolicy (\r
1103 IN EFI_MEMORY_TYPE OldType,\r
1104 IN EFI_MEMORY_TYPE NewType,\r
1105 IN EFI_PHYSICAL_ADDRESS Memory,\r
1106 IN UINT64 Length\r
1107 )\r
1108{\r
1109 UINT64 OldAttributes;\r
1110 UINT64 NewAttributes;\r
1111\r
1112 //\r
1113 // The policy configured in PcdDxeNxMemoryProtectionPolicy\r
1114 // does not apply to allocations performed in SMM mode.\r
1115 //\r
1116 if (IsInSmm ()) {\r
1117 return EFI_SUCCESS;\r
1118 }\r
1119\r
1120 //\r
1121 // If the CPU arch protocol is not installed yet, we cannot manage memory\r
1122 // permission attributes, and it is the job of the driver that installs this\r
1123 // protocol to set the permissions on existing allocations.\r
1124 //\r
1125 if (gCpu == NULL) {\r
1126 return EFI_SUCCESS;\r
1127 }\r
1128\r
1129 //\r
1130 // Check if a DXE memory protection policy has been configured\r
1131 //\r
1132 if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) == 0) {\r
1133 return EFI_SUCCESS;\r
1134 }\r
1135\r
1136 //\r
1137 // Update the executable permissions according to the DXE memory\r
1138 // protection policy, but only if\r
1139 // - the policy is different between the old and the new type, or\r
1140 // - this is a newly added region (OldType == EfiMaxMemoryType)\r
1141 //\r
1142 NewAttributes = GetPermissionAttributeForMemoryType (NewType);\r
1143\r
1144 if (OldType != EfiMaxMemoryType) {\r
1145 OldAttributes = GetPermissionAttributeForMemoryType (OldType);\r
1146 if (OldAttributes == NewAttributes) {\r
1147 // policy is the same between OldType and NewType\r
1148 return EFI_SUCCESS;\r
1149 }\r
1150 } else if (NewAttributes == 0) {\r
1151 // newly added region of a type that does not require protection\r
1152 return EFI_SUCCESS;\r
1153 }\r
1154\r
1155 return gCpu->SetMemoryAttributes (gCpu, Memory, Length, NewAttributes);\r
1156}\r