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