get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/813641/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 813641,
    "url": "http://patchwork.ozlabs.org/api/patches/813641/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20170913220546.19560-6-robdclark@gmail.com/",
    "project": {
        "id": 18,
        "url": "http://patchwork.ozlabs.org/api/projects/18/?format=api",
        "name": "U-Boot",
        "link_name": "uboot",
        "list_id": "u-boot.lists.denx.de",
        "list_email": "u-boot@lists.denx.de",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20170913220546.19560-6-robdclark@gmail.com>",
    "list_archive_url": null,
    "date": "2017-09-13T22:05:28",
    "name": "[U-Boot,v3,05/21] efi_loader: add device-path utils",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "281799b6a95afbe9b62cae83ec35ac19cf12db6a",
    "submitter": {
        "id": 18760,
        "url": "http://patchwork.ozlabs.org/api/people/18760/?format=api",
        "name": "Rob Clark",
        "email": "robdclark@gmail.com"
    },
    "delegate": {
        "id": 3400,
        "url": "http://patchwork.ozlabs.org/api/users/3400/?format=api",
        "username": "agraf",
        "first_name": "Alexander",
        "last_name": "Graf",
        "email": "agraf@suse.de"
    },
    "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20170913220546.19560-6-robdclark@gmail.com/mbox/",
    "series": [
        {
            "id": 2990,
            "url": "http://patchwork.ozlabs.org/api/series/2990/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=2990",
            "date": "2017-09-13T22:05:23",
            "name": "efi_loader: enough UEFI for standard distro boot",
            "version": 3,
            "mbox": "http://patchwork.ozlabs.org/series/2990/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/813641/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/813641/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<u-boot-bounces@lists.denx.de>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org",
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=lists.denx.de\n\t(client-ip=81.169.180.215; helo=lists.denx.de;\n\tenvelope-from=u-boot-bounces@lists.denx.de;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"Ckosl1Jy\"; dkim-atps=neutral"
        ],
        "Received": [
            "from lists.denx.de (dione.denx.de [81.169.180.215])\n\tby ozlabs.org (Postfix) with ESMTP id 3xswmm6vCMz9sNV\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 14 Sep 2017 08:09:12 +1000 (AEST)",
            "by lists.denx.de (Postfix, from userid 105)\n\tid 8D63CC2208F; Wed, 13 Sep 2017 22:07:32 +0000 (UTC)",
            "from lists.denx.de (localhost [IPv6:::1])\n\tby lists.denx.de (Postfix) with ESMTP id 8D0C1C2257F;\n\tWed, 13 Sep 2017 22:07:02 +0000 (UTC)",
            "by lists.denx.de (Postfix, from userid 105)\n\tid A192EC21F60; Wed, 13 Sep 2017 22:06:11 +0000 (UTC)",
            "from mail-qk0-f196.google.com (mail-qk0-f196.google.com\n\t[209.85.220.196])\n\tby lists.denx.de (Postfix) with ESMTPS id D7629C2258B\n\tfor <u-boot@lists.denx.de>; Wed, 13 Sep 2017 22:06:06 +0000 (UTC)",
            "by mail-qk0-f196.google.com with SMTP id r66so942216qke.4\n\tfor <u-boot@lists.denx.de>; Wed, 13 Sep 2017 15:06:06 -0700 (PDT)",
            "from localhost ([2601:184:4780:aac0:25f8:dd96:a084:785a])\n\tby smtp.gmail.com with ESMTPSA id\n\tw5sm1595097qkd.47.2017.09.13.15.06.03\n\t(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);\n\tWed, 13 Sep 2017 15:06:04 -0700 (PDT)"
        ],
        "X-Spam-Checker-Version": "SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de",
        "X-Spam-Level": "",
        "X-Spam-Status": "No, score=-0.0 required=5.0 tests=FREEMAIL_FROM,\n\tRCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL,\n\tT_DKIM_INVALID\n\tautolearn=unavailable autolearn_force=no version=3.4.0",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references;\n\tbh=6tVjFEhkD+n/lPFRMHZEy/F0zK8ykCSr4pMVfxeeooI=;\n\tb=Ckosl1JygCTrKrFCpK1SKR9Y7JdSIhrnECYFjQWlau7G29de1gg5ZsaXJtZxWBmgad\n\tFYi99Euaie8d/GP42CHbVo5q+/YA5dMaBmL83s7BHGGc0I7Wf0Y9G0ok/CSxeKD64sjT\n\teGDg3O8nyNV0fXLs44BPco1FMgIS+BqO1foEn12c4KQqyvGQhDjFzNivjYxe5fWcTfYq\n\t/Q1tVTRH0pWrbZSBFYREI8i5eOEYu9bD0YlokatzVF4OnlrI/cKRGf0NZwy7h3iB0pA9\n\tIONEETqT43HD1sIuUH6CeP9K8WsmYKC+ccYfuGoDv4Hy9Xf/xE505SxZzL7CYgn22r8P\n\tY7Tg==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=6tVjFEhkD+n/lPFRMHZEy/F0zK8ykCSr4pMVfxeeooI=;\n\tb=WPxhVnu2iFVLD9PteTVFqaxAMU/wugPv9r/dl3lDi3T732mPdnCsNwGAmD624O4Aeg\n\t6ExgrwYVcfmbbrRkiY6/3IYVEpBG/ygRoZaLJSrUH1l7pENrSCsc7jHMHm5Rdbm4vha5\n\tM12O1ynYBsZhwixsNt3vTbYOHb+Tgb2/uq8CQX4TyF/mM51CtvOW7KN7TTIxf+d1K5Sf\n\t3Y1fSICBPrDU4i9zbwtOCf53gUhxXNqYmCIooYNbvajZV5xAZ+NpaIm2jSrdySjwO67m\n\tf7oHtLTT+YHCiGp1gEPpPCn5E9HsQKSGrBUXADEtIJ3FcBcdjsIJFAPV94KLrmjBo8EX\n\tUTLQ==",
        "X-Gm-Message-State": "AHPjjUi0NWt7Xzs829jZOhnnsI09SJ7wcJ/qr6rslgG8VH5TeifjnLiV\n\tZnda7ig+/nrDklUoA/M=",
        "X-Google-Smtp-Source": "AOwi7QAQseY21mJlyIibSNUaX+KKJunPBMpifKKfsTwEK+6YTK35yUnbaOkckPvxNeQAplHgjbRNNw==",
        "X-Received": "by 10.55.16.207 with SMTP id 76mr20281qkq.120.1505340365344;\n\tWed, 13 Sep 2017 15:06:05 -0700 (PDT)",
        "From": "Rob Clark <robdclark@gmail.com>",
        "To": "U-Boot Mailing List <u-boot@lists.denx.de>",
        "Date": "Wed, 13 Sep 2017 18:05:28 -0400",
        "Message-Id": "<20170913220546.19560-6-robdclark@gmail.com>",
        "X-Mailer": "git-send-email 2.13.5",
        "In-Reply-To": "<20170913220546.19560-1-robdclark@gmail.com>",
        "References": "<20170913220546.19560-1-robdclark@gmail.com>",
        "Cc": "Heinrich Schuchardt <xypron.glpk@gmx.de>, Peter Jones <pjones@redhat.com>",
        "Subject": "[U-Boot] [PATCH v3 05/21] efi_loader: add device-path utils",
        "X-BeenThere": "u-boot@lists.denx.de",
        "X-Mailman-Version": "2.1.18",
        "Precedence": "list",
        "List-Id": "U-Boot discussion <u-boot.lists.denx.de>",
        "List-Unsubscribe": "<https://lists.denx.de/options/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=unsubscribe>",
        "List-Archive": "<http://lists.denx.de/pipermail/u-boot/>",
        "List-Post": "<mailto:u-boot@lists.denx.de>",
        "List-Help": "<mailto:u-boot-request@lists.denx.de?subject=help>",
        "List-Subscribe": "<https://lists.denx.de/listinfo/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=subscribe>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "base64",
        "Errors-To": "u-boot-bounces@lists.denx.de",
        "Sender": "\"U-Boot\" <u-boot-bounces@lists.denx.de>"
    },
    "content": "Helpers to construct device-paths from devices, partitions, files, and\nfor parsing and manipulating device-paths.\n\nFor non-legacy devices, this will use u-boot's device-model to construct\ndevice-paths which include bus hierarchy to construct device-paths.  For\nlegacy devices we still fake it, but slightly more convincingly.\n\nSigned-off-by: Rob Clark <robdclark@gmail.com>\n---\n include/efi_api.h                |  10 +\n include/efi_loader.h             |  26 ++\n lib/efi_loader/Makefile          |   2 +-\n lib/efi_loader/efi_boottime.c    |  13 +-\n lib/efi_loader/efi_device_path.c | 563 +++++++++++++++++++++++++++++++++++++++\n 5 files changed, 611 insertions(+), 3 deletions(-)\n create mode 100644 lib/efi_loader/efi_device_path.c",
    "diff": "diff --git a/include/efi_api.h b/include/efi_api.h\nindex b761cf4822..4e27c82129 100644\n--- a/include/efi_api.h\n+++ b/include/efi_api.h\n@@ -314,6 +314,7 @@ struct efi_device_path_acpi_path {\n #define DEVICE_PATH_TYPE_MESSAGING_DEVICE\t0x03\n #  define DEVICE_PATH_SUB_TYPE_MSG_USB\t\t0x05\n #  define DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR\t0x0b\n+#  define DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS\t0x0f\n #  define DEVICE_PATH_SUB_TYPE_MSG_SD\t\t0x1a\n #  define DEVICE_PATH_SUB_TYPE_MSG_MMC\t\t0x1d\n \n@@ -329,6 +330,15 @@ struct efi_device_path_mac_addr {\n \tu8 if_type;\n } __packed;\n \n+struct efi_device_path_usb_class {\n+\tstruct efi_device_path dp;\n+\tu16 vendor_id;\n+\tu16 product_id;\n+\tu8 device_class;\n+\tu8 device_subclass;\n+\tu8 device_protocol;\n+} __packed;\n+\n struct efi_device_path_sd_mmc_path {\n \tstruct efi_device_path dp;\n \tu8 slot_number;\ndiff --git a/include/efi_loader.h b/include/efi_loader.h\nindex 1179234f68..d052b03ab7 100644\n--- a/include/efi_loader.h\n+++ b/include/efi_loader.h\n@@ -197,6 +197,32 @@ extern void *efi_bounce_buffer;\n #define EFI_LOADER_BOUNCE_BUFFER_SIZE (64 * 1024 * 1024)\n #endif\n \n+\n+struct efi_device_path *efi_dp_next(const struct efi_device_path *dp);\n+int efi_dp_match(struct efi_device_path *a, struct efi_device_path *b);\n+struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,\n+\t\t\t\t   struct efi_device_path **rem);\n+unsigned efi_dp_size(const struct efi_device_path *dp);\n+struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp);\n+struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,\n+\t\t\t\t      const struct efi_device_path *dp2);\n+struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,\n+\t\t\t\t\t   const struct efi_device_path *node);\n+\n+\n+struct efi_device_path *efi_dp_from_dev(struct udevice *dev);\n+struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part);\n+struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,\n+\t\t\t\t\t const char *path);\n+struct efi_device_path *efi_dp_from_eth(void);\n+void efi_dp_split_file_path(struct efi_device_path *full_path,\n+\t\t\t    struct efi_device_path **device_path,\n+\t\t\t    struct efi_device_path **file_path);\n+\n+#define EFI_DP_TYPE(_dp, _type, _subtype) \\\n+\t(((_dp)->type == DEVICE_PATH_TYPE_##_type) && \\\n+\t ((_dp)->sub_type == DEVICE_PATH_SUB_TYPE_##_subtype))\n+\n /* Convert strings from normal C strings to uEFI strings */\n static inline void ascii2unicode(u16 *unicode, const char *ascii)\n {\ndiff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile\nindex 30bf343a36..f35e5ce8a8 100644\n--- a/lib/efi_loader/Makefile\n+++ b/lib/efi_loader/Makefile\n@@ -15,7 +15,7 @@ always := $(efiprogs-y)\n \n obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o\n obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o\n-obj-y += efi_memory.o efi_device_path_to_text.o\n+obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o\n obj-$(CONFIG_LCD) += efi_gop.o\n obj-$(CONFIG_DM_VIDEO) += efi_gop.o\n obj-$(CONFIG_PARTITIONS) += efi_disk.o\ndiff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c\nindex 43f32385fa..b962b62a97 100644\n--- a/lib/efi_loader/efi_boottime.c\n+++ b/lib/efi_loader/efi_boottime.c\n@@ -665,8 +665,17 @@ static efi_status_t EFIAPI efi_locate_device_path(efi_guid_t *protocol,\n \t\t\tstruct efi_device_path **device_path,\n \t\t\tefi_handle_t *device)\n {\n-\tEFI_ENTRY(\"%p, %p, %p\", protocol, device_path, device);\n-\treturn EFI_EXIT(EFI_NOT_FOUND);\n+\tstruct efi_object *efiobj;\n+\n+\tEFI_ENTRY(\"%pUl, %p, %p\", protocol, device_path, device);\n+\n+\tefiobj = efi_dp_find_obj(*device_path, device_path);\n+\tif (!efiobj)\n+\t\treturn EFI_EXIT(EFI_NOT_FOUND);\n+\n+\t*device = efiobj->handle;\n+\n+\treturn EFI_EXIT(EFI_SUCCESS);\n }\n \n /* Collapses configuration table entries, removing index i */\ndiff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c\nnew file mode 100644\nindex 0000000000..5d5c3b3464\n--- /dev/null\n+++ b/lib/efi_loader/efi_device_path.c\n@@ -0,0 +1,563 @@\n+/*\n+ * EFI device path from u-boot device-model mapping\n+ *\n+ * (C) Copyright 2017 Rob Clark\n+ *\n+ * SPDX-License-Identifier:\tGPL-2.0+\n+ */\n+\n+#include <common.h>\n+#include <blk.h>\n+#include <dm.h>\n+#include <usb.h>\n+#include <mmc.h>\n+#include <efi_loader.h>\n+#include <inttypes.h>\n+#include <part.h>\n+\n+/* template END node: */\n+static const struct efi_device_path END = {\n+\t.type     = DEVICE_PATH_TYPE_END,\n+\t.sub_type = DEVICE_PATH_SUB_TYPE_END,\n+\t.length   = sizeof(END),\n+};\n+\n+#define U_BOOT_GUID \\\n+\tEFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \\\n+\t\t 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b)\n+\n+/* template ROOT node: */\n+static const struct efi_device_path_vendor ROOT = {\n+\t.dp = {\n+\t\t.type     = DEVICE_PATH_TYPE_HARDWARE_DEVICE,\n+\t\t.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR,\n+\t\t.length   = sizeof(ROOT),\n+\t},\n+\t.guid = U_BOOT_GUID,\n+};\n+\n+static void *dp_alloc(size_t sz)\n+{\n+\tvoid *buf;\n+\n+\tif (efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, sz, &buf) != EFI_SUCCESS)\n+\t\treturn NULL;\n+\n+\treturn buf;\n+}\n+\n+/*\n+ * Iterate to next block in device-path, terminating (returning NULL)\n+ * at /End* node.\n+ */\n+struct efi_device_path *efi_dp_next(const struct efi_device_path *dp)\n+{\n+\tif (dp == NULL)\n+\t\treturn NULL;\n+\tif (dp->type == DEVICE_PATH_TYPE_END)\n+\t\treturn NULL;\n+\tdp = ((void *)dp) + dp->length;\n+\tif (dp->type == DEVICE_PATH_TYPE_END)\n+\t\treturn NULL;\n+\treturn (struct efi_device_path *)dp;\n+}\n+\n+/*\n+ * Compare two device-paths, stopping when the shorter of the two hits\n+ * an End* node.  This is useful to, for example, compare a device-path\n+ * representing a device with one representing a file on the device, or\n+ * a device with a parent device.\n+ */\n+int efi_dp_match(struct efi_device_path *a, struct efi_device_path *b)\n+{\n+\twhile (1) {\n+\t\tint ret;\n+\n+\t\tret = memcmp(&a->length, &b->length, sizeof(a->length));\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tret = memcmp(a, b, a->length);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\ta = efi_dp_next(a);\n+\t\tb = efi_dp_next(b);\n+\n+\t\tif (!a || !b)\n+\t\t\treturn 0;\n+\t}\n+}\n+\n+\n+/*\n+ * See UEFI spec (section 3.1.2, about short-form device-paths..\n+ * tl;dr: we can have a device-path that starts with a USB WWID\n+ * or USB Class node, and a few other cases which don't encode\n+ * the full device path with bus hierarchy:\n+ *\n+ *   - MESSAGING:USB_WWID\n+ *   - MESSAGING:USB_CLASS\n+ *   - MEDIA:FILE_PATH\n+ *   - MEDIA:HARD_DRIVE\n+ *   - MESSAGING:URI\n+ */\n+static struct efi_device_path *shorten_path(struct efi_device_path *dp)\n+{\n+\twhile (dp) {\n+\t\t/*\n+\t\t * TODO: Add MESSAGING:USB_WWID and MESSAGING:URI..\n+\t\t * in practice fallback.efi just uses MEDIA:HARD_DRIVE\n+\t\t * so not sure when we would see these other cases.\n+\t\t */\n+\t\tif (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_CLASS) ||\n+\t\t    EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) ||\n+\t\t    EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH))\n+\t\t\treturn dp;\n+\n+\t\tdp = efi_dp_next(dp);\n+\t}\n+\n+\treturn dp;\n+}\n+\n+static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,\n+\t\t\t\t   struct efi_device_path **rem)\n+{\n+\tstruct efi_object *efiobj;\n+\n+\tlist_for_each_entry(efiobj, &efi_obj_list, link) {\n+\t\tint i;\n+\n+\t\tfor (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {\n+\t\t\tstruct efi_handler *handler = &efiobj->protocols[i];\n+\t\t\tstruct efi_device_path *obj_dp;\n+\n+\t\t\tif (!handler->guid)\n+\t\t\t\tbreak;\n+\n+\t\t\tif (guidcmp(handler->guid, &efi_guid_device_path))\n+\t\t\t\tcontinue;\n+\n+\t\t\tobj_dp = handler->protocol_interface;\n+\n+\t\t\tdo {\n+\t\t\t\tif (efi_dp_match(dp, obj_dp) == 0) {\n+\t\t\t\t\tif (rem) {\n+\t\t\t\t\t\t*rem = ((void *)dp) +\n+\t\t\t\t\t\t\tefi_dp_size(obj_dp);\n+\t\t\t\t\t}\n+\t\t\t\t\treturn efiobj;\n+\t\t\t\t}\n+\n+\t\t\t\tobj_dp = shorten_path(efi_dp_next(obj_dp));\n+\t\t\t} while (short_path && obj_dp);\n+\t\t}\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+\n+/*\n+ * Find an efiobj from device-path, if 'rem' is not NULL, returns the\n+ * remaining part of the device path after the matched object.\n+ */\n+struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,\n+\t\t\t\t   struct efi_device_path **rem)\n+{\n+\tstruct efi_object *efiobj;\n+\n+\tefiobj = find_obj(dp, false, rem);\n+\n+\tif (!efiobj)\n+\t\tefiobj = find_obj(dp, true, rem);\n+\n+\treturn efiobj;\n+}\n+\n+/* return size not including End node: */\n+unsigned efi_dp_size(const struct efi_device_path *dp)\n+{\n+\tunsigned sz = 0;\n+\n+\twhile (dp) {\n+\t\tsz += dp->length;\n+\t\tdp = efi_dp_next(dp);\n+\t}\n+\n+\treturn sz;\n+}\n+\n+struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)\n+{\n+\tstruct efi_device_path *ndp;\n+\tunsigned sz = efi_dp_size(dp) + sizeof(END);\n+\n+\tif (!dp)\n+\t\treturn NULL;\n+\n+\tndp = dp_alloc(sz);\n+\tmemcpy(ndp, dp, sz);\n+\n+\treturn ndp;\n+}\n+\n+struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,\n+\t\t\t\t      const struct efi_device_path *dp2)\n+{\n+\tstruct efi_device_path *ret;\n+\n+\tif (!dp1) {\n+\t\tret = efi_dp_dup(dp2);\n+\t} else if (!dp2) {\n+\t\tret = efi_dp_dup(dp1);\n+\t} else {\n+\t\t/* both dp1 and dp2 are non-null */\n+\t\tunsigned sz1 = efi_dp_size(dp1);\n+\t\tunsigned sz2 = efi_dp_size(dp2);\n+\t\tvoid *p = dp_alloc(sz1 + sz2 + sizeof(END));\n+\t\tmemcpy(p, dp1, sz1);\n+\t\tmemcpy(p + sz1, dp2, sz2);\n+\t\tmemcpy(p + sz1 + sz2, &END, sizeof(END));\n+\t\tret = p;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,\n+\t\t\t\t\t   const struct efi_device_path *node)\n+{\n+\tstruct efi_device_path *ret;\n+\n+\tif (!node && !dp) {\n+\t\tret = efi_dp_dup(&END);\n+\t} else if (!node) {\n+\t\tret = efi_dp_dup(dp);\n+\t} else if (!dp) {\n+\t\tunsigned sz = node->length;\n+\t\tvoid *p = dp_alloc(sz + sizeof(END));\n+\t\tmemcpy(p, node, sz);\n+\t\tmemcpy(p + sz, &END, sizeof(END));\n+\t\tret = p;\n+\t} else {\n+\t\t/* both dp and node are non-null */\n+\t\tunsigned sz = efi_dp_size(dp);\n+\t\tvoid *p = dp_alloc(sz + node->length + sizeof(END));\n+\t\tmemcpy(p, dp, sz);\n+\t\tmemcpy(p + sz, node, node->length);\n+\t\tmemcpy(p + sz + node->length, &END, sizeof(END));\n+\t\tret = p;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+#ifdef CONFIG_DM\n+/* size of device-path not including END node for device and all parents\n+ * up to the root device.\n+ */\n+static unsigned dp_size(struct udevice *dev)\n+{\n+\tif (!dev || !dev->driver)\n+\t\treturn sizeof(ROOT);\n+\n+\tswitch (dev->driver->id) {\n+\tcase UCLASS_ROOT:\n+\tcase UCLASS_SIMPLE_BUS:\n+\t\t/* stop traversing parents at this point: */\n+\t\treturn sizeof(ROOT);\n+\tcase UCLASS_MMC:\n+\t\treturn dp_size(dev->parent) +\n+\t\t\tsizeof(struct efi_device_path_sd_mmc_path);\n+\tcase UCLASS_MASS_STORAGE:\n+\tcase UCLASS_USB_HUB:\n+\t\treturn dp_size(dev->parent) +\n+\t\t\tsizeof(struct efi_device_path_usb_class);\n+\tdefault:\n+\t\t/* just skip over unknown classes: */\n+\t\treturn dp_size(dev->parent);\n+\t}\n+}\n+\n+static void *dp_fill(void *buf, struct udevice *dev)\n+{\n+\tif (!dev || !dev->driver)\n+\t\treturn buf;\n+\n+\tswitch (dev->driver->id) {\n+\tcase UCLASS_ROOT:\n+\tcase UCLASS_SIMPLE_BUS: {\n+\t\t/* stop traversing parents at this point: */\n+\t\tstruct efi_device_path_vendor *vdp = buf;\n+\t\t*vdp = ROOT;\n+\t\treturn &vdp[1];\n+\t}\n+#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)\n+\tcase UCLASS_MMC: {\n+\t\tstruct efi_device_path_sd_mmc_path *sddp =\n+\t\t\tdp_fill(buf, dev->parent);\n+\t\tstruct mmc *mmc = mmc_get_mmc_dev(dev);\n+\t\tstruct blk_desc *desc = mmc_get_blk_desc(mmc);\n+\n+\t\tsddp->dp.type     = DEVICE_PATH_TYPE_MESSAGING_DEVICE;\n+\t\tsddp->dp.sub_type = (desc->if_type == IF_TYPE_MMC) ?\n+\t\t\tDEVICE_PATH_SUB_TYPE_MSG_MMC :\n+\t\t\tDEVICE_PATH_SUB_TYPE_MSG_SD;\n+\t\tsddp->dp.length   = sizeof(*sddp);\n+\t\tsddp->slot_number = dev->seq;\n+\n+\t\treturn &sddp[1];\n+\t}\n+#endif\n+\tcase UCLASS_MASS_STORAGE:\n+\tcase UCLASS_USB_HUB: {\n+\t\tstruct efi_device_path_usb_class *udp =\n+\t\t\tdp_fill(buf, dev->parent);\n+\t\tstruct usb_device *udev = dev_get_parent_priv(dev);\n+\t\tstruct usb_device_descriptor *desc = &udev->descriptor;\n+\n+\t\tudp->dp.type     = DEVICE_PATH_TYPE_MESSAGING_DEVICE;\n+\t\tudp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS;\n+\t\tudp->dp.length   = sizeof(*udp);\n+\t\tudp->vendor_id   = desc->idVendor;\n+\t\tudp->product_id  = desc->idProduct;\n+\t\tudp->device_class    = desc->bDeviceClass;\n+\t\tudp->device_subclass = desc->bDeviceSubClass;\n+\t\tudp->device_protocol = desc->bDeviceProtocol;\n+\n+\t\treturn &udp[1];\n+\t}\n+\tdefault:\n+\t\tdebug(\"unhandled device class: %s (%u)\\n\",\n+\t\t      dev->name, dev->driver->id);\n+\t\treturn dp_fill(buf, dev->parent);\n+\t}\n+}\n+\n+/* Construct a device-path from a device: */\n+struct efi_device_path *efi_dp_from_dev(struct udevice *dev)\n+{\n+\tvoid *buf, *start;\n+\n+\tstart = buf = dp_alloc(dp_size(dev) + sizeof(END));\n+\tbuf = dp_fill(buf, dev);\n+\t*((struct efi_device_path *)buf) = END;\n+\n+\treturn start;\n+}\n+#endif\n+\n+static unsigned dp_part_size(struct blk_desc *desc, int part)\n+{\n+\tunsigned dpsize;\n+\n+#ifdef CONFIG_BLK\n+\tdpsize = dp_size(desc->bdev->parent);\n+#else\n+\tdpsize = sizeof(ROOT) + sizeof(struct efi_device_path_usb);\n+#endif\n+\n+\tif (part == 0) /* the actual disk, not a partition */\n+\t\treturn dpsize;\n+\n+\tif (desc->part_type == PART_TYPE_ISO)\n+\t\tdpsize += sizeof(struct efi_device_path_cdrom_path);\n+\telse\n+\t\tdpsize += sizeof(struct efi_device_path_hard_drive_path);\n+\n+\treturn dpsize;\n+}\n+\n+static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)\n+{\n+\tdisk_partition_t info;\n+\n+#ifdef CONFIG_BLK\n+\tbuf = dp_fill(buf, desc->bdev->parent);\n+#else\n+\t/*\n+\t * We *could* make a more accurate path, by looking at if_type\n+\t * and handling all the different cases like we do for non-\n+\t * legacy (ie CONFIG_BLK=y) case.  But most important thing\n+\t * is just to have a unique device-path for if_type+devnum.\n+\t * So map things to a fictional USB device:\n+\t */\n+\tstruct efi_device_path_usb *udp;\n+\n+\tmemcpy(buf, &ROOT, sizeof(ROOT));\n+\tbuf += sizeof(ROOT);\n+\n+\tudp = buf;\n+\tudp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;\n+\tudp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB;\n+\tudp->dp.length = sizeof(*udp);\n+\tudp->parent_port_number = desc->if_type;\n+\tudp->usb_interface = desc->devnum;\n+\tbuf = &udp[1];\n+#endif\n+\n+\tif (part == 0) /* the actual disk, not a partition */\n+\t\treturn buf;\n+\n+\tpart_get_info(desc, part, &info);\n+\n+\tif (desc->part_type == PART_TYPE_ISO) {\n+\t\tstruct efi_device_path_cdrom_path *cddp = buf;\n+\n+\t\tcddp->boot_entry = part - 1;\n+\t\tcddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;\n+\t\tcddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;\n+\t\tcddp->dp.length = sizeof(*cddp);\n+\t\tcddp->partition_start = info.start;\n+\t\tcddp->partition_end = info.size;\n+\n+\t\tbuf = &cddp[1];\n+\t} else {\n+\t\tstruct efi_device_path_hard_drive_path *hddp = buf;\n+\n+\t\thddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;\n+\t\thddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH;\n+\t\thddp->dp.length = sizeof(*hddp);\n+\t\thddp->partition_number = part - 1;\n+\t\thddp->partition_start = info.start;\n+\t\thddp->partition_end = info.size;\n+\t\tif (desc->part_type == PART_TYPE_EFI)\n+\t\t\thddp->partmap_type = 2;\n+\t\telse\n+\t\t\thddp->partmap_type = 1;\n+\t\thddp->signature_type = desc->sig_type;\n+\t\tif (hddp->signature_type != 0)\n+\t\t\tmemcpy(hddp->partition_signature, &desc->guid_sig,\n+\t\t\t       sizeof(hddp->partition_signature));\n+\n+\t\tbuf = &hddp[1];\n+\t}\n+\n+\treturn buf;\n+}\n+\n+\n+/* Construct a device-path from a partition on a blk device: */\n+struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)\n+{\n+\tvoid *buf, *start;\n+\n+\tstart = buf = dp_alloc(dp_part_size(desc, part) + sizeof(END));\n+\n+\tbuf = dp_part_fill(buf, desc, part);\n+\n+\t*((struct efi_device_path *)buf) = END;\n+\n+\treturn start;\n+}\n+\n+/* convert path to an UEFI style path (ie. DOS style backslashes and utf16) */\n+static void path_to_uefi(u16 *uefi, const char *path)\n+{\n+\twhile (*path) {\n+\t\tchar c = *(path++);\n+\t\tif (c == '/')\n+\t\t\tc = '\\\\';\n+\t\t*(uefi++) = c;\n+\t}\n+\t*uefi = '\\0';\n+}\n+\n+/*\n+ * If desc is NULL, this creates a path with only the file component,\n+ * otherwise it creates a full path with both device and file components\n+ */\n+struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,\n+\t\tconst char *path)\n+{\n+\tstruct efi_device_path_file_path *fp;\n+\tvoid *buf, *start;\n+\tunsigned dpsize = 0, fpsize;\n+\n+\tif (desc)\n+\t\tdpsize = dp_part_size(desc, part);\n+\n+\tfpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);\n+\tdpsize += fpsize;\n+\n+\tstart = buf = dp_alloc(dpsize + sizeof(END));\n+\n+\tif (desc)\n+\t\tbuf = dp_part_fill(buf, desc, part);\n+\n+\t/* add file-path: */\n+\tfp = buf;\n+\tfp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;\n+\tfp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;\n+\tfp->dp.length = fpsize;\n+\tpath_to_uefi(fp->str, path);\n+\tbuf += fpsize;\n+\n+\t*((struct efi_device_path *)buf) = END;\n+\n+\treturn start;\n+}\n+\n+#ifdef CONFIG_NET\n+struct efi_device_path *efi_dp_from_eth(void)\n+{\n+\tstruct efi_device_path_mac_addr *ndp;\n+\tvoid *buf, *start;\n+\tunsigned dpsize = 0;\n+\n+\tassert(eth_get_dev());\n+\n+#ifdef CONFIG_DM_ETH\n+\tdpsize += dp_size(eth_get_dev());\n+#else\n+\tdpsize += sizeof(ROOT);\n+#endif\n+\tdpsize += sizeof(*ndp);\n+\n+\tstart = buf = dp_alloc(dpsize + sizeof(END));\n+\n+#ifdef CONFIG_DM_ETH\n+\tbuf = dp_fill(buf, eth_get_dev());\n+#else\n+\tmemcpy(buf, &ROOT, sizeof(ROOT));\n+\tbuf += sizeof(ROOT);\n+#endif\n+\n+\tndp = buf;\n+\tndp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;\n+\tndp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;\n+\tndp->dp.length = sizeof(*ndp);\n+\tmemcpy(ndp->mac.addr, eth_get_ethaddr(), ARP_HLEN);\n+\tbuf = &ndp[1];\n+\n+\t*((struct efi_device_path *)buf) = END;\n+\n+\treturn start;\n+}\n+#endif\n+\n+/*\n+ * Helper to split a full device path (containing both device and file\n+ * parts) into it's constituent parts.\n+ */\n+void efi_dp_split_file_path(struct efi_device_path *full_path,\n+\t\t\t    struct efi_device_path **device_path,\n+\t\t\t    struct efi_device_path **file_path)\n+{\n+\tstruct efi_device_path *p, *dp, *fp;\n+\n+\tdp = efi_dp_dup(full_path);\n+\tp = dp;\n+\twhile (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH))\n+\t\tp = efi_dp_next(p);\n+\tfp = efi_dp_dup(p);\n+\n+\tp->type = DEVICE_PATH_TYPE_END;\n+\tp->sub_type = DEVICE_PATH_SUB_TYPE_END;\n+\tp->length = sizeof(*p);\n+\n+\t*device_path = dp;\n+\t*file_path = fp;\n+}\n",
    "prefixes": [
        "U-Boot",
        "v3",
        "05/21"
    ]
}