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
53 uint8_t signature_type;
62 struct drive_path drive;
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;
108 _cleanup_free_ void *buf;
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 buf = malloc(st.st_size - 4 + 2);
140 n = read(fd, buf, (size_t) st.st_size - 4);
143 if (n != (ssize_t) st.st_size - 4)
146 /* Always NUL terminate (2 bytes, to protect UTF-16) */
147 ((char*) buf)[st.st_size - 4] = 0;
148 ((char*) buf)[st.st_size - 4 + 1] = 0;
152 *size = (size_t) st.st_size - 4;
160 int efi_set_variable(
169 } _packed_ * _cleanup_free_ buf = NULL;
170 _cleanup_free_ char *p = NULL;
171 _cleanup_close_ int fd = -1;
176 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
177 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
186 fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
190 buf = malloc(sizeof(uint32_t) + size);
194 buf->attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
195 memcpy(buf->buf, value, size);
197 return loop_write(fd, buf, sizeof(uint32_t) + size, false);
200 int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
201 _cleanup_free_ void *s = NULL;
206 r = efi_get_variable(vendor, name, NULL, &s, &ss);
210 x = utf16_to_utf8(s, ss);
218 static size_t utf16_size(const uint16_t *s) {
224 return (l+1) * sizeof(uint16_t);
227 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
234 const struct uuid *uuid = guid;
236 id128->bytes[0] = (uuid->u1 >> 24) & 0xff;
237 id128->bytes[1] = (uuid->u1 >> 16) & 0xff;
238 id128->bytes[2] = (uuid->u1 >> 8) & 0xff;
239 id128->bytes[3] = (uuid->u1) & 0xff;
240 id128->bytes[4] = (uuid->u2 >> 8) & 0xff;
241 id128->bytes[5] = (uuid->u2) & 0xff;
242 id128->bytes[6] = (uuid->u3 >> 8) & 0xff;
243 id128->bytes[7] = (uuid->u3) & 0xff;
244 memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
247 int efi_get_boot_option(
250 sd_id128_t *part_uuid,
255 _cleanup_free_ uint8_t *buf = NULL;
257 struct boot_option *header;
259 _cleanup_free_ char *s = NULL, *p = NULL;
260 sd_id128_t p_uuid = SD_ID128_NULL;
263 xsprintf(boot_id, "Boot%04X", id);
264 r = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
267 if (l < sizeof(struct boot_option))
270 header = (struct boot_option *)buf;
271 title_size = utf16_size(header->title);
272 if (title_size > l - offsetof(struct boot_option, title))
276 s = utf16_to_utf8(header->title, title_size);
281 if (header->path_len > 0) {
285 dbuf = buf + offsetof(struct boot_option, title) + title_size;
287 while (dnext < header->path_len) {
288 struct device_path *dpath;
290 dpath = (struct device_path *)(dbuf + dnext);
291 if (dpath->length < 4)
294 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
295 if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
298 dnext += dpath->length;
300 /* Type 0x04 – Media Device Path */
301 if (dpath->type != MEDIA_DEVICE_PATH)
304 /* Sub-Type 1 – Hard Drive */
305 if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
306 /* 0x02 – GUID Partition Table */
307 if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
310 /* 0x02 – GUID signature */
311 if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID)
315 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
319 /* Sub-Type 4 – File Path */
320 if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && path) {
321 p = utf16_to_utf8(dpath->path, dpath->length-4);
322 efi_tilt_backslashes(p);
339 *active = !!(header->attr & LOAD_OPTION_ACTIVE);
344 static void to_utf16(uint16_t *dest, const char *src) {
347 for (i = 0; src[i] != '\0'; i++)
359 static void id128_to_efi_guid(sd_id128_t id, void *guid) {
360 struct guid *uuid = guid;
362 uuid->u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3];
363 uuid->u2 = id.bytes[4] << 8 | id.bytes[5];
364 uuid->u3 = id.bytes[6] << 8 | id.bytes[7];
365 memcpy(uuid->u4, id.bytes+8, sizeof(uuid->u4));
368 static uint16_t *tilt_slashes(uint16_t *s) {
378 char *efi_tilt_backslashes(char *s) {
388 int efi_add_boot_option(uint16_t id, const char *title,
389 uint32_t part, uint64_t pstart, uint64_t psize,
390 sd_id128_t part_uuid, const char *path) {
395 struct boot_option *option;
396 struct device_path *devicep;
397 _cleanup_free_ char *buf = NULL;
399 title_len = (strlen(title)+1) * 2;
400 path_len = (strlen(path)+1) * 2;
402 buf = calloc(sizeof(struct boot_option) + title_len +
403 sizeof(struct drive_path) +
404 sizeof(struct device_path) + path_len, 1);
409 option = (struct boot_option *)buf;
410 option->attr = LOAD_OPTION_ACTIVE;
411 option->path_len = offsetof(struct device_path, drive) + sizeof(struct drive_path) +
412 offsetof(struct device_path, path) + path_len +
413 offsetof(struct device_path, path);
414 to_utf16(option->title, title);
415 size = offsetof(struct boot_option, title) + title_len;
418 devicep = (struct device_path *)(buf + size);
419 devicep->type = MEDIA_DEVICE_PATH;
420 devicep->sub_type = MEDIA_HARDDRIVE_DP;
421 devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path);
422 devicep->drive.part_nr = part;
423 devicep->drive.part_start = pstart;
424 devicep->drive.part_size = psize;
425 devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
426 devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
427 id128_to_efi_guid(part_uuid, devicep->drive.signature);
428 size += devicep->length;
431 devicep = (struct device_path *)(buf + size);
432 devicep->type = MEDIA_DEVICE_PATH;
433 devicep->sub_type = MEDIA_FILEPATH_DP;
434 devicep->length = offsetof(struct device_path, path) + path_len;
435 to_utf16(devicep->path, path);
436 tilt_slashes(devicep->path);
437 size += devicep->length;
440 devicep = (struct device_path *)(buf + size);
441 devicep->type = END_DEVICE_PATH_TYPE;
442 devicep->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE;
443 devicep->length = offsetof(struct device_path, path);
444 size += devicep->length;
446 xsprintf(boot_id, "Boot%04X", id);
447 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, buf, size);
450 int efi_remove_boot_option(uint16_t id) {
453 xsprintf(boot_id, "Boot%04X", id);
454 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, 0);
457 int efi_get_boot_order(uint16_t **order) {
458 _cleanup_free_ void *buf = NULL;
462 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
469 if (l % sizeof(uint16_t) > 0 ||
470 l / sizeof(uint16_t) > INT_MAX)
475 return (int) (l / sizeof(uint16_t));
478 int efi_set_boot_order(uint16_t *order, size_t n) {
479 return efi_set_variable(EFI_VENDOR_GLOBAL, "BootOrder", order, n * sizeof(uint16_t));
482 static int boot_id_hex(const char s[4]) {
486 for (i = 0; i < 4; i++)
487 if (s[i] >= '0' && s[i] <= '9')
488 id |= (s[i] - '0') << (3 - i) * 4;
489 else if (s[i] >= 'A' && s[i] <= 'F')
490 id |= (s[i] - 'A' + 10) << (3 - i) * 4;
497 static int cmp_uint16(const void *_a, const void *_b) {
498 const uint16_t *a = _a, *b = _b;
500 return (int)*a - (int)*b;
503 int efi_get_boot_options(uint16_t **options) {
504 _cleanup_closedir_ DIR *dir = NULL;
506 _cleanup_free_ uint16_t *list = NULL;
512 dir = opendir("/sys/firmware/efi/efivars/");
516 FOREACH_DIRENT(de, dir, return -errno) {
519 if (strncmp(de->d_name, "Boot", 4) != 0)
522 if (strlen(de->d_name) != 45)
525 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
528 id = boot_id_hex(de->d_name + 4);
532 if (!GREEDY_REALLOC(list, alloc, count + 1))
538 qsort_safe(list, count, sizeof(uint16_t), cmp_uint16);
545 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
546 _cleanup_free_ char *j = NULL;
553 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
557 r = safe_atou64(j, &x);
565 int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) {
572 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
576 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
583 if (y > USEC_PER_HOUR)
592 int efi_loader_get_device_part_uuid(sd_id128_t *u) {
593 _cleanup_free_ char *p = NULL;
596 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
600 if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
601 &parsed[0], &parsed[1], &parsed[2], &parsed[3],
602 &parsed[4], &parsed[5], &parsed[6], &parsed[7],
603 &parsed[8], &parsed[9], &parsed[10], &parsed[11],
604 &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
610 for (i = 0; i < ELEMENTSOF(parsed); i++)
611 u->bytes[i] = parsed[i];