12 Commits

Author SHA1 Message Date
Lauri Kenttä
5856d25b5b Update change log and tag v2.2.0 2023-11-17 23:24:58 +02:00
Lauri Kenttä
466ab69c48 Use shim 15.7 to support Secure Boot
Use shim-signed and shim-helpers-{arch}-signed from Debian:
https://packages.debian.org/bookworm/shim-signed
2023-11-17 23:24:58 +02:00
Lauri Kenttä
14aa79929a Easily override GIT_DESCRIBE 2023-11-17 23:13:12 +02:00
Lauri Kenttä
5e32a3f880 Add clean target to Makefile 2023-11-17 23:13:12 +02:00
Lauri Kenttä
db934099df Gather log during boot 2023-11-17 23:13:12 +02:00
Lauri Kenttä
e93ed54cb2 Make setup menu shorter 2023-11-17 22:47:29 +02:00
Lauri Kenttä
9b3b045a21 Add SBAT section to the EFI binaries 2023-11-17 22:26:43 +02:00
Lauri Kenttä
be8a5d35d2 Sign the EFI files 2023-11-17 22:26:43 +02:00
Lauri Kenttä
2366fc8b98 Warn about Fast Startup (Hiberboot) 2023-11-16 22:56:10 +02:00
Lauri Kenttä
e04ba3e451 Log boot entries during setup 2023-11-16 22:07:08 +02:00
Lauri Kenttä
f40f2bc9dc Clarify LogBGRT output for corner cases 2023-11-09 21:46:39 +02:00
Lauri Kenttä
2f572b24d4 Free BMP if it's invalid 2023-11-09 21:46:35 +02:00
18 changed files with 696 additions and 101 deletions

View File

@@ -2,6 +2,12 @@
All notable changes to this project will be documented in this file.
## 2.2.0 - 2023-11-17
### Added
- Support Secure Boot with *shim* boot loader.
- Gather debug log during boot and read it with setup.exe.
## 2.1.0 - 2023-10-04
### Added

View File

