/** @file
Copyright (C) 2021, Mike Beaton. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#ifndef LINUX_BOOT_INTERNAL_H
#define LINUX_BOOT_INTERNAL_H
#if !defined(OC_TRACE_GRUB_VARS)
#define OC_TRACE_GRUB_VARS DEBUG_VERBOSE
#endif
#if !defined(OC_TRACE_KERNEL_OPTS)
#define OC_TRACE_KERNEL_OPTS DEBUG_VERBOSE
#endif
#include
#include
#include
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
#define IS_ALPHA(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
/*
Allow scan of ESP.
*/
#define LINUX_BOOT_SCAN_ESP BIT0
/*
Allow scan of XBOOTLDR.
*/
#define LINUX_BOOT_SCAN_XBOOTLDR BIT1
/*
Allow scan of Linux Root filesystems.
*/
#define LINUX_BOOT_SCAN_LINUX_ROOT BIT2
/*
Allow scan of Linux Data filesystems.
*/
#define LINUX_BOOT_SCAN_LINUX_DATA BIT3
/*
Some space for additional file systems.
*/
/*
Allow scan of any filesystem not explicitly mentioned
(including but not limited FAT other than ESP, and NTFS).
*/
#define LINUX_BOOT_SCAN_OTHER BIT7
/*
Allow autodetect of vmlinuz-{version} and matching init*-{version},
if scan for usable /loader/entries fails.
*/
#define LINUX_BOOT_ALLOW_AUTODETECT BIT8
/*
Define entry id by the first part (to dash) of the filename
from which it was created. Results in the first matching entry (after sorting)
always being the default entry, which results in updated Linux becoming the
new default automatically.
*/
#define LINUX_BOOT_USE_LATEST BIT9
/*
If set, add "ro" as initial option to all distros. Can be sepcified per
FS by using argument partuuidopts:{partuuid}+=ro instead.
*/
#define LINUX_BOOT_ADD_RO BIT10
/*
Prepend filesystem type and first 8 hex digits of PARTUUID to discovered
entry titles, to help in debugging where entries came from.
*/
#define LINUX_BOOT_ADD_DEBUG_INFO BIT15
#define LINUX_BOOT_ALL ( \
LINUX_BOOT_SCAN_ESP | \
LINUX_BOOT_SCAN_XBOOTLDR | \
LINUX_BOOT_SCAN_LINUX_ROOT | \
LINUX_BOOT_SCAN_LINUX_DATA | \
LINUX_BOOT_SCAN_OTHER | \
LINUX_BOOT_ALLOW_AUTODETECT | \
LINUX_BOOT_USE_LATEST | \
LINUX_BOOT_ADD_RO | \
LINUX_BOOT_ADD_DEBUG_INFO \
)
/*
GRUB var error codes.
*/
#define VAR_ERR_NONE (0)
#define VAR_ERR_INDENTED BIT0 // Naive detection of GRUB conditional logic
#define VAR_ERR_HAS_VARS BIT1 // We do not support nested vars (in name or value), even though GRUB does
/*
Global flags for this instance of OpenLinuxBoot.efi.
*/
extern UINTN gLinuxBootFlags;
/*
Boot picker context.
*/
extern OC_PICKER_CONTEXT *gPickerContext;
/*
Stored parsed load options.
Would be freed at driver unload, if that happened.
*/
extern OC_FLEX_ARRAY *gParsedLoadOptions;
/*
The array of loader entries, either really from *.conf files or generated by autodetect.
*/
extern OC_FLEX_ARRAY *gNamedLoaderEntries;
/*
The current partuuid.
*/
extern EFI_GUID gPartuuid;
/*
Human readable ascii name of current file system type.
*/
extern CHAR8 *gFileSystemType;
// TODO: Are all of the below types used outside a single file?
// TODO: Is this file sensibly ordered?
/*
Forward declaration of GRUB_VAR structure.
*/
typedef struct GRUB_VAR_ GRUB_VAR;
/*
Forward declaration of LOADER_ENTRY structure.
*/
typedef struct LOADER_ENTRY_ LOADER_ENTRY;
/*
Forward declaration of NAMED_LOADER_ENTRY structure.
*/
typedef struct NAMED_LOADER_ENTRY_ NAMED_LOADER_ENTRY;
/*
Forward declaration of VMLINUZ_FILE structure.
*/
typedef struct VMLINUZ_FILE_ VMLINUZ_FILE;
/*
GRUB vars.
*/
EFI_STATUS
InternalInitGrubVars (
VOID
);
VOID
InternalFreeGrubVars (
VOID
);
EFI_STATUS
InternalSetGrubVar (
CHAR8 *Key,
CHAR8 *Value,
UINTN Errors
);
BOOLEAN
InternalHasGrubVars (
CHAR8 *Options
);
GRUB_VAR *
InternalGetGrubVar (
IN CONST CHAR8 *Key
);
EFI_STATUS
InternalExpandGrubVarsForArray (
IN OUT OC_FLEX_ARRAY *Options
);
EFI_STATUS
InternalExpandGrubVars (
IN CONST CHAR8 *Options,
IN OUT CHAR8 **Result
);
/*
Process grubenv file.
*/
EFI_STATUS
InternalProcessGrubEnv (
IN OUT CHAR8 *Content,
IN CONST UINTN Length
);
/*
Process grub.cfg file.
*/
EFI_STATUS
InternalProcessGrubCfg (
IN OUT CHAR8 *Content
);
LOADER_ENTRY *
InternalAllocateLoaderEntry (
VOID
);
VOID
InternalFreeLoaderEntry (
LOADER_ENTRY **Entry
);
EFI_STATUS
InternalProcessLoaderEntryFile (
IN CONST CHAR16 *FileName,
IN OUT CHAR8 *Content,
OUT LOADER_ENTRY **Entry,
IN CONST BOOLEAN Grub2
);
/*
GRUB variable.
*/
struct GRUB_VAR_ {
//
// Points within loaded file memory.
//
CHAR8 *Key;
//
// Points within loaded file memory, may be empty string.
//
CHAR8 *Value;
//
// GRUB var error code flags.
//
UINTN Errors;
};
/*
Loader entries.
*/
NAMED_LOADER_ENTRY *
InternalCreateNamedLoaderEntry (
IN LOADER_ENTRY *Entry,
IN CHAR16 *FileName
);
VOID
InternalFreePickerEntry (
IN OC_PICKER_ENTRY *Entry
);
VOID
InternalFreeNamedLoaderEntry (
NAMED_LOADER_ENTRY *Entry
);
EFI_STATUS
InternalConvertNamedLoaderEntriesToBootEntries (
IN EFI_FILE_PROTOCOL *RootDirectory,
OUT OC_PICKER_ENTRY **Entries,
OUT UINTN *NumEntries
);
EFI_STATUS
ScanLoaderEntries (
IN EFI_FILE_PROTOCOL *RootDirectory,
OUT OC_PICKER_ENTRY **Entries,
OUT UINTN *NumEntries
);
/*
BLSpec / blscfg loader entry.
Some items within here probably don't need to be allocated and could stay
pointing within the source file as long as that is in memory (specifically
Version and Linux, which are probably never going to be modified), but to
keep things sane everything is (re)allocated.
*/
struct LOADER_ENTRY_ {
//
// First(blscfg)/last(sd-boot) title line encountered.
// Otherwise attempted autodetect "{Variant}" (e.g. "Ubuntu", "Fedora") from within kernel image.
// Otherwise "Linux".
//
CHAR8 *Title;
//
// First(blscfg)/last(sd-boot) version line encountered;
// Otherwise version-id from {machine-id}-{kernel-version}.conf or vmlinuz-{kernel-version} filename.
// Otherwise attempted autodetect from within kernel image.
//
CHAR8 *Version;
//
// First(blscfg)/last(sd-boot) linux line encountered.
// Required.
//
CHAR8 *Linux;
//
// Option lines encountered.
// In pure BLSpec (and in sd-boot) all are used; in blscfg only the first option line is used, so we match that.
// TODO: Test starting something (not really a Linux kernel?) with no options and no initrds.
//
OC_FLEX_ARRAY *Options;
//
// Initrd lines encountered.
// (All are used in both blscfg and sd-boot.)
//
OC_FLEX_ARRAY *Initrds;
//
// id line is not read from .conf file even if present.
// OcId is generated from .conf filename, to share machine-id between
// {machine-id}-{kernel-version}.conf files, in order to auto-boot the
// most recent kernel when a new one appears.
//
CHAR8 *OcId;
//
// Autodetect from within kernel image ("{Variant}:Linux").
// Otherwise just "Linux".
//
CHAR8 *OcFlavour;
//
// Is this an auxiliary entry for OpenCore?
//
BOOLEAN OcAuxiliary;
};
//
// Values for NAMED_LOADER_ENTRY DuplicateFlags.
// We previously implemented pure-Boot Loader Spec-style title disambiguation
// only when there is more than one entry with the same name, however
// within OC it works better to always disambiguate when
// HideAuxiliary is FALSE and never otherwise.
//
#define DUPLICATE_ID_SCANNED BIT0
/*
Loader entry associated with filename, for sorting.
*/
struct NAMED_LOADER_ENTRY_ {
CHAR16 *FileName;
LOADER_ENTRY *Entry;
UINTN DuplicateFlags;
};
struct VMLINUZ_FILE_ {
CHAR16 *FileName;
CHAR16 *Version;
UINTN StrLen;
};
/*
Autodetect.
*/
EFI_STATUS
AutodetectLinux (
IN EFI_FILE_PROTOCOL *RootDirectory,
OUT OC_PICKER_ENTRY **Entries,
OUT UINTN *NumEntries
);
#endif // LINUX_BOOT_INTERNAL_H