From e2f68c8f9f4fab48f1ef3a4585932f757593fa92 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Wed, 20 Jun 2018 14:43:32 -0400 Subject: [PATCH 13/17] Move ACPI ID parsing to a shared location. This is getting out of PCI because we have some other platforms that do ACPI root parsing, but don't use the PCI roots. Signed-off-by: Peter Jones --- src/linux-acpi.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++ src/linux-pci.c | 112 +++++--------------------------------------- src/linux.c | 11 ++++- src/linux.h | 19 +++++--- 4 files changed, 152 insertions(+), 109 deletions(-) create mode 100644 src/linux-acpi.c diff --git a/src/linux-acpi.c b/src/linux-acpi.c new file mode 100644 index 00000000000..cb93a113ee2 --- /dev/null +++ b/src/linux-acpi.c @@ -0,0 +1,119 @@ +/* + * libefiboot - library for the manipulation of EFI boot variables + * Copyright 2012-2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * . + * + */ + +#include "fix_coverity.h" + +#include +#include +#include +#include +#include + +#include "efiboot.h" + +int HIDDEN +parse_acpi_hid_uid(struct device *dev, const char *fmt, ...) +{ + int rc; + char *path = NULL; + va_list ap; + char *fbuf = NULL; + uint16_t tmp16; + uint32_t acpi_hid = 0; + uint64_t acpi_uid_int = 0; + + debug(DEBUG, "entry"); + + va_start(ap, fmt); + rc = vasprintfa(&path, fmt, ap); + va_end(ap); + debug(DEBUG, "path:%s rc:%d", path, rc); + if (rc < 0 || path == NULL) + return -1; + + rc = read_sysfs_file(&fbuf, "%s/firmware_node/path", path); + if (rc > 0) { + size_t l = strlen(fbuf); + if (l > 1) { + fbuf[l-1] = 0; + dev->acpi_root.acpi_cid_str = strdup(fbuf); + debug(DEBUG, "Setting ACPI root path to \"%s\"", fbuf); + } + } + + rc = read_sysfs_file(&fbuf, "%s/firmware_node/hid", path); + if (rc < 0 || fbuf == NULL) { + efi_error("could not read %s/firmware_node/hid", path); + return -1; + } + + rc = strlen(fbuf); + if (rc < 4) { +hid_err: + efi_error("could not parse %s/firmware_node/hid", path); + return -1; + } + rc -= 4; + + rc = sscanf((char *)fbuf + rc, "%04hx", &tmp16); + debug(DEBUG, "rc:%d hid:0x%08x\n", rc, tmp16); + if (rc != 1) + goto hid_err; + + acpi_hid = EFIDP_EFI_PNP_ID(tmp16); + + /* + * Apparently basically nothing can look up a PcieRoot() node, + * because they just check _CID. So since _CID for the root pretty + * much always has to be PNP0A03 anyway, just use that no matter + * what. + */ + if (acpi_hid == EFIDP_ACPI_PCIE_ROOT_HID) + acpi_hid = EFIDP_ACPI_PCI_ROOT_HID; + dev->acpi_root.acpi_hid = acpi_hid; + debug(DEBUG, "acpi root HID:0x%08x", acpi_hid); + + errno = 0; + fbuf = NULL; + rc = read_sysfs_file(&fbuf, "%s/firmware_node/uid", path); + if ((rc <= 0 && errno != ENOENT) || fbuf == NULL) { + efi_error("could not read %s/firmware_node/uid", path); + return -1; + } + if (rc > 0) { + rc = sscanf((char *)fbuf, "%"PRIu64"\n", &acpi_uid_int); + if (rc == 1) { + dev->acpi_root.acpi_uid = acpi_uid_int; + } else { + /* kernel uses "%s\n" to print it, so there + * should always be some value and a newline... */ + int l = strlen((char *)fbuf); + if (l >= 1) { + fbuf[l-1] = '\0'; + dev->acpi_root.acpi_uid_str = strdup(fbuf); + } + } + } + debug(DEBUG, "acpi root UID:0x%"PRIx64" uidstr:\"%s\"", + dev->acpi_root.acpi_uid, dev->acpi_root.acpi_uid_str); + + errno = 0; + return 0; +} diff --git a/src/linux-pci.c b/src/linux-pci.c index 4fbd108e3ed..aa3e40c0f7c 100644 --- a/src/linux-pci.c +++ b/src/linux-pci.c @@ -37,21 +37,17 @@ * ^ root hub ^device ^device * * for network devices, we also get: - * /sys/class/net/$IFACE -> ../../devices/$PCI_STUFF/net/$IFACE + * /sys/class/net/$IFACE -> ../../devices/$PCI_DEVICES/net/$IFACE + * + * In both cases our "current" pointer should be at $PCI_DEVICES. * */ static ssize_t -parse_pci(struct device *dev, const char *current, const char *root UNUSED) +parse_pci(struct device *dev, const char *current, const char *root) { int rc; int pos; - uint16_t root_domain; - uint8_t root_bus; - uint32_t acpi_hid = 0; - uint64_t acpi_uid_int = 0; const char *devpart = current; - char *fbuf = NULL; - uint16_t tmp16 = 0; char *spaces; pos = strlen(current); @@ -62,66 +58,6 @@ parse_pci(struct device *dev, const char *current, const char *root UNUSED) debug(DEBUG, "entry"); - /* - * find the pci root domain and port; they basically look like: - * pci0000:00/ - * ^d ^p - */ - rc = sscanf(devpart, "../../devices/pci%hx:%hhx/%n", &root_domain, &root_bus, &pos); - /* - * If we can't find that, it's not a PCI device. - */ - if (rc != 2) - return 0; - devpart += pos; - - dev->pci_root.pci_root_domain = root_domain; - dev->pci_root.pci_root_bus = root_bus; - - rc = read_sysfs_file(&fbuf, - "devices/pci%04hx:%02hhx/firmware_node/hid", - root_domain, root_bus); - if (rc < 0 || fbuf == NULL) - return -1; - - rc = sscanf((char *)fbuf, "PNP%hx", &tmp16); - if (rc != 1) - return -1; - acpi_hid = EFIDP_EFI_PNP_ID(tmp16); - - /* - * Apparently basically nothing can look up a PcieRoot() node, - * because they just check _CID. So since _CID for the root pretty - * much always has to be PNP0A03 anyway, just use that no matter - * what. - */ - if (acpi_hid == EFIDP_ACPI_PCIE_ROOT_HID) - acpi_hid = EFIDP_ACPI_PCI_ROOT_HID; - dev->pci_root.pci_root_acpi_hid = acpi_hid; - - errno = 0; - fbuf = NULL; - rc = read_sysfs_file(&fbuf, - "devices/pci%04hx:%02hhx/firmware_node/uid", - root_domain, root_bus); - if ((rc <= 0 && errno != ENOENT) || fbuf == NULL) - return -1; - if (rc > 0) { - rc = sscanf((char *)fbuf, "%"PRIu64"\n", &acpi_uid_int); - if (rc == 1) { - dev->pci_root.pci_root_acpi_uid = acpi_uid_int; - } else { - /* kernel uses "%s\n" to print it, so there - * should always be some value and a newline... */ - int l = strlen((char *)fbuf); - if (l >= 1) { - fbuf[l-1] = '\0'; - dev->pci_root.pci_root_acpi_uid_str = fbuf; - } - } - } - errno = 0; - /* find the pci domain/bus/device/function: * 0000:00:01.0/0000:01:00.0/ * ^d ^b ^d ^f (of the last one in the series) @@ -136,7 +72,7 @@ parse_pci(struct device *dev, const char *current, const char *root UNUSED) debug(DEBUG, "searching for 0000:00:00.0/"); rc = sscanf(devpart, "%hx:%hhx:%hhx.%hhx/%n", &domain, &bus, &device, &function, &pos); - debug(DEBUG, "current:\"%s\" rc:%d pos:%d\n", devpart, rc, pos); + debug(DEBUG, "current:\"%s\" rc:%d pos:%d", devpart, rc, pos); arrow(DEBUG, spaces, 9, pos, rc, 3); if (rc != 4) break; @@ -157,24 +93,26 @@ parse_pci(struct device *dev, const char *current, const char *root UNUSED) dev->pci_dev[i].pci_bus = bus; dev->pci_dev[i].pci_device = device; dev->pci_dev[i].pci_function = function; - char *tmp = strndup(current, devpart-current+1); + char *tmp = strndup(root, devpart-root+1); char *linkbuf = NULL; if (!tmp) { efi_error("could not allocate memory"); return -1; } - tmp[devpart - current] = '\0'; + tmp[devpart - root] = '\0'; rc = sysfs_readlink(&linkbuf, "class/block/%s/driver", tmp); - free(tmp); if (rc < 0 || !linkbuf) { - efi_error("Could not find driver for pci device"); + efi_error("Could not find driver for pci device %s", tmp); + free(tmp); return -1; } + free(tmp); dev->pci_dev[i].driverlink = strdup(linkbuf); debug(DEBUG, "driver:%s\n", linkbuf); dev->n_pci_devs += 1; } + debug(DEBUG, "next:\"%s\"", devpart); return devpart - current; } @@ -186,34 +124,6 @@ dp_create_pci(struct device *dev, debug(DEBUG, "entry buf:%p size:%zd off:%zd", buf, size, off); - if (dev->pci_root.pci_root_acpi_uid_str) { - debug(DEBUG, "creating acpi_hid_ex dp hid:0x%08x uid:\"%s\"", - dev->pci_root.pci_root_acpi_hid, - dev->pci_root.pci_root_acpi_uid_str); - new = efidp_make_acpi_hid_ex(buf + off, size ? size - off : 0, - dev->pci_root.pci_root_acpi_hid, - 0, 0, "", - dev->pci_root.pci_root_acpi_uid_str, - ""); - if (new < 0) { - efi_error("efidp_make_acpi_hid_ex() failed"); - return new; - } - } else { - debug(DEBUG, "creating acpi_hid dp hid:0x%08x uid:0x%0"PRIx64, - dev->pci_root.pci_root_acpi_hid, - dev->pci_root.pci_root_acpi_uid); - new = efidp_make_acpi_hid(buf + off, size ? size - off : 0, - dev->pci_root.pci_root_acpi_hid, - dev->pci_root.pci_root_acpi_uid); - if (new < 0) { - efi_error("efidp_make_acpi_hid() failed"); - return new; - } - } - off += new; - sz += new; - debug(DEBUG, "creating PCI device path nodes"); for (unsigned int i = 0; i < dev->n_pci_devs; i++) { debug(DEBUG, "creating PCI device path node %u", i); diff --git a/src/linux.c b/src/linux.c index ef560753481..9f3a22f7025 100644 --- a/src/linux.c +++ b/src/linux.c @@ -272,6 +272,13 @@ device_free(struct device *dev) if (dev->probes) free(dev->probes); + if (dev->acpi_root.acpi_hid_str) + free(dev->acpi_root.acpi_hid_str); + if (dev->acpi_root.acpi_uid_str) + free(dev->acpi_root.acpi_uid_str); + if (dev->acpi_root.acpi_cid_str) + free(dev->acpi_root.acpi_cid_str); + if (dev->interface_type == network) { if (dev->ifname) free(dev->ifname); @@ -325,8 +332,8 @@ struct device HIDDEN goto err; } - dev->pci_root.pci_root_domain = 0xffff; - dev->pci_root.pci_root_bus = 0xff; + dev->pci_root.pci_domain = 0xffff; + dev->pci_root.pci_bus = 0xff; if (S_ISBLK(dev->stat.st_mode)) { dev->major = major(dev->stat.st_rdev); diff --git a/src/linux.h b/src/linux.h index 35951bb4d16..aa9e3d14a83 100644 --- a/src/linux.h +++ b/src/linux.h @@ -21,12 +21,18 @@ #ifndef _EFIBOOT_LINUX_H #define _EFIBOOT_LINUX_H +struct acpi_root_info { + uint32_t acpi_hid; + uint64_t acpi_uid; + uint32_t acpi_cid; + char *acpi_hid_str; + char *acpi_uid_str; + char *acpi_cid_str; +}; + struct pci_root_info { - uint16_t pci_root_domain; - uint8_t pci_root_bus; - uint32_t pci_root_acpi_hid; - uint64_t pci_root_acpi_uid; - char *pci_root_acpi_uid_str; + uint16_t pci_domain; + uint8_t pci_bus; }; struct pci_dev_info { @@ -121,6 +127,7 @@ struct device { char *disk_name; char *part_name; + struct acpi_root_info acpi_root; struct pci_root_info pci_root; unsigned int n_pci_devs; struct pci_dev_info *pci_dev; @@ -147,7 +154,7 @@ extern int HIDDEN set_disk_name(struct device *dev, const char * const fmt, ...) extern bool HIDDEN is_pata(struct device *dev); extern int HIDDEN make_blockdev_path(uint8_t *buf, ssize_t size, struct device *dev); - +extern int HIDDEN parse_acpi_hid_uid(struct device *dev, const char *fmt, ...); extern int HIDDEN eb_nvme_ns_id(int fd, uint32_t *ns_id); int HIDDEN get_sector_size(int filedes); -- 2.17.1