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/>.
34 #include "alloc-util.h"
35 #include "dirent-util.h"
40 #include "parse-util.h"
41 #include "stdio-util.h"
42 #include "time-util.h"
49 #define LOAD_OPTION_ACTIVE 0x00000001
50 #define MEDIA_DEVICE_PATH 0x04
51 #define MEDIA_HARDDRIVE_DP 0x01
52 #define MEDIA_FILEPATH_DP 0x04
53 #define SIGNATURE_TYPE_GUID 0x02
54 #define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
55 #define END_DEVICE_PATH_TYPE 0x7f
56 #define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
57 #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
71 uint8_t signature_type
;
80 struct drive_path drive
;
84 bool is_efi_boot(void) {
85 return access("/sys/firmware/efi", F_OK
) >= 0;
88 static int read_flag(const char *varname
) {
90 _cleanup_free_
void *v
= NULL
;
94 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, varname
, NULL
, &v
, &s
);
106 bool is_efi_secure_boot(void) {
107 return read_flag("SecureBoot") > 0;
110 bool is_efi_secure_boot_setup_mode(void) {
111 return read_flag("SetupMode") > 0;
114 int efi_reboot_to_firmware_supported(void) {
118 _cleanup_free_
void *v
= NULL
;
120 if (!is_efi_boot() || detect_container() > 0)
123 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndicationsSupported", NULL
, &v
, &s
);
126 else if (s
!= sizeof(uint64_t))
130 b
&= EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
131 return b
> 0 ? 0 : -EOPNOTSUPP
;
134 static int get_os_indications(uint64_t *os_indication
) {
137 _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;
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
) {