2 * libefiboot - library for the manipulation of EFI boot variables
3 * Copyright 2012-2018 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License as
7 * published by the Free Software Foundation; either version 2.1 of the
8 * License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "fix_coverity.h"
32 * support for ACPI-like platform root hub and devices
34 * various devices /sys/dev/block/$major:$minor start with:
35 * maj:min -> ../../devices/ACPI0000:00/$PCI_DEVICES/$BLOCKDEV_STUFF/block/$DISK/$PART
36 * i.e.: APMC0D0D:00/ata1/host0/target0:0:0/0:0:0:0/block/sda
37 * ^ root hub ^blockdev stuff
39 * maj:min -> ../../devices/ACPI0000:00/$PCI_DEVICES/$BLOCKDEV_STUFF/block/$DISK/$PART
40 * i.e.: APMC0D0D:00/0000:00:1d.0/0000:05:00.0/ata1/host0/target0:0:0/0:0:0:0/block/sda
41 * ^ root hub ^pci dev ^pci dev ^ blockdev stuff
44 parse_acpi_root(struct device *dev, const char *current, const char *root UNUSED)
50 char *acpi_header = NULL;
53 const char *devpart = current;
56 pos = strlen(current);
57 spaces = alloca(pos+1);
58 memset(spaces, ' ', pos+1);
65 * find the ACPI root dunno0 and dunno1; they basically look like:
68 * This is annoying because "/%04ms%h:%hhx/" won't bind from the right
71 rc = sscanf(devpart, "../../devices/platform/%n", &pos);
72 debug("devpart:\"%s\" rc:%d pos:%d", devpart, rc, pos);
73 if (rc != 0 || pos < 1)
78 * If it's too short to be A0000:00, it's not an ACPI string
80 if (strlen(devpart) < 8)
83 colon = strchr(devpart, ':');
86 pos = colon - devpart;
89 * If colon doesn't point at something between one of these:
90 * A0000:00 ACPI0000:00
92 * Then it's not an ACPI string.
94 if (pos < 5 || pos > 8)
97 dev->acpi_root.acpi_hid_str = strndup(devpart, pos + 1);
98 if (!dev->acpi_root.acpi_hid_str) {
99 efi_error("Could not allocate memory");
102 dev->acpi_root.acpi_hid_str[pos] = 0;
103 debug("acpi_hid_str:\"%s\"", dev->acpi_root.acpi_hid_str);
106 debug("devpart:\"%s\" rc:%d pos:%d", devpart, rc, pos);
107 acpi_header = strndupa(devpart, pos);
110 acpi_header[pos] = 0;
111 debug("devpart:\"%s\" acpi_header:\"%s\"", devpart, acpi_header);
115 * If we can't find these numbers, it's not an ACPI string
117 rc = sscanf(devpart, "%hx:%hhx/%n", &pad0, &pad1, &pos);
119 efi_error("Could not parse ACPI path \"%s\"", devpart);
122 debug("devpart:\"%s\" parsed:%04hx:%02hhx pos:%d rc:%d",
123 devpart, pad0, pad1, pos, rc);
127 rc = parse_acpi_hid_uid(dev, "devices/platform/%s%04hX:%02hhX",
128 acpi_header, pad0, pad1);
129 debug("rc:%d acpi_header:%s pad0:%04hX pad1:%02hhX",
130 rc, acpi_header, pad0, pad1);
131 if (rc < 0 && errno == ENOENT) {
132 rc = parse_acpi_hid_uid(dev, "devices/platform/%s%04hx:%02hhx",
133 acpi_header, pad0, pad1);
134 debug("rc:%d acpi_header:%s pad0:%04hx pad1:%02hhx",
135 rc, acpi_header, pad0, pad1);
138 efi_error("Could not parse hid/uid");
141 debug("Parsed HID:0x%08x UID:0x%"PRIx64" uidstr:\"%s\" path:\"%s\"",
142 dev->acpi_root.acpi_hid, dev->acpi_root.acpi_uid,
143 dev->acpi_root.acpi_uid_str,
144 dev->acpi_root.acpi_cid_str);
146 return devpart - current;
150 dp_create_acpi_root(struct device *dev,
151 uint8_t *buf, ssize_t size, ssize_t off)
153 ssize_t sz = 0, new = 0;
155 debug("entry buf:%p size:%zd off:%zd", buf, size, off);
157 if (dev->acpi_root.acpi_uid_str || dev->acpi_root.acpi_cid_str) {
158 debug("creating acpi_hid_ex dp hid:0x%08x uid:0x%"PRIx64" uidstr:\"%s\" cidstr:\"%s\"",
159 dev->acpi_root.acpi_hid, dev->acpi_root.acpi_uid,
160 dev->acpi_root.acpi_uid_str, dev->acpi_root.acpi_cid_str);
161 new = efidp_make_acpi_hid_ex(buf + off, size ? size - off : 0,
162 dev->acpi_root.acpi_hid,
163 dev->acpi_root.acpi_uid,
164 dev->acpi_root.acpi_cid,
165 dev->acpi_root.acpi_hid_str,
166 dev->acpi_root.acpi_uid_str,
167 dev->acpi_root.acpi_cid_str);
169 efi_error("efidp_make_acpi_hid_ex() failed");
173 debug("creating acpi_hid dp hid:0x%08x uid:0x%0"PRIx64,
174 dev->acpi_root.acpi_hid,
175 dev->acpi_root.acpi_uid);
176 new = efidp_make_acpi_hid(buf + off, size ? size - off : 0,
177 dev->acpi_root.acpi_hid,
178 dev->acpi_root.acpi_uid);
180 efi_error("efidp_make_acpi_hid() failed");
186 debug("returning %zd", sz);
190 enum interface_type acpi_root_iftypes[] = { acpi_root, unknown };
192 struct dev_probe HIDDEN acpi_root_parser = {
194 .iftypes = acpi_root_iftypes,
195 .flags = DEV_PROVIDES_ROOT,
196 .parse = parse_acpi_root,
197 .create = dp_create_acpi_root,