Refactor EFI boot entry code into a new class

This commit is contained in:
Lauri Kenttä
2024-05-09 19:24:24 +03:00
parent af4f99aab6
commit c826149183
4 changed files with 323 additions and 263 deletions

View File

@@ -10,7 +10,7 @@ GNUEFI_INC = gnu-efi/inc
FILES_C = src/main.c src/util.c src/types.c src/config.c src/sbat.c src/efi.c FILES_C = src/main.c src/util.c src/types.c src/config.c src/sbat.c src/efi.c
FILES_H = $(wildcard src/*.h) FILES_H = $(wildcard src/*.h)
FILES_CS = src/Setup.cs src/Esp.cs src/Efi.cs FILES_CS = src/Setup.cs src/Esp.cs src/Efi.cs src/EfiBootEntries.cs
GIT_DESCRIBE := $(firstword $(GIT_DESCRIBE) $(shell git describe --tags) unknown) GIT_DESCRIBE := $(firstword $(GIT_DESCRIBE) $(shell git describe --tags) unknown)
CFLAGS += '-DGIT_DESCRIBE_W=L"$(GIT_DESCRIBE)"' '-DGIT_DESCRIBE="$(GIT_DESCRIBE)"' CFLAGS += '-DGIT_DESCRIBE_W=L"$(GIT_DESCRIBE)"' '-DGIT_DESCRIBE="$(GIT_DESCRIBE)"'
RELEASE_NAME = HackBGRT-$(GIT_DESCRIBE:v%=%) RELEASE_NAME = HackBGRT-$(GIT_DESCRIBE:v%=%)

View File

@@ -64,88 +64,6 @@ public class Efi {
} }
} }
/**
* Information about an EFI boot entry.
*/
public class BootEntryData {
public UInt32 Attributes;
public string Label;
public class DevicePathNode {
public byte Type, SubType;
public byte[] Data;
public DevicePathNode(byte[] data) {
Type = data[0];
SubType = data[1];
Data = data.Skip(4).ToArray();
}
public byte[] ToBytes() {
var len = Data.Length + 4;
return new byte[] { Type, SubType, (byte)(len & 0xff), (byte)(len >> 8) }.Concat(Data).ToArray();
}
}
public List<DevicePathNode> DevicePathNodes;
public byte[] Arguments;
public BootEntryData(byte[] data) {
Attributes = BitConverter.ToUInt32(data, 0);
var pathNodesLength = BitConverter.ToUInt16(data, 4);
Label = new string(BytesToUInt16s(data).Skip(3).TakeWhile(i => i != 0).Select(i => (char)i).ToArray());
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) {
return; // throw new Exception("Bad entry.");
}
var node = new DevicePathNode(data.Skip(pos).Take(len).ToArray());
DevicePathNodes.Add(node);
if (node.Type == 0x7f && node.SubType == 0xff) {
// End of entire device path.
// Apparently some firmwares produce paths with unused nodes at the end.
break;
}
pos += len;
}
Arguments = data.Skip(pathNodesEnd).ToArray();
}
public byte[] ToBytes() {
return new byte[0]
.Concat(BitConverter.GetBytes((UInt32) Attributes))
.Concat(BitConverter.GetBytes((UInt16) DevicePathNodes.Sum(n => n.Data.Length + 4)))
.Concat(Encoding.Unicode.GetBytes(Label + "\0"))
.Concat(DevicePathNodes.SelectMany(n => n.ToBytes()))
.Concat(Arguments)
.ToArray();
}
public DevicePathNode FileNameNode {
get {
var d = DevicePathNodes;
return d.Count > 1 && d[d.Count - 1].Type == 0x7F && d[d.Count - 2].Type == 0x04 ? d[d.Count - 2] : null;
}
}
public bool HasFileName {
get {
return FileNameNode != null;
}
}
public string FileName {
get {
if (!HasFileName) {
return "";
}
return new string(Encoding.Unicode.GetChars(FileNameNode.Data).TakeWhile(c => c != '\0').ToArray());
}
set {
if (!HasFileName) {
throw new Exception("Logic error: Setting FileName on a bad boot entry.");
}
FileNameNode.Data = Encoding.Unicode.GetBytes(value + "\0");
}
}
}
/** /**
* GUID of the global EFI variables. * GUID of the global EFI variables.
*/ */
@@ -206,7 +124,7 @@ public class Efi {
* @param guid GUID of the EFI variable. * @param guid GUID of the EFI variable.
* @return Information about the EFI variable. * @return Information about the EFI variable.
*/ */
private static Variable GetVariable(string name, string guid = EFI_GLOBAL_GUID) { public static Variable GetVariable(string name, string guid = EFI_GLOBAL_GUID) {
Variable result = new Variable(); Variable result = new Variable();
result.Name = name; result.Name = name;
result.Guid = guid; result.Guid = guid;
@@ -255,7 +173,7 @@ public class Efi {
* @param v Information of the variable. * @param v Information of the variable.
* @param dryRun Don't actually set the variable. * @param dryRun Don't actually set the variable.
*/ */
private static void SetVariable(Variable v, bool dryRun = false) { public static void SetVariable(Variable v, bool dryRun = false) {
Setup.WriteLine($"Writing EFI variable {v.Name} (see log for details)"); Setup.WriteLine($"Writing EFI variable {v.Name} (see log for details)");
Setup.Log($"Writing EFI variable: {v}"); Setup.Log($"Writing EFI variable: {v}");
if (dryRun) { if (dryRun) {
@@ -341,177 +259,6 @@ public class Efi {
return Enumerable.Range(0, bytes.Length / 2).Select(i => (UInt16) (bytes[2 * i] + 0x100 * bytes[2 * i + 1])); return Enumerable.Range(0, bytes.Length / 2).Select(i => (UInt16) (bytes[2 * i] + 0x100 * bytes[2 * i + 1]));
} }
/**
* Disable the said boot entry from BootOrder.
*
* @param label Label of the boot entry.
* @param fileName File name of the boot entry.
* @param dryRun Don't actually disable the entry.
* @return True, if the entry was found in BootOrder.
*/
public static bool DisableBootEntry(string label, string fileName, bool dryRun = false) {
Variable bootOrder;
try {
bootOrder = GetVariable("BootOrder");
} catch {
return false;
}
if (bootOrder.Data == null) {
return false;
}
Setup.Log($"Read EFI variable: {bootOrder}");
var found = false;
var bootOrderInts = new List<UInt16>();
foreach (var num in BytesToUInt16s(bootOrder.Data)) {
var entry = GetVariable(String.Format("Boot{0:X04}", num));
if (entry.Data != null) {
var entryData = new BootEntryData(entry.Data);
if (entryData.Label == label && entryData.FileName == fileName) {
found = true;
continue;
}
}
bootOrderInts.Add(num);
}
if (found) {
bootOrder.Data = bootOrderInts.SelectMany(num => new byte[] { (byte)(num & 0xff), (byte)(num >> 8) }).ToArray();
SetVariable(bootOrder, dryRun);
}
return found;
}
/**
* Create and enable the said boot entry from BootOrder.
*
* @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 alwaysCopyFromMS, bool dryRun = false) {
Variable msEntry = null, ownEntry = null;
UInt16 msNum = 0, ownNum = 0;
// Find a free entry and the MS bootloader entry.
Variable bootOrder = null;
try {
bootOrder = GetVariable("BootOrder");
} catch {
if (dryRun) {
return;
}
}
if (bootOrder == null || bootOrder.Data == null) {
throw new Exception("MakeBootEntry: Could not read BootOrder. Maybe your computer is defective.");
}
var bootCurrent = GetVariable("BootCurrent");
if (bootCurrent.Data == null) {
throw new Exception("MakeBootEntry: Could not read BootCurrent. Maybe your computer is defective.");
}
Setup.Log($"Read EFI variable: {bootOrder}");
Setup.Log($"Read EFI variable: {bootCurrent}");
var bootOrderInts = new List<UInt16>(BytesToUInt16s(bootOrder.Data));
foreach (var num in BytesToUInt16s(bootCurrent.Data).Concat(bootOrderInts).Concat(Enumerable.Range(0, 0xff).Select(i => (UInt16) i))) {
var entry = GetVariable(String.Format("Boot{0:X04}", num));
if (entry.Data == null) {
// Use only Boot0000 .. Boot00FF because some firmwares expect that.
if (ownEntry == null && num < 0x100) {
ownNum = num;
ownEntry = entry;
}
} else {
var entryData = new BootEntryData(entry.Data);
if (!entryData.HasFileName) {
continue;
}
if (entryData.Label == label && entryData.FileName == fileName) {
ownNum = num;
ownEntry = entry;
}
if (msEntry == null && entryData.FileName.StartsWith("\\EFI\\Microsoft\\Boot\\bootmgfw.efi", StringComparison.OrdinalIgnoreCase)) {
msNum = num;
msEntry = entry;
}
}
if (ownEntry != null && msEntry != null) {
break;
}
}
if (ownEntry == null) {
throw new Exception("MakeBootEntry: Boot entry list is full.");
} else if (msEntry == null) {
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);
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
ownEntry.Attributes = 7; // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
ownEntry.Data = entryData.ToBytes();
SetVariable(ownEntry, dryRun);
}
var msPos = bootOrderInts.IndexOf(msNum);
var ownPos = bootOrderInts.IndexOf(ownNum);
var mustAdd = ownPos == -1;
var mustMove = 0 <= msPos && msPos <= ownPos;
if (mustAdd || mustMove) {
if (mustMove) {
bootOrderInts.RemoveAt(ownPos);
}
bootOrderInts.Insert(msPos < 0 ? 0 : msPos, ownNum);
bootOrder.Data = bootOrderInts.SelectMany(num => new byte[] { (byte)(num & 0xff), (byte)(num >> 8) }).ToArray();
SetVariable(bootOrder, dryRun);
}
}
/**
* Log the boot entries.
*/
public static void LogBootEntries() {
try {
var bootOrder = GetVariable("BootOrder");
var bootCurrent = GetVariable("BootCurrent");
Setup.Log($"LogBootOrder: {bootOrder}");
Setup.Log($"LogBootOrder: {bootCurrent}");
var bootOrderInts = new List<UInt16>(BytesToUInt16s(bootOrder.Data));
// Windows can't enumerate EFI variables, and trying them all is too slow.
// BootOrder + BootCurrent + the first 0xff entries should be enough.
var seen = new HashSet<UInt16>();
foreach (var num in bootOrderInts.Concat(BytesToUInt16s(bootCurrent.Data)).Concat(Enumerable.Range(0, 0xff).Select(i => (UInt16) i))) {
if (seen.Contains(num)) {
continue;
}
seen.Add(num);
var entry = GetVariable(String.Format("Boot{0:X04}", num));
if (entry.Data != null) {
Setup.Log($"LogBootOrder: {entry}");
}
}
} catch (Exception e) {
Setup.Log($"LogBootOrder failed: {e.ToString()}");
}
}
/** /**
* Retrieve HackBGRT log collected during boot. * Retrieve HackBGRT log collected during boot.
*/ */

309
src/EfiBootEntries.cs Normal file
View File

@@ -0,0 +1,309 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
/**
* A class for handling EFI boot entries. Lazy access with cache.
* Notice: Data is not updated after the first read.
*/
public class EfiBootEntries {
/**
* Information about an EFI boot entry.
*/
public class BootEntryData {
public UInt32 Attributes;
public string Label;
public class DevicePathNode {
public byte Type, SubType;
public byte[] Data;
public DevicePathNode(byte[] data) {
Type = data[0];
SubType = data[1];
Data = data.Skip(4).ToArray();
}
public byte[] ToBytes() {
var len = Data.Length + 4;
return new byte[] { Type, SubType, (byte)(len & 0xff), (byte)(len >> 8) }.Concat(Data).ToArray();
}
}
public List<DevicePathNode> DevicePathNodes;
public byte[] Arguments;
public BootEntryData(byte[] data) {
Attributes = BitConverter.ToUInt32(data, 0);
var pathNodesLength = BitConverter.ToUInt16(data, 4);
Label = new string(Efi.BytesToUInt16s(data).Skip(3).TakeWhile(i => i != 0).Select(i => (char)i).ToArray());
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) {
return; // throw new Exception("Bad entry.");
}
var node = new DevicePathNode(data.Skip(pos).Take(len).ToArray());
DevicePathNodes.Add(node);
if (node.Type == 0x7f && node.SubType == 0xff) {
// End of entire device path.
// Apparently some firmwares produce paths with unused nodes at the end.
break;
}
pos += len;
}
Arguments = data.Skip(pathNodesEnd).ToArray();
}
public byte[] ToBytes() {
return new byte[0]
.Concat(BitConverter.GetBytes((UInt32) Attributes))
.Concat(BitConverter.GetBytes((UInt16) DevicePathNodes.Sum(n => n.Data.Length + 4)))
.Concat(Encoding.Unicode.GetBytes(Label + "\0"))
.Concat(DevicePathNodes.SelectMany(n => n.ToBytes()))
.Concat(Arguments)
.ToArray();
}
public DevicePathNode FileNameNode {
get {
var d = DevicePathNodes;
return d.Count > 1 && d[d.Count - 1].Type == 0x7F && d[d.Count - 2].Type == 0x04 ? d[d.Count - 2] : null;
}
}
public bool HasFileName {
get {
return FileNameNode != null;
}
}
public string FileName {
get {
if (!HasFileName) {
return "";
}
return new string(Encoding.Unicode.GetChars(FileNameNode.Data).TakeWhile(c => c != '\0').ToArray());
}
set {
if (!HasFileName) {
throw new Exception("Logic error: Setting FileName on a bad boot entry.");
}
FileNameNode.Data = Encoding.Unicode.GetBytes(value + "\0");
}
}
}
/**
* Path to the Windows boot loader.
*/
public const string WindowsLoaderPath = "\\EFI\\Microsoft\\Boot\\bootmgfw.efi";
/**
* Path to the HackBGRT loader.
*/
public const string OwnLoaderPath = "\\EFI\\HackBGRT\\loader.efi";
private readonly Dictionary<UInt16, (Efi.Variable, BootEntryData)> cache;
private readonly Efi.Variable BootOrder;
private readonly Efi.Variable BootCurrent;
private readonly List<UInt16> BootOrderInts;
private readonly List<UInt16> BootCurrentInts;
/**
* Constructor. Reads BootOrder and BootCurrent.
*/
public EfiBootEntries() {
cache = new Dictionary<UInt16, (Efi.Variable, BootEntryData)>();
BootOrder = Efi.GetVariable("BootOrder");
BootCurrent = Efi.GetVariable("BootCurrent");
if (BootOrder.Data == null || BootCurrent.Data == null) {
throw new Exception("Could not read BootOrder or BootCurrent.");
}
BootCurrentInts = new List<UInt16>(Efi.BytesToUInt16s(BootCurrent.Data));
BootOrderInts = new List<UInt16>(Efi.BytesToUInt16s(BootOrder.Data));
}
/**
* Get the boot entry with the given number.
*
* @param num Number of the boot entry.
* @return The boot entry.
*/
public (Efi.Variable, BootEntryData) GetEntry(UInt16 num) {
if (!cache.ContainsKey(num)) {
var v = Efi.GetVariable(String.Format("Boot{0:X04}", num));
cache[num] = (v, v.Data == null ? null : new BootEntryData(v.Data));
}
return cache[num];
}
/**
* Find entry by file name.
*
* @param fileName File name of the boot entry.
* @return The boot entry.
*/
public (UInt16, Efi.Variable, BootEntryData) FindEntry(string fileName) {
var rest = Enumerable.Range(0, 0xff).Select(i => (UInt16) i);
var entryAccessOrder = BootCurrentInts.Concat(BootOrderInts).Concat(rest);
foreach (var num in entryAccessOrder) {
var (v, e) = GetEntry(num);
if (fileName == null ? e == null : (e != null && e.FileName.Equals(fileName, StringComparison.OrdinalIgnoreCase))) {
return (num, v, e);
}
}
return (0xffff, null, null);
}
/**
* Get the Windows boot entry.
*/
public (UInt16, Efi.Variable, BootEntryData) WindowsEntry {
get { return FindEntry(WindowsLoaderPath); }
}
/**
* Get the HackBGRT boot entry.
*/
public (UInt16, Efi.Variable, BootEntryData) OwnEntry {
get { return FindEntry(OwnLoaderPath); }
}
/**
* Get a free boot entry.
*/
public (UInt16, Efi.Variable, BootEntryData) FreeEntry {
get { return FindEntry(null); }
}
/**
* Disable the said boot entry from BootOrder.
*
* @param dryRun Don't actually write to NVRAM.
* @return True, if the entry was found in BootOrder.
*/
public bool DisableOwnEntry(bool dryRun = false) {
var (ownNum, ownVar, _) = OwnEntry;
if (ownVar == null) {
Setup.Log("Own entry not found.");
return false;
}
Setup.Log($"Old boot order: {BootOrder}");
if (!BootOrderInts.Contains(ownNum)) {
Setup.Log("Own entry not in BootOrder.");
} else {
Setup.Log($"Disabling own entry: {ownNum:X04}");
BootOrderInts.Remove(ownNum);
BootOrder.Data = BootOrderInts.SelectMany(num => new byte[] { (byte)(num & 0xff), (byte)(num >> 8) }).ToArray();
Efi.SetVariable(BootOrder, dryRun);
return true;
}
return false;
}
/**
* Create the boot entry.
*
* @param alwaysCopyFromMS If true, do not preserve any existing data.
* @param dryRun Don't actually write to NVRAM.
*/
public void MakeOwnEntry(bool alwaysCopyFromMS, bool dryRun = false) {
var (msNum, msVar, msEntry) = WindowsEntry;
if (msEntry == null) {
throw new Exception("MakeOwnEntry: Windows Boot Manager not found.");
}
var (ownNum, ownVar, ownEntry) = OwnEntry;
if (ownVar == null) {
(ownNum, ownVar, ownEntry) = FreeEntry;
if (ownVar == null) {
throw new Exception("MakeOwnEntry: No free entry.");
}
Setup.Log($"Creating own entry {ownNum:X4}.");
} else {
Setup.Log($"Updating own entry {ownNum:X4}.");
}
Setup.Log($"Read EFI variable: {msVar}");
Setup.Log($"Read EFI variable: {ownVar}");
// Make a new boot entry using the MS entry as a starting point.
if (!alwaysCopyFromMS && ownEntry != null) {
// 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(ownEntry.Arguments.Take(12).Select(c => (char) c).ToArray());
if (str == "WINDOWS\0\x01\0\0\0") {
ownEntry.Arguments[8] = (byte) 'X';
} else if (str != "WINDOWS\0\x58\0\0\0") {
// Not recognized. Clear the arguments.
ownEntry.Arguments = new byte[0];
}
} else {
ownEntry = msEntry;
ownEntry.Arguments = new byte[0];
ownEntry.Label = "HackBGRT";
ownEntry.FileName = OwnLoaderPath;
}
ownEntry.Attributes = 1; // LOAD_OPTION_ACTIVE
ownVar.Attributes = 7; // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
ownVar.Data = ownEntry.ToBytes();
Efi.SetVariable(ownVar, dryRun);
}
/**
* Enable the own boot entry.
*
* @param dryRun Don't actually write to NVRAM.
*/
public void EnableOwnEntry(bool dryRun = false) {
var (ownNum, ownVar, _) = OwnEntry;
if (ownVar == null) {
Setup.Log("Own entry not found.");
return;
}
var (msNum, _, _) = WindowsEntry;
var msPos = BootOrderInts.IndexOf(msNum);
var ownPos = BootOrderInts.IndexOf(ownNum);
var mustAdd = ownPos == -1;
var mustMove = 0 <= msPos && msPos <= ownPos;
Setup.Log($"Old boot order: {BootOrder}");
if (mustAdd || mustMove) {
Setup.Log($"Enabling own entry: {ownNum:X04}");
if (mustMove) {
BootOrderInts.RemoveAt(ownPos);
}
BootOrderInts.Insert(msPos < 0 ? 0 : msPos, ownNum);
BootOrder.Data = BootOrderInts.SelectMany(num => new byte[] { (byte)(num & 0xff), (byte)(num >> 8) }).ToArray();
Efi.SetVariable(BootOrder, dryRun);
}
}
/**
* Log the boot entries.
*/
public void LogEntries() {
Setup.Log($"LogEntries: {BootOrder}");
Setup.Log($"LogEntries: {BootCurrent}");
// Windows can't enumerate EFI variables, and trying them all is too slow.
// BootOrder + BootCurrent + the first 0xff entries should be enough.
var seen = new HashSet<UInt16>();
foreach (var num in BootOrderInts.Concat(BootCurrentInts).Concat(Enumerable.Range(0, 0xff).Select(i => (UInt16) i))) {
if (seen.Contains(num)) {
continue;
}
seen.Add(num);
var (v, e) = GetEntry(num);
if (e != null) {
Setup.Log($"LogEntries: {v}");
}
}
}
/**
* Try to log the boot entries.
*/
public static void TryLogEntries() {
try {
new EfiBootEntries().LogEntries();
} catch (Exception e) {
Setup.Log($"LogEntries failed: {e.ToString()}");
}
}
}

View File

@@ -453,7 +453,7 @@ public class Setup {
} }
var guid = match.Value; var guid = match.Value;
Execute("bcdedit", $"/set {guid} device partition={Esp.Location}", true); Execute("bcdedit", $"/set {guid} device partition={Esp.Location}", true);
Execute("bcdedit", $"/set {guid} path \\EFI\\HackBGRT\\loader.efi", true); Execute("bcdedit", $"/set {guid} path {EfiBootEntries.OwnLoaderPath}", true);
foreach (var arg in new string[] { "locale", "inherit", "default", "resumeobject", "displayorder", "toolsdisplayorder", "timeout" }) { foreach (var arg in new string[] { "locale", "inherit", "default", "resumeobject", "displayorder", "toolsdisplayorder", "timeout" }) {
Execute("bcdedit", $"/deletevalue {guid} {arg}", true); Execute("bcdedit", $"/deletevalue {guid} {arg}", true);
} }
@@ -462,9 +462,11 @@ public class Setup {
WriteLine("Enabled NVRAM entry for HackBGRT with BCDEdit."); WriteLine("Enabled NVRAM entry for HackBGRT with BCDEdit.");
// Verify that the entry was created. // Verify that the entry was created.
Execute("bcdedit", "/enum firmware", true); Execute("bcdedit", "/enum firmware", true);
Efi.MakeAndEnableBootEntry("HackBGRT", "\\EFI\\HackBGRT\\loader.efi", false, DryRun); var e = new EfiBootEntries();
e.MakeOwnEntry(false, DryRun); // Fix load options for shim.
e.EnableOwnEntry(DryRun);
Execute("bcdedit", $"/enum {guid}", true); Execute("bcdedit", $"/enum {guid}", true);
Efi.LogBootEntries(); e.LogEntries();
} catch (Exception e) { } catch (Exception e) {
Log($"EnableBCDEdit failed: {e.ToString()}"); Log($"EnableBCDEdit failed: {e.ToString()}");
throw new SetupException("Failed to enable HackBGRT with BCDEdit!"); throw new SetupException("Failed to enable HackBGRT with BCDEdit!");
@@ -508,10 +510,12 @@ public class Setup {
* Enable HackBGRT boot entry. * Enable HackBGRT boot entry.
*/ */
protected void EnableEntry() { protected void EnableEntry() {
Efi.MakeAndEnableBootEntry("HackBGRT", "\\EFI\\HackBGRT\\loader.efi", true, DryRun); var e = new EfiBootEntries();
e.MakeOwnEntry(true, DryRun);
e.EnableOwnEntry(DryRun);
WriteLine("Enabled NVRAM entry for HackBGRT."); WriteLine("Enabled NVRAM entry for HackBGRT.");
// Verify that the entry was created. // Verify that the entry was created.
Efi.LogBootEntries(); e.LogEntries();
Execute("bcdedit", "/enum firmware", true); Execute("bcdedit", "/enum firmware", true);
} }
@@ -519,7 +523,7 @@ public class Setup {
* Disable HackBGRT boot entry. * Disable HackBGRT boot entry.
*/ */
protected void DisableEntry() { protected void DisableEntry() {
Efi.DisableBootEntry("HackBGRT", "\\EFI\\HackBGRT\\loader.efi", DryRun); new EfiBootEntries().DisableOwnEntry(DryRun);
WriteLine("Disabled NVRAM entry for HackBGRT."); WriteLine("Disabled NVRAM entry for HackBGRT.");
} }
@@ -943,7 +947,7 @@ public class Setup {
var bootLog = $"\n--- BOOT LOG START ---\n{Efi.GetHackBGRTLog()}\n--- BOOT LOG END ---"; var bootLog = $"\n--- BOOT LOG START ---\n{Efi.GetHackBGRTLog()}\n--- BOOT LOG END ---";
Setup.Log(bootLog); Setup.Log(bootLog);
Efi.LogBGRT(); Efi.LogBGRT();
Efi.LogBootEntries(); EfiBootEntries.TryLogEntries();
if (GetBootTime() is DateTime bootTime) { if (GetBootTime() is DateTime bootTime) {
var configTime = new[] { File.GetCreationTime("config.txt"), File.GetLastWriteTime("config.txt") }.Max(); var configTime = new[] { File.GetCreationTime("config.txt"), File.GetLastWriteTime("config.txt") }.Max();
Log($"Boot time = {bootTime}, config.txt changed = {configTime}"); Log($"Boot time = {bootTime}, config.txt changed = {configTime}");