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