mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
Platform: OpenLinuxBoot.efi
This commit is contained in:
parent
d2ba13b6a2
commit
22cfebdf6f
@ -5,7 +5,6 @@
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/OcDebugLogLib.h>
|
||||
#include <Library/OcMiscLib.h>
|
||||
|
||||
@ -6,6 +6,11 @@ OpenCore Changelog
|
||||
- Added pattern-based automatic variable initialisation for better security
|
||||
- Updated underlying EDK II package to edk2-stable202108
|
||||
- Updated Apple Secure Boot variables for `x86legacy`
|
||||
- Update Linux variants in Flavours.md
|
||||
- Implement Boot Entry Protocol, allowing plug-in boot entry drivers
|
||||
- Add StringBuffer and FlexArray libraries
|
||||
- Update Drivers to support arguments (requires config.plist update, see samples)
|
||||
- Add OpenLinuxBoot driver: OC-native Linux autodetect and boot without chaining via GRUB
|
||||
|
||||
#### v0.7.2
|
||||
- Fixed OSBundleLibraries/OSBundleLibaries64 handling
|
||||
|
||||
@ -3682,6 +3682,7 @@ nvram 4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102:boot-log |
|
||||
\item \texttt{GSTT} --- GoptStop
|
||||
\item \texttt{HDA} --- AudioDxe
|
||||
\item \texttt{KKT} --- KeyTester
|
||||
\item \texttt{LNX} --- OpenLinuxBoot
|
||||
\item \texttt{MMDD} --- MmapDump
|
||||
\item \texttt{OCPAVP} --- PavpProvision
|
||||
\item \texttt{OCRST} --- ResetSystem
|
||||
@ -4106,8 +4107,13 @@ rm vault.pub
|
||||
of EFI System Partition file system.
|
||||
\item \texttt{0x00000800} (bit \texttt{11}) --- \texttt{OC\_SCAN\_ALLOW\_FS\_NTFS}, allows scanning
|
||||
of NTFS (Msft Basic Data) file system.
|
||||
\item \texttt{0x00001000} (bit \texttt{12}) --- \texttt{OC\_SCAN\_ALLOW\_FS\_EXT}, allows scanning
|
||||
of EXT (Linux Root) file system.
|
||||
\item \texttt{0x00001000} (bit \texttt{12}) --- \texttt{OC\_SCAN\_ALLOW\_FS\_LINUX\_ROOT}, allows
|
||||
scanning of Linux Root file systems.
|
||||
\item \texttt{0x00002000} (bit \texttt{13}) --- \texttt{OC\_SCAN\_ALLOW\_FS\_LINUX\_DATA}, allows
|
||||
scanning of Linux Data file systems.
|
||||
\item \texttt{0x00004000} (bit \texttt{14}) --- \texttt{OC\_SCAN\_ALLOW\_FS\_XBOOTLDR}, allows
|
||||
scanning the Extended Boot Loader Partition as defined by the
|
||||
\href{https://systemd.io/BOOT\_LOADER\_SPECIFICATION/}{Boot Loader Specification}.
|
||||
\item \texttt{0x00010000} (bit \texttt{16}) --- \texttt{OC\_SCAN\_ALLOW\_DEVICE\_SATA}, allow
|
||||
scanning SATA devices.
|
||||
\item \texttt{0x00020000} (bit \texttt{17}) --- \texttt{OC\_SCAN\_ALLOW\_DEVICE\_SASEX}, allow
|
||||
@ -5916,11 +5922,14 @@ Depending on the firmware, a different set of drivers may be required.
|
||||
Loading an incompatible driver may lead the system to unbootable state or
|
||||
even cause permanent firmware damage. Some of the known drivers are listed below:
|
||||
|
||||
\begin{tabular}{p{1.3in}p{5.55in}}
|
||||
\begin{longtable}{p{1.3in}p{5.55in}}
|
||||
\href{https://github.com/acidanthera/OpenCorePkg}{\texttt{AudioDxe}}\textbf{*}
|
||||
& HDA audio support driver in UEFI firmware for most Intel and some other analog audio controllers.
|
||||
Staging driver, refer to \href{https://github.com/acidanthera/bugtracker/issues/740}{acidanthera/bugtracker\#740}
|
||||
for known issues in AudioDxe. \\
|
||||
\href{https://github.com/acidanthera/OcBinaryData}{\texttt{btrfs\_x64}}
|
||||
& Open source BTRFS file system driver, required for booting with \hyperref[uefilinux]{OpenLinuxBoot}
|
||||
from a file system which is now quite commonly used with Linux. \\
|
||||
\href{https://github.com/acidanthera/OpenCorePkg}{\texttt{CrScreenshotDxe}}\textbf{*}
|
||||
& Screenshot making driver saving images to the root of OpenCore partition (ESP) or
|
||||
any available writeable filesystem upon pressing \texttt{F10}.
|
||||
@ -5930,6 +5939,9 @@ even cause permanent firmware damage. Some of the known drivers are listed below
|
||||
& Proprietary ExFAT file system driver for Bootcamp support commonly found in Apple
|
||||
firmware. For Sandy Bridge and earlier CPUs, the \texttt{ExFatDxeLegacy} driver should be
|
||||
used due to the lack of \texttt{RDRAND} instruction support. \\
|
||||
\href{https://github.com/acidanthera/OcBinaryData}{\texttt{ext4\_x64}}
|
||||
& Open source EXT4 file system driver, required for booting with \hyperref[uefilinux]{OpenLinuxBoot}
|
||||
from the file system most commonly used with Linux. \\
|
||||
\href{https://github.com/acidanthera/OcBinaryData}{\texttt{HfsPlus}}
|
||||
& Recommended. Proprietary HFS file system driver with bless support commonly found in Apple
|
||||
firmware. For Sandy Bridge and earlier CPUs, the \texttt{HfsPlusLegacy} driver should be
|
||||
@ -5952,6 +5964,10 @@ even cause permanent firmware damage. Some of the known drivers are listed below
|
||||
& \hyperref[ueficanopy]{OpenCore plugin} implementing graphical interface. \\
|
||||
\href{https://github.com/acidanthera/OpenCorePkg}{\texttt{OpenRuntime}}\textbf{*}
|
||||
& \hyperref[uefiruntime]{OpenCore plugin} implementing \texttt{OC\_FIRMWARE\_RUNTIME} protocol. \\
|
||||
\href{https://github.com/acidanthera/OpenCorePkg}{\texttt{OpenLinuxBoot}}\textbf{*}
|
||||
& \hyperref[uefilinux]{OpenCore plugin} implementing \texttt{OC\_BOOT\_ENTRY\_PROTOCOL}
|
||||
to allow direct detection and booting of Linux distributiuons from OpenCore, without
|
||||
chainloading via GRUB. \\
|
||||
\href{https://github.com/acidanthera/OpenCorePkg}{\texttt{OpenUsbKbDxe}}\textbf{*}
|
||||
& USB keyboard driver adding support for \texttt{AppleKeyMapAggregator} protocols
|
||||
on top of a custom USB keyboard driver implementation. This is an alternative to
|
||||
@ -5982,7 +5998,7 @@ even cause permanent firmware damage. Some of the known drivers are listed below
|
||||
& XHCI USB controller support driver from \texttt{MdeModulePkg}. This driver is
|
||||
included in most types of firmware starting with the Sandy Bridge generation. For earlier firmware
|
||||
or legacy systems, it may be used to support external USB 3.0 PCI cards.
|
||||
\end{tabular}
|
||||
\end{longtable}
|
||||
|
||||
Driver marked with \textbf{*} are bundled with OpenCore.
|
||||
To compile the drivers from UDK (EDK II) the same command used for
|
||||
@ -6158,6 +6174,178 @@ functioning. Feature highlights:
|
||||
mapping (e.g. \texttt{EnableWriteUnprotector}).
|
||||
\end{itemize}
|
||||
|
||||
\subsection{OpenLinuxBoot}\label{uefilinux}
|
||||
|
||||
\texttt{OpenLinuxBoot} is an OpenCore plugin implementing \texttt{OC\_BOOT\_ENTRY\_PROTOCOL}.
|
||||
It detects and boots Linux distros which are installed according to the
|
||||
\href{https://systemd.io/BOOT_LOADER_SPECIFICATION/}{Boot Loader Specification}
|
||||
or to the closely related (but not identical, see next paragraph)
|
||||
\href{https://fedoraproject.org/wiki/Changes/BootLoaderSpecByDefault}{systemd BootLoaderSpecByDefault}.
|
||||
In effect this means Linux distributions where the available boot options are found in
|
||||
\texttt{\{ESP\}/loader/entries/*.conf} files (for instance \texttt{/boot/efi/loader/entries/*.conf})
|
||||
or in \texttt{\{boot\}/loader/entries/*.conf} files (for instance \texttt{/boot/loader/entries/*.conf}).
|
||||
The former layout -- pure Boot Loader Specification, using kernel files on the EFI System Partition or
|
||||
Extended Boot Loader Partition -- is specific to systemd-boot, the latter
|
||||
layout with kernel files typically on the partition which will be mounted as \texttt{/boot}
|
||||
applies to most Fedora-related distros including Fedora itself, RHEL and variants.
|
||||
|
||||
BootLoaderSpecByDefault includes the possibility of expanding GRUB variables
|
||||
in its \texttt{*.conf} files -- and this is used in practice in certain distros such as CentOS.
|
||||
In order to correctly handle this, \texttt{OpenLinuxBoot} extracts all variables from
|
||||
\texttt{\{boot\}/grub2/grubenv} and any unconditionally set variables from \texttt{\{boot\}/grub2/grub.cfg}.
|
||||
This has proved sufficient in practice to extract the required variables seen so far in distros which use this
|
||||
GRUB-specific feature.
|
||||
|
||||
For distributions which do not use either of the above schemes, \texttt{OpenLinuxBoot} will autodetect and
|
||||
boot \texttt{\{boot\}/vmlinuz*} kernel files directly, after linking these automatically -- based on the
|
||||
kernel version in the filename -- to their associated \texttt{\{boot\}/init*} ramdisk files, and after
|
||||
searching in \texttt{/etc/default/grub} for kernel boot options and \texttt{/etc/os-release} for the
|
||||
distro name.
|
||||
This layout applies to most Debian-related distros, including Debian itself, Ubuntu and variants.
|
||||
|
||||
The method of starting the kernel relies on it being compiled with EFISTUB, however this applies
|
||||
to almost all modern distros, particularly those which use systemd. Most modern distros
|
||||
use systemd as their system manager (even though at the same time most do \emph{not} use systemd-boot as
|
||||
their bootloader).
|
||||
|
||||
The latest kernel version of a given install is always shown in the boot menu. Additional versions,
|
||||
recovery versions, etc. are added as auxiliary boot entries, so depending on OpenCore's
|
||||
\texttt{HideAuxiliary} setting may not be shown until the space key is pressed.
|
||||
|
||||
\emph{Note 1}: \texttt{OpenLinuxBoot} requires filesystem drivers that may not be available in
|
||||
firmware such as EXT4 and BTRFS drivers. These drivers can be obtained from external sources.
|
||||
Drivers tested in basic scenarios can be downloaded from \href{https://github.com/acidanthera/OcBinaryData}{OcBinaryData}.
|
||||
Be aware that these drivers are neither tested for reliability in all scenarious, nor underwent any
|
||||
tamper-resistance testing, therefore have may carry potential security or data-loss risks.
|
||||
|
||||
Most Linux distributions keep their boot files on the EXT4 file system even when the distribution's
|
||||
main filesystem is something else such as BTRFS, therefore a suitable UEFI EXT4 file system
|
||||
driver such as \href{https://github.com/acidanthera/OcBinaryData}{\texttt{ext4\_x64}} is normally required.
|
||||
A BTRFS driver such as \href{https://github.com/acidanthera/OcBinaryData}{\texttt{btrfs\_x64}}
|
||||
will be required in a somewhat less standard setup where the boot files are on a BTRFS partition,
|
||||
e.g. as by default in openSUSE.
|
||||
|
||||
Pure Boot Loader Spec (e.g. as implemented by systemd-boot) keeps all kernel and ramdisk images directly
|
||||
on the EFI System Partition (or an Extended Boot Loader Partition), therefore it requires no additional
|
||||
filesystem driver - but it is not widely used except in Arch Linux.
|
||||
|
||||
\emph{Note 2}: systemd-boot users (probably almost exclusively Arch Linux users) should be aware that \texttt{OpenLinuxBoot}
|
||||
does not support the systemd-boot--specific \href{https://systemd.io/BOOT\_LOADER\_INTERFACE/}{Boot Loader Interface};
|
||||
therefore use \texttt{efibootmgr} rather than \texttt{bootctl} for any low-level Linux command line interaction with
|
||||
the boot menu.
|
||||
|
||||
The default parameter values should work well, but if you need to parameterise this driver the following
|
||||
options may be specified in \texttt{UEFI/Drivers/Arguments}:
|
||||
|
||||
\begin{itemize}
|
||||
\tightlist
|
||||
\item \texttt{flags} - Default: all flags except \texttt{LINUX\_BOOT\_ADD\_DEBUG\_INFO} are set. \medskip
|
||||
|
||||
Available flags are: \medskip
|
||||
|
||||
\begin{itemize}
|
||||
\tightlist
|
||||
\item \texttt{0x00000001} (bit \texttt{0}) --- \texttt{LINUX\_BOOT\_SCAN\_ESP},
|
||||
Allows scanning for entries on EFI System Partition.
|
||||
\item \texttt{0x00000002} (bit \texttt{1}) --- \texttt{LINUX\_BOOT\_SCAN\_XBOOTLDR},
|
||||
Allows scanning for entries on Extended Boot Loader Partition.
|
||||
\item \texttt{0x00000004} (bit \texttt{2}) --- \texttt{LINUX\_BOOT\_SCAN\_LINUX\_ROOT},
|
||||
Allows scanning for entries on Linux Root filesystems.
|
||||
\item \texttt{0x00000008} (bit \texttt{3}) --- \texttt{LINUX\_BOOT\_SCAN\_LINUX\_DATA},
|
||||
Allows scanning for entries on Linux Data filesystems.
|
||||
\item \texttt{0x00000080} (bit \texttt{7}) --- \texttt{LINUX\_BOOT\_SCAN\_OTHER},
|
||||
Allows scanning for entries on file systems not matched by any of the above. \medskip
|
||||
|
||||
The following notes apply to all of the above options: \medskip
|
||||
|
||||
\emph{Note 1}: Apple filesystems APFS and HFS are never scanned.
|
||||
\medskip
|
||||
|
||||
\emph{Note 2}: Regardless of the above flags, a file system must first be
|
||||
allowed by \texttt{Misc/Security/ScanPolicy} before it can be seen by
|
||||
\texttt{OpenLinuxBoot} or any other \texttt{OC\_BOOT\_ENTRY\_PROTOCOL} driver.
|
||||
\medskip
|
||||
|
||||
\emph{Note 3}: It is recommended to enable scanning \texttt{LINUX\_ROOT} and \texttt{LINUX\_DATA}
|
||||
in both \texttt{OpenLinuxBoot} flags and \texttt{Misc/Security/ScanPolicy} in order to be sure
|
||||
to detect all valid Linux installs.
|
||||
\medskip
|
||||
|
||||
\item \texttt{0x00000100} (bit \texttt{8}) --- \texttt{LINUX\_BOOT\_ALLOW\_AUTODETECT},
|
||||
If set allows autodetecting and linking \texttt{vmlinuz*} and \texttt{init*} ramdisk files
|
||||
when \texttt{loader/entries} files are not found.
|
||||
\item \texttt{0x00000200} (bit \texttt{9}) --- \texttt{LINUX\_BOOT\_USE\_LATEST},
|
||||
When a Linux entry generated by \texttt{OpenLinuxBoot} is selected as the default boot entry
|
||||
in OpenCore, automatically switch to the latest kernel when a new version is installed. \medskip
|
||||
|
||||
When this option is set, an internal menu entry id is shared between kernel versions from the same install
|
||||
of Linux. Linux boot options are always sorted highest kernel version first, so this means that
|
||||
the latest kernel version of the same install always shows as the default, with this option set. \medskip
|
||||
|
||||
\emph{Note}: This option is recommended on all systems. \medskip
|
||||
|
||||
\item \texttt{0x00000400} (bit \texttt{10}) --- \texttt{LINUX\_BOOT\_ADD\_RO},
|
||||
This option applies to autodetected Linux only (i.e. to Debian-style distrubutions, not to BLSpec and
|
||||
Fedora-style distributions with \texttt{/loader/entries/*.conf} files).
|
||||
Some distrubtions run a filesystem check on loading which requires the root
|
||||
filesystem to initially be mounted read-only via the \texttt{ro} kernel option. Set this bit to add this
|
||||
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. To specify this option for specific
|
||||
distros only, use \texttt{partuuidopts:\{partuuid\}+=ro} instead of this flag.
|
||||
\item \texttt{0x00008000} (bit \texttt{15}) --- \texttt{LINUX\_BOOT\_ADD\_DEBUG\_INFO},
|
||||
Adds a human readable file system type, followed by the first eight characters of the
|
||||
partition's unique partition uuid, to each generated entry name. Can help with debugging
|
||||
the origin of entries generated by the driver when there are multiple Linux installs on
|
||||
one system.
|
||||
\end{itemize} \medskip
|
||||
|
||||
Flag values can be specified in hexadecimal beginning with \texttt{0x} or in decimal,
|
||||
e.g. \texttt{flags=0x80} or \texttt{flags=128}. \medskip
|
||||
|
||||
\item \texttt{partuuidopts:\{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.
|
||||
\medskip
|
||||
|
||||
\emph{Note}: The \texttt{partuuid} value to be specified here is typically the same as the \texttt{PARTUUID}
|
||||
seen in \texttt{root=PARTUUID=...} in the Linux kernel boot options (view using
|
||||
\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 you should not need this option in the latter case, but in case you do, 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, you may wish to examine how your drives are mounted using the
|
||||
Linux \texttt{mount} command, and then find out the partuuid of relevant mounted drives 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
|
||||
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
|
||||
a \texttt{vt.handoff} options, such as \texttt{autopts+="vt.handoff=7"} or \texttt{autopts+="vt.handoff=3"}
|
||||
(check \texttt{cat /proc/cmdline} when booted via your existing bootloader) on Ubuntu and related distros,
|
||||
in order to add the \texttt{vt.handoff} option to the auto-detected GRUB defaults, and avoid a flash of text
|
||||
showing before the distro splash screen.
|
||||
\medskip
|
||||
|
||||
Users may wish to compare their Linux boot options (shown with \texttt{cat /proc/cmdline}) seen when booting via
|
||||
\texttt{OpenLinuxBoot} and via their distro's original bootloader, which is normally GRUB (but might also be e.g.
|
||||
systemd-boot or EXTLINUX). Expect the options generated by \texttt{OpenLinuxBoot} not to
|
||||
contain a \texttt{BOOT\_IMAGE=...} value where GRUB options do, and to contain an
|
||||
\texttt{initrd=...} value where the GRUB options do not, since GRUB hands over ramdisks in a different way.
|
||||
All remaining parameters should match, however -- perhaps excluding less important graphics handover options,
|
||||
such as in the Ubuntu example given in \texttt{autoopts}.
|
||||
\texttt{OpenLinuxBoot} will not start a distro unless it can find some configured options to use, therefore in
|
||||
the hopefully unlikely case where no auto-detectable options are available, the user will need to specify the correct options
|
||||
with \texttt{partuuidopts} or \texttt{autoopts} before the distro will boot. Examine the OpenCore debug log
|
||||
for \texttt{LNX:} entries containing further information about what was found.
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Properties}\label{uefiprops}
|
||||
|
||||
\begin{enumerate}
|
||||
@ -6228,12 +6416,11 @@ functioning. Feature highlights:
|
||||
|
||||
\item
|
||||
\texttt{Drivers}\\
|
||||
\textbf{Type}: \texttt{plist\ array}\\
|
||||
\textbf{Type}: \texttt{plist\ dict}\\
|
||||
\textbf{Failsafe}: None\\
|
||||
\textbf{Description}: Load selected drivers from \texttt{OC/Drivers}
|
||||
directory.
|
||||
|
||||
To be filled with string filenames meant to be loaded as UEFI drivers.
|
||||
directory using the settings specified in the
|
||||
\hyperref[uefidriversprops]{Drivers Properties} section below.
|
||||
|
||||
\item
|
||||
\texttt{Input}\\
|
||||
@ -6681,6 +6868,33 @@ functioning. Feature highlights:
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Drivers Properties}\label{uefidriversprops}
|
||||
|
||||
\begin{enumerate}
|
||||
|
||||
\item
|
||||
\texttt{Path}\\
|
||||
\textbf{Type}: \texttt{plist\ string}\\
|
||||
\textbf{Failsafe}: Empty\\
|
||||
\textbf{Description}: Path of file to be loaded as a UEFI driver
|
||||
from \texttt{OC/Drivers} directory.
|
||||
|
||||
\item
|
||||
\texttt{Enabled}\\
|
||||
\textbf{Type}: \texttt{plist\ boolean}\\
|
||||
\textbf{Failsafe}: \texttt{false}\\
|
||||
\textbf{Description}: If \texttt{false} this driver entry will be ignored.
|
||||
|
||||
\item
|
||||
\texttt{Arguments}\\
|
||||
\textbf{Type}: \texttt{plist\ string}\\
|
||||
\textbf{Failsafe}: Empty\\
|
||||
\textbf{Description}: Some OC plugins accept optional additional arguments
|
||||
which may be specified as a string here.
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
|
||||
\subsection{Input Properties}\label{uefiinputprops}
|
||||
|
||||
\begin{enumerate}
|
||||
|
||||
@ -78,6 +78,7 @@ Please open an Issue or Pull Request if an additional Linux flavour is required.
|
||||
- **Linux** - Base icon for Linux (`Linux.icns`)
|
||||
- **Arch:Linux** - Arch Linux (`Arch.icns`, etc.)
|
||||
- **Astra:Linux** - Astra Linux
|
||||
- **CentOS:Linux** - CentOS
|
||||
- **Debian:Linux** - Debian
|
||||
- **Deepin:Linux** - Deepin
|
||||
- **elementaryOS:Linux** - elementary OS
|
||||
@ -90,16 +91,18 @@ Please open an Issue or Pull Request if an additional Linux flavour is required.
|
||||
- **Mageia:Linux** - Mageia (fork of former Mandriva)
|
||||
- **Manjaro:Linux** - Manjaro
|
||||
- **Mint:Linux** - Linux Mint
|
||||
- **openSUSE:Linux** - openSUSE
|
||||
- **Oracle:Linux** - Oracle Linux
|
||||
- **PopOS:Linux** - Pop!_OS
|
||||
- **RHEL:Linux** - Red Hat Enterprise Linux
|
||||
- **Rocky:Linux** - Rocky Linux
|
||||
- **Solus:Linux** - Solus
|
||||
- **Ubuntu:Linux** - Ubuntu
|
||||
- **Lubuntu:Ubuntu:Linux** - Lubuntu (`Lubuntu.icns`, etc.)
|
||||
- **UbuntuMATE:Ubuntu:Linux** - Ubuntu MATE
|
||||
- **Void:Linux** - Void Linux
|
||||
- **Xubuntu:Ubuntu:Linux** - Xubuntu
|
||||
- **Zorin:Linux** - Zorin OS
|
||||
- **openSUSE:Linux** - openSUSE
|
||||
|
||||
## Other Operating Systems
|
||||
|
||||
|
||||
@ -1305,20 +1305,134 @@
|
||||
<true/>
|
||||
<key>Drivers</key>
|
||||
<array>
|
||||
<string>HfsPlus.efi</string>
|
||||
<string>OpenRuntime.efi</string>
|
||||
<string>#OpenCanopy.efi</string>
|
||||
<string>#AudioDxe.efi</string>
|
||||
<string>#OpenPartitionDxe.efi</string>
|
||||
<string>#OpenUsbKbDxe.efi</string>
|
||||
<string>#UsbMouseDxe.efi</string>
|
||||
<string>#Ps2KeyboardDxe.efi</string>
|
||||
<string>#Ps2MouseDxe.efi</string>
|
||||
<string>#HiiDatabase.efi</string>
|
||||
<string>#NvmExpressDxe.efi</string>
|
||||
<string>#XhciDxe.efi</string>
|
||||
<string>#ExFatDxe.efi</string>
|
||||
<string>#CrScreenshotDxe.efi</string>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>HfsPlus.efi</string>
|
||||
<key>Enabled</key>
|
||||
<true/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>OpenRuntime.efi</string>
|
||||
<key>Enabled</key>
|
||||
<true/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>OpenCanopy.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>AudioDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>OpenPartitionDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>OpenUsbKbDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>UsbMouseDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>Ps2KeyboardDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>Ps2MouseDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>HiiDatabase.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>NvmExpressDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>XhciDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>ExFatDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>CrScreenshotDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>ext4_x64.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>OpenLinuxBoot.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>Input</key>
|
||||
<dict>
|
||||
|
||||
@ -1643,20 +1643,134 @@
|
||||
<true/>
|
||||
<key>Drivers</key>
|
||||
<array>
|
||||
<string>HfsPlus.efi</string>
|
||||
<string>OpenRuntime.efi</string>
|
||||
<string>#OpenCanopy.efi</string>
|
||||
<string>#AudioDxe.efi</string>
|
||||
<string>#OpenPartitionDxe.efi</string>
|
||||
<string>#OpenUsbKbDxe.efi</string>
|
||||
<string>#UsbMouseDxe.efi</string>
|
||||
<string>#Ps2KeyboardDxe.efi</string>
|
||||
<string>#Ps2MouseDxe.efi</string>
|
||||
<string>#HiiDatabase.efi</string>
|
||||
<string>#NvmExpressDxe.efi</string>
|
||||
<string>#XhciDxe.efi</string>
|
||||
<string>#ExFatDxe.efi</string>
|
||||
<string>#CrScreenshotDxe.efi</string>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>HfsPlus.efi</string>
|
||||
<key>Enabled</key>
|
||||
<true/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>OpenRuntime.efi</string>
|
||||
<key>Enabled</key>
|
||||
<true/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>OpenCanopy.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>AudioDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>OpenPartitionDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>OpenUsbKbDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>UsbMouseDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>Ps2KeyboardDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>Ps2MouseDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>HiiDatabase.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>NvmExpressDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>XhciDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>ExFatDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>CrScreenshotDxe.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>ext4_x64.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Path</key>
|
||||
<string>OpenLinuxBoot.efi</string>
|
||||
<key>Enabled</key>
|
||||
<false/>
|
||||
<key>Arguments</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>Input</key>
|
||||
<dict>
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
#include <IndustryStandard/AppleHid.h>
|
||||
#include <Library/OcAppleBootPolicyLib.h>
|
||||
#include <Library/OcAppleKeyMapLib.h>
|
||||
#include <Library/OcFlexArrayLib.h>
|
||||
#include <Library/OcStringLib.h>
|
||||
#include <Library/OcStorageLib.h>
|
||||
#include <Library/OcTypingLib.h>
|
||||
@ -24,6 +25,10 @@
|
||||
//#define BUILTIN_DEMONSTRATE_TYPING
|
||||
#endif
|
||||
|
||||
#if !defined(OC_TRACE_PARSE_VARS)
|
||||
#define OC_TRACE_PARSE_VARS DEBUG_VERBOSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
Primary picker context.
|
||||
**/
|
||||
@ -180,7 +185,7 @@ EFI_STATUS
|
||||
|
||||
/**
|
||||
Discovered boot entry.
|
||||
Note, inner resources must be freed with OcResetBootEntry.
|
||||
Note, inner resources must be freed with FreeBootEntry.
|
||||
**/
|
||||
typedef struct OC_BOOT_ENTRY_ {
|
||||
//
|
||||
@ -197,6 +202,10 @@ typedef struct OC_BOOT_ENTRY_ {
|
||||
//
|
||||
OC_BOOT_SYSTEM_ACTION SystemAction;
|
||||
//
|
||||
// Id under which to save entry as default.
|
||||
//
|
||||
CHAR16 *Id;
|
||||
//
|
||||
// Obtained human visible name.
|
||||
//
|
||||
CHAR16 *Name;
|
||||
@ -235,6 +244,10 @@ typedef struct OC_BOOT_ENTRY_ {
|
||||
//
|
||||
BOOLEAN IsCustom;
|
||||
//
|
||||
// Set when entry was created by OC_BOOT_ENTRY_PROTOCOL.
|
||||
//
|
||||
BOOLEAN IsBootEntryProtocol;
|
||||
//
|
||||
// Should make this option default boot option.
|
||||
//
|
||||
BOOLEAN SetDefault;
|
||||
@ -247,6 +260,11 @@ typedef struct OC_BOOT_ENTRY_ {
|
||||
//
|
||||
BOOLEAN ExposeDevicePath;
|
||||
//
|
||||
// Partition UUID of entry device.
|
||||
// Set for boot entry protocol boot entries only.
|
||||
//
|
||||
EFI_GUID UniquePartitionGUID;
|
||||
//
|
||||
// Load option data (usually "boot args") size.
|
||||
//
|
||||
UINT32 LoadOptionsSize;
|
||||
@ -256,6 +274,24 @@ typedef struct OC_BOOT_ENTRY_ {
|
||||
VOID *LoadOptions;
|
||||
} OC_BOOT_ENTRY;
|
||||
|
||||
/**
|
||||
Parsed load option or shell variable.
|
||||
**/
|
||||
typedef struct OC_PARSED_VAR_ASCII_ {
|
||||
CHAR8 *Name;
|
||||
CHAR8 *Value;
|
||||
} OC_PARSED_VAR_ASCII;
|
||||
|
||||
typedef struct OC_PARSED_VAR_UNICODE_ {
|
||||
CHAR16 *Name;
|
||||
CHAR16 *Value;
|
||||
} OC_PARSED_VAR_UNICODE;
|
||||
|
||||
typedef union OC_PARSED_VAR_ {
|
||||
OC_PARSED_VAR_ASCII Ascii;
|
||||
OC_PARSED_VAR_UNICODE Unicode;
|
||||
} OC_PARSED_VAR;
|
||||
|
||||
/**
|
||||
Boot filesystem containing boot entries.
|
||||
**/
|
||||
@ -356,9 +392,21 @@ typedef struct OC_BOOT_CONTEXT_ {
|
||||
#define OC_SCAN_ALLOW_FS_NTFS BIT11
|
||||
|
||||
/**
|
||||
Allow scanning EXT filesystems (e.g. EXT4).
|
||||
Allow scanning Linux Root filesystems.
|
||||
https://systemd.io/DISCOVERABLE_PARTITIONS/
|
||||
**/
|
||||
#define OC_SCAN_ALLOW_FS_EXT BIT12
|
||||
#define OC_SCAN_ALLOW_FS_LINUX_ROOT BIT12
|
||||
|
||||
/**
|
||||
Allow scanning Linux Data filesystems.
|
||||
https://systemd.io/DISCOVERABLE_PARTITIONS/
|
||||
**/
|
||||
#define OC_SCAN_ALLOW_FS_LINUX_DATA BIT13
|
||||
|
||||
/**
|
||||
Allow scanning XBOOTLDR filesystems.
|
||||
**/
|
||||
#define OC_SCAN_ALLOW_FS_XBOOTLDR BIT14
|
||||
|
||||
/**
|
||||
Allow scanning SATA devices.
|
||||
@ -416,11 +464,12 @@ typedef struct OC_BOOT_CONTEXT_ {
|
||||
OC_SCAN_ALLOW_DEVICE_PCI)
|
||||
|
||||
/**
|
||||
All device bits used by OC_SCAN_DEVICE_LOCK.
|
||||
All file system bits used by OC_SCAN_DEVICE_LOCK.
|
||||
**/
|
||||
#define OC_SCAN_FILE_SYSTEM_BITS ( \
|
||||
OC_SCAN_ALLOW_FS_APFS | OC_SCAN_ALLOW_FS_HFS | OC_SCAN_ALLOW_FS_ESP | \
|
||||
OC_SCAN_ALLOW_FS_NTFS | OC_SCAN_ALLOW_FS_EXT)
|
||||
OC_SCAN_ALLOW_FS_APFS | OC_SCAN_ALLOW_FS_HFS | OC_SCAN_ALLOW_FS_ESP | \
|
||||
OC_SCAN_ALLOW_FS_NTFS | OC_SCAN_ALLOW_FS_LINUX_ROOT | \
|
||||
OC_SCAN_ALLOW_FS_LINUX_DATA | OC_SCAN_ALLOW_FS_XBOOTLDR )
|
||||
|
||||
/**
|
||||
By default allow booting from APFS from internal drives.
|
||||
@ -473,14 +522,23 @@ EFI_STATUS
|
||||
|
||||
/**
|
||||
Custom picker entry.
|
||||
Note that OpenLinuxBoot OC_BOOT_ENTRY_PROTOCOL_REVISION needs incrementing
|
||||
when this structure is updated.
|
||||
**/
|
||||
typedef struct {
|
||||
//
|
||||
// Used by OC_BOOT_ENTRY_PROTOCOL to reidentify entry.
|
||||
// Multiple entries may share an id - allows e.g. newest version
|
||||
// of Linux install to automatically become selected default.
|
||||
//
|
||||
CONST CHAR8 *Id;
|
||||
//
|
||||
// Entry name.
|
||||
//
|
||||
CONST CHAR8 *Name;
|
||||
//
|
||||
// Entry path.
|
||||
// Absolute device path to file for user custom entries,
|
||||
// file path relative to device root for boot entry protocol.
|
||||
//
|
||||
CONST CHAR8 *Path;
|
||||
//
|
||||
@ -1378,6 +1436,18 @@ typedef struct OC_BOOT_ARGUMENTS_ {
|
||||
EFI_SYSTEM_TABLE *SystemTable;
|
||||
} OC_BOOT_ARGUMENTS;
|
||||
|
||||
///
|
||||
/// Boot services does not zero LoadOptions and LoadOptionsSize of a
|
||||
/// loaded image by default. Applying a limit to accepted LoadOptionsSize
|
||||
/// is intended to spot this and make it less likely to cause a segmentation
|
||||
/// fault if a newer driver (using LoadOptions) is called by an older version
|
||||
/// of OC (or anything else) which leaves these uninitialised.
|
||||
/// However the 'uninitialised' (?) value in LoadOptionsSize seems to be small
|
||||
/// but not zero, therefore unfortunately this approach - while not harmful - is
|
||||
/// not helping to detect this situation.
|
||||
///
|
||||
#define MAX_LOAD_OPTIONS_SIZE SIZE_4KB
|
||||
|
||||
/**
|
||||
Parse macOS kernel into unified boot arguments structure.
|
||||
|
||||
@ -1747,4 +1817,189 @@ OcImageLoaderLoad (
|
||||
OUT EFI_HANDLE *ImageHandle
|
||||
);
|
||||
|
||||
/**
|
||||
Parse loaded image protocol load options.
|
||||
|
||||
Assumes CHAR_NULL terminated Unicode string of space separated options,
|
||||
each of form {name} or {name}={value}. Double quotes can be used round {value} to
|
||||
include spaces, and '\' can be used within quoted or unquoted values to escape any
|
||||
character (including space and '"').
|
||||
|
||||
NB Var names and values are left as pointers to within the original raw LoadOptions
|
||||
string, which may be modified during processing.
|
||||
|
||||
@param[in] LoadedImage Loaded image handle.
|
||||
@param[out] ParsedVars Parsed load options if successful, NULL otherwise.
|
||||
Caller may free after use with OcFlexArrayFree
|
||||
if required.
|
||||
|
||||
@retval EFI_SUCCESS Success.
|
||||
@retval EFI_NOT_FOUND Missing or empty load options.
|
||||
@retval EFI_OUT_OF_RESOURCES Out of memory.
|
||||
@retval EFI_INVALID_PARAMETER Invalid load options detected.
|
||||
**/
|
||||
EFI_STATUS
|
||||
OcParseLoadOptions (
|
||||
IN CONST EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
|
||||
OUT OC_FLEX_ARRAY **ParsedVars
|
||||
);
|
||||
|
||||
/**
|
||||
Parse Unix-style var file or string. Parses a couple of useful ASCII
|
||||
GRUB config files (multi-line, name=var, with optinal comments) and
|
||||
defines a standard format for Unicode UEFI LoadOptions.
|
||||
|
||||
Assumes CHAR_NULL terminated Unicode string of space separated options,
|
||||
each of form {name} or {name}={value}. Double quotes can be used round {value} to
|
||||
include spaces, and '\' can be used within quoted or unquoted values to escape any
|
||||
character (including space and '"').
|
||||
Comments (if any) run from '#' to end of same line.
|
||||
|
||||
NB Var names and values are left as pointers to within the raw string, which may
|
||||
be modified during processing.
|
||||
|
||||
@param[in] StrVars Raw var string.
|
||||
@param[out] ParsedVars Parsed variables if successful, NULL otherwise.
|
||||
Caller may free after use with OcFlexArrayFree
|
||||
if required.
|
||||
@param[in] IsUnicode Are option names and values Unicode or ASCII?
|
||||
|
||||
@retval EFI_SUCCESS Success.
|
||||
@retval EFI_NOT_FOUND Missing or empty load options.
|
||||
@retval EFI_OUT_OF_RESOURCES Out of memory.
|
||||
@retval EFI_INVALID_PARAMETER Invalid load options detected.
|
||||
**/
|
||||
EFI_STATUS
|
||||
OcParseVars (
|
||||
IN VOID *StrVars,
|
||||
OUT OC_FLEX_ARRAY **ParsedVars,
|
||||
IN CONST BOOLEAN IsUnicode
|
||||
);
|
||||
|
||||
/**
|
||||
Get string value of parsed var or load option.
|
||||
Returned value is in same format as raw options.
|
||||
Return value points directly into original raw option memory,
|
||||
so may need to be copied if it is to be retained, and must not
|
||||
be freed directly.
|
||||
|
||||
@param[in] ParsedVars Parsed variables.
|
||||
@param[in] Name Option name.
|
||||
@param[in] StrValue Option value if successful, not modified otherwise;
|
||||
note that NULL is returned if option exists with no value.
|
||||
Caller must not attempt to free this memory.
|
||||
@param[in] IsUnicode Are option names and values Unicode or ASCII?
|
||||
|
||||
@retval TRUE Option exists.
|
||||
@retval FALSE Option not found.
|
||||
**/
|
||||
BOOLEAN
|
||||
OcParsedVarsGetStr (
|
||||
IN CONST OC_FLEX_ARRAY *ParsedVars,
|
||||
IN CONST VOID *Name,
|
||||
OUT VOID **StrValue,
|
||||
IN CONST BOOLEAN IsUnicode
|
||||
);
|
||||
|
||||
/**
|
||||
Get string value of parsed var or load option.
|
||||
Return value points directly into original raw option memory,
|
||||
so may need to be copied if it is to be retained, and must not
|
||||
be freed directly.
|
||||
|
||||
@param[in] ParsedVars Parsed variables.
|
||||
@param[in] Name Option name.
|
||||
@param[in] StrValue Option value if successful, not modified otherwise;
|
||||
note that NULL is returned if option exists with no value.
|
||||
Caller must not attempt to free this memory.
|
||||
|
||||
@retval TRUE Option exists.
|
||||
@retval FALSE Option not found.
|
||||
**/
|
||||
BOOLEAN
|
||||
OcParsedVarsGetUnicodeStr (
|
||||
IN CONST OC_FLEX_ARRAY *ParsedVars,
|
||||
IN CONST CHAR16 *Name,
|
||||
OUT CHAR16 **StrValue
|
||||
);
|
||||
|
||||
/**
|
||||
Get ASCII string value of parsed var or load option.
|
||||
Return value points directly into original raw option memory,
|
||||
so may need to be copied if it is to be retained, and must not
|
||||
be freed directly.
|
||||
|
||||
@param[in] ParsedVars Parsed variables.
|
||||
@param[in] Name Option name.
|
||||
@param[in] StrValue Option value if successful, not modified otherwise;
|
||||
note that NULL is returned if option exists with no value.
|
||||
Caller must not attempt to free this memory.
|
||||
|
||||
@retval TRUE Option exists.
|
||||
@retval FALSE Option not found.
|
||||
**/
|
||||
BOOLEAN
|
||||
OcParsedVarsGetAsciiStr (
|
||||
IN CONST OC_FLEX_ARRAY *ParsedVars,
|
||||
IN CONST CHAR8 *Name,
|
||||
OUT CHAR8 **StrValue
|
||||
);
|
||||
|
||||
/**
|
||||
Get presence or absence of parsed shell var or load option.
|
||||
|
||||
@param[in] ParsedVars Parsed variables.
|
||||
@param[in] Name Option name.
|
||||
@param[in] IsUnicode Are option names and values Unicode or ASCII?
|
||||
|
||||
@retval TRUE Option exists (with or without a value).
|
||||
@retval FALSE Option not found.
|
||||
**/
|
||||
BOOLEAN
|
||||
OcHasParsedVar (
|
||||
IN CONST OC_FLEX_ARRAY *ParsedVars,
|
||||
IN CONST VOID *Name,
|
||||
IN CONST BOOLEAN IsUnicode
|
||||
);
|
||||
|
||||
/**
|
||||
Get integer value of parsed shell var or load option (parses hex and decimal representations).
|
||||
|
||||
@param[in] ParsedVars Parsed variables.
|
||||
@param[in] Name Option name.
|
||||
@param[in] Value Option value if successful, not modified otherwise.
|
||||
@param[in] IsUnicode Are option names and values Unicode or ASCII?
|
||||
|
||||
@retval EFI_SUCCESS Success.
|
||||
@retval EFI_NOT_FOUND Option not found, or has no value.
|
||||
@retval other Error encountered when parsing option as int.
|
||||
**/
|
||||
EFI_STATUS
|
||||
OcParsedVarsGetInt (
|
||||
IN CONST OC_FLEX_ARRAY *ParsedVars,
|
||||
IN CONST VOID *Name,
|
||||
OUT UINTN *Value,
|
||||
IN CONST BOOLEAN IsUnicode
|
||||
);
|
||||
|
||||
/**
|
||||
Get guid value of parsed shell var or load option.
|
||||
|
||||
@param[in] ParsedVars Parsed variables.
|
||||
@param[in] Name Option name.
|
||||
@param[in] Value Option value if successful, not modified otherwise.
|
||||
@param[in] IsUnicode Are option names and values Unicode or ASCII?
|
||||
|
||||
@retval EFI_SUCCESS Success.
|
||||
@retval EFI_NOT_FOUND Option not found, or has no value.
|
||||
@retval other Error encountered when parsing option as guid.
|
||||
**/
|
||||
EFI_STATUS
|
||||
OcParsedVarsGetGuid (
|
||||
IN CONST OC_FLEX_ARRAY *ParsedVars,
|
||||
IN CONST VOID *Name,
|
||||
OUT EFI_GUID *Value,
|
||||
IN CONST BOOLEAN IsUnicode
|
||||
);
|
||||
|
||||
#endif // OC_BOOT_MANAGEMENT_LIB_H
|
||||
|
||||
@ -569,10 +569,16 @@ typedef enum {
|
||||
**/
|
||||
|
||||
///
|
||||
/// Drivers is a sorted array of strings containing driver paths.
|
||||
/// Drivers is an ordered array of drivers to load.
|
||||
///
|
||||
#define OC_UEFI_DRIVER_ENTRY_FIELDS(_, __) \
|
||||
_(OC_STRING , Path , , OC_STRING_CONSTR ("", _, __) , OC_DESTR (OC_STRING) ) \
|
||||
_(BOOLEAN , Enabled , , FALSE , ()) \
|
||||
_(OC_STRING , Arguments , , OC_STRING_CONSTR ("", _, __) , OC_DESTR (OC_STRING) )
|
||||
OC_DECLARE (OC_UEFI_DRIVER_ENTRY)
|
||||
|
||||
#define OC_UEFI_DRIVER_ARRAY_FIELDS(_, __) \
|
||||
OC_ARRAY (OC_STRING, _, __)
|
||||
OC_ARRAY (OC_UEFI_DRIVER_ENTRY, _, __)
|
||||
OC_DECLARE (OC_UEFI_DRIVER_ARRAY)
|
||||
|
||||
///
|
||||
|
||||
@ -116,11 +116,11 @@ OcGetVolumeLabel (
|
||||
*/
|
||||
EFI_STATUS
|
||||
OcSafeFileOpen (
|
||||
IN EFI_FILE_PROTOCOL *Protocol,
|
||||
OUT EFI_FILE_PROTOCOL **NewHandle,
|
||||
IN CONST CHAR16 *FileName,
|
||||
IN UINT64 OpenMode,
|
||||
IN UINT64 Attributes
|
||||
IN CONST EFI_FILE_PROTOCOL *Protocol,
|
||||
OUT EFI_FILE_PROTOCOL **NewHandle,
|
||||
IN CONST CHAR16 *FileName,
|
||||
IN CONST UINT64 OpenMode,
|
||||
IN CONST UINT64 Attributes
|
||||
);
|
||||
|
||||
/**
|
||||
@ -137,10 +137,10 @@ OcSafeFileOpen (
|
||||
**/
|
||||
VOID *
|
||||
OcReadFile (
|
||||
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem,
|
||||
IN CONST CHAR16 *FilePath,
|
||||
OUT UINT32 *FileSize OPTIONAL,
|
||||
IN UINT32 MaxFileSize OPTIONAL
|
||||
IN CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem,
|
||||
IN CONST CHAR16 *FilePath,
|
||||
OUT UINT32 *FileSize OPTIONAL,
|
||||
IN CONST UINT32 MaxFileSize OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
@ -148,19 +148,19 @@ OcReadFile (
|
||||
Null termination does not affect the returned file size.
|
||||
Depending on the implementation 0 byte files may return null.
|
||||
|
||||
@param[in] RootFile A pointer to the file protocol of the directory.
|
||||
@param[in] FilePath The full path to the file on the device.
|
||||
@param[out] FileSize The size of the file read (optional).
|
||||
@param[in] MaxFileSize Upper file size bound (optional).
|
||||
@param[in] RootDirectory A pointer to the file protocol of the directory.
|
||||
@param[in] FilePath The full path to the file on the device.
|
||||
@param[out] FileSize The size of the file read (optional).
|
||||
@param[in] MaxFileSize Upper file size bound (optional).
|
||||
|
||||
@retval A pointer to a buffer containing file read or NULL.
|
||||
**/
|
||||
VOID *
|
||||
OcReadFileFromFile (
|
||||
IN EFI_FILE_PROTOCOL *RootFile,
|
||||
IN CONST CHAR16 *FilePath,
|
||||
OUT UINT32 *FileSize OPTIONAL,
|
||||
IN UINT32 MaxFileSize OPTIONAL
|
||||
OcReadFileFromDirectory (
|
||||
IN CONST EFI_FILE_PROTOCOL *RootDirectory,
|
||||
IN CONST CHAR16 *FilePath,
|
||||
OUT UINT32 *FileSize OPTIONAL,
|
||||
IN UINT32 MaxFileSize OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
@ -260,6 +260,68 @@ OcGetNewestFileFromDirectory (
|
||||
OUT EFI_FILE_INFO **FileInfo
|
||||
);
|
||||
|
||||
/**
|
||||
Ensure specified file is directory or file as specified by IsDirectory.
|
||||
|
||||
@param[in] File The file to check.
|
||||
@param[in] IsDirectory Require that file is directory.
|
||||
|
||||
@retval EFI_SUCCESS File is directory/file as specified.
|
||||
@retval EFI_INVALID_PARAMETER File is not directory/file as specified.
|
||||
**/
|
||||
EFI_STATUS
|
||||
OcEnsureDirectory (
|
||||
IN EFI_FILE_PROTOCOL *File,
|
||||
IN BOOLEAN IsDirectory
|
||||
);
|
||||
|
||||
/**
|
||||
Process directory item.
|
||||
|
||||
NB Successful processing must return EFI_SUCCESS or EFI_NOT_FOUND, or further
|
||||
processing will be aborted.
|
||||
|
||||
Return EFI_NOT_FOUND to continue processing but act if no file found.
|
||||
|
||||
@param[in] Directory Parent directory file handle.
|
||||
@param[in] FileInfo EFI_FILE_INFO allocated from pool memory,
|
||||
will be freed after this call,
|
||||
data to preserve must be copied.
|
||||
@param[in] FileInfoSize FileInfoSize.
|
||||
@param[in,out] Context Optional application-specific context.
|
||||
|
||||
@retval EFI_SUCCESS File found and successfully processed.
|
||||
@retval EFI_NOT_FOUND (Act as if) no matching file was found.
|
||||
@retval other Error processing file (aborts directory scan).
|
||||
**/
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(*OC_PROCESS_DIRECTORY_ENTRY) (
|
||||
EFI_FILE_HANDLE Directory,
|
||||
EFI_FILE_INFO *FileInfo,
|
||||
UINTN FileInfoSize,
|
||||
VOID *Context OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
Scan directory, calling specified procedure for each directory entry.
|
||||
|
||||
@param[in] Directory The directory to scan.
|
||||
@param[in] ProcessEntry Process entry, called for each directory entry matching filter.
|
||||
@param[in,out] Context Optional application-specific context.
|
||||
|
||||
@retval EFI_NOT_FOUND Successful processing, no entries matching filter were found.
|
||||
@retval EFI_SUCCESS Successful processing, at least one entry matching filter was found.
|
||||
@retval EFI_OUT_OF_RESOURCES Out of memory.
|
||||
@retval other Other error returned by file system or ProcessEntry during processing
|
||||
**/
|
||||
EFI_STATUS
|
||||
OcScanDirectory (
|
||||
IN EFI_FILE_HANDLE Directory,
|
||||
IN OC_PROCESS_DIRECTORY_ENTRY ProcessEntry,
|
||||
IN OUT VOID *Context OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
Get file information of specified type.
|
||||
|
||||
|
||||
263
Include/Acidanthera/Library/OcFlexArrayLib.h
Normal file
263
Include/Acidanthera/Library/OcFlexArrayLib.h
Normal file
@ -0,0 +1,263 @@
|
||||
/** @file
|
||||
Copyright (C) 2021, Mike Beaton. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#ifndef OC_FLEX_ARRAY_LIB_H
|
||||
#define OC_FLEX_ARRAY_LIB_H
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/OcStringLib.h>
|
||||
#include <Protocol/ApplePlatformInfoDatabase.h>
|
||||
|
||||
/*
|
||||
Forward declaration of OC_FLEX_ARRAY structure.
|
||||
*/
|
||||
typedef struct OC_FLEX_ARRAY_ OC_FLEX_ARRAY;
|
||||
|
||||
/**
|
||||
Free any allocated memory pointed to by flex array item.
|
||||
|
||||
@param[in] Item Item to free.
|
||||
**/
|
||||
typedef
|
||||
VOID
|
||||
(* OC_FLEX_ARRAY_FREE_ITEM) (
|
||||
IN VOID *Item
|
||||
);
|
||||
|
||||
/**
|
||||
Utility method to free memory pointed to by flex array
|
||||
item when the item is a single pointer, or when the only
|
||||
allocated memory is pointed to by a pointer which is the
|
||||
first element.
|
||||
|
||||
@param[in] Item Flex array item to free.
|
||||
**/
|
||||
VOID
|
||||
OcFlexArrayFreePointerItem (
|
||||
IN VOID *Item
|
||||
);
|
||||
|
||||
/**
|
||||
Initialize flex array.
|
||||
|
||||
@param[in] ItemSize Size of each item in the array.
|
||||
@param[in] FreeItem Method to free one item, called once per item by
|
||||
OcFlexArrayFree; may be NULL if there is nothing
|
||||
pointed to by pool items which needs freeing.
|
||||
|
||||
@retval Non-null Flex array was created.
|
||||
@retval NULL Out of memory.
|
||||
**/
|
||||
OC_FLEX_ARRAY *
|
||||
OcFlexArrayInit (
|
||||
IN CONST UINTN ItemSize,
|
||||
IN CONST OC_FLEX_ARRAY_FREE_ITEM FreeItem OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
Add new item to flex array, resizing if necessary. New item memory is zeroed.
|
||||
|
||||
@param[in,out] FlexArray Flex array to modify.
|
||||
|
||||
@retval Non-null Address of item created.
|
||||
@retval NULL Out of memory, in which case FlexArray->Items will be set
|
||||
to NULL, but FlexArray itself will still be allocated.
|
||||
**/
|
||||
VOID *
|
||||
OcFlexArrayAddItem (
|
||||
IN OUT OC_FLEX_ARRAY *FlexArray
|
||||
);
|
||||
|
||||
/**
|
||||
Insert new item at position in flex array, resizing array if necessary. New item memory is zeroed.
|
||||
|
||||
@param[in,out] FlexArray Flex array to modify.
|
||||
@param[in] InsertIndex Index at which to insert; must be less than or equal to current item count.
|
||||
|
||||
@retval Non-null Address of item created.
|
||||
@retval NULL Out of memory, in which case FlexArray->Items will be set
|
||||
to NULL, but FlexArray itself will still be allocated.
|
||||
**/
|
||||
VOID *
|
||||
OcFlexArrayInsertItem (
|
||||
IN OUT OC_FLEX_ARRAY *FlexArray,
|
||||
IN CONST UINTN InsertIndex
|
||||
);
|
||||
|
||||
/**
|
||||
Return item at index in array.
|
||||
|
||||
@param[in,out] FlexArray Flex array to access.
|
||||
@param[in,out] Index Index of item to return.
|
||||
|
||||
@retval Non-null Item.
|
||||
@retval NULL Out-of-range item requested. This also ASSERTs.
|
||||
**/
|
||||
VOID *
|
||||
OcFlexArrayItemAt (
|
||||
IN CONST OC_FLEX_ARRAY *FlexArray,
|
||||
IN CONST UINTN Index
|
||||
);
|
||||
|
||||
/**
|
||||
Free flex array.
|
||||
|
||||
@param[in,out] FlexArray Flex array to free.
|
||||
**/
|
||||
VOID
|
||||
OcFlexArrayFree (
|
||||
IN OUT OC_FLEX_ARRAY **FlexArray
|
||||
);
|
||||
|
||||
/**
|
||||
Free dynamic container object, but do not free and
|
||||
pass back out allocated items with item count.
|
||||
|
||||
@param[in,out] FlexArray Flex array to free.
|
||||
@param[in,out] Items Pool allocated flex array item list.
|
||||
@param[in,out] Count Item list count.
|
||||
**/
|
||||
VOID
|
||||
OcFlexArrayFreeContainer (
|
||||
IN OUT OC_FLEX_ARRAY **FlexArray,
|
||||
IN OUT VOID **Items,
|
||||
IN OUT UINTN *Count
|
||||
);
|
||||
|
||||
/*
|
||||
Flex array.
|
||||
*/
|
||||
struct OC_FLEX_ARRAY_ {
|
||||
//
|
||||
// Allocated array.
|
||||
//
|
||||
VOID *Items;
|
||||
//
|
||||
// Item size.
|
||||
//
|
||||
UINTN ItemSize;
|
||||
//
|
||||
// Current used count.
|
||||
//
|
||||
UINTN Count;
|
||||
//
|
||||
// Current allocated count.
|
||||
//
|
||||
UINTN AllocatedCount;
|
||||
//
|
||||
// Optional method to free memory pointed to from item.
|
||||
//
|
||||
OC_FLEX_ARRAY_FREE_ITEM FreeItem;
|
||||
};
|
||||
|
||||
/*
|
||||
Forward declaration of OC_STRING_BUFFER structure.
|
||||
*/
|
||||
typedef struct OC_STRING_BUFFER_ OC_STRING_BUFFER;
|
||||
|
||||
/**
|
||||
Initialize string buffer.
|
||||
|
||||
@retval Non-null Buffer was created.
|
||||
@retval NULL Out of memory.
|
||||
**/
|
||||
OC_STRING_BUFFER *
|
||||
OcAsciiStringBufferInit (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Append new string to buffer, resizing if necessary.
|
||||
|
||||
@param[in,out] StringBuffer Buffer to modify.
|
||||
@param[in] AppendString String to append. If NULL, nothing will be modified.
|
||||
|
||||
@retval EFI_SUCCESS String was appended.
|
||||
@retval EFI_OUT_OF_RESOURCES Out of memory.
|
||||
@retval EFI_UNSUPPORTED Internal error.
|
||||
**/
|
||||
EFI_STATUS
|
||||
OcAsciiStringBufferAppend (
|
||||
IN OUT OC_STRING_BUFFER *Buffer,
|
||||
IN CONST CHAR8 *AppendString OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
Append new substring to buffer, resizing if necessary.
|
||||
|
||||
@param[in,out] StringBuffer Buffer to modify.
|
||||
@param[in] AppendString String to append. If NULL, nothing will be modified.
|
||||
@param[in] Length Maxiumum length of substring to use. 0 means use 0 characters.
|
||||
Use MAX_UINTN for all chars. Ignored if AppendString is NULL.
|
||||
|
||||
@retval EFI_SUCCESS String was appended.
|
||||
@retval EFI_OUT_OF_RESOURCES Out of memory.
|
||||
@retval EFI_UNSUPPORTED Internal error.
|
||||
**/
|
||||
EFI_STATUS
|
||||
OcAsciiStringBufferAppendN (
|
||||
IN OUT OC_STRING_BUFFER *Buffer,
|
||||
IN CONST CHAR8 *AppendString, OPTIONAL
|
||||
IN CONST UINTN Length
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
Safely print to string buffer.
|
||||
|
||||
@param[in,out] StringBuffer Buffer to modify.
|
||||
@param[in] FormatString A Null-terminated ASCII format string.
|
||||
@param[in] ... Variable argument list whose contents are accessed based on the
|
||||
format string specified by FormatString.
|
||||
|
||||
@retval EFI_SUCCESS When data was printed to string buffer.
|
||||
@retval EFI_OUT_OF_RESOURCES Out of memory increasing string buffer sufficiently to print to.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
OcAsciiStringBufferSPrint (
|
||||
IN OUT OC_STRING_BUFFER *Buffer,
|
||||
IN CONST CHAR8 *FormatString,
|
||||
...
|
||||
);
|
||||
|
||||
/**
|
||||
Free string buffer memory and return pointer to pool allocated resultant string.
|
||||
Note that if no data was ever appended to the string then the return value
|
||||
will be NULL, not a zero length string.
|
||||
|
||||
@param[in,out] StringBuffer StringBuffer to free.
|
||||
|
||||
@retval Non-NULL Pointer to pool allocated accumulated string.
|
||||
@retval NULL No data was ever added to the string.
|
||||
**/
|
||||
CHAR8 *
|
||||
OcAsciiStringBufferFreeContainer (
|
||||
IN OUT OC_STRING_BUFFER **StringBuffer
|
||||
);
|
||||
|
||||
/**
|
||||
Free string buffer memory; free and discard any allocated resultant string.
|
||||
|
||||
@param[in,out] StringBuffer StringBuffer to free.
|
||||
|
||||
@retval Non-NULL Pointer to pool allocated accumulated string.
|
||||
@retval NULL No data was ever added to the string.
|
||||
**/
|
||||
VOID
|
||||
OcAsciiStringBufferFree (
|
||||
IN OUT OC_STRING_BUFFER **StringBuffer
|
||||
);
|
||||
|
||||
/*
|
||||
String buffer.
|
||||
*/
|
||||
struct OC_STRING_BUFFER_ {
|
||||
CHAR8 *String;
|
||||
UINTN StringLength;
|
||||
UINTN BufferSize;
|
||||
};
|
||||
|
||||
#endif // OC_FLEX_ARRAY_LIB_H
|
||||
@ -29,6 +29,11 @@
|
||||
**/
|
||||
#define SECONDS_TO_MICROSECONDS(x) ((x)*1000000)
|
||||
|
||||
/**
|
||||
Character length of EFI_GUID string representation.
|
||||
**/
|
||||
#define OC_EFI_GUID_STR_LEN (sizeof (EFI_GUID) * 2 + 4)
|
||||
|
||||
BOOLEAN
|
||||
FindPattern (
|
||||
IN CONST UINT8 *Pattern,
|
||||
|
||||
@ -434,6 +434,19 @@ OcAsciiPrintBuffer (
|
||||
...
|
||||
);
|
||||
|
||||
/**
|
||||
Convert a null-terminated ASCII string, in-place, to all lowercase.
|
||||
Then return it.
|
||||
|
||||
@param Str The null-terminated string to be converted to all lowercase.
|
||||
|
||||
@return The null-terminated string converted into all lowercase.
|
||||
**/
|
||||
CHAR8 *
|
||||
OcAsciiToLower (
|
||||
CHAR8 *Str
|
||||
);
|
||||
|
||||
/**
|
||||
Returns the first occurrence of a Null-terminated Unicode sub-string
|
||||
in a Null-terminated Unicode string through a case insensitive comparison.
|
||||
@ -682,4 +695,33 @@ MixedStrCmp (
|
||||
IN CONST CHAR8 *SecondString
|
||||
);
|
||||
|
||||
/**
|
||||
Function to reverse sort when comparing by Unicode strings using UefiSortLib PerformQuickSort.
|
||||
|
||||
@param[in] Buffer1 The pointer to String to compare (CHAR16**).
|
||||
@param[in] Buffer2 The pointer to second String to compare (CHAR16**).
|
||||
|
||||
@retval 0 Buffer1 equal to Buffer2.
|
||||
@return < 0 Buffer1 is less than Buffer2.
|
||||
@return > 0 Buffer1 is greater than Buffer2.
|
||||
**/
|
||||
INTN
|
||||
EFIAPI
|
||||
OcReverseStringCompare (
|
||||
IN CONST VOID *Buffer1,
|
||||
IN CONST VOID *Buffer2
|
||||
);
|
||||
|
||||
/**
|
||||
Determine if a particular character is whitespace.
|
||||
|
||||
@param[in] Ch The character to check.
|
||||
|
||||
@return Returns TRUE if Ch is a whitespace character.
|
||||
**/
|
||||
BOOLEAN
|
||||
OcIsSpace (
|
||||
CHAR16 Ch
|
||||
);
|
||||
|
||||
#endif // OC_STRING_LIB_H
|
||||
|
||||
99
Include/Acidanthera/Protocol/OcBootEntry.h
Normal file
99
Include/Acidanthera/Protocol/OcBootEntry.h
Normal file
@ -0,0 +1,99 @@
|
||||
/** @file
|
||||
OpenCore Boot Entry Protocol.
|
||||
|
||||
Copyright (C) 2021, Mike Beaton. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#ifndef OC_BOOT_ENTRY_PROTOCOL_H
|
||||
#define OC_BOOT_ENTRY_PROTOCOL_H
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/OcBootManagementLib.h>
|
||||
|
||||
#include <Protocol/SimpleFileSystem.h>
|
||||
|
||||
/**
|
||||
8604716E-ADD4-45B4-8495-08E36D497F4F
|
||||
**/
|
||||
#define OC_BOOT_ENTRY_PROTOCOL_GUID \
|
||||
{ \
|
||||
0x8604716E, 0xADD4, 0x45B4, { 0x84, 0x95, 0x08, 0xE3, 0x6D, 0x49, 0x7F, 0x4F } \
|
||||
}
|
||||
|
||||
/**
|
||||
Currently supported OC_BOOT_ENTRY_PROTOCOL protocol revision.
|
||||
Needs to be changed every time the contract changes, including when
|
||||
passed-in structures OC_PICKER_ENTRY and OC_PICKER_ENTRY change.
|
||||
|
||||
WARNING: This protocol is currently undergoing active design.
|
||||
**/
|
||||
#define OC_BOOT_ENTRY_PROTOCOL_REVISION 1
|
||||
|
||||
/**
|
||||
Forward declaration of OC_BOOT_ENTRY_PROTOCOL structure.
|
||||
**/
|
||||
typedef struct OC_BOOT_ENTRY_PROTOCOL_ OC_BOOT_ENTRY_PROTOCOL;
|
||||
|
||||
/**
|
||||
Return list of OpenCore boot entries associated with filesystem.
|
||||
|
||||
@param[in] PickerContext Picker context.
|
||||
@param[in] Device The handle of the device to scan. NULL is passed in to
|
||||
request custom entries. All implementations must support a
|
||||
NULL input value, but may immediately return EFI_NOT_FOUND
|
||||
if they do not provide any custom entries.
|
||||
@param[out] BootEntries List of boot entries associated with the filesystem.
|
||||
On EFI_SUCCESS BootEntries must be freed by the caller
|
||||
with FreePool after use, and each individual boot entry
|
||||
should eventually be freed by FreeBootEntry (as for boot
|
||||
entries created within OC itself).
|
||||
Does not point to allocated memory on return, if any status
|
||||
other than EFI_SUCCESS was returned.
|
||||
@param[out] NumEntries The number of entries returned in the BootEntries list.
|
||||
If any status other than EFI_SUCCESS was returned, this
|
||||
value may not have been initialised and should be ignored
|
||||
by the caller.
|
||||
|
||||
@retval EFI_SUCCESS At least one matching entry was found, and the list and
|
||||
count of boot entries has been returned.
|
||||
@retval EFI_NOT_FOUND No matching boot entries were found.
|
||||
@retval EFI_OUT_OF_RESOURCES Memory allocation failure.
|
||||
@retval other An error returned by a sub-operation.
|
||||
**/
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI *OC_GET_BOOT_ENTRIES) (
|
||||
IN OC_PICKER_CONTEXT *PickerContext,
|
||||
IN CONST EFI_HANDLE Device,
|
||||
OUT OC_PICKER_ENTRY **Entries,
|
||||
OUT UINTN *NumEntries
|
||||
);
|
||||
|
||||
/**
|
||||
Free list of OpenCore boot entries from previous call to OC_GET_BOOT_ENTRIES.
|
||||
|
||||
@param[in] Entries List of boot entries, as returned by previous call.
|
||||
Correct implementation of interface should additionally
|
||||
zero this pointer before returning.
|
||||
@param[in] NumEntries The number of entries, as returned by previous call.
|
||||
**/
|
||||
typedef
|
||||
VOID
|
||||
(EFIAPI *OC_FREE_BOOT_ENTRIES) (
|
||||
IN OC_PICKER_ENTRY **Entries,
|
||||
IN UINTN NumEntries
|
||||
);
|
||||
|
||||
/**
|
||||
The structure exposed by the OC_BOOT_ENTRY_PROTOCOL.
|
||||
**/
|
||||
struct OC_BOOT_ENTRY_PROTOCOL_ {
|
||||
UINTN Revision;
|
||||
OC_GET_BOOT_ENTRIES GetBootEntries;
|
||||
OC_FREE_BOOT_ENTRIES FreeBootEntries;
|
||||
};
|
||||
|
||||
extern EFI_GUID gOcBootEntryProtocolGuid;
|
||||
|
||||
#endif // OC_BOOT_ENTRY_PROTOCOL_H
|
||||
@ -1,15 +1,6 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, vit9696. All rights reserved.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
Copyright (C) 2019-2021, vit9696, mikebeaton. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#include <Guid/AppleVariable.h>
|
||||
@ -18,13 +9,37 @@
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcBootManagementLib.h>
|
||||
#include <Library/OcMiscLib.h>
|
||||
#include <Library/OcFlexArrayLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
|
||||
#include "BootManagementInternal.h"
|
||||
|
||||
/*
|
||||
Shell var and load options processing states.
|
||||
*/
|
||||
typedef enum PARSE_VARS_STATE_ {
|
||||
PARSE_VARS_WHITE_SPACE,
|
||||
PARSE_VARS_COMMENT,
|
||||
PARSE_VARS_NAME,
|
||||
PARSE_VARS_VALUE_FIRST,
|
||||
PARSE_VARS_VALUE,
|
||||
PARSE_VARS_QUOTED_VALUE,
|
||||
PARSE_VARS_SHELL_EXPANSION
|
||||
} PARSE_VARS_STATE;
|
||||
|
||||
|
||||
//
|
||||
// Shift from token start to current position forwards by offset characters.
|
||||
//
|
||||
#define SHIFT_TOKEN(pos, token, offset) { \
|
||||
CopyMem ((UINT8 *)(token) + (offset), (token), (UINT8 *)(pos) - (UINT8 *)(token)); \
|
||||
(token) = (UINT8 *)(token) + (offset); \
|
||||
(pos) = (UINT8 *)(token) + (offset); \
|
||||
}
|
||||
|
||||
VOID
|
||||
OcParseBootArgs (
|
||||
OUT OC_BOOT_ARGUMENTS *Arguments,
|
||||
@ -360,3 +375,348 @@ OcCheckArgumentFromEnv (
|
||||
|
||||
return HasArgument;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
OcParseLoadOptions (
|
||||
IN CONST EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
|
||||
OUT OC_FLEX_ARRAY **ParsedVars
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
ASSERT (LoadedImage != NULL);
|
||||
ASSERT (ParsedVars != NULL);
|
||||
*ParsedVars = NULL;
|
||||
|
||||
if (LoadedImage->LoadOptionsSize % sizeof (CHAR16) != 0 || LoadedImage->LoadOptionsSize > MAX_LOAD_OPTIONS_SIZE) {
|
||||
DEBUG ((DEBUG_ERROR, "OCB: Invalid LoadOptions (%p:%u)\n", LoadedImage->LoadOptions, LoadedImage->LoadOptionsSize));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (LoadedImage->LoadOptions == NULL ||
|
||||
LoadedImage->LoadOptionsSize == 0 ||
|
||||
((CHAR16 *)LoadedImage->LoadOptions)[0] == CHAR_NULL) {
|
||||
DEBUG ((OC_TRACE_PARSE_VARS, "OCB: No LoadOptions (%p:%u)\n", LoadedImage->LoadOptions, LoadedImage->LoadOptionsSize));
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
Status = OcParseVars (LoadedImage->LoadOptions, ParsedVars, TRUE);
|
||||
|
||||
if (Status == EFI_INVALID_PARAMETER) {
|
||||
DEBUG ((DEBUG_ERROR, "OCB: Invalid LoadOptions (%p:%u)\n", LoadedImage->LoadOptions, LoadedImage->LoadOptionsSize));
|
||||
} else if (Status == EFI_NOT_FOUND) {
|
||||
DEBUG ((DEBUG_WARN, "OCB: Empty LoadOptions\n"));
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
OcParseVars (
|
||||
IN VOID *StrVars,
|
||||
OUT OC_FLEX_ARRAY **ParsedVars,
|
||||
IN CONST BOOLEAN IsUnicode
|
||||
)
|
||||
{
|
||||
VOID *Pos;
|
||||
PARSE_VARS_STATE State;
|
||||
PARSE_VARS_STATE PushState;
|
||||
BOOLEAN Retake;
|
||||
CHAR16 Ch;
|
||||
VOID *Name;
|
||||
VOID *Value;
|
||||
OC_PARSED_VAR *Option;
|
||||
|
||||
if (StrVars == NULL || (IsUnicode ? ((CHAR16 *) StrVars)[0] == CHAR_NULL : ((CHAR8 *) StrVars)[0] == '\0')) {
|
||||
DEBUG ((OC_TRACE_PARSE_VARS, "OCB: No vars (%p)\n", StrVars));
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
*ParsedVars = OcFlexArrayInit (sizeof (OC_PARSED_VAR), NULL);
|
||||
if (*ParsedVars == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Pos = StrVars;
|
||||
State = PARSE_VARS_WHITE_SPACE;
|
||||
PushState = PARSE_VARS_WHITE_SPACE;
|
||||
Retake = FALSE;
|
||||
|
||||
do {
|
||||
Ch = IsUnicode ? *((CHAR16 *) Pos) : *((CHAR8 *) Pos);
|
||||
switch (State) {
|
||||
case PARSE_VARS_WHITE_SPACE:
|
||||
if (Ch == '#') {
|
||||
State = PARSE_VARS_COMMENT;
|
||||
} else if (!(OcIsSpace (Ch) || Ch == CHAR_NULL)) {
|
||||
Name = Pos;
|
||||
State = PARSE_VARS_NAME;
|
||||
}
|
||||
break;
|
||||
|
||||
case PARSE_VARS_COMMENT:
|
||||
if (Ch == '\n') {
|
||||
State = PARSE_VARS_WHITE_SPACE;
|
||||
}
|
||||
break;
|
||||
|
||||
case PARSE_VARS_NAME:
|
||||
if (Ch == L'=' || OcIsSpace (Ch) || Ch == CHAR_NULL) {
|
||||
if (IsUnicode) {
|
||||
*((CHAR16 *) Pos) = CHAR_NULL;
|
||||
} else {
|
||||
*((CHAR8 *) Pos) = '\0';
|
||||
}
|
||||
if (Ch == L'=') {
|
||||
State = PARSE_VARS_VALUE_FIRST;
|
||||
} else {
|
||||
State = PARSE_VARS_WHITE_SPACE;
|
||||
}
|
||||
Option = OcFlexArrayAddItem (*ParsedVars);
|
||||
if (Option == NULL) {
|
||||
OcFlexArrayFree (ParsedVars);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
if (IsUnicode) {
|
||||
Option->Unicode.Name = Name;
|
||||
DEBUG ((OC_TRACE_PARSE_VARS, "OCB: Name=\"%s\"\n", Name));
|
||||
} else {
|
||||
Option->Ascii.Name = Name;
|
||||
DEBUG ((OC_TRACE_PARSE_VARS, "OCB: Name=\"%a\"\n", Name));
|
||||
}
|
||||
if (State == PARSE_VARS_WHITE_SPACE) {
|
||||
DEBUG ((OC_TRACE_PARSE_VARS, "OCB: No value %u\n", 1));
|
||||
}
|
||||
Name = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case PARSE_VARS_VALUE_FIRST:
|
||||
if (Ch == L'"') {
|
||||
State = PARSE_VARS_QUOTED_VALUE;
|
||||
Value = (UINT8 *) Pos + (IsUnicode ? sizeof (CHAR16) : sizeof (CHAR8));
|
||||
} else {
|
||||
State = PARSE_VARS_VALUE;
|
||||
Value = Pos;
|
||||
Retake = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case PARSE_VARS_SHELL_EXPANSION:
|
||||
if (Ch == '`') {
|
||||
ASSERT (PushState != PARSE_VARS_WHITE_SPACE);
|
||||
State = PushState;
|
||||
}
|
||||
break;
|
||||
|
||||
case PARSE_VARS_VALUE:
|
||||
case PARSE_VARS_QUOTED_VALUE:
|
||||
if (Ch == L'`') {
|
||||
PushState = State;
|
||||
State = PARSE_VARS_SHELL_EXPANSION;
|
||||
} else if (Ch == L'\\') {
|
||||
SHIFT_TOKEN (Pos, Value, IsUnicode ? sizeof (CHAR16) : sizeof (CHAR8));
|
||||
} else if (
|
||||
(State == PARSE_VARS_VALUE && (OcIsSpace (Ch) || Ch == CHAR_NULL)) ||
|
||||
(State == PARSE_VARS_QUOTED_VALUE && Ch == '"')) {
|
||||
//
|
||||
// Explicitly quoted empty string needs to be stored detectably
|
||||
// differently from missing value.
|
||||
//
|
||||
if (State != PARSE_VARS_QUOTED_VALUE && Pos == Value) {
|
||||
DEBUG ((OC_TRACE_PARSE_VARS, "OCB: No value %u\n", 2));
|
||||
} else {
|
||||
if (PushState != PARSE_VARS_WHITE_SPACE) {
|
||||
DEBUG ((OC_TRACE_PARSE_VARS, "OCB: Found shell expansion, cancelling value\n"));
|
||||
PushState = PARSE_VARS_WHITE_SPACE;
|
||||
} else {
|
||||
if (IsUnicode) {
|
||||
*((CHAR16 *) Pos) = CHAR_NULL;
|
||||
Option->Unicode.Value = Value;
|
||||
DEBUG ((OC_TRACE_PARSE_VARS, "OCB: Value=\"%s\"\n", Value));
|
||||
} else {
|
||||
*((CHAR8 *) Pos) = '\0';
|
||||
Option->Ascii.Value = Value;
|
||||
DEBUG ((OC_TRACE_PARSE_VARS, "OCB: Value=\"%a\"\n", Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
Value = NULL;
|
||||
Option = NULL;
|
||||
State = PARSE_VARS_WHITE_SPACE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT (FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (Retake) {
|
||||
Retake = FALSE;
|
||||
} else {
|
||||
Pos = (UINT8 *) Pos + (IsUnicode ? sizeof (CHAR16) : sizeof (CHAR8));
|
||||
}
|
||||
} while (Ch != CHAR_NULL);
|
||||
|
||||
if (State != PARSE_VARS_WHITE_SPACE || PushState != PARSE_VARS_WHITE_SPACE) {
|
||||
//
|
||||
// E.g. for GRUB config files this may potentially be caused by a file
|
||||
// neither we nor the user directly controls, so better warn than error.
|
||||
//
|
||||
DEBUG ((DEBUG_WARN, "OCB: Invalid vars (%u)\n", State));
|
||||
OcFlexArrayFree (ParsedVars);
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if ((*ParsedVars)->Items == NULL) {
|
||||
OcFlexArrayFree (ParsedVars);
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
OcParsedVarsGetStr (
|
||||
IN CONST OC_FLEX_ARRAY *ParsedVars,
|
||||
IN CONST VOID *Name,
|
||||
OUT VOID **Value,
|
||||
IN CONST BOOLEAN IsUnicode
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
OC_PARSED_VAR *Option;
|
||||
|
||||
ASSERT (Name != NULL);
|
||||
ASSERT (Value != NULL);
|
||||
|
||||
if (ParsedVars == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ASSERT (ParsedVars->Items != NULL);
|
||||
|
||||
for (Index = 0; Index < ParsedVars->Count; ++Index) {
|
||||
Option = OcFlexArrayItemAt (ParsedVars, Index);
|
||||
if (IsUnicode) {
|
||||
ASSERT (Option->Unicode.Name != NULL);
|
||||
if (StrCmp (Option->Unicode.Name, Name) == 0) {
|
||||
*Value = Option->Unicode.Value;
|
||||
DEBUG ((OC_TRACE_PARSE_VARS, "OCB: Using \"%s\"=\"%s\"\n", Name, *Value));
|
||||
return TRUE;
|
||||
}
|
||||
} else {
|
||||
ASSERT (Option->Ascii.Name != NULL);
|
||||
if (AsciiStrCmp (Option->Ascii.Name, Name) == 0) {
|
||||
*Value = Option->Ascii.Value;
|
||||
DEBUG ((OC_TRACE_PARSE_VARS, "OCB: Using \"%a\"=\"%a\"\n", Name, *Value));
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsUnicode) {
|
||||
DEBUG ((OC_TRACE_PARSE_VARS, "OCB: No value for \"%s\"\n", Name));
|
||||
} else {
|
||||
DEBUG ((OC_TRACE_PARSE_VARS, "OCB: No value for \"%a\"\n", Name));
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
OcParsedVarsGetUnicodeStr (
|
||||
IN CONST OC_FLEX_ARRAY *ParsedVars,
|
||||
IN CONST CHAR16 *Name,
|
||||
OUT CHAR16 **Value
|
||||
)
|
||||
{
|
||||
return OcParsedVarsGetStr (ParsedVars, Name, (VOID**)Value, TRUE);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
OcParsedVarsGetAsciiStr (
|
||||
IN CONST OC_FLEX_ARRAY *ParsedVars,
|
||||
IN CONST CHAR8 *Name,
|
||||
OUT CHAR8 **Value
|
||||
)
|
||||
{
|
||||
return OcParsedVarsGetStr (ParsedVars, Name, (VOID**)Value, FALSE);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
OcHasParsedVar (
|
||||
IN CONST OC_FLEX_ARRAY *ParsedVars,
|
||||
IN CONST VOID *Name,
|
||||
IN CONST BOOLEAN IsUnicode
|
||||
)
|
||||
{
|
||||
VOID *Value;
|
||||
|
||||
return OcParsedVarsGetStr (ParsedVars, Name, &Value, IsUnicode);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
OcParsedVarsGetInt (
|
||||
IN CONST OC_FLEX_ARRAY *ParsedVars,
|
||||
IN CONST VOID *Name,
|
||||
OUT UINTN *Value,
|
||||
IN CONST BOOLEAN IsUnicode
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
VOID *StrValue;
|
||||
|
||||
if (!OcParsedVarsGetStr (ParsedVars, Name, &StrValue, IsUnicode)) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (StrValue == NULL) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (IsUnicode){
|
||||
if (OcUnicodeStartsWith (StrValue, L"0x", TRUE)) {
|
||||
Status = StrHexToUintnS (StrValue, NULL, Value);
|
||||
} else {
|
||||
Status = StrDecimalToUintnS (StrValue, NULL, Value);
|
||||
}
|
||||
} else {
|
||||
if (OcAsciiStartsWith (StrValue, "0x", TRUE)) {
|
||||
Status = AsciiStrHexToUintnS (StrValue, NULL, Value);
|
||||
} else {
|
||||
Status = AsciiStrDecimalToUintnS (StrValue, NULL, Value);
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
OcParsedVarsGetGuid (
|
||||
IN CONST OC_FLEX_ARRAY *ParsedVars,
|
||||
IN CONST VOID *Name,
|
||||
OUT EFI_GUID *Value,
|
||||
IN CONST BOOLEAN IsUnicode
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
VOID *StrValue;
|
||||
|
||||
if (!OcParsedVarsGetStr (ParsedVars, Name, &StrValue, IsUnicode)) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (StrValue == NULL) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (IsUnicode) {
|
||||
Status = StrToGuid (StrValue, Value);
|
||||
} else {
|
||||
Status = AsciiStrToGuid (StrValue, Value);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
@ -1,18 +1,10 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, vit9696. All rights reserved.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
Copyright (C) 2019-2021, vit9696, mikebeaton. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#include "BootManagementInternal.h"
|
||||
#include "BootEntryProtocolInternal.h"
|
||||
|
||||
#include <Protocol/DevicePath.h>
|
||||
#include <Protocol/SimpleFileSystem.h>
|
||||
@ -22,6 +14,7 @@
|
||||
#include <Guid/AppleVariable.h>
|
||||
#include <Guid/FileInfo.h>
|
||||
#include <Guid/GlobalVariable.h>
|
||||
#include <Guid/Gpt.h>
|
||||
#include <Guid/OcVariable.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
@ -136,7 +129,7 @@ ExpandShortFormBootPath (
|
||||
//
|
||||
// Check whether we are allowed to boot from this filesystem.
|
||||
//
|
||||
*FileSystem = InternalFileSystemForHandle (BootContext, FileSystemHandle, LazyScan);
|
||||
*FileSystem = InternalFileSystemForHandle (BootContext, FileSystemHandle, LazyScan, NULL);
|
||||
if (*FileSystem == NULL) {
|
||||
continue;
|
||||
}
|
||||
@ -276,13 +269,14 @@ RegisterBootOption (
|
||||
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"OCB: Registering entry %s [%a] (T:%d|F:%d|G:%d|E:%d) - %s\n",
|
||||
"OCB: Registering entry %s [%a] (T:%d|F:%d|G:%d|E:%d|B:%d) - %s\n",
|
||||
BootEntry->Name,
|
||||
BootEntry->Flavour,
|
||||
BootEntry->Type,
|
||||
BootEntry->IsFolder,
|
||||
BootEntry->IsGeneric,
|
||||
BootEntry->IsExternal,
|
||||
BootEntry->IsBootEntryProtocol,
|
||||
OC_HUMAN_STRING (TextDevicePath)
|
||||
));
|
||||
|
||||
@ -507,6 +501,51 @@ AddBootEntryOnFileSystem (
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Release boot entry contents allocated from pool.
|
||||
|
||||
@param[in,out] BootEntry Located boot entry.
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
FreeBootEntry (
|
||||
IN OC_BOOT_ENTRY *BootEntry
|
||||
)
|
||||
{
|
||||
if (BootEntry->DevicePath != NULL) {
|
||||
FreePool (BootEntry->DevicePath);
|
||||
BootEntry->DevicePath = NULL;
|
||||
}
|
||||
|
||||
if (BootEntry->Id != NULL) {
|
||||
FreePool (BootEntry->Id);
|
||||
BootEntry->Id = NULL;
|
||||
}
|
||||
|
||||
if (BootEntry->Name != NULL) {
|
||||
FreePool (BootEntry->Name);
|
||||
BootEntry->Name = NULL;
|
||||
}
|
||||
|
||||
if (BootEntry->PathName != NULL) {
|
||||
FreePool (BootEntry->PathName);
|
||||
BootEntry->PathName = NULL;
|
||||
}
|
||||
|
||||
if (BootEntry->LoadOptions != NULL) {
|
||||
FreePool (BootEntry->LoadOptions);
|
||||
BootEntry->LoadOptions = NULL;
|
||||
BootEntry->LoadOptionsSize = 0;
|
||||
}
|
||||
|
||||
if (BootEntry->Flavour != NULL) {
|
||||
FreePool (BootEntry->Flavour);
|
||||
BootEntry->Flavour = NULL;
|
||||
}
|
||||
|
||||
FreePool (BootEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
Create bootable entry from custom entry.
|
||||
|
||||
@ -516,12 +555,12 @@ AddBootEntryOnFileSystem (
|
||||
|
||||
@retval EFI_SUCCESS on success.
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
AddBootEntryFromCustomEntry (
|
||||
InternalAddBootEntryFromCustomEntry (
|
||||
IN OUT OC_BOOT_CONTEXT *BootContext,
|
||||
IN OUT OC_BOOT_FILESYSTEM *FileSystem,
|
||||
IN OC_PICKER_ENTRY *CustomEntry
|
||||
IN OC_PICKER_ENTRY *CustomEntry,
|
||||
IN BOOLEAN IsBootEntryProtocol
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
@ -532,8 +571,17 @@ AddBootEntryFromCustomEntry (
|
||||
CHAR16 *BootDirectoryName;
|
||||
EFI_HANDLE Device;
|
||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
|
||||
CONST EFI_PARTITION_ENTRY *PartitionEntry;
|
||||
|
||||
if (CustomEntry->Auxiliary && BootContext->PickerContext->HideAuxiliary) {
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"OCB: Not adding hidden auxiliary entry %a (%a|B:%d) -> %a\n",
|
||||
CustomEntry->Name,
|
||||
CustomEntry->Tool ? "tool" : "os",
|
||||
IsBootEntryProtocol,
|
||||
CustomEntry->Path
|
||||
));
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
@ -545,32 +593,38 @@ AddBootEntryFromCustomEntry (
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
if (CustomEntry->Id != NULL) {
|
||||
BootEntry->Id = AsciiStrCopyToUnicode (CustomEntry->Id, 0);
|
||||
if (BootEntry->Id == NULL) {
|
||||
FreeBootEntry (BootEntry);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
BootEntry->Name = AsciiStrCopyToUnicode (CustomEntry->Name, 0);
|
||||
if (BootEntry->Name == NULL) {
|
||||
FreePool (BootEntry);
|
||||
FreeBootEntry (BootEntry);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
PathName = AsciiStrCopyToUnicode (CustomEntry->Path, 0);
|
||||
if (PathName == NULL) {
|
||||
FreePool (BootEntry->Name);
|
||||
FreePool (BootEntry);
|
||||
FreeBootEntry (BootEntry);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
BootEntry->Flavour = AllocateCopyPool (AsciiStrSize (CustomEntry->Flavour), CustomEntry->Flavour);
|
||||
if (BootEntry->Flavour == NULL) {
|
||||
FreePool (PathName);
|
||||
FreePool (BootEntry->Name);
|
||||
FreePool (BootEntry);
|
||||
FreeBootEntry (BootEntry);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"OCB: Adding custom entry %s (%a) -> %a\n",
|
||||
"OCB: Adding custom entry %s (%a|B:%d) -> %a\n",
|
||||
BootEntry->Name,
|
||||
CustomEntry->Tool ? "tool" : "os",
|
||||
IsBootEntryProtocol,
|
||||
CustomEntry->Path
|
||||
));
|
||||
|
||||
@ -581,12 +635,19 @@ AddBootEntryFromCustomEntry (
|
||||
} else {
|
||||
BootEntry->Type = OC_BOOT_EXTERNAL_OS;
|
||||
|
||||
BootEntry->DevicePath = ConvertTextToDevicePath (PathName);
|
||||
//
|
||||
// For boot entry protocol path is relative to device root,
|
||||
// for user entry path is absolute device path.
|
||||
//
|
||||
if (IsBootEntryProtocol) {
|
||||
UnicodeUefiSlashes (PathName);
|
||||
BootEntry->DevicePath = FileDevicePath (FileSystem->Handle, PathName);
|
||||
} else {
|
||||
BootEntry->DevicePath = ConvertTextToDevicePath (PathName);
|
||||
}
|
||||
FreePool (PathName);
|
||||
if (BootEntry->DevicePath == NULL) {
|
||||
FreePool (BootEntry->Flavour);
|
||||
FreePool (BootEntry->Name);
|
||||
FreePool (BootEntry);
|
||||
FreeBootEntry (BootEntry);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
@ -598,10 +659,7 @@ AddBootEntryFromCustomEntry (
|
||||
)
|
||||
);
|
||||
if (FilePath == NULL) {
|
||||
FreePool (BootEntry->Flavour);
|
||||
FreePool (BootEntry->Name);
|
||||
FreePool (BootEntry->DevicePath);
|
||||
FreePool (BootEntry);
|
||||
FreeBootEntry (BootEntry);
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
@ -610,10 +668,7 @@ AddBootEntryFromCustomEntry (
|
||||
FilePath->PathName
|
||||
);
|
||||
if (BootEntry->PathName == NULL) {
|
||||
FreePool (BootEntry->Flavour);
|
||||
FreePool (BootEntry->Name);
|
||||
FreePool (BootEntry->DevicePath);
|
||||
FreePool (BootEntry);
|
||||
FreeBootEntry (BootEntry);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
@ -663,6 +718,15 @@ AddBootEntryFromCustomEntry (
|
||||
}
|
||||
|
||||
BootEntry->IsCustom = TRUE;
|
||||
BootEntry->IsBootEntryProtocol = IsBootEntryProtocol;
|
||||
if (IsBootEntryProtocol) {
|
||||
PartitionEntry = OcGetGptPartitionEntry (FileSystem->Handle);
|
||||
if (PartitionEntry == NULL) {
|
||||
BootEntry->UniquePartitionGUID = gEfiPartTypeUnusedGuid;
|
||||
} else {
|
||||
BootEntry->UniquePartitionGUID = PartitionEntry->UniquePartitionGUID;
|
||||
}
|
||||
}
|
||||
|
||||
RegisterBootOption (
|
||||
BootContext,
|
||||
@ -953,7 +1017,7 @@ AddBootEntryFromBless (
|
||||
// Obtain recovery file system and ensure scan policy if it was not done before.
|
||||
//
|
||||
if (FileSystem->RecoveryFs == NULL) {
|
||||
FileSystem->RecoveryFs = InternalFileSystemForHandle (BootContext, RecoveryDeviceHandle, LazyScan);
|
||||
FileSystem->RecoveryFs = InternalFileSystemForHandle (BootContext, RecoveryDeviceHandle, LazyScan, NULL);
|
||||
}
|
||||
|
||||
//
|
||||
@ -1047,9 +1111,18 @@ AddBootEntryFromSelfRecovery (
|
||||
/**
|
||||
Create bootable entries from boot options.
|
||||
|
||||
@param[in,out] BootContext Context of filesystems.
|
||||
@param[in] BootOption Boot option number.
|
||||
@param[in] LazyScan Lazy filesystem scanning.
|
||||
@param[in,out] BootContext Context of filesystems.
|
||||
@param[in] BootOption Boot option number.
|
||||
@param[in] LazyScan Lazy filesystem scanning.
|
||||
@param[in,out] CustomFileSystem File system on which to add user defined custom option.
|
||||
If non-NULL still searching for first (normally only) OC
|
||||
custom entry, either user defined or entry protocol.
|
||||
@param[out] CustomIndex Index of custom user defined entry, if matched.
|
||||
@param[in] EntryProtocolHandles Installed Boot Entry Protocol handles.
|
||||
@param[in] EntryProtocolHandleCount Installed Boot Entry Protocol handle count.
|
||||
@param[out] EntryProtocolPartuuid Unique partition UUID of parition with entry protocol
|
||||
custom entry, if matched.
|
||||
@param[out] EntryProtocolId Id of entry protocol custom entry, if matched.
|
||||
|
||||
@retval EFI_SUCCESS if at least one option was added.
|
||||
**/
|
||||
@ -1060,7 +1133,11 @@ AddBootEntryFromBootOption (
|
||||
IN UINT16 BootOption,
|
||||
IN BOOLEAN LazyScan,
|
||||
IN OUT OC_BOOT_FILESYSTEM *CustomFileSystem,
|
||||
IN OUT UINT32 *CustomIndex
|
||||
OUT UINT32 *CustomIndex, OPTIONAL
|
||||
IN EFI_HANDLE *EntryProtocolHandles,
|
||||
IN UINTN EntryProtocolHandleCount,
|
||||
OUT EFI_GUID *EntryProtocolPartuuid, OPTIONAL
|
||||
OUT CHAR16 **EntryProtocolId OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
@ -1075,10 +1152,13 @@ AddBootEntryFromBootOption (
|
||||
BOOLEAN IsRoot;
|
||||
EFI_LOAD_OPTION *LoadOption;
|
||||
UINTN LoadOptionSize;
|
||||
LIST_ENTRY *Link;
|
||||
UINT32 Index;
|
||||
INTN CmpResult;
|
||||
|
||||
CONST OC_CUSTOM_BOOT_DEVICE_PATH *CustomDevPath;
|
||||
UINT32 Index;
|
||||
INTN CmpResult;
|
||||
CONST EFI_PARTITION_ENTRY *PartitionEntry;
|
||||
CONST OC_CUSTOM_BOOT_DEVICE_PATH *CustomDevPath;
|
||||
CONST OC_ENTRY_PROTOCOL_DEVICE_PATH *EntryProtocolDevPath;
|
||||
|
||||
DEBUG ((DEBUG_INFO, "OCB: Building entry from Boot%04x\n", BootOption));
|
||||
|
||||
@ -1186,7 +1266,7 @@ AddBootEntryFromBootOption (
|
||||
// Ensure that we are allowed to boot from this filesystem.
|
||||
//
|
||||
if (DevicePath != NULL) {
|
||||
FileSystem = InternalFileSystemForHandle (BootContext, FileSystemHandle, LazyScan);
|
||||
FileSystem = InternalFileSystemForHandle (BootContext, FileSystemHandle, LazyScan, NULL);
|
||||
if (FileSystem == NULL) {
|
||||
DevicePath = NULL;
|
||||
}
|
||||
@ -1247,28 +1327,87 @@ AddBootEntryFromBootOption (
|
||||
NULL
|
||||
);
|
||||
} while (NumPatchedNodes > 0);
|
||||
//
|
||||
// If requested, pre-construct a custom entry found in BOOT#### so it can be
|
||||
// set as default.
|
||||
//
|
||||
|
||||
if (ExpandedDevicePath == NULL && CustomFileSystem != NULL) {
|
||||
ASSERT (CustomIndex != NULL);
|
||||
//
|
||||
// If non-standard device path, attempt to pre-construct a user config
|
||||
// custom entry found in BOOT#### so it can be set as default.
|
||||
//
|
||||
ASSERT (CustomIndex == NULL || *CustomIndex == MAX_UINT32);
|
||||
|
||||
CustomDevPath = InternalGetOcCustomDevPath (DevicePath);
|
||||
|
||||
for (Index = 0; Index < BootContext->PickerContext->AllCustomEntryCount; ++Index) {
|
||||
CmpResult = MixedStrCmp (
|
||||
CustomDevPath->EntryName.PathName,
|
||||
BootContext->PickerContext->CustomEntries[Index].Name
|
||||
);
|
||||
if (CmpResult == 0) {
|
||||
*CustomIndex = Index;
|
||||
AddBootEntryFromCustomEntry (
|
||||
BootContext,
|
||||
CustomFileSystem,
|
||||
&BootContext->PickerContext->CustomEntries[Index]
|
||||
if (CustomDevPath != NULL) {
|
||||
for (Index = 0; Index < BootContext->PickerContext->AllCustomEntryCount; ++Index) {
|
||||
CmpResult = MixedStrCmp (
|
||||
CustomDevPath->EntryName.PathName,
|
||||
BootContext->PickerContext->CustomEntries[Index].Name
|
||||
);
|
||||
break;
|
||||
if (CmpResult == 0) {
|
||||
if (CustomIndex != NULL) {
|
||||
*CustomIndex = Index;
|
||||
}
|
||||
InternalAddBootEntryFromCustomEntry (
|
||||
BootContext,
|
||||
CustomFileSystem,
|
||||
&BootContext->PickerContext->CustomEntries[Index],
|
||||
FALSE
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// If still unknown device path, attempt to pre-construct an entry protocol
|
||||
// entry found in BOOT#### so it can be set as default.
|
||||
//
|
||||
ASSERT (EntryProtocolId == NULL || *EntryProtocolId == NULL);
|
||||
ASSERT ((EntryProtocolPartuuid == NULL) == (EntryProtocolId == NULL));
|
||||
|
||||
EntryProtocolDevPath = InternalGetOcEntryProtocolDevPath (DevicePath);
|
||||
|
||||
if (EntryProtocolDevPath != NULL) {
|
||||
for (
|
||||
Link = GetFirstNode (&BootContext->FileSystems);
|
||||
!IsNull (&BootContext->FileSystems, Link);
|
||||
Link = GetNextNode (&BootContext->FileSystems, Link)) {
|
||||
FileSystem = BASE_CR (Link, OC_BOOT_FILESYSTEM, Link);
|
||||
|
||||
//
|
||||
// Search for ID on matching device only.
|
||||
// Note that on, e.g., OVMF, every single device has partition UUID 00000000-0000-0000-0000000000000000,
|
||||
// therefore the first matching entry protocol ID on *any* filesystem will match.
|
||||
//
|
||||
PartitionEntry = OcGetGptPartitionEntry (FileSystem->Handle);
|
||||
if (PartitionEntry == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (CompareMem (
|
||||
&PartitionEntry->UniquePartitionGUID,
|
||||
&EntryProtocolDevPath->Partuuid,
|
||||
sizeof (EFI_GUID)) == 0) {
|
||||
Status = AddEntriesFromBootEntryProtocol (
|
||||
BootContext,
|
||||
FileSystem,
|
||||
EntryProtocolHandles,
|
||||
EntryProtocolHandleCount,
|
||||
EntryProtocolDevPath->EntryName.PathName,
|
||||
TRUE
|
||||
);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
if (EntryProtocolPartuuid != NULL) {
|
||||
*EntryProtocolPartuuid = PartitionEntry->UniquePartitionGUID;
|
||||
}
|
||||
if (EntryProtocolId != NULL) {
|
||||
*EntryProtocolId = AllocateCopyPool (StrSize (EntryProtocolDevPath->EntryName.PathName), EntryProtocolDevPath->EntryName.PathName);
|
||||
//
|
||||
// If NULL allocated, just continue as if we had not matched.
|
||||
//
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1366,46 +1505,6 @@ AddBootEntryFromBootOption (
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Release boot entry contents allocated from pool.
|
||||
|
||||
@param[in,out] BootEntry Located boot entry.
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
FreeBootEntry (
|
||||
IN OC_BOOT_ENTRY *BootEntry
|
||||
)
|
||||
{
|
||||
if (BootEntry->DevicePath != NULL) {
|
||||
FreePool (BootEntry->DevicePath);
|
||||
BootEntry->DevicePath = NULL;
|
||||
}
|
||||
|
||||
if (BootEntry->Name != NULL) {
|
||||
FreePool (BootEntry->Name);
|
||||
BootEntry->Name = NULL;
|
||||
}
|
||||
|
||||
if (BootEntry->PathName != NULL) {
|
||||
FreePool (BootEntry->PathName);
|
||||
BootEntry->PathName = NULL;
|
||||
}
|
||||
|
||||
if (BootEntry->LoadOptions != NULL) {
|
||||
FreePool (BootEntry->LoadOptions);
|
||||
BootEntry->LoadOptions = NULL;
|
||||
BootEntry->LoadOptionsSize = 0;
|
||||
}
|
||||
|
||||
if (BootEntry->Flavour != NULL) {
|
||||
FreePool (BootEntry->Flavour);
|
||||
BootEntry->Flavour = NULL;
|
||||
}
|
||||
|
||||
FreePool (BootEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
Allocate a new filesystem entry in boot entries
|
||||
in case it can be used according to current ScanPolicy.
|
||||
@ -1549,10 +1648,11 @@ AddFileSystemEntryForCustom (
|
||||
continue;
|
||||
}
|
||||
|
||||
Status = AddBootEntryFromCustomEntry (
|
||||
Status = InternalAddBootEntryFromCustomEntry (
|
||||
BootContext,
|
||||
FileSystem,
|
||||
&BootContext->PickerContext->CustomEntries[Index]
|
||||
&BootContext->PickerContext->CustomEntries[Index],
|
||||
FALSE
|
||||
);
|
||||
|
||||
if (!EFI_ERROR (Status)) {
|
||||
@ -1621,14 +1721,19 @@ FreeFileSystemEntry (
|
||||
|
||||
OC_BOOT_FILESYSTEM *
|
||||
InternalFileSystemForHandle (
|
||||
IN OC_BOOT_CONTEXT *BootContext,
|
||||
IN EFI_HANDLE FileSystemHandle,
|
||||
IN BOOLEAN LazyScan
|
||||
IN OC_BOOT_CONTEXT *BootContext,
|
||||
IN EFI_HANDLE FileSystemHandle,
|
||||
IN BOOLEAN LazyScan,
|
||||
OUT BOOLEAN *AlreadySeen OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
LIST_ENTRY *Link;
|
||||
OC_BOOT_FILESYSTEM *FileSystem;
|
||||
OC_BOOT_FILESYSTEM *FileSystem;
|
||||
|
||||
if (AlreadySeen != NULL) {
|
||||
*AlreadySeen = FALSE;
|
||||
}
|
||||
|
||||
for (
|
||||
Link = GetFirstNode (&BootContext->FileSystems);
|
||||
@ -1638,6 +1743,9 @@ InternalFileSystemForHandle (
|
||||
|
||||
if (FileSystem->Handle == FileSystemHandle) {
|
||||
DEBUG ((DEBUG_INFO, "OCB: Matched fs %p%a\n", FileSystemHandle, LazyScan ? " (lazy)" : ""));
|
||||
if (AlreadySeen != NULL) {
|
||||
*AlreadySeen = TRUE;
|
||||
}
|
||||
return FileSystem;
|
||||
}
|
||||
}
|
||||
@ -1824,6 +1932,11 @@ OcScanForBootEntries (
|
||||
OC_BOOT_FILESYSTEM *CustomFileSystem;
|
||||
OC_BOOT_FILESYSTEM *CustomFileSystemDefault;
|
||||
UINT32 DefaultCustomIndex;
|
||||
EFI_GUID DefaultEntryProtocolPartuuid;
|
||||
CHAR16 *DefaultEntryProtocolId;
|
||||
EFI_HANDLE *EntryProtocolHandles;
|
||||
UINTN EntryProtocolHandleCount;
|
||||
CONST EFI_PARTITION_ENTRY *PartitionEntry;
|
||||
|
||||
//
|
||||
// Obtain the list of filesystems filtered by scan policy.
|
||||
@ -1838,6 +1951,11 @@ OcScanForBootEntries (
|
||||
|
||||
DEBUG ((DEBUG_INFO, "OCB: Found %u potentially bootable filesystems\n", (UINT32) BootContext->FileSystemCount));
|
||||
|
||||
//
|
||||
// Locate loaded boot entry protocol drivers.
|
||||
//
|
||||
LocateBootEntryProtocolHandles (&EntryProtocolHandles, &EntryProtocolHandleCount);
|
||||
|
||||
//
|
||||
// Create primary boot options from BootOrder.
|
||||
//
|
||||
@ -1855,7 +1973,8 @@ OcScanForBootEntries (
|
||||
// Delay CustomFileSystem insertion to have custom entries at the end.
|
||||
//
|
||||
|
||||
DefaultCustomIndex = MAX_UINT32;
|
||||
DefaultCustomIndex = MAX_UINT32;
|
||||
DefaultEntryProtocolId = NULL;
|
||||
|
||||
if (Context->BootOrder != NULL) {
|
||||
CustomFileSystemDefault = CustomFileSystem;
|
||||
@ -1866,14 +1985,18 @@ OcScanForBootEntries (
|
||||
Context->BootOrder[Index],
|
||||
FALSE,
|
||||
CustomFileSystemDefault,
|
||||
&DefaultCustomIndex
|
||||
&DefaultCustomIndex,
|
||||
EntryProtocolHandles,
|
||||
EntryProtocolHandleCount,
|
||||
&DefaultEntryProtocolPartuuid,
|
||||
&DefaultEntryProtocolId
|
||||
);
|
||||
|
||||
//
|
||||
// Pre-create at most one custom entry. Under normal circumstances, no
|
||||
// more than one entry should exist anyway.
|
||||
//
|
||||
if (DefaultCustomIndex != MAX_UINT32) {
|
||||
if (DefaultCustomIndex != MAX_UINT32 || DefaultEntryProtocolId != NULL) {
|
||||
CustomFileSystemDefault = NULL;
|
||||
}
|
||||
}
|
||||
@ -1905,12 +2028,37 @@ OcScanForBootEntries (
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Try boot entry protocol.
|
||||
// Entry protocol entries should almost certainly be added regardless
|
||||
// of bless; e.g. user might well have /loader/entries in ESP, in addition
|
||||
// to normal blessed files.
|
||||
//
|
||||
PartitionEntry = OcGetGptPartitionEntry (FileSystem->Handle);
|
||||
if (PartitionEntry != NULL) {
|
||||
AddEntriesFromBootEntryProtocol (
|
||||
BootContext,
|
||||
FileSystem,
|
||||
EntryProtocolHandles,
|
||||
EntryProtocolHandleCount,
|
||||
CompareMem (&DefaultEntryProtocolPartuuid, &PartitionEntry->UniquePartitionGUID, sizeof (EFI_GUID)) == 0 ?
|
||||
DefaultEntryProtocolId :
|
||||
NULL,
|
||||
FALSE
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Record predefined recoveries.
|
||||
//
|
||||
AddBootEntryFromSelfRecovery (BootContext, FileSystem);
|
||||
}
|
||||
|
||||
if (DefaultEntryProtocolId != NULL) {
|
||||
FreePool (DefaultEntryProtocolId);
|
||||
DefaultEntryProtocolId = NULL;
|
||||
}
|
||||
|
||||
if (CustomFileSystem != NULL) {
|
||||
//
|
||||
// Insert the custom file system last for entry order.
|
||||
@ -1922,8 +2070,22 @@ OcScanForBootEntries (
|
||||
// Build custom and system options.
|
||||
//
|
||||
AddFileSystemEntryForCustom (BootContext, CustomFileSystem, DefaultCustomIndex);
|
||||
|
||||
//
|
||||
// Boot entry protocol also supports custom and system entries.
|
||||
//
|
||||
AddEntriesFromBootEntryProtocol (
|
||||
BootContext,
|
||||
CustomFileSystem,
|
||||
EntryProtocolHandles,
|
||||
EntryProtocolHandleCount,
|
||||
NULL,
|
||||
FALSE
|
||||
);
|
||||
}
|
||||
|
||||
FreeBootEntryProtocolHandles (&EntryProtocolHandles);
|
||||
|
||||
if (BootContext->BootEntryCount == 0) {
|
||||
OcFreeBootContext (BootContext);
|
||||
return NULL;
|
||||
@ -1947,11 +2109,13 @@ OcScanForDefaultBootEntry (
|
||||
OC_BOOT_CONTEXT *BootContext;
|
||||
UINTN Index;
|
||||
OC_BOOT_FILESYSTEM *FileSystem;
|
||||
BOOLEAN AlreadySeen;
|
||||
EFI_STATUS Status;
|
||||
UINTN NoHandles;
|
||||
EFI_HANDLE *Handles;
|
||||
UINT32 DefaultCustomIndex;
|
||||
OC_BOOT_FILESYSTEM *CustomFileSystem;
|
||||
EFI_HANDLE *EntryProtocolHandles;
|
||||
UINTN EntryProtocolHandleCount;
|
||||
|
||||
//
|
||||
// Obtain empty list of filesystems.
|
||||
@ -1963,6 +2127,11 @@ OcScanForDefaultBootEntry (
|
||||
|
||||
DEBUG ((DEBUG_INFO, "OCB: Looking up for default entry\n"));
|
||||
|
||||
//
|
||||
// Locate loaded boot entry protocol drivers.
|
||||
//
|
||||
LocateBootEntryProtocolHandles (&EntryProtocolHandles, &EntryProtocolHandleCount);
|
||||
|
||||
//
|
||||
// Create primary boot options from BootOrder.
|
||||
//
|
||||
@ -1986,20 +2155,26 @@ OcScanForDefaultBootEntry (
|
||||
if (Context->BootOrder != NULL) {
|
||||
for (Index = 0; Index < Context->BootOrderCount; ++Index) {
|
||||
//
|
||||
// DefaultCustomIndex is not used as the entry list will never be shown.
|
||||
// Returned default entry values not required, as no other
|
||||
// entries will be created after a match here.
|
||||
//
|
||||
AddBootEntryFromBootOption (
|
||||
BootContext,
|
||||
Context->BootOrder[Index],
|
||||
TRUE,
|
||||
CustomFileSystem,
|
||||
&DefaultCustomIndex
|
||||
NULL,
|
||||
EntryProtocolHandles,
|
||||
EntryProtocolHandleCount,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
|
||||
//
|
||||
// Return as long as we are good.
|
||||
//
|
||||
if (BootContext->DefaultEntry != NULL) {
|
||||
FreeBootEntryProtocolHandles (&EntryProtocolHandles);
|
||||
return BootContext;
|
||||
}
|
||||
}
|
||||
@ -2022,36 +2197,50 @@ OcScanForDefaultBootEntry (
|
||||
if (!EFI_ERROR (Status)) {
|
||||
for (Index = 0; Index < NoHandles; ++Index) {
|
||||
//
|
||||
// Do not add filesystems twice.
|
||||
// If file system has been seen during BOOT#### entry processing then
|
||||
// bless has already been processed (and failed or we would not be here).
|
||||
//
|
||||
if (InternalFileSystemForHandle (BootContext, Handles[Index], FALSE) != NULL) {
|
||||
FileSystem = InternalFileSystemForHandle (BootContext, Handles[Index], TRUE, &AlreadySeen);
|
||||
if (FileSystem == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Status = AddFileSystemEntry (
|
||||
BootContext,
|
||||
Handles[Index],
|
||||
&FileSystem
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
continue;
|
||||
if (!AlreadySeen) {
|
||||
AddBootEntryFromBless (
|
||||
BootContext,
|
||||
FileSystem,
|
||||
gAppleBootPolicyPredefinedPaths,
|
||||
gAppleBootPolicyNumPredefinedPaths,
|
||||
FALSE,
|
||||
FALSE
|
||||
);
|
||||
if (BootContext->DefaultEntry != NULL) {
|
||||
FreeBootEntryProtocolHandles (&EntryProtocolHandles);
|
||||
FreePool (Handles);
|
||||
return BootContext;
|
||||
}
|
||||
}
|
||||
|
||||
AddBootEntryFromBless (
|
||||
//
|
||||
// Try boot entry protocol. No need to deduplicate as won't reach
|
||||
// here if default entry from BOOT#### was successfully created.
|
||||
//
|
||||
AddEntriesFromBootEntryProtocol (
|
||||
BootContext,
|
||||
FileSystem,
|
||||
gAppleBootPolicyPredefinedPaths,
|
||||
gAppleBootPolicyNumPredefinedPaths,
|
||||
FALSE,
|
||||
EntryProtocolHandles,
|
||||
EntryProtocolHandleCount,
|
||||
NULL,
|
||||
FALSE
|
||||
);
|
||||
if (BootContext->DefaultEntry != NULL) {
|
||||
FreeBootEntryProtocolHandles (&EntryProtocolHandles);
|
||||
FreePool (Handles);
|
||||
return BootContext;
|
||||
}
|
||||
|
||||
AddBootEntryFromSelfRecovery (BootContext, FileSystem);
|
||||
if (BootContext->DefaultEntry != NULL) {
|
||||
FreeBootEntryProtocolHandles (&EntryProtocolHandles);
|
||||
FreePool (Handles);
|
||||
return BootContext;
|
||||
}
|
||||
@ -2066,6 +2255,24 @@ OcScanForDefaultBootEntry (
|
||||
// as the list is never shown.
|
||||
//
|
||||
AddFileSystemEntryForCustom (BootContext, CustomFileSystem, MAX_UINT32);
|
||||
if (BootContext->DefaultEntry != NULL) {
|
||||
FreeBootEntryProtocolHandles (&EntryProtocolHandles);
|
||||
return BootContext;
|
||||
}
|
||||
|
||||
//
|
||||
// Boot entry protocol for custom and system entries.
|
||||
//
|
||||
AddEntriesFromBootEntryProtocol (
|
||||
BootContext,
|
||||
CustomFileSystem,
|
||||
EntryProtocolHandles,
|
||||
EntryProtocolHandleCount,
|
||||
NULL,
|
||||
FALSE
|
||||
);
|
||||
|
||||
FreeBootEntryProtocolHandles (&EntryProtocolHandles);
|
||||
}
|
||||
|
||||
if (BootContext->DefaultEntry == NULL) {
|
||||
|
||||
199
Library/OcBootManagementLib/BootEntryProtocol.c
Normal file
199
Library/OcBootManagementLib/BootEntryProtocol.c
Normal file
@ -0,0 +1,199 @@
|
||||
/** @file
|
||||
Boot Entry Protocol.
|
||||
|
||||
Copyright (c) 2021, Mike Beaton. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#include "BootEntryProtocolInternal.h"
|
||||
#include "BootManagementInternal.h"
|
||||
|
||||
#include <Protocol/OcBootEntry.h>
|
||||
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcFileLib.h>
|
||||
#include <Library/OcDebugLogLib.h>
|
||||
|
||||
VOID
|
||||
LocateBootEntryProtocolHandles (
|
||||
IN OUT EFI_HANDLE **EntryProtocolHandles,
|
||||
IN OUT UINTN *EntryProtocolHandleCount
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = gBS->LocateHandleBuffer (
|
||||
ByProtocol,
|
||||
&gOcBootEntryProtocolGuid,
|
||||
NULL,
|
||||
EntryProtocolHandleCount,
|
||||
EntryProtocolHandles
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
//
|
||||
// No loaded drivers is fine
|
||||
//
|
||||
if (Status != EFI_NOT_FOUND) {
|
||||
DEBUG ((DEBUG_ERROR, "BEP: Error locating driver handles - %r\n", Status));
|
||||
}
|
||||
|
||||
*EntryProtocolHandleCount = 0;
|
||||
*EntryProtocolHandles = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
FreeBootEntryProtocolHandles (
|
||||
EFI_HANDLE **EntryProtocolHandles
|
||||
)
|
||||
{
|
||||
if (*EntryProtocolHandles == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
FreePool (*EntryProtocolHandles);
|
||||
*EntryProtocolHandles = NULL;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
AddEntriesFromBootEntryProtocol (
|
||||
IN OUT OC_BOOT_CONTEXT *BootContext,
|
||||
IN OUT OC_BOOT_FILESYSTEM *FileSystem,
|
||||
IN EFI_HANDLE *EntryProtocolHandles,
|
||||
IN UINTN EntryProtocolHandleCount,
|
||||
IN CONST CHAR16 *DefaultEntryId, OPTIONAL
|
||||
IN CONST BOOLEAN CreateDefault
|
||||
)
|
||||
{
|
||||
EFI_STATUS ReturnStatus;
|
||||
EFI_STATUS Status;
|
||||
UINTN Index;
|
||||
UINTN EntryIndex;
|
||||
OC_BOOT_ENTRY_PROTOCOL *BootEntryProtocol;
|
||||
OC_PICKER_ENTRY *Entries;
|
||||
UINTN NumEntries;
|
||||
|
||||
DEBUG_CODE_BEGIN ();
|
||||
if (CreateDefault) {
|
||||
ASSERT ((DefaultEntryId != NULL));
|
||||
}
|
||||
DEBUG_CODE_END ();
|
||||
|
||||
ReturnStatus = EFI_NOT_FOUND;
|
||||
|
||||
for (Index = 0; Index < EntryProtocolHandleCount; ++Index) {
|
||||
//
|
||||
// Previously marked as invalid protocol revision.
|
||||
//
|
||||
if (EntryProtocolHandles[Index] == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Status = gBS->HandleProtocol (
|
||||
EntryProtocolHandles[Index],
|
||||
&gOcBootEntryProtocolGuid,
|
||||
(VOID **) &BootEntryProtocol
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR, "BEP: HandleProtocol failed - %r\n", Status));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (BootEntryProtocol->Revision != OC_BOOT_ENTRY_PROTOCOL_REVISION) {
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"BEP: Invalid revision %u (!= %u) in loaded driver\n",
|
||||
BootEntryProtocol->Revision,
|
||||
OC_BOOT_ENTRY_PROTOCOL_REVISION
|
||||
));
|
||||
EntryProtocolHandles[Index] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
Status = BootEntryProtocol->GetBootEntries (
|
||||
BootContext->PickerContext,
|
||||
FileSystem->Handle == OC_CUSTOM_FS_HANDLE ? NULL : FileSystem->Handle,
|
||||
&Entries,
|
||||
&NumEntries
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
//
|
||||
// No entries for any given driver on any given filesystem is normal.
|
||||
//
|
||||
if (Status != EFI_NOT_FOUND) {
|
||||
DEBUG ((DEBUG_WARN, "BEP: Unable to fetch boot entries - %r\n", Status));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
for (EntryIndex = 0; EntryIndex < NumEntries; EntryIndex++) {
|
||||
if (Entries[EntryIndex].Id == NULL) {
|
||||
DEBUG ((DEBUG_WARN, "BEP: Entry->Id is required, ignoring entry.\n"));
|
||||
}
|
||||
if (DefaultEntryId == NULL ||
|
||||
(MixedStrCmp (DefaultEntryId, Entries[EntryIndex].Id) == 0) == CreateDefault) {
|
||||
Status = InternalAddBootEntryFromCustomEntry (
|
||||
BootContext,
|
||||
FileSystem,
|
||||
&Entries[EntryIndex],
|
||||
TRUE
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
//
|
||||
// EFI_UNSUPPORTED is auxiliary entry when HideAuxiliary=true.
|
||||
//
|
||||
if (Status != EFI_UNSUPPORTED) {
|
||||
DEBUG ((DEBUG_WARN, "BEP: Error adding entries - %r\n", Status));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ReturnStatus = EFI_SUCCESS;
|
||||
|
||||
//
|
||||
// Stop searching after first match for default entry. Possible additional
|
||||
// matches, e.g. older versions of Linux kernel, are normal.
|
||||
//
|
||||
if (CreateDefault) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// Create remaining matches after skipping first match for pre-created entry.
|
||||
//
|
||||
if (!CreateDefault) {
|
||||
DefaultEntryId = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BootEntryProtocol->FreeBootEntries (
|
||||
&Entries,
|
||||
NumEntries
|
||||
);
|
||||
|
||||
//
|
||||
// If not found, keep hunting for default entry on other installed drivers.
|
||||
//
|
||||
if (CreateDefault) {
|
||||
if (ReturnStatus == EFI_NOT_FOUND) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// On other error adding entry (should not fail), abort.
|
||||
//
|
||||
if (EFI_ERROR (Status) && Status != EFI_UNSUPPORTED) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ReturnStatus;
|
||||
}
|
||||
56
Library/OcBootManagementLib/BootEntryProtocolInternal.h
Normal file
56
Library/OcBootManagementLib/BootEntryProtocolInternal.h
Normal file
@ -0,0 +1,56 @@
|
||||
/** @file
|
||||
Copyright (C) 2021, Mike Beaton. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#ifndef BOOT_ENTRY_PROTOCOL_INTERNAL_H
|
||||
#define BOOT_ENTRY_PROTOCOL_INTERNAL_H
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/OcBootManagementLib.h>
|
||||
|
||||
/**
|
||||
Locate boot entry protocol handles.
|
||||
|
||||
@param[in,out] EntryProtocolHandles Boot entry protocol handles, or NULL if none.
|
||||
@param[in,out] EntryProtocolHandleCount Count of boot entry protocol handles.
|
||||
**/
|
||||
VOID
|
||||
LocateBootEntryProtocolHandles (
|
||||
IN OUT EFI_HANDLE **EntryProtocolHandles,
|
||||
IN OUT UINTN *EntryProtocolHandleCount
|
||||
);
|
||||
|
||||
/**
|
||||
Free boot entry protocol handles.
|
||||
|
||||
@param[in,out] EntryProtocolHandles Boot entry protocol handles, or NULL if none.
|
||||
**/
|
||||
VOID
|
||||
FreeBootEntryProtocolHandles (
|
||||
EFI_HANDLE **EntryProtocolHandles
|
||||
);
|
||||
|
||||
/**
|
||||
Request bootable entries from installed boot entry protocol drivers.
|
||||
|
||||
@param[in,out] BootContext Context of filesystems.
|
||||
@param[in,out] FileSystem Filesystem to scan for entries.
|
||||
@param[in] EntryProtocolHandles Boot entry protocol handles, or NULL if none.
|
||||
@param[in] EntryProtocolHandleCount Count of boot entry protocol handles.
|
||||
@param[in] DefaultEntryId Id of saved default entry on this file system.
|
||||
@param[in] CreateDefault Create default entry if TRUE, create all others otherwise.
|
||||
|
||||
@retval EFI_SUCCESS At least one entry was created.
|
||||
**/
|
||||
EFI_STATUS
|
||||
AddEntriesFromBootEntryProtocol (
|
||||
IN OUT OC_BOOT_CONTEXT *BootContext,
|
||||
IN OUT OC_BOOT_FILESYSTEM *FileSystem,
|
||||
IN EFI_HANDLE *EntryProtocolHandles,
|
||||
IN UINTN EntryProtocolHandleCount,
|
||||
IN CONST CHAR16 *DefaultEntryId, OPTIONAL
|
||||
IN CONST BOOLEAN CreateDefault
|
||||
);
|
||||
|
||||
#endif // BOOT_ENTRY_PROTOCOL_INTERNAL_H
|
||||
@ -33,6 +33,13 @@
|
||||
{ 0xd6f263f9, 0x0b19, 0x4670, \
|
||||
{ 0xb0, 0xa4, 0x9d, 0x95, 0x9f, 0x58, 0xdf, 0x65 } }
|
||||
|
||||
///
|
||||
/// Identifies the DevicePath structure for Boot Entry Brotocol custom entries.
|
||||
///
|
||||
#define OC_ENTRY_PROTOCOL_DEVICE_PATH_GUID \
|
||||
{ 0x669bf063, 0x78c1, 0x4c29, \
|
||||
{ 0x93, 0x34, 0x2f, 0xf0, 0x15, 0xfe, 0xa2, 0xfe } }
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
///
|
||||
@ -43,6 +50,16 @@ typedef PACKED struct {
|
||||
FILEPATH_DEVICE_PATH EntryName;
|
||||
} OC_CUSTOM_BOOT_DEVICE_PATH;
|
||||
|
||||
///
|
||||
/// DevicePath to describe Boot Entry Protocol custom entries.
|
||||
/// Include partuuid of boot drive in VenHw custom memory.
|
||||
///
|
||||
typedef PACKED struct {
|
||||
VENDOR_DEVICE_PATH Hdr;
|
||||
EFI_GUID Partuuid;
|
||||
FILEPATH_DEVICE_PATH EntryName;
|
||||
} OC_ENTRY_PROTOCOL_DEVICE_PATH;
|
||||
|
||||
//
|
||||
// Ideally, a variant of FILEPATH_DEVICE_PATH will be used with PathName as a
|
||||
// flexible array. Such cannot be used for declarations, so provide an
|
||||
@ -53,6 +70,15 @@ typedef PACKED struct {
|
||||
EFI_DEVICE_PATH_PROTOCOL EntryName;
|
||||
} OC_CUSTOM_BOOT_DEVICE_PATH_DECL;
|
||||
|
||||
//
|
||||
// Version not including first char of path name.
|
||||
//
|
||||
typedef PACKED struct {
|
||||
VENDOR_DEVICE_PATH Header;
|
||||
EFI_GUID Partuuid;
|
||||
EFI_DEVICE_PATH_PROTOCOL EntryName;
|
||||
} OC_ENTRY_PROTOCOL_DEVICE_PATH_DECL;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
///
|
||||
@ -61,6 +87,12 @@ typedef PACKED struct {
|
||||
#define SIZE_OF_OC_CUSTOM_BOOT_DEVICE_PATH \
|
||||
(sizeof (VENDOR_DEVICE_PATH) + SIZE_OF_FILEPATH_DEVICE_PATH)
|
||||
|
||||
///
|
||||
/// The size of a OC_ENTRY_PROTOCOL_DEVICE_PATH structure excluding the name.
|
||||
///
|
||||
#define SIZE_OF_OC_ENTRY_PROTOCOL_DEVICE_PATH \
|
||||
(sizeof (VENDOR_DEVICE_PATH) + sizeof (EFI_GUID) + SIZE_OF_FILEPATH_DEVICE_PATH)
|
||||
|
||||
//
|
||||
// Max. supported Apple version string size
|
||||
//
|
||||
@ -166,6 +198,24 @@ InternalGetBootOptionPath (
|
||||
IN UINTN LoadOptionSize
|
||||
);
|
||||
|
||||
/**
|
||||
Create bootable entry from custom entry.
|
||||
|
||||
@param[in,out] BootContext Context of filesystems.
|
||||
@param[in,out] FileSystem Filesystem to add custom entry.
|
||||
@param[in] CustomEntry Custom entry.
|
||||
@param[in] IsBootEntryProtocol Is entry from OC_BOOT_ENTRY_PROTOCOL.
|
||||
|
||||
@retval EFI_SUCCESS on success.
|
||||
**/
|
||||
EFI_STATUS
|
||||
InternalAddBootEntryFromCustomEntry (
|
||||
IN OUT OC_BOOT_CONTEXT *BootContext,
|
||||
IN OUT OC_BOOT_FILESYSTEM *FileSystem,
|
||||
IN OC_PICKER_ENTRY *CustomEntry,
|
||||
IN BOOLEAN IsBootEntryProtocol
|
||||
);
|
||||
|
||||
/**
|
||||
Describe boot entry contents by setting fields other than DevicePath.
|
||||
|
||||
@ -190,18 +240,21 @@ InternalIsAppleLegacyLoadApp (
|
||||
This solves the problem of checking scan policy multiple times
|
||||
as well as the problem of finding the filesystem to add entries too.
|
||||
|
||||
@param[in] BootContext Context of filesystems.
|
||||
@param[in] FileSystemHandle Partition handle.
|
||||
@param[in] LazyScan Lazy filesystem scanning.
|
||||
@param[in] BootContext Context of filesystems.
|
||||
@param[in] FileSystemHandle Partition handle.
|
||||
@param[in] LazyScan Lazy filesystem scanning.
|
||||
@param[out] AlreadySeen Set to TRUE if file system was
|
||||
already present in context.
|
||||
|
||||
@retval discovered filesystem (legit).
|
||||
@retcal NULL when booting is not allowed from this filesystem.
|
||||
**/
|
||||
OC_BOOT_FILESYSTEM *
|
||||
InternalFileSystemForHandle (
|
||||
IN OC_BOOT_CONTEXT *BootContext,
|
||||
IN EFI_HANDLE FileSystemHandle,
|
||||
IN BOOLEAN LazyScan
|
||||
IN OC_BOOT_CONTEXT *BootContext,
|
||||
IN EFI_HANDLE FileSystemHandle,
|
||||
IN BOOLEAN LazyScan,
|
||||
OUT BOOLEAN *AlreadySeen OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
@ -230,6 +283,16 @@ InternalGetOcCustomDevPath (
|
||||
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
||||
);
|
||||
|
||||
/**
|
||||
Determines whether DevicePath is a Boot Entry Protocol custom boot entry.
|
||||
|
||||
@returns The Boot Entry Protocol custom boot entry, or NULL.
|
||||
**/
|
||||
CONST OC_ENTRY_PROTOCOL_DEVICE_PATH *
|
||||
InternalGetOcEntryProtocolDevPath (
|
||||
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
InternalRunRequestPrivilege (
|
||||
IN OC_PICKER_CONTEXT *PickerContext,
|
||||
|
||||
@ -1,15 +1,6 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, vit9696. All rights reserved.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
Copyright (C) 2019-2021, vit9696, mikebeaton. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#include <Uefi.h>
|
||||
@ -19,6 +10,7 @@
|
||||
#include <Guid/AppleFile.h>
|
||||
#include <Guid/AppleVariable.h>
|
||||
#include <Guid/GlobalVariable.h>
|
||||
#include <Guid/Gpt.h>
|
||||
#include <Guid/OcVariable.h>
|
||||
|
||||
#include <Protocol/DevicePath.h>
|
||||
@ -40,7 +32,7 @@
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
|
||||
///
|
||||
/// Template for an OpenCore custom boot entry DevicePath node.
|
||||
/// Template for OpenCore custom boot entry DevicePath.
|
||||
///
|
||||
STATIC CONST OC_CUSTOM_BOOT_DEVICE_PATH_DECL mOcCustomBootDevPathTemplate = {
|
||||
{
|
||||
@ -58,6 +50,26 @@ STATIC CONST OC_CUSTOM_BOOT_DEVICE_PATH_DECL mOcCustomBootDevPathTemplate = {
|
||||
}
|
||||
};
|
||||
|
||||
///
|
||||
/// Template for Boot Entry Protocol custom boot entry DevicePath.
|
||||
///
|
||||
STATIC CONST OC_ENTRY_PROTOCOL_DEVICE_PATH_DECL mOcEntryProtocolDevPathTemplate = {
|
||||
{
|
||||
{
|
||||
HARDWARE_DEVICE_PATH,
|
||||
HW_VENDOR_DP,
|
||||
{ sizeof (VENDOR_DEVICE_PATH) + sizeof (EFI_GUID), 0 }
|
||||
},
|
||||
OC_ENTRY_PROTOCOL_DEVICE_PATH_GUID
|
||||
},
|
||||
EFI_PART_TYPE_UNUSED_GUID,
|
||||
{
|
||||
MEDIA_DEVICE_PATH,
|
||||
MEDIA_FILEPATH_DP,
|
||||
{ SIZE_OF_FILEPATH_DEVICE_PATH, 0 }
|
||||
}
|
||||
};
|
||||
|
||||
CONST OC_CUSTOM_BOOT_DEVICE_PATH *
|
||||
InternalGetOcCustomDevPath (
|
||||
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
||||
@ -90,6 +102,38 @@ InternalGetOcCustomDevPath (
|
||||
return CustomDevPath;
|
||||
}
|
||||
|
||||
CONST OC_ENTRY_PROTOCOL_DEVICE_PATH *
|
||||
InternalGetOcEntryProtocolDevPath (
|
||||
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
||||
)
|
||||
{
|
||||
UINTN DevicePathSize;
|
||||
INTN CmpResult;
|
||||
CONST OC_ENTRY_PROTOCOL_DEVICE_PATH *EntryProtocolDevPath;
|
||||
|
||||
DevicePathSize = GetDevicePathSize (DevicePath);
|
||||
if (DevicePathSize < SIZE_OF_OC_ENTRY_PROTOCOL_DEVICE_PATH) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CmpResult = CompareMem (
|
||||
DevicePath,
|
||||
&mOcEntryProtocolDevPathTemplate.Header,
|
||||
sizeof (mOcEntryProtocolDevPathTemplate.Header)
|
||||
);
|
||||
if (CmpResult != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EntryProtocolDevPath = (CONST OC_ENTRY_PROTOCOL_DEVICE_PATH *) DevicePath;
|
||||
if (EntryProtocolDevPath->EntryName.Header.Type != MEDIA_DEVICE_PATH
|
||||
|| EntryProtocolDevPath->EntryName.Header.SubType != MEDIA_FILEPATH_DP) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return EntryProtocolDevPath;
|
||||
}
|
||||
|
||||
EFI_LOAD_OPTION *
|
||||
InternalGetBootOptionData (
|
||||
OUT UINTN *OptionSize,
|
||||
@ -358,7 +402,7 @@ InternalMatchCustomBootEntryByDevicePath (
|
||||
{
|
||||
INTN CmpResult;
|
||||
|
||||
if (!BootEntry->IsCustom) {
|
||||
if (!BootEntry->IsCustom || BootEntry->IsBootEntryProtocol) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -370,6 +414,32 @@ InternalMatchCustomBootEntryByDevicePath (
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
STATIC
|
||||
BOOLEAN
|
||||
InternalMatchEntryProtocolEntryByDevicePath (
|
||||
IN OUT OC_BOOT_ENTRY *BootEntry,
|
||||
IN CONST OC_ENTRY_PROTOCOL_DEVICE_PATH *DevicePath
|
||||
)
|
||||
{
|
||||
INTN CmpResult;
|
||||
|
||||
if (!BootEntry->IsCustom || !BootEntry->IsBootEntryProtocol || BootEntry->Id == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CmpResult = CompareMem (&BootEntry->UniquePartitionGUID, &DevicePath->Partuuid, sizeof (EFI_GUID));
|
||||
if (CmpResult != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CmpResult = StrCmp (BootEntry->Id, DevicePath->EntryName.PathName);
|
||||
if (CmpResult != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
InternalClearNextVariables (
|
||||
@ -735,23 +805,34 @@ OcSetDefaultBootEntry (
|
||||
EFI_DEVICE_PATH *BootOptionRemainingDevicePath;
|
||||
EFI_HANDLE DeviceHandle;
|
||||
BOOLEAN MatchedEntry;
|
||||
BOOLEAN IsOverflow;
|
||||
BOOLEAN IsAsciiOptionName;
|
||||
EFI_GUID *BootVariableGuid;
|
||||
CHAR16 *BootOrderName;
|
||||
CHAR16 *BootVariableName;
|
||||
CHAR16 *LoadOptionId;
|
||||
VOID *LoadOptionName;
|
||||
CHAR8 *FirstFlavourEnd;
|
||||
UINT16 *BootOrder;
|
||||
UINT16 *NewBootOrder;
|
||||
UINT16 BootTmp;
|
||||
UINT16 EntryIdLength;
|
||||
UINTN BootOrderCount;
|
||||
UINTN BootChosenIndex;
|
||||
UINTN Index;
|
||||
UINTN DevicePathSize;
|
||||
UINTN LoadOptionSize;
|
||||
UINTN LoadOptionIdSize;
|
||||
UINTN LoadOptionNameSize;
|
||||
UINTN LoadOptionNameLen;
|
||||
UINTN CopiedLength;
|
||||
EFI_LOAD_OPTION *LoadOption;
|
||||
|
||||
CONST OC_CUSTOM_BOOT_DEVICE_PATH *CustomDevPath;
|
||||
OC_CUSTOM_BOOT_DEVICE_PATH *DestCustomDevPath;
|
||||
EFI_DEVICE_PATH_PROTOCOL *DestCustomEndNode;
|
||||
CONST OC_CUSTOM_BOOT_DEVICE_PATH *CustomDevPath;
|
||||
CONST OC_ENTRY_PROTOCOL_DEVICE_PATH *EntryProtocolDevPath;
|
||||
VENDOR_DEVICE_PATH *DestCustomDevPath;
|
||||
FILEPATH_DEVICE_PATH *DestCustomEntryName;
|
||||
EFI_DEVICE_PATH_PROTOCOL *DestCustomEndNode;
|
||||
|
||||
//
|
||||
// Do not allow when prohibited.
|
||||
@ -839,6 +920,14 @@ OcSetDefaultBootEntry (
|
||||
Entry,
|
||||
CustomDevPath
|
||||
);
|
||||
} else {
|
||||
EntryProtocolDevPath = InternalGetOcEntryProtocolDevPath (BootOptionDevicePath);
|
||||
if (EntryProtocolDevPath != NULL) {
|
||||
MatchedEntry = InternalMatchEntryProtocolEntryByDevicePath (
|
||||
Entry,
|
||||
EntryProtocolDevPath
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -849,12 +938,61 @@ OcSetDefaultBootEntry (
|
||||
//
|
||||
// Write to Boot0080
|
||||
//
|
||||
LoadOptionNameSize = StrSize (Entry->Name);
|
||||
ASSERT (Entry->Name != NULL);
|
||||
IsAsciiOptionName = FALSE;
|
||||
if (Entry->Id == NULL) {
|
||||
//
|
||||
// Re-use user defined entry name as stored id.
|
||||
//
|
||||
LoadOptionName = Entry->Name;
|
||||
LoadOptionNameSize = StrSize (Entry->Name);
|
||||
|
||||
LoadOptionId = LoadOptionName;
|
||||
LoadOptionIdSize = LoadOptionNameSize;
|
||||
} else {
|
||||
//
|
||||
// Re-use first part of flavour as option name if available, it is more human
|
||||
// readable than entry id, but is not version specific, unlike entry name.
|
||||
//
|
||||
LoadOptionId = Entry->Id;
|
||||
LoadOptionIdSize = StrSize (Entry->Id);
|
||||
|
||||
if (Entry->Flavour != NULL && Entry->Flavour[0] != '\0' && Entry->Flavour[0] != ':') {
|
||||
FirstFlavourEnd = OcAsciiStrChr (Entry->Flavour, ':');
|
||||
if (FirstFlavourEnd != NULL) {
|
||||
LoadOptionNameLen = FirstFlavourEnd - Entry->Flavour;
|
||||
} else {
|
||||
LoadOptionNameLen = AsciiStrLen (Entry->Flavour);
|
||||
}
|
||||
IsAsciiOptionName = TRUE;
|
||||
LoadOptionNameSize = (LoadOptionNameLen + 1) * sizeof (CHAR16) / sizeof (CHAR8);
|
||||
LoadOptionName = Entry->Flavour;
|
||||
} else {
|
||||
LoadOptionName = LoadOptionId;
|
||||
LoadOptionNameSize = LoadOptionIdSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Entry->IsCustom) {
|
||||
DevicePathSize = GetDevicePathSize (Entry->DevicePath);
|
||||
} else {
|
||||
DevicePathSize = SIZE_OF_OC_CUSTOM_BOOT_DEVICE_PATH + LoadOptionNameSize + sizeof (EFI_DEVICE_PATH_PROTOCOL);
|
||||
DevicePathSize = SIZE_OF_OC_CUSTOM_BOOT_DEVICE_PATH
|
||||
+ (Entry->IsBootEntryProtocol ? sizeof (EFI_GUID) : 0)
|
||||
+ LoadOptionIdSize
|
||||
+ sizeof (EFI_DEVICE_PATH_PROTOCOL);
|
||||
|
||||
if (LoadOptionIdSize > MAX_UINT16) {
|
||||
IsOverflow = TRUE;
|
||||
} else {
|
||||
IsOverflow = OcOverflowAddU16 (SIZE_OF_FILEPATH_DEVICE_PATH, (UINT16)LoadOptionIdSize, &EntryIdLength);
|
||||
}
|
||||
if (IsOverflow) {
|
||||
DEBUG ((DEBUG_ERROR, "OCB: Overflowing option id size (%u)\n", LoadOptionIdSize));
|
||||
if (BootOrder != NULL) {
|
||||
FreePool (BootOrder);
|
||||
}
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
LoadOptionSize = sizeof (EFI_LOAD_OPTION) + LoadOptionNameSize + DevicePathSize;
|
||||
@ -870,35 +1008,61 @@ OcSetDefaultBootEntry (
|
||||
|
||||
LoadOption->Attributes = LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT;
|
||||
LoadOption->FilePathListLength = (UINT16) DevicePathSize;
|
||||
CopyMem (LoadOption + 1, Entry->Name, LoadOptionNameSize);
|
||||
if (IsAsciiOptionName) {
|
||||
Status = AsciiStrnToUnicodeStrS (LoadOptionName, LoadOptionNameLen, (CHAR16 *)(LoadOption + 1), LoadOptionNameSize / sizeof (CHAR16), &CopiedLength);
|
||||
ASSERT (!EFI_ERROR (Status));
|
||||
ASSERT (CopiedLength == LoadOptionNameLen);
|
||||
} else {
|
||||
CopyMem (LoadOption + 1, LoadOptionName, LoadOptionNameSize);
|
||||
}
|
||||
|
||||
if (!Entry->IsCustom) {
|
||||
CopyMem ((UINT8 *) (LoadOption + 1) + LoadOptionNameSize, Entry->DevicePath, DevicePathSize);
|
||||
} else {
|
||||
DestCustomDevPath = (OC_CUSTOM_BOOT_DEVICE_PATH *) (
|
||||
DestCustomDevPath = (VENDOR_DEVICE_PATH *) (
|
||||
(UINT8 *) (LoadOption + 1) + LoadOptionNameSize
|
||||
);
|
||||
if (Entry->IsBootEntryProtocol) {
|
||||
CopyMem (
|
||||
DestCustomDevPath,
|
||||
&mOcEntryProtocolDevPathTemplate,
|
||||
sizeof (mOcEntryProtocolDevPathTemplate)
|
||||
);
|
||||
CopyMem (
|
||||
DestCustomDevPath + 1,
|
||||
&Entry->UniquePartitionGUID,
|
||||
sizeof (EFI_GUID)
|
||||
);
|
||||
DestCustomEntryName = (FILEPATH_DEVICE_PATH *) (
|
||||
(UINT8 *) (DestCustomDevPath + 1) +
|
||||
sizeof (EFI_GUID)
|
||||
);
|
||||
} else {
|
||||
CopyMem (
|
||||
DestCustomDevPath,
|
||||
&mOcCustomBootDevPathTemplate,
|
||||
sizeof (mOcCustomBootDevPathTemplate)
|
||||
);
|
||||
DestCustomEntryName = (FILEPATH_DEVICE_PATH *) (
|
||||
(UINT8 *) (DestCustomDevPath + 1)
|
||||
);
|
||||
}
|
||||
|
||||
CopyMem (
|
||||
DestCustomDevPath,
|
||||
&mOcCustomBootDevPathTemplate,
|
||||
sizeof (mOcCustomBootDevPathTemplate)
|
||||
DestCustomEntryName->PathName,
|
||||
LoadOptionId,
|
||||
LoadOptionIdSize
|
||||
);
|
||||
CopyMem (
|
||||
DestCustomDevPath->EntryName.PathName,
|
||||
Entry->Name,
|
||||
LoadOptionNameSize
|
||||
);
|
||||
//
|
||||
// FIXME: This may theoretically overflow.
|
||||
//
|
||||
DestCustomDevPath->EntryName.Header.Length[0] += (UINT8) LoadOptionNameSize;
|
||||
|
||||
DestCustomEntryName->Header.Length[0] = (UINT8) EntryIdLength;
|
||||
DestCustomEntryName->Header.Length[1] = (UINT8) (EntryIdLength >> 8);
|
||||
|
||||
DestCustomEndNode = (EFI_DEVICE_PATH_PROTOCOL *) (
|
||||
(UINT8 *) DestCustomDevPath + SIZE_OF_OC_CUSTOM_BOOT_DEVICE_PATH + LoadOptionNameSize
|
||||
(UINT8 *) DestCustomEntryName + EntryIdLength
|
||||
);
|
||||
SetDevicePathEndNode (DestCustomEndNode);
|
||||
|
||||
ASSERT (GetDevicePathSize (&DestCustomDevPath->Hdr.Header) == DevicePathSize);
|
||||
ASSERT (GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DestCustomDevPath) == DevicePathSize);
|
||||
}
|
||||
|
||||
Status = gRT->SetVariable (
|
||||
|
||||
@ -39,6 +39,8 @@
|
||||
BootEntryInfo.c
|
||||
BootEntryManagement.c
|
||||
BootManagementInternal.h
|
||||
BootEntryProtocol.c
|
||||
BootEntryProtocolInternal.h
|
||||
BuiltinPicker.c
|
||||
DefaultEntryChoice.c
|
||||
DmgBootSupport.c
|
||||
@ -77,6 +79,7 @@
|
||||
gAppleSecureBootVariableGuid ## SOMETIMES_CONSUMES
|
||||
gAppleTamperResistantBootSecureVariableGuid ## SOMETIMES_CONSUMES
|
||||
gAppleTamperResistantBootEfiUserVariableGuid ## SOMETIMES_CONSUMES
|
||||
gEfiPartTypeUnusedGuid ## SOMETIMES_CONSUMES
|
||||
gOcVendorVariableGuid ## SOMETIMES_CONSUMES
|
||||
gOcReadOnlyVariableGuid ## SOMETIMES_CONSUMES
|
||||
gOcWriteOnlyVariableGuid ## SOMETIMES_CONSUMES
|
||||
@ -92,6 +95,7 @@
|
||||
gOcFirmwareRuntimeProtocolGuid ## SOMETIMES_CONSUMES
|
||||
gOcAudioProtocolGuid ## SOMETIMES_CONSUMES
|
||||
gAppleBeepGenProtocolGuid ## SOMETIMES_CONSUMES
|
||||
gOcBootEntryProtocolGuid ## CONSUMES
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
@ -112,8 +116,9 @@
|
||||
OcCryptoLib
|
||||
OcDeviceMiscLib
|
||||
OcDevicePathLib
|
||||
OcGuardLib
|
||||
OcFileLib
|
||||
OcFlexArrayLib
|
||||
OcGuardLib
|
||||
OcMachoLib
|
||||
OcMiscLib
|
||||
OcPeCoffLib
|
||||
|
||||
@ -192,6 +192,7 @@ EFI_GUID mMsftRecoveryPartitionTypeGuid = {
|
||||
/**
|
||||
Linux partitions.
|
||||
https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs
|
||||
https://systemd.io/DISCOVERABLE_PARTITIONS/
|
||||
**/
|
||||
EFI_GUID mLinuxRootX86PartitionTypeGuid = {
|
||||
0x44479540, 0xF297, 0x41B2, {0x9A, 0xF7, 0xD1, 0x31, 0xD5, 0xF0, 0x45, 0x8A}
|
||||
@ -201,6 +202,18 @@ EFI_GUID mLinuxRootX8664PartitionTypeGuid = {
|
||||
0x4F68BCE3, 0xE8CD, 0x4DB1, {0x96, 0xE7, 0xFB, 0xCA, 0xF9, 0x84, 0xB7, 0x09}
|
||||
};
|
||||
|
||||
EFI_GUID mLinuxFileSystemPartitionTypeGuid = {
|
||||
0x0FC63DAF, 0x8483, 0x4772, { 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4 }
|
||||
};
|
||||
|
||||
/**
|
||||
Extended Boot Loader Partition (XBOOTLDR).
|
||||
https://systemd.io/BOOT_LOADER_SPECIFICATION/
|
||||
**/
|
||||
EFI_GUID mXBootLdrPartitionTypeGuid = {
|
||||
0xBC13C2FF, 0x59E6, 0x4262, { 0xA3, 0x52, 0xB2, 0x75, 0xFD, 0x6F, 0x71, 0x72 }
|
||||
};
|
||||
|
||||
UINT32
|
||||
OcGetFileSystemPolicyType (
|
||||
IN EFI_HANDLE Handle
|
||||
@ -223,6 +236,10 @@ OcGetFileSystemPolicyType (
|
||||
return OC_SCAN_ALLOW_FS_ESP;
|
||||
}
|
||||
|
||||
if (CompareGuid (&PartitionEntry->PartitionTypeGUID, &mXBootLdrPartitionTypeGuid)) {
|
||||
return OC_SCAN_ALLOW_FS_XBOOTLDR;
|
||||
}
|
||||
|
||||
//
|
||||
// Unsure whether these two should be separate, likely not.
|
||||
//
|
||||
@ -237,7 +254,11 @@ OcGetFileSystemPolicyType (
|
||||
|
||||
if (CompareGuid (&PartitionEntry->PartitionTypeGUID, &mLinuxRootX86PartitionTypeGuid)
|
||||
|| CompareGuid (&PartitionEntry->PartitionTypeGUID, &mLinuxRootX8664PartitionTypeGuid)) {
|
||||
return OC_SCAN_ALLOW_FS_EXT;
|
||||
return OC_SCAN_ALLOW_FS_LINUX_ROOT;
|
||||
}
|
||||
|
||||
if (CompareGuid (&PartitionEntry->PartitionTypeGUID, &mLinuxFileSystemPartitionTypeGuid)) {
|
||||
return OC_SCAN_ALLOW_FS_LINUX_DATA;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -71,6 +71,7 @@ OC_STRUCTORS (OC_PLATFORM_NVRAM_CONFIG, ())
|
||||
OC_STRUCTORS (OC_PLATFORM_SMBIOS_CONFIG, ())
|
||||
OC_STRUCTORS (OC_PLATFORM_CONFIG, ())
|
||||
|
||||
OC_STRUCTORS (OC_UEFI_DRIVER_ENTRY, ())
|
||||
OC_ARRAY_STRUCTORS (OC_UEFI_DRIVER_ARRAY)
|
||||
OC_STRUCTORS (OC_UEFI_APFS, ())
|
||||
OC_STRUCTORS (OC_UEFI_APPLEINPUT, ())
|
||||
@ -667,7 +668,15 @@ mPlatformConfigurationSchema[] = {
|
||||
|
||||
STATIC
|
||||
OC_SCHEMA
|
||||
mUefiDriversSchema = OC_SCHEMA_STRING (NULL);
|
||||
mUefiDriversSchemaEntry[] = {
|
||||
OC_SCHEMA_STRING_IN ("Arguments", OC_UEFI_DRIVER_ENTRY, Arguments),
|
||||
OC_SCHEMA_BOOLEAN_IN ("Enabled", OC_UEFI_DRIVER_ENTRY, Enabled),
|
||||
OC_SCHEMA_STRING_IN ("Path", OC_UEFI_DRIVER_ENTRY, Path),
|
||||
};
|
||||
|
||||
STATIC
|
||||
OC_SCHEMA
|
||||
mUefiDriversSchema = OC_SCHEMA_DICT (NULL, mUefiDriversSchemaEntry);
|
||||
|
||||
STATIC
|
||||
OC_SCHEMA
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
## @file
|
||||
#
|
||||
# Component description file for OcMisclibrary.
|
||||
# Component description file for OcDeviceMiscLib.
|
||||
#
|
||||
# Copyright (C) 2016 - 2018, The HermitCrabs Lab. All rights reserved.<BR>
|
||||
#
|
||||
|
||||
@ -1,15 +1,6 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, vit9696. All rights reserved.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
Copyright (C) 2019-2021, vit9696, Goldfish64, mikebeaton. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#include <Uefi.h>
|
||||
@ -420,6 +411,30 @@ OcDirectorySeachContextInit (
|
||||
ZeroMem (Context, sizeof (*Context));
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
OcEnsureDirectory (
|
||||
IN EFI_FILE_PROTOCOL *File,
|
||||
IN BOOLEAN IsDirectory
|
||||
)
|
||||
{
|
||||
EFI_FILE_INFO *FileInfo;
|
||||
|
||||
//
|
||||
// Ensure this is a directory/file.
|
||||
//
|
||||
FileInfo = OcGetFileInfo (File, &gEfiFileInfoGuid, 0, NULL);
|
||||
if (FileInfo == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
if (((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) != IsDirectory) {
|
||||
FreePool (FileInfo);
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
FreePool (FileInfo);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
OcGetNewestFileFromDirectory (
|
||||
IN OUT DIRECTORY_SEARCH_CONTEXT *Context,
|
||||
@ -445,18 +460,10 @@ OcGetNewestFileFromDirectory (
|
||||
LatestIndex = 0;
|
||||
LatestEpoch = 0;
|
||||
|
||||
//
|
||||
// Ensure this is a directory.
|
||||
//
|
||||
FileInfoCurrent = OcGetFileInfo (Directory, &gEfiFileInfoGuid, 0, NULL);
|
||||
if (FileInfoCurrent == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
Status = OcEnsureDirectory (Directory, TRUE);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
if (!(FileInfoCurrent->Attribute & EFI_FILE_DIRECTORY)) {
|
||||
FreePool (FileInfoCurrent);
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
FreePool (FileInfoCurrent);
|
||||
|
||||
//
|
||||
// Allocate two FILE_INFO structures.
|
||||
@ -564,3 +571,80 @@ OcGetNewestFileFromDirectory (
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: OcGetNewestFileFromDirectory above and ScanExtensions in CachelessContext.c could be redone using this.
|
||||
// TODO: I am unclear exactly what the Apple 32-bit HFS is being described as doing (see also OcGetFileInfo), so
|
||||
// have just copied the existing handling.
|
||||
//
|
||||
EFI_STATUS
|
||||
OcScanDirectory (
|
||||
IN EFI_FILE_HANDLE Directory,
|
||||
IN OC_PROCESS_DIRECTORY_ENTRY ProcessEntry,
|
||||
IN OUT VOID *Context OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_STATUS TempStatus;
|
||||
EFI_FILE_INFO *FileInfo;
|
||||
UINTN FileInfoSize;
|
||||
|
||||
ASSERT (Directory != NULL);
|
||||
ASSERT (ProcessEntry != NULL);
|
||||
|
||||
Status = OcEnsureDirectory (Directory, TRUE);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate FILE_INFO structure.
|
||||
//
|
||||
FileInfo = AllocatePool (SIZE_1KB);
|
||||
if (FileInfo == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Status = EFI_NOT_FOUND;
|
||||
Directory->SetPosition (Directory, 0);
|
||||
|
||||
do {
|
||||
//
|
||||
// Apple's HFS+ driver does not adhere to the spec and will return zero for
|
||||
// EFI_BUFFER_TOO_SMALL. EFI_FILE_INFO structures larger than 1KB are
|
||||
// unrealistic as the filename is the only variable.
|
||||
//
|
||||
FileInfoSize = SIZE_1KB - sizeof (CHAR16);
|
||||
TempStatus = Directory->Read (Directory, &FileInfoSize, FileInfo);
|
||||
if (EFI_ERROR (TempStatus)) {
|
||||
Status = TempStatus;
|
||||
break;
|
||||
}
|
||||
|
||||
if (FileInfoSize > 0) {
|
||||
TempStatus = ProcessEntry (Directory, FileInfo, FileInfoSize, Context);
|
||||
|
||||
//
|
||||
// Act as if no matching file was found.
|
||||
//
|
||||
if (TempStatus == EFI_NOT_FOUND) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (EFI_ERROR (TempStatus)) {
|
||||
Status = TempStatus;
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// At least one file found.
|
||||
//
|
||||
Status = EFI_SUCCESS;
|
||||
}
|
||||
} while (FileInfoSize > 0);
|
||||
|
||||
Directory->SetPosition (Directory, 0);
|
||||
FreePool (FileInfo);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
@ -27,11 +27,11 @@
|
||||
|
||||
EFI_STATUS
|
||||
OcSafeFileOpen (
|
||||
IN EFI_FILE_PROTOCOL *Protocol,
|
||||
OUT EFI_FILE_PROTOCOL **NewHandle,
|
||||
IN CONST CHAR16 *FileName,
|
||||
IN UINT64 OpenMode,
|
||||
IN UINT64 Attributes
|
||||
IN CONST EFI_FILE_PROTOCOL *Protocol,
|
||||
OUT EFI_FILE_PROTOCOL **NewHandle,
|
||||
IN CONST CHAR16 *FileName,
|
||||
IN CONST UINT64 OpenMode,
|
||||
IN CONST UINT64 Attributes
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
@ -48,7 +48,7 @@ OcSafeFileOpen (
|
||||
|
||||
*NewHandle = NULL;
|
||||
Status = Protocol->Open (
|
||||
Protocol,
|
||||
(EFI_FILE_PROTOCOL *) Protocol,
|
||||
NewHandle,
|
||||
(CHAR16 *) FileName,
|
||||
OpenMode,
|
||||
|
||||
@ -31,10 +31,10 @@
|
||||
|
||||
VOID *
|
||||
OcReadFile (
|
||||
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem,
|
||||
IN CONST CHAR16 *FilePath,
|
||||
OUT UINT32 *FileSize OPTIONAL,
|
||||
IN UINT32 MaxFileSize OPTIONAL
|
||||
IN CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem,
|
||||
IN CONST CHAR16 *FilePath,
|
||||
OUT UINT32 *FileSize OPTIONAL,
|
||||
IN CONST UINT32 MaxFileSize OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
@ -48,7 +48,7 @@ OcReadFile (
|
||||
ASSERT (FilePath != NULL);
|
||||
|
||||
Status = FileSystem->OpenVolume (
|
||||
FileSystem,
|
||||
(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *) FileSystem,
|
||||
&Volume
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
@ -58,7 +58,7 @@ OcReadFile (
|
||||
Status = OcSafeFileOpen (
|
||||
Volume,
|
||||
&FileHandle,
|
||||
(CHAR16 *) FilePath,
|
||||
FilePath,
|
||||
EFI_FILE_MODE_READ,
|
||||
0
|
||||
);
|
||||
@ -151,11 +151,11 @@ OcReadFileSize (
|
||||
}
|
||||
|
||||
VOID *
|
||||
OcReadFileFromFile (
|
||||
IN EFI_FILE_PROTOCOL *RootFile,
|
||||
IN CONST CHAR16 *FilePath,
|
||||
OUT UINT32 *FileSize OPTIONAL,
|
||||
IN UINT32 MaxFileSize OPTIONAL
|
||||
OcReadFileFromDirectory (
|
||||
IN CONST EFI_FILE_PROTOCOL *RootDirectory,
|
||||
IN CONST CHAR16 *FilePath,
|
||||
OUT UINT32 *FileSize OPTIONAL,
|
||||
IN UINT32 MaxFileSize OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
@ -163,13 +163,13 @@ OcReadFileFromFile (
|
||||
UINT32 Size;
|
||||
UINT8 *FileBuffer;
|
||||
|
||||
ASSERT (RootFile != NULL);
|
||||
ASSERT (RootDirectory != NULL);
|
||||
ASSERT (FilePath != NULL);
|
||||
|
||||
Status = OcSafeFileOpen (
|
||||
RootFile,
|
||||
RootDirectory,
|
||||
&File,
|
||||
(CHAR16 *) FilePath,
|
||||
FilePath,
|
||||
EFI_FILE_MODE_READ,
|
||||
0
|
||||
);
|
||||
|
||||
196
Library/OcFlexArrayLib/AsciiStringBuffer.c
Normal file
196
Library/OcFlexArrayLib/AsciiStringBuffer.c
Normal file
@ -0,0 +1,196 @@
|
||||
/** @file
|
||||
String buffer.
|
||||
|
||||
Copyright (c) 2021, Mike Beaton. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#include <Base.h>
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcDebugLogLib.h>
|
||||
#include <Library/OcFlexArrayLib.h>
|
||||
#include <Library/OcGuardLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
|
||||
OC_STRING_BUFFER *
|
||||
OcAsciiStringBufferInit (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
OC_STRING_BUFFER *Buffer;
|
||||
|
||||
Buffer = AllocateZeroPool (sizeof (OC_STRING_BUFFER));
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
OcAsciiStringBufferAppend (
|
||||
IN OUT OC_STRING_BUFFER *Buffer,
|
||||
IN CONST CHAR8 *AppendString OPTIONAL
|
||||
)
|
||||
{
|
||||
return OcAsciiStringBufferAppendN (Buffer, AppendString, MAX_UINTN);
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
InternalAsciiStringBufferExtendBy (
|
||||
IN OUT OC_STRING_BUFFER *Buffer,
|
||||
IN CONST UINTN AppendLength,
|
||||
OUT UINTN *TargetLength
|
||||
)
|
||||
{
|
||||
UINTN NewSize;
|
||||
|
||||
ASSERT (AppendLength != 0);
|
||||
|
||||
if (Buffer->String == NULL) {
|
||||
ASSERT (Buffer->BufferSize == 0);
|
||||
|
||||
Buffer->String = AllocatePool (AppendLength + 1);
|
||||
if (Buffer->String == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Buffer->BufferSize = AppendLength + 1;
|
||||
*TargetLength = AppendLength;
|
||||
} else {
|
||||
if (Buffer->BufferSize == 0) {
|
||||
ASSERT (FALSE);
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
NewSize = Buffer->BufferSize;
|
||||
if (OcOverflowAddUN (Buffer->StringLength, AppendLength, TargetLength)) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
while (NewSize <= *TargetLength) {
|
||||
if (OcOverflowMulUN (NewSize, 2, &NewSize)) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
if (NewSize > Buffer->BufferSize) {
|
||||
Buffer->String = ReallocatePool (Buffer->BufferSize, NewSize, Buffer->String);
|
||||
if (Buffer->String == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
Buffer->BufferSize = NewSize;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
OcAsciiStringBufferAppendN (
|
||||
IN OUT OC_STRING_BUFFER *Buffer,
|
||||
IN CONST CHAR8 *AppendString, OPTIONAL
|
||||
IN CONST UINTN Length
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN AppendLength;
|
||||
UINTN TargetLength;
|
||||
|
||||
if (AppendString == NULL) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
AppendLength = AsciiStrnLenS (AppendString, Length);
|
||||
|
||||
//
|
||||
// Buffer stays NULL if zero appended.
|
||||
//
|
||||
if (AppendLength == 0) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
Status = InternalAsciiStringBufferExtendBy (Buffer, AppendLength, &TargetLength);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = AsciiStrnCpyS (&Buffer->String[Buffer->StringLength], AppendLength + 1, AppendString, AppendLength);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Buffer->StringLength = TargetLength;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
OcAsciiStringBufferSPrint (
|
||||
IN OUT OC_STRING_BUFFER *Buffer,
|
||||
IN CONST CHAR8 *FormatString,
|
||||
...
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
VA_LIST Marker;
|
||||
VA_LIST Marker2;
|
||||
UINTN NumberOfPrinted;
|
||||
UINTN TargetLength;
|
||||
|
||||
ASSERT (FormatString != NULL);
|
||||
|
||||
VA_START (Marker, FormatString);
|
||||
|
||||
VA_COPY (Marker2, Marker);
|
||||
NumberOfPrinted = SPrintLengthAsciiFormat (FormatString, Marker2);
|
||||
VA_END (Marker2);
|
||||
|
||||
//
|
||||
// Buffer stays NULL if zero appended.
|
||||
//
|
||||
if (NumberOfPrinted == 0) {
|
||||
Status = EFI_SUCCESS;
|
||||
} else {
|
||||
Status = InternalAsciiStringBufferExtendBy (Buffer, NumberOfPrinted, &TargetLength);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
AsciiVSPrint (&Buffer->String[Buffer->StringLength], NumberOfPrinted + 1, FormatString, Marker);
|
||||
Buffer->StringLength = TargetLength;
|
||||
}
|
||||
}
|
||||
|
||||
VA_END (Marker);
|
||||
return Status;
|
||||
}
|
||||
|
||||
CHAR8 *
|
||||
OcAsciiStringBufferFreeContainer (
|
||||
IN OUT OC_STRING_BUFFER **Buffer
|
||||
)
|
||||
{
|
||||
CHAR8 *String;
|
||||
|
||||
if (Buffer == NULL || *Buffer == NULL) {
|
||||
ASSERT (FALSE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
String = (*Buffer)->String;
|
||||
FreePool (*Buffer);
|
||||
*Buffer = NULL;
|
||||
|
||||
return String;
|
||||
}
|
||||
|
||||
VOID
|
||||
OcAsciiStringBufferFree (
|
||||
IN OUT OC_STRING_BUFFER **StringBuffer
|
||||
)
|
||||
{
|
||||
CHAR8 *Result;
|
||||
|
||||
Result = OcAsciiStringBufferFreeContainer (StringBuffer);
|
||||
if (Result != NULL) {
|
||||
FreePool (Result);
|
||||
}
|
||||
}
|
||||
|
||||
195
Library/OcFlexArrayLib/FlexArray.c
Normal file
195
Library/OcFlexArrayLib/FlexArray.c
Normal file
@ -0,0 +1,195 @@
|
||||
/** @file
|
||||
Auto-resizing array.
|
||||
|
||||
Copyright (c) 2021, Mike Beaton. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcDebugLogLib.h>
|
||||
#include <Library/OcFlexArrayLib.h>
|
||||
#include <Library/OcGuardLib.h>
|
||||
|
||||
#define INITIAL_NUM_ITEMS (8)
|
||||
|
||||
OC_FLEX_ARRAY *
|
||||
OcFlexArrayInit (
|
||||
IN CONST UINTN ItemSize,
|
||||
IN CONST OC_FLEX_ARRAY_FREE_ITEM FreeItem OPTIONAL
|
||||
)
|
||||
{
|
||||
OC_FLEX_ARRAY *FlexArray;
|
||||
|
||||
ASSERT (ItemSize > 0);
|
||||
|
||||
FlexArray = AllocateZeroPool (sizeof (OC_FLEX_ARRAY));
|
||||
if (FlexArray != NULL) {
|
||||
FlexArray->ItemSize = ItemSize;
|
||||
FlexArray->FreeItem = FreeItem;
|
||||
}
|
||||
return FlexArray;
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID *
|
||||
InternalFlexArrayAddItem (
|
||||
IN OUT OC_FLEX_ARRAY *FlexArray
|
||||
)
|
||||
{
|
||||
VOID *TmpBuffer;
|
||||
UINTN NewSize;
|
||||
VOID *Item;
|
||||
|
||||
ASSERT (FlexArray != NULL);
|
||||
|
||||
if (FlexArray->Items == NULL) {
|
||||
FlexArray->AllocatedCount = INITIAL_NUM_ITEMS;
|
||||
if (OcOverflowMulUN (FlexArray->AllocatedCount, FlexArray->ItemSize, &NewSize)) {
|
||||
return NULL;
|
||||
}
|
||||
FlexArray->Count = 1;
|
||||
FlexArray->Items = AllocatePool (NewSize);
|
||||
if (FlexArray->Items == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
ASSERT (FlexArray->Count > 0);
|
||||
ASSERT (FlexArray->AllocatedCount > 0);
|
||||
ASSERT (FlexArray->Count <= FlexArray->AllocatedCount);
|
||||
++(FlexArray->Count);
|
||||
if (FlexArray->Count > FlexArray->AllocatedCount) {
|
||||
if (OcOverflowMulUN (FlexArray->AllocatedCount * FlexArray->ItemSize, 2, &NewSize)) {
|
||||
return NULL;
|
||||
}
|
||||
TmpBuffer = ReallocatePool (FlexArray->AllocatedCount * FlexArray->ItemSize, NewSize, FlexArray->Items);
|
||||
if (TmpBuffer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
FlexArray->Items = TmpBuffer;
|
||||
FlexArray->AllocatedCount = FlexArray->AllocatedCount * 2;
|
||||
}
|
||||
}
|
||||
|
||||
Item = OcFlexArrayItemAt (FlexArray, FlexArray->Count - 1);
|
||||
|
||||
return Item;
|
||||
}
|
||||
|
||||
VOID *
|
||||
OcFlexArrayAddItem (
|
||||
IN OUT OC_FLEX_ARRAY *FlexArray
|
||||
)
|
||||
{
|
||||
VOID *Item;
|
||||
|
||||
ASSERT (FlexArray != NULL);
|
||||
|
||||
Item = InternalFlexArrayAddItem (FlexArray);
|
||||
|
||||
if (Item != NULL) {
|
||||
ZeroMem (Item, FlexArray->ItemSize);
|
||||
}
|
||||
|
||||
return Item;
|
||||
}
|
||||
|
||||
VOID *
|
||||
OcFlexArrayInsertItem (
|
||||
IN OUT OC_FLEX_ARRAY *FlexArray,
|
||||
IN CONST UINTN InsertIndex
|
||||
)
|
||||
{
|
||||
VOID *Item;
|
||||
VOID *Dest;
|
||||
|
||||
ASSERT (FlexArray != NULL);
|
||||
ASSERT (InsertIndex <= FlexArray->Count);
|
||||
|
||||
if (InsertIndex == FlexArray->Count) {
|
||||
return OcFlexArrayAddItem (FlexArray);
|
||||
}
|
||||
|
||||
Item = InternalFlexArrayAddItem (FlexArray);
|
||||
|
||||
if (Item == NULL) {
|
||||
return Item;
|
||||
}
|
||||
|
||||
Item = OcFlexArrayItemAt (FlexArray, InsertIndex);
|
||||
Dest = OcFlexArrayItemAt (FlexArray, InsertIndex + 1);
|
||||
CopyMem (Dest, Item, (FlexArray->Count - InsertIndex) * FlexArray->ItemSize);
|
||||
|
||||
ZeroMem (Item, FlexArray->ItemSize);
|
||||
|
||||
return Item;
|
||||
}
|
||||
|
||||
VOID *
|
||||
OcFlexArrayItemAt (
|
||||
IN CONST OC_FLEX_ARRAY *FlexArray,
|
||||
IN CONST UINTN Index
|
||||
)
|
||||
{
|
||||
if (Index >= FlexArray->Count || FlexArray->Items == NULL) {
|
||||
ASSERT (FALSE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ((UINT8 *) FlexArray->Items) + Index * FlexArray->ItemSize;
|
||||
}
|
||||
|
||||
VOID
|
||||
OcFlexArrayFree (
|
||||
IN OC_FLEX_ARRAY **FlexArray
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
ASSERT (FlexArray != NULL);
|
||||
|
||||
if (*FlexArray != NULL) {
|
||||
if ((*FlexArray)->Items != NULL) {
|
||||
if ((*FlexArray)->FreeItem) {
|
||||
for (Index = 0; Index < (*FlexArray)->Count; Index++) {
|
||||
(*FlexArray)->FreeItem (OcFlexArrayItemAt (*FlexArray, Index));
|
||||
}
|
||||
}
|
||||
FreePool ((*FlexArray)->Items);
|
||||
}
|
||||
FreePool (*FlexArray);
|
||||
*FlexArray = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
OcFlexArrayFreeContainer (
|
||||
IN OC_FLEX_ARRAY **FlexArray,
|
||||
IN VOID **Items,
|
||||
IN UINTN *Count
|
||||
)
|
||||
{
|
||||
if (FlexArray == NULL || *FlexArray == NULL) {
|
||||
ASSERT (FALSE);
|
||||
*Items = NULL;
|
||||
*Count = 0;
|
||||
} else {
|
||||
*Items = (*FlexArray)->Items;
|
||||
*Count = (*FlexArray)->Count;
|
||||
FreePool (*FlexArray);
|
||||
*FlexArray = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
OcFlexArrayFreePointerItem (
|
||||
IN VOID *Item
|
||||
)
|
||||
{
|
||||
ASSERT (Item != NULL);
|
||||
if (*(VOID **)Item != NULL) {
|
||||
FreePool (*(VOID **)Item);
|
||||
*(VOID **)Item = NULL;
|
||||
}
|
||||
}
|
||||
27
Library/OcFlexArrayLib/OcFlexArrayLib.inf
Executable file
27
Library/OcFlexArrayLib/OcFlexArrayLib.inf
Executable file
@ -0,0 +1,27 @@
|
||||
## @file
|
||||
# Component description file for OcFlexArray library.
|
||||
#
|
||||
# Copyright (C) 2021, Mike Beaton. All rights reserved.<BR>
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = OcFlexArrayLib
|
||||
FILE_GUID = 38906C95-DCBA-491C-9FFA-E0AAFFF88EA0
|
||||
MODULE_TYPE = BASE
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = OcFlexArrayLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER UEFI_APPLICATION DXE_SMM_DRIVER
|
||||
|
||||
# VALID_ARCHITECTURES = IA32 X64
|
||||
|
||||
[Packages]
|
||||
OpenCorePkg/OpenCorePkg.dec
|
||||
MdePkg/MdePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
|
||||
[Sources]
|
||||
FlexArray.c
|
||||
AsciiStringBuffer.c
|
||||
@ -331,7 +331,7 @@ OcKernelLoadAndReserveKext (
|
||||
UnicodeUefiSlashes (FullPath);
|
||||
|
||||
if (IsForced) {
|
||||
Kext->PlistData = OcReadFileFromFile (
|
||||
Kext->PlistData = OcReadFileFromDirectory (
|
||||
RootFile,
|
||||
FullPath,
|
||||
&Kext->PlistDataSize,
|
||||
@ -388,7 +388,7 @@ OcKernelLoadAndReserveKext (
|
||||
UnicodeUefiSlashes (FullPath);
|
||||
|
||||
if (IsForced) {
|
||||
Kext->ImageData = OcReadFileFromFile (
|
||||
Kext->ImageData = OcReadFileFromDirectory (
|
||||
RootFile,
|
||||
FullPath,
|
||||
&Kext->ImageDataSize,
|
||||
|
||||
@ -88,15 +88,18 @@ OcLoadDrivers (
|
||||
OUT EFI_HANDLE **DriversToConnect OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
VOID *Driver;
|
||||
UINT32 DriverSize;
|
||||
UINT32 Index;
|
||||
CHAR16 DriverPath[OC_STORAGE_SAFE_PATH_MAX];
|
||||
EFI_HANDLE ImageHandle;
|
||||
EFI_HANDLE *DriversToConnectIterator;
|
||||
VOID *DriverBinding;
|
||||
BOOLEAN SkipDriver;
|
||||
EFI_STATUS Status;
|
||||
VOID *Driver;
|
||||
UINT32 DriverSize;
|
||||
UINT32 Index;
|
||||
CHAR16 DriverPath[OC_STORAGE_SAFE_PATH_MAX];
|
||||
EFI_HANDLE ImageHandle;
|
||||
EFI_HANDLE *DriversToConnectIterator;
|
||||
VOID *DriverBinding;
|
||||
BOOLEAN SkipDriver;
|
||||
OC_UEFI_DRIVER_ENTRY *DriverEntry;
|
||||
CHAR8 *DriverFileName;
|
||||
CONST CHAR8 *DriverArguments;
|
||||
|
||||
DriversToConnectIterator = NULL;
|
||||
if (DriversToConnect != NULL) {
|
||||
@ -106,18 +109,22 @@ OcLoadDrivers (
|
||||
DEBUG ((DEBUG_INFO, "OC: Got %u drivers\n", Config->Uefi.Drivers.Count));
|
||||
|
||||
for (Index = 0; Index < Config->Uefi.Drivers.Count; ++Index) {
|
||||
SkipDriver = OC_BLOB_GET (Config->Uefi.Drivers.Values[Index])[0] == '#';
|
||||
DriverEntry = Config->Uefi.Drivers.Values[Index];
|
||||
DriverFileName = OC_BLOB_GET (&DriverEntry->Path);
|
||||
DriverArguments = OC_BLOB_GET (&DriverEntry->Arguments);
|
||||
|
||||
SkipDriver = !DriverEntry->Enabled || DriverFileName == NULL || DriverFileName[0] == '\0';
|
||||
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"OC: Driver %a at %u is %a\n",
|
||||
OC_BLOB_GET (Config->Uefi.Drivers.Values[Index]),
|
||||
DriverFileName,
|
||||
Index,
|
||||
SkipDriver ? "skipped!" : "being loaded..."
|
||||
));
|
||||
|
||||
//
|
||||
// Skip drivers marked as comments.
|
||||
// Skip disabled drivers.
|
||||
//
|
||||
if (SkipDriver) {
|
||||
continue;
|
||||
@ -127,14 +134,14 @@ OcLoadDrivers (
|
||||
DriverPath,
|
||||
sizeof (DriverPath),
|
||||
OPEN_CORE_UEFI_DRIVER_PATH "%a",
|
||||
OC_BLOB_GET (Config->Uefi.Drivers.Values[Index])
|
||||
DriverFileName
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"OC: Driver %s%a does not fit path!\n",
|
||||
OPEN_CORE_UEFI_DRIVER_PATH,
|
||||
OC_BLOB_GET (Config->Uefi.Drivers.Values[Index])
|
||||
DriverFileName
|
||||
));
|
||||
continue;
|
||||
}
|
||||
@ -144,7 +151,7 @@ OcLoadDrivers (
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"OC: Driver %a at %u cannot be found!\n",
|
||||
OC_BLOB_GET (Config->Uefi.Drivers.Values[Index]),
|
||||
DriverFileName,
|
||||
Index
|
||||
));
|
||||
//
|
||||
@ -169,7 +176,7 @@ OcLoadDrivers (
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"OC: Driver %a at %u cannot be loaded - %r!\n",
|
||||
OC_BLOB_GET (Config->Uefi.Drivers.Values[Index]),
|
||||
DriverFileName,
|
||||
Index,
|
||||
Status
|
||||
));
|
||||
@ -177,6 +184,20 @@ OcLoadDrivers (
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DriverArguments != NULL && DriverArguments[0] != '\0') {
|
||||
OcAppendArgumentsToLoadedImage (ImageHandle, &DriverArguments, 1, TRUE);
|
||||
} else {
|
||||
//
|
||||
// These are not zeroed by boot services image loader, which means new drivers
|
||||
// expecting load options loaded with old OC may crash horribly, instead
|
||||
// of just seeing no options. Annoyingly the value in LoadOptions is non-randome
|
||||
// and lowish, therefore setting an upper limit on option size, to attempt to
|
||||
// reject unitialized values, does not help.
|
||||
//
|
||||
((EFI_LOADED_IMAGE_PROTOCOL *)ImageHandle)->LoadOptionsSize = 0;
|
||||
((EFI_LOADED_IMAGE_PROTOCOL *)ImageHandle)->LoadOptions = NULL;
|
||||
}
|
||||
|
||||
Status = gBS->StartImage (
|
||||
ImageHandle,
|
||||
NULL,
|
||||
@ -187,7 +208,7 @@ OcLoadDrivers (
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"OC: Driver %a at %u cannot be started - %r!\n",
|
||||
OC_BLOB_GET (Config->Uefi.Drivers.Values[Index]),
|
||||
DriverFileName,
|
||||
Index,
|
||||
Status
|
||||
));
|
||||
@ -198,7 +219,7 @@ OcLoadDrivers (
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"OC: Driver %a at %u is successfully loaded!\n",
|
||||
OC_BLOB_GET (Config->Uefi.Drivers.Values[Index]),
|
||||
DriverFileName,
|
||||
Index
|
||||
));
|
||||
|
||||
@ -233,7 +254,7 @@ OcLoadDrivers (
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"OC: Driver %a at %u needs connection.\n",
|
||||
OC_BLOB_GET (Config->Uefi.Drivers.Values[Index]),
|
||||
DriverFileName,
|
||||
Index
|
||||
));
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
## @file
|
||||
#
|
||||
# Component description file for OcMisclibrary.
|
||||
# Component description file for OcMiscLib.
|
||||
#
|
||||
# Copyright (C) 2016 - 2018, The HermitCrabs Lab. All rights reserved.<BR>
|
||||
#
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
## @file
|
||||
#
|
||||
# Component description file for OcMisclibrary.
|
||||
# Component description file for OcMp3Lib.
|
||||
#
|
||||
# Copyright (C) 2016 - 2018, The HermitCrabs Lab. All rights reserved.<BR>
|
||||
#
|
||||
|
||||
@ -526,3 +526,20 @@ OcAsciiPrintBuffer (
|
||||
AsciiStrCatS (*AsciiBuffer, *AsciiBufferSize, Tmp);
|
||||
}
|
||||
}
|
||||
|
||||
CHAR8 *
|
||||
OcAsciiToLower (
|
||||
CHAR8 *Str
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
ASSERT (Str != NULL);
|
||||
|
||||
for (Index = 0; Str[Index] != '\0'; ++Index) {
|
||||
if (Str[Index] >= 'A' && Str[Index] <= 'Z') {
|
||||
Str[Index] -= ('A' - 'a');
|
||||
}
|
||||
}
|
||||
return Str;
|
||||
}
|
||||
|
||||
@ -37,9 +37,11 @@
|
||||
[Packages]
|
||||
OpenCorePkg/OpenCorePkg.dec
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
BaseMemoryLib
|
||||
MemoryAllocationLib
|
||||
PrintLib
|
||||
SortLib
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
#include <Library/OcStringLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/PcdLib.h>
|
||||
#include <Library/SortLib.h>
|
||||
|
||||
INTN
|
||||
EFIAPI
|
||||
@ -503,3 +504,21 @@ MixedStrCmp (
|
||||
|
||||
return *FirstString - *SecondString;
|
||||
}
|
||||
|
||||
INTN
|
||||
EFIAPI
|
||||
OcReverseStringCompare (
|
||||
IN CONST VOID *Buffer1,
|
||||
IN CONST VOID *Buffer2
|
||||
)
|
||||
{
|
||||
return -StringCompare (Buffer1, Buffer2);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
OcIsSpace (
|
||||
CHAR16 Ch
|
||||
)
|
||||
{
|
||||
return (Ch == L' ') || (Ch == L'\t') || (Ch == L'\r') || (Ch == L'\n') || (Ch == L'\v') || (Ch == L'\f');
|
||||
}
|
||||
|
||||
@ -504,6 +504,9 @@
|
||||
## Include/Acidanthera/Protocol/OcForceResolution.h
|
||||
gOcForceResolutionProtocolGuid = { 0xBC7EC589, 0x2390, 0x4DA3, { 0x80, 0x25, 0x77, 0xDA, 0xD3, 0x4F, 0x36, 0x09 }}
|
||||
|
||||
## Include/Acidanthera/Protocol/OcBootEntry.h
|
||||
gOcBootEntryProtocolGuid = { 0x8604716E, 0xADD4, 0x45B4, { 0x84, 0x95, 0x08, 0xE3, 0x6D, 0x49, 0x7F, 0x4F }}
|
||||
|
||||
## Include/AMI/Protocol/AmiPointer.h
|
||||
gAmiEfiPointerProtocolGuid = { 0x15A10CE7, 0xEAB5, 0x43BF, { 0x90, 0x42, 0x74, 0x43, 0x2E, 0x69, 0x63, 0x77 }}
|
||||
|
||||
@ -849,6 +852,9 @@
|
||||
## @libraryclass
|
||||
OcFirmwareVolumeLib|Include/Acidanthera/Library/OcFirmwareVolumeLib.h
|
||||
|
||||
## @libraryclass
|
||||
OcFlexArrayLib|Include/Acidanthera/Library/OcFlexArrayLib.h
|
||||
|
||||
## @libraryclass
|
||||
OcGuardLib|Include/Acidanthera/Library/OcGuardLib.h
|
||||
|
||||
|
||||
@ -87,6 +87,7 @@
|
||||
OcFileLib|OpenCorePkg/Library/OcFileLib/OcFileLib.inf
|
||||
OcFirmwarePasswordLib|OpenCorePkg/Library/OcFirmwarePasswordLib/OcFirmwarePasswordLib.inf
|
||||
OcFirmwareVolumeLib|OpenCorePkg/Library/OcFirmwareVolumeLib/OcFirmwareVolumeLib.inf
|
||||
OcFlexArrayLib|OpenCorePkg/Library/OcFlexArrayLib/OcFlexArrayLib.inf
|
||||
OcGuardLib|OpenCorePkg/Library/OcGuardLib/OcGuardLib.inf
|
||||
OcHashServicesLib|OpenCorePkg/Library/OcHashServicesLib/OcHashServicesLib.inf
|
||||
OcHdaDevicesLib|OpenCorePkg/Library/OcHdaDevicesLib/OcHdaDevicesLib.inf
|
||||
@ -229,6 +230,7 @@
|
||||
OpenCorePkg/Library/OcFileLib/OcFileLib.inf
|
||||
OpenCorePkg/Library/OcFirmwarePasswordLib/OcFirmwarePasswordLib.inf
|
||||
OpenCorePkg/Library/OcFirmwareVolumeLib/OcFirmwareVolumeLib.inf
|
||||
OpenCorePkg/Library/OcFlexArrayLib/OcFlexArrayLib.inf
|
||||
OpenCorePkg/Library/OcGuardLib/OcGuardLib.inf
|
||||
OpenCorePkg/Library/OcHashServicesLib/OcHashServicesLib.inf
|
||||
OpenCorePkg/Library/OcHdaDevicesLib/OcHdaDevicesLib.inf
|
||||
@ -259,6 +261,7 @@
|
||||
OpenCorePkg/Library/OcXmlLib/OcXmlLib.inf
|
||||
OpenCorePkg/Platform/CrScreenshotDxe/CrScreenshotDxe.inf
|
||||
OpenCorePkg/Platform/OpenCanopy/OpenCanopy.inf
|
||||
OpenCorePkg/Platform/OpenLinuxBoot/OpenLinuxBoot.inf
|
||||
OpenCorePkg/Platform/OpenPartitionDxe/PartitionDxe.inf
|
||||
OpenCorePkg/Platform/OpenRuntime/OpenRuntime.inf
|
||||
OpenCorePkg/Platform/OpenUsbKbDxe/UsbKbDxe.inf
|
||||
|
||||
693
Platform/OpenLinuxBoot/Autodetect.c
Normal file
693
Platform/OpenLinuxBoot/Autodetect.c
Normal file
@ -0,0 +1,693 @@
|
||||
/** @file
|
||||
vmlinuz and initramfs/initrd autodetect.
|
||||
|
||||
Copyright (c) 2021, Mike Beaton. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#include "LinuxBootInternal.h"
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcBootManagementLib.h>
|
||||
#include <Library/OcDebugLogLib.h>
|
||||
#include <Library/OcFileLib.h>
|
||||
#include <Library/OcFlexArrayLib.h>
|
||||
#include <Library/OcStringLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
|
||||
#include <Protocol/OcBootEntry.h>
|
||||
|
||||
#define GRUB_DEFAULT_FILE L"\\etc\\default\\grub"
|
||||
#define OS_RELEASE_FILE L"\\etc\\os-release"
|
||||
#define AUTODETECT_DIR L"\\boot"
|
||||
#define ROOT_FS_FILE L"\\bin\\sh"
|
||||
|
||||
STATIC
|
||||
OC_FLEX_ARRAY
|
||||
*mVmlinuzFiles;
|
||||
|
||||
STATIC
|
||||
OC_FLEX_ARRAY
|
||||
*mInitrdFiles;
|
||||
|
||||
STATIC
|
||||
OC_FLEX_ARRAY
|
||||
*mEtcOsReleaseOptions;
|
||||
|
||||
STATIC
|
||||
CHAR8
|
||||
*mPrettyName;
|
||||
|
||||
STATIC
|
||||
OC_FLEX_ARRAY
|
||||
*mEtcDefaultGrubOptions;
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
ProcessVmlinuzFile (
|
||||
EFI_FILE_HANDLE Directory,
|
||||
EFI_FILE_INFO *FileInfo,
|
||||
UINTN FileInfoSize,
|
||||
VOID *Context OPTIONAL
|
||||
)
|
||||
{
|
||||
CHAR16 *Dash;
|
||||
VMLINUZ_FILE *VmlinuzFile;
|
||||
|
||||
if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
//
|
||||
// Do not use files without '-' in the name, i.e. we do not need and
|
||||
// do not try to use `vmlinuz` or `initrd` symlinks even if present
|
||||
// (and even though we can in fact specify them as filenames and boot
|
||||
// fine from them).
|
||||
//
|
||||
Dash = OcStrChr (FileInfo->FileName, L'-');
|
||||
if (Dash == NULL || Dash[1] == L'\0') {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (StrnCmp (L"vmlinuz", FileInfo->FileName, L_STR_LEN (L"vmlinuz")) == 0) {
|
||||
VmlinuzFile = OcFlexArrayAddItem (mVmlinuzFiles);
|
||||
} else if (StrnCmp (L"init", FileInfo->FileName, L_STR_LEN (L"init")) == 0) {
|
||||
//
|
||||
// initrd* or initramfs*
|
||||
//
|
||||
VmlinuzFile = OcFlexArrayAddItem (mInitrdFiles);
|
||||
} else {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (VmlinuzFile == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
VmlinuzFile->FileName = AllocateCopyPool (StrSize (FileInfo->FileName), FileInfo->FileName);
|
||||
if (VmlinuzFile->FileName == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
VmlinuzFile->Version = &VmlinuzFile->FileName[&Dash[1] - FileInfo->FileName];
|
||||
VmlinuzFile->StrLen = StrLen (FileInfo->FileName);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
CreateAsciiRelativePath (
|
||||
CHAR8 **Dest,
|
||||
CHAR16 *DirectoryPath,
|
||||
UINTN DirectoryPathLength,
|
||||
CHAR16 *FilePath,
|
||||
UINTN FilePathLength
|
||||
)
|
||||
{
|
||||
UINTN Size;
|
||||
|
||||
Size = DirectoryPathLength + FilePathLength + 2;
|
||||
*Dest = AllocatePool (Size);
|
||||
if (*Dest == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
AsciiSPrint (*Dest, Size, "%s\\%s", DirectoryPath, FilePath);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
CreateRootPartuuid (
|
||||
CHAR8 **Dest
|
||||
)
|
||||
{
|
||||
UINTN Length;
|
||||
UINTN NumPrinted;
|
||||
|
||||
Length = L_STR_LEN ("root=PARTUUID=") + OC_EFI_GUID_STR_LEN;
|
||||
|
||||
*Dest = AllocatePool (Length + 1);
|
||||
if (*Dest == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
NumPrinted = AsciiSPrint (*Dest, Length + 1, "%a%g", "root=PARTUUID=", gPartuuid);
|
||||
ASSERT (NumPrinted == Length);
|
||||
|
||||
OcAsciiToLower (&(*Dest)[L_STR_LEN ("root=PARTUUID=")]);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
AutodetectTitle (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
CHAR8 *AsciiStrValue;
|
||||
BOOLEAN Found;
|
||||
|
||||
mPrettyName = NULL;
|
||||
if (mEtcOsReleaseOptions != NULL) {
|
||||
//
|
||||
// If neither are present, default title gets set later to "Linux".
|
||||
//
|
||||
Found = FALSE;
|
||||
for (Index = 0; Index < 2; Index++) {
|
||||
if (OcParsedVarsGetAsciiStr (
|
||||
mEtcOsReleaseOptions,
|
||||
Index == 0 ? "PRETTY_NAME" : "NAME",
|
||||
&AsciiStrValue
|
||||
) &&
|
||||
AsciiStrValue != NULL) {
|
||||
mPrettyName = AsciiStrValue;
|
||||
Found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Found) {
|
||||
DEBUG ((DEBUG_INFO, "LNX: Found distro %a\n", mPrettyName));
|
||||
} else {
|
||||
DEBUG ((DEBUG_WARN, "LNX: Neither %a nor %a found in %s\n", "PRETTY_NAME", "NAME", OS_RELEASE_FILE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
LoadEtcFiles (
|
||||
IN CONST EFI_FILE_PROTOCOL *RootDirectory
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
CHAR8 *Contents;
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
|
||||
mEtcOsReleaseOptions = NULL;
|
||||
|
||||
//
|
||||
// Load distro name from /etc/os-release.
|
||||
//
|
||||
Contents = OcReadFileFromDirectory (RootDirectory, OS_RELEASE_FILE, NULL, 0);
|
||||
if (Contents == NULL) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: %s not found\n", OS_RELEASE_FILE));
|
||||
} else {
|
||||
DEBUG ((DEBUG_INFO, "LNX: Reading %s\n", OS_RELEASE_FILE));
|
||||
Status = OcParseVars (Contents, &mEtcOsReleaseOptions, FALSE);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (Contents);
|
||||
DEBUG ((DEBUG_WARN, "LNX: Cannot parse %s - %r\n", OS_RELEASE_FILE, Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Do this early purely to give a nicer log entry order - distro is named
|
||||
// before reports about it (esp. e.g. error below if it is not GRUB-based).
|
||||
//
|
||||
AutodetectTitle ();
|
||||
}
|
||||
|
||||
//
|
||||
// Load kernel options from /etc/default/grub.
|
||||
//
|
||||
Contents = OcReadFileFromDirectory (RootDirectory, GRUB_DEFAULT_FILE, NULL, 0);
|
||||
if (Contents == NULL) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: %s not found (bootloader is not GRUB?)\n", GRUB_DEFAULT_FILE));
|
||||
} else {
|
||||
DEBUG ((DEBUG_INFO, "LNX: Reading %s\n", GRUB_DEFAULT_FILE));
|
||||
Status = OcParseVars (Contents, &mEtcDefaultGrubOptions, FALSE);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (Contents);
|
||||
DEBUG ((DEBUG_WARN, "LNX: Cannot parse %s - %r\n", GRUB_DEFAULT_FILE, Status));
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
FreeEtcFiles (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
OcFlexArrayFree (&mEtcOsReleaseOptions);
|
||||
OcFlexArrayFree (&mEtcDefaultGrubOptions);
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
InsertOption (
|
||||
IN CONST UINTN InsertIndex,
|
||||
IN OC_FLEX_ARRAY *Options,
|
||||
IN CONST VOID *Value,
|
||||
IN CONST BOOLEAN IsUnicode
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN OptionsLength;
|
||||
UINTN CopiedLength;
|
||||
CHAR8 **Option;
|
||||
|
||||
if (IsUnicode) {
|
||||
OptionsLength = StrLen (Value);
|
||||
} else {
|
||||
OptionsLength = AsciiStrLen (Value);
|
||||
}
|
||||
|
||||
if (OptionsLength > 0) {
|
||||
Option = OcFlexArrayInsertItem (Options, InsertIndex);
|
||||
if (Option == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
if (IsUnicode) {
|
||||
*Option = AllocatePool ((OptionsLength + 1) * sizeof (CHAR16));
|
||||
if (*Option == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Status = UnicodeStrnToAsciiStrS (Value, OptionsLength, *Option, OptionsLength + 1, &CopiedLength);
|
||||
ASSERT (!EFI_ERROR (Status));
|
||||
ASSERT (CopiedLength == OptionsLength);
|
||||
} else {
|
||||
*Option = AllocateCopyPool (OptionsLength + 1, Value);
|
||||
if (*Option == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
AddOption (
|
||||
IN OC_FLEX_ARRAY *Options,
|
||||
IN CONST VOID *Value,
|
||||
IN CONST BOOLEAN IsUnicode
|
||||
)
|
||||
{
|
||||
return InsertOption (Options->Count, Options, Value, IsUnicode);
|
||||
}
|
||||
|
||||
//
|
||||
// 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
|
||||
EFI_STATUS
|
||||
AutodetectBootOptions (
|
||||
IN CONST BOOLEAN IsRescue,
|
||||
IN OC_FLEX_ARRAY *Options
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN Index;
|
||||
UINTN InsertIndex;
|
||||
OC_PARSED_VAR *Option;
|
||||
EFI_GUID Guid;
|
||||
CHAR8 *AsciiStrValue;
|
||||
BOOLEAN Found;
|
||||
|
||||
if ((gLinuxBootFlags & LINUX_BOOT_ADD_RO) != 0) {
|
||||
DEBUG ((OC_TRACE_KERNEL_OPTS, "LNX: Adding \"ro\"\n"));
|
||||
Status = AddOption (Options, "ro", FALSE);
|
||||
}
|
||||
|
||||
Found = FALSE;
|
||||
InsertIndex = Options->Count;
|
||||
|
||||
//
|
||||
// Look for user-specified options for this partuuid.
|
||||
// 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 < gParsedLoadOptions->Count; Index++) {
|
||||
Option = OcFlexArrayItemAt (gParsedLoadOptions, Index);
|
||||
//
|
||||
// partuuidopts:{partuuid}[+]="...": user options for specified partuuid.
|
||||
//
|
||||
if (OcUnicodeStartsWith (Option->Unicode.Name, L"partuuidopts:", 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);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: Cannot parse partuuid from %s - %r\n", Option->Unicode.Name, Status));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CompareMem (&gPartuuid, &Guid, sizeof (EFI_GUID)) != 0) {
|
||||
DEBUG ((OC_TRACE_KERNEL_OPTS, "LNX: No match %g != %g\n", &gPartuuid, &Guid));
|
||||
} else {
|
||||
DEBUG ((OC_TRACE_KERNEL_OPTS, "LNX: Using partuuidopts=\"%s\"\n", Option->Unicode.Value));
|
||||
|
||||
Status = AddOption (Options, Option->Unicode.Value, TRUE);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// partuuidopts:{partuuid}+="...": use user options in addition to detected options.
|
||||
//
|
||||
if (!OcUnicodeEndsWith (Option->Unicode.Name, L"+", FALSE)) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
Found = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Use options from GRUB default location.
|
||||
//
|
||||
if (mEtcDefaultGrubOptions != NULL) {
|
||||
//
|
||||
// If both are present both should be added, standard grub scripts add them
|
||||
// in this order.
|
||||
// Rescue should only use GRUB_CMDLINE_LINUX so this is correct as
|
||||
// far as it goes; however note that rescue options are unfortunately not
|
||||
// normally stored here, but are generated in the depths of grub scripts.
|
||||
//
|
||||
for (Index = 0; Index < (IsRescue ? 1u : 2u); Index++) {
|
||||
if (OcParsedVarsGetAsciiStr (
|
||||
mEtcDefaultGrubOptions,
|
||||
Index == 0 ? "GRUB_CMDLINE_LINUX" : "GRUB_CMDLINE_LINUX_DEFAULT",
|
||||
&AsciiStrValue
|
||||
) &&
|
||||
AsciiStrValue != NULL) {
|
||||
|
||||
//
|
||||
// Insert these after "ro" but before "partuuidopts+".
|
||||
//
|
||||
if (AsciiStrValue[0] != '\0') {
|
||||
Status = InsertOption (InsertIndex, Options, AsciiStrValue, FALSE);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
InsertIndex++;
|
||||
}
|
||||
|
||||
//
|
||||
// Empty string value is good enough for found: we are operating
|
||||
// from GRUB cfg files rather than pure guesswork.
|
||||
//
|
||||
Found = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Use global defaults, if user has defined any.
|
||||
//
|
||||
for (Index = 0; Index < gParsedLoadOptions->Count; Index++) {
|
||||
Option = OcFlexArrayItemAt (gParsedLoadOptions, Index);
|
||||
if (!Found && 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;
|
||||
}
|
||||
|
||||
Status = AddOption (Options, Option->Unicode.Value, TRUE);
|
||||
return Status;
|
||||
} 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;
|
||||
}
|
||||
|
||||
Status = AddOption (Options, Option->Unicode.Value, TRUE);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Found = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// It might be valid to have no options except "ro", but at least empty
|
||||
// string "GRUB_CMDLINE_LINUX" needs to be present in that case or we stop.
|
||||
//
|
||||
if (!Found) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: No grub default or user defined options - aborting\n"));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
GenerateEntriesForVmlinuzFiles (
|
||||
IN CHAR16 *DirectoryPath
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN VmlinuzIndex;
|
||||
UINTN InitrdIndex;
|
||||
UINTN ShortestMatch;
|
||||
UINTN DirectoryPathLength;
|
||||
NAMED_LOADER_ENTRY *NamedEntry;
|
||||
LOADER_ENTRY *Entry;
|
||||
VMLINUZ_FILE *VmlinuzFile;
|
||||
VMLINUZ_FILE *InitrdFile;
|
||||
VMLINUZ_FILE *InitrdMatch;
|
||||
CHAR8 **Option;
|
||||
BOOLEAN IsRescue;
|
||||
|
||||
ASSERT (DirectoryPath != NULL);
|
||||
DirectoryPathLength = StrLen (DirectoryPath);
|
||||
|
||||
for (VmlinuzIndex = 0; VmlinuzIndex < mVmlinuzFiles->Count; VmlinuzIndex++) {
|
||||
VmlinuzFile = OcFlexArrayItemAt (mVmlinuzFiles, VmlinuzIndex);
|
||||
|
||||
IsRescue = FALSE;
|
||||
if (OcUnicodeStartsWith (VmlinuzFile->Version, L"0", FALSE)
|
||||
|| StrStr (VmlinuzFile->Version, L"rescue") != NULL
|
||||
|| StrStr (VmlinuzFile->Version, L"recovery") != NULL) {
|
||||
//
|
||||
// We might have to scan /boot/grb/grub.cfg as grub os-prober does if
|
||||
// we want to find rescue version options, or we need to find a way
|
||||
// for user to pass these in, since they are generated in the depths
|
||||
// of the grub scripts, and in typical distros are not present in
|
||||
// /etc/default/grub, even though it looks as if they could be.
|
||||
//
|
||||
IsRescue = TRUE;
|
||||
DEBUG ((DEBUG_INFO, "LNX: %s=rescue\n", VmlinuzFile->Version));
|
||||
}
|
||||
|
||||
ShortestMatch = MAX_UINTN;
|
||||
InitrdMatch = NULL;
|
||||
|
||||
//
|
||||
// Find shortest init* filename containing the same version string.
|
||||
//
|
||||
for (InitrdIndex = 0; InitrdIndex < mInitrdFiles->Count; InitrdIndex++) {
|
||||
InitrdFile = OcFlexArrayItemAt (mInitrdFiles, InitrdIndex);
|
||||
if (InitrdFile->StrLen < ShortestMatch) {
|
||||
if (StrStr (InitrdFile->Version, VmlinuzFile->Version) != NULL) {
|
||||
InitrdMatch = InitrdFile;
|
||||
ShortestMatch = InitrdFile->StrLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Entry = InternalAllocateLoaderEntry ();
|
||||
if (Entry == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
//
|
||||
// Linux.
|
||||
//
|
||||
Status = CreateAsciiRelativePath (&Entry->Linux, DirectoryPath, DirectoryPathLength, VmlinuzFile->FileName, VmlinuzFile->StrLen);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Version.
|
||||
//
|
||||
Entry->Version = AllocateCopyPool (
|
||||
VmlinuzFile->StrLen - (VmlinuzFile->Version - VmlinuzFile->FileName) + 1,
|
||||
&Entry->Linux[VmlinuzFile->Version - VmlinuzFile->FileName + DirectoryPathLength + 1]
|
||||
);
|
||||
if (Entry->Version == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
//
|
||||
// FileName & Id.
|
||||
//
|
||||
NamedEntry = InternalCreateNamedLoaderEntry (Entry, VmlinuzFile->FileName);
|
||||
if (NamedEntry == NULL) {
|
||||
InternalFreeLoaderEntry (&Entry);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
} else {
|
||||
//
|
||||
// Named entry filename - do not free twice.
|
||||
//
|
||||
VmlinuzFile->FileName = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Use title from os-release file.
|
||||
//
|
||||
Entry->Title = AllocateCopyPool (AsciiStrSize (mPrettyName), mPrettyName);
|
||||
if (Entry->Title == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
//
|
||||
// Initrd.
|
||||
//
|
||||
if (InitrdMatch == NULL) {
|
||||
//
|
||||
// No need for WARN, where initrd was required user will see clear (and safe) warning from Linux kernel.
|
||||
//
|
||||
DEBUG ((DEBUG_INFO, "LNX: No matching initrd/initramfs file found for %a\n", Entry->Linux));
|
||||
} else {
|
||||
Option = OcFlexArrayAddItem (Entry->Initrds);
|
||||
if (Option == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
Status = CreateAsciiRelativePath (Option, DirectoryPath, DirectoryPathLength, InitrdMatch->FileName, InitrdMatch->StrLen);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// root=PARTUUID=... option.
|
||||
//
|
||||
Option = OcFlexArrayAddItem (Entry->Options);
|
||||
if (Option == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Status = CreateRootPartuuid (Option);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Remaining options.
|
||||
//
|
||||
Status = AutodetectBootOptions (IsRescue, Entry->Options);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
AutodetectLinux (
|
||||
IN EFI_FILE_PROTOCOL *RootDirectory,
|
||||
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 = OcEnsureDirectory (RootFsFile, FALSE);
|
||||
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)){
|
||||
mVmlinuzFiles = OcFlexArrayInit (sizeof (VMLINUZ_FILE), OcFlexArrayFreePointerItem);
|
||||
if (mVmlinuzFiles == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
if (!EFI_ERROR (Status)){
|
||||
mInitrdFiles = OcFlexArrayInit (sizeof (VMLINUZ_FILE), OcFlexArrayFreePointerItem);
|
||||
if (mInitrdFiles == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Place vmlinuz* and init* files into arrays.
|
||||
//
|
||||
if (!EFI_ERROR (Status)){
|
||||
Status = OcScanDirectory (VmlinuzDirectory, ProcessVmlinuzFile, NULL);
|
||||
}
|
||||
|
||||
if (!EFI_ERROR (Status)) {
|
||||
gNamedLoaderEntries = OcFlexArrayInit (sizeof (NAMED_LOADER_ENTRY), (OC_FLEX_ARRAY_FREE_ITEM) InternalFreeNamedLoaderEntry);
|
||||
if (gNamedLoaderEntries == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
} else {
|
||||
Status = LoadEtcFiles (RootDirectory);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
Status = GenerateEntriesForVmlinuzFiles (AUTODETECT_DIR);
|
||||
}
|
||||
FreeEtcFiles();
|
||||
}
|
||||
|
||||
if (!EFI_ERROR (Status)) {
|
||||
Status = InternalConvertNamedLoaderEntriesToBootEntries (
|
||||
RootDirectory,
|
||||
Entries,
|
||||
NumEntries
|
||||
);
|
||||
}
|
||||
|
||||
OcFlexArrayFree (&gNamedLoaderEntries);
|
||||
}
|
||||
|
||||
if (mVmlinuzFiles != NULL) {
|
||||
OcFlexArrayFree (&mVmlinuzFiles);
|
||||
}
|
||||
|
||||
if (mInitrdFiles != NULL) {
|
||||
OcFlexArrayFree (&mInitrdFiles);
|
||||
}
|
||||
|
||||
VmlinuzDirectory->Close (VmlinuzDirectory);
|
||||
return Status;
|
||||
}
|
||||
472
Platform/OpenLinuxBoot/GrubCfg.c
Normal file
472
Platform/OpenLinuxBoot/GrubCfg.c
Normal file
@ -0,0 +1,472 @@
|
||||
/** @file
|
||||
Naive GRUB config parser.
|
||||
|
||||
Attemps to respect GRUB escape and line continuation syntax, and
|
||||
then to extract GRUB set commands for some basic processing.
|
||||
|
||||
Copyright (c) 2021, Mike Beaton. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#include "LinuxBootInternal.h"
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/OcDebugLogLib.h>
|
||||
#include <Library/OcMiscLib.h>
|
||||
#include <Library/OcStringLib.h>
|
||||
|
||||
/*
|
||||
grub.cfg processing states.
|
||||
*/
|
||||
typedef enum GRUB_PARSE_STATE_ {
|
||||
GRUB_LEADING_SPACE,
|
||||
GRUB_COMMENT,
|
||||
GRUB_TOKEN,
|
||||
GRUB_SINGLE_QUOTE,
|
||||
GRUB_DOUBLE_QUOTE
|
||||
} GRUB_PARSE_STATE;
|
||||
|
||||
/*
|
||||
grub.cfg $var processing states.
|
||||
*/
|
||||
typedef enum GRUB_VAR_STATE_ {
|
||||
GRUB_VAR_NONE,
|
||||
GRUB_VAR_START,
|
||||
GRUB_VAR_END,
|
||||
GRUB_VAR_CHAR
|
||||
} GRUB_VAR_STATE;
|
||||
|
||||
#define GRUB_LINE "in grub.cfg at line"
|
||||
|
||||
/*
|
||||
grub.cfg $var processing flags.
|
||||
*/
|
||||
#define VAR_FLAGS_NONE (0)
|
||||
#define VAR_FLAGS_BRACE BIT0
|
||||
#define VAR_FLAGS_NUMERIC BIT1
|
||||
|
||||
#define SHIFT_TOKEN(offset) { \
|
||||
CopyMem (*Token + (offset), *Token, &Content[*Pos] - *Token); \
|
||||
*Token += (offset); \
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
GrubNextToken (
|
||||
CHAR8 *Content,
|
||||
UINTN *Pos,
|
||||
UINTN *Line,
|
||||
CHAR8 **Token,
|
||||
BOOLEAN *IsIndented,
|
||||
BOOLEAN *ContainsVars
|
||||
)
|
||||
{
|
||||
GRUB_PARSE_STATE GrubState;
|
||||
GRUB_VAR_STATE VarState;
|
||||
UINTN GrubVarFlags;
|
||||
|
||||
BOOLEAN Escaped;
|
||||
BOOLEAN TokenCompleted;
|
||||
BOOLEAN Retake;
|
||||
|
||||
CHAR8 Ch;
|
||||
CHAR8 Ch2;
|
||||
|
||||
UINTN Add;
|
||||
|
||||
*Token = NULL;
|
||||
*IsIndented = FALSE;
|
||||
*ContainsVars = FALSE;
|
||||
|
||||
GrubState = GRUB_LEADING_SPACE;
|
||||
VarState = GRUB_VAR_NONE;
|
||||
|
||||
Escaped = FALSE;
|
||||
TokenCompleted = FALSE;
|
||||
Retake = FALSE;
|
||||
|
||||
do {
|
||||
Ch = Content[*Pos];
|
||||
|
||||
if (Ch == '\n') {
|
||||
*Line += 1;
|
||||
} else if (!(Ch == '\0' || Ch == '\t' || (Ch >= 32 && Ch <= 127))) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: Invalid char 0x%x %a %u\n", Ch, GRUB_LINE, Line));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Deal with escape char and line continuation.
|
||||
//
|
||||
if (Ch == '\\') {
|
||||
Ch2 = Content[(*Pos) + 1];
|
||||
|
||||
if (Ch2 == '\0' || Ch2 == '\n') {
|
||||
//
|
||||
// Line continuation.
|
||||
//
|
||||
if (VarState != GRUB_VAR_NONE) {
|
||||
//
|
||||
// We could handle this fine (just remove this check), but GRUB doesn't:
|
||||
// https://www.gnu.org/software/grub/manual/grub/html_node/grub_fot.html#FOOT7
|
||||
//
|
||||
DEBUG ((DEBUG_WARN, "LNX: Illegal line continuation within variable name %a %u\n", GRUB_LINE, Line));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// '\n' go to char afterwards, '\0' go to '\0'.
|
||||
//
|
||||
Add = (Ch2 == '\n' ? 2 : 1);
|
||||
SHIFT_TOKEN (Add);
|
||||
*Pos += Add;
|
||||
Ch = Content[*Pos];
|
||||
*Line += 1;
|
||||
} else {
|
||||
//
|
||||
// Escapes.
|
||||
//
|
||||
switch (GrubState) {
|
||||
//
|
||||
// No escapes in single quote.
|
||||
//
|
||||
case GRUB_SINGLE_QUOTE:
|
||||
break;
|
||||
|
||||
//
|
||||
// Only these escapes in double quote.
|
||||
//
|
||||
case GRUB_DOUBLE_QUOTE:
|
||||
if (Ch2 == '$' || Ch2 == '"') {
|
||||
Escaped = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
//
|
||||
// Anything can be escaped.
|
||||
//
|
||||
default:
|
||||
Escaped = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Escaped) {
|
||||
SHIFT_TOKEN (1);
|
||||
++(*Pos);
|
||||
Ch = Ch2;
|
||||
Escaped = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Grub var is a special state which can be entered within other states.
|
||||
// Allowed: $?, $@, $#, $nnn, $alphanumeric
|
||||
//
|
||||
if (VarState != GRUB_VAR_NONE) {
|
||||
ASSERT (GrubState == GRUB_TOKEN || GrubState == GRUB_SINGLE_QUOTE || GrubState == GRUB_DOUBLE_QUOTE);
|
||||
|
||||
switch (VarState) {
|
||||
case GRUB_VAR_START:
|
||||
//
|
||||
// The fact that a token contains a var reference means we cannot use it;
|
||||
// we are looking for tokens which define vars, not ones which use them.
|
||||
//
|
||||
*ContainsVars = TRUE;
|
||||
|
||||
if (Ch == '{') {
|
||||
if ((GrubVarFlags & VAR_FLAGS_BRACE) != 0) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: Illegal character in variable name %a %u\n", GRUB_LINE, Line));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
GrubVarFlags |= VAR_FLAGS_BRACE;
|
||||
} else if (Ch == '}') {
|
||||
//
|
||||
// Empty var name is valid.
|
||||
//
|
||||
if ((GrubVarFlags & VAR_FLAGS_BRACE) == 0) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: Illegal character in variable name %a %u\n", GRUB_LINE, Line));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
VarState = GRUB_VAR_NONE;
|
||||
} else if (Ch == '@' || Ch == '?' || Ch == '#') {
|
||||
VarState = GRUB_VAR_END;
|
||||
} else if (IS_DIGIT (Ch)) {
|
||||
GrubVarFlags |= VAR_FLAGS_NUMERIC;
|
||||
VarState = GRUB_VAR_CHAR;
|
||||
} else if (Ch == '_' || IS_ALPHA (Ch)) {
|
||||
VarState = GRUB_VAR_CHAR;
|
||||
} else {
|
||||
DEBUG ((DEBUG_WARN, "LNX: Illegal character in variable name %a %u\n", GRUB_LINE, Line));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case GRUB_VAR_END:
|
||||
if ((GrubVarFlags & VAR_FLAGS_BRACE) != 0) {
|
||||
if (Ch != '}') {
|
||||
DEBUG ((DEBUG_WARN, "LNX: Illegal character in variable name %a %u\n", GRUB_LINE, Line));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
} else {
|
||||
Retake = TRUE;
|
||||
}
|
||||
VarState = GRUB_VAR_NONE;
|
||||
break;
|
||||
|
||||
case GRUB_VAR_CHAR:
|
||||
if (!(IS_DIGIT (Ch) ||
|
||||
((GrubVarFlags & VAR_FLAGS_NUMERIC) == 0
|
||||
&& (Ch == '_' || IS_ALPHA (Ch))))) {
|
||||
VarState = GRUB_VAR_END;
|
||||
Retake = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT (FALSE);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (GrubState) {
|
||||
case GRUB_LEADING_SPACE:
|
||||
if (Ch == '\0' || Ch == '\n' || (!Escaped && Ch == ';')) {
|
||||
TokenCompleted = TRUE;
|
||||
Retake = TRUE;
|
||||
} else if (Ch == ' ' || Ch == '\t') {
|
||||
*IsIndented = TRUE;
|
||||
} else if (Ch == '#') {
|
||||
GrubState = GRUB_COMMENT;
|
||||
} else {
|
||||
*Token = &Content[*Pos];
|
||||
GrubState = GRUB_TOKEN;
|
||||
Retake = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRUB_COMMENT:
|
||||
if (Ch == '\n' || Ch == '\0') {
|
||||
TokenCompleted = TRUE;
|
||||
Retake = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRUB_TOKEN:
|
||||
if (Ch == '\n' || Ch == '\0' || (!Escaped && (Ch == ';' || Ch == ' ' || Ch == '\t'))) {
|
||||
TokenCompleted = TRUE;
|
||||
Retake = TRUE;
|
||||
} else if (!Escaped && Ch == '\'') {
|
||||
SHIFT_TOKEN (1);
|
||||
GrubState = GRUB_SINGLE_QUOTE;
|
||||
} else if (!Escaped && Ch == '"') {
|
||||
SHIFT_TOKEN (1);
|
||||
GrubState = GRUB_DOUBLE_QUOTE;
|
||||
} else if (!Escaped && Ch == '$') {
|
||||
VarState = GRUB_VAR_START;
|
||||
GrubVarFlags = VAR_FLAGS_NONE;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRUB_SINGLE_QUOTE:
|
||||
if (Ch == '\'') {
|
||||
SHIFT_TOKEN (1);
|
||||
GrubState = GRUB_TOKEN;
|
||||
} else if (Ch == '$') {
|
||||
VarState = GRUB_VAR_START;
|
||||
GrubVarFlags = VAR_FLAGS_NONE;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRUB_DOUBLE_QUOTE:
|
||||
if (!Escaped && Ch == '"') {
|
||||
SHIFT_TOKEN (1);
|
||||
GrubState = GRUB_TOKEN;
|
||||
} else if (!Escaped && Ch == '$') {
|
||||
VarState = GRUB_VAR_START;
|
||||
GrubVarFlags = VAR_FLAGS_NONE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Retake) {
|
||||
Retake = FALSE;
|
||||
} else if (Ch != '\0') {
|
||||
++(*Pos);
|
||||
}
|
||||
}
|
||||
while (Ch != '\0' && !TokenCompleted);
|
||||
|
||||
if (!TokenCompleted && GrubState != GRUB_LEADING_SPACE) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: Syntax error (state=%u) %a %u\n", GrubState, GRUB_LINE, Line));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
BOOLEAN
|
||||
GrubNextLine (
|
||||
CHAR8 Ch,
|
||||
UINTN *Pos
|
||||
)
|
||||
{
|
||||
if (Ch == '\0') {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (Ch == ';' || Ch == '\n') {
|
||||
(*Pos)++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ASSERT (Ch == ' ' || Ch == '\t');
|
||||
|
||||
(*Pos)++;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
SetVar (
|
||||
UINTN Line,
|
||||
CHAR8 *Token,
|
||||
BOOLEAN IsIndented,
|
||||
BOOLEAN ContainsVars
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
CHAR8 *Equals;
|
||||
CHAR8 *Dollar;
|
||||
UINTN VarStatus;
|
||||
|
||||
//
|
||||
// Note: It is correct grub2 parsing to treat these tokens with = in (whether after set or not) as one token.
|
||||
//
|
||||
Equals = OcAsciiStrChr (Token, '=');
|
||||
if (Equals == NULL) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: Invalid set command %a %u\n", GRUB_LINE, Line));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
*Equals = '\0';
|
||||
|
||||
Dollar = OcAsciiStrChr (Token, '$');
|
||||
if (Dollar != NULL) {
|
||||
//
|
||||
// Non-typical but valid GRUB syntax to use variable replacements within
|
||||
// variable name; we don't know what the name is (and are probably pretty
|
||||
// unlikely to find the required values in valid, non-indented variables
|
||||
// which we do know), so we ignore it.
|
||||
//
|
||||
DEBUG ((DEBUG_WARN, "LNX: Ignoring tokenised %a %a %a %u\n", "variable name", Token, GRUB_LINE, Line));
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
VarStatus = 0;
|
||||
if (IsIndented) {
|
||||
VarStatus |= VAR_ERR_INDENTED;
|
||||
}
|
||||
if (ContainsVars) {
|
||||
VarStatus |= VAR_ERR_HAS_VARS;
|
||||
}
|
||||
Status = InternalSetGrubVar (Token, Equals + 1, VarStatus);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
InternalProcessGrubCfg (
|
||||
IN OUT CHAR8 *Content
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN Pos;
|
||||
UINTN Line;
|
||||
UINTN NextLine;
|
||||
UINTN TokenIndex;
|
||||
CHAR8 *Dollar;
|
||||
CHAR8 *Equals;
|
||||
CHAR8 *Token;
|
||||
CHAR8 LastChar;
|
||||
BOOLEAN IsIndented;
|
||||
BOOLEAN ContainsVars;
|
||||
BOOLEAN SetCommand;
|
||||
BOOLEAN SetIsIndented;
|
||||
|
||||
Pos = 0;
|
||||
Line = 1;
|
||||
|
||||
do {
|
||||
TokenIndex = 0;
|
||||
SetCommand = FALSE;
|
||||
|
||||
do {
|
||||
//
|
||||
// Save new line number until we've finished any messages.
|
||||
//
|
||||
NextLine = Line;
|
||||
Status = GrubNextToken (Content, &Pos, &NextLine, &Token, &IsIndented, &ContainsVars);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Terminate token and remember terminator char.
|
||||
//
|
||||
LastChar = Content[Pos];
|
||||
if (Token != NULL) {
|
||||
Content[Pos] = '\0';
|
||||
|
||||
if (TokenIndex == 0) {
|
||||
//
|
||||
// Warn on pretty obscure - though valid - syntax of building the command name from variables;
|
||||
// do not warn for direct setting of grub internal values with no set command, i.e. just name=value,
|
||||
// where the $ is only in the value.
|
||||
//
|
||||
Dollar = OcAsciiStrChr (Token, '$');
|
||||
if (Dollar != NULL) {
|
||||
Equals = OcAsciiStrChr (Token, '=');
|
||||
if (Equals == NULL || Dollar < Equals) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: Ignoring tokenised %a %a %a %u\n", "command", Token, GRUB_LINE, Line));
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// No non-indented variables after non-indented blscfg command can be used.
|
||||
//
|
||||
if (AsciiStrCmp("blscfg", Token) == 0) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// We could process grub unset command similarly to set, but we probably don't need it.
|
||||
//
|
||||
if (AsciiStrCmp("set", Token) == 0) {
|
||||
SetCommand = TRUE;
|
||||
SetIsIndented = IsIndented;
|
||||
}
|
||||
}
|
||||
} else if (TokenIndex == 1 && SetCommand) {
|
||||
Status = SetVar (Line, Token, SetIsIndented, ContainsVars);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
++TokenIndex;
|
||||
}
|
||||
Line = NextLine;
|
||||
} while (!GrubNextLine (LastChar, &Pos));
|
||||
} while (LastChar != '\0');
|
||||
|
||||
//
|
||||
// Possibly allow through on flag?
|
||||
//
|
||||
DEBUG ((DEBUG_WARN, "LNX: blscfg command not found in grub.cfg\n"));
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
85
Platform/OpenLinuxBoot/GrubEnv.c
Normal file
85
Platform/OpenLinuxBoot/GrubEnv.c
Normal file
@ -0,0 +1,85 @@
|
||||
/** @file
|
||||
GRUB environment block parser.
|
||||
|
||||
Copyright (c) 2021, Mike Beaton. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/OcDebugLogLib.h>
|
||||
#include "LinuxBootInternal.h"
|
||||
|
||||
/*
|
||||
grubenv processing states.
|
||||
*/
|
||||
typedef enum GRUBENV_STATE_ {
|
||||
GRUBENV_NEXT_LINE,
|
||||
GRUBENV_KEY,
|
||||
GRUBENV_VAR,
|
||||
GRUBENV_COMMENT
|
||||
} GRUBENV_STATE;
|
||||
|
||||
EFI_STATUS
|
||||
InternalProcessGrubEnv (
|
||||
IN OUT CHAR8 *Content,
|
||||
IN CONST UINTN Length
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN Pos;
|
||||
UINTN KeyStart;
|
||||
UINTN VarStart;
|
||||
GRUBENV_STATE State;
|
||||
|
||||
State = GRUBENV_NEXT_LINE;
|
||||
|
||||
//
|
||||
// In a valid grubenv block the last comment, if present, is not
|
||||
// \n terminated, but all var lines must be.
|
||||
//
|
||||
for (Pos = 0; Pos < Length && Content[Pos] != '\0'; Pos++) {
|
||||
switch (State) {
|
||||
case GRUBENV_NEXT_LINE:
|
||||
if (Content[Pos] == '#') {
|
||||
State = GRUBENV_COMMENT;
|
||||
} else {
|
||||
KeyStart = Pos;
|
||||
State = GRUBENV_KEY;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRUBENV_COMMENT:
|
||||
if (Content[Pos] == '\n') {
|
||||
State = GRUBENV_NEXT_LINE;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRUBENV_KEY:
|
||||
if (Content[Pos] == '=') {
|
||||
Content[Pos] = '\0';
|
||||
VarStart = Pos + 1;
|
||||
State = GRUBENV_VAR;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRUBENV_VAR:
|
||||
if (Content[Pos] == '\n') {
|
||||
Content[Pos] = '\0';
|
||||
Status = InternalSetGrubVar (&Content[KeyStart], &Content[VarStart], VAR_ERR_NONE);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
State = GRUBENV_NEXT_LINE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT (FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT (State == GRUBENV_COMMENT || State == GRUBENV_NEXT_LINE);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
273
Platform/OpenLinuxBoot/GrubVars.c
Normal file
273
Platform/OpenLinuxBoot/GrubVars.c
Normal file
@ -0,0 +1,273 @@
|
||||
/** @file
|
||||
Copyright (c) 2021, Mike Beaton. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#include "LinuxBootInternal.h"
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcDebugLogLib.h>
|
||||
#include <Library/OcFlexArrayLib.h>
|
||||
#include <Library/OcStringLib.h>
|
||||
#include <Library/OcStringLib.h>
|
||||
|
||||
#include <Protocol/OcBootEntry.h>
|
||||
|
||||
STATIC OC_FLEX_ARRAY *mGrubVars = NULL;
|
||||
|
||||
EFI_STATUS
|
||||
InternalInitGrubVars (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
mGrubVars = OcFlexArrayInit (sizeof (GRUB_VAR), NULL);
|
||||
if (mGrubVars == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
VOID
|
||||
InternalFreeGrubVars (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
if (mGrubVars != NULL) {
|
||||
OcFlexArrayFree (&mGrubVars);
|
||||
}
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
InternalSetGrubVar (
|
||||
CHAR8 *Key,
|
||||
CHAR8 *Value,
|
||||
UINTN Errors
|
||||
)
|
||||
{
|
||||
GRUB_VAR *Var;
|
||||
UINTN Index;
|
||||
UINTN WereErrors;
|
||||
|
||||
ASSERT (mGrubVars != NULL);
|
||||
ASSERT (Key[0] != '\0');
|
||||
|
||||
for (Index = 0; Index < mGrubVars->Count; ++Index) {
|
||||
Var = OcFlexArrayItemAt (mGrubVars, Index);
|
||||
if (AsciiStrCmp (Var->Key, Key) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Index < mGrubVars->Count) {
|
||||
Var->Value = Value;
|
||||
WereErrors = Var->Errors;
|
||||
|
||||
//
|
||||
// Probably not worth the two lines of code (because unlikely to
|
||||
// occur), but: allow later non-indented no-vars value to overwrite
|
||||
// earlier non-indented has-vars value and thereby become usable.
|
||||
//
|
||||
if ((Errors & VAR_ERR_INDENTED) == 0) {
|
||||
Var->Errors &= ~VAR_ERR_HAS_VARS;
|
||||
}
|
||||
|
||||
//
|
||||
// Indentation err stays set because, even if grub.cfg code layout is
|
||||
// reasonable as we are assuming, we are not parsing enough to tell
|
||||
// which order (or none) indented vars are set in.
|
||||
//
|
||||
Var->Errors |= Errors;
|
||||
|
||||
DEBUG ((OC_TRACE_GRUB_VARS,
|
||||
"LNX: Repeated %a=%a (0x%x->0x%x)\n",
|
||||
Key,
|
||||
Value,
|
||||
WereErrors,
|
||||
Var->Errors
|
||||
));
|
||||
} else {
|
||||
Var = OcFlexArrayAddItem (mGrubVars);
|
||||
if (Var == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Var->Key = Key;
|
||||
Var->Value = Value;
|
||||
Var->Errors = Errors;
|
||||
|
||||
DEBUG ((OC_TRACE_GRUB_VARS,
|
||||
"LNX: Added %a=%a (0x%x)\n",
|
||||
Key,
|
||||
Value,
|
||||
Errors
|
||||
));
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Compatible with Grub2 blscfg's simple definition of what gets replaced,
|
||||
// cf InternalExpandGrubVars. (If there was more complex logic, it would
|
||||
// probably make most sense just not to have this pre-check.)
|
||||
//
|
||||
BOOLEAN
|
||||
InternalHasGrubVars (
|
||||
CHAR8 *Value
|
||||
)
|
||||
{
|
||||
return OcAsciiStrChr (Value, '$') != NULL;
|
||||
}
|
||||
|
||||
GRUB_VAR *
|
||||
InternalGetGrubVar (
|
||||
IN CONST CHAR8 *Key
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
GRUB_VAR *Var;
|
||||
|
||||
for (Index = 0; Index < mGrubVars->Count; Index++) {
|
||||
Var = OcFlexArrayItemAt (mGrubVars, Index);
|
||||
if (AsciiStrCmp (Var->Key, Key) == 0) {
|
||||
return Var;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
InternalExpandGrubVarsForArray (
|
||||
IN OUT OC_FLEX_ARRAY *Options
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN Index;
|
||||
CHAR8 **Value;
|
||||
CHAR8 *Result;
|
||||
|
||||
for (Index = 0; Index < Options->Count; Index++) {
|
||||
Value = OcFlexArrayItemAt (Options, Index);
|
||||
if (InternalHasGrubVars (*Value)) {
|
||||
Status = InternalExpandGrubVars (*Value, &Result);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
FreePool (*Value);
|
||||
*Value = Result;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
InternalExpandGrubVars (
|
||||
IN CONST CHAR8 *Value,
|
||||
IN OUT CHAR8 **Result
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN Pos;
|
||||
UINTN LastPos;
|
||||
BOOLEAN InVar;
|
||||
BOOLEAN Retake;
|
||||
GRUB_VAR *Var;
|
||||
CHAR8 Ch;
|
||||
UINTN VarLength;
|
||||
OC_STRING_BUFFER *StringBuffer;
|
||||
|
||||
ASSERT (Value != NULL);
|
||||
ASSERT (Result != NULL);
|
||||
|
||||
*Result = NULL;
|
||||
|
||||
if (Value == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
StringBuffer = OcAsciiStringBufferInit ();
|
||||
if (StringBuffer == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Pos = 0;
|
||||
LastPos = 0;
|
||||
InVar = FALSE;
|
||||
Status = EFI_SUCCESS;
|
||||
|
||||
//
|
||||
// These simple checks for what counts as a var to replace (including
|
||||
// the fact that there is no escape for '$') match Grub2 blscfg module.
|
||||
//
|
||||
do {
|
||||
Ch = Value[Pos];
|
||||
if (!InVar) {
|
||||
if (Ch == '$' || Ch == '\0') {
|
||||
Status = OcAsciiStringBufferAppendN (StringBuffer, &Value[LastPos], Pos - LastPos);
|
||||
|
||||
InVar = TRUE;
|
||||
LastPos = Pos + 1;
|
||||
}
|
||||
} else if (!(Ch == '_' || IS_DIGIT (Ch) || IS_ALPHA (Ch))) {
|
||||
((CHAR8 *)Value)[Pos] = '\0';
|
||||
Var = InternalGetGrubVar (&Value[LastPos]);
|
||||
if (Var == NULL) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: Missing required grub var $%a\n", &Value[LastPos]));
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
} else if (Var->Errors != 0) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: Unusable grub var $%a - 0x%x\n", &Value[LastPos], Var->Errors));
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
}
|
||||
((CHAR8 *)Value)[Pos] = Ch;
|
||||
|
||||
//
|
||||
// Blscfg always appends a space to each expanded token (and the var values
|
||||
// are often set up to end with a space, too), then later GRUB tokenization
|
||||
// of the options as grub booter options (which we do not currently do - may
|
||||
// be needed in some escaped cases?) cleans it up. Here, we try to combine
|
||||
// obvious doubled up spaces right away.
|
||||
//
|
||||
if (!EFI_ERROR (Status)) {
|
||||
if (Var->Value != NULL) {
|
||||
VarLength = AsciiStrLen (Var->Value);
|
||||
if (VarLength > 0 && Var->Value[VarLength - 1] == ' ') {
|
||||
--VarLength;
|
||||
}
|
||||
}
|
||||
Status = OcAsciiStringBufferAppendN (StringBuffer, Var->Value, VarLength);
|
||||
}
|
||||
|
||||
if (!EFI_ERROR (Status) && !(Ch == ' ' || Ch == '\0')) {
|
||||
Status = OcAsciiStringBufferAppend (StringBuffer, " ");
|
||||
}
|
||||
|
||||
InVar = FALSE;
|
||||
Retake = TRUE;
|
||||
LastPos = Pos;
|
||||
}
|
||||
|
||||
if (Retake) {
|
||||
Retake = FALSE;
|
||||
} else {
|
||||
++Pos;
|
||||
}
|
||||
}
|
||||
while (Ch != '\0' && !EFI_ERROR (Status));
|
||||
|
||||
*Result = OcAsciiStringBufferFreeContainer (&StringBuffer);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
if (*Result != NULL) {
|
||||
FreePool (*Result);
|
||||
*Result = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG ((OC_TRACE_GRUB_VARS, "LNX: Expanding '%a' => '%a' - %r\n", Value, *Result, Status));
|
||||
|
||||
return Status;
|
||||
}
|
||||
360
Platform/OpenLinuxBoot/LinuxBootInternal.h
Normal file
360
Platform/OpenLinuxBoot/LinuxBootInternal.h
Normal file
@ -0,0 +1,360 @@
|
||||
/** @file
|
||||
Copyright (C) 2021, Mike Beaton. All rights reserved.<BR>
|
||||
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 <Uefi.h>
|
||||
#include <Library/OcBootManagementLib.h>
|
||||
#include <Library/OcMiscLib.h>
|
||||
|
||||
#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
|
||||
1169
Platform/OpenLinuxBoot/LoaderEntry.c
Normal file
1169
Platform/OpenLinuxBoot/LoaderEntry.c
Normal file
File diff suppressed because it is too large
Load Diff
307
Platform/OpenLinuxBoot/OpenLinuxBoot.c
Normal file
307
Platform/OpenLinuxBoot/OpenLinuxBoot.c
Normal file
@ -0,0 +1,307 @@
|
||||
/** @file
|
||||
Linux boot driver, supporting Boot Loader Specification, GRUB2 blscfg, and autodetect.
|
||||
|
||||
Copyright (c) 2021, Mike Beaton. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#include "LinuxBootInternal.h"
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Guid/Gpt.h>
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcBootManagementLib.h>
|
||||
#include <Library/OcDebugLogLib.h>
|
||||
#include <Library/OcFileLib.h>
|
||||
#include <Library/OcFlexArrayLib.h>
|
||||
#include <Library/OcStringLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
|
||||
#include <Protocol/OcBootEntry.h>
|
||||
|
||||
UINTN gLinuxBootFlags = LINUX_BOOT_ALL & ~LINUX_BOOT_ADD_DEBUG_INFO;
|
||||
|
||||
OC_PICKER_CONTEXT *gPickerContext;
|
||||
OC_FLEX_ARRAY *gParsedLoadOptions;
|
||||
OC_FLEX_ARRAY *gNamedLoaderEntries;
|
||||
EFI_GUID gPartuuid;
|
||||
CHAR8 *gFileSystemType;
|
||||
|
||||
VOID
|
||||
InternalFreePickerEntry (
|
||||
IN OC_PICKER_ENTRY *Entry
|
||||
)
|
||||
{
|
||||
ASSERT (Entry != NULL);
|
||||
|
||||
if (Entry == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: Is this un-CONST casting okay?
|
||||
// (Are they CONST because they are not supposed to be freed when used as before?)
|
||||
//
|
||||
if (Entry->Id != NULL) {
|
||||
FreePool ((CHAR8 *)Entry->Id);
|
||||
}
|
||||
if (Entry->Name != NULL) {
|
||||
FreePool ((CHAR8 *)Entry->Name);
|
||||
}
|
||||
if (Entry->Path != NULL) {
|
||||
FreePool ((CHAR8 *)Entry->Path);
|
||||
}
|
||||
if (Entry->Arguments != NULL) {
|
||||
FreePool ((CHAR8 *)Entry->Arguments);
|
||||
}
|
||||
if (Entry->Flavour != NULL) {
|
||||
FreePool ((CHAR8 *)Entry->Flavour);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
EFIAPI
|
||||
OcFreeLinuxBootEntries (
|
||||
IN OC_PICKER_ENTRY **Entries,
|
||||
IN UINTN NumEntries
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
ASSERT (Entries != NULL);
|
||||
ASSERT (*Entries != NULL);
|
||||
if (Entries == NULL || *Entries == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Index = 0; Index < NumEntries; Index++) {
|
||||
InternalFreePickerEntry (&(*Entries)[Index]);
|
||||
}
|
||||
|
||||
FreePool (*Entries);
|
||||
*Entries = NULL;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
OcGetLinuxBootEntries (
|
||||
IN OC_PICKER_CONTEXT *PickerContext,
|
||||
IN CONST EFI_HANDLE Device,
|
||||
OUT OC_PICKER_ENTRY **Entries,
|
||||
OUT UINTN *NumEntries
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
|
||||
EFI_FILE_PROTOCOL *RootDirectory;
|
||||
UINT32 FileSystemPolicy;
|
||||
CONST EFI_PARTITION_ENTRY *PartitionEntry;
|
||||
|
||||
ASSERT (PickerContext != NULL);
|
||||
ASSERT (Entries != NULL);
|
||||
ASSERT (NumEntries != NULL);
|
||||
|
||||
gPickerContext = PickerContext;
|
||||
*Entries = NULL;
|
||||
*NumEntries = 0;
|
||||
|
||||
//
|
||||
// No custom entries.
|
||||
//
|
||||
if (Device == NULL) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
//
|
||||
// Open partition file system.
|
||||
//
|
||||
Status = gBS->HandleProtocol (
|
||||
Device,
|
||||
&gEfiSimpleFileSystemProtocolGuid,
|
||||
(VOID **) &FileSystem
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: Missing filesystem - %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Get handle to partiton root directory.
|
||||
//
|
||||
Status = FileSystem->OpenVolume (
|
||||
FileSystem,
|
||||
&RootDirectory
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: Invalid root volume - %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
gFileSystemType = NULL;
|
||||
|
||||
FileSystemPolicy = OcGetFileSystemPolicyType (Device);
|
||||
|
||||
//
|
||||
// Disallow Apple filesystems, mainly to avoid needlessly
|
||||
// scanning multiple APFS partitions.
|
||||
//
|
||||
if ((FileSystemPolicy & OC_SCAN_ALLOW_FS_APFS) != 0) {
|
||||
gFileSystemType = "APFS";
|
||||
DEBUG ((DEBUG_INFO, "LNX: %a - not scanning\n", gFileSystemType));
|
||||
Status = EFI_NOT_FOUND;
|
||||
} else if ((FileSystemPolicy & OC_SCAN_ALLOW_FS_HFS) != 0) {
|
||||
gFileSystemType = "HFS";
|
||||
DEBUG ((DEBUG_INFO, "LNX: %a - not scanning\n", gFileSystemType));
|
||||
Status = EFI_NOT_FOUND;
|
||||
} else if ((FileSystemPolicy & OC_SCAN_ALLOW_FS_ESP) != 0) {
|
||||
gFileSystemType = "ESP";
|
||||
if ((gLinuxBootFlags & LINUX_BOOT_SCAN_ESP) == 0) {
|
||||
DEBUG ((DEBUG_INFO, "LNX: %a - requested not to scan\n", gFileSystemType));
|
||||
Status = EFI_NOT_FOUND;
|
||||
}
|
||||
} else if ((FileSystemPolicy & OC_SCAN_ALLOW_FS_XBOOTLDR) != 0) {
|
||||
gFileSystemType = "XBOOTLDR";
|
||||
if ((gLinuxBootFlags & LINUX_BOOT_SCAN_XBOOTLDR) == 0) {
|
||||
DEBUG ((DEBUG_INFO, "LNX: %a - requested not to scan\n", gFileSystemType));
|
||||
Status = EFI_NOT_FOUND;
|
||||
}
|
||||
} else if ((FileSystemPolicy & OC_SCAN_ALLOW_FS_LINUX_ROOT) != 0) {
|
||||
gFileSystemType = "ROOT";
|
||||
if ((gLinuxBootFlags & LINUX_BOOT_SCAN_LINUX_ROOT) == 0) {
|
||||
DEBUG ((DEBUG_INFO, "LNX: %a - requested not to scan\n", gFileSystemType));
|
||||
Status = EFI_NOT_FOUND;
|
||||
}
|
||||
} else if ((FileSystemPolicy & OC_SCAN_ALLOW_FS_LINUX_DATA) != 0) {
|
||||
gFileSystemType = "DATA";
|
||||
if ((gLinuxBootFlags & LINUX_BOOT_SCAN_LINUX_DATA) == 0) {
|
||||
DEBUG ((DEBUG_INFO, "LNX: %a - requested not to scan\n", gFileSystemType));
|
||||
Status = EFI_NOT_FOUND;
|
||||
}
|
||||
} else {
|
||||
if ((FileSystemPolicy & OC_SCAN_ALLOW_FS_NTFS) != 0) {
|
||||
//
|
||||
// This is not just NTFS, Msft Basic Data part type GUID is used for non-ESP FAT too.
|
||||
//
|
||||
gFileSystemType = "NTFS/FAT";
|
||||
} else {
|
||||
gFileSystemType = "OTHER";
|
||||
}
|
||||
|
||||
if ((gLinuxBootFlags & LINUX_BOOT_SCAN_OTHER) == 0) {
|
||||
DEBUG ((DEBUG_INFO, "LNX: %a - requested not to scan\n", gFileSystemType));
|
||||
Status = EFI_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
RootDirectory->Close (RootDirectory);
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Save PARTUUID for autodetect.
|
||||
//
|
||||
PartitionEntry = OcGetGptPartitionEntry (Device);
|
||||
if (PartitionEntry == NULL) {
|
||||
gPartuuid = gEfiPartTypeUnusedGuid;
|
||||
} else {
|
||||
gPartuuid = PartitionEntry->UniquePartitionGUID;
|
||||
}
|
||||
|
||||
//
|
||||
// Log TypeGUID and PARTUUID of the drive we're in.
|
||||
//
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"LNX: TypeGUID: %g (%a) PARTUUID: %g\n",
|
||||
PartitionEntry->PartitionTypeGUID,
|
||||
gFileSystemType,
|
||||
PartitionEntry->UniquePartitionGUID
|
||||
));
|
||||
|
||||
//
|
||||
// Scan for boot loader spec & blscfg entries (Fedora-like).
|
||||
//
|
||||
Status = ScanLoaderEntries (
|
||||
RootDirectory,
|
||||
Entries,
|
||||
NumEntries
|
||||
);
|
||||
|
||||
//
|
||||
// Note: As currently structured, will fall through to autodetect
|
||||
// if no /loader/entries/*.conf files are present, but also if there
|
||||
// are only unusable files in there.
|
||||
//
|
||||
if (EFI_ERROR (Status)) {
|
||||
if (Status != EFI_NOT_FOUND) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: ScanLoaderEntries - %r\n", Status));
|
||||
}
|
||||
|
||||
//
|
||||
// Auto-detect vmlinuz and initrd files on own root filesystem (Debian-like).
|
||||
//
|
||||
if ((gLinuxBootFlags & LINUX_BOOT_ALLOW_AUTODETECT) != 0) {
|
||||
Status = AutodetectLinux (
|
||||
RootDirectory,
|
||||
Entries,
|
||||
NumEntries
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {
|
||||
DEBUG ((DEBUG_WARN, "LNX: AutodetectLinux - %r\n", Status));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Status == EFI_NOT_FOUND) {
|
||||
DEBUG ((DEBUG_INFO, "LNX: Nothing found\n"));
|
||||
}
|
||||
|
||||
RootDirectory->Close (RootDirectory);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
STATIC
|
||||
OC_BOOT_ENTRY_PROTOCOL
|
||||
mLinuxBootEntryProtocol = {
|
||||
OC_BOOT_ENTRY_PROTOCOL_REVISION,
|
||||
OcGetLinuxBootEntries,
|
||||
OcFreeLinuxBootEntries
|
||||
};
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
UefiMain (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = OcParseLoadOptions (ImageHandle, &gParsedLoadOptions);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
OcParsedVarsGetInt (gParsedLoadOptions, L"flags", &gLinuxBootFlags, TRUE);
|
||||
} else if (Status != EFI_NOT_FOUND) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&ImageHandle,
|
||||
&gOcBootEntryProtocolGuid,
|
||||
&mLinuxBootEntryProtocol,
|
||||
NULL
|
||||
);
|
||||
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
44
Platform/OpenLinuxBoot/OpenLinuxBoot.inf
Normal file
44
Platform/OpenLinuxBoot/OpenLinuxBoot.inf
Normal file
@ -0,0 +1,44 @@
|
||||
## @file
|
||||
# Linux boot entry protocol implementation.
|
||||
#
|
||||
# Copyright (C) 2021, Mike Beaton. All rights reserved.<BR>
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
##
|
||||
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = OpenLinuxBoot
|
||||
ENTRY_POINT = UefiMain
|
||||
FILE_GUID = B2EC4DF3-FC2C-4D24-B1D6-B2D2DE8D8172
|
||||
MODULE_TYPE = UEFI_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
|
||||
[Packages]
|
||||
OpenCorePkg/OpenCorePkg.dec
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
[Guids]
|
||||
gEfiPartTypeUnusedGuid ## SOMETIMES_CONSUMES
|
||||
|
||||
[LibraryClasses]
|
||||
OcBootManagementLib
|
||||
OcDebugLogLib
|
||||
OcFileLib
|
||||
OcFlexArrayLib
|
||||
SortLib
|
||||
UefiBootServicesTableLib
|
||||
UefiDriverEntryPoint
|
||||
UefiLib
|
||||
|
||||
[Protocols]
|
||||
gOcBootEntryProtocolGuid # PRODUCES
|
||||
|
||||
[Sources]
|
||||
Autodetect.c
|
||||
GrubCfg.c
|
||||
GrubEnv.c
|
||||
GrubVars.c
|
||||
LoaderEntry.c
|
||||
OpenLinuxBoot.c
|
||||
@ -71,6 +71,7 @@ extern EFI_GUID gEfiLegacyRegionProtocolGuid;
|
||||
extern EFI_GUID gEfiLegacyRegion2ProtocolGuid;
|
||||
extern EFI_GUID gEfiPciRootBridgeIoProtocolGuid;
|
||||
extern EFI_GUID gEfiSmbiosTableGuid;
|
||||
extern EFI_GUID gEfiUnicodeCollation2ProtocolGuid;
|
||||
|
||||
extern EFI_GUID gOcBootstrapProtocolGuid;
|
||||
extern EFI_GUID gOcVendorVariableGuid;
|
||||
|
||||
@ -56,6 +56,7 @@ EFI_GUID gEfiLegacyRegionProtocolGuid = { 0x0fc9013a, 0x0568, 0x4ba9, { 0
|
||||
EFI_GUID gEfiLegacyRegion2ProtocolGuid = { 0x70101eaf, 0x85, 0x440c, { 0xb3, 0x56, 0x8e, 0xe3, 0x6f, 0xef, 0x24, 0xf0 }};
|
||||
EFI_GUID gEfiPciRootBridgeIoProtocolGuid = { 0x2F707EBB, 0x4A1A, 0x11D4, { 0x9A, 0x38, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
|
||||
EFI_GUID gEfiSmbiosTableGuid = { 0xEB9D2D31, 0x2D88, 0x11D3, { 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
|
||||
EFI_GUID gEfiUnicodeCollation2ProtocolGuid = { 0xa4c751fc, 0x23ae, 0x4c3e, { 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49 }};
|
||||
|
||||
EFI_GUID gOcBootstrapProtocolGuid = { 0xBA1EB455, 0xB182, 0x4F14, { 0x85, 0x21, 0xE4, 0x22, 0xC3, 0x25, 0xDE, 0xF6 }};
|
||||
EFI_GUID gOcVendorVariableGuid = { 0x4D1FDA02, 0x38C7, 0x4A6A, { 0x9C, 0xC6, 0x4B, 0xCC, 0xA8, 0xB3, 0x01, 0x02 }};
|
||||
|
||||
@ -136,7 +136,7 @@ ifneq ($(STANDALONE),1)
|
||||
#
|
||||
# UDK implementations.
|
||||
#
|
||||
OBJS += UefiLib.o UefiLibPrint.o CpuDeadLoop.o BaseDebugPrintErrorLevelLib.o DebugLib.o PrintLib.o PrintLibInternal.o String.o SafeString.o SwapBytes16.o SwapBytes32.o LinkedList.o HighBitSet32.o HighBitSet64.o MtrrLib.o GetPowerOfTwo32.o GetPowerOfTwo64.o Cpu.o BmpSupportLib.o SafeIntLib.o X86GetInterruptState.o PciLib.o PciExpressLib.o DevicePathUtilities.o UefiDevicePathLib.o DevicePathToText.o DevicePathFromText.o BitField.o CheckSum.o
|
||||
OBJS += UefiLib.o UefiLibPrint.o CpuDeadLoop.o BaseDebugPrintErrorLevelLib.o DebugLib.o PrintLib.o PrintLibInternal.o String.o SafeString.o SwapBytes16.o SwapBytes32.o LinkedList.o HighBitSet32.o HighBitSet64.o MtrrLib.o GetPowerOfTwo32.o GetPowerOfTwo64.o Cpu.o BmpSupportLib.o SafeIntLib.o X86GetInterruptState.o PciLib.o PciExpressLib.o DevicePathUtilities.o UefiDevicePathLib.o DevicePathToText.o DevicePathFromText.o BitField.o CheckSum.o UefiSortLib.o
|
||||
#
|
||||
# Customised/Simplified implementations at userspace level.
|
||||
#
|
||||
@ -201,6 +201,7 @@ ifneq ($(STANDALONE),1)
|
||||
$(UDK_PATH)/MdePkg/Library/BasePciExpressLib:$\
|
||||
$(UDK_PATH)/MdePkg/Library/UefiDevicePathLib:$\
|
||||
$(UDK_PATH)/MdeModulePkg/Library/BaseBmpSupportLib:$\
|
||||
$(UDK_PATH)/MdeModulePkg/Library/UefiSortLib:$\
|
||||
$(UDK_PATH)/UefiCpuPkg/Library/MtrrLib:$\
|
||||
$(OC_USER)/Library/OcGuardLib:$\
|
||||
$(OC_USER)/Library/OcSerializeLib:$\
|
||||
|
||||
@ -203,21 +203,27 @@ AsciiPropertyIsLegal (
|
||||
|
||||
BOOLEAN
|
||||
AsciiUefiDriverIsLegal (
|
||||
IN CONST CHAR8 *Driver
|
||||
IN CONST CHAR8 *Driver,
|
||||
IN CONST UINTN DriverIndex
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
UINTN DriverLength;
|
||||
|
||||
//
|
||||
// If an EFI driver does not contain .efi suffix,
|
||||
// then it must be illegal.
|
||||
//
|
||||
if (!OcAsciiEndsWith (Driver, ".efi", TRUE)) {
|
||||
DriverLength = AsciiStrLen (Driver);
|
||||
if (DriverLength == 0) {
|
||||
DEBUG ((DEBUG_WARN, "UEFI->Drivers[%u].Path value is missing!\n", DriverIndex));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DriverLength = AsciiStrLen (Driver);
|
||||
//
|
||||
// If an EFI driver does not have .efi suffix,
|
||||
// then it must be illegal.
|
||||
//
|
||||
if (!OcAsciiEndsWith (Driver, ".efi", TRUE)) {
|
||||
DEBUG ((DEBUG_WARN, "UEFI->Drivers[%u].Path does not end with \"%a\"!\n", DriverIndex, ".efi"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (Index = 0; Index < DriverLength; ++Index) {
|
||||
//
|
||||
@ -235,6 +241,7 @@ AsciiUefiDriverIsLegal (
|
||||
//
|
||||
// Disallowed characters matched.
|
||||
//
|
||||
DEBUG ((DEBUG_WARN, "UEFI->Drivers[%u].Path contains illegal character!\n", DriverIndex));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
@ -99,13 +99,15 @@ AsciiPropertyIsLegal (
|
||||
/**
|
||||
Check if a UEFI Driver matches specific conventions.
|
||||
|
||||
@param[in] Driver Driver to be checked.
|
||||
@param[in] Driver Driver path name to be checked.
|
||||
@param[in] DriverIndex Index of driver being checked.
|
||||
|
||||
@retval TRUE If path of Driver contains .efi suffix, and only contains 0-9, A-Z, a-z, '_', '-', '.', and '/'.
|
||||
**/
|
||||
BOOLEAN
|
||||
AsciiUefiDriverIsLegal (
|
||||
IN CONST CHAR8 *Driver
|
||||
IN CONST CHAR8 *Driver,
|
||||
IN CONST UINTN DriverIndex
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@ -140,18 +140,19 @@ CheckBooterQuirks (
|
||||
IN OC_GLOBAL_CONFIG *Config
|
||||
)
|
||||
{
|
||||
UINT32 ErrorCount;
|
||||
UINT32 Index;
|
||||
OC_BOOTER_CONFIG *UserBooter;
|
||||
OC_UEFI_CONFIG *UserUefi;
|
||||
CONST CHAR8 *Driver;
|
||||
UINT8 MaxSlide;
|
||||
BOOLEAN IsAllowRelocationBlockEnabled;
|
||||
BOOLEAN IsProvideCustomSlideEnabled;
|
||||
BOOLEAN IsEnableSafeModeSlideEnabled;
|
||||
BOOLEAN IsDisableVariableWriteEnabled;
|
||||
BOOLEAN IsEnableWriteUnprotectorEnabled;
|
||||
BOOLEAN HasOpenRuntimeEfiDriver;
|
||||
UINT32 ErrorCount;
|
||||
UINT32 Index;
|
||||
OC_BOOTER_CONFIG *UserBooter;
|
||||
OC_UEFI_CONFIG *UserUefi;
|
||||
OC_UEFI_DRIVER_ENTRY *DriverEntry;
|
||||
CONST CHAR8 *Driver;
|
||||
UINT8 MaxSlide;
|
||||
BOOLEAN IsAllowRelocationBlockEnabled;
|
||||
BOOLEAN IsProvideCustomSlideEnabled;
|
||||
BOOLEAN IsEnableSafeModeSlideEnabled;
|
||||
BOOLEAN IsDisableVariableWriteEnabled;
|
||||
BOOLEAN IsEnableWriteUnprotectorEnabled;
|
||||
BOOLEAN HasOpenRuntimeEfiDriver;
|
||||
|
||||
ErrorCount = 0;
|
||||
UserBooter = &Config->Booter;
|
||||
@ -165,13 +166,14 @@ CheckBooterQuirks (
|
||||
MaxSlide = UserBooter->Quirks.ProvideMaxSlide;
|
||||
|
||||
for (Index = 0; Index < UserUefi->Drivers.Count; ++Index) {
|
||||
Driver = OC_BLOB_GET (UserUefi->Drivers.Values[Index]);
|
||||
DriverEntry = UserUefi->Drivers.Values[Index];
|
||||
Driver = OC_BLOB_GET (&DriverEntry->Path);
|
||||
|
||||
//
|
||||
// Skip sanitising UEFI->Drivers as it will be performed when checking UEFI section.
|
||||
//
|
||||
|
||||
if (AsciiStrCmp (Driver, "OpenRuntime.efi") == 0) {
|
||||
if (DriverEntry->Enabled && AsciiStrCmp (Driver, "OpenRuntime.efi") == 0) {
|
||||
HasOpenRuntimeEfiDriver = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,21 +184,22 @@ CheckMiscBoot (
|
||||
IN OC_GLOBAL_CONFIG *Config
|
||||
)
|
||||
{
|
||||
UINT32 ErrorCount;
|
||||
OC_MISC_CONFIG *UserMisc;
|
||||
OC_UEFI_CONFIG *UserUefi;
|
||||
UINT32 ConsoleAttributes;
|
||||
CONST CHAR8 *HibernateMode;
|
||||
UINT32 PickerAttributes;
|
||||
UINT32 Index;
|
||||
CONST CHAR8 *Driver;
|
||||
BOOLEAN HasOpenCanopyEfiDriver;
|
||||
CONST CHAR8 *PickerMode;
|
||||
CONST CHAR8 *PickerVariant;
|
||||
BOOLEAN IsPickerAudioAssistEnabled;
|
||||
BOOLEAN IsAudioSupportEnabled;
|
||||
CONST CHAR8 *LauncherOption;
|
||||
CONST CHAR8 *LauncherPath;
|
||||
UINT32 ErrorCount;
|
||||
OC_MISC_CONFIG *UserMisc;
|
||||
OC_UEFI_CONFIG *UserUefi;
|
||||
UINT32 ConsoleAttributes;
|
||||
CONST CHAR8 *HibernateMode;
|
||||
UINT32 PickerAttributes;
|
||||
UINT32 Index;
|
||||
OC_UEFI_DRIVER_ENTRY *DriverEntry;
|
||||
CONST CHAR8 *Driver;
|
||||
BOOLEAN HasOpenCanopyEfiDriver;
|
||||
CONST CHAR8 *PickerMode;
|
||||
CONST CHAR8 *PickerVariant;
|
||||
BOOLEAN IsPickerAudioAssistEnabled;
|
||||
BOOLEAN IsAudioSupportEnabled;
|
||||
CONST CHAR8 *LauncherOption;
|
||||
CONST CHAR8 *LauncherPath;
|
||||
|
||||
ErrorCount = 0;
|
||||
UserMisc = &Config->Misc;
|
||||
@ -221,15 +222,16 @@ CheckMiscBoot (
|
||||
|
||||
PickerAttributes = UserMisc->Boot.PickerAttributes;
|
||||
if ((PickerAttributes & ~OC_ATTR_ALL_BITS) != 0) {
|
||||
DEBUG ((DEBUG_WARN, "Misc->Boot->PickerAttributes is has unknown bits set!\n"));
|
||||
DEBUG ((DEBUG_WARN, "Misc->Boot->PickerAttributes has unknown bits set!\n"));
|
||||
++ErrorCount;
|
||||
}
|
||||
|
||||
HasOpenCanopyEfiDriver = FALSE;
|
||||
for (Index = 0; Index < UserUefi->Drivers.Count; ++Index) {
|
||||
Driver = OC_BLOB_GET (UserUefi->Drivers.Values[Index]);
|
||||
DriverEntry = UserUefi->Drivers.Values[Index];
|
||||
Driver = OC_BLOB_GET (&DriverEntry->Path);
|
||||
|
||||
if (AsciiStrCmp (Driver, "OpenCanopy.efi") == 0) {
|
||||
if (DriverEntry->Enabled && AsciiStrCmp (Driver, "OpenCanopy.efi") == 0) {
|
||||
HasOpenCanopyEfiDriver = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,6 +231,7 @@ CheckUEFIDrivers (
|
||||
UINT32 ErrorCount;
|
||||
OC_UEFI_CONFIG *UserUefi;
|
||||
UINT32 Index;
|
||||
OC_UEFI_DRIVER_ENTRY *DriverEntry;
|
||||
CONST CHAR8 *Driver;
|
||||
BOOLEAN HasOpenRuntimeEfiDriver;
|
||||
BOOLEAN HasOpenUsbKbDxeEfiDriver;
|
||||
@ -258,7 +259,8 @@ CheckUEFIDrivers (
|
||||
HasAudioDxeEfiDriver = FALSE;
|
||||
IndexAudioDxeEfiDriver = 0;
|
||||
for (Index = 0; Index < UserUefi->Drivers.Count; ++Index) {
|
||||
Driver = OC_BLOB_GET (UserUefi->Drivers.Values[Index]);
|
||||
DriverEntry = UserUefi->Drivers.Values[Index];
|
||||
Driver = OC_BLOB_GET (&DriverEntry->Path);
|
||||
|
||||
//
|
||||
// Check the length of path relative to OC directory.
|
||||
@ -268,19 +270,18 @@ CheckUEFIDrivers (
|
||||
++ErrorCount;
|
||||
}
|
||||
|
||||
if (Driver[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Sanitise strings.
|
||||
//
|
||||
if (!AsciiUefiDriverIsLegal (Driver)) {
|
||||
DEBUG ((DEBUG_WARN, "UEFI->Drivers[%u] contains illegal character!\n", Index));
|
||||
if (!AsciiUefiDriverIsLegal (Driver, Index)) {
|
||||
++ErrorCount;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!DriverEntry->Enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (AsciiStrCmp (Driver, "OpenRuntime.efi") == 0) {
|
||||
HasOpenRuntimeEfiDriver = TRUE;
|
||||
}
|
||||
|
||||
@ -157,6 +157,7 @@ package() {
|
||||
"AudioDxe.efi"
|
||||
"CrScreenshotDxe.efi"
|
||||
"OpenCanopy.efi"
|
||||
"OpenLinuxBoot.efi"
|
||||
"OpenPartitionDxe.efi"
|
||||
"OpenRuntime.efi"
|
||||
"OpenUsbKbDxe.efi"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user