[Buildroot] [PATCH v2 2/6] fs/iso9660: add support to Grub EFI bootloader in the image

Yann E. MORIN yann.morin.1998 at free.fr
Tue Sep 21 15:36:09 UTC 2021


Köry, All,

On 2021-09-21 15:28 +0200, Kory Maincent spake thusly:
> Add support to boot the Grub bootloader from an EFI BIOS in the ISO9660
> image.
> For that we need to create EFI System Partition (ESP). The ESP is a vfat
> partition which contain the Grub2 binary at the /EFI/BOOT/ location.
> xorriso command will generate the iso image including the ESP.
> 
> We notice Grub can not read and mount the ESP, therefore we place the Grub
> configuration file in the ISO9660 partition. A Grub2 builtin configuration
> need to be used to tell Grub2 to search automatically its configuration
> file in the ISO9660 partition. Use 'set root=(cd0)' in the configuration
> file passed to BR2_TARGET_GRUB2_BUILTIN_CONFIG_EFI.
> 
> Signed-off-by: Kory Maincent <kory.maincent at bootlin.com>
> ---
> 
> Changes in v2:
> Following the review from Yann E. Morin:
> - Add parameter to mkfs and mcopy to allow reproducible builds
> - Fix typos and variable multi-line assignement
> 
>  fs/iso9660/Config.in  | 30 ++++++++++++++++++++++++------
>  fs/iso9660/iso9660.mk | 38 +++++++++++++++++++++++++++++++++++---
>  2 files changed, 59 insertions(+), 9 deletions(-)
> 
> diff --git a/fs/iso9660/Config.in b/fs/iso9660/Config.in
> index 6f001c0640..4fc96db28c 100644
> --- a/fs/iso9660/Config.in
> +++ b/fs/iso9660/Config.in
> @@ -3,6 +3,7 @@ config BR2_TARGET_ROOTFS_ISO9660
>  	depends on (BR2_i386 || BR2_x86_64)
>  	depends on BR2_LINUX_KERNEL
>  	depends on BR2_TARGET_GRUB2_I386_PC || \
> +		BR2_TARGET_GRUB2_I386_EFI || BR2_TARGET_GRUB2_X86_64_EFI || \

iso9660 already depends on (BR2_i386 || BR2_x86_64), and thanks to the
select of a default platform for i386 and x86_64, we know that at least
one of the three i386-pc, i386-efi, or x86_64-efi is set, so we can
simplify the condition to just:

    depends on BR2_TARGET_GRUB2 || BR2_TARGET_SYSLINUX_ISOLINUX

No?

>  		BR2_TARGET_SYSLINUX_ISOLINUX
>  	select BR2_LINUX_KERNEL_INSTALL_TARGET \
>  	       if (!BR2_TARGET_ROOTFS_ISO9660_INITRD && !BR2_TARGET_ROOTFS_INITRAMFS)
> @@ -27,22 +28,38 @@ choice
>  
>  config BR2_TARGET_ROOTFS_ISO9660_GRUB2
>  	bool "grub2"
> -	depends on BR2_TARGET_GRUB2_I386_PC
> +	depends on BR2_TARGET_GRUB2_I386_PC || BR2_TARGET_GRUB2_I386_EFI || \
> +		BR2_TARGET_GRUB2_X86_64_EFI

Similarly here, the condition can be simplified to just:

    depends on BR2_TARGET_GRUB2

> +	select BR2_TARGET_ROOTFS_ISO9660_BIOS_BOOTLOADER \
> +	       if BR2_TARGET_GRUB2_I386_PC
> +	select BR2_TARGET_ROOTFS_ISO9660_EFI_BOOTLOADER \
> +	       if (BR2_TARGET_GRUB2_I386_EFI || BR2_TARGET_GRUB2_X86_64_EFI)
>  	help
>  	  Use Grub 2 as the bootloader for the ISO9660 image. Make
>  	  sure to enable the 'iso9660' module in
> -	  BR2_TARGET_GRUB2_BUILTIN_MODULES and to use 'cd' as the boot
> -	  partition in BR2_TARGET_GRUB2_BOOT_PARTITION=.
> +	  BR2_TARGET_GRUB2_BUILTIN_MODULES_PC or
> +	  BR2_TARGET_GRUB2_BUILTIN_MODULES_EFI. Use 'cd' as the boot
> +	  partition in BR2_TARGET_GRUB2_BOOT_PARTITION= for GRUB on BIOS
> +	  or 'set root=(cd0)' in the configuration file passed to
> +	  BR2_TARGET_GRUB2_BUILTIN_CONFIG_EFI for GRUB on EFI.
>  
>  config BR2_TARGET_ROOTFS_ISO9660_ISOLINUX
>  	bool "isolinux"
>  	depends on BR2_TARGET_SYSLINUX_ISOLINUX
> +	select BR2_TARGET_ROOTFS_ISO9660_BIOS_BOOTLOADER
>  
>  endchoice
>  
> +config BR2_TARGET_ROOTFS_ISO9660_BIOS_BOOTLOADER
> +	bool
> +
> +config BR2_TARGET_ROOTFS_ISO9660_EFI_BOOTLOADER
> +	bool
> +
>  config BR2_TARGET_ROOTFS_ISO9660_BOOT_MENU
>  	string "Boot menu config file"
> -	default "fs/iso9660/grub.cfg" if BR2_TARGET_ROOTFS_ISO9660_GRUB2
> +	default "fs/iso9660/grub.cfg" if BR2_TARGET_ROOTFS_ISO9660_GRUB2_PC || \
> +					BR2_TARGET_ROOTFS_ISO9660_GRUB2_EFI

