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