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