提交 97c1f841 编写于 作者: M MikeBeaton

OpenLinuxBoot: Boot from standalone /boot partition

上级 bab4ef84
......@@ -11,6 +11,9 @@ OpenCore Changelog
- Added global MSR 35h fix to `ProvideCurrentCpuInfo`, allowing `-cpu host` in KVM
- Fixed potential memory corruption with AVX acceleration enabled
- Added `LogModules` for positive and negative log filtering by modules
- Renamed OpenLinuxBoot driver argument from `partuuidopts:{PARTUUID}` to `autoopts:{PARTUUID}`
- Supported booting Linux from stand-alone `/boot` partition without `/loader/entries` files (user must specify full kernel boot options)
- Handled XML entities in driver arguments
#### v0.7.8
- Updated ocvalidate to warn about insecure `DmgLoading` with secure `SecureBootModel` (already disallowed in runtime)
......
cc719727cce977f2aed6cdaa5b88c23f
a0a659b25c35186210abda2a59316cf0
......@@ -6405,7 +6405,7 @@ log when booting (or attempting to boot) a given distro against the options seen
\texttt{cat /proc/cmdline} when the same distro has been booted via its native bootloader.
In general (for safety and security of the running distro) these options should match, and if they do not
it is recommended to use the driver arguments below (in particular \texttt{LINUX\_BOOT\_ADD\_RO},
\texttt{LINUX\_BOOT\_ADD\_RW}, \texttt{partuuidopts} and \texttt{autoopts}) to modify the options as required.
\texttt{LINUX\_BOOT\_ADD\_RW}, \texttt{autoopts:\{PARTUUID\}} and \texttt{autoopts}) to modify the options as required.
Note however that the following differences are normal and do not need to be fixed:
\begin{itemize}
\tightlist
......@@ -6433,9 +6433,15 @@ The default parameter values should work well with no changes under most circums
options for the driver may be specified in \texttt{UEFI/Drivers/Arguments}:
\begin{itemize}
\tightlist
\item \texttt{flags} - Default: all flags are set except the following:
\begin{itemize}
\tightlist
\item \texttt{flags} - Default: all flags except \texttt{LINUX\_BOOT\_ADD\_DEBUG\_INFO} and
\texttt{LINUX\_BOOT\_LOG\_VERBOSE} are set. \medskip
\item \texttt{LINUX\_BOOT\_ADD\_RW},
\item \texttt{LINUX\_BOOT\_LOG\_VERBOSE} and
\item \texttt{LINUX\_BOOT\_ADD\_DEBUG\_INFO}.
\end{itemize}
\medskip
Available flags are: \medskip
......@@ -6489,14 +6495,14 @@ options for the driver may be specified in \texttt{UEFI/Drivers/Arguments}:
option on autodetected distros; should be harmless but very slightly slow down boot time (due to requried
remount as read-write) on distros which do not require it.
When there are multiple distros and it is required to specify this option for specific distros only, use
\texttt{partuuidopts:\{partuuid\}+=ro} to manually add the option where required, instead of using this flag.
\texttt{autoopts:\{PARTUUID\}+=ro} to manually add the option where required, instead of using this flag.
\item \texttt{0x00000800} (bit \texttt{11}) --- \texttt{LINUX\_BOOT\_ADD\_RW},
Like \texttt{LINUX\_BOOT\_ADD\_RO}, this option applies to autodetected Linux only. It is not
required for most distros (which usually require either \texttt{ro} or nothing to be added to
detected boot options), but is required on some Arch-derived distros, e.g. EndeavourOS.
When there are multiple distros and it is required to specify this option for specific distros only, use
\texttt{partuuidopts:\{partuuid\}+=rw} to manually add the option where required, instead of using this flag.
\texttt{autoopts:\{PARTUUID\}+=rw} to manually add the option where required, instead of using this flag.
If this option and \texttt{LINUX\_BOOT\_ADD\_RO} are both specified, only this option is applied
and \texttt{LINUX\_BOOT\_ADD\_RO} is ignored.
......@@ -6520,12 +6526,12 @@ options for the driver may be specified in \texttt{UEFI/Drivers/Arguments}:
add or remove, using syntax such as \texttt{flags+=0xC000} to add all debugging
options or \texttt{flags-=0x400} to remove the \texttt{LINUX\_BOOT\_ADD\_RO} option. \medskip
\item \texttt{partuuidopts:\{partuuid\}[+]="\{options\}"} - Default: not set. \medskip
\item \texttt{autoopts:\{PARTUUID\}[+]="\{options\}"} - Default: not set. \medskip
Allows specifying kernel options for a given partition only. If specified with \texttt{+=} then
these are used in addition to autodetected options, if specified with \texttt{=} they are used instead.
Used for autodetected Linux only. Values specified here are never used for entries created from
\texttt{/loader/entries/*.conf} files.
Allows manually specifying kernel options to use in autodetect mode for a given partition only. If specified
with \texttt{+=} then these are used in addition to any autodetected options, if specified with \texttt{=}
they are used instead. Used for autodetected Linux only. Values specified here are never used for entries created
from \texttt{/loader/entries/*.conf} files.
\medskip
\emph{Note}: The \texttt{partuuid} value to be specified here is typically the same as the \texttt{PARTUUID}
......@@ -6533,15 +6539,15 @@ options for the driver may be specified in \texttt{UEFI/Drivers/Arguments}:
\texttt{cat /proc/cmdline}) for autodetected Debian-style distros, but is not the same for
Fedora-style distros booted from \texttt{/loader/entries/*.conf} files. \medskip
Typically this option should not be needed in the latter case, but in case it is, to find out the unique
partition uuid to use look for \texttt{LNX:} entries in the OpenCore debug log file. Alternatively, and
Typically this option should not be needed for \texttt{/loader/entries} distros, but in case it is to find out the
unique partition uuid to use look for \texttt{LNX:} entries in the OpenCore debug log file. Alternatively, and
for more advanced scenarios, it is possible to examine how the distro's partitions are mounted using the
Linux \texttt{mount} command, and then find out the partuuid of relevant mounted partitions by examining the
output of \texttt{ls -l /dev/disk/by-partuuid}. \medskip
\item \texttt{autoopts[+]="\{options\}"} - Default: None specified. The kernel options to use
for autodetected Linux only. The value here is never used for entries created from
\texttt{/loader/entries/*.conf} files. \texttt{partuuidopts} may be more suitable where there are multiple
\texttt{/loader/entries/*.conf} files. \texttt{autoopts:\{PARTUUID\}} may be more suitable where there are multiple
distros, but \texttt{autoopts} with no PARTUUID required is more convenient for just one distro.
If specified with \texttt{+=} then these are used in addition to autodetected options, if specified
with \texttt{=} they are used instead. As example usage, it is possible to use \texttt{+=} format to add
......@@ -6565,8 +6571,12 @@ boot \texttt{\{boot\}/vmlinuz*} kernel files directly. It links these automatica
kernel version in the filename -- to their associated \texttt{\{boot\}/init*} ramdisk files.
This applies to most Debian-related distros, including Debian itself, Ubuntu and variants.
When autodetecting, OpenLinuxBoot looks in \texttt{/etc/default/grub} for kernel boot options and
\texttt{/etc/os-release} for the distro name.
When autodetecting in \texttt{/boot} as part of the root filesystem, OpenLinuxBoot looks in \texttt{/etc/default/grub}
for kernel boot options and \texttt{/etc/os-release} for the distro name. When autodetecting in a standalone boot
partition (i.e. when \texttt{/boot} has its own mount point), OpenLinuxBoot cannot autodetect kernel arguments and
all kernel arguments except \texttt{initrd=...} must be fully specified by hand using \texttt{autoopts=...} or
\texttt{autoopts:\{partuuid\}=...} (\texttt{+=} variants of these options will not work, as these only add additional
arguments).
BootLoaderSpecByDefault (but not pure Boot Loader Specification) can expand GRUB variables
in the \texttt{*.conf} files -- and this is used in practice in certain distros such as CentOS.
......
\documentclass[]{article}
%DIF LATEXDIFF DIFFERENCE FILE
%DIF DEL PreviousConfiguration.tex Fri Feb 11 00:24:26 2022
%DIF ADD ../Configuration.tex Fri Feb 25 23:37:24 2022
%DIF DEL PreviousConfiguration.tex Thu Feb 10 01:48:29 2022
%DIF ADD ../Configuration.tex Sun Feb 27 08:57:52 2022
\usepackage{lmodern}
\usepackage{amssymb,amsmath}
......@@ -118,7 +118,7 @@
%DIF HYPERREF PREAMBLE %DIF PREAMBLE
\providecommand{\DIFadd}[1]{\texorpdfstring{\DIFaddtex{#1}}{#1}} %DIF PREAMBLE
\providecommand{\DIFdel}[1]{\texorpdfstring{\DIFdeltex{#1}}{}} %DIF PREAMBLE
%DIF COLORLISTINGS PREAMBLE %DIF PREAMBLE
%DIF LISTINGS PREAMBLE %DIF PREAMBLE
\RequirePackage{listings} %DIF PREAMBLE
\RequirePackage{color} %DIF PREAMBLE
\lstdefinelanguage{DIFcode}{ %DIF PREAMBLE
......@@ -6475,7 +6475,7 @@ log when booting (or attempting to boot) a given distro against the options seen
\texttt{cat /proc/cmdline} when the same distro has been booted via its native bootloader.
In general (for safety and security of the running distro) these options should match, and if they do not
it is recommended to use the driver arguments below (in particular \texttt{LINUX\_BOOT\_ADD\_RO},
\texttt{LINUX\_BOOT\_ADD\_RW}, \texttt{partuuidopts} and \texttt{autoopts}) to modify the options as required.
\texttt{LINUX\_BOOT\_ADD\_RW}, \texttt{\DIFdelbegin \DIFdel{partuuidopts}\DIFdelend \DIFaddbegin \DIFadd{autoopts:\{PARTUUID\}}\DIFaddend } and \texttt{autoopts}) to modify the options as required.
Note however that the following differences are normal and do not need to be fixed:
\begin{itemize}
\tightlist
......@@ -6503,9 +6503,17 @@ The default parameter values should work well with no changes under most circums
options for the driver may be specified in \texttt{UEFI/Drivers/Arguments}:
\begin{itemize}
\tightlist
\item \texttt{flags} - Default: all flags \DIFdelbegin \DIFdel{except }\texttt{\DIFdel{LINUX\_BOOT\_ADD\_DEBUG\_INFO}} %DIFAUXCMD
\DIFdelend \DIFaddbegin \DIFadd{are set except the following:
}\begin{itemize}
\tightlist
\item \texttt{flags} - Default: all flags except \texttt{LINUX\_BOOT\_ADD\_DEBUG\_INFO} and
\texttt{LINUX\_BOOT\_LOG\_VERBOSE} are set. \medskip
\item \texttt{\DIFadd{LINUX\_BOOT\_ADD\_RW}}\DIFadd{,
}\item \texttt{\DIFadd{LINUX\_BOOT\_LOG\_VERBOSE}} \DIFaddend and
\DIFdelbegin \texttt{\DIFdel{LINUX\_BOOT\_LOG\_VERBOSE}} %DIFAUXCMD
\DIFdel{are set . }\DIFdelend \DIFaddbegin \item \texttt{\DIFadd{LINUX\_BOOT\_ADD\_DEBUG\_INFO}}\DIFadd{.
}\end{itemize}
\DIFaddend \medskip
Available flags are: \medskip
......@@ -6559,14 +6567,14 @@ options for the driver may be specified in \texttt{UEFI/Drivers/Arguments}:
option on autodetected distros; should be harmless but very slightly slow down boot time (due to requried
remount as read-write) on distros which do not require it.
When there are multiple distros and it is required to specify this option for specific distros only, use
\texttt{partuuidopts:\{partuuid\}+=ro} to manually add the option where required, instead of using this flag.
\texttt{\DIFdelbegin \DIFdel{partuuidopts}\DIFdelend \DIFaddbegin \DIFadd{autoopts}\DIFaddend :\{\DIFdelbegin \DIFdel{partuuid}\DIFdelend \DIFaddbegin \DIFadd{PARTUUID}\DIFaddend \}+=ro} to manually add the option where required, instead of using this flag.
\item \texttt{0x00000800} (bit \texttt{11}) --- \texttt{LINUX\_BOOT\_ADD\_RW},
Like \texttt{LINUX\_BOOT\_ADD\_RO}, this option applies to autodetected Linux only. It is not
required for most distros (which usually require either \texttt{ro} or nothing to be added to
detected boot options), but is required on some Arch-derived distros, e.g. EndeavourOS.
When there are multiple distros and it is required to specify this option for specific distros only, use
\texttt{partuuidopts:\{partuuid\}+=rw} to manually add the option where required, instead of using this flag.
\texttt{\DIFdelbegin \DIFdel{partuuidopts}\DIFdelend \DIFaddbegin \DIFadd{autoopts}\DIFaddend :\{\DIFdelbegin \DIFdel{partuuid}\DIFdelend \DIFaddbegin \DIFadd{PARTUUID}\DIFaddend \}+=rw} to manually add the option where required, instead of using this flag.
If this option and \texttt{LINUX\_BOOT\_ADD\_RO} are both specified, only this option is applied
and \texttt{LINUX\_BOOT\_ADD\_RO} is ignored.
......@@ -6590,12 +6598,12 @@ options for the driver may be specified in \texttt{UEFI/Drivers/Arguments}:
add or remove, using syntax such as \texttt{flags+=0xC000} to add all debugging
options or \texttt{flags-=0x400} to remove the \texttt{LINUX\_BOOT\_ADD\_RO} option. \medskip
\item \texttt{partuuidopts:\{partuuid\}[+]="\{options\}"} - Default: not set. \medskip
\item \texttt{\DIFdelbegin \DIFdel{partuuidopts}\DIFdelend \DIFaddbegin \DIFadd{autoopts}\DIFaddend :\{\DIFdelbegin \DIFdel{partuuid}\DIFdelend \DIFaddbegin \DIFadd{PARTUUID}\DIFaddend \}[+]="\{options\}"} - Default: not set. \medskip
Allows specifying kernel options for a given partition only. If specified with \texttt{+=} then
these are used in addition to autodetected options, if specified with \texttt{=} they are used instead.
Used for autodetected Linux only. Values specified here are never used for entries created from
\texttt{/loader/entries/*.conf} files.
Allows \DIFaddbegin \DIFadd{manually }\DIFaddend specifying kernel options \DIFaddbegin \DIFadd{to use in autodetect mode }\DIFaddend for a given partition only. If specified
with \texttt{+=} then these are used in addition to \DIFaddbegin \DIFadd{any }\DIFaddend autodetected options, if specified with \texttt{=}
they are used instead. Used for autodetected Linux only. Values specified here are never used for entries created
from \texttt{/loader/entries/*.conf} files.
\medskip
\emph{Note}: The \texttt{partuuid} value to be specified here is typically the same as the \texttt{PARTUUID}
......@@ -6603,15 +6611,15 @@ options for the driver may be specified in \texttt{UEFI/Drivers/Arguments}:
\texttt{cat /proc/cmdline}) for autodetected Debian-style distros, but is not the same for
Fedora-style distros booted from \texttt{/loader/entries/*.conf} files. \medskip
Typically this option should not be needed in the latter case, but in case it is, to find out the unique
partition uuid to use look for \texttt{LNX:} entries in the OpenCore debug log file. Alternatively, and
Typically this option should not be needed \DIFdelbegin \DIFdel{in the latter case}\DIFdelend \DIFaddbegin \DIFadd{for }\texttt{\DIFadd{/loader/entries}} \DIFadd{distros}\DIFaddend , but in case it is \DIFdelbegin \DIFdel{, }\DIFdelend to find out the
unique partition uuid to use look for \texttt{LNX:} entries in the OpenCore debug log file. Alternatively, and
for more advanced scenarios, it is possible to examine how the distro's partitions are mounted using the
Linux \texttt{mount} command, and then find out the partuuid of relevant mounted partitions by examining the
output of \texttt{ls -l /dev/disk/by-partuuid}. \medskip
\item \texttt{autoopts[+]="\{options\}"} - Default: None specified. The kernel options to use
for autodetected Linux only. The value here is never used for entries created from
\texttt{/loader/entries/*.conf} files. \texttt{partuuidopts} may be more suitable where there are multiple
\texttt{/loader/entries/*.conf} files. \texttt{\DIFdelbegin \DIFdel{partuuidopts}\DIFdelend \DIFaddbegin \DIFadd{autoopts:\{PARTUUID\}}\DIFaddend } may be more suitable where there are multiple
distros, but \texttt{autoopts} with no PARTUUID required is more convenient for just one distro.
If specified with \texttt{+=} then these are used in addition to autodetected options, if specified
with \texttt{=} they are used instead. As example usage, it is possible to use \texttt{+=} format to add
......@@ -6635,8 +6643,13 @@ boot \texttt{\{boot\}/vmlinuz*} kernel files directly. It links these automatica
kernel version in the filename -- to their associated \texttt{\{boot\}/init*} ramdisk files.
This applies to most Debian-related distros, including Debian itself, Ubuntu and variants.
When autodetecting, OpenLinuxBoot looks in \texttt{/etc/default/grub} for kernel boot options and
\texttt{/etc/os-release} for the distro name.
When autodetecting \DIFaddbegin \DIFadd{in }\texttt{\DIFadd{/boot}} \DIFadd{as part of the root filesystem}\DIFaddend , OpenLinuxBoot looks in \texttt{/etc/default/grub}
for kernel boot options and \texttt{/etc/os-release} for the distro name. \DIFaddbegin \DIFadd{When autodetecting in a standalone boot
partition (i.e. when }\texttt{\DIFadd{/boot}} \DIFadd{has its own mount point), OpenLinuxBoot cannot autodetect kernel arguments and
all kernel arguments except }\texttt{\DIFadd{initrd=...}} \DIFadd{must be fully specified by hand using }\texttt{\DIFadd{autoopts=...}} \DIFadd{or
}\texttt{\DIFadd{autoopts:\{partuuid\}=...}} \DIFadd{(}\texttt{\DIFadd{+=}} \DIFadd{variants of these options will not work, as these only add additional
arguments).
}\DIFaddend
BootLoaderSpecByDefault (but not pure Boot Loader Specification) can expand GRUB variables
in the \texttt{*.conf} files -- and this is used in practice in certain distros such as CentOS.
......
......@@ -37,7 +37,7 @@ typedef enum PARSE_VARS_STATE_ {
#define SHIFT_TOKEN(pos, token, offset) do { \
CopyMem ((UINT8 *)(token) + (offset), (token), (UINT8 *)(pos) - (UINT8 *)(token)); \
(token) = (UINT8 *)(token) + (offset); \
(pos) = (UINT8 *)(token) + (offset); \
(pos) = (UINT8 *)(pos) + (offset); \
} while (0)
VOID
......@@ -516,6 +516,7 @@ OcParseVars (
State = PARSE_VARS_SHELL_EXPANSION;
} else if (Ch == L'\\') {
SHIFT_TOKEN (Pos, Value, IsUnicode ? sizeof (CHAR16) : sizeof (CHAR8));
Ch = IsUnicode ? *((CHAR16 *) Pos) : *((CHAR8 *) Pos);
} else if (
(State == PARSE_VARS_VALUE && (OcIsSpace (Ch) || Ch == CHAR_NULL)) ||
(State == PARSE_VARS_QUOTED_VALUE && Ch == '"')) {
......
......@@ -104,6 +104,7 @@ OcLoadDrivers (
CONST CHAR8 *DriverComment;
CHAR8 *DriverFileName;
CONST CHAR8 *DriverArguments;
CONST CHAR8 *UnescapedArguments;
DriversToConnectIterator = NULL;
if (DriversToConnect != NULL) {
......@@ -208,7 +209,19 @@ OcLoadDrivers (
FreePool (Driver);
continue;
}
if (!OcAppendArgumentsToLoadedImage (LoadedImage, &DriverArguments, 1, TRUE)) {
UnescapedArguments = XmlUnescapeString (DriverArguments);
if (UnescapedArguments == NULL) {
DEBUG ((
DEBUG_ERROR,
"OC: Cannot unescape arguments for driver %a at %u\n",
DriverFileName,
Index
));
gBS->UnloadImage (ImageHandle);
FreePool (Driver);
continue;
}
if (!OcAppendArgumentsToLoadedImage (LoadedImage, &UnescapedArguments, 1, TRUE)) {
DEBUG ((
DEBUG_ERROR,
"OC: Unable to apply arguments to driver %a at %u - %r!\n",
......@@ -218,8 +231,10 @@ OcLoadDrivers (
));
gBS->UnloadImage (ImageHandle);
FreePool (Driver);
FreePool ((CHAR8 *)UnescapedArguments);
continue;
}
FreePool ((CHAR8 *)UnescapedArguments);
}
Status = gBS->StartImage (
......
......@@ -25,6 +25,7 @@
#define GRUB_DEFAULT_FILE L"\\etc\\default\\grub"
#define OS_RELEASE_FILE L"\\etc\\os-release"
#define AUTODETECT_DIR L"\\boot"
#define ROOT_DIR L"\\"
#define ROOT_FS_FILE L"\\bin\\sh"
STATIC
......@@ -59,6 +60,26 @@ STATIC
CHAR8
*mEtcDefaultGrubFileContents;
STATIC
OC_FLEX_ARRAY
*mPerPartuuidAutoOpts;
STATIC
CHAR16
*mCurrentPartuuidAutoOpts;
STATIC
CHAR16
*mCurrentPartuuidAutoOptsPlus;
STATIC
CHAR16
*mGlobalAutoOpts;
STATIC
CHAR16
*mGlobalAutoOptsPlus;
STATIC
EFI_STATUS
ProcessVmlinuzFile (
......@@ -129,15 +150,18 @@ CreateAsciiRelativePath (
)
{
UINTN Size;
BOOLEAN UseDir;
UseDir = !(DirectoryPathLength == 1 && DirectoryPath[0] == L'\\');
Size = DirectoryPathLength + FilePathLength + 2;
Size = (UseDir ? DirectoryPathLength : 0) + FilePathLength + 2;
*Dest = AllocatePool (Size);
if (*Dest == NULL) {
return EFI_OUT_OF_RESOURCES;
}
AsciiSPrint (*Dest, Size, "%s\\%s", DirectoryPath, FilePath);
AsciiSPrint (*Dest, Size, "%s\\%s", UseDir ? DirectoryPath : L"", FilePath);
return EFI_SUCCESS;
}
......@@ -210,26 +234,31 @@ AutodetectTitle (
STATIC
EFI_STATUS
LoadOsRelease (
IN CONST EFI_FILE_PROTOCOL *RootDirectory
IN CONST EFI_FILE_PROTOCOL *RootDirectory,
IN CONST BOOLEAN IsStandaloneBoot
)
{
EFI_STATUS Status;
BOOLEAN ReadRequired;
BOOLEAN TryReading;
mEtcOsReleaseOptions = NULL;
mEtcOsReleaseFileContents = NULL;
mPrettyName = NULL;
ReadRequired = (mDiskLabel == NULL);
TryReading = (mDiskLabel == NULL);
DEBUG_CODE_BEGIN ();
ReadRequired = TRUE;
TryReading = TRUE;
DEBUG_CODE_END ();
if (IsStandaloneBoot) {
TryReading = FALSE;
}
//
// Load distro name from /etc/os-release.
//
if (ReadRequired) {
if (TryReading) {
mEtcOsReleaseFileContents = OcReadFileFromDirectory (RootDirectory, OS_RELEASE_FILE, NULL, 0);
if (mEtcOsReleaseFileContents == NULL) {
DEBUG ((DEBUG_WARN, "LNX: %s not found\n", OS_RELEASE_FILE));
......@@ -265,7 +294,8 @@ LoadOsRelease (
STATIC
EFI_STATUS
LoadDefaultGrub (
IN CONST EFI_FILE_PROTOCOL *RootDirectory
IN CONST EFI_FILE_PROTOCOL *RootDirectory,
IN CONST BOOLEAN IsStandaloneBoot
)
{
EFI_STATUS Status;
......@@ -273,6 +303,10 @@ LoadDefaultGrub (
mEtcDefaultGrubOptions = NULL;
mEtcDefaultGrubFileContents = NULL;
if (IsStandaloneBoot) {
return EFI_SUCCESS;
}
//
// Load kernel options from /etc/default/grub.
//
......@@ -426,135 +460,186 @@ InsertRootOption (
return CreateRootPartuuid (NewOption);
}
//
// TODO: Options for rescue versions. Would it be better e.g. just to add "ro" and nothing else?
// However on some installs (e.g. where modules to load are specified in the kernel opts) this
// would not boot at all.
// Maybe upgrade to partuuidopts:{partuuid}r="...": user options for rescue kernels on specified partuuid?
//
STATIC
VOID
GetCurrentPartuuidAutoOpts (
VOID
)
{
UINTN Index;
AUTOOPTS *AutoOpts;
mCurrentPartuuidAutoOpts = NULL;
mCurrentPartuuidAutoOptsPlus = NULL;
for (Index = 0; Index < mPerPartuuidAutoOpts->Count; Index++) {
AutoOpts = OcFlexArrayItemAt (mPerPartuuidAutoOpts, Index);
if (CompareMem (&gPartuuid, &AutoOpts->Guid, sizeof (EFI_GUID)) == 0) {
if (AutoOpts->PlusOpts) {
mCurrentPartuuidAutoOptsPlus = AutoOpts->Opts;
} else {
mCurrentPartuuidAutoOpts = AutoOpts->Opts;
}
}
}
}
EFI_STATUS
AutodetectBootOptions (
IN CONST BOOLEAN IsRescue,
InternalPreloadAutoOpts (
IN OC_FLEX_ARRAY *Options
)
)
{
EFI_STATUS Status;
UINTN Index;
UINTN InsertIndex;
UINTN OptionCount;
OC_PARSED_VAR *Option;
EFI_GUID Guid;
CHAR8 *AsciiStrValue;
CHAR8 *GrubVarName;
BOOLEAN FoundOptions;
BOOLEAN PlusOpts;
CHAR8 *AddRxOption;
AUTOOPTS *AutoOpts;
mGlobalAutoOpts = NULL;
mGlobalAutoOptsPlus = NULL;
OptionCount = 0;
if (gParsedLoadOptions != NULL) {
OptionCount = gParsedLoadOptions->Count;
mPerPartuuidAutoOpts = OcFlexArrayInit (sizeof (AUTOOPTS), NULL);
if (mPerPartuuidAutoOpts == NULL) {
return EFI_OUT_OF_RESOURCES;
}
FoundOptions = FALSE;
if (Options == NULL) {
return EFI_SUCCESS;
}
//
// Look for user-specified options for this partuuid.
// Look for autoopts.
// Remember that although args are ASCII in the OC config file, they are
// Unicode by the time they get passed as UEFI LoadOptions.
//
for (Index = 0; Index < OptionCount; Index++) {
Option = OcFlexArrayItemAt (gParsedLoadOptions, Index);
for (Index = 0; Index < Options->Count; Index++) {
Option = OcFlexArrayItemAt (Options, Index);
//
// partuuidopts:{partuuid}[+]="...": user options for specified partuuid.
// autoopts:{partuuid}[+]="...": user options for specified partuuid.
//
if (OcUnicodeStartsWith (Option->Unicode.Name, L"partuuidopts:", TRUE)) {
if (OcUnicodeStartsWith (Option->Unicode.Name, L"autoopts:", TRUE)) {
if (Option->Unicode.Value == NULL) {
DEBUG ((DEBUG_WARN, "LNX: Missing value for %s\n", Option->Unicode.Name));
continue;
}
Status = StrToGuid (&Option->Unicode.Name[L_STR_LEN (L"partuuidopts:")], &Guid);
AutoOpts = OcFlexArrayAddItem (mPerPartuuidAutoOpts);
Status = StrToGuid (&Option->Unicode.Name[L_STR_LEN (L"autoopts:")], &AutoOpts->Guid);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "LNX: Cannot parse partuuid from %s - %r\n", Option->Unicode.Name, Status));
OcFlexArrayDiscardItem (mPerPartuuidAutoOpts, FALSE);
continue;
}
if (CompareMem (&gPartuuid, &Guid, sizeof (EFI_GUID)) != 0) {
DEBUG ((
(gLinuxBootFlags & LINUX_BOOT_LOG_VERBOSE) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
"LNX: No match partuuidopts:%g != %g\n",
&Guid,
&gPartuuid
));
} else {
PlusOpts = OcUnicodeEndsWith (Option->Unicode.Name, L"+", FALSE);
DEBUG ((
(gLinuxBootFlags & LINUX_BOOT_LOG_VERBOSE) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
"LNX: Using partuuidopts%a=\"%s\"\n",
PlusOpts ? "+" : "",
Option->Unicode.Value
));
Status = AddOption (Options, Option->Unicode.Value, TRUE);
if (EFI_ERROR (Status)) {
return Status;
}
if (!PlusOpts) {
return EFI_SUCCESS;
}
FoundOptions = TRUE;
}
}
}
//
// Use global defaults, if user has defined any.
//
for (Index = 0; Index < OptionCount; Index++) {
Option = OcFlexArrayItemAt (gParsedLoadOptions, Index);
//
// Don't use autoopts if partition specific partuuidopts already found.
//
if (!FoundOptions && StrCmp (Option->Unicode.Name, L"autoopts") == 0) {
AutoOpts->Opts = Option->Unicode.Value;
AutoOpts->PlusOpts = OcUnicodeEndsWith (Option->Unicode.Name, L"+", FALSE);
} else if (StrCmp (Option->Unicode.Name, L"autoopts") == 0) {
if (Option->Unicode.Value == NULL) {
DEBUG ((DEBUG_WARN, "LNX: Missing value for %s\n", Option->Unicode.Name));
continue;
}
DEBUG ((
(gLinuxBootFlags & LINUX_BOOT_LOG_VERBOSE) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
"LNX: Using %s=\"%s\"\n",
Option->Unicode.Name,
Option->Unicode.Value
));
Status = AddOption (Options, Option->Unicode.Value, TRUE);
return Status;
mGlobalAutoOpts = Option->Unicode.Value;
} else if (StrCmp (Option->Unicode.Name, L"autoopts+") == 0) {
if (Option->Unicode.Value == NULL) {
DEBUG ((DEBUG_WARN, "LNX: Missing value for %s\n", Option->Unicode.Name));
continue;
}
DEBUG ((
(gLinuxBootFlags & LINUX_BOOT_LOG_VERBOSE) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
"LNX: Using %s=\"%s\"\n",
Option->Unicode.Name,
Option->Unicode.Value
));
mGlobalAutoOptsPlus = Option->Unicode.Value;
}
}
Status = AddOption (Options, Option->Unicode.Value, TRUE);
if (EFI_ERROR (Status)) {
return Status;
}
return EFI_SUCCESS;
}
FoundOptions = TRUE;
//
// TODO: Options for rescue versions. Would it be better e.g. just to add "ro" and nothing else?
// However on some installs (e.g. where modules to load are specified in the kernel opts) this
// would not boot at all.
// Maybe upgrade to autoopts:{partuuid}r="...": user options for rescue kernels on specified partuuid?
//
STATIC
EFI_STATUS
AutodetectBootOptions (
IN CONST BOOLEAN IsRescue,
IN CONST BOOLEAN IsStandaloneBoot,
IN OC_FLEX_ARRAY *Options
)
{
EFI_STATUS Status;
UINTN Index;
UINTN InsertIndex;
CHAR8 *AsciiStrValue;
CHAR8 *GrubVarName;
BOOLEAN FoundOptions;
CHAR8 *AddRxOption;
FoundOptions = FALSE;
//
// Do we have user-specified options for this partuuid?
//
if (mCurrentPartuuidAutoOpts) {
DEBUG ((
(gLinuxBootFlags & LINUX_BOOT_LOG_VERBOSE) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
"LNX: Using autoopts:%g%a=\"%s\"\n",
&gPartuuid,
"",
mCurrentPartuuidAutoOpts
));
Status = AddOption (Options, mCurrentPartuuidAutoOpts, TRUE);
return Status;
}
if (mCurrentPartuuidAutoOptsPlus) {
DEBUG ((
(gLinuxBootFlags & LINUX_BOOT_LOG_VERBOSE) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
"LNX: Using autoopts:%g%a=\"%s\"\n",
&gPartuuid,
"+",
mCurrentPartuuidAutoOptsPlus
));
Status = AddOption (Options, mCurrentPartuuidAutoOptsPlus, TRUE);
if (EFI_ERROR (Status)) {
return Status;
}
FoundOptions = TRUE;
}
//
// Don't use autoopts if partition specific autoopts:{partuuid} already found.
//
if (!FoundOptions && mGlobalAutoOpts) {
DEBUG ((
(gLinuxBootFlags & LINUX_BOOT_LOG_VERBOSE) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
"LNX: Using autoopts%a=\"%s\"\n",
"",
mGlobalAutoOpts
));
Status = AddOption (Options, mGlobalAutoOpts, TRUE);
return Status;
} else if (mGlobalAutoOptsPlus) {
DEBUG ((
(gLinuxBootFlags & LINUX_BOOT_LOG_VERBOSE) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
"LNX: Using autoopts%a=\"%s\"\n",
"+",
mGlobalAutoOptsPlus
));
Status = AddOption (Options, mGlobalAutoOptsPlus, TRUE);
if (EFI_ERROR (Status)) {
return Status;
}
FoundOptions = TRUE;
}
//
// Should only have attempted to detect kernels on standalone boot partition if we had full user options.
//
ASSERT (!IsStandaloneBoot);
//
// Code only reaches here and below if has been nothing or only += options above.
......@@ -661,7 +746,8 @@ AutodetectBootOptions (
STATIC
EFI_STATUS
GenerateEntriesForVmlinuzFiles (
IN CHAR16 *DirectoryPath
IN CHAR16 *DirectoryPath,
IN CONST BOOLEAN IsStandaloneBoot
)
{
EFI_STATUS Status;
......@@ -780,7 +866,7 @@ GenerateEntriesForVmlinuzFiles (
//
// Add all options.
//
Status = AutodetectBootOptions (IsRescue, Entry->Options);
Status = AutodetectBootOptions (IsRescue, IsStandaloneBoot, Entry->Options);
if (EFI_ERROR (Status)) {
return Status;
}
......@@ -791,42 +877,35 @@ GenerateEntriesForVmlinuzFiles (
STATIC
EFI_STATUS
InternalAutodetectLinux (
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
)
{
EFI_STATUS Status;
EFI_FILE_PROTOCOL *VmlinuzDirectory;
EFI_FILE_PROTOCOL *RootFsFile;
//
// For now we are only searching in /boot.
// vmlinuz files in / should not require autodetect, as
// they should be accompanied by /loader/entries (Fedora-style),
// and vmlinuz files in /boot not accompanied by /loader/entries
// is Debian-style, so it seems sensible to wait to see what
// else there is rather than speculatively adding directories.
//
Status = OcSafeFileOpen (RootDirectory, &VmlinuzDirectory, AUTODETECT_DIR, EFI_FILE_MODE_READ, 0);
if (EFI_ERROR (Status)) {
return Status;
}
mVmlinuzFiles = NULL;
mInitrdFiles = NULL;
Status = OcSafeFileOpen (RootDirectory, &RootFsFile, ROOT_FS_FILE, EFI_FILE_MODE_READ, 0);
if (!EFI_ERROR (Status)) {
Status = OcEnsureDirectoryFile (RootFsFile, FALSE);
Status = EFI_SUCCESS;
if (!IsStandaloneBoot) {
Status = OcSafeFileOpen (RootDirectory, &RootFsFile, ROOT_FS_FILE, EFI_FILE_MODE_READ, 0);
if (!EFI_ERROR (Status)) {
Status = OcEnsureDirectoryFile (RootFsFile, FALSE);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "LNX: %s found but not a %a - %r\n", ROOT_FS_FILE, "file", Status));
}
RootFsFile->Close (RootFsFile);
}
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "LNX: %s found but not a %a - %r\n", ROOT_FS_FILE, "file", Status));
DEBUG ((DEBUG_WARN, "LNX: AutodetectLinux not root fs - %r\n", Status));
}
RootFsFile->Close (RootFsFile);
}
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "LNX: Does not appear to be root filesystem - %r\n", Status));
}
if (!EFI_ERROR (Status)) {
......@@ -866,12 +945,12 @@ InternalAutodetectLinux (
Status = EFI_OUT_OF_RESOURCES;
} else {
LoadAppleDiskLabel (VmlinuzDirectory);
Status = LoadOsRelease (RootDirectory);
Status = LoadOsRelease (RootDirectory, IsStandaloneBoot);
if (!EFI_ERROR (Status)) {
Status = LoadDefaultGrub (RootDirectory);
Status = LoadDefaultGrub (RootDirectory, IsStandaloneBoot);
}
if (!EFI_ERROR (Status)) {
Status = GenerateEntriesForVmlinuzFiles (AUTODETECT_DIR);
Status = GenerateEntriesForVmlinuzFiles (AutodetectDir, IsStandaloneBoot);
}
FreeEtcFiles ();
}
......@@ -895,25 +974,70 @@ InternalAutodetectLinux (
OcFlexArrayFree (&mInitrdFiles);
}
VmlinuzDirectory->Close (VmlinuzDirectory);
return Status;
}
STATIC
EFI_STATUS
AutodetectLinux (
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
)
{
EFI_STATUS Status;
Status = InternalAutodetectLinux (RootDirectory, Entries, NumEntries);
Status = AutodetectLinuxAtDirectory (RootDirectory, VmlinuzDirectory, AutodetectDir, IsStandaloneBoot, Entries, NumEntries);
DEBUG ((
(EFI_ERROR (Status) && Status != EFI_NOT_FOUND) ? DEBUG_WARN : DEBUG_INFO,
"LNX: AutodetectLinux - %r\n",
Status));
"LNX: AutodetectLinux %s - %r\n",
AutodetectDir,
Status
));
return Status;
}
EFI_STATUS
InternalAutodetectLinux (
IN EFI_FILE_PROTOCOL *RootDirectory,
OUT OC_PICKER_ENTRY **Entries,
OUT UINTN *NumEntries
)
{
EFI_STATUS Status;
EFI_FILE_PROTOCOL *VmlinuzDirectory;
GetCurrentPartuuidAutoOpts ();
//
// Autodetect at /boot if present.
//
Status = OcSafeFileOpen (RootDirectory, &VmlinuzDirectory, AUTODETECT_DIR, EFI_FILE_MODE_READ, 0);
if (!EFI_ERROR (Status)) {
Status = DoAutodetectLinux (RootDirectory, VmlinuzDirectory, AUTODETECT_DIR, FALSE, Entries, NumEntries);
VmlinuzDirectory->Close (VmlinuzDirectory);
}
//
// Try to autodetect kernels at / only if detecting at /boot failed and we have full user-specified
// options, since we can't autodetect any options on standalone /boot (unless we parse grub.cfg for
// boot entries, and even then not all standalone boot setups have it).
//
if (EFI_ERROR (Status)) {
if (mCurrentPartuuidAutoOpts != NULL || (mGlobalAutoOpts != NULL && mCurrentPartuuidAutoOptsPlus == NULL)) {
Status = DoAutodetectLinux (RootDirectory, RootDirectory, ROOT_DIR, TRUE, Entries, NumEntries);
} else {
DEBUG ((
(gLinuxBootFlags & LINUX_BOOT_LOG_VERBOSE) == 0 ? DEBUG_VERBOSE : DEBUG_INFO,
"LNX: Not trying to autodetect kernel on possible standalone /boot partition without full autoopts\n"
));
}
}
return Status;
}
......@@ -62,12 +62,12 @@
#define LINUX_BOOT_USE_LATEST BIT9
/*
If set, add "ro" as initial option to all distros. Can be specified per
FS by using argument partuuidopts:{partuuid}+=ro instead.
FS by using argument autoopts:{partuuid}+=ro instead.
*/
#define LINUX_BOOT_ADD_RO BIT10
/*
If set, add "rw" as initial option to all distros. Can be specified per
FS by using argument partuuidopts:{partuuid}+=rw instead.
FS by using argument autoopts:{partuuid}+=rw instead.
*/
#define LINUX_BOOT_ADD_RW BIT11
/*
......@@ -97,6 +97,7 @@
LINUX_BOOT_ALLOW_AUTODETECT | \
LINUX_BOOT_USE_LATEST | \
LINUX_BOOT_ADD_RO | \
LINUX_BOOT_ADD_RW | \
LINUX_BOOT_ALLOW_CONF_AUTO_ROOT | \
LINUX_BOOT_LOG_VERBOSE | \
LINUX_BOOT_ADD_DEBUG_INFO \
......@@ -119,12 +120,6 @@ extern UINTN gLinuxBootFlags;
*/
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.
*/
......@@ -153,11 +148,6 @@ typedef struct GRUB_VAR_ GRUB_VAR;
*/
typedef struct LOADER_ENTRY_ LOADER_ENTRY;
/*
Forward declaration of VMLINUZ_FILE structure.
*/
typedef struct VMLINUZ_FILE_ VMLINUZ_FILE;
/*
GRUB vars.
*/
......@@ -329,17 +319,34 @@ struct LOADER_ENTRY_ {
BOOLEAN DuplicateIdScanned;
};
struct VMLINUZ_FILE_ {
typedef struct VMLINUZ_FILE_ {
CHAR16 *FileName;
CHAR16 *Version;
UINTN StrLen;
};
} VMLINUZ_FILE;
/*
Autodetect options.
*/
typedef struct AUTOOPTS_ {
EFI_GUID Guid;
CHAR16 *Opts;
BOOLEAN PlusOpts;
} AUTOOPTS;
/*
Load autoopts.
*/
EFI_STATUS
InternalPreloadAutoOpts (
IN OC_FLEX_ARRAY *Options
);
/*
Autodetect.
*/
EFI_STATUS
AutodetectLinux (
InternalAutodetectLinux (
IN EFI_FILE_PROTOCOL *RootDirectory,
OUT OC_PICKER_ENTRY **Entries,
OUT UINTN *NumEntries
......
......@@ -21,10 +21,11 @@
#include <Protocol/OcBootEntry.h>
UINTN gLinuxBootFlags = LINUX_BOOT_ALL & ~(LINUX_BOOT_ADD_DEBUG_INFO | LINUX_BOOT_LOG_VERBOSE);
UINTN gLinuxBootFlags = LINUX_BOOT_ALL & ~(LINUX_BOOT_ADD_DEBUG_INFO | LINUX_BOOT_LOG_VERBOSE | LINUX_BOOT_ADD_RW);
OC_FLEX_ARRAY *mParsedLoadOptions;
OC_PICKER_CONTEXT *gPickerContext;
OC_FLEX_ARRAY *gParsedLoadOptions;
OC_FLEX_ARRAY *gLoaderEntries;
EFI_GUID gPartuuid;
CHAR8 *gFileSystemType;
......@@ -237,17 +238,16 @@ OcGetLinuxBootEntries (
// if no /loader/entries/*.conf files are present, but also if there
// are only unusable files in there.
//
if (EFI_ERROR (Status)) {
if (EFI_ERROR (Status)
&& (gLinuxBootFlags & LINUX_BOOT_ALLOW_AUTODETECT) != 0) {
//
// Auto-detect vmlinuz and initrd files on own root filesystem (Debian-like).
//
if ((gLinuxBootFlags & LINUX_BOOT_ALLOW_AUTODETECT) != 0) {
Status = AutodetectLinux (
RootDirectory,
Entries,
NumEntries
);
}
Status = InternalAutodetectLinux (
RootDirectory,
Entries,
NumEntries
);
}
RootDirectory->Close (RootDirectory);
......@@ -285,17 +285,31 @@ UefiMain (
return Status;
}
Status = OcParseLoadOptions (LoadedImage, &gParsedLoadOptions);
//
// Keep mParsedLoadOptions kicking around, as all found options link into its memory.
//
Status = OcParseLoadOptions (LoadedImage, &mParsedLoadOptions);
if (!EFI_ERROR (Status)) {
AddBootFlags = 0;
RemoveBootFlags = 0;
OcParsedVarsGetInt (gParsedLoadOptions, L"flags", &gLinuxBootFlags, TRUE);
OcParsedVarsGetInt (gParsedLoadOptions, L"flags+", &AddBootFlags, TRUE);
OcParsedVarsGetInt (gParsedLoadOptions, L"flags-", &RemoveBootFlags, TRUE);
OcParsedVarsGetInt (mParsedLoadOptions, L"flags", &gLinuxBootFlags, TRUE);
OcParsedVarsGetInt (mParsedLoadOptions, L"flags+", &AddBootFlags, TRUE);
OcParsedVarsGetInt (mParsedLoadOptions, L"flags-", &RemoveBootFlags, TRUE);
gLinuxBootFlags |= AddBootFlags;
gLinuxBootFlags &= ~RemoveBootFlags;
} else if (Status != EFI_NOT_FOUND) {
return Status;
} else {
if (Status != EFI_NOT_FOUND) {
return Status;
}
ASSERT (mParsedLoadOptions == NULL);
}
if ((gLinuxBootFlags & LINUX_BOOT_ALLOW_AUTODETECT) != 0) {
Status = InternalPreloadAutoOpts (mParsedLoadOptions);
if (EFI_ERROR (Status)) {
return Status;
}
}
Status = gBS->InstallMultipleProtocolInterfaces (
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册