12#include <Library/BaseLib.h>
13#include <Library/DevicePathLib.h>
14#include <Library/MemoryAllocationLib.h>
20#include <Library/PrintLib.h>
21#include <Library/UefiBootServicesTableLib.h>
25#define GRUB_DEFAULT_FILE L"\\etc\\default\\grub"
26#define OS_RELEASE_FILE L"\\etc\\os-release"
27#define AUTODETECT_DIR L"\\boot"
29#define ROOT_FS_FILE L"\\bin\\sh"
86 EFI_FILE_HANDLE Directory,
87 EFI_FILE_INFO *FileInfo,
89 VOID *Context OPTIONAL
95 if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {
105 Dash =
OcStrChr (FileInfo->FileName, L
'-');
106 if ((Dash == NULL) || (Dash[1] == L
'\0')) {
107 return EFI_NOT_FOUND;
110 if (StrnCmp (L
"vmlinuz", FileInfo->FileName,
L_STR_LEN (L
"vmlinuz")) == 0) {
112 }
else if (StrnCmp (L
"init", FileInfo->FileName,
L_STR_LEN (L
"init")) == 0) {
118 return EFI_NOT_FOUND;
123 "LNX: Found %s...\n",
127 if (VmlinuzFile == NULL) {
128 return EFI_OUT_OF_RESOURCES;
131 VmlinuzFile->
FileName = AllocateCopyPool (StrSize (FileInfo->FileName), FileInfo->FileName);
132 if (VmlinuzFile->
FileName == NULL) {
133 return EFI_OUT_OF_RESOURCES;
136 VmlinuzFile->
Version = &VmlinuzFile->
FileName[&Dash[1] - FileInfo->FileName];
137 VmlinuzFile->
StrLen = StrLen (FileInfo->FileName);
146 CHAR16 *DirectoryPath,
147 UINTN DirectoryPathLength,
155 UseDir = !(DirectoryPathLength == 1 && DirectoryPath[0] == L
'\\');
157 Size = (UseDir ? DirectoryPathLength : 0) + FilePathLength + 2;
158 *Dest = AllocatePool (
Size);
161 return EFI_OUT_OF_RESOURCES;
164 AsciiSPrint (*Dest,
Size,
"%s\\%s", UseDir ? DirectoryPath : L
"",
FilePath);
180 *Dest = AllocatePool (
Length + 1);
182 return EFI_OUT_OF_RESOURCES;
185 NumPrinted = AsciiSPrint (*Dest,
Length + 1,
"%a%g",
"root=PARTUUID=", &
gPartuuid);
210 for (Index = 0; Index < 2; Index++) {
213 (Index == 0) ?
"PRETTY_NAME" :
"NAME",
226 "LNX: Found distro %a\n",
230 DEBUG ((DEBUG_WARN,
"LNX: Neither %a nor %a found in %s\n",
"PRETTY_NAME",
"NAME",
OS_RELEASE_FILE));
238 IN CONST EFI_FILE_PROTOCOL *RootDirectory,
239 IN CONST BOOLEAN IsStandaloneBoot
255 if (IsStandaloneBoot) {
273 if (EFI_ERROR (Status)) {
276 DEBUG ((DEBUG_WARN,
"LNX: Cannot parse %s - %r\n",
OS_RELEASE_FILE, Status));
298 IN CONST EFI_FILE_PROTOCOL *RootDirectory,
299 IN CONST BOOLEAN IsStandaloneBoot
307 if (IsStandaloneBoot) {
316 DEBUG ((DEBUG_INFO,
"LNX: %s not found (bootloader is not GRUB?)\n",
GRUB_DEFAULT_FILE));
324 if (EFI_ERROR (Status)) {
338 IN CONST EFI_FILE_PROTOCOL *VmlinuzDirectory
350 DEBUG ((DEBUG_INFO,
"LNX: %s %s not present\n", L
".contentDetails", L
".disk_label.contentDetails"));
352 DEBUG ((DEBUG_INFO,
"LNX: Found disk label '%a'\n",
mDiskLabel));
389 IN CONST UINTN InsertIndex,
391 IN CONST VOID *Value,
401 OptionsLength = StrLen (Value);
403 OptionsLength = AsciiStrLen (Value);
406 if (OptionsLength > 0) {
408 if (Option == NULL) {
409 return EFI_OUT_OF_RESOURCES;
413 *Option = AllocatePool ((OptionsLength + 1) *
sizeof (CHAR16));
414 if (*Option == NULL) {
415 return EFI_OUT_OF_RESOURCES;
418 Status = UnicodeStrnToAsciiStrS (Value, OptionsLength, *Option, OptionsLength + 1, &CopiedLength);
419 ASSERT_EFI_ERROR (Status);
420 ASSERT (CopiedLength == OptionsLength);
422 *Option = AllocateCopyPool (OptionsLength + 1, Value);
423 if (*Option == NULL) {
424 return EFI_OUT_OF_RESOURCES;
436 IN CONST VOID *Value,
440 return InsertOption (Options->Count, Options, Value, StringFormat);
452 "LNX: Creating \"root=PARTUUID=%g\"\n",
457 if (NewOption == NULL) {
458 return EFI_OUT_OF_RESOURCES;
503 return EFI_OUT_OF_RESOURCES;
506 if (Options == NULL) {
515 for (Index = 0; Index < Options->Count; Index++) {
522 DEBUG ((DEBUG_WARN,
"LNX: Missing value for %s\n", Option->
Unicode.
Name));
529 if (EFI_ERROR (Status)) {
530 DEBUG ((DEBUG_WARN,
"LNX: Cannot parse partuuid from %s - %r\n", Option->
Unicode.
Name, Status));
537 }
else if (StrCmp (Option->
Unicode.
Name, L
"autoopts") == 0) {
539 DEBUG ((DEBUG_WARN,
"LNX: Missing value for %s\n", Option->
Unicode.
Name));
544 }
else if (StrCmp (Option->
Unicode.
Name, L
"autoopts+") == 0) {
546 DEBUG ((DEBUG_WARN,
"LNX: Missing value for %s\n", Option->
Unicode.
Name));
566 IN CONST BOOLEAN IsRescue,
567 IN CONST BOOLEAN IsStandaloneBoot,
574 CHAR8 *AsciiStrValue;
576 BOOLEAN FoundOptions;
579 FoundOptions = FALSE;
587 "LNX: Using autoopts:%g%a=\"%s\"\n",
599 "LNX: Using autoopts:%g%a=\"%s\"\n",
605 if (EFI_ERROR (Status)) {
618 "LNX: Using autoopts%a=\"%s\"\n",
628 "LNX: Using autoopts%a=\"%s\"\n",
634 if (EFI_ERROR (Status)) {
644 ASSERT (!IsStandaloneBoot);
663 for (Index = 0; Index < (IsRescue ? 1u : 2u); Index++) {
665 GrubVarName =
"GRUB_CMDLINE_LINUX";
667 GrubVarName =
"GRUB_CMDLINE_LINUX_DEFAULT";
675 && (AsciiStrValue != NULL))
679 "LNX: Using %a=\"%a\"\n",
684 if (AsciiStrValue[0] !=
'\0') {
686 if (EFI_ERROR (Status)) {
711 DEBUG ((DEBUG_WARN,
"LNX: No grub default or user defined options - aborting\n"));
712 return EFI_INVALID_PARAMETER;
715 #if !defined (LINUX_ALLOW_MBR)
717 Status = EFI_UNSUPPORTED;
718 DEBUG ((DEBUG_WARN,
"LNX: Cannot autodetect root on MBR partition - %r\n", Status));
728 if (EFI_ERROR (Status)) {
741 if (AddRxOption != NULL) {
744 "LNX: Adding \"%a\"\n",
756 IN CHAR16 *DirectoryPath,
757 IN CONST BOOLEAN IsStandaloneBoot
764 UINTN DirectoryPathLength;
772 ASSERT (DirectoryPath != NULL);
775 DirectoryPathLength = StrLen (DirectoryPath);
782 || (StrStr (VmlinuzFile->
Version, L
"rescue") != NULL))
792 DEBUG ((DEBUG_INFO,
"LNX: %s=rescue\n", VmlinuzFile->
Version));
795 ShortestMatch = MAX_UINTN;
803 if (InitrdFile->
StrLen < ShortestMatch) {
805 InitrdMatch = InitrdFile;
806 ShortestMatch = InitrdFile->
StrLen;
813 return EFI_OUT_OF_RESOURCES;
826 if (EFI_ERROR (Status)) {
834 if (EFI_ERROR (Status)) {
843 if (Entry->
Title == NULL) {
844 return EFI_OUT_OF_RESOURCES;
851 if (InitrdMatch == NULL) {
856 DEBUG ((DEBUG_WARN,
"LNX: No matching initrd/initramfs file found for %a\n", Entry->
Linux));
859 if (Option == NULL) {
860 return EFI_OUT_OF_RESOURCES;
870 if (EFI_ERROR (Status)) {
879 if (EFI_ERROR (Status)) {
890 IN EFI_FILE_PROTOCOL *RootDirectory,
891 IN EFI_FILE_PROTOCOL *VmlinuzDirectory,
892 IN CHAR16 *AutodetectDir,
893 IN CONST BOOLEAN IsStandaloneBoot,
895 OUT UINTN *NumEntries
899 EFI_FILE_PROTOCOL *RootFsFile;
904 Status = EFI_SUCCESS;
906 if (!IsStandaloneBoot) {
908 if (!EFI_ERROR (Status)) {
910 if (EFI_ERROR (Status)) {
911 DEBUG ((DEBUG_WARN,
"LNX: %s found but not a %a - %r\n",
ROOT_FS_FILE,
"file", Status));
914 RootFsFile->Close (RootFsFile);
917 if (EFI_ERROR (Status)) {
918 DEBUG ((DEBUG_WARN,
"LNX: AutodetectLinux not root fs - %r\n", Status));
922 if (!EFI_ERROR (Status)) {
925 Status = EFI_OUT_OF_RESOURCES;
929 if (!EFI_ERROR (Status)) {
932 Status = EFI_OUT_OF_RESOURCES;
939 if (!EFI_ERROR (Status)) {
946 Status = EFI_NOT_FOUND;
950 if (!EFI_ERROR (Status)) {
956 Status = EFI_OUT_OF_RESOURCES;
960 if (!EFI_ERROR (Status)) {
964 if (!EFI_ERROR (Status)) {
971 if (!EFI_ERROR (Status)) {
996 IN EFI_FILE_PROTOCOL *RootDirectory,
997 IN EFI_FILE_PROTOCOL *VmlinuzDirectory,
998 IN CHAR16 *AutodetectDir,
999 IN CONST BOOLEAN IsStandaloneBoot,
1001 OUT UINTN *NumEntries
1009 (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) ? DEBUG_WARN : DEBUG_INFO,
1010 "LNX: AutodetectLinux %s - %r\n",
1020 IN EFI_FILE_PROTOCOL *RootDirectory,
1022 OUT UINTN *NumEntries
1026 EFI_FILE_PROTOCOL *VmlinuzDirectory;
1034 if (!EFI_ERROR (Status)) {
1036 VmlinuzDirectory->Close (VmlinuzDirectory);
1044 if (EFI_ERROR (Status)) {
1050 "LNX: Not trying to autodetect kernel on possible standalone /boot partition without full autoopts\n"
STATIC OC_FLEX_ARRAY * mVmlinuzFiles
STATIC EFI_STATUS CreateRootPartuuid(CHAR8 **Dest)
STATIC CHAR16 * mGlobalAutoOpts
STATIC OC_FLEX_ARRAY * mEtcOsReleaseOptions
STATIC VOID LoadAppleDiskLabel(IN CONST EFI_FILE_PROTOCOL *VmlinuzDirectory)
STATIC EFI_STATUS InsertOption(IN CONST UINTN InsertIndex, IN OC_FLEX_ARRAY *Options, IN CONST VOID *Value, IN CONST OC_STRING_FORMAT StringFormat)
STATIC CHAR16 * mCurrentPartuuidAutoOpts
STATIC CHAR16 * mGlobalAutoOptsPlus
STATIC OC_FLEX_ARRAY * mPerPartuuidAutoOpts
EFI_STATUS InsertRootOption(IN OC_FLEX_ARRAY *Options)
EFI_STATUS InternalAutodetectLinux(IN EFI_FILE_PROTOCOL *RootDirectory, OUT OC_PICKER_ENTRY **Entries, OUT UINTN *NumEntries)
STATIC CHAR8 * mDiskLabel
STATIC EFI_STATUS LoadDefaultGrub(IN CONST EFI_FILE_PROTOCOL *RootDirectory, IN CONST BOOLEAN IsStandaloneBoot)
STATIC EFI_STATUS LoadOsRelease(IN CONST EFI_FILE_PROTOCOL *RootDirectory, IN CONST BOOLEAN IsStandaloneBoot)
STATIC OC_FLEX_ARRAY * mEtcDefaultGrubOptions
STATIC CHAR8 * mPrettyName
STATIC CHAR8 * mEtcDefaultGrubFileContents
STATIC OC_FLEX_ARRAY * mInitrdFiles
STATIC CHAR8 * mEtcOsReleaseFileContents
STATIC CHAR16 * mCurrentPartuuidAutoOptsPlus
EFI_STATUS InternalPreloadAutoOpts(IN OC_FLEX_ARRAY *Options)
STATIC EFI_STATUS DoAutodetectLinux(IN EFI_FILE_PROTOCOL *RootDirectory, IN EFI_FILE_PROTOCOL *VmlinuzDirectory, IN CHAR16 *AutodetectDir, IN CONST BOOLEAN IsStandaloneBoot, OUT OC_PICKER_ENTRY **Entries, OUT UINTN *NumEntries)
STATIC EFI_STATUS AddOption(IN OC_FLEX_ARRAY *Options, IN CONST VOID *Value, IN CONST OC_STRING_FORMAT StringFormat)
STATIC VOID GetCurrentPartuuidAutoOpts(VOID)
STATIC VOID FreeEtcFiles(VOID)
#define GRUB_DEFAULT_FILE
STATIC EFI_STATUS ProcessVmlinuzFile(EFI_FILE_HANDLE Directory, EFI_FILE_INFO *FileInfo, UINTN FileInfoSize, VOID *Context OPTIONAL)
STATIC EFI_STATUS CreateAsciiRelativePath(CHAR8 **Dest, CHAR16 *DirectoryPath, UINTN DirectoryPathLength, CHAR16 *FilePath, UINTN FilePathLength)
STATIC VOID AutodetectTitle(VOID)
STATIC EFI_STATUS AutodetectLinuxAtDirectory(IN EFI_FILE_PROTOCOL *RootDirectory, IN EFI_FILE_PROTOCOL *VmlinuzDirectory, IN CHAR16 *AutodetectDir, IN CONST BOOLEAN IsStandaloneBoot, OUT OC_PICKER_ENTRY **Entries, OUT UINTN *NumEntries)
STATIC EFI_STATUS AutodetectBootOptions(IN CONST BOOLEAN IsRescue, IN CONST BOOLEAN IsStandaloneBoot, IN OC_FLEX_ARRAY *Options)
STATIC EFI_STATUS GenerateEntriesForVmlinuzFiles(IN CHAR16 *DirectoryPath, IN CONST BOOLEAN IsStandaloneBoot)
OC_FLEX_ARRAY * gLoaderEntries
#define LINUX_BOOT_ADD_RO
EFI_STATUS InternalConvertLoaderEntriesToBootEntries(IN EFI_FILE_PROTOCOL *RootDirectory, OUT OC_PICKER_ENTRY **Entries, OUT UINTN *NumEntries)
#define LINUX_BOOT_ADD_RW
VOID InternalFreeLoaderEntry(LOADER_ENTRY *Entry)
OC_PICKER_CONTEXT * gPickerContext
LOADER_ENTRY * InternalAllocateLoaderEntry(VOID)
EFI_STATUS InternalIdVersionFromFileName(IN OUT LOADER_ENTRY *Entry, IN CHAR16 *FileName)
#define LINUX_BOOT_LOG_VERBOSE
DMG_FILEPATH_DEVICE_PATH FilePath
DMG_SIZE_DEVICE_PATH Size
BOOLEAN OcParsedVarsGetAsciiStr(IN CONST OC_FLEX_ARRAY *ParsedVars, IN CONST CHAR8 *Name, OUT CHAR8 **StrValue)
#define OC_ATTR_USE_DISK_LABEL_FILE
EFI_STATUS OcParseVars(IN VOID *StrVars, OUT OC_FLEX_ARRAY **ParsedVars, IN CONST OC_STRING_FORMAT StringFormat, IN CONST BOOLEAN TokensOnly)
EFI_STATUS OcEnsureDirectoryFile(IN EFI_FILE_PROTOCOL *File, IN BOOLEAN IsDirectory)
VOID * OcReadFileFromDirectory(IN CONST EFI_FILE_PROTOCOL *RootDirectory, IN CONST CHAR16 *FilePath, OUT UINT32 *FileSize OPTIONAL, IN UINT32 MaxFileSize OPTIONAL)
EFI_STATUS OcScanDirectory(IN EFI_FILE_HANDLE Directory, IN OC_PROCESS_DIRECTORY_ENTRY ProcessEntry, IN OUT VOID *Context OPTIONAL)
EFI_STATUS OcSafeFileOpen(IN CONST EFI_FILE_PROTOCOL *Directory, OUT EFI_FILE_PROTOCOL **NewHandle, IN CONST CHAR16 *FileName, IN CONST UINT64 OpenMode, IN CONST UINT64 Attributes)
VOID OcFlexArrayFree(IN OUT OC_FLEX_ARRAY **FlexArray)
VOID * OcFlexArrayInsertItem(IN OUT OC_FLEX_ARRAY *FlexArray, IN CONST UINTN InsertIndex)
OC_FLEX_ARRAY * OcFlexArrayInit(IN CONST UINTN ItemSize, IN CONST OC_FLEX_ARRAY_FREE_ITEM FreeItem OPTIONAL)
VOID(* OC_FLEX_ARRAY_FREE_ITEM)(IN VOID *Item)
VOID OcFlexArrayFreePointerItem(IN VOID *Item)
VOID * OcFlexArrayAddItem(IN OUT OC_FLEX_ARRAY *FlexArray)
VOID * OcFlexArrayItemAt(IN CONST OC_FLEX_ARRAY *FlexArray, IN CONST UINTN Index)
VOID OcFlexArrayDiscardItem(IN OUT OC_FLEX_ARRAY *FlexArray, IN CONST BOOLEAN FreeItem)
CHAR8 * OcAsciiToLower(CHAR8 *Str)
CHAR16 *EFIAPI OcStrChr(IN CONST CHAR16 *String, IN CHAR16 Char)
#define L_STR_LEN(String)
enum _OC_STRING_FORMAT OC_STRING_FORMAT
BOOLEAN EFIAPI OcUnicodeStartsWith(IN CONST CHAR16 *String, IN CONST CHAR16 *SearchString, IN BOOLEAN CaseInsensitiveMatch)
BOOLEAN EFIAPI OcUnicodeEndsWith(IN CONST CHAR16 *String, IN CONST CHAR16 *SearchString, IN BOOLEAN CaseInsensitiveMatch)
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
OC_PARSED_VAR_UNICODE Unicode