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