1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "alloc-util.h"
6 #include "dirent-util.h"
10 #include "sort-util.h"
11 #include "stat-util.h"
12 #include "stdio-util.h"
17 #define LOAD_OPTION_ACTIVE 0x00000001
18 #define MEDIA_DEVICE_PATH 0x04
19 #define MEDIA_HARDDRIVE_DP 0x01
20 #define MEDIA_FILEPATH_DP 0x04
21 #define SIGNATURE_TYPE_GUID 0x02
22 #define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
23 #define END_DEVICE_PATH_TYPE 0x7f
24 #define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
26 #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI UINT64_C(0x0000000000000001)
28 #define boot_option__contents \
35 struct boot_option boot_option__contents
;
36 struct boot_option__packed boot_option__contents _packed_
;
37 assert_cc(offsetof(struct boot_option
, title
) == offsetof(struct boot_option__packed
, title
));
38 /* sizeof(struct boot_option) != sizeof(struct boot_option__packed), so
39 * the *size* of the structure should not be used anywhere below. */
47 uint8_t signature_type
;
50 #define device_path__contents \
57 struct drive_path drive; \
61 struct device_path device_path__contents
;
62 struct device_path__packed device_path__contents _packed_
;
63 assert_cc(sizeof(struct device_path
) == sizeof(struct device_path__packed
));
65 int efi_reboot_to_firmware_supported(void) {
66 _cleanup_free_
void *v
= NULL
;
67 static int cache
= -1;
80 r
= efi_get_variable(EFI_GLOBAL_VARIABLE(OsIndicationsSupported
), NULL
, &v
, &s
);
82 goto not_supported
; /* variable doesn't exist? it's not supported then */
85 if (s
!= sizeof(uint64_t))
89 if (!(b
& EFI_OS_INDICATIONS_BOOT_TO_FW_UI
))
90 goto not_supported
; /* bit unset? it's not supported then */
100 static int get_os_indications(uint64_t *ret
) {
101 static struct stat cache_stat
= {};
102 _cleanup_free_
void *v
= NULL
;
103 static uint64_t cache
;
104 struct stat new_stat
;
110 /* Let's verify general support first */
111 r
= efi_reboot_to_firmware_supported();
115 /* stat() the EFI variable, to see if the mtime changed. If it did we need to cache again. */
116 if (stat(EFIVAR_PATH(EFI_GLOBAL_VARIABLE(OsIndications
)), &new_stat
) < 0) {
120 /* Doesn't exist? Then we can exit early (also see below) */
124 } else if (stat_inode_unmodified(&new_stat
, &cache_stat
)) {
125 /* inode didn't change, we can return the cached value */
130 r
= efi_get_variable(EFI_GLOBAL_VARIABLE(OsIndications
), NULL
, &v
, &s
);
132 /* Some firmware implementations that do support OsIndications and report that with
133 * OsIndicationsSupported will remove the OsIndications variable when it is unset. Let's
134 * pretend it's 0 then, to hide this implementation detail. Note that this call will return
135 * -ENOENT then only if the support for OsIndications is missing entirely, as determined by
136 * efi_reboot_to_firmware_supported() above. */
142 if (s
!= sizeof(uint64_t))
145 cache_stat
= new_stat
;
146 *ret
= cache
= *(uint64_t *)v
;
150 int efi_get_reboot_to_firmware(void) {
154 r
= get_os_indications(&b
);
158 return !!(b
& EFI_OS_INDICATIONS_BOOT_TO_FW_UI
);
161 int efi_set_reboot_to_firmware(bool value
) {
165 r
= get_os_indications(&b
);
169 b_new
= UPDATE_FLAG(b
, EFI_OS_INDICATIONS_BOOT_TO_FW_UI
, value
);
171 /* Avoid writing to efi vars store if we can due to firmware bugs. */
173 return efi_set_variable(EFI_GLOBAL_VARIABLE(OsIndications
), &b_new
, sizeof(uint64_t));
178 static ssize_t
utf16_size(const uint16_t *s
, size_t buf_len_bytes
) {
181 /* Returns the size of the string in bytes without the terminating two zero bytes */
183 while (l
< buf_len_bytes
/ sizeof(uint16_t)) {
185 return (l
+ 1) * sizeof(uint16_t);
189 return -EINVAL
; /* The terminator was not found */
192 int efi_get_boot_option(
195 sd_id128_t
*ret_part_uuid
,
199 char variable
[STRLEN(EFI_GLOBAL_VARIABLE_STR("Boot")) + 4 + 1];
200 _cleanup_free_
uint8_t *buf
= NULL
;
202 struct boot_option
*header
;
204 _cleanup_free_
char *s
= NULL
, *p
= NULL
;
205 sd_id128_t p_uuid
= SD_ID128_NULL
;
211 xsprintf(variable
, EFI_GLOBAL_VARIABLE_STR("Boot%04X"), id
);
212 r
= efi_get_variable(variable
, NULL
, (void **)&buf
, &l
);
215 if (l
< offsetof(struct boot_option
, title
))
218 header
= (struct boot_option
*)buf
;
219 title_size
= utf16_size(header
->title
, l
- offsetof(struct boot_option
, title
));
224 s
= utf16_to_utf8(header
->title
, title_size
);
229 if (header
->path_len
> 0) {
233 doff
= offsetof(struct boot_option
, title
) + title_size
;
235 if (header
->path_len
> l
- doff
)
239 while (dnext
< header
->path_len
) {
240 struct device_path
*dpath
;
242 dpath
= (struct device_path
*)(dbuf
+ dnext
);
243 if (dpath
->length
< 4)
246 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
247 if (dpath
->type
== END_DEVICE_PATH_TYPE
&& dpath
->sub_type
== END_ENTIRE_DEVICE_PATH_SUBTYPE
)
250 dnext
+= dpath
->length
;
252 /* Type 0x04 – Media Device Path */
253 if (dpath
->type
!= MEDIA_DEVICE_PATH
)
256 /* Sub-Type 1 – Hard Drive */
257 if (dpath
->sub_type
== MEDIA_HARDDRIVE_DP
) {
258 /* 0x02 – GUID Partition Table */
259 if (dpath
->drive
.mbr_type
!= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
)
262 /* 0x02 – GUID signature */
263 if (dpath
->drive
.signature_type
!= SIGNATURE_TYPE_GUID
)
267 p_uuid
= efi_guid_to_id128(dpath
->drive
.signature
);
271 /* Sub-Type 4 – File Path */
272 if (dpath
->sub_type
== MEDIA_FILEPATH_DP
&& !p
&& ret_path
) {
273 p
= utf16_to_utf8(dpath
->path
, dpath
->length
-4);
277 efi_tilt_backslashes(p
);
284 *ret_title
= TAKE_PTR(s
);
286 *ret_part_uuid
= p_uuid
;
288 *ret_path
= TAKE_PTR(p
);
290 *ret_active
= header
->attr
& LOAD_OPTION_ACTIVE
;
295 static void to_utf16(uint16_t *dest
, const char *src
) {
298 for (i
= 0; src
[i
] != '\0'; i
++)
303 static uint16_t *tilt_slashes(uint16_t *s
) {
304 for (uint16_t *p
= s
; *p
; p
++)
311 int efi_add_boot_option(
317 sd_id128_t part_uuid
,
320 size_t size
, title_len
, path_len
;
321 _cleanup_free_
char *buf
= NULL
;
322 struct boot_option
*option
;
323 struct device_path
*devicep
;
324 char variable
[STRLEN(EFI_GLOBAL_VARIABLE_STR("Boot")) + 4 + 1];
329 title_len
= (strlen(title
)+1) * 2;
330 path_len
= (strlen(path
)+1) * 2;
332 buf
= malloc0(offsetof(struct boot_option
, title
) + title_len
+
333 sizeof(struct drive_path
) +
334 sizeof(struct device_path
) + path_len
);
339 option
= (struct boot_option
*)buf
;
340 option
->attr
= LOAD_OPTION_ACTIVE
;
341 option
->path_len
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
) +
342 offsetof(struct device_path
, path
) + path_len
+
343 offsetof(struct device_path
, path
);
344 to_utf16(option
->title
, title
);
345 size
= offsetof(struct boot_option
, title
) + title_len
;
348 devicep
= (struct device_path
*)(buf
+ size
);
349 devicep
->type
= MEDIA_DEVICE_PATH
;
350 devicep
->sub_type
= MEDIA_HARDDRIVE_DP
;
351 devicep
->length
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
);
352 memcpy(&devicep
->drive
.part_nr
, &part
, sizeof(uint32_t));
353 memcpy(&devicep
->drive
.part_start
, &pstart
, sizeof(uint64_t));
354 memcpy(&devicep
->drive
.part_size
, &psize
, sizeof(uint64_t));
355 efi_id128_to_guid(part_uuid
, devicep
->drive
.signature
);
356 devicep
->drive
.mbr_type
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
357 devicep
->drive
.signature_type
= SIGNATURE_TYPE_GUID
;
358 size
+= devicep
->length
;
361 devicep
= (struct device_path
*)(buf
+ size
);
362 devicep
->type
= MEDIA_DEVICE_PATH
;
363 devicep
->sub_type
= MEDIA_FILEPATH_DP
;
364 devicep
->length
= offsetof(struct device_path
, path
) + path_len
;
365 to_utf16(devicep
->path
, path
);
366 tilt_slashes(devicep
->path
);
367 size
+= devicep
->length
;
370 devicep
= (struct device_path
*)(buf
+ size
);
371 devicep
->type
= END_DEVICE_PATH_TYPE
;
372 devicep
->sub_type
= END_ENTIRE_DEVICE_PATH_SUBTYPE
;
373 devicep
->length
= offsetof(struct device_path
, path
);
374 size
+= devicep
->length
;
376 xsprintf(variable
, EFI_GLOBAL_VARIABLE_STR("Boot%04X"), id
);
377 return efi_set_variable(variable
, buf
, size
);
380 int efi_remove_boot_option(uint16_t id
) {
381 char variable
[STRLEN(EFI_GLOBAL_VARIABLE_STR("Boot")) + 4 + 1];
386 xsprintf(variable
, EFI_GLOBAL_VARIABLE_STR("Boot%04X"), id
);
387 return efi_set_variable(variable
, NULL
, 0);
390 int efi_get_boot_order(uint16_t **ret_order
) {
391 _cleanup_free_
void *buf
= NULL
;
400 r
= efi_get_variable(EFI_GLOBAL_VARIABLE(BootOrder
), NULL
, &buf
, &l
);
407 if (l
% sizeof(uint16_t) > 0 ||
408 l
/ sizeof(uint16_t) > INT_MAX
)
411 *ret_order
= TAKE_PTR(buf
);
412 return (int) (l
/ sizeof(uint16_t));
415 int efi_set_boot_order(const uint16_t *order
, size_t n
) {
420 return efi_set_variable(EFI_GLOBAL_VARIABLE(BootOrder
), order
, n
* sizeof(uint16_t));
423 static int boot_id_hex(const char s
[static 4]) {
428 for (int i
= 0; i
< 4; i
++)
429 if (s
[i
] >= '0' && s
[i
] <= '9')
430 id
|= (s
[i
] - '0') << (3 - i
) * 4;
431 else if (s
[i
] >= 'A' && s
[i
] <= 'F')
432 id
|= (s
[i
] - 'A' + 10) << (3 - i
) * 4;
439 int efi_get_boot_options(uint16_t **ret_options
) {
440 _cleanup_closedir_
DIR *dir
= NULL
;
441 _cleanup_free_
uint16_t *list
= NULL
;
449 dir
= opendir(EFIVAR_PATH("."));
453 FOREACH_DIRENT(de
, dir
, return -errno
) {
456 if (!startswith(de
->d_name
, "Boot"))
459 if (strlen(de
->d_name
) != 45)
462 if (!streq(de
->d_name
+ 8, EFI_GLOBAL_VARIABLE_STR(""))) /* generate variable suffix using macro */
465 id
= boot_id_hex(de
->d_name
+ 4);
469 if (!GREEDY_REALLOC(list
, count
+ 1))
475 typesafe_qsort(list
, count
, cmp_uint16
);
477 *ret_options
= TAKE_PTR(list
);
482 bool efi_has_tpm2(void) {
483 static int cache
= -1;
485 /* Returns whether the system has a TPM2 chip which is known to the EFI firmware. */
490 /* First, check if we are on an EFI boot at all. */
491 if (!is_efi_boot()) {
496 /* Then, check if the ACPI table "TPM2" exists, which is the TPM2 event log table, see:
497 * https://trustedcomputinggroup.org/wp-content/uploads/TCG_ACPIGeneralSpecification_v1.20_r8.pdf
498 * This table exists whenever the firmware is hooked up to TPM2. */
499 cache
= access("/sys/firmware/acpi/tables/TPM2", F_OK
) >= 0;
504 log_debug_errno(errno
, "Unable to test whether /sys/firmware/acpi/tables/TPM2 exists, assuming it doesn't: %m");
506 /* As the last try, check if the EFI firmware provides the EFI_TCG2_FINAL_EVENTS_TABLE
507 * stored in EFI configuration table, see:
508 * https://trustedcomputinggroup.org/wp-content/uploads/EFI-Protocol-Specification-rev13-160330final.pdf
510 cache
= access("/sys/kernel/security/tpm0/binary_bios_measurements", F_OK
) >= 0;
511 if (!cache
&& errno
!= ENOENT
)
512 log_debug_errno(errno
, "Unable to test whether /sys/kernel/security/tpm0/binary_bios_measurements exists, assuming it doesn't: %m");
526 sd_id128_t
efi_guid_to_id128(const void *guid
) {
527 const struct efi_guid
*uuid
= ASSERT_PTR(guid
); /* cast is safe, because struct efi_guid is packed */
530 id128
.bytes
[0] = (uuid
->u1
>> 24) & 0xff;
531 id128
.bytes
[1] = (uuid
->u1
>> 16) & 0xff;
532 id128
.bytes
[2] = (uuid
->u1
>> 8) & 0xff;
533 id128
.bytes
[3] = uuid
->u1
& 0xff;
535 id128
.bytes
[4] = (uuid
->u2
>> 8) & 0xff;
536 id128
.bytes
[5] = uuid
->u2
& 0xff;
538 id128
.bytes
[6] = (uuid
->u3
>> 8) & 0xff;
539 id128
.bytes
[7] = uuid
->u3
& 0xff;
541 memcpy(&id128
.bytes
[8], uuid
->u4
, sizeof(uuid
->u4
));
546 void efi_id128_to_guid(sd_id128_t id
, void *ret_guid
) {
549 struct efi_guid uuid
= {
550 .u1
= id
.bytes
[0] << 24 | id
.bytes
[1] << 16 | id
.bytes
[2] << 8 | id
.bytes
[3],
551 .u2
= id
.bytes
[4] << 8 | id
.bytes
[5],
552 .u3
= id
.bytes
[6] << 8 | id
.bytes
[7],
554 memcpy(uuid
.u4
, id
.bytes
+8, sizeof(uuid
.u4
));
555 memcpy(ret_guid
, &uuid
, sizeof(uuid
));