]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Sample/Platform/Generic/MonoStatusCode/Library/Pei/MemoryStatusCode/MemoryStatusCode.c
Add in more library for ECP.
[mirror_edk2.git] / EdkCompatibilityPkg / Sample / Platform / Generic / MonoStatusCode / Library / Pei / MemoryStatusCode / MemoryStatusCode.c
1 /*++
2
3 Copyright (c) 2004 - 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
8
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.
11
12 Module Name:
13
14 MemoryStatusCode.c
15
16 Abstract:
17
18 Lib to provide memory journal status code reporting Routines.
19
20 --*/
21
22 #include "MemoryStatusCode.h"
23 #include "PeiLib.h"
24 #include "MonoStatusCode.h"
25
26 //
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.
30 //
31 BOOLEAN mRunningFromMemory = FALSE;
32
33 //
34 // Global variable used to replace the PPI once we start running from memory.
35 //
36 PEI_STATUS_CODE_MEMORY_PPI mStatusCodeMemoryPpi = { 0, 0, 0, 0 };
37
38 //
39 // PPI descriptor for the MonoStatusCode PEIM, see MonoStatusCode.c
40 //
41 extern EFI_PEI_PPI_DESCRIPTOR mPpiListStatusCode;
42
43 VOID
44 EFIAPI
45 MemoryInitializeStatusCode (
46 IN EFI_FFS_FILE_HEADER *FfsHeader,
47 IN EFI_PEI_SERVICES **PeiServices
48 )
49 /*++
50
51 Routine Description:
52
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
58
59 Arguments:
60
61 FfsHeader - FV this PEIM was loaded from.
62 PeiServices - General purpose services available to every PEIM.
63
64 Returns:
65
66 None
67
68 --*/
69 {
70 EFI_STATUS Status;
71 MEMORY_STATUS_CODE_INSTANCE *PrivateData;
72 PEI_STATUS_CODE_MEMORY_PPI *StatusCodeMemoryPpi;
73 PEI_STATUS_CODE_PPI *ReportStatusCodePpi;
74 EFI_PHYSICAL_ADDRESS Buffer;
75 VOID *StartPointer;
76 UINTN Length;
77 UINTN LastEntry;
78 EFI_PEI_PPI_DESCRIPTOR *ReportStatusCodeDescriptor;
79 EFI_PEI_PPI_DESCRIPTOR *StatusCodeMemoryDescriptor;
80
81 //
82 // Determine if we are being called after relocation into memory.
83 //
84 if (!mRunningFromMemory) {
85 //
86 // If we are not running from memory, we need to allocate some heap and
87 // install the PPI
88 //
89 //
90 // Allocate heap storage for the journal
91 //
92 Status = (*PeiServices)->AllocatePool (
93 PeiServices,
94 PEI_STATUS_CODE_HEAP_LENGTH,
95 &StartPointer
96 );
97
98 //
99 // This is not a required feature to boot.
100 //
101 if (EFI_ERROR (Status)) {
102 return ;
103 }
104 //
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
109 // memory.
110 //
111 Status = (*PeiServices)->AllocatePool (
112 PeiServices,
113 sizeof (MEMORY_STATUS_CODE_INSTANCE),
114 &PrivateData
115 );
116
117 //
118 // This is not a required feature to boot.
119 //
120 if (EFI_ERROR (Status)) {
121 return ;
122 }
123 //
124 // Update the contents of the private data.
125 //
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 =
138 (
139 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
140 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
141 );
142 PrivateData->NotifyDescriptor.Guid = &gPeiFvFileLoaderPpiGuid;
143 PrivateData->NotifyDescriptor.Notify = LoadImageCallback;
144 #endif
145 //
146 // Publish the PPI
147 //
148 Status = (*PeiServices)->InstallPpi (PeiServices, &PrivateData->PpiDescriptor);
149 if (EFI_ERROR (Status)) {
150 return ;
151 }
152 //
153 // Post a callback to relocate to memory
154 //
155 #if (PI_SPECIFICATION_VERSION < 0x00010000)
156 Status = (**PeiServices).NotifyPpi (PeiServices, &PrivateData->NotifyDescriptor);
157 if (EFI_ERROR (Status)) {
158 return ;
159 }
160 #endif
161 } else {
162 //
163 // If we are running from memory, we need to copy from the heap to a RT
164 // memory buffer.
165 //
166 //
167 // Locate Journal
168 //
169 Status = (*PeiServices)->LocatePpi (
170 PeiServices,
171 &gPeiStatusCodeMemoryPpiGuid,
172 0,
173 &StatusCodeMemoryDescriptor,
174 &StatusCodeMemoryPpi
175 );
176 if (EFI_ERROR (Status)) {
177 return ;
178 }
179 //
180 // Get private data
181 //
182 PrivateData = MEMORY_STATUS_CODE_FROM_DESCRIPTOR_THIS (StatusCodeMemoryDescriptor);
183
184 //
185 // At this point, we need to fix up any addresses that we have as the heap
186 // has moved.
187 //
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;
196 #endif
197
198 //
199 // Allocate RT memory.
200 //
201 Status = (*PeiServices)->AllocatePages (
202 PeiServices,
203 EfiRuntimeServicesData,
204 PEI_STATUS_CODE_RT_PAGES,
205 &Buffer
206 );
207 if (EFI_ERROR (Status)) {
208 return ;
209 }
210
211 DEBUG_CODE (
212 EfiCommonLibZeroMem ((VOID *) (UINTN) Buffer, PEI_STATUS_CODE_RT_LENGTH);
213 )
214 //
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.
218 //
219 if (PEI_STATUS_CODE_RT_LENGTH <= PEI_STATUS_CODE_HEAP_LENGTH) {
220 return ;
221 }
222
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);
228 } else {
229 //
230 // The last entry will be the new last entry after moving heap to buffer
231 //
232 LastEntry = (PEI_STATUS_CODE_MAX_HEAP_ENTRY - StatusCodeMemoryPpi->FirstEntry) + StatusCodeMemoryPpi->LastEntry;
233 //
234 // Copy from the first entry to the end of the heap
235 //
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);
239 //
240 // Copy from the start to the heap to the last entry
241 //
242 StartPointer = (VOID *) (UINTN) StatusCodeMemoryPpi->Address;
243 (*PeiServices)->CopyMem (
244 (VOID *) (UINTN) (Buffer + Length),
245 StartPointer,
246 (StatusCodeMemoryPpi->LastEntry * sizeof (EFI_STATUS_CODE_ENTRY))
247 );
248 };
249
250 //
251 // Update the PPI to NULL, so it will not be used.
252 //
253 StatusCodeMemoryPpi->FirstEntry = 0;
254 StatusCodeMemoryPpi->LastEntry = 0;
255 StatusCodeMemoryPpi->Address = 0;
256 StatusCodeMemoryPpi->Length = 0;
257
258 //
259 // Update in memory version of PPI that will be used.
260 //
261 mStatusCodeMemoryPpi.FirstEntry = 0;
262 mStatusCodeMemoryPpi.LastEntry = LastEntry;
263 mStatusCodeMemoryPpi.Address = (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer;
264 mStatusCodeMemoryPpi.Length = PEI_STATUS_CODE_RT_LENGTH;
265
266 //
267 // Reinstall the report status code function
268 //
269 //
270 // Locate status code PPI
271 //
272 Status = (*PeiServices)->LocatePpi (
273 PeiServices,
274 &gPeiStatusCodePpiGuid,
275 0,
276 &ReportStatusCodeDescriptor,
277 &ReportStatusCodePpi
278 );
279 if (EFI_ERROR (Status)) {
280 return ;
281 }
282 //
283 // Reinstall the ReportStatusCode interface using the memory-based
284 // descriptor
285 //
286 Status = (*PeiServices)->ReInstallPpi (
287 PeiServices,
288 ReportStatusCodeDescriptor,
289 &mPpiListStatusCode
290 );
291 if (EFI_ERROR (Status)) {
292 EFI_BREAKPOINT ();
293 return ;
294 }
295 //
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.
300 //
301 StatusCodeMemoryPpi = &mStatusCodeMemoryPpi;
302 Status = PeiBuildHobGuidData (
303 PeiServices,
304 &gPeiStatusCodeMemoryPpiGuid,
305 &StatusCodeMemoryPpi,
306 sizeof (VOID *)
307 );
308 if (EFI_ERROR (Status)) {
309 EFI_BREAKPOINT ();
310 return ;
311 }
312 }
313 }
314
315 EFI_STATUS
316 EFIAPI
317 MemoryReportStatusCode (
318 IN EFI_PEI_SERVICES **PeiServices,
319 IN EFI_STATUS_CODE_TYPE CodeType,
320 IN EFI_STATUS_CODE_VALUE Value,
321 IN UINT32 Instance,
322 IN EFI_GUID * CallerId ,
323 IN EFI_STATUS_CODE_DATA * Data OPTIONAL
324 )
325 /*++
326
327 Routine Description:
328
329 Provide a memory status code
330
331 Arguments:
332
333 Same as ReportStatusCode PPI
334
335 Returns:
336
337 EFI_SUCCESS This function always returns success
338
339 --*/
340 {
341 EFI_STATUS Status;
342 PEI_STATUS_CODE_MEMORY_PPI *StatusCodeMemoryPpi;
343 EFI_STATUS_CODE_ENTRY *CurrentEntry;
344 UINTN LastEntry;
345 MEMORY_STATUS_CODE_INSTANCE *PrivateData;
346 EFI_PEI_PPI_DESCRIPTOR *StatusCodeMemoryDescriptor;
347
348 //
349 // We don't care to log debug codes.
350 //
351 if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {
352 return EFI_SUCCESS;
353 }
354
355 if (!mRunningFromMemory) {
356 //
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.
359 //
360 if (!PeiServices) {
361 return EFI_SUCCESS;
362 }
363 //
364 // Locate Journal
365 //
366 Status = (*PeiServices)->LocatePpi (
367 PeiServices,
368 &gPeiStatusCodeMemoryPpiGuid,
369 0,
370 &StatusCodeMemoryDescriptor,
371 &StatusCodeMemoryPpi
372 );
373 if (EFI_ERROR (Status)) {
374 return EFI_SUCCESS;
375 }
376 //
377 // Determine the last entry in the journal.
378 // This is needed to properly implement the rolling queue.
379 //
380 LastEntry = PEI_STATUS_CODE_MAX_HEAP_ENTRY;
381
382 //
383 // Get private data
384 //
385 PrivateData = MEMORY_STATUS_CODE_FROM_DESCRIPTOR_THIS (StatusCodeMemoryDescriptor);
386
387 //
388 // Once memory gets installed, heap gets moved to real memory.
389 // We need to fix up the pointers to match the move.
390 //
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;
399 #endif
400 StatusCodeMemoryPpi = PrivateData->PpiDescriptor.Ppi;
401 } else {
402 //
403 // Use global/memory copy of the PPI
404 //
405 StatusCodeMemoryPpi = &mStatusCodeMemoryPpi;
406
407 //
408 // Determine the last entry in the journal.
409 // This is needed to properly implement the rolling queue.
410 //
411 LastEntry = PEI_STATUS_CODE_MAX_RT_ENTRY;
412 }
413 //
414 // Return if we are using a cleared PPI somehow
415 //
416 if (!StatusCodeMemoryPpi->Address || !StatusCodeMemoryPpi->Length) {
417 return EFI_SUCCESS;
418 }
419 //
420 // Update the latest entry in the journal (may actually be first due to rolling
421 // queue).
422 //
423 CurrentEntry = (EFI_STATUS_CODE_ENTRY *) (UINTN) (StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->LastEntry * sizeof (EFI_STATUS_CODE_ENTRY)));
424
425 StatusCodeMemoryPpi->LastEntry = (StatusCodeMemoryPpi->LastEntry + 1) % LastEntry;
426 if (StatusCodeMemoryPpi->LastEntry == StatusCodeMemoryPpi->FirstEntry) {
427 StatusCodeMemoryPpi->FirstEntry = (StatusCodeMemoryPpi->FirstEntry + 1) % LastEntry;
428 }
429
430 CurrentEntry->Type = CodeType;
431 CurrentEntry->Value = Value;
432 CurrentEntry->Instance = Instance;
433
434 return EFI_SUCCESS;
435 }
436
437
438 #if (PI_SPECIFICATION_VERSION < 0x00010000)
439
440 EFI_STATUS
441 EFIAPI
442 LoadImageCallback (
443 IN EFI_PEI_SERVICES **PeiServices,
444 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
445 IN VOID *Ppi
446 )
447 /*++
448
449 Routine Description:
450
451 Relocate the PEIM into memory.
452
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.
458
459 A second benefit is speed optimization throughout DXE.
460
461 Arguments:
462
463 PeiServices - General purpose services available to every PEIM.
464 NotifyDescriptor - Information about the notify event.
465 Ppi - Context
466
467 Returns:
468
469 EFI_SUCCESS This function always returns success.
470
471 --*/
472 {
473 EFI_STATUS Status;
474 EFI_PHYSICAL_ADDRESS ImageAddress;
475 EFI_PHYSICAL_ADDRESS EntryPoint;
476 UINT64 ImageSize;
477 MEMORY_STATUS_CODE_INSTANCE *PrivateData;
478
479 //
480 // Relocate to memory
481 //
482 if (!mRunningFromMemory) {
483 //
484 // Use the callback descriptor to get the FfsHeader
485 //
486 PrivateData = MEMORY_STATUS_CODE_FROM_NOTIFY_THIS (NotifyDescriptor);
487
488 Status = ((EFI_PEI_FV_FILE_LOADER_PPI *) Ppi)->FvLoadFile (
489 Ppi,
490 PrivateData->FfsHeader,
491 &ImageAddress,
492 &ImageSize,
493 &EntryPoint
494 );
495 if (EFI_ERROR (Status)) {
496 return EFI_SUCCESS;
497 }
498 //
499 // Set the flag in the loaded image that indicates the PEIM is executing
500 // from memory.
501 //
502 #ifdef EFI_NT_EMULATOR
503 //
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.
507 //
508 * (BOOLEAN *) ((UINTN) &mRunningFromMemory + (UINTN) EntryPoint - (UINTN) InstallMonoStatusCode) = TRUE;
509 #else
510 * (BOOLEAN *) ((UINTN) &mRunningFromMemory + (UINTN) EntryPoint - (UINTN) InstallMonoStatusCode) = TRUE;
511 #endif
512 Status = ((EFI_PEIM_ENTRY_POINT )(UINTN) EntryPoint) (PrivateData->FfsHeader, PeiServices);
513 if (EFI_ERROR (Status)) {
514 return EFI_SUCCESS;
515 }
516 }
517
518 return EFI_SUCCESS;
519 }
520 #endif
521