Metabolix / HackBGRT

Windows boot logo changer for UEFI systems
MIT License
2.22k stars 239 forks source link

Add clean and qemu test targets to Makefile. #157

Closed diekmann closed 9 months ago

diekmann commented 10 months ago

Selecting the loader.efi in OVMF manually is not super convenient, but at least it is a reproducible way to run the compiled EFI binary without rebooting the whole machine.

I still cannot produce a working binary on my system, but at least, this Makefile target allows me to fail faster.

Tested on vanilla Windows 11 with WSL Ubuntu and gnu-efi 3.0.11 and qemu 6.2.0.

Metabolix commented 10 months ago

I will not merge this. It's specific to your testing environment and even the comment mostly describes your situation. All things don't need to be merged upstream, it's still ok to keep them locally.

To make your testing experience smoother, you can copy the .efi file to efi_test/EFI/boot/bootx64.efi which is loaded by default, or you can create a UEFI shell script efi_test/startup.nsh with contents FS0:\EFI\HackBGRT\loader.efi. Tested on Arch Linux with QEMU 8.1.2 and edk2-ovmf 202308.

diekmann commented 10 months ago

Howdy Metabolix, thanks a lot for taking the time to look at this PR! I totally understand that this is your repo and that you don't want to merge a PR which may be opinionated towards my system.

I tried building your software. It compiled, but it always crashed for me. In qemu, with this X64 Exception Type - 06(#UD - Invalid Opcode) and with just a blank screen on real hardware. Cross-compiling an UEFI application with w64-mingw32 seems to be a rather uncommon choice and I had quite a lot of fun debugging why I could not get this running on my system. 😄

On my system (ubuntu 22.04 on wsl on win 11), it looked like the gnu-efi w64-mingw32 compiled, but produced a buggy library which messed up the calling convention. I finally found this via printf debugging and when I realized that specifying my own uefi_call_wrapper made the thing work. My uefi_call_wrapper was basically just passing through the function call without adapting calling convention, since w64-mingw32 already uses the correct calling convention. I fund that my gnu-efi version 3.0.15 did not compile correctly with mingw, because the mingw MAKEFILE file choked on the mingw gcc version, but did not abort compilation.

I have modified the HackBGRT Makefile such that it vendors gnu-efi as a git submodule and passes the compiler options to make this compile. The -DGNU_EFI_USE_MS_ABI for both gnu-efi and HackBGRT is the important option which makes sure both use the default calling convention.

If I find the time to cleanup all these custom hacks I added and create a clean branch, would you be interested in a PR which vendors gnu-efi as a submodule to help compiling HackBGRT more hermetically?

Metabolix commented 10 months ago

Thanks for the detailed explanation. Funny, my problem is quite the opposite: I can't make a working binary with the native (Linux) gnu-efi linker scripts and objcopy magic, and that's why I ended up using MinGW, which works great. In the long run, I would prefer to switch to the native GCC. Another interesting alternative is to rewrite the whole thing in Rust, which seems to produce EFI working binaries out-of-the-box with the uefi-rs crate.

diekmann commented 10 months ago

Meta: I think we can close this PR, this discussion is now basically off-topic chat 😄 Thanks for your explanations 💟


Heh, interesting. I once played with the objcopy magic to build an UEFI application and even linked a Rust library into it. I borrowed heavily from shim. Limitations: I only used gnu-efi headers and I did not link against the gnu-efi lib.

While debugging my MinGW issues, I found this interesting article: Goodbye Gnu-EFI! While I haven't tried it, it looks like clang is a sweet spot for a compiler: It can natively compile to the PE Windows style (no cross-compilation) and clang and rust work together nicely. For some architectures, folks even claim that cross-language link-time-optimization is working between the two. When I tried 2.5 years ago for the wasm target thoug, it did not work. But wasm limitations do not apply here.

Metabolix commented 9 months ago

Haha, I reopened this by accident. Thanks for your useful research. I've now switched to Clang, included gnu-efi as a submodule to get the headers but also reimplemented some functions to avoid actually building and linking the whole gnu-efi. Maybe it now works for you too?

diekmann commented 9 months ago

I think I got a working bootx64.efi compiled with your clang setup at 7ccdcc4a7706e11753a387f5f7424c885d855bf7. 👍

Very smooth 👍

I did not test the csharp or shim or signing part, I just took the compiled bootx64.efi and copied it to my working 2.1.0 branch and installed it.

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.3 LTS
Release:        22.04
Codename:       jammy
$ clang --version
Ubuntu clang version 14.0.0-1ubuntu1.1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

and

lld-14 (1:14.0.0-1ubuntu1.1)

on wsl on win 11