]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Misc/PropertiesTable.c
MdeModulePkg: Fix Memory Attributes table type issue
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Misc / PropertiesTable.c
CommitLineData
03d486b2
JY
1/** @file\r
2 UEFI PropertiesTable support\r
3\r
82f0f411 4Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
03d486b2
JY
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <PiDxe.h>\r
16#include <Library/BaseLib.h>\r
17#include <Library/BaseMemoryLib.h>\r
18#include <Library/MemoryAllocationLib.h>\r
19#include <Library/UefiBootServicesTableLib.h>\r
20#include <Library/DxeServicesTableLib.h>\r
21#include <Library/DebugLib.h>\r
22#include <Library/UefiLib.h>\r
23#include <Library/PcdLib.h>\r
24\r
25#include <Guid/EventGroup.h>\r
26#include <Protocol/DxeSmmReadyToLock.h>\r
27\r
28#include <Library/PeCoffLib.h>\r
29#include <Library/PeCoffGetEntryPointLib.h>\r
30#include <Protocol/Runtime.h>\r
31\r
32#include <Guid/PropertiesTable.h>\r
33\r
34#include "DxeMain.h"\r
35\r
36#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \\r
37 ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))\r
38\r
39#define IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE SIGNATURE_32 ('I','P','R','C')\r
40\r
41typedef struct {\r
42 UINT32 Signature;\r
43 LIST_ENTRY Link;\r
44 EFI_PHYSICAL_ADDRESS CodeSegmentBase;\r
45 UINT64 CodeSegmentSize;\r
46} IMAGE_PROPERTIES_RECORD_CODE_SECTION;\r
47\r
48#define IMAGE_PROPERTIES_RECORD_SIGNATURE SIGNATURE_32 ('I','P','R','D')\r
49\r
50typedef struct {\r
51 UINT32 Signature;\r
52 LIST_ENTRY Link;\r
53 EFI_PHYSICAL_ADDRESS ImageBase;\r
54 UINT64 ImageSize;\r
55 UINTN CodeSegmentCount;\r
56 LIST_ENTRY CodeSegmentList;\r
57} IMAGE_PROPERTIES_RECORD;\r
58\r
59#define IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I','P','P','D')\r
60\r
61typedef struct {\r
62 UINT32 Signature;\r
63 UINTN ImageRecordCount;\r
64 UINTN CodeSegmentCountMax;\r
65 LIST_ENTRY ImageRecordList;\r
66} IMAGE_PROPERTIES_PRIVATE_DATA;\r
67\r
68IMAGE_PROPERTIES_PRIVATE_DATA mImagePropertiesPrivateData = {\r
69 IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE,\r
70 0,\r
71 0,\r
72 INITIALIZE_LIST_HEAD_VARIABLE (mImagePropertiesPrivateData.ImageRecordList)\r
73};\r
74\r
75EFI_PROPERTIES_TABLE mPropertiesTable = {\r
76 EFI_PROPERTIES_TABLE_VERSION,\r
77 sizeof(EFI_PROPERTIES_TABLE),\r
78 EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA\r
79};\r
80\r
81EFI_LOCK mPropertiesTableLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);\r
82\r
82f0f411 83BOOLEAN mPropertiesTableEnable;\r
f5a91bba 84\r
03d486b2
JY
85//\r
86// Below functions are for MemoryMap\r
87//\r
88\r
89/**\r
90 Converts a number of EFI_PAGEs to a size in bytes.\r
91\r
92 NOTE: Do not use EFI_PAGES_TO_SIZE because it handles UINTN only.\r
93\r
94 @param Pages The number of EFI_PAGES.\r
95\r
96 @return The number of bytes associated with the number of EFI_PAGEs specified\r
97 by Pages.\r
98**/\r
2caab142 99STATIC\r
03d486b2
JY
100UINT64\r
101EfiPagesToSize (\r
102 IN UINT64 Pages\r
103 )\r
104{\r
105 return LShiftU64 (Pages, EFI_PAGE_SHIFT);\r
106}\r
107\r
108/**\r
109 Converts a size, in bytes, to a number of EFI_PAGESs.\r
110\r
111 NOTE: Do not use EFI_SIZE_TO_PAGES because it handles UINTN only.\r
112\r
113 @param Size A size in bytes.\r
114\r
115 @return The number of EFI_PAGESs associated with the number of bytes specified\r
116 by Size.\r
117\r
118**/\r
2caab142 119STATIC\r
03d486b2
JY
120UINT64\r
121EfiSizeToPages (\r
122 IN UINT64 Size\r
123 )\r
124{\r
125 return RShiftU64 (Size, EFI_PAGE_SHIFT) + ((((UINTN)Size) & EFI_PAGE_MASK) ? 1 : 0);\r
126}\r
127\r
128/**\r
129 Acquire memory lock on mPropertiesTableLock.\r
130**/\r
2caab142 131STATIC\r
03d486b2
JY
132VOID\r
133CoreAcquirePropertiesTableLock (\r
134 VOID\r
135 )\r
136{\r
137 CoreAcquireLock (&mPropertiesTableLock);\r
138}\r
139\r
140/**\r
141 Release memory lock on mPropertiesTableLock.\r
142**/\r
2caab142 143STATIC\r
03d486b2
JY
144VOID\r
145CoreReleasePropertiesTableLock (\r
146 VOID\r
147 )\r
148{\r
149 CoreReleaseLock (&mPropertiesTableLock);\r
150}\r
151\r
03d486b2
JY
152/**\r
153 Sort memory map entries based upon PhysicalStart, from low to high.\r
154\r
155 @param MemoryMap A pointer to the buffer in which firmware places\r
156 the current memory map.\r
157 @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.\r
158 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
159**/\r
2caab142 160STATIC\r
03d486b2
JY
161VOID\r
162SortMemoryMap (\r
163 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
164 IN UINTN MemoryMapSize,\r
165 IN UINTN DescriptorSize\r
166 )\r
167{\r
168 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
169 EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;\r
170 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
171 EFI_MEMORY_DESCRIPTOR TempMemoryMap;\r
172\r
173 MemoryMapEntry = MemoryMap;\r
174 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
175 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
176 while (MemoryMapEntry < MemoryMapEnd) {\r
177 while (NextMemoryMapEntry < MemoryMapEnd) {\r
178 if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {\r
179 CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
180 CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
181 CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));\r
182 }\r
183\r
184 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
185 }\r
186\r
187 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
188 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
189 }\r
190\r
191 return ;\r
192}\r
193\r
194/**\r
195 Merge continous memory map entries whose have same attributes.\r
196\r
197 @param MemoryMap A pointer to the buffer in which firmware places\r
198 the current memory map.\r
199 @param MemoryMapSize A pointer to the size, in bytes, of the\r
200 MemoryMap buffer. On input, this is the size of\r
201 the current memory map. On output,\r
202 it is the size of new memory map after merge.\r
203 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
204**/\r
2caab142 205STATIC\r
03d486b2
JY
206VOID\r
207MergeMemoryMap (\r
208 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
209 IN OUT UINTN *MemoryMapSize,\r
210 IN UINTN DescriptorSize\r
211 )\r
212{\r
213 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
214 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
215 UINT64 MemoryBlockLength;\r
216 EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;\r
217 EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;\r
218\r
219 MemoryMapEntry = MemoryMap;\r
220 NewMemoryMapEntry = MemoryMap;\r
221 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);\r
222 while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {\r
223 CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
224 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
225\r
f5a91bba
JY
226 do {\r
227 MemoryBlockLength = (UINT64) (EfiPagesToSize (MemoryMapEntry->NumberOfPages));\r
228 if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&\r
229 (MemoryMapEntry->Type == NextMemoryMapEntry->Type) &&\r
230 (MemoryMapEntry->Attribute == NextMemoryMapEntry->Attribute) &&\r
82f0f411 231 ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {\r
f5a91bba
JY
232 MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
233 if (NewMemoryMapEntry != MemoryMapEntry) {\r
234 NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
235 }\r
236\r
237 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
238 continue;\r
239 } else {\r
240 MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
241 break;\r
242 }\r
243 } while (TRUE);\r
03d486b2
JY
244\r
245 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
246 NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);\r
247 }\r
248\r
249 *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;\r
250\r
251 return ;\r
252}\r
253\r
254/**\r
255 Enforce memory map attributes.\r
256 This function will set EfiRuntimeServicesData/EfiMemoryMappedIO/EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP.\r
257\r
258 @param MemoryMap A pointer to the buffer in which firmware places\r
259 the current memory map.\r
260 @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.\r
261 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
262**/\r
2caab142 263STATIC\r
03d486b2
JY
264VOID\r
265EnforceMemoryMapAttribute (\r
266 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
267 IN UINTN MemoryMapSize,\r
268 IN UINTN DescriptorSize\r
269 )\r
270{\r
271 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
272 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
273\r
274 MemoryMapEntry = MemoryMap;\r
275 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
276 while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {\r
277 switch (MemoryMapEntry->Type) {\r
278 case EfiRuntimeServicesCode:\r
279 // do nothing\r
280 break;\r
281 case EfiRuntimeServicesData:\r
282 case EfiMemoryMappedIO:\r
283 case EfiMemoryMappedIOPortSpace:\r
284 MemoryMapEntry->Attribute |= EFI_MEMORY_XP;\r
285 break;\r
286 case EfiReservedMemoryType:\r
287 case EfiACPIMemoryNVS:\r
288 break;\r
289 }\r
290\r
291 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
292 }\r
293\r
294 return ;\r
295}\r
296\r
03d486b2
JY
297/**\r
298 Return the first image record, whose [ImageBase, ImageSize] covered by [Buffer, Length].\r
299\r
300 @param Buffer Start Address\r
301 @param Length Address length\r
302\r
303 @return first image record covered by [buffer, length]\r
304**/\r
2caab142 305STATIC\r
03d486b2
JY
306IMAGE_PROPERTIES_RECORD *\r
307GetImageRecordByAddress (\r
308 IN EFI_PHYSICAL_ADDRESS Buffer,\r
309 IN UINT64 Length\r
310 )\r
311{\r
312 IMAGE_PROPERTIES_RECORD *ImageRecord;\r
313 LIST_ENTRY *ImageRecordLink;\r
314 LIST_ENTRY *ImageRecordList;\r
315\r
316 ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;\r
317\r
318 for (ImageRecordLink = ImageRecordList->ForwardLink;\r
319 ImageRecordLink != ImageRecordList;\r
320 ImageRecordLink = ImageRecordLink->ForwardLink) {\r
321 ImageRecord = CR (\r
322 ImageRecordLink,\r
323 IMAGE_PROPERTIES_RECORD,\r
324 Link,\r
325 IMAGE_PROPERTIES_RECORD_SIGNATURE\r
326 );\r
327\r
328 if ((Buffer <= ImageRecord->ImageBase) &&\r
329 (Buffer + Length >= ImageRecord->ImageBase + ImageRecord->ImageSize)) {\r
330 return ImageRecord;\r
331 }\r
332 }\r
333\r
334 return NULL;\r
335}\r
336\r
337/**\r
338 Set the memory map to new entries, according to one old entry,\r
339 based upon PE code section and data section in image record\r
340\r
341 @param ImageRecord An image record whose [ImageBase, ImageSize] covered\r
342 by old memory map entry.\r
343 @param NewRecord A pointer to several new memory map entries.\r
344 The caller gurantee the buffer size be 1 +\r
345 (SplitRecordCount * DescriptorSize) calculated\r
346 below.\r
347 @param OldRecord A pointer to one old memory map entry.\r
348 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
349**/\r
2caab142 350STATIC\r
03d486b2
JY
351UINTN\r
352SetNewRecord (\r
353 IN IMAGE_PROPERTIES_RECORD *ImageRecord,\r
354 IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,\r
355 IN EFI_MEMORY_DESCRIPTOR *OldRecord,\r
356 IN UINTN DescriptorSize\r
357 )\r
358{\r
359 EFI_MEMORY_DESCRIPTOR TempRecord;\r
360 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
361 LIST_ENTRY *ImageRecordCodeSectionLink;\r
362 LIST_ENTRY *ImageRecordCodeSectionEndLink;\r
363 LIST_ENTRY *ImageRecordCodeSectionList;\r
364 UINTN NewRecordCount;\r
365 UINT64 PhysicalEnd;\r
366 UINT64 ImageEnd;\r
367\r
368 CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR));\r
369 PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages);\r
370 NewRecordCount = 0;\r
371\r
372 ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;\r
373\r
374 ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;\r
375 ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;\r
376 while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {\r
377 ImageRecordCodeSection = CR (\r
378 ImageRecordCodeSectionLink,\r
379 IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
380 Link,\r
381 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
382 );\r
383 ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
384\r
385 if (TempRecord.PhysicalStart <= ImageRecordCodeSection->CodeSegmentBase) {\r
386 //\r
387 // DATA\r
388 //\r
82f0f411
JY
389 if (!mPropertiesTableEnable) {\r
390 NewRecord->Type = TempRecord.Type;\r
391 } else {\r
392 NewRecord->Type = EfiRuntimeServicesData;\r
393 }\r
03d486b2
JY
394 NewRecord->PhysicalStart = TempRecord.PhysicalStart;\r
395 NewRecord->VirtualStart = 0;\r
396 NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentBase - NewRecord->PhysicalStart);\r
397 NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;\r
398 if (NewRecord->NumberOfPages != 0) {\r
399 NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);\r
400 NewRecordCount ++;\r
401 }\r
402\r
403 //\r
404 // CODE\r
405 //\r
82f0f411
JY
406 if (!mPropertiesTableEnable) {\r
407 NewRecord->Type = TempRecord.Type;\r
408 } else {\r
409 NewRecord->Type = EfiRuntimeServicesCode;\r
410 }\r
03d486b2
JY
411 NewRecord->PhysicalStart = ImageRecordCodeSection->CodeSegmentBase;\r
412 NewRecord->VirtualStart = 0;\r
413 NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize);\r
414 NewRecord->Attribute = (TempRecord.Attribute & (~EFI_MEMORY_XP)) | EFI_MEMORY_RO;\r
415 if (NewRecord->NumberOfPages != 0) {\r
416 NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);\r
417 NewRecordCount ++;\r
418 }\r
419\r
420 TempRecord.PhysicalStart = ImageRecordCodeSection->CodeSegmentBase + EfiPagesToSize (EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize));\r
421 TempRecord.NumberOfPages = EfiSizeToPages(PhysicalEnd - TempRecord.PhysicalStart);\r
422 if (TempRecord.NumberOfPages == 0) {\r
423 break;\r
424 }\r
425 }\r
426 }\r
427\r
428 ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;\r
429\r
430 //\r
431 // Final DATA\r
432 //\r
433 if (TempRecord.PhysicalStart < ImageEnd) {\r
82f0f411
JY
434 if (!mPropertiesTableEnable) {\r
435 NewRecord->Type = TempRecord.Type;\r
436 } else {\r
437 NewRecord->Type = EfiRuntimeServicesData;\r
438 }\r
03d486b2
JY
439 NewRecord->PhysicalStart = TempRecord.PhysicalStart;\r
440 NewRecord->VirtualStart = 0;\r
441 NewRecord->NumberOfPages = EfiSizeToPages (ImageEnd - TempRecord.PhysicalStart);\r
442 NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;\r
443 NewRecordCount ++;\r
444 }\r
445\r
446 return NewRecordCount;\r
447}\r
448\r
449/**\r
450 Return the max number of new splitted entries, according to one old entry,\r
451 based upon PE code section and data section.\r
452\r
453 @param OldRecord A pointer to one old memory map entry.\r
454\r
455 @retval 0 no entry need to be splitted.\r
456 @return the max number of new splitted entries\r
457**/\r
2caab142 458STATIC\r
03d486b2
JY
459UINTN\r
460GetMaxSplitRecordCount (\r
461 IN EFI_MEMORY_DESCRIPTOR *OldRecord\r
462 )\r
463{\r
464 IMAGE_PROPERTIES_RECORD *ImageRecord;\r
465 UINTN SplitRecordCount;\r
466 UINT64 PhysicalStart;\r
467 UINT64 PhysicalEnd;\r
468\r
469 SplitRecordCount = 0;\r
470 PhysicalStart = OldRecord->PhysicalStart;\r
471 PhysicalEnd = OldRecord->PhysicalStart + EfiPagesToSize(OldRecord->NumberOfPages);\r
472\r
473 do {\r
474 ImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart);\r
475 if (ImageRecord == NULL) {\r
476 break;\r
477 }\r
478 SplitRecordCount += (2 * ImageRecord->CodeSegmentCount + 1);\r
479 PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;\r
480 } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));\r
481\r
482 if (SplitRecordCount != 0) {\r
483 SplitRecordCount--;\r
484 }\r
485\r
486 return SplitRecordCount;\r
487}\r
488\r
489/**\r
490 Split the memory map to new entries, according to one old entry,\r
491 based upon PE code section and data section.\r
492\r
493 @param OldRecord A pointer to one old memory map entry.\r
494 @param NewRecord A pointer to several new memory map entries.\r
495 The caller gurantee the buffer size be 1 +\r
496 (SplitRecordCount * DescriptorSize) calculated\r
497 below.\r
9d58ab09 498 @param MaxSplitRecordCount The max number of splitted entries\r
03d486b2
JY
499 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
500\r
501 @retval 0 no entry is splitted.\r
502 @return the real number of splitted record.\r
503**/\r
2caab142 504STATIC\r
03d486b2
JY
505UINTN\r
506SplitRecord (\r
507 IN EFI_MEMORY_DESCRIPTOR *OldRecord,\r
508 IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,\r
509 IN UINTN MaxSplitRecordCount,\r
510 IN UINTN DescriptorSize\r
511 )\r
512{\r
513 EFI_MEMORY_DESCRIPTOR TempRecord;\r
514 IMAGE_PROPERTIES_RECORD *ImageRecord;\r
515 IMAGE_PROPERTIES_RECORD *NewImageRecord;\r
516 UINT64 PhysicalStart;\r
517 UINT64 PhysicalEnd;\r
518 UINTN NewRecordCount;\r
519 UINTN TotalNewRecordCount;\r
82f0f411 520 BOOLEAN IsLastRecordData;\r
03d486b2
JY
521\r
522 if (MaxSplitRecordCount == 0) {\r
523 CopyMem (NewRecord, OldRecord, DescriptorSize);\r
524 return 0;\r
525 }\r
526\r
527 TotalNewRecordCount = 0;\r
528\r
529 //\r
530 // Override previous record\r
531 //\r
532 CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR));\r
533 PhysicalStart = TempRecord.PhysicalStart;\r
534 PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages);\r
535\r
536 ImageRecord = NULL;\r
537 do {\r
538 NewImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart);\r
539 if (NewImageRecord == NULL) {\r
540 //\r
541 // No more image covered by this range, stop\r
542 //\r
543 if ((PhysicalEnd > PhysicalStart) && (ImageRecord != NULL)) {\r
544 //\r
545 // If this is still address in this record, need record.\r
546 //\r
547 NewRecord = PREVIOUS_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);\r
82f0f411
JY
548 IsLastRecordData = FALSE;\r
549 if (!mPropertiesTableEnable) {\r
550 if ((NewRecord->Attribute & EFI_MEMORY_XP) != 0) {\r
551 IsLastRecordData = TRUE;\r
552 }\r
553 } else {\r
554 if (NewRecord->Type == EfiRuntimeServicesData) {\r
555 IsLastRecordData = TRUE;\r
556 }\r
557 }\r
558 if (IsLastRecordData) {\r
03d486b2
JY
559 //\r
560 // Last record is DATA, just merge it.\r
561 //\r
562 NewRecord->NumberOfPages = EfiSizeToPages(PhysicalEnd - NewRecord->PhysicalStart);\r
563 } else {\r
564 //\r
565 // Last record is CODE, create a new DATA entry.\r
566 //\r
567 NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);\r
82f0f411
JY
568 if (!mPropertiesTableEnable) {\r
569 NewRecord->Type = TempRecord.Type;\r
570 } else {\r
571 NewRecord->Type = EfiRuntimeServicesData;\r
572 }\r
03d486b2
JY
573 NewRecord->PhysicalStart = TempRecord.PhysicalStart;\r
574 NewRecord->VirtualStart = 0;\r
575 NewRecord->NumberOfPages = TempRecord.NumberOfPages;\r
576 NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;\r
577 TotalNewRecordCount ++;\r
578 }\r
579 }\r
580 break;\r
581 }\r
582 ImageRecord = NewImageRecord;\r
583\r
584 //\r
585 // Set new record\r
586 //\r
587 NewRecordCount = SetNewRecord (ImageRecord, NewRecord, &TempRecord, DescriptorSize);\r
588 TotalNewRecordCount += NewRecordCount;\r
589 NewRecord = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)NewRecord + NewRecordCount * DescriptorSize);\r
590\r
591 //\r
592 // Update PhysicalStart, in order to exclude the image buffer already splitted.\r
593 //\r
594 PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;\r
595 TempRecord.PhysicalStart = PhysicalStart;\r
596 TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);\r
597 } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));\r
598\r
599 return TotalNewRecordCount - 1;\r
600}\r
601\r
602/**\r
603 Split the original memory map, and add more entries to describe PE code section and data section.\r
604 This function will set EfiRuntimeServicesData to be EFI_MEMORY_XP.\r
605 This function will merge entries with same attributes finally.\r
606\r
607 NOTE: It assumes PE code/data section are page aligned.\r
608 NOTE: It assumes enough entry is prepared for new memory map.\r
609\r
610 Split table:\r
611 +---------------+\r
612 | Record X |\r
613 +---------------+\r
614 | Record RtCode |\r
615 +---------------+\r
616 | Record Y |\r
617 +---------------+\r
618 ==>\r
619 +---------------+\r
620 | Record X |\r
621 +---------------+ ----\r
622 | Record RtData | |\r
623 +---------------+ |\r
624 | Record RtCode | |-> PE/COFF1\r
625 +---------------+ |\r
626 | Record RtData | |\r
627 +---------------+ ----\r
628 | Record RtData | |\r
629 +---------------+ |\r
630 | Record RtCode | |-> PE/COFF2\r
631 +---------------+ |\r
632 | Record RtData | |\r
633 +---------------+ ----\r
634 | Record Y |\r
635 +---------------+\r
636\r
637 @param MemoryMapSize A pointer to the size, in bytes, of the\r
638 MemoryMap buffer. On input, this is the size of\r
639 old MemoryMap before split. The actual buffer\r
640 size of MemoryMap is MemoryMapSize +\r
641 (AdditionalRecordCount * DescriptorSize) calculated\r
642 below. On output, it is the size of new MemoryMap\r
643 after split.\r
644 @param MemoryMap A pointer to the buffer in which firmware places\r
645 the current memory map.\r
646 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
647**/\r
2caab142 648STATIC\r
03d486b2
JY
649VOID\r
650SplitTable (\r
651 IN OUT UINTN *MemoryMapSize,\r
652 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
653 IN UINTN DescriptorSize\r
654 )\r
655{\r
656 INTN IndexOld;\r
657 INTN IndexNew;\r
658 UINTN MaxSplitRecordCount;\r
659 UINTN RealSplitRecordCount;\r
660 UINTN TotalSplitRecordCount;\r
661 UINTN AdditionalRecordCount;\r
662\r
663 AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount;\r
664\r
665 TotalSplitRecordCount = 0;\r
666 //\r
667 // Let old record point to end of valid MemoryMap buffer.\r
668 //\r
669 IndexOld = ((*MemoryMapSize) / DescriptorSize) - 1;\r
670 //\r
671 // Let new record point to end of full MemoryMap buffer.\r
672 //\r
673 IndexNew = ((*MemoryMapSize) / DescriptorSize) - 1 + AdditionalRecordCount;\r
674 for (; IndexOld >= 0; IndexOld--) {\r
675 MaxSplitRecordCount = GetMaxSplitRecordCount ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize));\r
676 //\r
677 // Split this MemoryMap record\r
678 //\r
679 IndexNew -= MaxSplitRecordCount;\r
680 RealSplitRecordCount = SplitRecord (\r
681 (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize),\r
682 (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexNew * DescriptorSize),\r
683 MaxSplitRecordCount,\r
684 DescriptorSize\r
685 );\r
686 //\r
687 // Adjust IndexNew according to real split.\r
688 //\r
689 CopyMem (\r
690 ((UINT8 *)MemoryMap + (IndexNew + MaxSplitRecordCount - RealSplitRecordCount) * DescriptorSize),\r
691 ((UINT8 *)MemoryMap + IndexNew * DescriptorSize),\r
692 RealSplitRecordCount * DescriptorSize\r
693 );\r
694 IndexNew = IndexNew + MaxSplitRecordCount - RealSplitRecordCount;\r
695 TotalSplitRecordCount += RealSplitRecordCount;\r
696 IndexNew --;\r
697 }\r
698 //\r
699 // Move all records to the beginning.\r
700 //\r
701 CopyMem (\r
702 MemoryMap,\r
703 (UINT8 *)MemoryMap + (AdditionalRecordCount - TotalSplitRecordCount) * DescriptorSize,\r
704 (*MemoryMapSize) + TotalSplitRecordCount * DescriptorSize\r
705 );\r
706\r
707 *MemoryMapSize = (*MemoryMapSize) + DescriptorSize * TotalSplitRecordCount;\r
708\r
709 //\r
710 // Sort from low to high (Just in case)\r
711 //\r
712 SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);\r
713\r
714 //\r
715 // Set RuntimeData to XP\r
716 //\r
717 EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, DescriptorSize);\r
718\r
719 //\r
720 // Merge same type to save entry size\r
721 //\r
722 MergeMemoryMap (MemoryMap, MemoryMapSize, DescriptorSize);\r
723\r
724 return ;\r
725}\r
726\r
727/**\r
f5a91bba 728 This function for GetMemoryMap() with properties table capability.\r
03d486b2
JY
729\r
730 It calls original GetMemoryMap() to get the original memory map information. Then\r
731 plus the additional memory map entries for PE Code/Data seperation.\r
732\r
733 @param MemoryMapSize A pointer to the size, in bytes, of the\r
734 MemoryMap buffer. On input, this is the size of\r
735 the buffer allocated by the caller. On output,\r
736 it is the size of the buffer returned by the\r
737 firmware if the buffer was large enough, or the\r
738 size of the buffer needed to contain the map if\r
739 the buffer was too small.\r
740 @param MemoryMap A pointer to the buffer in which firmware places\r
741 the current memory map.\r
742 @param MapKey A pointer to the location in which firmware\r
743 returns the key for the current memory map.\r
744 @param DescriptorSize A pointer to the location in which firmware\r
745 returns the size, in bytes, of an individual\r
746 EFI_MEMORY_DESCRIPTOR.\r
747 @param DescriptorVersion A pointer to the location in which firmware\r
748 returns the version number associated with the\r
749 EFI_MEMORY_DESCRIPTOR.\r
750\r
751 @retval EFI_SUCCESS The memory map was returned in the MemoryMap\r
752 buffer.\r
753 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current\r
754 buffer size needed to hold the memory map is\r
755 returned in MemoryMapSize.\r
756 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
757\r
758**/\r
759EFI_STATUS\r
760EFIAPI\r
761CoreGetMemoryMapPropertiesTable (\r
762 IN OUT UINTN *MemoryMapSize,\r
763 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
764 OUT UINTN *MapKey,\r
765 OUT UINTN *DescriptorSize,\r
766 OUT UINT32 *DescriptorVersion\r
767 )\r
768{\r
769 EFI_STATUS Status;\r
770 UINTN OldMemoryMapSize;\r
771 UINTN AdditionalRecordCount;\r
772\r
773 //\r
774 // If PE code/data is not aligned, just return.\r
775 //\r
776 if ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {\r
777 return CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);\r
778 }\r
779\r
780 if (MemoryMapSize == NULL) {\r
781 return EFI_INVALID_PARAMETER;\r
782 }\r
783\r
784 CoreAcquirePropertiesTableLock ();\r
785\r
786 AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount;\r
787\r
788 OldMemoryMapSize = *MemoryMapSize;\r
789 Status = CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);\r
790 if (Status == EFI_BUFFER_TOO_SMALL) {\r
791 *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;\r
792 } else if (Status == EFI_SUCCESS) {\r
793 if (OldMemoryMapSize - *MemoryMapSize < (*DescriptorSize) * AdditionalRecordCount) {\r
794 *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;\r
795 //\r
796 // Need update status to buffer too small\r
797 //\r
798 Status = EFI_BUFFER_TOO_SMALL;\r
799 } else {\r
800 //\r
801 // Split PE code/data\r
802 //\r
803 SplitTable (MemoryMapSize, MemoryMap, *DescriptorSize);\r
804 }\r
805 }\r
806\r
807 CoreReleasePropertiesTableLock ();\r
808 return Status;\r
809}\r
810\r
811//\r
812// Below functions are for ImageRecord\r
813//\r
814\r
815/**\r
ab91c9a8 816 Set PropertiesTable according to PE/COFF image section alignment.\r
03d486b2
JY
817\r
818 @param SectionAlignment PE/COFF section alignment\r
819**/\r
2caab142 820STATIC\r
03d486b2
JY
821VOID\r
822SetPropertiesTableSectionAlignment (\r
823 IN UINT32 SectionAlignment\r
824 )\r
825{\r
0255cfb8 826 if (((SectionAlignment & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) &&\r
03d486b2
JY
827 ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) != 0)) {\r
828 DEBUG ((EFI_D_VERBOSE, "SetPropertiesTableSectionAlignment - Clear\n"));\r
a6451806 829 mPropertiesTable.MemoryProtectionAttribute &= ~((UINT64)EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);\r
03d486b2
JY
830 gBS->GetMemoryMap = CoreGetMemoryMap;\r
831 gBS->Hdr.CRC32 = 0;\r
832 gBS->CalculateCrc32 ((UINT8 *)gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);\r
833 }\r
834}\r
835\r
836/**\r
837 Swap two code sections in image record.\r
838\r
839 @param FirstImageRecordCodeSection first code section in image record\r
840 @param SecondImageRecordCodeSection second code section in image record\r
841**/\r
2caab142 842STATIC\r
03d486b2
JY
843VOID\r
844SwapImageRecordCodeSection (\r
845 IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *FirstImageRecordCodeSection,\r
846 IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *SecondImageRecordCodeSection\r
847 )\r
848{\r
849 IMAGE_PROPERTIES_RECORD_CODE_SECTION TempImageRecordCodeSection;\r
850\r
851 TempImageRecordCodeSection.CodeSegmentBase = FirstImageRecordCodeSection->CodeSegmentBase;\r
852 TempImageRecordCodeSection.CodeSegmentSize = FirstImageRecordCodeSection->CodeSegmentSize;\r
853\r
854 FirstImageRecordCodeSection->CodeSegmentBase = SecondImageRecordCodeSection->CodeSegmentBase;\r
855 FirstImageRecordCodeSection->CodeSegmentSize = SecondImageRecordCodeSection->CodeSegmentSize;\r
856\r
857 SecondImageRecordCodeSection->CodeSegmentBase = TempImageRecordCodeSection.CodeSegmentBase;\r
858 SecondImageRecordCodeSection->CodeSegmentSize = TempImageRecordCodeSection.CodeSegmentSize;\r
859}\r
860\r
861/**\r
862 Sort code section in image record, based upon CodeSegmentBase from low to high.\r
863\r
864 @param ImageRecord image record to be sorted\r
865**/\r
2caab142 866STATIC\r
03d486b2
JY
867VOID\r
868SortImageRecordCodeSection (\r
869 IN IMAGE_PROPERTIES_RECORD *ImageRecord\r
870 )\r
871{\r
872 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
873 IMAGE_PROPERTIES_RECORD_CODE_SECTION *NextImageRecordCodeSection;\r
874 LIST_ENTRY *ImageRecordCodeSectionLink;\r
875 LIST_ENTRY *NextImageRecordCodeSectionLink;\r
876 LIST_ENTRY *ImageRecordCodeSectionEndLink;\r
877 LIST_ENTRY *ImageRecordCodeSectionList;\r
878\r
879 ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;\r
880\r
881 ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;\r
882 NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
883 ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;\r
884 while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {\r
885 ImageRecordCodeSection = CR (\r
886 ImageRecordCodeSectionLink,\r
887 IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
888 Link,\r
889 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
890 );\r
891 while (NextImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {\r
892 NextImageRecordCodeSection = CR (\r
893 NextImageRecordCodeSectionLink,\r
894 IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
895 Link,\r
896 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
897 );\r
898 if (ImageRecordCodeSection->CodeSegmentBase > NextImageRecordCodeSection->CodeSegmentBase) {\r
899 SwapImageRecordCodeSection (ImageRecordCodeSection, NextImageRecordCodeSection);\r
900 }\r
901 NextImageRecordCodeSectionLink = NextImageRecordCodeSectionLink->ForwardLink;\r
902 }\r
903\r
904 ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
905 NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
906 }\r
907}\r
908\r
909/**\r
9d58ab09 910 Check if code section in image record is valid.\r
03d486b2
JY
911\r
912 @param ImageRecord image record to be checked\r
913\r
914 @retval TRUE image record is valid\r
915 @retval FALSE image record is invalid\r
916**/\r
2caab142 917STATIC\r
03d486b2
JY
918BOOLEAN\r
919IsImageRecordCodeSectionValid (\r
920 IN IMAGE_PROPERTIES_RECORD *ImageRecord\r
921 )\r
922{\r
923 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
924 IMAGE_PROPERTIES_RECORD_CODE_SECTION *LastImageRecordCodeSection;\r
925 LIST_ENTRY *ImageRecordCodeSectionLink;\r
926 LIST_ENTRY *ImageRecordCodeSectionEndLink;\r
927 LIST_ENTRY *ImageRecordCodeSectionList;\r
928\r
929 DEBUG ((EFI_D_VERBOSE, "ImageCode SegmentCount - 0x%x\n", ImageRecord->CodeSegmentCount));\r
930\r
931 ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;\r
932\r
933 ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;\r
934 ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;\r
935 LastImageRecordCodeSection = NULL;\r
936 while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {\r
937 ImageRecordCodeSection = CR (\r
938 ImageRecordCodeSectionLink,\r
939 IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
940 Link,\r
941 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
942 );\r
943 if (ImageRecordCodeSection->CodeSegmentSize == 0) {\r
944 return FALSE;\r
945 }\r
946 if (ImageRecordCodeSection->CodeSegmentBase < ImageRecord->ImageBase) {\r
947 return FALSE;\r
948 }\r
949 if (ImageRecordCodeSection->CodeSegmentBase >= MAX_ADDRESS - ImageRecordCodeSection->CodeSegmentSize) {\r
950 return FALSE;\r
951 }\r
952 if ((ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize) > (ImageRecord->ImageBase + ImageRecord->ImageSize)) {\r
953 return FALSE;\r
954 }\r
955 if (LastImageRecordCodeSection != NULL) {\r
956 if ((LastImageRecordCodeSection->CodeSegmentBase + LastImageRecordCodeSection->CodeSegmentSize) > ImageRecordCodeSection->CodeSegmentBase) {\r
957 return FALSE;\r
958 }\r
959 }\r
960\r
961 LastImageRecordCodeSection = ImageRecordCodeSection;\r
962 ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
963 }\r
964\r
965 return TRUE;\r
966}\r
967\r
968/**\r
969 Swap two image records.\r
970\r
971 @param FirstImageRecord first image record.\r
972 @param SecondImageRecord second image record.\r
973**/\r
2caab142 974STATIC\r
03d486b2
JY
975VOID\r
976SwapImageRecord (\r
977 IN IMAGE_PROPERTIES_RECORD *FirstImageRecord,\r
978 IN IMAGE_PROPERTIES_RECORD *SecondImageRecord\r
979 )\r
980{\r
981 IMAGE_PROPERTIES_RECORD TempImageRecord;\r
982\r
983 TempImageRecord.ImageBase = FirstImageRecord->ImageBase;\r
984 TempImageRecord.ImageSize = FirstImageRecord->ImageSize;\r
985 TempImageRecord.CodeSegmentCount = FirstImageRecord->CodeSegmentCount;\r
986\r
987 FirstImageRecord->ImageBase = SecondImageRecord->ImageBase;\r
988 FirstImageRecord->ImageSize = SecondImageRecord->ImageSize;\r
989 FirstImageRecord->CodeSegmentCount = SecondImageRecord->CodeSegmentCount;\r
990\r
991 SecondImageRecord->ImageBase = TempImageRecord.ImageBase;\r
992 SecondImageRecord->ImageSize = TempImageRecord.ImageSize;\r
993 SecondImageRecord->CodeSegmentCount = TempImageRecord.CodeSegmentCount;\r
994\r
995 SwapListEntries (&FirstImageRecord->CodeSegmentList, &SecondImageRecord->CodeSegmentList);\r
996}\r
997\r
998/**\r
999 Sort image record based upon the ImageBase from low to high.\r
1000**/\r
2caab142 1001STATIC\r
03d486b2
JY
1002VOID\r
1003SortImageRecord (\r
1004 VOID\r
1005 )\r
1006{\r
1007 IMAGE_PROPERTIES_RECORD *ImageRecord;\r
1008 IMAGE_PROPERTIES_RECORD *NextImageRecord;\r
1009 LIST_ENTRY *ImageRecordLink;\r
1010 LIST_ENTRY *NextImageRecordLink;\r
1011 LIST_ENTRY *ImageRecordEndLink;\r
1012 LIST_ENTRY *ImageRecordList;\r
1013\r
1014 ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;\r
1015\r
1016 ImageRecordLink = ImageRecordList->ForwardLink;\r
1017 NextImageRecordLink = ImageRecordLink->ForwardLink;\r
1018 ImageRecordEndLink = ImageRecordList;\r
1019 while (ImageRecordLink != ImageRecordEndLink) {\r
1020 ImageRecord = CR (\r
1021 ImageRecordLink,\r
1022 IMAGE_PROPERTIES_RECORD,\r
1023 Link,\r
1024 IMAGE_PROPERTIES_RECORD_SIGNATURE\r
1025 );\r
1026 while (NextImageRecordLink != ImageRecordEndLink) {\r
1027 NextImageRecord = CR (\r
1028 NextImageRecordLink,\r
1029 IMAGE_PROPERTIES_RECORD,\r
1030 Link,\r
1031 IMAGE_PROPERTIES_RECORD_SIGNATURE\r
1032 );\r
1033 if (ImageRecord->ImageBase > NextImageRecord->ImageBase) {\r
1034 SwapImageRecord (ImageRecord, NextImageRecord);\r
1035 }\r
1036 NextImageRecordLink = NextImageRecordLink->ForwardLink;\r
1037 }\r
1038\r
1039 ImageRecordLink = ImageRecordLink->ForwardLink;\r
1040 NextImageRecordLink = ImageRecordLink->ForwardLink;\r
1041 }\r
1042}\r
1043\r
1044/**\r
9d58ab09 1045 Dump image record.\r
03d486b2 1046**/\r
2caab142 1047STATIC\r
03d486b2
JY
1048VOID\r
1049DumpImageRecord (\r
1050 VOID\r
1051 )\r
1052{\r
1053 IMAGE_PROPERTIES_RECORD *ImageRecord;\r
1054 LIST_ENTRY *ImageRecordLink;\r
1055 LIST_ENTRY *ImageRecordList;\r
1056 UINTN Index;\r
1057\r
1058 ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;\r
1059\r
1060 for (ImageRecordLink = ImageRecordList->ForwardLink, Index= 0;\r
1061 ImageRecordLink != ImageRecordList;\r
1062 ImageRecordLink = ImageRecordLink->ForwardLink, Index++) {\r
1063 ImageRecord = CR (\r
1064 ImageRecordLink,\r
1065 IMAGE_PROPERTIES_RECORD,\r
1066 Link,\r
1067 IMAGE_PROPERTIES_RECORD_SIGNATURE\r
1068 );\r
1069 DEBUG ((EFI_D_VERBOSE, " Image[%d]: 0x%016lx - 0x%016lx\n", Index, ImageRecord->ImageBase, ImageRecord->ImageSize));\r
1070 }\r
1071}\r
1072\r
1073/**\r
1074 Insert image record.\r
1075\r
1076 @param RuntimeImage Runtime image information\r
1077**/\r
1078VOID\r
1079InsertImageRecord (\r
1080 IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage\r
1081 )\r
1082{\r
1083 VOID *ImageAddress;\r
1084 EFI_IMAGE_DOS_HEADER *DosHdr;\r
1085 UINT32 PeCoffHeaderOffset;\r
1086 UINT32 SectionAlignment;\r
03d486b2
JY
1087 EFI_IMAGE_SECTION_HEADER *Section;\r
1088 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
03d486b2
JY
1089 UINT8 *Name;\r
1090 UINTN Index;\r
1091 IMAGE_PROPERTIES_RECORD *ImageRecord;\r
1092 CHAR8 *PdbPointer;\r
1093 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
81338070 1094 UINT16 Magic;\r
03d486b2
JY
1095\r
1096 DEBUG ((EFI_D_VERBOSE, "InsertImageRecord - 0x%x\n", RuntimeImage));\r
1097 DEBUG ((EFI_D_VERBOSE, "InsertImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));\r
1098\r
1099 ImageRecord = AllocatePool (sizeof(*ImageRecord));\r
1100 if (ImageRecord == NULL) {\r
1101 return ;\r
1102 }\r
1103 ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;\r
1104\r
1105 DEBUG ((EFI_D_VERBOSE, "ImageRecordCount - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));\r
1106\r
1107 //\r
1108 // Step 1: record whole region\r
1109 //\r
1110 ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase;\r
1111 ImageRecord->ImageSize = RuntimeImage->ImageSize;\r
1112\r
1113 ImageAddress = RuntimeImage->ImageBase;\r
1114\r
1115 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
1116 if (PdbPointer != NULL) {\r
1117 DEBUG ((EFI_D_VERBOSE, " Image - %a\n", PdbPointer));\r
1118 }\r
1119\r
1120 //\r
1121 // Check PE/COFF image\r
1122 //\r
1123 DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;\r
1124 PeCoffHeaderOffset = 0;\r
1125 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
1126 PeCoffHeaderOffset = DosHdr->e_lfanew;\r
1127 }\r
1128\r
1129 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);\r
1130 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1131 DEBUG ((EFI_D_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));\r
81338070 1132 // It might be image in SMM.\r
03d486b2
JY
1133 goto Finish;\r
1134 }\r
1135\r
1136 //\r
81338070 1137 // Get SectionAlignment\r
03d486b2
JY
1138 //\r
1139 if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1140 //\r
1141 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value\r
1142 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the\r
1143 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
1144 // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
1145 //\r
81338070 1146 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
03d486b2
JY
1147 } else {\r
1148 //\r
1149 // Get the magic value from the PE/COFF Optional Header\r
1150 //\r
81338070
JY
1151 Magic = Hdr.Pe32->OptionalHeader.Magic;\r
1152 }\r
1153 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1154 SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;\r
1155 } else {\r
03d486b2
JY
1156 SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;\r
1157 }\r
1158\r
1159 SetPropertiesTableSectionAlignment (SectionAlignment);\r
0255cfb8 1160 if ((SectionAlignment & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {\r
2495c9bf 1161 DEBUG ((EFI_D_WARN, "!!!!!!!! InsertImageRecord - Section Alignment(0x%x) is not %dK !!!!!!!!\n",\r
0255cfb8 1162 SectionAlignment, EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT >> 10));\r
03d486b2
JY
1163 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
1164 if (PdbPointer != NULL) {\r
2495c9bf 1165 DEBUG ((EFI_D_WARN, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));\r
03d486b2
JY
1166 }\r
1167 goto Finish;\r
1168 }\r
1169\r
1170 Section = (EFI_IMAGE_SECTION_HEADER *) (\r
1171 (UINT8 *) (UINTN) ImageAddress +\r
1172 PeCoffHeaderOffset +\r
1173 sizeof(UINT32) +\r
1174 sizeof(EFI_IMAGE_FILE_HEADER) +\r
1175 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
1176 );\r
1177 ImageRecord->CodeSegmentCount = 0;\r
1178 InitializeListHead (&ImageRecord->CodeSegmentList);\r
1179 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
1180 Name = Section[Index].Name;\r
1181 DEBUG ((\r
1182 EFI_D_VERBOSE,\r
1183 " Section - '%c%c%c%c%c%c%c%c'\n",\r
1184 Name[0],\r
1185 Name[1],\r
1186 Name[2],\r
1187 Name[3],\r
1188 Name[4],\r
1189 Name[5],\r
1190 Name[6],\r
1191 Name[7]\r
1192 ));\r
1193\r
1194 if ((Section[Index].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) {\r
1195 DEBUG ((EFI_D_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));\r
1196 DEBUG ((EFI_D_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));\r
1197 DEBUG ((EFI_D_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));\r
1198 DEBUG ((EFI_D_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));\r
1199 DEBUG ((EFI_D_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));\r
1200 DEBUG ((EFI_D_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));\r
1201 DEBUG ((EFI_D_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));\r
1202 DEBUG ((EFI_D_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));\r
1203 DEBUG ((EFI_D_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics));\r
1204\r
1205 //\r
1206 // Step 2: record code section\r
1207 //\r
1208 ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection));\r
1209 if (ImageRecordCodeSection == NULL) {\r
1210 return ;\r
1211 }\r
1212 ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;\r
1213\r
1214 ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;\r
1215 ImageRecordCodeSection->CodeSegmentSize = Section[Index].SizeOfRawData;\r
1216\r
1217 DEBUG ((EFI_D_VERBOSE, "ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));\r
1218\r
1219 InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);\r
1220 ImageRecord->CodeSegmentCount++;\r
1221 }\r
1222 }\r
1223\r
1224 if (ImageRecord->CodeSegmentCount == 0) {\r
1225 SetPropertiesTableSectionAlignment (1);\r
1226 DEBUG ((EFI_D_ERROR, "!!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n"));\r
1227 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
1228 if (PdbPointer != NULL) {\r
1229 DEBUG ((EFI_D_ERROR, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));\r
1230 }\r
1231 goto Finish;\r
1232 }\r
1233\r
1234 //\r
1235 // Final\r
1236 //\r
1237 SortImageRecordCodeSection (ImageRecord);\r
1238 //\r
1239 // Check overlap all section in ImageBase/Size\r
1240 //\r
1241 if (!IsImageRecordCodeSectionValid (ImageRecord)) {\r
1242 DEBUG ((EFI_D_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));\r
1243 goto Finish;\r
1244 }\r
1245\r
1246 InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link);\r
1247 mImagePropertiesPrivateData.ImageRecordCount++;\r
1248\r
1249 SortImageRecord ();\r
1250\r
1251 if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) {\r
1252 mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount;\r
1253 }\r
1254\r
1255Finish:\r
1256 return ;\r
1257}\r
1258\r
1259/**\r
ab91c9a8 1260 Find image record according to image base and size.\r
03d486b2
JY
1261\r
1262 @param ImageBase Base of PE image\r
1263 @param ImageSize Size of PE image\r
1264\r
1265 @return image record\r
1266**/\r
2caab142 1267STATIC\r
03d486b2
JY
1268IMAGE_PROPERTIES_RECORD *\r
1269FindImageRecord (\r
1270 IN EFI_PHYSICAL_ADDRESS ImageBase,\r
1271 IN UINT64 ImageSize\r
1272 )\r
1273{\r
1274 IMAGE_PROPERTIES_RECORD *ImageRecord;\r
1275 LIST_ENTRY *ImageRecordLink;\r
1276 LIST_ENTRY *ImageRecordList;\r
1277\r
1278 ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;\r
1279\r
1280 for (ImageRecordLink = ImageRecordList->ForwardLink;\r
1281 ImageRecordLink != ImageRecordList;\r
1282 ImageRecordLink = ImageRecordLink->ForwardLink) {\r
1283 ImageRecord = CR (\r
1284 ImageRecordLink,\r
1285 IMAGE_PROPERTIES_RECORD,\r
1286 Link,\r
1287 IMAGE_PROPERTIES_RECORD_SIGNATURE\r
1288 );\r
1289\r
1290 if ((ImageBase == ImageRecord->ImageBase) &&\r
1291 (ImageSize == ImageRecord->ImageSize)) {\r
1292 return ImageRecord;\r
1293 }\r
1294 }\r
1295\r
1296 return NULL;\r
1297}\r
1298\r
1299/**\r
1300 Remove Image record.\r
1301\r
1302 @param RuntimeImage Runtime image information\r
1303**/\r
1304VOID\r
1305RemoveImageRecord (\r
1306 IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage\r
1307 )\r
1308{\r
1309 IMAGE_PROPERTIES_RECORD *ImageRecord;\r
1310 LIST_ENTRY *CodeSegmentListHead;\r
1311 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
1312\r
1313 DEBUG ((EFI_D_VERBOSE, "RemoveImageRecord - 0x%x\n", RuntimeImage));\r
1314 DEBUG ((EFI_D_VERBOSE, "RemoveImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));\r
1315\r
1316 ImageRecord = FindImageRecord ((EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize);\r
1317 if (ImageRecord == NULL) {\r
1318 DEBUG ((EFI_D_ERROR, "!!!!!!!! ImageRecord not found !!!!!!!!\n"));\r
1319 return ;\r
1320 }\r
1321\r
1322 CodeSegmentListHead = &ImageRecord->CodeSegmentList;\r
1323 while (!IsListEmpty (CodeSegmentListHead)) {\r
1324 ImageRecordCodeSection = CR (\r
1325 CodeSegmentListHead->ForwardLink,\r
1326 IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
1327 Link,\r
1328 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
1329 );\r
1330 RemoveEntryList (&ImageRecordCodeSection->Link);\r
1331 FreePool (ImageRecordCodeSection);\r
1332 }\r
1333\r
1334 RemoveEntryList (&ImageRecord->Link);\r
1335 FreePool (ImageRecord);\r
1336 mImagePropertiesPrivateData.ImageRecordCount--;\r
1337}\r
1338\r
1339\r
1340/**\r
1341 Install PropertiesTable.\r
1342\r
1343 @param[in] Event The Event this notify function registered to.\r
1344 @param[in] Context Pointer to the context data registered to the Event.\r
1345**/\r
1346VOID\r
1347EFIAPI\r
1348InstallPropertiesTable (\r
1349 EFI_EVENT Event,\r
1350 VOID *Context\r
1351 )\r
1352{\r
bc31c0c6 1353 if (PcdGetBool (PcdPropertiesTableEnable)) {\r
03d486b2
JY
1354 EFI_STATUS Status;\r
1355\r
1356 Status = gBS->InstallConfigurationTable (&gEfiPropertiesTableGuid, &mPropertiesTable);\r
1357 ASSERT_EFI_ERROR (Status);\r
1358\r
1359 DEBUG ((EFI_D_INFO, "MemoryProtectionAttribute - 0x%016lx\n", mPropertiesTable.MemoryProtectionAttribute));\r
1360 if ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {\r
2495c9bf
LG
1361 DEBUG ((EFI_D_ERROR, "MemoryProtectionAttribute NON_EXECUTABLE_PE_DATA is not set, "));\r
1362 DEBUG ((EFI_D_ERROR, "because Runtime Driver Section Alignment is not %dK.\n", EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT >> 10));\r
03d486b2
JY
1363 return ;\r
1364 }\r
1365\r
1366 gBS->GetMemoryMap = CoreGetMemoryMapPropertiesTable;\r
1367 gBS->Hdr.CRC32 = 0;\r
1368 gBS->CalculateCrc32 ((UINT8 *)gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);\r
1369\r
1370 DEBUG ((EFI_D_VERBOSE, "Total Image Count - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));\r
1371 DEBUG ((EFI_D_VERBOSE, "Dump ImageRecord:\n"));\r
1372 DumpImageRecord ();\r
82f0f411
JY
1373\r
1374 mPropertiesTableEnable = TRUE;\r
03d486b2
JY
1375 }\r
1376}\r
1377\r
1378/**\r
1379 Initialize PropertiesTable support.\r
1380**/\r
1381VOID\r
1382EFIAPI\r
1383CoreInitializePropertiesTable (\r
1384 VOID\r
1385 )\r
1386{\r
1387 EFI_STATUS Status;\r
1388 EFI_EVENT EndOfDxeEvent;\r
1389\r
1390 Status = gBS->CreateEventEx (\r
1391 EVT_NOTIFY_SIGNAL,\r
1392 TPL_NOTIFY,\r
1393 InstallPropertiesTable,\r
1394 NULL,\r
1395 &gEfiEndOfDxeEventGroupGuid,\r
1396 &EndOfDxeEvent\r
1397 );\r
1398 ASSERT_EFI_ERROR (Status);\r
1399 return ;\r
1400}\r