I forgot to state so in the previous review, but I think it is more
appropriate to duplicate the default for each case; that's nicer to
read:

    default "fs/iso9660/grub.cfg" if BR2_TARGET_ROOTFS_ISO9660_GRUB2_PC
    default "fs/iso9660/grub.cfg" if BR2_TARGET_ROOTFS_ISO9660_GRUB2_EFI

However, BR2_TARGET_ROOTFS_ISO9660_GRUB2_PC and BR2_TARGET_ROOTFS_ISO9660_GRUB2_EFI
are defined nowhere...

Did you mean BR2_TARGET_ROOTFS_ISO9660_BIOS_BOOTLOADER or
BR2_TARGET_ROOTFS_ISO9660_EFI_BOOTLOADER by chance?

>  	default "fs/iso9660/isolinux.cfg" if BR2_TARGET_ROOTFS_ISO9660_ISOLINUX
>  	help
>  	  Use this option to provide a custom bootloader configuration
> @@ -83,7 +100,8 @@ config BR2_TARGET_ROOTFS_ISO9660_HYBRID
>  
>  endif
>  
> -comment "iso image needs a Linux kernel and either grub2 i386-pc or isolinux to be built"
> +comment "iso image needs a Linux kernel and either grub2 or isolinux to be built"
>  	depends on BR2_i386 || BR2_x86_64
>  	depends on !BR2_LINUX_KERNEL || \
> -		!(BR2_TARGET_GRUB2_I386_PC || BR2_TARGET_SYSLINUX_ISOLINUX)
> +		!(BR2_TARGET_GRUB2_I386_PC || BR2_TARGET_GRUB2_I386_EFI || \
> +		BR2_TARGET_GRUB2_X86_64_EFI || BR2_TARGET_SYSLINUX_ISOLINUX)

Ditto, the condition can be simplified, as in the comment iself:

    depends on !BR2_LINUX_KERNEL || \
            !(BR2_TARGET_GRUB2 || BR2_TARGET_SYSLINUX_ISOLINUX)

> diff --git a/fs/iso9660/iso9660.mk b/fs/iso9660/iso9660.mk
> index 23421a9a5c..d46aec002b 100644
> --- a/fs/iso9660/iso9660.mk
> +++ b/fs/iso9660/iso9660.mk
> @@ -57,7 +57,11 @@ else
>  ROOTFS_ISO9660_TMP_TARGET_DIR = $(TARGET_DIR)
>  endif
>  
> -ifeq ($(BR2_TARGET_ROOTFS_ISO9660_GRUB2),y)
> +ifeq ($(BR2_REPRODUCIBLE),y)
> +ROOTFS_ISO9660_MKFS_OPTS = --invariant

'MKFS' is ambiguous: it seems to imply it applies to the iso9660 mkfs,
while in fact it applies to the vfat mkfs. So, maybe (yes, bikesheding,
and naming is hard): ROOTFS_ISO9660_VFAT_OPTS ?

