From c826149183c12371ff65a1ca88406f47b1dd748b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauri=20Kentt=C3=A4?= Date: Thu, 9 May 2024 19:24:24 +0300 Subject: [PATCH] Refactor EFI boot entry code into a new class --- Makefile | 2 +- src/Efi.cs | 257 +---------------------------------- src/EfiBootEntries.cs | 309 ++++++++++++++++++++++++++++++++++++++++++ src/Setup.cs | 18 ++- 4 files changed, 323 insertions(+), 263 deletions(-) create mode 100644 src/EfiBootEntries.cs diff --git a/Makefile b/Makefile index c3a4a65..0cd504d 100644 --- a/Makefile +++ b/Makefile @@ -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_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) CFLAGS += '-DGIT_DESCRIBE_W=L"$(GIT_DESCRIBE)"' '-DGIT_DESCRIBE="$(GIT_DESCRIBE)"' RELEASE_NAME = HackBGRT-$(GIT_DESCRIBE:v%=%) diff --git a/src/Efi.cs b/src/Efi.cs index bbaa194..3fc71c4 100644 --- a/src/Efi.cs +++ b/src/Efi.cs @@ -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 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(); - 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. */ @@ -206,7 +124,7 @@ public class Efi { * @param guid GUID of 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(); result.Name = name; result.Guid = guid; @@ -255,7 +173,7 @@ public class Efi { * @param v Information of 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.Log($"Writing EFI variable: {v}"); 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])); } - /** - * 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(); - 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(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(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(); - 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. */ diff --git a/src/EfiBootEntries.cs b/src/EfiBootEntries.cs new file mode 100644 index 0000000..3cbc935 --- /dev/null +++ b/src/EfiBootEntries.cs @@ -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 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(); + 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 cache; + private readonly Efi.Variable BootOrder; + private readonly Efi.Variable BootCurrent; + private readonly List BootOrderInts; + private readonly List BootCurrentInts; + + /** + * Constructor. Reads BootOrder and BootCurrent. + */ + public EfiBootEntries() { + cache = new Dictionary(); + 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(Efi.BytesToUInt16s(BootCurrent.Data)); + BootOrderInts = new List(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(); + 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()}"); + } + } +} diff --git a/src/Setup.cs b/src/Setup.cs index f9068c3..e8b350e 100644 --- a/src/Setup.cs +++ b/src/Setup.cs @@ -453,7 +453,7 @@ public class Setup { } var guid = match.Value; 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" }) { Execute("bcdedit", $"/deletevalue {guid} {arg}", true); } @@ -462,9 +462,11 @@ 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); + var e = new EfiBootEntries(); + e.MakeOwnEntry(false, DryRun); // Fix load options for shim. + e.EnableOwnEntry(DryRun); Execute("bcdedit", $"/enum {guid}", true); - Efi.LogBootEntries(); + e.LogEntries(); } catch (Exception e) { Log($"EnableBCDEdit failed: {e.ToString()}"); throw new SetupException("Failed to enable HackBGRT with BCDEdit!"); @@ -508,10 +510,12 @@ public class Setup { * Enable HackBGRT boot entry. */ 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."); // Verify that the entry was created. - Efi.LogBootEntries(); + e.LogEntries(); Execute("bcdedit", "/enum firmware", true); } @@ -519,7 +523,7 @@ public class Setup { * Disable HackBGRT boot entry. */ protected void DisableEntry() { - Efi.DisableBootEntry("HackBGRT", "\\EFI\\HackBGRT\\loader.efi", DryRun); + new EfiBootEntries().DisableOwnEntry(DryRun); 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 ---"; Setup.Log(bootLog); Efi.LogBGRT(); - Efi.LogBootEntries(); + EfiBootEntries.TryLogEntries(); if (GetBootTime() is DateTime bootTime) { var configTime = new[] { File.GetCreationTime("config.txt"), File.GetLastWriteTime("config.txt") }.Max(); Log($"Boot time = {bootTime}, config.txt changed = {configTime}");