1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
31 bool is_efi_boot(void) {
32 return access("/sys/firmware/efi", F_OK) >= 0;
42 _cleanup_close_ int fd = -1;
43 _cleanup_free_ char *p = NULL;
54 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
55 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
58 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
62 if (fstat(fd, &st) < 0)
66 if (st.st_size > 4*1024*1024 + 4)
69 n = read(fd, &a, sizeof(a));
75 r = malloc(st.st_size - 4 + 2);
79 n = read(fd, r, (size_t) st.st_size - 4);
84 if (n != (ssize_t) st.st_size - 4) {
89 /* Always NUL terminate (2 bytes, to protect UTF-16) */
90 ((char*) r)[st.st_size - 4] = 0;
91 ((char*) r)[st.st_size - 4 + 1] = 0;
94 *size = (size_t) st.st_size - 4;
102 int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
103 _cleanup_free_ void *s = NULL;
108 r = efi_get_variable(vendor, name, NULL, &s, &ss);
112 x = utf16_to_utf8(s, ss);
120 static size_t utf16_size(const uint16_t *s) {
126 return (l+1) * sizeof(uint16_t);
129 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
136 const struct uuid *uuid = guid;
138 id128->bytes[0] = (uuid->u1 >> 24) & 0xff;
139 id128->bytes[1] = (uuid->u1 >> 16) & 0xff;
140 id128->bytes[2] = (uuid->u1 >> 8) & 0xff;
141 id128->bytes[3] = (uuid->u1) & 0xff;
142 id128->bytes[4] = (uuid->u2 >> 8) & 0xff;
143 id128->bytes[5] = (uuid->u2) & 0xff;
144 id128->bytes[6] = (uuid->u3 >> 8) & 0xff;
145 id128->bytes[7] = (uuid->u3) & 0xff;
146 memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
149 int efi_get_boot_option(
152 sd_id128_t *part_uuid,
167 uint8_t signature_type;
176 struct drive_path drive;
181 _cleanup_free_ uint8_t *buf = NULL;
183 struct boot_option *header;
187 sd_id128_t p_uuid = SD_ID128_NULL;
190 snprintf(boot_id, sizeof(boot_id), "Boot%04X", id);
191 err = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
194 if (l < sizeof(struct boot_option))
197 header = (struct boot_option *)buf;
198 title_size = utf16_size(header->title);
199 if (title_size > l - offsetof(struct boot_option, title))
202 s = utf16_to_utf8(header->title, title_size);
208 if (header->path_len > 0) {
212 dbuf = buf + offsetof(struct boot_option, title) + title_size;
214 while (dnext < header->path_len) {
215 struct device_path *dpath;
217 dpath = (struct device_path *)(dbuf + dnext);
218 if (dpath->length < 4)
221 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
222 if (dpath->type == 0x7f && dpath->sub_type == 0xff)
225 dnext += dpath->length;
227 /* Type 0x04 – Media Device Path */
228 if (dpath->type != 0x04)
231 /* Sub-Type 1 – Hard Drive */
232 if (dpath->sub_type == 0x01) {
233 /* 0x02 – GUID Partition Table */
234 if (dpath->drive.mbr_type != 0x02)
237 /* 0x02 – GUID signature */
238 if (dpath->drive.signature_type != 0x02)
241 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
245 /* Sub-Type 4 – File Path */
246 if (dpath->sub_type == 0x04) {
247 p = utf16_to_utf8(dpath->path, dpath->length-4);
267 int efi_get_boot_order(uint16_t **order) {
272 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
281 if ((l % sizeof(uint16_t) > 0) ||
282 (l / sizeof(uint16_t) > INT_MAX)) {
288 return (int) (l / sizeof(uint16_t));
291 static int boot_id_hex(const char s[4]) {
295 for (i = 0; i < 4; i++)
296 if (s[i] >= '0' && s[i] <= '9')
297 id |= (s[i] - '0') << (3 - i) * 4;
298 else if (s[i] >= 'A' && s[i] <= 'F')
299 id |= (s[i] - 'A' + 10) << (3 - i) * 4;
306 static int cmp_uint16(const void *_a, const void *_b) {
307 const uint16_t *a = _a, *b = _b;
317 int efi_get_boot_options(uint16_t **options) {
318 _cleanup_closedir_ DIR *dir = NULL;
320 uint16_t *list = NULL;
325 dir = opendir("/sys/firmware/efi/efivars/");
329 FOREACH_DIRENT(de, dir, r = -errno; goto fail) {
333 if (strncmp(de->d_name, "Boot", 4) != 0)
336 if (strlen(de->d_name) != 45)
339 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
342 id = boot_id_hex(de->d_name + 4);
346 t = realloc(list, (count + 1) * sizeof(uint16_t));
356 qsort(list, count, sizeof(uint16_t), cmp_uint16);
366 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
367 _cleanup_free_ char *j = NULL;
374 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
378 r = safe_atou64(j, &x);
386 static int get_boot_usec(usec_t *firmware, usec_t *loader) {
393 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
397 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
404 if (y > USEC_PER_HOUR)
413 int efi_get_boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_timestamp *loader) {
422 dual_timestamp_get(&_n);
426 r = get_boot_usec(&x, &y);
430 /* Let's convert this to timestamps where the firmware
431 * began/loader began working. To make this more confusing:
432 * since usec_t is unsigned and the kernel's monotonic clock
433 * begins at kernel initialization we'll actually initialize
434 * the monotonic timestamps here as negative of the actual
437 firmware->monotonic = y;
438 loader->monotonic = y - x;
440 a = n->monotonic + firmware->monotonic;
441 firmware->realtime = n->realtime > a ? n->realtime - a : 0;
443 a = n->monotonic + loader->monotonic;
444 loader->realtime = n->realtime > a ? n->realtime - a : 0;
449 int efi_get_loader_device_part_uuid(sd_id128_t *u) {
450 _cleanup_free_ char *p = NULL;
456 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
460 if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
461 &parsed[0], &parsed[1], &parsed[2], &parsed[3],
462 &parsed[4], &parsed[5], &parsed[6], &parsed[7],
463 &parsed[8], &parsed[9], &parsed[10], &parsed[11],
464 &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
467 for (i = 0; i < ELEMENTSOF(parsed); i++)
468 u->bytes[i] = parsed[i];