Files
efi-shim-bootloader/Makefile
2026-05-26 03:27:31 -07:00

295 lines
9.4 KiB
Makefile

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)"