]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c
EmbeddedPkg: Add LoadFile2 for linux initrd
[mirror_edk2.git] / EmbeddedPkg / Library / AndroidBootImgLib / AndroidBootImgLib.c
index d9e7aa7d2b36b4f13544013ca401e8898cef6ee1..cc39fef4895c36583192bc46c64f9e137b5ced00 100644 (file)
 #include <libfdt.h>\r
 #include <Library/AndroidBootImgLib.h>\r
 #include <Library/PrintLib.h>\r
+#include <Library/DevicePathLib.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r
 #include <Library/UefiLib.h>\r
 \r
 #include <Protocol/AndroidBootImg.h>\r
+#include <Protocol/LoadFile2.h>\r
 #include <Protocol/LoadedImage.h>\r
 \r
-#include <libfdt.h>\r
+#include <Guid/LinuxEfiInitrdMedia.h>\r
 \r
 #define FDT_ADDITIONAL_ENTRIES_SIZE 0x400\r
 \r
@@ -25,7 +27,15 @@ typedef struct {
   EFI_DEVICE_PATH_PROTOCOL                End;\r
 } MEMORY_DEVICE_PATH;\r
 \r
+typedef struct {\r
+  VENDOR_DEVICE_PATH                      VendorMediaNode;\r
+  EFI_DEVICE_PATH_PROTOCOL                EndNode;\r
+} RAMDISK_DEVICE_PATH;\r
+\r
 STATIC ANDROID_BOOTIMG_PROTOCOL                 *mAndroidBootImg;\r
+STATIC VOID                                     *mRamdiskData = NULL;\r
+STATIC UINTN                                    mRamdiskSize = 0;\r
+STATIC EFI_HANDLE                               mRamDiskLoadFileHandle = NULL;\r
 \r
 STATIC CONST MEMORY_DEVICE_PATH mMemoryDevicePathTemplate =\r
 {\r
@@ -48,6 +58,99 @@ STATIC CONST MEMORY_DEVICE_PATH mMemoryDevicePathTemplate =
   } // End\r
 };\r
 \r
