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/>.
32 #define LOAD_OPTION_ACTIVE 0x00000001
33 #define MEDIA_DEVICE_PATH 0x04
34 #define MEDIA_HARDDRIVE_DP 0x01
35 #define MEDIA_FILEPATH_DP 0x04
36 #define SIGNATURE_TYPE_GUID 0x02
37 #define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
38 #define END_DEVICE_PATH_TYPE 0x7f
39 #define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
45 } __attribute__((packed));
53 uint8_t signature_type;
54 } __attribute__((packed));
62 struct drive_path drive;
64 } __attribute__((packed));
66 bool is_efi_boot(void) {
67 return access("/sys/firmware/efi", F_OK) >= 0;
70 static int read_flag(const char *varname) {
72 _cleanup_free_ void *v = NULL;
76 r = efi_get_variable(EFI_VENDOR_GLOBAL, varname, NULL, &v, &s);
88 int is_efi_secure_boot(void) {
89 return read_flag("SecureBoot");
92 int is_efi_secure_boot_setup_mode(void) {
93 return read_flag("SetupMode");
103 _cleanup_close_ int fd = -1;
104 _cleanup_free_ char *p = NULL;
115 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
116 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
119 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
123 if (fstat(fd, &st) < 0)
127 if (st.st_size > 4*1024*1024 + 4)
130 n = read(fd, &a, sizeof(a));
136 r = malloc(st.st_size - 4 + 2);
140 n = read(fd, r, (size_t) st.st_size - 4);
145 if (n != (ssize_t) st.st_size - 4) {
150 /* Always NUL terminate (2 bytes, to protect UTF-16) */
151 ((char*) r)[st.st_size - 4] = 0;
152 ((char*) r)[st.st_size - 4 + 1] = 0;
155 *size = (size_t) st.st_size - 4;
163 int efi_set_variable(
172 } __attribute__((packed)) *buf = NULL;
180 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
181 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
189 fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
195 buf = malloc(sizeof(uint32_t) + size);
201 buf->attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
202 memcpy(buf->buf, value, size);
204 r = write(fd, buf, sizeof(uint32_t) + size);
210 if ((size_t)r != sizeof(uint32_t) + size) {
223 int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
224 _cleanup_free_ void *s = NULL;
229 r = efi_get_variable(vendor, name, NULL, &s, &ss);
233 x = utf16_to_utf8(s, ss);
241 static size_t utf16_size(const uint16_t *s) {
247 return (l+1) * sizeof(uint16_t);
250 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
257 const struct uuid *uuid = guid;
259 id128->bytes[0] = (uuid->u1 >> 24) & 0xff;
260 id128->bytes[1] = (uuid->u1 >> 16) & 0xff;
261 id128->bytes[2] = (uuid->u1 >> 8) & 0xff;
262 id128->bytes[3] = (uuid->u1) & 0xff;
263 id128->bytes[4] = (uuid->u2 >> 8) & 0xff;
264 id128->bytes[5] = (uuid->u2) & 0xff;
265 id128->bytes[6] = (uuid->u3 >> 8) & 0xff;
266 id128->bytes[7] = (uuid->u3) & 0xff;
267 memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
270 int efi_get_boot_option(
273 sd_id128_t *part_uuid,
288 uint8_t signature_type;
297 struct drive_path drive;
302 _cleanup_free_ uint8_t *buf = NULL;
304 struct boot_option *header;
308 sd_id128_t p_uuid = SD_ID128_NULL;
311 snprintf(boot_id, sizeof(boot_id), "Boot%04X", id);
312 err = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
315 if (l < sizeof(struct boot_option))
318 header = (struct boot_option *)buf;
319 title_size = utf16_size(header->title);
320 if (title_size > l - offsetof(struct boot_option, title))
324 s = utf16_to_utf8(header->title, title_size);
331 if (header->path_len > 0) {
335 dbuf = buf + offsetof(struct boot_option, title) + title_size;
337 while (dnext < header->path_len) {
338 struct device_path *dpath;
340 dpath = (struct device_path *)(dbuf + dnext);
341 if (dpath->length < 4)
344 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
345 if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
348 dnext += dpath->length;
350 /* Type 0x04 – Media Device Path */
351 if (dpath->type != MEDIA_DEVICE_PATH)
354 /* Sub-Type 1 – Hard Drive */
355 if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
356 /* 0x02 – GUID Partition Table */
357 if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
360 /* 0x02 – GUID signature */
361 if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID)
365 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
369 /* Sub-Type 4 – File Path */
370 if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && path) {
371 p = utf16_to_utf8(dpath->path, dpath->length-4);
372 efi_tilt_backslashes(p);
385 *active = !!header->attr & LOAD_OPTION_ACTIVE;
394 static void to_utf16(uint16_t *dest, const char *src) {
397 for (i = 0; src[i] != '\0'; i++)
407 } __attribute__((packed));
409 static void id128_to_efi_guid(sd_id128_t id, void *guid) {
410 struct guid *uuid = guid;
412 uuid->u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3];
413 uuid->u2 = id.bytes[4] << 8 | id.bytes[5];
414 uuid->u3 = id.bytes[6] << 8 | id.bytes[7];
415 memcpy(uuid->u4, id.bytes+8, sizeof(uuid->u4));
418 static uint16_t *tilt_slashes(uint16_t *s) {
428 char *efi_tilt_backslashes(char *s) {
438 int efi_add_boot_option(uint16_t id, const char *title,
439 uint32_t part, uint64_t pstart, uint64_t psize,
440 sd_id128_t part_uuid, const char *path) {
446 struct boot_option *option;
447 struct device_path *devicep;
450 title_len = (strlen(title)+1) * 2;
451 path_len = (strlen(path)+1) * 2;
453 buf = calloc(sizeof(struct boot_option) + title_len +
454 sizeof(struct drive_path) +
455 sizeof(struct device_path) + path_len, 1);
462 option = (struct boot_option *)buf;
463 option->attr = LOAD_OPTION_ACTIVE;
464 option->path_len = offsetof(struct device_path, drive) + sizeof(struct drive_path) +
465 offsetof(struct device_path, path) + path_len +
466 offsetof(struct device_path, path);
467 to_utf16(option->title, title);
468 size = offsetof(struct boot_option, title) + title_len;
471 devicep = (struct device_path *)(buf + size);
472 devicep->type = MEDIA_DEVICE_PATH;
473 devicep->sub_type = MEDIA_HARDDRIVE_DP;
474 devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path);
475 devicep->drive.part_nr = part;
476 devicep->drive.part_start = pstart;
477 devicep->drive.part_size = psize;
478 devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
479 devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
480 id128_to_efi_guid(part_uuid, devicep->drive.signature);
481 size += devicep->length;
484 devicep = (struct device_path *)(buf + size);
485 devicep->type = MEDIA_DEVICE_PATH;
486 devicep->sub_type = MEDIA_FILEPATH_DP;
487 devicep->length = offsetof(struct device_path, path) + path_len;
488 to_utf16(devicep->path, path);
489 tilt_slashes(devicep->path);
490 size += devicep->length;
493 devicep = (struct device_path *)(buf + size);
494 devicep->type = END_DEVICE_PATH_TYPE;
495 devicep->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE;
496 devicep->length = offsetof(struct device_path, path);
497 size += devicep->length;
499 snprintf(boot_id, sizeof(boot_id), "Boot%04X", id);
500 err = efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, buf, size);
507 int efi_remove_boot_option(uint16_t id) {
510 snprintf(boot_id, sizeof(boot_id), "Boot%04X", id);
511 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, 0);
514 int efi_get_boot_order(uint16_t **order) {
519 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
528 if ((l % sizeof(uint16_t) > 0) ||
529 (l / sizeof(uint16_t) > INT_MAX)) {
535 return (int) (l / sizeof(uint16_t));
538 int efi_set_boot_order(uint16_t *order, size_t n) {
539 return efi_set_variable(EFI_VENDOR_GLOBAL, "BootOrder", order, n * sizeof(uint16_t));
542 static int boot_id_hex(const char s[4]) {
546 for (i = 0; i < 4; i++)
547 if (s[i] >= '0' && s[i] <= '9')
548 id |= (s[i] - '0') << (3 - i) * 4;
549 else if (s[i] >= 'A' && s[i] <= 'F')
550 id |= (s[i] - 'A' + 10) << (3 - i) * 4;
557 static int cmp_uint16(const void *_a, const void *_b) {
558 const uint16_t *a = _a, *b = _b;
560 return (int)*a - (int)*b;
563 int efi_get_boot_options(uint16_t **options) {
564 _cleanup_closedir_ DIR *dir = NULL;
566 uint16_t *list = NULL;
571 dir = opendir("/sys/firmware/efi/efivars/");
575 FOREACH_DIRENT(de, dir, r = -errno; goto fail) {
579 if (strncmp(de->d_name, "Boot", 4) != 0)
582 if (strlen(de->d_name) != 45)
585 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
588 id = boot_id_hex(de->d_name + 4);
592 t = realloc(list, (count + 1) * sizeof(uint16_t));
602 qsort_safe(list, count, sizeof(uint16_t), cmp_uint16);
612 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
613 _cleanup_free_ char *j = NULL;
620 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
624 r = safe_atou64(j, &x);
632 int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) {
639 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
643 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
650 if (y > USEC_PER_HOUR)
659 int efi_loader_get_device_part_uuid(sd_id128_t *u) {
660 _cleanup_free_ char *p = NULL;
663 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
667 if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
668 &parsed[0], &parsed[1], &parsed[2], &parsed[3],
669 &parsed[4], &parsed[5], &parsed[6], &parsed[7],
670 &parsed[8], &parsed[9], &parsed[10], &parsed[11],
671 &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
677 for (i = 0; i < ELEMENTSOF(parsed); i++)
678 u->bytes[i] = parsed[i];