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