From be657aa40e9398dbe7f4ce746efe3921b4ebc504 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Mon, 4 Dec 2017 17:27:57 -0500 Subject: [PATCH] Add NVDIMM-P support --- src/creator.c | 10 ++- src/dp-message.c | 25 +++++++ src/include/efivar/efivar-dp.h | 8 +++ src/libefivar.map.in | 4 ++ src/linux.c | 157 +++++++++++++++++++++++++++++++++-------- src/linux.h | 3 +- 6 files changed, 174 insertions(+), 33 deletions(-) diff --git a/src/creator.c b/src/creator.c index 6747eee..c8739f4 100644 --- a/src/creator.c +++ b/src/creator.c @@ -239,6 +239,9 @@ efi_va_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size, off += sz; } + if (info.interface_type == nd_pmem) + options |= EFIBOOT_ABBREV_FILE; + if (!(options & EFIBOOT_ABBREV_FILE)) { int disk_fd; int saved_errno; @@ -362,7 +365,12 @@ efi_generate_file_device_path(uint8_t *buf, ssize_t size, va_start(ap, options); - ret = efi_va_generate_file_device_path_from_esp(buf, size, + if (!strcmp(parent_devpath, "/dev/block")) + ret = efi_va_generate_file_device_path_from_esp(buf, size, + child_devpath, rc, + relpath, options, ap); + else + ret = efi_va_generate_file_device_path_from_esp(buf, size, parent_devpath, rc, relpath, options, ap); saved_errno = errno; diff --git a/src/dp-message.c b/src/dp-message.c index 235bc7f..eada00f 100644 --- a/src/dp-message.c +++ b/src/dp-message.c @@ -622,6 +622,11 @@ _format_message_dn(char *buf, size_t size, const_efidp dp) format(buf, size, off, "Dns", ")"); break; } + case EFIDP_MSG_NVDIMM: + format(buf, size, off, "NVDIMM", "NVDIMM("); + format_guid(buf, size, off, "NVDIMM", &dp->nvdimm.uuid); + format(buf, size, off, "NVDIMM", ")"); + break; default: format(buf, size, off, "Msg", "Msg(%d,", dp->subtype); format_hex(buf, size, off, "Msg", (uint8_t *)dp+4, @@ -802,3 +807,23 @@ efidp_make_sas(uint8_t *buf, ssize_t size, uint64_t sas_address) return sz; } + +ssize_t +__attribute__((__visibility__ ("default"))) +efidp_make_nvdimm(uint8_t *buf, ssize_t size, efi_guid_t *uuid) +{ + efidp_nvdimm *nvdimm = (efidp_nvdimm *)buf; + ssize_t req = sizeof (*nvdimm); + ssize_t sz; + + sz = efidp_make_generic(buf, size, EFIDP_MESSAGE_TYPE, + EFIDP_MSG_NVDIMM, sizeof (*nvdimm)); + if (size && sz == req) { + memcpy(&nvdimm->uuid, uuid, sizeof(*uuid)); + } + + if (sz < 0) + efi_error("efidp_make_generic failed"); + + return sz; +} diff --git a/src/include/efivar/efivar-dp.h b/src/include/efivar/efivar-dp.h index eb644fa..9bbb5de 100644 --- a/src/include/efivar/efivar-dp.h +++ b/src/include/efivar/efivar-dp.h @@ -705,6 +705,13 @@ typedef struct { efi_ip_addr_t addrs[]; } EFIVAR_PACKED efidp_dns; +#define EFIDP_MSG_NVDIMM 0x20 +typedef struct { + efidp_header header; + efi_guid_t uuid; +} EFIVAR_PACKED efidp_nvdimm; +extern ssize_t efidp_make_nvdimm(uint8_t *buf, ssize_t size, efi_guid_t *uuid); + /* Each media subtype */ #define EFIDP_MEDIA_HD 0x1 typedef struct { @@ -869,6 +876,7 @@ typedef union { efidp_emmc emmc; efidp_btle btle; efidp_dns dns; + efidp_nvdimm nvdimm; efidp_hd hd; efidp_cdrom cdrom; efidp_media_vendor media_vendor; diff --git a/src/libefivar.map.in b/src/libefivar.map.in index a95a505..6677266 100644 --- a/src/libefivar.map.in +++ b/src/libefivar.map.in @@ -114,3 +114,7 @@ LIBEFIVAR_1.30 { LIBEFIVAR_1.32 { global: efi_guid_ux_capsule; } LIBEFIVAR_1.30; + +LIBEFIVAR_1.33 { + global: efidp_make_nvdimm; +} LIBEFIVAR_1.32; diff --git a/src/linux.c b/src/linux.c index 143f2c1..1b24006 100644 --- a/src/linux.c +++ b/src/linux.c @@ -77,7 +77,13 @@ set_disk_and_part_name(struct disk_info *info) * If there's a better way to figure this out, it'd be good, because * I don't want to have to change this for every new disk type... */ - if (!strcmp(penultimate, "block")) { + if (!strncmp(ultimate, "pmem", 4)) { + if (!info->disk_name) { + info->disk_name = strdup(ultimate); + if (!info->disk_name) + return -1; + } + } else if (!strcmp(penultimate, "block")) { if (!info->disk_name) { info->disk_name = strdup(ultimate); if (!info->disk_name) @@ -204,6 +210,27 @@ find_parent_devpath(const char * const child, char **parent) return 0; } +/* NVDIMM-P paths */ +static int +sysfs_test_pmem(const char *buf) +{ + char *driverbuf = NULL; + int rc; + + rc = sysfs_readlink(&driverbuf, + "/sys/dev/block/%s/device/driver", buf); + if (rc < 0 || !driverbuf) + return 0; + + char *driver = strrchr(driverbuf, '/'); + if (!driver || !*driver) + return -1; + driver+=1; + if (!strcmp(driver, "nd_pmem")) + return 1; + return 0; +} + static int sysfs_test_nvme(const char *buf, ssize_t size) { @@ -328,6 +355,46 @@ sysfs_sata_get_port_info(uint32_t print_id, struct disk_info *info) return 0; } +/* pmem12s -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s + * dev: 259:0 + * device -> ../../../btt12.1 + * device/uuid: 0cee166e-dd56-4bc2-99d2-2544b69025b8 + * 259:0 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s + * + * pmem12.1s -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.2/block/pmem12.1s + * dev: 259:1 + * device -> ../../../btt12.2 + * device/uuid: 78d94521-91f7-47db-b3a7-51b764281940 + * 259:1 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.2/block/pmem12.1s + * + * pmem12.2 -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/pfn12.1/block/pmem12.2 + * dev: 259:2 + * device -> ../../../pfn12.1 + * device/uuid: 829c5205-89a5-4581-9819-df7d7754c622 + * 259:2 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/pfn12.1/block/pmem12.2 + */ +static ssize_t +sysfs_parse_pmem(uint8_t *buf, ssize_t size, ssize_t *off, + const char *pbuf, ssize_t psize __attribute__((__unused__)), + ssize_t *poff __attribute__((__unused__)), + struct disk_info *info) +{ + uint8_t *filebuf = NULL; + int rc; + + rc = read_sysfs_file(&filebuf, + "/sys/class/block/%s/device/uuid", pbuf); + if ((rc < 0 && errno == ENOENT) || filebuf == NULL) + return -1; + + rc = efi_str_to_guid((char *)filebuf, &info->nvdimm_label); + if (rc < 0) + return -1; + + *off = efidp_make_nvdimm(buf, size, &info->nvdimm_label); + return *off; +} + static ssize_t sysfs_parse_nvme(uint8_t *buf, ssize_t size, ssize_t *off, const char *pbuf, ssize_t psize, ssize_t *poff, @@ -764,44 +831,72 @@ make_blockdev_path(uint8_t *buf, ssize_t size, struct disk_info *info) } /* - * the sysfs path basically looks like: + * the sysfs path basically looks like one of: * ../../devices/pci$PCI_STUFF/$BLOCKDEV_STUFF/block/$DISK/$PART + * ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s */ - rc = sscanf(linkbuf+loff, "../../devices/%n", &lsz); - if (rc != 0) + rc = sysfs_test_pmem(linkbuf+loff); + if (rc < 0) { + efi_error("sysfs_test_pmem(\"%s\") failed", linkbuf+loff); return -1; - loff += lsz; + } + else if (rc > 0) { + ssize_t linksz=0; + info->interface_type = nd_pmem; + rc = sysfs_parse_pmem(buf+off, size?size-off:0, &sz, + linkbuf+loff, PATH_MAX-off, + &linksz, info); + if (rc < 0) + return -1; + loff += linksz; + off += sz; + found = 1; + } - ssize_t tmplsz=0; - sz = make_pci_path(buf, size, linkbuf+loff, &tmplsz); - if (sz < 0) - return -1; - loff += tmplsz; - off += sz; + if (!found) { + rc = sscanf(linkbuf+loff, "../../devices/%n", &lsz); + if (rc != 0) { + efi_error("scanf(\"%s\", %s, &lz) failed", + linkbuf+loff, "../../devices/%n"); + return -1; + } + loff += lsz; - char *tmppath = strdupa(linkbuf); - if (!tmppath) - return -1; - tmppath[loff] = '\0'; - rc = sysfs_readlink(&driverbuf, "/sys/dev/block/%s/driver", tmppath); - if (rc < 0 || !driverbuf) - return -1; + ssize_t tmplsz=0; + sz = make_pci_path(buf, size, linkbuf+loff, &tmplsz); + if (sz < 0) + return -1; + loff += tmplsz; + off += sz; - char *driver = strrchr(driverbuf, '/'); - if (!driver || !*driver) - return -1; - driver+=1; + char *tmppath; + tmppath = strdupa(linkbuf); + if (!tmppath) + return -1; + tmppath[loff] = '\0'; + rc = sysfs_readlink(&driverbuf, "/sys/dev/block/%s/driver", + tmppath); + if (rc < 0 || !driverbuf) + return -1; - if (!strncmp(driver, "pata_", 5) || !(strcmp(driver, "ata_piix"))) - info->interface_type = ata; + char *driver = strrchr(driverbuf, '/'); + if (!driver || !*driver) + return -1; + driver+=1; + + if (!strncmp(driver, "pata_", 5) || + !(strcmp(driver, "ata_piix"))) + info->interface_type = ata; + } - if (info->interface_type == interface_type_unknown || - info->interface_type == atapi || - info->interface_type == usb || - info->interface_type == i1394 || - info->interface_type == fibre || - info->interface_type == i2o || - info->interface_type == md) { + if (!found && + (info->interface_type == interface_type_unknown || + info->interface_type == atapi || + info->interface_type == usb || + info->interface_type == i1394 || + info->interface_type == fibre || + info->interface_type == i2o || + info->interface_type == md)) { uint32_t tosser; int tmpoff; diff --git a/src/linux.h b/src/linux.h index 7f7bc86..a42b920 100644 --- a/src/linux.h +++ b/src/linux.h @@ -86,6 +86,7 @@ struct disk_info { struct sas_info sas_info; struct sata_info sata_info; struct nvme_info nvme_info; + efi_guid_t nvdimm_label; }; char *disk_name; @@ -96,7 +97,7 @@ enum _bus_type {bus_type_unknown, isa, pci}; enum _interface_type {interface_type_unknown, ata, atapi, scsi, sata, sas, usb, i1394, fibre, i2o, md, - virtblk, nvme}; + virtblk, nvme, nd_pmem}; extern int eb_disk_info_from_fd(int fd, struct disk_info *info); extern int set_disk_and_part_name(struct disk_info *info); -- 2.11.0