PROJECT_NAME = ipxe-stub SRC_DIR = src BUILD_DIR = build GNU_EFI_DIR = includes/deps/gnu-efi OUTPUT_DIR = output KEYS_DIR = keys SHIM_DIR = input/shim OPENSSL_CNF = openssl.cnf SIGNING_KEY = $(KEYS_DIR)/signing.key SIGNING_CERT = $(KEYS_DIR)/signing.crt SIGNING_DER = $(KEYS_DIR)/signing.der HOST_ARCH := $(shell uname -m) ARCH ?= $(HOST_ARCH) ifeq ($(ARCH),x86_64) TARGET_ARCH = x86_64 EFI_BINARY = BOOTX64.EFI STUB_BINARY = stubx64.efi ENROLL_BINARY = enroll-x64.efi ARCH_CFLAGS = -mno-red-zone else ifeq ($(ARCH),aarch64) TARGET_ARCH = aarch64 EFI_BINARY = BOOTAA64.EFI STUB_BINARY = stubaa64.efi ENROLL_BINARY = enroll-aa64.efi ARCH_CFLAGS = else ifeq ($(ARCH),ia32) TARGET_ARCH = ia32 EFI_BINARY = BOOTIA32.EFI STUB_BINARY = stubia32.efi ENROLL_BINARY = enroll-ia32.efi ARCH_CFLAGS = else $(error Unsupported ARCH=$(ARCH). Use x86_64, aarch64, or ia32) endif ifeq ($(HOST_ARCH),x86_64) HOST_ARCH_NORM = x86_64 else ifeq ($(HOST_ARCH),aarch64) HOST_ARCH_NORM = aarch64 else ifeq ($(HOST_ARCH),i686) HOST_ARCH_NORM = ia32 else HOST_ARCH_NORM = unknown endif ifneq ($(HOST_ARCH_NORM),$(TARGET_ARCH)) CROSS = 1 else CROSS = 0 endif ifeq ($(CROSS),1) ifeq ($(TARGET_ARCH),x86_64) CROSS_PREFIX = x86_64-linux-gnu- else ifeq ($(TARGET_ARCH),aarch64) CROSS_PREFIX = aarch64-linux-gnu- else ifeq ($(TARGET_ARCH),ia32) CROSS_PREFIX = i686-linux-gnu- endif CC = $(CROSS_PREFIX)gcc LD = $(CROSS_PREFIX)ld AR = $(CROSS_PREFIX)ar OBJCOPY = $(CROSS_PREFIX)objcopy else CC = gcc LD = ld AR = ar OBJCOPY = objcopy endif GNU_EFI_INC = $(GNU_EFI_DIR)/inc GNU_EFI_LIB_DIR = $(GNU_EFI_DIR)/$(TARGET_ARCH)/lib GNU_EFI_GNUEFI = $(GNU_EFI_DIR)/gnuefi ARCH_BUILD_DIR = $(BUILD_DIR)/$(TARGET_ARCH) EFI_BUILD_DIR = $(ARCH_BUILD_DIR)/efi EFI_CRT0 = $(EFI_BUILD_DIR)/crt0-efi-$(TARGET_ARCH).o EFI_RELOC = $(EFI_BUILD_DIR)/reloc_$(TARGET_ARCH).o EFI_LIBEFI = $(GNU_EFI_LIB_DIR)/libefi.a EFI_LIBGNUEFI = $(EFI_BUILD_DIR)/libgnuefi.a EFI_LDS = $(GNU_EFI_GNUEFI)/elf_$(TARGET_ARCH)_efi.lds CFLAGS = -I$(GNU_EFI_INC) \ -I$(GNU_EFI_INC)/$(TARGET_ARCH) \ -I$(GNU_EFI_INC)/protocol \ -Iincludes \ -fno-stack-protector \ -fpic \ -fshort-wchar \ $(ARCH_CFLAGS) \ -DEFI_FUNCTION_WRAPPER LDFLAGS = -nostdlib \ -znocombreloc \ -T $(EFI_LDS) \ -shared \ -Bsymbolic \ -L$(GNU_EFI_LIB_DIR) \ -L$(EFI_BUILD_DIR) \ $(EFI_CRT0) LIBS = -l:libgnuefi.a -l:libefi.a OBJCOPY_FLAGS = -j .text \ -j .sdata \ -j .data \ -j .rodata \ -j .dynamic \ -j .dynsym \ -j .rel \ -j .rela \ -j .reloc \ --target=efi-app-$(TARGET_ARCH) LOADER_OBJ = $(ARCH_BUILD_DIR)/loader.o LOADER_SO = $(ARCH_BUILD_DIR)/loader.so TARGET_EFI = $(OUTPUT_DIR)/$(EFI_BINARY) STUB_OBJ = $(ARCH_BUILD_DIR)/stub.o STUB_SO = $(ARCH_BUILD_DIR)/stub.so TARGET_STUB = $(OUTPUT_DIR)/$(STUB_BINARY) ENROLL_OBJ = $(ARCH_BUILD_DIR)/enroll.o ENROLL_SO = $(ARCH_BUILD_DIR)/enroll.so TARGET_ENROLL = $(OUTPUT_DIR)/$(ENROLL_BINARY) .PHONY: all enroll clean distclean all-arches check-deps test-efi info keygen sign iso all: check-deps $(TARGET_EFI) $(TARGET_STUB) $(TARGET_ENROLL) @echo "✓ Built: $(TARGET_EFI) (loader → $(STUB_BINARY))" @echo "✓ Built: $(TARGET_STUB)" @echo "✓ Built: $(TARGET_ENROLL) (→ mm$(TARGET_ARCH).efi on ISO)" all-arches: $(MAKE) all ARCH=x86_64 $(MAKE) all ARCH=aarch64 $(MAKE) all ARCH=ia32 enroll: check-deps $(TARGET_ENROLL) @echo "✓ Built: $(TARGET_ENROLL)" check-deps: @echo "Host: $(HOST_ARCH) Target: $(TARGET_ARCH) Mode: $(if $(filter 1,$(CROSS)),cross,native)" ifeq ($(CROSS),1) @which $(CC) > /dev/null 2>&1 || \ (echo "Install: sudo apt install gcc-$(TARGET_ARCH)-linux-gnu binutils-$(TARGET_ARCH)-linux-gnu" && exit 1) endif $(EFI_LIBEFI): @echo "→ Building libefi.a" @if [ "$(CROSS)" = "1" ]; then \ $(MAKE) -C $(GNU_EFI_DIR) ARCH=$(TARGET_ARCH) CROSS_COMPILE=$(CROSS_PREFIX) lib; \ else \ $(MAKE) -C $(GNU_EFI_DIR) ARCH=$(TARGET_ARCH) lib; \ fi $(EFI_CRT0): | $(EFI_BUILD_DIR) $(CC) -I$(GNU_EFI_INC) -I$(GNU_EFI_INC)/$(TARGET_ARCH) \ -fno-stack-protector -fpic \ -c -o $@ $(GNU_EFI_GNUEFI)/crt0-efi-$(TARGET_ARCH).S $(EFI_RELOC): | $(EFI_BUILD_DIR) $(CC) -I$(GNU_EFI_INC) -I$(GNU_EFI_INC)/$(TARGET_ARCH) \ -fno-stack-protector -fpic -fshort-wchar $(ARCH_CFLAGS) \ -c -o $@ $(GNU_EFI_GNUEFI)/reloc_$(TARGET_ARCH).c $(EFI_LIBGNUEFI): $(EFI_RELOC) | $(EFI_BUILD_DIR) $(AR) rcs $@ $(EFI_RELOC) $(BUILD_DIR) $(ARCH_BUILD_DIR) $(OUTPUT_DIR) $(EFI_BUILD_DIR): @mkdir -p $@ $(LOADER_OBJ): src/loader.c | $(ARCH_BUILD_DIR) $(CC) $(CFLAGS) -DSTUB_NAME='"$(STUB_BINARY)"' -c $< -o $@ $(LOADER_SO): $(LOADER_OBJ) $(EFI_CRT0) $(EFI_LIBGNUEFI) $(EFI_LIBEFI) $(LD) $(LDFLAGS) $(LOADER_OBJ) -o $@ $(LIBS) $(TARGET_EFI): $(LOADER_SO) | $(OUTPUT_DIR) $(OBJCOPY) $(OBJCOPY_FLAGS) $(LOADER_SO) $@ $(STUB_OBJ): src/stub.c | $(ARCH_BUILD_DIR) $(CC) $(CFLAGS) -c $< -o $@ $(STUB_SO): $(STUB_OBJ) $(EFI_CRT0) $(EFI_LIBGNUEFI) $(EFI_LIBEFI) $(LD) $(LDFLAGS) $(STUB_OBJ) -o $@ $(LIBS) $(TARGET_STUB): $(STUB_SO) | $(OUTPUT_DIR) $(OBJCOPY) $(OBJCOPY_FLAGS) $(STUB_SO) $@ $(ENROLL_OBJ): src/enroll.c | $(ARCH_BUILD_DIR) $(CC) $(CFLAGS) -c $< -o $@ $(ENROLL_SO): $(ENROLL_OBJ) $(EFI_CRT0) $(EFI_LIBGNUEFI) $(EFI_LIBEFI) $(LD) $(LDFLAGS) $(ENROLL_OBJ) -o $@ $(LIBS) $(TARGET_ENROLL): $(ENROLL_SO) | $(OUTPUT_DIR) $(OBJCOPY) $(OBJCOPY_FLAGS) $(ENROLL_SO) $@ test-efi: @if [ -f "$(TARGET_EFI)" ]; then \ echo -n " Type: "; file $(TARGET_EFI) | grep -oE "PE32\+? executable.*EFI" || echo "unknown"; \ echo -n " Size: "; ls -lh $(TARGET_EFI) | awk '{print $$5}'; \ fi keygen: @if [ -f $(SIGNING_KEY) ]; then \ echo "Keys already exist. Delete keys/ to regenerate."; exit 1; \ fi bash gen-key.sh @echo " openssl.cnf — config used for key generation" @echo "✓ Keys generated in $(KEYS_DIR)/" @echo " signing.key — keep private" @echo " signing.crt — PEM cert" @echo " signing.der — DER cert (place at EFI/BOOT/cert.der on ISO)" sign: all-arches @if [ ! -f $(SIGNING_KEY) ]; then \ echo "No signing key found. Run: make keygen"; exit 1; \ fi @which sbsign > /dev/null 2>&1 || \ (echo "Install: sudo apt install sbsigntool" && exit 1) @for efi in $(OUTPUT_DIR)/BOOT*.EFI $(OUTPUT_DIR)/stub*.efi; do \ [ -f "$$efi" ] || continue; \ sbsign --key $(SIGNING_KEY) --cert $(SIGNING_CERT) \ --output "$$efi" "$$efi" 2>&1 | grep -v "^warning:"; \ echo "✓ Signed: $$efi"; \ done @[ -f $(OUTPUT_DIR)/enroll-x64.efi ] && \ sbsign --key $(SIGNING_KEY) --cert $(SIGNING_CERT) \ --output $(OUTPUT_DIR)/mmx64.efi $(OUTPUT_DIR)/enroll-x64.efi 2>&1 | grep -v "^warning:" && \ echo "✓ Signed: $(OUTPUT_DIR)/mmx64.efi" || true @[ -f $(OUTPUT_DIR)/enroll-aa64.efi ] && \ sbsign --key $(SIGNING_KEY) --cert $(SIGNING_CERT) \ --output $(OUTPUT_DIR)/mmaa64.efi $(OUTPUT_DIR)/enroll-aa64.efi 2>&1 | grep -v "^warning:" && \ echo "✓ Signed: $(OUTPUT_DIR)/mmaa64.efi" || true @[ -f $(OUTPUT_DIR)/enroll-ia32.efi ] && \ sbsign --key $(SIGNING_KEY) --cert $(SIGNING_CERT) \ --output $(OUTPUT_DIR)/mmia32.efi $(OUTPUT_DIR)/enroll-ia32.efi 2>&1 | grep -v "^warning:" && \ echo "✓ Signed: $(OUTPUT_DIR)/mmia32.efi" || true iso: sign @which xorriso > /dev/null 2>&1 || \ (echo "Install: sudo apt install xorriso" && exit 1) @if [ ! -f $(SIGNING_DER) ]; then \ echo "No signing.der found. Run: make keygen"; exit 1; \ fi @rm -rf iso_root @mkdir -p iso_root/EFI/BOOT iso_root/IPXE @# Our signed stubs — firmware picks the right arch automatically cp $(OUTPUT_DIR)/BOOTX64.EFI iso_root/EFI/BOOT/BOOTX64.EFI @[ -f $(OUTPUT_DIR)/BOOTAA64.EFI ] && \ cp $(OUTPUT_DIR)/BOOTAA64.EFI iso_root/EFI/BOOT/BOOTAA64.EFI || true @[ -f $(OUTPUT_DIR)/BOOTIA32.EFI ] && \ cp $(OUTPUT_DIR)/BOOTIA32.EFI iso_root/EFI/BOOT/BOOTIA32.EFI || true @# stub.efi — arch-neutral, loaded by all BOOT*.EFI stubs cp $(OUTPUT_DIR)/stub.efi iso_root/EFI/BOOT/stub.efi @# Pre-signed + renamed MOK manager binaries @[ -f $(OUTPUT_DIR)/mmx64.efi ] && \ cp $(OUTPUT_DIR)/mmx64.efi iso_root/EFI/BOOT/mmx64.efi || true @[ -f $(OUTPUT_DIR)/mmaa64.efi ] && \ cp $(OUTPUT_DIR)/mmaa64.efi iso_root/EFI/BOOT/mmaa64.efi || true @[ -f $(OUTPUT_DIR)/mmia32.efi ] && \ cp $(OUTPUT_DIR)/mmia32.efi iso_root/EFI/BOOT/mmia32.efi || true @# Signing cert — enroll.efi reads this; also enrollable via UEFI setup cp $(SIGNING_DER) iso_root/EFI/BOOT/cert.der @# iPXE binaries @if [ -f ipxe/ipxe.efi ]; then cp ipxe/ipxe.efi iso_root/IPXE/ipxe.efi; \ else echo "Warning: ipxe/ipxe.efi not found — IPXE/ will be empty"; fi @if [ -f ipxe/ipxe-snp.efi ]; then cp ipxe/ipxe-snp.efi iso_root/IPXE/ipxe-snp.efi; \ else echo "Warning: ipxe/ipxe-snp.efi not found"; fi xorriso -as mkisofs \ -o output/ipxe-boot.iso \ -e EFI/BOOT/BOOTX64.EFI \ -no-emul-boot \ -isohybrid-gpt-basdat \ iso_root @echo "✓ ISO: output/ipxe-boot.iso" clean: rm -rf $(BUILD_DIR) $(OUTPUT_DIR) iso_root distclean: clean $(MAKE) -C $(GNU_EFI_DIR) clean > /dev/null 2>&1 || true info: @echo "Target: $(TARGET_ARCH) Binary: $(EFI_BINARY) Compiler: $(CC)"