mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-30 05:08:29 +00:00 
			
		
		
		
	 16f6922709
			
		
	
	
		16f6922709
		
	
	
	
	
		
			
			There are cases that the operands of an expression are all with rank less
than UINT64/INT64 and the result of the expression is explicitly cast to
UINT64/INT64 to fit the target size.
An example will be:
UINT32 a,b;
// a and b can be any unsigned int type with rank less than UINT64, like
// UINT8, UINT16, etc.
UINT64 c;
c = (UINT64) (a + b);
Some static code checkers may warn that the expression result might
overflow within the rank of "int" (integer promotions) and the result is
then cast to a bigger size.
The commit refines codes by the following rules:
1). When the expression is possible to overflow the range of unsigned int/
int:
c = (UINT64)a + b;
2). When the expression will not overflow within the rank of "int", remove
the explicit type casts:
c = a + b;
3). When the expression will be cast to pointer of possible greater size:
UINT32 a,b;
VOID *c;
c = (VOID *)(UINTN)(a + b); --> c = (VOID *)((UINTN)a + b);
4). When one side of a comparison expression contains only operands with
rank less than UINT32:
UINT8 a;
UINT16 b;
UINTN c;
if ((UINTN)(a + b) > c) {...} --> if (((UINT32)a + b) > c) {...}
For rule 4), if we remove the 'UINTN' type cast like:
if (a + b > c) {...}
The VS compiler will complain with warning C4018 (signed/unsigned
mismatch, level 3 warning) due to promoting 'a + b' to type 'int'.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
Reviewed-by: Feng Tian <feng.tian@intel.com>
		
	
			
		
			
				
	
	
		
			540 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			540 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Misc library functions.
 | |
| 
 | |
| Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
 | |
