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/>.
30 bool is_efi_boot(void) {
31 return access("/sys/firmware/efi", F_OK) >= 0;
41 _cleanup_close_ int fd = -1;
42 _cleanup_free_ char *p = NULL;
53 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
54 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
57 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
61 if (fstat(fd, &st) < 0)
65 if (st.st_size > 4*1024*1024 + 4)
68 n = read(fd, &a, sizeof(a));
74 r = malloc(st.st_size - 4 + 2);
78 n = read(fd, r, (size_t) st.st_size - 4);
83 if (n != (ssize_t) st.st_size - 4) {
88 /* Always NUL terminate (2 bytes, to protect UTF-16) */
89 ((char*) r)[st.st_size - 4] = 0;
90 ((char*) r)[st.st_size - 4 + 1] = 0;
93 *size = (size_t) st.st_size - 4;
101 int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
102 _cleanup_free_ void *s = NULL;
107 r = efi_get_variable(vendor, name, NULL, &s, &ss);
111 x = utf16_to_utf8(s, ss);
119 static size_t utf16_size(const uint16_t *s) {
125 return (l+1) * sizeof(uint16_t);
128 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
135 const struct uuid *uuid = guid;
137 id128->bytes[0] = (uuid->u1 >> 24) & 0xff;
138 id128->bytes[1] = (uuid->u1 >> 16) & 0xff;
139 id128->bytes[2] = (uuid->u1 >> 8) & 0xff;
140 id128->bytes[3] = (uuid->u1) & 0xff;
141 id128->bytes[4] = (uuid->u2 >> 8) & 0xff;
142 id128->bytes[5] = (uuid->u2) & 0xff;
143 id128->bytes[6] = (uuid->u3 >> 8) & 0xff;
144 id128->bytes[7] = (uuid->u3) & 0xff;
145 memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
148 int efi_get_boot_option(
151 sd_id128_t *part_uuid,
166 uint8_t signature_type;
175 struct drive_path drive;
180 _cleanup_free_ uint8_t *buf = NULL;
182 struct boot_option *header;
186 sd_id128_t p_uuid = SD_ID128_NULL;
189 snprintf(boot_id, sizeof(boot_id), "Boot%04X", id);
190 err = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
193 if (l < sizeof(struct boot_option))
196 header = (struct boot_option *)buf;
197 title_size = utf16_size(header->title);
198 if (title_size > l - offsetof(struct boot_option, title))
201 s = utf16_to_utf8(header->title, title_size);
207 if (header->path_len > 0) {
211 dbuf = buf + offsetof(struct boot_option, title) + title_size;
213 while (dnext < header->path_len) {
214 struct device_path *dpath;
216 dpath = (struct device_path *)(dbuf + dnext);
217 if (dpath->length < 4)
220 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
221 if (dpath->type == 0x7f && dpath->sub_type == 0xff)
224 dnext += dpath->length;
226 /* Type 0x04 – Media Device Path */
227 if (dpath->type != 0x04)
230 /* Sub-Type 1 – Hard Drive */
231 if (dpath->sub_type == 0x01) {
232 /* 0x02 – GUID Partition Table */
233 if (dpath->drive.mbr_type != 0x02)
236 /* 0x02 – GUID signature */
237 if (dpath->drive.signature_type != 0x02)
240 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
244 /* Sub-Type 4 – File Path */
245 if (dpath->sub_type == 0x04) {
246 p = utf16_to_utf8(dpath->path, dpath->length-4);
266 int efi_get_boot_order(uint16_t **order) {
271 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
280 if ((l % sizeof(uint16_t) > 0) ||
281 (l / sizeof(uint16_t) > INT_MAX)) {
287 return (int) (l / sizeof(uint16_t));
290 int efi_get_boot_options(uint16_t **options) {
291 _cleanup_closedir_ DIR *dir = NULL;
293 uint16_t *list = NULL;
298 dir = opendir("/sys/firmware/efi/efivars/");
302 while ((de = readdir(dir))) {
307 if (strncmp(de->d_name, "Boot", 4) != 0)
310 n = strlen(de->d_name);
314 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
322 if (!isdigit(a) || !isdigit(b) || !isdigit(c) || !isdigit(d))
325 t = realloc(list, (count + 1) * sizeof(uint16_t));
332 list[count ++] = (a - '0') * 1000 + (b - '0') * 100 + (c - '0') * 10 + (d - '0');
340 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
341 _cleanup_free_ void *i = NULL;
342 _cleanup_free_ char *j = NULL;
350 r = efi_get_variable(EFI_VENDOR_LOADER, name, NULL, &i, &is);
354 j = utf16_to_utf8(i, is);
358 r = safe_atou64(j, &x);
366 static int get_boot_usec(usec_t *firmware, usec_t *loader) {
373 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
377 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
384 if (y > USEC_PER_HOUR)
393 int efi_get_boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_timestamp *loader) {
402 dual_timestamp_get(&_n);
406 r = get_boot_usec(&x, &y);
410 /* Let's convert this to timestamps where the firmware
411 * began/loader began working. To make this more confusing:
412 * since usec_t is unsigned and the kernel's monotonic clock
413 * begins at kernel initialization we'll actually initialize
414 * the monotonic timestamps here as negative of the actual
417 firmware->monotonic = y;
418 loader->monotonic = y - x;
420 a = n->monotonic + firmware->monotonic;
421 firmware->realtime = n->realtime > a ? n->realtime - a : 0;
423 a = n->monotonic + loader->monotonic;
424 loader->realtime = n->realtime > a ? n->realtime - a : 0;
429 int efi_get_loader_device_part_uuid(sd_id128_t *u) {
430 _cleanup_free_ void *s = NULL;
431 _cleanup_free_ char *p = NULL;
438 r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", NULL, &s, &ss);
442 p = utf16_to_utf8(s, ss);
446 if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
447 &parsed[0], &parsed[1], &parsed[2], &parsed[3],
448 &parsed[4], &parsed[5], &parsed[6], &parsed[7],
449 &parsed[8], &parsed[9], &parsed[10], &parsed[11],
450 &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
453 for (i = 0; i < ELEMENTSOF(parsed); i++)
454 u->bytes[i] = parsed[i];