3 Copyright (c) 2004 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Lib to provide memory journal status code reporting Routines.
22 #include "MemoryStatusCode.h"
24 #include "MonoStatusCode.h"
27 // Global variable. Not accessible while running from flash.
28 // After we relocate ourselves into memory, we update this
29 // and use it to determine if we are running from flash or memory.
31 BOOLEAN mRunningFromMemory
= FALSE
;
34 // Global variable used to replace the PPI once we start running from memory.
36 PEI_STATUS_CODE_MEMORY_PPI mStatusCodeMemoryPpi
= { 0, 0, 0, 0 };
39 // PPI descriptor for the MonoStatusCode PEIM, see MonoStatusCode.c
41 extern EFI_PEI_PPI_DESCRIPTOR mPpiListStatusCode
;
45 MemoryInitializeStatusCode (
46 IN EFI_FFS_FILE_HEADER
*FfsHeader
,
47 IN EFI_PEI_SERVICES
**PeiServices
53 Initialization routine.
54 Allocates heap space for storing Status Codes.
55 Installs a PPI to point to that heap space.
56 Installs a callback to switch to memory.
57 Installs a callback to
61 FfsHeader - FV this PEIM was loaded from.
62 PeiServices - General purpose services available to every PEIM.
71 MEMORY_STATUS_CODE_INSTANCE
*PrivateData
;
72 PEI_STATUS_CODE_MEMORY_PPI
*StatusCodeMemoryPpi
;
73 PEI_STATUS_CODE_PPI
*ReportStatusCodePpi
;
74 EFI_PHYSICAL_ADDRESS Buffer
;
78 EFI_PEI_PPI_DESCRIPTOR
*ReportStatusCodeDescriptor
;
79 EFI_PEI_PPI_DESCRIPTOR
*StatusCodeMemoryDescriptor
;
82 // Determine if we are being called after relocation into memory.
84 if (!mRunningFromMemory
) {
86 // If we are not running from memory, we need to allocate some heap and
90 // Allocate heap storage for the journal
92 Status
= (*PeiServices
)->AllocatePool (
94 PEI_STATUS_CODE_HEAP_LENGTH
,
95 (VOID
**) &StartPointer
99 // This is not a required feature to boot.
101 if (EFI_ERROR (Status
)) {
105 // Allocate heap storage for private data
106 // The private data contains the FFS header for this PEIM,
107 // a PPI containing information about the status code journal, and
108 // a notification for the LoadFile service, to relocate the PEIM into
111 Status
= (*PeiServices
)->AllocatePool (
113 sizeof (MEMORY_STATUS_CODE_INSTANCE
),
114 (VOID
**) &PrivateData
118 // This is not a required feature to boot.
120 if (EFI_ERROR (Status
)) {
124 // Update the contents of the private data.
126 PrivateData
->Signature
= MEMORY_STATUS_CODE_SIGNATURE
;
127 PrivateData
->This
= PrivateData
;
128 PrivateData
->FfsHeader
= FfsHeader
;
129 PrivateData
->PpiDescriptor
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
130 PrivateData
->PpiDescriptor
.Guid
= &gPeiStatusCodeMemoryPpiGuid
;
131 PrivateData
->PpiDescriptor
.Ppi
= &PrivateData
->StatusCodeMemoryPpi
;
132 PrivateData
->StatusCodeMemoryPpi
.FirstEntry
= 0;
133 PrivateData
->StatusCodeMemoryPpi
.LastEntry
= 0;
134 PrivateData
->StatusCodeMemoryPpi
.Address
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) StartPointer
;
135 PrivateData
->StatusCodeMemoryPpi
.Length
= PEI_STATUS_CODE_HEAP_LENGTH
;
136 #if (PI_SPECIFICATION_VERSION < 0x00010000)
137 PrivateData
->NotifyDescriptor
.Flags
=
139 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
|
140 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
142 PrivateData
->NotifyDescriptor
.Guid
= &gPeiFvFileLoaderPpiGuid
;
143 PrivateData
->NotifyDescriptor
.Notify
= LoadImageCallback
;
148 Status
= (*PeiServices
)->InstallPpi (PeiServices
, &PrivateData
->PpiDescriptor
);
149 if (EFI_ERROR (Status
)) {
153 // Post a callback to relocate to memory
155 #if (PI_SPECIFICATION_VERSION < 0x00010000)
156 Status
= (**PeiServices
).NotifyPpi (PeiServices
, &PrivateData
->NotifyDescriptor
);
157 if (EFI_ERROR (Status
)) {
163 // If we are running from memory, we need to copy from the heap to a RT
169 Status
= (*PeiServices
)->LocatePpi (
171 &gPeiStatusCodeMemoryPpiGuid
,
173 &StatusCodeMemoryDescriptor
,
174 (VOID
**) &StatusCodeMemoryPpi
176 if (EFI_ERROR (Status
)) {
182 PrivateData
= MEMORY_STATUS_CODE_FROM_DESCRIPTOR_THIS (StatusCodeMemoryDescriptor
);
185 // At this point, we need to fix up any addresses that we have as the heap
188 PrivateData
->PpiDescriptor
.Ppi
= &PrivateData
->StatusCodeMemoryPpi
;
189 PrivateData
->PpiDescriptor
.Guid
= &gPeiStatusCodeMemoryPpiGuid
;
190 PrivateData
->StatusCodeMemoryPpi
.Address
= PrivateData
->StatusCodeMemoryPpi
.Address
+
191 (UINTN
) PrivateData
- (UINTN
) PrivateData
->This
;
192 PrivateData
->This
= PrivateData
;
193 #if (PI_SPECIFICATION_VERSION < 0x00010000)
194 PrivateData
->NotifyDescriptor
.Guid
= &gPeiFvFileLoaderPpiGuid
;
195 PrivateData
->NotifyDescriptor
.Notify
= LoadImageCallback
;
199 // Allocate RT memory.
201 Status
= (*PeiServices
)->AllocatePages (
203 EfiRuntimeServicesData
,
204 PEI_STATUS_CODE_RT_PAGES
,
207 if (EFI_ERROR (Status
)) {
212 EfiCommonLibZeroMem ((VOID
*) (UINTN
) Buffer
, PEI_STATUS_CODE_RT_LENGTH
);
215 // Copy the heap to the allocated memory.
216 // Unwind the rolling queue to start at 0 in the new space. We need to do
217 // this because the new queue is much bigger than the heap allocation.
219 if (PEI_STATUS_CODE_RT_LENGTH
<= PEI_STATUS_CODE_HEAP_LENGTH
) {
223 if (StatusCodeMemoryPpi
->LastEntry
>= StatusCodeMemoryPpi
->FirstEntry
) {
224 LastEntry
= StatusCodeMemoryPpi
->LastEntry
- StatusCodeMemoryPpi
->FirstEntry
;
225 StartPointer
= (VOID
*) ((UINTN
) StatusCodeMemoryPpi
->Address
+ (StatusCodeMemoryPpi
->FirstEntry
* sizeof (EFI_STATUS_CODE_ENTRY
)));
226 Length
= (StatusCodeMemoryPpi
->LastEntry
- StatusCodeMemoryPpi
->FirstEntry
) * sizeof (EFI_STATUS_CODE_ENTRY
);
227 (*PeiServices
)->CopyMem ((VOID
*) (UINTN
) Buffer
, StartPointer
, Length
);
230 // The last entry will be the new last entry after moving heap to buffer
232 LastEntry
= (PEI_STATUS_CODE_MAX_HEAP_ENTRY
- StatusCodeMemoryPpi
->FirstEntry
) + StatusCodeMemoryPpi
->LastEntry
;
234 // Copy from the first entry to the end of the heap
236 StartPointer
= (VOID
*) ((UINTN
) StatusCodeMemoryPpi
->Address
+ (StatusCodeMemoryPpi
->FirstEntry
* sizeof (EFI_STATUS_CODE_ENTRY
)));
237 Length
= PEI_STATUS_CODE_HEAP_LENGTH
- (StatusCodeMemoryPpi
->FirstEntry
* sizeof (EFI_STATUS_CODE_ENTRY
));
238 (*PeiServices
)->CopyMem ((VOID
*) (UINTN
) Buffer
, StartPointer
, Length
);
240 // Copy from the start to the heap to the last entry
242 StartPointer
= (VOID
*) (UINTN
) StatusCodeMemoryPpi
->Address
;
243 (*PeiServices
)->CopyMem (
244 (VOID
*) (UINTN
) (Buffer
+ Length
),
246 (StatusCodeMemoryPpi
->LastEntry
* sizeof (EFI_STATUS_CODE_ENTRY
))
251 // Update the PPI to NULL, so it will not be used.
253 StatusCodeMemoryPpi
->FirstEntry
= 0;
254 StatusCodeMemoryPpi
->LastEntry
= 0;
255 StatusCodeMemoryPpi
->Address
= 0;
256 StatusCodeMemoryPpi
->Length
= 0;
259 // Update in memory version of PPI that will be used.
261 mStatusCodeMemoryPpi
.FirstEntry
= 0;
262 mStatusCodeMemoryPpi
.LastEntry
= LastEntry
;
263 mStatusCodeMemoryPpi
.Address
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) Buffer
;
264 mStatusCodeMemoryPpi
.Length
= PEI_STATUS_CODE_RT_LENGTH
;
267 // Reinstall the report status code function
270 // Locate status code PPI
272 Status
= (*PeiServices
)->LocatePpi (
274 &gPeiStatusCodePpiGuid
,
276 &ReportStatusCodeDescriptor
,
277 (VOID
**) &ReportStatusCodePpi
279 if (EFI_ERROR (Status
)) {
283 // Reinstall the ReportStatusCode interface using the memory-based
286 Status
= (*PeiServices
)->ReInstallPpi (
288 ReportStatusCodeDescriptor
,
291 if (EFI_ERROR (Status
)) {
296 // Publish a GUIDed HOB that contains a pointer to the status code PPI
297 // structure. This is a bit of a short cut as I just used the PPI GUID to
298 // identify the HOB. This HOB is caught by the DXE status code memory
299 // listener and used to find the journal.
301 StatusCodeMemoryPpi
= &mStatusCodeMemoryPpi
;
302 Status
= PeiBuildHobGuidData (
304 &gPeiStatusCodeMemoryPpiGuid
,
305 &StatusCodeMemoryPpi
,
308 if (EFI_ERROR (Status
)) {
317 MemoryReportStatusCode (
318 IN EFI_PEI_SERVICES
**PeiServices
,
319 IN EFI_STATUS_CODE_TYPE CodeType
,
320 IN EFI_STATUS_CODE_VALUE Value
,
322 IN EFI_GUID
* CallerId
,
323 IN EFI_STATUS_CODE_DATA
* Data OPTIONAL
329 Provide a memory status code
333 Same as ReportStatusCode PPI
337 EFI_SUCCESS This function always returns success
342 PEI_STATUS_CODE_MEMORY_PPI
*StatusCodeMemoryPpi
;
343 EFI_STATUS_CODE_ENTRY
*CurrentEntry
;
345 MEMORY_STATUS_CODE_INSTANCE
*PrivateData
;
346 EFI_PEI_PPI_DESCRIPTOR
*StatusCodeMemoryDescriptor
;
349 // We don't care to log debug codes.
351 if ((CodeType
& EFI_STATUS_CODE_TYPE_MASK
) == EFI_DEBUG_CODE
) {
355 if (!mRunningFromMemory
) {
357 // If we are called from DXE and have not been reinstalled into memory, we
358 // can no longer locate the journal, so we can no longer log status codes.
366 Status
= (*PeiServices
)->LocatePpi (
368 &gPeiStatusCodeMemoryPpiGuid
,
370 &StatusCodeMemoryDescriptor
,
371 (VOID
**) &StatusCodeMemoryPpi
373 if (EFI_ERROR (Status
)) {
377 // Determine the last entry in the journal.
378 // This is needed to properly implement the rolling queue.
380 LastEntry
= PEI_STATUS_CODE_MAX_HEAP_ENTRY
;
385 PrivateData
= MEMORY_STATUS_CODE_FROM_DESCRIPTOR_THIS (StatusCodeMemoryDescriptor
);
388 // Once memory gets installed, heap gets moved to real memory.
389 // We need to fix up the pointers to match the move.
391 PrivateData
->PpiDescriptor
.Ppi
= &PrivateData
->StatusCodeMemoryPpi
;
392 PrivateData
->PpiDescriptor
.Guid
= &gPeiStatusCodeMemoryPpiGuid
;
393 PrivateData
->StatusCodeMemoryPpi
.Address
= PrivateData
->StatusCodeMemoryPpi
.Address
+
394 (UINTN
) PrivateData
- (UINTN
) PrivateData
->This
;
395 PrivateData
->This
= PrivateData
;
396 #if (PI_SPECIFICATION_VERSION < 0x00010000)
397 PrivateData
->NotifyDescriptor
.Guid
= &gPeiFvFileLoaderPpiGuid
;
398 PrivateData
->NotifyDescriptor
.Notify
= LoadImageCallback
;
400 StatusCodeMemoryPpi
= PrivateData
->PpiDescriptor
.Ppi
;
403 // Use global/memory copy of the PPI
405 StatusCodeMemoryPpi
= &mStatusCodeMemoryPpi
;
408 // Determine the last entry in the journal.
409 // This is needed to properly implement the rolling queue.
411 LastEntry
= PEI_STATUS_CODE_MAX_RT_ENTRY
;
414 // Return if we are using a cleared PPI somehow
416 if (!StatusCodeMemoryPpi
->Address
|| !StatusCodeMemoryPpi
->Length
) {
420 // Update the latest entry in the journal (may actually be first due to rolling
423 CurrentEntry
= (EFI_STATUS_CODE_ENTRY
*) (UINTN
) (StatusCodeMemoryPpi
->Address
+ (StatusCodeMemoryPpi
->LastEntry
* sizeof (EFI_STATUS_CODE_ENTRY
)));
425 StatusCodeMemoryPpi
->LastEntry
= (StatusCodeMemoryPpi
->LastEntry
+ 1) % LastEntry
;
426 if (StatusCodeMemoryPpi
->LastEntry
== StatusCodeMemoryPpi
->FirstEntry
) {
427 StatusCodeMemoryPpi
->FirstEntry
= (StatusCodeMemoryPpi
->FirstEntry
+ 1) % LastEntry
;
430 CurrentEntry
->Type
= CodeType
;
431 CurrentEntry
->Value
= Value
;
432 CurrentEntry
->Instance
= Instance
;
438 #if (PI_SPECIFICATION_VERSION < 0x00010000)
443 IN EFI_PEI_SERVICES
**PeiServices
,
444 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
451 Relocate the PEIM into memory.
453 Once load protocol becomes available, relocate our PEIM into memory.
454 The primary benefit is to eliminate the blackout window that we would have in
455 the memory log between the end of PEI and the status code DXE driver taking
456 control. If we don't do this, we cannot determine where our memory journal
457 is located and cannot function.
459 A second benefit is speed optimization throughout DXE.
463 PeiServices - General purpose services available to every PEIM.
464 NotifyDescriptor - Information about the notify event.
469 EFI_SUCCESS This function always returns success.
474 EFI_PHYSICAL_ADDRESS ImageAddress
;
475 EFI_PHYSICAL_ADDRESS EntryPoint
;
477 MEMORY_STATUS_CODE_INSTANCE
*PrivateData
;
480 // Relocate to memory
482 if (!mRunningFromMemory
) {
484 // Use the callback descriptor to get the FfsHeader
486 PrivateData
= MEMORY_STATUS_CODE_FROM_NOTIFY_THIS (NotifyDescriptor
);
488 Status
= ((EFI_PEI_FV_FILE_LOADER_PPI
*) Ppi
)->FvLoadFile (
490 PrivateData
->FfsHeader
,
495 if (EFI_ERROR (Status
)) {
499 // Set the flag in the loaded image that indicates the PEIM is executing
502 #ifdef EFI_NT_EMULATOR
504 // For NT32, we should also relocate image here, because if the DLL
505 // is already load, we will NOT load it twice. This feature is added to
506 // prevent loading driver twice in DXE phase cause system crash.
508 * (BOOLEAN
*) ((UINTN
) &mRunningFromMemory
+ (UINTN
) EntryPoint
- (UINTN
) InstallMonoStatusCode
) = TRUE
;
510 * (BOOLEAN
*) ((UINTN
) &mRunningFromMemory
+ (UINTN
) EntryPoint
- (UINTN
) InstallMonoStatusCode
) = TRUE
;
512 Status
= ((EFI_PEIM_ENTRY_POINT
)(UINTN
) EntryPoint
) (PrivateData
->FfsHeader
, PeiServices
);
513 if (EFI_ERROR (Status
)) {