Merge EDK tracker 892 to EDK II.
892 Internal Shell sometimes can't boot when boot option is not enumerated

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@4112 6f19259b-4bc3-4df7-8a09-765794883524
diff --git a/Nt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c b/Nt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c
index 2e241ed..cc6adcd 100644
--- a/Nt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c
+++ b/Nt32Pkg/Library/EdkGenericBdsLib/BdsBoot.c
@@ -122,6 +122,7 @@
   EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;

   EFI_BLOCK_IO_PROTOCOL     *BlkIo;

   VOID                      *Buffer;

+  LIST_ENTRY                TempBootLists;

 

   //

   // Record the performance data for End of BDS

@@ -178,6 +179,23 @@
     //

     return BdsLibDoLegacyBoot (Option);

   }

+  

+  //

+  // If the boot option point to Internal FV shell, make sure it is valid

+  //

+  Status = UpdateFvFileDevicePath (&DevicePath, &gEfiShellFileGuid);

+  if (!EFI_ERROR(Status)) {

+    if (Option->DevicePath != NULL) {

+      FreePool (Option->DevicePath);

+    }

+    Option->DevicePath  = AllocateZeroPool (GetDevicePathSize (DevicePath));

+    CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));

+    //

+    // Update the shell boot option

+    //

+    InitializeListHead (&TempBootLists);

+    BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder"); 

+  }

 

   DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Booting EFI 1.1 way %S\n", Option->Description));

 

@@ -1090,3 +1108,203 @@
   }

 

 }

+

+EFI_STATUS

+EFIAPI

+UpdateFvFileDevicePath (

+  IN  OUT EFI_DEVICE_PATH_PROTOCOL      **DevicePath,

+  IN  EFI_GUID                          *FileGuid

+  )

+/*++

+

+Routine Description:

+   According to a file guild, check a Fv file device path is valid. If it is invalid,

+   try to return the valid device path.

+   FV address maybe changes for memory layout adjust from time to time, use this funciton 

+   could promise the Fv file device path is right.

+

+Arguments:

+  DevicePath - on input, the Fv file device path need to check

+                    on output, the updated valid Fv file device path

+                    

+  FileGuid - the Fv file guild

+  

+Returns:

+  EFI_INVALID_PARAMETER - the input DevicePath or FileGuid is invalid parameter

+  EFI_UNSUPPORTED - the input DevicePath does not contain Fv file guild at all

+  EFI_ALREADY_STARTED - the input DevicePath has pointed to Fv file, it is valid

+  EFI_SUCCESS - has successfully updated the invalid DevicePath, and return the updated

+                          device path in DevicePath

+                

+--*/

+{

+  EFI_DEVICE_PATH_PROTOCOL      *TempDevicePath;

+  EFI_DEVICE_PATH_PROTOCOL      *LastDeviceNode;

+  EFI_STATUS                    Status;

+  EFI_GUID                      *GuidPoint;

+  UINTN                         Index;

+  UINTN                         FvHandleCount;

+  EFI_HANDLE                    *FvHandleBuffer;

+  EFI_FV_FILETYPE               Type;

+  UINTN                         Size;

+  EFI_FV_FILE_ATTRIBUTES        Attributes;

+  UINT32                        AuthenticationStatus;

+  BOOLEAN                       FindFvFile;

+  EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;

+  EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;

+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;

+  EFI_HANDLE                    FoundFvHandle;

+  EFI_DEVICE_PATH_PROTOCOL      *NewDevicePath;

+  

+  if ((DevicePath == NULL) || (*DevicePath == NULL)) {

+    return EFI_INVALID_PARAMETER;

+  }

+  if (FileGuid == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+  //

+  // Check whether the device path point to the default the input Fv file

+  //

+  TempDevicePath = *DevicePath; 

+  LastDeviceNode = TempDevicePath;

+  while (!EfiIsDevicePathEnd (TempDevicePath)) {

+     LastDeviceNode = TempDevicePath;

+     TempDevicePath = EfiNextDevicePathNode (TempDevicePath);

+  }

+

+  GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)LastDeviceNode);

+

+  if (GuidPoint == NULL) {

+    //

+    // if this option does not points to a Fv file, just return EFI_UNSUPPORTED

+    //

+    return EFI_UNSUPPORTED;

+  }

+

+  if (!CompareGuid (GuidPoint, FileGuid)) {

+    //

+    // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED

+    //

+    return EFI_UNSUPPORTED;

+  }

