Commit db8952e7 authored by Ard Biesheuvel's avatar Ard Biesheuvel

efi/dev-path-parser: Add struct definition for vendor type device path nodes

In preparation of adding support for loading the initrd via a special
device path, add the struct definition of a vendor GUIDed device path
node to efi.h.

Since we will be producing these data structures rather than just
consumsing the ones instantiated by the firmware, refactor the various
device path node definitions so we can take the size of each node using
sizeof() rather than having to resort to opaque arithmetic in the static
initializers.

While at it, drop the #if IS_ENABLED() check for the declaration of
efi_get_device_by_path(), which is unnecessary, and constify its first
argument as well.
Signed-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
parent a570b062
...@@ -46,7 +46,7 @@ struct properties_header { ...@@ -46,7 +46,7 @@ struct properties_header {
}; };
static void __init unmarshal_key_value_pairs(struct dev_header *dev_header, static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
struct device *dev, void *ptr, struct device *dev, const void *ptr,
struct property_entry entry[]) struct property_entry entry[])
{ {
int i; int i;
...@@ -117,10 +117,10 @@ static int __init unmarshal_devices(struct properties_header *properties) ...@@ -117,10 +117,10 @@ static int __init unmarshal_devices(struct properties_header *properties)
while (offset + sizeof(struct dev_header) < properties->len) { while (offset + sizeof(struct dev_header) < properties->len) {
struct dev_header *dev_header = (void *)properties + offset; struct dev_header *dev_header = (void *)properties + offset;
struct property_entry *entry = NULL; struct property_entry *entry = NULL;
const struct efi_dev_path *ptr;
struct device *dev; struct device *dev;
size_t len; size_t len;
int ret, i; int ret, i;
void *ptr;
if (offset + dev_header->len > properties->len || if (offset + dev_header->len > properties->len ||
dev_header->len <= sizeof(*dev_header)) { dev_header->len <= sizeof(*dev_header)) {
...@@ -131,10 +131,10 @@ static int __init unmarshal_devices(struct properties_header *properties) ...@@ -131,10 +131,10 @@ static int __init unmarshal_devices(struct properties_header *properties)
ptr = dev_header->path; ptr = dev_header->path;
len = dev_header->len - sizeof(*dev_header); len = dev_header->len - sizeof(*dev_header);
dev = efi_get_device_by_path((struct efi_dev_path **)&ptr, &len); dev = efi_get_device_by_path(&ptr, &len);
if (IS_ERR(dev)) { if (IS_ERR(dev)) {
pr_err("device path parse error %ld at %#zx:\n", pr_err("device path parse error %ld at %#zx:\n",
PTR_ERR(dev), ptr - (void *)dev_header); PTR_ERR(dev), (void *)ptr - (void *)dev_header);
print_hex_dump(KERN_ERR, pr_fmt(), DUMP_PREFIX_OFFSET, print_hex_dump(KERN_ERR, pr_fmt(), DUMP_PREFIX_OFFSET,
16, 1, dev_header, dev_header->len, true); 16, 1, dev_header, dev_header->len, true);
dev = NULL; dev = NULL;
......
...@@ -31,13 +31,13 @@ static int __init match_acpi_dev(struct device *dev, const void *data) ...@@ -31,13 +31,13 @@ static int __init match_acpi_dev(struct device *dev, const void *data)
return !strcmp("0", hid_uid.uid); return !strcmp("0", hid_uid.uid);
} }
static long __init parse_acpi_path(struct efi_dev_path *node, static long __init parse_acpi_path(const struct efi_dev_path *node,
struct device *parent, struct device **child) struct device *parent, struct device **child)
{ {
struct acpi_hid_uid hid_uid = {}; struct acpi_hid_uid hid_uid = {};
struct device *phys_dev; struct device *phys_dev;
if (node->length != 12) if (node->header.length != 12)
return -EINVAL; return -EINVAL;
sprintf(hid_uid.hid[0].id, "%c%c%c%04X", sprintf(hid_uid.hid[0].id, "%c%c%c%04X",
...@@ -69,12 +69,12 @@ static int __init match_pci_dev(struct device *dev, void *data) ...@@ -69,12 +69,12 @@ static int __init match_pci_dev(struct device *dev, void *data)
return dev_is_pci(dev) && to_pci_dev(dev)->devfn == devfn; return dev_is_pci(dev) && to_pci_dev(dev)->devfn == devfn;
} }
static long __init parse_pci_path(struct efi_dev_path *node, static long __init parse_pci_path(const struct efi_dev_path *node,
struct device *parent, struct device **child) struct device *parent, struct device **child)
{ {
unsigned int devfn; unsigned int devfn;
if (node->length != 6) if (node->header.length != 6)
return -EINVAL; return -EINVAL;
if (!parent) if (!parent)
return -EINVAL; return -EINVAL;
...@@ -105,19 +105,19 @@ static long __init parse_pci_path(struct efi_dev_path *node, ...@@ -105,19 +105,19 @@ static long __init parse_pci_path(struct efi_dev_path *node,
* search for a device. * search for a device.
*/ */
static long __init parse_end_path(struct efi_dev_path *node, static long __init parse_end_path(const struct efi_dev_path *node,
struct device *parent, struct device **child) struct device *parent, struct device **child)
{ {
if (node->length != 4) if (node->header.length != 4)
return -EINVAL; return -EINVAL;
if (node->sub_type != EFI_DEV_END_INSTANCE && if (node->header.sub_type != EFI_DEV_END_INSTANCE &&
node->sub_type != EFI_DEV_END_ENTIRE) node->header.sub_type != EFI_DEV_END_ENTIRE)
return -EINVAL; return -EINVAL;
if (!parent) if (!parent)
return -ENODEV; return -ENODEV;
*child = get_device(parent); *child = get_device(parent);
return node->sub_type; return node->header.sub_type;
} }
/** /**
...@@ -156,7 +156,7 @@ static long __init parse_end_path(struct efi_dev_path *node, ...@@ -156,7 +156,7 @@ static long __init parse_end_path(struct efi_dev_path *node,
* %ERR_PTR(-EINVAL) if a node is malformed or exceeds @len, * %ERR_PTR(-EINVAL) if a node is malformed or exceeds @len,
* %ERR_PTR(-ENOTSUPP) if support for a node type is not yet implemented. * %ERR_PTR(-ENOTSUPP) if support for a node type is not yet implemented.
*/ */
struct device * __init efi_get_device_by_path(struct efi_dev_path **node, struct device * __init efi_get_device_by_path(const struct efi_dev_path **node,
size_t *len) size_t *len)
{ {
struct device *parent = NULL, *child; struct device *parent = NULL, *child;
...@@ -166,16 +166,16 @@ struct device * __init efi_get_device_by_path(struct efi_dev_path **node, ...@@ -166,16 +166,16 @@ struct device * __init efi_get_device_by_path(struct efi_dev_path **node,
return NULL; return NULL;
while (!ret) { while (!ret) {
if (*len < 4 || *len < (*node)->length) if (*len < 4 || *len < (*node)->header.length)
ret = -EINVAL; ret = -EINVAL;
else if ((*node)->type == EFI_DEV_ACPI && else if ((*node)->header.type == EFI_DEV_ACPI &&
(*node)->sub_type == EFI_DEV_BASIC_ACPI) (*node)->header.sub_type == EFI_DEV_BASIC_ACPI)
ret = parse_acpi_path(*node, parent, &child); ret = parse_acpi_path(*node, parent, &child);
else if ((*node)->type == EFI_DEV_HW && else if ((*node)->header.type == EFI_DEV_HW &&
(*node)->sub_type == EFI_DEV_PCI) (*node)->header.sub_type == EFI_DEV_PCI)
ret = parse_pci_path(*node, parent, &child); ret = parse_pci_path(*node, parent, &child);
else if (((*node)->type == EFI_DEV_END_PATH || else if (((*node)->header.type == EFI_DEV_END_PATH ||
(*node)->type == EFI_DEV_END_PATH2)) (*node)->header.type == EFI_DEV_END_PATH2))
ret = parse_end_path(*node, parent, &child); ret = parse_end_path(*node, parent, &child);
else else
ret = -ENOTSUPP; ret = -ENOTSUPP;
...@@ -185,8 +185,8 @@ struct device * __init efi_get_device_by_path(struct efi_dev_path **node, ...@@ -185,8 +185,8 @@ struct device * __init efi_get_device_by_path(struct efi_dev_path **node,
return ERR_PTR(ret); return ERR_PTR(ret);
parent = child; parent = child;
*node = (void *)*node + (*node)->length; *node = (void *)*node + (*node)->header.length;
*len -= (*node)->length; *len -= (*node)->header.length;
} }
if (ret == EFI_DEV_END_ENTIRE) if (ret == EFI_DEV_END_ENTIRE)
......
...@@ -855,30 +855,40 @@ extern int efi_status_to_err(efi_status_t status); ...@@ -855,30 +855,40 @@ extern int efi_status_to_err(efi_status_t status);
#define EFI_DEV_END_ENTIRE 0xFF #define EFI_DEV_END_ENTIRE 0xFF
struct efi_generic_dev_path { struct efi_generic_dev_path {
u8 type; u8 type;
u8 sub_type; u8 sub_type;
u16 length; u16 length;
} __attribute ((packed)); } __packed;
struct efi_acpi_dev_path {
struct efi_generic_dev_path header;
u32 hid;
u32 uid;
} __packed;
struct efi_pci_dev_path {
struct efi_generic_dev_path header;
u8 fn;
u8 dev;
} __packed;
struct efi_vendor_dev_path {
struct efi_generic_dev_path header;
efi_guid_t vendorguid;
u8 vendordata[];
} __packed;
struct efi_dev_path { struct efi_dev_path {
u8 type; /* can be replaced with unnamed */
u8 sub_type; /* struct efi_generic_dev_path; */
u16 length; /* once we've moved to -std=c11 */
union { union {
struct { struct efi_generic_dev_path header;
u32 hid; struct efi_acpi_dev_path acpi;
u32 uid; struct efi_pci_dev_path pci;
} acpi; struct efi_vendor_dev_path vendor;
struct {
u8 fn;
u8 dev;
} pci;
}; };
} __attribute ((packed)); } __packed;
#if IS_ENABLED(CONFIG_EFI_DEV_PATH_PARSER) struct device *efi_get_device_by_path(const struct efi_dev_path **node,
struct device *efi_get_device_by_path(struct efi_dev_path **node, size_t *len); size_t *len);
#endif
static inline void memrange_efi_to_native(u64 *addr, u64 *npages) static inline void memrange_efi_to_native(u64 *addr, u64 *npages)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment