OSDN Git Service

Update abixml for newer libabigail
[android-x86/external-efivar.git] / src / linux-pmem.c
1 /*
2  * libefiboot - library for the manipulation of EFI boot variables
3  * Copyright 2012-2018 Red Hat, Inc.
4  *
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.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #include "fix_coverity.h"
22
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <inttypes.h>
26 #include <stdint.h>
27 #include <unistd.h>
28
29 #include "efiboot.h"
30
31 /*
32  * support NVDIMM-P (pmem / btt) devices
33  * (does not include NVDIMM-${ANYTHING_ELSE})
34  *
35  * /sys/dev/block/$major:$minor looks like:
36  * 259:0 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region9/btt9.0/block/pmem9s
37  * 259:1 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region11/btt11.0/block/pmem11s
38  * 259:3 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region11/btt11.0/block/pmem11s/pmem11s1
39  *
40  * /sys/dev/block/259:0/device looks like:
41  * device -> ../../../btt9.0
42  * /sys/dev/block/259:1/device looks like:
43  * device -> ../../../btt11.0
44  *
45  * /sys/dev/block/259:1/partition looks like:
46  * $ cat partition
47  * 1
48  *
49  * /sys/dev/block/259:0/uuid looks like:
50  * $ cat uuid
51  * 6e54091e-7476-47ac-824b-b6dd69878661
52  *
53  * pmem12s -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
54  * dev: 259:0
55  * device -> ../../../btt12.1
56  * device/uuid: 0cee166e-dd56-4bc2-99d2-2544b69025b8
57  * 259:0 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
58  *
59  * pmem12.1s -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.2/block/pmem12.1s
60  * dev: 259:1
61  * device -> ../../../btt12.2
62  * device/uuid: 78d94521-91f7-47db-b3a7-51b764281940
63  * 259:1 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.2/block/pmem12.1s
64  *
65  * pmem12.2 -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/pfn12.1/block/pmem12.2
66  * dev: 259:2
67  * device -> ../../../pfn12.1
68  * device/uuid: 829c5205-89a5-4581-9819-df7d7754c622
69  * 259:2 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/pfn12.1/block/pmem12.2
70  */
71
72 static ssize_t
73 parse_pmem(struct device *dev, const char *current, const char *root UNUSED)
74 {
75         uint8_t *filebuf = NULL;
76         uint8_t system, sysbus, acpi_id;
77         uint16_t pnp_id;
78         int ndbus, region, btt_region_id, btt_id, rc, pos;
79         char *namespace = NULL;
80
81         debug("entry");
82
83         if (!strcmp(dev->driver, "nd_pmem")) {
84                 ;
85 #if 0 /* dunno */
86         } else if (!strcmp(dev->driver, "nd_blk")) {
87                 /* dunno */
88                 dev->inteface_type = scsi;
89 #endif
90         } else {
91                 /*
92                  * not a pmem device
93                  */
94                 return 0;
95         }
96
97         /*
98          * We're not actually using any of the values here except pos (our
99          * return value), but rather just being paranoid that this is the sort
100          * of device we care about.
101          *
102          * 259:0 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
103          */
104         rc = sscanf(current,
105                     "../../devices/LNXSYSTM:%hhx/LNXSYBUS:%hhx/ACPI%hx:%hhx/ndbus%d/region%d/btt%d.%d/%n",
106                     &system, &sysbus, &pnp_id, &acpi_id, &ndbus, &region,
107                     &btt_region_id, &btt_id, &pos);
108         if (rc < 8)
109                 return 0;
110
111         /*
112          * but the UUID we really do need to have.
113          */
114         rc = read_sysfs_file(&filebuf,
115                              "class/block/%s/device/namespace", dev->disk_name);
116         if ((rc < 0 && errno == ENOENT) || filebuf == NULL)
117                 return -1;
118
119         rc = sscanf((char *)filebuf, "%ms[^\n]\n", &namespace);
120         if (rc != 1 || namespace == NULL)
121                 return -1;
122
123         filebuf = NULL;
124         debug("nvdimm namespace is \"%s\"", namespace);
125         rc = read_sysfs_file(&filebuf, "bus/nd/devices/%s/uuid", namespace);
126         free(namespace);
127         if (rc < 0 || filebuf == NULL)
128                 return -1;
129
130         rc = efi_str_to_guid((char *)filebuf,
131                              &dev->nvdimm_info.namespace_label);
132         if (rc < 0)
133                 return -1;
134
135         filebuf = NULL;
136         rc = read_sysfs_file(&filebuf, "class/block/%s/device/uuid",
137                              dev->disk_name);
138         if (rc < 0 || filebuf == NULL)
139                 return -1;
140
141         rc = efi_str_to_guid((char *)filebuf,
142                              &dev->nvdimm_info.nvdimm_label);
143         if (rc < 0)
144                 return -1;
145
146         /*
147          * Right now it's not clear what encoding NVDIMM($uuid) gets in the
148          * binary format, so this will be in the mixed endian format EFI GUIDs
149          * are in (33221100-1100-1100-0011-223344556677) unless you set this
150          * variable.
151          */
152         if (getenv("LIBEFIBOOT_SWIZZLE_PMEM_UUID") != NULL) {
153                 swizzle_guid_to_uuid(&dev->nvdimm_info.namespace_label);
154                 swizzle_guid_to_uuid(&dev->nvdimm_info.nvdimm_label);
155         }
156
157         dev->interface_type = nd_pmem;
158
159         return pos;
160 }
161
162 static ssize_t
163 dp_create_pmem(struct device *dev,
164                uint8_t *buf, ssize_t size, ssize_t off)
165 {
166         ssize_t sz, sz1;
167
168         debug("entry");
169
170         sz = efidp_make_nvdimm(buf + off, size ? size - off : 0,
171                                &dev->nvdimm_info.namespace_label);
172         if (sz < 0)
173                 return sz;
174         off += sz;
175         sz1 = efidp_make_nvdimm(buf + off, size ? size - off : 0,
176                                 &dev->nvdimm_info.nvdimm_label);
177         if (sz1 < 0)
178                 return sz1;
179
180         return sz + sz1;
181 }
182
183 enum interface_type pmem_iftypes[] = { nd_pmem, unknown };
184
185 struct dev_probe HIDDEN pmem_parser = {
186         .name = "pmem",
187         .iftypes = pmem_iftypes,
188         .flags = DEV_PROVIDES_ROOT|DEV_PROVIDES_HD,
189         .parse = parse_pmem,
190         .create = dp_create_pmem,
191 };