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
);
122 if (r
== -ENOENT
) /* variable doesn't exist? it's not supported then */
126 if (s
!= sizeof(uint64_t))
130 if (!(b
& EFI_OS_INDICATIONS_BOOT_TO_FW_UI
))
131 return -EOPNOTSUPP
; /* bit unset? it's not supported then */
136 static int get_os_indications(uint64_t *os_indication
) {
137 _cleanup_free_
void *v
= NULL
;
141 r
= efi_reboot_to_firmware_supported();
145 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndications", NULL
, &v
, &s
);
147 /* Some firmware implementations that do support
148 * OsIndications and report that with
149 * OsIndicationsSupported will remove the
150 * OsIndications variable when it is unset. Let's
151 * pretend it's 0 then, to hide this implementation
152 * detail. Note that this call will return -ENOENT
153 * then only if the support for OsIndications is
154 * missing entirely, as determined by
155 * efi_reboot_to_firmware_supported() above. */
160 else if (s
!= sizeof(uint64_t))
163 *os_indication
= *(uint64_t *)v
;
167 int efi_get_reboot_to_firmware(void) {
171 r
= get_os_indications(&b
);
175 return !!(b
& EFI_OS_INDICATIONS_BOOT_TO_FW_UI
);
178 int efi_set_reboot_to_firmware(bool value
) {
182 r
= get_os_indications(&b
);
187 b_new
= b
| EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
189 b_new
= b
& ~EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
191 /* Avoid writing to efi vars store if we can due to firmware bugs. */
193 return efi_set_variable(EFI_VENDOR_GLOBAL
, "OsIndications", &b_new
, sizeof(uint64_t));
198 int efi_get_variable(
205 _cleanup_close_
int fd
= -1;
206 _cleanup_free_
char *p
= NULL
;
210 _cleanup_free_
void *buf
= NULL
;
217 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
218 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
221 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
225 if (fstat(fd
, &st
) < 0)
229 if (st
.st_size
> 4*1024*1024 + 4)
232 n
= read(fd
, &a
, sizeof(a
));
238 buf
= malloc(st
.st_size
- 4 + 2);
242 n
= read(fd
, buf
, (size_t) st
.st_size
- 4);
245 if (n
!= (ssize_t
) st
.st_size
- 4)
248 /* Always NUL terminate (2 bytes, to protect UTF-16) */
249 ((char*) buf
)[st
.st_size
- 4] = 0;
250 ((char*) buf
)[st
.st_size
- 4 + 1] = 0;
252 *value
= TAKE_PTR(buf
);
253 *size
= (size_t) st
.st_size
- 4;
261 int efi_set_variable(
270 } _packed_
* _cleanup_free_ buf
= NULL
;
271 _cleanup_free_
char *p
= NULL
;
272 _cleanup_close_
int fd
= -1;
275 assert(value
|| size
== 0);
278 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
279 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
288 fd
= open(p
, O_WRONLY
|O_CREAT
|O_NOCTTY
|O_CLOEXEC
, 0644);
292 buf
= malloc(sizeof(uint32_t) + size
);
296 buf
->attr
= EFI_VARIABLE_NON_VOLATILE
|EFI_VARIABLE_BOOTSERVICE_ACCESS
|EFI_VARIABLE_RUNTIME_ACCESS
;
297 memcpy(buf
->buf
, value
, size
);
299 return loop_write(fd
, buf
, sizeof(uint32_t) + size
, false);
302 int efi_get_variable_string(sd_id128_t vendor
, const char *name
, char **p
) {
303 _cleanup_free_
void *s
= NULL
;
308 r
= efi_get_variable(vendor
, name
, NULL
, &s
, &ss
);
312 x
= utf16_to_utf8(s
, ss
);
320 static size_t utf16_size(const uint16_t *s
) {
326 return (l
+1) * sizeof(uint16_t);
329 static void efi_guid_to_id128(const void *guid
, sd_id128_t
*id128
) {
336 const struct uuid
*uuid
= guid
;
338 id128
->bytes
[0] = (uuid
->u1
>> 24) & 0xff;
339 id128
->bytes
[1] = (uuid
->u1
>> 16) & 0xff;
340 id128
->bytes
[2] = (uuid
->u1
>> 8) & 0xff;
341 id128
->bytes
[3] = (uuid
->u1
) & 0xff;
342 id128
->bytes
[4] = (uuid
->u2
>> 8) & 0xff;
343 id128
->bytes
[5] = (uuid
->u2
) & 0xff;
344 id128
->bytes
[6] = (uuid
->u3
>> 8) & 0xff;
345 id128
->bytes
[7] = (uuid
->u3
) & 0xff;
346 memcpy(&id128
->bytes
[8], uuid
->u4
, sizeof(uuid
->u4
));
349 int efi_get_boot_option(
352 sd_id128_t
*part_uuid
,
357 _cleanup_free_
uint8_t *buf
= NULL
;
359 struct boot_option
*header
;
361 _cleanup_free_
char *s
= NULL
, *p
= NULL
;
362 sd_id128_t p_uuid
= SD_ID128_NULL
;
365 xsprintf(boot_id
, "Boot%04X", id
);
366 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, (void **)&buf
, &l
);
369 if (l
< sizeof(struct boot_option
))
372 header
= (struct boot_option
*)buf
;
373 title_size
= utf16_size(header
->title
);
374 if (title_size
> l
- offsetof(struct boot_option
, title
))
378 s
= utf16_to_utf8(header
->title
, title_size
);
383 if (header
->path_len
> 0) {
387 dbuf
= buf
+ offsetof(struct boot_option
, title
) + title_size
;
389 while (dnext
< header
->path_len
) {
390 struct device_path
*dpath
;
392 dpath
= (struct device_path
*)(dbuf
+ dnext
);
393 if (dpath
->length
< 4)
396 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
397 if (dpath
->type
== END_DEVICE_PATH_TYPE
&& dpath
->sub_type
== END_ENTIRE_DEVICE_PATH_SUBTYPE
)
400 dnext
+= dpath
->length
;
402 /* Type 0x04 – Media Device Path */
403 if (dpath
->type
!= MEDIA_DEVICE_PATH
)
406 /* Sub-Type 1 – Hard Drive */
407 if (dpath
->sub_type
== MEDIA_HARDDRIVE_DP
) {
408 /* 0x02 – GUID Partition Table */
409 if (dpath
->drive
.mbr_type
!= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
)
412 /* 0x02 – GUID signature */
413 if (dpath
->drive
.signature_type
!= SIGNATURE_TYPE_GUID
)
417 efi_guid_to_id128(dpath
->drive
.signature
, &p_uuid
);
421 /* Sub-Type 4 – File Path */
422 if (dpath
->sub_type
== MEDIA_FILEPATH_DP
&& !p
&& path
) {
423 p
= utf16_to_utf8(dpath
->path
, dpath
->length
-4);
424 efi_tilt_backslashes(p
);
431 *title
= TAKE_PTR(s
);
437 *active
= !!(header
->attr
& LOAD_OPTION_ACTIVE
);
442 static void to_utf16(uint16_t *dest
, const char *src
) {
445 for (i
= 0; src
[i
] != '\0'; i
++)
457 static void id128_to_efi_guid(sd_id128_t id
, void *guid
) {
458 struct guid
*uuid
= guid
;
460 uuid
->u1
= id
.bytes
[0] << 24 | id
.bytes
[1] << 16 | id
.bytes
[2] << 8 | id
.bytes
[3];
461 uuid
->u2
= id
.bytes
[4] << 8 | id
.bytes
[5];
462 uuid
->u3
= id
.bytes
[6] << 8 | id
.bytes
[7];
463 memcpy(uuid
->u4
, id
.bytes
+8, sizeof(uuid
->u4
));
466 static uint16_t *tilt_slashes(uint16_t *s
) {
476 int efi_add_boot_option(uint16_t id
, const char *title
,
477 uint32_t part
, uint64_t pstart
, uint64_t psize
,
478 sd_id128_t part_uuid
, const char *path
) {
483 struct boot_option
*option
;
484 struct device_path
*devicep
;
485 _cleanup_free_
char *buf
= NULL
;
487 title_len
= (strlen(title
)+1) * 2;
488 path_len
= (strlen(path
)+1) * 2;
490 buf
= calloc(sizeof(struct boot_option
) + title_len
+
491 sizeof(struct drive_path
) +
492 sizeof(struct device_path
) + path_len
, 1);
497 option
= (struct boot_option
*)buf
;
498 option
->attr
= LOAD_OPTION_ACTIVE
;
499 option
->path_len
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
) +
500 offsetof(struct device_path
, path
) + path_len
+
501 offsetof(struct device_path
, path
);
502 to_utf16(option
->title
, title
);
503 size
= offsetof(struct boot_option
, title
) + title_len
;
506 devicep
= (struct device_path
*)(buf
+ size
);
507 devicep
->type
= MEDIA_DEVICE_PATH
;
508 devicep
->sub_type
= MEDIA_HARDDRIVE_DP
;
509 devicep
->length
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
);
510 devicep
->drive
.part_nr
= part
;
511 devicep
->drive
.part_start
= pstart
;
512 devicep
->drive
.part_size
= psize
;
513 devicep
->drive
.signature_type
= SIGNATURE_TYPE_GUID
;
514 devicep
->drive
.mbr_type
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
515 id128_to_efi_guid(part_uuid
, devicep
->drive
.signature
);
516 size
+= devicep
->length
;
519 devicep
= (struct device_path
*)(buf
+ size
);
520 devicep
->type
= MEDIA_DEVICE_PATH
;
521 devicep
->sub_type
= MEDIA_FILEPATH_DP
;
522 devicep
->length
= offsetof(struct device_path
, path
) + path_len
;
523 to_utf16(devicep
->path
, path
);
524 tilt_slashes(devicep
->path
);
525 size
+= devicep
->length
;
528 devicep
= (struct device_path
*)(buf
+ size
);
529 devicep
->type
= END_DEVICE_PATH_TYPE
;
530 devicep
->sub_type
= END_ENTIRE_DEVICE_PATH_SUBTYPE
;
531 devicep
->length
= offsetof(struct device_path
, path
);
532 size
+= devicep
->length
;
534 xsprintf(boot_id
, "Boot%04X", id
);
535 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, buf
, size
);
538 int efi_remove_boot_option(uint16_t id
) {
541 xsprintf(boot_id
, "Boot%04X", id
);
542 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, 0);
545 int efi_get_boot_order(uint16_t **order
) {
546 _cleanup_free_
void *buf
= NULL
;
550 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "BootOrder", NULL
, &buf
, &l
);
557 if (l
% sizeof(uint16_t) > 0 ||
558 l
/ sizeof(uint16_t) > INT_MAX
)
561 *order
= TAKE_PTR(buf
);
562 return (int) (l
/ sizeof(uint16_t));
565 int efi_set_boot_order(uint16_t *order
, size_t n
) {
566 return efi_set_variable(EFI_VENDOR_GLOBAL
, "BootOrder", order
, n
* sizeof(uint16_t));
569 static int boot_id_hex(const char s
[4]) {
573 for (i
= 0; i
< 4; i
++)
574 if (s
[i
] >= '0' && s
[i
] <= '9')
575 id
|= (s
[i
] - '0') << (3 - i
) * 4;
576 else if (s
[i
] >= 'A' && s
[i
] <= 'F')
577 id
|= (s
[i
] - 'A' + 10) << (3 - i
) * 4;
584 static int cmp_uint16(const void *_a
, const void *_b
) {
585 const uint16_t *a
= _a
, *b
= _b
;
587 return (int)*a
- (int)*b
;
590 int efi_get_boot_options(uint16_t **options
) {
591 _cleanup_closedir_
DIR *dir
= NULL
;
593 _cleanup_free_
uint16_t *list
= NULL
;
599 dir
= opendir("/sys/firmware/efi/efivars/");
603 FOREACH_DIRENT(de
, dir
, return -errno
) {
606 if (strncmp(de
->d_name
, "Boot", 4) != 0)
609 if (strlen(de
->d_name
) != 45)
612 if (strcmp(de
->d_name
+ 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
615 id
= boot_id_hex(de
->d_name
+ 4);
619 if (!GREEDY_REALLOC(list
, alloc
, count
+ 1))
625 qsort_safe(list
, count
, sizeof(uint16_t), cmp_uint16
);
627 *options
= TAKE_PTR(list
);
632 static int read_usec(sd_id128_t vendor
, const char *name
, usec_t
*u
) {
633 _cleanup_free_
char *j
= NULL
;
640 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, name
, &j
);
644 r
= safe_atou64(j
, &x
);
652 int efi_loader_get_boot_usec(usec_t
*firmware
, usec_t
*loader
) {
659 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeInitUSec", &x
);
663 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeExecUSec", &y
);
670 if (y
> USEC_PER_HOUR
)
679 int efi_loader_get_device_part_uuid(sd_id128_t
*u
) {
680 _cleanup_free_
char *p
= NULL
;
683 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, "LoaderDevicePartUUID", &p
);
687 if (sscanf(p
, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
688 &parsed
[0], &parsed
[1], &parsed
[2], &parsed
[3],
689 &parsed
[4], &parsed
[5], &parsed
[6], &parsed
[7],
690 &parsed
[8], &parsed
[9], &parsed
[10], &parsed
[11],
691 &parsed
[12], &parsed
[13], &parsed
[14], &parsed
[15]) != 16)
697 for (i
= 0; i
< ELEMENTSOF(parsed
); i
++)
698 u
->bytes
[i
] = parsed
[i
];
706 char *efi_tilt_backslashes(char *s
) {