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/>.
33 #define LOAD_OPTION_ACTIVE 0x00000001
34 #define MEDIA_DEVICE_PATH 0x04
35 #define MEDIA_HARDDRIVE_DP 0x01
36 #define MEDIA_FILEPATH_DP 0x04
37 #define SIGNATURE_TYPE_GUID 0x02
38 #define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
39 #define END_DEVICE_PATH_TYPE 0x7f
40 #define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
41 #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
55 uint8_t signature_type
;
64 struct drive_path drive
;
68 bool is_efi_boot(void) {
69 return access("/sys/firmware/efi", F_OK
) >= 0;
72 static int read_flag(const char *varname
) {
74 _cleanup_free_
void *v
= NULL
;
78 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, varname
, NULL
, &v
, &s
);
90 bool is_efi_secure_boot(void) {
91 return read_flag("SecureBoot") > 0;
94 bool is_efi_secure_boot_setup_mode(void) {
95 return read_flag("SetupMode") > 0;
98 int efi_reboot_to_firmware_supported(void) {
102 _cleanup_free_
void *v
= NULL
;
104 if (!is_efi_boot() || detect_container(NULL
) > 0)
107 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndicationsSupported", NULL
, &v
, &s
);
110 else if (s
!= sizeof(uint64_t))
114 b
&= EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
115 return b
> 0 ? 0 : -EOPNOTSUPP
;
118 static int get_os_indications(uint64_t *os_indication
) {
121 _cleanup_free_
void *v
= NULL
;
123 r
= efi_reboot_to_firmware_supported();
127 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndications", NULL
, &v
, &s
);
130 else if (s
!= sizeof(uint64_t))
133 *os_indication
= *(uint64_t *)v
;
137 int efi_get_reboot_to_firmware(void) {
141 r
= get_os_indications(&b
);
145 return !!(b
& EFI_OS_INDICATIONS_BOOT_TO_FW_UI
);
148 int efi_set_reboot_to_firmware(bool value
) {
152 r
= get_os_indications(&b
);
157 b_new
= b
| EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
159 b_new
= b
& ~EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
161 /* Avoid writing to efi vars store if we can due to firmware bugs. */
163 return efi_set_variable(EFI_VENDOR_GLOBAL
, "OsIndications", &b_new
, sizeof(uint64_t));
168 int efi_get_variable(
175 _cleanup_close_
int fd
= -1;
176 _cleanup_free_
char *p
= NULL
;
180 _cleanup_free_
void *buf
= NULL
;
187 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
188 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
191 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
195 if (fstat(fd
, &st
) < 0)
199 if (st
.st_size
> 4*1024*1024 + 4)
202 n
= read(fd
, &a
, sizeof(a
));
208 buf
= malloc(st
.st_size
- 4 + 2);
212 n
= read(fd
, buf
, (size_t) st
.st_size
- 4);
215 if (n
!= (ssize_t
) st
.st_size
- 4)
218 /* Always NUL terminate (2 bytes, to protect UTF-16) */
219 ((char*) buf
)[st
.st_size
- 4] = 0;
220 ((char*) buf
)[st
.st_size
- 4 + 1] = 0;
224 *size
= (size_t) st
.st_size
- 4;
232 int efi_set_variable(
241 } _packed_
* _cleanup_free_ buf
= NULL
;
242 _cleanup_free_
char *p
= NULL
;
243 _cleanup_close_
int fd
= -1;
248 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
249 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
258 fd
= open(p
, O_WRONLY
|O_CREAT
|O_NOCTTY
|O_CLOEXEC
, 0644);
262 buf
= malloc(sizeof(uint32_t) + size
);
266 buf
->attr
= EFI_VARIABLE_NON_VOLATILE
|EFI_VARIABLE_BOOTSERVICE_ACCESS
|EFI_VARIABLE_RUNTIME_ACCESS
;
267 memcpy(buf
->buf
, value
, size
);
269 return loop_write(fd
, buf
, sizeof(uint32_t) + size
, false);
272 int efi_get_variable_string(sd_id128_t vendor
, const char *name
, char **p
) {
273 _cleanup_free_
void *s
= NULL
;
278 r
= efi_get_variable(vendor
, name
, NULL
, &s
, &ss
);
282 x
= utf16_to_utf8(s
, ss
);
290 static size_t utf16_size(const uint16_t *s
) {
296 return (l
+1) * sizeof(uint16_t);
299 static void efi_guid_to_id128(const void *guid
, sd_id128_t
*id128
) {
306 const struct uuid
*uuid
= guid
;
308 id128
->bytes
[0] = (uuid
->u1
>> 24) & 0xff;
309 id128
->bytes
[1] = (uuid
->u1
>> 16) & 0xff;
310 id128
->bytes
[2] = (uuid
->u1
>> 8) & 0xff;
311 id128
->bytes
[3] = (uuid
->u1
) & 0xff;
312 id128
->bytes
[4] = (uuid
->u2
>> 8) & 0xff;
313 id128
->bytes
[5] = (uuid
->u2
) & 0xff;
314 id128
->bytes
[6] = (uuid
->u3
>> 8) & 0xff;
315 id128
->bytes
[7] = (uuid
->u3
) & 0xff;
316 memcpy(&id128
->bytes
[8], uuid
->u4
, sizeof(uuid
->u4
));
319 int efi_get_boot_option(
322 sd_id128_t
*part_uuid
,
327 _cleanup_free_
uint8_t *buf
= NULL
;
329 struct boot_option
*header
;
331 _cleanup_free_
char *s
= NULL
, *p
= NULL
;
332 sd_id128_t p_uuid
= SD_ID128_NULL
;
335 xsprintf(boot_id
, "Boot%04X", id
);
336 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, (void **)&buf
, &l
);
339 if (l
< sizeof(struct boot_option
))
342 header
= (struct boot_option
*)buf
;
343 title_size
= utf16_size(header
->title
);
344 if (title_size
> l
- offsetof(struct boot_option
, title
))
348 s
= utf16_to_utf8(header
->title
, title_size
);
353 if (header
->path_len
> 0) {
357 dbuf
= buf
+ offsetof(struct boot_option
, title
) + title_size
;
359 while (dnext
< header
->path_len
) {
360 struct device_path
*dpath
;
362 dpath
= (struct device_path
*)(dbuf
+ dnext
);
363 if (dpath
->length
< 4)
366 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
367 if (dpath
->type
== END_DEVICE_PATH_TYPE
&& dpath
->sub_type
== END_ENTIRE_DEVICE_PATH_SUBTYPE
)
370 dnext
+= dpath
->length
;
372 /* Type 0x04 – Media Device Path */
373 if (dpath
->type
!= MEDIA_DEVICE_PATH
)
376 /* Sub-Type 1 – Hard Drive */
377 if (dpath
->sub_type
== MEDIA_HARDDRIVE_DP
) {
378 /* 0x02 – GUID Partition Table */
379 if (dpath
->drive
.mbr_type
!= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
)
382 /* 0x02 – GUID signature */
383 if (dpath
->drive
.signature_type
!= SIGNATURE_TYPE_GUID
)
387 efi_guid_to_id128(dpath
->drive
.signature
, &p_uuid
);
391 /* Sub-Type 4 – File Path */
392 if (dpath
->sub_type
== MEDIA_FILEPATH_DP
&& !p
&& path
) {
393 p
= utf16_to_utf8(dpath
->path
, dpath
->length
-4);
394 efi_tilt_backslashes(p
);
411 *active
= !!(header
->attr
& LOAD_OPTION_ACTIVE
);
416 static void to_utf16(uint16_t *dest
, const char *src
) {
419 for (i
= 0; src
[i
] != '\0'; i
++)
431 static void id128_to_efi_guid(sd_id128_t id
, void *guid
) {
432 struct guid
*uuid
= guid
;
434 uuid
->u1
= id
.bytes
[0] << 24 | id
.bytes
[1] << 16 | id
.bytes
[2] << 8 | id
.bytes
[3];
435 uuid
->u2
= id
.bytes
[4] << 8 | id
.bytes
[5];
436 uuid
->u3
= id
.bytes
[6] << 8 | id
.bytes
[7];
437 memcpy(uuid
->u4
, id
.bytes
+8, sizeof(uuid
->u4
));
440 static uint16_t *tilt_slashes(uint16_t *s
) {
450 int efi_add_boot_option(uint16_t id
, const char *title
,
451 uint32_t part
, uint64_t pstart
, uint64_t psize
,
452 sd_id128_t part_uuid
, const char *path
) {
457 struct boot_option
*option
;
458 struct device_path
*devicep
;
459 _cleanup_free_
char *buf
= NULL
;
461 title_len
= (strlen(title
)+1) * 2;
462 path_len
= (strlen(path
)+1) * 2;
464 buf
= calloc(sizeof(struct boot_option
) + title_len
+
465 sizeof(struct drive_path
) +
466 sizeof(struct device_path
) + path_len
, 1);
471 option
= (struct boot_option
*)buf
;
472 option
->attr
= LOAD_OPTION_ACTIVE
;
473 option
->path_len
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
) +
474 offsetof(struct device_path
, path
) + path_len
+
475 offsetof(struct device_path
, path
);
476 to_utf16(option
->title
, title
);
477 size
= offsetof(struct boot_option
, title
) + title_len
;
480 devicep
= (struct device_path
*)(buf
+ size
);
481 devicep
->type
= MEDIA_DEVICE_PATH
;
482 devicep
->sub_type
= MEDIA_HARDDRIVE_DP
;
483 devicep
->length
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
);
484 devicep
->drive
.part_nr
= part
;
485 devicep
->drive
.part_start
= pstart
;
486 devicep
->drive
.part_size
= psize
;
487 devicep
->drive
.signature_type
= SIGNATURE_TYPE_GUID
;
488 devicep
->drive
.mbr_type
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
489 id128_to_efi_guid(part_uuid
, devicep
->drive
.signature
);
490 size
+= devicep
->length
;
493 devicep
= (struct device_path
*)(buf
+ size
);
494 devicep
->type
= MEDIA_DEVICE_PATH
;
495 devicep
->sub_type
= MEDIA_FILEPATH_DP
;
496 devicep
->length
= offsetof(struct device_path
, path
) + path_len
;
497 to_utf16(devicep
->path
, path
);
498 tilt_slashes(devicep
->path
);
499 size
+= devicep
->length
;
502 devicep
= (struct device_path
*)(buf
+ size
);
503 devicep
->type
= END_DEVICE_PATH_TYPE
;
504 devicep
->sub_type
= END_ENTIRE_DEVICE_PATH_SUBTYPE
;
505 devicep
->length
= offsetof(struct device_path
, path
);
506 size
+= devicep
->length
;
508 xsprintf(boot_id
, "Boot%04X", id
);
509 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, buf
, size
);
512 int efi_remove_boot_option(uint16_t id
) {
515 xsprintf(boot_id
, "Boot%04X", id
);
516 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, 0);
519 int efi_get_boot_order(uint16_t **order
) {
520 _cleanup_free_
void *buf
= NULL
;
524 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "BootOrder", NULL
, &buf
, &l
);
531 if (l
% sizeof(uint16_t) > 0 ||
532 l
/ sizeof(uint16_t) > INT_MAX
)
537 return (int) (l
/ sizeof(uint16_t));
540 int efi_set_boot_order(uint16_t *order
, size_t n
) {
541 return efi_set_variable(EFI_VENDOR_GLOBAL
, "BootOrder", order
, n
* sizeof(uint16_t));
544 static int boot_id_hex(const char s
[4]) {
548 for (i
= 0; i
< 4; i
++)
549 if (s
[i
] >= '0' && s
[i
] <= '9')
550 id
|= (s
[i
] - '0') << (3 - i
) * 4;
551 else if (s
[i
] >= 'A' && s
[i
] <= 'F')
552 id
|= (s
[i
] - 'A' + 10) << (3 - i
) * 4;
559 static int cmp_uint16(const void *_a
, const void *_b
) {
560 const uint16_t *a
= _a
, *b
= _b
;
562 return (int)*a
- (int)*b
;
565 int efi_get_boot_options(uint16_t **options
) {
566 _cleanup_closedir_
DIR *dir
= NULL
;
568 _cleanup_free_
uint16_t *list
= NULL
;
574 dir
= opendir("/sys/firmware/efi/efivars/");
578 FOREACH_DIRENT(de
, dir
, return -errno
) {
581 if (strncmp(de
->d_name
, "Boot", 4) != 0)
584 if (strlen(de
->d_name
) != 45)
587 if (strcmp(de
->d_name
+ 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
590 id
= boot_id_hex(de
->d_name
+ 4);
594 if (!GREEDY_REALLOC(list
, alloc
, count
+ 1))
600 qsort_safe(list
, count
, sizeof(uint16_t), cmp_uint16
);
607 static int read_usec(sd_id128_t vendor
, const char *name
, usec_t
*u
) {
608 _cleanup_free_
char *j
= NULL
;
615 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, name
, &j
);
619 r
= safe_atou64(j
, &x
);
627 int efi_loader_get_boot_usec(usec_t
*firmware
, usec_t
*loader
) {
634 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeInitUSec", &x
);
638 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeExecUSec", &y
);
645 if (y
> USEC_PER_HOUR
)
654 int efi_loader_get_device_part_uuid(sd_id128_t
*u
) {
655 _cleanup_free_
char *p
= NULL
;
658 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, "LoaderDevicePartUUID", &p
);
662 if (sscanf(p
, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
663 &parsed
[0], &parsed
[1], &parsed
[2], &parsed
[3],
664 &parsed
[4], &parsed
[5], &parsed
[6], &parsed
[7],
665 &parsed
[8], &parsed
[9], &parsed
[10], &parsed
[11],
666 &parsed
[12], &parsed
[13], &parsed
[14], &parsed
[15]) != 16)
672 for (i
= 0; i
< ELEMENTSOF(parsed
); i
++)
673 u
->bytes
[i
] = parsed
[i
];
681 char *efi_tilt_backslashes(char *s
) {