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/>.
26 #include "dirent-util.h"
30 #include "parse-util.h"
37 #define LOAD_OPTION_ACTIVE 0x00000001
38 #define MEDIA_DEVICE_PATH 0x04
39 #define MEDIA_HARDDRIVE_DP 0x01
40 #define MEDIA_FILEPATH_DP 0x04
41 #define SIGNATURE_TYPE_GUID 0x02
42 #define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
43 #define END_DEVICE_PATH_TYPE 0x7f
44 #define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
45 #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
59 uint8_t signature_type
;
68 struct drive_path drive
;
72 bool is_efi_boot(void) {
73 return access("/sys/firmware/efi", F_OK
) >= 0;
76 static int read_flag(const char *varname
) {
78 _cleanup_free_
void *v
= NULL
;
82 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, varname
, NULL
, &v
, &s
);
94 bool is_efi_secure_boot(void) {
95 return read_flag("SecureBoot") > 0;
98 bool is_efi_secure_boot_setup_mode(void) {
99 return read_flag("SetupMode") > 0;
102 int efi_reboot_to_firmware_supported(void) {
106 _cleanup_free_
void *v
= NULL
;
108 if (!is_efi_boot() || detect_container() > 0)
111 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndicationsSupported", NULL
, &v
, &s
);
114 else if (s
!= sizeof(uint64_t))
118 b
&= EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
119 return b
> 0 ? 0 : -EOPNOTSUPP
;
122 static int get_os_indications(uint64_t *os_indication
) {
125 _cleanup_free_
void *v
= NULL
;
127 r
= efi_reboot_to_firmware_supported();
131 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndications", NULL
, &v
, &s
);
133 /* Some firmware implementations that do support
134 * OsIndications and report that with
135 * OsIndicationsSupported will remove the
136 * OsIndications variable when it is unset. Let's
137 * pretend it's 0 then, to hide this implementation
138 * detail. Note that this call will return -ENOENT
139 * then only if the support for OsIndications is
140 * missing entirely, as determined by
141 * efi_reboot_to_firmware_supported() above. */
146 else if (s
!= sizeof(uint64_t))
149 *os_indication
= *(uint64_t *)v
;
153 int efi_get_reboot_to_firmware(void) {
157 r
= get_os_indications(&b
);
161 return !!(b
& EFI_OS_INDICATIONS_BOOT_TO_FW_UI
);
164 int efi_set_reboot_to_firmware(bool value
) {
168 r
= get_os_indications(&b
);
173 b_new
= b
| EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
175 b_new
= b
& ~EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
177 /* Avoid writing to efi vars store if we can due to firmware bugs. */
179 return efi_set_variable(EFI_VENDOR_GLOBAL
, "OsIndications", &b_new
, sizeof(uint64_t));
184 int efi_get_variable(
191 _cleanup_close_
int fd
= -1;
192 _cleanup_free_
char *p
= NULL
;
196 _cleanup_free_
void *buf
= NULL
;
203 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
204 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
207 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
211 if (fstat(fd
, &st
) < 0)
215 if (st
.st_size
> 4*1024*1024 + 4)
218 n
= read(fd
, &a
, sizeof(a
));
224 buf
= malloc(st
.st_size
- 4 + 2);
228 n
= read(fd
, buf
, (size_t) st
.st_size
- 4);
231 if (n
!= (ssize_t
) st
.st_size
- 4)
234 /* Always NUL terminate (2 bytes, to protect UTF-16) */
235 ((char*) buf
)[st
.st_size
- 4] = 0;
236 ((char*) buf
)[st
.st_size
- 4 + 1] = 0;
240 *size
= (size_t) st
.st_size
- 4;
248 int efi_set_variable(
257 } _packed_
* _cleanup_free_ buf
= NULL
;
258 _cleanup_free_
char *p
= NULL
;
259 _cleanup_close_
int fd
= -1;
264 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
265 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
274 fd
= open(p
, O_WRONLY
|O_CREAT
|O_NOCTTY
|O_CLOEXEC
, 0644);
278 buf
= malloc(sizeof(uint32_t) + size
);
282 buf
->attr
= EFI_VARIABLE_NON_VOLATILE
|EFI_VARIABLE_BOOTSERVICE_ACCESS
|EFI_VARIABLE_RUNTIME_ACCESS
;
283 memcpy(buf
->buf
, value
, size
);
285 return loop_write(fd
, buf
, sizeof(uint32_t) + size
, false);
288 int efi_get_variable_string(sd_id128_t vendor
, const char *name
, char **p
) {
289 _cleanup_free_
void *s
= NULL
;
294 r
= efi_get_variable(vendor
, name
, NULL
, &s
, &ss
);
298 x
= utf16_to_utf8(s
, ss
);
306 static size_t utf16_size(const uint16_t *s
) {
312 return (l
+1) * sizeof(uint16_t);
315 static void efi_guid_to_id128(const void *guid
, sd_id128_t
*id128
) {
322 const struct uuid
*uuid
= guid
;
324 id128
->bytes
[0] = (uuid
->u1
>> 24) & 0xff;
325 id128
->bytes
[1] = (uuid
->u1
>> 16) & 0xff;
326 id128
->bytes
[2] = (uuid
->u1
>> 8) & 0xff;
327 id128
->bytes
[3] = (uuid
->u1
) & 0xff;
328 id128
->bytes
[4] = (uuid
->u2
>> 8) & 0xff;
329 id128
->bytes
[5] = (uuid
->u2
) & 0xff;
330 id128
->bytes
[6] = (uuid
->u3
>> 8) & 0xff;
331 id128
->bytes
[7] = (uuid
->u3
) & 0xff;
332 memcpy(&id128
->bytes
[8], uuid
->u4
, sizeof(uuid
->u4
));
335 int efi_get_boot_option(
338 sd_id128_t
*part_uuid
,
343 _cleanup_free_
uint8_t *buf
= NULL
;
345 struct boot_option
*header
;
347 _cleanup_free_
char *s
= NULL
, *p
= NULL
;
348 sd_id128_t p_uuid
= SD_ID128_NULL
;
351 xsprintf(boot_id
, "Boot%04X", id
);
352 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, (void **)&buf
, &l
);
355 if (l
< sizeof(struct boot_option
))
358 header
= (struct boot_option
*)buf
;
359 title_size
= utf16_size(header
->title
);
360 if (title_size
> l
- offsetof(struct boot_option
, title
))
364 s
= utf16_to_utf8(header
->title
, title_size
);
369 if (header
->path_len
> 0) {
373 dbuf
= buf
+ offsetof(struct boot_option
, title
) + title_size
;
375 while (dnext
< header
->path_len
) {
376 struct device_path
*dpath
;
378 dpath
= (struct device_path
*)(dbuf
+ dnext
);
379 if (dpath
->length
< 4)
382 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
383 if (dpath
->type
== END_DEVICE_PATH_TYPE
&& dpath
->sub_type
== END_ENTIRE_DEVICE_PATH_SUBTYPE
)
386 dnext
+= dpath
->length
;
388 /* Type 0x04 – Media Device Path */
389 if (dpath
->type
!= MEDIA_DEVICE_PATH
)
392 /* Sub-Type 1 – Hard Drive */
393 if (dpath
->sub_type
== MEDIA_HARDDRIVE_DP
) {
394 /* 0x02 – GUID Partition Table */
395 if (dpath
->drive
.mbr_type
!= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
)
398 /* 0x02 – GUID signature */
399 if (dpath
->drive
.signature_type
!= SIGNATURE_TYPE_GUID
)
403 efi_guid_to_id128(dpath
->drive
.signature
, &p_uuid
);
407 /* Sub-Type 4 – File Path */
408 if (dpath
->sub_type
== MEDIA_FILEPATH_DP
&& !p
&& path
) {
409 p
= utf16_to_utf8(dpath
->path
, dpath
->length
-4);
410 efi_tilt_backslashes(p
);
427 *active
= !!(header
->attr
& LOAD_OPTION_ACTIVE
);
432 static void to_utf16(uint16_t *dest
, const char *src
) {
435 for (i
= 0; src
[i
] != '\0'; i
++)
447 static void id128_to_efi_guid(sd_id128_t id
, void *guid
) {
448 struct guid
*uuid
= guid
;
450 uuid
->u1
= id
.bytes
[0] << 24 | id
.bytes
[1] << 16 | id
.bytes
[2] << 8 | id
.bytes
[3];
451 uuid
->u2
= id
.bytes
[4] << 8 | id
.bytes
[5];
452 uuid
->u3
= id
.bytes
[6] << 8 | id
.bytes
[7];
453 memcpy(uuid
->u4
, id
.bytes
+8, sizeof(uuid
->u4
));
456 static uint16_t *tilt_slashes(uint16_t *s
) {
466 int efi_add_boot_option(uint16_t id
, const char *title
,
467 uint32_t part
, uint64_t pstart
, uint64_t psize
,
468 sd_id128_t part_uuid
, const char *path
) {
473 struct boot_option
*option
;
474 struct device_path
*devicep
;
475 _cleanup_free_
char *buf
= NULL
;
477 title_len
= (strlen(title
)+1) * 2;
478 path_len
= (strlen(path
)+1) * 2;
480 buf
= calloc(sizeof(struct boot_option
) + title_len
+
481 sizeof(struct drive_path
) +
482 sizeof(struct device_path
) + path_len
, 1);
487 option
= (struct boot_option
*)buf
;
488 option
->attr
= LOAD_OPTION_ACTIVE
;
489 option
->path_len
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
) +
490 offsetof(struct device_path
, path
) + path_len
+
491 offsetof(struct device_path
, path
);
492 to_utf16(option
->title
, title
);
493 size
= offsetof(struct boot_option
, title
) + title_len
;
496 devicep
= (struct device_path
*)(buf
+ size
);
497 devicep
->type
= MEDIA_DEVICE_PATH
;
498 devicep
->sub_type
= MEDIA_HARDDRIVE_DP
;
499 devicep
->length
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
);
500 devicep
->drive
.part_nr
= part
;
501 devicep
->drive
.part_start
= pstart
;
502 devicep
->drive
.part_size
= psize
;
503 devicep
->drive
.signature_type
= SIGNATURE_TYPE_GUID
;
504 devicep
->drive
.mbr_type
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
505 id128_to_efi_guid(part_uuid
, devicep
->drive
.signature
);
506 size
+= devicep
->length
;
509 devicep
= (struct device_path
*)(buf
+ size
);
510 devicep
->type
= MEDIA_DEVICE_PATH
;
511 devicep
->sub_type
= MEDIA_FILEPATH_DP
;
512 devicep
->length
= offsetof(struct device_path
, path
) + path_len
;
513 to_utf16(devicep
->path
, path
);
514 tilt_slashes(devicep
->path
);
515 size
+= devicep
->length
;
518 devicep
= (struct device_path
*)(buf
+ size
);
519 devicep
->type
= END_DEVICE_PATH_TYPE
;
520 devicep
->sub_type
= END_ENTIRE_DEVICE_PATH_SUBTYPE
;
521 devicep
->length
= offsetof(struct device_path
, path
);
522 size
+= devicep
->length
;
524 xsprintf(boot_id
, "Boot%04X", id
);
525 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, buf
, size
);
528 int efi_remove_boot_option(uint16_t id
) {
531 xsprintf(boot_id
, "Boot%04X", id
);
532 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, 0);
535 int efi_get_boot_order(uint16_t **order
) {
536 _cleanup_free_
void *buf
= NULL
;
540 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "BootOrder", NULL
, &buf
, &l
);
547 if (l
% sizeof(uint16_t) > 0 ||
548 l
/ sizeof(uint16_t) > INT_MAX
)
553 return (int) (l
/ sizeof(uint16_t));
556 int efi_set_boot_order(uint16_t *order
, size_t n
) {
557 return efi_set_variable(EFI_VENDOR_GLOBAL
, "BootOrder", order
, n
* sizeof(uint16_t));
560 static int boot_id_hex(const char s
[4]) {
564 for (i
= 0; i
< 4; i
++)
565 if (s
[i
] >= '0' && s
[i
] <= '9')
566 id
|= (s
[i
] - '0') << (3 - i
) * 4;
567 else if (s
[i
] >= 'A' && s
[i
] <= 'F')
568 id
|= (s
[i
] - 'A' + 10) << (3 - i
) * 4;
575 static int cmp_uint16(const void *_a
, const void *_b
) {
576 const uint16_t *a
= _a
, *b
= _b
;
578 return (int)*a
- (int)*b
;
581 int efi_get_boot_options(uint16_t **options
) {
582 _cleanup_closedir_
DIR *dir
= NULL
;
584 _cleanup_free_
uint16_t *list
= NULL
;
590 dir
= opendir("/sys/firmware/efi/efivars/");
594 FOREACH_DIRENT(de
, dir
, return -errno
) {
597 if (strncmp(de
->d_name
, "Boot", 4) != 0)
600 if (strlen(de
->d_name
) != 45)
603 if (strcmp(de
->d_name
+ 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
606 id
= boot_id_hex(de
->d_name
+ 4);
610 if (!GREEDY_REALLOC(list
, alloc
, count
+ 1))
616 qsort_safe(list
, count
, sizeof(uint16_t), cmp_uint16
);
623 static int read_usec(sd_id128_t vendor
, const char *name
, usec_t
*u
) {
624 _cleanup_free_
char *j
= NULL
;
631 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, name
, &j
);
635 r
= safe_atou64(j
, &x
);
643 int efi_loader_get_boot_usec(usec_t
*firmware
, usec_t
*loader
) {
650 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeInitUSec", &x
);
654 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeExecUSec", &y
);
661 if (y
> USEC_PER_HOUR
)
670 int efi_loader_get_device_part_uuid(sd_id128_t
*u
) {
671 _cleanup_free_
char *p
= NULL
;
674 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, "LoaderDevicePartUUID", &p
);
678 if (sscanf(p
, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
679 &parsed
[0], &parsed
[1], &parsed
[2], &parsed
[3],
680 &parsed
[4], &parsed
[5], &parsed
[6], &parsed
[7],
681 &parsed
[8], &parsed
[9], &parsed
[10], &parsed
[11],
682 &parsed
[12], &parsed
[13], &parsed
[14], &parsed
[15]) != 16)
688 for (i
= 0; i
< ELEMENTSOF(parsed
); i
++)
689 u
->bytes
[i
] = parsed
[i
];
697 char *efi_tilt_backslashes(char *s
) {