• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Misc library functions.
3 
4 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "InternalBm.h"
17 
18 /**
19   Delete the instance in Multi which matches partly with Single instance
20 
21   @param  Multi                 A pointer to a multi-instance device path data
22                                 structure.
23   @param  Single                A pointer to a single-instance device path data
24                                 structure.
25 
26   @return This function will remove the device path instances in Multi which partly
27           match with the Single, and return the result device path. If there is no
28           remaining device path as a result, this function will return NULL.
29 
30 **/
31 EFI_DEVICE_PATH_PROTOCOL *
BmDelPartMatchInstance(IN EFI_DEVICE_PATH_PROTOCOL * Multi,IN EFI_DEVICE_PATH_PROTOCOL * Single)32 BmDelPartMatchInstance (
33   IN     EFI_DEVICE_PATH_PROTOCOL  *Multi,
34   IN     EFI_DEVICE_PATH_PROTOCOL  *Single
35   )
36 {
37   EFI_DEVICE_PATH_PROTOCOL  *Instance;
38   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
39   EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;
40   UINTN                     InstanceSize;
41   UINTN                     SingleDpSize;
42 
43   NewDevicePath     = NULL;
44   TempNewDevicePath = NULL;
45 
46   if (Multi == NULL || Single == NULL) {
47     return Multi;
48   }
49 
50   Instance        = GetNextDevicePathInstance (&Multi, &InstanceSize);
51   SingleDpSize    = GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;
52   InstanceSize   -= END_DEVICE_PATH_LENGTH;
53 
54   while (Instance != NULL) {
55 
56     if (CompareMem (Instance, Single, MIN (SingleDpSize, InstanceSize)) != 0) {
57       //
58       // Append the device path instance which does not match with Single
59       //
60       TempNewDevicePath = NewDevicePath;
61       NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);
62       if (TempNewDevicePath != NULL) {
63         FreePool(TempNewDevicePath);
64       }
65     }
66     FreePool(Instance);
67     Instance      = GetNextDevicePathInstance (&Multi, &InstanceSize);
68     InstanceSize -= END_DEVICE_PATH_LENGTH;
69   }
70 
71   return NewDevicePath;
72 }
73 
74 /**
75   Function compares a device path data structure to that of all the nodes of a
76   second device path instance.
77 
78   @param  Multi                 A pointer to a multi-instance device path data
79                                 structure.
80   @param  Single                A pointer to a single-instance device path data
81                                 structure.
82 
83   @retval TRUE                  If the Single device path is contained within Multi device path.
84   @retval FALSE                 The Single device path is not match within Multi device path.
85 
86 **/
87 BOOLEAN
BmMatchDevicePaths(IN EFI_DEVICE_PATH_PROTOCOL * Multi,IN EFI_DEVICE_PATH_PROTOCOL * Single)88 BmMatchDevicePaths (
89   IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,
90   IN  EFI_DEVICE_PATH_PROTOCOL  *Single
91   )
92 {
93   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
94   EFI_DEVICE_PATH_PROTOCOL  *DevicePathInst;
95   UINTN                     Size;
96 
97   if (Multi == NULL || Single  == NULL) {
98     return FALSE;
99   }
100 
101   DevicePath     = Multi;
102   DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
103 
104   //
105   // Search for the match of 'Single' in 'Multi'
106   //
107   while (DevicePathInst != NULL) {
108     //
109     // If the single device path is found in multiple device paths,
110     // return success
111     //
112     if (CompareMem (Single, DevicePathInst, Size) == 0) {
113       FreePool (DevicePathInst);
114       return TRUE;
115     }
116 
117     FreePool (DevicePathInst);
118     DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
119   }
120 
121   return FALSE;
122 }
123 
124 /**
125   This routine adjust the memory information for different memory type and
126   save them into the variables for next boot. It resets the system when
127   memory information is updated and the current boot option belongs to
128   boot category instead of application category. It doesn't count the
129   reserved memory occupied by RAM Disk.
130 
131   @param Boot               TRUE if current boot option belongs to boot
132                             category instead of application category.
133 **/
134 VOID
BmSetMemoryTypeInformationVariable(IN BOOLEAN Boot)135 BmSetMemoryTypeInformationVariable (
136   IN BOOLEAN                    Boot
137   )
138 {
139   EFI_STATUS                   Status;
140   EFI_MEMORY_TYPE_INFORMATION  *PreviousMemoryTypeInformation;
141   EFI_MEMORY_TYPE_INFORMATION  *CurrentMemoryTypeInformation;
142   UINTN                        VariableSize;
143   UINTN                        Index;
144   UINTN                        Index1;
145   UINT32                       Previous;
146   UINT32                       Current;
147   UINT32                       Next;
148   EFI_HOB_GUID_TYPE            *GuidHob;
149   BOOLEAN                      MemoryTypeInformationModified;
150   BOOLEAN                      MemoryTypeInformationVariableExists;
151   EFI_BOOT_MODE                BootMode;
152 
153   MemoryTypeInformationModified       = FALSE;
154   MemoryTypeInformationVariableExists = FALSE;
155 
156 
157   BootMode = GetBootModeHob ();
158   //
159   // In BOOT_IN_RECOVERY_MODE, Variable region is not reliable.
160   //
161   if (BootMode == BOOT_IN_RECOVERY_MODE) {
162     return;
163   }
164 
165   //
166   // Only check the the Memory Type Information variable in the boot mode
167   // other than BOOT_WITH_DEFAULT_SETTINGS because the Memory Type
168   // Information is not valid in this boot mode.
169   //
170   if (BootMode != BOOT_WITH_DEFAULT_SETTINGS) {
171     VariableSize = 0;
172     Status = gRT->GetVariable (
173                     EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
174                     &gEfiMemoryTypeInformationGuid,
175                     NULL,
176                     &VariableSize,
177                     NULL
178                     );
179     if (Status == EFI_BUFFER_TOO_SMALL) {
180       MemoryTypeInformationVariableExists = TRUE;
181     }
182   }
183 
184   //
185   // Retrieve the current memory usage statistics.  If they are not found, then
186   // no adjustments can be made to the Memory Type Information variable.
187   //
188   Status = EfiGetSystemConfigurationTable (
189              &gEfiMemoryTypeInformationGuid,
190              (VOID **) &CurrentMemoryTypeInformation
191              );
192   if (EFI_ERROR (Status) || CurrentMemoryTypeInformation == NULL) {
193     return;
194   }
195 
196   //
197   // Get the Memory Type Information settings from Hob if they exist,
198   // PEI is responsible for getting them from variable and build a Hob to save them.
199   // If the previous Memory Type Information is not available, then set defaults
200   //
201   GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
202   if (GuidHob == NULL) {
203     //
204     // If Platform has not built Memory Type Info into the Hob, just return.
205     //
206     return;
207   }
208   PreviousMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
209   VariableSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
210 
211   //
212   // Use a heuristic to adjust the Memory Type Information for the next boot
213   //
214   DEBUG ((EFI_D_INFO, "Memory  Previous  Current    Next   \n"));
215   DEBUG ((EFI_D_INFO, " Type    Pages     Pages     Pages  \n"));
216   DEBUG ((EFI_D_INFO, "======  ========  ========  ========\n"));
217 
218   for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
219 
220     for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) {
221       if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) {
222         break;
223       }
224     }
225     if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) {
226       continue;
227     }
228 
229     //
230     // Previous is the number of pages pre-allocated
231     // Current is the number of pages actually needed
232     //
233     Previous = PreviousMemoryTypeInformation[Index].NumberOfPages;
234     Current  = CurrentMemoryTypeInformation[Index1].NumberOfPages;
235     Next     = Previous;
236 
237     //
238     // Inconsistent Memory Reserved across bootings may lead to S4 fail
239     // Write next varible to 125% * current when the pre-allocated memory is:
240     //  1. More than 150% of needed memory and boot mode is BOOT_WITH_DEFAULT_SETTING
241     //  2. Less than the needed memory
242     //
243     if ((Current + (Current >> 1)) < Previous) {
244       if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
245         Next = Current + (Current >> 2);
246       }
247     } else if (Current > Previous) {
248       Next = Current + (Current >> 2);
249     }
250     if (Next > 0 && Next < 4) {
251       Next = 4;
252     }
253 
254     if (Next != Previous) {
255       PreviousMemoryTypeInformation[Index].NumberOfPages = Next;
256       MemoryTypeInformationModified = TRUE;
257     }
258 
259     DEBUG ((EFI_D_INFO, "  %02x    %08x  %08x  %08x\n", PreviousMemoryTypeInformation[Index].Type, Previous, Current, Next));
260   }
261 
262   //
263   // If any changes were made to the Memory Type Information settings, then set the new variable value;
264   // Or create the variable in first boot.
265   //
266   if (MemoryTypeInformationModified || !MemoryTypeInformationVariableExists) {
267     Status = BmSetVariableAndReportStatusCodeOnError (
268                EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
269                &gEfiMemoryTypeInformationGuid,
270                EFI_VARIABLE_NON_VOLATILE  | EFI_VARIABLE_BOOTSERVICE_ACCESS,
271                VariableSize,
272                PreviousMemoryTypeInformation
273                );
274 
275     if (!EFI_ERROR (Status)) {
276       //
277       // If the Memory Type Information settings have been modified and the boot option belongs to boot category,
278       // then reset the platform so the new Memory Type Information setting will be used to guarantee that an S4
279       // entry/resume cycle will not fail.
280       //
281       if (MemoryTypeInformationModified && Boot && PcdGetBool (PcdResetOnMemoryTypeInformationChange)) {
282         DEBUG ((EFI_D_INFO, "Memory Type Information settings change. Warm Reset!!!\n"));
283         gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
284       }
285     } else {
286       DEBUG ((EFI_D_ERROR, "Memory Type Information settings cannot be saved. OS S4 may fail!\n"));
287     }
288   }
289 }
290 
291 /**
292   Set the variable and report the error through status code upon failure.
293 
294   @param  VariableName           A Null-terminated string that is the name of the vendor's variable.
295                                  Each VariableName is unique for each VendorGuid. VariableName must
296                                  contain 1 or more characters. If VariableName is an empty string,
297                                  then EFI_INVALID_PARAMETER is returned.
298   @param  VendorGuid             A unique identifier for the vendor.
299   @param  Attributes             Attributes bitmask to set for the variable.
300   @param  DataSize               The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
301                                  EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or
302                                  EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
303                                  causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
304                                  set, then a SetVariable() call with a DataSize of zero will not cause any change to
305                                  the variable value (the timestamp associated with the variable may be updated however
306                                  even if no new data value is provided,see the description of the
307                                  EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
308                                  be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
309   @param  Data                   The contents for the variable.
310 
311   @retval EFI_SUCCESS            The firmware has successfully stored the variable and its data as
312                                  defined by the Attributes.
313   @retval EFI_INVALID_PARAMETER  An invalid combination of attribute bits, name, and GUID was supplied, or the
314                                  DataSize exceeds the maximum allowed.
315   @retval EFI_INVALID_PARAMETER  VariableName is an empty string.
316   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.
317   @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
318   @retval EFI_WRITE_PROTECTED    The variable in question is read-only.
319   @retval EFI_WRITE_PROTECTED    The variable in question cannot be deleted.
320   @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
321                                  or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo
322                                  does NOT pass the validation check carried out by the firmware.
323 
324   @retval EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.
325 **/
326 EFI_STATUS
BmSetVariableAndReportStatusCodeOnError(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN UINT32 Attributes,IN UINTN DataSize,IN VOID * Data)327 BmSetVariableAndReportStatusCodeOnError (
328   IN CHAR16     *VariableName,
329   IN EFI_GUID   *VendorGuid,
330   IN UINT32     Attributes,
331   IN UINTN      DataSize,
332   IN VOID       *Data
333   )
334 {
335   EFI_STATUS                 Status;
336   EDKII_SET_VARIABLE_STATUS  *SetVariableStatus;
337   UINTN                      NameSize;
338 
339   Status = gRT->SetVariable (
340                   VariableName,
341                   VendorGuid,
342                   Attributes,
343                   DataSize,
344                   Data
345                   );
346   if (EFI_ERROR (Status)) {
347     NameSize = StrSize (VariableName);
348     SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);
349     if (SetVariableStatus != NULL) {
350       CopyGuid (&SetVariableStatus->Guid, VendorGuid);
351       SetVariableStatus->NameSize   = NameSize;
352       SetVariableStatus->DataSize   = DataSize;
353       SetVariableStatus->SetStatus  = Status;
354       SetVariableStatus->Attributes = Attributes;
355       CopyMem (SetVariableStatus + 1,                          VariableName, NameSize);
356       CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data,         DataSize);
357 
358       REPORT_STATUS_CODE_EX (
359         EFI_ERROR_CODE,
360         PcdGet32 (PcdErrorCodeSetVariable),
361         0,
362         NULL,
363         &gEdkiiStatusCodeDataTypeVariableGuid,
364         SetVariableStatus,
365         sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize
366         );
367 
368       FreePool (SetVariableStatus);
369     }
370   }
371 
372   return Status;
373 }
374 
375 
376 /**
377   Print the device path info.
378 
379   @param DevicePath           The device path need to print.
380 **/
381 VOID
BmPrintDp(EFI_DEVICE_PATH_PROTOCOL * DevicePath)382 BmPrintDp (
383   EFI_DEVICE_PATH_PROTOCOL            *DevicePath
384   )
385 {
386   CHAR16                              *Str;
387 
388   Str = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
389   DEBUG ((EFI_D_INFO, "%s", Str));
390   if (Str != NULL) {
391     FreePool (Str);
392   }
393 }
394 
395 /**
396   Convert a single character to number.
397   It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'
398 
399   @param    Char   The input char which need to convert to int.
400 
401   @return  The converted 8-bit number or (UINTN) -1 if conversion failed.
402 **/
403 UINTN
BmCharToUint(IN CHAR16 Char)404 BmCharToUint (
405   IN CHAR16                           Char
406   )
407 {
408   if ((Char >= L'0') && (Char <= L'9')) {
409     return (UINTN) (Char - L'0');
410   }
411 
412   if ((Char >= L'A') && (Char <= L'F')) {
413     return (UINTN) (Char - L'A' + 0xA);
414   }
415 
416   ASSERT (FALSE);
417   return (UINTN) -1;
418 }
419 
420 /**
421   Dispatch the deferred images that are returned from all DeferredImageLoad instances.
422 
423   @retval EFI_SUCCESS       At least one deferred image is loaded successfully and started.
424   @retval EFI_NOT_FOUND     There is no deferred image.
425   @retval EFI_ACCESS_DENIED There are deferred images but all of them are failed to load.
426 **/
427 EFI_STATUS
428 EFIAPI
EfiBootManagerDispatchDeferredImages(VOID)429 EfiBootManagerDispatchDeferredImages (
430   VOID
431   )
432 {
433   EFI_STATUS                         Status;
434   EFI_DEFERRED_IMAGE_LOAD_PROTOCOL   *DeferredImage;
435   UINTN                              HandleCount;
436   EFI_HANDLE                         *Handles;
437   UINTN                              Index;
438   UINTN                              ImageIndex;
439   EFI_DEVICE_PATH_PROTOCOL           *ImageDevicePath;
440   VOID                               *Image;
441   UINTN                              ImageSize;
442   BOOLEAN                            BootOption;
443   EFI_HANDLE                         ImageHandle;
444   UINTN                              ExitDataSize;
445   CHAR16                             *ExitData;
446   UINTN                              ImageCount;
447   UINTN                              LoadCount;
448 
449   //
450   // Find all the deferred image load protocols.
451   //
452   HandleCount = 0;
453   Handles = NULL;
454   Status = gBS->LocateHandleBuffer (
455     ByProtocol,
456     &gEfiDeferredImageLoadProtocolGuid,
457     NULL,
458     &HandleCount,
459     &Handles
460   );
461   if (EFI_ERROR (Status)) {
462     return EFI_NOT_FOUND;
463   }
464 
465   ImageCount = 0;
466   LoadCount  = 0;
467   for (Index = 0; Index < HandleCount; Index++) {
468     Status = gBS->HandleProtocol (Handles[Index], &gEfiDeferredImageLoadProtocolGuid, (VOID **) &DeferredImage);
469     if (EFI_ERROR (Status)) {
470       continue;
471     }
472 
473     for (ImageIndex = 0; ;ImageIndex++) {
474       //
475       // Load all the deferred images in this protocol instance.
476       //
477       Status = DeferredImage->GetImageInfo (
478                                 DeferredImage,
479                                 ImageIndex,
480                                 &ImageDevicePath,
481                                 (VOID **) &Image,
482                                 &ImageSize,
483                                 &BootOption
484                                 );
485       if (EFI_ERROR (Status)) {
486         break;
487       }
488       ImageCount++;
489       //
490       // Load and start the image.
491       //
492       Status = gBS->LoadImage (
493         BootOption,
494         gImageHandle,
495         ImageDevicePath,
496         NULL,
497         0,
498         &ImageHandle
499       );
500       if (!EFI_ERROR (Status)) {
501         LoadCount++;
502         //
503         // Before calling the image, enable the Watchdog Timer for
504         // a 5 Minute period
505         //
506         gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
507         Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);
508         if (ExitData != NULL) {
509           FreePool (ExitData);
510         }
511 
512         //
513         // Clear the Watchdog Timer after the image returns.
514         //
515         gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
516       }
517     }
518   }
519   if (Handles != NULL) {
520     FreePool (Handles);
521   }
522 
523   if (ImageCount == 0) {
524     return EFI_NOT_FOUND;
525   } else {
526     if (LoadCount == 0) {
527       return EFI_ACCESS_DENIED;
528     } else {
529       return EFI_SUCCESS;
530     }
531   }
532 }
533