linux/drivers/firmware/efi/dev-path-parser.c
<<
>>
Prefs
   1/*
   2 * dev-path-parser.c - EFI Device Path parser
   3 * Copyright (C) 2016 Lukas Wunner <lukas@wunner.de>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License (version 2) as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
  16 */
  17
  18#include <linux/acpi.h>
  19#include <linux/efi.h>
  20#include <linux/pci.h>
  21
  22struct acpi_hid_uid {
  23        struct acpi_device_id hid[2];
  24        char uid[11]; /* UINT_MAX + null byte */
  25};
  26
  27static int __init match_acpi_dev(struct device *dev, void *data)
  28{
  29        struct acpi_hid_uid hid_uid = *(struct acpi_hid_uid *)data;
  30        struct acpi_device *adev = to_acpi_device(dev);
  31
  32        if (acpi_match_device_ids(adev, hid_uid.hid))
  33                return 0;
  34
  35        if (adev->pnp.unique_id)
  36                return !strcmp(adev->pnp.unique_id, hid_uid.uid);
  37        else
  38                return !strcmp("0", hid_uid.uid);
  39}
  40
  41static long __init parse_acpi_path(struct efi_dev_path *node,
  42                                   struct device *parent, struct device **child)
  43{
  44        struct acpi_hid_uid hid_uid = {};
  45        struct device *phys_dev;
  46
  47        if (node->length != 12)
  48                return -EINVAL;
  49
  50        sprintf(hid_uid.hid[0].id, "%c%c%c%04X",
  51                'A' + ((node->acpi.hid >> 10) & 0x1f) - 1,
  52                'A' + ((node->acpi.hid >>  5) & 0x1f) - 1,
  53                'A' + ((node->acpi.hid >>  0) & 0x1f) - 1,
  54                        node->acpi.hid >> 16);
  55        sprintf(hid_uid.uid, "%u", node->acpi.uid);
  56
  57        *child = bus_find_device(&acpi_bus_type, NULL, &hid_uid,
  58                                 match_acpi_dev);
  59        if (!*child)
  60                return -ENODEV;
  61
  62        phys_dev = acpi_get_first_physical_node(to_acpi_device(*child));
  63        if (phys_dev) {
  64                get_device(phys_dev);
  65                put_device(*child);
  66                *child = phys_dev;
  67        }
  68
  69        return 0;
  70}
  71
  72static int __init match_pci_dev(struct device *dev, void *data)
  73{
  74        unsigned int devfn = *(unsigned int *)data;
  75
  76        return dev_is_pci(dev) && to_pci_dev(dev)->devfn == devfn;
  77}
  78
  79static long __init parse_pci_path(struct efi_dev_path *node,
  80                                  struct device *parent, struct device **child)
  81{
  82        unsigned int devfn;
  83
  84        if (node->length != 6)
  85                return -EINVAL;
  86        if (!parent)
  87                return -EINVAL;
  88
  89        devfn = PCI_DEVFN(node->pci.dev, node->pci.fn);
  90
  91        *child = device_find_child(parent, &devfn, match_pci_dev);
  92        if (!*child)
  93                return -ENODEV;
  94
  95        return 0;
  96}
  97
  98/*
  99 * Insert parsers for further node types here.
 100 *
 101 * Each parser takes a pointer to the @node and to the @parent (will be NULL
 102 * for the first device path node). If a device corresponding to @node was
 103 * found below @parent, its reference count should be incremented and the
 104 * device returned in @child.
 105 *
 106 * The return value should be 0 on success or a negative int on failure.
 107 * The special return values 0x01 (EFI_DEV_END_INSTANCE) and 0xFF
 108 * (EFI_DEV_END_ENTIRE) signal the end of the device path, only
 109 * parse_end_path() is supposed to return this.
 110 *
 111 * Be sure to validate the node length and contents before commencing the
 112 * search for a device.
 113 */
 114
 115static long __init parse_end_path(struct efi_dev_path *node,
 116                                  struct device *parent, struct device **child)
 117{
 118        if (node->length != 4)
 119                return -EINVAL;
 120        if (node->sub_type != EFI_DEV_END_INSTANCE &&
 121            node->sub_type != EFI_DEV_END_ENTIRE)
 122                return -EINVAL;
 123        if (!parent)
 124                return -ENODEV;
 125
 126        *child = get_device(parent);
 127        return node->sub_type;
 128}
 129
 130/**
 131 * efi_get_device_by_path - find device by EFI Device Path
 132 * @node: EFI Device Path
 133 * @len: maximum length of EFI Device Path in bytes
 134 *
 135 * Parse a series of EFI Device Path nodes at @node and find the corresponding
 136 * device.  If the device was found, its reference count is incremented and a
 137 * pointer to it is returned.  The caller needs to drop the reference with
 138 * put_device() after use.  The @node pointer is updated to point to the
 139 * location immediately after the "End of Hardware Device Path" node.
 140 *
 141 * If another Device Path instance follows, @len is decremented by the number
 142 * of bytes consumed.  Otherwise @len is set to %0.
 143 *
 144 * If a Device Path node is malformed or its corresponding device is not found,
 145 * @node is updated to point to this offending node and an ERR_PTR is returned.
 146 *
 147 * If @len is initially %0, the function returns %NULL.  Thus, to iterate over
 148 * all instances in a path, the following idiom may be used:
 149 *
 150 *      while (!IS_ERR_OR_NULL(dev = efi_get_device_by_path(&node, &len))) {
 151 *              // do something with dev
 152 *              put_device(dev);
 153 *      }
 154 *      if (IS_ERR(dev))
 155 *              // report error
 156 *
 157 * Devices can only be found if they're already instantiated. Most buses
 158 * instantiate devices in the "subsys" initcall level, hence the earliest
 159 * initcall level in which this function should be called is "fs".
 160 *
 161 * Returns the device on success or
 162 *      %ERR_PTR(-ENODEV) if no device was found,
 163 *      %ERR_PTR(-EINVAL) if a node is malformed or exceeds @len,
 164 *      %ERR_PTR(-ENOTSUPP) if support for a node type is not yet implemented.
 165 */
 166struct device * __init efi_get_device_by_path(struct efi_dev_path **node,
 167                                              size_t *len)
 168{
 169        struct device *parent = NULL, *child;
 170        long ret = 0;
 171
 172        if (!*len)
 173                return NULL;
 174
 175        while (!ret) {
 176                if (*len < 4 || *len < (*node)->length)
 177                        ret = -EINVAL;
 178                else if ((*node)->type     == EFI_DEV_ACPI &&
 179                         (*node)->sub_type == EFI_DEV_BASIC_ACPI)
 180                        ret = parse_acpi_path(*node, parent, &child);
 181                else if ((*node)->type     == EFI_DEV_HW &&
 182                         (*node)->sub_type == EFI_DEV_PCI)
 183                        ret = parse_pci_path(*node, parent, &child);
 184                else if (((*node)->type    == EFI_DEV_END_PATH ||
 185                          (*node)->type    == EFI_DEV_END_PATH2))
 186                        ret = parse_end_path(*node, parent, &child);
 187                else
 188                        ret = -ENOTSUPP;
 189
 190                put_device(parent);
 191                if (ret < 0)
 192                        return ERR_PTR(ret);
 193
 194                parent = child;
 195                *node  = (void *)*node + (*node)->length;
 196                *len  -= (*node)->length;
 197        }
 198
 199        if (ret == EFI_DEV_END_ENTIRE)
 200                *len = 0;
 201
 202        return child;
 203}
 204