+STATIC CONST RAMDISK_DEVICE_PATH mRamdiskDevicePath =\r
+{\r
+  {\r
+    {\r
+      MEDIA_DEVICE_PATH,\r
+      MEDIA_VENDOR_DP,\r
+      { sizeof (VENDOR_DEVICE_PATH), 0 }\r
+    },\r
+    LINUX_EFI_INITRD_MEDIA_GUID\r
+  },\r
+  {\r
+    END_DEVICE_PATH_TYPE,\r
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+    { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }\r
+  }\r
+};\r
+\r
+/**\r
+  Causes the driver to load a specified file.\r
+\r
+  @param  This       Protocol instance pointer.\r
+  @param  FilePath   The device specific path of the file to load.\r
+  @param  BootPolicy Should always be FALSE.\r
+  @param  BufferSize On input the size of Buffer in bytes. On output with a return\r
+                     code of EFI_SUCCESS, the amount of data transferred to\r
+                     Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,\r
+                     the size of Buffer required to retrieve the requested file.\r
+  @param  Buffer     The memory buffer to transfer the file to. IF Buffer is NULL,\r
+                     then no the size of the requested file is returned in\r
+                     BufferSize.\r
+\r
+  @retval EFI_SUCCESS           The file was loaded.\r
+  @retval EFI_UNSUPPORTED       BootPolicy is TRUE.\r
+  @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or\r
+                                BufferSize is NULL.\r
+  @retval EFI_NO_MEDIA          No medium was present to load the file.\r
+  @retval EFI_DEVICE_ERROR      The file was not loaded due to a device error.\r
+  @retval EFI_NO_RESPONSE       The remote system did not respond.\r
+  @retval EFI_NOT_FOUND         The file was not found\r
+  @retval EFI_ABORTED           The file load process was manually canceled.\r
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to read the current\r
+                                directory entry. BufferSize has been updated with\r
+                                the size needed to complete the request.\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AndroidBootImgLoadFile2 (\r
+  IN EFI_LOAD_FILE2_PROTOCOL    *This,\r
+  IN EFI_DEVICE_PATH_PROTOCOL   *FilePath,\r
+  IN BOOLEAN                    BootPolicy,\r
+  IN OUT UINTN                  *BufferSize,\r
+  IN VOID                       *Buffer OPTIONAL\r
+  )\r
+\r
+{\r
+  // Verify if the valid parameters\r
+  if (This == NULL ||\r
+      BufferSize == NULL ||\r
+      FilePath == NULL ||\r
+      !IsDevicePathValid (FilePath, 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BootPolicy) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  // Check if the given buffer size is big enough\r
+  // EFI_BUFFER_TOO_SMALL to allow caller to allocate a bigger buffer\r
+  if (mRamdiskSize == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  if (Buffer == NULL || *BufferSize < mRamdiskSize) {\r
+    *BufferSize = mRamdiskSize;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  // Copy InitRd\r
+  CopyMem (Buffer, mRamdiskData, mRamdiskSize);\r
+  *BufferSize = mRamdiskSize;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+///\r
+/// Load File Protocol instance\r
+///\r
+STATIC EFI_LOAD_FILE2_PROTOCOL  mAndroidBootImgLoadFile2 = {\r
+  AndroidBootImgLoadFile2\r
+};\r
+\r
 EFI_STATUS\r
 AndroidBootImgGetImgSize (\r
   IN  VOID    *BootImg,\r
@@ -97,7 +200,7 @@ AndroidBootImgGetKernelInfo (
   ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));\r
 \r
   *KernelSize = Header->KernelSize;\r
-  *Kernel = BootImg + Header->PageSize;\r
+  *Kernel = (VOID *)((UINTN)BootImg + Header->PageSize);\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -216,6 +319,60 @@ AndroidBootImgUpdateArgs (
   return Status;\r
 }\r
 \r
+EFI_STATUS\r
+AndroidBootImgInstallLoadFile2 (\r
+  IN  VOID                  *RamdiskData,\r
+  IN  UINTN                  RamdiskSize\r
+  )\r
+{\r
+  mRamDiskLoadFileHandle = NULL;\r
+  mRamdiskData = RamdiskData;\r
+  mRamdiskSize = RamdiskSize;\r
+  return gBS->InstallMultipleProtocolInterfaces (\r
+                &mRamDiskLoadFileHandle,\r
+                &gEfiLoadFile2ProtocolGuid,\r
+                &mAndroidBootImgLoadFile2,\r
+                &gEfiDevicePathProtocolGuid,\r
+                &mRamdiskDevicePath,\r
+                NULL\r
+                );\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgUninstallLoadFile2 (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+  mRamdiskData = NULL;\r
+  mRamdiskSize = 0;\r
+  if (mRamDiskLoadFileHandle != NULL) {\r
+    Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                    mRamDiskLoadFileHandle,\r
+                    &gEfiLoadFile2ProtocolGuid,\r
+                    &mAndroidBootImgLoadFile2,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    &mRamdiskDevicePath,\r
+                    NULL\r
+                    );\r
+    mRamDiskLoadFileHandle = NULL;\r
+  }\r
+  return Status;\r
+}\r
+\r
+BOOLEAN AndroidBootImgAcpiSupported (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  VOID       *AcpiTable;\r
+\r
+  Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, &AcpiTable);\r
+  return !EFI_ERROR (Status);\r
+}\r
+\r
 EFI_STATUS\r
 AndroidBootImgLocateFdt (\r
   IN  VOID                  *BootImg,\r
@@ -327,23 +484,30 @@ AndroidBootImgUpdateFdt (
     goto Fdt_Exit;\r
   }\r
 \r
-  ChosenNode = AndroidBootImgGetChosenNode(UpdatedFdtBase);\r
-  if (!ChosenNode) {\r
-    goto Fdt_Exit;\r
-  }\r
+  if (FeaturePcdGet (PcdAndroidBootLoadFile2)) {\r
+    Status = AndroidBootImgInstallLoadFile2 (RamdiskData, RamdiskSize);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Fdt_Exit;\r
+    }\r
+  } else {\r
+    ChosenNode = AndroidBootImgGetChosenNode(UpdatedFdtBase);\r
+    if (!ChosenNode) {\r
+      goto Fdt_Exit;\r
+    }\r
 \r
-  Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,\r
-                                        "linux,initrd-start",\r
-                                        (UINTN)RamdiskData);\r
-  if (EFI_ERROR (Status)) {\r
-    goto Fdt_Exit;\r
-  }\r
+    Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,\r
+                                          "linux,initrd-start",\r
+                                          (UINTN)RamdiskData);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Fdt_Exit;\r
+    }\r
 \r
-  Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,\r
-                                        "linux,initrd-end",\r
-                                        (UINTN)(RamdiskData + RamdiskSize));\r
-  if (EFI_ERROR (Status)) {\r
-    goto Fdt_Exit;\r
+    Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,\r
+                                          "linux,initrd-end",\r
+                                          (UINTN)RamdiskData + RamdiskSize);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Fdt_Exit;\r
+    }\r
   }\r
 \r
   if (mAndroidBootImg->UpdateDtb) {\r
@@ -351,12 +515,13 @@ AndroidBootImgUpdateFdt (
     if (EFI_ERROR (Status)) {\r
       goto Fdt_Exit;\r
     }\r
-\r
-    Status = gBS->InstallConfigurationTable (\r
-                    &gFdtTableGuid,\r
-                    (VOID *)(UINTN)NewFdtBase\r
-                    );\r
+  } else {\r
+    NewFdtBase = UpdatedFdtBase;\r
   }\r
+  Status = gBS->InstallConfigurationTable (\r
+                  &gFdtTableGuid,\r
+                  (VOID *)(UINTN)NewFdtBase\r
+                  );\r
 \r
   if (!EFI_ERROR (Status)) {\r
     return EFI_SUCCESS;\r
@@ -384,10 +549,13 @@ AndroidBootImgBoot (
   UINTN                               RamdiskSize;\r
   IN  VOID                           *FdtBase;\r
 \r
+  NewKernelArg = NULL;\r
+  ImageHandle = NULL;\r
+\r
   Status = gBS->LocateProtocol (&gAndroidBootImgProtocolGuid, NULL,\r
                                 (VOID **) &mAndroidBootImg);\r
   if (EFI_ERROR (Status)) {\r
-    return Status;\r
+    goto Exit;\r
   }\r
 \r
   Status = AndroidBootImgGetKernelInfo (\r
@@ -396,19 +564,19 @@ AndroidBootImgBoot (
             &KernelSize\r
             );\r
   if (EFI_ERROR (Status)) {\r
-    return Status;\r
+    goto Exit;\r
   }\r
 \r
   NewKernelArg = AllocateZeroPool (ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);\r
   if (NewKernelArg == NULL) {\r
     DEBUG ((DEBUG_ERROR, "Fail to allocate memory\n"));\r
-    return EFI_OUT_OF_RESOURCES;\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Exit;\r
   }\r
 \r
   Status = AndroidBootImgUpdateArgs (Buffer, NewKernelArg);\r
   if (EFI_ERROR (Status)) {\r
-    FreePool (NewKernelArg);\r
-    return Status;\r
+    goto Exit;\r
   }\r
 \r
   Status = AndroidBootImgGetRamdiskInfo (\r
@@ -417,19 +585,24 @@ AndroidBootImgBoot (
             &RamdiskSize\r
             );\r
   if (EFI_ERROR (Status)) {\r
-    return Status;\r
+    goto Exit;\r
   }\r
 \r
-  Status = AndroidBootImgLocateFdt (Buffer, &FdtBase);\r
-  if (EFI_ERROR (Status)) {\r
-    FreePool (NewKernelArg);\r
-    return Status;\r
-  }\r
+  if (AndroidBootImgAcpiSupported ()) {\r
+    Status = AndroidBootImgInstallLoadFile2 (RamdiskData, RamdiskSize);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+  } else {\r
+    Status = AndroidBootImgLocateFdt (Buffer, &FdtBase);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
 \r
-  Status = AndroidBootImgUpdateFdt (Buffer, FdtBase, RamdiskData, RamdiskSize);\r
-  if (EFI_ERROR (Status)) {\r
-    FreePool (NewKernelArg);\r
-    return Status;\r
+    Status = AndroidBootImgUpdateFdt (Buffer, FdtBase, RamdiskData, RamdiskSize);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
   }\r
 \r
   KernelDevicePath = mMemoryDevicePathTemplate;\r
@@ -441,10 +614,16 @@ AndroidBootImgBoot (
   Status = gBS->LoadImage (TRUE, gImageHandle,\r
                            (EFI_DEVICE_PATH *)&KernelDevicePath,\r
                            (VOID*)(UINTN)Kernel, KernelSize, &ImageHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
 \r
   // Set kernel arguments\r
   Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid,\r
                                 (VOID **) &ImageInfo);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
   ImageInfo->LoadOptions = NewKernelArg;\r
   ImageInfo->LoadOptionsSize = StrLen (NewKernelArg) * sizeof (CHAR16);\r
 \r
@@ -454,5 +633,19 @@ AndroidBootImgBoot (
   Status = gBS->StartImage (ImageHandle, NULL, NULL);\r
   // Clear the Watchdog Timer if the image returns\r
   gBS->SetWatchdogTimer (0, 0x10000, 0, NULL);\r
-  return EFI_SUCCESS;\r
+\r
+Exit:\r
+  //Unload image as it will not be used anymore\r
+  if (ImageHandle != NULL) {\r
+    gBS->UnloadImage (ImageHandle);\r
+    ImageHandle = NULL;\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    if (NewKernelArg != NULL) {\r
+      FreePool (NewKernelArg);\r
+      NewKernelArg = NULL;\r
+    }\r
+  }\r
+  AndroidBootImgUninstallLoadFile2 ();\r
+  return Status;\r
 }\r