| (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
 | |
| This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions of the BSD License
 | |
| which accompanies this distribution.  The full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "InternalBm.h"
 | |
| 
 | |
| /**
 | |
|   Delete the instance in Multi which matches partly with Single instance
 | |
| 
 | |
|   @param  Multi                 A pointer to a multi-instance device path data
 | |
|                                 structure.
 | |
|   @param  Single                A pointer to a single-instance device path data
 | |
|                                 structure.
 | |
| 
 | |
|   @return This function will remove the device path instances in Multi which partly
 | |
|           match with the Single, and return the result device path. If there is no
 | |
|           remaining device path as a result, this function will return NULL.
 | |
| 
 | |
| **/
 | |
| EFI_DEVICE_PATH_PROTOCOL *
 | |
| BmDelPartMatchInstance (
 | |
|   IN     EFI_DEVICE_PATH_PROTOCOL  *Multi,
 | |
|   IN     EFI_DEVICE_PATH_PROTOCOL  *Single
 | |
|   )
 | |
| {
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *Instance;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;
 | |
|   UINTN                     InstanceSize;
 | |
|   UINTN                     SingleDpSize;
 | |
| 
 | |
|   NewDevicePath     = NULL;
 | |
|   TempNewDevicePath = NULL;
 | |
| 
 | |
|   if (Multi == NULL || Single == NULL) {
 | |
|     return Multi;
 | |
|   }
 | |
| 
 | |
|   Instance        = GetNextDevicePathInstance (&Multi, &InstanceSize);
 | |
|   SingleDpSize    = GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;
 | |
|   InstanceSize   -= END_DEVICE_PATH_LENGTH;
 | |
| 
 | |
|   while (Instance != NULL) {
 | |
| 
 | |
|     if (CompareMem (Instance, Single, MIN (SingleDpSize, InstanceSize)) != 0) {
 | |
|       //
 | |
|       // Append the device path instance which does not match with Single
 | |
|       //
 | |
|       TempNewDevicePath = NewDevicePath;
 | |
|       NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);
 | |
|       if (TempNewDevicePath != NULL) {
 | |
|         FreePool(TempNewDevicePath);
 | |
|       }
 | |
|     }
 | |
|     FreePool(Instance);
 | |
|     Instance      = GetNextDevicePathInstance (&Multi, &InstanceSize);
 | |
|     InstanceSize -= END_DEVICE_PATH_LENGTH;
 | |
|   }
 | |
| 
 | |
|   return NewDevicePath;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Function compares a device path data structure to that of all the nodes of a
 | |
|   second device path instance.
 | |
| 
 | |
|   @param  Multi                 A pointer to a multi-instance device path data
 | |
|                                 structure.
 | |
|   @param  Single                A pointer to a single-instance device path data
 | |
|                                 structure.
 | |
| 
 | |
|   @retval TRUE                  If the Single device path is contained within Multi device path.
 | |
|   @retval FALSE                 The Single device path is not match within Multi device path.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| BmMatchDevicePaths (
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL  *Single
 | |
|   )
 | |
| {
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *DevicePathInst;
 | |
|   UINTN                     Size;
 | |
| 
 | |
|   if (Multi == NULL || Single  == NULL) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   DevicePath     = Multi;
 | |
|   DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
 | |
| 
 | |
|   //
 | |
|   // Search for the match of 'Single' in 'Multi'
 | |
|   //
 | |
|   while (DevicePathInst != NULL) {
 | |
|     //
 | |
|     // If the single device path is found in multiple device paths,
 | |
|     // return success
 | |
|     //
 | |
|     if (CompareMem (Single, DevicePathInst, Size) == 0) {
 | |
|       FreePool (DevicePathInst);
 | |
|       return TRUE;
 | |
|     }
 | |
| 
 | |
|     FreePool (DevicePathInst);
 | |
|     DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This routine adjust the memory information for different memory type and 
 | |
|   save them into the variables for next boot. It resets the system when
 | |
|   memory information is updated and the current boot option belongs to
 | |
|   boot category instead of application category. It doesn't count the
 | |
|   reserved memory occupied by RAM Disk.
 | |
| 
 | |
|   @param Boot               TRUE if current boot option belongs to boot
 | |
|                             category instead of application category.
 | |
| **/
 | |
| VOID
 | |
| BmSetMemoryTypeInformationVariable (
 | |
|   IN BOOLEAN                    Boot
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                   Status;
 | |
|   EFI_MEMORY_TYPE_INFORMATION  *PreviousMemoryTypeInformation;
 | |
|   EFI_MEMORY_TYPE_INFORMATION  *CurrentMemoryTypeInformation;
 | |
|   UINTN                        VariableSize;
 | |
|   UINTN                        Index;
 | |
|   UINTN                        Index1;
 | |
|   UINT32                       Previous;
 | |
|   UINT32                       Current;
 | |
|   UINT32                       Next;
 | |
|   EFI_HOB_GUID_TYPE            *GuidHob;
 | |
|   BOOLEAN                      MemoryTypeInformationModified;
 | |
|   BOOLEAN                      MemoryTypeInformationVariableExists;
 | |
|   EFI_BOOT_MODE                BootMode;
 | |
| 
 | |
|   MemoryTypeInformationModified       = FALSE;
 | |
|   MemoryTypeInformationVariableExists = FALSE;
 | |
| 
 | |
| 
 | |
|   BootMode = GetBootModeHob ();
 | |
|   //
 | |
|   // In BOOT_IN_RECOVERY_MODE, Variable region is not reliable.
 | |
|   //
 | |
|   if (BootMode == BOOT_IN_RECOVERY_MODE) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Only check the the Memory Type Information variable in the boot mode 
 | |
|   // other than BOOT_WITH_DEFAULT_SETTINGS because the Memory Type
 | |
|   // Information is not valid in this boot mode.
 | |
|   //
 | |
|   if (BootMode != BOOT_WITH_DEFAULT_SETTINGS) {
 | |
|     VariableSize = 0;
 | |
|     Status = gRT->GetVariable (
 | |
|                     EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
 | |
|                     &gEfiMemoryTypeInformationGuid,
 | |
|                     NULL, 
 | |
|                     &VariableSize, 
 | |
|                     NULL
 | |
|                     );
 | |
|     if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
|       MemoryTypeInformationVariableExists = TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Retrieve the current memory usage statistics.  If they are not found, then
 | |
|   // no adjustments can be made to the Memory Type Information variable.
 | |
|   //
 | |
|   Status = EfiGetSystemConfigurationTable (
 | |
|              &gEfiMemoryTypeInformationGuid,
 | |
|              (VOID **) &CurrentMemoryTypeInformation
 | |
|              );
 | |
|   if (EFI_ERROR (Status) || CurrentMemoryTypeInformation == NULL) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the Memory Type Information settings from Hob if they exist,
 | |
|   // PEI is responsible for getting them from variable and build a Hob to save them.
 | |
|   // If the previous Memory Type Information is not available, then set defaults
 | |
|   //
 | |
|   GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
 | |
|   if (GuidHob == NULL) {
 | |
|     //
 | |
|     // If Platform has not built Memory Type Info into the Hob, just return.
 | |
|     //
 | |
|     return;
 | |
|   }
 | |
|   VariableSize                  = GET_GUID_HOB_DATA_SIZE (GuidHob);
 | |
|   PreviousMemoryTypeInformation = AllocateCopyPool (VariableSize, GET_GUID_HOB_DATA (GuidHob));
 | |
|   if (PreviousMemoryTypeInformation == NULL) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Use a heuristic to adjust the Memory Type Information for the next boot
 | |
|   //
 | |
|   DEBUG ((EFI_D_INFO, "Memory  Previous  Current    Next   \n"));
 | |
|   DEBUG ((EFI_D_INFO, " Type    Pages     Pages     Pages  \n"));
 | |
|   DEBUG ((EFI_D_INFO, "======  ========  ========  ========\n"));
 | |
| 
 | |
|   for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
 | |
| 
 | |
|     for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) {
 | |
|       if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|     if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Previous is the number of pages pre-allocated
 | |
|     // Current is the number of pages actually needed
 | |
|     //
 | |
|     Previous = PreviousMemoryTypeInformation[Index].NumberOfPages;
 | |
|     Current  = CurrentMemoryTypeInformation[Index1].NumberOfPages;
 | |
|     Next     = Previous;
 | |
| 
 | |
|     //
 | |
|     // Inconsistent Memory Reserved across bootings may lead to S4 fail
 | |
|     // Write next varible to 125% * current when the pre-allocated memory is:
 | |
|     //  1. More than 150% of needed memory and boot mode is BOOT_WITH_DEFAULT_SETTING
 | |
|     //  2. Less than the needed memory
 | |
|     //
 | |
|     if ((Current + (Current >> 1)) < Previous) {
 | |
|       if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
 | |
|         Next = Current + (Current >> 2);
 | |
|       }
 | |
|     } else if (Current > Previous) {
 | |
|       Next = Current + (Current >> 2);
 | |
|     }
 | |
|     if (Next > 0 && Next < 4) {
 | |
|       Next = 4;
 | |
|     }
 | |
| 
 | |
|     if (Next != Previous) {
 | |
|       PreviousMemoryTypeInformation[Index].NumberOfPages = Next;
 | |
|       MemoryTypeInformationModified = TRUE;
 | |
|     }
 | |
| 
 | |
|     DEBUG ((EFI_D_INFO, "  %02x    %08x  %08x  %08x\n", PreviousMemoryTypeInformation[Index].Type, Previous, Current, Next));
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If any changes were made to the Memory Type Information settings, then set the new variable value;
 | |
|   // Or create the variable in first boot.
 | |
|   //
 | |
|   if (MemoryTypeInformationModified || !MemoryTypeInformationVariableExists) {
 | |
|     Status = BmSetVariableAndReportStatusCodeOnError (
 | |
|                EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
 | |
|                &gEfiMemoryTypeInformationGuid,
 | |
|                EFI_VARIABLE_NON_VOLATILE  | EFI_VARIABLE_BOOTSERVICE_ACCESS,
 | |
|                VariableSize,
 | |
|                PreviousMemoryTypeInformation
 | |
|                );
 | |
| 
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // If the Memory Type Information settings have been modified and the boot option belongs to boot category,
 | |
|       // then reset the platform so the new Memory Type Information setting will be used to guarantee that an S4
 | |
|       // entry/resume cycle will not fail.
 | |
|       //
 | |
|       if (MemoryTypeInformationModified) {
 | |
|         DEBUG ((EFI_D_INFO, "Memory Type Information settings change.\n"));
 | |
|         if (Boot && PcdGetBool (PcdResetOnMemoryTypeInformationChange)) {
 | |
|           DEBUG ((EFI_D_INFO, "...Warm Reset!!!\n"));
 | |
|           gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
 | |
|         }
 | |
|       }
 | |
|     } else {
 | |
|       DEBUG ((EFI_D_ERROR, "Memory Type Information settings cannot be saved. OS S4 may fail!\n"));
 | |
|     }
 | |
|   }
 | |
|   FreePool (PreviousMemoryTypeInformation);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Set the variable and report the error through status code upon failure.
 | |
| 
 | |
|   @param  VariableName           A Null-terminated string that is the name of the vendor's variable.
 | |
|                                  Each VariableName is unique for each VendorGuid. VariableName must
 | |
|                                  contain 1 or more characters. If VariableName is an empty string,
 | |
|                                  then EFI_INVALID_PARAMETER is returned.
 | |
|   @param  VendorGuid             A unique identifier for the vendor.
 | |
|   @param  Attributes             Attributes bitmask to set for the variable.
 | |
|   @param  DataSize               The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, 
 | |
|                                  EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or 
 | |
|                                  EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero 
 | |
|                                  causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is 
 | |
|                                  set, then a SetVariable() call with a DataSize of zero will not cause any change to 
 | |
|                                  the variable value (the timestamp associated with the variable may be updated however 
 | |
|                                  even if no new data value is provided,see the description of the 
 | |
|                                  EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not 
 | |
|                                  be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). 
 | |
|   @param  Data                   The contents for the variable.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The firmware has successfully stored the variable and its data as
 | |
|                                  defined by the Attributes.
 | |
|   @retval EFI_INVALID_PARAMETER  An invalid combination of attribute bits, name, and GUID was supplied, or the
 | |
|                                  DataSize exceeds the maximum allowed.
 | |
|   @retval EFI_INVALID_PARAMETER  VariableName is an empty string.
 | |
|   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.
 | |
|   @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
 | |
|   @retval EFI_WRITE_PROTECTED    The variable in question is read-only.
 | |
|   @retval EFI_WRITE_PROTECTED    The variable in question cannot be deleted.
 | |
|   @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 
 | |
|                                  or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo 
 | |
|                                  does NOT pass the validation check carried out by the firmware.
 | |
| 
 | |
|   @retval EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.
 | |
| **/
 | |
| EFI_STATUS
 | |
| BmSetVariableAndReportStatusCodeOnError (
 | |
|   IN CHAR16     *VariableName,
 | |
|   IN EFI_GUID   *VendorGuid,
 | |
|   IN UINT32     Attributes,
 | |
|   IN UINTN      DataSize,
 | |
|   IN VOID       *Data
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                 Status;
 | |
|   EDKII_SET_VARIABLE_STATUS  *SetVariableStatus;
 | |
|   UINTN                      NameSize;
 | |
| 
 | |
|   Status = gRT->SetVariable (
 | |
|                   VariableName,
 | |
|                   VendorGuid,
 | |
|                   Attributes,
 | |
|                   DataSize,
 | |
|                   Data
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     NameSize = StrSize (VariableName);
 | |
|     SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);
 | |
|     if (SetVariableStatus != NULL) {
 | |
|       CopyGuid (&SetVariableStatus->Guid, VendorGuid);
 | |
|       SetVariableStatus->NameSize   = NameSize;
 | |
|       SetVariableStatus->DataSize   = DataSize;
 | |
|       SetVariableStatus->SetStatus  = Status;
 | |
|       SetVariableStatus->Attributes = Attributes;
 | |
|       CopyMem (SetVariableStatus + 1,                          VariableName, NameSize);
 | |
|       CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data,         DataSize);
 | |
| 
 | |
|       REPORT_STATUS_CODE_EX (
 | |
|         EFI_ERROR_CODE,
 | |
|         PcdGet32 (PcdErrorCodeSetVariable),
 | |
|         0,
 | |
|         NULL,
 | |
|         &gEdkiiStatusCodeDataTypeVariableGuid,
 | |
|         SetVariableStatus,
 | |
|         sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize
 | |
|         );
 | |
| 
 | |
|       FreePool (SetVariableStatus);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Print the device path info.
 | |
| 
 | |
|   @param DevicePath           The device path need to print.
 | |
| **/
 | |
| VOID
 | |
| BmPrintDp (
 | |
|   EFI_DEVICE_PATH_PROTOCOL            *DevicePath
 | |
|   )
 | |
| {
 | |
|   CHAR16                              *Str;
 | |
| 
 | |
|   Str = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
 | |
|   DEBUG ((EFI_D_INFO, "%s", Str));
 | |
|   if (Str != NULL) {
 | |
|     FreePool (Str);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Convert a single character to number.
 | |
|   It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'
 | |
| 
 | |
|   @param    Char   The input char which need to convert to int.
 | |
| 
 | |
|   @return  The converted 8-bit number or (UINTN) -1 if conversion failed.
 | |
| **/
 | |
| UINTN
 | |
| BmCharToUint (
 | |
|   IN CHAR16                           Char
 | |
|   )
 | |
| {
 | |
|   if ((Char >= L'0') && (Char <= L'9')) {
 | |
|     return (Char - L'0');
 | |
|   }
 | |
| 
 | |
|   if ((Char >= L'A') && (Char <= L'F')) {
 | |
|     return (Char - L'A' + 0xA);
 | |
|   }
 | |
| 
 | |
|   ASSERT (FALSE);
 | |
|   return (UINTN) -1;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Dispatch the deferred images that are returned from all DeferredImageLoad instances.
 | |
| 
 | |
|   @retval EFI_SUCCESS       At least one deferred image is loaded successfully and started.
 | |
|   @retval EFI_NOT_FOUND     There is no deferred image.
 | |
|   @retval EFI_ACCESS_DENIED There are deferred images but all of them are failed to load.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EfiBootManagerDispatchDeferredImages (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                         Status;
 | |
|   EFI_DEFERRED_IMAGE_LOAD_PROTOCOL   *DeferredImage;
 | |
|   UINTN                              HandleCount;
 | |
|   EFI_HANDLE                         *Handles;
 | |
|   UINTN                              Index;
 | |
|   UINTN                              ImageIndex;
 | |
|   EFI_DEVICE_PATH_PROTOCOL           *ImageDevicePath;
 | |
|   VOID                               *Image;
 | |
|   UINTN                              ImageSize;
 | |
|   BOOLEAN                            BootOption;
 | |
|   EFI_HANDLE                         ImageHandle;
 | |
|   UINTN                              ExitDataSize;
 | |
|   CHAR16                             *ExitData;
 | |
|   UINTN                              ImageCount;
 | |
|   UINTN                              LoadCount;
 | |
| 
 | |
|   //
 | |
|   // Find all the deferred image load protocols.
 | |
|   //
 | |
|   HandleCount = 0;
 | |
|   Handles = NULL;
 | |
|   Status = gBS->LocateHandleBuffer (
 | |
|     ByProtocol,
 | |
|     &gEfiDeferredImageLoadProtocolGuid,
 | |
|     NULL,
 | |
|     &HandleCount,
 | |
|     &Handles
 | |
|   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   ImageCount = 0;
 | |
|   LoadCount  = 0;
 | |
|   for (Index = 0; Index < HandleCount; Index++) {
 | |
|     Status = gBS->HandleProtocol (Handles[Index], &gEfiDeferredImageLoadProtocolGuid, (VOID **) &DeferredImage);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     for (ImageIndex = 0; ;ImageIndex++) {
 | |
|       //
 | |
|       // Load all the deferred images in this protocol instance.
 | |
|       //
 | |
|       Status = DeferredImage->GetImageInfo (
 | |
|                                 DeferredImage,
 | |
|                                 ImageIndex,
 | |
|                                 &ImageDevicePath,
 | |
|                                 (VOID **) &Image,
 | |
|                                 &ImageSize,
 | |
|                                 &BootOption
 | |
|                                 );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         break;
 | |
|       }
 | |
|       ImageCount++;
 | |
|       //
 | |
|       // Load and start the image.
 | |
|       //
 | |
|       Status = gBS->LoadImage (
 | |
|         BootOption,
 | |
|         gImageHandle,
 | |
|         ImageDevicePath,
 | |
|         NULL,
 | |
|         0,
 | |
|         &ImageHandle
 | |
|       );
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         LoadCount++;
 | |
|         //
 | |
|         // Before calling the image, enable the Watchdog Timer for
 | |
|         // a 5 Minute period
 | |
|         //
 | |
|         gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
 | |
|         Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);
 | |
|         if (ExitData != NULL) {
 | |
|           FreePool (ExitData);
 | |
|         }
 | |
| 
 | |
|         //
 | |
|         // Clear the Watchdog Timer after the image returns.
 | |
|         //
 | |
|         gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   if (Handles != NULL) {
 | |
|     FreePool (Handles);
 | |
|   }
 | |
| 
 | |
|   if (ImageCount == 0) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   } else {
 | |
|     if (LoadCount == 0) {
 | |
|       return EFI_ACCESS_DENIED;
 | |
|     } else {
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| }
 |