]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Sample/Platform/Generic/MonoStatusCode/Library/Pei/MemoryStatusCode/MemoryStatusCode.c
Update the copyright notice format
[mirror_edk2.git] / EdkCompatibilityPkg / Sample / Platform / Generic / MonoStatusCode / Library / Pei / MemoryStatusCode / MemoryStatusCode.c
CommitLineData
b38907a6 1/*++\r
2\r
4b1e1121
HT
3Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>\r
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
292 EFI_BREAKPOINT ();\r
293 return ;\r
294 }\r
295 //\r
296 // Publish a GUIDed HOB that contains a pointer to the status code PPI\r
297 // structure. This is a bit of a short cut as I just used the PPI GUID to\r
298 // identify the HOB. This HOB is caught by the DXE status code memory\r
299 // listener and used to find the journal.\r
300 //\r
301 StatusCodeMemoryPpi = &mStatusCodeMemoryPpi;\r
302 Status = PeiBuildHobGuidData (\r
303 PeiServices,\r
304 &gPeiStatusCodeMemoryPpiGuid,\r
305 &StatusCodeMemoryPpi,\r
306 sizeof (VOID *)\r
307 );\r
308 if (EFI_ERROR (Status)) {\r
309 EFI_BREAKPOINT ();\r
310 return ;\r
311 }\r
312 }\r
313}\r
314\r
315EFI_STATUS\r
316EFIAPI\r
317MemoryReportStatusCode (\r
318 IN EFI_PEI_SERVICES **PeiServices,\r
319 IN EFI_STATUS_CODE_TYPE CodeType,\r
320 IN EFI_STATUS_CODE_VALUE Value,\r
321 IN UINT32 Instance,\r
322 IN EFI_GUID * CallerId ,\r
323 IN EFI_STATUS_CODE_DATA * Data OPTIONAL\r
324 )\r
325/*++\r
326\r
327Routine Description:\r
328\r
329 Provide a memory status code\r
330\r
331Arguments:\r
332\r
333 Same as ReportStatusCode PPI\r
334 \r
335Returns:\r
336\r
337 EFI_SUCCESS This function always returns success\r
338\r
339--*/\r
340{\r
341 EFI_STATUS Status;\r
342 PEI_STATUS_CODE_MEMORY_PPI *StatusCodeMemoryPpi;\r
343 EFI_STATUS_CODE_ENTRY *CurrentEntry;\r
344 UINTN LastEntry;\r
345 MEMORY_STATUS_CODE_INSTANCE *PrivateData;\r
346 EFI_PEI_PPI_DESCRIPTOR *StatusCodeMemoryDescriptor;\r
347\r
348 //\r
349 // We don't care to log debug codes.\r
350 //\r
351 if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {\r
352 return EFI_SUCCESS;\r
353 }\r
354\r
355 if (!mRunningFromMemory) {\r
356 //\r
357 // If we are called from DXE and have not been reinstalled into memory, we\r
358 // can no longer locate the journal, so we can no longer log status codes.\r
359 //\r
360 if (!PeiServices) {\r
361 return EFI_SUCCESS;\r
362 }\r
363 //\r
364 // Locate Journal\r
365 //\r
366 Status = (*PeiServices)->LocatePpi (\r
367 PeiServices,\r
368 &gPeiStatusCodeMemoryPpiGuid,\r
369 0,\r
370 &StatusCodeMemoryDescriptor,\r
d24d32dd 371 (VOID **) &StatusCodeMemoryPpi\r
b38907a6 372 );\r
373 if (EFI_ERROR (Status)) {\r
374 return EFI_SUCCESS;\r
375 }\r
376 //\r
377 // Determine the last entry in the journal.\r
378 // This is needed to properly implement the rolling queue.\r
379 //\r
380 LastEntry = PEI_STATUS_CODE_MAX_HEAP_ENTRY;\r
381\r
382 //\r
383 // Get private data\r
384 //\r
385 PrivateData = MEMORY_STATUS_CODE_FROM_DESCRIPTOR_THIS (StatusCodeMemoryDescriptor);\r
386\r
387 //\r
388 // Once memory gets installed, heap gets moved to real memory.\r
389 // We need to fix up the pointers to match the move.\r
390 //\r
391 PrivateData->PpiDescriptor.Ppi = &PrivateData->StatusCodeMemoryPpi;\r
392 PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid;\r
393 PrivateData->StatusCodeMemoryPpi.Address = PrivateData->StatusCodeMemoryPpi.Address +\r
394 (UINTN) PrivateData - (UINTN) PrivateData->This;\r
395 PrivateData->This = PrivateData;\r
396#if (PI_SPECIFICATION_VERSION < 0x00010000)\r
397 PrivateData->NotifyDescriptor.Guid = &gPeiFvFileLoaderPpiGuid;\r
398 PrivateData->NotifyDescriptor.Notify = LoadImageCallback;\r
399#endif\r
400 StatusCodeMemoryPpi = PrivateData->PpiDescriptor.Ppi;\r
401 } else {\r
402 //\r
403 // Use global/memory copy of the PPI\r
404 //\r
405 StatusCodeMemoryPpi = &mStatusCodeMemoryPpi;\r
406\r
407 //\r
408 // Determine the last entry in the journal.\r
409 // This is needed to properly implement the rolling queue.\r
410 //\r
411 LastEntry = PEI_STATUS_CODE_MAX_RT_ENTRY;\r
412 }\r
413 //\r
414 // Return if we are using a cleared PPI somehow\r
415 //\r
416 if (!StatusCodeMemoryPpi->Address || !StatusCodeMemoryPpi->Length) {\r
417 return EFI_SUCCESS;\r
418 }\r
419 //\r
420 // Update the latest entry in the journal (may actually be first due to rolling\r
421 // queue).\r
422 //\r
423 CurrentEntry = (EFI_STATUS_CODE_ENTRY *) (UINTN) (StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->LastEntry * sizeof (EFI_STATUS_CODE_ENTRY)));\r
424\r
425 StatusCodeMemoryPpi->LastEntry = (StatusCodeMemoryPpi->LastEntry + 1) % LastEntry;\r
426 if (StatusCodeMemoryPpi->LastEntry == StatusCodeMemoryPpi->FirstEntry) {\r
427 StatusCodeMemoryPpi->FirstEntry = (StatusCodeMemoryPpi->FirstEntry + 1) % LastEntry;\r
428 }\r
429\r
430 CurrentEntry->Type = CodeType;\r
431 CurrentEntry->Value = Value;\r
432 CurrentEntry->Instance = Instance;\r
433\r
434 return EFI_SUCCESS;\r
435}\r
436\r
437\r
438#if (PI_SPECIFICATION_VERSION < 0x00010000)\r
439\r
440EFI_STATUS\r
441EFIAPI\r
442LoadImageCallback (\r
443 IN EFI_PEI_SERVICES **PeiServices,\r
444 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
445 IN VOID *Ppi\r
446 )\r
447/*++\r
448\r
449Routine Description:\r
450\r
451 Relocate the PEIM into memory.\r
452\r
453 Once load protocol becomes available, relocate our PEIM into memory.\r
454 The primary benefit is to eliminate the blackout window that we would have in\r
455 the memory log between the end of PEI and the status code DXE driver taking\r
456 control. If we don't do this, we cannot determine where our memory journal\r
457 is located and cannot function.\r
458\r
459 A second benefit is speed optimization throughout DXE.\r
460\r
461Arguments:\r
462\r
463 PeiServices - General purpose services available to every PEIM.\r
464 NotifyDescriptor - Information about the notify event.\r
465 Ppi - Context\r
466 \r
467Returns:\r
468\r
469 EFI_SUCCESS This function always returns success.\r
470\r
471--*/\r
472{\r
473 EFI_STATUS Status;\r
474 EFI_PHYSICAL_ADDRESS ImageAddress;\r
475 EFI_PHYSICAL_ADDRESS EntryPoint;\r
476 UINT64 ImageSize;\r
477 MEMORY_STATUS_CODE_INSTANCE *PrivateData;\r
478\r
479 //\r
480 // Relocate to memory\r
481 //\r
482 if (!mRunningFromMemory) {\r
483 //\r
484 // Use the callback descriptor to get the FfsHeader\r
485 //\r
486 PrivateData = MEMORY_STATUS_CODE_FROM_NOTIFY_THIS (NotifyDescriptor);\r
487\r
488 Status = ((EFI_PEI_FV_FILE_LOADER_PPI *) Ppi)->FvLoadFile (\r
489 Ppi,\r
490 PrivateData->FfsHeader,\r
491 &ImageAddress,\r
492 &ImageSize,\r
493 &EntryPoint\r
494 );\r
495 if (EFI_ERROR (Status)) {\r
496 return EFI_SUCCESS;\r
497 }\r
498 //\r
499 // Set the flag in the loaded image that indicates the PEIM is executing\r
500 // from memory.\r
501 //\r
502#ifdef EFI_NT_EMULATOR\r
503 //\r
504 // For NT32, we should also relocate image here, because if the DLL\r
505 // is already load, we will NOT load it twice. This feature is added to\r
506 // prevent loading driver twice in DXE phase cause system crash.\r
507 //\r
508 * (BOOLEAN *) ((UINTN) &mRunningFromMemory + (UINTN) EntryPoint - (UINTN) InstallMonoStatusCode) = TRUE;\r
509#else\r
510 * (BOOLEAN *) ((UINTN) &mRunningFromMemory + (UINTN) EntryPoint - (UINTN) InstallMonoStatusCode) = TRUE;\r
511#endif\r
512 Status = ((EFI_PEIM_ENTRY_POINT )(UINTN) EntryPoint) (PrivateData->FfsHeader, PeiServices);\r
513 if (EFI_ERROR (Status)) {\r
514 return EFI_SUCCESS;\r
515 }\r
516 }\r
517\r
518 return EFI_SUCCESS;\r
519}\r
520#endif\r
521\r