Blob Blame Raw
From e2f68c8f9f4fab48f1ef3a4585932f757593fa92 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
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 <pjones@redhat.com>
---
 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "fix_coverity.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#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