diff --git a/dragonboard-fixes.patch b/dragonboard-fixes.patch index bc418b0..4a8ee44 100644 --- a/dragonboard-fixes.patch +++ b/dragonboard-fixes.patch @@ -589,83 +589,6 @@ index 0d3b7a35f4..a47b95264c 100644 -- 2.13.3 -From 8f96a0198893ace6d53993ac091e81e7c0d1764c Mon Sep 17 00:00:00 2001 -From: Rob Clark -Date: Sat, 24 Jun 2017 10:01:45 -0400 -Subject: [PATCH 10/23] db410c: config updates - -Signed-off-by: Rob Clark ---- - configs/dragonboard410c_defconfig | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/configs/dragonboard410c_defconfig b/configs/dragonboard410c_defconfig -index c78b4a6fd5..d9cb269085 100644 ---- a/configs/dragonboard410c_defconfig -+++ b/configs/dragonboard410c_defconfig -@@ -9,6 +9,7 @@ CONFIG_ENV_IS_NOWHERE=y - CONFIG_SYS_PROMPT="dragonboard410c => " - # CONFIG_CMD_IMI is not set - # CONFIG_CMD_IMLS is not set -+CONFIG_CMD_POWEROFF=y - CONFIG_CMD_MD5SUM=y - CONFIG_CMD_MEMINFO=y - CONFIG_CMD_UNZIP=y -@@ -21,11 +22,14 @@ CONFIG_CMD_TIMER=y - CONFIG_CLK=y - CONFIG_MSM_GPIO=y - CONFIG_PM8916_GPIO=y -+CONFIG_DM_KEYBOARD=y - CONFIG_LED=y - CONFIG_LED_GPIO=y - CONFIG_DM_MMC=y - CONFIG_MMC_SDHCI=y - CONFIG_MMC_SDHCI_MSM=y -+CONFIG_DM_ETH=y -+# CONFIG_NETDEVICES is not set - CONFIG_DM_PMIC=y - CONFIG_PMIC_PM8916=y - CONFIG_MSM_SERIAL=y -@@ -38,4 +42,11 @@ CONFIG_USB_EHCI_MSM=y - CONFIG_USB_ULPI_VIEWPORT=y - CONFIG_USB_ULPI=y - CONFIG_USB_STORAGE=y -+CONFIG_USB_KEYBOARD=y -+CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE=y -+CONFIG_DM_VIDEO=y -+# CONFIG_VIDEO_BPP8 is not set -+CONFIG_NO_FB_CLEAR=y -+CONFIG_VIDEO_SIMPLE=y -+CONFIG_FAT_WRITE=y - CONFIG_OF_LIBFDT_OVERLAY=y --- -2.13.3 - -From 4667c7da8cfb1883d5e734d1017b33e354e699eb Mon Sep 17 00:00:00 2001 -From: Rob Clark -Date: Fri, 21 Jul 2017 16:24:03 -0400 -Subject: [PATCH 11/23] db410c: enable r8152 usb eth - -Signed-off-by: Rob Clark ---- - include/configs/dragonboard410c.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/include/configs/dragonboard410c.h b/include/configs/dragonboard410c.h -index 626dff8dcd..bbc9685e0e 100644 ---- a/include/configs/dragonboard410c.h -+++ b/include/configs/dragonboard410c.h -@@ -44,6 +44,7 @@ - #define CONFIG_USB_ETHER_ASIX88179 - #define CONFIG_USB_ETHER_MCS7830 - #define CONFIG_USB_ETHER_SMSC95XX -+#define CONFIG_USB_ETHER_RTL8152 - - /* Extra Commands */ - /* Enable that for switching of boot partitions */ --- -2.13.3 - From 47f22a41df082c62411389ab5bf6e9ae26d93083 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 19 Jul 2017 10:39:12 -0400 @@ -764,3 +687,61 @@ index d2d29cc98f..703dd748f5 100644 -- 2.13.3 +From 2bf6ff0703fa92755469d8f218a75b07008e9768 Mon Sep 17 00:00:00 2001 +From: Peter Robinson +Date: Mon, 18 Sep 2017 09:34:30 +0100 +Subject: [PATCH] db410c: config updates + +Signed-off-by: Peter Robinson +--- + configs/dragonboard410c_defconfig | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/configs/dragonboard410c_defconfig b/configs/dragonboard410c_defconfig +index 2224b3850a..32efdfa46b 100644 +--- a/configs/dragonboard410c_defconfig ++++ b/configs/dragonboard410c_defconfig +@@ -10,6 +10,7 @@ CONFIG_BOOTARGS="console=ttyMSM0,115200n8" + CONFIG_SYS_PROMPT="dragonboard410c => " + # CONFIG_CMD_IMI is not set + # CONFIG_CMD_IMLS is not set ++CONFIG_CMD_POWEROFF=y + CONFIG_CMD_MD5SUM=y + CONFIG_CMD_MEMINFO=y + CONFIG_CMD_UNZIP=y +@@ -22,11 +23,14 @@ CONFIG_CMD_TIMER=y + CONFIG_CLK=y + CONFIG_MSM_GPIO=y + CONFIG_PM8916_GPIO=y ++CONFIG_DM_KEYBOARD=y + CONFIG_LED=y + CONFIG_LED_GPIO=y + CONFIG_DM_MMC=y + CONFIG_MMC_SDHCI=y + CONFIG_MMC_SDHCI_MSM=y ++CONFIG_DM_ETH=y ++# CONFIG_NETDEVICES is not set + CONFIG_DM_PMIC=y + CONFIG_PMIC_PM8916=y + CONFIG_MSM_SERIAL=y +@@ -39,9 +43,17 @@ CONFIG_USB_EHCI_MSM=y + CONFIG_USB_ULPI_VIEWPORT=y + CONFIG_USB_ULPI=y + CONFIG_USB_STORAGE=y ++CONFIG_USB_KEYBOARD=y + CONFIG_USB_HOST_ETHER=y + CONFIG_USB_ETHER_ASIX=y + CONFIG_USB_ETHER_ASIX88179=y + CONFIG_USB_ETHER_MCS7830=y ++CONFIG_USB_ETHER_RTL8152=y + CONFIG_USB_ETHER_SMSC95XX=y ++CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE=y ++CONFIG_DM_VIDEO=y ++# CONFIG_VIDEO_BPP8 is not set ++CONFIG_NO_FB_CLEAR=y ++CONFIG_VIDEO_SIMPLE=y ++CONFIG_FAT_WRITE=y + CONFIG_OF_LIBFDT_OVERLAY=y +-- +2.13.5 + diff --git a/env-Fix-out-of-tree-building-of-tools-all.patch b/env-Fix-out-of-tree-building-of-tools-all.patch deleted file mode 100644 index 277f1f1..0000000 --- a/env-Fix-out-of-tree-building-of-tools-all.patch +++ /dev/null @@ -1,69 +0,0 @@ -From patchwork Tue Sep 5 18:20:09 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [U-Boot] env: Fix out of tree building of tools-all -X-Patchwork-Submitter: Tom Rini -X-Patchwork-Id: 810244 -Message-Id: <1504635609-23585-1-git-send-email-trini@konsulko.com> -To: u-boot@lists.denx.de -Date: Tue, 5 Sep 2017 14:20:09 -0400 -From: Tom Rini -List-Id: U-Boot discussion - -With the move of environment code from common/ to env/ a number of -changes needed to be made to various make targets. We missed updating -some of the files required for out of tree builds of the tools. Correct -the 'environ' target to know that we need to work under tools/env/ still -(not tools/environ/) and then update the wrappers in env_attr.c and -env_flags.c to point to the new correct file. - -Reported-by: Peter Robinson -Signed-off-by: Tom Rini ---- - Makefile | 2 +- - tools/env/env_attr.c | 2 +- - tools/env/env_flags.c | 2 +- - tools/env/fw_env.c | 2 +- - 4 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/Makefile b/Makefile -index 792162521155..020ebd50ad22 100644 ---- a/Makefile -+++ b/Makefile -@@ -1466,7 +1466,7 @@ checkarmreloc: u-boot - fi - - environ: scripts_basic -- $(Q)$(MAKE) $(build)=tools/$@ -+ $(Q)$(MAKE) $(build)=tools/env - - tools-only: scripts_basic $(version_h) $(timestamp_h) - $(Q)$(MAKE) $(build)=tools -diff --git a/tools/env/env_attr.c b/tools/env/env_attr.c -index 502d4c900bf2..4d8536335c30 100644 ---- a/tools/env/env_attr.c -+++ b/tools/env/env_attr.c -@@ -1 +1 @@ --#include "../../common/env_attr.c" -+#include "../../env/attr.c" -diff --git a/tools/env/env_flags.c b/tools/env/env_flags.c -index b261cb8e3907..71e13e2021f6 100644 ---- a/tools/env/env_flags.c -+++ b/tools/env/env_flags.c -@@ -1 +1 @@ --#include "../../common/env_flags.c" -+#include "../../env/flags.c" -diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c -index 965e1662d702..ab06415898c2 100644 ---- a/tools/env/fw_env.c -+++ b/tools/env/fw_env.c -@@ -755,7 +755,7 @@ static int flash_read_buf (int dev, int fd, void *buf, size_t count, - - /* - * If a block is bad, we retry in the next block at the same -- * offset - see common/env_nand.c::writeenv() -+ * offset - see env/nand.c::writeenv() - */ - lseek (fd, blockstart + block_seek, SEEK_SET); - diff --git a/mvebu-enable-generic-distro-boot-config.patch b/mvebu-enable-generic-distro-boot-config.patch index 6f0ab06..51ec5b5 100644 --- a/mvebu-enable-generic-distro-boot-config.patch +++ b/mvebu-enable-generic-distro-boot-config.patch @@ -1,6 +1,6 @@ -From 09339c34eeab4a73d5dfa48034b6c8ae8a775c14 Mon Sep 17 00:00:00 2001 +From 8de891d0767aafb383b6f533b08a5c0b75b4718b Mon Sep 17 00:00:00 2001 From: Peter Robinson -Date: Tue, 14 Feb 2017 13:15:23 +0000 +Date: Mon, 18 Sep 2017 15:48:32 +0100 Subject: [PATCH] arm: mvebu: enable generic distro boot config Switch all of the mvebu boards to support disto generic booting @@ -8,33 +8,17 @@ This will enable Fedora, Debian and other distros to support mvebu systems easier. Tested on SolidRun ClearFog Signed-off-by: Dennis Gilmore +Signed-off-by: Peter Robinson --- - include/configs/clearfog.h | 5 --- include/configs/mv-common.h | 84 +++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 84 insertions(+), 5 deletions(-) + 1 file changed, 84 insertions(+) -diff --git a/include/configs/clearfog.h b/include/configs/clearfog.h -index 0c51d2a..0034604 100644 ---- a/include/configs/clearfog.h -+++ b/include/configs/clearfog.h -@@ -79,11 +79,6 @@ - - #define CONFIG_SYS_ALT_MEMTEST - --/* Keep device tree and initrd in lower memory so the kernel can access them */ --#define CONFIG_EXTRA_ENV_SETTINGS \ -- "fdt_high=0x10000000\0" \ -- "initrd_high=0x10000000\0" -- - /* SPL */ - /* - * Select the boot device here diff --git a/include/configs/mv-common.h b/include/configs/mv-common.h -index 25562fa..aebfabe 100644 +index 7c2bab2fc6..2819493fca 100644 --- a/include/configs/mv-common.h +++ b/include/configs/mv-common.h -@@ -139,4 +139,88 @@ - #define CONFIG_LZO +@@ -130,4 +130,88 @@ + #define CONFIG_MTD_PARTITIONS #endif +#ifndef CONFIG_SPL_BUILD @@ -123,5 +107,5 @@ index 25562fa..aebfabe 100644 + #endif /* _MV_COMMON_H */ -- -2.9.3 +2.13.5 diff --git a/rpi-Revert-dm-Drop-CONFIG_OF_EMBED.patch b/rpi-Revert-dm-Drop-CONFIG_OF_EMBED.patch deleted file mode 100644 index f53a81d..0000000 --- a/rpi-Revert-dm-Drop-CONFIG_OF_EMBED.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 2ae1d3eefc1850a37b9a2922da25b96784c5fbc1 Mon Sep 17 00:00:00 2001 -From: Peter Robinson -Date: Tue, 15 Aug 2017 11:17:47 +0100 -Subject: [PATCH] rpi: re-add CONFIG_OF_EMBED - -Signed-off-by: Peter Robinson ---- - configs/rpi_2_defconfig | 1 + - configs/rpi_3_32b_defconfig | 1 + - configs/rpi_3_defconfig | 1 + - configs/rpi_defconfig | 1 + - 4 files changed, 4 insertions(+) - -diff --git a/configs/rpi_2_defconfig b/configs/rpi_2_defconfig -index 63d1e4042d..98353d0683 100644 ---- a/configs/rpi_2_defconfig -+++ b/configs/rpi_2_defconfig -@@ -4,6 +4,7 @@ - CONFIG_DEFAULT_DEVICE_TREE="bcm2836-rpi-2-b" - CONFIG_DISTRO_DEFAULTS=y - CONFIG_OF_BOARD_SETUP=y -+CONFIG_OF_EMBED=y - # CONFIG_DISPLAY_CPUINFO is not set - # CONFIG_DISPLAY_BOARDINFO is not set - CONFIG_SYS_PROMPT="U-Boot> " -diff --git a/configs/rpi_3_32b_defconfig b/configs/rpi_3_32b_defconfig -index 343cb197a1..51009bccb9 100644 ---- a/configs/rpi_3_32b_defconfig -+++ b/configs/rpi_3_32b_defconfig -@@ -5,6 +5,7 @@ - CONFIG_DEFAULT_DEVICE_TREE="bcm2837-rpi-3-b" - CONFIG_DISTRO_DEFAULTS=y - CONFIG_OF_BOARD_SETUP=y -+CONFIG_OF_EMBED=y - # CONFIG_DISPLAY_CPUINFO is not set - # CONFIG_DISPLAY_BOARDINFO is not set - CONFIG_SYS_PROMPT="U-Boot> " -diff --git a/configs/rpi_3_defconfig b/configs/rpi_3_defconfig -index 6c9f2e32b5..c3c0185954 100644 ---- a/configs/rpi_3_defconfig -+++ b/configs/rpi_3_defconfig -@@ -5,6 +5,7 @@ - CONFIG_DEFAULT_DEVICE_TREE="bcm2837-rpi-3-b" - CONFIG_DISTRO_DEFAULTS=y - CONFIG_OF_BOARD_SETUP=y -+CONFIG_OF_EMBED=y - # CONFIG_DISPLAY_CPUINFO is not set - # CONFIG_DISPLAY_BOARDINFO is not set - CONFIG_SYS_PROMPT="U-Boot> " -diff --git a/configs/rpi_defconfig b/configs/rpi_defconfig -index 6b3cec5ce0..ad5be72510 100644 ---- a/configs/rpi_defconfig -+++ b/configs/rpi_defconfig -@@ -4,6 +4,7 @@ - CONFIG_DEFAULT_DEVICE_TREE="bcm2835-rpi-b" - CONFIG_DISTRO_DEFAULTS=y - CONFIG_OF_BOARD_SETUP=y -+CONFIG_OF_EMBED=y - # CONFIG_DISPLAY_CPUINFO is not set - # CONFIG_DISPLAY_BOARDINFO is not set - CONFIG_SYS_PROMPT="U-Boot> " --- -2.13.4 - diff --git a/sources b/sources index 59cf916..d111dc5 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (u-boot-2017.09-rc4.tar.bz2) = 3fbada7aab3208e5ec43fe675776da7d9a36acd793c84aadcd52bc6f18a040565e3d3639c0b1801a33a959ee56757331da4630f0de5fa7b46c7ae3b2666e5cf2 +SHA512 (u-boot-2017.09.tar.bz2) = dff6e793f135e7d6cb9d85d6ef8e4aa7ed5c1e20eece4f434e8c0a6039eb75c3f2cb7bc550121b1f5a5709e943c7cc5d6d8590e05a47a6b0d0d8f05185fe7ec6 diff --git a/sunxi-dm-pine64.patch b/sunxi-dm-pine64.patch deleted file mode 100644 index ac05f5f..0000000 --- a/sunxi-dm-pine64.patch +++ /dev/null @@ -1,51 +0,0 @@ -From d667f43d25d9c7fe48bc9d163dc9c9e062361acb Mon Sep 17 00:00:00 2001 -From: Peter Robinson -Date: Thu, 17 Aug 2017 11:55:55 +0100 -Subject: [PATCH] pine64 use DM mmc - -Signed-off-by: Peter Robinson ---- - configs/pine64_plus_defconfig | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/configs/pine64_plus_defconfig b/configs/pine64_plus_defconfig -index a509ca92b2..da3663fbb1 100644 ---- a/configs/pine64_plus_defconfig -+++ b/configs/pine64_plus_defconfig -@@ -14,3 +14,9 @@ CONFIG_SPL=y - CONFIG_OF_LIST="sun50i-a64-pine64 sun50i-a64-pine64-plus" - CONFIG_SUN8I_EMAC=y - CONFIG_USB_EHCI_HCD=y -+# CONFIG_SPL_BLK is not set -+CONFIG_DM_MMC=y -+# CONFIG_SPL_DM_MMC is not set -+# CONFIG_SPL_DM_MMC_OPS is not set -+CONFIG_SCSI=y -+CONFIG_DM_SCSI=y --- -2.13.5 - -From d1569782c6fe336577d801ea8c9300e63eb3e9c1 Mon Sep 17 00:00:00 2001 -From: Peter Robinson -Date: Thu, 17 Aug 2017 12:01:59 +0100 -Subject: [PATCH] add mmc - ---- - configs/pine64_plus_defconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/configs/pine64_plus_defconfig b/configs/pine64_plus_defconfig -index da3663fbb1..78f9cfe21d 100644 ---- a/configs/pine64_plus_defconfig -+++ b/configs/pine64_plus_defconfig -@@ -15,6 +15,7 @@ CONFIG_OF_LIST="sun50i-a64-pine64 sun50i-a64-pine64-plus" - CONFIG_SUN8I_EMAC=y - CONFIG_USB_EHCI_HCD=y - # CONFIG_SPL_BLK is not set -+CONFIG_MMC=y - CONFIG_DM_MMC=y - # CONFIG_SPL_DM_MMC is not set - # CONFIG_SPL_DM_MMC_OPS is not set --- -2.13.5 - diff --git a/uboot-tools.spec b/uboot-tools.spec index 6a717cc..6272daa 100644 --- a/uboot-tools.spec +++ b/uboot-tools.spec @@ -1,8 +1,8 @@ -%global candidate rc4 +#global candidate rc4 Name: uboot-tools Version: 2017.09 -Release: 0.6%{?candidate:.%{candidate}}%{?dist} +Release: 1%{?candidate:.%{candidate}}%{?dist} Summary: U-Boot utilities License: GPLv2+ BSD LGPL-2.1+ LGPL-2.0+ URL: http://www.denx.de/wiki/U-Boot @@ -14,19 +14,17 @@ Source3: aarch64-boards Source4: aarch64-chromebooks # Fedoraisms patches, general fixes -Patch1: uefi-use-Fedora-specific-path-name.patch -Patch2: uefi-fixes.patch -Patch3: env-Fix-out-of-tree-building-of-tools-all.patch +Patch1: uefi-vsprintf.patch +Patch2: uefi-improve-fat.patch +Patch3: uefi-efi_loader-enough-UEFI-for-standard-distro-boot.patch +Patch4: uefi-use-Fedora-specific-path-name.patch # Board fixes and enablement Patch10: dragonboard-fixes.patch -Patch11: rpi-Revert-dm-Drop-CONFIG_OF_EMBED.patch -Patch12: qemu-machine-virt-ARM.patch -Patch13: sti-STiH410-B2260-support.patch - +Patch11: qemu-machine-virt-ARM.patch +Patch12: sti-STiH410-B2260-support.patch +Patch13: mvebu-enable-generic-distro-boot-config.patch # Patch15: mx6-Initial-Hummingboard-2-support.patch -# Patch16: sunxi-dm-pine64.patch -# Patch17: mvebu-enable-generic-distro-boot-config.patch BuildRequires: bc BuildRequires: dtc @@ -278,6 +276,9 @@ cp -p board/warp7/README builds/docs/README.warp7 %endif %changelog +* Mon Sep 18 2017 Peter Robinson 2017.09-1 +- 2017.09 + * Tue Sep 12 2017 Than Ngo - 2017.09-0.6.rc4 - fixed the check for rockchip rk3368 boards diff --git a/uefi-efi_loader-enough-UEFI-for-standard-distro-boot.patch b/uefi-efi_loader-enough-UEFI-for-standard-distro-boot.patch new file mode 100644 index 0000000..4ab5dbc --- /dev/null +++ b/uefi-efi_loader-enough-UEFI-for-standard-distro-boot.patch @@ -0,0 +1,4423 @@ +From patchwork Wed Sep 13 22:05:24 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot,v3,01/21] part: move efi_guid_t +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813637 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-2-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Petr Kulhavy , Heinrich Schuchardt , + Alison Chaiken , + Steve Rae , + Maxime Ripard +Date: Wed, 13 Sep 2017 18:05:24 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +Prep work for next patch. + +Signed-off-by: Rob Clark +Reviewed-by: Heinrich Schuchardt +--- + include/efi.h | 4 ++++ + include/part.h | 3 ++- + include/part_efi.h | 4 ---- + 3 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/include/efi.h b/include/efi.h +index 02b78b31b1..87b0b43f20 100644 +--- a/include/efi.h ++++ b/include/efi.h +@@ -28,6 +28,10 @@ + + struct efi_device_path; + ++typedef struct { ++ u8 b[16]; ++} efi_guid_t; ++ + #define EFI_BITS_PER_LONG BITS_PER_LONG + + /* +diff --git a/include/part.h b/include/part.h +index 86117a7ce5..b2e820ef8a 100644 +--- a/include/part.h ++++ b/include/part.h +@@ -280,8 +280,9 @@ struct part_driver { + #define U_BOOT_PART_TYPE(__name) \ + ll_entry_declare(struct part_driver, __name, part_driver) + +-#if CONFIG_IS_ENABLED(EFI_PARTITION) + #include ++ ++#if CONFIG_IS_ENABLED(EFI_PARTITION) + /* disk/part_efi.c */ + /** + * write_gpt_table() - Write the GUID Partition Table to disk +diff --git a/include/part_efi.h b/include/part_efi.h +index 317c044795..31e6bc6e14 100644 +--- a/include/part_efi.h ++++ b/include/part_efi.h +@@ -58,10 +58,6 @@ + /* linux/include/efi.h */ + typedef u16 efi_char16_t; + +-typedef struct { +- u8 b[16]; +-} efi_guid_t; +- + /* based on linux/include/genhd.h */ + struct partition { + u8 boot_ind; /* 0x80 - active */ + +From patchwork Wed Sep 13 22:05:25 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot,v3,02/21] part: extract MBR signature from partitions +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813639 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-3-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Petr Kulhavy , Heinrich Schuchardt , + Wenbin Song , + Alison Chaiken , Peter Jones , + Vincent Tinelli , + Steve Rae , + Maxime Ripard +Date: Wed, 13 Sep 2017 18:05:25 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +From: Peter Jones + +EFI client programs need the signature information from the partition +table to determine the disk a partition is on, so we need to fill that +in here. + +Signed-off-by: Peter Jones +[separated from efi_loader part, and fixed build-errors for non- + CONFIG_EFI_PARTITION case] +Signed-off-by: Rob Clark +--- + disk/part_dos.c | 12 +++++++++--- + disk/part_efi.c | 20 ++++++++++++++++++++ + include/blk.h | 18 ++++++++++++++++++ + 3 files changed, 47 insertions(+), 3 deletions(-) + +diff --git a/disk/part_dos.c b/disk/part_dos.c +index 7ede15ec26..850a538e83 100644 +--- a/disk/part_dos.c ++++ b/disk/part_dos.c +@@ -89,14 +89,20 @@ static int test_block_type(unsigned char *buffer) + + static int part_test_dos(struct blk_desc *dev_desc) + { +- ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz); ++ ALLOC_CACHE_ALIGN_BUFFER(legacy_mbr, mbr, dev_desc->blksz); + +- if (blk_dread(dev_desc, 0, 1, (ulong *)buffer) != 1) ++ if (blk_dread(dev_desc, 0, 1, (ulong *)mbr) != 1) + return -1; + +- if (test_block_type(buffer) != DOS_MBR) ++ if (test_block_type((unsigned char *)mbr) != DOS_MBR) + return -1; + ++ if (dev_desc->sig_type == SIG_TYPE_NONE && ++ mbr->unique_mbr_signature != 0) { ++ dev_desc->sig_type = SIG_TYPE_MBR; ++ dev_desc->mbr_sig = mbr->unique_mbr_signature; ++ } ++ + return 0; + } + +diff --git a/disk/part_efi.c b/disk/part_efi.c +index 2973d52f6a..208bb14ee8 100644 +--- a/disk/part_efi.c ++++ b/disk/part_efi.c +@@ -923,11 +923,19 @@ static int is_pmbr_valid(legacy_mbr * mbr) + static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba, + gpt_header *pgpt_head, gpt_entry **pgpt_pte) + { ++ ALLOC_CACHE_ALIGN_BUFFER(legacy_mbr, mbr, dev_desc->blksz); ++ + if (!dev_desc || !pgpt_head) { + printf("%s: Invalid Argument(s)\n", __func__); + return 0; + } + ++ /* Read MBR Header from device */ ++ if (blk_dread(dev_desc, 0, 1, (ulong *)mbr) != 1) { ++ printf("*** ERROR: Can't read MBR header ***\n"); ++ return 0; ++ } ++ + /* Read GPT Header from device */ + if (blk_dread(dev_desc, (lbaint_t)lba, 1, pgpt_head) != 1) { + printf("*** ERROR: Can't read GPT header ***\n"); +@@ -937,6 +945,18 @@ static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba, + if (validate_gpt_header(pgpt_head, (lbaint_t)lba, dev_desc->lba)) + return 0; + ++ if (dev_desc->sig_type == SIG_TYPE_NONE) { ++ efi_guid_t empty = {}; ++ if (memcmp(&pgpt_head->disk_guid, &empty, sizeof(empty))) { ++ dev_desc->sig_type = SIG_TYPE_GUID; ++ memcpy(&dev_desc->guid_sig, &pgpt_head->disk_guid, ++ sizeof(empty)); ++ } else if (mbr->unique_mbr_signature != 0) { ++ dev_desc->sig_type = SIG_TYPE_MBR; ++ dev_desc->mbr_sig = mbr->unique_mbr_signature; ++ } ++ } ++ + /* Read and allocate Partition Table Entries */ + *pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head); + if (*pgpt_pte == NULL) { +diff --git a/include/blk.h b/include/blk.h +index 1965812a9d..41b4d7efa8 100644 +--- a/include/blk.h ++++ b/include/blk.h +@@ -8,6 +8,8 @@ + #ifndef BLK_H + #define BLK_H + ++#include ++ + #ifdef CONFIG_SYS_64BIT_LBA + typedef uint64_t lbaint_t; + #define LBAFlength "ll" +@@ -41,6 +43,17 @@ enum if_type { + #define BLK_REV_SIZE 8 + + /* ++ * Identifies the partition table type (ie. MBR vs GPT GUID) signature ++ */ ++enum sig_type { ++ SIG_TYPE_NONE, ++ SIG_TYPE_MBR, ++ SIG_TYPE_GUID, ++ ++ SIG_TYPE_COUNT /* Number of signature types */ ++}; ++ ++/* + * With driver model (CONFIG_BLK) this is uclass platform data, accessible + * with dev_get_uclass_platdata(dev) + */ +@@ -67,6 +80,11 @@ struct blk_desc { + char vendor[BLK_VEN_SIZE + 1]; /* device vendor string */ + char product[BLK_PRD_SIZE + 1]; /* device product number */ + char revision[BLK_REV_SIZE + 1]; /* firmware revision */ ++ enum sig_type sig_type; /* Partition table signature type */ ++ union { ++ uint32_t mbr_sig; /* MBR integer signature */ ++ efi_guid_t guid_sig; /* GPT GUID Signature */ ++ }; + #if CONFIG_IS_ENABLED(BLK) + /* + * For now we have a few functions which take struct blk_desc as a + +From patchwork Wed Sep 13 22:05:26 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot,v3,03/21] efi: add some missing __packed +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813645 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-4-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt , Peter Jones +Date: Wed, 13 Sep 2017 18:05:26 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +All of the device-path related structures should be packed. UEFI +defines the device-path as a byte-aligned data structure. + +Signed-off-by: Rob Clark +--- + include/efi_api.h | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/include/efi_api.h b/include/efi_api.h +index ec1b321e8e..175341348e 100644 +--- a/include/efi_api.h ++++ b/include/efi_api.h +@@ -284,11 +284,11 @@ struct efi_device_path { + u8 type; + u8 sub_type; + u16 length; +-}; ++} __packed; + + struct efi_mac_addr { + u8 addr[32]; +-}; ++} __packed; + + #define DEVICE_PATH_TYPE_MESSAGING_DEVICE 0x03 + # define DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR 0x0b +@@ -297,7 +297,7 @@ struct efi_device_path_mac_addr { + struct efi_device_path dp; + struct efi_mac_addr mac; + u8 if_type; +-}; ++} __packed; + + #define DEVICE_PATH_TYPE_MEDIA_DEVICE 0x04 + # define DEVICE_PATH_SUB_TYPE_FILE_PATH 0x04 +@@ -305,7 +305,7 @@ struct efi_device_path_mac_addr { + struct efi_device_path_file_path { + struct efi_device_path dp; + u16 str[32]; +-}; ++} __packed; + + #define BLOCK_IO_GUID \ + EFI_GUID(0x964e5b21, 0x6459, 0x11d2, \ + +From patchwork Wed Sep 13 22:05:27 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot,v3,04/21] efi: add some more device path structures +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813638 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-5-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt , Peter Jones +Date: Wed, 13 Sep 2017 18:05:27 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +From: Peter Jones + +Signed-off-by: Peter Jones +Signed-off-by: Rob Clark +--- + include/efi_api.h | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 54 insertions(+) + +diff --git a/include/efi_api.h b/include/efi_api.h +index 175341348e..b761cf4822 100644 +--- a/include/efi_api.h ++++ b/include/efi_api.h +@@ -290,8 +290,38 @@ struct efi_mac_addr { + u8 addr[32]; + } __packed; + ++#define DEVICE_PATH_TYPE_HARDWARE_DEVICE 0x01 ++# define DEVICE_PATH_SUB_TYPE_VENDOR 0x04 ++ ++struct efi_device_path_vendor { ++ struct efi_device_path dp; ++ efi_guid_t guid; ++ u8 vendor_data[]; ++} __packed; ++ ++#define DEVICE_PATH_TYPE_ACPI_DEVICE 0x02 ++# define DEVICE_PATH_SUB_TYPE_ACPI_DEVICE 0x01 ++ ++#define EFI_PNP_ID(ID) (u32)(((ID) << 16) | 0x41D0) ++#define EISA_PNP_ID(ID) EFI_PNP_ID(ID) ++ ++struct efi_device_path_acpi_path { ++ struct efi_device_path dp; ++ u32 hid; ++ u32 uid; ++} __packed; ++ + #define DEVICE_PATH_TYPE_MESSAGING_DEVICE 0x03 ++# define DEVICE_PATH_SUB_TYPE_MSG_USB 0x05 + # define DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR 0x0b ++# define DEVICE_PATH_SUB_TYPE_MSG_SD 0x1a ++# define DEVICE_PATH_SUB_TYPE_MSG_MMC 0x1d ++ ++struct efi_device_path_usb { ++ struct efi_device_path dp; ++ u8 parent_port_number; ++ u8 usb_interface; ++} __packed; + + struct efi_device_path_mac_addr { + struct efi_device_path dp; +@@ -299,9 +329,33 @@ struct efi_device_path_mac_addr { + u8 if_type; + } __packed; + ++struct efi_device_path_sd_mmc_path { ++ struct efi_device_path dp; ++ u8 slot_number; ++} __packed; ++ + #define DEVICE_PATH_TYPE_MEDIA_DEVICE 0x04 ++# define DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH 0x01 ++# define DEVICE_PATH_SUB_TYPE_CDROM_PATH 0x02 + # define DEVICE_PATH_SUB_TYPE_FILE_PATH 0x04 + ++struct efi_device_path_hard_drive_path { ++ struct efi_device_path dp; ++ u32 partition_number; ++ u64 partition_start; ++ u64 partition_end; ++ u8 partition_signature[16]; ++ u8 partmap_type; ++ u8 signature_type; ++} __packed; ++ ++struct efi_device_path_cdrom_path { ++ struct efi_device_path dp; ++ u32 boot_entry; ++ u64 partition_start; ++ u64 partition_end; ++} __packed; ++ + struct efi_device_path_file_path { + struct efi_device_path dp; + u16 str[32]; + +From patchwork Wed Sep 13 22:05:28 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot,v3,05/21] efi_loader: add device-path utils +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813641 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-6-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt , Peter Jones +Date: Wed, 13 Sep 2017 18:05:28 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +Helpers to construct device-paths from devices, partitions, files, and +for parsing and manipulating device-paths. + +For non-legacy devices, this will use u-boot's device-model to construct +device-paths which include bus hierarchy to construct device-paths. For +legacy devices we still fake it, but slightly more convincingly. + +Signed-off-by: Rob Clark +--- + include/efi_api.h | 10 + + include/efi_loader.h | 26 ++ + lib/efi_loader/Makefile | 2 +- + lib/efi_loader/efi_boottime.c | 13 +- + lib/efi_loader/efi_device_path.c | 563 +++++++++++++++++++++++++++++++++++++++ + 5 files changed, 611 insertions(+), 3 deletions(-) + create mode 100644 lib/efi_loader/efi_device_path.c + +diff --git a/include/efi_api.h b/include/efi_api.h +index b761cf4822..4e27c82129 100644 +--- a/include/efi_api.h ++++ b/include/efi_api.h +@@ -314,6 +314,7 @@ struct efi_device_path_acpi_path { + #define DEVICE_PATH_TYPE_MESSAGING_DEVICE 0x03 + # define DEVICE_PATH_SUB_TYPE_MSG_USB 0x05 + # define DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR 0x0b ++# define DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS 0x0f + # define DEVICE_PATH_SUB_TYPE_MSG_SD 0x1a + # define DEVICE_PATH_SUB_TYPE_MSG_MMC 0x1d + +@@ -329,6 +330,15 @@ struct efi_device_path_mac_addr { + u8 if_type; + } __packed; + ++struct efi_device_path_usb_class { ++ struct efi_device_path dp; ++ u16 vendor_id; ++ u16 product_id; ++ u8 device_class; ++ u8 device_subclass; ++ u8 device_protocol; ++} __packed; ++ + struct efi_device_path_sd_mmc_path { + struct efi_device_path dp; + u8 slot_number; +diff --git a/include/efi_loader.h b/include/efi_loader.h +index 1179234f68..d052b03ab7 100644 +--- a/include/efi_loader.h ++++ b/include/efi_loader.h +@@ -197,6 +197,32 @@ extern void *efi_bounce_buffer; + #define EFI_LOADER_BOUNCE_BUFFER_SIZE (64 * 1024 * 1024) + #endif + ++ ++struct efi_device_path *efi_dp_next(const struct efi_device_path *dp); ++int efi_dp_match(struct efi_device_path *a, struct efi_device_path *b); ++struct efi_object *efi_dp_find_obj(struct efi_device_path *dp, ++ struct efi_device_path **rem); ++unsigned efi_dp_size(const struct efi_device_path *dp); ++struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp); ++struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1, ++ const struct efi_device_path *dp2); ++struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp, ++ const struct efi_device_path *node); ++ ++ ++struct efi_device_path *efi_dp_from_dev(struct udevice *dev); ++struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part); ++struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part, ++ const char *path); ++struct efi_device_path *efi_dp_from_eth(void); ++void efi_dp_split_file_path(struct efi_device_path *full_path, ++ struct efi_device_path **device_path, ++ struct efi_device_path **file_path); ++ ++#define EFI_DP_TYPE(_dp, _type, _subtype) \ ++ (((_dp)->type == DEVICE_PATH_TYPE_##_type) && \ ++ ((_dp)->sub_type == DEVICE_PATH_SUB_TYPE_##_subtype)) ++ + /* Convert strings from normal C strings to uEFI strings */ + static inline void ascii2unicode(u16 *unicode, const char *ascii) + { +diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile +index 30bf343a36..f35e5ce8a8 100644 +--- a/lib/efi_loader/Makefile ++++ b/lib/efi_loader/Makefile +@@ -15,7 +15,7 @@ always := $(efiprogs-y) + + obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o + obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o +-obj-y += efi_memory.o efi_device_path_to_text.o ++obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o + obj-$(CONFIG_LCD) += efi_gop.o + obj-$(CONFIG_DM_VIDEO) += efi_gop.o + obj-$(CONFIG_PARTITIONS) += efi_disk.o +diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c +index 43f32385fa..b962b62a97 100644 +--- a/lib/efi_loader/efi_boottime.c ++++ b/lib/efi_loader/efi_boottime.c +@@ -665,8 +665,17 @@ static efi_status_t EFIAPI efi_locate_device_path(efi_guid_t *protocol, + struct efi_device_path **device_path, + efi_handle_t *device) + { +- EFI_ENTRY("%p, %p, %p", protocol, device_path, device); +- return EFI_EXIT(EFI_NOT_FOUND); ++ struct efi_object *efiobj; ++ ++ EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device); ++ ++ efiobj = efi_dp_find_obj(*device_path, device_path); ++ if (!efiobj) ++ return EFI_EXIT(EFI_NOT_FOUND); ++ ++ *device = efiobj->handle; ++ ++ return EFI_EXIT(EFI_SUCCESS); + } + + /* Collapses configuration table entries, removing index i */ +diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c +new file mode 100644 +index 0000000000..5d5c3b3464 +--- /dev/null ++++ b/lib/efi_loader/efi_device_path.c +@@ -0,0 +1,563 @@ ++/* ++ * EFI device path from u-boot device-model mapping ++ * ++ * (C) Copyright 2017 Rob Clark ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* template END node: */ ++static const struct efi_device_path END = { ++ .type = DEVICE_PATH_TYPE_END, ++ .sub_type = DEVICE_PATH_SUB_TYPE_END, ++ .length = sizeof(END), ++}; ++ ++#define U_BOOT_GUID \ ++ EFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \ ++ 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b) ++ ++/* template ROOT node: */ ++static const struct efi_device_path_vendor ROOT = { ++ .dp = { ++ .type = DEVICE_PATH_TYPE_HARDWARE_DEVICE, ++ .sub_type = DEVICE_PATH_SUB_TYPE_VENDOR, ++ .length = sizeof(ROOT), ++ }, ++ .guid = U_BOOT_GUID, ++}; ++ ++static void *dp_alloc(size_t sz) ++{ ++ void *buf; ++ ++ if (efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, sz, &buf) != EFI_SUCCESS) ++ return NULL; ++ ++ return buf; ++} ++ ++/* ++ * Iterate to next block in device-path, terminating (returning NULL) ++ * at /End* node. ++ */ ++struct efi_device_path *efi_dp_next(const struct efi_device_path *dp) ++{ ++ if (dp == NULL) ++ return NULL; ++ if (dp->type == DEVICE_PATH_TYPE_END) ++ return NULL; ++ dp = ((void *)dp) + dp->length; ++ if (dp->type == DEVICE_PATH_TYPE_END) ++ return NULL; ++ return (struct efi_device_path *)dp; ++} ++ ++/* ++ * Compare two device-paths, stopping when the shorter of the two hits ++ * an End* node. This is useful to, for example, compare a device-path ++ * representing a device with one representing a file on the device, or ++ * a device with a parent device. ++ */ ++int efi_dp_match(struct efi_device_path *a, struct efi_device_path *b) ++{ ++ while (1) { ++ int ret; ++ ++ ret = memcmp(&a->length, &b->length, sizeof(a->length)); ++ if (ret) ++ return ret; ++ ++ ret = memcmp(a, b, a->length); ++ if (ret) ++ return ret; ++ ++ a = efi_dp_next(a); ++ b = efi_dp_next(b); ++ ++ if (!a || !b) ++ return 0; ++ } ++} ++ ++ ++/* ++ * See UEFI spec (section 3.1.2, about short-form device-paths.. ++ * tl;dr: we can have a device-path that starts with a USB WWID ++ * or USB Class node, and a few other cases which don't encode ++ * the full device path with bus hierarchy: ++ * ++ * - MESSAGING:USB_WWID ++ * - MESSAGING:USB_CLASS ++ * - MEDIA:FILE_PATH ++ * - MEDIA:HARD_DRIVE ++ * - MESSAGING:URI ++ */ ++static struct efi_device_path *shorten_path(struct efi_device_path *dp) ++{ ++ while (dp) { ++ /* ++ * TODO: Add MESSAGING:USB_WWID and MESSAGING:URI.. ++ * in practice fallback.efi just uses MEDIA:HARD_DRIVE ++ * so not sure when we would see these other cases. ++ */ ++ if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_CLASS) || ++ EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) || ++ EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH)) ++ return dp; ++ ++ dp = efi_dp_next(dp); ++ } ++ ++ return dp; ++} ++ ++static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path, ++ struct efi_device_path **rem) ++{ ++ struct efi_object *efiobj; ++ ++ list_for_each_entry(efiobj, &efi_obj_list, link) { ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { ++ struct efi_handler *handler = &efiobj->protocols[i]; ++ struct efi_device_path *obj_dp; ++ ++ if (!handler->guid) ++ break; ++ ++ if (guidcmp(handler->guid, &efi_guid_device_path)) ++ continue; ++ ++ obj_dp = handler->protocol_interface; ++ ++ do { ++ if (efi_dp_match(dp, obj_dp) == 0) { ++ if (rem) { ++ *rem = ((void *)dp) + ++ efi_dp_size(obj_dp); ++ } ++ return efiobj; ++ } ++ ++ obj_dp = shorten_path(efi_dp_next(obj_dp)); ++ } while (short_path && obj_dp); ++ } ++ } ++ ++ return NULL; ++} ++ ++ ++/* ++ * Find an efiobj from device-path, if 'rem' is not NULL, returns the ++ * remaining part of the device path after the matched object. ++ */ ++struct efi_object *efi_dp_find_obj(struct efi_device_path *dp, ++ struct efi_device_path **rem) ++{ ++ struct efi_object *efiobj; ++ ++ efiobj = find_obj(dp, false, rem); ++ ++ if (!efiobj) ++ efiobj = find_obj(dp, true, rem); ++ ++ return efiobj; ++} ++ ++/* return size not including End node: */ ++unsigned efi_dp_size(const struct efi_device_path *dp) ++{ ++ unsigned sz = 0; ++ ++ while (dp) { ++ sz += dp->length; ++ dp = efi_dp_next(dp); ++ } ++ ++ return sz; ++} ++ ++struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp) ++{ ++ struct efi_device_path *ndp; ++ unsigned sz = efi_dp_size(dp) + sizeof(END); ++ ++ if (!dp) ++ return NULL; ++ ++ ndp = dp_alloc(sz); ++ memcpy(ndp, dp, sz); ++ ++ return ndp; ++} ++ ++struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1, ++ const struct efi_device_path *dp2) ++{ ++ struct efi_device_path *ret; ++ ++ if (!dp1) { ++ ret = efi_dp_dup(dp2); ++ } else if (!dp2) { ++ ret = efi_dp_dup(dp1); ++ } else { ++ /* both dp1 and dp2 are non-null */ ++ unsigned sz1 = efi_dp_size(dp1); ++ unsigned sz2 = efi_dp_size(dp2); ++ void *p = dp_alloc(sz1 + sz2 + sizeof(END)); ++ memcpy(p, dp1, sz1); ++ memcpy(p + sz1, dp2, sz2); ++ memcpy(p + sz1 + sz2, &END, sizeof(END)); ++ ret = p; ++ } ++ ++ return ret; ++} ++ ++struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp, ++ const struct efi_device_path *node) ++{ ++ struct efi_device_path *ret; ++ ++ if (!node && !dp) { ++ ret = efi_dp_dup(&END); ++ } else if (!node) { ++ ret = efi_dp_dup(dp); ++ } else if (!dp) { ++ unsigned sz = node->length; ++ void *p = dp_alloc(sz + sizeof(END)); ++ memcpy(p, node, sz); ++ memcpy(p + sz, &END, sizeof(END)); ++ ret = p; ++ } else { ++ /* both dp and node are non-null */ ++ unsigned sz = efi_dp_size(dp); ++ void *p = dp_alloc(sz + node->length + sizeof(END)); ++ memcpy(p, dp, sz); ++ memcpy(p + sz, node, node->length); ++ memcpy(p + sz + node->length, &END, sizeof(END)); ++ ret = p; ++ } ++ ++ return ret; ++} ++ ++#ifdef CONFIG_DM ++/* size of device-path not including END node for device and all parents ++ * up to the root device. ++ */ ++static unsigned dp_size(struct udevice *dev) ++{ ++ if (!dev || !dev->driver) ++ return sizeof(ROOT); ++ ++ switch (dev->driver->id) { ++ case UCLASS_ROOT: ++ case UCLASS_SIMPLE_BUS: ++ /* stop traversing parents at this point: */ ++ return sizeof(ROOT); ++ case UCLASS_MMC: ++ return dp_size(dev->parent) + ++ sizeof(struct efi_device_path_sd_mmc_path); ++ case UCLASS_MASS_STORAGE: ++ case UCLASS_USB_HUB: ++ return dp_size(dev->parent) + ++ sizeof(struct efi_device_path_usb_class); ++ default: ++ /* just skip over unknown classes: */ ++ return dp_size(dev->parent); ++ } ++} ++ ++static void *dp_fill(void *buf, struct udevice *dev) ++{ ++ if (!dev || !dev->driver) ++ return buf; ++ ++ switch (dev->driver->id) { ++ case UCLASS_ROOT: ++ case UCLASS_SIMPLE_BUS: { ++ /* stop traversing parents at this point: */ ++ struct efi_device_path_vendor *vdp = buf; ++ *vdp = ROOT; ++ return &vdp[1]; ++ } ++#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC) ++ case UCLASS_MMC: { ++ struct efi_device_path_sd_mmc_path *sddp = ++ dp_fill(buf, dev->parent); ++ struct mmc *mmc = mmc_get_mmc_dev(dev); ++ struct blk_desc *desc = mmc_get_blk_desc(mmc); ++ ++ sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; ++ sddp->dp.sub_type = (desc->if_type == IF_TYPE_MMC) ? ++ DEVICE_PATH_SUB_TYPE_MSG_MMC : ++ DEVICE_PATH_SUB_TYPE_MSG_SD; ++ sddp->dp.length = sizeof(*sddp); ++ sddp->slot_number = dev->seq; ++ ++ return &sddp[1]; ++ } ++#endif ++ case UCLASS_MASS_STORAGE: ++ case UCLASS_USB_HUB: { ++ struct efi_device_path_usb_class *udp = ++ dp_fill(buf, dev->parent); ++ struct usb_device *udev = dev_get_parent_priv(dev); ++ struct usb_device_descriptor *desc = &udev->descriptor; ++ ++ udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; ++ udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS; ++ udp->dp.length = sizeof(*udp); ++ udp->vendor_id = desc->idVendor; ++ udp->product_id = desc->idProduct; ++ udp->device_class = desc->bDeviceClass; ++ udp->device_subclass = desc->bDeviceSubClass; ++ udp->device_protocol = desc->bDeviceProtocol; ++ ++ return &udp[1]; ++ } ++ default: ++ debug("unhandled device class: %s (%u)\n", ++ dev->name, dev->driver->id); ++ return dp_fill(buf, dev->parent); ++ } ++} ++ ++/* Construct a device-path from a device: */ ++struct efi_device_path *efi_dp_from_dev(struct udevice *dev) ++{ ++ void *buf, *start; ++ ++ start = buf = dp_alloc(dp_size(dev) + sizeof(END)); ++ buf = dp_fill(buf, dev); ++ *((struct efi_device_path *)buf) = END; ++ ++ return start; ++} ++#endif ++ ++static unsigned dp_part_size(struct blk_desc *desc, int part) ++{ ++ unsigned dpsize; ++ ++#ifdef CONFIG_BLK ++ dpsize = dp_size(desc->bdev->parent); ++#else ++ dpsize = sizeof(ROOT) + sizeof(struct efi_device_path_usb); ++#endif ++ ++ if (part == 0) /* the actual disk, not a partition */ ++ return dpsize; ++ ++ if (desc->part_type == PART_TYPE_ISO) ++ dpsize += sizeof(struct efi_device_path_cdrom_path); ++ else ++ dpsize += sizeof(struct efi_device_path_hard_drive_path); ++ ++ return dpsize; ++} ++ ++static void *dp_part_fill(void *buf, struct blk_desc *desc, int part) ++{ ++ disk_partition_t info; ++ ++#ifdef CONFIG_BLK ++ buf = dp_fill(buf, desc->bdev->parent); ++#else ++ /* ++ * We *could* make a more accurate path, by looking at if_type ++ * and handling all the different cases like we do for non- ++ * legacy (ie CONFIG_BLK=y) case. But most important thing ++ * is just to have a unique device-path for if_type+devnum. ++ * So map things to a fictional USB device: ++ */ ++ struct efi_device_path_usb *udp; ++ ++ memcpy(buf, &ROOT, sizeof(ROOT)); ++ buf += sizeof(ROOT); ++ ++ udp = buf; ++ udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; ++ udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB; ++ udp->dp.length = sizeof(*udp); ++ udp->parent_port_number = desc->if_type; ++ udp->usb_interface = desc->devnum; ++ buf = &udp[1]; ++#endif ++ ++ if (part == 0) /* the actual disk, not a partition */ ++ return buf; ++ ++ part_get_info(desc, part, &info); ++ ++ if (desc->part_type == PART_TYPE_ISO) { ++ struct efi_device_path_cdrom_path *cddp = buf; ++ ++ cddp->boot_entry = part - 1; ++ cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; ++ cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH; ++ cddp->dp.length = sizeof(*cddp); ++ cddp->partition_start = info.start; ++ cddp->partition_end = info.size; ++ ++ buf = &cddp[1]; ++ } else { ++ struct efi_device_path_hard_drive_path *hddp = buf; ++ ++ hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; ++ hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH; ++ hddp->dp.length = sizeof(*hddp); ++ hddp->partition_number = part - 1; ++ hddp->partition_start = info.start; ++ hddp->partition_end = info.size; ++ if (desc->part_type == PART_TYPE_EFI) ++ hddp->partmap_type = 2; ++ else ++ hddp->partmap_type = 1; ++ hddp->signature_type = desc->sig_type; ++ if (hddp->signature_type != 0) ++ memcpy(hddp->partition_signature, &desc->guid_sig, ++ sizeof(hddp->partition_signature)); ++ ++ buf = &hddp[1]; ++ } ++ ++ return buf; ++} ++ ++ ++/* Construct a device-path from a partition on a blk device: */ ++struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part) ++{ ++ void *buf, *start; ++ ++ start = buf = dp_alloc(dp_part_size(desc, part) + sizeof(END)); ++ ++ buf = dp_part_fill(buf, desc, part); ++ ++ *((struct efi_device_path *)buf) = END; ++ ++ return start; ++} ++ ++/* convert path to an UEFI style path (ie. DOS style backslashes and utf16) */ ++static void path_to_uefi(u16 *uefi, const char *path) ++{ ++ while (*path) { ++ char c = *(path++); ++ if (c == '/') ++ c = '\\'; ++ *(uefi++) = c; ++ } ++ *uefi = '\0'; ++} ++ ++/* ++ * If desc is NULL, this creates a path with only the file component, ++ * otherwise it creates a full path with both device and file components ++ */ ++struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part, ++ const char *path) ++{ ++ struct efi_device_path_file_path *fp; ++ void *buf, *start; ++ unsigned dpsize = 0, fpsize; ++ ++ if (desc) ++ dpsize = dp_part_size(desc, part); ++ ++ fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1); ++ dpsize += fpsize; ++ ++ start = buf = dp_alloc(dpsize + sizeof(END)); ++ ++ if (desc) ++ buf = dp_part_fill(buf, desc, part); ++ ++ /* add file-path: */ ++ fp = buf; ++ fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; ++ fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; ++ fp->dp.length = fpsize; ++ path_to_uefi(fp->str, path); ++ buf += fpsize; ++ ++ *((struct efi_device_path *)buf) = END; ++ ++ return start; ++} ++ ++#ifdef CONFIG_NET ++struct efi_device_path *efi_dp_from_eth(void) ++{ ++ struct efi_device_path_mac_addr *ndp; ++ void *buf, *start; ++ unsigned dpsize = 0; ++ ++ assert(eth_get_dev()); ++ ++#ifdef CONFIG_DM_ETH ++ dpsize += dp_size(eth_get_dev()); ++#else ++ dpsize += sizeof(ROOT); ++#endif ++ dpsize += sizeof(*ndp); ++ ++ start = buf = dp_alloc(dpsize + sizeof(END)); ++ ++#ifdef CONFIG_DM_ETH ++ buf = dp_fill(buf, eth_get_dev()); ++#else ++ memcpy(buf, &ROOT, sizeof(ROOT)); ++ buf += sizeof(ROOT); ++#endif ++ ++ ndp = buf; ++ ndp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; ++ ndp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR; ++ ndp->dp.length = sizeof(*ndp); ++ memcpy(ndp->mac.addr, eth_get_ethaddr(), ARP_HLEN); ++ buf = &ndp[1]; ++ ++ *((struct efi_device_path *)buf) = END; ++ ++ return start; ++} ++#endif ++ ++/* ++ * Helper to split a full device path (containing both device and file ++ * parts) into it's constituent parts. ++ */ ++void efi_dp_split_file_path(struct efi_device_path *full_path, ++ struct efi_device_path **device_path, ++ struct efi_device_path **file_path) ++{ ++ struct efi_device_path *p, *dp, *fp; ++ ++ dp = efi_dp_dup(full_path); ++ p = dp; ++ while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH)) ++ p = efi_dp_next(p); ++ fp = efi_dp_dup(p); ++ ++ p->type = DEVICE_PATH_TYPE_END; ++ p->sub_type = DEVICE_PATH_SUB_TYPE_END; ++ p->length = sizeof(*p); ++ ++ *device_path = dp; ++ *file_path = fp; ++} + +From patchwork Wed Sep 13 22:05:29 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot, v3, + 06/21] efi_loader: drop redundant efi_device_path_protocol +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813650 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-7-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt , Peter Jones +Date: Wed, 13 Sep 2017 18:05:29 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +This is really the same thing as the efi_device_path struct. + +Signed-off-by: Rob Clark +--- + include/efi_api.h | 12 ++---------- + lib/efi_loader/efi_device_path_to_text.c | 13 ++++++++----- + 2 files changed, 10 insertions(+), 15 deletions(-) + +diff --git a/include/efi_api.h b/include/efi_api.h +index 4e27c82129..ac58fd58de 100644 +--- a/include/efi_api.h ++++ b/include/efi_api.h +@@ -487,22 +487,14 @@ struct efi_console_control_protocol + EFI_GUID(0x8b843e20, 0x8132, 0x4852, \ + 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c) + +-struct efi_device_path_protocol +-{ +- uint8_t type; +- uint8_t sub_type; +- uint16_t length; +- uint8_t data[]; +-}; +- + struct efi_device_path_to_text_protocol + { + uint16_t *(EFIAPI *convert_device_node_to_text)( +- struct efi_device_path_protocol *device_node, ++ struct efi_device_path *device_node, + bool display_only, + bool allow_shortcuts); + uint16_t *(EFIAPI *convert_device_path_to_text)( +- struct efi_device_path_protocol *device_path, ++ struct efi_device_path *device_path, + bool display_only, + bool allow_shortcuts); + }; +diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c +index 4b2f43f0c8..f9d071ac50 100644 +--- a/lib/efi_loader/efi_device_path_to_text.c ++++ b/lib/efi_loader/efi_device_path_to_text.c +@@ -16,7 +16,7 @@ const efi_guid_t efi_guid_device_path_to_text_protocol = + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; + + static uint16_t *efi_convert_device_node_to_text( +- struct efi_device_path_protocol *device_node, ++ struct efi_device_path *device_node, + bool display_only, + bool allow_shortcuts) + { +@@ -55,15 +55,18 @@ static uint16_t *efi_convert_device_node_to_text( + break; + case DEVICE_PATH_TYPE_MEDIA_DEVICE: + switch (device_node->sub_type) { +- case DEVICE_PATH_SUB_TYPE_FILE_PATH: ++ case DEVICE_PATH_SUB_TYPE_FILE_PATH: { ++ struct efi_device_path_file_path *fp = ++ (struct efi_device_path_file_path *)device_node; + buffer_size = device_node->length - 4; + r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, + buffer_size, (void **) &buffer); + if (r != EFI_SUCCESS) + return NULL; +- memcpy(buffer, device_node->data, buffer_size); ++ memcpy(buffer, fp->str, buffer_size); + break; + } ++ } + break; + } + +@@ -89,7 +92,7 @@ static uint16_t *efi_convert_device_node_to_text( + } + + static uint16_t EFIAPI *efi_convert_device_node_to_text_ext( +- struct efi_device_path_protocol *device_node, ++ struct efi_device_path *device_node, + bool display_only, + bool allow_shortcuts) + { +@@ -105,7 +108,7 @@ static uint16_t EFIAPI *efi_convert_device_node_to_text_ext( + } + + static uint16_t EFIAPI *efi_convert_device_path_to_text( +- struct efi_device_path_protocol *device_path, ++ struct efi_device_path *device_path, + bool display_only, + bool allow_shortcuts) + { + +From patchwork Wed Sep 13 22:05:30 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot,v3,07/21] efi_loader: flesh out device-path to text +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813658 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-8-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt , Peter Jones +Date: Wed, 13 Sep 2017 18:05:30 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +It needs to handle more device-path node types, and also multiple levels +of path hierarchy. To simplify this, initially construct utf8 string to +a temporary buffer, and then allocate the real utf16 buffer that is +returned. This should be mostly for debugging or at least not critical- +path so an extra copy won't hurt, and is saner than the alternative. + +Signed-off-by: Rob Clark +--- + include/efi_api.h | 1 + + include/efi_loader.h | 2 + + lib/efi_loader/efi_device_path_to_text.c | 241 +++++++++++++++++++++++-------- + 3 files changed, 181 insertions(+), 63 deletions(-) + +diff --git a/include/efi_api.h b/include/efi_api.h +index ac58fd58de..0c36122107 100644 +--- a/include/efi_api.h ++++ b/include/efi_api.h +@@ -304,6 +304,7 @@ struct efi_device_path_vendor { + + #define EFI_PNP_ID(ID) (u32)(((ID) << 16) | 0x41D0) + #define EISA_PNP_ID(ID) EFI_PNP_ID(ID) ++#define EISA_PNP_NUM(ID) ((ID) >> 16) + + struct efi_device_path_acpi_path { + struct efi_device_path dp; +diff --git a/include/efi_loader.h b/include/efi_loader.h +index d052b03ab7..f39c2ee6da 100644 +--- a/include/efi_loader.h ++++ b/include/efi_loader.h +@@ -59,6 +59,8 @@ extern struct efi_simple_input_interface efi_con_in; + extern const struct efi_console_control_protocol efi_console_control; + extern const struct efi_device_path_to_text_protocol efi_device_path_to_text; + ++uint16_t *efi_dp_str(struct efi_device_path *dp); ++ + extern const efi_guid_t efi_guid_console_control; + extern const efi_guid_t efi_guid_device_path; + extern const efi_guid_t efi_guid_loaded_image; +diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c +index f9d071ac50..1a5ef3919b 100644 +--- a/lib/efi_loader/efi_device_path_to_text.c ++++ b/lib/efi_loader/efi_device_path_to_text.c +@@ -15,82 +15,197 @@ + const efi_guid_t efi_guid_device_path_to_text_protocol = + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; + +-static uint16_t *efi_convert_device_node_to_text( +- struct efi_device_path *device_node, +- bool display_only, +- bool allow_shortcuts) ++static char *dp_unknown(char *s, struct efi_device_path *dp) + { +- unsigned long buffer_size; +- efi_status_t r; +- uint16_t *buffer = NULL; +- int i; ++ s += sprintf(s, "/UNKNOWN(%04x,%04x)", dp->type, dp->sub_type); ++ return s; ++} + +- switch (device_node->type) { +- case DEVICE_PATH_TYPE_END: +- return NULL; +- case DEVICE_PATH_TYPE_MESSAGING_DEVICE: +- switch (device_node->sub_type) { +- case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: { +- struct efi_device_path_mac_addr *dp = +- (struct efi_device_path_mac_addr *)device_node; +- +- if (dp->if_type != 0 && dp->if_type != 1) +- break; +- r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, +- 2 * MAC_OUTPUT_LEN, +- (void **)&buffer); +- if (r != EFI_SUCCESS) +- return NULL; +- sprintf((char *)buffer, +- "MAC(%02x%02x%02x%02x%02x%02x,0x%1x)", +- dp->mac.addr[0], dp->mac.addr[1], +- dp->mac.addr[2], dp->mac.addr[3], +- dp->mac.addr[4], dp->mac.addr[5], +- dp->if_type); +- for (i = MAC_OUTPUT_LEN - 1; i >= 0; --i) +- buffer[i] = ((uint8_t *)buffer)[i]; ++static char *dp_hardware(char *s, struct efi_device_path *dp) ++{ ++ switch (dp->sub_type) { ++ case DEVICE_PATH_SUB_TYPE_VENDOR: { ++ struct efi_device_path_vendor *vdp = ++ (struct efi_device_path_vendor *)dp; ++ s += sprintf(s, "/VenHw(%pUl)", &vdp->guid); ++ break; ++ } ++ default: ++ s = dp_unknown(s, dp); ++ break; ++ } ++ return s; ++} ++ ++static char *dp_acpi(char *s, struct efi_device_path *dp) ++{ ++ switch (dp->sub_type) { ++ case DEVICE_PATH_SUB_TYPE_ACPI_DEVICE: { ++ struct efi_device_path_acpi_path *adp = ++ (struct efi_device_path_acpi_path *)dp; ++ s += sprintf(s, "/Acpi(PNP%04x", EISA_PNP_NUM(adp->hid)); ++ if (adp->uid) ++ s += sprintf(s, ",%d", adp->uid); ++ s += sprintf(s, ")"); ++ break; ++ } ++ default: ++ s = dp_unknown(s, dp); ++ break; ++ } ++ return s; ++} ++ ++static char *dp_msging(char *s, struct efi_device_path *dp) ++{ ++ switch (dp->sub_type) { ++ case DEVICE_PATH_SUB_TYPE_MSG_USB: { ++ struct efi_device_path_usb *udp = ++ (struct efi_device_path_usb *)dp; ++ s += sprintf(s, "/Usb(0x%x,0x%x)", udp->parent_port_number, ++ udp->usb_interface); ++ break; ++ } ++ case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: { ++ struct efi_device_path_mac_addr *mdp = ++ (struct efi_device_path_mac_addr *)dp; ++ ++ if (mdp->if_type != 0 && mdp->if_type != 1) + break; +- } +- } ++ ++ s += sprintf(s, "/MAC(%02x%02x%02x%02x%02x%02x,0x%1x)", ++ mdp->mac.addr[0], mdp->mac.addr[1], ++ mdp->mac.addr[2], mdp->mac.addr[3], ++ mdp->mac.addr[4], mdp->mac.addr[5], ++ mdp->if_type); ++ ++ break; ++ } ++ case DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS: { ++ struct efi_device_path_usb_class *ucdp = ++ (struct efi_device_path_usb_class *)dp; ++ ++ s += sprintf(s, "/USBClass(%x,%x,%x,%x,%x)", ++ ucdp->vendor_id, ucdp->product_id, ++ ucdp->device_class, ucdp->device_subclass, ++ ucdp->device_protocol); ++ ++ break; ++ } ++ case DEVICE_PATH_SUB_TYPE_MSG_SD: ++ case DEVICE_PATH_SUB_TYPE_MSG_MMC: { ++ const char *typename = ++ (dp->sub_type == DEVICE_PATH_SUB_TYPE_MSG_SD) ? ++ "SDCard" : "MMC"; ++ struct efi_device_path_sd_mmc_path *sddp = ++ (struct efi_device_path_sd_mmc_path *)dp; ++ s += sprintf(s, "/%s(Slot%u)", typename, sddp->slot_number); ++ break; ++ } ++ default: ++ s = dp_unknown(s, dp); + break; +- case DEVICE_PATH_TYPE_MEDIA_DEVICE: +- switch (device_node->sub_type) { +- case DEVICE_PATH_SUB_TYPE_FILE_PATH: { +- struct efi_device_path_file_path *fp = +- (struct efi_device_path_file_path *)device_node; +- buffer_size = device_node->length - 4; +- r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, +- buffer_size, (void **) &buffer); +- if (r != EFI_SUCCESS) +- return NULL; +- memcpy(buffer, fp->str, buffer_size); ++ } ++ return s; ++} ++ ++static char *dp_media(char *s, struct efi_device_path *dp) ++{ ++ switch (dp->sub_type) { ++ case DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH: { ++ struct efi_device_path_hard_drive_path *hddp = ++ (struct efi_device_path_hard_drive_path *)dp; ++ void *sig = hddp->partition_signature; ++ ++ switch (hddp->signature_type) { ++ case SIG_TYPE_MBR: ++ s += sprintf(s, "/HD(Part%d,Sig%08x)", ++ hddp->partition_number, ++ *(uint32_t *)sig); + break; ++ case SIG_TYPE_GUID: ++ s += sprintf(s, "/HD(Part%d,Sig%pUl)", ++ hddp->partition_number, sig); ++ default: ++ s += sprintf(s, "/HD(Part%d,MBRType=%02x,SigType=%02x)", ++ hddp->partition_number, hddp->partmap_type, ++ hddp->signature_type); + } +- } ++ ++ break; ++ } ++ case DEVICE_PATH_SUB_TYPE_CDROM_PATH: { ++ struct efi_device_path_cdrom_path *cddp = ++ (struct efi_device_path_cdrom_path *)dp; ++ s += sprintf(s, "/CDROM(0x%x)", cddp->boot_entry); ++ break; ++ } ++ case DEVICE_PATH_SUB_TYPE_FILE_PATH: { ++ struct efi_device_path_file_path *fp = ++ (struct efi_device_path_file_path *)dp; ++ int slen = (dp->length - sizeof(*dp)) / 2; ++ s += sprintf(s, "/%-*ls", slen, fp->str); ++ break; ++ } ++ default: ++ s = dp_unknown(s, dp); + break; + } ++ return s; ++} + +- /* +- * For all node types that we do not yet support return +- * 'UNKNOWN(type,subtype)'. +- */ +- if (!buffer) { +- r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, +- 2 * UNKNOWN_OUTPUT_LEN, +- (void **)&buffer); +- if (r != EFI_SUCCESS) +- return NULL; +- sprintf((char *)buffer, +- "UNKNOWN(%04x,%04x)", +- device_node->type, +- device_node->sub_type); +- for (i = UNKNOWN_OUTPUT_LEN - 1; i >= 0; --i) +- buffer[i] = ((uint8_t *)buffer)[i]; ++static uint16_t *efi_convert_device_node_to_text( ++ struct efi_device_path *dp, ++ bool display_only, ++ bool allow_shortcuts) ++{ ++ unsigned long len; ++ efi_status_t r; ++ char buf[512]; /* this ought be be big enough for worst case */ ++ char *str = buf; ++ uint16_t *out; ++ ++ while (dp) { ++ switch (dp->type) { ++ case DEVICE_PATH_TYPE_HARDWARE_DEVICE: ++ str = dp_hardware(str, dp); ++ break; ++ case DEVICE_PATH_TYPE_ACPI_DEVICE: ++ str = dp_acpi(str, dp); ++ break; ++ case DEVICE_PATH_TYPE_MESSAGING_DEVICE: ++ str = dp_msging(str, dp); ++ break; ++ case DEVICE_PATH_TYPE_MEDIA_DEVICE: ++ str = dp_media(str, dp); ++ break; ++ default: ++ str = dp_unknown(str, dp); ++ } ++ ++ dp = efi_dp_next(dp); + } + +- return buffer; ++ *str++ = '\0'; ++ ++ len = str - buf; ++ r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, 2 * len, (void **)&out); ++ if (r != EFI_SUCCESS) ++ return NULL; ++ ++ ascii2unicode(out, buf); ++ out[len - 1] = 0; ++ ++ return out; + } + ++/* helper for debug prints.. efi_free_pool() the result. */ ++uint16_t *efi_dp_str(struct efi_device_path *dp) ++{ ++ return efi_convert_device_node_to_text(dp, true, true); ++} ++ ++ + static uint16_t EFIAPI *efi_convert_device_node_to_text_ext( + struct efi_device_path *device_node, + bool display_only, + +From patchwork Wed Sep 13 22:05:31 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot,v3,08/21] efi_loader: use proper device-paths for partitions +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813648 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-9-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt +Date: Wed, 13 Sep 2017 18:05:31 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +Also, create disk objects for the disk itself, in addition to the +partitions. (UEFI terminology is a bit confusing, a "disk" object is +really a partition.) This helps grub properly identify the boot device +since it is trying to match up partition "disk" object with it's parent +device. + +Now instead of seeing devices like: + + /File(sdhci@07864000.blk)/EndEntire + /File(usb_mass_storage.lun0)/EndEntire + +You see: + + /ACPI(133741d0,0)/UnknownMessaging(1d)/EndEntire + /ACPI(133741d0,0)/UnknownMessaging(1d)/HD(0,800,64000,dd904a8c00000000,1,1)/EndEntire + /ACPI(133741d0,0)/UnknownMessaging(1d)/HD(1,64800,200000,dd904a8c00000000,1,1)/EndEntire + /ACPI(133741d0,0)/UnknownMessaging(1d)/HD(2,264800,19a000,dd904a8c00000000,1,1)/EndEntire + /ACPI(133741d0,0)/USB(0,0)/USB(0,0)/USB(0,0)/EndEntire + /ACPI(133741d0,0)/USB(0,0)/USB(0,0)/USB(0,0)/HD(0,800,60000,38ca680200000000,1,1)/EndEntire + /ACPI(133741d0,0)/USB(0,0)/USB(0,0)/USB(0,0)/HD(1,61000,155000,38ca680200000000,1,1)/EndEntire + /ACPI(133741d0,0)/USB(0,0)/USB(0,0)/USB(0,0)/HD(2,20fa800,1bbf8800,38ca680200000000,1,1)/EndEntire + /ACPI(133741d0,0)/USB(0,0)/USB(0,0)/USB(0,0)/HD(3,1b6800,1f44000,38ca680200000000,1,1)/EndEntire + +This is on a board with single USB disk and single sd-card. The +UnknownMessaging(1d) node in the device-path is the MMC device, +but grub_efi_print_device_path() hasn't been updated yet for some +of the newer device-path sub-types. + +This patch is inspired by a patch originally from Peter Jones, but +re-worked to use efi_device_path, so it doesn't much resemble the +original. + +Signed-off-by: Rob Clark +--- + lib/efi_loader/efi_disk.c | 54 +++++++++++++++++++++++++++-------------------- + 1 file changed, 31 insertions(+), 23 deletions(-) + +diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c +index ed06485e33..14f3e020c8 100644 +--- a/lib/efi_loader/efi_disk.c ++++ b/lib/efi_loader/efi_disk.c +@@ -28,11 +28,13 @@ struct efi_disk_obj { + /* EFI Interface Media descriptor struct, referenced by ops */ + struct efi_block_io_media media; + /* EFI device path to this block device */ +- struct efi_device_path_file_path *dp; ++ struct efi_device_path *dp; ++ /* partition # */ ++ unsigned part; + /* Offset into disk for simple partitions */ + lbaint_t offset; + /* Internal block device */ +- const struct blk_desc *desc; ++ struct blk_desc *desc; + }; + + static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this, +@@ -172,26 +174,26 @@ static const struct efi_block_io block_io_disk_template = { + + static void efi_disk_add_dev(const char *name, + const char *if_typename, +- const struct blk_desc *desc, ++ struct blk_desc *desc, + int dev_index, +- lbaint_t offset) ++ lbaint_t offset, ++ unsigned part) + { + struct efi_disk_obj *diskobj; +- struct efi_device_path_file_path *dp; +- int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2); + + /* Don't add empty devices */ + if (!desc->lba) + return; + +- diskobj = calloc(1, objlen); ++ diskobj = calloc(1, sizeof(*diskobj)); + + /* Fill in object data */ +- dp = (void *)&diskobj[1]; ++ diskobj->dp = efi_dp_from_part(desc, part); ++ diskobj->part = part; + diskobj->parent.protocols[0].guid = &efi_block_io_guid; + diskobj->parent.protocols[0].protocol_interface = &diskobj->ops; + diskobj->parent.protocols[1].guid = &efi_guid_device_path; +- diskobj->parent.protocols[1].protocol_interface = dp; ++ diskobj->parent.protocols[1].protocol_interface = diskobj->dp; + diskobj->parent.handle = diskobj; + diskobj->ops = block_io_disk_template; + diskobj->ifname = if_typename; +@@ -207,17 +209,6 @@ static void efi_disk_add_dev(const char *name, + diskobj->media.last_block = desc->lba - offset; + diskobj->ops.media = &diskobj->media; + +- /* Fill in device path */ +- diskobj->dp = dp; +- dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; +- dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; +- dp[0].dp.length = sizeof(*dp); +- ascii2unicode(dp[0].str, name); +- +- dp[1].dp.type = DEVICE_PATH_TYPE_END; +- dp[1].dp.sub_type = DEVICE_PATH_SUB_TYPE_END; +- dp[1].dp.length = sizeof(*dp); +- + /* Hook up to the device list */ + list_add_tail(&diskobj->parent.link, &efi_obj_list); + } +@@ -236,14 +227,18 @@ static int efi_disk_create_eltorito(struct blk_desc *desc, + if (desc->part_type != PART_TYPE_ISO) + return 0; + ++ /* and devices for each partition: */ + while (!part_get_info(desc, part, &info)) { + snprintf(devname, sizeof(devname), "%s:%d", pdevname, + part); + efi_disk_add_dev(devname, if_typename, desc, diskid, +- info.start); ++ info.start, part); + part++; + disks++; + } ++ ++ /* ... and add block device: */ ++ efi_disk_add_dev(devname, if_typename, desc, diskid, 0, 0); + #endif + + return disks; +@@ -271,9 +266,22 @@ int efi_disk_register(void) + uclass_next_device_check(&dev)) { + struct blk_desc *desc = dev_get_uclass_platdata(dev); + const char *if_typename = dev->driver->name; ++ disk_partition_t info; ++ int part = 1; + + printf("Scanning disk %s...\n", dev->name); +- efi_disk_add_dev(dev->name, if_typename, desc, desc->devnum, 0); ++ ++ /* add devices for each partition: */ ++ while (!part_get_info(desc, part, &info)) { ++ efi_disk_add_dev(dev->name, if_typename, desc, ++ desc->devnum, 0, part); ++ part++; ++ } ++ ++ /* ... and add block device: */ ++ efi_disk_add_dev(dev->name, if_typename, desc, ++ desc->devnum, 0, 0); ++ + disks++; + + /* +@@ -309,7 +317,7 @@ int efi_disk_register(void) + + snprintf(devname, sizeof(devname), "%s%d", + if_typename, i); +- efi_disk_add_dev(devname, if_typename, desc, i, 0); ++ efi_disk_add_dev(devname, if_typename, desc, i, 0, 0); + disks++; + + /* + +From patchwork Wed Sep 13 22:05:32 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot,v3,09/21] efi_loader: use proper device-paths for net +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813640 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-10-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt +Date: Wed, 13 Sep 2017 18:05:32 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +Signed-off-by: Rob Clark +--- + lib/efi_loader/efi_net.c | 19 ++----------------- + 1 file changed, 2 insertions(+), 17 deletions(-) + +diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c +index 0b949d86e8..aa0618fd3a 100644 +--- a/lib/efi_loader/efi_net.c ++++ b/lib/efi_loader/efi_net.c +@@ -26,9 +26,6 @@ struct efi_net_obj { + /* EFI Interface callback struct for network */ + struct efi_simple_network net; + struct efi_simple_network_mode net_mode; +- /* Device path to the network adapter */ +- struct efi_device_path_mac_addr dp_mac; +- struct efi_device_path_file_path dp_end; + /* PXE struct to transmit dhcp data */ + struct efi_pxe pxe; + struct efi_pxe_mode pxe_mode; +@@ -213,16 +210,6 @@ void efi_net_set_dhcp_ack(void *pkt, int len) + int efi_net_register(void **handle) + { + struct efi_net_obj *netobj; +- struct efi_device_path_mac_addr dp_net = { +- .dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE, +- .dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR, +- .dp.length = sizeof(dp_net), +- }; +- struct efi_device_path_file_path dp_end = { +- .dp.type = DEVICE_PATH_TYPE_END, +- .dp.sub_type = DEVICE_PATH_SUB_TYPE_END, +- .dp.length = sizeof(dp_end), +- }; + + if (!eth_get_dev()) { + /* No eth device active, don't expose any */ +@@ -236,7 +223,8 @@ int efi_net_register(void **handle) + netobj->parent.protocols[0].guid = &efi_net_guid; + netobj->parent.protocols[0].protocol_interface = &netobj->net; + netobj->parent.protocols[1].guid = &efi_guid_device_path; +- netobj->parent.protocols[1].protocol_interface = &netobj->dp_mac; ++ netobj->parent.protocols[1].protocol_interface = ++ efi_dp_from_eth(); + netobj->parent.protocols[2].guid = &efi_pxe_guid; + netobj->parent.protocols[2].protocol_interface = &netobj->pxe; + netobj->parent.handle = &netobj->net; +@@ -255,9 +243,6 @@ int efi_net_register(void **handle) + netobj->net.receive = efi_net_receive; + netobj->net.mode = &netobj->net_mode; + netobj->net_mode.state = EFI_NETWORK_STARTED; +- netobj->dp_mac = dp_net; +- netobj->dp_end = dp_end; +- memcpy(netobj->dp_mac.mac.addr, eth_get_ethaddr(), 6); + memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6); + netobj->net_mode.max_packet_size = PKTSIZE; + + +From patchwork Wed Sep 13 22:05:33 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot, v3, + 10/21] efi_loader: refactor boot device and loaded_image handling +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813642 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-11-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt +Date: Wed, 13 Sep 2017 18:05:33 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +Get rid of the hacky fake boot-device and duplicate device-path +constructing (which needs to match what efi_disk and efi_net do). +Instead convert over to use efi_device_path helpers to construct +device-paths, and use that to look up the actual boot device. + +Also, extract out a helper to plug things in properly to the +loaded_image. In a following patch we'll want to re-use this in +efi_load_image() to handle the case of loading an image from a +file_path. + +Signed-off-by: Rob Clark +--- + cmd/bootefi.c | 201 +++++++++++++----------------------------- + include/efi_loader.h | 5 +- + lib/efi_loader/efi_boottime.c | 36 ++++++++ + lib/efi_loader/efi_net.c | 5 +- + 4 files changed, 100 insertions(+), 147 deletions(-) + +diff --git a/cmd/bootefi.c b/cmd/bootefi.c +index 3196d86040..0980088668 100644 +--- a/cmd/bootefi.c ++++ b/cmd/bootefi.c +@@ -22,97 +22,14 @@ DECLARE_GLOBAL_DATA_PTR; + + static uint8_t efi_obj_list_initalized; + +-/* +- * When booting using the "bootefi" command, we don't know which +- * physical device the file came from. So we create a pseudo-device +- * called "bootefi" with the device path /bootefi. +- * +- * In addition to the originating device we also declare the file path +- * of "bootefi" based loads to be /bootefi. +- */ +-static struct efi_device_path_file_path bootefi_image_path[] = { +- { +- .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE, +- .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH, +- .dp.length = sizeof(bootefi_image_path[0]), +- .str = { 'b','o','o','t','e','f','i' }, +- }, { +- .dp.type = DEVICE_PATH_TYPE_END, +- .dp.sub_type = DEVICE_PATH_SUB_TYPE_END, +- .dp.length = sizeof(bootefi_image_path[0]), +- } +-}; +- +-static struct efi_device_path_file_path bootefi_device_path[] = { +- { +- .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE, +- .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH, +- .dp.length = sizeof(bootefi_image_path[0]), +- .str = { 'b','o','o','t','e','f','i' }, +- }, { +- .dp.type = DEVICE_PATH_TYPE_END, +- .dp.sub_type = DEVICE_PATH_SUB_TYPE_END, +- .dp.length = sizeof(bootefi_image_path[0]), +- } +-}; +- +-/* The EFI loaded_image interface for the image executed via "bootefi" */ +-static struct efi_loaded_image loaded_image_info = { +- .device_handle = bootefi_device_path, +- .file_path = bootefi_image_path, +-}; +- +-/* The EFI object struct for the image executed via "bootefi" */ +-static struct efi_object loaded_image_info_obj = { +- .handle = &loaded_image_info, +- .protocols = { +- { +- /* +- * When asking for the loaded_image interface, just +- * return handle which points to loaded_image_info +- */ +- .guid = &efi_guid_loaded_image, +- .protocol_interface = &loaded_image_info, +- }, +- { +- /* +- * When asking for the device path interface, return +- * bootefi_device_path +- */ +- .guid = &efi_guid_device_path, +- .protocol_interface = bootefi_device_path, +- }, +- { +- .guid = &efi_guid_console_control, +- .protocol_interface = (void *) &efi_console_control +- }, +- { +- .guid = &efi_guid_device_path_to_text_protocol, +- .protocol_interface = (void *) &efi_device_path_to_text +- }, +- }, +-}; +- +-/* The EFI object struct for the device the "bootefi" image was loaded from */ +-static struct efi_object bootefi_device_obj = { +- .handle = bootefi_device_path, +- .protocols = { +- { +- /* When asking for the device path interface, return +- * bootefi_device_path */ +- .guid = &efi_guid_device_path, +- .protocol_interface = bootefi_device_path +- } +- }, +-}; ++static struct efi_device_path *bootefi_image_path; ++static struct efi_device_path *bootefi_device_path; + + /* Initialize and populate EFI object list */ + static void efi_init_obj_list(void) + { + efi_obj_list_initalized = 1; + +- list_add_tail(&loaded_image_info_obj.link, &efi_obj_list); +- list_add_tail(&bootefi_device_obj.link, &efi_obj_list); + efi_console_register(); + #ifdef CONFIG_PARTITIONS + efi_disk_register(); +@@ -121,13 +38,7 @@ static void efi_init_obj_list(void) + efi_gop_register(); + #endif + #ifdef CONFIG_NET +- void *nethandle = loaded_image_info.device_handle; +- efi_net_register(&nethandle); +- +- if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6)) +- loaded_image_info.device_handle = nethandle; +- else +- loaded_image_info.device_handle = bootefi_device_path; ++ efi_net_register(); + #endif + #ifdef CONFIG_GENERATE_SMBIOS_TABLE + efi_smbios_register(); +@@ -210,14 +121,27 @@ static unsigned long efi_run_in_el2(asmlinkage ulong (*entry)( + * Load an EFI payload into a newly allocated piece of memory, register all + * EFI objects it would want to access and jump to it. + */ +-static unsigned long do_bootefi_exec(void *efi, void *fdt) ++static unsigned long do_bootefi_exec(void *efi, void *fdt, ++ struct efi_device_path *device_path, ++ struct efi_device_path *image_path) + { ++ struct efi_loaded_image loaded_image_info = {}; ++ struct efi_object loaded_image_info_obj = {}; ++ ulong ret; ++ + ulong (*entry)(void *image_handle, struct efi_system_table *st) + asmlinkage; + ulong fdt_pages, fdt_size, fdt_start, fdt_end; + const efi_guid_t fdt_guid = EFI_FDT_GUID; + bootm_headers_t img = { 0 }; + ++ /* Initialize and populate EFI object list */ ++ if (!efi_obj_list_initalized) ++ efi_init_obj_list(); ++ ++ efi_setup_loaded_image(&loaded_image_info, &loaded_image_info_obj, ++ device_path, image_path); ++ + /* + * gd lives in a fixed register which may get clobbered while we execute + * the payload. So save it here and restore it on every callback entry +@@ -252,18 +176,18 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) + + /* Load the EFI payload */ + entry = efi_load_pe(efi, &loaded_image_info); +- if (!entry) +- return -ENOENT; +- +- /* Initialize and populate EFI object list */ +- if (!efi_obj_list_initalized) +- efi_init_obj_list(); ++ if (!entry) { ++ ret = -ENOENT; ++ goto exit; ++ } + + /* Call our payload! */ + debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry); + + if (setjmp(&loaded_image_info.exit_jmp)) { +- return loaded_image_info.exit_status; ++ ret = loaded_image_info.exit_status; ++ EFI_EXIT(ret); ++ goto exit; + } + + #ifdef CONFIG_ARM64 +@@ -282,7 +206,13 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) + } + #endif + +- return efi_do_enter(&loaded_image_info, &systab, entry); ++ ret = efi_do_enter(&loaded_image_info, &systab, entry); ++ ++exit: ++ /* image has returned, loaded-image obj goes *poof*: */ ++ list_del(&loaded_image_info_obj.link); ++ ++ return ret; + } + + +@@ -315,7 +245,8 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) + } + + printf("## Starting EFI application at %08lx ...\n", addr); +- r = do_bootefi_exec((void *)addr, (void*)fdt_addr); ++ r = do_bootefi_exec((void *)addr, (void *)fdt_addr, ++ bootefi_device_path, bootefi_image_path); + printf("## Application terminated, r = %lu\n", + r & ~EFI_ERROR_MASK); + +@@ -344,58 +275,44 @@ U_BOOT_CMD( + bootefi_help_text + ); + +-void efi_set_bootdev(const char *dev, const char *devnr, const char *path) ++static int parse_partnum(const char *devnr) + { +- __maybe_unused struct blk_desc *desc; +- char devname[32] = { 0 }; /* dp->str is u16[32] long */ +- char *colon, *s; +- +-#if defined(CONFIG_BLK) || CONFIG_IS_ENABLED(ISO_PARTITION) +- desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10)); +-#endif +- +-#ifdef CONFIG_BLK +- if (desc) { +- snprintf(devname, sizeof(devname), "%s", desc->bdev->name); +- } else +-#endif +- +- { +- /* Assemble the condensed device name we use in efi_disk.c */ +- snprintf(devname, sizeof(devname), "%s%s", dev, devnr); ++ const char *str = strchr(devnr, ':'); ++ if (str) { ++ str++; ++ return simple_strtoul(str, NULL, 16); + } ++ return 0; ++} + +- colon = strchr(devname, ':'); +- +-#if CONFIG_IS_ENABLED(ISO_PARTITION) +- /* For ISOs we create partition block devices */ +- if (desc && (desc->type != DEV_TYPE_UNKNOWN) && +- (desc->part_type == PART_TYPE_ISO)) { +- if (!colon) +- snprintf(devname, sizeof(devname), "%s:1", devname); ++void efi_set_bootdev(const char *dev, const char *devnr, const char *path) ++{ ++ char filename[32] = { 0 }; /* dp->str is u16[32] long */ ++ char *s; + +- colon = NULL; +- } +-#endif ++ if (strcmp(dev, "Net")) { ++ struct blk_desc *desc; ++ int part; + +- if (colon) +- *colon = '\0'; ++ desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10)); ++ part = parse_partnum(devnr); + +- /* Patch bootefi_device_path to the target device */ +- memset(bootefi_device_path[0].str, 0, sizeof(bootefi_device_path[0].str)); +- ascii2unicode(bootefi_device_path[0].str, devname); ++ bootefi_device_path = efi_dp_from_part(desc, part); ++ } else { ++#ifdef CONFIG_NET ++ bootefi_device_path = efi_dp_from_eth(); ++#endif ++ } + +- /* Patch bootefi_image_path to the target file path */ +- memset(bootefi_image_path[0].str, 0, sizeof(bootefi_image_path[0].str)); + if (strcmp(dev, "Net")) { + /* Add leading / to fs paths, because they're absolute */ +- snprintf(devname, sizeof(devname), "/%s", path); ++ snprintf(filename, sizeof(filename), "/%s", path); + } else { +- snprintf(devname, sizeof(devname), "%s", path); ++ snprintf(filename, sizeof(filename), "%s", path); + } + /* DOS style file path: */ +- s = devname; ++ s = filename; + while ((s = strchr(s, '/'))) + *s++ = '\\'; +- ascii2unicode(bootefi_image_path[0].str, devname); ++ bootefi_image_path = efi_dp_from_file(NULL, 0, filename); + } +diff --git a/include/efi_loader.h b/include/efi_loader.h +index f39c2ee6da..ec8803f588 100644 +--- a/include/efi_loader.h ++++ b/include/efi_loader.h +@@ -136,7 +136,7 @@ int efi_disk_register(void); + /* Called by bootefi to make GOP (graphical) interface available */ + int efi_gop_register(void); + /* Called by bootefi to make the network interface available */ +-int efi_net_register(void **handle); ++int efi_net_register(void); + /* Called by bootefi to make SMBIOS tables available */ + void efi_smbios_register(void); + +@@ -193,6 +193,9 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, + int efi_memory_init(void); + /* Adds new or overrides configuration table entry to the system table */ + efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table); ++void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *obj, ++ struct efi_device_path *device_path, ++ struct efi_device_path *file_path); + + #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER + extern void *efi_bounce_buffer; +diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c +index b962b62a97..837e61d8fe 100644 +--- a/lib/efi_loader/efi_boottime.c ++++ b/lib/efi_loader/efi_boottime.c +@@ -726,6 +726,42 @@ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid, + return EFI_EXIT(efi_install_configuration_table(guid, table)); + } + ++/* Initialize a loaded_image_info + loaded_image_info object with correct ++ * protocols, boot-device, etc. ++ */ ++void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *obj, ++ struct efi_device_path *device_path, ++ struct efi_device_path *file_path) ++{ ++ obj->handle = info; ++ ++ /* ++ * When asking for the device path interface, return ++ * bootefi_device_path ++ */ ++ obj->protocols[0].guid = &efi_guid_device_path; ++ obj->protocols[0].protocol_interface = device_path; ++ ++ /* ++ * When asking for the loaded_image interface, just ++ * return handle which points to loaded_image_info ++ */ ++ obj->protocols[1].guid = &efi_guid_loaded_image; ++ obj->protocols[1].protocol_interface = info; ++ ++ obj->protocols[2].guid = &efi_guid_console_control; ++ obj->protocols[2].protocol_interface = (void *)&efi_console_control; ++ ++ obj->protocols[3].guid = &efi_guid_device_path_to_text_protocol; ++ obj->protocols[3].protocol_interface = ++ (void *)&efi_device_path_to_text; ++ ++ info->file_path = file_path; ++ info->device_handle = efi_dp_find_obj(device_path, NULL); ++ ++ list_add_tail(&obj->link, &efi_obj_list); ++} ++ + static efi_status_t EFIAPI efi_load_image(bool boot_policy, + efi_handle_t parent_image, + struct efi_device_path *file_path, +diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c +index aa0618fd3a..91f1e4a69e 100644 +--- a/lib/efi_loader/efi_net.c ++++ b/lib/efi_loader/efi_net.c +@@ -207,7 +207,7 @@ void efi_net_set_dhcp_ack(void *pkt, int len) + } + + /* This gets called from do_bootefi_exec(). */ +-int efi_net_register(void **handle) ++int efi_net_register(void) + { + struct efi_net_obj *netobj; + +@@ -253,8 +253,5 @@ int efi_net_register(void **handle) + /* Hook net up to the device list */ + list_add_tail(&netobj->parent.link, &efi_obj_list); + +- if (handle) +- *handle = &netobj->net; +- + return 0; + } + +From patchwork Wed Sep 13 22:05:34 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot,v3,11/21] efi_loader: add file/filesys support +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813652 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-12-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt , Peter Jones +Date: Wed, 13 Sep 2017 18:05:34 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +fallback.efi (and probably other things) use UEFI's simple-file-system +protocol and file support to search for OS's to boot. + +Signed-off-by: Rob Clark +--- + include/efi.h | 2 + + include/efi_api.h | 65 +++++ + include/efi_loader.h | 13 + + lib/efi_loader/Makefile | 1 + + lib/efi_loader/efi_disk.c | 32 +++ + lib/efi_loader/efi_file.c | 560 ++++++++++++++++++++++++++++++++++++++ + lib/efi_loader/efi_image_loader.c | 3 + + 7 files changed, 676 insertions(+) + create mode 100644 lib/efi_loader/efi_file.c + +diff --git a/include/efi.h b/include/efi.h +index 87b0b43f20..ddd2b96417 100644 +--- a/include/efi.h ++++ b/include/efi.h +@@ -81,6 +81,8 @@ typedef struct { + #define EFI_IP_ADDRESS_CONFLICT (EFI_ERROR_MASK | 34) + #define EFI_HTTP_ERROR (EFI_ERROR_MASK | 35) + ++#define EFI_WARN_DELETE_FAILURE 2 ++ + typedef unsigned long efi_status_t; + typedef u64 efi_physical_addr_t; + typedef u64 efi_virtual_addr_t; +diff --git a/include/efi_api.h b/include/efi_api.h +index 0c36122107..1aae96355f 100644 +--- a/include/efi_api.h ++++ b/include/efi_api.h +@@ -666,4 +666,69 @@ struct efi_pxe { + struct efi_pxe_mode *mode; + }; + ++#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \ ++ EFI_GUID(0x964e5b22, 0x6459, 0x11d2, \ ++ 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b) ++#define EFI_FILE_PROTOCOL_REVISION 0x00010000 ++ ++struct efi_file_handle { ++ u64 rev; ++ efi_status_t (EFIAPI *open)(struct efi_file_handle *file, ++ struct efi_file_handle **new_handle, ++ s16 *file_name, u64 open_mode, u64 attributes); ++ efi_status_t (EFIAPI *close)(struct efi_file_handle *file); ++ efi_status_t (EFIAPI *delete)(struct efi_file_handle *file); ++ efi_status_t (EFIAPI *read)(struct efi_file_handle *file, ++ u64 *buffer_size, void *buffer); ++ efi_status_t (EFIAPI *write)(struct efi_file_handle *file, ++ u64 *buffer_size, void *buffer); ++ efi_status_t (EFIAPI *getpos)(struct efi_file_handle *file, ++ u64 *pos); ++ efi_status_t (EFIAPI *setpos)(struct efi_file_handle *file, ++ u64 pos); ++ efi_status_t (EFIAPI *getinfo)(struct efi_file_handle *file, ++ efi_guid_t *info_type, u64 *buffer_size, void *buffer); ++ efi_status_t (EFIAPI *setinfo)(struct efi_file_handle *file, ++ efi_guid_t *info_type, u64 buffer_size, void *buffer); ++ efi_status_t (EFIAPI *flush)(struct efi_file_handle *file); ++}; ++ ++#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \ ++ EFI_GUID(0x964e5b22, 0x6459, 0x11d2, \ ++ 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b) ++#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION 0x00010000 ++ ++struct efi_simple_file_system_protocol { ++ u64 rev; ++ efi_status_t (EFIAPI *open_volume)(struct efi_simple_file_system_protocol *this, ++ struct efi_file_handle **root); ++}; ++ ++#define EFI_FILE_INFO_GUID \ ++ EFI_GUID(0x9576e92, 0x6d3f, 0x11d2, \ ++ 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b) ++ ++#define EFI_FILE_MODE_READ 0x0000000000000001 ++#define EFI_FILE_MODE_WRITE 0x0000000000000002 ++#define EFI_FILE_MODE_CREATE 0x8000000000000000 ++ ++#define EFI_FILE_READ_ONLY 0x0000000000000001 ++#define EFI_FILE_HIDDEN 0x0000000000000002 ++#define EFI_FILE_SYSTEM 0x0000000000000004 ++#define EFI_FILE_RESERVED 0x0000000000000008 ++#define EFI_FILE_DIRECTORY 0x0000000000000010 ++#define EFI_FILE_ARCHIVE 0x0000000000000020 ++#define EFI_FILE_VALID_ATTR 0x0000000000000037 ++ ++struct efi_file_info { ++ u64 size; ++ u64 file_size; ++ u64 physical_size; ++ struct efi_time create_time; ++ struct efi_time last_access_time; ++ struct efi_time modification_time; ++ u64 attribute; ++ s16 file_name[0]; ++}; ++ + #endif +diff --git a/include/efi_loader.h b/include/efi_loader.h +index ec8803f588..b0c1e8fb78 100644 +--- a/include/efi_loader.h ++++ b/include/efi_loader.h +@@ -65,6 +65,8 @@ extern const efi_guid_t efi_guid_console_control; + extern const efi_guid_t efi_guid_device_path; + extern const efi_guid_t efi_guid_loaded_image; + extern const efi_guid_t efi_guid_device_path_to_text_protocol; ++extern const efi_guid_t efi_simple_file_system_protocol_guid; ++extern const efi_guid_t efi_file_info_guid; + + extern unsigned int __efi_runtime_start, __efi_runtime_stop; + extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop; +@@ -140,6 +142,9 @@ int efi_net_register(void); + /* Called by bootefi to make SMBIOS tables available */ + void efi_smbios_register(void); + ++struct efi_simple_file_system_protocol * ++efi_fs_from_path(struct efi_device_path *fp); ++ + /* Called by networking code to memorize the dhcp ack package */ + void efi_net_set_dhcp_ack(void *pkt, int len); + +@@ -168,6 +173,14 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, + /* Call this to signal an event */ + void efi_signal_event(struct efi_event *event); + ++/* open file system: */ ++struct efi_simple_file_system_protocol *efi_simple_file_system( ++ struct blk_desc *desc, int part, struct efi_device_path *dp); ++ ++/* open file from device-path: */ ++struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp); ++ ++ + /* Generic EFI memory allocator, call this to get memory */ + void *efi_alloc(uint64_t len, int memory_type); + /* More specific EFI memory allocator, called by EFI payloads */ +diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile +index f35e5ce8a8..cce92cfeb5 100644 +--- a/lib/efi_loader/Makefile ++++ b/lib/efi_loader/Makefile +@@ -16,6 +16,7 @@ always := $(efiprogs-y) + obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o + obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o + obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o ++obj-y += efi_file.o + obj-$(CONFIG_LCD) += efi_gop.o + obj-$(CONFIG_DM_VIDEO) += efi_gop.o + obj-$(CONFIG_PARTITIONS) += efi_disk.o +diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c +index 14f3e020c8..9805585eb1 100644 +--- a/lib/efi_loader/efi_disk.c ++++ b/lib/efi_loader/efi_disk.c +@@ -31,6 +31,8 @@ struct efi_disk_obj { + struct efi_device_path *dp; + /* partition # */ + unsigned part; ++ /* handle to filesys proto (for partition objects) */ ++ struct efi_simple_file_system_protocol *volume; + /* Offset into disk for simple partitions */ + lbaint_t offset; + /* Internal block device */ +@@ -172,6 +174,28 @@ static const struct efi_block_io block_io_disk_template = { + .flush_blocks = &efi_disk_flush_blocks, + }; + ++/* ++ * Find filesystem from a device-path. The passed in path 'p' probably ++ * contains one or more /File(name) nodes, so the comparison stops at ++ * the first /File() node, and returns the pointer to that via 'rp'. ++ * This is mostly intended to be a helper to map a device-path to an ++ * efi_file_handle object. ++ */ ++struct efi_simple_file_system_protocol * ++efi_fs_from_path(struct efi_device_path *fp) ++{ ++ struct efi_object *efiobj; ++ struct efi_disk_obj *diskobj; ++ ++ efiobj = efi_dp_find_obj(fp, NULL); ++ if (!efiobj) ++ return NULL; ++ ++ diskobj = container_of(efiobj, struct efi_disk_obj, parent); ++ ++ return diskobj->volume; ++} ++ + static void efi_disk_add_dev(const char *name, + const char *if_typename, + struct blk_desc *desc, +@@ -194,6 +218,14 @@ static void efi_disk_add_dev(const char *name, + diskobj->parent.protocols[0].protocol_interface = &diskobj->ops; + diskobj->parent.protocols[1].guid = &efi_guid_device_path; + diskobj->parent.protocols[1].protocol_interface = diskobj->dp; ++ if (part >= 1) { ++ diskobj->volume = efi_simple_file_system(desc, part, ++ diskobj->dp); ++ diskobj->parent.protocols[2].guid = ++ &efi_simple_file_system_protocol_guid; ++ diskobj->parent.protocols[2].protocol_interface = ++ diskobj->volume; ++ } + diskobj->parent.handle = diskobj; + diskobj->ops = block_io_disk_template; + diskobj->ifname = if_typename; +diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c +new file mode 100644 +index 0000000000..5e1eee5a20 +--- /dev/null ++++ b/lib/efi_loader/efi_file.c +@@ -0,0 +1,560 @@ ++/* ++ * EFI utils ++ * ++ * Copyright (c) 2017 Rob Clark ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++struct file_system { ++ struct efi_simple_file_system_protocol base; ++ struct efi_device_path *dp; ++ struct blk_desc *desc; ++ int part; ++}; ++#define to_fs(x) container_of(x, struct file_system, base) ++ ++struct file_handle { ++ struct efi_file_handle base; ++ struct file_system *fs; ++ loff_t offset; /* current file position/cursor */ ++ int isdir; ++ ++ /* for reading a directory: */ ++ struct fs_dir_stream *dirs; ++ struct fs_dirent *dent; ++ ++ char path[0]; ++}; ++#define to_fh(x) container_of(x, struct file_handle, base) ++ ++static const struct efi_file_handle efi_file_handle_protocol; ++ ++static char *basename(struct file_handle *fh) ++{ ++ char *s = strrchr(fh->path, '/'); ++ if (s) ++ return s + 1; ++ return fh->path; ++} ++ ++static int set_blk_dev(struct file_handle *fh) ++{ ++ return fs_set_blk_dev_with_part(fh->fs->desc, fh->fs->part); ++} ++ ++static int is_dir(struct file_handle *fh) ++{ ++ struct fs_dir_stream *dirs; ++ ++ set_blk_dev(fh); ++ dirs = fs_opendir(fh->path); ++ if (!dirs) ++ return 0; ++ ++ fs_closedir(dirs); ++ ++ return 1; ++} ++ ++/* ++ * Normalize a path which may include either back or fwd slashes, ++ * double slashes, . or .. entries in the path, etc. ++ */ ++static int sanitize_path(char *path) ++{ ++ char *p ; ++ ++ /* backslash to slash: */ ++ p = path; ++ while ((p = strchr(p, '\\'))) ++ *p++ = '/'; ++ ++ /* handle double-slashes: */ ++ p = path; ++ while ((p = strstr(p, "//"))) { ++ char *src = p + 1; ++ memmove(p, src, strlen(src) + 1); ++ } ++ ++ /* handle extra /.'s */ ++ p = path; ++ while ((p = strstr(p, "/."))) { ++ /* ++ * You'd be tempted to do this *after* handling ".."s ++ * below to avoid having to check if "/." is start of ++ * a "/..", but that won't have the correct results.. ++ * for example, "/foo/./../bar" would get resolved to ++ * "/foo/bar" if you did these two passes in the other ++ * order ++ */ ++ if (p[2] == '.') { ++ p += 2; ++ continue; ++ } ++ char *src = p + 2; ++ memmove(p, src, strlen(src) + 1); ++ } ++ ++ /* handle extra /..'s: */ ++ p = path; ++ while ((p = strstr(p, "/.."))) { ++ char *src = p + 3; ++ ++ p--; ++ ++ /* find beginning of previous path entry: */ ++ while (true) { ++ if (p < path) ++ return -1; ++ if (*p == '/') ++ break; ++ p--; ++ } ++ ++ memmove(p, src, strlen(src) + 1); ++ } ++ ++ return 0; ++} ++ ++/* NOTE: despite what you would expect, 'file_name' is actually a path. ++ * With windoze style backlashes, ofc. ++ */ ++static struct efi_file_handle *file_open(struct file_system *fs, ++ struct file_handle *parent, s16 *file_name, u64 mode) ++{ ++ struct file_handle *fh; ++ char f0[MAX_UTF8_PER_UTF16] = {0}; ++ int plen = 0; ++ int flen = 0; ++ ++ if (file_name) { ++ utf16_to_utf8((u8 *)f0, (u16 *)file_name, 1); ++ flen = utf16_strlen((u16 *)file_name); ++ } ++ ++ /* we could have a parent, but also an absolute path: */ ++ if (f0[0] == '\\') { ++ plen = 0; ++ } else if (parent) { ++ plen = strlen(parent->path) + 1; ++ } ++ ++ /* +2 is for null and '/' */ ++ fh = calloc(1, sizeof(*fh) + plen + (flen * MAX_UTF8_PER_UTF16) + 2); ++ ++ fh->base = efi_file_handle_protocol; ++ fh->fs = fs; ++ ++ if (parent) { ++ char *p = fh->path; ++ ++ if (plen > 0) { ++ strcpy(p, parent->path); ++ p += plen - 1; ++ *p++ = '/'; ++ } ++ ++ utf16_to_utf8((u8 *)p, (u16 *)file_name, flen); ++ ++ if (sanitize_path(fh->path)) ++ goto error; ++ ++ /* check if file exists: */ ++ if (set_blk_dev(fh)) ++ goto error; ++ ++ if (!((mode & EFI_FILE_MODE_CREATE) || fs_exists(fh->path))) ++ goto error; ++ ++ /* figure out if file is a directory: */ ++ fh->isdir = is_dir(fh); ++ } else { ++ fh->isdir = 1; ++ strcpy(fh->path, ""); ++ } ++ ++ return &fh->base; ++ ++error: ++ free(fh); ++ return NULL; ++} ++ ++static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file, ++ struct efi_file_handle **new_handle, ++ s16 *file_name, u64 open_mode, u64 attributes) ++{ ++ struct file_handle *fh = to_fh(file); ++ ++ EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle, file_name, ++ open_mode, attributes); ++ ++ *new_handle = file_open(fh->fs, fh, file_name, open_mode); ++ if (!*new_handle) ++ return EFI_EXIT(EFI_NOT_FOUND); ++ ++ return EFI_EXIT(EFI_SUCCESS); ++} ++ ++static efi_status_t file_close(struct file_handle *fh) ++{ ++ fs_closedir(fh->dirs); ++ free(fh); ++ return EFI_SUCCESS; ++} ++ ++static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file) ++{ ++ struct file_handle *fh = to_fh(file); ++ EFI_ENTRY("%p", file); ++ return EFI_EXIT(file_close(fh)); ++} ++ ++static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file) ++{ ++ struct file_handle *fh = to_fh(file); ++ EFI_ENTRY("%p", file); ++ file_close(fh); ++ return EFI_EXIT(EFI_WARN_DELETE_FAILURE); ++} ++ ++static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size, ++ void *buffer) ++{ ++ loff_t actread; ++ ++ if (fs_read(fh->path, (ulong)buffer, fh->offset, ++ *buffer_size, &actread)) ++ return EFI_DEVICE_ERROR; ++ ++ *buffer_size = actread; ++ fh->offset += actread; ++ ++ return EFI_SUCCESS; ++} ++ ++static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size, ++ void *buffer) ++{ ++ struct efi_file_info *info = buffer; ++ struct fs_dirent *dent; ++ unsigned required_size; ++ ++ if (!fh->dirs) { ++ assert(fh->offset == 0); ++ fh->dirs = fs_opendir(fh->path); ++ if (!fh->dirs) ++ return EFI_DEVICE_ERROR; ++ } ++ ++ /* ++ * So this is a bit awkward. Since fs layer is stateful and we ++ * can't rewind an entry, in the EFI_BUFFER_TOO_SMALL case below ++ * we might have to return without consuming the dent.. so we ++ * have to stash it for next call. ++ */ ++ if (fh->dent) { ++ dent = fh->dent; ++ fh->dent = NULL; ++ } else { ++ dent = fs_readdir(fh->dirs); ++ } ++ ++ ++ if (!dent) { ++ /* no more files in directory: */ ++ /* workaround shim.efi bug/quirk.. as find_boot_csv() ++ * loops through directory contents, it initially calls ++ * read w/ zero length buffer to find out how much mem ++ * to allocate for the EFI_FILE_INFO, then allocates, ++ * and then calls a 2nd time. If we return size of ++ * zero the first time, it happily passes that to ++ * AllocateZeroPool(), and when that returns NULL it ++ * thinks it is EFI_OUT_OF_RESOURCES. So on first ++ * call return a non-zero size: ++ */ ++ if (*buffer_size == 0) ++ *buffer_size = sizeof(*info); ++ else ++ *buffer_size = 0; ++ return EFI_SUCCESS; ++ } ++ ++ /* check buffer size: */ ++ required_size = sizeof(*info) + 2 * (strlen(dent->name) + 1); ++ if (*buffer_size < required_size) { ++ *buffer_size = required_size; ++ fh->dent = dent; ++ return EFI_BUFFER_TOO_SMALL; ++ } ++ ++ *buffer_size = required_size; ++ memset(info, 0, required_size); ++ ++ info->size = required_size; ++ info->file_size = dent->size; ++ info->physical_size = dent->size; ++ ++ if (dent->type == FS_DT_DIR) ++ info->attribute |= EFI_FILE_DIRECTORY; ++ ++ ascii2unicode((u16 *)info->file_name, dent->name); ++ ++ fh->offset++; ++ ++ return EFI_SUCCESS; ++} ++ ++static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file, ++ u64 *buffer_size, void *buffer) ++{ ++ struct file_handle *fh = to_fh(file); ++ efi_status_t ret = EFI_SUCCESS; ++ ++ EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); ++ ++ if (set_blk_dev(fh)) { ++ ret = EFI_DEVICE_ERROR; ++ goto error; ++ } ++ ++ if (fh->isdir) ++ ret = dir_read(fh, buffer_size, buffer); ++ else ++ ret = file_read(fh, buffer_size, buffer); ++ ++error: ++ return EFI_EXIT(ret); ++} ++ ++static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file, ++ u64 *buffer_size, void *buffer) ++{ ++ struct file_handle *fh = to_fh(file); ++ efi_status_t ret = EFI_SUCCESS; ++ loff_t actwrite; ++ ++ EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); ++ ++ if (set_blk_dev(fh)) { ++ ret = EFI_DEVICE_ERROR; ++ goto error; ++ } ++ ++ if (fs_write(fh->path, (ulong)buffer, fh->offset, *buffer_size, ++ &actwrite)) { ++ ret = EFI_DEVICE_ERROR; ++ goto error; ++ } ++ ++ *buffer_size = actwrite; ++ fh->offset += actwrite; ++ ++error: ++ return EFI_EXIT(ret); ++} ++ ++static efi_status_t EFIAPI efi_file_getpos(struct efi_file_handle *file, ++ u64 *pos) ++{ ++ struct file_handle *fh = to_fh(file); ++ EFI_ENTRY("%p, %p", file, pos); ++ *pos = fh->offset; ++ return EFI_EXIT(EFI_SUCCESS); ++} ++ ++static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file, ++ u64 pos) ++{ ++ struct file_handle *fh = to_fh(file); ++ efi_status_t ret = EFI_SUCCESS; ++ ++ EFI_ENTRY("%p, %llu", file, pos); ++ ++ if (fh->isdir) { ++ if (pos != 0) { ++ ret = EFI_UNSUPPORTED; ++ goto error; ++ } ++ fs_closedir(fh->dirs); ++ fh->dirs = NULL; ++ } ++ ++ if (pos == ~0ULL) { ++ loff_t file_size; ++ ++ if (set_blk_dev(fh)) { ++ ret = EFI_DEVICE_ERROR; ++ goto error; ++ } ++ ++ if (fs_size(fh->path, &file_size)) { ++ ret = EFI_DEVICE_ERROR; ++ goto error; ++ } ++ ++ pos = file_size; ++ } ++ ++ fh->offset = pos; ++ ++error: ++ return EFI_EXIT(ret); ++} ++ ++static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file, ++ efi_guid_t *info_type, u64 *buffer_size, void *buffer) ++{ ++ struct file_handle *fh = to_fh(file); ++ efi_status_t ret = EFI_SUCCESS; ++ ++ EFI_ENTRY("%p, %p, %p, %p", file, info_type, buffer_size, buffer); ++ ++ if (!guidcmp(info_type, &efi_file_info_guid)) { ++ struct efi_file_info *info = buffer; ++ char *filename = basename(fh); ++ unsigned required_size; ++ loff_t file_size; ++ ++ /* check buffer size: */ ++ required_size = sizeof(*info) + 2 * (strlen(filename) + 1); ++ if (*buffer_size < required_size) { ++ *buffer_size = required_size; ++ ret = EFI_BUFFER_TOO_SMALL; ++ goto error; ++ } ++ ++ if (set_blk_dev(fh)) { ++ ret = EFI_DEVICE_ERROR; ++ goto error; ++ } ++ ++ if (fs_size(fh->path, &file_size)) { ++ ret = EFI_DEVICE_ERROR; ++ goto error; ++ } ++ ++ memset(info, 0, required_size); ++ ++ info->size = required_size; ++ info->file_size = file_size; ++ info->physical_size = file_size; ++ ++ if (fh->isdir) ++ info->attribute |= EFI_FILE_DIRECTORY; ++ ++ ascii2unicode((u16 *)info->file_name, filename); ++ } else { ++ ret = EFI_UNSUPPORTED; ++ } ++ ++error: ++ return EFI_EXIT(ret); ++} ++ ++static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file, ++ efi_guid_t *info_type, u64 buffer_size, void *buffer) ++{ ++ EFI_ENTRY("%p, %p, %llu, %p", file, info_type, buffer_size, buffer); ++ return EFI_EXIT(EFI_UNSUPPORTED); ++} ++ ++static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file) ++{ ++ EFI_ENTRY("%p", file); ++ return EFI_EXIT(EFI_SUCCESS); ++} ++ ++static const struct efi_file_handle efi_file_handle_protocol = { ++ .rev = EFI_FILE_PROTOCOL_REVISION, ++ .open = efi_file_open, ++ .close = efi_file_close, ++ .delete = efi_file_delete, ++ .read = efi_file_read, ++ .write = efi_file_write, ++ .getpos = efi_file_getpos, ++ .setpos = efi_file_setpos, ++ .getinfo = efi_file_getinfo, ++ .setinfo = efi_file_setinfo, ++ .flush = efi_file_flush, ++}; ++ ++struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp) ++{ ++ struct efi_simple_file_system_protocol *v; ++ struct efi_file_handle *f; ++ efi_status_t ret; ++ ++ v = efi_fs_from_path(fp); ++ if (!v) ++ return NULL; ++ ++ EFI_CALL(ret = v->open_volume(v, &f)); ++ if (ret != EFI_SUCCESS) ++ return NULL; ++ ++ /* skip over device-path nodes before the file path: */ ++ while (fp && !EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) ++ fp = efi_dp_next(fp); ++ ++ while (fp) { ++ struct efi_device_path_file_path *fdp = ++ container_of(fp, struct efi_device_path_file_path, dp); ++ struct efi_file_handle *f2; ++ ++ if (!EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) { ++ printf("bad file path!\n"); ++ f->close(f); ++ return NULL; ++ } ++ ++ EFI_CALL(ret = f->open(f, &f2, (s16 *)fdp->str, ++ EFI_FILE_MODE_READ, 0)); ++ if (ret != EFI_SUCCESS) ++ return NULL; ++ ++ fp = efi_dp_next(fp); ++ ++ EFI_CALL(f->close(f)); ++ f = f2; ++ } ++ ++ return f; ++} ++ ++static efi_status_t EFIAPI ++efi_open_volume(struct efi_simple_file_system_protocol *this, ++ struct efi_file_handle **root) ++{ ++ struct file_system *fs = to_fs(this); ++ ++ EFI_ENTRY("%p, %p", this, root); ++ ++ *root = file_open(fs, NULL, NULL, 0); ++ ++ return EFI_EXIT(EFI_SUCCESS); ++} ++ ++struct efi_simple_file_system_protocol * ++efi_simple_file_system(struct blk_desc *desc, int part, ++ struct efi_device_path *dp) ++{ ++ struct file_system *fs; ++ ++ fs = calloc(1, sizeof(*fs)); ++ fs->base.rev = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION; ++ fs->base.open_volume = efi_open_volume; ++ fs->desc = desc; ++ fs->part = part; ++ fs->dp = dp; ++ ++ return &fs->base; ++} +diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c +index f961407f50..469acae082 100644 +--- a/lib/efi_loader/efi_image_loader.c ++++ b/lib/efi_loader/efi_image_loader.c +@@ -17,6 +17,9 @@ DECLARE_GLOBAL_DATA_PTR; + + const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID; + const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID; ++const efi_guid_t efi_simple_file_system_protocol_guid = ++ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; ++const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID; + + static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel, + unsigned long rel_size, void *efi_reloc) + +From patchwork Wed Sep 13 22:05:35 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot,v3,12/21] efi_loader: support load_image() from a file-path +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813656 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-13-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt +Date: Wed, 13 Sep 2017 18:05:35 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +Previously we only supported the case when the EFI application loaded +the image into memory for us. But fallback.efi does not do this. + +Signed-off-by: Rob Clark +--- + lib/efi_loader/efi_boottime.c | 85 +++++++++++++++++++++++++++++++++++-------- + 1 file changed, 70 insertions(+), 15 deletions(-) + +diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c +index 837e61d8fe..ec40f41bcb 100644 +--- a/lib/efi_loader/efi_boottime.c ++++ b/lib/efi_loader/efi_boottime.c +@@ -762,6 +762,47 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob + list_add_tail(&obj->link, &efi_obj_list); + } + ++static efi_status_t load_image_from_path(struct efi_device_path *file_path, ++ void **buffer) ++{ ++ struct efi_file_info *info = NULL; ++ struct efi_file_handle *f; ++ static efi_status_t ret; ++ uint64_t bs; ++ ++ f = efi_file_from_path(file_path); ++ if (!f) ++ return EFI_DEVICE_ERROR; ++ ++ bs = 0; ++ EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, ++ &bs, info)); ++ if (ret == EFI_BUFFER_TOO_SMALL) { ++ info = malloc(bs); ++ EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, ++ &bs, info)); ++ } ++ if (ret != EFI_SUCCESS) ++ goto error; ++ ++ ret = efi_allocate_pool(EFI_LOADER_DATA, info->file_size, buffer); ++ if (ret) ++ goto error; ++ ++ EFI_CALL(ret = f->read(f, &info->file_size, *buffer)); ++ ++error: ++ free(info); ++ EFI_CALL(f->close(f)); ++ ++ if (ret != EFI_SUCCESS) { ++ efi_free_pool(*buffer); ++ *buffer = NULL; ++ } ++ ++ return ret; ++} ++ + static efi_status_t EFIAPI efi_load_image(bool boot_policy, + efi_handle_t parent_image, + struct efi_device_path *file_path, +@@ -769,25 +810,40 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, + unsigned long source_size, + efi_handle_t *image_handle) + { +- static struct efi_object loaded_image_info_obj = { +- .protocols = { +- { +- .guid = &efi_guid_loaded_image, +- }, +- }, +- }; + struct efi_loaded_image *info; + struct efi_object *obj; + + EFI_ENTRY("%d, %p, %p, %p, %ld, %p", boot_policy, parent_image, + file_path, source_buffer, source_size, image_handle); +- info = malloc(sizeof(*info)); +- loaded_image_info_obj.protocols[0].protocol_interface = info; +- obj = malloc(sizeof(loaded_image_info_obj)); +- memset(info, 0, sizeof(*info)); +- memcpy(obj, &loaded_image_info_obj, sizeof(loaded_image_info_obj)); +- obj->handle = info; +- info->file_path = file_path; ++ ++ info = calloc(1, sizeof(*info)); ++ obj = calloc(1, sizeof(*obj)); ++ ++ if (!source_buffer) { ++ struct efi_device_path *dp, *fp; ++ efi_status_t ret; ++ ++ ret = load_image_from_path(file_path, &source_buffer); ++ if (ret != EFI_SUCCESS) { ++ free(info); ++ free(obj); ++ return EFI_EXIT(ret); ++ } ++ ++ /* ++ * split file_path which contains both the device and ++ * file parts: ++ */ ++ efi_dp_split_file_path(file_path, &dp, &fp); ++ ++ efi_setup_loaded_image(info, obj, dp, fp); ++ } else { ++ /* In this case, file_path is the "device" path, ie. ++ * something like a HARDWARE_DEVICE:MEMORY_MAPPED ++ */ ++ efi_setup_loaded_image(info, obj, file_path, NULL); ++ } ++ + info->reserved = efi_load_pe(source_buffer, info); + if (!info->reserved) { + free(info); +@@ -796,7 +852,6 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, + } + + *image_handle = info; +- list_add_tail(&obj->link, &efi_obj_list); + + return EFI_EXIT(EFI_SUCCESS); + } + +From patchwork Wed Sep 13 22:05:36 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot, v3, + 13/21] efi_loader: make pool allocations cacheline aligned +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813657 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-14-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt +Date: Wed, 13 Sep 2017 18:05:36 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +This avoids printf() spam about file reads (such as loading an image) +into unaligned buffers (and the associated memcpy()). And generally +seems like a good idea. + +Signed-off-by: Rob Clark +--- + lib/efi_loader/efi_memory.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c +index 9e079f1fa3..1f0b9d0449 100644 +--- a/lib/efi_loader/efi_memory.c ++++ b/lib/efi_loader/efi_memory.c +@@ -43,7 +43,7 @@ void *efi_bounce_buffer; + */ + struct efi_pool_allocation { + u64 num_pages; +- char data[]; ++ char data[] __attribute__((aligned(ARCH_DMA_MINALIGN))); + }; + + /* +@@ -356,7 +356,8 @@ efi_status_t efi_allocate_pool(int pool_type, unsigned long size, + { + efi_status_t r; + efi_physical_addr_t t; +- u64 num_pages = (size + sizeof(u64) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; ++ u64 num_pages = (size + sizeof(struct efi_pool_allocation) + ++ EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + + if (size == 0) { + *buffer = NULL; + +From patchwork Wed Sep 13 22:05:37 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot,v3,14/21] efi_loader: efi variable support +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813643 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-15-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt +Date: Wed, 13 Sep 2017 18:05:37 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +Add EFI variable support, mapping to u-boot environment variables. +Variables are pretty important for setting up boot order, among other +things. If the board supports saveenv, then it will be called in +ExitBootServices() to persist variables set by the efi payload. (For +example, fallback.efi configuring BootOrder and BootXXXX load-option +variables.) + +Variables are *not* currently exposed at runtime, post ExitBootServices. +On boards without a dedicated device for storage, which the loaded OS +is not trying to also use, this is rather tricky. One idea, at least +for boards that can persist RAM across reboot, is to keep a "journal" +of modified variables in RAM, and then turn halt into a reboot into +u-boot, plus store variables, plus halt. Whatever the solution, it +likely involves some per-board support. + +Mapping between EFI variables and u-boot variables: + + efi_$guid_$varname = {attributes}(type)value + +For example: + + efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported= + "{ro,boot,run}(blob)0000000000000000" + efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder= + "(blob)00010000" + +The attributes are a comma separated list of these possible +attributes: + + + ro - read-only + + boot - boot-services access + + run - runtime access + +NOTE: with current implementation, no variables are available after +ExitBootServices, and all are persisted (if possible). + +If not specified, the attributes default to "{boot}". + +The required type is one of: + + + utf8 - raw utf8 string + + blob - arbitrary length hex string + +Signed-off-by: Rob Clark +--- + cmd/bootefi.c | 4 + + include/efi.h | 19 +++ + include/efi_loader.h | 10 ++ + lib/efi_loader/Makefile | 2 +- + lib/efi_loader/efi_boottime.c | 6 + + lib/efi_loader/efi_runtime.c | 17 ++- + lib/efi_loader/efi_variable.c | 335 ++++++++++++++++++++++++++++++++++++++++++ + 7 files changed, 388 insertions(+), 5 deletions(-) + create mode 100644 lib/efi_loader/efi_variable.c + +diff --git a/cmd/bootefi.c b/cmd/bootefi.c +index 0980088668..d3ae33e25b 100644 +--- a/cmd/bootefi.c ++++ b/cmd/bootefi.c +@@ -181,6 +181,10 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt, + goto exit; + } + ++ /* we don't support much: */ ++ env_set("efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported", ++ "{ro,boot}(blob)0000000000000000"); ++ + /* Call our payload! */ + debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry); + +diff --git a/include/efi.h b/include/efi.h +index ddd2b96417..04e83220b4 100644 +--- a/include/efi.h ++++ b/include/efi.h +@@ -324,6 +324,25 @@ extern char image_base[]; + /* Start and end of U-Boot image (for payload) */ + extern char _binary_u_boot_bin_start[], _binary_u_boot_bin_end[]; + ++/* ++ * Variable Attributes ++ */ ++#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 ++#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 ++#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 ++#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x0000000000000008 ++#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x0000000000000010 ++#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x0000000000000020 ++#define EFI_VARIABLE_APPEND_WRITE 0x0000000000000040 ++ ++#define EFI_VARIABLE_MASK (EFI_VARIABLE_NON_VOLATILE | \ ++ EFI_VARIABLE_BOOTSERVICE_ACCESS | \ ++ EFI_VARIABLE_RUNTIME_ACCESS | \ ++ EFI_VARIABLE_HARDWARE_ERROR_RECORD | \ ++ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | \ ++ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \ ++ EFI_VARIABLE_APPEND_WRITE) ++ + /** + * efi_get_sys_table() - Get access to the main EFI system table + * +diff --git a/include/efi_loader.h b/include/efi_loader.h +index b0c1e8fb78..9eee62dc9c 100644 +--- a/include/efi_loader.h ++++ b/include/efi_loader.h +@@ -277,6 +277,16 @@ efi_status_t __efi_runtime EFIAPI efi_get_time( + struct efi_time_cap *capabilities); + void efi_get_time_init(void); + ++efi_status_t EFIAPI efi_get_variable(s16 *variable_name, ++ efi_guid_t *vendor, u32 *attributes, ++ unsigned long *data_size, void *data); ++efi_status_t EFIAPI efi_get_next_variable( ++ unsigned long *variable_name_size, ++ s16 *variable_name, efi_guid_t *vendor); ++efi_status_t EFIAPI efi_set_variable(s16 *variable_name, ++ efi_guid_t *vendor, u32 attributes, ++ unsigned long data_size, void *data); ++ + #else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */ + + /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */ +diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile +index cce92cfeb5..f58cb13337 100644 +--- a/lib/efi_loader/Makefile ++++ b/lib/efi_loader/Makefile +@@ -16,7 +16,7 @@ always := $(efiprogs-y) + obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o + obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o + obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o +-obj-y += efi_file.o ++obj-y += efi_file.o efi_variable.o + obj-$(CONFIG_LCD) += efi_gop.o + obj-$(CONFIG_DM_VIDEO) += efi_gop.o + obj-$(CONFIG_PARTITIONS) += efi_disk.o +diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c +index ec40f41bcb..c406ff82ff 100644 +--- a/lib/efi_loader/efi_boottime.c ++++ b/lib/efi_loader/efi_boottime.c +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -942,6 +943,11 @@ static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle, + { + EFI_ENTRY("%p, %ld", image_handle, map_key); + ++#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) ++ /* save any EFI variables that have been written: */ ++ env_save(); ++#endif ++ + board_quiesce_devices(); + + /* Fix up caches for EFI payloads if necessary */ +diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c +index ad7f3754bd..2f95c766ac 100644 +--- a/lib/efi_loader/efi_runtime.c ++++ b/lib/efi_loader/efi_runtime.c +@@ -184,7 +184,16 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = { + /* Clean up system table */ + .ptr = &systab.boottime, + .patchto = NULL, +- }, ++ }, { ++ .ptr = &efi_runtime_services.get_variable, ++ .patchto = &efi_device_error, ++ }, { ++ .ptr = &efi_runtime_services.get_next_variable, ++ .patchto = &efi_device_error, ++ }, { ++ .ptr = &efi_runtime_services.set_variable, ++ .patchto = &efi_device_error, ++ } + }; + + static bool efi_runtime_tobedetached(void *p) +@@ -382,9 +391,9 @@ struct efi_runtime_services __efi_runtime_data efi_runtime_services = { + .set_wakeup_time = (void *)&efi_unimplemented, + .set_virtual_address_map = &efi_set_virtual_address_map, + .convert_pointer = (void *)&efi_invalid_parameter, +- .get_variable = (void *)&efi_device_error, +- .get_next_variable = (void *)&efi_device_error, +- .set_variable = (void *)&efi_device_error, ++ .get_variable = efi_get_variable, ++ .get_next_variable = efi_get_next_variable, ++ .set_variable = efi_set_variable, + .get_next_high_mono_count = (void *)&efi_device_error, + .reset_system = &efi_reset_system_boottime, + }; +diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c +new file mode 100644 +index 0000000000..5569b3d3f0 +--- /dev/null ++++ b/lib/efi_loader/efi_variable.c +@@ -0,0 +1,335 @@ ++/* ++ * EFI utils ++ * ++ * Copyright (c) 2017 Rob Clark ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++#include ++#include ++#include ++ ++#define READ_ONLY BIT(31) ++ ++/* ++ * Mapping between EFI variables and u-boot variables: ++ * ++ * efi_$guid_$varname = {attributes}(type)value ++ * ++ * For example: ++ * ++ * efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported= ++ * "{ro,boot,run}(blob)0000000000000000" ++ * efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder= ++ * "(blob)00010000" ++ * ++ * The attributes are a comma separated list of these possible ++ * attributes: ++ * ++ * + ro - read-only ++ * + boot - boot-services access ++ * + run - runtime access ++ * ++ * NOTE: with current implementation, no variables are available after ++ * ExitBootServices, and all are persisted (if possible). ++ * ++ * If not specified, the attributes default to "{boot}". ++ * ++ * The required type is one of: ++ * ++ * + utf8 - raw utf8 string ++ * + blob - arbitrary length hex string ++ * ++ * Maybe a utf16 type would be useful to for a string value to be auto ++ * converted to utf16? ++ */ ++ ++#define MAX_VAR_NAME 31 ++#define MAX_NATIVE_VAR_NAME \ ++ (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx_") + \ ++ (MAX_VAR_NAME * MAX_UTF8_PER_UTF16)) ++ ++static int hex(unsigned char ch) ++{ ++ if (ch >= 'a' && ch <= 'f') ++ return ch-'a'+10; ++ if (ch >= '0' && ch <= '9') ++ return ch-'0'; ++ if (ch >= 'A' && ch <= 'F') ++ return ch-'A'+10; ++ return -1; ++} ++ ++static const char *hex2mem(u8 *mem, const char *hexstr, int count) ++{ ++ memset(mem, 0, count/2); ++ ++ do { ++ int nibble; ++ ++ *mem = 0; ++ ++ if (!count || !*hexstr) ++ break; ++ ++ nibble = hex(*hexstr); ++ if (nibble < 0) ++ break; ++ ++ *mem = nibble; ++ count--; ++ hexstr++; ++ ++ if (!count || !*hexstr) ++ break; ++ ++ nibble = hex(*hexstr); ++ if (nibble < 0) ++ break; ++ ++ *mem = (*mem << 4) | nibble; ++ count--; ++ hexstr++; ++ mem++; ++ ++ } while (1); ++ ++ if (*hexstr) ++ return hexstr; ++ ++ return NULL; ++} ++ ++static char *mem2hex(char *hexstr, const u8 *mem, int count) ++{ ++ static const char hexchars[] = "0123456789abcdef"; ++ ++ while (count-- > 0) { ++ u8 ch = *mem++; ++ *hexstr++ = hexchars[ch >> 4]; ++ *hexstr++ = hexchars[ch & 0xf]; ++ } ++ ++ return hexstr; ++} ++ ++static efi_status_t efi_to_native(char *native, s16 *variable_name, ++ efi_guid_t *vendor) ++{ ++ size_t len; ++ ++ len = utf16_strlen((u16 *)variable_name); ++ if (len >= MAX_VAR_NAME) ++ return EFI_DEVICE_ERROR; ++ ++ native += sprintf(native, "efi_%pUl_", vendor); ++ native = (char *)utf16_to_utf8((u8 *)native, (u16 *)variable_name, len); ++ *native = '\0'; ++ ++ return EFI_SUCCESS; ++} ++ ++static const char *prefix(const char *str, const char *prefix) ++{ ++ size_t n = strlen(prefix); ++ if (!strncmp(prefix, str, n)) ++ return str + n; ++ return NULL; ++} ++ ++/* parse attributes part of variable value, if present: */ ++static const char *parse_attr(const char *str, u32 *attrp) ++{ ++ u32 attr = 0; ++ char sep = '{'; ++ ++ if (*str != '{') { ++ *attrp = EFI_VARIABLE_BOOTSERVICE_ACCESS; ++ return str; ++ } ++ ++ while (*str == sep) { ++ const char *s; ++ ++ str++; ++ ++ if ((s = prefix(str, "ro"))) { ++ attr |= READ_ONLY; ++ } else if ((s = prefix(str, "boot"))) { ++ attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS; ++ } else if ((s = prefix(str, "run"))) { ++ attr |= EFI_VARIABLE_RUNTIME_ACCESS; ++ } else { ++ printf("invalid attribute: %s\n", str); ++ break; ++ } ++ ++ str = s; ++ sep = ','; ++ } ++ ++ str++; ++ ++ *attrp = attr; ++ ++ return str; ++} ++ ++/* http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES#GetVariable.28.29 */ ++efi_status_t EFIAPI efi_get_variable(s16 *variable_name, ++ efi_guid_t *vendor, u32 *attributes, ++ unsigned long *data_size, void *data) ++{ ++ char native_name[MAX_NATIVE_VAR_NAME + 1]; ++ efi_status_t ret; ++ unsigned long in_size; ++ const char *val, *s; ++ u32 attr; ++ ++ EFI_ENTRY("%p %p %p %p %p", variable_name, vendor, attributes, ++ data_size, data); ++ ++ if (!variable_name || !vendor || !data_size) ++ return EFI_EXIT(EFI_INVALID_PARAMETER); ++ ++ ret = efi_to_native(native_name, variable_name, vendor); ++ if (ret) ++ return EFI_EXIT(ret); ++ ++ debug("%s: get '%s'\n", __func__, native_name); ++ ++ val = env_get(native_name); ++ if (!val) ++ return EFI_EXIT(EFI_NOT_FOUND); ++ ++ val = parse_attr(val, &attr); ++ ++ in_size = *data_size; ++ ++ if ((s = prefix(val, "(blob)"))) { ++ unsigned len = strlen(s); ++ ++ /* two characters per byte: */ ++ len = DIV_ROUND_UP(len, 2); ++ *data_size = len; ++ ++ if (in_size < len) ++ return EFI_EXIT(EFI_BUFFER_TOO_SMALL); ++ ++ if (!data) ++ return EFI_EXIT(EFI_INVALID_PARAMETER); ++ ++ if (hex2mem(data, s, len * 2)) ++ return EFI_EXIT(EFI_DEVICE_ERROR); ++ ++ debug("%s: got value: \"%s\"\n", __func__, s); ++ } else if ((s = prefix(val, "(utf8)"))) { ++ unsigned len = strlen(s) + 1; ++ ++ *data_size = len; ++ ++ if (in_size < len) ++ return EFI_EXIT(EFI_BUFFER_TOO_SMALL); ++ ++ if (!data) ++ return EFI_EXIT(EFI_INVALID_PARAMETER); ++ ++ memcpy(data, s, len); ++ ((char *)data)[len] = '\0'; ++ ++ debug("%s: got value: \"%s\"\n", __func__, (char *)data); ++ } else { ++ debug("%s: invalid value: '%s'\n", __func__, val); ++ return EFI_EXIT(EFI_DEVICE_ERROR); ++ } ++ ++ if (attributes) ++ *attributes = attr & EFI_VARIABLE_MASK; ++ ++ return EFI_EXIT(EFI_SUCCESS); ++} ++ ++/* http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES#GetNextVariableName.28.29 */ ++efi_status_t EFIAPI efi_get_next_variable( ++ unsigned long *variable_name_size, ++ s16 *variable_name, efi_guid_t *vendor) ++{ ++ EFI_ENTRY("%p %p %p", variable_name_size, variable_name, vendor); ++ ++ return EFI_EXIT(EFI_DEVICE_ERROR); ++} ++ ++/* http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES#SetVariable.28.29 */ ++efi_status_t EFIAPI efi_set_variable(s16 *variable_name, ++ efi_guid_t *vendor, u32 attributes, ++ unsigned long data_size, void *data) ++{ ++ char native_name[MAX_NATIVE_VAR_NAME + 1]; ++ efi_status_t ret = EFI_SUCCESS; ++ char *val, *s; ++ u32 attr; ++ ++ EFI_ENTRY("%p %p %x %lu %p", variable_name, vendor, attributes, ++ data_size, data); ++ ++ if (!variable_name || !vendor) ++ return EFI_EXIT(EFI_INVALID_PARAMETER); ++ ++ ret = efi_to_native(native_name, variable_name, vendor); ++ if (ret) ++ return EFI_EXIT(ret); ++ ++#define ACCESS_ATTR (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS) ++ ++ if ((data_size == 0) || !(attributes & ACCESS_ATTR)) { ++ /* delete the variable: */ ++ env_set(native_name, NULL); ++ return EFI_EXIT(EFI_SUCCESS); ++ } ++ ++ val = env_get(native_name); ++ if (val) { ++ parse_attr(val, &attr); ++ ++ if (attr & READ_ONLY) ++ return EFI_EXIT(EFI_WRITE_PROTECTED); ++ } ++ ++ val = malloc(2 * data_size + strlen("{ro,run,boot}(blob)") + 1); ++ if (!val) ++ return EFI_EXIT(EFI_OUT_OF_RESOURCES); ++ ++ s = val; ++ ++ /* store attributes: */ ++ attributes &= (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS); ++ s += sprintf(s, "{"); ++ while (attributes) { ++ u32 attr = 1 << (ffs(attributes) - 1); ++ ++ if (attr == EFI_VARIABLE_BOOTSERVICE_ACCESS) ++ s += sprintf(s, "boot"); ++ else if (attr == EFI_VARIABLE_RUNTIME_ACCESS) ++ s += sprintf(s, "run"); ++ ++ attributes &= ~attr; ++ if (attributes) ++ s += sprintf(s, ","); ++ } ++ s += sprintf(s, "}"); ++ ++ /* store payload: */ ++ s += sprintf(s, "(blob)"); ++ s = mem2hex(s, data, data_size); ++ *s = '\0'; ++ ++ debug("%s: setting: %s=%s\n", __func__, native_name, val); ++ ++ if (env_set(native_name, val)) ++ ret = EFI_DEVICE_ERROR; ++ ++ free(val); ++ ++ return EFI_EXIT(ret); ++} + +From patchwork Wed Sep 13 22:05:38 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot,v3,15/21] efi_loader: add bootmgr +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813660 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-16-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt , Peter Jones +Date: Wed, 13 Sep 2017 18:05:38 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +Similar to a "real" UEFI implementation, the bootmgr looks at the +BootOrder and BootXXXX variables to try to find an EFI payload to load +and boot. This is added as a sub-command of bootefi. + +The idea is that the distro bootcmd would first try loading a payload +via the bootmgr, and then if that fails (ie. first boot or corrupted +EFI variables) it would fallback to loading bootaa64.efi. (Which +would then load fallback.efi which would look for \EFI\*\boot.csv and +populate BootOrder and BootXXXX based on what it found.) + +Signed-off-by: Rob Clark +--- + cmd/bootefi.c | 48 +++++++++- + include/config_distro_bootcmd.h | 5 ++ + include/efi_api.h | 4 + + include/efi_loader.h | 6 ++ + lib/efi_loader/Makefile | 2 +- + lib/efi_loader/efi_bootmgr.c | 180 ++++++++++++++++++++++++++++++++++++++ + lib/efi_loader/efi_boottime.c | 6 +- + lib/efi_loader/efi_image_loader.c | 1 + + 8 files changed, 246 insertions(+), 6 deletions(-) + create mode 100644 lib/efi_loader/efi_bootmgr.c + +diff --git a/cmd/bootefi.c b/cmd/bootefi.c +index d3ae33e25b..fcd8dbafc1 100644 +--- a/cmd/bootefi.c ++++ b/cmd/bootefi.c +@@ -219,6 +219,36 @@ exit: + return ret; + } + ++static int do_bootefi_bootmgr_exec(unsigned long fdt_addr) ++{ ++ struct efi_device_path *device_path, *file_path; ++ void *addr; ++ efi_status_t r; ++ ++ /* Initialize and populate EFI object list */ ++ if (!efi_obj_list_initalized) ++ efi_init_obj_list(); ++ ++ /* ++ * gd lives in a fixed register which may get clobbered while we execute ++ * the payload. So save it here and restore it on every callback entry ++ */ ++ efi_save_gd(); ++ ++ addr = efi_bootmgr_load(&device_path, &file_path); ++ if (!addr) ++ return 1; ++ ++ printf("## Starting EFI application at %p ...\n", addr); ++ r = do_bootefi_exec(addr, (void *)fdt_addr, device_path, file_path); ++ printf("## Application terminated, r = %lu\n", ++ r & ~EFI_ERROR_MASK); ++ ++ if (r != EFI_SUCCESS) ++ return 1; ++ ++ return 0; ++} + + /* Interpreter command to boot an arbitrary EFI image from memory */ + static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +@@ -237,7 +267,14 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) + memcpy((char *)addr, __efi_hello_world_begin, size); + } else + #endif +- { ++ if (!strcmp(argv[1], "bootmgr")) { ++ unsigned long fdt_addr = 0; ++ ++ if (argc > 2) ++ fdt_addr = simple_strtoul(argv[2], NULL, 16); ++ ++ return do_bootefi_bootmgr_exec(fdt_addr); ++ } else { + saddr = argv[1]; + + addr = simple_strtoul(saddr, NULL, 16); +@@ -270,7 +307,11 @@ static char bootefi_help_text[] = + "hello\n" + " - boot a sample Hello World application stored within U-Boot" + #endif +- ; ++ "bootmgr [fdt addr]\n" ++ " - load and boot EFI payload based on BootOrder/BootXXXX variables.\n" ++ "\n" ++ " If specified, the device tree located at gets\n" ++ " exposed as EFI configuration table.\n"; + #endif + + U_BOOT_CMD( +@@ -308,6 +349,9 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path) + #endif + } + ++ if (!path) ++ return; ++ + if (strcmp(dev, "Net")) { + /* Add leading / to fs paths, because they're absolute */ + snprintf(filename, sizeof(filename), "/%s", path); +diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h +index 9ed6b9892c..e0d0034ed3 100644 +--- a/include/config_distro_bootcmd.h ++++ b/include/config_distro_bootcmd.h +@@ -112,6 +112,11 @@ + + #define BOOTENV_SHARED_EFI \ + "boot_efi_binary=" \ ++ "if fdt addr ${fdt_addr_r}; then " \ ++ "bootefi bootmgr ${fdt_addr_r};" \ ++ "else " \ ++ "bootefi bootmgr ${fdtcontroladdr};" \ ++ "fi;" \ + "load ${devtype} ${devnum}:${distro_bootpart} " \ + "${kernel_addr_r} efi/boot/"BOOTEFI_NAME"; " \ + "if fdt addr ${fdt_addr_r}; then " \ +diff --git a/include/efi_api.h b/include/efi_api.h +index 1aae96355f..d0aefa8221 100644 +--- a/include/efi_api.h ++++ b/include/efi_api.h +@@ -211,6 +211,10 @@ struct efi_runtime_services { + EFI_GUID(0x00000000, 0x0000, 0x0000, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + ++#define EFI_GLOBAL_VARIABLE_GUID \ ++ EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, \ ++ 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c) ++ + #define LOADED_IMAGE_PROTOCOL_GUID \ + EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, \ + 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) +diff --git a/include/efi_loader.h b/include/efi_loader.h +index 9eee62dc9c..adc0bcf609 100644 +--- a/include/efi_loader.h ++++ b/include/efi_loader.h +@@ -61,6 +61,7 @@ extern const struct efi_device_path_to_text_protocol efi_device_path_to_text; + + uint16_t *efi_dp_str(struct efi_device_path *dp); + ++extern const efi_guid_t efi_global_variable_guid; + extern const efi_guid_t efi_guid_console_control; + extern const efi_guid_t efi_guid_device_path; + extern const efi_guid_t efi_guid_loaded_image; +@@ -209,6 +210,8 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table + void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *obj, + struct efi_device_path *device_path, + struct efi_device_path *file_path); ++efi_status_t efi_load_image_from_path(struct efi_device_path *file_path, ++ void **buffer); + + #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER + extern void *efi_bounce_buffer; +@@ -287,6 +290,9 @@ efi_status_t EFIAPI efi_set_variable(s16 *variable_name, + efi_guid_t *vendor, u32 attributes, + unsigned long data_size, void *data); + ++void *efi_bootmgr_load(struct efi_device_path **device_path, ++ struct efi_device_path **file_path); ++ + #else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */ + + /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */ +diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile +index f58cb13337..930c0e218e 100644 +--- a/lib/efi_loader/Makefile ++++ b/lib/efi_loader/Makefile +@@ -16,7 +16,7 @@ always := $(efiprogs-y) + obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o + obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o + obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o +-obj-y += efi_file.o efi_variable.o ++obj-y += efi_file.o efi_variable.o efi_bootmgr.o + obj-$(CONFIG_LCD) += efi_gop.o + obj-$(CONFIG_DM_VIDEO) += efi_gop.o + obj-$(CONFIG_PARTITIONS) += efi_disk.o +diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c +new file mode 100644 +index 0000000000..857d88a879 +--- /dev/null ++++ b/lib/efi_loader/efi_bootmgr.c +@@ -0,0 +1,180 @@ ++/* ++ * EFI utils ++ * ++ * Copyright (c) 2017 Rob Clark ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++#include ++#include ++#include ++#include ++ ++static const struct efi_boot_services *bs; ++static const struct efi_runtime_services *rs; ++ ++#define LOAD_OPTION_ACTIVE 0x00000001 ++#define LOAD_OPTION_FORCE_RECONNECT 0x00000002 ++#define LOAD_OPTION_HIDDEN 0x00000008 ++ ++/* ++ * bootmgr implements the logic of trying to find a payload to boot ++ * based on the BootOrder + BootXXXX variables, and then loading it. ++ * ++ * TODO detecting a special key held (f9?) and displaying a boot menu ++ * like you would get on a PC would be clever. ++ * ++ * TODO if we had a way to write and persist variables after the OS ++ * has started, we'd also want to check OsIndications to see if we ++ * should do normal or recovery boot. ++ */ ++ ++ ++/* ++ * See section 3.1.3 in the v2.7 UEFI spec for more details on ++ * the layout of EFI_LOAD_OPTION. In short it is: ++ * ++ * typedef struct _EFI_LOAD_OPTION { ++ * UINT32 Attributes; ++ * UINT16 FilePathListLength; ++ * // CHAR16 Description[]; <-- variable length, NULL terminated ++ * // EFI_DEVICE_PATH_PROTOCOL FilePathList[]; <-- FilePathListLength bytes ++ * // UINT8 OptionalData[]; ++ * } EFI_LOAD_OPTION; ++ */ ++struct load_option { ++ u32 attributes; ++ u16 file_path_length; ++ u16 *label; ++ struct efi_device_path *file_path; ++ u8 *optional_data; ++}; ++ ++/* parse an EFI_LOAD_OPTION, as described above */ ++static void parse_load_option(struct load_option *lo, void *ptr) ++{ ++ lo->attributes = *(u32 *)ptr; ++ ptr += sizeof(u32); ++ ++ lo->file_path_length = *(u16 *)ptr; ++ ptr += sizeof(u16); ++ ++ lo->label = ptr; ++ ptr += (utf16_strlen(lo->label) + 1) * 2; ++ ++ lo->file_path = ptr; ++ ptr += lo->file_path_length; ++ ++ lo->optional_data = ptr; ++} ++ ++/* free() the result */ ++static void *get_var(u16 *name, const efi_guid_t *vendor, ++ unsigned long *size) ++{ ++ efi_guid_t *v = (efi_guid_t *)vendor; ++ efi_status_t ret; ++ void *buf = NULL; ++ ++ *size = 0; ++ EFI_CALL(ret = rs->get_variable((s16 *)name, v, NULL, size, buf)); ++ if (ret == EFI_BUFFER_TOO_SMALL) { ++ buf = malloc(*size); ++ EFI_CALL(ret = rs->get_variable((s16 *)name, v, NULL, size, buf)); ++ } ++ ++ if (ret != EFI_SUCCESS) { ++ free(buf); ++ *size = 0; ++ return NULL; ++ } ++ ++ return buf; ++} ++ ++/* ++ * Attempt to load load-option number 'n', returning device_path and file_path ++ * if successful. This checks that the EFI_LOAD_OPTION is active (enabled) ++ * and that the specified file to boot exists. ++ */ ++static void *try_load_entry(uint16_t n, struct efi_device_path **device_path, ++ struct efi_device_path **file_path) ++{ ++ struct load_option lo; ++ u16 varname[] = L"Boot0000"; ++ u16 hexmap[] = L"0123456789ABCDEF"; ++ void *load_option, *image = NULL; ++ unsigned long size; ++ ++ varname[4] = hexmap[(n & 0xf000) >> 12]; ++ varname[5] = hexmap[(n & 0x0f00) >> 8]; ++ varname[6] = hexmap[(n & 0x00f0) >> 4]; ++ varname[7] = hexmap[(n & 0x000f) >> 0]; ++ ++ load_option = get_var(varname, &efi_global_variable_guid, &size); ++ if (!load_option) ++ return NULL; ++ ++ parse_load_option(&lo, load_option); ++ ++ if (lo.attributes & LOAD_OPTION_ACTIVE) { ++ efi_status_t ret; ++ u16 *str = NULL; ++ ++ debug("%s: trying to load \"%ls\" from: %ls\n", __func__, ++ lo.label, (str = efi_dp_str(lo.file_path))); ++ efi_free_pool(str); ++ ++ ret = efi_load_image_from_path(lo.file_path, &image); ++ ++ if (ret != EFI_SUCCESS) ++ goto error; ++ ++ printf("Booting: %ls\n", lo.label); ++ efi_dp_split_file_path(lo.file_path, device_path, file_path); ++ } ++ ++error: ++ free(load_option); ++ ++ return image; ++} ++ ++/* ++ * Attempt to load, in the order specified by BootOrder EFI variable, the ++ * available load-options, finding and returning the first one that can ++ * be loaded successfully. ++ */ ++void *efi_bootmgr_load(struct efi_device_path **device_path, ++ struct efi_device_path **file_path) ++{ ++ uint16_t *bootorder; ++ unsigned long size; ++ void *image = NULL; ++ int i, num; ++ ++ __efi_entry_check(); ++ ++ bs = systab.boottime; ++ rs = systab.runtime; ++ ++ bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size); ++ if (!bootorder) ++ goto error; ++ ++ num = size / sizeof(uint16_t); ++ for (i = 0; i < num; i++) { ++ debug("%s: trying to load Boot%04X\n", __func__, bootorder[i]); ++ image = try_load_entry(bootorder[i], device_path, file_path); ++ if (image) ++ break; ++ } ++ ++ free(bootorder); ++ ++error: ++ __efi_exit_check(); ++ ++ return image; ++} +diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c +index c406ff82ff..cea242cd49 100644 +--- a/lib/efi_loader/efi_boottime.c ++++ b/lib/efi_loader/efi_boottime.c +@@ -763,8 +763,8 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob + list_add_tail(&obj->link, &efi_obj_list); + } + +-static efi_status_t load_image_from_path(struct efi_device_path *file_path, +- void **buffer) ++efi_status_t efi_load_image_from_path(struct efi_device_path *file_path, ++ void **buffer) + { + struct efi_file_info *info = NULL; + struct efi_file_handle *f; +@@ -824,7 +824,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, + struct efi_device_path *dp, *fp; + efi_status_t ret; + +- ret = load_image_from_path(file_path, &source_buffer); ++ ret = efi_load_image_from_path(file_path, &source_buffer); + if (ret != EFI_SUCCESS) { + free(info); + free(obj); +diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c +index 469acae082..242e6a504b 100644 +--- a/lib/efi_loader/efi_image_loader.c ++++ b/lib/efi_loader/efi_image_loader.c +@@ -15,6 +15,7 @@ + + DECLARE_GLOBAL_DATA_PTR; + ++const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID; + const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID; + const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID; + const efi_guid_t efi_simple_file_system_protocol_guid = + +From patchwork Wed Sep 13 22:05:39 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot,v3,16/21] efi_loader: file_path should be variable length +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813647 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-17-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt , Peter Jones +Date: Wed, 13 Sep 2017 18:05:39 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +Signed-off-by: Rob Clark +--- + include/efi_api.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/efi_api.h b/include/efi_api.h +index d0aefa8221..604c5b7ec4 100644 +--- a/include/efi_api.h ++++ b/include/efi_api.h +@@ -373,7 +373,7 @@ struct efi_device_path_cdrom_path { + + struct efi_device_path_file_path { + struct efi_device_path dp; +- u16 str[32]; ++ u16 str[]; + } __packed; + + #define BLOCK_IO_GUID \ + +From patchwork Wed Sep 13 22:05:40 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot, v3, + 17/21] efi_loader: set loaded image code/data type properly +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813655 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-18-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt +Date: Wed, 13 Sep 2017 18:05:40 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +These should be set according to the image type. Shell.efi and SCT.efi +use these fields to determine what sort of image they are loading. + +Signed-off-by: Rob Clark +--- + include/pe.h | 6 ++++++ + lib/efi_loader/efi_image_loader.c | 22 ++++++++++++++++++++++ + 2 files changed, 28 insertions(+) + +diff --git a/include/pe.h b/include/pe.h +index deb35a0ea4..4ef3e92efa 100644 +--- a/include/pe.h ++++ b/include/pe.h +@@ -62,6 +62,12 @@ typedef struct _IMAGE_DATA_DIRECTORY { + + #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + ++/* PE32+ Subsystem type for EFI images */ ++#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 ++#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 ++#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 ++#define IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 ++ + typedef struct _IMAGE_OPTIONAL_HEADER64 { + uint16_t Magic; /* 0x20b */ + uint8_t MajorLinkerVersion; +diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c +index 242e6a504b..af29cc4f04 100644 +--- a/lib/efi_loader/efi_image_loader.c ++++ b/lib/efi_loader/efi_image_loader.c +@@ -94,6 +94,7 @@ void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info) + unsigned long virt_size = 0; + bool can_run_nt64 = true; + bool can_run_nt32 = true; ++ uint16_t image_type; + + #if defined(CONFIG_ARM64) + can_run_nt32 = false; +@@ -139,6 +140,7 @@ void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info) + entry = efi_reloc + opt->AddressOfEntryPoint; + rel_size = opt->DataDirectory[rel_idx].Size; + rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress; ++ image_type = opt->Subsystem; + } else if (can_run_nt32 && + (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)) { + IMAGE_OPTIONAL_HEADER32 *opt = &nt->OptionalHeader; +@@ -152,12 +154,32 @@ void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info) + entry = efi_reloc + opt->AddressOfEntryPoint; + rel_size = opt->DataDirectory[rel_idx].Size; + rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress; ++ image_type = opt->Subsystem; + } else { + printf("%s: Invalid optional header magic %x\n", __func__, + nt->OptionalHeader.Magic); + return NULL; + } + ++ switch (image_type) { ++ case IMAGE_SUBSYSTEM_EFI_APPLICATION: ++ loaded_image_info->image_code_type = EFI_LOADER_CODE; ++ loaded_image_info->image_data_type = EFI_LOADER_DATA; ++ break; ++ case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: ++ loaded_image_info->image_code_type = EFI_BOOT_SERVICES_CODE; ++ loaded_image_info->image_data_type = EFI_BOOT_SERVICES_DATA; ++ break; ++ case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: ++ case IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER: ++ loaded_image_info->image_code_type = EFI_RUNTIME_SERVICES_CODE; ++ loaded_image_info->image_data_type = EFI_RUNTIME_SERVICES_DATA; ++ break; ++ default: ++ printf("%s: invalid image type: %u\n", __func__, image_type); ++ break; ++ } ++ + /* Load sections into RAM */ + for (i = num_sections - 1; i >= 0; i--) { + IMAGE_SECTION_HEADER *sec = §ions[i]; + +From patchwork Wed Sep 13 22:05:41 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [U-Boot,v3,18/21] efi_loader: print GUIDs +X-Patchwork-Submitter: Rob Clark +X-Patchwork-Id: 813646 +X-Patchwork-Delegate: agraf@suse.de +Message-Id: <20170913220546.19560-19-robdclark@gmail.com> +To: U-Boot Mailing List +Cc: Heinrich Schuchardt +Date: Wed, 13 Sep 2017 18:05:41 -0400 +From: Rob Clark +List-Id: U-Boot discussion + +Utilize printf GUID support to print GUIDs. + +Signed-off-by: Rob Clark +--- + lib/efi_loader/efi_boottime.c | 22 +++++++++++----------- + lib/efi_loader/efi_variable.c | 6 +++--- + 2 files changed, 14 insertions(+), 14 deletions(-) + +diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c +index cea242cd49..b6f32c98d9 100644 +--- a/lib/efi_loader/efi_boottime.c ++++ b/lib/efi_loader/efi_boottime.c +@@ -514,7 +514,7 @@ static efi_status_t EFIAPI efi_install_protocol_interface_ext(void **handle, + efi_guid_t *protocol, int protocol_interface_type, + void *protocol_interface) + { +- EFI_ENTRY("%p, %p, %d, %p", handle, protocol, protocol_interface_type, ++ EFI_ENTRY("%p, %pUl, %d, %p", handle, protocol, protocol_interface_type, + protocol_interface); + + return EFI_EXIT(efi_install_protocol_interface(handle, protocol, +@@ -526,7 +526,7 @@ static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle, + efi_guid_t *protocol, void *old_interface, + void *new_interface) + { +- EFI_ENTRY("%p, %p, %p, %p", handle, protocol, old_interface, ++ EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, old_interface, + new_interface); + return EFI_EXIT(EFI_ACCESS_DENIED); + } +@@ -575,7 +575,7 @@ out: + static efi_status_t EFIAPI efi_uninstall_protocol_interface_ext(void *handle, + efi_guid_t *protocol, void *protocol_interface) + { +- EFI_ENTRY("%p, %p, %p", handle, protocol, protocol_interface); ++ EFI_ENTRY("%p, %pUl, %p", handle, protocol, protocol_interface); + + return EFI_EXIT(efi_uninstall_protocol_interface(handle, protocol, + protocol_interface)); +@@ -585,7 +585,7 @@ static efi_status_t EFIAPI efi_register_protocol_notify(efi_guid_t *protocol, + struct efi_event *event, + void **registration) + { +- EFI_ENTRY("%p, %p, %p", protocol, event, registration); ++ EFI_ENTRY("%pUl, %p, %p", protocol, event, registration); + return EFI_EXIT(EFI_OUT_OF_RESOURCES); + } + +@@ -655,7 +655,7 @@ static efi_status_t EFIAPI efi_locate_handle_ext( + efi_guid_t *protocol, void *search_key, + unsigned long *buffer_size, efi_handle_t *buffer) + { +- EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key, ++ EFI_ENTRY("%d, %pUl, %p, %p, %p", search_type, protocol, search_key, + buffer_size, buffer); + + return EFI_EXIT(efi_locate_handle(search_type, protocol, search_key, +@@ -723,7 +723,7 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table + static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid, + void *table) + { +- EFI_ENTRY("%p, %p", guid, table); ++ EFI_ENTRY("%pUl, %p", guid, table); + return EFI_EXIT(efi_install_configuration_table(guid, table)); + } + +@@ -1012,7 +1012,7 @@ static efi_status_t EFIAPI efi_close_protocol(void *handle, + void *agent_handle, + void *controller_handle) + { +- EFI_ENTRY("%p, %p, %p, %p", handle, protocol, agent_handle, ++ EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, agent_handle, + controller_handle); + return EFI_EXIT(EFI_NOT_FOUND); + } +@@ -1022,7 +1022,7 @@ static efi_status_t EFIAPI efi_open_protocol_information(efi_handle_t handle, + struct efi_open_protocol_info_entry **entry_buffer, + unsigned long *entry_count) + { +- EFI_ENTRY("%p, %p, %p, %p", handle, protocol, entry_buffer, ++ EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, entry_buffer, + entry_count); + return EFI_EXIT(EFI_NOT_FOUND); + } +@@ -1088,7 +1088,7 @@ static efi_status_t EFIAPI efi_locate_handle_buffer( + efi_status_t r; + unsigned long buffer_size = 0; + +- EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key, ++ EFI_ENTRY("%d, %pUl, %p, %p, %p", search_type, protocol, search_key, + no_handles, buffer); + + if (!no_handles || !buffer) { +@@ -1120,7 +1120,7 @@ static efi_status_t EFIAPI efi_locate_protocol(efi_guid_t *protocol, + struct list_head *lhandle; + int i; + +- EFI_ENTRY("%p, %p, %p", protocol, registration, protocol_interface); ++ EFI_ENTRY("%pUl, %p, %p", protocol, registration, protocol_interface); + + if (!protocol || !protocol_interface) + return EFI_EXIT(EFI_INVALID_PARAMETER); +@@ -1228,7 +1228,7 @@ static efi_status_t EFIAPI efi_open_protocol( + int i; + efi_status_t r = EFI_INVALID_PARAMETER; + +- EFI_ENTRY("%p, %p, %p, %p, %p, 0x%x", handle, protocol, ++ EFI_ENTRY("%p, %pUl, %p, %p, %p, 0x%x", handle, protocol, + protocol_interface, agent_handle, controller_handle, + attributes); + +diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c +index 5569b3d3f0..6c177da3a6 100644 +--- a/lib/efi_loader/efi_variable.c ++++ b/lib/efi_loader/efi_variable.c +@@ -187,7 +187,7 @@ efi_status_t EFIAPI efi_get_variable(s16 *variable_name, + const char *val, *s; + u32 attr; + +- EFI_ENTRY("%p %p %p %p %p", variable_name, vendor, attributes, ++ EFI_ENTRY("\"%ls\" %pUl %p %p %p", variable_name, vendor, attributes, + data_size, data); + + if (!variable_name || !vendor || !data_size) +@@ -255,7 +255,7 @@ efi_status_t EFIAPI efi_get_next_variable( + unsigned long *variable_name_size, + s16 *variable_name, efi_guid_t *vendor) + { +- EFI_ENTRY("%p %p %p", variable_name_size, variable_name, vendor); ++ EFI_ENTRY("%p \"%ls\" %pUl", variable_name_size, variable_name, vendor); + + return EFI_EXIT(EFI_DEVICE_ERROR); + } +@@ -270,7 +270,7 @@ efi_status_t EFIAPI efi_set_variable(s16 *variable_name, + char *val, *s; + u32 attr; + +- EFI_ENTRY("%p %p %x %lu %p", variable_name, vendor, attributes, ++ EFI_ENTRY("\"%ls\" %pUl %x %lu %p", variable_name, vendor, attributes, + data_size, data); + + if (!variable_name || !vendor) + diff --git a/uefi-fixes.patch b/uefi-fixes.patch deleted file mode 100644 index 662c8b5..0000000 --- a/uefi-fixes.patch +++ /dev/null @@ -1,2342 +0,0 @@ -From 8cb4ccaf3be1258bfaa8069501028ad1e825489d Mon Sep 17 00:00:00 2001 -From: Rob Clark -Date: Mon, 24 Jul 2017 10:15:08 -0400 -Subject: [PATCH 01/13] efi_loader: add back optional efi_handler::open() - -In some cases it is useful to defer creation of the protocol interface -object. So add back an optional ->open() hook that is used if -protcol_interface is NULL. - -I've slightly simplified the fxn ptr signature to remove unneeded args, -and so compiler will complain if patches that used the "old way" are, -and which do not need this extra complexity, are rebased. - -Signed-off-by: Rob Clark ---- - include/efi_loader.h | 12 +++++++++++- - lib/efi_loader/efi_boottime.c | 30 ++++++++++++++++++++++++------ - 2 files changed, 35 insertions(+), 7 deletions(-) - -diff --git a/include/efi_loader.h b/include/efi_loader.h -index 037cc7c543..03c4ed5e1c 100644 ---- a/include/efi_loader.h -+++ b/include/efi_loader.h -@@ -70,10 +70,17 @@ extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop; - /* - * When the UEFI payload wants to open a protocol on an object to get its - * interface (usually a struct with callback functions), this struct maps the -- * protocol GUID to the respective protocol interface */ -+ * protocol GUID to the respective protocol interface. -+ * -+ * The optional ->open() fxn can be used for cases where the protocol -+ * interface is constructed on-demand, and is called if protocol_interface -+ * is NULL. -+ */ - struct efi_handler { - const efi_guid_t *guid; - void *protocol_interface; -+ efi_status_t (EFIAPI *open)(void *handle, const efi_guid_t *protocol, -+ void **protocol_interface); - }; - - /* -@@ -191,6 +198,9 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, - int efi_memory_init(void); - /* Adds new or overrides configuration table entry to the system table */ - efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table); -+efi_status_t efi_get_protocol(struct efi_object *efiobj, -+ struct efi_handler *handler, -+ void **protocol_interface); - - #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER - extern void *efi_bounce_buffer; -diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c -index 59479eddb9..4b78f6d556 100644 ---- a/lib/efi_loader/efi_boottime.c -+++ b/lib/efi_loader/efi_boottime.c -@@ -1004,6 +1004,23 @@ out: - return EFI_EXIT(r); - } - -+efi_status_t efi_get_protocol(struct efi_object *efiobj, -+ struct efi_handler *handler, -+ void **protocol_interface) -+{ -+ efi_status_t ret = EFI_SUCCESS; -+ -+ if (!handler->protocol_interface) { -+ ret = handler->open(efiobj->handle, -+ handler->guid, -+ &handler->protocol_interface); -+ } -+ *protocol_interface = -+ handler->protocol_interface; -+ -+ return ret; -+} -+ - static efi_status_t EFIAPI efi_locate_protocol(efi_guid_t *protocol, - void *registration, - void **protocol_interface) -@@ -1026,9 +1043,10 @@ static efi_status_t EFIAPI efi_locate_protocol(efi_guid_t *protocol, - if (!handler->guid) - continue; - if (!guidcmp(handler->guid, protocol)) { -- *protocol_interface = -- handler->protocol_interface; -- return EFI_EXIT(EFI_SUCCESS); -+ efi_status_t ret; -+ ret = efi_get_protocol(efiobj, handler, -+ protocol_interface); -+ return EFI_EXIT(ret); - } - } - } -@@ -1162,12 +1180,12 @@ static efi_status_t EFIAPI efi_open_protocol( - if (!hprotocol) - continue; - if (!guidcmp(hprotocol, protocol)) { -+ r = EFI_SUCCESS; - if (attributes != - EFI_OPEN_PROTOCOL_TEST_PROTOCOL) { -- *protocol_interface = -- handler->protocol_interface; -+ r = efi_get_protocol(efiobj, handler, -+ protocol_interface); - } -- r = EFI_SUCCESS; - goto out; - } - } --- -2.13.3 - -From 784e48fe7488893209f4569a2a1664890fd75d4e Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Tue, 25 Jul 2017 13:40:43 -0400 -Subject: [PATCH 02/13] part: extract MBR signature from partitions - -EFI client programs need the signature information from the partition -table to determine the disk a partition is on, so we need to fill that -in here. - -Signed-off-by: Peter Jones -[separated from efi_loader part, and fixed build-errors for non- - CONFIG_EFI_PARTITION case] -Signed-off-by: Rob Clark ---- - disk/part_dos.c | 12 +++++++++--- - disk/part_efi.c | 20 ++++++++++++++++++++ - include/blk.h | 15 +++++++++++++++ - include/efi.h | 4 ++++ - include/part.h | 3 ++- - include/part_efi.h | 4 ---- - 6 files changed, 50 insertions(+), 8 deletions(-) - -diff --git a/disk/part_dos.c b/disk/part_dos.c -index 7ede15ec26..850a538e83 100644 ---- a/disk/part_dos.c -+++ b/disk/part_dos.c -@@ -89,14 +89,20 @@ static int test_block_type(unsigned char *buffer) - - static int part_test_dos(struct blk_desc *dev_desc) - { -- ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz); -+ ALLOC_CACHE_ALIGN_BUFFER(legacy_mbr, mbr, dev_desc->blksz); - -- if (blk_dread(dev_desc, 0, 1, (ulong *)buffer) != 1) -+ if (blk_dread(dev_desc, 0, 1, (ulong *)mbr) != 1) - return -1; - -- if (test_block_type(buffer) != DOS_MBR) -+ if (test_block_type((unsigned char *)mbr) != DOS_MBR) - return -1; - -+ if (dev_desc->sig_type == SIG_TYPE_NONE && -+ mbr->unique_mbr_signature != 0) { -+ dev_desc->sig_type = SIG_TYPE_MBR; -+ dev_desc->mbr_sig = mbr->unique_mbr_signature; -+ } -+ - return 0; - } - -diff --git a/disk/part_efi.c b/disk/part_efi.c -index 1b7ba27947..71e4188455 100644 ---- a/disk/part_efi.c -+++ b/disk/part_efi.c -@@ -871,11 +871,19 @@ static int is_pmbr_valid(legacy_mbr * mbr) - static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba, - gpt_header *pgpt_head, gpt_entry **pgpt_pte) - { -+ ALLOC_CACHE_ALIGN_BUFFER(legacy_mbr, mbr, dev_desc->blksz); -+ - if (!dev_desc || !pgpt_head) { - printf("%s: Invalid Argument(s)\n", __func__); - return 0; - } - -+ /* Read MBR Header from device */ -+ if (blk_dread(dev_desc, 0, 1, (ulong *)mbr) != 1) { -+ printf("*** ERROR: Can't read MBR header ***\n"); -+ return 0; -+ } -+ - /* Read GPT Header from device */ - if (blk_dread(dev_desc, (lbaint_t)lba, 1, pgpt_head) != 1) { - printf("*** ERROR: Can't read GPT header ***\n"); -@@ -885,6 +893,18 @@ static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba, - if (validate_gpt_header(pgpt_head, (lbaint_t)lba, dev_desc->lba)) - return 0; - -+ if (dev_desc->sig_type == SIG_TYPE_NONE) { -+ efi_guid_t empty = {}; -+ if (memcmp(&pgpt_head->disk_guid, &empty, sizeof(empty))) { -+ dev_desc->sig_type = SIG_TYPE_GUID; -+ memcpy(&dev_desc->guid_sig, &pgpt_head->disk_guid, -+ sizeof(empty)); -+ } else if (mbr->unique_mbr_signature != 0) { -+ dev_desc->sig_type = SIG_TYPE_MBR; -+ dev_desc->mbr_sig = mbr->unique_mbr_signature; -+ } -+ } -+ - /* Read and allocate Partition Table Entries */ - *pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head); - if (*pgpt_pte == NULL) { -diff --git a/include/blk.h b/include/blk.h -index ef29a07ee2..3a5e04c00d 100644 ---- a/include/blk.h -+++ b/include/blk.h -@@ -8,6 +8,8 @@ - #ifndef BLK_H - #define BLK_H - -+#include -+ - #ifdef CONFIG_SYS_64BIT_LBA - typedef uint64_t lbaint_t; - #define LBAFlength "ll" -@@ -35,6 +37,14 @@ enum if_type { - IF_TYPE_COUNT, /* Number of interface types */ - }; - -+enum sig_type { -+ SIG_TYPE_NONE, -+ SIG_TYPE_MBR, -+ SIG_TYPE_GUID, -+ -+ SIG_TYPE_COUNT /* Number of signature types */ -+}; -+ - /* - * With driver model (CONFIG_BLK) this is uclass platform data, accessible - * with dev_get_uclass_platdata(dev) -@@ -62,6 +72,11 @@ struct blk_desc { - char vendor[40+1]; /* IDE model, SCSI Vendor */ - char product[20+1]; /* IDE Serial no, SCSI product */ - char revision[8+1]; /* firmware revision */ -+ enum sig_type sig_type; /* Partition table signature type */ -+ union { -+ uint32_t mbr_sig; /* MBR integer signature */ -+ efi_guid_t guid_sig; /* GPT GUID Signature */ -+ }; - #if CONFIG_IS_ENABLED(BLK) - /* - * For now we have a few functions which take struct blk_desc as a -diff --git a/include/efi.h b/include/efi.h -index 02b78b31b1..87b0b43f20 100644 ---- a/include/efi.h -+++ b/include/efi.h -@@ -28,6 +28,10 @@ - - struct efi_device_path; - -+typedef struct { -+ u8 b[16]; -+} efi_guid_t; -+ - #define EFI_BITS_PER_LONG BITS_PER_LONG - - /* -diff --git a/include/part.h b/include/part.h -index 83bce05a43..ac5ee895e9 100644 ---- a/include/part.h -+++ b/include/part.h -@@ -259,8 +259,9 @@ struct part_driver { - #define U_BOOT_PART_TYPE(__name) \ - ll_entry_declare(struct part_driver, __name, part_driver) - --#if CONFIG_IS_ENABLED(EFI_PARTITION) - #include -+ -+#if CONFIG_IS_ENABLED(EFI_PARTITION) - /* disk/part_efi.c */ - /** - * write_gpt_table() - Write the GUID Partition Table to disk -diff --git a/include/part_efi.h b/include/part_efi.h -index 317c044795..31e6bc6e14 100644 ---- a/include/part_efi.h -+++ b/include/part_efi.h -@@ -58,10 +58,6 @@ - /* linux/include/efi.h */ - typedef u16 efi_char16_t; - --typedef struct { -- u8 b[16]; --} efi_guid_t; -- - /* based on linux/include/genhd.h */ - struct partition { - u8 boot_ind; /* 0x80 - active */ --- -2.13.3 - -From a6235e1a0f298f4e1e0271e772e457988f90ac2a Mon Sep 17 00:00:00 2001 -From: Peter Jones -Date: Wed, 21 Jun 2017 16:39:02 -0400 -Subject: [PATCH 03/13] efi: add some more device path structures - -Signed-off-by: Peter Jones ---- - include/efi_api.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 47 insertions(+), 2 deletions(-) - -diff --git a/include/efi_api.h b/include/efi_api.h -index ec1b321e8e..85afbeb72b 100644 ---- a/include/efi_api.h -+++ b/include/efi_api.h -@@ -290,22 +290,67 @@ struct efi_mac_addr { - u8 addr[32]; - }; - -+#define DEVICE_PATH_TYPE_ACPI_DEVICE 0x02 -+#define DEVICE_PATH_SUB_TYPE_ACPI_DEVICE 0x01 -+ -+#define EFI_PNP_ID(ID) (u32)(((ID) << 16) | 0x41D0) -+#define EISA_PNP_ID(ID) EFI_PNP_ID(ID) -+ -+struct efi_device_path_acpi_path { -+ struct efi_device_path dp; -+ u32 hid; -+ u32 uid; -+} __packed; -+ - #define DEVICE_PATH_TYPE_MESSAGING_DEVICE 0x03 -+# define DEVICE_PATH_SUB_TYPE_MSG_USB 0x05 - # define DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR 0x0b -+# define DEVICE_PATH_SUB_TYPE_MSG_SD 0x1a -+# define DEVICE_PATH_SUB_TYPE_MSG_MMC 0x1d -+ -+struct efi_device_path_usb { -+ struct efi_device_path dp; -+ u8 parent_port_number; -+ u8 usb_interface; -+} __packed; - - struct efi_device_path_mac_addr { - struct efi_device_path dp; - struct efi_mac_addr mac; - u8 if_type; --}; -+} __packed; -+ -+struct efi_device_path_sd_mmc_path { -+ struct efi_device_path dp; -+ u8 slot_number; -+} __packed; - - #define DEVICE_PATH_TYPE_MEDIA_DEVICE 0x04 -+# define DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH 0x01 -+# define DEVICE_PATH_SUB_TYPE_CDROM_PATH 0x02 - # define DEVICE_PATH_SUB_TYPE_FILE_PATH 0x04 - -+struct efi_device_path_hard_drive_path { -+ struct efi_device_path dp; -+ u32 partition_number; -+ u64 partition_start; -+ u64 partition_end; -+ u8 partition_signature[16]; -+ u8 partmap_type; -+ u8 signature_type; -+} __packed; -+ -+struct efi_device_path_cdrom_path { -+ struct efi_device_path dp; -+ u32 boot_entry; -+ u64 partition_start; -+ u64 partition_end; -+} __packed; -+ - struct efi_device_path_file_path { - struct efi_device_path dp; - u16 str[32]; --}; -+} __packed; - - #define BLOCK_IO_GUID \ - EFI_GUID(0x964e5b21, 0x6459, 0x11d2, \ --- -2.13.3 - -From 86eed9c21403969fdc69e508261a2e091c24897b Mon Sep 17 00:00:00 2001 -From: Rob Clark -Date: Sun, 23 Jul 2017 11:25:53 -0400 -Subject: [PATCH 04/13] fs: add fs_readdir() - -Needed to support efi file protocol. The fallback.efi loader wants -to be able to read the contents of the /EFI directory to find an OS -to boot. - -Currently only implemented for FAT, but that is all that UEFI is -required to support. - -Signed-off-by: Rob Clark ---- - fs/fat/fat.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++------------- - fs/fs.c | 25 +++++++++++++++++++++++++ - include/fat.h | 4 +++- - include/fs.h | 21 +++++++++++++++++++++ - 4 files changed, 95 insertions(+), 14 deletions(-) - -diff --git a/fs/fat/fat.c b/fs/fat/fat.c -index 9ad18f96ff..04d8616598 100644 ---- a/fs/fat/fat.c -+++ b/fs/fat/fat.c -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -575,17 +576,25 @@ static __u8 mkcksum(const char name[8], const char ext[3]) - /* - * Get the directory entry associated with 'filename' from the directory - * starting at 'startsect' -+ * -+ * Last two args are only used for dols==LS_READDIR - */ - __u8 get_dentfromdir_block[MAX_CLUSTSIZE] - __aligned(ARCH_DMA_MINALIGN); - --static dir_entry *get_dentfromdir(fsdata *mydata, int startsect, -- char *filename, dir_entry *retdent, -- int dols) -+static dir_entry *get_dentfromdir(fsdata *mydata, char *filename, -+ dir_entry *retdent, int dols, -+ loff_t pos, struct fs_dirent *d) - { - __u16 prevcksum = 0xffff; - __u32 curclust = START(retdent); - int files = 0, dirs = 0; -+ int readdir = 0; -+ -+ if (dols == LS_READDIR) { -+ readdir = 1; -+ dols = 0; -+ } - - debug("get_dentfromdir: %s\n", filename); - -@@ -618,7 +627,7 @@ static dir_entry *get_dentfromdir(fsdata *mydata, int startsect, - get_vfatname(mydata, curclust, - get_dentfromdir_block, - dentptr, l_name); -- if (dols) { -+ if (dols || readdir) { - int isdir; - char dirc; - int doit = 0; -@@ -637,7 +646,14 @@ static dir_entry *get_dentfromdir(fsdata *mydata, int startsect, - } - } - if (doit) { -- if (dirc == ' ') { -+ if (readdir) { -+ if ((dirs + files - 1) == pos) { -+ strcpy(d->name, l_name); -+ if (!isdir) -+ d->size = FAT2CPU32(dentptr->size); -+ return NULL; -+ } -+ } else if (dirc == ' ') { - printf(" %8u %s%c\n", - FAT2CPU32(dentptr->size), - l_name, -@@ -676,7 +692,7 @@ static dir_entry *get_dentfromdir(fsdata *mydata, int startsect, - } - - get_name(dentptr, s_name); -- if (dols) { -+ if (dols || readdir) { - int isdir = (dentptr->attr & ATTR_DIR); - char dirc; - int doit = 0; -@@ -694,7 +710,14 @@ static dir_entry *get_dentfromdir(fsdata *mydata, int startsect, - } - - if (doit) { -- if (dirc == ' ') { -+ if (readdir) { -+ if ((dirs + files - 1) == pos) { -+ strcpy(d->name, s_name); -+ if (!isdir) -+ d->size = FAT2CPU32(dentptr->size); -+ return NULL; -+ } -+ } else if (dirc == ' ') { - printf(" %8u %s%c\n", - FAT2CPU32(dentptr->size), - s_name, dirc); -@@ -825,7 +848,7 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer, - __u32 cursect; - int idx, isdir = 0; - int files = 0, dirs = 0; -- int ret = -1; -+ int ret = (dols == LS_READDIR) ? -ENOTDIR : -1; - int firsttime; - __u32 root_cluster = 0; - __u32 read_blk; -@@ -906,7 +929,8 @@ root_reparse: - if (!dols) - goto exit; - -- dols = LS_ROOT; -+ if (dols == LS_YES) -+ dols = LS_ROOT; - } else if ((idx = dirdelim(fnamecopy)) >= 0) { - isdir = 1; - fnamecopy[idx] = '\0'; -@@ -1151,8 +1175,6 @@ rootdir_done: - firsttime = 1; - - while (isdir) { -- int startsect = mydata->data_begin -- + START(dentptr) * mydata->clust_size; - dir_entry dent; - char *nextname = NULL; - -@@ -1177,10 +1199,14 @@ rootdir_done: - } - } - -- if (get_dentfromdir(mydata, startsect, subname, dentptr, -- isdir ? 0 : dols) == NULL) { -+ if (get_dentfromdir(mydata, subname, dentptr, -+ isdir ? 0 : dols, pos, buffer) == NULL) { - if (dols && !isdir) - *size = 0; -+ if (dols == LS_READDIR) { -+ struct fs_dirent *dent = buffer; -+ ret = dent->name[0] ? 0 : -ENOENT; -+ } - goto exit; - } - -@@ -1353,6 +1379,13 @@ int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len, - return ret; - } - -+int fat_readdir(const char *filename, loff_t offset, struct fs_dirent *dent) -+{ -+ loff_t actread; -+ return do_fat_read_at(filename, offset, dent, sizeof(*dent), -+ LS_READDIR, 0, &actread); -+} -+ - void fat_close(void) - { - } -diff --git a/fs/fs.c b/fs/fs.c -index 595ff1fe69..42a028a6ce 100644 ---- a/fs/fs.c -+++ b/fs/fs.c -@@ -69,6 +69,12 @@ static inline int fs_uuid_unsupported(char *uuid_str) - return -1; - } - -+static inline int fs_readdir_unsupported(const char *filename, loff_t offset, -+ struct fs_dirent *dent) -+{ -+ return -ENXIO; -+} -+ - struct fstype_info { - int fstype; - char *name; -@@ -92,6 +98,7 @@ struct fstype_info { - loff_t len, loff_t *actwrite); - void (*close)(void); - int (*uuid)(char *uuid_str); -+ int (*readdir)(const char *filename, loff_t offset, struct fs_dirent *dent); - }; - - static struct fstype_info fstypes[] = { -@@ -112,6 +119,7 @@ static struct fstype_info fstypes[] = { - .write = fs_write_unsupported, - #endif - .uuid = fs_uuid_unsupported, -+ .readdir = fat_readdir, - }, - #endif - #ifdef CONFIG_FS_EXT4 -@@ -131,6 +139,7 @@ static struct fstype_info fstypes[] = { - .write = fs_write_unsupported, - #endif - .uuid = ext4fs_uuid, -+ .readdir = fs_readdir_unsupported, - }, - #endif - #ifdef CONFIG_SANDBOX -@@ -146,6 +155,7 @@ static struct fstype_info fstypes[] = { - .read = fs_read_sandbox, - .write = fs_write_sandbox, - .uuid = fs_uuid_unsupported, -+ .readdir = fs_readdir_unsupported, - }, - #endif - #ifdef CONFIG_CMD_UBIFS -@@ -161,6 +171,7 @@ static struct fstype_info fstypes[] = { - .read = ubifs_read, - .write = fs_write_unsupported, - .uuid = fs_uuid_unsupported, -+ .readdir = fs_readdir_unsupported, - }, - #endif - { -@@ -175,6 +186,7 @@ static struct fstype_info fstypes[] = { - .read = fs_read_unsupported, - .write = fs_write_unsupported, - .uuid = fs_uuid_unsupported, -+ .readdir = fs_readdir_unsupported, - }, - }; - -@@ -334,6 +346,19 @@ int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len, - return ret; - } - -+int fs_readdir(const char *filename, loff_t offset, struct fs_dirent *dent) -+{ -+ struct fstype_info *info = fs_get_info(fs_type); -+ int ret; -+ -+ memset(dent, 0, sizeof(*dent)); -+ -+ ret = info->readdir(filename, offset, dent); -+ fs_close(); -+ -+ return ret; -+} -+ - int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], - int fstype) - { -diff --git a/include/fat.h b/include/fat.h -index 71879f01ca..0ef3f5be16 100644 ---- a/include/fat.h -+++ b/include/fat.h -@@ -61,8 +61,8 @@ - /* Flags telling whether we should read a file or list a directory */ - #define LS_NO 0 - #define LS_YES 1 --#define LS_DIR 1 - #define LS_ROOT 2 -+#define LS_READDIR 3 /* read directory entry at specified offset */ - - #define ISDIRDELIM(c) ((c) == '/' || (c) == '\\') - -@@ -210,5 +210,7 @@ int file_fat_write(const char *filename, void *buf, loff_t offset, loff_t len, - loff_t *actwrite); - int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len, - loff_t *actread); -+struct fs_dirent; -+int fat_readdir(const char *filename, loff_t offset, struct fs_dirent *dir); - void fat_close(void); - #endif /* _FAT_H_ */ -diff --git a/include/fs.h b/include/fs.h -index 2f2aca8378..71051d7c66 100644 ---- a/include/fs.h -+++ b/include/fs.h -@@ -79,6 +79,27 @@ int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len, - loff_t *actwrite); - - /* -+ * A directory entry. -+ */ -+struct fs_dirent { -+ loff_t size; -+ char name[256]; -+}; -+ -+/* -+ * fs_readdir - Read a directory. -+ * -+ * @filename: Name of file to read from -+ * @offset: The offset into the directory to read, ie. offset of N returns -+ * the N'th directory entry -+ * @dent: on success, filled in with directory entry -+ * @return 0 on success, -ENOTDIR if specified file is not a directory, -+ * or -ENOENT if offset is beyond last directory entry, or -ENXIO if -+ * operation is not supported. -+ */ -+int fs_readdir(const char *filename, loff_t offset, struct fs_dirent *dent); -+ -+/* - * Common implementation for various filesystem commands, optionally limited - * to a specific filesystem type via the fstype parameter. - */ --- -2.13.3 - -From 9c814af51bb6b2ac462f94d7a7d5484954a95d17 Mon Sep 17 00:00:00 2001 -From: Rob Clark -Date: Thu, 27 Jul 2017 14:12:21 -0400 -Subject: [PATCH 05/13] efi_loader: add device-path utils - -Helpers to construct device-paths from devices, partitions, files, and -for parsing and manipulating device-paths. - -For non-legacy devices, this will use u-boot's device-model to construct -device-paths which include bus hierarchy to construct device-paths. For -legacy devices we still fake it, but slightly more convincingly. - -Signed-off-by: Rob Clark ---- - include/efi_api.h | 10 + - include/efi_loader.h | 20 ++ - lib/efi_loader/Makefile | 2 +- - lib/efi_loader/efi_device_path.c | 485 +++++++++++++++++++++++++++++++++++++++ - 4 files changed, 516 insertions(+), 1 deletion(-) - create mode 100644 lib/efi_loader/efi_device_path.c - -diff --git a/include/efi_api.h b/include/efi_api.h -index 85afbeb72b..0ebe8d0283 100644 ---- a/include/efi_api.h -+++ b/include/efi_api.h -@@ -305,6 +305,7 @@ struct efi_device_path_acpi_path { - #define DEVICE_PATH_TYPE_MESSAGING_DEVICE 0x03 - # define DEVICE_PATH_SUB_TYPE_MSG_USB 0x05 - # define DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR 0x0b -+# define DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS 0x0f - # define DEVICE_PATH_SUB_TYPE_MSG_SD 0x1a - # define DEVICE_PATH_SUB_TYPE_MSG_MMC 0x1d - -@@ -320,6 +321,15 @@ struct efi_device_path_mac_addr { - u8 if_type; - } __packed; - -+struct efi_device_path_usb_class { -+ struct efi_device_path dp; -+ u16 vendor_id; -+ u16 product_id; -+ u8 device_class; -+ u8 device_subclass; -+ u8 device_protocol; -+} __packed; -+ - struct efi_device_path_sd_mmc_path { - struct efi_device_path dp; - u8 slot_number; -diff --git a/include/efi_loader.h b/include/efi_loader.h -index 03c4ed5e1c..1028bfb75d 100644 ---- a/include/efi_loader.h -+++ b/include/efi_loader.h -@@ -207,6 +207,26 @@ extern void *efi_bounce_buffer; - #define EFI_LOADER_BOUNCE_BUFFER_SIZE (64 * 1024 * 1024) - #endif - -+ -+struct efi_device_path *efi_dp_next(struct efi_device_path *dp); -+int efi_dp_match(struct efi_device_path *a, struct efi_device_path *b); -+struct efi_object *efi_dp_find_obj(struct efi_device_path *dp); -+unsigned efi_dp_size(struct efi_device_path *dp); -+struct efi_device_path *efi_dp_dup(struct efi_device_path *dp); -+ -+struct efi_device_path *efi_dp_from_dev(struct udevice *dev); -+struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part); -+struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part, -+ const char *path); -+struct efi_device_path *efi_dp_from_eth(void); -+void efi_dp_split_file_path(struct efi_device_path *full_path, -+ struct efi_device_path **device_path, -+ struct efi_device_path **file_path); -+ -+#define EFI_DP_TYPE(_dp, _type, _subtype) \ -+ (((_dp)->type == DEVICE_PATH_TYPE_##_type) && \ -+ ((_dp)->sub_type == DEVICE_PATH_SUB_TYPE_##_subtype)) -+ - /* Convert strings from normal C strings to uEFI strings */ - static inline void ascii2unicode(u16 *unicode, const char *ascii) - { -diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile -index 30bf343a36..f35e5ce8a8 100644 ---- a/lib/efi_loader/Makefile -+++ b/lib/efi_loader/Makefile -@@ -15,7 +15,7 @@ always := $(efiprogs-y) - - obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o - obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o --obj-y += efi_memory.o efi_device_path_to_text.o -+obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o - obj-$(CONFIG_LCD) += efi_gop.o - obj-$(CONFIG_DM_VIDEO) += efi_gop.o - obj-$(CONFIG_PARTITIONS) += efi_disk.o -diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c -new file mode 100644 -index 0000000000..b5acf73f98 ---- /dev/null -+++ b/lib/efi_loader/efi_device_path.c -@@ -0,0 +1,485 @@ -+/* -+ * EFI device path from u-boot device-model mapping -+ * -+ * (C) Copyright 2017 Rob Clark -+ * -+ * SPDX-License-Identifier: GPL-2.0+ -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* template END node: */ -+const static struct efi_device_path END = { -+ .type = DEVICE_PATH_TYPE_END, -+ .sub_type = DEVICE_PATH_SUB_TYPE_END, -+ .length = sizeof(END), -+}; -+ -+/* template ROOT node, a fictional ACPI PNP device: */ -+const static struct efi_device_path_acpi_path ROOT = { -+ .dp = { -+ .type = DEVICE_PATH_TYPE_ACPI_DEVICE, -+ .sub_type = DEVICE_PATH_SUB_TYPE_ACPI_DEVICE, -+ .length = sizeof(ROOT), -+ }, -+ .hid = EISA_PNP_ID(0x1337), -+ .uid = 0, -+}; -+ -+ -+/* -+ * Iterate to next block in device-path, terminating (returning NULL) -+ * at /End* node. -+ */ -+struct efi_device_path *efi_dp_next(struct efi_device_path *dp) -+{ -+ if (dp == NULL) -+ return NULL; -+ dp = ((void *)dp) + dp->length; -+ if (dp->type == DEVICE_PATH_TYPE_END) -+ return NULL; -+ return dp; -+} -+ -+/* -+ * Compare two device-paths, stopping when the shorter of the two hits -+ * an End* node. This is useful to, for example, compare a device-path -+ * representing a device with one representing a file on the device, or -+ * a device with a parent device. -+ */ -+int efi_dp_match(struct efi_device_path *a, struct efi_device_path *b) -+{ -+ while (1) { -+ int ret; -+ -+ ret = memcmp(&a->length, &b->length, sizeof(a->length)); -+ if (ret) -+ return ret; -+ -+ ret = memcmp(a, b, a->length); -+ if (ret) -+ return ret; -+ -+ a = efi_dp_next(a); -+ b = efi_dp_next(b); -+ -+ if (!a || !b) -+ return 0; -+ } -+} -+ -+ -+/* -+ * See UEFI spec (section 3.1.2, about short-form device-paths.. -+ * tl;dr: we can have a device-path that starts with a USB WWID -+ * or USB Class node, and a few other cases which don't encode -+ * the full device path with bus hierarchy: -+ * -+ * - MESSAGING:USB_WWID -+ * - MESSAGING:USB_CLASS -+ * - MEDIA:FILE_PATH -+ * - MEDIA:HARD_DRIVE -+ * - MESSAGING:URI -+ */ -+static struct efi_device_path *shorten_path(struct efi_device_path *dp) -+{ -+ while (dp) { -+ /* -+ * TODO: Add MESSAGING:USB_WWID and MESSAGING:URI.. -+ * in practice fallback.efi just uses MEDIA:HARD_DRIVE -+ * so not sure when we would see these other cases. -+ */ -+ if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_CLASS) || -+ EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) || -+ EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH)) -+ return dp; -+ -+ dp = efi_dp_next(dp); -+ } -+ -+ return dp; -+} -+ -+static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path) -+{ -+ struct efi_object *efiobj; -+ -+ list_for_each_entry(efiobj, &efi_obj_list, link) { -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { -+ struct efi_handler *handler = &efiobj->protocols[i]; -+ struct efi_device_path *obj_dp; -+ efi_status_t ret; -+ -+ if (!handler->guid) -+ break; -+ -+ if (guidcmp(handler->guid, &efi_guid_device_path)) -+ continue; -+ -+ ret = efi_get_protocol(efiobj, handler, (void **)&obj_dp); -+ if (ret != EFI_SUCCESS) -+ continue; -+ -+ do { -+ if (efi_dp_match(dp, obj_dp) == 0) -+ return efiobj; -+ -+ obj_dp = shorten_path(efi_dp_next(obj_dp)); -+ } while (short_path && obj_dp); -+ } -+ } -+ -+ return NULL; -+} -+ -+ -+/* Find an efiobj from device-path */ -+struct efi_object *efi_dp_find_obj(struct efi_device_path *dp) -+{ -+ struct efi_object *efiobj; -+ -+ efiobj = find_obj(dp, false); -+ -+ if (!efiobj) -+ efiobj = find_obj(dp, true); -+ -+ return efiobj; -+} -+ -+/* return size not including End node: */ -+unsigned efi_dp_size(struct efi_device_path *dp) -+{ -+ unsigned sz = 0; -+ -+ while (dp) { -+ sz += dp->length; -+ dp = efi_dp_next(dp); -+ } -+ -+ return sz; -+} -+ -+struct efi_device_path *efi_dp_dup(struct efi_device_path *dp) -+{ -+ struct efi_device_path *ndp; -+ unsigned sz = efi_dp_size(dp) + sizeof(struct efi_device_path); -+ -+ ndp = malloc(sz); -+ memcpy(ndp, dp, sz); -+ -+ return ndp; -+} -+ -+#ifdef CONFIG_DM -+/* size of device-path not including END node for device and all parents -+ * up to the root device. -+ */ -+static unsigned dp_size(struct udevice *dev) -+{ -+ if (!dev || !dev->driver) -+ return sizeof(ROOT); -+ -+ switch (dev->driver->id) { -+ case UCLASS_ROOT: -+ case UCLASS_SIMPLE_BUS: -+ /* stop traversing parents at this point: */ -+ return sizeof(ROOT); -+ case UCLASS_MMC: -+ return dp_size(dev->parent) + sizeof(struct efi_device_path_sd_mmc_path); -+ case UCLASS_MASS_STORAGE: -+ case UCLASS_USB_HUB: -+ return dp_size(dev->parent) + sizeof(struct efi_device_path_usb_class); -+ default: -+ /* just skip over unknown classes: */ -+ return dp_size(dev->parent); -+ } -+} -+ -+static void *dp_fill(void *buf, struct udevice *dev) -+{ -+ if (!dev || !dev->driver) -+ return buf; -+ -+ switch (dev->driver->id) { -+ case UCLASS_ROOT: -+ case UCLASS_SIMPLE_BUS: { -+ /* stop traversing parents at this point: */ -+ struct efi_device_path_acpi_path *adp = buf; -+ *adp = ROOT; -+ return &adp[1]; -+ } -+#if defined(CONFIG_DM_MMC) && defined (CONFIG_MMC) -+ case UCLASS_MMC: { -+ struct efi_device_path_sd_mmc_path *sddp = -+ dp_fill(buf, dev->parent); -+ struct mmc *mmc = mmc_get_mmc_dev(dev); -+ struct blk_desc *desc = mmc_get_blk_desc(mmc); -+ -+ sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; -+ sddp->dp.sub_type = (desc->if_type == IF_TYPE_MMC) ? -+ DEVICE_PATH_SUB_TYPE_MSG_MMC : -+ DEVICE_PATH_SUB_TYPE_MSG_SD; -+ sddp->dp.length = sizeof(*sddp); -+ sddp->slot_number = 0; // XXX ??? -+ -+ return &sddp[1]; -+ } -+#endif -+ case UCLASS_MASS_STORAGE: -+ case UCLASS_USB_HUB: { -+ struct efi_device_path_usb_class *udp = -+ dp_fill(buf, dev->parent); -+ struct usb_device *udev = dev_get_parent_priv(dev); -+ struct usb_device_descriptor *desc = &udev->descriptor; -+ -+ udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; -+ udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS; -+ udp->dp.length = sizeof(*udp); -+ udp->vendor_id = desc->idVendor; -+ udp->product_id = desc->idProduct; -+ udp->device_class = desc->bDeviceClass; -+ udp->device_subclass = desc->bDeviceSubClass; -+ udp->device_protocol = desc->bDeviceProtocol; -+ -+ return &udp[1]; -+ } -+ default: -+ debug("unhandled device class: %s (%u)\n", -+ dev->name, dev->driver->id); -+ return dp_fill(buf, dev->parent); -+ } -+} -+ -+/* Construct a device-path from a device: */ -+struct efi_device_path *efi_dp_from_dev(struct udevice *dev) -+{ -+ void *buf, *start; -+ -+ start = buf = calloc(1, dp_size(dev) + sizeof(END)); -+ buf = dp_fill(buf, dev); -+ *((struct efi_device_path *)buf) = END; -+ -+ return start; -+} -+#endif -+ -+static unsigned dp_part_size(struct blk_desc *desc, int part) -+{ -+ unsigned dpsize; -+ -+#ifdef CONFIG_BLK -+ dpsize = dp_size(desc->bdev->parent); -+#else -+ dpsize = sizeof(ROOT) + sizeof(struct efi_device_path_file_path); -+#endif -+ -+ if (part == 0) /* the actual disk, not a partition */ -+ return dpsize; -+ -+ if (desc->part_type == PART_TYPE_ISO) { -+ dpsize += sizeof(struct efi_device_path_cdrom_path); -+ } else { -+ dpsize += sizeof(struct efi_device_path_hard_drive_path); -+ } -+ -+ return dpsize; -+} -+ -+static void *dp_part_fill(void *buf, struct blk_desc *desc, int part) -+{ -+ disk_partition_t info; -+ -+#ifdef CONFIG_BLK -+ buf = dp_fill(buf, desc->bdev->parent); -+#else -+ struct efi_device_path_file_path *fp; -+ char devname[32] = { 0 }; /* fp->str is u16[32] long */ -+ -+ snprintf(devname, sizeof(devname), "%d.%d.%d", desc->if_type, -+ desc->devnum, part); -+ -+ memcpy(buf, &ROOT, sizeof(ROOT)); -+ buf += sizeof(ROOT); -+ -+ fp = buf; -+ fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; -+ fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; -+ fp->dp.length = sizeof(*fp); -+ ascii2unicode(fp->str, devname); -+ buf = &fp[1]; -+#endif -+ -+ if (part == 0) /* the actual disk, not a partition */ -+ return buf; -+ -+ part_get_info(desc, part, &info); -+ -+ if (desc->part_type == PART_TYPE_ISO) { -+ struct efi_device_path_cdrom_path *cddp = buf; -+ -+ cddp->boot_entry = part - 1; -+ cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; -+ cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH; -+ cddp->dp.length = sizeof (*cddp); -+ cddp->partition_start = info.start; -+ cddp->partition_end = info.size; -+ -+ buf = &cddp[1]; -+ } else { -+ struct efi_device_path_hard_drive_path *hddp = buf; -+ -+ hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; -+ hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH; -+ hddp->dp.length = sizeof (*hddp); -+ hddp->partition_number = part - 1; -+ hddp->partition_start = info.start; -+ hddp->partition_end = info.size; -+ if (desc->part_type == PART_TYPE_EFI) -+ hddp->partmap_type = 2; -+ else -+ hddp->partmap_type = 1; -+ hddp->signature_type = desc->sig_type; -+ if (hddp->signature_type != 0) -+ memcpy(hddp->partition_signature, &desc->guid_sig, -+ sizeof(hddp->partition_signature)); -+ -+ buf = &hddp[1]; -+ } -+ -+ return buf; -+} -+ -+ -+/* Construct a device-path from a partition on a blk device: */ -+struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part) -+{ -+ void *buf, *start; -+ -+ start = buf = calloc(1, dp_part_size(desc, part) + sizeof(END)); -+ -+ buf = dp_part_fill(buf, desc, part); -+ -+ *((struct efi_device_path *)buf) = END; -+ -+ return start; -+} -+ -+/* convert path to an UEFI style path (ie. DOS style backslashes and utf16) */ -+static void path_to_uefi(u16 *uefi, const char *path) -+{ -+ while (*path) { -+ char c = *(path++); -+ if (c == '/') -+ c = '\\'; -+ *(uefi++) = c; -+ } -+ *uefi = '\0'; -+} -+ -+/* -+ * If desc is NULL, this creates a path with only the file component, -+ * otherwise it creates a full path with both device and file components -+ */ -+struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part, -+ const char *path) -+{ -+ struct efi_device_path_file_path *fp; -+ void *buf, *start; -+ unsigned dpsize = 0, fpsize; -+ -+ if (desc) -+ dpsize = dp_part_size(desc, part); -+ -+ // TODO efi_device_path_file_path should be variable length: -+ fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1); -+ dpsize += fpsize; -+ -+ start = buf = calloc(1, dpsize + sizeof(END)); -+ -+ if (desc) -+ buf = dp_part_fill(buf, desc, part); -+ -+ /* add file-path: */ -+ fp = buf; -+ fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; -+ fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; -+ fp->dp.length = fpsize; -+ path_to_uefi(fp->str, path); -+ buf += fpsize; -+ -+ *((struct efi_device_path *)buf) = END; -+ -+ return start; -+} -+ -+#ifdef CONFIG_NET -+struct efi_device_path *efi_dp_from_eth(void) -+{ -+ struct efi_device_path_mac_addr *ndp; -+ void *buf, *start; -+ unsigned dpsize = 0; -+ -+ assert(eth_get_dev()); -+ -+#ifdef CONFIG_DM_ETH -+ dpsize += dp_size(eth_get_dev()); -+#else -+ dpsize += sizeof(ROOT); -+#endif -+ dpsize += sizeof(*ndp); -+ -+ start = buf = calloc(1, dpsize + sizeof(END)); -+ -+#ifdef CONFIG_DM_ETH -+ buf = dp_fill(buf, eth_get_dev()); -+#else -+ memcpy(buf, &ROOT, sizeof(ROOT)); -+ buf += sizeof(ROOT); -+#endif -+ -+ ndp = buf; -+ ndp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; -+ ndp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR; -+ ndp->dp.length = sizeof(*ndp); -+ memcpy(ndp->mac.addr, eth_get_ethaddr(), ARP_HLEN); -+ buf = &ndp[1]; -+ -+ *((struct efi_device_path *)buf) = END; -+ -+ return start; -+} -+#endif -+ -+/* -+ * Helper to split a full device path (containing both device and file -+ * parts) into it's constituent parts. -+ */ -+void efi_dp_split_file_path(struct efi_device_path *full_path, -+ struct efi_device_path **device_path, -+ struct efi_device_path **file_path) -+{ -+ struct efi_device_path *p, *dp, *fp; -+ -+ dp = efi_dp_dup(full_path); -+ p = dp; -+ while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH)) -+ p = efi_dp_next(p); -+ fp = efi_dp_dup(p); -+ -+ p->type = DEVICE_PATH_TYPE_END; -+ p->sub_type = DEVICE_PATH_SUB_TYPE_END; -+ p->length = sizeof(*p); -+ -+ *device_path = dp; -+ *file_path = fp; -+} --- -2.13.3 - -From 5685374b81f9ff62419a53fb2fd6f140add56def Mon Sep 17 00:00:00 2001 -From: Rob Clark -Date: Mon, 31 Jul 2017 09:07:49 -0400 -Subject: [PATCH 06/13] efi_loader: drop redundant efi_device_path_protocol - -This is really the same thing as the efi_device_path struct. - -Signed-off-by: Rob Clark ---- - include/efi_api.h | 12 ++---------- - lib/efi_loader/efi_device_path_to_text.c | 13 ++++++++----- - 2 files changed, 10 insertions(+), 15 deletions(-) - -diff --git a/include/efi_api.h b/include/efi_api.h -index 0ebe8d0283..7691a054a5 100644 ---- a/include/efi_api.h -+++ b/include/efi_api.h -@@ -478,22 +478,14 @@ struct efi_console_control_protocol - EFI_GUID(0x8b843e20, 0x8132, 0x4852, \ - 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c) - --struct efi_device_path_protocol --{ -- uint8_t type; -- uint8_t sub_type; -- uint16_t length; -- uint8_t data[]; --}; -- - struct efi_device_path_to_text_protocol - { - uint16_t *(EFIAPI *convert_device_node_to_text)( -- struct efi_device_path_protocol *device_node, -+ struct efi_device_path *device_node, - bool display_only, - bool allow_shortcuts); - uint16_t *(EFIAPI *convert_device_path_to_text)( -- struct efi_device_path_protocol *device_path, -+ struct efi_device_path *device_path, - bool display_only, - bool allow_shortcuts); - }; -diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c -index 4b2f43f0c8..f9d071ac50 100644 ---- a/lib/efi_loader/efi_device_path_to_text.c -+++ b/lib/efi_loader/efi_device_path_to_text.c -@@ -16,7 +16,7 @@ const efi_guid_t efi_guid_device_path_to_text_protocol = - EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; - - static uint16_t *efi_convert_device_node_to_text( -- struct efi_device_path_protocol *device_node, -+ struct efi_device_path *device_node, - bool display_only, - bool allow_shortcuts) - { -@@ -55,15 +55,18 @@ static uint16_t *efi_convert_device_node_to_text( - break; - case DEVICE_PATH_TYPE_MEDIA_DEVICE: - switch (device_node->sub_type) { -- case DEVICE_PATH_SUB_TYPE_FILE_PATH: -+ case DEVICE_PATH_SUB_TYPE_FILE_PATH: { -+ struct efi_device_path_file_path *fp = -+ (struct efi_device_path_file_path *)device_node; - buffer_size = device_node->length - 4; - r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, - buffer_size, (void **) &buffer); - if (r != EFI_SUCCESS) - return NULL; -- memcpy(buffer, device_node->data, buffer_size); -+ memcpy(buffer, fp->str, buffer_size); - break; - } -+ } - break; - } - -@@ -89,7 +92,7 @@ static uint16_t *efi_convert_device_node_to_text( - } - - static uint16_t EFIAPI *efi_convert_device_node_to_text_ext( -- struct efi_device_path_protocol *device_node, -+ struct efi_device_path *device_node, - bool display_only, - bool allow_shortcuts) - { -@@ -105,7 +108,7 @@ static uint16_t EFIAPI *efi_convert_device_node_to_text_ext( - } - - static uint16_t EFIAPI *efi_convert_device_path_to_text( -- struct efi_device_path_protocol *device_path, -+ struct efi_device_path *device_path, - bool display_only, - bool allow_shortcuts) - { --- -2.13.3 - -From 87811659b781575024ae3499f5b5f6d1ca4aefb0 Mon Sep 17 00:00:00 2001 -From: Rob Clark -Date: Mon, 31 Jul 2017 11:25:49 -0400 -Subject: [PATCH 07/13] efi_loader: add guidstr helper - -There are a couple places where we'll need GUID -> string. So add a -helper. - -Signed-off-by: Rob Clark ---- - include/efi_loader.h | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/include/efi_loader.h b/include/efi_loader.h -index 1028bfb75d..e6c46f713e 100644 ---- a/include/efi_loader.h -+++ b/include/efi_loader.h -@@ -239,6 +239,21 @@ static inline int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2) - return memcmp(g1, g2, sizeof(efi_guid_t)); - } - -+static inline int guidstr(char *s, const efi_guid_t *g) -+{ -+ /* unpacked-guid, otherwise we have to have to consider endianess */ -+ struct { -+ uint32_t data1; -+ uint16_t data2; -+ uint16_t data3; -+ uint8_t data4[8]; -+ } *ug = (void *)g; -+ return sprintf(s, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", -+ ug->data1, ug->data2, ug->data3, ug->data4[0], -+ ug->data4[1], ug->data4[2], ug->data4[3], ug->data4[4], -+ ug->data4[5], ug->data4[6], ug->data4[7]); -+} -+ - /* - * Use these to indicate that your code / data should go into the EFI runtime - * section and thus still be available when the OS is running --- -2.13.3 - -From 3cbfcc19afa80f28819630e2ff1e9b0ef71f1cce Mon Sep 17 00:00:00 2001 -From: Rob Clark -Date: Mon, 31 Jul 2017 11:28:01 -0400 -Subject: [PATCH 08/13] efi_loader: flesh out device-path to text - -It needs to handle more device-path node types, and also multiple levels -of path hierarchy. To simplify this, initially construct utf8 string to -a temporary buffer, and then allocate the real utf16 buffer that is -returned. This should be mostly for debugging or at least not critical- -path so an extra copy won't hurt, and is saner than the alternative. - -Signed-off-by: Rob Clark ---- - include/efi_api.h | 1 + - include/efi_loader.h | 2 + - lib/efi_loader/efi_device_path_to_text.c | 223 ++++++++++++++++++++++--------- - 3 files changed, 163 insertions(+), 63 deletions(-) - -diff --git a/include/efi_api.h b/include/efi_api.h -index 7691a054a5..dd79cace32 100644 ---- a/include/efi_api.h -+++ b/include/efi_api.h -@@ -295,6 +295,7 @@ struct efi_mac_addr { - - #define EFI_PNP_ID(ID) (u32)(((ID) << 16) | 0x41D0) - #define EISA_PNP_ID(ID) EFI_PNP_ID(ID) -+#define EISA_PNP_NUM(ID) ((ID) >> 16) - - struct efi_device_path_acpi_path { - struct efi_device_path dp; -diff --git a/include/efi_loader.h b/include/efi_loader.h -index e6c46f713e..1ab4af0f88 100644 ---- a/include/efi_loader.h -+++ b/include/efi_loader.h -@@ -59,6 +59,8 @@ extern struct efi_simple_input_interface efi_con_in; - extern const struct efi_console_control_protocol efi_console_control; - extern const struct efi_device_path_to_text_protocol efi_device_path_to_text; - -+uint16_t *efi_dp_str(struct efi_device_path *dp); -+ - extern const efi_guid_t efi_guid_console_control; - extern const efi_guid_t efi_guid_device_path; - extern const efi_guid_t efi_guid_loaded_image; -diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c -index f9d071ac50..d10a1319af 100644 ---- a/lib/efi_loader/efi_device_path_to_text.c -+++ b/lib/efi_loader/efi_device_path_to_text.c -@@ -15,82 +15,179 @@ - const efi_guid_t efi_guid_device_path_to_text_protocol = - EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; - --static uint16_t *efi_convert_device_node_to_text( -- struct efi_device_path *device_node, -- bool display_only, -- bool allow_shortcuts) -+static char *dp_unknown(char *s, struct efi_device_path *dp) - { -- unsigned long buffer_size; -- efi_status_t r; -- uint16_t *buffer = NULL; -- int i; -+ s += sprintf(s, "/UNKNOWN(%04x,%04x)", dp->type, dp->sub_type); -+ return s; -+} - -- switch (device_node->type) { -- case DEVICE_PATH_TYPE_END: -- return NULL; -- case DEVICE_PATH_TYPE_MESSAGING_DEVICE: -- switch (device_node->sub_type) { -- case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: { -- struct efi_device_path_mac_addr *dp = -- (struct efi_device_path_mac_addr *)device_node; -- -- if (dp->if_type != 0 && dp->if_type != 1) -- break; -- r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, -- 2 * MAC_OUTPUT_LEN, -- (void **)&buffer); -- if (r != EFI_SUCCESS) -- return NULL; -- sprintf((char *)buffer, -- "MAC(%02x%02x%02x%02x%02x%02x,0x%1x)", -- dp->mac.addr[0], dp->mac.addr[1], -- dp->mac.addr[2], dp->mac.addr[3], -- dp->mac.addr[4], dp->mac.addr[5], -- dp->if_type); -- for (i = MAC_OUTPUT_LEN - 1; i >= 0; --i) -- buffer[i] = ((uint8_t *)buffer)[i]; -+static char *dp_acpi(char *s, struct efi_device_path *dp) -+{ -+ switch (dp->sub_type) { -+ case DEVICE_PATH_SUB_TYPE_ACPI_DEVICE: { -+ struct efi_device_path_acpi_path *adp = -+ (struct efi_device_path_acpi_path *)dp; -+ s += sprintf(s, "/Acpi(PNP%04x", EISA_PNP_NUM(adp->hid)); -+ if (adp->uid) -+ s += sprintf(s, ",%d", adp->uid); -+ s += sprintf(s, ")"); -+ break; -+ } -+ default: -+ s = dp_unknown(s, dp); -+ break; -+ } -+ return s; -+} -+ -+static char *dp_msging(char *s, struct efi_device_path *dp) -+{ -+ switch (dp->sub_type) { -+ case DEVICE_PATH_SUB_TYPE_MSG_USB: { -+ struct efi_device_path_usb *udp = -+ (struct efi_device_path_usb *)dp; -+ s += sprintf(s, "/Usb(0x%x,0x%x)", udp->parent_port_number, -+ udp->usb_interface); -+ break; -+ } -+ case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: { -+ struct efi_device_path_mac_addr *mdp = -+ (struct efi_device_path_mac_addr *)dp; -+ -+ if (mdp->if_type != 0 && mdp->if_type != 1) - break; -- } -- } -+ -+ s += sprintf(s, "/MAC(%02x%02x%02x%02x%02x%02x,0x%1x)", -+ mdp->mac.addr[0], mdp->mac.addr[1], -+ mdp->mac.addr[2], mdp->mac.addr[3], -+ mdp->mac.addr[4], mdp->mac.addr[5], -+ mdp->if_type); -+ -+ break; -+ } -+ case DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS: { -+ struct efi_device_path_usb_class *ucdp = -+ (struct efi_device_path_usb_class *)dp; -+ -+ s += sprintf(s, "/USBClass(%x,%x,%x,%x,%x)", -+ ucdp->vendor_id, ucdp->product_id, -+ ucdp->device_class, ucdp->device_subclass, -+ ucdp->device_protocol); -+ -+ break; -+ } -+ case DEVICE_PATH_SUB_TYPE_MSG_SD: -+ case DEVICE_PATH_SUB_TYPE_MSG_MMC: { -+ const char *typename = -+ (dp->sub_type == DEVICE_PATH_SUB_TYPE_MSG_SD) ? -+ "SDCard" : "MMC"; -+ struct efi_device_path_sd_mmc_path *sddp = -+ (struct efi_device_path_sd_mmc_path *)dp; -+ s += sprintf(s, "/%s(Slot%u)", typename, sddp->slot_number); -+ break; -+ } -+ default: -+ s = dp_unknown(s, dp); - break; -- case DEVICE_PATH_TYPE_MEDIA_DEVICE: -- switch (device_node->sub_type) { -- case DEVICE_PATH_SUB_TYPE_FILE_PATH: { -- struct efi_device_path_file_path *fp = -- (struct efi_device_path_file_path *)device_node; -- buffer_size = device_node->length - 4; -- r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, -- buffer_size, (void **) &buffer); -- if (r != EFI_SUCCESS) -- return NULL; -- memcpy(buffer, fp->str, buffer_size); -+ } -+ return s; -+} -+ -+static char *dp_media(char *s, struct efi_device_path *dp) -+{ -+ switch (dp->sub_type) { -+ case DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH: { -+ struct efi_device_path_hard_drive_path *hddp = -+ (struct efi_device_path_hard_drive_path *)dp; -+ void *sig = hddp->partition_signature; -+ -+ switch (hddp->signature_type) { -+ case SIG_TYPE_MBR: -+ s += sprintf(s, "/HD(Part%d,Sig%08x)", -+ hddp->partition_number, -+ *(uint32_t *)sig); - break; -+ case SIG_TYPE_GUID: -+ s += sprintf(s, "HD(Part%d,Sig", hddp->partition_number); -+ s += guidstr(s, (efi_guid_t *)sig); -+ s += sprintf(s, ")"); -+ default: -+ s += sprintf(s, "/HD(Part%d,MBRType=%02x,SigType=%02x)", -+ hddp->partition_number, hddp->partmap_type, -+ hddp->signature_type); - } -- } -+ -+ break; -+ } -+ case DEVICE_PATH_SUB_TYPE_CDROM_PATH: { -+ struct efi_device_path_cdrom_path *cddp = -+ (struct efi_device_path_cdrom_path *)dp; -+ s += sprintf(s, "/CDROM(0x%x)", cddp->boot_entry); -+ break; -+ } -+ case DEVICE_PATH_SUB_TYPE_FILE_PATH: { -+ struct efi_device_path_file_path *fp = -+ (struct efi_device_path_file_path *)dp; -+ int slen = (dp->length - sizeof(*dp)) / 2; -+ s += sprintf(s, "/%-*ls", slen, fp->str); -+ break; -+ } -+ default: -+ s = dp_unknown(s, dp); - break; - } -+ return s; -+} - -- /* -- * For all node types that we do not yet support return -- * 'UNKNOWN(type,subtype)'. -- */ -- if (!buffer) { -- r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, -- 2 * UNKNOWN_OUTPUT_LEN, -- (void **)&buffer); -- if (r != EFI_SUCCESS) -- return NULL; -- sprintf((char *)buffer, -- "UNKNOWN(%04x,%04x)", -- device_node->type, -- device_node->sub_type); -- for (i = UNKNOWN_OUTPUT_LEN - 1; i >= 0; --i) -- buffer[i] = ((uint8_t *)buffer)[i]; -+static uint16_t *efi_convert_device_node_to_text( -+ struct efi_device_path *dp, -+ bool display_only, -+ bool allow_shortcuts) -+{ -+ unsigned long len; -+ efi_status_t r; -+ char buf[512]; /* this ought be be big enough for worst case */ -+ char *str = buf; -+ uint16_t *out; -+ -+ while (dp) { -+ switch (dp->type) { -+ case DEVICE_PATH_TYPE_ACPI_DEVICE: -+ str = dp_acpi(str, dp); -+ break; -+ case DEVICE_PATH_TYPE_MESSAGING_DEVICE: -+ str = dp_msging(str, dp); -+ break; -+ case DEVICE_PATH_TYPE_MEDIA_DEVICE: -+ str = dp_media(str, dp); -+ break; -+ default: -+ str = dp_unknown(str, dp); -+ } -+ -+ dp = efi_dp_next(dp); - } - -- return buffer; -+ *str++ = '\0'; -+ -+ len = str - buf; -+ r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, 2 * len, (void **)&out); -+ if (r != EFI_SUCCESS) -+ return NULL; -+ -+ ascii2unicode(out, buf); -+ out[len - 1] = 0; -+ -+ return out; - } - -+/* helper for debug prints.. efi_free_pool() the result. */ -+uint16_t *efi_dp_str(struct efi_device_path *dp) -+{ -+ return efi_convert_device_node_to_text(dp, true, true); -+} -+ -+ - static uint16_t EFIAPI *efi_convert_device_node_to_text_ext( - struct efi_device_path *device_node, - bool display_only, --- -2.13.3 - -From 281813fc5f8e13b20201eb4279bb32d296c99930 Mon Sep 17 00:00:00 2001 -From: Rob Clark -Date: Thu, 27 Jul 2017 14:22:21 -0400 -Subject: [PATCH 09/13] efi_loader: use proper device-paths for partitions - -Also, create disk objects for the disk itself, in addition to the -partitions. (UEFI terminology is a bit confusing, a "disk" object is -really a partition.) This helps grub properly identify the boot device -since it is trying to match up partition "disk" object with it's parent -device. - -Now instead of seeing devices like: - - /File(sdhci@07864000.blk)/EndEntire - /File(usb_mass_storage.lun0)/EndEntire - -You see: - - /ACPI(133741d0,0)/UnknownMessaging(1d)/EndEntire - /ACPI(133741d0,0)/UnknownMessaging(1d)/HD(0,800,64000,dd904a8c00000000,1,1)/EndEntire - /ACPI(133741d0,0)/UnknownMessaging(1d)/HD(1,64800,200000,dd904a8c00000000,1,1)/EndEntire - /ACPI(133741d0,0)/UnknownMessaging(1d)/HD(2,264800,19a000,dd904a8c00000000,1,1)/EndEntire - /ACPI(133741d0,0)/USB(0,0)/USB(0,0)/USB(0,0)/EndEntire - /ACPI(133741d0,0)/USB(0,0)/USB(0,0)/USB(0,0)/HD(0,800,60000,38ca680200000000,1,1)/EndEntire - /ACPI(133741d0,0)/USB(0,0)/USB(0,0)/USB(0,0)/HD(1,61000,155000,38ca680200000000,1,1)/EndEntire - /ACPI(133741d0,0)/USB(0,0)/USB(0,0)/USB(0,0)/HD(2,20fa800,1bbf8800,38ca680200000000,1,1)/EndEntire - /ACPI(133741d0,0)/USB(0,0)/USB(0,0)/USB(0,0)/HD(3,1b6800,1f44000,38ca680200000000,1,1)/EndEntire - -This is on a board with single USB disk and single sd-card. The -UnknownMessaging(1d) node in the device-path is the MMC device, -but grub_efi_print_device_path() hasn't been updated yet for some -of the newer device-path sub-types. - -This patch is inspired by a patch originally from Peter Jones, but -re-worked to use efi_device_path, so it doesn't much resemble the -original. - -Signed-off-by: Rob Clark ---- - lib/efi_loader/efi_disk.c | 54 +++++++++++++++++++++++++++-------------------- - 1 file changed, 31 insertions(+), 23 deletions(-) - -diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c -index ed06485e33..eea65a402a 100644 ---- a/lib/efi_loader/efi_disk.c -+++ b/lib/efi_loader/efi_disk.c -@@ -28,11 +28,13 @@ struct efi_disk_obj { - /* EFI Interface Media descriptor struct, referenced by ops */ - struct efi_block_io_media media; - /* EFI device path to this block device */ -- struct efi_device_path_file_path *dp; -+ struct efi_device_path *dp; -+ /* partition # */ -+ unsigned part; - /* Offset into disk for simple partitions */ - lbaint_t offset; - /* Internal block device */ -- const struct blk_desc *desc; -+ struct blk_desc *desc; - }; - - static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this, -@@ -172,26 +174,26 @@ static const struct efi_block_io block_io_disk_template = { - - static void efi_disk_add_dev(const char *name, - const char *if_typename, -- const struct blk_desc *desc, -+ struct blk_desc *desc, - int dev_index, -- lbaint_t offset) -+ lbaint_t offset, -+ unsigned part) - { - struct efi_disk_obj *diskobj; -- struct efi_device_path_file_path *dp; -- int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2); - - /* Don't add empty devices */ - if (!desc->lba) - return; - -- diskobj = calloc(1, objlen); -+ diskobj = calloc(1, sizeof(*diskobj)); - - /* Fill in object data */ -- dp = (void *)&diskobj[1]; -+ diskobj->dp = efi_dp_from_part(desc, part); -+ diskobj->part = part; - diskobj->parent.protocols[0].guid = &efi_block_io_guid; - diskobj->parent.protocols[0].protocol_interface = &diskobj->ops; - diskobj->parent.protocols[1].guid = &efi_guid_device_path; -- diskobj->parent.protocols[1].protocol_interface = dp; -+ diskobj->parent.protocols[1].protocol_interface = diskobj->dp; - diskobj->parent.handle = diskobj; - diskobj->ops = block_io_disk_template; - diskobj->ifname = if_typename; -@@ -207,17 +209,6 @@ static void efi_disk_add_dev(const char *name, - diskobj->media.last_block = desc->lba - offset; - diskobj->ops.media = &diskobj->media; - -- /* Fill in device path */ -- diskobj->dp = dp; -- dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; -- dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; -- dp[0].dp.length = sizeof(*dp); -- ascii2unicode(dp[0].str, name); -- -- dp[1].dp.type = DEVICE_PATH_TYPE_END; -- dp[1].dp.sub_type = DEVICE_PATH_SUB_TYPE_END; -- dp[1].dp.length = sizeof(*dp); -- - /* Hook up to the device list */ - list_add_tail(&diskobj->parent.link, &efi_obj_list); - } -@@ -236,14 +227,18 @@ static int efi_disk_create_eltorito(struct blk_desc *desc, - if (desc->part_type != PART_TYPE_ISO) - return 0; - -+ /* and devices for each partition: */ - while (!part_get_info(desc, part, &info)) { - snprintf(devname, sizeof(devname), "%s:%d", pdevname, - part); - efi_disk_add_dev(devname, if_typename, desc, diskid, -- info.start); -+ info.start, part); - part++; - disks++; - } -+ -+ /* ... and add block device: */ -+ efi_disk_add_dev(devname, if_typename, desc, diskid, 0, 0); - #endif - - return disks; -@@ -271,9 +266,22 @@ int efi_disk_register(void) - uclass_next_device_check(&dev)) { - struct blk_desc *desc = dev_get_uclass_platdata(dev); - const char *if_typename = dev->driver->name; -+ disk_partition_t info; -+ int part = 1; - - printf("Scanning disk %s...\n", dev->name); -- efi_disk_add_dev(dev->name, if_typename, desc, desc->devnum, 0); -+ -+ /* add devices for each partition: */ -+ while (!part_get_info(desc, part, &info)) { -+ efi_disk_add_dev(dev->name, if_typename, desc, -+ desc->devnum, 0, part); -+ part++; -+ } -+ -+ /* ... and add block device: */ -+ efi_disk_add_dev(dev->name, if_typename, desc, -+ desc->devnum, 0, 0); -+ - disks++; - - /* -@@ -309,7 +317,7 @@ int efi_disk_register(void) - - snprintf(devname, sizeof(devname), "%s%d", - if_typename, i); -- efi_disk_add_dev(devname, if_typename, desc, i, 0); -+ efi_disk_add_dev(devname, if_typename, desc, i, 0, 0); - disks++; - - /* --- -2.13.3 - -From c72b667b6ea2f3e2483a0ec0ac4f443d9e09863b Mon Sep 17 00:00:00 2001 -From: Rob Clark -Date: Thu, 27 Jul 2017 16:50:45 -0400 -Subject: [PATCH 10/13] efi_loader: use proper device-paths for net - -Signed-off-by: Rob Clark ---- - include/efi_loader.h | 2 +- - lib/efi_loader/efi_net.c | 24 +++--------------------- - 2 files changed, 4 insertions(+), 22 deletions(-) - -diff --git a/include/efi_loader.h b/include/efi_loader.h -index 1ab4af0f88..c783d0da51 100644 ---- a/include/efi_loader.h -+++ b/include/efi_loader.h -@@ -143,7 +143,7 @@ int efi_disk_register(void); - /* Called by bootefi to make GOP (graphical) interface available */ - int efi_gop_register(void); - /* Called by bootefi to make the network interface available */ --int efi_net_register(void **handle); -+int efi_net_register(void); - /* Called by bootefi to make SMBIOS tables available */ - void efi_smbios_register(void); - -diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c -index 0b949d86e8..91f1e4a69e 100644 ---- a/lib/efi_loader/efi_net.c -+++ b/lib/efi_loader/efi_net.c -@@ -26,9 +26,6 @@ struct efi_net_obj { - /* EFI Interface callback struct for network */ - struct efi_simple_network net; - struct efi_simple_network_mode net_mode; -- /* Device path to the network adapter */ -- struct efi_device_path_mac_addr dp_mac; -- struct efi_device_path_file_path dp_end; - /* PXE struct to transmit dhcp data */ - struct efi_pxe pxe; - struct efi_pxe_mode pxe_mode; -@@ -210,19 +207,9 @@ void efi_net_set_dhcp_ack(void *pkt, int len) - } - - /* This gets called from do_bootefi_exec(). */ --int efi_net_register(void **handle) -+int efi_net_register(void) - { - struct efi_net_obj *netobj; -- struct efi_device_path_mac_addr dp_net = { -- .dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE, -- .dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR, -- .dp.length = sizeof(dp_net), -- }; -- struct efi_device_path_file_path dp_end = { -- .dp.type = DEVICE_PATH_TYPE_END, -- .dp.sub_type = DEVICE_PATH_SUB_TYPE_END, -- .dp.length = sizeof(dp_end), -- }; - - if (!eth_get_dev()) { - /* No eth device active, don't expose any */ -@@ -236,7 +223,8 @@ int efi_net_register(void **handle) - netobj->parent.protocols[0].guid = &efi_net_guid; - netobj->parent.protocols[0].protocol_interface = &netobj->net; - netobj->parent.protocols[1].guid = &efi_guid_device_path; -- netobj->parent.protocols[1].protocol_interface = &netobj->dp_mac; -+ netobj->parent.protocols[1].protocol_interface = -+ efi_dp_from_eth(); - netobj->parent.protocols[2].guid = &efi_pxe_guid; - netobj->parent.protocols[2].protocol_interface = &netobj->pxe; - netobj->parent.handle = &netobj->net; -@@ -255,9 +243,6 @@ int efi_net_register(void **handle) - netobj->net.receive = efi_net_receive; - netobj->net.mode = &netobj->net_mode; - netobj->net_mode.state = EFI_NETWORK_STARTED; -- netobj->dp_mac = dp_net; -- netobj->dp_end = dp_end; -- memcpy(netobj->dp_mac.mac.addr, eth_get_ethaddr(), 6); - memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6); - netobj->net_mode.max_packet_size = PKTSIZE; - -@@ -268,8 +253,5 @@ int efi_net_register(void **handle) - /* Hook net up to the device list */ - list_add_tail(&netobj->parent.link, &efi_obj_list); - -- if (handle) -- *handle = &netobj->net; -- - return 0; - } --- -2.13.3 - -From 52f916744dc8ac73f00480a906c4239160a007ad Mon Sep 17 00:00:00 2001 -From: Rob Clark -Date: Thu, 27 Jul 2017 15:18:18 -0400 -Subject: [PATCH 11/13] efi_loader: refactor boot device and loaded_image - handling - -Get rid of the hacky fake boot-device and duplicate device-path -constructing (which needs to match what efi_disk and efi_net do). -Instead convert over to use efi_device_path helpers to construct -device-paths, and use that to look up the actual boot device. - -Also, extract out a helper to plug things in properly to the -loaded_image. In a following patch we'll want to re-use this in -efi_load_image() to handle the case of loading an image from a -file_path. - -Signed-off-by: Rob Clark ---- - cmd/bootefi.c | 201 +++++++++++++----------------------------- - include/efi_loader.h | 3 + - lib/efi_loader/efi_boottime.c | 35 ++++++++ - 3 files changed, 97 insertions(+), 142 deletions(-) - -diff --git a/cmd/bootefi.c b/cmd/bootefi.c -index d20775eccd..b9e1e5e131 100644 ---- a/cmd/bootefi.c -+++ b/cmd/bootefi.c -@@ -22,97 +22,14 @@ DECLARE_GLOBAL_DATA_PTR; - - static uint8_t efi_obj_list_initalized; - --/* -- * When booting using the "bootefi" command, we don't know which -- * physical device the file came from. So we create a pseudo-device -- * called "bootefi" with the device path /bootefi. -- * -- * In addition to the originating device we also declare the file path -- * of "bootefi" based loads to be /bootefi. -- */ --static struct efi_device_path_file_path bootefi_image_path[] = { -- { -- .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE, -- .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH, -- .dp.length = sizeof(bootefi_image_path[0]), -- .str = { 'b','o','o','t','e','f','i' }, -- }, { -- .dp.type = DEVICE_PATH_TYPE_END, -- .dp.sub_type = DEVICE_PATH_SUB_TYPE_END, -- .dp.length = sizeof(bootefi_image_path[0]), -- } --}; -- --static struct efi_device_path_file_path bootefi_device_path[] = { -- { -- .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE, -- .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH, -- .dp.length = sizeof(bootefi_image_path[0]), -- .str = { 'b','o','o','t','e','f','i' }, -- }, { -- .dp.type = DEVICE_PATH_TYPE_END, -- .dp.sub_type = DEVICE_PATH_SUB_TYPE_END, -- .dp.length = sizeof(bootefi_image_path[0]), -- } --}; -- --/* The EFI loaded_image interface for the image executed via "bootefi" */ --static struct efi_loaded_image loaded_image_info = { -- .device_handle = bootefi_device_path, -- .file_path = bootefi_image_path, --}; -- --/* The EFI object struct for the image executed via "bootefi" */ --static struct efi_object loaded_image_info_obj = { -- .handle = &loaded_image_info, -- .protocols = { -- { -- /* -- * When asking for the loaded_image interface, just -- * return handle which points to loaded_image_info -- */ -- .guid = &efi_guid_loaded_image, -- .protocol_interface = &loaded_image_info, -- }, -- { -- /* -- * When asking for the device path interface, return -- * bootefi_device_path -- */ -- .guid = &efi_guid_device_path, -- .protocol_interface = bootefi_device_path, -- }, -- { -- .guid = &efi_guid_console_control, -- .protocol_interface = (void *) &efi_console_control -- }, -- { -- .guid = &efi_guid_device_path_to_text_protocol, -- .protocol_interface = (void *) &efi_device_path_to_text -- }, -- }, --}; -- --/* The EFI object struct for the device the "bootefi" image was loaded from */ --static struct efi_object bootefi_device_obj = { -- .handle = bootefi_device_path, -- .protocols = { -- { -- /* When asking for the device path interface, return -- * bootefi_device_path */ -- .guid = &efi_guid_device_path, -- .protocol_interface = bootefi_device_path -- } -- }, --}; -+static struct efi_device_path *bootefi_image_path; -+static struct efi_device_path *bootefi_device_path; - - /* Initialize and populate EFI object list */ - static void efi_init_obj_list(void) - { - efi_obj_list_initalized = 1; - -- list_add_tail(&loaded_image_info_obj.link, &efi_obj_list); -- list_add_tail(&bootefi_device_obj.link, &efi_obj_list); - efi_console_register(); - #ifdef CONFIG_PARTITIONS - efi_disk_register(); -@@ -121,13 +38,7 @@ static void efi_init_obj_list(void) - efi_gop_register(); - #endif - #ifdef CONFIG_NET -- void *nethandle = loaded_image_info.device_handle; -- efi_net_register(&nethandle); -- -- if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6)) -- loaded_image_info.device_handle = nethandle; -- else -- loaded_image_info.device_handle = bootefi_device_path; -+ efi_net_register(); - #endif - #ifdef CONFIG_GENERATE_SMBIOS_TABLE - efi_smbios_register(); -@@ -210,14 +121,27 @@ static unsigned long efi_run_in_el2(asmlinkage ulong (*entry)( - * Load an EFI payload into a newly allocated piece of memory, register all - * EFI objects it would want to access and jump to it. - */ --static unsigned long do_bootefi_exec(void *efi, void *fdt) -+static unsigned long do_bootefi_exec(void *efi, void *fdt, -+ struct efi_device_path *device_path, -+ struct efi_device_path *image_path) - { -+ struct efi_loaded_image loaded_image_info = {}; -+ struct efi_object loaded_image_info_obj = {}; -+ ulong ret; -+ - ulong (*entry)(void *image_handle, struct efi_system_table *st) - asmlinkage; - ulong fdt_pages, fdt_size, fdt_start, fdt_end; - const efi_guid_t fdt_guid = EFI_FDT_GUID; - bootm_headers_t img = { 0 }; - -+ /* Initialize and populate EFI object list */ -+ if (!efi_obj_list_initalized) -+ efi_init_obj_list(); -+ -+ efi_setup_loaded_image(&loaded_image_info, &loaded_image_info_obj, -+ device_path, image_path); -+ - /* - * gd lives in a fixed register which may get clobbered while we execute - * the payload. So save it here and restore it on every callback entry -@@ -252,18 +176,18 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) - - /* Load the EFI payload */ - entry = efi_load_pe(efi, &loaded_image_info); -- if (!entry) -- return -ENOENT; -- -- /* Initialize and populate EFI object list */ -- if (!efi_obj_list_initalized) -- efi_init_obj_list(); -+ if (!entry) { -+ ret = -ENOENT; -+ goto exit; -+ } - - /* Call our payload! */ - debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry); - - if (setjmp(&loaded_image_info.exit_jmp)) { -- return loaded_image_info.exit_status; -+ ret = loaded_image_info.exit_status; -+ EFI_EXIT(ret); -+ goto exit; - } - - #ifdef CONFIG_ARM64 -@@ -282,7 +206,13 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) - } - #endif - -- return efi_do_enter(&loaded_image_info, &systab, entry); -+ ret = efi_do_enter(&loaded_image_info, &systab, entry); -+ -+exit: -+ /* image has returned, loaded-image obj goes *poof*: */ -+ list_del(&loaded_image_info_obj.link); -+ -+ return ret; - } - - -@@ -315,7 +245,8 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) - } - - printf("## Starting EFI application at %08lx ...\n", addr); -- r = do_bootefi_exec((void *)addr, (void*)fdt_addr); -+ r = do_bootefi_exec((void *)addr, (void*)fdt_addr, -+ bootefi_device_path, bootefi_image_path); - printf("## Application terminated, r = %lu\n", - r & ~EFI_ERROR_MASK); - -@@ -344,58 +275,44 @@ U_BOOT_CMD( - bootefi_help_text - ); - --void efi_set_bootdev(const char *dev, const char *devnr, const char *path) -+static int parse_partnum(const char *devnr) - { -- __maybe_unused struct blk_desc *desc; -- char devname[32] = { 0 }; /* dp->str is u16[32] long */ -- char *colon, *s; -- --#if defined(CONFIG_BLK) || CONFIG_IS_ENABLED(ISO_PARTITION) -- desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10)); --#endif -- --#ifdef CONFIG_BLK -- if (desc) { -- snprintf(devname, sizeof(devname), "%s", desc->bdev->name); -- } else --#endif -- -- { -- /* Assemble the condensed device name we use in efi_disk.c */ -- snprintf(devname, sizeof(devname), "%s%s", dev, devnr); -+ const char *str = strchr(devnr, ':'); -+ if (str) { -+ str++; -+ return simple_strtoul(str, NULL, 16); - } -+ return 0; -+} - -- colon = strchr(devname, ':'); -- --#if CONFIG_IS_ENABLED(ISO_PARTITION) -- /* For ISOs we create partition block devices */ -- if (desc && (desc->type != DEV_TYPE_UNKNOWN) && -- (desc->part_type == PART_TYPE_ISO)) { -- if (!colon) -- snprintf(devname, sizeof(devname), "%s:1", devname); -+void efi_set_bootdev(const char *dev, const char *devnr, const char *path) -+{ -+ char filename[32] = { 0 }; /* dp->str is u16[32] long */ -+ char *s; - -- colon = NULL; -- } --#endif -+ if (strcmp(dev, "Net")) { -+ struct blk_desc *desc; -+ int part; - -- if (colon) -- *colon = '\0'; -+ desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10)); -+ part = parse_partnum(devnr); - -- /* Patch bootefi_device_path to the target device */ -- memset(bootefi_device_path[0].str, 0, sizeof(bootefi_device_path[0].str)); -- ascii2unicode(bootefi_device_path[0].str, devname); -+ bootefi_device_path = efi_dp_from_part(desc, part); -+ } else { -+#ifdef CONFIG_NET -+ bootefi_device_path = efi_dp_from_eth(); -+#endif -+ } - -- /* Patch bootefi_image_path to the target file path */ -- memset(bootefi_image_path[0].str, 0, sizeof(bootefi_image_path[0].str)); - if (strcmp(dev, "Net")) { - /* Add leading / to fs paths, because they're absolute */ -- snprintf(devname, sizeof(devname), "/%s", path); -+ snprintf(filename, sizeof(filename), "/%s", path); - } else { -- snprintf(devname, sizeof(devname), "%s", path); -+ snprintf(filename, sizeof(filename), "%s", path); - } - /* DOS style file path: */ -- s = devname; -+ s = filename; - while ((s = strchr(s, '/'))) - *s++ = '\\'; -- ascii2unicode(bootefi_image_path[0].str, devname); -+ bootefi_image_path = efi_dp_from_file(NULL, 0, filename); - } -diff --git a/include/efi_loader.h b/include/efi_loader.h -index c783d0da51..479fb6b63d 100644 ---- a/include/efi_loader.h -+++ b/include/efi_loader.h -@@ -203,6 +203,9 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table - efi_status_t efi_get_protocol(struct efi_object *efiobj, - struct efi_handler *handler, - void **protocol_interface); -+void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *obj, -+ struct efi_device_path *device_path, -+ struct efi_device_path *file_path); - - #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER - extern void *efi_bounce_buffer; -diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c -index 4b78f6d556..4a19fabdb3 100644 ---- a/lib/efi_loader/efi_boottime.c -+++ b/lib/efi_loader/efi_boottime.c -@@ -714,6 +714,41 @@ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid, - return EFI_EXIT(efi_install_configuration_table(guid, table)); - } - -+/* Initialize a loaded_image_info + loaded_image_info object with correct -+ * protocols, boot-device, etc. -+ */ -+void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *obj, -+ struct efi_device_path *device_path, -+ struct efi_device_path *file_path) -+{ -+ obj->handle = info; -+ -+ /* -+ * When asking for the device path interface, return -+ * bootefi_device_path -+ */ -+ obj->protocols[0].guid = &efi_guid_device_path; -+ obj->protocols[0].protocol_interface = device_path; -+ -+ /* -+ * When asking for the loaded_image interface, just -+ * return handle which points to loaded_image_info -+ */ -+ obj->protocols[1].guid = &efi_guid_loaded_image; -+ obj->protocols[1].protocol_interface = info; -+ -+ obj->protocols[2].guid = &efi_guid_console_control; -+ obj->protocols[2].protocol_interface = (void *)&efi_console_control; -+ -+ obj->protocols[3].guid = &efi_guid_device_path_to_text_protocol; -+ obj->protocols[3].protocol_interface = (void *)&efi_guid_device_path_to_text_protocol; -+ -+ info->file_path = file_path; -+ info->device_handle = efi_dp_find_obj(device_path); -+ -+ list_add_tail(&obj->link, &efi_obj_list); -+} -+ - static efi_status_t EFIAPI efi_load_image(bool boot_policy, - efi_handle_t parent_image, - struct efi_device_path *file_path, --- -2.13.3 diff --git a/uefi-improve-fat.patch b/uefi-improve-fat.patch new file mode 100644 index 0000000..f6445cb --- /dev/null +++ b/uefi-improve-fat.patch @@ -0,0 +1,2620 @@ +From 45449980f80169214633f2649a27c791d0104e9d Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Sat, 9 Sep 2017 13:15:52 -0400 +Subject: [PATCH 34/47] fs/fat: split out helper to init fsdata +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Want to re-use this in fat dirent iterator in next patch. + +Signed-off-by: Rob Clark +Reviewed-by: Łukasz Majewski +Reviewed-by: Simon Glass +--- + fs/fat/fat.c | 73 +++++++++++++++++++++++++++++++++++------------------------ + include/fat.h | 1 + + 2 files changed, 44 insertions(+), 30 deletions(-) + +diff --git a/fs/fat/fat.c b/fs/fat/fat.c +index 465a6875ed..e1c0a15dc7 100644 +--- a/fs/fat/fat.c ++++ b/fs/fat/fat.c +@@ -808,35 +808,17 @@ exit: + return ret; + } + +-__u8 do_fat_read_at_block[MAX_CLUSTSIZE] +- __aligned(ARCH_DMA_MINALIGN); +- +-int do_fat_read_at(const char *filename, loff_t pos, void *buffer, +- loff_t maxsize, int dols, int dogetsize, loff_t *size) ++static int get_fs_info(fsdata *mydata) + { +- char fnamecopy[2048]; + boot_sector bs; + volume_info volinfo; +- fsdata datablock; +- fsdata *mydata = &datablock; +- dir_entry *dentptr = NULL; +- __u16 prevcksum = 0xffff; +- char *subname = ""; +- __u32 cursect; +- int idx, isdir = 0; +- int files = 0, dirs = 0; +- int ret = -1; +- int firsttime; + __u32 root_cluster = 0; +- __u32 read_blk; +- int rootdir_size = 0; +- int buffer_blk_cnt; +- int do_read; +- __u8 *dir_ptr; ++ int ret; + +- if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) { ++ ret = read_bootsectandvi(&bs, &volinfo, &mydata->fatsize); ++ if (ret) { + debug("Error: reading boot sector\n"); +- return -1; ++ return ret; + } + + if (mydata->fatsize == 32) { +@@ -848,8 +830,7 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer, + + mydata->fat_sect = bs.reserved; + +- cursect = mydata->rootdir_sect +- = mydata->fat_sect + mydata->fatlength * bs.fats; ++ mydata->rootdir_sect = mydata->fat_sect + mydata->fatlength * bs.fats; + + mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; + mydata->clust_size = bs.cluster_size; +@@ -863,12 +844,12 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer, + mydata->data_begin = mydata->rootdir_sect - + (mydata->clust_size * 2); + } else { +- rootdir_size = ((bs.dir_entries[1] * (int)256 + +- bs.dir_entries[0]) * +- sizeof(dir_entry)) / +- mydata->sect_size; ++ mydata->rootdir_size = ((bs.dir_entries[1] * (int)256 + ++ bs.dir_entries[0]) * ++ sizeof(dir_entry)) / ++ mydata->sect_size; + mydata->data_begin = mydata->rootdir_sect + +- rootdir_size - ++ mydata->rootdir_size - + (mydata->clust_size * 2); + } + +@@ -893,6 +874,38 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer, + debug("Sector size: %d, cluster size: %d\n", mydata->sect_size, + mydata->clust_size); + ++ return 0; ++} ++ ++__u8 do_fat_read_at_block[MAX_CLUSTSIZE] ++ __aligned(ARCH_DMA_MINALIGN); ++ ++int do_fat_read_at(const char *filename, loff_t pos, void *buffer, ++ loff_t maxsize, int dols, int dogetsize, loff_t *size) ++{ ++ char fnamecopy[2048]; ++ fsdata datablock; ++ fsdata *mydata = &datablock; ++ dir_entry *dentptr = NULL; ++ __u16 prevcksum = 0xffff; ++ char *subname = ""; ++ __u32 cursect; ++ int idx, isdir = 0; ++ int files = 0, dirs = 0; ++ int ret = -1; ++ int firsttime; ++ __u32 root_cluster = 0; ++ __u32 read_blk; ++ int rootdir_size = 0; ++ int buffer_blk_cnt; ++ int do_read; ++ __u8 *dir_ptr; ++ ++ if (get_fs_info(mydata)) ++ return -1; ++ ++ cursect = mydata->rootdir_sect; ++ + /* "cwd" is always the root... */ + while (ISDIRDELIM(*filename)) + filename++; +diff --git a/include/fat.h b/include/fat.h +index 71879f01ca..b671ee8f81 100644 +--- a/include/fat.h ++++ b/include/fat.h +@@ -174,6 +174,7 @@ typedef struct { + __u16 clust_size; /* Size of clusters in sectors */ + int data_begin; /* The sector of the first cluster, can be negative */ + int fatbufnum; /* Used by get_fatent, init to -1 */ ++ int rootdir_size; /* Size of root dir for non-FAT32 */ + } fsdata; + + typedef int (file_detectfs_func)(void); +-- +2.13.5 + +From c6e3baa565bc3b5828cf0d67ca6429dbe5f8687c Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Sat, 9 Sep 2017 13:15:53 -0400 +Subject: [PATCH 35/47] fs/fat: introduce new director iterators +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Untangle directory traversal into a simple iterator, to replace the +existing multi-purpose do_fat_read_at() + get_dentfromdir(). + +Signed-off-by: Rob Clark +Reviewed-by: Łukasz Majewski +--- + fs/fat/fat.c | 356 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- + include/fat.h | 7 ++ + 2 files changed, 360 insertions(+), 3 deletions(-) + +diff --git a/fs/fat/fat.c b/fs/fat/fat.c +index e1c0a15dc7..ee2bbe38f1 100644 +--- a/fs/fat/fat.c ++++ b/fs/fat/fat.c +@@ -812,7 +812,6 @@ static int get_fs_info(fsdata *mydata) + { + boot_sector bs; + volume_info volinfo; +- __u32 root_cluster = 0; + int ret; + + ret = read_bootsectandvi(&bs, &volinfo, &mydata->fatsize); +@@ -822,7 +821,6 @@ static int get_fs_info(fsdata *mydata) + } + + if (mydata->fatsize == 32) { +- root_cluster = bs.root_cluster; + mydata->fatlength = bs.fat32_length; + } else { + mydata->fatlength = bs.fat_length; +@@ -843,6 +841,7 @@ static int get_fs_info(fsdata *mydata) + if (mydata->fatsize == 32) { + mydata->data_begin = mydata->rootdir_sect - + (mydata->clust_size * 2); ++ mydata->root_cluster = bs.root_cluster; + } else { + mydata->rootdir_size = ((bs.dir_entries[1] * (int)256 + + bs.dir_entries[0]) * +@@ -851,6 +850,9 @@ static int get_fs_info(fsdata *mydata) + mydata->data_begin = mydata->rootdir_sect + + mydata->rootdir_size - + (mydata->clust_size * 2); ++ mydata->root_cluster = (mydata->rootdir_sect - ++ mydata->data_begin) / ++ mydata->clust_size; + } + + mydata->fatbufnum = -1; +@@ -868,7 +870,7 @@ static int get_fs_info(fsdata *mydata) + mydata->fatsize, mydata->fat_sect, mydata->fatlength); + debug("Rootdir begins at cluster: %d, sector: %d, offset: %x\n" + "Data begins at: %d\n", +- root_cluster, ++ mydata->root_cluster, + mydata->rootdir_sect, + mydata->rootdir_sect * mydata->sect_size, mydata->data_begin); + debug("Sector size: %d, cluster size: %d\n", mydata->sect_size, +@@ -1245,6 +1247,354 @@ exit: + return ret; + } + ++ ++/* ++ * Directory iterator, to simplify filesystem traversal ++ * ++ * Implements an iterator pattern to traverse directory tables, ++ * transparently handling directory tables split across multiple ++ * clusters, and the difference between FAT12/FAT16 root directory ++ * (contiguous) and subdirectories + FAT32 root (chained). ++ * ++ * Rough usage: ++ * ++ * for (fat_itr_root(&itr, fsdata); fat_itr_next(&itr); ) { ++ * // to traverse down to a subdirectory pointed to by ++ * // current iterator position: ++ * fat_itr_child(&itr, &itr); ++ * } ++ * ++ * For more complete example, see fat_itr_resolve() ++ */ ++ ++typedef struct { ++ fsdata *fsdata; /* filesystem parameters */ ++ unsigned clust; /* current cluster */ ++ int last_cluster; /* set once we've read last cluster */ ++ int is_root; /* is iterator at root directory */ ++ int remaining; /* remaining dent's in current cluster */ ++ ++ /* current iterator position values: */ ++ dir_entry *dent; /* current directory entry */ ++ char l_name[VFAT_MAXLEN_BYTES]; /* long (vfat) name */ ++ char s_name[14]; /* short 8.3 name */ ++ char *name; /* l_name if there is one, else s_name */ ++ ++ /* storage for current cluster in memory: */ ++ u8 block[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN); ++} fat_itr; ++ ++static int fat_itr_isdir(fat_itr *itr); ++ ++/** ++ * fat_itr_root() - initialize an iterator to start at the root ++ * directory ++ * ++ * @itr: iterator to initialize ++ * @fsdata: filesystem data for the partition ++ * @return 0 on success, else -errno ++ */ ++static int fat_itr_root(fat_itr *itr, fsdata *fsdata) ++{ ++ if (get_fs_info(fsdata)) ++ return -ENXIO; ++ ++ itr->fsdata = fsdata; ++ itr->clust = fsdata->root_cluster; ++ itr->dent = NULL; ++ itr->remaining = 0; ++ itr->last_cluster = 0; ++ itr->is_root = 1; ++ ++ return 0; ++} ++ ++/** ++ * fat_itr_child() - initialize an iterator to descend into a sub- ++ * directory ++ * ++ * Initializes 'itr' to iterate the contents of the directory at ++ * the current cursor position of 'parent'. It is an error to ++ * call this if the current cursor of 'parent' is pointing at a ++ * regular file. ++ * ++ * Note that 'itr' and 'parent' can be the same pointer if you do ++ * not need to preserve 'parent' after this call, which is useful ++ * for traversing directory structure to resolve a file/directory. ++ * ++ * @itr: iterator to initialize ++ * @parent: the iterator pointing at a directory entry in the ++ * parent directory of the directory to iterate ++ */ ++static void fat_itr_child(fat_itr *itr, fat_itr *parent) ++{ ++ fsdata *mydata = parent->fsdata; /* for silly macros */ ++ unsigned clustnum = START(parent->dent); ++ ++ assert(fat_itr_isdir(parent)); ++ ++ itr->fsdata = parent->fsdata; ++ if (clustnum > 0) { ++ itr->clust = clustnum; ++ } else { ++ itr->clust = parent->fsdata->root_cluster; ++ } ++ itr->dent = NULL; ++ itr->remaining = 0; ++ itr->last_cluster = 0; ++ itr->is_root = 0; ++} ++ ++static void *next_cluster(fat_itr *itr) ++{ ++ fsdata *mydata = itr->fsdata; /* for silly macros */ ++ int ret; ++ u32 sect; ++ ++ /* have we reached the end? */ ++ if (itr->last_cluster) ++ return NULL; ++ ++ sect = clust_to_sect(itr->fsdata, itr->clust); ++ ++ debug("FAT read(sect=%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n", ++ sect, itr->fsdata->clust_size, DIRENTSPERBLOCK); ++ ++ /* ++ * NOTE: do_fat_read_at() had complicated logic to deal w/ ++ * vfat names that span multiple clusters in the fat16 case, ++ * which get_dentfromdir() probably also needed (and was ++ * missing). And not entirely sure what fat32 didn't have ++ * the same issue.. We solve that by only caring about one ++ * dent at a time and iteratively constructing the vfat long ++ * name. ++ */ ++ ret = disk_read(sect, itr->fsdata->clust_size, ++ itr->block); ++ if (ret < 0) { ++ debug("Error: reading block\n"); ++ return NULL; ++ } ++ ++ if (itr->is_root && itr->fsdata->fatsize != 32) { ++ itr->clust++; ++ sect = clust_to_sect(itr->fsdata, itr->clust); ++ if (sect - itr->fsdata->rootdir_sect >= ++ itr->fsdata->rootdir_size) { ++ debug("cursect: 0x%x\n", itr->clust); ++ itr->last_cluster = 1; ++ } ++ } else { ++ itr->clust = get_fatent(itr->fsdata, itr->clust); ++ if (CHECK_CLUST(itr->clust, itr->fsdata->fatsize)) { ++ debug("cursect: 0x%x\n", itr->clust); ++ itr->last_cluster = 1; ++ } ++ } ++ ++ return itr->block; ++} ++ ++static dir_entry *next_dent(fat_itr *itr) ++{ ++ if (itr->remaining == 0) { ++ struct dir_entry *dent = next_cluster(itr); ++ unsigned nbytes = itr->fsdata->sect_size * ++ itr->fsdata->clust_size; ++ ++ /* have we reached the last cluster? */ ++ if (!dent) ++ return NULL; ++ ++ itr->remaining = nbytes / sizeof(dir_entry) - 1; ++ itr->dent = dent; ++ } else { ++ itr->remaining--; ++ itr->dent++; ++ } ++ ++ /* have we reached the last valid entry? */ ++ if (itr->dent->name[0] == 0) ++ return NULL; ++ ++ return itr->dent; ++} ++ ++static dir_entry *extract_vfat_name(fat_itr *itr) ++{ ++ struct dir_entry *dent = itr->dent; ++ int seqn = itr->dent->name[0] & ~LAST_LONG_ENTRY_MASK; ++ u8 chksum, alias_checksum = ((dir_slot *)dent)->alias_checksum; ++ int n = 0; ++ ++ while (seqn--) { ++ char buf[13]; ++ int idx = 0; ++ ++ slot2str((dir_slot *)dent, buf, &idx); ++ ++ /* shift accumulated long-name up and copy new part in: */ ++ memmove(itr->l_name + idx, itr->l_name, n); ++ memcpy(itr->l_name, buf, idx); ++ n += idx; ++ ++ dent = next_dent(itr); ++ if (!dent) ++ return NULL; ++ } ++ ++ itr->l_name[n] = '\0'; ++ ++ chksum = mkcksum(dent->name, dent->ext); ++ ++ /* checksum mismatch could mean deleted file, etc.. skip it: */ ++ if (chksum != alias_checksum) { ++ debug("** chksum=%x, alias_checksum=%x, l_name=%s, s_name=%8s.%3s\n", ++ chksum, alias_checksum, itr->l_name, dent->name, dent->ext); ++ return NULL; ++ } ++ ++ return dent; ++} ++ ++/** ++ * fat_itr_next() - step to the next entry in a directory ++ * ++ * Must be called once on a new iterator before the cursor is valid. ++ * ++ * @itr: the iterator to iterate ++ * @return boolean, 1 if success or 0 if no more entries in the ++ * current directory ++ */ ++static int fat_itr_next(fat_itr *itr) ++{ ++ dir_entry *dent; ++ ++ itr->name = NULL; ++ ++ while (1) { ++ dent = next_dent(itr); ++ if (!dent) ++ return 0; ++ ++ if (dent->name[0] == DELETED_FLAG || ++ dent->name[0] == aRING) ++ continue; ++ ++ if (dent->attr & ATTR_VOLUME) { ++ if (vfat_enabled && ++ (dent->attr & ATTR_VFAT) == ATTR_VFAT && ++ (dent->name[0] & LAST_LONG_ENTRY_MASK)) { ++ dent = extract_vfat_name(itr); ++ if (!dent) ++ continue; ++ itr->name = itr->l_name; ++ break; ++ } else { ++ /* Volume label or VFAT entry, skip */ ++ continue; ++ } ++ } ++ ++ break; ++ } ++ ++ get_name(dent, itr->s_name); ++ if (!itr->name) ++ itr->name = itr->s_name; ++ ++ return 1; ++} ++ ++/** ++ * fat_itr_isdir() - is current cursor position pointing to a directory ++ * ++ * @itr: the iterator ++ * @return true if cursor is at a directory ++ */ ++static int fat_itr_isdir(fat_itr *itr) ++{ ++ return !!(itr->dent->attr & ATTR_DIR); ++} ++ ++/* ++ * Helpers: ++ */ ++ ++#define TYPE_FILE 0x1 ++#define TYPE_DIR 0x2 ++#define TYPE_ANY (TYPE_FILE | TYPE_DIR) ++ ++/** ++ * fat_itr_resolve() - traverse directory structure to resolve the ++ * requested path. ++ * ++ * Traverse directory structure to the requested path. If the specified ++ * path is to a directory, this will descend into the directory and ++ * leave it iterator at the start of the directory. If the path is to a ++ * file, it will leave the iterator in the parent directory with current ++ * cursor at file's entry in the directory. ++ * ++ * @itr: iterator initialized to root ++ * @path: the requested path ++ * @type: bitmask of allowable file types ++ * @return 0 on success or -errno ++ */ ++static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type) ++{ ++ const char *next; ++ ++ /* chomp any extra leading slashes: */ ++ while (path[0] && ISDIRDELIM(path[0])) ++ path++; ++ ++ /* are we at the end? */ ++ if (strlen(path) == 0) { ++ if (!(type & TYPE_DIR)) ++ return -ENOENT; ++ return 0; ++ } ++ ++ /* find length of next path entry: */ ++ next = path; ++ while (next[0] && !ISDIRDELIM(next[0])) ++ next++; ++ ++ while (fat_itr_next(itr)) { ++ int match = 0; ++ unsigned n = max(strlen(itr->name), (size_t)(next - path)); ++ ++ /* check both long and short name: */ ++ if (!strncasecmp(path, itr->name, n)) ++ match = 1; ++ else if (itr->name != itr->s_name && ++ !strncasecmp(path, itr->s_name, n)) ++ match = 1; ++ ++ if (!match) ++ continue; ++ ++ if (fat_itr_isdir(itr)) { ++ /* recurse into directory: */ ++ fat_itr_child(itr, itr); ++ return fat_itr_resolve(itr, next, type); ++ } else if (next[0]) { ++ /* ++ * If next is not empty then we have a case ++ * like: /path/to/realfile/nonsense ++ */ ++ debug("bad trailing path: %s\n", next); ++ return -ENOENT; ++ } else if (!(type & TYPE_FILE)) { ++ return -ENOTDIR; ++ } else { ++ return 0; ++ } ++ } ++ ++ return -ENOENT; ++} ++ + int do_fat_read(const char *filename, void *buffer, loff_t maxsize, int dols, + loff_t *actread) + { +diff --git a/include/fat.h b/include/fat.h +index b671ee8f81..21bb6666cf 100644 +--- a/include/fat.h ++++ b/include/fat.h +@@ -175,8 +175,15 @@ typedef struct { + int data_begin; /* The sector of the first cluster, can be negative */ + int fatbufnum; /* Used by get_fatent, init to -1 */ + int rootdir_size; /* Size of root dir for non-FAT32 */ ++ __u32 root_cluster; /* First cluster of root dir for FAT32 */ + } fsdata; + ++/* TODO clean up places that are open-coding this: */ ++static inline u32 clust_to_sect(fsdata *fsdata, u32 clust) ++{ ++ return fsdata->data_begin + clust * fsdata->clust_size; ++} ++ + typedef int (file_detectfs_func)(void); + typedef int (file_ls_func)(const char *dir); + typedef int (file_read_func)(const char *filename, void *buffer, +-- +2.13.5 + +From 8eafae209c35932d9a6560809c55ee4641534236 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Sat, 9 Sep 2017 13:15:54 -0400 +Subject: [PATCH 36/47] fat/fs: convert to directory iterators +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +And drop a whole lot of ugly code! + +Signed-off-by: Rob Clark +Reviewed-by: Łukasz Majewski +Reviewed-by: Simon Glass +--- + fs/fat/fat.c | 722 +++++++--------------------------------------------------- + include/fat.h | 6 - + 2 files changed, 76 insertions(+), 652 deletions(-) + +diff --git a/fs/fat/fat.c b/fs/fat/fat.c +index ee2bbe38f1..bbba7947ee 100644 +--- a/fs/fat/fat.c ++++ b/fs/fat/fat.c +@@ -119,22 +119,6 @@ int fat_register_device(struct blk_desc *dev_desc, int part_no) + } + + /* +- * Get the first occurence of a directory delimiter ('/' or '\') in a string. +- * Return index into string if found, -1 otherwise. +- */ +-static int dirdelim(char *str) +-{ +- char *start = str; +- +- while (*str != '\0') { +- if (ISDIRDELIM(*str)) +- return str - start; +- str++; +- } +- return -1; +-} +- +-/* + * Extract zero terminated short name from a directory entry. + */ + static void get_name(dir_entry *dirent, char *s_name) +@@ -468,95 +452,6 @@ static int slot2str(dir_slot *slotptr, char *l_name, int *idx) + return 0; + } + +-/* +- * Extract the full long filename starting at 'retdent' (which is really +- * a slot) into 'l_name'. If successful also copy the real directory entry +- * into 'retdent' +- * Return 0 on success, -1 otherwise. +- */ +-static int +-get_vfatname(fsdata *mydata, int curclust, __u8 *cluster, +- dir_entry *retdent, char *l_name) +-{ +- dir_entry *realdent; +- dir_slot *slotptr = (dir_slot *)retdent; +- __u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ? +- PREFETCH_BLOCKS : +- mydata->clust_size); +- __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff; +- int idx = 0; +- +- if (counter > VFAT_MAXSEQ) { +- debug("Error: VFAT name is too long\n"); +- return -1; +- } +- +- while ((__u8 *)slotptr < buflimit) { +- if (counter == 0) +- break; +- if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter) +- return -1; +- slotptr++; +- counter--; +- } +- +- if ((__u8 *)slotptr >= buflimit) { +- dir_slot *slotptr2; +- +- if (curclust == 0) +- return -1; +- curclust = get_fatent(mydata, curclust); +- if (CHECK_CLUST(curclust, mydata->fatsize)) { +- debug("curclust: 0x%x\n", curclust); +- printf("Invalid FAT entry\n"); +- return -1; +- } +- +- if (get_cluster(mydata, curclust, get_contents_vfatname_block, +- mydata->clust_size * mydata->sect_size) != 0) { +- debug("Error: reading directory block\n"); +- return -1; +- } +- +- slotptr2 = (dir_slot *)get_contents_vfatname_block; +- while (counter > 0) { +- if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK) +- & 0xff) != counter) +- return -1; +- slotptr2++; +- counter--; +- } +- +- /* Save the real directory entry */ +- realdent = (dir_entry *)slotptr2; +- while ((__u8 *)slotptr2 > get_contents_vfatname_block) { +- slotptr2--; +- slot2str(slotptr2, l_name, &idx); +- } +- } else { +- /* Save the real directory entry */ +- realdent = (dir_entry *)slotptr; +- } +- +- do { +- slotptr--; +- if (slot2str(slotptr, l_name, &idx)) +- break; +- } while (!(slotptr->id & LAST_LONG_ENTRY_MASK)); +- +- l_name[idx] = '\0'; +- if (*l_name == DELETED_FLAG) +- *l_name = '\0'; +- else if (*l_name == aRING) +- *l_name = DELETED_FLAG; +- downcase(l_name); +- +- /* Return the real directory entry */ +- memcpy(retdent, realdent, sizeof(dir_entry)); +- +- return 0; +-} +- + /* Calculate short name checksum */ + static __u8 mkcksum(const char name[8], const char ext[3]) + { +@@ -573,169 +468,13 @@ static __u8 mkcksum(const char name[8], const char ext[3]) + } + + /* +- * Get the directory entry associated with 'filename' from the directory +- * starting at 'startsect' ++ * TODO these should go away once fat_write is reworked to use the ++ * directory iterator + */ + __u8 get_dentfromdir_block[MAX_CLUSTSIZE] + __aligned(ARCH_DMA_MINALIGN); +- +-static dir_entry *get_dentfromdir(fsdata *mydata, int startsect, +- char *filename, dir_entry *retdent, +- int dols) +-{ +- __u16 prevcksum = 0xffff; +- __u32 curclust = START(retdent); +- int files = 0, dirs = 0; +- +- debug("get_dentfromdir: %s\n", filename); +- +- while (1) { +- dir_entry *dentptr; +- +- int i; +- +- if (get_cluster(mydata, curclust, get_dentfromdir_block, +- mydata->clust_size * mydata->sect_size) != 0) { +- debug("Error: reading directory block\n"); +- return NULL; +- } +- +- dentptr = (dir_entry *)get_dentfromdir_block; +- +- for (i = 0; i < DIRENTSPERCLUST; i++) { +- char s_name[14], l_name[VFAT_MAXLEN_BYTES]; +- +- l_name[0] = '\0'; +- if (dentptr->name[0] == DELETED_FLAG) { +- dentptr++; +- continue; +- } +- if ((dentptr->attr & ATTR_VOLUME)) { +- if (vfat_enabled && +- (dentptr->attr & ATTR_VFAT) == ATTR_VFAT && +- (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { +- prevcksum = ((dir_slot *)dentptr)->alias_checksum; +- get_vfatname(mydata, curclust, +- get_dentfromdir_block, +- dentptr, l_name); +- if (dols) { +- int isdir; +- char dirc; +- int doit = 0; +- +- isdir = (dentptr->attr & ATTR_DIR); +- +- if (isdir) { +- dirs++; +- dirc = '/'; +- doit = 1; +- } else { +- dirc = ' '; +- if (l_name[0] != 0) { +- files++; +- doit = 1; +- } +- } +- if (doit) { +- if (dirc == ' ') { +- printf(" %8u %s%c\n", +- FAT2CPU32(dentptr->size), +- l_name, +- dirc); +- } else { +- printf(" %s%c\n", +- l_name, +- dirc); +- } +- } +- dentptr++; +- continue; +- } +- debug("vfatname: |%s|\n", l_name); +- } else { +- /* Volume label or VFAT entry */ +- dentptr++; +- continue; +- } +- } +- if (dentptr->name[0] == 0) { +- if (dols) { +- printf("\n%d file(s), %d dir(s)\n\n", +- files, dirs); +- } +- debug("Dentname == NULL - %d\n", i); +- return NULL; +- } +- if (vfat_enabled) { +- __u8 csum = mkcksum(dentptr->name, dentptr->ext); +- if (dols && csum == prevcksum) { +- prevcksum = 0xffff; +- dentptr++; +- continue; +- } +- } +- +- get_name(dentptr, s_name); +- if (dols) { +- int isdir = (dentptr->attr & ATTR_DIR); +- char dirc; +- int doit = 0; +- +- if (isdir) { +- dirs++; +- dirc = '/'; +- doit = 1; +- } else { +- dirc = ' '; +- if (s_name[0] != 0) { +- files++; +- doit = 1; +- } +- } +- +- if (doit) { +- if (dirc == ' ') { +- printf(" %8u %s%c\n", +- FAT2CPU32(dentptr->size), +- s_name, dirc); +- } else { +- printf(" %s%c\n", +- s_name, dirc); +- } +- } +- +- dentptr++; +- continue; +- } +- +- if (strcmp(filename, s_name) +- && strcmp(filename, l_name)) { +- debug("Mismatch: |%s|%s|\n", s_name, l_name); +- dentptr++; +- continue; +- } +- +- memcpy(retdent, dentptr, sizeof(dir_entry)); +- +- debug("DentName: %s", s_name); +- debug(", start: 0x%x", START(dentptr)); +- debug(", size: 0x%x %s\n", +- FAT2CPU32(dentptr->size), +- (dentptr->attr & ATTR_DIR) ? "(DIR)" : ""); +- +- return retdent; +- } +- +- curclust = get_fatent(mydata, curclust); +- if (CHECK_CLUST(curclust, mydata->fatsize)) { +- debug("curclust: 0x%x\n", curclust); +- printf("Invalid FAT entry\n"); +- return NULL; +- } +- } +- +- return NULL; +-} ++__u8 do_fat_read_at_block[MAX_CLUSTSIZE] ++ __aligned(ARCH_DMA_MINALIGN); + + /* + * Read boot sector and volume info from a FAT filesystem +@@ -879,374 +618,6 @@ static int get_fs_info(fsdata *mydata) + return 0; + } + +-__u8 do_fat_read_at_block[MAX_CLUSTSIZE] +- __aligned(ARCH_DMA_MINALIGN); +- +-int do_fat_read_at(const char *filename, loff_t pos, void *buffer, +- loff_t maxsize, int dols, int dogetsize, loff_t *size) +-{ +- char fnamecopy[2048]; +- fsdata datablock; +- fsdata *mydata = &datablock; +- dir_entry *dentptr = NULL; +- __u16 prevcksum = 0xffff; +- char *subname = ""; +- __u32 cursect; +- int idx, isdir = 0; +- int files = 0, dirs = 0; +- int ret = -1; +- int firsttime; +- __u32 root_cluster = 0; +- __u32 read_blk; +- int rootdir_size = 0; +- int buffer_blk_cnt; +- int do_read; +- __u8 *dir_ptr; +- +- if (get_fs_info(mydata)) +- return -1; +- +- cursect = mydata->rootdir_sect; +- +- /* "cwd" is always the root... */ +- while (ISDIRDELIM(*filename)) +- filename++; +- +- /* Make a copy of the filename and convert it to lowercase */ +- strcpy(fnamecopy, filename); +- downcase(fnamecopy); +- +-root_reparse: +- if (*fnamecopy == '\0') { +- if (!dols) +- goto exit; +- +- dols = LS_ROOT; +- } else if ((idx = dirdelim(fnamecopy)) >= 0) { +- isdir = 1; +- fnamecopy[idx] = '\0'; +- subname = fnamecopy + idx + 1; +- +- /* Handle multiple delimiters */ +- while (ISDIRDELIM(*subname)) +- subname++; +- } else if (dols) { +- isdir = 1; +- } +- +- buffer_blk_cnt = 0; +- firsttime = 1; +- while (1) { +- int i; +- +- if (mydata->fatsize == 32 || firsttime) { +- dir_ptr = do_fat_read_at_block; +- firsttime = 0; +- } else { +- /** +- * FAT16 sector buffer modification: +- * Each loop, the second buffered block is moved to +- * the buffer begin, and two next sectors are read +- * next to the previously moved one. So the sector +- * buffer keeps always 3 sectors for fat16. +- * And the current sector is the buffer second sector +- * beside the "firsttime" read, when it is the first one. +- * +- * PREFETCH_BLOCKS is 2 for FAT16 == loop[0:1] +- * n = computed root dir sector +- * loop | cursect-1 | cursect | cursect+1 | +- * 0 | sector n+0 | sector n+1 | none | +- * 1 | none | sector n+0 | sector n+1 | +- * 0 | sector n+1 | sector n+2 | sector n+3 | +- * 1 | sector n+3 | ... +- */ +- dir_ptr = (do_fat_read_at_block + mydata->sect_size); +- memcpy(do_fat_read_at_block, dir_ptr, mydata->sect_size); +- } +- +- do_read = 1; +- +- if (mydata->fatsize == 32 && buffer_blk_cnt) +- do_read = 0; +- +- if (do_read) { +- read_blk = (mydata->fatsize == 32) ? +- mydata->clust_size : PREFETCH_BLOCKS; +- +- debug("FAT read(sect=%d, cnt:%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n", +- cursect, read_blk, mydata->clust_size, DIRENTSPERBLOCK); +- +- if (disk_read(cursect, read_blk, dir_ptr) < 0) { +- debug("Error: reading rootdir block\n"); +- goto exit; +- } +- +- dentptr = (dir_entry *)dir_ptr; +- } +- +- for (i = 0; i < DIRENTSPERBLOCK; i++) { +- char s_name[14], l_name[VFAT_MAXLEN_BYTES]; +- __u8 csum; +- +- l_name[0] = '\0'; +- if (dentptr->name[0] == DELETED_FLAG) { +- dentptr++; +- continue; +- } +- +- if (vfat_enabled) +- csum = mkcksum(dentptr->name, dentptr->ext); +- +- if (dentptr->attr & ATTR_VOLUME) { +- if (vfat_enabled && +- (dentptr->attr & ATTR_VFAT) == ATTR_VFAT && +- (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { +- prevcksum = +- ((dir_slot *)dentptr)->alias_checksum; +- +- get_vfatname(mydata, +- root_cluster, +- dir_ptr, +- dentptr, l_name); +- +- if (dols == LS_ROOT) { +- char dirc; +- int doit = 0; +- int isdir = +- (dentptr->attr & ATTR_DIR); +- +- if (isdir) { +- dirs++; +- dirc = '/'; +- doit = 1; +- } else { +- dirc = ' '; +- if (l_name[0] != 0) { +- files++; +- doit = 1; +- } +- } +- if (doit) { +- if (dirc == ' ') { +- printf(" %8u %s%c\n", +- FAT2CPU32(dentptr->size), +- l_name, +- dirc); +- } else { +- printf(" %s%c\n", +- l_name, +- dirc); +- } +- } +- dentptr++; +- continue; +- } +- debug("Rootvfatname: |%s|\n", +- l_name); +- } else { +- /* Volume label or VFAT entry */ +- dentptr++; +- continue; +- } +- } else if (dentptr->name[0] == 0) { +- debug("RootDentname == NULL - %d\n", i); +- if (dols == LS_ROOT) { +- printf("\n%d file(s), %d dir(s)\n\n", +- files, dirs); +- ret = 0; +- } +- goto exit; +- } +- else if (vfat_enabled && +- dols == LS_ROOT && csum == prevcksum) { +- prevcksum = 0xffff; +- dentptr++; +- continue; +- } +- +- get_name(dentptr, s_name); +- +- if (dols == LS_ROOT) { +- int isdir = (dentptr->attr & ATTR_DIR); +- char dirc; +- int doit = 0; +- +- if (isdir) { +- dirc = '/'; +- if (s_name[0] != 0) { +- dirs++; +- doit = 1; +- } +- } else { +- dirc = ' '; +- if (s_name[0] != 0) { +- files++; +- doit = 1; +- } +- } +- if (doit) { +- if (dirc == ' ') { +- printf(" %8u %s%c\n", +- FAT2CPU32(dentptr->size), +- s_name, dirc); +- } else { +- printf(" %s%c\n", +- s_name, dirc); +- } +- } +- dentptr++; +- continue; +- } +- +- if (strcmp(fnamecopy, s_name) +- && strcmp(fnamecopy, l_name)) { +- debug("RootMismatch: |%s|%s|\n", s_name, +- l_name); +- dentptr++; +- continue; +- } +- +- if (isdir && !(dentptr->attr & ATTR_DIR)) +- goto exit; +- +- debug("RootName: %s", s_name); +- debug(", start: 0x%x", START(dentptr)); +- debug(", size: 0x%x %s\n", +- FAT2CPU32(dentptr->size), +- isdir ? "(DIR)" : ""); +- +- goto rootdir_done; /* We got a match */ +- } +- debug("END LOOP: buffer_blk_cnt=%d clust_size=%d\n", buffer_blk_cnt, +- mydata->clust_size); +- +- /* +- * On FAT32 we must fetch the FAT entries for the next +- * root directory clusters when a cluster has been +- * completely processed. +- */ +- ++buffer_blk_cnt; +- int rootdir_end = 0; +- if (mydata->fatsize == 32) { +- if (buffer_blk_cnt == mydata->clust_size) { +- int nxtsect = 0; +- int nxt_clust = 0; +- +- nxt_clust = get_fatent(mydata, root_cluster); +- rootdir_end = CHECK_CLUST(nxt_clust, 32); +- +- nxtsect = mydata->data_begin + +- (nxt_clust * mydata->clust_size); +- +- root_cluster = nxt_clust; +- +- cursect = nxtsect; +- buffer_blk_cnt = 0; +- } +- } else { +- if (buffer_blk_cnt == PREFETCH_BLOCKS) +- buffer_blk_cnt = 0; +- +- rootdir_end = (++cursect - mydata->rootdir_sect >= +- rootdir_size); +- } +- +- /* If end of rootdir reached */ +- if (rootdir_end) { +- if (dols == LS_ROOT) { +- printf("\n%d file(s), %d dir(s)\n\n", +- files, dirs); +- *size = 0; +- } +- goto exit; +- } +- } +-rootdir_done: +- +- firsttime = 1; +- +- while (isdir) { +- int startsect = mydata->data_begin +- + START(dentptr) * mydata->clust_size; +- dir_entry dent; +- char *nextname = NULL; +- +- dent = *dentptr; +- dentptr = &dent; +- +- idx = dirdelim(subname); +- +- if (idx >= 0) { +- subname[idx] = '\0'; +- nextname = subname + idx + 1; +- /* Handle multiple delimiters */ +- while (ISDIRDELIM(*nextname)) +- nextname++; +- if (dols && *nextname == '\0') +- firsttime = 0; +- } else { +- if (dols && firsttime) { +- firsttime = 0; +- } else { +- isdir = 0; +- } +- } +- +- if (get_dentfromdir(mydata, startsect, subname, dentptr, +- isdir ? 0 : dols) == NULL) { +- if (dols && !isdir) +- *size = 0; +- goto exit; +- } +- +- if (isdir && !(dentptr->attr & ATTR_DIR)) +- goto exit; +- +- /* +- * If we are looking for a directory, and found a directory +- * type entry, and the entry is for the root directory (as +- * denoted by a cluster number of 0), jump back to the start +- * of the function, since at least on FAT12/16, the root dir +- * lives in a hard-coded location and needs special handling +- * to parse, rather than simply following the cluster linked +- * list in the FAT, like other directories. +- */ +- if (isdir && (dentptr->attr & ATTR_DIR) && !START(dentptr)) { +- /* +- * Modify the filename to remove the prefix that gets +- * back to the root directory, so the initial root dir +- * parsing code can continue from where we are without +- * confusion. +- */ +- strcpy(fnamecopy, nextname ?: ""); +- /* +- * Set up state the same way as the function does when +- * first started. This is required for the root dir +- * parsing code operates in its expected environment. +- */ +- subname = ""; +- cursect = mydata->rootdir_sect; +- isdir = 0; +- goto root_reparse; +- } +- +- if (idx >= 0) +- subname = nextname; +- } +- +- if (dogetsize) { +- *size = FAT2CPU32(dentptr->size); +- ret = 0; +- } else { +- ret = get_contents(mydata, dentptr, pos, buffer, maxsize, size); +- } +- debug("Size: %u, got: %llu\n", FAT2CPU32(dentptr->size), *size); +- +-exit: +- free(mydata->fatbuf); +- return ret; +-} +- + + /* + * Directory iterator, to simplify filesystem traversal +@@ -1595,12 +966,6 @@ static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type) + return -ENOENT; + } + +-int do_fat_read(const char *filename, void *buffer, loff_t maxsize, int dols, +- loff_t *actread) +-{ +- return do_fat_read_at(filename, 0, buffer, maxsize, dols, 0, actread); +-} +- + int file_fat_detectfs(void) + { + boot_sector bs; +@@ -1665,31 +1030,96 @@ int file_fat_detectfs(void) + + int file_fat_ls(const char *dir) + { +- loff_t size; ++ fsdata fsdata; ++ fat_itr itrblock, *itr = &itrblock; ++ int files = 0, dirs = 0; ++ int ret; ++ ++ ret = fat_itr_root(itr, &fsdata); ++ if (ret) ++ return ret; ++ ++ ret = fat_itr_resolve(itr, dir, TYPE_DIR); ++ if (ret) ++ return ret; ++ ++ while (fat_itr_next(itr)) { ++ if (fat_itr_isdir(itr)) { ++ printf(" %s/\n", itr->name); ++ dirs++; ++ } else { ++ printf(" %8u %s\n", ++ FAT2CPU32(itr->dent->size), ++ itr->name); ++ files++; ++ } ++ } + +- return do_fat_read(dir, NULL, 0, LS_YES, &size); ++ printf("\n%d file(s), %d dir(s)\n\n", files, dirs); ++ ++ return 0; + } + + int fat_exists(const char *filename) + { ++ fsdata fsdata; ++ fat_itr itrblock, *itr = &itrblock; + int ret; +- loff_t size; + +- ret = do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1, &size); ++ ret = fat_itr_root(itr, &fsdata); ++ if (ret) ++ return 0; ++ ++ ret = fat_itr_resolve(itr, filename, TYPE_ANY); + return ret == 0; + } + + int fat_size(const char *filename, loff_t *size) + { +- return do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1, size); ++ fsdata fsdata; ++ fat_itr itrblock, *itr = &itrblock; ++ int ret; ++ ++ ret = fat_itr_root(itr, &fsdata); ++ if (ret) ++ return ret; ++ ++ ret = fat_itr_resolve(itr, filename, TYPE_FILE); ++ if (ret) { ++ /* ++ * Directories don't have size, but fs_size() is not ++ * expected to fail if passed a directory path: ++ */ ++ fat_itr_root(itr, &fsdata); ++ if (!fat_itr_resolve(itr, filename, TYPE_DIR)) { ++ *size = 0; ++ return 0; ++ } ++ return ret; ++ } ++ ++ *size = FAT2CPU32(itr->dent->size); ++ ++ return 0; + } + + int file_fat_read_at(const char *filename, loff_t pos, void *buffer, + loff_t maxsize, loff_t *actread) + { ++ fsdata fsdata; ++ fat_itr itrblock, *itr = &itrblock; ++ int ret; ++ ++ ret = fat_itr_root(itr, &fsdata); ++ if (ret) ++ return ret; ++ ++ ret = fat_itr_resolve(itr, filename, TYPE_FILE); ++ if (ret) ++ return ret; ++ + printf("reading %s\n", filename); +- return do_fat_read_at(filename, pos, buffer, maxsize, LS_NO, 0, +- actread); ++ return get_contents(&fsdata, itr->dent, pos, buffer, maxsize, actread); + } + + int file_fat_read(const char *filename, void *buffer, int maxsize) +diff --git a/include/fat.h b/include/fat.h +index 21bb6666cf..18d8981c48 100644 +--- a/include/fat.h ++++ b/include/fat.h +@@ -58,12 +58,6 @@ + */ + #define LAST_LONG_ENTRY_MASK 0x40 + +-/* Flags telling whether we should read a file or list a directory */ +-#define LS_NO 0 +-#define LS_YES 1 +-#define LS_DIR 1 +-#define LS_ROOT 2 +- + #define ISDIRDELIM(c) ((c) == '/' || (c) == '\\') + + #define FSTYPE_NONE (-1) +-- +2.13.5 + +From 4bbcc965f995564870ca02606137e60e873e0a1f Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Sat, 9 Sep 2017 13:15:55 -0400 +Subject: [PATCH 37/47] fs: add fs_readdir() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Needed to support efi file protocol. The fallback.efi loader wants +to be able to read the contents of the /EFI directory to find an OS +to boot. + +Modelled after POSIX opendir()/readdir()/closedir(). Unlike the other +fs APIs, this is stateful (ie. state is held in the FS_DIR "directory +stream"), to avoid re-traversing of the directory structure at each +step. The directory stream must be released with closedir() when it +is no longer needed. + +Signed-off-by: Rob Clark +Reviewed-by: Łukasz Majewski +Reviewed-by: Simon Glass +--- + disk/part.c | 31 ++++++++++------- + fs/fs.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + include/fs.h | 67 +++++++++++++++++++++++++++++++++++++ + include/part.h | 9 +++++ + 4 files changed, 199 insertions(+), 12 deletions(-) + +diff --git a/disk/part.c b/disk/part.c +index c67fdacc79..aa9183d696 100644 +--- a/disk/part.c ++++ b/disk/part.c +@@ -331,6 +331,24 @@ int part_get_info(struct blk_desc *dev_desc, int part, + return -1; + } + ++int part_get_info_whole_disk(struct blk_desc *dev_desc, disk_partition_t *info) ++{ ++ info->start = 0; ++ info->size = dev_desc->lba; ++ info->blksz = dev_desc->blksz; ++ info->bootable = 0; ++ strcpy((char *)info->type, BOOT_PART_TYPE); ++ strcpy((char *)info->name, "Whole Disk"); ++#if CONFIG_IS_ENABLED(PARTITION_UUIDS) ++ info->uuid[0] = 0; ++#endif ++#ifdef CONFIG_PARTITION_TYPE_GUID ++ info->type_guid[0] = 0; ++#endif ++ ++ return 0; ++} ++ + int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str, + struct blk_desc **dev_desc) + { +@@ -523,18 +541,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str, + + (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); + +- info->start = 0; +- info->size = (*dev_desc)->lba; +- info->blksz = (*dev_desc)->blksz; +- info->bootable = 0; +- strcpy((char *)info->type, BOOT_PART_TYPE); +- strcpy((char *)info->name, "Whole Disk"); +-#if CONFIG_IS_ENABLED(PARTITION_UUIDS) +- info->uuid[0] = 0; +-#endif +-#ifdef CONFIG_PARTITION_TYPE_GUID +- info->type_guid[0] = 0; +-#endif ++ part_get_info_whole_disk(*dev_desc, info); + + ret = 0; + goto cleanup; +diff --git a/fs/fs.c b/fs/fs.c +index 13cd3626c6..fc0c953fcb 100644 +--- a/fs/fs.c ++++ b/fs/fs.c +@@ -21,6 +21,7 @@ + DECLARE_GLOBAL_DATA_PTR; + + static struct blk_desc *fs_dev_desc; ++static int fs_dev_part; + static disk_partition_t fs_partition; + static int fs_type = FS_TYPE_ANY; + +@@ -69,6 +70,12 @@ static inline int fs_uuid_unsupported(char *uuid_str) + return -1; + } + ++static inline int fs_opendir_unsupported(const char *filename, ++ struct fs_dir_stream **dirs) ++{ ++ return -EACCES; ++} ++ + struct fstype_info { + int fstype; + char *name; +@@ -92,6 +99,20 @@ struct fstype_info { + loff_t len, loff_t *actwrite); + void (*close)(void); + int (*uuid)(char *uuid_str); ++ /* ++ * Open a directory stream. On success return 0 and directory ++ * stream pointer via 'dirsp'. On error, return -errno. See ++ * fs_opendir(). ++ */ ++ int (*opendir)(const char *filename, struct fs_dir_stream **dirsp); ++ /* ++ * Read next entry from directory stream. On success return 0 ++ * and directory entry pointer via 'dentp'. On error return ++ * -errno. See fs_readdir(). ++ */ ++ int (*readdir)(struct fs_dir_stream *dirs, struct fs_dirent **dentp); ++ /* see fs_closedir() */ ++ void (*closedir)(struct fs_dir_stream *dirs); + }; + + static struct fstype_info fstypes[] = { +@@ -112,6 +133,7 @@ static struct fstype_info fstypes[] = { + .write = fs_write_unsupported, + #endif + .uuid = fs_uuid_unsupported, ++ .opendir = fs_opendir_unsupported, + }, + #endif + #ifdef CONFIG_FS_EXT4 +@@ -131,6 +153,7 @@ static struct fstype_info fstypes[] = { + .write = fs_write_unsupported, + #endif + .uuid = ext4fs_uuid, ++ .opendir = fs_opendir_unsupported, + }, + #endif + #ifdef CONFIG_SANDBOX +@@ -146,6 +169,7 @@ static struct fstype_info fstypes[] = { + .read = fs_read_sandbox, + .write = fs_write_sandbox, + .uuid = fs_uuid_unsupported, ++ .opendir = fs_opendir_unsupported, + }, + #endif + #ifdef CONFIG_CMD_UBIFS +@@ -161,6 +185,7 @@ static struct fstype_info fstypes[] = { + .read = ubifs_read, + .write = fs_write_unsupported, + .uuid = fs_uuid_unsupported, ++ .opendir = fs_opendir_unsupported, + }, + #endif + { +@@ -175,6 +200,7 @@ static struct fstype_info fstypes[] = { + .read = fs_read_unsupported, + .write = fs_write_unsupported, + .uuid = fs_uuid_unsupported, ++ .opendir = fs_opendir_unsupported, + }, + }; + +@@ -228,6 +254,31 @@ int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype) + + if (!info->probe(fs_dev_desc, &fs_partition)) { + fs_type = info->fstype; ++ fs_dev_part = part; ++ return 0; ++ } ++ } ++ ++ return -1; ++} ++ ++/* set current blk device w/ blk_desc + partition # */ ++int fs_set_blk_dev_with_part(struct blk_desc *desc, int part) ++{ ++ struct fstype_info *info; ++ int ret, i; ++ ++ if (part >= 1) ++ ret = part_get_info(desc, part, &fs_partition); ++ else ++ ret = part_get_info_whole_disk(desc, &fs_partition); ++ if (ret) ++ return ret; ++ fs_dev_desc = desc; ++ ++ for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) { ++ if (!info->probe(fs_dev_desc, &fs_partition)) { ++ fs_type = info->fstype; + return 0; + } + } +@@ -334,6 +385,59 @@ int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len, + return ret; + } + ++struct fs_dir_stream *fs_opendir(const char *filename) ++{ ++ struct fstype_info *info = fs_get_info(fs_type); ++ struct fs_dir_stream *dirs = NULL; ++ int ret; ++ ++ ret = info->opendir(filename, &dirs); ++ fs_close(); ++ if (ret) { ++ errno = -ret; ++ return NULL; ++ } ++ ++ dirs->desc = fs_dev_desc; ++ dirs->part = fs_dev_part; ++ ++ return dirs; ++} ++ ++struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs) ++{ ++ struct fstype_info *info; ++ struct fs_dirent *dirent; ++ int ret; ++ ++ fs_set_blk_dev_with_part(dirs->desc, dirs->part); ++ info = fs_get_info(fs_type); ++ ++ ret = info->readdir(dirs, &dirent); ++ fs_close(); ++ if (ret) { ++ errno = -ret; ++ return NULL; ++ } ++ ++ return dirent; ++} ++ ++void fs_closedir(struct fs_dir_stream *dirs) ++{ ++ struct fstype_info *info; ++ ++ if (!dirs) ++ return; ++ ++ fs_set_blk_dev_with_part(dirs->desc, dirs->part); ++ info = fs_get_info(fs_type); ++ ++ info->closedir(dirs); ++ fs_close(); ++} ++ ++ + int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], + int fstype) + { +diff --git a/include/fs.h b/include/fs.h +index 2f2aca8378..0869ad6e80 100644 +--- a/include/fs.h ++++ b/include/fs.h +@@ -27,6 +27,17 @@ + int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype); + + /* ++ * fs_set_blk_dev_with_part - Set current block device + partition ++ * ++ * Similar to fs_set_blk_dev(), but useful for cases where you already ++ * know the blk_desc and part number. ++ * ++ * Returns 0 on success. ++ * Returns non-zero if invalid partition or error accessing the disk. ++ */ ++int fs_set_blk_dev_with_part(struct blk_desc *desc, int part); ++ ++/* + * Print the list of files on the partition previously set by fs_set_blk_dev(), + * in directory "dirname". + * +@@ -79,6 +90,62 @@ int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len, + loff_t *actwrite); + + /* ++ * Directory entry types, matches the subset of DT_x in posix readdir() ++ * which apply to u-boot. ++ */ ++#define FS_DT_DIR 4 /* directory */ ++#define FS_DT_REG 8 /* regular file */ ++#define FS_DT_LNK 10 /* symbolic link */ ++ ++/* ++ * A directory entry, returned by fs_readdir(). Returns information ++ * about the file/directory at the current directory entry position. ++ */ ++struct fs_dirent { ++ unsigned type; /* one of FS_DT_x (not a mask) */ ++ loff_t size; /* size in bytes */ ++ char name[256]; ++}; ++ ++/* Note: fs_dir_stream should be treated as opaque to the user of fs layer */ ++struct fs_dir_stream { ++ /* private to fs. layer: */ ++ struct blk_desc *desc; ++ int part; ++}; ++ ++/* ++ * fs_opendir - Open a directory ++ * ++ * @filename: the path to directory to open ++ * @return a pointer to the directory stream or NULL on error and errno ++ * set appropriately ++ */ ++struct fs_dir_stream *fs_opendir(const char *filename); ++ ++/* ++ * fs_readdir - Read the next directory entry in the directory stream. ++ * ++ * Works in an analogous way to posix readdir(). The previously returned ++ * directory entry is no longer valid after calling fs_readdir() again. ++ * After fs_closedir() is called, the returned directory entry is no ++ * longer valid. ++ * ++ * @dirs: the directory stream ++ * @return the next directory entry (only valid until next fs_readdir() or ++ * fs_closedir() call, do not attempt to free()) or NULL if the end of ++ * the directory is reached. ++ */ ++struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs); ++ ++/* ++ * fs_closedir - close a directory stream ++ * ++ * @dirs: the directory stream ++ */ ++void fs_closedir(struct fs_dir_stream *dirs); ++ ++/* + * Common implementation for various filesystem commands, optionally limited + * to a specific filesystem type via the fstype parameter. + */ +diff --git a/include/part.h b/include/part.h +index 0d5c99836b..86117a7ce5 100644 +--- a/include/part.h ++++ b/include/part.h +@@ -98,6 +98,12 @@ int host_get_dev_err(int dev, struct blk_desc **blk_devp); + + /* disk/part.c */ + int part_get_info(struct blk_desc *dev_desc, int part, disk_partition_t *info); ++/** ++ * part_get_info_whole_disk() - get partition info for the special case of ++ * a partition occupying the entire disk. ++ */ ++int part_get_info_whole_disk(struct blk_desc *dev_desc, disk_partition_t *info); ++ + void part_print(struct blk_desc *dev_desc); + void part_init(struct blk_desc *dev_desc); + void dev_print(struct blk_desc *dev_desc); +@@ -203,6 +209,9 @@ static inline struct blk_desc *mg_disk_get_dev(int dev) { return NULL; } + + static inline int part_get_info(struct blk_desc *dev_desc, int part, + disk_partition_t *info) { return -1; } ++static inline int part_get_info_whole_disk(struct blk_desc *dev_desc, ++ disk_partition_t *info) ++{ return -1; } + static inline void part_print(struct blk_desc *dev_desc) {} + static inline void part_init(struct blk_desc *dev_desc) {} + static inline void dev_print(struct blk_desc *dev_desc) {} +-- +2.13.5 + +From 1f40366b319eac7eb02f8894fff5c94fbdb47d30 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Sat, 9 Sep 2017 13:15:56 -0400 +Subject: [PATCH 38/47] fs/fat: implement opendir/readdir/closedir +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Implement the readdir interface using the directory iterators. + +Signed-off-by: Rob Clark +Reviewed-by: Łukasz Majewski +Reviewed-by: Simon Glass +--- + fs/fat/fat.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 61 insertions(+) + +diff --git a/fs/fat/fat.c b/fs/fat/fat.c +index bbba7947ee..82ddb7eab1 100644 +--- a/fs/fat/fat.c ++++ b/fs/fat/fat.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1146,6 +1147,66 @@ int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len, + return ret; + } + ++typedef struct { ++ struct fs_dir_stream parent; ++ struct fs_dirent dirent; ++ fsdata fsdata; ++ fat_itr itr; ++} fat_dir; ++ ++int fat_opendir(const char *filename, struct fs_dir_stream **dirsp) ++{ ++ fat_dir *dir = malloc(sizeof(*dir)); ++ int ret; ++ ++ if (!dir) ++ return -ENOMEM; ++ ++ ret = fat_itr_root(&dir->itr, &dir->fsdata); ++ if (ret) ++ goto fail; ++ ++ ret = fat_itr_resolve(&dir->itr, filename, TYPE_DIR); ++ if (ret) ++ goto fail; ++ ++ *dirsp = (struct fs_dir_stream *)dir; ++ return 0; ++ ++fail: ++ free(dir); ++ return ret; ++} ++ ++int fat_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp) ++{ ++ fat_dir *dir = (fat_dir *)dirs; ++ struct fs_dirent *dent = &dir->dirent; ++ ++ if (!fat_itr_next(&dir->itr)) ++ return -ENOENT; ++ ++ memset(dent, 0, sizeof(*dent)); ++ strcpy(dent->name, dir->itr.name); ++ ++ if (fat_itr_isdir(&dir->itr)) { ++ dent->type = FS_DT_DIR; ++ } else { ++ dent->type = FS_DT_REG; ++ dent->size = FAT2CPU32(dir->itr.dent->size); ++ } ++ ++ *dentp = dent; ++ ++ return 0; ++} ++ ++void fat_closedir(struct fs_dir_stream *dirs) ++{ ++ fat_dir *dir = (fat_dir *)dirs; ++ free(dir); ++} ++ + void fat_close(void) + { + } +-- +2.13.5 + +From 41fa83d1a6cdd8ddfb3fbe332252193ff8fb8b71 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Sat, 9 Sep 2017 13:15:57 -0400 +Subject: [PATCH 39/47] fat/fs: remove a bunch of dead code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Spotted by chance, when trying to remove file_fat_ls(), I noticed there +were some dead users of the API. + +Signed-off-by: Rob Clark +Acked-by: Stefan Brüns +Reviewed-by: Simon Glass +--- + fs/fat/Makefile | 4 -- + fs/fat/file.c | 183 -------------------------------------------------------- + include/fat.h | 20 ------- + 3 files changed, 207 deletions(-) + delete mode 100644 fs/fat/file.c + +diff --git a/fs/fat/Makefile b/fs/fat/Makefile +index b60e8486c4..3e2a6b01a8 100644 +--- a/fs/fat/Makefile ++++ b/fs/fat/Makefile +@@ -5,7 +5,3 @@ + + obj-$(CONFIG_FS_FAT) := fat.o + obj-$(CONFIG_FAT_WRITE):= fat_write.o +- +-ifndef CONFIG_SPL_BUILD +-obj-$(CONFIG_FS_FAT) += file.o +-endif +diff --git a/fs/fat/file.c b/fs/fat/file.c +deleted file mode 100644 +index 89706117b9..0000000000 +--- a/fs/fat/file.c ++++ /dev/null +@@ -1,183 +0,0 @@ +-/* +- * file.c +- * +- * Mini "VFS" by Marcus Sundberg +- * +- * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6 +- * 2003-03-10 - kharris@nexus-tech.net - ported to uboot +- * +- * SPDX-License-Identifier: GPL-2.0+ +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* Supported filesystems */ +-static const struct filesystem filesystems[] = { +- { file_fat_detectfs, file_fat_ls, file_fat_read, "FAT" }, +-}; +-#define NUM_FILESYS (sizeof(filesystems)/sizeof(struct filesystem)) +- +-/* The filesystem which was last detected */ +-static int current_filesystem = FSTYPE_NONE; +- +-/* The current working directory */ +-#define CWD_LEN 511 +-char file_cwd[CWD_LEN+1] = "/"; +- +-const char * +-file_getfsname(int idx) +-{ +- if (idx < 0 || idx >= NUM_FILESYS) +- return NULL; +- +- return filesystems[idx].name; +-} +- +-static void +-pathcpy(char *dest, const char *src) +-{ +- char *origdest = dest; +- +- do { +- if (dest-file_cwd >= CWD_LEN) { +- *dest = '\0'; +- return; +- } +- *(dest) = *(src); +- if (*src == '\0') { +- if (dest-- != origdest && ISDIRDELIM(*dest)) { +- *dest = '\0'; +- } +- return; +- } +- ++dest; +- +- if (ISDIRDELIM(*src)) +- while (ISDIRDELIM(*src)) src++; +- else +- src++; +- } while (1); +-} +- +-int +-file_cd(const char *path) +-{ +- if (ISDIRDELIM(*path)) { +- while (ISDIRDELIM(*path)) path++; +- strncpy(file_cwd+1, path, CWD_LEN-1); +- } else { +- const char *origpath = path; +- char *tmpstr = file_cwd; +- int back = 0; +- +- while (*tmpstr != '\0') tmpstr++; +- do { +- tmpstr--; +- } while (ISDIRDELIM(*tmpstr)); +- +- while (*path == '.') { +- path++; +- while (*path == '.') { +- path++; +- back++; +- } +- if (*path != '\0' && !ISDIRDELIM(*path)) { +- path = origpath; +- back = 0; +- break; +- } +- while (ISDIRDELIM(*path)) path++; +- origpath = path; +- } +- +- while (back--) { +- /* Strip off path component */ +- while (!ISDIRDELIM(*tmpstr)) { +- tmpstr--; +- } +- if (tmpstr == file_cwd) { +- /* Incremented again right after the loop. */ +- tmpstr--; +- break; +- } +- /* Skip delimiters */ +- while (ISDIRDELIM(*tmpstr)) tmpstr--; +- } +- tmpstr++; +- if (*path == '\0') { +- if (tmpstr == file_cwd) { +- *tmpstr = '/'; +- tmpstr++; +- } +- *tmpstr = '\0'; +- return 0; +- } +- *tmpstr = '/'; +- pathcpy(tmpstr+1, path); +- } +- +- return 0; +-} +- +-int +-file_detectfs(void) +-{ +- int i; +- +- current_filesystem = FSTYPE_NONE; +- +- for (i = 0; i < NUM_FILESYS; i++) { +- if (filesystems[i].detect() == 0) { +- strcpy(file_cwd, "/"); +- current_filesystem = i; +- break; +- } +- } +- +- return current_filesystem; +-} +- +-int +-file_ls(const char *dir) +-{ +- char fullpath[1024]; +- const char *arg; +- +- if (current_filesystem == FSTYPE_NONE) { +- printf("Can't list files without a filesystem!\n"); +- return -1; +- } +- +- if (ISDIRDELIM(*dir)) { +- arg = dir; +- } else { +- sprintf(fullpath, "%s/%s", file_cwd, dir); +- arg = fullpath; +- } +- return filesystems[current_filesystem].ls(arg); +-} +- +-int file_read(const char *filename, void *buffer, int maxsize) +-{ +- char fullpath[1024]; +- const char *arg; +- +- if (current_filesystem == FSTYPE_NONE) { +- printf("Can't load file without a filesystem!\n"); +- return -1; +- } +- +- if (ISDIRDELIM(*filename)) { +- arg = filename; +- } else { +- sprintf(fullpath, "%s/%s", file_cwd, filename); +- arg = fullpath; +- } +- +- return filesystems[current_filesystem].read(arg, buffer, maxsize); +-} +diff --git a/include/fat.h b/include/fat.h +index 18d8981c48..b255ce5337 100644 +--- a/include/fat.h ++++ b/include/fat.h +@@ -178,25 +178,6 @@ static inline u32 clust_to_sect(fsdata *fsdata, u32 clust) + return fsdata->data_begin + clust * fsdata->clust_size; + } + +-typedef int (file_detectfs_func)(void); +-typedef int (file_ls_func)(const char *dir); +-typedef int (file_read_func)(const char *filename, void *buffer, +- int maxsize); +- +-struct filesystem { +- file_detectfs_func *detect; +- file_ls_func *ls; +- file_read_func *read; +- const char name[12]; +-}; +- +-/* FAT tables */ +-file_detectfs_func file_fat_detectfs; +-file_ls_func file_fat_ls; +-file_read_func file_fat_read; +- +-/* Currently this doesn't check if the dir exists or is valid... */ +-int file_cd(const char *path); + int file_fat_detectfs(void); + int file_fat_ls(const char *dir); + int fat_exists(const char *filename); +@@ -204,7 +185,6 @@ int fat_size(const char *filename, loff_t *size); + int file_fat_read_at(const char *filename, loff_t pos, void *buffer, + loff_t maxsize, loff_t *actread); + int file_fat_read(const char *filename, void *buffer, int maxsize); +-const char *file_getfsname(int idx); + int fat_set_blk_dev(struct blk_desc *rbdd, disk_partition_t *info); + int fat_register_device(struct blk_desc *dev_desc, int part_no); + +-- +2.13.5 + +From 89191d626793490b579e1d36e7d7a4464a20f9f6 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Sat, 9 Sep 2017 13:15:58 -0400 +Subject: [PATCH 40/47] fat/fs: move ls to generic implementation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add a generic implementation of 'ls' using opendir/readdir/closedir, and +replace fat's custom implementation. Other filesystems should move to +the generic implementation after they add opendir/readdir/closedir +support. + +Signed-off-by: Rob Clark +Reviewed-by: Łukasz Majewski +Reviewed-by: Simon Glass +--- + fs/fat/fat.c | 32 -------------------------------- + fs/fs.c | 35 +++++++++++++++++++++++++++++++++-- + include/fat.h | 5 ++++- + 3 files changed, 37 insertions(+), 35 deletions(-) + +diff --git a/fs/fat/fat.c b/fs/fat/fat.c +index 82ddb7eab1..c951d84f57 100644 +--- a/fs/fat/fat.c ++++ b/fs/fat/fat.c +@@ -1029,38 +1029,6 @@ int file_fat_detectfs(void) + return 0; + } + +-int file_fat_ls(const char *dir) +-{ +- fsdata fsdata; +- fat_itr itrblock, *itr = &itrblock; +- int files = 0, dirs = 0; +- int ret; +- +- ret = fat_itr_root(itr, &fsdata); +- if (ret) +- return ret; +- +- ret = fat_itr_resolve(itr, dir, TYPE_DIR); +- if (ret) +- return ret; +- +- while (fat_itr_next(itr)) { +- if (fat_itr_isdir(itr)) { +- printf(" %s/\n", itr->name); +- dirs++; +- } else { +- printf(" %8u %s\n", +- FAT2CPU32(itr->dent->size), +- itr->name); +- files++; +- } +- } +- +- printf("\n%d file(s), %d dir(s)\n\n", files, dirs); +- +- return 0; +-} +- + int fat_exists(const char *filename) + { + fsdata fsdata; +diff --git a/fs/fs.c b/fs/fs.c +index fc0c953fcb..3481229aa6 100644 +--- a/fs/fs.c ++++ b/fs/fs.c +@@ -37,6 +37,35 @@ static inline int fs_ls_unsupported(const char *dirname) + return -1; + } + ++/* generic implementation of ls in terms of opendir/readdir/closedir */ ++__maybe_unused ++static int fs_ls_generic(const char *dirname) ++{ ++ struct fs_dir_stream *dirs; ++ struct fs_dirent *dent; ++ int nfiles = 0, ndirs = 0; ++ ++ dirs = fs_opendir(dirname); ++ if (!dirs) ++ return -errno; ++ ++ while ((dent = fs_readdir(dirs))) { ++ if (dent->type == FS_DT_DIR) { ++ printf(" %s/\n", dent->name); ++ ndirs++; ++ } else { ++ printf(" %8lld %s\n", dent->size, dent->name); ++ nfiles++; ++ } ++ } ++ ++ fs_closedir(dirs); ++ ++ printf("\n%d file(s), %d dir(s)\n\n", nfiles, ndirs); ++ ++ return 0; ++} ++ + static inline int fs_exists_unsupported(const char *filename) + { + return 0; +@@ -123,7 +152,7 @@ static struct fstype_info fstypes[] = { + .null_dev_desc_ok = false, + .probe = fat_set_blk_dev, + .close = fat_close, +- .ls = file_fat_ls, ++ .ls = fs_ls_generic, + .exists = fat_exists, + .size = fat_size, + .read = fat_read_file, +@@ -133,7 +162,9 @@ static struct fstype_info fstypes[] = { + .write = fs_write_unsupported, + #endif + .uuid = fs_uuid_unsupported, +- .opendir = fs_opendir_unsupported, ++ .opendir = fat_opendir, ++ .readdir = fat_readdir, ++ .closedir = fat_closedir, + }, + #endif + #ifdef CONFIG_FS_EXT4 +diff --git a/include/fat.h b/include/fat.h +index b255ce5337..83cd90017e 100644 +--- a/include/fat.h ++++ b/include/fat.h +@@ -11,6 +11,7 @@ + #define _FAT_H_ + + #include ++#include + + #define CONFIG_SUPPORT_VFAT + /* Maximum Long File Name length supported here is 128 UTF-16 code units */ +@@ -179,7 +180,6 @@ static inline u32 clust_to_sect(fsdata *fsdata, u32 clust) + } + + int file_fat_detectfs(void); +-int file_fat_ls(const char *dir); + int fat_exists(const char *filename); + int fat_size(const char *filename, loff_t *size); + int file_fat_read_at(const char *filename, loff_t pos, void *buffer, +@@ -192,5 +192,8 @@ int file_fat_write(const char *filename, void *buf, loff_t offset, loff_t len, + loff_t *actwrite); + int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len, + loff_t *actread); ++int fat_opendir(const char *filename, struct fs_dir_stream **dirsp); ++int fat_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp); ++void fat_closedir(struct fs_dir_stream *dirs); + void fat_close(void); + #endif /* _FAT_H_ */ +-- +2.13.5 + +From 21a24c3bf35bac83d66ce4a48eb0c7dd8a7227cb Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Sat, 9 Sep 2017 13:15:59 -0400 +Subject: [PATCH 41/47] fs/fat: fix case for FAT shortnames +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Noticed when comparing our output to linux. There are some lcase bits +which control whether filename and/or extension should be downcase'd. + +Signed-off-by: Rob Clark +Reviewed-by: Łukasz Majewski +Reviewed-by: Simon Glass +--- + fs/fat/fat.c | 16 ++++++++++------ + fs/fat/fat_write.c | 4 ++-- + include/fat.h | 6 +++++- + 3 files changed, 17 insertions(+), 9 deletions(-) + +diff --git a/fs/fat/fat.c b/fs/fat/fat.c +index c951d84f57..65873a2c2a 100644 +--- a/fs/fat/fat.c ++++ b/fs/fat/fat.c +@@ -29,11 +29,13 @@ static const int vfat_enabled = 0; + #endif + + /* +- * Convert a string to lowercase. ++ * Convert a string to lowercase. Converts at most 'len' characters, ++ * 'len' may be larger than the length of 'str' if 'str' is NULL ++ * terminated. + */ +-static void downcase(char *str) ++static void downcase(char *str, size_t len) + { +- while (*str != '\0') { ++ while (*str != '\0' && len--) { + *str = tolower(*str); + str++; + } +@@ -131,10 +133,13 @@ static void get_name(dir_entry *dirent, char *s_name) + ptr = s_name; + while (*ptr && *ptr != ' ') + ptr++; ++ if (dirent->lcase & CASE_LOWER_BASE) ++ downcase(s_name, (unsigned)(ptr - s_name)); + if (dirent->ext[0] && dirent->ext[0] != ' ') { +- *ptr = '.'; +- ptr++; ++ *ptr++ = '.'; + memcpy(ptr, dirent->ext, 3); ++ if (dirent->lcase & CASE_LOWER_EXT) ++ downcase(ptr, 3); + ptr[3] = '\0'; + while (*ptr && *ptr != ' ') + ptr++; +@@ -144,7 +149,6 @@ static void get_name(dir_entry *dirent, char *s_name) + *s_name = '\0'; + else if (*s_name == aRING) + *s_name = DELETED_FLAG; +- downcase(s_name); + } + + static int flush_dirty_fat_buffer(fsdata *mydata); +diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c +index 4ca024c208..d0468baf8f 100644 +--- a/fs/fat/fat_write.c ++++ b/fs/fat/fat_write.c +@@ -345,7 +345,7 @@ get_long_file_name(fsdata *mydata, int curclust, __u8 *cluster, + *l_name = '\0'; + else if (*l_name == aRING) + *l_name = DELETED_FLAG; +- downcase(l_name); ++ downcase(l_name, INT_MAX); + + /* Return the real directory entry */ + *retdent = realdent; +@@ -981,7 +981,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, + + memcpy(l_filename, filename, name_len); + l_filename[name_len] = 0; /* terminate the string */ +- downcase(l_filename); ++ downcase(l_filename, INT_MAX); + + startsect = mydata->rootdir_sect; + retdent = find_directory_entry(mydata, startsect, +diff --git a/include/fat.h b/include/fat.h +index 83cd90017e..0f58939124 100644 +--- a/include/fat.h ++++ b/include/fat.h +@@ -128,10 +128,14 @@ typedef struct volume_info + /* Boot sign comes last, 2 bytes */ + } volume_info; + ++/* see dir_entry::lcase: */ ++#define CASE_LOWER_BASE 8 /* base (name) is lower case */ ++#define CASE_LOWER_EXT 16 /* extension is lower case */ ++ + typedef struct dir_entry { + char name[8],ext[3]; /* Name and extension */ + __u8 attr; /* Attribute bits */ +- __u8 lcase; /* Case for base and extension */ ++ __u8 lcase; /* Case for name and ext (CASE_LOWER_x) */ + __u8 ctime_ms; /* Creation time, milliseconds */ + __u16 ctime; /* Creation time */ + __u16 cdate; /* Creation date */ +-- +2.13.5 + +From 265edc03d5a19550d92cbd6e10631d5a15bdd1d5 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Sat, 9 Sep 2017 13:16:00 -0400 +Subject: [PATCH 42/47] fs/fat: Clean up open-coded sector <-> cluster + conversions + +Use the clust_to_sect() helper that was introduced earlier, and add an +inverse sect_to_clust(), plus update the various spots that open-coded +this conversion previously. + +Signed-off-by: Rob Clark +Reviewed-by: Simon Glass +--- + fs/fat/fat.c | 8 +++----- + fs/fat/fat_write.c | 8 +++----- + include/fat.h | 6 +++++- + 3 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/fs/fat/fat.c b/fs/fat/fat.c +index 65873a2c2a..f5f74c12ff 100644 +--- a/fs/fat/fat.c ++++ b/fs/fat/fat.c +@@ -257,8 +257,7 @@ get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size) + int ret; + + if (clustnum > 0) { +- startsect = mydata->data_begin + +- clustnum * mydata->clust_size; ++ startsect = clust_to_sect(mydata, clustnum); + } else { + startsect = mydata->rootdir_sect; + } +@@ -594,9 +593,8 @@ static int get_fs_info(fsdata *mydata) + mydata->data_begin = mydata->rootdir_sect + + mydata->rootdir_size - + (mydata->clust_size * 2); +- mydata->root_cluster = (mydata->rootdir_sect - +- mydata->data_begin) / +- mydata->clust_size; ++ mydata->root_cluster = ++ sect_to_clust(mydata, mydata->rootdir_sect); + } + + mydata->fatbufnum = -1; +diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c +index d0468baf8f..9d2e0ed74c 100644 +--- a/fs/fat/fat_write.c ++++ b/fs/fat/fat_write.c +@@ -502,8 +502,7 @@ set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, + int ret; + + if (clustnum > 0) +- startsect = mydata->data_begin + +- clustnum * mydata->clust_size; ++ startsect = clust_to_sect(mydata, clustnum); + else + startsect = mydata->rootdir_sect; + +@@ -751,8 +750,7 @@ static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size) + __u32 startsect, sect_num, offset; + + if (clustnum > 0) { +- startsect = mydata->data_begin + +- clustnum * mydata->clust_size; ++ startsect = clust_to_sect(mydata, clustnum); + } else { + startsect = mydata->rootdir_sect; + } +@@ -791,7 +789,7 @@ static dir_entry *empty_dentptr; + static dir_entry *find_directory_entry(fsdata *mydata, int startsect, + char *filename, dir_entry *retdent, __u32 start) + { +- __u32 curclust = (startsect - mydata->data_begin) / mydata->clust_size; ++ __u32 curclust = sect_to_clust(mydata, startsect); + + debug("get_dentfromdir: %s\n", filename); + +diff --git a/include/fat.h b/include/fat.h +index 0f58939124..bdeda95e6d 100644 +--- a/include/fat.h ++++ b/include/fat.h +@@ -177,12 +177,16 @@ typedef struct { + __u32 root_cluster; /* First cluster of root dir for FAT32 */ + } fsdata; + +-/* TODO clean up places that are open-coding this: */ + static inline u32 clust_to_sect(fsdata *fsdata, u32 clust) + { + return fsdata->data_begin + clust * fsdata->clust_size; + } + ++static inline u32 sect_to_clust(fsdata *fsdata, u32 sect) ++{ ++ return (sect - fsdata->data_begin) / fsdata->clust_size; ++} ++ + int file_fat_detectfs(void); + int fat_exists(const char *filename); + int fat_size(const char *filename, loff_t *size); +-- +2.13.5 + +From 725ffdb5cbcc4b8a9726a68cc6ae0713266ba5a9 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Tue, 12 Sep 2017 16:40:01 -0400 +Subject: [PATCH 43/47] fs/fat: fix fatbuf leak +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A new fatbuf was allocated by get_fs_info() (called by fat_itr_root()), +but not freed, resulting in eventually running out of memory. Spotted +by running 'ls -r' in a large FAT filesystem from Shell.efi. + +fatbuf is mainly used to cache FAT entry lookups (get_fatent()).. +possibly once fat_write.c it can move into the iterator to simplify +this. + +Signed-off-by: Rob Clark +Reviewed-by: Simon Glass +Reviewed-by: Łukasz Majewski +--- + fs/fat/fat.c | 23 ++++++++++++++++------- + 1 file changed, 16 insertions(+), 7 deletions(-) + +diff --git a/fs/fat/fat.c b/fs/fat/fat.c +index f5f74c12ff..f0284398b4 100644 +--- a/fs/fat/fat.c ++++ b/fs/fat/fat.c +@@ -1042,6 +1042,7 @@ int fat_exists(const char *filename) + return 0; + + ret = fat_itr_resolve(itr, filename, TYPE_ANY); ++ free(fsdata.fatbuf); + return ret == 0; + } + +@@ -1061,17 +1062,19 @@ int fat_size(const char *filename, loff_t *size) + * Directories don't have size, but fs_size() is not + * expected to fail if passed a directory path: + */ ++ free(fsdata.fatbuf); + fat_itr_root(itr, &fsdata); + if (!fat_itr_resolve(itr, filename, TYPE_DIR)) { + *size = 0; +- return 0; ++ ret = 0; + } +- return ret; ++ goto out; + } + + *size = FAT2CPU32(itr->dent->size); +- +- return 0; ++out: ++ free(fsdata.fatbuf); ++ return ret; + } + + int file_fat_read_at(const char *filename, loff_t pos, void *buffer, +@@ -1087,10 +1090,14 @@ int file_fat_read_at(const char *filename, loff_t pos, void *buffer, + + ret = fat_itr_resolve(itr, filename, TYPE_FILE); + if (ret) +- return ret; ++ goto out; + + printf("reading %s\n", filename); +- return get_contents(&fsdata, itr->dent, pos, buffer, maxsize, actread); ++ ret = get_contents(&fsdata, itr->dent, pos, buffer, maxsize, actread); ++ ++out: ++ free(fsdata.fatbuf); ++ return ret; + } + + int file_fat_read(const char *filename, void *buffer, int maxsize) +@@ -1126,7 +1133,7 @@ typedef struct { + + int fat_opendir(const char *filename, struct fs_dir_stream **dirsp) + { +- fat_dir *dir = malloc(sizeof(*dir)); ++ fat_dir *dir = calloc(1, sizeof(*dir)); + int ret; + + if (!dir) +@@ -1144,6 +1151,7 @@ int fat_opendir(const char *filename, struct fs_dir_stream **dirsp) + return 0; + + fail: ++ free(dir->fsdata.fatbuf); + free(dir); + return ret; + } +@@ -1174,6 +1182,7 @@ int fat_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp) + void fat_closedir(struct fs_dir_stream *dirs) + { + fat_dir *dir = (fat_dir *)dirs; ++ free(dir->fsdata.fatbuf); + free(dir); + } + +-- +2.13.5 + diff --git a/uefi-use-Fedora-specific-path-name.patch b/uefi-use-Fedora-specific-path-name.patch index 0bd7f40..08f20fa 100644 --- a/uefi-use-Fedora-specific-path-name.patch +++ b/uefi-use-Fedora-specific-path-name.patch @@ -1,6 +1,6 @@ -From 95140df8476e255cb279a60228b9c703b3ca318f Mon Sep 17 00:00:00 2001 +From 0b10d2ebcaf9244eba57790ede30fed6bc6c4223 Mon Sep 17 00:00:00 2001 From: Peter Robinson -Date: Wed, 12 Jul 2017 08:43:31 +0100 +Date: Mon, 18 Sep 2017 09:24:37 +0100 Subject: [PATCH] use Fedora specific EFI path/name Signed-off-by: Peter Robinson @@ -9,7 +9,7 @@ Signed-off-by: Peter Robinson 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h -index 4b2c493ae3..704dee7772 100644 +index e0d0034ed3..18da4ff737 100644 --- a/include/config_distro_bootcmd.h +++ b/include/config_distro_bootcmd.h @@ -88,7 +88,7 @@ @@ -21,16 +21,16 @@ index 4b2c493ae3..704dee7772 100644 #elif defined(CONFIG_ARM) #define BOOTEFI_NAME "bootarm.efi" #endif -@@ -113,7 +113,7 @@ - #define BOOTENV_SHARED_EFI \ - "boot_efi_binary=" \ +@@ -118,7 +118,7 @@ + "bootefi bootmgr ${fdtcontroladdr};" \ + "fi;" \ "load ${devtype} ${devnum}:${distro_bootpart} " \ - "${kernel_addr_r} efi/boot/"BOOTEFI_NAME"; " \ + "${kernel_addr_r} efi/fedora/"BOOTEFI_NAME"; " \ "if fdt addr ${fdt_addr_r}; then " \ "bootefi ${kernel_addr_r} ${fdt_addr_r};" \ "else " \ -@@ -136,9 +136,9 @@ +@@ -141,9 +141,9 @@ "fi;" \ "done;" \ "if test -e ${devtype} ${devnum}:${distro_bootpart} " \ @@ -43,5 +43,5 @@ index 4b2c493ae3..704dee7772 100644 "echo EFI LOAD FAILED: continuing...; " \ "fi; " \ -- -2.13.0 +2.13.5 diff --git a/uefi-vsprintf.patch b/uefi-vsprintf.patch new file mode 100644 index 0000000..7cd72b2 --- /dev/null +++ b/uefi-vsprintf.patch @@ -0,0 +1,544 @@ +From 4a85663ec7eddd955d22f1b0f34a9708eac82314 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Sat, 9 Sep 2017 06:47:39 -0400 +Subject: [PATCH 002/105] kbuild: Enable -fshort-wchar + +EFI_LOADER really wants UTF-16 strings (ie. %ls and L"string" are 16bit +chars instead of 32bit chars). But rather than enabling -fshort-wchar +conditionally if EFI_LOADER is enabled, it was deemed preferrable to +globally switch. + +Signed-off-by: Rob Clark +Acked-by: Masahiro Yamada +--- + Makefile | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Makefile b/Makefile +index 8086f3c93e..8250b3409a 100644 +--- a/Makefile ++++ b/Makefile +@@ -360,6 +360,7 @@ KBUILD_CPPFLAGS := -D__KERNEL__ -D__UBOOT__ + KBUILD_CFLAGS := -Wall -Wstrict-prototypes \ + -Wno-format-security \ + -fno-builtin -ffreestanding ++KBUILD_CFLAGS += -fshort-wchar + KBUILD_AFLAGS := -D__ASSEMBLY__ + + # Read UBOOTRELEASE from include/config/uboot.release (if it exists) +-- +2.13.5 + +From 78178bb0c9dfe2a91a636a411291d8bab50e8a7d Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Sat, 9 Sep 2017 06:47:40 -0400 +Subject: [PATCH 003/105] lib: add some utf16 handling helpers + +We'll eventually want these in a few places in efi_loader, and also +vsprintf. + +Signed-off-by: Rob Clark +--- + include/charset.h | 65 ++++++++++++++++++++++++++++ + lib/Makefile | 1 + + lib/charset.c | 101 +++++++++++++++++++++++++++++++++++++++++++ + lib/efi_loader/efi_console.c | 17 ++------ + 4 files changed, 170 insertions(+), 14 deletions(-) + create mode 100644 include/charset.h + create mode 100644 lib/charset.c + +diff --git a/include/charset.h b/include/charset.h +new file mode 100644 +index 0000000000..39279f746a +--- /dev/null ++++ b/include/charset.h +@@ -0,0 +1,65 @@ ++/* ++ * charset conversion utils ++ * ++ * Copyright (c) 2017 Rob Clark ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++#ifndef __CHARSET_H_ ++#define __CHARSET_H_ ++ ++#define MAX_UTF8_PER_UTF16 4 ++ ++/** ++ * utf16_strlen() - Get the length of an utf16 string ++ * ++ * Returns the number of 16 bit characters in an utf16 string, not ++ * including the terminating NULL character. ++ * ++ * @in the string to measure ++ * @return the string length ++ */ ++size_t utf16_strlen(const uint16_t *in); ++ ++/** ++ * utf16_strnlen() - Get the length of a fixed-size utf16 string. ++ * ++ * Returns the number of 16 bit characters in an utf16 string, ++ * not including the terminating NULL character, but at most ++ * 'count' number of characters. In doing this, utf16_strnlen() ++ * looks at only the first 'count' characters. ++ * ++ * @in the string to measure ++ * @count the maximum number of characters to count ++ * @return the string length, up to a maximum of 'count' ++ */ ++size_t utf16_strnlen(const uint16_t *in, size_t count); ++ ++/** ++ * utf16_strcpy() - UTF16 equivalent of strcpy() ++ */ ++uint16_t *utf16_strcpy(uint16_t *dest, const uint16_t *src); ++ ++/** ++ * utf16_strdup() - UTF16 equivalent of strdup() ++ */ ++uint16_t *utf16_strdup(const uint16_t *s); ++ ++/** ++ * utf16_to_utf8() - Convert an utf16 string to utf8 ++ * ++ * Converts 'size' characters of the utf16 string 'src' to utf8 ++ * written to the 'dest' buffer. ++ * ++ * NOTE that a single utf16 character can generate up to 4 utf8 ++ * characters. See MAX_UTF8_PER_UTF16. ++ * ++ * @dest the destination buffer to write the utf8 characters ++ * @src the source utf16 string ++ * @size the number of utf16 characters to convert ++ * @return the pointer to the first unwritten byte in 'dest' ++ */ ++uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size); ++ ++#endif /* __CHARSET_H_ */ +diff --git a/lib/Makefile b/lib/Makefile +index da6a11aca3..15bba9eac2 100644 +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -18,6 +18,7 @@ obj-$(CONFIG_OF_LIVE) += of_live.o + obj-$(CONFIG_CMD_DHRYSTONE) += dhry/ + + obj-$(CONFIG_AES) += aes.o ++obj-y += charset.o + obj-$(CONFIG_USB_TTY) += circbuf.o + obj-y += crc7.o + obj-y += crc8.o +diff --git a/lib/charset.c b/lib/charset.c +new file mode 100644 +index 0000000000..ff76e88c77 +--- /dev/null ++++ b/lib/charset.c +@@ -0,0 +1,101 @@ ++/* ++ * charset conversion utils ++ * ++ * Copyright (c) 2017 Rob Clark ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++#include ++#include ++#include ++ ++/* ++ * utf8/utf16 conversion mostly lifted from grub ++ */ ++ ++size_t utf16_strlen(const uint16_t *in) ++{ ++ size_t i; ++ for (i = 0; in[i]; i++); ++ return i; ++} ++ ++size_t utf16_strnlen(const uint16_t *in, size_t count) ++{ ++ size_t i; ++ for (i = 0; count-- && in[i]; i++); ++ return i; ++} ++ ++uint16_t *utf16_strcpy(uint16_t *dest, const uint16_t *src) ++{ ++ uint16_t *tmp = dest; ++ ++ while ((*dest++ = *src++) != '\0') ++ /* nothing */; ++ return tmp; ++ ++} ++ ++uint16_t *utf16_strdup(const uint16_t *s) ++{ ++ uint16_t *new; ++ if (!s || !(new = malloc((utf16_strlen(s) + 1) * 2))) ++ return NULL; ++ utf16_strcpy(new, s); ++ return new; ++} ++ ++/* Convert UTF-16 to UTF-8. */ ++uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size) ++{ ++ uint32_t code_high = 0; ++ ++ while (size--) { ++ uint32_t code = *src++; ++ ++ if (code_high) { ++ if (code >= 0xDC00 && code <= 0xDFFF) { ++ /* Surrogate pair. */ ++ code = ((code_high - 0xD800) << 10) + (code - 0xDC00) + 0x10000; ++ ++ *dest++ = (code >> 18) | 0xF0; ++ *dest++ = ((code >> 12) & 0x3F) | 0x80; ++ *dest++ = ((code >> 6) & 0x3F) | 0x80; ++ *dest++ = (code & 0x3F) | 0x80; ++ } else { ++ /* Error... */ ++ *dest++ = '?'; ++ /* *src may be valid. Don't eat it. */ ++ src--; ++ } ++ ++ code_high = 0; ++ } else { ++ if (code <= 0x007F) { ++ *dest++ = code; ++ } else if (code <= 0x07FF) { ++ *dest++ = (code >> 6) | 0xC0; ++ *dest++ = (code & 0x3F) | 0x80; ++ } else if (code >= 0xD800 && code <= 0xDBFF) { ++ code_high = code; ++ continue; ++ } else if (code >= 0xDC00 && code <= 0xDFFF) { ++ /* Error... */ ++ *dest++ = '?'; ++ } else if (code < 0x10000) { ++ *dest++ = (code >> 12) | 0xE0; ++ *dest++ = ((code >> 6) & 0x3F) | 0x80; ++ *dest++ = (code & 0x3F) | 0x80; ++ } else { ++ *dest++ = (code >> 18) | 0xF0; ++ *dest++ = ((code >> 12) & 0x3F) | 0x80; ++ *dest++ = ((code >> 6) & 0x3F) | 0x80; ++ *dest++ = (code & 0x3F) | 0x80; ++ } ++ } ++ } ++ ++ return dest; ++} +diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c +index 5ebce4b544..3fc82b8726 100644 +--- a/lib/efi_loader/efi_console.c ++++ b/lib/efi_loader/efi_console.c +@@ -7,6 +7,7 @@ + */ + + #include ++#include + #include + + static bool console_size_queried; +@@ -138,20 +139,8 @@ static efi_status_t EFIAPI efi_cout_reset( + + static void print_unicode_in_utf8(u16 c) + { +- char utf8[4] = { 0 }; +- char *b = utf8; +- +- if (c < 0x80) { +- *(b++) = c; +- } else if (c < 0x800) { +- *(b++) = 192 + c / 64; +- *(b++) = 128 + c % 64; +- } else { +- *(b++) = 224 + c / 4096; +- *(b++) = 128 + c / 64 % 64; +- *(b++) = 128 + c % 64; +- } +- ++ char utf8[MAX_UTF8_PER_UTF16] = { 0 }; ++ utf16_to_utf8((u8 *)utf8, &c, 1); + puts(utf8); + } + +-- +2.13.5 + +From 274325c50951dd16ad2a6f45e79dc062ad47011b Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Sat, 9 Sep 2017 06:47:41 -0400 +Subject: [PATCH 004/105] vsprintf.c: add UTF-16 string (%ls) support + +This is convenient for efi_loader which deals a lot with UTF-16. Only +enabled with CC_SHORT_WCHAR, leaving room to add a UTF-32 version when +CC_SHORT_WCHAR is not enabled. + +Signed-off-by: Rob Clark +Reviewed-by: Simon Glass +Reviewed-by: Simon Glass +--- + examples/api/Makefile | 1 + + lib/vsprintf.c | 30 ++++++++++++++++++++++++++++-- + 2 files changed, 29 insertions(+), 2 deletions(-) + +diff --git a/examples/api/Makefile b/examples/api/Makefile +index dab6398bab..87c15d0f68 100644 +--- a/examples/api/Makefile ++++ b/examples/api/Makefile +@@ -34,6 +34,7 @@ EXT_COBJ-y += lib/div64.o + EXT_COBJ-y += lib/string.o + EXT_COBJ-y += lib/time.o + EXT_COBJ-y += lib/vsprintf.o ++EXT_COBJ-y += lib/charset.o + EXT_SOBJ-$(CONFIG_PPC) += arch/powerpc/lib/ppcstring.o + ifeq ($(ARCH),arm) + EXT_SOBJ-$(CONFIG_USE_ARCH_MEMSET) += arch/arm/lib/memset.o +diff --git a/lib/vsprintf.c b/lib/vsprintf.c +index 874a2951f7..97bed9d36d 100644 +--- a/lib/vsprintf.c ++++ b/lib/vsprintf.c +@@ -17,6 +17,7 @@ + #include + + #include ++#include + + #include + #define noinline __attribute__((noinline)) +@@ -270,6 +271,26 @@ static char *string(char *buf, char *end, char *s, int field_width, + return buf; + } + ++static char *string16(char *buf, char *end, u16 *s, int field_width, ++ int precision, int flags) ++{ ++ u16 *str = s ? s : L""; ++ int utf16_len = utf16_strnlen(str, precision); ++ u8 utf8[utf16_len * MAX_UTF8_PER_UTF16]; ++ int utf8_len, i; ++ ++ utf8_len = utf16_to_utf8(utf8, str, utf16_len) - utf8; ++ ++ if (!(flags & LEFT)) ++ while (utf8_len < field_width--) ++ ADDCH(buf, ' '); ++ for (i = 0; i < utf8_len; ++i) ++ ADDCH(buf, utf8[i]); ++ while (utf8_len < field_width--) ++ ADDCH(buf, ' '); ++ return buf; ++} ++ + #ifdef CONFIG_CMD_NET + static const char hex_asc[] = "0123456789abcdef"; + #define hex_asc_lo(x) hex_asc[((x) & 0x0f)] +@@ -528,8 +549,13 @@ repeat: + continue; + + case 's': +- str = string(str, end, va_arg(args, char *), +- field_width, precision, flags); ++ if (qualifier == 'l' && !IS_ENABLED(CONFIG_SPL_BUILD)) { ++ str = string16(str, end, va_arg(args, u16 *), ++ field_width, precision, flags); ++ } else { ++ str = string(str, end, va_arg(args, char *), ++ field_width, precision, flags); ++ } + continue; + + case 'p': +-- +2.13.5 + +From 22ada0c8e6d50281af72176eecdfc356c794639c Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Sat, 9 Sep 2017 06:47:42 -0400 +Subject: [PATCH 005/105] vsprintf.c: add GUID printing + +This works (roughly) the same way as linux's, but we currently always +print lower-case (ie. we just keep %pUB and %pUL for compat with linux), +mostly just because that is what uuid_bin_to_str() supports. + + %pUb: 01020304-0506-0708-090a-0b0c0d0e0f10 + %pUl: 04030201-0605-0807-090a-0b0c0d0e0f10 + +It will be used by a later efi_loader paths for efi variables and for +device-path-to-text protocol, and also quite useful for debug prints +of protocol GUIDs. + +Signed-off-by: Rob Clark +Tested-by: Heinrich Schuchardt +Reviewed-by: Simon Glass +--- + examples/api/Makefile | 1 + + include/config_fallbacks.h | 1 + + lib/vsprintf.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- + 3 files changed, 46 insertions(+), 2 deletions(-) + +diff --git a/examples/api/Makefile b/examples/api/Makefile +index 87c15d0f68..899527267d 100644 +--- a/examples/api/Makefile ++++ b/examples/api/Makefile +@@ -35,6 +35,7 @@ EXT_COBJ-y += lib/string.o + EXT_COBJ-y += lib/time.o + EXT_COBJ-y += lib/vsprintf.o + EXT_COBJ-y += lib/charset.o ++EXT_COBJ-$(CONFIG_LIB_UUID) += lib/uuid.o + EXT_SOBJ-$(CONFIG_PPC) += arch/powerpc/lib/ppcstring.o + ifeq ($(ARCH),arm) + EXT_SOBJ-$(CONFIG_USE_ARCH_MEMSET) += arch/arm/lib/memset.o +diff --git a/include/config_fallbacks.h b/include/config_fallbacks.h +index 46b7a2a6f2..2c4d43d672 100644 +--- a/include/config_fallbacks.h ++++ b/include/config_fallbacks.h +@@ -58,6 +58,7 @@ + + #if (CONFIG_IS_ENABLED(PARTITION_UUIDS) || \ + CONFIG_IS_ENABLED(EFI_PARTITION) || \ ++ CONFIG_IS_ENABLED(EFI_LOADER) || \ + defined(CONFIG_RANDOM_UUID) || \ + defined(CONFIG_CMD_UUID) || \ + defined(CONFIG_BOOTP_PXE)) && \ +diff --git a/lib/vsprintf.c b/lib/vsprintf.c +index 97bed9d36d..dd572d2868 100644 +--- a/lib/vsprintf.c ++++ b/lib/vsprintf.c +@@ -18,6 +18,7 @@ + + #include + #include ++#include + + #include + #define noinline __attribute__((noinline)) +@@ -366,6 +367,40 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width, + } + #endif + ++#ifdef CONFIG_LIB_UUID ++/* ++ * This works (roughly) the same way as linux's, but we currently always ++ * print lower-case (ie. we just keep %pUB and %pUL for compat with linux), ++ * mostly just because that is what uuid_bin_to_str() supports. ++ * ++ * %pUb: 01020304-0506-0708-090a-0b0c0d0e0f10 ++ * %pUl: 04030201-0605-0807-090a-0b0c0d0e0f10 ++ */ ++static char *uuid_string(char *buf, char *end, u8 *addr, int field_width, ++ int precision, int flags, const char *fmt) ++{ ++ char uuid[UUID_STR_LEN + 1]; ++ int str_format = UUID_STR_FORMAT_STD; ++ ++ switch (*(++fmt)) { ++ case 'L': ++ case 'l': ++ str_format = UUID_STR_FORMAT_GUID; ++ break; ++ case 'B': ++ case 'b': ++ /* this is the default */ ++ break; ++ default: ++ break; ++ } ++ ++ uuid_bin_to_str(addr, uuid, str_format); ++ ++ return string(buf, end, uuid, field_width, precision, flags); ++} ++#endif ++ + /* + * Show a '%p' thing. A kernel extension is that the '%p' is followed + * by an extra set of alphanumeric characters that are extended format +@@ -399,8 +434,8 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, + flags); + #endif + +-#ifdef CONFIG_CMD_NET + switch (*fmt) { ++#ifdef CONFIG_CMD_NET + case 'a': + flags |= SPECIAL | ZEROPAD; + +@@ -430,8 +465,15 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, + precision, flags); + flags &= ~SPECIAL; + break; +- } + #endif ++#ifdef CONFIG_LIB_UUID ++ case 'U': ++ return uuid_string(buf, end, ptr, field_width, precision, ++ flags, fmt); ++#endif ++ default: ++ break; ++ } + flags |= SMALL; + if (field_width == -1) { + field_width = 2*sizeof(void *); +-- +2.13.5 + +From 7e3e20560784b048ff19e90cd36b6680626b1ab3 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Sat, 9 Sep 2017 06:47:43 -0400 +Subject: [PATCH 006/105] examples: add fallback memcpy + +Solves build issue: + + Building current source for 134 boards (12 threads, 1 job per thread) + arm: + lsxhl + +examples/api/vsprintf.o: In function `string16': + +lib/vsprintf.c:278: undefined reference to `memcpy' + +examples/api/uuid.o: In function `uuid_bin_to_str': + +lib/uuid.c:197: undefined reference to `memcpy' + +lib/uuid.c:199: undefined reference to `memcpy' + +make[3]: *** [examples/api/demo] Error 1 + +make[2]: *** [examples/api] Error 2 + +make[1]: *** [examples] Error 2 + +make: *** [sub-make] Error 2 + 133 0 1 /134 sheevaplug + +Signed-off-by: Rob Clark +--- + examples/api/glue.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/examples/api/glue.c b/examples/api/glue.c +index 8aabf32c89..575c1e55f3 100644 +--- a/examples/api/glue.c ++++ b/examples/api/glue.c +@@ -416,3 +416,15 @@ void ub_display_clear(void) + { + syscall(API_DISPLAY_CLEAR, NULL); + } ++ ++__weak void *memcpy(void *dest, const void *src, size_t size) ++{ ++ unsigned char *dptr = dest; ++ const unsigned char *ptr = src; ++ const unsigned char *end = src + size; ++ ++ while (ptr < end) ++ *dptr++ = *ptr++; ++ ++ return dest; ++} +-- +2.13.5 +