1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
33 #include "alloc-util.h"
34 #include "dirent-util.h"
39 #include "parse-util.h"
40 #include "stdio-util.h"
41 #include "time-util.h"
48 #define LOAD_OPTION_ACTIVE 0x00000001
49 #define MEDIA_DEVICE_PATH 0x04
50 #define MEDIA_HARDDRIVE_DP 0x01
51 #define MEDIA_FILEPATH_DP 0x04
52 #define SIGNATURE_TYPE_GUID 0x02
53 #define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
54 #define END_DEVICE_PATH_TYPE 0x7f
55 #define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
56 #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
70 uint8_t signature_type
;
79 struct drive_path drive
;
83 bool is_efi_boot(void) {
84 return access("/sys/firmware/efi", F_OK
) >= 0;
87 static int read_flag(const char *varname
) {
88 _cleanup_free_
void *v
= NULL
;
93 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, varname
, NULL
, &v
, &s
);
104 bool is_efi_secure_boot(void) {
105 return read_flag("SecureBoot") > 0;
108 bool is_efi_secure_boot_setup_mode(void) {
109 return read_flag("SetupMode") > 0;
112 int efi_reboot_to_firmware_supported(void) {
113 _cleanup_free_
void *v
= NULL
;
118 if (!is_efi_boot() || detect_container() > 0)
121 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndicationsSupported", NULL
, &v
, &s
);
124 if (s
!= sizeof(uint64_t))
128 if (!(b
& EFI_OS_INDICATIONS_BOOT_TO_FW_UI
))
129 return -EOPNOTSUPP
; /* bit unset? it's not supported then */
134 static int get_os_indications(uint64_t *os_indication
) {
135 _cleanup_free_
void *v
= NULL
;
139 r
= efi_reboot_to_firmware_supported();
143 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndications", NULL
, &v
, &s
);
145 /* Some firmware implementations that do support
146 * OsIndications and report that with
147 * OsIndicationsSupported will remove the
148 * OsIndications variable when it is unset. Let's
149 * pretend it's 0 then, to hide this implementation
150 * detail. Note that this call will return -ENOENT
151 * then only if the support for OsIndications is
152 * missing entirely, as determined by
153 * efi_reboot_to_firmware_supported() above. */
158 else if (s
!= sizeof(uint64_t))
161 *os_indication
= *(uint64_t *)v
;
165 int efi_get_reboot_to_firmware(void) {
169 r
= get_os_indications(&b
);
173 return !!(b
& EFI_OS_INDICATIONS_BOOT_TO_FW_UI
);
176 int efi_set_reboot_to_firmware(bool value
) {
180 r
= get_os_indications(&b
);
185 b_new
= b
| EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
187 b_new
= b
& ~EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
189 /* Avoid writing to efi vars store if we can due to firmware bugs. */
191 return efi_set_variable(EFI_VENDOR_GLOBAL
, "OsIndications", &b_new
, sizeof(uint64_t));
196 int efi_get_variable(
203 _cleanup_close_
int fd
= -1;
204 _cleanup_free_
char *p
= NULL
;
208 _cleanup_free_
void *buf
= NULL
;
215 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
216 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
219 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
223 if (fstat(fd
, &st
) < 0)
227 if (st
.st_size
> 4*1024*1024 + 4)
230 n
= read(fd
, &a
, sizeof(a
));
236 buf
= malloc(st
.st_size
- 4 + 2);
240 n
= read(fd
, buf
, (size_t) st
.st_size
- 4);
243 if (n
!= (ssize_t
) st
.st_size
- 4)
246 /* Always NUL terminate (2 bytes, to protect UTF-16) */
247 ((char*) buf
)[st
.st_size
- 4] = 0;
248 ((char*) buf
)[st
.st_size
- 4 + 1] = 0;
252 *size
= (size_t) st
.st_size
- 4;
260 int efi_set_variable(
269 } _packed_
* _cleanup_free_ buf
= NULL
;
270 _cleanup_free_
char *p
= NULL
;
271 _cleanup_close_
int fd
= -1;
274 assert(value
|| size
== 0);
277 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
278 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
287 fd
= open(p
, O_WRONLY
|O_CREAT
|O_NOCTTY
|O_CLOEXEC
, 0644);
291 buf
= malloc(sizeof(uint32_t) + size
);
295 buf
->attr
= EFI_VARIABLE_NON_VOLATILE
|EFI_VARIABLE_BOOTSERVICE_ACCESS
|EFI_VARIABLE_RUNTIME_ACCESS
;
296 memcpy(buf
->buf
, value
, size
);
298 return loop_write(fd
, buf
, sizeof(uint32_t) + size
, false);
301 int efi_get_variable_string(sd_id128_t vendor
, const char *name
, char **p
) {
302 _cleanup_free_
void *s
= NULL
;
307 r
= efi_get_variable(vendor
, name
, NULL
, &s
, &ss
);
311 x
= utf16_to_utf8(s
, ss
);
319 static size_t utf16_size(const uint16_t *s
) {
325 return (l
+1) * sizeof(uint16_t);
328 static void efi_guid_to_id128(const void *guid
, sd_id128_t
*id128
) {
335 const struct uuid
*uuid
= guid
;
337 id128
->bytes
[0] = (uuid
->u1
>> 24) & 0xff;
338 id128
->bytes
[1] = (uuid
->u1
>> 16) & 0xff;
339 id128
->bytes
[2] = (uuid
->u1
>> 8) & 0xff;
340 id128
->bytes
[3] = (uuid
->u1
) & 0xff;
341 id128
->bytes
[4] = (uuid
->u2
>> 8) & 0xff;
342 id128
->bytes
[5] = (uuid
->u2
) & 0xff;
343 id128
->bytes
[6] = (uuid
->u3
>> 8) & 0xff;
344 id128
->bytes
[7] = (uuid
->u3
) & 0xff;
345 memcpy(&id128
->bytes
[8], uuid
->u4
, sizeof(uuid
->u4
));
348 int efi_get_boot_option(
351 sd_id128_t
*part_uuid
,
356 _cleanup_free_
uint8_t *buf
= NULL
;
358 struct boot_option
*header
;
360 _cleanup_free_
char *s
= NULL
, *p
= NULL
;
361 sd_id128_t p_uuid
= SD_ID128_NULL
;
364 xsprintf(boot_id
, "Boot%04X", id
);
365 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, (void **)&buf
, &l
);
368 if (l
< sizeof(struct boot_option
))
371 header
= (struct boot_option
*)buf
;
372 title_size
= utf16_size(header
->title
);
373 if (title_size
> l
- offsetof(struct boot_option
, title
))
377 s
= utf16_to_utf8(header
->title
, title_size
);
382 if (header
->path_len
> 0) {
386 dbuf
= buf
+ offsetof(struct boot_option
, title
) + title_size
;
388 while (dnext
< header
->path_len
) {
389 struct device_path
*dpath
;
391 dpath
= (struct device_path
*)(dbuf
+ dnext
);
392 if (dpath
->length
< 4)
395 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
396 if (dpath
->type
== END_DEVICE_PATH_TYPE
&& dpath
->sub_type
== END_ENTIRE_DEVICE_PATH_SUBTYPE
)
399 dnext
+= dpath
->length
;
401 /* Type 0x04 – Media Device Path */
402 if (dpath
->type
!= MEDIA_DEVICE_PATH
)
405 /* Sub-Type 1 – Hard Drive */
406 if (dpath
->sub_type
== MEDIA_HARDDRIVE_DP
) {
407 /* 0x02 – GUID Partition Table */
408 if (dpath
->drive
.mbr_type
!= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
)
411 /* 0x02 – GUID signature */
412 if (dpath
->drive
.signature_type
!= SIGNATURE_TYPE_GUID
)
416 efi_guid_to_id128(dpath
->drive
.signature
, &p_uuid
);
420 /* Sub-Type 4 – File Path */
421 if (dpath
->sub_type
== MEDIA_FILEPATH_DP
&& !p
&& path
) {
422 p
= utf16_to_utf8(dpath
->path
, dpath
->length
-4);
423 efi_tilt_backslashes(p
);
440 *active
= !!(header
->attr
& LOAD_OPTION_ACTIVE
);
445 static void to_utf16(uint16_t *dest
, const char *src
) {
448 for (i
= 0; src
[i
] != '\0'; i
++)
460 static void id128_to_efi_guid(sd_id128_t id
, void *guid
) {
461 struct guid
*uuid
= guid
;
463 uuid
->u1
= id
.bytes
[0] << 24 | id
.bytes
[1] << 16 | id
.bytes
[2] << 8 | id
.bytes
[3];
464 uuid
->u2
= id
.bytes
[4] << 8 | id
.bytes
[5];
465 uuid
->u3
= id
.bytes
[6] << 8 | id
.bytes
[7];
466 memcpy(uuid
->u4
, id
.bytes
+8, sizeof(uuid
->u4
));
469 static uint16_t *tilt_slashes(uint16_t *s
) {
479 int efi_add_boot_option(uint16_t id
, const char *title
,
480 uint32_t part
, uint64_t pstart
, uint64_t psize
,
481 sd_id128_t part_uuid
, const char *path
) {
486 struct boot_option
*option
;
487 struct device_path
*devicep
;
488 _cleanup_free_
char *buf
= NULL
;
490 title_len
= (strlen(title
)+1) * 2;
491 path_len
= (strlen(path
)+1) * 2;
493 buf
= calloc(sizeof(struct boot_option
) + title_len
+
494 sizeof(struct drive_path
) +
495 sizeof(struct device_path
) + path_len
, 1);
500 option
= (struct boot_option
*)buf
;
501 option
->attr
= LOAD_OPTION_ACTIVE
;
502 option
->path_len
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
) +
503 offsetof(struct device_path
, path
) + path_len
+
504 offsetof(struct device_path
, path
);
505 to_utf16(option
->title
, title
);
506 size
= offsetof(struct boot_option
, title
) + title_len
;
509 devicep
= (struct device_path
*)(buf
+ size
);
510 devicep
->type
= MEDIA_DEVICE_PATH
;
511 devicep
->sub_type
= MEDIA_HARDDRIVE_DP
;
512 devicep
->length
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
);
513 devicep
->drive
.part_nr
= part
;
514 devicep
->drive
.part_start
= pstart
;
515 devicep
->drive
.part_size
= psize
;
516 devicep
->drive
.signature_type
= SIGNATURE_TYPE_GUID
;
517 devicep
->drive
.mbr_type
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
518 id128_to_efi_guid(part_uuid
, devicep
->drive
.signature
);
519 size
+= devicep
->length
;
522 devicep
= (struct device_path
*)(buf
+ size
);
523 devicep
->type
= MEDIA_DEVICE_PATH
;
524 devicep
->sub_type
= MEDIA_FILEPATH_DP
;
525 devicep
->length
= offsetof(struct device_path
, path
) + path_len
;
526 to_utf16(devicep
->path
, path
);
527 tilt_slashes(devicep
->path
);
528 size
+= devicep
->length
;
531 devicep
= (struct device_path
*)(buf
+ size
);
532 devicep
->type
= END_DEVICE_PATH_TYPE
;
533 devicep
->sub_type
= END_ENTIRE_DEVICE_PATH_SUBTYPE
;
534 devicep
->length
= offsetof(struct device_path
, path
);
535 size
+= devicep
->length
;
537 xsprintf(boot_id
, "Boot%04X", id
);
538 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, buf
, size
);
541 int efi_remove_boot_option(uint16_t id
) {
544 xsprintf(boot_id
, "Boot%04X", id
);
545 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, 0);
548 int efi_get_boot_order(uint16_t **order
) {
549 _cleanup_free_
void *buf
= NULL
;
553 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "BootOrder", NULL
, &buf
, &l
);
560 if (l
% sizeof(uint16_t) > 0 ||
561 l
/ sizeof(uint16_t) > INT_MAX
)
566 return (int) (l
/ sizeof(uint16_t));
569 int efi_set_boot_order(uint16_t *order
, size_t n
) {
570 return efi_set_variable(EFI_VENDOR_GLOBAL
, "BootOrder", order
, n
* sizeof(uint16_t));
573 static int boot_id_hex(const char s
[4]) {
577 for (i
= 0; i
< 4; i
++)
578 if (s
[i
] >= '0' && s
[i
] <= '9')
579 id
|= (s
[i
] - '0') << (3 - i
) * 4;
580 else if (s
[i
] >= 'A' && s
[i
] <= 'F')
581 id
|= (s
[i
] - 'A' + 10) << (3 - i
) * 4;
588 static int cmp_uint16(const void *_a
, const void *_b
) {
589 const uint16_t *a
= _a
, *b
= _b
;
591 return (int)*a
- (int)*b
;
594 int efi_get_boot_options(uint16_t **options
) {
595 _cleanup_closedir_
DIR *dir
= NULL
;
597 _cleanup_free_
uint16_t *list
= NULL
;
603 dir
= opendir("/sys/firmware/efi/efivars/");
607 FOREACH_DIRENT(de
, dir
, return -errno
) {
610 if (strncmp(de
->d_name
, "Boot", 4) != 0)
613 if (strlen(de
->d_name
) != 45)
616 if (strcmp(de
->d_name
+ 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
619 id
= boot_id_hex(de
->d_name
+ 4);
623 if (!GREEDY_REALLOC(list
, alloc
, count
+ 1))
629 qsort_safe(list
, count
, sizeof(uint16_t), cmp_uint16
);
636 static int read_usec(sd_id128_t vendor
, const char *name
, usec_t
*u
) {
637 _cleanup_free_
char *j
= NULL
;
644 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, name
, &j
);
648 r
= safe_atou64(j
, &x
);
656 int efi_loader_get_boot_usec(usec_t
*firmware
, usec_t
*loader
) {
663 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeInitUSec", &x
);
667 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeExecUSec", &y
);
674 if (y
> USEC_PER_HOUR
)
683 int efi_loader_get_device_part_uuid(sd_id128_t
*u
) {
684 _cleanup_free_
char *p
= NULL
;
687 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, "LoaderDevicePartUUID", &p
);
691 if (sscanf(p
, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
692 &parsed
[0], &parsed
[1], &parsed
[2], &parsed
[3],
693 &parsed
[4], &parsed
[5], &parsed
[6], &parsed
[7],
694 &parsed
[8], &parsed
[9], &parsed
[10], &parsed
[11],
695 &parsed
[12], &parsed
[13], &parsed
[14], &parsed
[15]) != 16)
701 for (i
= 0; i
< ELEMENTSOF(parsed
); i
++)
702 u
->bytes
[i
] = parsed
[i
];
710 char *efi_tilt_backslashes(char *s
) {