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/>.
27 #include "acpi-fpdt.h"
34 bool is_efi_boot(void) {
35 return access("/sys/firmware/efi", F_OK) >= 0;
38 static int read_flag(const char *varname) {
40 _cleanup_free_ void *v = NULL;
44 r = efi_get_variable(EFI_VENDOR_GLOBAL, varname, NULL, &v, &s);
56 int is_efi_secure_boot(void) {
57 return read_flag("SecureBoot");
60 int is_efi_secure_boot_setup_mode(void) {
61 return read_flag("SetupMode");
71 _cleanup_close_ int fd = -1;
72 _cleanup_free_ char *p = NULL;
83 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
84 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
87 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
91 if (fstat(fd, &st) < 0)
95 if (st.st_size > 4*1024*1024 + 4)
98 n = read(fd, &a, sizeof(a));
104 r = malloc(st.st_size - 4 + 2);
108 n = read(fd, r, (size_t) st.st_size - 4);
113 if (n != (ssize_t) st.st_size - 4) {
118 /* Always NUL terminate (2 bytes, to protect UTF-16) */
119 ((char*) r)[st.st_size - 4] = 0;
120 ((char*) r)[st.st_size - 4 + 1] = 0;
123 *size = (size_t) st.st_size - 4;
131 int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
132 _cleanup_free_ void *s = NULL;
137 r = efi_get_variable(vendor, name, NULL, &s, &ss);
141 x = utf16_to_utf8(s, ss);
149 static size_t utf16_size(const uint16_t *s) {
155 return (l+1) * sizeof(uint16_t);
158 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
165 const struct uuid *uuid = guid;
167 id128->bytes[0] = (uuid->u1 >> 24) & 0xff;
168 id128->bytes[1] = (uuid->u1 >> 16) & 0xff;
169 id128->bytes[2] = (uuid->u1 >> 8) & 0xff;
170 id128->bytes[3] = (uuid->u1) & 0xff;
171 id128->bytes[4] = (uuid->u2 >> 8) & 0xff;
172 id128->bytes[5] = (uuid->u2) & 0xff;
173 id128->bytes[6] = (uuid->u3 >> 8) & 0xff;
174 id128->bytes[7] = (uuid->u3) & 0xff;
175 memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
178 int efi_get_boot_option(
181 sd_id128_t *part_uuid,
196 uint8_t signature_type;
205 struct drive_path drive;
210 _cleanup_free_ uint8_t *buf = NULL;
212 struct boot_option *header;
216 sd_id128_t p_uuid = SD_ID128_NULL;
219 snprintf(boot_id, sizeof(boot_id), "Boot%04X", id);
220 err = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
223 if (l < sizeof(struct boot_option))
226 header = (struct boot_option *)buf;
227 title_size = utf16_size(header->title);
228 if (title_size > l - offsetof(struct boot_option, title))
232 s = utf16_to_utf8(header->title, title_size);
239 if (header->path_len > 0) {
243 dbuf = buf + offsetof(struct boot_option, title) + title_size;
245 while (dnext < header->path_len) {
246 struct device_path *dpath;
248 dpath = (struct device_path *)(dbuf + dnext);
249 if (dpath->length < 4)
252 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
253 if (dpath->type == 0x7f && dpath->sub_type == 0xff)
256 dnext += dpath->length;
258 /* Type 0x04 – Media Device Path */
259 if (dpath->type != 0x04)
262 /* Sub-Type 1 – Hard Drive */
263 if (dpath->sub_type == 0x01) {
264 /* 0x02 – GUID Partition Table */
265 if (dpath->drive.mbr_type != 0x02)
268 /* 0x02 – GUID signature */
269 if (dpath->drive.signature_type != 0x02)
273 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
277 /* Sub-Type 4 – File Path */
278 if (dpath->sub_type == 0x04 && !p && path) {
279 p = utf16_to_utf8(dpath->path, dpath->length-4);
299 int efi_get_boot_order(uint16_t **order) {
304 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
313 if ((l % sizeof(uint16_t) > 0) ||
314 (l / sizeof(uint16_t) > INT_MAX)) {
320 return (int) (l / sizeof(uint16_t));
323 static int boot_id_hex(const char s[4]) {
327 for (i = 0; i < 4; i++)
328 if (s[i] >= '0' && s[i] <= '9')
329 id |= (s[i] - '0') << (3 - i) * 4;
330 else if (s[i] >= 'A' && s[i] <= 'F')
331 id |= (s[i] - 'A' + 10) << (3 - i) * 4;
338 static int cmp_uint16(const void *_a, const void *_b) {
339 const uint16_t *a = _a, *b = _b;
341 return (int)*a - (int)*b;
344 int efi_get_boot_options(uint16_t **options) {
345 _cleanup_closedir_ DIR *dir = NULL;
347 uint16_t *list = NULL;
352 dir = opendir("/sys/firmware/efi/efivars/");
356 FOREACH_DIRENT(de, dir, r = -errno; goto fail) {
360 if (strncmp(de->d_name, "Boot", 4) != 0)
363 if (strlen(de->d_name) != 45)
366 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
369 id = boot_id_hex(de->d_name + 4);
373 t = realloc(list, (count + 1) * sizeof(uint16_t));
383 qsort_safe(list, count, sizeof(uint16_t), cmp_uint16);
393 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
394 _cleanup_free_ char *j = NULL;
401 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
405 r = safe_atou64(j, &x);
413 int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) {
420 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
424 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
431 if (y > USEC_PER_HOUR)
440 int efi_loader_get_device_part_uuid(sd_id128_t *u) {
441 _cleanup_free_ char *p = NULL;
447 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
451 if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
452 &parsed[0], &parsed[1], &parsed[2], &parsed[3],
453 &parsed[4], &parsed[5], &parsed[6], &parsed[7],
454 &parsed[8], &parsed[9], &parsed[10], &parsed[11],
455 &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
458 for (i = 0; i < ELEMENTSOF(parsed); i++)
459 u->bytes[i] = parsed[i];