x86: generate EFI platform bootable images

Add EFI platform bootable images for x86 platforms. These images can
also boot from legacy BIOS platform.

EFI System Partition need to be fat12/fat16/fat32 (not need to load
filesystem drivers), so the first partition of EFI images are not ext4
filesystem any more.

GPT partition table has an alternate partition table, we did not
generate it. This may cause problems when use these images as qemu disk
(kernel can not find rootfs), we pad enough sectors will be ok.

Signed-off-by: 李国 <uxgood.org@gmail.com>
[part_magic_* refactoring, removed genisoimage checks]
Signed-off-by: Petr Štetiar <ynezz@true.cz>
master
李国 2020-03-26 14:05:33 +08:00 committed by Petr Štetiar
parent d9228514cc
commit a6b7c3e672
12 changed files with 165 additions and 38 deletions

View File

@ -188,19 +188,28 @@ menu "Target Images"
select PACKAGE_grub2
default y
config GRUB_EFI_IMAGES
bool "Build GRUB EFI images (Linux x86 or x86_64 host only)"
depends on TARGET_x86
depends on TARGET_ROOTFS_EXT4FS || TARGET_ROOTFS_JFFS2 || TARGET_ROOTFS_SQUASHFS
select PACKAGE_grub2
select PACKAGE_grub2-efi
select PACKAGE_kmod-fs-vfat
default y
config GRUB_CONSOLE
bool "Use Console Terminal (in addition to Serial)"
depends on GRUB_IMAGES
depends on GRUB_IMAGES || GRUB_EFI_IMAGES
default y
config GRUB_SERIAL
string "Serial port device"
depends on GRUB_IMAGES
depends on GRUB_IMAGES || GRUB_EFI_IMAGES
default "ttyS0"
config GRUB_BAUDRATE
int "Serial port baud rate"
depends on GRUB_IMAGES
depends on GRUB_IMAGES || GRUB_EFI_IMAGES
default 38400 if TARGET_x86_generic
default 115200
@ -211,20 +220,20 @@ menu "Target Images"
config GRUB_BOOTOPTS
string "Extra kernel boot options"
depends on GRUB_IMAGES
depends on GRUB_IMAGES || GRUB_EFI_IMAGES
help
If you don't know, just leave it blank.
config GRUB_TIMEOUT
string "Seconds to wait before booting the default entry"
depends on GRUB_IMAGES
depends on GRUB_IMAGES || GRUB_EFI_IMAGES
default "5"
help
If you don't know, 5 seconds is a reasonable default.
config GRUB_TITLE
string "Title for the menu entry in GRUB"
depends on GRUB_IMAGES
depends on GRUB_IMAGES || GRUB_EFI_IMAGES
default "OpenWrt"
help
This is the title of the GRUB menu entry.
@ -233,18 +242,18 @@ menu "Target Images"
config ISO_IMAGES
bool "Build LiveCD image (ISO)"
depends on TARGET_x86
select GRUB_IMAGES
depends on GRUB_IMAGES || GRUB_EFI_IMAGES
config VDI_IMAGES
bool "Build VirtualBox image files (VDI)"
depends on TARGET_x86
select GRUB_IMAGES
depends on GRUB_IMAGES || GRUB_EFI_IMAGES
select PACKAGE_kmod-e1000
config VMDK_IMAGES
bool "Build VMware image files (VMDK)"
depends on TARGET_x86
select GRUB_IMAGES
depends on GRUB_IMAGES || GRUB_EFI_IMAGES
select PACKAGE_kmod-e1000
config TARGET_IMAGES_GZIP
@ -272,7 +281,7 @@ menu "Target Images"
config TARGET_ROOTFS_PARTNAME
string "Root partition on target device"
depends on GRUB_IMAGES
depends on GRUB_IMAGES || GRUB_EFI_IMAGES
help
Override the root partition on the final device. If left empty,
it will be mounted by PARTUUID which makes the kernel find the

