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) {
44 r = efi_get_variable(EFI_VENDOR_GLOBAL, varname, NULL, &v, &s);
60 int is_efi_secure_boot(void) {
61 return read_flag("SecureBoot");
64 int is_efi_secure_boot_setup_mode(void) {
65 return read_flag("SetupMode");
75 _cleanup_close_ int fd = -1;
76 _cleanup_free_ char *p = NULL;
87 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
88 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
91 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
95 if (fstat(fd, &st) < 0)
99 if (st.st_size > 4*1024*1024 + 4)
102 n = read(fd, &a, sizeof(a));
108 r = malloc(st.st_size - 4 + 2);
112 n = read(fd, r, (size_t) st.st_size - 4);
117 if (n != (ssize_t) st.st_size - 4) {
122 /* Always NUL terminate (2 bytes, to protect UTF-16) */
123 ((char*) r)[st.st_size - 4] = 0;
124 ((char*) r)[st.st_size - 4 + 1] = 0;
127 *size = (size_t) st.st_size - 4;
135 int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
136 _cleanup_free_ void *s = NULL;
141 r = efi_get_variable(vendor, name, NULL, &s, &ss);
145 x = utf16_to_utf8(s, ss);
153 static size_t utf16_size(const uint16_t *s) {
159 return (l+1) * sizeof(uint16_t);
162 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
169 const struct uuid *uuid = guid;
171 id128->bytes[0] = (uuid->u1 >> 24) & 0xff;
172 id128->bytes[1] = (uuid->u1 >> 16) & 0xff;
173 id128->bytes[2] = (uuid->u1 >> 8) & 0xff;
174 id128->bytes[3] = (uuid->u1) & 0xff;
175 id128->bytes[4] = (uuid->u2 >> 8) & 0xff;
176 id128->bytes[5] = (uuid->u2) & 0xff;
177 id128->bytes[6] = (uuid->u3 >> 8) & 0xff;
178 id128->bytes[7] = (uuid->u3) & 0xff;
179 memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
182 int efi_get_boot_option(
185 sd_id128_t *part_uuid,
200 uint8_t signature_type;
209 struct drive_path drive;
214 _cleanup_free_ uint8_t *buf = NULL;
216 struct boot_option *header;
220 sd_id128_t p_uuid = SD_ID128_NULL;
223 snprintf(boot_id, sizeof(boot_id), "Boot%04X", id);
224 err = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
227 if (l < sizeof(struct boot_option))
230 header = (struct boot_option *)buf;
231 title_size = utf16_size(header->title);
232 if (title_size > l - offsetof(struct boot_option, title))
236 s = utf16_to_utf8(header->title, title_size);
243 if (header->path_len > 0) {
247 dbuf = buf + offsetof(struct boot_option, title) + title_size;
249 while (dnext < header->path_len) {
250 struct device_path *dpath;
252 dpath = (struct device_path *)(dbuf + dnext);
253 if (dpath->length < 4)
256 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
257 if (dpath->type == 0x7f && dpath->sub_type == 0xff)
260 dnext += dpath->length;
262 /* Type 0x04 – Media Device Path */
263 if (dpath->type != 0x04)
266 /* Sub-Type 1 – Hard Drive */
267 if (dpath->sub_type == 0x01) {
268 /* 0x02 – GUID Partition Table */
269 if (dpath->drive.mbr_type != 0x02)
272 /* 0x02 – GUID signature */
273 if (dpath->drive.signature_type != 0x02)
277 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
281 /* Sub-Type 4 – File Path */
282 if (dpath->sub_type == 0x04 && !p && path) {
283 p = utf16_to_utf8(dpath->path, dpath->length-4);
303 int efi_get_boot_order(uint16_t **order) {
308 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
317 if ((l % sizeof(uint16_t) > 0) ||
318 (l / sizeof(uint16_t) > INT_MAX)) {
324 return (int) (l / sizeof(uint16_t));
327 static int boot_id_hex(const char s[4]) {
331 for (i = 0; i < 4; i++)
332 if (s[i] >= '0' && s[i] <= '9')
333 id |= (s[i] - '0') << (3 - i) * 4;
334 else if (s[i] >= 'A' && s[i] <= 'F')
335 id |= (s[i] - 'A' + 10) << (3 - i) * 4;
342 static int cmp_uint16(const void *_a, const void *_b) {
343 const uint16_t *a = _a, *b = _b;
345 return (int)*a - (int)*b;
348 int efi_get_boot_options(uint16_t **options) {
349 _cleanup_closedir_ DIR *dir = NULL;
351 uint16_t *list = NULL;
356 dir = opendir("/sys/firmware/efi/efivars/");
360 FOREACH_DIRENT(de, dir, r = -errno; goto fail) {
364 if (strncmp(de->d_name, "Boot", 4) != 0)
367 if (strlen(de->d_name) != 45)
370 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
373 id = boot_id_hex(de->d_name + 4);
377 t = realloc(list, (count + 1) * sizeof(uint16_t));
387 qsort(list, count, sizeof(uint16_t), cmp_uint16);
397 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
398 _cleanup_free_ char *j = NULL;
405 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
409 r = safe_atou64(j, &x);
417 int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) {
424 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
428 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
435 if (y > USEC_PER_HOUR)
444 int efi_loader_get_device_part_uuid(sd_id128_t *u) {
445 _cleanup_free_ char *p = NULL;
451 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
455 if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
456 &parsed[0], &parsed[1], &parsed[2], &parsed[3],
457 &parsed[4], &parsed[5], &parsed[6], &parsed[7],
458 &parsed[8], &parsed[9], &parsed[10], &parsed[11],
459 &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
462 for (i = 0; i < ELEMENTSOF(parsed); i++)
463 u->bytes[i] = parsed[i];