+/**\r
+ Return the next matched load option buffer.\r
+ The routine keeps calling BmGetNextLoadOptionDevicePath() until a valid\r
+ load option is read.\r
+\r
+ @param Type The load option type.\r
+ It's used to check whether the load option is valid.\r
+ When it's LoadOptionTypeMax, the routine only guarantees\r
+ the load option is a valid PE image but doesn't guarantee\r
+ the PE's subsystem type is valid.\r
+ @param FilePath The device path pointing to a load option.\r
+ It could be a short-form device path.\r
+ @param FullPath Return the next full device path of the load option after\r
+ short-form device path expanding.\r
+ Caller is responsible to free it.\r
+ NULL to return the first matched full device path.\r
+ @param FileSize Return the load option size.\r
+\r
+ @return The load option buffer. Caller is responsible to free the memory.\r
+**/\r
+VOID *\r
+BmGetNextLoadOptionBuffer (\r
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
+ OUT UINTN *FileSize\r
+ )\r
+{\r
+ VOID *FileBuffer;\r
+ EFI_DEVICE_PATH_PROTOCOL *PreFullPath;\r
+ EFI_DEVICE_PATH_PROTOCOL *CurFullPath;\r
+ UINTN LocalFileSize;\r
+ UINT32 AuthenticationStatus;\r
+ EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;\r
+\r
+ LocalFileSize = 0;\r
+ FileBuffer = NULL;\r
+ CurFullPath = *FullPath;\r
+ do {\r
+ PreFullPath = CurFullPath;\r
+ CurFullPath = BmGetNextLoadOptionDevicePath (FilePath, CurFullPath);\r
+ //\r
+ // Only free the full path created *inside* this routine\r
+ //\r
+ if ((PreFullPath != NULL) && (PreFullPath != *FullPath)) {\r
+ FreePool (PreFullPath);\r
+ }\r
+ if (CurFullPath == NULL) {\r
+ break;\r
+ }\r
+ FileBuffer = GetFileBufferByFilePath (TRUE, CurFullPath, &LocalFileSize, &AuthenticationStatus);\r
+ if ((FileBuffer != NULL) && !BmIsLoadOptionPeHeaderValid (Type, FileBuffer, LocalFileSize)) {\r
+ //\r
+ // Free the RAM disk file system if the load option is invalid.\r
+ //\r
+ RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);\r
+ if (RamDiskDevicePath != NULL) {\r
+ BmDestroyRamDisk (RamDiskDevicePath);\r
+ FreePool (RamDiskDevicePath);\r
+ }\r
+\r
+ //\r
+ // Free the invalid load option buffer.\r
+ //\r
+ FreePool (FileBuffer);\r
+ FileBuffer = NULL;\r
+ }\r
+ } while (FileBuffer == NULL);\r
+\r
+ if (FileBuffer == NULL) {\r
+ CurFullPath = NULL;\r
+ LocalFileSize = 0;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "[Bds] Expand "));\r
+ BmPrintDp (FilePath);\r
+ DEBUG ((DEBUG_INFO, " -> "));\r
+ BmPrintDp (CurFullPath);\r
+ DEBUG ((DEBUG_INFO, "\n"));\r
+\r
+ *FullPath = CurFullPath;\r
+ *FileSize = LocalFileSize;\r
+ return FileBuffer;\r
+}\r
+\r