mirror of
https://github.com/Metabolix/HackBGRT.git
synced 2025-12-06 17:15:42 -08:00
Fix a shim error caused by bad load options data
Shim expects a filename or nothing in the load options.
To avoid an error message during boot, do several things:
When creating the NVRAM entry, use empty load options. The current
string ("HackBGRT\0") was just a decoration, and it's luckily ignored
by shim because the length is odd.
When creating the entry with BCDEdit, manually fix the load options.
The load options in BCDEdit entries start with "WINDOWS\0" followed
by UINT32 version, as seen in ReactOS struct BL_WINDOWS_LOAD_OPTIONS.
The version is 1, but BCDEdit seems to be happy with a higher number.
By setting this version to 'X' (0x58), the string becomes a valid
UCS-2 file name. Update the installer so that the HackBGRT loader is
installed with this weird file name.
The reason why the load options cannot be deleted completely is that
BCDEdit will recreate the entry on next boot if it doesn't find the
entry it just tried to create.
See: https://github.com/rhboot/shim/pull/621
See: https://github.com/reactos/reactos/blob/v0.4.7/boot/environ/include/bl.h#L911
This commit is contained in:
26
src/Efi.cs
26
src/Efi.cs
@@ -93,6 +93,7 @@ public class Efi {
|
||||
var pos = 6 + 2 * (Label.Length + 1);
|
||||
var pathNodesEnd = pos + pathNodesLength;
|
||||
DevicePathNodes = new List<DevicePathNode>();
|
||||
Arguments = new byte[0];
|
||||
while (pos + 4 <= pathNodesEnd) {
|
||||
var len = BitConverter.ToUInt16(data, pos + 2);
|
||||
if (len < 4 || pos + len > pathNodesEnd) {
|
||||
@@ -378,9 +379,10 @@ public class Efi {
|
||||
*
|
||||
* @param label Label of the boot entry.
|
||||
* @param fileName File name of the boot entry.
|
||||
* @param alwaysCopyFromMS If true, do not preserve any existing data.
|
||||
* @param dryRun Don't actually create the entry.
|
||||
*/
|
||||
public static void MakeAndEnableBootEntry(string label, string fileName, bool dryRun = false) {
|
||||
public static void MakeAndEnableBootEntry(string label, string fileName, bool alwaysCopyFromMS, bool dryRun = false) {
|
||||
Variable msEntry = null, ownEntry = null;
|
||||
UInt16 msNum = 0, ownNum = 0;
|
||||
|
||||
@@ -435,12 +437,28 @@ public class Efi {
|
||||
throw new Exception("MakeBootEntry: Windows Boot Manager not found.");
|
||||
} else {
|
||||
Setup.Log($"Read EFI variable: {msEntry}");
|
||||
Setup.Log($"Read EFI variable: {ownEntry}");
|
||||
// Make a new boot entry using the MS entry as a starting point.
|
||||
var entryData = new BootEntryData(msEntry.Data);
|
||||
entryData.Arguments = Encoding.UTF8.GetBytes(label + "\0");
|
||||
if (!alwaysCopyFromMS && ownEntry.Data != null) {
|
||||
entryData = new BootEntryData(ownEntry.Data);
|
||||
// Shim expects the arguments to be a filename or nothing.
|
||||
// But BCDEdit expects some Microsoft-specific data.
|
||||
// Modify the entry so that BCDEdit still recognises it
|
||||
// but the data becomes a valid UCS-2 / UTF-16LE file name.
|
||||
var str = new string(entryData.Arguments.Take(12).Select(c => (char) c).ToArray());
|
||||
if (str == "WINDOWS\0\x01\0\0\0") {
|
||||
entryData.Arguments[8] = (byte) 'X';
|
||||
} else if (str != "WINDOWS\0\x58\0\0\0") {
|
||||
// Not recognized. Clear the arguments.
|
||||
entryData.Arguments = new byte[0];
|
||||
}
|
||||
} else {
|
||||
entryData.Arguments = new byte[0];
|
||||
entryData.Label = label;
|
||||
entryData.FileName = fileName;
|
||||
}
|
||||
entryData.Attributes = 1; // LOAD_OPTION_ACTIVE
|
||||
entryData.Label = label;
|
||||
entryData.FileName = fileName;
|
||||
ownEntry.Attributes = 7; // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
|
||||
ownEntry.Data = entryData.ToBytes();
|
||||
SetVariable(ownEntry, dryRun);
|
||||
|
||||
@@ -373,6 +373,7 @@ public class Setup {
|
||||
loaderDest = $"grub{EfiArch}.efi";
|
||||
}
|
||||
InstallFile(loaderSource, loaderDest);
|
||||
InstallFile(loaderSource, "\u4957\u444e\u574f\u0053\u0058"); // bytes "WINDOWS\0X\0" as UTF-16
|
||||
if (LoaderIsSigned) {
|
||||
InstallFile("certificate.cer");
|
||||
}
|
||||
@@ -415,6 +416,7 @@ public class Setup {
|
||||
WriteLine("Enabled NVRAM entry for HackBGRT with BCDEdit.");
|
||||
// Verify that the entry was created.
|
||||
Execute("bcdedit", "/enum firmware", true);
|
||||
Efi.MakeAndEnableBootEntry("HackBGRT", "\\EFI\\HackBGRT\\loader.efi", false, DryRun);
|
||||
Execute("bcdedit", $"/enum {guid}", true);
|
||||
Efi.LogBootEntries();
|
||||
} catch (Exception e) {
|
||||
@@ -460,7 +462,7 @@ public class Setup {
|
||||
* Enable HackBGRT boot entry.
|
||||
*/
|
||||
protected void EnableEntry() {
|
||||
Efi.MakeAndEnableBootEntry("HackBGRT", "\\EFI\\HackBGRT\\loader.efi", DryRun);
|
||||
Efi.MakeAndEnableBootEntry("HackBGRT", "\\EFI\\HackBGRT\\loader.efi", true, DryRun);
|
||||
WriteLine("Enabled NVRAM entry for HackBGRT.");
|
||||
// Verify that the entry was created.
|
||||
Efi.LogBootEntries();
|
||||
|
||||
Reference in New Issue
Block a user