@@ -7,20 +7,23 @@ LIBS = -L$(GNUEFI_LIB) -lefi -lgcc
GNUEFI_INC = /usr/$(CC_PREFIX)/include/efi
GNUEFI_LIB = /usr/$(CC_PREFIX)/lib
FILES_C = src/main.c src/util.c src/types.c src/config.c
FILES_C = src/main.c src/util.c src/types.c src/config.c src/sbat.c
FILES_H = $(wildcard src/*.h)
FILES_CS = src/Setup.cs src/Esp.cs src/Efi.cs
GIT_DESCRIBE = $(firstword $(shell git describe --tags) unknown)
CFLAGS += '-DGIT_DESCRIBE=L"$(GIT_DESCRIBE)"'
GIT_DESCRIBE := $(firstword $(GIT_DESCRIBE) $(shell git describe --tags) unknown)
CFLAGS += '-DGIT_DESCRIBE_W=L"$(GIT_DESCRIBE)"' '-DGIT_DESCRIBE="$(GIT_DESCRIBE)"'
ZIPDIR = HackBGRT-$(GIT_DESCRIBE:v%=%)
ZIP = $(ZIPDIR).zip
all: efi setup zip
efi: bootx64.efi bootia32.efi
.PHONY: all efi efi-signed setup zip clean
all: efi setup
efi: efi/bootx64.efi efi/bootia32.efi
efi-signed: efi-signed/bootx64.efi efi-signed/bootia32.efi
setup: setup.exe
zip: $(ZIP)
$(ZIP): bootx64.efi bootia32.efi config.txt splash.bmp setup.exe README.md CHANGELOG.md README.efilib LICENSE
$(ZIP): efi-signed certificate.cer config.txt splash.bmp setup.exe README.md CHANGELOG.md README.efilib LICENSE shim-signed shim.md
test ! -d "$(ZIPDIR)"
mkdir "$(ZIPDIR)"
cp -a $^ "$(ZIPDIR)" || (rm -rf "$(ZIPDIR)"; exit 1)
@@ -33,12 +36,36 @@ src/GIT_DESCRIBE.cs: $(FILES_CS) $(FILES_C) $(FILES_H)
setup.exe: $(FILES_CS) src/GIT_DESCRIBE.cs
csc /define:GIT_DESCRIBE /out:$@ $^
bootx64.efi: CC_PREFIX = x86_64-w64-mingw32
bootx64.efi: GNUEFI_ARCH = x86_64
bootx64.efi: $(FILES_C)
certificate.cer pki:
@echo
@echo "You need proper keys to sign the EFI executables."
@echo "Example:"
@echo "mkdir -p pki"
@echo "certutil --empty-password -N -d pki"
@echo "efikeygen -d pki -n HackBGRT-signer -S -k -c 'CN=HackBGRT Secure Boot Signer,OU=HackBGRT,O=Unknown,MAIL=unknown@example.com' -u 'URL'"
@echo "certutil -d pki -n HackBGRT-signer -Lr > certificate.cer"
@echo "Modify and run the commands yourself."
@echo
@false
efi-signed/%.efi: efi/%.efi
mkdir -p efi-signed
pesign --force -n pki -i $< -o $@ -c HackBGRT-signer -s
efi-signed/bootx64.efi: pki
efi-signed/bootia32.efi: pki
efi/bootx64.efi: CC_PREFIX = x86_64-w64-mingw32
efi/bootx64.efi: GNUEFI_ARCH = x86_64
efi/bootx64.efi: $(FILES_C)
@mkdir -p efi
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS) -s
bootia32.efi: CC_PREFIX = i686-w64-mingw32
bootia32.efi: GNUEFI_ARCH = ia32
bootia32.efi: $(FILES_C)
efi/bootia32.efi: CC_PREFIX = i686-w64-mingw32
efi/bootia32.efi: GNUEFI_ARCH = ia32
efi/bootia32.efi: $(FILES_C)
@mkdir -p efi
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS) -s
clean:
rm -rf setup.exe efi efi-signed

View File

@@ -11,18 +11,24 @@ When booting on a UEFI-based computer, Windows may show a vendor-defined logo wh
**Important:** If you mess up the installation, your system may become unbootable! Create a rescue disk before use. This software comes with no warranty. Use at your own risk.
* Make sure that your computer is booting with UEFI.
* Make sure that Secure Boot is disabled, unless you know how to sign EFI applications.
* Make sure that you have read the Secure Boot instructions.
* Make sure that BitLocker is disabled, or find your recovery key.
### Secure Boot instructions
HackBGRT is not approved by Microsoft. Instead, HackBGRT comes with the *shim* boot loader, which allows to manually select HackBGRT as a trusted program. After installing HackBGRT and rebooting your computer, you have to **follow the instructions in [shim.md](shim.md)** to achieve this. These steps cannot be automated, that's the whole point of Secure Boot. Although HackBGRT is self-signed with a certificate, it's not advisable to enroll foreign certificates directly into your firmware.
The *shim* boot loader is maintained by Red Hat, Inc, and the included signed copy of *shim* is extracted from Debian GNU/Linux many thanks to the maintainers! For copyright information, see [shim-signed/COPYRIGHT](shim-signed/COPYRIGHT).
### Windows installation
* Get the latest release from the Releases page.
* Start `setup.exe` and follow the instructions.
* You may need to manually disable Secure Boot and then retry.
* The installer will launch Paint for editing the image.
* If Windows later restores the original boot loader, just reinstall.
* If you wish to change the image or other configuration, just reinstall.
* For advanced settings, edit `config.txt` before installing. No extra support provided!
* After installing, read the instructions in [shim.md](shim.md) and reboot your computer.
### Quiet (batch) installation
@@ -35,11 +41,13 @@ When booting on a UEFI-based computer, Windows may show a vendor-defined logo wh
* `disable-bootmgr` use `bcdedit` to disable the EFI boot entry.
* `enable-overwrite` overwrite the MS boot loader.
* `disable-overwrite` restore the MS boot loader.
* `skip-shim` skip *shim* when installing.
* `allow-secure-boot` ignore Secure Boot in subsequent commands.
* `allow-bitlocker` ignore BitLocker in subsequent commands.
* `allow-bad-loader` ignore bad boot loader configuration in subsequent commands.
* `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`).
* 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

View File

@@ -38,6 +38,11 @@ image= y=-200 path=\EFI\HackBGRT\splash.bmp
# Preferred resolution. Use 0x0 for maximum and -1x-1 for original.
resolution=0x0
# Logging (0 for disabled, 1 for enabled).
# When logging is enabled, setup.exe can show debug information about the current boot.
# The log might occupy a few kilobytes of RAM.
log=1
# Debug mode (0 for disabled, 1 for enabled).
# Shows debug information and prompts for keypress before booting.
debug=0

55
shim-signed/COPYRIGHT Normal file
View File

@@ -0,0 +1,55 @@
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
Files: *
Copyright: 2012 Red Hat, Inc
2009-2012 Intel Corporation
License: BSD-2-Clause
Files: debian/po/cs.po
Copyright: 2018 Michal Simunek <michal.simunek@gmail.com>
License: BSD-2-Clause
Files: debian/po/de.po
Copyright: 2017, 2018 Markus Hiereth <markus.hiereth@freenet.de>
License: BSD-2-Clause
Files: debian/po/fr.po
Copyright: 2017, 2018 Alban Vidal <alban.vidal@zordhak.fr>
License: BSD-2-Clause
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.

BIN
shim-signed/mmia32.efi Normal file

Binary file not shown.

BIN
shim-signed/mmx64.efi Normal file

Binary file not shown.

BIN
shim-signed/shimia32.efi Normal file

Binary file not shown.

BIN
shim-signed/shimx64.efi Normal file

Binary file not shown.

286
shim.md Normal file
View File

@@ -0,0 +1,286 @@
# Secure Boot and *shim*
Secure Boot accepts only trusted files during boot. The *shim* boot loader is a tool which allows you to select which files to trust. HackBGRT installs *shim* for you, but you need to configure it with these instructions.
On the first boot after installing HackBGRT, you will see an error message saying "Verification failed". You need to press a key to enter the setup tool (MOKManager) where you can choose to trust HackBGRT. After that, use arrow keys to navigate and *Enter* to continue as described below.
## 1. Verification failed
This is the start of *shim* configuration.
```
ERROR
Verification failed: (0x1A) Security Violation
+----+
| OK |
+----+
```
Select `OK`, *Enter*.
```
Shim UEFI key management
Press any key to perform MOK management
Booting in 5 seconds
```
Press a key quickly to enter *MOK management* or the *MOKManager* program.
## 2. MOK management
```
Perform MOK management
Continue to boot
Enroll key from disk
Enroll hash from disk
```
Select `Enroll hash from disk`, *Enter*. This is the safest option where you choose to trust only a specific version of HackBGRT.
You can also choose to `Enroll key from disk`, which means that you choose to trust anything signed with the same certificate. How do you know if it's safe? You don't that's why you should rather use the other option or build your own version of HackBGRT with your own certificate.
## 3a. Enroll hash from disk
```
Select Binary
The Selected Binary will have its hash Enrolled
This means it will subsequently Boot with no prompting
Remember to make sure it is a genuine binary before enrolling its hash
+----------------+
| YOUR DISK NAME |
+----------------+
```
Select the disk, *Enter*.
```
+---------------+
| EFI/ |
| loader/ |
| vmlinuz-linux |
+---------------+
```
Select `EFI/`, *Enter*.
```
+------------+
| ../ |
| Boot/ |
| HackBGRT/ |
| Microsoft/ |
+------------+
```
Select `HackBGRT/`, *Enter*.
```
+-----------------+
| ../ |
| grubx64.efi |
| loader.efi |
| mmx64.efi |
| certificate.cer |
| splash.bmp |
| config.txt |
+-----------------+
```
Select `grubx64.efi`, *Enter*.
```
[Enroll MOK]
+------------+
| View key 0 |
| Continue |
+------------+
```
To verify the key contents, select `View key 0`, *Enter*.
```
SHA256 hash
(some hexadecimal values)
```
Press *Enter* to continue.
```
[Enroll MOK]
+------------+
| View key 0 |
| Continue |
+------------+
```
Select `Continue`, *Enter*.
```
Enroll the key(s)?
+-----+
| No |
| Yes |
+-----+
```
Select `Yes`, *Enter*.
```
Perform MOK management
+-----------------------+
| Reboot |
| Enroll key from disk |
| Enroll hash from disk |
+-----------------------+
```
Select `Reboot`, *Enter*.
You are now ready to boot using HackBGRT.
## 3b. Enroll key from disk
```
Select Key
The selected key will be enrolled into the MOK database
This means any binaries signed with it will be run without prompting
Remember to make sure it is a genuine key before Enrolling it
+----------------+
| YOUR DISK NAME |
+----------------+
```
Select the disk, *Enter*.
```
+---------------+
| EFI/ |
| loader/ |
| vmlinuz-linux |
+---------------+
```
Select `EFI/`, *Enter*.
```
+------------+
| ../ |
| Boot/ |
| HackBGRT/ |
| Microsoft/ |
+------------+
```
Select `HackBGRT/`, *Enter*.
```
+-----------------+
| ../ |
| grubx64.efi |
| loader.efi |
| mmx64.efi |
| certificate.cer |
| splash.bmp |
| config.txt |
+-----------------+
```
Select `certificate.cer`, *Enter*.
```
[Enroll MOK]
+------------+
| View key 0 |
| Continue |
+------------+
```
To verify the key contents, select `View key 0`, *Enter*.
```
[Extended Key Usage]
OID: Code Signing
[Serial Number]
6B:24:52:E9:3B:84:41:73:B0:22:92:E8:BE:8E:38:85:
[Issuer]
CN=HackBGRT Secure Boot Signer, O=Metabolix
[Subject]
CN=HackBGRT Secure Boot Signer, O=Metabolix
[Valid Not Before]
Nov 9 13:43:56 2023 GMT
[Valid Not After]
Jan 19 03:14:07 2037 GMT
[Fingerprint]
79 8E 64 40 D1 D1 F4 53 30 8D
A0 83 A4 77 FE 57 45 30 36 60
```
Press *Enter* to continue.
```
[Enroll MOK]
+------------+
| View key 0 |
| Continue |
+------------+
```
Select `Continue`, *Enter*.
```
Enroll the key(s)?
+-----+
| No |
| Yes |
+-----+
```
Select `Yes`, *Enter*.
```
Perform MOK management
+-----------------------+
| Reboot |
| Enroll key from disk |
| Enroll hash from disk |
+-----------------------+
```
Select `Reboot`, *Enter*.
You are now ready to boot using HackBGRT.
## Tutorial: *shim* for dummies
To install *shim* manually, follow these steps (assuming x64 architecture):
1. Get *shim*, preferably *shim-signed*.
2. Rename your boot loader to `grubx64.efi`.
3. Copy `shimx64.efi` where your loader used to be.
4. Copy `mmx64.efi` to the same folder.
The *shim* boot process is as follows:
1. Your computer starts `your-loader-name.efi`, which is now really *shim*.
2. Next, *shim* tries to load `grubx64.efi`.
3. If `grubx64.efi` is trusted, the boot process continues.
4. Otherwise, *shim* offers to launch *MOKManager* `mmx64.efi`, and you can try again after that.

View File

@@ -55,6 +55,9 @@ public class Efi {
* @return String representation of this object.
*/
public override string ToString() {
if (Data == null) {
return $"{Name} Guid={Guid} Attributes={Attributes} Data=null";
}
var hex = BitConverter.ToString(Data).Replace("-", " ");
var text = new string(Data.Select(c => 0x20 <= c && c <= 0x7f ? (char) c : ' ').ToArray());
return $"{Name} Guid={Guid} Attributes={Attributes} Text='{text}' Bytes='{hex}'";
@@ -136,8 +139,19 @@ public class Efi {
}
}
/**
* GUID of the global EFI variables.
*/
public const string EFI_GLOBAL_GUID = "{8be4df61-93ca-11d2-aa0d-00e098032b8c}";
/**
* GUID for HackBGRT EFI variables.
*/
public const string EFI_HACKBGRT_GUID = "{03c64761-075f-4dba-abfb-2ed89e18b236}";
/**
* Directory containing EFI variables in Linux.
*/
public const string LinuxEfiDir = "/sys/firmware/efi/efivars";
/**
@@ -445,6 +459,41 @@ public class Efi {
}
}
/**
* 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.
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) {
Setup.Log($"LogBootOrder: {entry}");
}
}
} catch (Exception e) {
Setup.Log($"LogBootOrder failed: {e.ToString()}");
}
}
/**
* Retrieve HackBGRT log collected during boot.
*/
public static string GetHackBGRTLog() {
try {
var log = GetVariable("HackBGRTLog", EFI_HACKBGRT_GUID);
return new string(BytesToUInt16s(log.Data).Select(i => (char)i).ToArray());
} catch (Exception e) {
return $"Log not found: {e.ToString()}";
}
}
/**
* Log the BGRT table (for debugging).
*/
@@ -456,14 +505,14 @@ public class Efi {
var ret = GetSystemFirmwareTable(acpiBE, bgrtLE, buf, size);
if (ret == size) {
var hex = BitConverter.ToString(buf).Replace("-", " ");
Setup.Log($"LogBGRT: {hex}");
Setup.Log($"LogBGRT: {size} bytes: {hex}");
} else if (ret == 0) {
Setup.Log($"LogBGRT: Win32Error {Marshal.GetLastWin32Error()}");
} else {
Setup.Log($"LogBGRT: Size problems: spec {0x38}, buf {size}, ret {ret}");
}
} catch (Exception e) {
Setup.Log($"LogBGRT: {e}");
Setup.Log($"LogBGRT failed: {e}");
}
}
}

