mirror of
https://github.com/Metabolix/HackBGRT.git
synced 2025-12-07 01:26:14 -08:00
Compare commits
14 Commits
1e36d7e388
...
v2.5.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e9ef85451 | ||
|
|
96599b1838 | ||
|
|
611ab30db3 | ||
|
|
ffa3e335ea | ||
|
|
a1f6297759 | ||
|
|
afd0780b61 | ||
|
|
320e154457 | ||
|
|
785307c0e2 | ||
|
|
be62caa400 | ||
|
|
734ea21308 | ||
|
|
1946765680 | ||
|
|
79ee253108 | ||
|
|
82abb0c120 | ||
|
|
830db410ea |
16
CHANGELOG.md
16
CHANGELOG.md
@@ -2,6 +2,22 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## 2.5.2 - 2025-04-13
|
||||
|
||||
### Fixed
|
||||
- Try to avoid mistaking C: for ESP.
|
||||
- Don't require Windows boot loader entry if it's not needed.
|
||||
|
||||
### Changed
|
||||
- Allow overriding ESP path.
|
||||
- Try to load `config.txt` from the current dir, to support multiple configurations.
|
||||
- Improve output and README for various situations.
|
||||
|
||||
## 2.5.1 - 2024-08-18
|
||||
|
||||
### Changed
|
||||
- Update *shim* to 15.8.
|
||||
|
||||
## 2.5.0 - 2024-06-21
|
||||
|
||||
### Changed
|
||||
|
||||
25
README.md
25
README.md
@@ -52,6 +52,9 @@ The *shim* boot loader is maintained by Red Hat, Inc, and the included signed co
|
||||
* `disable` – run all relevant `disable-*` commands.
|
||||
* `uninstall` – disable and remove completely.
|
||||
* `show-boot-log` – show the debug log collected during boot (if `log=1` is set in `config.txt`).
|
||||
* `arch=...` – force architecture.
|
||||
* `esp=...` – force EFI System Partition path.
|
||||
* `dry-run` – skip actual changes.
|
||||
* For example, run `setup.exe batch install allow-secure-boot enable-overwrite` to copy files and overwrite the MS boot loader regardless of Secure Boot status.
|
||||
|
||||
### Multi-boot configurations
|
||||
@@ -68,6 +71,8 @@ If you need it for other systems as well:
|
||||
|
||||
To install purely on Linux, you can install with `setup.exe dry-run` and then manually copy files from `dry-run/EFI` to your `[EFI System Partition]/EFI`. For further instructions, consult the documentation of your own Linux system.
|
||||
|
||||
HackBGRT tries to read its configuration from the same directory where it's installed, so you can even make (manually) multiple installations in different directories.
|
||||
|
||||
## Configuration
|
||||
|
||||
The configuration options are described in `config.txt`, which the installer copies into `[EFI System Partition]\EFI\HackBGRT\config.txt`.
|
||||
@@ -82,6 +87,10 @@ If you copy an image file to ESP manually, note that the image must be a 24-bit
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### BCDEdit failed
|
||||
|
||||
You can first try the other installation option in the menu. If it doesn't work either, your computer might have a problem. Open Command Prompt and figure out why `bcdedit /enum firmware` fails. In some cases, disabling antivirus, checking the hard disk or searching for 'how to fix 0x800703EE' may help.
|
||||
|
||||
### Verification failed, Security violation
|
||||
|
||||
This is part of the setup on first boot. Make sure you have read and understood [shim.md](shim.md).
|
||||
@@ -92,11 +101,11 @@ Sometimes the first boot is very slow (multiple minutes) for an unknown reason.
|
||||
|
||||
### Image is not visible, "nothing happens"
|
||||
|
||||
Run the setup again and select the option to check the boot log. Continue troubleshooting according to the log contents:
|
||||
Run the setup again and select the option to check the boot log, marked with `BOOT LOG START` in the log file. Continue troubleshooting according to the log contents:
|
||||
|
||||
#### Log is empty
|
||||
#### Boot log is empty
|
||||
|
||||
If the log is empty, then HackBGRT is not in use. Many computers now have a security feature which causes this problem: the computer resets some settings on reboot and skips the newly-installed HackBGRT.
|
||||
If the log is empty, then HackBGRT is not in use. Many computers now have a security feature which causes this problem: the computer prevents enabling HackBGRT automatically, instead it resets a certain setting (BootOrder) on reboot and skips the newly-installed HackBGRT.
|
||||
|
||||
You have to fix this manually. (After all, the security feature is specifically designed to prevent automatic changes.)
|
||||
|
||||
@@ -112,13 +121,15 @@ Some people report that HackBGRT is not visible in the computer settings. That's
|
||||
|
||||
If all else fails and you are sure about your computer skills, you can try the legacy installation method. The method bypasses this particular problem but may cause very serious problems if configured incorrectly.
|
||||
|
||||
#### Log is not empty
|
||||
#### Boot log is not empty
|
||||
|
||||
Try to reinstall HackBGRT with the default configuration and image.
|
||||
If the log shows that HackBGRT has been run during boot, the problem is usually in your configuration file or image. Try to reinstall HackBGRT with the default configuration and image.
|
||||
|
||||
If the default logo works, try again with your custom image. Make sure that the image has a reasonable size and position and that you haven't messed up `config.txt`.
|
||||
If the default logo works, try again with your custom image. Make sure that the image has a reasonable size and position so that it fits the resolution which HackBGRT reports during boot. The resolution may be lower than your desktop resolution.
|
||||
|
||||
If the default logo does not work, check the boot log again.
|
||||
When you get your image working with the default configuration, you can do any other necessary changes to `config.txt`.
|
||||
|
||||
If the default logo does not work, check the boot log again to see if there is some obvious error.
|
||||
You may report an issue and attach the `setup.log` file.
|
||||
|
||||
### Impossible to boot at all
|
||||
|
||||
@@ -1,55 +1,30 @@
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: shim
|
||||
Upstream-Contact: Peter Jones <pjones@redhat.com>
|
||||
Source: https://github.com/rhboot/shim
|
||||
Copyright 2012 Red Hat, Inc <mjg@redhat.com>
|
||||
|
||||
Files: *
|
||||
Copyright: 2012 Red Hat, Inc
|
||||
2009-2012 Intel Corporation
|
||||
License: BSD-2-Clause
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
Files: debian/po/cs.po
|
||||
Copyright: 2018 Michal Simunek <michal.simunek@gmail.com>
|
||||
License: BSD-2-Clause
|
||||
Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
Files: debian/po/de.po
|
||||
Copyright: 2017, 2018 Markus Hiereth <markus.hiereth@freenet.de>
|
||||
License: BSD-2-Clause
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
Files: debian/po/fr.po
|
||||
Copyright: 2017, 2018 Alban Vidal <alban.vidal@zordhak.fr>
|
||||
License: BSD-2-Clause
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Files: debian/po/nl.po
|
||||
Copyright: 2017, 2018 Frans Spiesschaert <Frans.Spiesschaert@yucom.be>
|
||||
License: BSD-2-Clause
|
||||
|
||||
Files: debian/po/pt.po
|
||||
Copyright: 2017, 2018 Rui Branco <ruipb@debianpt.org>
|
||||
License: BSD-2-Clause
|
||||
|
||||
License: BSD-2-Clause
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
.
|
||||
Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
.
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the
|
||||
distribution.
|
||||
.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
Significant portions of this code are derived from Tianocore
|
||||
(http://tianocore.sf.net) and are Copyright 2009-2012 Intel
|
||||
Corporation.
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
30
src/Efi.cs
30
src/Efi.cs
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.ComponentModel;
|
||||
using Microsoft.Win32;
|
||||
|
||||
/**
|
||||
@@ -147,24 +148,21 @@ public class Efi {
|
||||
if (len == buf.Length) {
|
||||
continue;
|
||||
}
|
||||
if (len > 0 || Marshal.GetLastWin32Error() == 0) {
|
||||
var error = Marshal.GetLastWin32Error();
|
||||
const int ERROR_ENVVAR_NOT_FOUND = 0xCB;
|
||||
if (error == ERROR_ENVVAR_NOT_FOUND) {
|
||||
return result;
|
||||
}
|
||||
if (len > 0 || error == 0) {
|
||||
result.Data = new byte[len];
|
||||
Array.Copy(buf, 0, result.Data, 0, len);
|
||||
return result;
|
||||
}
|
||||
switch (len != 0 ? 0 : Marshal.GetLastWin32Error()) {
|
||||
case 203:
|
||||
// Not found.
|
||||
return result;
|
||||
case 87:
|
||||
throw new Exception("GetVariable: Invalid parameter");
|
||||
case 1314:
|
||||
throw new Exception("GetVariable: Privilege not held");
|
||||
default:
|
||||
throw new Exception("GetVariable: error " + Marshal.GetLastWin32Error());
|
||||
}
|
||||
const int ERROR_INVALID_FUNCTION = 0x1;
|
||||
var msg = $"GetVariable: error 0x{error:X08}: ${new Win32Exception(error).Message}";
|
||||
throw error == ERROR_INVALID_FUNCTION ? new NotImplementedException(msg) : new Exception(msg);
|
||||
}
|
||||
throw new Exception("GetFirmwareEnvironmentVariable: too big data");
|
||||
throw new Exception("GetVariable: result exceeds 1MB");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,11 +264,13 @@ public class Efi {
|
||||
try {
|
||||
var log = GetVariable("HackBGRTLog", EFI_HACKBGRT_GUID);
|
||||
if (log.Data == null) {
|
||||
return "Log is empty.";
|
||||
return "Boot log is empty.";
|
||||
}
|
||||
return new string(BytesToUInt16s(log.Data).Select(i => (char)i).ToArray());
|
||||
} catch (NotImplementedException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
return $"Log not found: {e.ToString()}";
|
||||
return $"Boot log not found: {e.ToString()}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,16 @@ public class EfiBootEntries {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Status of the own boot entry.
|
||||
*/
|
||||
public enum OwnEntryStatus {
|
||||
NotFound,
|
||||
Disabled,
|
||||
EnabledAfterWindows,
|
||||
Enabled
|
||||
}
|
||||
|
||||
/**
|
||||
* Path to the Windows boot loader.
|
||||
*/
|
||||
@@ -173,6 +183,26 @@ public class EfiBootEntries {
|
||||
get { return FindEntry(null); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the own entry is enabled.
|
||||
*/
|
||||
public OwnEntryStatus GetOwnEntryStatus() {
|
||||
var (ownNum, ownVar, _) = OwnEntry;
|
||||
if (ownVar == null) {
|
||||
return OwnEntryStatus.NotFound;
|
||||
}
|
||||
var (msNum, _, _) = WindowsEntry;
|
||||
var msPos = BootOrderInts.IndexOf(msNum);
|
||||
var ownPos = BootOrderInts.IndexOf(ownNum);
|
||||
if (ownPos < 0) {
|
||||
return OwnEntryStatus.Disabled;
|
||||
}
|
||||
if (ownPos < msPos || msPos < 0) {
|
||||
return OwnEntryStatus.Enabled;
|
||||
}
|
||||
return OwnEntryStatus.EnabledAfterWindows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the said boot entry from BootOrder.
|
||||
*
|
||||
@@ -206,9 +236,6 @@ public class EfiBootEntries {
|
||||
*/
|
||||
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;
|
||||
@@ -236,6 +263,9 @@ public class EfiBootEntries {
|
||||
ownEntry.Arguments = new byte[0];
|
||||
}
|
||||
} else {
|
||||
if (msEntry == null) {
|
||||
throw new Exception("MakeOwnEntry: Windows Boot Manager not found.");
|
||||
}
|
||||
ownEntry = msEntry;
|
||||
ownEntry.Arguments = new byte[0];
|
||||
ownEntry.Label = "HackBGRT";
|
||||
@@ -295,15 +325,4 @@ public class EfiBootEntries {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to log the boot entries.
|
||||
*/
|
||||
public static void TryLogEntries() {
|
||||
try {
|
||||
new EfiBootEntries().LogEntries();
|
||||
} catch (Exception e) {
|
||||
Setup.Log($"LogEntries failed: {e.ToString()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
69
src/Esp.cs
69
src/Esp.cs
@@ -19,6 +19,22 @@ public sealed class Esp {
|
||||
}
|
||||
}
|
||||
|
||||
/** Output of mountvol. */
|
||||
private static string MountvolOutput;
|
||||
|
||||
/** Possible drive letter for the ESP. */
|
||||
public static string DriveLetters = "ABZYXWVUTSRQPONMLKJIHGFEDC";
|
||||
|
||||
/** Does MountvolOutput contain /S? */
|
||||
public static bool MountvolESPNotSupported {
|
||||
get {
|
||||
if (MountvolOutput == null) {
|
||||
MountvolOutput = Setup.Execute("mountvol", "", false);
|
||||
}
|
||||
return MountvolOutput.Contains(" /S") == false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor: do nothing.
|
||||
*/
|
||||
@@ -67,29 +83,48 @@ public sealed class Esp {
|
||||
*
|
||||
* @return true if the drive was found.
|
||||
*/
|
||||
public static bool Find() {
|
||||
if (MountInstance != null) {
|
||||
return true;
|
||||
}
|
||||
Setup.Log("Esp.Find()");
|
||||
public static bool FindOrMount() {
|
||||
return Location != null || FindWithMountvol() || Mount() || TryAllDrives();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the EFI System Partition, if it's already mounted.
|
||||
*
|
||||
* @return true if the drive was found.
|
||||
*/
|
||||
private static bool FindWithMountvol() {
|
||||
Setup.Log("Esp: Detect from mountvol output.");
|
||||
try {
|
||||
// Match "The EFI System Partition is mounted at E:\" with some language support.
|
||||
MountvolOutput = Setup.Execute("mountvol", "", false);
|
||||
var re = new Regex(" EFI[^\n]*(?:\n[ \t]*)?([A-Z]:\\\\)");
|
||||
var m = re.Match(Setup.Execute("mountvol", "", false));
|
||||
var m = re.Match(MountvolOutput);
|
||||
if (m.Success && TryPath(m.Groups[1].Captures[0].Value)) {
|
||||
return true;
|
||||
}
|
||||
Setup.Log("Esp.Find: no match");
|
||||
Setup.Log("Esp: no match");
|
||||
} catch (Exception e) {
|
||||
Setup.Log($"Esp.Find: {e.ToString()}");
|
||||
Setup.Log($"Esp: {e.ToString()}");
|
||||
}
|
||||
for (char c = 'A'; c <= 'Z'; ++c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try all drive letters to find the EFI System Partition.
|
||||
*
|
||||
* @return true if the drive was found.
|
||||
*/
|
||||
private static bool TryAllDrives() {
|
||||
Setup.Log("Esp: Detect by trying all drive letters.");
|
||||
foreach (char c in DriveLetters) {
|
||||
if (TryPath(c + ":\\")) {
|
||||
Setup.Log($"Esp.Find: found {c}");
|
||||
Setup.Log($"Esp: found {c}");
|
||||
if (c == 'C') {
|
||||
Setup.Log("Esp: WARNING: It's unlikely that C: is really the ESP.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Setup.Log("Esp.Find: not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -98,11 +133,15 @@ public sealed class Esp {
|
||||
*
|
||||
* @return true if the drive was mounted, false otherwise.
|
||||
*/
|
||||
public static bool Mount() {
|
||||
if (MountInstance != null) {
|
||||
return true;
|
||||
private static bool Mount() {
|
||||
if (MountvolESPNotSupported) {
|
||||
return false;
|
||||
}
|
||||
for (char c = 'A'; c <= 'Z'; ++c) {
|
||||
Setup.Log("Esp: Try to mount with mountvol.");
|
||||
foreach (char c in DriveLetters) {
|
||||
if (Directory.Exists(c + ":\\")) {
|
||||
continue;
|
||||
}
|
||||
Setup.Log($"Esp.Mount: {c}");
|
||||
if (Setup.Execute("mountvol", c + ": /S", true) != null) {
|
||||
MountInstance = new Esp();
|
||||
|
||||
75
src/Setup.cs
75
src/Setup.cs
@@ -106,6 +106,9 @@ public class Setup {
|
||||
/** @var Dry run? */
|
||||
protected bool DryRun;
|
||||
|
||||
/** @var User-defined ESP path */
|
||||
protected string UserEspPath;
|
||||
|
||||
/** @var Run in batch mode? */
|
||||
protected bool Batch;
|
||||
|
||||
@@ -289,9 +292,17 @@ public class Setup {
|
||||
if (DryRun) {
|
||||
Directory.CreateDirectory(Path.Combine("dry-run", "EFI"));
|
||||
Esp.TryPath("dry-run", false);
|
||||
} else if (UserEspPath != null) {
|
||||
WriteLine($"Using user-defined ESP path: {UserEspPath}");
|
||||
if (!Esp.TryPath(UserEspPath, false)) {
|
||||
throw new SetupException("The ESP path doesn't look like an EFI System Partition.");
|
||||
}
|
||||
}
|
||||
if (Esp.Location == null && !Esp.Find() && !Esp.Mount() && !Batch) {
|
||||
if (!Esp.FindOrMount() && !Batch) {
|
||||
WriteLine("EFI System Partition was not found.");
|
||||
if (Esp.MountvolESPNotSupported) {
|
||||
WriteLine("Your computer doesn't support mountvol /S. You have to mount ESP manually.");
|
||||
}
|
||||
WriteLine("Press enter to exit, or give ESP path here: ");
|
||||
string s = Console.ReadLine();
|
||||
Log($"User input: {s}");
|
||||
@@ -306,6 +317,9 @@ public class Setup {
|
||||
throw new SetupException("EFI System Partition was not found.");
|
||||
}
|
||||
WriteLine($"EFI System Partition location is {Esp.Location}");
|
||||
if (Esp.Location.StartsWith("C:")) {
|
||||
WriteLine("Warning: EFI System Partition is not normally C: drive.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -441,12 +455,12 @@ public class Setup {
|
||||
}
|
||||
var bcdeditEnum = Execute("bcdedit", "/enum firmware");
|
||||
if (bcdeditEnum.ExitCode != 0) {
|
||||
WriteLine("BCDEdit is not working. Fix it or try another method.");
|
||||
if (bcdeditEnum.Output != null) {
|
||||
var lastLine = bcdeditEnum.Output.Split("\n".ToCharArray()).Last();
|
||||
WriteLine($"BCDEdit output: {lastLine}");
|
||||
WriteLine("Disable antivirus, check your hard disk, or search 'how to fix 0x800703EE'.");
|
||||
var lines = bcdeditEnum.Output.Split("\n".ToCharArray());
|
||||
var lastLine = lines.Select(s => s != "").Last();
|
||||
WriteLine($"BCDEdit failed with: {lastLine}");
|
||||
}
|
||||
WriteLine("BCDEdit failed. See README for further information.");
|
||||
throw new SetupException("Failed to enable HackBGRT with BCDEdit!");
|
||||
}
|
||||
try {
|
||||
@@ -468,13 +482,12 @@ public class Setup {
|
||||
var fwbootmgr = "{fwbootmgr}";
|
||||
Execute("bcdedit", $"/set {fwbootmgr} displayorder {guid} /addfirst", true);
|
||||
WriteLine("Enabled NVRAM entry for HackBGRT with BCDEdit.");
|
||||
// Verify that the entry was created.
|
||||
Execute("bcdedit", "/enum firmware", true);
|
||||
|
||||
Execute("bcdedit", $"/enum {guid}", true);
|
||||
var e = new EfiBootEntries();
|
||||
e.MakeOwnEntry(false, DryRun); // Fix load options for shim.
|
||||
e.EnableOwnEntry(DryRun);
|
||||
Execute("bcdedit", $"/enum {guid}", true);
|
||||
e.LogEntries();
|
||||
} catch (Exception e) {
|
||||
Log($"EnableBCDEdit failed: {e.ToString()}");
|
||||
throw new SetupException("Failed to enable HackBGRT with BCDEdit!");
|
||||
@@ -522,9 +535,6 @@ public class Setup {
|
||||
e.MakeOwnEntry(true, DryRun);
|
||||
e.EnableOwnEntry(DryRun);
|
||||
WriteLine("Enabled NVRAM entry for HackBGRT.");
|
||||
// Verify that the entry was created.
|
||||
e.LogEntries();
|
||||
Execute("bcdedit", "/enum firmware", true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -535,6 +545,27 @@ public class Setup {
|
||||
WriteLine("Disabled NVRAM entry for HackBGRT.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Log boot entries and report the status of HackBGRT boot entry.
|
||||
*/
|
||||
public void CheckEntries() {
|
||||
try {
|
||||
var efiBootEntries = new EfiBootEntries();
|
||||
efiBootEntries.LogEntries();
|
||||
var entryStatusText = efiBootEntries.GetOwnEntryStatus() switch {
|
||||
EfiBootEntries.OwnEntryStatus.NotFound => "missing",
|
||||
EfiBootEntries.OwnEntryStatus.Disabled => "disabled (not in BootOrder)",
|
||||
EfiBootEntries.OwnEntryStatus.EnabledAfterWindows => "disabled (after Windows in BootOrder)",
|
||||
EfiBootEntries.OwnEntryStatus.Enabled => "enabled correctly",
|
||||
_ => throw new SetupException("Unknown HackBGRT boot entry status!")
|
||||
};
|
||||
WriteLine($"HackBGRT boot entry is {entryStatusText}.");
|
||||
} catch (Exception e) {
|
||||
WriteLine($"Failed to check EFI boot entries: {e.Message}");
|
||||
Setup.Log(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get paths related to MS boot loader.
|
||||
*/
|
||||
@@ -952,10 +983,19 @@ public class Setup {
|
||||
|
||||
InitEspPath();
|
||||
InitEspInfo();
|
||||
var bootLog = $"\n--- BOOT LOG START ---\n{Efi.GetHackBGRTLog()}\n--- BOOT LOG END ---";
|
||||
Func<string> tryGetBootLog = () => {
|
||||
try {
|
||||
return $"\n--- BOOT LOG START ---\n{Efi.GetHackBGRTLog()}\n--- BOOT LOG END ---";
|
||||
} catch (NotImplementedException e) {
|
||||
throw new SetupException($"Looks like you're not booting in UEFI mode. ({e.Message})");
|
||||
}
|
||||
};
|
||||
var bootLog = tryGetBootLog();
|
||||
Setup.Log(bootLog);
|
||||
|
||||
Efi.LogBGRT();
|
||||
EfiBootEntries.TryLogEntries();
|
||||
CheckEntries();
|
||||
|
||||
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}");
|
||||
@@ -976,7 +1016,7 @@ public class Setup {
|
||||
WriteLine($"Error: {e.Message}");
|
||||
WriteLine($"Reverting. Use batch mode with allow-bad-loader to override.");
|
||||
revert();
|
||||
throw new SetupException("Check your configuration and try again.");
|
||||
throw new SetupException($"Error in configuration: {e.Message}");
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -987,6 +1027,8 @@ public class Setup {
|
||||
HandleBitLocker();
|
||||
enable();
|
||||
verify(revert);
|
||||
CheckEntries();
|
||||
Execute("bcdedit", "/enum firmware", true);
|
||||
};
|
||||
foreach (var arg in actions) {
|
||||
Log($"Running action '{arg}'.");
|
||||
@@ -1012,6 +1054,7 @@ public class Setup {
|
||||
BootToFW();
|
||||
} else if (arg == "show-boot-log") {
|
||||
WriteLine(bootLog);
|
||||
CheckEntries();
|
||||
} else {
|
||||
throw new SetupException($"Invalid action: '{arg}'!");
|
||||
}
|
||||
@@ -1028,6 +1071,7 @@ public class Setup {
|
||||
var self = Assembly.GetExecutingAssembly().Location;
|
||||
Directory.SetCurrentDirectory(Path.GetDirectoryName(self));
|
||||
WriteLine($"HackBGRT installer version: {Version}");
|
||||
Log($"Windows version: {Environment.OSVersion}");
|
||||
Log($"Args: {String.Join(" ", args)}");
|
||||
Environment.ExitCode = new Setup().Run(args);
|
||||
}
|
||||
@@ -1044,7 +1088,7 @@ public class Setup {
|
||||
AllowSecureBoot = args.Contains("allow-secure-boot");
|
||||
AllowBitLocker = args.Contains("allow-bitlocker");
|
||||
SkipShim = args.Contains("skip-shim");
|
||||
ForwardArguments = String.Join(" ", args.Where(s => ForwardableArguments.Contains(s) || s.StartsWith("arch=")));
|
||||
ForwardArguments = String.Join(" ", args.Where(s => ForwardableArguments.Contains(s) || s.StartsWith("arch=") || s.StartsWith("esp=")));
|
||||
try {
|
||||
if (!(Directory.Exists("efi") || Directory.Exists("efi-signed")) || !File.Exists("config.txt")) {
|
||||
WriteLine("This setup program is not in the correct directory!");
|
||||
@@ -1052,6 +1096,7 @@ public class Setup {
|
||||
return 1;
|
||||
}
|
||||
SetArch(args.Where(s => s.StartsWith("arch=")).Select(s => s.Substring(5)).LastOrDefault());
|
||||
UserEspPath = args.Where(s => s.StartsWith("esp=")).Select(s => s.Substring(4)).LastOrDefault();
|
||||
if (args.Contains("is-elevated") && !HasPrivileges() && !DryRun) {
|
||||
WriteLine("This installer needs to be run as administrator!");
|
||||
return 1;
|
||||
|
||||
27
src/efi.c
27
src/efi.c
@@ -64,6 +64,33 @@ EFI_DEVICE_PATH *FileDevicePath(IN EFI_HANDLE Device OPTIONAL, IN CHAR16 *FileNa
|
||||
return new_path;
|
||||
}
|
||||
|
||||
CHAR16 *DevicePathToStr(EFI_DEVICE_PATH *DevPath) {
|
||||
UINTN path_length = 0;
|
||||
for (EFI_DEVICE_PATH *p0 = DevPath;; p0 = NextDevicePathNode(p0)) {
|
||||
if (DevicePathType(p0) != MEDIA_DEVICE_PATH || DevicePathSubType(p0) != MEDIA_FILEPATH_DP) {
|
||||
break;
|
||||
}
|
||||
path_length += DevicePathNodeLength(p0) + 1;
|
||||
}
|
||||
|
||||
CHAR16* str;
|
||||
UINTN size_str = (path_length + 1) * sizeof(*str);
|
||||
|
||||
if (!path_length || EFI_ERROR(BS->AllocatePool(EfiBootServicesData, size_str, (void**)&str))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINTN pos = 0;
|
||||
for (EFI_DEVICE_PATH *p0 = DevPath; pos < path_length; p0 = NextDevicePathNode(p0)) {
|
||||
FILEPATH_DEVICE_PATH *f = (FILEPATH_DEVICE_PATH *) p0;
|
||||
BS->CopyMem(str + pos, f->PathName, StrLen(f->PathName) * sizeof(*str));
|
||||
pos += DevicePathNodeLength(p0) + 1;
|
||||
str[pos - 1] = L'\\';
|
||||
}
|
||||
str[pos - 1] = 0;
|
||||
return str;
|
||||
}
|
||||
|
||||
INTN CompareMem(IN CONST VOID *Dest, IN CONST VOID *Src, IN UINTN len) {
|
||||
CONST UINT8 *d = Dest, *s = Src;
|
||||
for (UINTN i = 0; i < len; ++i) {
|
||||
|
||||
31
src/main.c
31
src/main.c
@@ -439,16 +439,39 @@ EFI_STATUS EFIAPI efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *ST_) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
EFI_FILE_HANDLE base_dir;
|
||||
if (EFI_ERROR(root_dir->Open(root_dir, &base_dir, L"\\EFI\\HackBGRT", EFI_FILE_MODE_READ, 0))) {
|
||||
Log(config.debug, L"Failed to HackBGRT directory.\n");
|
||||
base_dir = root_dir;
|
||||
CHAR16* default_dir_path = L"\\EFI\\HackBGRT";
|
||||
Log(config.debug, L"Default directory: %s\n", default_dir_path);
|
||||
EFI_FILE_HANDLE default_dir;
|
||||
if (EFI_ERROR(root_dir->Open(root_dir, &default_dir, default_dir_path, EFI_FILE_MODE_READ, 0))) {
|
||||
Log(config.debug, L"Failed to open HackBGRT default directory.\n");
|
||||
default_dir = root_dir;
|
||||
}
|
||||
|
||||
CHAR16* working_dir_path = DevicePathToStr(image->FilePath);
|
||||
for (int i = StrLen(working_dir_path), skipped_last_component = 0; i--;) {
|
||||
if (working_dir_path[i] == L'/' || working_dir_path[i] == L'\\') {
|
||||
working_dir_path[i] = skipped_last_component++ ? L'\\' : L'\0';
|
||||
}
|
||||
}
|
||||
Log(config.debug, L"Working directory: %s\n", working_dir_path);
|
||||
EFI_FILE_HANDLE working_dir;
|
||||
if (EFI_ERROR(root_dir->Open(root_dir, &working_dir, working_dir_path, EFI_FILE_MODE_READ, 0))) {
|
||||
Log(config.debug, L"Failed to open HackBGRT working directory.\n");
|
||||
working_dir = default_dir;
|
||||
}
|
||||
|
||||
EFI_FILE_HANDLE base_dir = working_dir;
|
||||
|
||||
EFI_SHELL_PARAMETERS_PROTOCOL *shell_param_proto = NULL;
|
||||
if (EFI_ERROR(BS->OpenProtocol(image_handle, TmpGuidPtr((EFI_GUID) EFI_SHELL_PARAMETERS_PROTOCOL_GUID), (void**) &shell_param_proto, 0, 0, EFI_OPEN_PROTOCOL_GET_PROTOCOL)) || shell_param_proto->Argc <= 1) {
|
||||
const CHAR16* config_path = L"config.txt";
|
||||
retry_read_config:
|
||||
if (!ReadConfigFile(&config, base_dir, config_path)) {
|
||||
if (base_dir != default_dir && StrCmp(default_dir_path, working_dir_path) != 0) {
|
||||
base_dir = default_dir;
|
||||
Log(config.debug, L"Trying the default directory.\n");
|
||||
goto retry_read_config;
|
||||
}
|
||||
Log(1, L"No config, no command line!\n", config_path);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user