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