+  

+  //

+  // Check whether the input Fv file device path is valid

+  //

+  TempDevicePath = *DevicePath; 

+  FoundFvHandle = NULL;

+  Status = gBS->LocateDevicePath (

+                  &gEfiFirmwareVolume2ProtocolGuid,

+                  &TempDevicePath, 

+                  &FoundFvHandle

+                  );

+  if (!EFI_ERROR (Status)) {

+    Status = gBS->HandleProtocol (

+                    FoundFvHandle,

+                    &gEfiFirmwareVolume2ProtocolGuid,

+                    (VOID **) &Fv

+                    );

+    if (!EFI_ERROR (Status)) {

+      //

+      // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there

+      //

+      Status = Fv->ReadFile (

+                    Fv,

+                    FileGuid,

+                    NULL,

+                    &Size,

+                    &Type,

+                    &Attributes,

+                    &AuthenticationStatus

+                    );

+      if (!EFI_ERROR (Status)) {

+        return EFI_ALREADY_STARTED;

+      }

+    }

+  }

+ 

+  //

+  // Look for the input wanted FV file in current FV

+  // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV

+  //

+  FindFvFile = FALSE;

+  FoundFvHandle = NULL;

+  Status = gBS->HandleProtocol (

+             mBdsImageHandle,

+             &gEfiLoadedImageProtocolGuid,

+             &LoadedImage

+             );

+  if (!EFI_ERROR (Status)) {

+    Status = gBS->HandleProtocol (

+                    LoadedImage->DeviceHandle,

+                    &gEfiFirmwareVolume2ProtocolGuid,

+                    (VOID **) &Fv

+                    );

+    if (!EFI_ERROR (Status)) {

+      Status = Fv->ReadFile (

+                    Fv,

+                    FileGuid,

+                    NULL,

+                    &Size,

+                    &Type,

+                    &Attributes,

+                    &AuthenticationStatus

+                    );

+      if (!EFI_ERROR (Status)) {

+        FindFvFile = TRUE;

+        FoundFvHandle = LoadedImage->DeviceHandle;

+      }

+    }

+  }

+  //

+  // Second, if fail to find, try to enumerate all FV

+  //

+  if (!FindFvFile) {

+    gBS->LocateHandleBuffer (

+          ByProtocol,

+          &gEfiFirmwareVolume2ProtocolGuid,

+          NULL,

+          &FvHandleCount,

+          &FvHandleBuffer

+          );

+    for (Index = 0; Index < FvHandleCount; Index++) {

+      gBS->HandleProtocol (

+            FvHandleBuffer[Index],

+            &gEfiFirmwareVolume2ProtocolGuid,

+            (VOID **) &Fv

+            );

+

+      Status = Fv->ReadFile (

+                    Fv,

+                    FileGuid,

+                    NULL,

+                    &Size,

+                    &Type,

+                    &Attributes,

+                    &AuthenticationStatus

+                    );

+      if (EFI_ERROR (Status)) {

+        //

+        // Skip if input Fv file not in the FV

+        //

+        continue;

+      }

+      FindFvFile = TRUE;

+      FoundFvHandle = FvHandleBuffer[Index];

+      break;

+    }  

+  }

+

+  if (FindFvFile) {

+    //

+    // Build the shell device path

+    //

+    NewDevicePath = DevicePathFromHandle (FoundFvHandle);

+    EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);

+    NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);

+    *DevicePath = NewDevicePath;

+    return EFI_SUCCESS;

+  }

+

+  return EFI_NOT_FOUND;

+}

diff --git a/Nt32Pkg/Library/EdkGenericBdsLib/EdkGenericBdsLibInternal.h b/Nt32Pkg/Library/EdkGenericBdsLib/EdkGenericBdsLibInternal.h
index 991d9b2..f94809d 100644
--- a/Nt32Pkg/Library/EdkGenericBdsLib/EdkGenericBdsLibInternal.h
+++ b/Nt32Pkg/Library/EdkGenericBdsLib/EdkGenericBdsLibInternal.h
@@ -86,5 +86,11 @@
   VOID

   );

 

+EFI_STATUS

+EFIAPI

+UpdateFvFileDevicePath (

+  IN  OUT EFI_DEVICE_PATH_PROTOCOL      **DevicePath,

+  IN  EFI_GUID                          *FileGuid

+  );

 

 #endif