--- /dev/null
+/** @file\r
+ Implement defer image load services for user identification in UEFI2.2.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution. The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "DxeDeferImageLoadLib.h"\r
+\r
+//\r
+// Handle for the Deferred Image Load Protocol instance produced by this driver.\r
+//\r
+EFI_HANDLE mDeferredImageHandle = NULL;\r
+BOOLEAN mIsProtocolInstalled = FALSE;\r
+EFI_USER_MANAGER_PROTOCOL *mUserManager = NULL;\r
+DEFERRED_IMAGE_TABLE mDeferredImage = {\r
+ 0, // Deferred image count\r
+ NULL // The deferred image info\r
+};\r
+\r
+EFI_DEFERRED_IMAGE_LOAD_PROTOCOL gDeferredImageLoad = {\r
+ GetDefferedImageInfo\r
+};\r
+\r
+/**\r
+ Get the image type.\r
+\r
+ @param[in] File This is a pointer to the device path of the file\r
+ that is being dispatched. \r
+\r
+ @return UINT32 Image Type \r
+\r
+**/\r
+UINT32\r
+GetFileType (\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE DeviceHandle; \r
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+\r
+ //\r
+ // First check to see if File is from a Firmware Volume\r
+ //\r
+ DeviceHandle = NULL;\r
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+ Status = gBS->LocateDevicePath (\r
+ &gEfiFirmwareVolume2ProtocolGuid,\r
+ &TempDevicePath,\r
+ &DeviceHandle\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = gBS->OpenProtocol (\r
+ DeviceHandle,\r
+ &gEfiFirmwareVolume2ProtocolGuid,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ return IMAGE_FROM_FV;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Next check to see if File is from a Block I/O device\r
+ //\r
+ DeviceHandle = NULL;\r
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+ Status = gBS->LocateDevicePath (\r
+ &gEfiBlockIoProtocolGuid,\r
+ &TempDevicePath,\r
+ &DeviceHandle\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ BlockIo = NULL;\r
+ Status = gBS->OpenProtocol (\r
+ DeviceHandle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlockIo,\r
+ NULL,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status) && BlockIo != NULL) {\r
+ if (BlockIo->Media != NULL) {\r
+ if (BlockIo->Media->RemovableMedia) {\r
+ //\r
+ // Block I/O is present and specifies the media is removable\r
+ //\r
+ return IMAGE_FROM_REMOVABLE_MEDIA;\r
+ } else {\r
+ //\r
+ // Block I/O is present and specifies the media is not removable\r
+ //\r
+ return IMAGE_FROM_FIXED_MEDIA;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // File is not in a Firmware Volume or on a Block I/O device, so check to see if \r
+ // the device path supports the Simple File System Protocol.\r
+ //\r
+ DeviceHandle = NULL;\r
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+ Status = gBS->LocateDevicePath (\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ &TempDevicePath,\r
+ &DeviceHandle\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Simple File System is present without Block I/O, so assume media is fixed.\r
+ //\r
+ return IMAGE_FROM_FIXED_MEDIA;\r
+ }\r
+\r
+ //\r
+ // File is not from an FV, Block I/O or Simple File System, so the only options\r
+ // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC. \r
+ //\r
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+ while (!IsDevicePathEndType (TempDevicePath)) {\r
+ switch (DevicePathType (TempDevicePath)) {\r
+ \r
+ case MEDIA_DEVICE_PATH:\r
+ if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {\r
+ return IMAGE_FROM_OPTION_ROM;\r
+ }\r
+ break;\r
+\r
+ case MESSAGING_DEVICE_PATH:\r
+ if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {\r
+ return IMAGE_FROM_REMOVABLE_MEDIA;\r
+ } \r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ TempDevicePath = NextDevicePathNode (TempDevicePath);\r
+ }\r
+ return IMAGE_UNKNOWN; \r
+}\r
+\r
+\r
+/**\r
+ Get current user's access right.\r
+\r
+ @param[out] AccessControl Points to the user's access control data, the\r
+ caller should free data buffer.\r
+ @param[in] AccessType The type of user access control.\r
+\r
+ @retval EFI_SUCCESS Get current user access control successfully\r
+ @retval others Fail to get current user access control\r
+\r
+**/\r
+EFI_STATUS\r
+GetAccessControl (\r
+ OUT EFI_USER_INFO_ACCESS_CONTROL **AccessControl,\r
+ IN UINT32 AccessType\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_USER_INFO_HANDLE UserInfo;\r
+ EFI_USER_INFO *Info;\r
+ UINTN InfoSize;\r
+ EFI_USER_INFO_ACCESS_CONTROL *Access;\r
+ EFI_USER_PROFILE_HANDLE CurrentUser;\r
+ UINTN CheckLen;\r
+ EFI_USER_MANAGER_PROTOCOL *UserManager;\r
+\r
+ CurrentUser = NULL;\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiUserManagerProtocolGuid,\r
+ NULL,\r
+ (VOID **) &UserManager\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ \r
+ //\r
+ // Get current user access information.\r
+ //\r
+ UserManager->Current (UserManager, &CurrentUser);\r
+\r
+ UserInfo = NULL;\r
+ Info = NULL;\r
+ InfoSize = 0;\r
+ while (TRUE) {\r
+ //\r
+ // Get next user information.\r
+ //\r
+ Status = UserManager->GetNextInfo (UserManager, CurrentUser, &UserInfo);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = UserManager->GetInfo (\r
+ UserManager,\r
+ CurrentUser,\r
+ UserInfo,\r
+ Info,\r
+ &InfoSize\r
+ );\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ if (Info != NULL) {\r
+ FreePool (Info);\r
+ }\r
+ Info = AllocateZeroPool (InfoSize);\r
+ ASSERT (Info != NULL);\r
+ Status = UserManager->GetInfo (\r
+ UserManager,\r
+ CurrentUser,\r
+ UserInfo,\r
+ Info,\r
+ &InfoSize\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ \r
+ ASSERT (Info != NULL);\r
+ if (Info->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD) {\r
+ continue;\r
+ }\r
+ \r
+ //\r
+ // Get specified access information.\r
+ //\r
+ CheckLen = 0;\r
+ while (CheckLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {\r
+ Access = (EFI_USER_INFO_ACCESS_CONTROL *) ((UINT8 *) (Info + 1) + CheckLen);\r
+ if ((Access->Type == AccessType)) {\r
+ *AccessControl = AllocateZeroPool (Access->Size);\r
+ ASSERT (*AccessControl != NULL);\r
+ CopyMem (*AccessControl, Access, Access->Size);\r
+ FreePool (Info);\r
+ return EFI_SUCCESS;\r
+ }\r
+ CheckLen += Access->Size;\r
+ }\r
+ }\r
+ \r
+ if (Info != NULL) {\r
+ FreePool (Info);\r
+ }\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ Convert the '/' to '\' in the specified string.\r
+\r
+ @param[in, out] Str Points to the string to convert.\r
+\r
+**/\r
+VOID\r
+ConvertDPStr (\r
+ IN OUT EFI_STRING Str \r
+ )\r
+{\r
+ INTN Count;\r
+ INTN Index;\r
+ \r
+ Count = StrSize(Str) / 2 - 1;\r
+\r
+ if (Count < 4) {\r
+ return;\r
+ }\r
+ \r
+ //\r
+ // Convert device path string.\r
+ //\r
+ Index = Count - 1;\r
+ while (Index > 0) {\r
+ //\r
+ // Find the last '/'.\r
+ //\r
+ for (Index = Count - 1; Index > 0; Index--) {\r
+ if (Str[Index] == L'/')\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Check next char.\r
+ //\r
+ if (Str[Index + 1] == L'\\')\r
+ return;\r
+ \r
+ Str[Index] = L'\\';\r
+ \r
+ //\r
+ // Check previous char.\r
+ //\r
+ if ((Index > 0) && (Str[Index - 1] == L'\\')) {\r
+ CopyMem (&Str[Index - 1], &Str[Index], (UINTN) ((Count - Index + 1) * sizeof (CHAR16)));\r
+ return;\r
+ }\r
+ Index--;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Check whether the DevicePath2 is identical with DevicePath1, or identical with\r
+ DevicePath1's child device path.\r
+\r
+ If DevicePath2 is identical with DevicePath1, or with DevicePath1's child device\r
+ path, then TRUE returned. Otherwise, FALSE is returned.\r
+ \r
+ If DevicePath1 is NULL, then ASSERT().\r
+ If DevicePath2 is NULL, then ASSERT().\r
+\r
+ @param[in] DevicePath1 A pointer to a device path.\r
+ @param[in] DevicePath2 A pointer to a device path.\r
+\r
+ @retval TRUE Two device paths are identical , or DevicePath2 is \r
+ DevicePath1's child device path.\r
+ @retval FALSE Two device paths are not identical, and DevicePath2 \r
+ is not DevicePath1's child device path.\r
+\r
+**/\r
+BOOLEAN\r
+CheckDevicePath (\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1,\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STRING DevicePathStr1;\r
+ EFI_STRING DevicePathStr2;\r
+ UINTN StrLen1;\r
+ UINTN StrLen2;\r
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevicePathText;\r
+ BOOLEAN DevicePathEqual;\r
+\r
+ ASSERT (DevicePath1 != NULL);\r
+ ASSERT (DevicePath2 != NULL);\r
+ \r
+ DevicePathEqual = FALSE;\r
+ DevicePathText = NULL;\r
+ Status = gBS->LocateProtocol ( \r
+ &gEfiDevicePathToTextProtocolGuid,\r
+ NULL,\r
+ (VOID **) &DevicePathText\r
+ );\r
+ ASSERT (Status == EFI_SUCCESS);\r
+ \r
+ //\r
+ // Get first device path string.\r
+ //\r
+ DevicePathStr1 = DevicePathText->ConvertDevicePathToText (DevicePath1, TRUE, TRUE);\r
+ ConvertDPStr (DevicePathStr1);\r
+ //\r
+ // Get second device path string.\r
+ //\r
+ DevicePathStr2 = DevicePathText->ConvertDevicePathToText (DevicePath2, TRUE, TRUE);\r
+ ConvertDPStr (DevicePathStr2);\r
+ \r
+ //\r
+ // Compare device path string.\r
+ //\r
+ StrLen1 = StrSize (DevicePathStr1);\r
+ StrLen2 = StrSize (DevicePathStr2);\r
+ if (StrLen1 > StrLen2) {\r
+ DevicePathEqual = FALSE;\r
+ goto Done;\r
+ }\r
+ \r
+ if (CompareMem (DevicePathStr1, DevicePathStr2, StrLen1) == 0) {\r
+ DevicePathEqual = TRUE;\r
+ }\r
+\r
+Done:\r
+ FreePool (DevicePathStr1);\r
+ FreePool (DevicePathStr2);\r
+ return DevicePathEqual;\r
+}\r
+\r
+\r
+/**\r
+ Check whether the image pointed to by DevicePath is in the device path list \r
+ specified by AccessType. \r
+\r
+ @param[in] DevicePath Points to device path.\r
+ @param[in] AccessType The type of user access control.\r
+ \r
+ @retval TURE The DevicePath is in the specified List.\r
+ @retval FALSE The DevicePath is not in the specified List.\r
+\r
+**/\r
+BOOLEAN\r
+IsDevicePathInList (\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ IN UINT32 AccessType\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_USER_INFO_ACCESS_CONTROL *Access;\r
+ EFI_DEVICE_PATH_PROTOCOL *Path;\r
+ UINTN OffSet; \r
+\r
+ Status = GetAccessControl (&Access, AccessType);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ } \r
+\r
+ OffSet = 0;\r
+ while (OffSet < Access->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {\r
+ Path = (EFI_DEVICE_PATH_PROTOCOL*)((UINT8*)(Access + 1) + OffSet); \r
+ if (CheckDevicePath (Path, DevicePath)) {\r
+ //\r
+ // The device path is found in list.\r
+ //\r
+ FreePool (Access);\r
+ return TRUE;\r
+ } \r
+ OffSet += GetDevicePathSize (Path);\r
+ }\r
+ \r
+ FreePool (Access);\r
+ return FALSE; \r
+}\r
+\r
+\r
+/**\r
+ Check whether the image pointed to by DevicePath is permitted to load. \r
+\r
+ @param[in] DevicePath Points to device path\r
+ \r
+ @retval TURE The image pointed by DevicePath is permitted to load.\r
+ @retval FALSE The image pointed by DevicePath is forbidden to load.\r
+\r
+**/\r
+BOOLEAN\r
+VerifyDevicePath (\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_PERMIT_LOAD)) {\r
+ //\r
+ // This access control overrides any restrictions put in place by the \r
+ // EFI_USER_INFO_ACCESS_FORBID_LOAD record.\r
+ //\r
+ return TRUE;\r
+ }\r
+ \r
+ if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_FORBID_LOAD)) {\r
+ //\r
+ // The device path is found in the forbidden list.\r
+ //\r
+ return FALSE;\r
+ }\r
+ \r
+ return TRUE; \r
+}\r
+\r
+\r
+/**\r
+ Check the image pointed by DevicePath is a boot option or not. \r
+\r
+ @param[in] DevicePath Points to device path.\r
+ \r
+ @retval TURE The image pointed by DevicePath is a boot option.\r
+ @retval FALSE The image pointed by DevicePath is not a boot option.\r
+\r
+**/\r
+BOOLEAN\r
+IsBootOption (\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 *BootOrderList;\r
+ UINTN BootOrderListSize;\r
+ UINTN Index;\r
+ CHAR16 StrTemp[20];\r
+ UINT8 *OptionBuffer;\r
+ UINT8 *OptionPtr;\r
+ EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;\r
+ \r
+ //\r
+ // Get BootOrder\r
+ //\r
+ BootOrderListSize = 0;\r
+ BootOrderList = NULL; \r
+ Status = gRT->GetVariable (\r
+ L"BootOrder", \r
+ &gEfiGlobalVariableGuid, \r
+ NULL, \r
+ &BootOrderListSize, \r
+ NULL\r
+ );\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ BootOrderList = AllocateZeroPool (BootOrderListSize);\r
+ ASSERT (BootOrderList != NULL);\r
+ Status = gRT->GetVariable (\r
+ L"BootOrder", \r
+ &gEfiGlobalVariableGuid, \r
+ NULL, \r
+ &BootOrderListSize, \r
+ BootOrderList\r
+ );\r
+ }\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // No Boot option\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ OptionBuffer = NULL;\r
+ for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
+ //\r
+ // Try to find the DevicePath in BootOption\r
+ //\r
+ UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);\r
+ OptionBuffer = GetEfiGlobalVariable (StrTemp);\r
+ if (OptionBuffer == NULL) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Check whether the image is forbidden.\r
+ //\r
+ \r
+ OptionPtr = OptionBuffer;\r
+ //\r
+ // Skip attribute.\r
+ //\r
+ OptionPtr += sizeof (UINT32);\r
+\r
+ //\r
+ // Skip device path length.\r
+ //\r
+ OptionPtr += sizeof (UINT16);\r
+\r
+ //\r
+ // Skip descript string\r
+ //\r
+ OptionPtr += StrSize ((UINT16 *) OptionPtr);\r
+ \r
+ //\r
+ // Now OptionPtr points to Device Path.\r
+ //\r
+ OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) OptionPtr;\r
+\r
+ if (CheckDevicePath (DevicePath, OptionDevicePath)) {\r
+ FreePool (OptionBuffer);\r
+ OptionBuffer = NULL;\r
+ return TRUE;\r
+ }\r
+ FreePool (OptionBuffer);\r
+ OptionBuffer = NULL;\r
+ }\r
+\r
+ if (BootOrderList != NULL) {\r
+ FreePool (BootOrderList);\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+\r
+/**\r
+ Add the image info to a deferred image list.\r
+\r
+ @param[in] ImageDevicePath A pointer to the device path of a image. \r
+ @param[in] Image Points to the first byte of the image, or NULL if the \r
+ image is not available.\r
+ @param[in] ImageSize The size of the image, or 0 if the image is not available.\r
+ \r
+**/\r
+VOID\r
+PutDefferedImageInfo (\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath,\r
+ IN VOID *Image,\r
+ IN UINTN ImageSize\r
+ )\r
+{\r
+ DEFERRED_IMAGE_INFO *CurImageInfo;\r
+ UINTN PathSize;\r
+\r
+ //\r
+ // Expand memory for the new deferred image.\r
+ //\r
+ if (mDeferredImage.Count == 0) {\r
+ mDeferredImage.ImageInfo = AllocatePool (sizeof (DEFERRED_IMAGE_INFO));\r
+ ASSERT (mDeferredImage.ImageInfo != NULL);\r
+ } else {\r
+ CurImageInfo = AllocatePool ((mDeferredImage.Count + 1) * sizeof (DEFERRED_IMAGE_INFO));\r
+ ASSERT (CurImageInfo != NULL);\r
+ \r
+ CopyMem (\r
+ CurImageInfo, \r
+ mDeferredImage.ImageInfo,\r
+ mDeferredImage.Count * sizeof (DEFERRED_IMAGE_INFO)\r
+ );\r
+ FreePool (mDeferredImage.ImageInfo);\r
+ mDeferredImage.ImageInfo = CurImageInfo;\r
+ }\r
+ mDeferredImage.Count++;\r
+ \r
+ //\r
+ // Save the deferred image information.\r
+ //\r
+ CurImageInfo = &mDeferredImage.ImageInfo[mDeferredImage.Count - 1];\r
+ PathSize = GetDevicePathSize (ImageDevicePath);\r
+ CurImageInfo->ImageDevicePath = AllocateZeroPool (PathSize);\r
+ ASSERT (CurImageInfo->ImageDevicePath != NULL);\r
+ CopyMem (CurImageInfo->ImageDevicePath, ImageDevicePath, PathSize);\r
+\r
+ CurImageInfo->Image = Image;\r
+ CurImageInfo->ImageSize = ImageSize;\r
+ CurImageInfo->BootOption = IsBootOption (ImageDevicePath);\r
+}\r
+\r
+\r
+/**\r
+ Returns information about a deferred image.\r
+\r
+ This function returns information about a single deferred image. The deferred images are \r
+ numbered consecutively, starting with 0. If there is no image which corresponds to \r
+ ImageIndex, then EFI_NOT_FOUND is returned. All deferred images may be returned by \r
+ iteratively calling this function until EFI_NOT_FOUND is returned.\r
+ Image may be NULL and ImageSize set to 0 if the decision to defer execution was made \r
+ because of the location of the executable image, rather than its actual contents. \r
+\r
+ @param[in] This Points to this instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL.\r
+ @param[in] ImageIndex Zero-based index of the deferred index.\r
+ @param[out] ImageDevicePath On return, points to a pointer to the device path of the image. \r
+ The device path should not be freed by the caller. \r
+ @param[out] Image On return, points to the first byte of the image or NULL if the \r
+ image is not available. The image should not be freed by the caller\r
+ unless LoadImage() has been successfully called. \r
+ @param[out] ImageSize On return, the size of the image, or 0 if the image is not available.\r
+ @param[out] BootOption On return, points to TRUE if the image was intended as a boot option \r
+ or FALSE if it was not intended as a boot option. \r
+ \r
+ @retval EFI_SUCCESS Image information returned successfully.\r
+ @retval EFI_NOT_FOUND ImageIndex does not refer to a valid image.\r
+ @retval EFI_INVALID_PARAMETER ImageDevicePath is NULL or Image is NULL or ImageSize is NULL or \r
+ BootOption is NULL.\r
+ \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetDefferedImageInfo (\r
+ IN EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *This,\r
+ IN UINTN ImageIndex,\r
+ OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath,\r
+ OUT VOID **Image,\r
+ OUT UINTN *ImageSize,\r
+ OUT BOOLEAN *BootOption\r
+ )\r
+{\r
+ DEFERRED_IMAGE_INFO *ReqImageInfo;\r
+\r
+ //\r
+ // Check the parameter.\r
+ //\r
+\r
+ if ((This == NULL) || (ImageSize == NULL) || (Image == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ if ((ImageDevicePath == NULL) || (BootOption == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (ImageIndex >= mDeferredImage.Count) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ \r
+ //\r
+ // Get the request deferred image.\r
+ // \r
+ ReqImageInfo = &mDeferredImage.ImageInfo[ImageIndex];\r
+ \r
+ *ImageDevicePath = ReqImageInfo->ImageDevicePath;\r
+ *Image = ReqImageInfo->Image;\r
+ *ImageSize = ReqImageInfo->ImageSize;\r
+ *BootOption = ReqImageInfo->BootOption;\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Provides the service of deferring image load based on platform policy control,\r
+ and installs Deferred Image Load Protocol.\r
+\r
+ @param[in] AuthenticationStatus This is the authentication status returned from the \r
+ security measurement services for the input file.\r
+ @param[in] File This is a pointer to the device path of the file that\r
+ is being dispatched. This will optionally be used for\r
+ logging.\r
+ @param[in] FileBuffer File buffer matches the input file device path.\r
+ @param[in] FileSize Size of File buffer matches the input file device path.\r
+\r
+ @retval EFI_SUCCESS The file specified by File did authenticate, and the\r
+ platform policy dictates that the DXE Core may use File.\r
+ @retval EFI_INVALID_PARAMETER File is NULL.\r
+ @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and\r
+ the platform policy dictates that File should be placed\r
+ in the untrusted state. A file may be promoted from\r
+ the untrusted to the trusted state at a future time\r
+ with a call to the Trust() DXE Service.\r
+ @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and\r
+ the platform policy dictates that File should not be\r
+ used for any purpose.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeDeferImageLoadHandler (\r
+ IN UINT32 AuthenticationStatus,\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
+ IN VOID *FileBuffer,\r
+ IN UINTN FileSize\r
+ )\r
+\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_USER_PROFILE_HANDLE CurrentUser;\r
+ UINT32 Policy;\r
+ UINT32 FileType;\r
+\r
+ if (File == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check whether user has a logon.\r
+ // \r
+ CurrentUser = NULL;\r
+ if (mUserManager != NULL) {\r
+ mUserManager->Current (mUserManager, &CurrentUser);\r
+ if (CurrentUser != NULL) {\r
+ //\r
+ // The user is logon; verify the FilePath by current user access policy.\r
+ //\r
+ if (!VerifyDevicePath (File)) {\r
+ DEBUG ((EFI_D_ERROR, "[Security] The image is forbidden to load!\n"));\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Still no user logon.\r
+ // Check the file type and get policy setting.\r
+ //\r
+ FileType = GetFileType (File);\r
+ Policy = PcdGet32 (PcdDeferImageLoadPolicy);\r
+ if ((Policy & FileType) == FileType) {\r
+ //\r
+ // This file type is secure to load.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+ \r
+ DEBUG ((EFI_D_ERROR, "[Security] No user identified, the image is deferred to load!\n"));\r
+ PutDefferedImageInfo (File, NULL, 0);\r
+\r
+ //\r
+ // Install the Deferred Image Load Protocol onto a new handle.\r
+ //\r
+ if (!mIsProtocolInstalled) {\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mDeferredImageHandle,\r
+ &gEfiDeferredImageLoadProtocolGuid,\r
+ &gDeferredImageLoad,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ mIsProtocolInstalled = TRUE;\r
+ }\r
+\r
+ return EFI_ACCESS_DENIED;\r
+}\r
+\r
+/**\r
+ Locate user manager protocol when user manager is installed. \r
+\r
+ @param[in] Event The Event that is being processed, not used.\r
+ @param[in] Context Event Context, not used. \r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+FindUserManagerProtocol (\r
+ IN EFI_EVENT Event,\r
+ IN VOID* Context\r
+ )\r
+{\r
+ gBS->LocateProtocol (\r
+ &gEfiUserManagerProtocolGuid,\r
+ NULL,\r
+ (VOID **) &mUserManager\r
+ );\r
+ \r
+}\r
+\r
+\r
+/**\r
+ Register security handler for deferred image load.\r
+\r
+ @param[in] ImageHandle ImageHandle of the loaded driver.\r
+ @param[in] SystemTable Pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The handlers were registered successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeDeferImageLoadLibConstructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ VOID *Registration;\r
+ \r
+ //\r
+ // Register user manager notification function.\r
+ //\r
+ EfiCreateProtocolNotifyEvent (\r
+ &gEfiUserManagerProtocolGuid, \r
+ TPL_CALLBACK,\r
+ FindUserManagerProtocol,\r
+ NULL,\r
+ &Registration\r
+ );\r
+ \r
+ return RegisterSecurityHandler (\r
+ DxeDeferImageLoadHandler,\r
+ EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD \r
+ ); \r
+}\r
+\r
+\r