View File

@ -45,6 +45,7 @@ IMG_PREFIX:=$(VERSION_DIST_SANITIZED)-$(IMG_PREFIX_VERNUM)$(IMG_PREFIX_VERCODE)$
IMG_ROOTFS:=$(IMG_PREFIX)-rootfs
IMG_COMBINED:=$(IMG_PREFIX)-combined
IMG_PART_SIGNATURE:=$(shell echo $(SOURCE_DATE_EPOCH)$(LINUX_VERMAGIC) | mkhash md5 | cut -b1-8)
IMG_PART_DISKGUID:=$(shell echo $(SOURCE_DATE_EPOCH)$(LINUX_VERMAGIC) | mkhash md5 | sed -r 's/(.{8})(.{4})(.{4})(.{4})(.{10})../\1-\2-\3-\4-\500/')
MKFS_DEVTABLE_OPT := -D $(INCLUDE_DIR)/device_table.txt

View File

@ -102,6 +102,24 @@ get_magic_long() {
(get_image "$@" | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2>/dev/null
}
get_magic_gpt() {
(get_image "$@" | dd bs=8 count=1 skip=64) 2>/dev/null
}
get_magic_vfat() {
(get_image "$@" | dd bs=1 count=3 skip=54) 2>/dev/null
}
part_magic_efi() {
local magic=$(get_magic_gpt "$@")
[ "$magic" = "EFI PART" ]
}
part_magic_fat() {
local magic=$(get_magic_vfat "$@")
[ "$magic" = "FAT" ]
}
export_bootdevice() {
local cmdline bootdisk rootpart uuid blockdev uevent line class
local MAJOR MINOR DEVNAME DEVTYPE
@ -136,6 +154,17 @@ export_bootdevice() {
fi
done
;;
PARTUUID=????????-????-????-????-??????????02)
uuid="${rootpart#PARTUUID=}"
uuid="${uuid%02}00"
for disk in $(find /dev -type b); do
set -- $(dd if=$disk bs=1 skip=568 count=16 2>/dev/null | hexdump -v -e '8/1 "%02x "" "2/1 "%02x""-"6/1 "%02x"')
if [ "$4$3$2$1-$6$5-$8$7-$9" = "$uuid" ]; then
uevent="/sys/class/block/${disk##*/}/uevent"
break
fi
done
;;
/dev/*)
uevent="/sys/class/block/${rootpart##*/}/../uevent"
;;
@ -207,6 +236,22 @@ get_partitions() { # <device> <filename>
rm -f "/tmp/partmap.$filename"
local part
part_magic_efi "$disk" && {
#export_partdevice will fail when partition number is greater than 15, as
#the partition major device number is not equal to the disk major device number
for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
set -- $(hexdump -v -n 48 -s "$((0x380 + $part * 0x80))" -e '4/4 "%08x"" "4/4 "%08x"" "4/4 "0x%08X "' "$disk")
local type="$1"
local lba="$(( $(hex_le32_to_cpu $4) * 0x100000000 + $(hex_le32_to_cpu $3) ))"
local end="$(( $(hex_le32_to_cpu $6) * 0x100000000 + $(hex_le32_to_cpu $5) ))"
local num="$(( $end - $lba ))"
[ "$type" = "00000000000000000000000000000000" ] && continue
printf "%2d %5d %7d\n" $part $lba $num >> "/tmp/partmap.$filename"
done
} || {
for part in 1 2 3 4; do
set -- $(hexdump -v -n 12 -s "$((0x1B2 + $part * 16))" -e '3/4 "0x%08X "' "$disk")
@ -218,6 +263,7 @@ get_partitions() { # <device> <filename>
printf "%2d %5d %7d\n" $part $lba $num >> "/tmp/partmap.$filename"
done
}
fi
}

View File

@ -20,7 +20,7 @@ sect=63
cyl=$(( (KERNELSIZE + ROOTFSSIZE) * 1024 * 1024 / (head * sect * 512)))
# create partition table
set $(ptgen -o "$OUTPUT" -h $head -s $sect -p ${KERNELSIZE}m -p ${ROOTFSSIZE}m ${ALIGN:+-l $ALIGN} ${SIGNATURE:+-S 0x$SIGNATURE})
set $(ptgen -o "$OUTPUT" -h $head -s $sect ${GUID:+-g} -p ${KERNELSIZE}m -p ${ROOTFSSIZE}m ${ALIGN:+-l $ALIGN} ${SIGNATURE:+-S 0x$SIGNATURE} ${GUID:+-G $GUID})
KERNELOFFSET="$(($1 / 512))"
KERNELSIZE="$2"
@ -30,6 +30,12 @@ ROOTFSSIZE="$(($4 / 512))"
[ -n "$PADDING" ] && dd if=/dev/zero of="$OUTPUT" bs=512 seek="$ROOTFSOFFSET" conv=notrunc count="$ROOTFSSIZE"
dd if="$ROOTFSIMAGE" of="$OUTPUT" bs=512 seek="$ROOTFSOFFSET" conv=notrunc
if [ -n "$GUID" ]; then
[ -n "$PADDING" ] && dd if=/dev/zero of="$OUTPUT" bs=512 seek="$(($ROOTFSOFFSET + $ROOTFSSIZE))" conv=notrunc count="$sect"
mkfs.fat -n kernel -C "$OUTPUT.kernel" -S 512 "$(($KERNELSIZE / 1024))"
mcopy -s -i "$OUTPUT.kernel" "$KERNELDIR"/* ::/
else
make_ext4fs -J -L kernel -l "$KERNELSIZE" "$OUTPUT.kernel" "$KERNELDIR"
fi
dd if="$OUTPUT.kernel" of="$OUTPUT" bs=512 seek="$KERNELOFFSET" conv=notrunc
rm -f "$OUTPUT.kernel"

View File

@ -2,13 +2,14 @@
# Copyright (C) 2012-2015 OpenWrt.org
move_config() {
local partdev
local partdev parttype=ext4
. /lib/upgrade/common.sh
if export_bootdevice && export_partdevice partdev 1; then
mkdir -p /boot
mount -t ext4 -o rw,noatime "/dev/$partdev" /boot
part_magic_fat "/dev/$partdev" && parttype=vfat
mount -t $parttype -o rw,noatime "/dev/$partdev" /boot
if [ -f "/boot/$BACKUP_FILE" ]; then
mv -f "/boot/$BACKUP_FILE" /
fi

View File

@ -6,6 +6,7 @@ upgrade_bootloader() {
. /lib/upgrade/common.sh
if [ ! -f /boot/grub/upgraded ] && export_bootdevice && export_partdevice diskdev 0; then
part_magic_efi "/dev/$diskdev" && return 0
echo "(hd0) /dev/$diskdev" > /tmp/device.map
/usr/sbin/grub-bios-setup \
-m "/tmp/device.map" \

View File

@ -20,7 +20,7 @@ platform_check_image() {
get_partitions "/dev/$diskdev" bootdisk
#extract the boot sector from the image
get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b 2>/dev/null
get_image "$@" | dd of=/tmp/image.bs count=63 bs=512b 2>/dev/null
get_partitions /tmp/image.bs image
@ -37,29 +37,31 @@ platform_check_image() {
}
platform_copy_config() {
local partdev
local partdev parttype=ext4
if export_partdevice partdev 1; then
mount -t ext4 -o rw,noatime "/dev/$partdev" /mnt
part_magic_fat "/dev/$partdev" && parttype=vfat
mount -t $parttype -o rw,noatime "/dev/$partdev" /mnt
cp -af "$UPGRADE_BACKUP" "/mnt/$BACKUP_FILE"
umount /mnt
fi
}
platform_do_bootloader_upgrade() {
local bootpart
local bootpart parttable=msdos
local diskdev="$1"
if export_partdevice bootpart 1; then
mkdir -p /tmp/boot
mount -o rw,noatime "/dev/$bootpart" /tmp/boot
echo "(hd0) /dev/$diskdev" > /tmp/device.map
part_magic_efi "/dev/$diskdev" && parttable=gpt
echo "Upgrading bootloader on /dev/$diskdev..."
grub-bios-setup \
-m "/tmp/device.map" \
-d "/tmp/boot/boot/grub" \
-r "hd0,msdos1" \
-r "hd0,${parttable}1" \
"/dev/$diskdev" \
&& touch /boot/grub/upgraded
@ -81,7 +83,7 @@ platform_do_upgrade() {
get_partitions "/dev/$diskdev" bootdisk
#extract the boot sector from the image
get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b
get_image "$@" | dd of=/tmp/image.bs count=63 bs=512b >/dev/null
get_partitions /tmp/image.bs image
@ -106,7 +108,7 @@ platform_do_upgrade() {
while read part start size; do
if export_partdevice partdev $part; then
echo "Writing image to /dev/$partdev..."
get_image "$@" | dd of="/dev/$partdev" ibs="512" obs=1M skip="$start" count="$size" conv=fsync
get_image "$@" | dd of="/dev/$partdev" ibs=512 obs=1M skip="$start" count="$size" conv=fsync
else
echo "Unable to find partition $part device, skipped."
fi
@ -117,4 +119,15 @@ platform_do_upgrade() {
get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync
platform_do_bootloader_upgrade "$diskdev"
local parttype=ext4
part_magic_efi "/dev/$diskdev" || return 0
if export_partdevice partdev 1; then
part_magic_fat "/dev/$partdev" && parttype=vfat
mount -t $parttype -o rw,noatime "/dev/$partdev" /mnt
set -- $(dd if="/dev/$diskdev" bs=1 skip=1168 count=16 2>/dev/null | hexdump -v -e '8/1 "%02x "" "2/1 "%02x""-"6/1 "%02x"')
sed -i "s/\(PARTUUID=\)[a-f0-9-]\+/\1$4$3$2$1-$6$5-$8$7-$9/ig" /mnt/boot/grub/grub.cfg
umount /mnt
fi
}

View File

@ -139,6 +139,7 @@ CONFIG_FB_DEFERRED_IO=y
CONFIG_FB_EFI=y
CONFIG_FB_HYPERV=y
# CONFIG_FB_I810 is not set
CONFIG_FB_SIMPLE=y
CONFIG_FB_SYS_COPYAREA=y
CONFIG_FB_SYS_FILLRECT=y
CONFIG_FB_SYS_FOPS=y

View File

@ -139,6 +139,7 @@ CONFIG_FB_DEFERRED_IO=y
CONFIG_FB_EFI=y
CONFIG_FB_HYPERV=y
# CONFIG_FB_I810 is not set
CONFIG_FB_SIMPLE=y
CONFIG_FB_SYS_COPYAREA=y
CONFIG_FB_SYS_FILLRECT=y
CONFIG_FB_SYS_FOPS=y

View File

@ -38,6 +38,8 @@ endif
ROOTPART:=$(call qstrip,$(CONFIG_TARGET_ROOTFS_PARTNAME))
ROOTPART:=$(if $(ROOTPART),$(ROOTPART),PARTUUID=$(IMG_PART_SIGNATURE)-02)
GPT_ROOTPART:=$(call qstrip,$(CONFIG_TARGET_ROOTFS_PARTNAME))
GPT_ROOTPART:=$(if $(GPT_ROOTPART),$(GPT_ROOTPART),PARTUUID=$(shell echo $(IMG_PART_DISKGUID) | sed 's/00$$/02/'))
GRUB_TIMEOUT:=$(call qstrip,$(CONFIG_GRUB_TIMEOUT))
GRUB_TITLE:=$(call qstrip,$(CONFIG_GRUB_TITLE))
@ -47,7 +49,12 @@ BOOTOPTS:=$(call qstrip,$(CONFIG_GRUB_BOOTOPTS))
define Build/combined
$(CP) $(KDIR)/$(KERNEL_NAME) $@.boot/boot/vmlinuz
-$(CP) $(STAGING_DIR_ROOT)/boot/. $@.boot/boot/
PADDING="1" SIGNATURE="$(IMG_PART_SIGNATURE)" $(SCRIPT_DIR)/gen_image_generic.sh \
$(if $(filter $(1),efi),
$(INSTALL_DIR) $@.boot/efi/boot
$(CP) $(STAGING_DIR_IMAGE)/grub2/boot$(if $(CONFIG_x86_64),x64,ia32).efi $@.boot/efi/boot/
)
PADDING="1" SIGNATURE="$(IMG_PART_SIGNATURE)" \
$(if $(filter $(1),efi),GUID="$(IMG_PART_DISKGUID)") $(SCRIPT_DIR)/gen_image_generic.sh \
$@ \
$(CONFIG_TARGET_KERNEL_PARTSIZE) $@.boot \
$(CONFIG_TARGET_ROOTFS_PARTSIZE) $(IMAGE_ROOTFS) \
@ -61,6 +68,7 @@ define Build/grub-config
-e 's#@SERIAL_CONFIG@#$(strip $(GRUB_SERIAL_CONFIG))#g' \
-e 's#@TERMINAL_CONFIG@#$(strip $(GRUB_TERMINAL_CONFIG))#g' \
-e 's#@ROOTPART@#root=$(ROOTPART) rootwait#g' \
-e 's#@GPT_ROOTPART@#root=$(GPT_ROOTPART) rootwait#g' \
-e 's#@CMDLINE@#$(BOOTOPTS) $(GRUB_CONSOLE_CMDLINE)#g' \
-e 's#@TIMEOUT@#$(GRUB_TIMEOUT)#g' \
-e 's#@TITLE@#$(GRUB_TITLE)#g' \
@ -71,12 +79,12 @@ define Build/grub-install
rm -fR $@.grub2
$(INSTALL_DIR) $@.grub2
$(CP) $(STAGING_DIR_IMAGE)/grub2/boot.img $@.grub2/
$(CP) $(STAGING_DIR_IMAGE)/grub2/$(GRUB2_VARIANT)-core.img $@.grub2/core.img
$(CP) $(STAGING_DIR_IMAGE)/grub2/$(if $(filter $(1),efi),gpt,$(GRUB2_VARIANT))-core.img $@.grub2/core.img
echo '(hd0) $@' > $@.grub2/device.map
$(STAGING_DIR_HOST)/bin/grub-bios-setup \
-m "$@.grub2/device.map" \
-d "$@.grub2" \
-r "hd0,msdos1" \
-r "hd0,$(if $(filter $(1),efi),gpt1,msdos1)" \
$@
endef
@ -87,7 +95,15 @@ define Build/iso
$(STAGING_DIR_IMAGE)/grub2/eltorito.img \
> $@.boot/boot/grub/eltorito.img
-$(CP) $(STAGING_DIR_ROOT)/boot/. $@.boot/boot/
$(if $(filter $(1),efi),
mkfs.fat -C $@.boot/boot/grub/isoboot.img -S 512 1440
mmd -i $@.boot/boot/grub/isoboot.img ::/efi ::/efi/boot
mcopy -i $@.boot/boot/grub/isoboot.img \
$(STAGING_DIR_IMAGE)/grub2/iso-boot$(if $(CONFIG_x86_64),x64,ia32).efi \
::/efi/boot/boot$(if $(CONFIG_x86_64),x64,ia32).efi
)
mkisofs -R -b boot/grub/eltorito.img -no-emul-boot -boot-info-table \
$(if $(filter $(1),efi),-boot-load-size 4 -c boot.cat -eltorito-alt-boot -b boot/grub/isoboot.img -no-emul-boot) \
-o $@ $@.boot $(TARGET_DIR)
endef
@ -100,23 +116,37 @@ define Device/Default
IMAGE/combined.vmdk := grub-config pc | combined | grub-install | qemu-image vmdk
IMAGE/rootfs.img := append-rootfs
IMAGE/rootfs.img.gz := append-rootfs | gzip
ARTIFACT/image-efi.iso := grub-config iso | iso efi
IMAGE/combined-efi.img := grub-config efi | combined efi | grub-install efi
IMAGE/combined-efi.img.gz := grub-config efi | combined efi | grub-install efi | gzip
IMAGE/combined-efi.vdi := grub-config efi | combined efi | grub-install efi | qemu-image vdi
IMAGE/combined-efi.vmdk := grub-config efi | combined efi | grub-install efi | qemu-image vmdk
ifeq ($(CONFIG_TARGET_IMAGES_GZIP),y)
IMAGES := combined.img.gz rootfs.img.gz
IMAGES-y := rootfs.img.gz
IMAGES-$$(CONFIG_GRUB_IMAGES) += combined.img.gz
IMAGES-$$(CONFIG_GRUB_EFI_IMAGES) += combined-efi.img.gz
else
IMAGES := combined.img rootfs.img
IMAGES-y := rootfs.img
IMAGES-$$(CONFIG_GRUB_IMAGES) += combined.img
IMAGES-$$(CONFIG_GRUB_EFI_IMAGES) += combined-efi.img
endif
KERNEL := kernel-bin
KERNEL_INSTALL := 1
KERNEL_NAME := bzImage
ifeq ($(CONFIG_ISO_IMAGES),y)
ARTIFACTS := image.iso
ARTIFACTS-$$(CONFIG_GRUB_IMAGES) += image.iso
ARTIFACTS-$$(CONFIG_GRUB_EFI_IMAGES) += image-efi.iso
endif
ifeq ($(CONFIG_VDI_IMAGES),y)
IMAGES += combined.vdi
IMAGES-$$(CONFIG_GRUB_IMAGES) += combined.vdi
IMAGES-$$(CONFIG_GRUB_EFI_IMAGES) += combined-efi.vdi
endif
ifeq ($(CONFIG_VMDK_IMAGES),y)
IMAGES += combined.vmdk
IMAGES-$$(CONFIG_GRUB_IMAGES) += combined.vmdk
IMAGES-$$(CONFIG_GRUB_EFI_IMAGES) += combined-efi.vmdk
endif
IMAGES := $$(IMAGES-y)
ARTIFACTS := $$(ARTIFACTS-y)
endef
$(eval $(call Image/gzip-ext4-padded-squashfs))

View File

@ -0,0 +1,13 @@
@SERIAL_CONFIG@
@TERMINAL_CONFIG@
set default="0"
set timeout="@TIMEOUT@"
set root='(hd0,gpt1)'
menuentry "@TITLE@" {
linux /boot/vmlinuz @GPT_ROOTPART@ @CMDLINE@ noinitrd
}
menuentry "@TITLE@ (failsafe)" {
linux /boot/vmlinuz failsafe=true @GPT_ROOTPART@ @CMDLINE@ noinitrd
}

View File

@ -3,7 +3,12 @@
set default="0"
set timeout="@TIMEOUT@"
if [ "${grub_platform}" = "efi" ]; then
set root='(cd0)'
else
set root='(cd)'
fi
menuentry "@TITLE@" {
linux /boot/vmlinuz root=/dev/sr0 rootfstype=iso9660 rootwait @CMDLINE@ noinitrd