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/>.
33 bool is_efi_boot(void) {
34 return access("/sys/firmware/efi", F_OK) >= 0;
44 _cleanup_close_ int fd = -1;
45 _cleanup_free_ char *p = NULL;
56 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
57 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
60 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
64 if (fstat(fd, &st) < 0)
68 if (st.st_size > 4*1024*1024 + 4)
71 n = read(fd, &a, sizeof(a));
77 r = malloc(st.st_size - 4 + 2);
81 n = read(fd, r, (size_t) st.st_size - 4);
86 if (n != (ssize_t) st.st_size - 4) {
91 /* Always NUL terminate (2 bytes, to protect UTF-16) */
92 ((char*) r)[st.st_size - 4] = 0;
93 ((char*) r)[st.st_size - 4 + 1] = 0;
96 *size = (size_t) st.st_size - 4;
104 int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
105 _cleanup_free_ void *s = NULL;
110 r = efi_get_variable(vendor, name, NULL, &s, &ss);
114 x = utf16_to_utf8(s, ss);
122 static size_t utf16_size(const uint16_t *s) {
128 return (l+1) * sizeof(uint16_t);
131 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
138 const struct uuid *uuid = guid;
140 id128->bytes[0] = (uuid->u1 >> 24) & 0xff;
141 id128->bytes[1] = (uuid->u1 >> 16) & 0xff;
142 id128->bytes[2] = (uuid->u1 >> 8) & 0xff;
143 id128->bytes[3] = (uuid->u1) & 0xff;
144 id128->bytes[4] = (uuid->u2 >> 8) & 0xff;
145 id128->bytes[5] = (uuid->u2) & 0xff;
146 id128->bytes[6] = (uuid->u3 >> 8) & 0xff;
147 id128->bytes[7] = (uuid->u3) & 0xff;
148 memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
151 int efi_get_boot_option(
154 sd_id128_t *part_uuid,
169 uint8_t signature_type;
178 struct drive_path drive;
183 _cleanup_free_ uint8_t *buf = NULL;
185 struct boot_option *header;
189 sd_id128_t p_uuid = SD_ID128_NULL;
192 snprintf(boot_id, sizeof(boot_id), "Boot%04X", id);
193 err = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
196 if (l < sizeof(struct boot_option))
199 header = (struct boot_option *)buf;
200 title_size = utf16_size(header->title);
201 if (title_size > l - offsetof(struct boot_option, title))
204 s = utf16_to_utf8(header->title, title_size);
210 if (header->path_len > 0) {
214 dbuf = buf + offsetof(struct boot_option, title) + title_size;
216 while (dnext < header->path_len) {
217 struct device_path *dpath;
219 dpath = (struct device_path *)(dbuf + dnext);
220 if (dpath->length < 4)
223 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
224 if (dpath->type == 0x7f && dpath->sub_type == 0xff)
227 dnext += dpath->length;
229 /* Type 0x04 – Media Device Path */
230 if (dpath->type != 0x04)
233 /* Sub-Type 1 – Hard Drive */
234 if (dpath->sub_type == 0x01) {
235 /* 0x02 – GUID Partition Table */
236 if (dpath->drive.mbr_type != 0x02)
239 /* 0x02 – GUID signature */
240 if (dpath->drive.signature_type != 0x02)
243 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
247 /* Sub-Type 4 – File Path */
248 if (dpath->sub_type == 0x04) {
249 p = utf16_to_utf8(dpath->path, dpath->length-4);
269 int efi_get_boot_order(uint16_t **order) {
274 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
283 if ((l % sizeof(uint16_t) > 0) ||
284 (l / sizeof(uint16_t) > INT_MAX)) {
290 return (int) (l / sizeof(uint16_t));
293 static int boot_id_hex(const char s[4]) {
297 for (i = 0; i < 4; i++)
298 if (s[i] >= '0' && s[i] <= '9')
299 id |= (s[i] - '0') << (3 - i) * 4;
300 else if (s[i] >= 'A' && s[i] <= 'F')
301 id |= (s[i] - 'A' + 10) << (3 - i) * 4;
308 static int cmp_uint16(const void *_a, const void *_b) {
309 const uint16_t *a = _a, *b = _b;
311 return (int)*a - (int)*b;
314 int efi_get_boot_options(uint16_t **options) {
315 _cleanup_closedir_ DIR *dir = NULL;
317 uint16_t *list = NULL;
322 dir = opendir("/sys/firmware/efi/efivars/");
326 FOREACH_DIRENT(de, dir, r = -errno; goto fail) {
330 if (strncmp(de->d_name, "Boot", 4) != 0)
333 if (strlen(de->d_name) != 45)
336 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
339 id = boot_id_hex(de->d_name + 4);
343 t = realloc(list, (count + 1) * sizeof(uint16_t));
353 qsort(list, count, sizeof(uint16_t), cmp_uint16);
363 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
364 _cleanup_free_ char *j = NULL;
371 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
375 r = safe_atou64(j, &x);
383 static int get_boot_usec(usec_t *firmware, usec_t *loader) {
390 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
394 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
401 if (y > USEC_PER_HOUR)
410 int efi_get_boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_timestamp *loader) {
419 dual_timestamp_get(&_n);
423 r = get_boot_usec(&x, &y);
427 /* Let's convert this to timestamps where the firmware
428 * began/loader began working. To make this more confusing:
429 * since usec_t is unsigned and the kernel's monotonic clock
430 * begins at kernel initialization we'll actually initialize
431 * the monotonic timestamps here as negative of the actual
434 firmware->monotonic = y;
435 loader->monotonic = y - x;
437 a = n->monotonic + firmware->monotonic;
438 firmware->realtime = n->realtime > a ? n->realtime - a : 0;
440 a = n->monotonic + loader->monotonic;
441 loader->realtime = n->realtime > a ? n->realtime - a : 0;
446 int efi_get_loader_device_part_uuid(sd_id128_t *u) {
447 _cleanup_free_ char *p = NULL;
453 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
457 if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
458 &parsed[0], &parsed[1], &parsed[2], &parsed[3],
459 &parsed[4], &parsed[5], &parsed[6], &parsed[7],
460 &parsed[8], &parsed[9], &parsed[10], &parsed[11],
461 &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
464 for (i = 0; i < ELEMENTSOF(parsed); i++)
465 u->bytes[i] = parsed[i];