mirror of
https://github.com/Metabolix/HackBGRT.git
synced 2025-12-07 09:36:10 -08:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5856d25b5b | ||
|
|
466ab69c48 | ||
|
|
14aa79929a | ||
|
|
5e32a3f880 | ||
|
|
db934099df | ||
|
|
e93ed54cb2 | ||
|
|
9b3b045a21 | ||
|
|
be8a5d35d2 | ||
|
|
2366fc8b98 | ||
|
|
e04ba3e451 | ||
|
|
f40f2bc9dc | ||
|
|
2f572b24d4 |
@@ -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
|
||||
|
||||
51
Makefile
51
Makefile
@@ -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
|
||||
|
||||
12
README.md
12
README.md
@@ -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
|
||||
|
||||
@@ -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
55
shim-signed/COPYRIGHT
Normal 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
BIN
shim-signed/mmia32.efi
Normal file
Binary file not shown.
BIN
shim-signed/mmx64.efi
Normal file
BIN
shim-signed/mmx64.efi
Normal file
Binary file not shown.
BIN
shim-signed/shimia32.efi
Normal file
BIN
shim-signed/shimia32.efi
Normal file
Binary file not shown.
BIN
shim-signed/shimx64.efi
Normal file
BIN
shim-signed/shimx64.efi
Normal file
Binary file not shown.
286
shim.md
Normal file
286
shim.md
Normal 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.
|
||||
53
src/Efi.cs
53
src/Efi.cs
@@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
145
src/Setup.cs
145
src/Setup.cs
@@ -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();
|
||||
}
|
||||
|
||||
16
src/config.c
16
src/config.c
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
113
src/main.c
113
src/main.c
@@ -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
10
src/sbat.c
Normal 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"
|
||||
;
|
||||
27
src/util.c
27
src/util.c
@@ -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) {
|
||||
|
||||
12
src/util.h
12
src/util.h
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user