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/>.
35 #define LOAD_OPTION_ACTIVE 0x00000001
36 #define MEDIA_DEVICE_PATH 0x04
37 #define MEDIA_HARDDRIVE_DP 0x01
38 #define MEDIA_FILEPATH_DP 0x04
39 #define SIGNATURE_TYPE_GUID 0x02
40 #define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
41 #define END_DEVICE_PATH_TYPE 0x7f
42 #define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
43 #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
57 uint8_t signature_type
;
66 struct drive_path drive
;
70 bool is_efi_boot(void) {
71 return access("/sys/firmware/efi", F_OK
) >= 0;
74 static int read_flag(const char *varname
) {
76 _cleanup_free_
void *v
= NULL
;
80 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, varname
, NULL
, &v
, &s
);
92 bool is_efi_secure_boot(void) {
93 return read_flag("SecureBoot") > 0;
96 bool is_efi_secure_boot_setup_mode(void) {
97 return read_flag("SetupMode") > 0;
100 int efi_reboot_to_firmware_supported(void) {
104 _cleanup_free_
void *v
= NULL
;
106 if (!is_efi_boot() || detect_container() > 0)
109 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndicationsSupported", NULL
, &v
, &s
);
112 else if (s
!= sizeof(uint64_t))
116 b
&= EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
117 return b
> 0 ? 0 : -EOPNOTSUPP
;
120 static int get_os_indications(uint64_t *os_indication
) {
123 _cleanup_free_
void *v
= NULL
;
125 r
= efi_reboot_to_firmware_supported();
129 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndications", NULL
, &v
, &s
);
131 /* Some firmware implementations that do support
132 * OsIndications and report that with
133 * OsIndicationsSupported will remove the
134 * OsIndications variable when it is unset. Let's
135 * pretend it's 0 then, to hide this implementation
136 * detail. Note that this call will return -ENOENT
137 * then only if the support for OsIndications is
138 * missing entirely, as determined by
139 * efi_reboot_to_firmware_supported() above. */
144 else if (s
!= sizeof(uint64_t))
147 *os_indication
= *(uint64_t *)v
;
151 int efi_get_reboot_to_firmware(void) {
155 r
= get_os_indications(&b
);
159 return !!(b
& EFI_OS_INDICATIONS_BOOT_TO_FW_UI
);
162 int efi_set_reboot_to_firmware(bool value
) {
166 r
= get_os_indications(&b
);
171 b_new
= b
| EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
173 b_new
= b
& ~EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
175 /* Avoid writing to efi vars store if we can due to firmware bugs. */
177 return efi_set_variable(EFI_VENDOR_GLOBAL
, "OsIndications", &b_new
, sizeof(uint64_t));
182 int efi_get_variable(
189 _cleanup_close_
int fd
= -1;
190 _cleanup_free_
char *p
= NULL
;
194 _cleanup_free_
void *buf
= NULL
;
201 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
202 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
205 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
209 if (fstat(fd
, &st
) < 0)
213 if (st
.st_size
> 4*1024*1024 + 4)
216 n
= read(fd
, &a
, sizeof(a
));
222 buf
= malloc(st
.st_size
- 4 + 2);
226 n
= read(fd
, buf
, (size_t) st
.st_size
- 4);
229 if (n
!= (ssize_t
) st
.st_size
- 4)
232 /* Always NUL terminate (2 bytes, to protect UTF-16) */
233 ((char*) buf
)[st
.st_size
- 4] = 0;
234 ((char*) buf
)[st
.st_size
- 4 + 1] = 0;
238 *size
= (size_t) st
.st_size
- 4;
246 int efi_set_variable(
255 } _packed_
* _cleanup_free_ buf
= NULL
;
256 _cleanup_free_
char *p
= NULL
;
257 _cleanup_close_
int fd
= -1;
262 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
263 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
272 fd
= open(p
, O_WRONLY
|O_CREAT
|O_NOCTTY
|O_CLOEXEC
, 0644);
276 buf
= malloc(sizeof(uint32_t) + size
);
280 buf
->attr
= EFI_VARIABLE_NON_VOLATILE
|EFI_VARIABLE_BOOTSERVICE_ACCESS
|EFI_VARIABLE_RUNTIME_ACCESS
;
281 memcpy(buf
->buf
, value
, size
);
283 return loop_write(fd
, buf
, sizeof(uint32_t) + size
, false);
286 int efi_get_variable_string(sd_id128_t vendor
, const char *name
, char **p
) {
287 _cleanup_free_
void *s
= NULL
;
292 r
= efi_get_variable(vendor
, name
, NULL
, &s
, &ss
);
296 x
= utf16_to_utf8(s
, ss
);
304 static size_t utf16_size(const uint16_t *s
) {
310 return (l
+1) * sizeof(uint16_t);
313 static void efi_guid_to_id128(const void *guid
, sd_id128_t
*id128
) {
320 const struct uuid
*uuid
= guid
;
322 id128
->bytes
[0] = (uuid
->u1
>> 24) & 0xff;
323 id128
->bytes
[1] = (uuid
->u1
>> 16) & 0xff;
324 id128
->bytes
[2] = (uuid
->u1
>> 8) & 0xff;
325 id128
->bytes
[3] = (uuid
->u1
) & 0xff;
326 id128
->bytes
[4] = (uuid
->u2
>> 8) & 0xff;
327 id128
->bytes
[5] = (uuid
->u2
) & 0xff;
328 id128
->bytes
[6] = (uuid
->u3
>> 8) & 0xff;
329 id128
->bytes
[7] = (uuid
->u3
) & 0xff;
330 memcpy(&id128
->bytes
[8], uuid
->u4
, sizeof(uuid
->u4
));
333 int efi_get_boot_option(
336 sd_id128_t
*part_uuid
,
341 _cleanup_free_
uint8_t *buf
= NULL
;
343 struct boot_option
*header
;
345 _cleanup_free_
char *s
= NULL
, *p
= NULL
;
346 sd_id128_t p_uuid
= SD_ID128_NULL
;
349 xsprintf(boot_id
, "Boot%04X", id
);
350 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, (void **)&buf
, &l
);
353 if (l
< sizeof(struct boot_option
))
356 header
= (struct boot_option
*)buf
;
357 title_size
= utf16_size(header
->title
);
358 if (title_size
> l
- offsetof(struct boot_option
, title
))
362 s
= utf16_to_utf8(header
->title
, title_size
);
367 if (header
->path_len
> 0) {
371 dbuf
= buf
+ offsetof(struct boot_option
, title
) + title_size
;
373 while (dnext
< header
->path_len
) {
374 struct device_path
*dpath
;
376 dpath
= (struct device_path
*)(dbuf
+ dnext
);
377 if (dpath
->length
< 4)
380 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
381 if (dpath
->type
== END_DEVICE_PATH_TYPE
&& dpath
->sub_type
== END_ENTIRE_DEVICE_PATH_SUBTYPE
)
384 dnext
+= dpath
->length
;
386 /* Type 0x04 – Media Device Path */
387 if (dpath
->type
!= MEDIA_DEVICE_PATH
)
390 /* Sub-Type 1 – Hard Drive */
391 if (dpath
->sub_type
== MEDIA_HARDDRIVE_DP
) {
392 /* 0x02 – GUID Partition Table */
393 if (dpath
->drive
.mbr_type
!= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
)
396 /* 0x02 – GUID signature */
397 if (dpath
->drive
.signature_type
!= SIGNATURE_TYPE_GUID
)
401 efi_guid_to_id128(dpath
->drive
.signature
, &p_uuid
);
405 /* Sub-Type 4 – File Path */
406 if (dpath
->sub_type
== MEDIA_FILEPATH_DP
&& !p
&& path
) {
407 p
= utf16_to_utf8(dpath
->path
, dpath
->length
-4);
408 efi_tilt_backslashes(p
);
425 *active
= !!(header
->attr
& LOAD_OPTION_ACTIVE
);
430 static void to_utf16(uint16_t *dest
, const char *src
) {
433 for (i
= 0; src
[i
] != '\0'; i
++)
445 static void id128_to_efi_guid(sd_id128_t id
, void *guid
) {
446 struct guid
*uuid
= guid
;
448 uuid
->u1
= id
.bytes
[0] << 24 | id
.bytes
[1] << 16 | id
.bytes
[2] << 8 | id
.bytes
[3];
449 uuid
->u2
= id
.bytes
[4] << 8 | id
.bytes
[5];
450 uuid
->u3
= id
.bytes
[6] << 8 | id
.bytes
[7];
451 memcpy(uuid
->u4
, id
.bytes
+8, sizeof(uuid
->u4
));
454 static uint16_t *tilt_slashes(uint16_t *s
) {
464 int efi_add_boot_option(uint16_t id
, const char *title
,
465 uint32_t part
, uint64_t pstart
, uint64_t psize
,
466 sd_id128_t part_uuid
, const char *path
) {
471 struct boot_option
*option
;
472 struct device_path
*devicep
;
473 _cleanup_free_
char *buf
= NULL
;
475 title_len
= (strlen(title
)+1) * 2;
476 path_len
= (strlen(path
)+1) * 2;
478 buf
= calloc(sizeof(struct boot_option
) + title_len
+
479 sizeof(struct drive_path
) +
480 sizeof(struct device_path
) + path_len
, 1);
485 option
= (struct boot_option
*)buf
;
486 option
->attr
= LOAD_OPTION_ACTIVE
;
487 option
->path_len
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
) +
488 offsetof(struct device_path
, path
) + path_len
+
489 offsetof(struct device_path
, path
);
490 to_utf16(option
->title
, title
);
491 size
= offsetof(struct boot_option
, title
) + title_len
;
494 devicep
= (struct device_path
*)(buf
+ size
);
495 devicep
->type
= MEDIA_DEVICE_PATH
;
496 devicep
->sub_type
= MEDIA_HARDDRIVE_DP
;
497 devicep
->length
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
);
498 devicep
->drive
.part_nr
= part
;
499 devicep
->drive
.part_start
= pstart
;
500 devicep
->drive
.part_size
= psize
;
501 devicep
->drive
.signature_type
= SIGNATURE_TYPE_GUID
;
502 devicep
->drive
.mbr_type
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
503 id128_to_efi_guid(part_uuid
, devicep
->drive
.signature
);
504 size
+= devicep
->length
;
507 devicep
= (struct device_path
*)(buf
+ size
);
508 devicep
->type
= MEDIA_DEVICE_PATH
;
509 devicep
->sub_type
= MEDIA_FILEPATH_DP
;
510 devicep
->length
= offsetof(struct device_path
, path
) + path_len
;
511 to_utf16(devicep
->path
, path
);
512 tilt_slashes(devicep
->path
);
513 size
+= devicep
->length
;
516 devicep
= (struct device_path
*)(buf
+ size
);
517 devicep
->type
= END_DEVICE_PATH_TYPE
;
518 devicep
->sub_type
= END_ENTIRE_DEVICE_PATH_SUBTYPE
;
519 devicep
->length
= offsetof(struct device_path
, path
);
520 size
+= devicep
->length
;
522 xsprintf(boot_id
, "Boot%04X", id
);
523 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, buf
, size
);
526 int efi_remove_boot_option(uint16_t id
) {
529 xsprintf(boot_id
, "Boot%04X", id
);
530 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, 0);
533 int efi_get_boot_order(uint16_t **order
) {
534 _cleanup_free_
void *buf
= NULL
;
538 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "BootOrder", NULL
, &buf
, &l
);
545 if (l
% sizeof(uint16_t) > 0 ||
546 l
/ sizeof(uint16_t) > INT_MAX
)
551 return (int) (l
/ sizeof(uint16_t));
554 int efi_set_boot_order(uint16_t *order
, size_t n
) {
555 return efi_set_variable(EFI_VENDOR_GLOBAL
, "BootOrder", order
, n
* sizeof(uint16_t));
558 static int boot_id_hex(const char s
[4]) {
562 for (i
= 0; i
< 4; i
++)
563 if (s
[i
] >= '0' && s
[i
] <= '9')
564 id
|= (s
[i
] - '0') << (3 - i
) * 4;
565 else if (s
[i
] >= 'A' && s
[i
] <= 'F')
566 id
|= (s
[i
] - 'A' + 10) << (3 - i
) * 4;
573 static int cmp_uint16(const void *_a
, const void *_b
) {
574 const uint16_t *a
= _a
, *b
= _b
;
576 return (int)*a
- (int)*b
;
579 int efi_get_boot_options(uint16_t **options
) {
580 _cleanup_closedir_
DIR *dir
= NULL
;
582 _cleanup_free_
uint16_t *list
= NULL
;
588 dir
= opendir("/sys/firmware/efi/efivars/");
592 FOREACH_DIRENT(de
, dir
, return -errno
) {
595 if (strncmp(de
->d_name
, "Boot", 4) != 0)
598 if (strlen(de
->d_name
) != 45)
601 if (strcmp(de
->d_name
+ 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
604 id
= boot_id_hex(de
->d_name
+ 4);
608 if (!GREEDY_REALLOC(list
, alloc
, count
+ 1))
614 qsort_safe(list
, count
, sizeof(uint16_t), cmp_uint16
);
621 static int read_usec(sd_id128_t vendor
, const char *name
, usec_t
*u
) {
622 _cleanup_free_
char *j
= NULL
;
629 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, name
, &j
);
633 r
= safe_atou64(j
, &x
);
641 int efi_loader_get_boot_usec(usec_t
*firmware
, usec_t
*loader
) {
648 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeInitUSec", &x
);
652 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeExecUSec", &y
);
659 if (y
> USEC_PER_HOUR
)
668 int efi_loader_get_device_part_uuid(sd_id128_t
*u
) {
669 _cleanup_free_
char *p
= NULL
;
672 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, "LoaderDevicePartUUID", &p
);
676 if (sscanf(p
, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
677 &parsed
[0], &parsed
[1], &parsed
[2], &parsed
[3],
678 &parsed
[4], &parsed
[5], &parsed
[6], &parsed
[7],
679 &parsed
[8], &parsed
[9], &parsed
[10], &parsed
[11],
680 &parsed
[12], &parsed
[13], &parsed
[14], &parsed
[15]) != 16)
686 for (i
= 0; i
< ELEMENTSOF(parsed
); i
++)
687 u
->bytes
[i
] = parsed
[i
];
695 char *efi_tilt_backslashes(char *s
) {