> +endif
> +
> +ifeq ($(BR2_TARGET_ROOTFS_ISO9660_GRUB2)$(BR2_TARGET_ROOTFS_ISO9660_BIOS_BOOTLOADER),yy)
>  ROOTFS_ISO9660_DEPENDENCIES += grub2
>  ROOTFS_ISO9660_BOOTLOADER_CONFIG_PATH = \
>  	$(ROOTFS_ISO9660_TMP_TARGET_DIR)/boot/grub/grub.cfg
> @@ -66,6 +70,21 @@ define ROOTFS_ISO9660_INSTALL_BOOTLOADER
>  	$(INSTALL) -D -m 0644 $(BINARIES_DIR)/grub-eltorito.img \
>  		$(ROOTFS_ISO9660_TMP_TARGET_DIR)/boot/grub/grub-eltorito.img
>  endef
> +else ifeq ($(BR2_TARGET_ROOTFS_ISO9660_GRUB2)$(BR2_TARGET_ROOTFS_ISO9660_EFI_BOOTLOADER),yy)
> +ROOTFS_ISO9660_DEPENDENCIES += grub2 host-dosfstools host-mtools
> +ROOTFS_ISO9660_EFI_PARTITION = boot/fat.efi
> +ROOTFS_ISO9660_EFI_PARTITION_PATH = $(ROOTFS_ISO9660_TMP_TARGET_DIR)/$(ROOTFS_ISO9660_EFI_PARTITION)
> +ROOTFS_ISO9660_EFI_PARTITION_CONTENT = $(BINARIES_DIR)/efi-part
> +ROOTFS_ISO9660_BOOTLOADER_CONFIG_PATH = \
> +	$(ROOTFS_ISO9660_TMP_TARGET_DIR)/boot/grub/grub.cfg
> +define ROOTFS_ISO9660_INSTALL_BOOTLOADER
> +	rm -rf $(ROOTFS_ISO9660_EFI_PARTITION_PATH)
> +	mkdir -p $(dir $(ROOTFS_ISO9660_EFI_PARTITION_PATH))
> +	dd if=/dev/zero of=$(ROOTFS_ISO9660_EFI_PARTITION_PATH) bs=1M count=1
> +	$(HOST_DIR)/sbin/mkfs.vfat $(ROOTFS_ISO9660_MKFS_OPTS) $(ROOTFS_ISO9660_EFI_PARTITION_PATH)
> +	$(HOST_DIR)/bin/mcopy -p -m -i $(ROOTFS_ISO9660_EFI_PARTITION_PATH) -s \
> +		$(ROOTFS_ISO9660_EFI_PARTITION_CONTENT)/* ::/

Ah, but the whole point of reproducible, and thus --invariant and -p -m,
is that the generated filesystem is reproducible. Here, the VFAT fs
itself is reproducible thanks to --invariant, but you copy a file with
the date/time the build occurs, which by definition is not reproducible.
You should touch the file to $(SOURCE_DATE_EPOCH) before copying into
the vfat.

Yes, reproducibility is hard, but not as much as naming is. ;-]

> +endef
>  else ifeq ($(BR2_TARGET_ROOTFS_ISO9660_ISOLINUX),y)
>  ROOTFS_ISO9660_DEPENDENCIES += syslinux
>  ROOTFS_ISO9660_BOOTLOADER_CONFIG_PATH = \
> @@ -128,9 +147,22 @@ ROOTFS_ISO9660_PRE_GEN_HOOKS += ROOTFS_ISO9660_DISABLE_EXTERNAL_INITRD
>  
>  endif # ROOTFS_ISO9660_USE_INITRD
>  
> +ifeq ($(BR2_TARGET_ROOTFS_ISO9660_BIOS_BOOTLOADER),y)
> +ROOTFS_ISO9660_OPTS += \
> +	-J \
> +	-R \
> +	-boot-load-size 4 \
> +	-boot-info-table \
> +	-no-emul-boot \

--no-emul-boot is in both cases, so maybe it can be left in the constant
options, in _CMDS below, no?

> +	-b $(ROOTFS_ISO9660_BOOT_IMAGE)
> +else ifeq ($(BR2_TARGET_ROOTFS_ISO9660_EFI_BOOTLOADER),y)

Note that BR2_TARGET_ROOTFS_ISO9660_BIOS_BOOTLOADER and
BR2_TARGET_ROOTFS_ISO9660_EFI_BOOTLOADER are mutually exclusive, by
definition, but we also know at least one will be set, also by
definition.

So, the else clause can be a simple one, without the ifeq.

/methink.

> +ROOTFS_ISO9660_OPTS += \
> +	--efi-boot $(ROOTFS_ISO9660_EFI_PARTITION) \
> +	-no-emul-boot

So with an EFI bootloader, we do not need to generate an ISO with Joliet
and RockRidge externsions? Or is that implied by the mere fact that it
is using an efi-boot?

Regards,
Yann E. MORIN.

> +endif
> +
>  define ROOTFS_ISO9660_CMD
> -	$(HOST_DIR)/bin/xorriso -as mkisofs -J -R -b $(ROOTFS_ISO9660_BOOT_IMAGE) \
> -		-no-emul-boot -boot-load-size 4 -boot-info-table \
> +	$(HOST_DIR)/bin/xorriso -as mkisofs \
>  		$(ROOTFS_ISO9660_OPTS) \
>  		-o $@ $(ROOTFS_ISO9660_TMP_TARGET_DIR)
>  endef
> -- 
> 2.25.1
> 

-- 
.-----------------.--------------------.------------------.--------------------.
|  Yann E. MORIN  | Real-Time Embedded | /"\ ASCII RIBBON | Erics' conspiracy: |
| +33 662 376 056 | Software  Designer | \ / CAMPAIGN     |  ___               |
| +33 561 099 427 `------------.-------:  X  AGAINST      |  \e/  There is no  |
| http://ymorin.is-a-geek.org/ | _/*\_ | / \ HTML MAIL    |   v   conspiracy.  |
'------------------------------^-------^------------------^--------------------'



More information about the buildroot mailing list