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