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