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
) {
89 _cleanup_free_
void *v
= NULL
;
93 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, varname
, NULL
, &v
, &s
);
105 bool is_efi_secure_boot(void) {
106 return read_flag("SecureBoot") > 0;
109 bool is_efi_secure_boot_setup_mode(void) {
110 return read_flag("SetupMode") > 0;
113 int efi_reboot_to_firmware_supported(void) {
117 _cleanup_free_
void *v
= NULL
;
119 if (!is_efi_boot() || detect_container() > 0)
122 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndicationsSupported", NULL
, &v
, &s
);
125 else if (s
!= sizeof(uint64_t))
129 b
&= EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
130 return b
> 0 ? 0 : -EOPNOTSUPP
;
133 static int get_os_indications(uint64_t *os_indication
) {
136 _cleanup_free_
void *v
= NULL
;
138 r
= efi_reboot_to_firmware_supported();
142 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndications", NULL
, &v
, &s
);
144 /* Some firmware implementations that do support
145 * OsIndications and report that with
146 * OsIndicationsSupported will remove the
147 * OsIndications variable when it is unset. Let's
148 * pretend it's 0 then, to hide this implementation
149 * detail. Note that this call will return -ENOENT
150 * then only if the support for OsIndications is
151 * missing entirely, as determined by
152 * efi_reboot_to_firmware_supported() above. */
157 else if (s
!= sizeof(uint64_t))
160 *os_indication
= *(uint64_t *)v
;
164 int efi_get_reboot_to_firmware(void) {
168 r
= get_os_indications(&b
);
172 return !!(b
& EFI_OS_INDICATIONS_BOOT_TO_FW_UI
);
175 int efi_set_reboot_to_firmware(bool value
) {
179 r
= get_os_indications(&b
);
184 b_new
= b
| EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
186 b_new
= b
& ~EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
188 /* Avoid writing to efi vars store if we can due to firmware bugs. */
190 return efi_set_variable(EFI_VENDOR_GLOBAL
, "OsIndications", &b_new
, sizeof(uint64_t));
195 int efi_get_variable(
202 _cleanup_close_
int fd
= -1;
203 _cleanup_free_
char *p
= NULL
;
207 _cleanup_free_
void *buf
= NULL
;
214 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
215 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
218 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
222 if (fstat(fd
, &st
) < 0)
226 if (st
.st_size
> 4*1024*1024 + 4)
229 n
= read(fd
, &a
, sizeof(a
));
235 buf
= malloc(st
.st_size
- 4 + 2);
239 n
= read(fd
, buf
, (size_t) st
.st_size
- 4);
242 if (n
!= (ssize_t
) st
.st_size
- 4)
245 /* Always NUL terminate (2 bytes, to protect UTF-16) */
246 ((char*) buf
)[st
.st_size
- 4] = 0;
247 ((char*) buf
)[st
.st_size
- 4 + 1] = 0;
251 *size
= (size_t) st
.st_size
- 4;
259 int efi_set_variable(
268 } _packed_
* _cleanup_free_ buf
= NULL
;
269 _cleanup_free_
char *p
= NULL
;
270 _cleanup_close_
int fd
= -1;
273 assert(value
|| size
== 0);
276 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
277 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
286 fd
= open(p
, O_WRONLY
|O_CREAT
|O_NOCTTY
|O_CLOEXEC
, 0644);
290 buf
= malloc(sizeof(uint32_t) + size
);
294 buf
->attr
= EFI_VARIABLE_NON_VOLATILE
|EFI_VARIABLE_BOOTSERVICE_ACCESS
|EFI_VARIABLE_RUNTIME_ACCESS
;
295 memcpy(buf
->buf
, value
, size
);
297 return loop_write(fd
, buf
, sizeof(uint32_t) + size
, false);
300 int efi_get_variable_string(sd_id128_t vendor
, const char *name
, char **p
) {
301 _cleanup_free_
void *s
= NULL
;
306 r
= efi_get_variable(vendor
, name
, NULL
, &s
, &ss
);
310 x
= utf16_to_utf8(s
, ss
);
318 static size_t utf16_size(const uint16_t *s
) {
324 return (l
+1) * sizeof(uint16_t);
327 static void efi_guid_to_id128(const void *guid
, sd_id128_t
*id128
) {
334 const struct uuid
*uuid
= guid
;
336 id128
->bytes
[0] = (uuid
->u1
>> 24) & 0xff;
337 id128
->bytes
[1] = (uuid
->u1
>> 16) & 0xff;
338 id128
->bytes
[2] = (uuid
->u1
>> 8) & 0xff;
339 id128
->bytes
[3] = (uuid
->u1
) & 0xff;
340 id128
->bytes
[4] = (uuid
->u2
>> 8) & 0xff;
341 id128
->bytes
[5] = (uuid
->u2
) & 0xff;
342 id128
->bytes
[6] = (uuid
->u3
>> 8) & 0xff;
343 id128
->bytes
[7] = (uuid
->u3
) & 0xff;
344 memcpy(&id128
->bytes
[8], uuid
->u4
, sizeof(uuid
->u4
));
347 int efi_get_boot_option(
350 sd_id128_t
*part_uuid
,
355 _cleanup_free_
uint8_t *buf
= NULL
;
357 struct boot_option
*header
;
359 _cleanup_free_
char *s
= NULL
, *p
= NULL
;
360 sd_id128_t p_uuid
= SD_ID128_NULL
;
363 xsprintf(boot_id
, "Boot%04X", id
);
364 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, (void **)&buf
, &l
);
367 if (l
< sizeof(struct boot_option
))
370 header
= (struct boot_option
*)buf
;
371 title_size
= utf16_size(header
->title
);
372 if (title_size
> l
- offsetof(struct boot_option
, title
))
376 s
= utf16_to_utf8(header
->title
, title_size
);
381 if (header
->path_len
> 0) {
385 dbuf
= buf
+ offsetof(struct boot_option
, title
) + title_size
;
387 while (dnext
< header
->path_len
) {
388 struct device_path
*dpath
;
390 dpath
= (struct device_path
*)(dbuf
+ dnext
);
391 if (dpath
->length
< 4)
394 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
395 if (dpath
->type
== END_DEVICE_PATH_TYPE
&& dpath
->sub_type
== END_ENTIRE_DEVICE_PATH_SUBTYPE
)
398 dnext
+= dpath
->length
;
400 /* Type 0x04 – Media Device Path */
401 if (dpath
->type
!= MEDIA_DEVICE_PATH
)
404 /* Sub-Type 1 – Hard Drive */
405 if (dpath
->sub_type
== MEDIA_HARDDRIVE_DP
) {
406 /* 0x02 – GUID Partition Table */
407 if (dpath
->drive
.mbr_type
!= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
)
410 /* 0x02 – GUID signature */
411 if (dpath
->drive
.signature_type
!= SIGNATURE_TYPE_GUID
)
415 efi_guid_to_id128(dpath
->drive
.signature
, &p_uuid
);
419 /* Sub-Type 4 – File Path */
420 if (dpath
->sub_type
== MEDIA_FILEPATH_DP
&& !p
&& path
) {
421 p
= utf16_to_utf8(dpath
->path
, dpath
->length
-4);
422 efi_tilt_backslashes(p
);
439 *active
= !!(header
->attr
& LOAD_OPTION_ACTIVE
);
444 static void to_utf16(uint16_t *dest
, const char *src
) {
447 for (i
= 0; src
[i
] != '\0'; i
++)
459 static void id128_to_efi_guid(sd_id128_t id
, void *guid
) {
460 struct guid
*uuid
= guid
;
462 uuid
->u1
= id
.bytes
[0] << 24 | id
.bytes
[1] << 16 | id
.bytes
[2] << 8 | id
.bytes
[3];
463 uuid
->u2
= id
.bytes
[4] << 8 | id
.bytes
[5];
464 uuid
->u3
= id
.bytes
[6] << 8 | id
.bytes
[7];
465 memcpy(uuid
->u4
, id
.bytes
+8, sizeof(uuid
->u4
));
468 static uint16_t *tilt_slashes(uint16_t *s
) {
478 int efi_add_boot_option(uint16_t id
, const char *title
,
479 uint32_t part
, uint64_t pstart
, uint64_t psize
,
480 sd_id128_t part_uuid
, const char *path
) {
485 struct boot_option
*option
;
486 struct device_path
*devicep
;
487 _cleanup_free_
char *buf
= NULL
;
489 title_len
= (strlen(title
)+1) * 2;
490 path_len
= (strlen(path
)+1) * 2;
492 buf
= calloc(sizeof(struct boot_option
) + title_len
+
493 sizeof(struct drive_path
) +
494 sizeof(struct device_path
) + path_len
, 1);
499 option
= (struct boot_option
*)buf
;
500 option
->attr
= LOAD_OPTION_ACTIVE
;
501 option
->path_len
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
) +
502 offsetof(struct device_path
, path
) + path_len
+
503 offsetof(struct device_path
, path
);
504 to_utf16(option
->title
, title
);
505 size
= offsetof(struct boot_option
, title
) + title_len
;
508 devicep
= (struct device_path
*)(buf
+ size
);
509 devicep
->type
= MEDIA_DEVICE_PATH
;
510 devicep
->sub_type
= MEDIA_HARDDRIVE_DP
;
511 devicep
->length
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
);
512 devicep
->drive
.part_nr
= part
;
513 devicep
->drive
.part_start
= pstart
;
514 devicep
->drive
.part_size
= psize
;
515 devicep
->drive
.signature_type
= SIGNATURE_TYPE_GUID
;
516 devicep
->drive
.mbr_type
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
517 id128_to_efi_guid(part_uuid
, devicep
->drive
.signature
);
518 size
+= devicep
->length
;
521 devicep
= (struct device_path
*)(buf
+ size
);
522 devicep
->type
= MEDIA_DEVICE_PATH
;
523 devicep
->sub_type
= MEDIA_FILEPATH_DP
;
524 devicep
->length
= offsetof(struct device_path
, path
) + path_len
;
525 to_utf16(devicep
->path
, path
);
526 tilt_slashes(devicep
->path
);
527 size
+= devicep
->length
;
530 devicep
= (struct device_path
*)(buf
+ size
);
531 devicep
->type
= END_DEVICE_PATH_TYPE
;
532 devicep
->sub_type
= END_ENTIRE_DEVICE_PATH_SUBTYPE
;
533 devicep
->length
= offsetof(struct device_path
, path
);
534 size
+= devicep
->length
;
536 xsprintf(boot_id
, "Boot%04X", id
);
537 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, buf
, size
);
540 int efi_remove_boot_option(uint16_t id
) {
543 xsprintf(boot_id
, "Boot%04X", id
);
544 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, 0);
547 int efi_get_boot_order(uint16_t **order
) {
548 _cleanup_free_
void *buf
= NULL
;
552 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "BootOrder", NULL
, &buf
, &l
);
559 if (l
% sizeof(uint16_t) > 0 ||
560 l
/ sizeof(uint16_t) > INT_MAX
)
565 return (int) (l
/ sizeof(uint16_t));
568 int efi_set_boot_order(uint16_t *order
, size_t n
) {
569 return efi_set_variable(EFI_VENDOR_GLOBAL
, "BootOrder", order
, n
* sizeof(uint16_t));
572 static int boot_id_hex(const char s
[4]) {
576 for (i
= 0; i
< 4; i
++)
577 if (s
[i
] >= '0' && s
[i
] <= '9')
578 id
|= (s
[i
] - '0') << (3 - i
) * 4;
579 else if (s
[i
] >= 'A' && s
[i
] <= 'F')
580 id
|= (s
[i
] - 'A' + 10) << (3 - i
) * 4;
587 static int cmp_uint16(const void *_a
, const void *_b
) {
588 const uint16_t *a
= _a
, *b
= _b
;
590 return (int)*a
- (int)*b
;
593 int efi_get_boot_options(uint16_t **options
) {
594 _cleanup_closedir_
DIR *dir
= NULL
;
596 _cleanup_free_
uint16_t *list
= NULL
;
602 dir
= opendir("/sys/firmware/efi/efivars/");
606 FOREACH_DIRENT(de
, dir
, return -errno
) {
609 if (strncmp(de
->d_name
, "Boot", 4) != 0)
612 if (strlen(de
->d_name
) != 45)
615 if (strcmp(de
->d_name
+ 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
618 id
= boot_id_hex(de
->d_name
+ 4);
622 if (!GREEDY_REALLOC(list
, alloc
, count
+ 1))
628 qsort_safe(list
, count
, sizeof(uint16_t), cmp_uint16
);
635 static int read_usec(sd_id128_t vendor
, const char *name
, usec_t
*u
) {
636 _cleanup_free_
char *j
= NULL
;
643 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, name
, &j
);
647 r
= safe_atou64(j
, &x
);
655 int efi_loader_get_boot_usec(usec_t
*firmware
, usec_t
*loader
) {
662 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeInitUSec", &x
);
666 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeExecUSec", &y
);
673 if (y
> USEC_PER_HOUR
)
682 int efi_loader_get_device_part_uuid(sd_id128_t
*u
) {
683 _cleanup_free_
char *p
= NULL
;
686 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, "LoaderDevicePartUUID", &p
);
690 if (sscanf(p
, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
691 &parsed
[0], &parsed
[1], &parsed
[2], &parsed
[3],
692 &parsed
[4], &parsed
[5], &parsed
[6], &parsed
[7],
693 &parsed
[8], &parsed
[9], &parsed
[10], &parsed
[11],
694 &parsed
[12], &parsed
[13], &parsed
[14], &parsed
[15]) != 16)
700 for (i
= 0; i
< ELEMENTSOF(parsed
); i
++)
701 u
->bytes
[i
] = parsed
[i
];
709 char *efi_tilt_backslashes(char *s
) {