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