3 Copyright (c) 2006, 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.
21 #include "MemoryStatusCode.h"
24 // Global variable. Not accessible while running from flash.
25 // After we relocate ourselves into memory, we update this
26 // and use it to determine if we are running from flash or memory.
30 // Global variable used to replace the PPI once we start running from memory.
32 PEI_STATUS_CODE_MEMORY_PPI mStatusCodeMemoryPpi
= { 0, 0, 0, 0 };
35 // PPI descriptor for the MonoStatusCode PEIM, see MonoStatusCode.c
37 extern EFI_PEI_PPI_DESCRIPTOR mPpiListStatusCode
;
41 MemoryStatusCodeInitialize (
42 IN EFI_FFS_FILE_HEADER
*FfsHeader
,
43 IN EFI_PEI_SERVICES
**PeiServices
49 Initialization routine.
50 Allocates heap space for storing Status Codes.
51 Installs a PPI to point to that heap space.
52 Installs a callback to switch to memory.
53 Installs a callback to
57 FfsHeader - FV this PEIM was loaded from.
58 PeiServices - General purpose services available to every PEIM.
67 MEMORY_STATUS_CODE_INSTANCE
*PrivateData
;
68 PEI_STATUS_CODE_MEMORY_PPI
*StatusCodeMemoryPpi
;
69 EFI_PEI_PROGRESS_CODE_PPI
*ReportStatusCodePpi
;
70 EFI_PHYSICAL_ADDRESS Buffer
;
74 EFI_PEI_PPI_DESCRIPTOR
*ReportStatusCodeDescriptor
;
75 EFI_PEI_PPI_DESCRIPTOR
*StatusCodeMemoryDescriptor
;
78 // Determine if we are being called after relocation into memory.
80 if (!gRunningFromMemory
) {
82 // If we are not running from memory, we need to allocate some heap and
86 // Allocate heap storage for the journal
88 Status
= (*PeiServices
)->AllocatePool (
90 PEI_STATUS_CODE_HEAP_LENGTH
,
95 // This is not a required feature to boot.
97 if (EFI_ERROR (Status
)) {
101 // Allocate heap storage for private data
102 // The private data contains the FFS header for this PEIM,
103 // a PPI containing information about the status code journal, and
104 // a notification for the LoadFile service, to relocate the PEIM into
107 Status
= (*PeiServices
)->AllocatePool (
109 sizeof (MEMORY_STATUS_CODE_INSTANCE
),
110 (VOID
**) &PrivateData
114 // This is not a required feature to boot.
116 if (EFI_ERROR (Status
)) {
120 // Update the contents of the private data.
122 PrivateData
->Signature
= MEMORY_STATUS_CODE_SIGNATURE
;
123 PrivateData
->This
= PrivateData
;
124 PrivateData
->FfsHeader
= FfsHeader
;
125 PrivateData
->PpiDescriptor
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
126 PrivateData
->PpiDescriptor
.Guid
= &gPeiStatusCodeMemoryPpiGuid
;
127 PrivateData
->PpiDescriptor
.Ppi
= &PrivateData
->StatusCodeMemoryPpi
;
128 PrivateData
->StatusCodeMemoryPpi
.FirstEntry
= 0;
129 PrivateData
->StatusCodeMemoryPpi
.LastEntry
= 0;
130 PrivateData
->StatusCodeMemoryPpi
.Address
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) StartPointer
;
131 PrivateData
->StatusCodeMemoryPpi
.Length
= PEI_STATUS_CODE_HEAP_LENGTH
;
132 PrivateData
->NotifyDescriptor
.Flags
=
134 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
|
135 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
137 PrivateData
->NotifyDescriptor
.Guid
= &gEfiPeiFvFileLoaderPpiGuid
;
138 PrivateData
->NotifyDescriptor
.Notify
= LoadImageCallback
;
143 Status
= (*PeiServices
)->InstallPpi (PeiServices
, &PrivateData
->PpiDescriptor
);
144 if (EFI_ERROR (Status
)) {
148 // Post a callback to relocate to memory
150 Status
= (**PeiServices
).NotifyPpi (PeiServices
, &PrivateData
->NotifyDescriptor
);
151 if (EFI_ERROR (Status
)) {
156 // If we are running from memory, we need to copy from the heap to a RT
162 Status
= (*PeiServices
)->LocatePpi (
164 &gPeiStatusCodeMemoryPpiGuid
,
166 &StatusCodeMemoryDescriptor
,
167 (VOID
**) &StatusCodeMemoryPpi
169 if (EFI_ERROR (Status
)) {
175 PrivateData
= _CR (StatusCodeMemoryDescriptor
, MEMORY_STATUS_CODE_INSTANCE
, PpiDescriptor
);
177 // At this point, we need to fix up any addresses that we have as the heap
180 PrivateData
->PpiDescriptor
.Ppi
= &PrivateData
->StatusCodeMemoryPpi
;
181 PrivateData
->PpiDescriptor
.Guid
= &gPeiStatusCodeMemoryPpiGuid
;
182 PrivateData
->StatusCodeMemoryPpi
.Address
= PrivateData
->StatusCodeMemoryPpi
.Address
+
183 (UINTN
) PrivateData
- (UINTN
) PrivateData
->This
;
184 PrivateData
->NotifyDescriptor
.Guid
= &gEfiPeiFvFileLoaderPpiGuid
;
185 PrivateData
->NotifyDescriptor
.Notify
= LoadImageCallback
;
186 PrivateData
->This
= PrivateData
;
189 // Allocate RT memory.
191 Status
= (*PeiServices
)->AllocatePages (
193 EfiRuntimeServicesData
,
194 PEI_STATUS_CODE_RT_PAGES
,
197 if (EFI_ERROR (Status
)) {
202 ZeroMem ((VOID
*) (UINTN
) Buffer
, PEI_STATUS_CODE_RT_LENGTH
);
206 // Copy the heap to the allocated memory.
207 // Unwind the rolling queue to start at 0 in the new space. We need to do
208 // this because the new queue is much bigger than the heap allocation.
210 if (PEI_STATUS_CODE_RT_LENGTH
<= PEI_STATUS_CODE_HEAP_LENGTH
) {
214 if (StatusCodeMemoryPpi
->LastEntry
>= StatusCodeMemoryPpi
->FirstEntry
) {
215 LastEntry
= StatusCodeMemoryPpi
->LastEntry
- StatusCodeMemoryPpi
->FirstEntry
;
216 StartPointer
= (VOID
*) ((UINTN
) StatusCodeMemoryPpi
->Address
+ (StatusCodeMemoryPpi
->FirstEntry
* sizeof (EFI_STATUS_CODE_ENTRY
)));
217 Length
= (StatusCodeMemoryPpi
->LastEntry
- StatusCodeMemoryPpi
->FirstEntry
) * sizeof (EFI_STATUS_CODE_ENTRY
);
218 (*PeiServices
)->CopyMem ((VOID
*) (UINTN
) Buffer
, StartPointer
, Length
);
221 // The last entry will be the new last entry after moving heap to buffer
223 LastEntry
= (PEI_STATUS_CODE_MAX_HEAP_ENTRY
- StatusCodeMemoryPpi
->FirstEntry
) + StatusCodeMemoryPpi
->LastEntry
;
225 // Copy from the first entry to the end of the heap
227 StartPointer
= (VOID
*) ((UINTN
) StatusCodeMemoryPpi
->Address
+ (StatusCodeMemoryPpi
->FirstEntry
* sizeof (EFI_STATUS_CODE_ENTRY
)));
228 Length
= PEI_STATUS_CODE_HEAP_LENGTH
- (StatusCodeMemoryPpi
->FirstEntry
* sizeof (EFI_STATUS_CODE_ENTRY
));
229 (*PeiServices
)->CopyMem ((VOID
*) (UINTN
) Buffer
, StartPointer
, Length
);
231 // Copy from the start to the heap to the last entry
233 StartPointer
= (VOID
*) (UINTN
) StatusCodeMemoryPpi
->Address
;
234 (*PeiServices
)->CopyMem (
235 (VOID
*) (UINTN
) (Buffer
+ Length
),
237 (StatusCodeMemoryPpi
->LastEntry
* sizeof (EFI_STATUS_CODE_ENTRY
))
242 // Update the PPI to NULL, so it will not be used.
244 StatusCodeMemoryPpi
->FirstEntry
= 0;
245 StatusCodeMemoryPpi
->LastEntry
= 0;
246 StatusCodeMemoryPpi
->Address
= 0;
247 StatusCodeMemoryPpi
->Length
= 0;
250 // Update in memory version of PPI that will be used.
252 mStatusCodeMemoryPpi
.FirstEntry
= 0;
253 mStatusCodeMemoryPpi
.LastEntry
= LastEntry
;
254 mStatusCodeMemoryPpi
.Address
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) Buffer
;
255 mStatusCodeMemoryPpi
.Length
= PEI_STATUS_CODE_RT_LENGTH
;
258 // Reinstall the report status code function
261 // Locate status code PPI
263 Status
= (*PeiServices
)->LocatePpi (
265 &gEfiPeiStatusCodePpiGuid
,
267 &ReportStatusCodeDescriptor
,
268 (VOID
**) &ReportStatusCodePpi
270 if (EFI_ERROR (Status
)) {
274 // Reinstall the ReportStatusCode interface using the memory-based
277 Status
= (*PeiServices
)->ReInstallPpi (
279 ReportStatusCodeDescriptor
,
282 if (EFI_ERROR (Status
)) {
287 // Publish a GUIDed HOB that contains a pointer to the status code PPI
288 // structure. This is a bit of a short cut as I just used the PPI GUID to
289 // identify the HOB. This HOB is caught by the DXE status code memory
290 // listener and used to find the journal.
292 StatusCodeMemoryPpi
= &mStatusCodeMemoryPpi
;
295 &gPeiStatusCodeMemoryPpiGuid
,
296 &StatusCodeMemoryPpi
,
304 MemoryReportStatusCode (
305 IN EFI_STATUS_CODE_TYPE CodeType
,
306 IN EFI_STATUS_CODE_VALUE Value
,
308 IN EFI_GUID
* CallerId
,
309 IN EFI_STATUS_CODE_DATA
* Data OPTIONAL
315 Provide a memory status code
319 Same as ReportStatusCode PPI
323 EFI_SUCCESS This function always returns success
328 PEI_STATUS_CODE_MEMORY_PPI
*StatusCodeMemoryPpi
;
329 EFI_STATUS_CODE_ENTRY
*CurrentEntry
;
331 MEMORY_STATUS_CODE_INSTANCE
*PrivateData
;
332 EFI_PEI_PPI_DESCRIPTOR
*StatusCodeMemoryDescriptor
;
333 EFI_PEI_SERVICES
**PeiServices
;
335 PeiServices
= GetPeiServicesTablePointer ();
337 // We don't care to log debug codes.
339 if ((CodeType
& EFI_STATUS_CODE_TYPE_MASK
) == EFI_DEBUG_CODE
) {
343 if (!gRunningFromMemory
) {
345 // If we are called from DXE and have not been reinstalled into memory, we
346 // can no longer locate the journal, so we can no longer log status codes.
354 Status
= (*PeiServices
)->LocatePpi (
356 &gPeiStatusCodeMemoryPpiGuid
,
358 &StatusCodeMemoryDescriptor
,
359 (VOID
**) &StatusCodeMemoryPpi
361 if (EFI_ERROR (Status
)) {
365 // Determine the last entry in the journal.
366 // This is needed to properly implement the rolling queue.
368 LastEntry
= PEI_STATUS_CODE_MAX_HEAP_ENTRY
;
373 PrivateData
= _CR (StatusCodeMemoryDescriptor
, MEMORY_STATUS_CODE_INSTANCE
, PpiDescriptor
);
376 // Once memory gets installed, heap gets moved to real memory.
377 // We need to fix up the pointers to match the move.
379 PrivateData
->PpiDescriptor
.Ppi
= &PrivateData
->StatusCodeMemoryPpi
;
380 PrivateData
->PpiDescriptor
.Guid
= &gPeiStatusCodeMemoryPpiGuid
;
381 PrivateData
->StatusCodeMemoryPpi
.Address
= PrivateData
->StatusCodeMemoryPpi
.Address
+
382 (UINTN
) PrivateData
- (UINTN
) PrivateData
->This
;
383 PrivateData
->NotifyDescriptor
.Guid
= &gEfiPeiFvFileLoaderPpiGuid
;
384 PrivateData
->NotifyDescriptor
.Notify
= LoadImageCallback
;
385 PrivateData
->This
= PrivateData
;
387 StatusCodeMemoryPpi
= PrivateData
->PpiDescriptor
.Ppi
;
390 // Use global/memory copy of the PPI
392 StatusCodeMemoryPpi
= &mStatusCodeMemoryPpi
;
395 // Determine the last entry in the journal.
396 // This is needed to properly implement the rolling queue.
398 LastEntry
= PEI_STATUS_CODE_MAX_RT_ENTRY
;
401 // Return if we are using a cleared PPI somehow
403 if (!StatusCodeMemoryPpi
->Address
|| !StatusCodeMemoryPpi
->Length
) {
407 // Update the latest entry in the journal (may actually be first due to rolling
410 CurrentEntry
= (EFI_STATUS_CODE_ENTRY
*) (UINTN
) (StatusCodeMemoryPpi
->Address
+ (StatusCodeMemoryPpi
->LastEntry
* sizeof (EFI_STATUS_CODE_ENTRY
)));
412 StatusCodeMemoryPpi
->LastEntry
= (StatusCodeMemoryPpi
->LastEntry
+ 1) % LastEntry
;
413 if (StatusCodeMemoryPpi
->LastEntry
== StatusCodeMemoryPpi
->FirstEntry
) {
414 StatusCodeMemoryPpi
->FirstEntry
= (StatusCodeMemoryPpi
->FirstEntry
+ 1) % LastEntry
;
417 CurrentEntry
->Type
= CodeType
;
418 CurrentEntry
->Value
= Value
;
419 CurrentEntry
->Instance
= Instance
;
427 IN EFI_PEI_SERVICES
**PeiServices
,
428 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
435 Relocate the PEIM into memory.
437 Once load protocol becomes available, relocate our PEIM into memory.
438 The primary benefit is to eliminate the blackout window that we would have in
439 the memory log between the end of PEI and the status code DXE driver taking
440 control. If we don't do this, we cannot determine where our memory journal
441 is located and cannot function.
443 A second benefit is speed optimization throughout DXE.
447 PeiServices - General purpose services available to every PEIM.
448 NotifyDescriptor - Information about the notify event.
453 EFI_SUCCESS This function always returns success.
458 EFI_PHYSICAL_ADDRESS ImageAddress
;
459 EFI_PHYSICAL_ADDRESS EntryPoint
;
461 MEMORY_STATUS_CODE_INSTANCE
*PrivateData
;
464 // Relocate to memory
466 if (!gRunningFromMemory
) {
468 // Use the callback descriptor to get the FfsHeader
470 PrivateData
= _CR (NotifyDescriptor
, MEMORY_STATUS_CODE_INSTANCE
, NotifyDescriptor
);
472 Status
= ((EFI_PEI_FV_FILE_LOADER_PPI
*) Ppi
)->FvLoadFile (
474 PrivateData
->FfsHeader
,
479 if (EFI_ERROR (Status
)) {
483 // Set the flag in the loaded image that indicates the PEIM is executing
486 #ifdef EFI_NT_EMULATOR
487 gRunningFromMemory
= TRUE
;
489 * (BOOLEAN
*) ((UINTN
) &gRunningFromMemory
+ (UINTN
) EntryPoint
- (UINTN
) _ModuleEntryPoint
) = TRUE
;
491 Status
= ((EFI_PEIM_ENTRY_POINT
)(UINTN
) EntryPoint
) (PrivateData
->FfsHeader
, PeiServices
);
492 if (EFI_ERROR (Status
)) {