From de20c9d04d33615e83fc46af27a399a66afbe755 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Fri, 4 Aug 2017 15:30:07 +0100 Subject: [PATCH] update DragonBoard 410c to latest, some uEFI fixes --- dragonboard-fixes.patch | 730 ++++++++++++ uboot-tools.spec | 18 +- uefi-fixes.patch | 2356 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 3099 insertions(+), 5 deletions(-) create mode 100644 uefi-fixes.patch diff --git a/dragonboard-fixes.patch b/dragonboard-fixes.patch index 48f254c..5c79536 100644 --- a/dragonboard-fixes.patch +++ b/dragonboard-fixes.patch @@ -83,3 +83,733 @@ index 11c842d..3b9932d 100644 "ramdisk_addr_r=0x84000000\0"\ "scriptaddr=0x90000000\0"\ "pxefile_addr_r=0x90100000\0"\ +From a2782063c8daf9000d131e85200bc631a16450b4 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Wed, 21 Jun 2017 14:21:15 -0400 +Subject: [PATCH 01/23] WIP: fix usb + +--- + common/usb_storage.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/common/usb_storage.c b/common/usb_storage.c +index df0b057308..b2a3ab49ec 100644 +--- a/common/usb_storage.c ++++ b/common/usb_storage.c +@@ -996,7 +996,7 @@ static int usb_request_sense(struct scsi_cmd *srb, struct us_data *ss) + + static int usb_test_unit_ready(struct scsi_cmd *srb, struct us_data *ss) + { +- int retries = 10; ++ int retries = 20; + + do { + memset(&srb->cmd[0], 0, 12); +@@ -1019,7 +1019,7 @@ static int usb_test_unit_ready(struct scsi_cmd *srb, struct us_data *ss) + if ((srb->sense_buf[2] == 0x02) && + (srb->sense_buf[12] == 0x3a)) + return -1; +- mdelay(100); ++ mdelay(250); + } while (retries--); + + return -1; +-- +2.13.3 + +From 40b06f8d422efc1d9674f081ef22445904c01f4f Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Mon, 3 Jul 2017 08:34:37 -0400 +Subject: [PATCH 02/23] HACK: disable emmc + +Hitting some timeout which makes boot take much longer. And +uefi/boot/rootfs partitions will be on sd-card or usb disk, etc, +so we can just ignore emmc. +--- + arch/arm/dts/dragonboard410c.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm/dts/dragonboard410c.dts b/arch/arm/dts/dragonboard410c.dts +index 7746622dda..0d3b7a35f4 100644 +--- a/arch/arm/dts/dragonboard410c.dts ++++ b/arch/arm/dts/dragonboard410c.dts +@@ -67,6 +67,7 @@ + reg = <0x78d9000 0x400>; + }; + ++/* + sdhci@07824000 { + compatible = "qcom,sdhci-msm-v4"; + reg = <0x7824900 0x11c 0x7824000 0x800>; +@@ -76,6 +77,7 @@ + clock = <&clkc 0>; + clock-frequency = <100000000>; + }; ++*/ + + sdhci@07864000 { + compatible = "qcom,sdhci-msm-v4"; +-- +2.13.3 + +From 03569f3ef44fd1208a68030c1740d7347bcf3fa3 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Fri, 23 Jun 2017 15:36:33 -0400 +Subject: [PATCH 03/23] dm: core: also parse chosen node + +This is the node that would contain, for example, the framebuffer setup +by an earlier stage. + +Signed-off-by: Rob Clark +--- + drivers/core/root.c | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/drivers/core/root.c b/drivers/core/root.c +index d691d6ff94..5e6b2da248 100644 +--- a/drivers/core/root.c ++++ b/drivers/core/root.c +@@ -266,6 +266,26 @@ static int dm_scan_fdt_node(struct udevice *parent, const void *blob, + for (offset = fdt_first_subnode(blob, offset); + offset > 0; + offset = fdt_next_subnode(blob, offset)) { ++ ofnode node = offset_to_ofnode(offset); ++ ++ /* "chosen" node isn't a device itself but may contain some: */ ++ if (strcmp(ofnode_get_name(node), "chosen") == 0) { ++ dm_dbg("parsing subnodes of \"chosen\"\n"); ++ ++ for (node = ofnode_first_subnode(node); ++ ofnode_valid(node); ++ node = ofnode_next_subnode(node)) { ++ dm_dbg("subnode: %s\n", ofnode_get_name(node)); ++ err = lists_bind_fdt(parent, node, NULL); ++ if (err && !ret) { ++ ret = err; ++ dm_dbg("%s: ret=%d\n", ofnode_get_name(node), ret); ++ } ++ } ++ ++ continue; ++ } ++ + if (pre_reloc_only && + !dm_fdt_pre_reloc(blob, offset)) + continue; +@@ -273,7 +293,7 @@ static int dm_scan_fdt_node(struct udevice *parent, const void *blob, + dm_dbg(" - ignoring disabled device\n"); + continue; + } +- err = lists_bind_fdt(parent, offset_to_ofnode(offset), NULL); ++ err = lists_bind_fdt(parent, node, NULL); + if (err && !ret) { + ret = err; + debug("%s: ret=%d\n", fdt_get_name(blob, offset, NULL), +-- +2.13.3 + +From 9f99ca35c96d4b564062bb86ddc62f7421632906 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Thu, 22 Jun 2017 16:17:00 -0400 +Subject: [PATCH 04/23] video: simplefb + +Not really qcom specific, but for now qcom/lk is the one firmware that +is (afaiu) setting up the appropriate dt node for pre-configured +display. Uses the generic simple-framebuffer DT bindings so this should +be useful on other platforms. + +Signed-off-by: Rob Clark +--- + drivers/video/Kconfig | 10 +++++++ + drivers/video/Makefile | 2 +- + drivers/video/simplefb.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 82 insertions(+), 1 deletion(-) + create mode 100644 drivers/video/simplefb.c + +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index 61dfed8c06..8eb0359231 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -628,4 +628,14 @@ config VIDEO_DW_HDMI + rather requires a SoC-specific glue driver to call it), it + can not be enabled from the configuration menu. + ++config VIDEO_SIMPLE ++ bool "Simple display driver for preconfigured display" ++ help ++ Enables a simple generic display driver which utilizes the ++ simple-framebuffer devicetree bindings. ++ ++ This driver assumes that the display hardware has been initialized ++ before u-boot starts, and u-boot will simply render to the pre- ++ allocated frame buffer surface. ++ + endmenu +diff --git a/drivers/video/Makefile b/drivers/video/Makefile +index ac5371f2ae..52f50f647b 100644 +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -57,7 +57,7 @@ obj-$(CONFIG_FORMIKE) += formike.o + obj-$(CONFIG_LG4573) += lg4573.o + obj-$(CONFIG_AM335X_LCD) += am335x-fb.o + obj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.o +- ++obj-$(CONFIG_VIDEO_SIMPLE) += simplefb.o + obj-${CONFIG_VIDEO_TEGRA124} += tegra124/ + obj-${CONFIG_EXYNOS_FB} += exynos/ + obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/ +diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c +new file mode 100644 +index 0000000000..035a9761b9 +--- /dev/null ++++ b/drivers/video/simplefb.c +@@ -0,0 +1,71 @@ ++/* ++ * (C) Copyright 2017 Rob Clark ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int simple_video_probe(struct udevice *dev) ++{ ++ struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); ++ struct video_priv *uc_priv = dev_get_uclass_priv(dev); ++ const void *blob = gd->fdt_blob; ++ const int node = dev_of_offset(dev); ++ const char *format; ++ fdt_addr_t base; ++ fdt_size_t size; ++ ++ base = fdtdec_get_addr_size_auto_parent(blob, dev_of_offset(dev->parent), ++ node, "reg", 0, &size, false); ++ if (base == FDT_ADDR_T_NONE) { ++ debug("%s: Failed to decode memory region\n", __func__); ++ return -EINVAL; ++ } ++ ++ debug("%s: base=%llx, size=%llu\n", __func__, base, size); ++ ++ // TODO is there some way to reserve the framebuffer ++ // region so it isn't clobbered? ++ plat->base = base; ++ plat->size = size; ++ ++ video_set_flush_dcache(dev, true); ++ ++ debug("%s: Query resolution...\n", __func__); ++ ++ uc_priv->xsize = fdtdec_get_uint(blob, node, "width", 0); ++ uc_priv->ysize = fdtdec_get_uint(blob, node, "height", 0); ++ uc_priv->rot = 0; ++ ++ format = fdt_getprop(blob, node, "format", NULL); ++ debug("%s: %dx%d@%s\n", __func__, uc_priv->xsize, uc_priv->ysize, format); ++ ++ if (strcmp(format, "r5g6b5") == 0) { ++ uc_priv->bpix = VIDEO_BPP16; ++ } else if (strcmp(format, "a8b8g8r8") == 0) { ++ uc_priv->bpix = VIDEO_BPP32; ++ } else { ++ printf("%s: invalid format: %s\n", __func__, format); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static const struct udevice_id simple_video_ids[] = { ++ { .compatible = "simple-framebuffer" }, ++ { } ++}; ++ ++U_BOOT_DRIVER(simple_video) = { ++ .name = "simple_video", ++ .id = UCLASS_VIDEO, ++ .of_match = simple_video_ids, ++ .probe = simple_video_probe, ++ .flags = DM_FLAG_PRE_RELOC, ++}; +-- +2.13.3 + +From 1d6f9273461ba5afa7f04cb8ea00fd87272642f8 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Tue, 4 Jul 2017 09:16:08 -0400 +Subject: [PATCH 05/23] video: add config option to skip framebuffer clear + +The use-case is that the thing that loaded u-boot already put a splash +image on screen. And we want to preserve that until grub boot menu +takes over. + +Signed-off-by: Rob Clark +--- + drivers/video/Kconfig | 8 ++++++++ + drivers/video/cfb_console.c | 3 ++- + drivers/video/video-uclass.c | 4 +++- + 3 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index 8eb0359231..7b56b20344 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -98,6 +98,14 @@ config SYS_WHITE_ON_BLACK + better in low-light situations or to reduce eye strain in some + cases. + ++config NO_FB_CLEAR ++ bool "Skip framebuffer clear" ++ help ++ If firmware (whatever loads u-boot) has already put a splash image ++ on screen, you might want to preserve it until whatever u-boots ++ loads takes over the screen. This, for example, can be used to ++ keep splash image on screen until grub graphical boot menu starts. ++ + source "drivers/video/fonts/Kconfig" + + config VIDCONSOLE_AS_LCD +diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c +index f54802052e..85fa5b0cae 100644 +--- a/drivers/video/cfb_console.c ++++ b/drivers/video/cfb_console.c +@@ -2091,7 +2091,8 @@ static int cfg_video_init(void) + } + eorx = fgx ^ bgx; + +- video_clear(); ++ if (!CONFIG_IS_ENABLED(NO_FB_CLEAR)) ++ video_clear(); + + #ifdef CONFIG_VIDEO_LOGO + /* Plot the logo and get start point of console */ +diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c +index 3036e3a1f2..dfa39b0d1b 100644 +--- a/drivers/video/video-uclass.c ++++ b/drivers/video/video-uclass.c +@@ -199,7 +199,9 @@ static int video_post_probe(struct udevice *dev) + #else + priv->colour_bg = 0xffffff; + #endif +- video_clear(dev); ++ ++ if (!CONFIG_IS_ENABLED(NO_FB_CLEAR)) ++ video_clear(dev); + + /* + * Create a text console device. For now we always do this, although +-- +2.13.3 + +From d031c039a18b3a76a4ef16fb4ff8581a79f42fe3 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Thu, 3 Aug 2017 09:52:14 -0400 +Subject: [PATCH 06/23] fdtdec: allow board to provide fdt for + CONFIG_OF_SEPARATE + +Similar to CONFIG_OF_BOARD, but in this case the fdt is still built by +u-boot build. This allows the board to patch the fdt, etc. + +In the specific case of dragonboard 410c, we pass the u-boot generated +fdt to the previous stage of bootloader (by embedding it in the +u-boot.img that is loaded by lk/aboot), which patches the fdt and passes +it back to u-boot. + +Signed-off-by: Rob Clark +--- + include/fdtdec.h | 3 ++- + lib/fdtdec.c | 45 ++++++++++++++++++++++++++------------------- + 2 files changed, 28 insertions(+), 20 deletions(-) + +diff --git a/include/fdtdec.h b/include/fdtdec.h +index 4a0947c626..b9acec735a 100644 +--- a/include/fdtdec.h ++++ b/include/fdtdec.h +@@ -986,7 +986,8 @@ int fdtdec_setup(void); + + /** + * Board-specific FDT initialization. Returns the address to a device tree blob. +- * Called when CONFIG_OF_BOARD is defined. ++ * Called when CONFIG_OF_BOARD is defined, or if CONFIG_OF_SEPARATE is defined ++ * and the board implements it. + */ + void *board_fdt_blob_setup(void); + +diff --git a/lib/fdtdec.c b/lib/fdtdec.c +index d2dbd0f122..07c458673c 100644 +--- a/lib/fdtdec.c ++++ b/lib/fdtdec.c +@@ -1203,34 +1203,41 @@ int fdtdec_setup_memory_banksize(void) + } + #endif + +-int fdtdec_setup(void) ++#ifdef CONFIG_OF_SEPARATE ++/* ++ * For CONFIG_OF_SEPARATE, the board may optionally implement this to ++ * provide and/or fixup the fdt. ++ */ ++__weak void *board_fdt_blob_setup(void) + { +-#if CONFIG_IS_ENABLED(OF_CONTROL) +-# ifdef CONFIG_OF_EMBED +- /* Get a pointer to the FDT */ +- gd->fdt_blob = __dtb_dt_begin; +-# elif defined CONFIG_OF_SEPARATE +-# ifdef CONFIG_SPL_BUILD ++ void *fdt_blob = NULL; ++#ifdef CONFIG_SPL_BUILD + /* FDT is at end of BSS unless it is in a different memory region */ + if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS)) +- gd->fdt_blob = (ulong *)&_image_binary_end; ++ fdt_blob = (ulong *)&_image_binary_end; + else +- gd->fdt_blob = (ulong *)&__bss_end; ++ fdt_blob = (ulong *)&__bss_end; + +-# elif defined CONFIG_FIT_EMBED +- gd->fdt_blob = locate_dtb_in_fit(&_end); ++#elif defined CONFIG_FIT_EMBED ++ fdt_blob = locate_dtb_in_fit(&_end); + +- if (gd->fdt_blob == NULL || gd->fdt_blob <= ((void *)&_end)) { ++ if (fdt_blob == NULL || fdt_blob <= ((void *)&_end)) + puts("Failed to find proper dtb in embedded FIT Image\n"); +- return -1; +- } +- +-# else ++#else + /* FDT is at end of image */ +- gd->fdt_blob = (ulong *)&_end; ++ fdt_blob = (ulong *)&_end; + # endif +-# elif defined(CONFIG_OF_BOARD) +- /* Allow the board to override the fdt address. */ ++ return fdt_blob; ++} ++#endif ++ ++int fdtdec_setup(void) ++{ ++#if CONFIG_IS_ENABLED(OF_CONTROL) ++# ifdef CONFIG_OF_EMBED ++ /* Get a pointer to the FDT */ ++ gd->fdt_blob = __dtb_dt_begin; ++# elif defined(CONFIG_OF_SEPARATE) || defined(CONFIG_OF_BOARD) + gd->fdt_blob = board_fdt_blob_setup(); + # elif defined(CONFIG_OF_HOSTFILE) + if (sandbox_read_fdt_from_file()) { +-- +2.13.3 + +From 7f0491168cf31c9935dede6fb1f560ef33cfb739 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Fri, 23 Jun 2017 07:52:08 -0400 +Subject: [PATCH 07/23] db410c: use fdt passed from lk + +lk patches the fdt to set some device's MAC addresses and more +importantly to patch in the simple-framebuffer node that we want u-boot +to see. + +Signed-off-by: Rob Clark +--- + board/qualcomm/dragonboard410c/Makefile | 1 + + board/qualcomm/dragonboard410c/dragonboard410c.c | 8 ++++++ + board/qualcomm/dragonboard410c/lowlevel_init.S | 36 ++++++++++++++++++++++++ + 3 files changed, 45 insertions(+) + create mode 100644 board/qualcomm/dragonboard410c/lowlevel_init.S + +diff --git a/board/qualcomm/dragonboard410c/Makefile b/board/qualcomm/dragonboard410c/Makefile +index cd678088fa..5082383be4 100644 +--- a/board/qualcomm/dragonboard410c/Makefile ++++ b/board/qualcomm/dragonboard410c/Makefile +@@ -5,4 +5,5 @@ + # + + obj-y := dragonboard410c.o ++obj-y += lowlevel_init.o + extra-y += head.o +diff --git a/board/qualcomm/dragonboard410c/dragonboard410c.c b/board/qualcomm/dragonboard410c/dragonboard410c.c +index 37d0b85e0e..1fa4dc1b15 100644 +--- a/board/qualcomm/dragonboard410c/dragonboard410c.c ++++ b/board/qualcomm/dragonboard410c/dragonboard410c.c +@@ -27,6 +27,14 @@ int dram_init_banksize(void) + return 0; + } + ++extern unsigned long fw_dtb_pointer; ++ ++void *board_fdt_blob_setup(void) ++{ ++ if (fdt_magic(fw_dtb_pointer) != FDT_MAGIC) ++ return NULL; ++ return (void *)fw_dtb_pointer; ++} + + int board_prepare_usb(enum usb_init_type type) + { +diff --git a/board/qualcomm/dragonboard410c/lowlevel_init.S b/board/qualcomm/dragonboard410c/lowlevel_init.S +new file mode 100644 +index 0000000000..cdbd8e14db +--- /dev/null ++++ b/board/qualcomm/dragonboard410c/lowlevel_init.S +@@ -0,0 +1,36 @@ ++/* ++ * (C) Copyright 2016 ++ * Cédric Schieli ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++#include ++ ++.align 8 ++.global fw_dtb_pointer ++fw_dtb_pointer: ++#ifdef CONFIG_ARM64 ++ .dword 0x0 ++#else ++ .word 0x0 ++#endif ++ ++/* ++ * Routine: save_boot_params (called after reset from start.S) ++ * Description: save ATAG/FDT address provided by the firmware at boot time ++ */ ++ ++.global save_boot_params ++save_boot_params: ++ ++ /* The firmware provided ATAG/FDT address can be found in r2/x0 */ ++#ifdef CONFIG_ARM64 ++ adr x8, fw_dtb_pointer ++ str x0, [x8] ++#else ++ str r2, fw_dtb_pointer ++#endif ++ ++ /* Returns */ ++ b save_boot_params_ret +-- +2.13.3 + +From 9999019fa74908218fd85a51f8c4b45231f9489a Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Wed, 19 Jul 2017 11:40:15 -0400 +Subject: [PATCH 08/23] db410c: add reserved-memory node to dts + +If lk lights up display and populates simple-framebuffer node, it will +also setup a reserved-memory node (needed by simplefb on linux). But +it isn't clever enough to cope when the reserved-memory node is not +present. + +Signed-off-by: Rob Clark +--- + arch/arm/dts/dragonboard410c.dts | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/dts/dragonboard410c.dts b/arch/arm/dts/dragonboard410c.dts +index 0d3b7a35f4..a47b95264c 100644 +--- a/arch/arm/dts/dragonboard410c.dts ++++ b/arch/arm/dts/dragonboard410c.dts +@@ -23,11 +23,16 @@ + reg = <0 0x80000000 0 0x3da00000>; + }; + ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ }; ++ + chosen { + stdout-path = "/soc/serial@78b0000"; + }; + +- + soc { + #address-cells = <0x1>; + #size-cells = <0x1>; +-- +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 76fba480e6ee494e2e01c19bb8952f42a3b6a710 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Mon, 3 Jul 2017 09:15:44 -0400 +Subject: [PATCH 12/23] usb: kbd: don't fail with iomux + +stdin might not be set, which would cause iomux_doenv() to fail +therefore causing probe_usb_keyboard() to fail. Furthermore if we do +have iomux enabled, the sensible thing (in terms of user experience) +would be to simply add ourselves to the list of stdin devices. + +Signed-off-by: Rob Clark +--- + common/usb_kbd.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/common/usb_kbd.c b/common/usb_kbd.c +index d2d29cc98f..703dd748f5 100644 +--- a/common/usb_kbd.c ++++ b/common/usb_kbd.c +@@ -517,7 +517,22 @@ static int probe_usb_keyboard(struct usb_device *dev) + + stdinname = getenv("stdin"); + #if CONFIG_IS_ENABLED(CONSOLE_MUX) ++ char *devname = DEVNAME; ++ /* ++ * stdin might not be set yet.. either way, with console-mux the ++ * sensible thing to do is add ourselves to the list of stdio ++ * devices: ++ */ ++ if (stdinname && !strstr(stdinname, DEVNAME)) { ++ char *newstdin = malloc(strlen(stdinname) + strlen(","DEVNAME) + 1); ++ sprintf(newstdin, "%s,"DEVNAME, stdinname); ++ stdinname = newstdin; ++ } else if (!stdinname) { ++ stdinname = devname; ++ } + error = iomux_doenv(stdin, stdinname); ++ if (stdinname != devname) ++ free(stdinname); + if (error) + return error; + #else +-- +2.13.3 + +From 47f22a41df082c62411389ab5bf6e9ae26d93083 Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Wed, 19 Jul 2017 10:39:12 -0400 +Subject: [PATCH 13/23] usb: kbd: add missing \n + +Signed-off-by: Rob Clark +--- + common/usb_kbd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/common/usb_kbd.c b/common/usb_kbd.c +index 703dd748f5..92d5e96d01 100644 +--- a/common/usb_kbd.c ++++ b/common/usb_kbd.c +@@ -655,7 +655,7 @@ static int usb_kbd_remove(struct udevice *dev) + + return 0; + err: +- printf("%s: warning, ret=%d", __func__, ret); ++ printf("%s: warning, ret=%d\n", __func__, ret); + return ret; + } + +-- +2.13.3 + +From 54997f67cc935704cab36025d98d27eaf5a4aa7c Mon Sep 17 00:00:00 2001 +From: Rob Clark +Date: Mon, 26 Jun 2017 10:29:40 -0400 +Subject: [PATCH 09/23] db410c: on aarch64 the fdtfile is in per-vendor + subdirectory + +Signed-off-by: Rob Clark +--- + include/configs/dragonboard410c.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/configs/dragonboard410c.h b/include/configs/dragonboard410c.h +index d9dc639aeb..626dff8dcd 100644 +--- a/include/configs/dragonboard410c.h ++++ b/include/configs/dragonboard410c.h +@@ -104,7 +104,7 @@ + "initrd_high=0xffffffffffffffff\0" \ + "linux_image=Image\0" \ + "kernel_addr_r=0x81000000\0"\ +- "fdtfile=apq8016-sbc.dtb\0" \ ++ "fdtfile=qcom/apq8016-sbc.dtb\0" \ + "fdt_addr_r=0x81e00000\0"\ + "ramdisk_addr_r=0x84000000\0"\ + "scriptaddr=0x90000000\0"\ +-- +2.13.3 + diff --git a/uboot-tools.spec b/uboot-tools.spec index eb54ad1..53b1819 100644 --- a/uboot-tools.spec +++ b/uboot-tools.spec @@ -2,7 +2,7 @@ Name: uboot-tools Version: 2017.09 -Release: 0.1%{?candidate:.%{candidate}}%{?dist} +Release: 0.2%{?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,13 +14,17 @@ Source3: aarch64-boards Source4: aarch64-chromebooks # Fedoraisms patches, general fixes +Patch0: sunxi-dm-mmc-sata.patch Patch1: uefi-use-Fedora-specific-path-name.patch -Patch2: net-Mark-the-ip_udp_hdr-struct-as-packed.patch +Patch2: uefi-fixes.patch +Patch3: net-Mark-the-ip_udp_hdr-struct-as-packed.patch # Board fixes and enablement -Patch10: dragonboard-fixes.patch -Patch11: mx6-Initial-Hummingboard-2-support.patch -Patch12: sti-STiH410-B2260-support.patch +Patch10: dragonboard-fixes.patch +Patch11: mx6-Initial-Hummingboard-2-support.patch +Patch12: sti-STiH410-B2260-support.patch +Patch13: rpi-Revert-dm-Drop-CONFIG_OF_EMBED.patch +Patch14: sunxi-dm-pine64.patch # Patch14: mvebu-enable-generic-distro-boot-config.patch @@ -273,6 +277,10 @@ cp -p board/warp7/README builds/docs/README.warp7 %endif %changelog +* Thu Aug 3 2017 Peter Robinson 2017.09-0.2.rc1 +- uEFI fixes +- DragonBoard 410c fixes + * Tue Aug 1 2017 Peter Robinson 2017.09-0.1.rc1 - 2017.09 RC1 - Initial patch rebase diff --git a/uefi-fixes.patch b/uefi-fixes.patch new file mode 100644 index 0000000..956235c --- /dev/null +++ b/uefi-fixes.patch @@ -0,0 +1,2356 @@ +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/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c +index e063e0c79b..411a8c9226 100644 +--- a/lib/efi_loader/efi_gop.c ++++ b/lib/efi_loader/efi_gop.c +@@ -137,7 +137,7 @@ int efi_gop_register(void) + struct udevice *vdev; + + /* We only support a single video output device for now */ +- if (uclass_first_device(UCLASS_VIDEO, &vdev)) ++ if (uclass_first_device(UCLASS_VIDEO, &vdev) || !vdev) + return -1; + + struct video_priv *priv = dev_get_uclass_priv(vdev);