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;
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 } _packed_ * _cleanup_free_ buf = NULL;
173 _cleanup_free_ char *p = NULL;
174 _cleanup_close_ int fd = -1;
179 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
180 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
189 fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
193 buf = malloc(sizeof(uint32_t) + size);
197 buf->attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
198 memcpy(buf->buf, value, size);
200 return loop_write(fd, buf, sizeof(uint32_t) + size, false);
203 int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
204 _cleanup_free_ void *s = NULL;
209 r = efi_get_variable(vendor, name, NULL, &s, &ss);
213 x = utf16_to_utf8(s, ss);
221 static size_t utf16_size(const uint16_t *s) {
227 return (l+1) * sizeof(uint16_t);
230 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
237 const struct uuid *uuid = guid;
239 id128->bytes[0] = (uuid->u1 >> 24) & 0xff;
240 id128->bytes[1] = (uuid->u1 >> 16) & 0xff;
241 id128->bytes[2] = (uuid->u1 >> 8) & 0xff;
242 id128->bytes[3] = (uuid->u1) & 0xff;
243 id128->bytes[4] = (uuid->u2 >> 8) & 0xff;
244 id128->bytes[5] = (uuid->u2) & 0xff;
245 id128->bytes[6] = (uuid->u3 >> 8) & 0xff;
246 id128->bytes[7] = (uuid->u3) & 0xff;
247 memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
250 int efi_get_boot_option(
253 sd_id128_t *part_uuid,
258 _cleanup_free_ uint8_t *buf = NULL;
260 struct boot_option *header;
262 _cleanup_free_ char *s = NULL, *p = NULL;
263 sd_id128_t p_uuid = SD_ID128_NULL;
266 xsprintf(boot_id, "Boot%04X", id);
267 r = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
270 if (l < sizeof(struct boot_option))
273 header = (struct boot_option *)buf;
274 title_size = utf16_size(header->title);
275 if (title_size > l - offsetof(struct boot_option, title))
279 s = utf16_to_utf8(header->title, title_size);
284 if (header->path_len > 0) {
288 dbuf = buf + offsetof(struct boot_option, title) + title_size;
290 while (dnext < header->path_len) {
291 struct device_path *dpath;
293 dpath = (struct device_path *)(dbuf + dnext);
294 if (dpath->length < 4)
297 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
298 if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
301 dnext += dpath->length;
303 /* Type 0x04 – Media Device Path */
304 if (dpath->type != MEDIA_DEVICE_PATH)
307 /* Sub-Type 1 – Hard Drive */
308 if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
309 /* 0x02 – GUID Partition Table */
310 if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
313 /* 0x02 – GUID signature */
314 if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID)
318 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
322 /* Sub-Type 4 – File Path */
323 if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && path) {
324 p = utf16_to_utf8(dpath->path, dpath->length-4);
325 efi_tilt_backslashes(p);
342 *active = !!(header->attr & LOAD_OPTION_ACTIVE);
347 static void to_utf16(uint16_t *dest, const char *src) {
350 for (i = 0; src[i] != '\0'; i++)
362 static void id128_to_efi_guid(sd_id128_t id, void *guid) {
363 struct guid *uuid = guid;
365 uuid->u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3];
366 uuid->u2 = id.bytes[4] << 8 | id.bytes[5];
367 uuid->u3 = id.bytes[6] << 8 | id.bytes[7];
368 memcpy(uuid->u4, id.bytes+8, sizeof(uuid->u4));
371 static uint16_t *tilt_slashes(uint16_t *s) {
381 char *efi_tilt_backslashes(char *s) {
391 int efi_add_boot_option(uint16_t id, const char *title,
392 uint32_t part, uint64_t pstart, uint64_t psize,
393 sd_id128_t part_uuid, const char *path) {
398 struct boot_option *option;
399 struct device_path *devicep;
400 _cleanup_free_ char *buf = NULL;
402 title_len = (strlen(title)+1) * 2;
403 path_len = (strlen(path)+1) * 2;
405 buf = calloc(sizeof(struct boot_option) + title_len +
406 sizeof(struct drive_path) +
407 sizeof(struct device_path) + path_len, 1);
412 option = (struct boot_option *)buf;
413 option->attr = LOAD_OPTION_ACTIVE;
414 option->path_len = offsetof(struct device_path, drive) + sizeof(struct drive_path) +
415 offsetof(struct device_path, path) + path_len +
416 offsetof(struct device_path, path);
417 to_utf16(option->title, title);
418 size = offsetof(struct boot_option, title) + title_len;
421 devicep = (struct device_path *)(buf + size);
422 devicep->type = MEDIA_DEVICE_PATH;
423 devicep->sub_type = MEDIA_HARDDRIVE_DP;
424 devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path);
425 devicep->drive.part_nr = part;
426 devicep->drive.part_start = pstart;
427 devicep->drive.part_size = psize;
428 devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
429 devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
430 id128_to_efi_guid(part_uuid, devicep->drive.signature);
431 size += devicep->length;
434 devicep = (struct device_path *)(buf + size);
435 devicep->type = MEDIA_DEVICE_PATH;
436 devicep->sub_type = MEDIA_FILEPATH_DP;
437 devicep->length = offsetof(struct device_path, path) + path_len;
438 to_utf16(devicep->path, path);
439 tilt_slashes(devicep->path);
440 size += devicep->length;
443 devicep = (struct device_path *)(buf + size);
444 devicep->type = END_DEVICE_PATH_TYPE;
445 devicep->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE;
446 devicep->length = offsetof(struct device_path, path);
447 size += devicep->length;
449 xsprintf(boot_id, "Boot%04X", id);
450 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, buf, size);
453 int efi_remove_boot_option(uint16_t id) {
456 xsprintf(boot_id, "Boot%04X", id);
457 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, 0);
460 int efi_get_boot_order(uint16_t **order) {
465 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
474 if ((l % sizeof(uint16_t) > 0) ||
475 (l / sizeof(uint16_t) > INT_MAX)) {
481 return (int) (l / sizeof(uint16_t));
484 int efi_set_boot_order(uint16_t *order, size_t n) {
485 return efi_set_variable(EFI_VENDOR_GLOBAL, "BootOrder", order, n * sizeof(uint16_t));
488 static int boot_id_hex(const char s[4]) {
492 for (i = 0; i < 4; i++)
493 if (s[i] >= '0' && s[i] <= '9')
494 id |= (s[i] - '0') << (3 - i) * 4;
495 else if (s[i] >= 'A' && s[i] <= 'F')
496 id |= (s[i] - 'A' + 10) << (3 - i) * 4;
503 static int cmp_uint16(const void *_a, const void *_b) {
504 const uint16_t *a = _a, *b = _b;
506 return (int)*a - (int)*b;
509 int efi_get_boot_options(uint16_t **options) {
510 _cleanup_closedir_ DIR *dir = NULL;
512 _cleanup_free_ uint16_t *list = NULL;
517 dir = opendir("/sys/firmware/efi/efivars/");
521 FOREACH_DIRENT(de, dir, return -errno) {
525 if (strncmp(de->d_name, "Boot", 4) != 0)
528 if (strlen(de->d_name) != 45)
531 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
534 id = boot_id_hex(de->d_name + 4);
538 t = realloc(list, (count + 1) * sizeof(uint16_t));
546 qsort_safe(list, count, sizeof(uint16_t), cmp_uint16);
553 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
554 _cleanup_free_ char *j = NULL;
561 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
565 r = safe_atou64(j, &x);
573 int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) {
580 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
584 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
591 if (y > USEC_PER_HOUR)
600 int efi_loader_get_device_part_uuid(sd_id128_t *u) {
601 _cleanup_free_ char *p = NULL;
604 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
608 if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
609 &parsed[0], &parsed[1], &parsed[2], &parsed[3],
610 &parsed[4], &parsed[5], &parsed[6], &parsed[7],
611 &parsed[8], &parsed[9], &parsed[10], &parsed[11],
612 &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
618 for (i = 0; i < ELEMENTSOF(parsed); i++)
619 u->bytes[i] = parsed[i];