Add NVDIMM support Re-written linux interface parser to handle how devices are partitioned better, and for cleaner code, with one file per device type. lots of verbosity updates better CI analysis with clang's analyzer as well as coverity Better handling of immutable bits in sysfs LIBEFIVAR_OPS=help lots of code cleanups. Signed-off-by: Peter Jones <pjones@redhat.com>
392 lines
14 KiB
Diff
392 lines
14 KiB
Diff
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 12/34] 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
|
|
|