diff --git a/config/Config-images.in b/config/Config-images.in index 3a1fad118b..a02e0c091a 100644 --- a/config/Config-images.in +++ b/config/Config-images.in @@ -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 "0" 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 diff --git a/include/image.mk b/include/image.mk index 8af5905c60..6204e8ab61 100644 --- a/include/image.mk +++ b/include/image.mk @@ -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 diff --git a/package/base-files/files/lib/upgrade/common.sh b/package/base-files/files/lib/upgrade/common.sh index a986cc0b5c..2cbc69e5dd 100644 --- a/package/base-files/files/lib/upgrade/common.sh +++ b/package/base-files/files/lib/upgrade/common.sh @@ -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,17 +236,34 @@ get_partitions() { # rm -f "/tmp/partmap.$filename" local part - for part in 1 2 3 4; do - set -- $(hexdump -v -n 12 -s "$((0x1B2 + $part * 16))" -e '3/4 "0x%08X "' "$disk") + 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="$(( $(hex_le32_to_cpu $1) % 256))" - local lba="$(( $(hex_le32_to_cpu $2) ))" - local num="$(( $(hex_le32_to_cpu $3) ))" + 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 -gt 0 ] || continue + [ "$type" = "00000000000000000000000000000000" ] && continue - printf "%2d %5d %7d\n" $part $lba $num >> "/tmp/partmap.$filename" - done + 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") + + local type="$(( $(hex_le32_to_cpu $1) % 256))" + local lba="$(( $(hex_le32_to_cpu $2) ))" + local num="$(( $(hex_le32_to_cpu $3) ))" + + [ $type -gt 0 ] || continue + + printf "%2d %5d %7d\n" $part $lba $num >> "/tmp/partmap.$filename" + done + } fi } diff --git a/package/boot/grub2/Makefile b/package/boot/grub2/Makefile index 980a6e372a..840401fa3a 100644 --- a/package/boot/grub2/Makefile +++ b/package/boot/grub2/Makefile @@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=grub PKG_CPE_ID:=cpe:/a:gnu:grub2 PKG_VERSION:=2.04 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=@GNU/grub @@ -27,14 +27,18 @@ PKG_FLAGS:=nonshared include $(INCLUDE_DIR)/host-build.mk include $(INCLUDE_DIR)/package.mk -define Package/grub2 +define Package/grub2/Default CATEGORY:=Boot Loaders SECTION:=boot - TITLE:=GRand Unified Bootloader + TITLE:=GRand Unified Bootloader ($(1)) URL:=http://www.gnu.org/software/grub/ DEPENDS:=@TARGET_x86 + VARIANT:=$(1) endef +Package/grub2=$(call Package/grub2/Default,pc) +Package/grub2-efi=$(call Package/grub2/Default,efi) + define Package/grub2-editenv CATEGORY:=Utilities SECTION:=utils @@ -42,6 +46,7 @@ define Package/grub2-editenv TITLE:=Grub2 Environment editor URL:=http://www.gnu.org/software/grub/ DEPENDS:=@TARGET_x86 + VARIANT:=pc endef define Package/grub2-editenv/description @@ -60,7 +65,7 @@ CONFIGURE_ARGS += \ --disable-device-mapper \ --disable-libzfs \ --disable-grub-mkfont \ - --with-platform=none + --with-platform=$(BUILD_VARIANT) HOST_CONFIGURE_VARS += \ grub_build_mkfont_excuse="don't want fonts" @@ -71,51 +76,73 @@ HOST_CONFIGURE_ARGS += \ --sbindir="$(STAGING_DIR_HOST)/bin" \ --disable-werror \ --disable-libzfs \ - --disable-nls + --disable-nls \ + --with-platform=none HOST_MAKE_FLAGS += \ TARGET_RANLIB=$(TARGET_RANLIB) \ LIBLZMA=$(STAGING_DIR_HOST)/lib/liblzma.a +TARGET_CFLAGS := + define Host/Configure $(SED) 's,(RANLIB),(TARGET_RANLIB),' $(HOST_BUILD_DIR)/grub-core/Makefile.in $(Host/Configure/Default) endef -define Host/Install - $(call Host/Install/Default) - - $(INSTALL_DIR) $(STAGING_DIR_HOST)/lib/grub/grub2-generic - $(STAGING_DIR_HOST)/bin/grub-mkimage \ - -d $(STAGING_DIR_HOST)/lib/grub/i386-pc \ - -p /boot/grub \ - -O i386-pc \ - -c ./files/grub-early.cfg \ - -o $(STAGING_DIR_HOST)/lib/grub/grub2-generic/core.img \ - at_keyboard biosdisk boot chain configfile ext2 linux ls part_msdos reboot serial vga - - $(INSTALL_DIR) $(STAGING_DIR_HOST)/lib/grub/grub2-iso - $(STAGING_DIR_HOST)/bin/grub-mkimage \ - -d $(STAGING_DIR_HOST)/lib/grub/i386-pc \ - -p /boot/grub \ - -O i386-pc \ - -c ./files/grub-early.cfg \ - -o $(STAGING_DIR_HOST)/lib/grub/grub2-iso/eltorito.img \ - at_keyboard biosdisk boot chain configfile iso9660 linux ls part_msdos reboot serial vga - - $(INSTALL_DIR) $(STAGING_DIR_HOST)/lib/grub/grub2-legacy - $(STAGING_DIR_HOST)/bin/grub-mkimage \ - -d $(STAGING_DIR_HOST)/lib/grub/i386-pc \ - -p /boot/grub \ - -O i386-pc \ - -c ./files/grub-early.cfg \ - -o $(STAGING_DIR_HOST)/lib/grub/grub2-legacy/core.img \ - biosdisk boot chain configfile ext2 linux ls part_msdos reboot serial vga -endef - define Package/grub2/install $(INSTALL_DIR) $(1)/usr/sbin $(INSTALL_BIN) $(PKG_BUILD_DIR)/grub-bios-setup $(1)/usr/sbin/ + $(INSTALL_DIR) $(STAGING_DIR_IMAGE)/grub2 + $(CP) $(PKG_BUILD_DIR)/grub-core/boot.img $(STAGING_DIR_IMAGE)/grub2/ + $(CP) $(PKG_BUILD_DIR)/grub-core/cdboot.img $(STAGING_DIR_IMAGE)/grub2/ + sed 's#msdos1#gpt1#g' ./files/grub-early.cfg >$(PKG_BUILD_DIR)/grub-early.cfg + $(STAGING_DIR_HOST)/bin/grub-mkimage \ + -d $(PKG_BUILD_DIR)/grub-core \ + -p /boot/grub \ + -O i386-pc \ + -c $(PKG_BUILD_DIR)/grub-early.cfg \ + -o $(STAGING_DIR_IMAGE)/grub2/gpt-core.img \ + at_keyboard biosdisk boot chain configfile fat linux ls part_gpt reboot serial vga + $(STAGING_DIR_HOST)/bin/grub-mkimage \ + -d $(PKG_BUILD_DIR)/grub-core \ + -p /boot/grub \ + -O i386-pc \ + -c ./files/grub-early.cfg \ + -o $(STAGING_DIR_IMAGE)/grub2/generic-core.img \ + at_keyboard biosdisk boot chain configfile ext2 linux ls part_msdos reboot serial vga + $(STAGING_DIR_HOST)/bin/grub-mkimage \ + -d $(PKG_BUILD_DIR)/grub-core \ + -p /boot/grub \ + -O i386-pc \ + -c ./files/grub-early.cfg \ + -o $(STAGING_DIR_IMAGE)/grub2/eltorito.img \ + at_keyboard biosdisk boot chain configfile iso9660 linux ls part_msdos reboot serial test vga + $(STAGING_DIR_HOST)/bin/grub-mkimage \ + -d $(PKG_BUILD_DIR)/grub-core \ + -p /boot/grub \ + -O i386-pc \ + -c ./files/grub-early.cfg \ + -o $(STAGING_DIR_IMAGE)/grub2/legacy-core.img \ + biosdisk boot chain configfile ext2 linux ls part_msdos reboot serial vga +endef + +define Package/grub2-efi/install + sed 's#msdos1#gpt1#g' ./files/grub-early.cfg >$(PKG_BUILD_DIR)/grub-early.cfg + $(STAGING_DIR_HOST)/bin/grub-mkimage \ + -d $(PKG_BUILD_DIR)/grub-core \ + -p /boot/grub \ + -O $(CONFIG_ARCH)-efi \ + -c $(PKG_BUILD_DIR)/grub-early.cfg \ + -o $(STAGING_DIR_IMAGE)/grub2/boot$(if $(CONFIG_x86_64),x64,ia32).efi \ + at_keyboard boot chain configfile fat linux ls part_gpt reboot serial efi_gop efi_uga + $(STAGING_DIR_HOST)/bin/grub-mkimage \ + -d $(PKG_BUILD_DIR)/grub-core \ + -p /boot/grub \ + -O $(CONFIG_ARCH)-efi \ + -c ./files/grub-early.cfg \ + -o $(STAGING_DIR_IMAGE)/grub2/iso-boot$(if $(CONFIG_x86_64),x64,ia32).efi \ + at_keyboard boot chain configfile fat iso9660 linux ls part_msdos part_gpt reboot serial test efi_gop efi_uga endef define Package/grub2-editenv/install @@ -125,4 +152,5 @@ endef $(eval $(call HostBuild)) $(eval $(call BuildPackage,grub2)) +$(eval $(call BuildPackage,grub2-efi)) $(eval $(call BuildPackage,grub2-editenv)) diff --git a/scripts/gen_image_generic.sh b/scripts/gen_image_generic.sh index 2c57d56f07..53f73dc6e1 100755 --- a/scripts/gen_image_generic.sh +++ b/scripts/gen_image_generic.sh @@ -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 -make_ext4fs -J -L kernel -l "$KERNELSIZE" "$OUTPUT.kernel" "$KERNELDIR" +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" diff --git a/target/linux/ipq40xx/config-5.4 b/target/linux/ipq40xx/config-5.4 index 86fabe6010..ba9ac7ddc4 100644 --- a/target/linux/ipq40xx/config-5.4 +++ b/target/linux/ipq40xx/config-5.4 @@ -344,6 +344,7 @@ CONFIG_MTD_SPI_NAND=y CONFIG_MTD_SPI_NOR=y CONFIG_MTD_SPLIT_FIRMWARE=y CONFIG_MTD_SPLIT_FIT_FW=y +CONFIG_MTD_SPLIT_WRGG_FW=y CONFIG_MTD_UBI=y CONFIG_MTD_UBI_BEB_LIMIT=20 CONFIG_MTD_UBI_BLOCK=y diff --git a/target/linux/x86/64/config-4.19 b/target/linux/x86/64/config-4.19 index 8b08fd8573..54e376571c 100644 --- a/target/linux/x86/64/config-4.19 +++ b/target/linux/x86/64/config-4.19 @@ -69,12 +69,15 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_GENERIC=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BALLOON_COMPACTION=y +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_BLK_DEV_INTEGRITY=y CONFIG_BLK_DEV_NVME=y CONFIG_NVME_MULTIPATH=y CONFIG_BLK_MQ_VIRTIO=y # CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set CONFIG_BTT=y +CONFIG_CDROM=y # CONFIG_CALGARY_IOMMU is not set # CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT is not set CONFIG_CONNECTOR=y @@ -294,6 +297,7 @@ CONFIG_IOSF_MBI=y # CONFIG_IOSF_MBI_DEBUG is not set # CONFIG_ISCSI_IBFT is not set # CONFIG_ISCSI_IBFT_FIND is not set +CONFIG_ISO9660_FS=y CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y # CONFIG_KVM_DEBUG_FS is not set CONFIG_KVM_GUEST=y diff --git a/target/linux/x86/64/config-5.4 b/target/linux/x86/64/config-5.4 index d092fc693a..2a7a332922 100644 --- a/target/linux/x86/64/config-5.4 +++ b/target/linux/x86/64/config-5.4 @@ -64,12 +64,15 @@ CONFIG_AUDIT_ARCH=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_GENERIC=y CONFIG_BALLOON_COMPACTION=y +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set CONFIG_BLK_DEV_INTEGRITY=y CONFIG_BLK_DEV_NVME=y CONFIG_BLK_MQ_VIRTIO=y CONFIG_BLK_PM=y # CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set CONFIG_BTT=y +CONFIG_CDROM=y # CONFIG_CALGARY_IOMMU is not set # CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT is not set CONFIG_CONNECTOR=y @@ -280,6 +283,7 @@ CONFIG_IOMMU_HELPER=y CONFIG_IOSF_MBI=y # CONFIG_IOSF_MBI_DEBUG is not set # CONFIG_ISCSI_IBFT is not set +CONFIG_ISO9660_FS=y CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y # CONFIG_KVM_DEBUG_FS is not set CONFIG_KVM_GUEST=y diff --git a/target/linux/x86/base-files/lib/preinit/79_move_config b/target/linux/x86/base-files/lib/preinit/79_move_config index 702da9e873..338398c947 100644 --- a/target/linux/x86/base-files/lib/preinit/79_move_config +++ b/target/linux/x86/base-files/lib/preinit/79_move_config @@ -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 diff --git a/target/linux/x86/base-files/lib/preinit/81_upgrade_bootloader b/target/linux/x86/base-files/lib/preinit/81_upgrade_bootloader index 3a4e756b1e..1379c9b2cb 100644 --- a/target/linux/x86/base-files/lib/preinit/81_upgrade_bootloader +++ b/target/linux/x86/base-files/lib/preinit/81_upgrade_bootloader @@ -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" \ diff --git a/target/linux/x86/base-files/lib/upgrade/platform.sh b/target/linux/x86/base-files/lib/upgrade/platform.sh index 53c751861c..ee88dfb082 100644 --- a/target/linux/x86/base-files/lib/upgrade/platform.sh +++ b/target/linux/x86/base-files/lib/upgrade/platform.sh @@ -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 + } diff --git a/target/linux/x86/generic/config-4.19 b/target/linux/x86/generic/config-4.19 index 4a689ca026..ada81ce04e 100644 --- a/target/linux/x86/generic/config-4.19 +++ b/target/linux/x86/generic/config-4.19 @@ -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 diff --git a/target/linux/x86/generic/config-5.4 b/target/linux/x86/generic/config-5.4 index 4a689ca026..ada81ce04e 100644 --- a/target/linux/x86/generic/config-5.4 +++ b/target/linux/x86/generic/config-5.4 @@ -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 diff --git a/target/linux/x86/image/Makefile b/target/linux/x86/image/Makefile index c0c5c8323a..7864dfa1f8 100644 --- a/target/linux/x86/image/Makefile +++ b/target/linux/x86/image/Makefile @@ -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' \ @@ -70,25 +78,32 @@ endef define Build/grub-install rm -fR $@.grub2 $(INSTALL_DIR) $@.grub2 - $(CP) $(STAGING_DIR_HOST)/lib/grub/i386-pc/*.img \ - $(STAGING_DIR_HOST)/lib/grub/grub2-$(GRUB2_VARIANT)/core.img \ - $@.grub2/ + $(CP) $(STAGING_DIR_IMAGE)/grub2/boot.img $@.grub2/ + $(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 define Build/iso $(CP) $(KDIR)/$(KERNEL_NAME) $@.boot/boot/vmlinuz cat \ - $(STAGING_DIR_HOST)/lib/grub/i386-pc/cdboot.img \ - $(STAGING_DIR_HOST)/lib/grub/grub2-iso/eltorito.img \ + $(STAGING_DIR_IMAGE)/grub2/cdboot.img \ + $(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 @@ -101,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)) diff --git a/target/linux/x86/image/grub-efi.cfg b/target/linux/x86/image/grub-efi.cfg new file mode 100644 index 0000000000..14d30e88e4 --- /dev/null +++ b/target/linux/x86/image/grub-efi.cfg @@ -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 +} diff --git a/target/linux/x86/image/grub-iso.cfg b/target/linux/x86/image/grub-iso.cfg index f5848b3853..4bef492a41 100644 --- a/target/linux/x86/image/grub-iso.cfg +++ b/target/linux/x86/image/grub-iso.cfg @@ -3,7 +3,12 @@ set default="0" set timeout="@TIMEOUT@" -set root='(cd)' + +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 diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile index 97c89eec27..561d6d868f 100644 --- a/tools/firmware-utils/Makefile +++ b/tools/firmware-utils/Makefile @@ -32,7 +32,7 @@ define Host/Compile $(call cc,dgfirmware) $(call cc,mksenaofw md5, -Wall --std=gnu99) $(call cc,trx2usr) - $(call cc,ptgen) + $(call cc,ptgen cyg_crc32) $(call cc,srec2bin) $(call cc,mkmylofw) $(call cc,mkcsysimg) diff --git a/tools/firmware-utils/src/ptgen.c b/tools/firmware-utils/src/ptgen.c index 0192bb65e5..83067c104d 100644 --- a/tools/firmware-utils/src/ptgen.c +++ b/tools/firmware-utils/src/ptgen.c @@ -5,6 +5,9 @@ * uses parts of afdisk * Copyright (C) 2002 by David Roetzel * + * UUID/GUID definition stolen from kernel/include/uapi/linux/uuid.h + * Copyright (C) 2010, Intel Corp. Huang Ying + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,17 +32,69 @@ #include #include #include +#include #include #include +#include "cyg_crc.h" #if __BYTE_ORDER == __BIG_ENDIAN +#define cpu_to_le16(x) bswap_16(x) #define cpu_to_le32(x) bswap_32(x) +#define cpu_to_le64(x) bswap_64(x) #elif __BYTE_ORDER == __LITTLE_ENDIAN +#define cpu_to_le16(x) (x) #define cpu_to_le32(x) (x) +#define cpu_to_le64(x) (x) #else #error unknown endianness! #endif +#define swap(a, b) \ + do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) + +typedef struct { + uint8_t b[16]; +} guid_t; + +#define GUID_INIT(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ +((guid_t) \ +{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ + (b) & 0xff, ((b) >> 8) & 0xff, \ + (c) & 0xff, ((c) >> 8) & 0xff, \ + (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}) + +#define GUID_STRING_LENGTH 36 + +#define GPT_SIGNATURE 0x5452415020494645ULL +#define GPT_REVISION 0x00010000 + +#define GUID_PARTITION_SYSTEM \ + GUID_INIT( 0xC12A7328, 0xF81F, 0x11d2, \ + 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B) + +#define GUID_PARTITION_BASIC_DATA \ + GUID_INIT( 0xEBD0A0A2, 0xB9E5, 0x4433, \ + 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7) + +#define GUID_PARTITION_BIOS_BOOT \ + GUID_INIT( 0x21686148, 0x6449, 0x6E6F, \ + 0x74, 0x4E, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49) + +#define GPT_HEADER_SIZE 92 +#define GPT_ENTRY_SIZE 128 +#define GPT_ENTRY_MAX 128 +#define GPT_ENTRY_NAME_SIZE 72 + +#define GPT_HEADER_SECTOR 1 +#define GPT_FIRST_ENTRY_SECTOR 2 + +#define MBR_ENTRY_MAX 4 +#define MBR_DISK_SIGNATURE_OFFSET 440 +#define MBR_PARTITION_ENTRY_OFFSET 446 +#define MBR_BOOT_SIGNATURE_OFFSET 510 + +#define DISK_SECTOR_SIZE 512 + /* Partition table entry */ struct pte { uint8_t active; @@ -55,13 +110,43 @@ struct partinfo { int type; }; +/* GPT Partition table header */ +struct gpth { + uint64_t signature; + uint32_t revision; + uint32_t size; + uint32_t crc32; + uint32_t reserved; + uint64_t self; + uint64_t alternate; + uint64_t first_usable; + uint64_t last_usable; + guid_t disk_guid; + uint64_t first_entry; + uint32_t entry_num; + uint32_t entry_size; + uint32_t entry_crc32; +} __attribute__((packed)); + +/* GPT Partition table entry */ +struct gpte { + guid_t type; + guid_t guid; + uint64_t start; + uint64_t end; + uint64_t attr; + char name[GPT_ENTRY_NAME_SIZE]; +} __attribute__((packed)); + + int verbose = 0; int active = 1; int heads = -1; int sectors = -1; int kb_align = 0; bool ignore_null_sized_partition = false; -struct partinfo parts[4]; +bool use_guid_partition_table = false; +struct partinfo parts[GPT_ENTRY_MAX]; char *filename = NULL; @@ -91,7 +176,7 @@ static long to_kbytes(const char *string) end++; if (*end) { - fprintf(stderr, "garbage after end of number\n"); + fputs("garbage after end of number\n", stderr); return 0; } @@ -132,20 +217,73 @@ static inline unsigned long round_to_kb(long sect) { return ((sect - 1) / kb_align + 1) * kb_align; } +/* Compute a CRC for guid partition table */ +static inline unsigned long gpt_crc32(void *buf, unsigned long len) +{ + return cyg_crc32_accumulate(~0L, buf, len) ^ ~0L; +} + +/* Parse a guid string to guid_t struct */ +static inline int guid_parse(char *buf, guid_t *guid) +{ + char b[4] = {0}; + char *p = buf; + unsigned i = 0; + if (strnlen(buf, GUID_STRING_LENGTH) != GUID_STRING_LENGTH) + return -1; + for (i = 0; i < sizeof(guid_t); i++) { + if (*p == '-') + p++; + if (*p == '\0') + return -1; + memcpy(b, p, 2); + guid->b[i] = strtol(b, 0, 16); + p += 2; + } + swap(guid->b[0], guid->b[3]); + swap(guid->b[1], guid->b[2]); + swap(guid->b[4], guid->b[5]); + swap(guid->b[6], guid->b[7]); + return 0; +} + +/* init an utf-16 string from utf-8 string */ +static inline void init_utf16(char *str, uint16_t *buf, unsigned bufsize) +{ + unsigned i, n = 0; + for (i = 0; i < bufsize; i++) { + if (str[n] == 0x00) { + buf[i] = 0x00; + return ; + } else if ((str[n] & 0x80) == 0x00) {//0xxxxxxx + buf[i] = cpu_to_le16(str[n++]); + } else if ((str[n] & 0xE0) == 0xC0) {//110xxxxx + buf[i] = cpu_to_le16((str[n] & 0x1F) << 6 | (str[n + 1] & 0x3F)); + n += 2; + } else if ((str[n] & 0xF0) == 0xE0) {//1110xxxx + buf[i] = cpu_to_le16((str[n] & 0x0F) << 12 | (str[n + 1] & 0x3F) << 6 | (str[n + 2] & 0x3F)); + n += 3; + } else { + buf[i] = cpu_to_le16('?'); + n++; + } + } +} + /* check the partition sizes and write the partition table */ static int gen_ptable(uint32_t signature, int nr) { - struct pte pte[4]; - unsigned long sect = 0; - int i, fd, ret = -1, start, len; + struct pte pte[MBR_ENTRY_MAX]; + unsigned long start, len, sect = 0; + int i, fd, ret = -1; - memset(pte, 0, sizeof(struct pte) * 4); + memset(pte, 0, sizeof(struct pte) * MBR_ENTRY_MAX); for (i = 0; i < nr; i++) { if (!parts[i].size) { if (ignore_null_sized_partition) continue; fprintf(stderr, "Invalid size in partition %d!\n", i); - return -1; + return ret; } pte[i].active = ((i + 1) == active) ? 0x80 : 0; @@ -165,30 +303,34 @@ static int gen_ptable(uint32_t signature, int nr) to_chs(start + len - 1, pte[i].chs_end); if (verbose) - fprintf(stderr, "Partition %d: start=%ld, end=%ld, size=%ld\n", i, (long)start * 512, ((long)start + (long)len) * 512, (long)len * 512); - printf("%ld\n", (long)start * 512); - printf("%ld\n", (long)len * 512); + fprintf(stderr, "Partition %d: start=%ld, end=%ld, size=%ld\n", + i, + (long)start * DISK_SECTOR_SIZE, + (long)(start + len) * DISK_SECTOR_SIZE, + (long)len * DISK_SECTOR_SIZE); + printf("%ld\n", (long)start * DISK_SECTOR_SIZE); + printf("%ld\n", (long)len * DISK_SECTOR_SIZE); } if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { fprintf(stderr, "Can't open output file '%s'\n",filename); - return -1; + return ret; } - lseek(fd, 440, SEEK_SET); + lseek(fd, MBR_DISK_SIGNATURE_OFFSET, SEEK_SET); if (write(fd, &signature, sizeof(signature)) != sizeof(signature)) { - fprintf(stderr, "write failed.\n"); + fputs("write failed.\n", stderr); goto fail; } - lseek(fd, 446, SEEK_SET); - if (write(fd, pte, sizeof(struct pte) * 4) != sizeof(struct pte) * 4) { - fprintf(stderr, "write failed.\n"); + lseek(fd, MBR_PARTITION_ENTRY_OFFSET, SEEK_SET); + if (write(fd, pte, sizeof(struct pte) * MBR_ENTRY_MAX) != sizeof(struct pte) * MBR_ENTRY_MAX) { + fputs("write failed.\n", stderr); goto fail; } - lseek(fd, 510, SEEK_SET); + lseek(fd, MBR_BOOT_SIGNATURE_OFFSET, SEEK_SET); if (write(fd, "\x55\xaa", 2) != 2) { - fprintf(stderr, "write failed.\n"); + fputs("write failed.\n", stderr); goto fail; } @@ -198,20 +340,161 @@ fail: return ret; } +/* check the partition sizes and write the guid partition table */ +static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr) +{ + struct pte pte; + struct gpth gpth = { + .signature = cpu_to_le64(GPT_SIGNATURE), + .revision = cpu_to_le32(GPT_REVISION), + .size = cpu_to_le32(GPT_HEADER_SIZE), + .self = cpu_to_le64(GPT_HEADER_SECTOR), + .first_usable = cpu_to_le64(GPT_FIRST_ENTRY_SECTOR + GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE), + .first_entry = cpu_to_le64(GPT_FIRST_ENTRY_SECTOR), + .disk_guid = guid, + .entry_num = cpu_to_le32(GPT_ENTRY_MAX), + .entry_size = cpu_to_le32(GPT_ENTRY_SIZE), + }; + struct gpte gpte[GPT_ENTRY_MAX]; + uint64_t start, end, sect = 0; + int fd, ret = -1; + unsigned i; + + memset(gpte, 0, GPT_ENTRY_SIZE * GPT_ENTRY_MAX); + for (i = 0; i < nr; i++) { + if (!parts[i].size) { + if (ignore_null_sized_partition) + continue; + fprintf(stderr, "Invalid size in partition %d!\n", i); + return ret; + } + start = sect + sectors; + if (kb_align != 0) + start = round_to_kb(start); + gpte[i].start = cpu_to_le64(start); + + sect = start + parts[i].size * 2; + if (kb_align == 0) + sect = round_to_cyl(sect); + gpte[i].end = cpu_to_le64(sect -1); + gpte[i].guid = guid; + gpte[i].guid.b[sizeof(guid_t) -1] += i + 1; + if (parts[i].type == 0xEF || (i + 1) == (unsigned)active) { + gpte[i].type = GUID_PARTITION_SYSTEM; + init_utf16("EFI System Partition", (uint16_t *)gpte[i].name, GPT_ENTRY_NAME_SIZE / sizeof(uint16_t)); + } else { + gpte[i].type = GUID_PARTITION_BASIC_DATA; + } + + if (verbose) + fprintf(stderr, "Partition %d: start=%" PRIu64 ", end=%" PRIu64 ", size=%" PRIu64 "\n", + i, + start * DISK_SECTOR_SIZE, sect * DISK_SECTOR_SIZE, + (sect - start) * DISK_SECTOR_SIZE); + printf("%" PRIu64 "\n", start * DISK_SECTOR_SIZE); + printf("%" PRIu64 "\n", (sect - start) * DISK_SECTOR_SIZE); + } + + gpte[GPT_ENTRY_MAX - 1].start = cpu_to_le64(GPT_FIRST_ENTRY_SECTOR + GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE); + gpte[GPT_ENTRY_MAX - 1].end = cpu_to_le64((kb_align ? round_to_kb(sectors) : (unsigned long)sectors) - 1); + gpte[GPT_ENTRY_MAX - 1].type = GUID_PARTITION_BIOS_BOOT; + gpte[GPT_ENTRY_MAX - 1].guid = guid; + gpte[GPT_ENTRY_MAX - 1].guid.b[sizeof(guid_t) -1] += GPT_ENTRY_MAX; + + end = sect + sectors - 1; + + pte.type = 0xEE; + pte.start = cpu_to_le32(GPT_HEADER_SECTOR); + pte.length = cpu_to_le32(end); + to_chs(GPT_HEADER_SECTOR, pte.chs_start); + to_chs(end, pte.chs_end); + + gpth.last_usable = cpu_to_le64(end - GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE - 1); + gpth.alternate = cpu_to_le64(end); + gpth.entry_crc32 = cpu_to_le32(gpt_crc32(gpte, GPT_ENTRY_SIZE * GPT_ENTRY_MAX)); + gpth.crc32 = cpu_to_le32(gpt_crc32((char *)&gpth, GPT_HEADER_SIZE)); + + if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { + fprintf(stderr, "Can't open output file '%s'\n",filename); + return ret; + } + + lseek(fd, MBR_DISK_SIGNATURE_OFFSET, SEEK_SET); + if (write(fd, &signature, sizeof(signature)) != sizeof(signature)) { + fputs("write failed.\n", stderr); + goto fail; + } + + lseek(fd, MBR_PARTITION_ENTRY_OFFSET, SEEK_SET); + if (write(fd, &pte, sizeof(struct pte)) != sizeof(struct pte)) { + fputs("write failed.\n", stderr); + goto fail; + } + + lseek(fd, MBR_BOOT_SIGNATURE_OFFSET, SEEK_SET); + if (write(fd, "\x55\xaa", 2) != 2) { + fputs("write failed.\n", stderr); + goto fail; + } + + if (write(fd, &gpth, GPT_HEADER_SIZE) != GPT_HEADER_SIZE) { + fputs("write failed.\n", stderr); + goto fail; + } + + lseek(fd, GPT_FIRST_ENTRY_SECTOR * DISK_SECTOR_SIZE, SEEK_SET); + if (write(fd, &gpte, GPT_ENTRY_SIZE * GPT_ENTRY_MAX) != GPT_ENTRY_SIZE * GPT_ENTRY_MAX) { + fputs("write failed.\n", stderr); + goto fail; + } + +#ifdef WANT_ALTERNATE_PTABLE + /* The alternate partition table (We omit it by default) */ + swap(gpth.self, gpth.alternate); + gpth.first_entry = cpu_to_le64(end - GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE), + gpth.crc32 = 0; + gpth.crc32 = cpu_to_le32(gpt_crc32(&gpth, GPT_HEADER_SIZE)); + + lseek(fd, end * DISK_SECTOR_SIZE - GPT_ENTRY_SIZE * GPT_ENTRY_MAX, SEEK_SET); + if (write(fd, &gpte, GPT_ENTRY_SIZE * GPT_ENTRY_MAX) != GPT_ENTRY_SIZE * GPT_ENTRY_MAX) { + fputs("write failed.\n", stderr); + goto fail; + } + + lseek(fd, end * DISK_SECTOR_SIZE, SEEK_SET); + if (write(fd, &gpth, GPT_HEADER_SIZE) != GPT_HEADER_SIZE) { + fputs("write failed.\n", stderr); + goto fail; + } + lseek(fd, (end + 1) * DISK_SECTOR_SIZE -1, SEEK_SET); + if (write(fd, "\x00", 1) != 1) { + fputs("write failed.\n", stderr); + goto fail; + } +#endif + + ret = 0; +fail: + close(fd); + return ret; +} + static void usage(char *prog) { - fprintf(stderr, "Usage: %s [-v] [-n] -h -s -o [-a 0..4] [-l ] [[-t ] -p ...] \n", prog); + fprintf(stderr, "Usage: %s [-v] [-n] [-g] -h -s -o [-a 0..4] [-l ] [-G ] [[-t ] -p ...] \n", prog); exit(EXIT_FAILURE); } int main (int argc, char **argv) { - char type = 0x83; + unsigned char type = 0x83; int ch; int part = 0; uint32_t signature = 0x5452574F; /* 'OWRT' */ + guid_t guid = GUID_INIT( signature, 0x2211, 0x4433, \ + 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0x00); - while ((ch = getopt(argc, argv, "h:s:p:a:t:o:vnl:S:")) != -1) { + while ((ch = getopt(argc, argv, "h:s:p:a:t:o:vngl:S:G:")) != -1) { switch (ch) { case 'o': filename = optarg; @@ -222,6 +505,9 @@ int main (int argc, char **argv) case 'n': ignore_null_sized_partition = true; break; + case 'g': + use_guid_partition_table = 1; + break; case 'h': heads = (int)strtoul(optarg, NULL, 0); break; @@ -229,8 +515,8 @@ int main (int argc, char **argv) sectors = (int)strtoul(optarg, NULL, 0); break; case 'p': - if (part > 3) { - fprintf(stderr, "Too many partitions\n"); + if (part > GPT_ENTRY_MAX - 1 || (!use_guid_partition_table && part > 3)) { + fputs("Too many partitions\n", stderr); exit(EXIT_FAILURE); } parts[part].size = to_kbytes(optarg); @@ -250,6 +536,12 @@ int main (int argc, char **argv) case 'S': signature = strtoul(optarg, NULL, 0); break; + case 'G': + if (guid_parse(optarg, &guid)) { + fputs("Invalid guid string\n", stderr); + exit(EXIT_FAILURE); + } + break; case '?': default: usage(argv[0]); @@ -259,5 +551,8 @@ int main (int argc, char **argv) if (argc || (heads <= 0) || (sectors <= 0) || !filename) usage(argv[0]); + if (use_guid_partition_table) + return gen_gptable(signature, guid, part) ? EXIT_FAILURE : EXIT_SUCCESS; + return gen_ptable(signature, part) ? EXIT_FAILURE : EXIT_SUCCESS; }