View File

@@ -10,6 +10,8 @@ using System.Diagnostics;
using System.Security.Principal;
using System.Text.RegularExpressions;
using System.Runtime.CompilerServices;
using System.Management;
using Microsoft.Win32;
[assembly: AssemblyInformationalVersionAttribute(GIT_DESCRIBE.data)]
[assembly: AssemblyProductAttribute("HackBGRT")]
@@ -51,6 +53,7 @@ public class Setup {
public enum BootLoaderType {
None,
Own,
Shim,
Microsoft,
Other,
}
@@ -61,12 +64,14 @@ public class Setup {
"allow-secure-boot",
"allow-bitlocker",
"allow-bad-loader",
"skip-shim",
"enable-entry", "disable-entry",
"enable-bcdedit", "disable-bcdedit",
"enable-overwrite", "disable-overwrite",
"disable",
"uninstall",
"boot-to-fw",
"show-boot-log",
};
/** @var The target directory. */
@@ -94,6 +99,9 @@ public class Setup {
/** @var Run in batch mode? */
protected bool Batch;
/** @var Is the loader signed? */
protected bool LoaderIsSigned = false;
/**
* Output a line.
*/
@@ -204,6 +212,8 @@ public class Setup {
string tmp = System.Text.Encoding.ASCII.GetString(data);
if (tmp.IndexOf("HackBGRT") >= 0 || tmp.IndexOf("HackBgrt") >= 0) {
return BootLoaderType.Own;
} else if (tmp.IndexOf("UEFI shim") >= 0) {
return BootLoaderType.Shim;
} else if (tmp.IndexOf("Microsoft Corporation") >= 0) {
return BootLoaderType.Microsoft;
} else {
@@ -307,11 +317,29 @@ public class Setup {
/**
* Install files to ESP.
*
* @param skipShim Whether to skip installing shim.
*/
protected void InstallFiles() {
if (!File.Exists($"boot{EfiArch}.efi")) {
protected void InstallFiles(bool skipShim) {
var loaderSource = Path.Combine("efi-signed", $"boot{EfiArch}.efi");
LoaderIsSigned = true;
if (!File.Exists(loaderSource)) {
loaderSource = Path.Combine("efi", $"boot{EfiArch}.efi");
LoaderIsSigned = false;
if (!File.Exists(loaderSource)) {
throw new SetupException($"Missing boot{EfiArch}.efi, {EfiArch} is not supported!");
}
}
var shimSource = Path.Combine("shim-signed", $"shim{EfiArch}.efi");
var mmSource = Path.Combine("shim-signed", $"mm{EfiArch}.efi");
if (!skipShim) {
if (!File.Exists(shimSource)) {
throw new SetupException($"Missing shim ({shimSource}), can't install shim for {EfiArch}!");
}
if (!File.Exists(mmSource)) {
throw new SetupException($"Missing MokManager ({mmSource}), can't install shim for {EfiArch}!");
}
}
try {
if (!Directory.Exists(InstallPath)) {
Directory.CreateDirectory(InstallPath);
@@ -330,8 +358,32 @@ public class Setup {
InstallImageFile(line.Substring(i + delim.Length));
}
}
InstallFile($"boot{EfiArch}.efi", "loader.efi");
var loaderDest = "loader.efi";
if (!skipShim) {
InstallFile(shimSource, loaderDest);
InstallFile(mmSource, $"mm{EfiArch}.efi");
loaderDest = $"grub{EfiArch}.efi";
}
InstallFile(loaderSource, loaderDest);
if (LoaderIsSigned) {
InstallFile("certificate.cer");
}
WriteLine($"HackBGRT has been copied to {InstallPath}.");
var enrollHashPath = $"EFI\\HackBGRT\\{loaderDest}";
var enrollKeyPath = "EFI\\HackBGRT\\certificate.cer";
if (skipShim) {
if (LoaderIsSigned) {
WriteLine($"Remember to enroll {enrollKeyPath} in your firmware!");
} else {
WriteLine("This HackBGRT build is not signed. You may need to disable Secure Boot.");
}
} else {
WriteLine($"On first boot, select 'Enroll hash from disk' and enroll {enrollHashPath}.");
if (LoaderIsSigned) {
WriteLine($"Alternatively, select 'Enroll key from disk' and enroll {enrollKeyPath}.");
}
}
}
/**
@@ -405,7 +457,6 @@ public class Setup {
protected void OverwriteMsLoader() {
var ms = Esp.MsLoaderPath;
var backup = BackupLoaderPath;
var own = Path.Combine(InstallPath, "loader.efi");
if (DetectLoader(ms) == BootLoaderType.Microsoft) {
InstallFile(ms, backup, false);
@@ -414,8 +465,13 @@ public class Setup {
// Duplicate check, but better to be sure...
throw new SetupException("Missing MS boot loader backup!");
}
var msDir = Path.GetDirectoryName(ms);
var msGrub = Path.Combine(msDir, $"grub{EfiArch}.efi");
var msMm = Path.Combine(msDir, $"mm{EfiArch}.efi");
try {
InstallFile(own, ms, false);
InstallFile(Path.Combine(InstallPath, "loader.efi"), ms, false);
InstallFile(Path.Combine(InstallPath, $"grub{EfiArch}.efi"), msGrub, false);
InstallFile(Path.Combine(InstallPath, $"mm{EfiArch}.efi"), msMm, false);
} catch (SetupException e) {
WriteLine(e.Message);
if (DetectLoader(ms) != BootLoaderType.Microsoft) {
@@ -434,7 +490,7 @@ public class Setup {
*/
protected void RestoreMsLoader() {
var ms = Esp.MsLoaderPath;
if (DetectLoader(ms) == BootLoaderType.Own) {
if (DetectLoader(ms) == BootLoaderType.Own || DetectLoader(ms) == BootLoaderType.Shim) {
WriteLine("Disabling an old version of HackBGRT.");
InstallFile(BackupLoaderPath, ms, false);
WriteLine($"{ms} has been restored.");
@@ -538,6 +594,9 @@ public class Setup {
WriteLine("Secure Boot status could not be determined.");
}
WriteLine("It's very important to disable Secure Boot before installing.");
if (LoaderIsSigned) {
WriteLine("Alternatively, you can enroll the certificate.cer in your firmware.");
}
WriteLine("Otherwise your machine may become unbootable.");
if (Batch) {
if (allowSecureBoot) {
@@ -674,6 +733,40 @@ public class Setup {
}
}
/**
* Log the boot time.
*
* @return The boot time, or null if it couldn't be determined.
*/
protected DateTime? GetBootTime() {
try {
var query = new ObjectQuery("SELECT LastBootUpTime FROM Win32_OperatingSystem WHERE Primary='true'");
foreach (var m in new ManagementObjectSearcher(query).Get()) {
return ManagementDateTimeConverter.ToDateTime(m["LastBootUpTime"].ToString());
}
} catch (Exception e) {
Log($"GetBootTime failed: {e.ToString()}");
}
return null;
}
/**
* Check if Hiberboot is enabled.
*
* @return True, if Hiberboot is enabled.
*/
protected bool IsHiberbootEnabled() {
try {
return (int) Registry.GetValue(
"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power",
"HiberbootEnabled",
0
) != 0;
} catch {
return false;
}
}
/**
* Ask for user's choice and install/uninstall.
*/
@@ -682,19 +775,14 @@ public class Setup {
WriteLine("Choose action (press a key):");
WriteLine(" I = install");
WriteLine(" - creates a new EFI boot entry for HackBGRT");
WriteLine(" - sometimes needs to be enabled in firmware settings");
WriteLine(" - should fall back to MS boot loader if HackBGRT fails");
WriteLine(" J = install (alternative)");
WriteLine(" - creates a new EFI boot entry with an alternative method (BCDEdit)");
WriteLine(" - always sets HackBGRT as the first boot option");
WriteLine(" - sometimes shows up as \"Windows Boot Manager\"");
WriteLine(" - should fall back to MS boot loader if HackBGRT fails");
WriteLine(" - try this if the first option doesn't work");
WriteLine(" O = install (legacy)");
WriteLine(" - overwrites the MS boot loader");
WriteLine(" - may require re-install after Windows updates");
WriteLine(" - could brick your system if configured incorrectly");
WriteLine(" - overwrites the MS boot loader; gets removed by Windows updates");
WriteLine(" - use as last resort; may brick your system if configured incorrectly");
WriteLine(" F = install files only");
WriteLine(" - needs to be enabled somehow");
WriteLine(" - ok for updating config, doesn't touch boot entries");
WriteLine(" D = disable");
WriteLine(" - removes created entries, restores MS boot loader");
WriteLine(" R = remove completely");
@@ -702,6 +790,7 @@ public class Setup {
WriteLine(" B = boot to UEFI setup");
WriteLine(" - lets you disable Secure Boot");
WriteLine(" - lets you move HackBGRT before Windows in boot order");
WriteLine(" L = show boot log (what HackBGRT did during boot)");
WriteLine(" C = cancel");
var k = Console.ReadKey().Key;
@@ -724,6 +813,8 @@ public class Setup {
RunPrivilegedActions(new string[] { "uninstall" });
} else if (k == ConsoleKey.B) {
RunPrivilegedActions(new string[] { "boot-to-fw" });
} else if (k == ConsoleKey.L) {
RunPrivilegedActions(new string[] { "show-boot-log" });
} else if (k == ConsoleKey.C) {
throw new ExitSetup(1);
} else {
@@ -757,10 +848,24 @@ public class Setup {
InitEspPath();
InitEspInfo();
var bootLog = $"\n--- BOOT LOG START ---\n{Efi.GetHackBGRTLog()}\n--- BOOT LOG END ---";
Setup.Log(bootLog);
Efi.LogBGRT();
Efi.LogBootEntries();
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}");
if (configTime > bootTime) {
WriteLine($"Windows was booted at {bootTime}. Remember to reboot after installing!");
}
}
if (IsHiberbootEnabled()) {
WriteLine("You may have to disable Fast Startup (Hiberboot) to reboot properly.");
}
bool allowSecureBoot = false;
bool allowBitLocker = false;
bool allowBadLoader = false;
bool skipShim = false;
Action<Action> verify = (Action revert) => {
try {
VerifyLoaderConfig();
@@ -776,7 +881,9 @@ public class Setup {
}
};
Action<Action, Action> enable = (Action enable, Action revert) => {
if (skipShim) {
HandleSecureBoot(allowSecureBoot);
}
HandleBitLocker(allowBitLocker);
enable();
verify(revert);
@@ -784,13 +891,15 @@ public class Setup {
foreach (var arg in actions) {
Log($"Running action '{arg}'.");
if (arg == "install") {
InstallFiles();
InstallFiles(skipShim);
} else if (arg == "allow-secure-boot") {
allowSecureBoot = true;
} else if (arg == "allow-bitlocker") {
allowBitLocker = true;
} else if (arg == "allow-bad-loader") {
allowBadLoader = true;
} else if (arg == "skip-shim") {
skipShim = true;
} else if (arg == "enable-entry") {
enable(() => EnableEntry(), () => DisableEntry());
} else if (arg == "disable-entry") {
@@ -809,6 +918,8 @@ public class Setup {
Uninstall();
} else if (arg == "boot-to-fw") {
BootToFW();
} else if (arg == "show-boot-log") {
WriteLine(bootLog);
} else {
throw new SetupException($"Invalid action: '{arg}'!");
}
@@ -874,7 +985,7 @@ public class Setup {
WriteLine("This was a dry run, your system was not actually modified.");
}
if (!Batch) {
WriteLine("If you need to report a bug, please include the setup.log file.");
WriteLine("If you need to report a bug,\n - run this setup again with menu option L (show-boot-log)\n - then include the setup.log file with your report.");
WriteLine("Press any key to quit.");
Console.ReadKey();
}

View File

@@ -8,7 +8,7 @@ BOOLEAN ReadConfigFile(struct HackBGRT_config* config, EFI_FILE_HANDLE root_dir,
UINTN data_bytes = 0;
data = LoadFileWithPadding(root_dir, path, &data_bytes, 4);
if (!data) {
Print(L"HackBGRT: Failed to load configuration (%s)!\n", path);
Log(1, L"HackBGRT: Failed to load configuration (%s)!\n", path);
return FALSE;
}
CHAR16* str;
@@ -74,9 +74,7 @@ static void SetBMPWithRandom(struct HackBGRT_config* config, int weight, enum Ha
config->image_weight_sum += weight;
UINT32 random = Random();
UINT32 limit = 0xfffffffful / config->image_weight_sum * weight;
if (config->debug) {
Print(L"HackBGRT: weight %d, action %d, x %d, y %d, o %d, path %s, random = %08x, limit = %08x\n", weight, action, x, y, o, path, random, limit);
}
Log(config->debug, L"HackBGRT: n=%d, action=%d, x=%d, y=%d, o=%d, path=%s, random = %08x, limit = %08x\n", weight, action, x, y, o, path, random, limit);
if (!config->image_weight_sum || random <= limit) {
config->action = action;
config->image_path = path;
@@ -112,7 +110,7 @@ static void ReadConfigImage(struct HackBGRT_config* config, const CHAR16* line)
} else if (StrStr(line, L"keep")) {
action = HackBGRT_KEEP;
} else {
Print(L"HackBGRT: Invalid image line: %s\n", line);
Log(1, L"HackBGRT: Invalid image line: %s\n", line);
return;
}
int weight = n && (!f || n < f) ? Atoi(n) : 1;
@@ -129,7 +127,7 @@ static void ReadConfigResolution(struct HackBGRT_config* config, const CHAR16* l
config->resolution_x = *x == '-' ? -(int)Atoi(x+1) : (int)Atoi(x);
config->resolution_y = *y == '-' ? -(int)Atoi(y+1) : (int)Atoi(y);
} else {
Print(L"HackBGRT: Invalid resolution line: %s\n", line);
Log(1, L"HackBGRT: Invalid resolution line: %s\n", line);
}
}
@@ -143,6 +141,10 @@ void ReadConfigLine(struct HackBGRT_config* config, EFI_FILE_HANDLE root_dir, co
config->debug = (StrCmp(line, L"debug=1") == 0);
return;
}
if (StrnCmp(line, L"log=", 4) == 0) {
config->log = (StrCmp(line, L"log=1") == 0);
return;
}
if (StrnCmp(line, L"image=", 6) == 0) {
ReadConfigImage(config, line + 6);
return;
@@ -159,5 +161,5 @@ void ReadConfigLine(struct HackBGRT_config* config, EFI_FILE_HANDLE root_dir, co
ReadConfigResolution(config, line + 11);
return;
}
Print(L"Unknown configuration directive: %s\n", line);
Log(1, L"Unknown configuration directive: %s\n", line);
}

View File

@@ -21,7 +21,7 @@ enum HackBGRT_coordinate {
* The configuration.
*/
struct HackBGRT_config {
int debug;
int debug, log;
enum HackBGRT_action action;
const CHAR16* image_path;
int image_x;

View File

@@ -6,20 +6,20 @@
#include "util.h"
/**
* The Print function signature.
* The version.
*/
typedef UINTN print_t(IN CONST CHAR16 *fmt, ...);
/**
* The function for debug printing; either Print or NullPrint.
*/
print_t* Debug = NullPrint;
#ifdef GIT_DESCRIBE_W
const CHAR16 version[] = GIT_DESCRIBE_W;
#else
const CHAR16 version[] = L"unknown; not an official release?";
#endif
/**
* The configuration.
*/
static struct HackBGRT_config config = {
.action = HackBGRT_KEEP
.log = 1,
.action = HackBGRT_KEEP,
};
/**
@@ -45,7 +45,7 @@ static void SetResolution(int w, int h) {
if (!gop) {
config.old_resolution_x = config.resolution_x = 0;
config.old_resolution_y = config.resolution_y = 0;
Debug(L"GOP not found!\n");
Log(config.debug, L"GOP not found!\n");
return;
}
UINTN best_i = gop->Mode->Mode;
@@ -54,7 +54,7 @@ static void SetResolution(int w, int h) {
w = (w <= 0 ? w < 0 ? best_w : 999999 : w);
h = (h <= 0 ? h < 0 ? best_h : 999999 : h);
Debug(L"Looking for resolution %dx%d...\n", w, h);
Log(config.debug, L"Looking for resolution %dx%d...\n", w, h);
for (UINT32 i = gop->Mode->MaxMode; i--;) {
int new_w = 0, new_h = 0;
@@ -87,7 +87,7 @@ static void SetResolution(int w, int h) {
best_h = new_h;
best_i = i;
}
Debug(L"Found resolution %dx%d.\n", best_w, best_h);
Log(config.debug, L"Found resolution %dx%d.\n", best_w, best_h);
config.resolution_x = best_w;
config.resolution_y = best_h;
if (best_i != gop->Mode->Mode) {
@@ -107,7 +107,7 @@ ACPI_SDT_HEADER* CreateXsdt(ACPI_SDT_HEADER* xsdt0, UINTN entries) {
UINT32 xsdt_len = sizeof(ACPI_SDT_HEADER) + entries * sizeof(UINT64);
BS->AllocatePool(EfiACPIReclaimMemory, xsdt_len, (void**)&xsdt);
if (!xsdt) {
Print(L"HackBGRT: Failed to allocate memory for XSDT.\n");
Log(1, L"HackBGRT: Failed to allocate memory for XSDT.\n");
return 0;
}
ZeroMem(xsdt, xsdt_len);
@@ -139,17 +139,17 @@ static ACPI_BGRT* HandleAcpiTables(enum HackBGRT_action action, ACPI_BGRT* bgrt)
if (CompareMem(rsdp->signature, "RSD PTR ", 8) != 0 || rsdp->revision < 2 || !VerifyAcpiRsdp2Checksums(rsdp)) {
continue;
}
Debug(L"RSDP @%x: revision = %d, OEM ID = %s\n", (UINTN)rsdp, rsdp->revision, TmpStr(rsdp->oem_id, 6));
Log(config.debug, L"RSDP @%x: revision = %d, OEM ID = %s\n", (UINTN)rsdp, rsdp->revision, TmpStr(rsdp->oem_id, 6));
ACPI_SDT_HEADER* xsdt = (ACPI_SDT_HEADER *) (UINTN) rsdp->xsdt_address;
if (!xsdt || CompareMem(xsdt->signature, "XSDT", 4) != 0 || !VerifyAcpiSdtChecksum(xsdt)) {
Debug(L"* XSDT: missing or invalid\n");
Log(config.debug, L"* XSDT: missing or invalid\n");
continue;
}
UINT64* entry_arr = (UINT64*)&xsdt[1];
UINT32 entry_arr_length = (xsdt->length - sizeof(*xsdt)) / sizeof(UINT64);
Debug(L"* XSDT @%x: OEM ID = %s, entry count = %d\n", (UINTN)xsdt, TmpStr(xsdt->oem_id, 6), entry_arr_length);
Log(config.debug, L"* XSDT @%x: OEM ID = %s, entry count = %d\n", (UINTN)xsdt, TmpStr(xsdt->oem_id, 6), entry_arr_length);
int bgrt_count = 0;
for (int j = 0; j < entry_arr_length; j++) {
@@ -157,16 +157,16 @@ static ACPI_BGRT* HandleAcpiTables(enum HackBGRT_action action, ACPI_BGRT* bgrt)
if (CompareMem(entry->signature, "BGRT", 4) != 0) {
continue;
}
Debug(L" - ACPI table @%x: %s, revision = %d, OEM ID = %s\n", (UINTN)entry, TmpStr(entry->signature, 4), entry->revision, TmpStr(entry->oem_id, 6));
Log(config.debug, L" - ACPI table @%x: %s, revision = %d, OEM ID = %s\n", (UINTN)entry, TmpStr(entry->signature, 4), entry->revision, TmpStr(entry->oem_id, 6));
switch (action) {
case HackBGRT_KEEP:
if (!bgrt) {
Debug(L" -> Returning this one for later use.\n");
Log(config.debug, L" -> Returning this one for later use.\n");
bgrt = (ACPI_BGRT*) entry;
}
break;
case HackBGRT_REMOVE:
Debug(L" -> Deleting.\n");
Log(config.debug, L" -> Deleting.\n");
for (int k = j+1; k < entry_arr_length; ++k) {
entry_arr[k-1] = entry_arr[k];
}
@@ -176,13 +176,13 @@ static ACPI_BGRT* HandleAcpiTables(enum HackBGRT_action action, ACPI_BGRT* bgrt)
--j;
break;
case HackBGRT_REPLACE:
Debug(L" -> Replacing.\n");
Log(config.debug, L" -> Replacing.\n");
entry_arr[j] = (UINTN) bgrt;
}
bgrt_count += 1;
}
if (!bgrt_count && action == HackBGRT_REPLACE && bgrt) {
Debug(L" - Adding missing BGRT.\n");
Log(config.debug, L" - Adding missing BGRT.\n");
xsdt = CreateXsdt(xsdt, entry_arr_length + 1);
entry_arr = (UINT64*)&xsdt[1];
entry_arr[entry_arr_length++] = (UINTN) bgrt;
@@ -208,7 +208,7 @@ static BMP* MakeBMP(int w, int h, UINT8 r, UINT8 g, UINT8 b) {
BMP* bmp = 0;
BS->AllocatePool(EfiBootServicesData, 54 + w * h * 4, (void**) &bmp);
if (!bmp) {
Print(L"HackBGRT: Failed to allocate a blank BMP!\n");
Log(1, L"HackBGRT: Failed to allocate a blank BMP!\n");
BS->Stall(1000000);
return 0;
}
@@ -243,16 +243,17 @@ static BMP* LoadBMP(EFI_FILE_HANDLE root_dir, const CHAR16* path) {
if (!path) {
return MakeBMP(1, 1, 0, 0, 0); // empty path = black image
}
Debug(L"HackBGRT: Loading %s.\n", path);
Log(config.debug, L"HackBGRT: Loading %s.\n", path);
UINTN size = 0;
BMP* bmp = LoadFile(root_dir, path, &size);
if (bmp) {
if (size >= bmp->file_size && CompareMem(bmp, "BM", 2) == 0 && bmp->file_size - bmp->pixel_data_offset > 4 && bmp->width && bmp->height && (bmp->bpp == 32 || bmp->bpp == 24) && bmp->compression == 0) {
return bmp;
}
Print(L"HackBGRT: Invalid BMP (%s)!\n", path);
FreePool(bmp);
Log(1, L"HackBGRT: Invalid BMP (%s)!\n", path);
} else {
Print(L"HackBGRT: Failed to load BMP (%s)!\n", path);
Log(1, L"HackBGRT: Failed to load BMP (%s)!\n", path);
}
BS->Stall(1000000);
return MakeBMP(16, 16, 255, 0, 0); // error = red image
@@ -320,7 +321,7 @@ void HackBgrt(EFI_FILE_HANDLE root_dir) {
// Replace missing = allocate new.
BS->AllocatePool(EfiACPIReclaimMemory, sizeof(*bgrt), (void**)&bgrt);
if (!bgrt) {
Print(L"HackBGRT: Failed to allocate memory for BGRT.\n");
Log(1, L"HackBGRT: Failed to allocate memory for BGRT.\n");
return;
}
}
@@ -372,8 +373,8 @@ void HackBgrt(EFI_FILE_HANDLE root_dir) {
bgrt->image_offset_x = max(0, min(max_x, new_x + (new_reso_x - new_bmp->width) / 2));
bgrt->image_offset_y = max(0, min(max_y, new_y + (new_reso_y - new_bmp->height) / 2));
Debug(
L"HackBGRT: BMP at (%d, %d), center (%d, %d), resolution (%d, %d) with orientation %d applied.\n",
Log(config.debug,
L"HackBGRT: BMP at (%d, %d), center (%d, %d), resolution (%d, %d), orientation %d.\n",
(int) bgrt->image_offset_x, (int) bgrt->image_offset_y,
new_x, new_y, new_reso_x, new_reso_y,
new_orientation * 90
@@ -387,12 +388,12 @@ void HackBgrt(EFI_FILE_HANDLE root_dir) {
/**
* Load an application.
*/
static EFI_HANDLE LoadApp(print_t* print_failure, EFI_HANDLE image_handle, EFI_LOADED_IMAGE* image, const CHAR16* path) {
static EFI_HANDLE LoadApp(int print_failure, EFI_HANDLE image_handle, EFI_LOADED_IMAGE* image, const CHAR16* path) {
EFI_DEVICE_PATH* boot_dp = FileDevicePath(image->DeviceHandle, (CHAR16*) path);
EFI_HANDLE result = 0;
Debug(L"HackBGRT: Loading application %s.\n", path);
Log(config.debug, L"HackBGRT: Loading application %s.\n", path);
if (EFI_ERROR(BS->LoadImage(0, image_handle, boot_dp, 0, 0, &result))) {
print_failure(L"HackBGRT: Failed to load application %s.\n", path);
Log(config.debug || print_failure, L"HackBGRT: Failed to load application %s.\n", path);
}
return result;
}
@@ -402,10 +403,11 @@ static EFI_HANDLE LoadApp(print_t* print_failure, EFI_HANDLE image_handle, EFI_L
*/
EFI_STATUS EFIAPI EfiMain(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *ST_) {
InitializeLib(image_handle, ST_);
Log(0, L"HackBGRT version: %s\n", version);
EFI_LOADED_IMAGE* image;
if (EFI_ERROR(BS->HandleProtocol(image_handle, &LoadedImageProtocol, (void**) &image))) {
Debug(L"HackBGRT: LOADED_IMAGE_PROTOCOL failed.\n");
Log(config.debug, L"HackBGRT: LOADED_IMAGE_PROTOCOL failed.\n");
goto fail;
}
@@ -417,14 +419,16 @@ EFI_STATUS EFIAPI EfiMain(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *ST_) {
if (argc <= 1) {
const CHAR16* config_path = L"\\EFI\\HackBGRT\\config.txt";
if (!ReadConfigFile(&config, root_dir, config_path)) {
Print(L"HackBGRT: No config, no command line!\n", config_path);
Log(1, L"HackBGRT: No config, no command line!\n", config_path);
goto fail;
}
}
for (int i = 1; i < argc; ++i) {
ReadConfigLine(&config, root_dir, argv[i]);
}
Debug = config.debug ? Print : NullPrint;
if (config.debug) {
Print(L"HackBGRT version: %s\n", version);
}
SetResolution(config.resolution_x, config.resolution_y);
HackBgrt(root_dir);
@@ -432,55 +436,54 @@ EFI_STATUS EFIAPI EfiMain(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *ST_) {
EFI_HANDLE next_image_handle = 0;
static CHAR16 backup_boot_path[] = L"\\EFI\\HackBGRT\\bootmgfw-original.efi";
static CHAR16 ms_boot_path[] = L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi";
int try_ms_quietly = 1;
if (config.boot_path && StriCmp(config.boot_path, L"MS") != 0) {
next_image_handle = LoadApp(Print, image_handle, image, config.boot_path);
} else {
config.boot_path = backup_boot_path;
next_image_handle = LoadApp(Debug, image_handle, image, config.boot_path);
if (!next_image_handle) {
config.boot_path = ms_boot_path;
next_image_handle = LoadApp(Debug, image_handle, image, config.boot_path);
}
next_image_handle = LoadApp(1, image_handle, image, config.boot_path);
try_ms_quietly = 0;
}
if (!next_image_handle) {
config.boot_path = backup_boot_path;
next_image_handle = LoadApp(Print, image_handle, image, config.boot_path);
next_image_handle = LoadApp(!try_ms_quietly, image_handle, image, config.boot_path);
if (!next_image_handle) {
config.boot_path = ms_boot_path;
next_image_handle = LoadApp(Print, image_handle, image, config.boot_path);
next_image_handle = LoadApp(!try_ms_quietly, image_handle, image, config.boot_path);
if (!next_image_handle) {
goto fail;
}
}
Print(L"HackBGRT: Reverting to %s.\n", config.boot_path);
if (try_ms_quietly) {
goto ready_to_boot;
}
Log(1, L"HackBGRT: Reverting to %s.\n", config.boot_path);
Print(L"Press escape to cancel or any other key (or wait 15 seconds) to boot.\n");
if (ReadKey(15000).ScanCode == SCAN_ESC) {
goto fail;
}
} else if (config.debug) {
Print(L"HackBGRT: Ready to boot. Disable debug mode to skip this screen.\n");
} else ready_to_boot: if (config.debug) {
Print(L"HackBGRT: Ready to boot.\n");
Print(L"If all goes well, you can set debug=0 and log=0 in config.txt.\n");
Print(L"Press escape to cancel or any other key (or wait 15 seconds) to boot.\n");
if (ReadKey(15000).ScanCode == SCAN_ESC) {
return 0;
}
}
if (!config.log) {
ClearLogVariable();
}
if (EFI_ERROR(BS->StartImage(next_image_handle, 0, 0))) {
Print(L"HackBGRT: Failed to start %s.\n", config.boot_path);
Log(1, L"HackBGRT: Failed to start %s.\n", config.boot_path);
goto fail;
}
Print(L"HackBGRT: Started %s. Why are we still here?!\n", config.boot_path);
Log(1, L"HackBGRT: Started %s. Why are we still here?!\n", config.boot_path);
Print(L"Please check that %s is not actually HackBGRT!\n", config.boot_path);
goto fail;
fail: {
Print(L"HackBGRT has failed. Use parameter debug=1 for details.\n");
Print(L"Get a Windows install disk or a recovery disk to fix your boot.\n");
#ifdef GIT_DESCRIBE
Print(L"HackBGRT version: " GIT_DESCRIBE L"\n");
#else
Print(L"HackBGRT version: unknown; not an official release?\n");
#endif
Log(1, L"HackBGRT has failed.\n");
Print(L"Dumping log:\n\n");
DumpLog();
Print(L"If you can't boot into Windows, get install/recovery disk to fix your boot.\n");
Print(L"Press any key (or wait 15 seconds) to exit.\n");
ReadKey(15000);
return 1;

10
src/sbat.c Normal file
View File

@@ -0,0 +1,10 @@
#ifdef GIT_DESCRIBE
#define SBAT_READABLE_VERSION GIT_DESCRIBE
#else
#define SBAT_READABLE_VERSION "unknown"
#endif
const char sbat[] __attribute__ ((section (".sbat"))) =
"sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md\n"
"hackbgrt,1,Metabolix,HackBGRT," SBAT_READABLE_VERSION ",https://github.com/Metabolix/HackBGRT\n"
;

View File

@@ -14,8 +14,31 @@ const CHAR16* TmpStr(CHAR8 *src, int length) {
return dest;
}
UINTN NullPrint(IN CONST CHAR16 *fmt, ...) {
return 0;
#define log_buffer_size (65536)
CHAR16 log_buffer[log_buffer_size] = {0};
CHAR16 LogVarName[] = L"HackBGRTLog";
EFI_GUID LogVarGuid = {0x03c64761, 0x075f, 0x4dba, {0xab, 0xfb, 0x2e, 0xd8, 0x9e, 0x18, 0xb2, 0x36}}; // self-made: 03c64761-075f-4dba-abfb-2ed89e18b236
void Log(int print, IN CONST CHAR16 *fmt, ...) {
va_list args;
CHAR16 buf[256];
va_start(args, fmt);
VSPrint(buf, sizeof(buf), fmt, args); // size is in bytes, not CHAR16s
va_end(args);
if (print) {
Print(L"%s", buf);
}
StrnCat(log_buffer, buf, log_buffer_size - StrLen(log_buffer) - 1);
LibSetVariable(LogVarName, &LogVarGuid, StrLen(log_buffer) * 2, log_buffer);
}
void DumpLog(void) {
Print(L"%s", log_buffer);
}
void ClearLogVariable(void) {
LibDeleteVariable(LogVarName, &LogVarGuid);
}
const CHAR16* TrimLeft(const CHAR16* s) {

View File

@@ -14,7 +14,17 @@ extern const CHAR16* TmpStr(CHAR8 *src, int length);
/**
* Empty function that has the same signature as Print.
*/
extern UINTN NullPrint(IN CONST CHAR16 *fmt, ...);
extern void Log(int print, IN CONST CHAR16 *fmt, ...);
/**
* Dump the log buffer to the screen.
*/
extern void DumpLog(void);
/**
* Clear the log EFI variable, for minor RAM savings.
*/
extern void ClearLogVariable(void);
/**
* Return the greater of two numbers.