Reputation: 540
I am trying to create a bootable UEFI ISO, but Hyper-V does not see it as a valid UEFI filesystem. What am I doing wrong?
ISO creation:
xorriso -as mkisofs -o uefi.iso -iso-level 3 -V UEFI isoFiles
isoFiles has a single file, boot/hello.efi
. When mounted or opened in an archive manager the file exists.
Edit: Let's have a lot more context for this shall we?
This is the EFI code, it uses gnu-efi v3.0.8:
#include <efi.h>
#include <efilib.h>
EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable){
EFI_STATUS Status;
EFI_INPUT_KEY Key;
ST = SystemTable;
Status = ST->ConOut->OutputString(ST->ConOut, L"Hello world!\n\r");
if(EFI_ERROR(Status)){
return Status;
}
Status = ST->ConIn->Reset(ST->ConIn, FALSE);
if(EFI_ERROR(Status)){
return Status;
}
while((Status = ST->ConIn->ReadKeyStroke(ST->ConIn, &Key)) == EFI_NOT_READY){}
return Status;
}
This is the Makefile for it:
DIR_OUT := ..
TARGET := uefi
OUT := $(DIR_OUT)/out/boot
DIR_SRC := src
DIR_BLD := build
EFI_DIR := gnu-efi-3.0.8
EFI_LIB := $(EFI_DIR)/x86_64/gnuefi/ $(EFI_DIR)/x86_64/lib
EFI_INC := $(EFI_DIR)/inc $(EFI_DIR)/inc/x86_64 $(EFI_DIR)/inc/protocol
EFI_CRT := $(EFI_DIR)/x86_64/gnuefi/crt0-efi-x86_64.o
EFI_LDS := $(EFI_DIR)/gnuefi/elf_x86_64_efi.lds
CFILES := $(wildcard $(DIR_SRC)/*.c)
OFILES := $(patsubst $(DIR_SRC)/%.c,$(DIR_BLD)/%.o,$(CFILES))
PREFIX :=
CC := $(PREFIX)gcc
LD := $(PREFIX)ld
OBJCPY := $(PREFIX)objcopy
INCLUDES := $(addprefix -I,$(EFI_INC))
CFLAGS := -fno-stack-protector -fpic -fshort-wchar -mno-red-zone -Wall -ffreestanding -DEFI_FUNCTION_WRAPPER -c $(INCLUDES)
LDFLAGS := -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic $(addprefix -L,$(EFI_LIB)) $(EFI_CRT)
all: builddir bootdir $(OUT)/$(TARGET).efi
.PRECIOUS: $(OFILES)
clean:
rm -vrf $(OFILES) $(OUT)/$(TARGET).efi
$(OUT)/$(TARGET).efi: $(DIR_BLD)/$(TARGET).efi
cp $< $@
%.efi: %.so
$(OBJCPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .reloc --target=efi-app-x86_64 $^ $@
$(DIR_BLD)/$(TARGET).so: $(OFILES)
$(LD) $(LDFLAGS) $< -o $@ -lefi -lgnuefi
$(DIR_BLD)/%.o: $(DIR_SRC)/%.c
$(CC) $(CFLAGS) $< -o $@
bootdir:
mkdir -p $(OUT)
builddir:
mkdir -p $(DIR_BLD)
This is the Makefile that creates the ISO:
ISO_DIR := ..
ISO_FILE := uefi.iso
ISO_LABEL := UEFI
DIR_BLD := build
MKFSISO := xorriso -as mkisofs
FATSIZE := 8M
MKFSVFAT := /sbin/mkfs.vfat
MOUNT := sudo mount
UMOUNT := sudo umount
UID := $(shell id -u gudenau)
GID := $(shell id -g gudenau)
all: buildDir $(ISO_DIR)/$(ISO_FILE)
.PRECIOUS: $(ISO_DIR)/$(ISO_FILE) $(DIR_BLD)/efi.img
$(ISO_DIR)/%.iso: $(DIR_BLD)/efi.img
$(MKFSISO) -o $@ -iso-level 3 -V "$(ISO_LABEL)" $(DIR_BLD)/efi.img -e /efi.img -no-emul-boot
%.img:
dd if=/dev/zero of=$@ bs=1024 count=1024
$(MKFSVFAT) $@
mkdir -p $(DIR_BLD)/image
$(MOUNT) -o gid=$(GID),uid=$(UID) $@ $(DIR_BLD)/image
mkdir -p $(DIR_BLD)/image/EFI/BOOT/
cp ../bootloader/build/uefi.efi $(DIR_BLD)/image/EFI/BOOT/BOOTX64.EFI
$(UMOUNT) $(DIR_BLD)/image
rm -vfr $(DIR_BLD)/image
clean:
rm -vf $(DIR_BLD)/efi.img $(ISO_DIR)/$(ISO_FILE)
buildDir:
mkdir -p $(DIR_BLD)
I know the Makefiles are really bad at the moment, but I am just trying to get it to work at the moment. I will make them better later.
Edit: After more research I have this Makefile now:
ISO_DIR := ..
ISO_FILE := uefi.iso
ISO_LABEL := UEFI
DIR_BLD := build
MKFSISO := xorriso -as mkisofs
FATHEADS := 32
FATTRACKS := 32
FATSECTOR := 512
FATTHING := 128
FATFORMAT := mformat
MMD := mmd
MCOPY := mcopy
all: buildDir $(ISO_DIR)/$(ISO_FILE)
.PRECIOUS: $(ISO_DIR)/$(ISO_FILE) $(DIR_BLD)/efi.img
$(ISO_DIR)/%.iso: $(DIR_BLD)/efi.img
$(MKFSISO) -o $@ -iso-level 3 -V "$(ISO_LABEL)" $(DIR_BLD)/efi.img -e /efi.img -no-emul-boot
%.img:
$(FATFORMAT) -i $@ -F -h $(FATHEADS) -t $(FATTRACKS) -n $(FATTHING) -c 1 -C
$(MDD) -i $@ ::/EFI
$(MDD) -i $@ ::/EFI/BOOT
$(MCOPY) -i $@ ../bootloader/build/uefi.efi ::/EFI/BOOT/BOOTX64.EFI
clean:
rm -vf $(DIR_BLD)/efi.img $(ISO_DIR)/$(ISO_FILE)
buildDir:
mkdir -p $(DIR_BLD)
But I can not figure out how to make a GPT image with it, as mkgpt
does not seem to exist.
Upvotes: 1
Views: 7058
Reputation: 344
Depending on the (virtual) medium type you need a partition table or an El Torito Boot Catalog which mark an EFI System Partition. Inside that partition must be a FAT filesystem with the start program. The name of this program depends on the CPU Type. E.g. \EFI\BOOT\BOOTX64.EFI for 64 bit Intel/AMD. For 32 bit Intel/AMD it's BOOTIA32.EFI.
So first of all you need to create that FAT filesystem image, with your program having the prescribed name. Let's name the image file "efi.img" and put it into the current working directory. Then you put the FAT image file as data file into the ISO and mark it as EFI El Torito boot image so that EFI will find it on a (virtual) DVD medium.
xorriso -as mkisofs -o uefi.iso -iso-level 3 -V UEFI isoFiles \
./efi.img -e /efi.img -no-emul-boot
(Note that option -e expects the file address inside the ISO.)
For booting from (virtual) hard disk or USB stick, you'd append the FAT filesystem image as MBR partition of type 0xEF:
xorriso -as mkisofs -o uefi.iso -iso-level 3 -V UEFI isoFiles \
-append_partition 2 0xef ./efi.img
(Note that option -append_partition expects the file address as on local hard disk.)
Both add-ons can be combined at the cost of having two copies of the FAT image in the ISO. xorriso versions >= 1.4.6 can avoid this duplication by a special pseudo-path "--interval:..." with option -e:
xorriso -as mkisofs -o uefi.iso -iso-level 3 -V UEFI isoFiles \
-append_partition 2 0xef ./efi.img \
-e --interval:appended_partition_2:all:: -no-emul-boot
Upvotes: 1