]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Sample/Platform/Generic/MonoStatusCode/Library/Pei/MemoryStatusCode/MemoryStatusCode.c
Add more check to make sure code run safely.
[mirror_edk2.git] / EdkCompatibilityPkg / Sample / Platform / Generic / MonoStatusCode / Library / Pei / MemoryStatusCode / MemoryStatusCode.c
CommitLineData
b38907a6 1/*++\r
2\r
4ac4deb7 3Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r
4b1e1121 4This program and the accompanying materials \r
b38907a6 5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13 \r
14 MemoryStatusCode.c\r
15 \r
16Abstract:\r
17\r
18 Lib to provide memory journal status code reporting Routines.\r
19\r
20--*/\r
21\r
22#include "MemoryStatusCode.h"\r
23#include "PeiLib.h"\r
24#include "MonoStatusCode.h"\r
25\r
26//\r
27// Global variable. Not accessible while running from flash.\r
28// After we relocate ourselves into memory, we update this\r
29// and use it to determine if we are running from flash or memory.\r
30//\r
31BOOLEAN mRunningFromMemory = FALSE;\r
32\r
33//\r
34// Global variable used to replace the PPI once we start running from memory.\r
35//\r
36PEI_STATUS_CODE_MEMORY_PPI mStatusCodeMemoryPpi = { 0, 0, 0, 0 };\r
37\r
38//\r
39// PPI descriptor for the MonoStatusCode PEIM, see MonoStatusCode.c\r
40//\r
41extern EFI_PEI_PPI_DESCRIPTOR mPpiListStatusCode;\r
42\r
43VOID\r
44EFIAPI\r
45MemoryInitializeStatusCode (\r
46 IN EFI_FFS_FILE_HEADER *FfsHeader,\r
47 IN EFI_PEI_SERVICES **PeiServices\r
48 )\r
49/*++\r
50\r
51Routine Description:\r
52\r
53 Initialization routine.\r
54 Allocates heap space for storing Status Codes.\r
55 Installs a PPI to point to that heap space.\r
56 Installs a callback to switch to memory.\r
57 Installs a callback to \r
58\r
59Arguments: \r
60\r
61 FfsHeader - FV this PEIM was loaded from.\r
62 PeiServices - General purpose services available to every PEIM.\r
63\r
64Returns: \r
65\r
66 None\r
67\r
68--*/\r
69{\r
70 EFI_STATUS Status;\r
71 MEMORY_STATUS_CODE_INSTANCE *PrivateData;\r
72 PEI_STATUS_CODE_MEMORY_PPI *StatusCodeMemoryPpi;\r
73 PEI_STATUS_CODE_PPI *ReportStatusCodePpi;\r
74 EFI_PHYSICAL_ADDRESS Buffer;\r
75 VOID *StartPointer;\r
76 UINTN Length;\r
77 UINTN LastEntry;\r
78 EFI_PEI_PPI_DESCRIPTOR *ReportStatusCodeDescriptor;\r
79 EFI_PEI_PPI_DESCRIPTOR *StatusCodeMemoryDescriptor;\r
80\r
81 //\r
82 // Determine if we are being called after relocation into memory.\r
83 //\r
84 if (!mRunningFromMemory) {\r
85 //\r
86 // If we are not running from memory, we need to allocate some heap and\r
87 // install the PPI\r
88 //\r
89 //\r
90 // Allocate heap storage for the journal\r
91 //\r
92 Status = (*PeiServices)->AllocatePool (\r
93 PeiServices,\r
94 PEI_STATUS_CODE_HEAP_LENGTH,\r
d24d32dd 95 (VOID **) &StartPointer\r
b38907a6 96 );\r
97\r
98 //\r
99 // This is not a required feature to boot.\r
100 //\r
101 if (EFI_ERROR (Status)) {\r
102 return ;\r
103 }\r
104 //\r
105 // Allocate heap storage for private data\r
106 // The private data contains the FFS header for this PEIM,\r
107 // a PPI containing information about the status code journal, and\r
108 // a notification for the LoadFile service, to relocate the PEIM into\r
109 // memory.\r
110 //\r
111 Status = (*PeiServices)->AllocatePool (\r
112 PeiServices,\r
113 sizeof (MEMORY_STATUS_CODE_INSTANCE),\r
d24d32dd 114 (VOID **) &PrivateData\r
b38907a6 115 );\r
116\r
117 //\r
118 // This is not a required feature to boot.\r
119 //\r
120 if (EFI_ERROR (Status)) {\r
121 return ;\r
122 }\r
123 //\r
124 // Update the contents of the private data.\r
125 //\r
126 PrivateData->Signature = MEMORY_STATUS_CODE_SIGNATURE;\r
127 PrivateData->This = PrivateData;\r
128 PrivateData->FfsHeader = FfsHeader;\r
129 PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
130 PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid;\r
131 PrivateData->PpiDescriptor.Ppi = &PrivateData->StatusCodeMemoryPpi;\r
132 PrivateData->StatusCodeMemoryPpi.FirstEntry = 0;\r
133 PrivateData->StatusCodeMemoryPpi.LastEntry = 0;\r
134 PrivateData->StatusCodeMemoryPpi.Address = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPointer;\r
135 PrivateData->StatusCodeMemoryPpi.Length = PEI_STATUS_CODE_HEAP_LENGTH;\r
136#if (PI_SPECIFICATION_VERSION < 0x00010000)\r
137 PrivateData->NotifyDescriptor.Flags =\r
138 (\r
139 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |\r
140 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST\r
141 );\r
142 PrivateData->NotifyDescriptor.Guid = &gPeiFvFileLoaderPpiGuid;\r
143 PrivateData->NotifyDescriptor.Notify = LoadImageCallback;\r
144#endif\r
145 //\r
146 // Publish the PPI\r
147 //\r
148 Status = (*PeiServices)->InstallPpi (PeiServices, &PrivateData->PpiDescriptor);\r
149 if (EFI_ERROR (Status)) {\r
150 return ;\r
151 }\r
152 //\r
153 // Post a callback to relocate to memory\r
154 //\r
155#if (PI_SPECIFICATION_VERSION < 0x00010000)\r
156 Status = (**PeiServices).NotifyPpi (PeiServices, &PrivateData->NotifyDescriptor);\r
157 if (EFI_ERROR (Status)) {\r
158 return ;\r
159 }\r
160#endif\r
161 } else {\r
162 //\r
163 // If we are running from memory, we need to copy from the heap to a RT\r
164 // memory buffer.\r
165 //\r
166 //\r
167 // Locate Journal\r
168 //\r
169 Status = (*PeiServices)->LocatePpi (\r
170 PeiServices,\r
171 &gPeiStatusCodeMemoryPpiGuid,\r
172 0,\r
173 &StatusCodeMemoryDescriptor,\r
d24d32dd 174 (VOID **) &StatusCodeMemoryPpi\r
b38907a6 175 );\r
176 if (EFI_ERROR (Status)) {\r
177 return ;\r
178 }\r
179 //\r
180 // Get private data\r
181 //\r
182 PrivateData = MEMORY_STATUS_CODE_FROM_DESCRIPTOR_THIS (StatusCodeMemoryDescriptor);\r
183\r
184 //\r
185 // At this point, we need to fix up any addresses that we have as the heap\r
186 // has moved.\r
187 //\r
188 PrivateData->PpiDescriptor.Ppi = &PrivateData->StatusCodeMemoryPpi;\r
189 PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid;\r
190 PrivateData->StatusCodeMemoryPpi.Address = PrivateData->StatusCodeMemoryPpi.Address +\r
191 (UINTN) PrivateData - (UINTN) PrivateData->This;\r
192 PrivateData->This = PrivateData;\r
193#if (PI_SPECIFICATION_VERSION < 0x00010000)\r
194 PrivateData->NotifyDescriptor.Guid = &gPeiFvFileLoaderPpiGuid;\r
195 PrivateData->NotifyDescriptor.Notify = LoadImageCallback;\r
196#endif\r
197\r
198 //\r
199 // Allocate RT memory.\r
200 //\r
201 Status = (*PeiServices)->AllocatePages (\r
202 PeiServices,\r
203 EfiRuntimeServicesData,\r
204 PEI_STATUS_CODE_RT_PAGES,\r
205 &Buffer\r
206 );\r
207 if (EFI_ERROR (Status)) {\r
208 return ;\r
209 }\r
210\r
211 DEBUG_CODE (\r
212 EfiCommonLibZeroMem ((VOID *) (UINTN) Buffer, PEI_STATUS_CODE_RT_LENGTH);\r
213 )\r
214 //\r
215 // Copy the heap to the allocated memory.\r
216 // Unwind the rolling queue to start at 0 in the new space. We need to do\r
217 // this because the new queue is much bigger than the heap allocation.\r
218 //\r
219 if (PEI_STATUS_CODE_RT_LENGTH <= PEI_STATUS_CODE_HEAP_LENGTH) {\r
220 return ;\r
221 }\r
222\r
223 if (StatusCodeMemoryPpi->LastEntry >= StatusCodeMemoryPpi->FirstEntry) {\r
224 LastEntry = StatusCodeMemoryPpi->LastEntry - StatusCodeMemoryPpi->FirstEntry;\r
225 StartPointer = (VOID *) ((UINTN) StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->FirstEntry * sizeof (EFI_STATUS_CODE_ENTRY)));\r
226 Length = (StatusCodeMemoryPpi->LastEntry - StatusCodeMemoryPpi->FirstEntry) * sizeof (EFI_STATUS_CODE_ENTRY);\r
227 (*PeiServices)->CopyMem ((VOID *) (UINTN) Buffer, StartPointer, Length);\r
228 } else {\r
229 //\r
230 // The last entry will be the new last entry after moving heap to buffer\r
231 //\r
232 LastEntry = (PEI_STATUS_CODE_MAX_HEAP_ENTRY - StatusCodeMemoryPpi->FirstEntry) + StatusCodeMemoryPpi->LastEntry;\r
233 //\r
234 // Copy from the first entry to the end of the heap\r
235 //\r
236 StartPointer = (VOID *) ((UINTN) StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->FirstEntry * sizeof (EFI_STATUS_CODE_ENTRY)));\r
237 Length = PEI_STATUS_CODE_HEAP_LENGTH - (StatusCodeMemoryPpi->FirstEntry * sizeof (EFI_STATUS_CODE_ENTRY));\r
238 (*PeiServices)->CopyMem ((VOID *) (UINTN) Buffer, StartPointer, Length);\r
239 //\r
240 // Copy from the start to the heap to the last entry\r
241 //\r
242 StartPointer = (VOID *) (UINTN) StatusCodeMemoryPpi->Address;\r
243 (*PeiServices)->CopyMem (\r
244 (VOID *) (UINTN) (Buffer + Length),\r
245 StartPointer,\r
246 (StatusCodeMemoryPpi->LastEntry * sizeof (EFI_STATUS_CODE_ENTRY))\r
247 );\r
248 };\r
249\r
250 //\r
251 // Update the PPI to NULL, so it will not be used.\r
252 //\r
253 StatusCodeMemoryPpi->FirstEntry = 0;\r
254 StatusCodeMemoryPpi->LastEntry = 0;\r
255 StatusCodeMemoryPpi->Address = 0;\r
256 StatusCodeMemoryPpi->Length = 0;\r
257\r
258 //\r
259 // Update in memory version of PPI that will be used.\r
260 //\r
261 mStatusCodeMemoryPpi.FirstEntry = 0;\r
262 mStatusCodeMemoryPpi.LastEntry = LastEntry;\r
263 mStatusCodeMemoryPpi.Address = (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer;\r
264 mStatusCodeMemoryPpi.Length = PEI_STATUS_CODE_RT_LENGTH;\r
265\r
266 //\r
267 // Reinstall the report status code function\r
268 //\r
269 //\r
270 // Locate status code PPI\r
271 //\r
272 Status = (*PeiServices)->LocatePpi (\r
273 PeiServices,\r
274 &gPeiStatusCodePpiGuid,\r
275 0,\r
276 &ReportStatusCodeDescriptor,\r
d24d32dd 277 (VOID **) &ReportStatusCodePpi\r
b38907a6 278 );\r
279 if (EFI_ERROR (Status)) {\r
280 return ;\r
281 }\r
282 //\r
283 // Reinstall the ReportStatusCode interface using the memory-based\r
284 // descriptor\r
285 //\r
286 Status = (*PeiServices)->ReInstallPpi (\r
287 PeiServices,\r
288 ReportStatusCodeDescriptor,\r
289 &mPpiListStatusCode\r
290 );\r
291 if (EFI_ERROR (Status)) {\r
4ac4deb7 292 EFI_DEADLOOP ();\r
b38907a6 293 }\r
294 //\r
295 // Publish a GUIDed HOB that contains a pointer to the status code PPI\r
296 // structure. This is a bit of a short cut as I just used the PPI GUID to\r
297 // identify the HOB. This HOB is caught by the DXE status code memory\r
298 // listener and used to find the journal.\r
299 //\r
300 StatusCodeMemoryPpi = &mStatusCodeMemoryPpi;\r
301 Status = PeiBuildHobGuidData (\r
302 PeiServices,\r
303 &gPeiStatusCodeMemoryPpiGuid,\r
304 &StatusCodeMemoryPpi,\r
305 sizeof (VOID *)\r
306 );\r
307 if (EFI_ERROR (Status)) {\r
4ac4deb7 308 EFI_DEADLOOP ();\r
b38907a6 309 }\r
310 }\r
311}\r
312\r
313EFI_STATUS\r
314EFIAPI\r
315MemoryReportStatusCode (\r
316 IN EFI_PEI_SERVICES **PeiServices,\r
317 IN EFI_STATUS_CODE_TYPE CodeType,\r
318 IN EFI_STATUS_CODE_VALUE Value,\r
319 IN UINT32 Instance,\r
320 IN EFI_GUID * CallerId ,\r
321 IN EFI_STATUS_CODE_DATA * Data OPTIONAL\r
322 )\r
323/*++\r
324\r
325Routine Description:\r
326\r
327 Provide a memory status code\r
328\r
329Arguments:\r
330\r
331 Same as ReportStatusCode PPI\r
332 \r
333Returns:\r
334\r
335 EFI_SUCCESS This function always returns success\r
336\r
337--*/\r
338{\r
339 EFI_STATUS Status;\r
340 PEI_STATUS_CODE_MEMORY_PPI *StatusCodeMemoryPpi;\r
341 EFI_STATUS_CODE_ENTRY *CurrentEntry;\r
342 UINTN LastEntry;\r
343 MEMORY_STATUS_CODE_INSTANCE *PrivateData;\r
344 EFI_PEI_PPI_DESCRIPTOR *StatusCodeMemoryDescriptor;\r
345\r
346 //\r
347 // We don't care to log debug codes.\r
348 //\r
349 if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {\r
350 return EFI_SUCCESS;\r
351 }\r
352\r
353 if (!mRunningFromMemory) {\r
354 //\r
355 // If we are called from DXE and have not been reinstalled into memory, we\r
356 // can no longer locate the journal, so we can no longer log status codes.\r
357 //\r
358 if (!PeiServices) {\r
359 return EFI_SUCCESS;\r
360 }\r
361 //\r
362 // Locate Journal\r
363 //\r
364 Status = (*PeiServices)->LocatePpi (\r
365 PeiServices,\r
366 &gPeiStatusCodeMemoryPpiGuid,\r
367 0,\r
368 &StatusCodeMemoryDescriptor,\r
d24d32dd 369 (VOID **) &StatusCodeMemoryPpi\r
b38907a6 370 );\r
371 if (EFI_ERROR (Status)) {\r
372 return EFI_SUCCESS;\r
373 }\r
374 //\r
375 // Determine the last entry in the journal.\r
376 // This is needed to properly implement the rolling queue.\r
377 //\r
378 LastEntry = PEI_STATUS_CODE_MAX_HEAP_ENTRY;\r
379\r
380 //\r
381 // Get private data\r
382 //\r
383 PrivateData = MEMORY_STATUS_CODE_FROM_DESCRIPTOR_THIS (StatusCodeMemoryDescriptor);\r
384\r
385 //\r
386 // Once memory gets installed, heap gets moved to real memory.\r
387 // We need to fix up the pointers to match the move.\r
388 //\r
389 PrivateData->PpiDescriptor.Ppi = &PrivateData->StatusCodeMemoryPpi;\r
390 PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid;\r
391 PrivateData->StatusCodeMemoryPpi.Address = PrivateData->StatusCodeMemoryPpi.Address +\r
392 (UINTN) PrivateData - (UINTN) PrivateData->This;\r
393 PrivateData->This = PrivateData;\r
394#if (PI_SPECIFICATION_VERSION < 0x00010000)\r
395 PrivateData->NotifyDescriptor.Guid = &gPeiFvFileLoaderPpiGuid;\r
396 PrivateData->NotifyDescriptor.Notify = LoadImageCallback;\r
397#endif\r
398 StatusCodeMemoryPpi = PrivateData->PpiDescriptor.Ppi;\r
399 } else {\r
400 //\r
401 // Use global/memory copy of the PPI\r
402 //\r
403 StatusCodeMemoryPpi = &mStatusCodeMemoryPpi;\r
404\r
405 //\r
406 // Determine the last entry in the journal.\r
407 // This is needed to properly implement the rolling queue.\r
408 //\r
409 LastEntry = PEI_STATUS_CODE_MAX_RT_ENTRY;\r
410 }\r
411 //\r
412 // Return if we are using a cleared PPI somehow\r
413 //\r
414 if (!StatusCodeMemoryPpi->Address || !StatusCodeMemoryPpi->Length) {\r
415 return EFI_SUCCESS;\r
416 }\r
417 //\r
418 // Update the latest entry in the journal (may actually be first due to rolling\r
419 // queue).\r
420 //\r
421 CurrentEntry = (EFI_STATUS_CODE_ENTRY *) (UINTN) (StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->LastEntry * sizeof (EFI_STATUS_CODE_ENTRY)));\r
422\r
423 StatusCodeMemoryPpi->LastEntry = (StatusCodeMemoryPpi->LastEntry + 1) % LastEntry;\r
424 if (StatusCodeMemoryPpi->LastEntry == StatusCodeMemoryPpi->FirstEntry) {\r
425 StatusCodeMemoryPpi->FirstEntry = (StatusCodeMemoryPpi->FirstEntry + 1) % LastEntry;\r
426 }\r
427\r
428 CurrentEntry->Type = CodeType;\r
429 CurrentEntry->Value = Value;\r
430 CurrentEntry->Instance = Instance;\r
431\r
432 return EFI_SUCCESS;\r
433}\r
434\r
435\r
436#if (PI_SPECIFICATION_VERSION < 0x00010000)\r
437\r
438EFI_STATUS\r
439EFIAPI\r
440LoadImageCallback (\r
441 IN EFI_PEI_SERVICES **PeiServices,\r
442 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
443 IN VOID *Ppi\r
444 )\r
445/*++\r
446\r
447Routine Description:\r
448\r
449 Relocate the PEIM into memory.\r
450\r
451 Once load protocol becomes available, relocate our PEIM into memory.\r
452 The primary benefit is to eliminate the blackout window that we would have in\r
453 the memory log between the end of PEI and the status code DXE driver taking\r
454 control. If we don't do this, we cannot determine where our memory journal\r
455 is located and cannot function.\r
456\r
457 A second benefit is speed optimization throughout DXE.\r
458\r
459Arguments:\r
460\r
461 PeiServices - General purpose services available to every PEIM.\r
462 NotifyDescriptor - Information about the notify event.\r
463 Ppi - Context\r
464 \r
465Returns:\r
466\r
467 EFI_SUCCESS This function always returns success.\r
468\r
469--*/\r
470{\r
471 EFI_STATUS Status;\r
472 EFI_PHYSICAL_ADDRESS ImageAddress;\r
473 EFI_PHYSICAL_ADDRESS EntryPoint;\r
474 UINT64 ImageSize;\r
475 MEMORY_STATUS_CODE_INSTANCE *PrivateData;\r
476\r
477 //\r
478 // Relocate to memory\r
479 //\r
480 if (!mRunningFromMemory) {\r
481 //\r
482 // Use the callback descriptor to get the FfsHeader\r
483 //\r
484 PrivateData = MEMORY_STATUS_CODE_FROM_NOTIFY_THIS (NotifyDescriptor);\r
485\r
486 Status = ((EFI_PEI_FV_FILE_LOADER_PPI *) Ppi)->FvLoadFile (\r
487 Ppi,\r
488 PrivateData->FfsHeader,\r
489 &ImageAddress,\r
490 &ImageSize,\r
491 &EntryPoint\r
492 );\r
493 if (EFI_ERROR (Status)) {\r
494 return EFI_SUCCESS;\r
495 }\r
496 //\r
497 // Set the flag in the loaded image that indicates the PEIM is executing\r
498 // from memory.\r
499 //\r
500#ifdef EFI_NT_EMULATOR\r
501 //\r
502 // For NT32, we should also relocate image here, because if the DLL\r
503 // is already load, we will NOT load it twice. This feature is added to\r
504 // prevent loading driver twice in DXE phase cause system crash.\r
505 //\r
506 * (BOOLEAN *) ((UINTN) &mRunningFromMemory + (UINTN) EntryPoint - (UINTN) InstallMonoStatusCode) = TRUE;\r
507#else\r
508 * (BOOLEAN *) ((UINTN) &mRunningFromMemory + (UINTN) EntryPoint - (UINTN) InstallMonoStatusCode) = TRUE;\r
509#endif\r
510 Status = ((EFI_PEIM_ENTRY_POINT )(UINTN) EntryPoint) (PrivateData->FfsHeader, PeiServices);\r
511 if (EFI_ERROR (Status)) {\r
512 return EFI_SUCCESS;\r
513 }\r
514 }\r
515\r
516 return EFI_SUCCESS;\r
517}\r
518#endif\r
519\r