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 "alloc-util.h"
27 #include "dirent-util.h"
31 #include "parse-util.h"
32 #include "stdio-util.h"
39 #define LOAD_OPTION_ACTIVE 0x00000001
40 #define MEDIA_DEVICE_PATH 0x04
41 #define MEDIA_HARDDRIVE_DP 0x01
42 #define MEDIA_FILEPATH_DP 0x04
43 #define SIGNATURE_TYPE_GUID 0x02
44 #define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
45 #define END_DEVICE_PATH_TYPE 0x7f
46 #define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
47 #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
61 uint8_t signature_type
;
70 struct drive_path drive
;
74 bool is_efi_boot(void) {
75 return access("/sys/firmware/efi", F_OK
) >= 0;
78 static int read_flag(const char *varname
) {
80 _cleanup_free_
void *v
= NULL
;
84 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, varname
, NULL
, &v
, &s
);
96 bool is_efi_secure_boot(void) {
97 return read_flag("SecureBoot") > 0;
100 bool is_efi_secure_boot_setup_mode(void) {
101 return read_flag("SetupMode") > 0;
104 int efi_reboot_to_firmware_supported(void) {
108 _cleanup_free_
void *v
= NULL
;
110 if (!is_efi_boot() || detect_container() > 0)
113 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndicationsSupported", NULL
, &v
, &s
);
116 else if (s
!= sizeof(uint64_t))
120 b
&= EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
121 return b
> 0 ? 0 : -EOPNOTSUPP
;
124 static int get_os_indications(uint64_t *os_indication
) {
127 _cleanup_free_
void *v
= NULL
;
129 r
= efi_reboot_to_firmware_supported();
133 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndications", NULL
, &v
, &s
);
135 /* Some firmware implementations that do support
136 * OsIndications and report that with
137 * OsIndicationsSupported will remove the
138 * OsIndications variable when it is unset. Let's
139 * pretend it's 0 then, to hide this implementation
140 * detail. Note that this call will return -ENOENT
141 * then only if the support for OsIndications is
142 * missing entirely, as determined by
143 * efi_reboot_to_firmware_supported() above. */
148 else if (s
!= sizeof(uint64_t))
151 *os_indication
= *(uint64_t *)v
;
155 int efi_get_reboot_to_firmware(void) {
159 r
= get_os_indications(&b
);
163 return !!(b
& EFI_OS_INDICATIONS_BOOT_TO_FW_UI
);
166 int efi_set_reboot_to_firmware(bool value
) {
170 r
= get_os_indications(&b
);
175 b_new
= b
| EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
177 b_new
= b
& ~EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
179 /* Avoid writing to efi vars store if we can due to firmware bugs. */
181 return efi_set_variable(EFI_VENDOR_GLOBAL
, "OsIndications", &b_new
, sizeof(uint64_t));
186 int efi_get_variable(
193 _cleanup_close_
int fd
= -1;
194 _cleanup_free_
char *p
= NULL
;
198 _cleanup_free_
void *buf
= NULL
;
205 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
206 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
209 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
213 if (fstat(fd
, &st
) < 0)
217 if (st
.st_size
> 4*1024*1024 + 4)
220 n
= read(fd
, &a
, sizeof(a
));
226 buf
= malloc(st
.st_size
- 4 + 2);
230 n
= read(fd
, buf
, (size_t) st
.st_size
- 4);
233 if (n
!= (ssize_t
) st
.st_size
- 4)
236 /* Always NUL terminate (2 bytes, to protect UTF-16) */
237 ((char*) buf
)[st
.st_size
- 4] = 0;
238 ((char*) buf
)[st
.st_size
- 4 + 1] = 0;
242 *size
= (size_t) st
.st_size
- 4;
250 int efi_set_variable(
259 } _packed_
* _cleanup_free_ buf
= NULL
;
260 _cleanup_free_
char *p
= NULL
;
261 _cleanup_close_
int fd
= -1;
266 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
267 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
276 fd
= open(p
, O_WRONLY
|O_CREAT
|O_NOCTTY
|O_CLOEXEC
, 0644);
280 buf
= malloc(sizeof(uint32_t) + size
);
284 buf
->attr
= EFI_VARIABLE_NON_VOLATILE
|EFI_VARIABLE_BOOTSERVICE_ACCESS
|EFI_VARIABLE_RUNTIME_ACCESS
;
285 memcpy(buf
->buf
, value
, size
);
287 return loop_write(fd
, buf
, sizeof(uint32_t) + size
, false);
290 int efi_get_variable_string(sd_id128_t vendor
, const char *name
, char **p
) {
291 _cleanup_free_
void *s
= NULL
;
296 r
= efi_get_variable(vendor
, name
, NULL
, &s
, &ss
);
300 x
= utf16_to_utf8(s
, ss
);
308 static size_t utf16_size(const uint16_t *s
) {
314 return (l
+1) * sizeof(uint16_t);
317 static void efi_guid_to_id128(const void *guid
, sd_id128_t
*id128
) {
324 const struct uuid
*uuid
= guid
;
326 id128
->bytes
[0] = (uuid
->u1
>> 24) & 0xff;
327 id128
->bytes
[1] = (uuid
->u1
>> 16) & 0xff;
328 id128
->bytes
[2] = (uuid
->u1
>> 8) & 0xff;
329 id128
->bytes
[3] = (uuid
->u1
) & 0xff;
330 id128
->bytes
[4] = (uuid
->u2
>> 8) & 0xff;
331 id128
->bytes
[5] = (uuid
->u2
) & 0xff;
332 id128
->bytes
[6] = (uuid
->u3
>> 8) & 0xff;
333 id128
->bytes
[7] = (uuid
->u3
) & 0xff;
334 memcpy(&id128
->bytes
[8], uuid
->u4
, sizeof(uuid
->u4
));
337 int efi_get_boot_option(
340 sd_id128_t
*part_uuid
,
345 _cleanup_free_
uint8_t *buf
= NULL
;
347 struct boot_option
*header
;
349 _cleanup_free_
char *s
= NULL
, *p
= NULL
;
350 sd_id128_t p_uuid
= SD_ID128_NULL
;
353 xsprintf(boot_id
, "Boot%04X", id
);
354 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, (void **)&buf
, &l
);
357 if (l
< sizeof(struct boot_option
))
360 header
= (struct boot_option
*)buf
;
361 title_size
= utf16_size(header
->title
);
362 if (title_size
> l
- offsetof(struct boot_option
, title
))
366 s
= utf16_to_utf8(header
->title
, title_size
);
371 if (header
->path_len
> 0) {
375 dbuf
= buf
+ offsetof(struct boot_option
, title
) + title_size
;
377 while (dnext
< header
->path_len
) {
378 struct device_path
*dpath
;
380 dpath
= (struct device_path
*)(dbuf
+ dnext
);
381 if (dpath
->length
< 4)
384 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
385 if (dpath
->type
== END_DEVICE_PATH_TYPE
&& dpath
->sub_type
== END_ENTIRE_DEVICE_PATH_SUBTYPE
)
388 dnext
+= dpath
->length
;
390 /* Type 0x04 – Media Device Path */
391 if (dpath
->type
!= MEDIA_DEVICE_PATH
)
394 /* Sub-Type 1 – Hard Drive */
395 if (dpath
->sub_type
== MEDIA_HARDDRIVE_DP
) {
396 /* 0x02 – GUID Partition Table */
397 if (dpath
->drive
.mbr_type
!= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
)
400 /* 0x02 – GUID signature */
401 if (dpath
->drive
.signature_type
!= SIGNATURE_TYPE_GUID
)
405 efi_guid_to_id128(dpath
->drive
.signature
, &p_uuid
);
409 /* Sub-Type 4 – File Path */
410 if (dpath
->sub_type
== MEDIA_FILEPATH_DP
&& !p
&& path
) {
411 p
= utf16_to_utf8(dpath
->path
, dpath
->length
-4);
412 efi_tilt_backslashes(p
);
429 *active
= !!(header
->attr
& LOAD_OPTION_ACTIVE
);
434 static void to_utf16(uint16_t *dest
, const char *src
) {
437 for (i
= 0; src
[i
] != '\0'; i
++)
449 static void id128_to_efi_guid(sd_id128_t id
, void *guid
) {
450 struct guid
*uuid
= guid
;
452 uuid
->u1
= id
.bytes
[0] << 24 | id
.bytes
[1] << 16 | id
.bytes
[2] << 8 | id
.bytes
[3];
453 uuid
->u2
= id
.bytes
[4] << 8 | id
.bytes
[5];
454 uuid
->u3
= id
.bytes
[6] << 8 | id
.bytes
[7];
455 memcpy(uuid
->u4
, id
.bytes
+8, sizeof(uuid
->u4
));
458 static uint16_t *tilt_slashes(uint16_t *s
) {
468 int efi_add_boot_option(uint16_t id
, const char *title
,
469 uint32_t part
, uint64_t pstart
, uint64_t psize
,
470 sd_id128_t part_uuid
, const char *path
) {
475 struct boot_option
*option
;
476 struct device_path
*devicep
;
477 _cleanup_free_
char *buf
= NULL
;
479 title_len
= (strlen(title
)+1) * 2;
480 path_len
= (strlen(path
)+1) * 2;
482 buf
= calloc(sizeof(struct boot_option
) + title_len
+
483 sizeof(struct drive_path
) +
484 sizeof(struct device_path
) + path_len
, 1);
489 option
= (struct boot_option
*)buf
;
490 option
->attr
= LOAD_OPTION_ACTIVE
;
491 option
->path_len
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
) +
492 offsetof(struct device_path
, path
) + path_len
+
493 offsetof(struct device_path
, path
);
494 to_utf16(option
->title
, title
);
495 size
= offsetof(struct boot_option
, title
) + title_len
;
498 devicep
= (struct device_path
*)(buf
+ size
);
499 devicep
->type
= MEDIA_DEVICE_PATH
;
500 devicep
->sub_type
= MEDIA_HARDDRIVE_DP
;
501 devicep
->length
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
);
502 devicep
->drive
.part_nr
= part
;
503 devicep
->drive
.part_start
= pstart
;
504 devicep
->drive
.part_size
= psize
;
505 devicep
->drive
.signature_type
= SIGNATURE_TYPE_GUID
;
506 devicep
->drive
.mbr_type
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
507 id128_to_efi_guid(part_uuid
, devicep
->drive
.signature
);
508 size
+= devicep
->length
;
511 devicep
= (struct device_path
*)(buf
+ size
);
512 devicep
->type
= MEDIA_DEVICE_PATH
;
513 devicep
->sub_type
= MEDIA_FILEPATH_DP
;
514 devicep
->length
= offsetof(struct device_path
, path
) + path_len
;
515 to_utf16(devicep
->path
, path
);
516 tilt_slashes(devicep
->path
);
517 size
+= devicep
->length
;
520 devicep
= (struct device_path
*)(buf
+ size
);
521 devicep
->type
= END_DEVICE_PATH_TYPE
;
522 devicep
->sub_type
= END_ENTIRE_DEVICE_PATH_SUBTYPE
;
523 devicep
->length
= offsetof(struct device_path
, path
);
524 size
+= devicep
->length
;
526 xsprintf(boot_id
, "Boot%04X", id
);
527 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, buf
, size
);
530 int efi_remove_boot_option(uint16_t id
) {
533 xsprintf(boot_id
, "Boot%04X", id
);
534 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, 0);
537 int efi_get_boot_order(uint16_t **order
) {
538 _cleanup_free_
void *buf
= NULL
;
542 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "BootOrder", NULL
, &buf
, &l
);
549 if (l
% sizeof(uint16_t) > 0 ||
550 l
/ sizeof(uint16_t) > INT_MAX
)
555 return (int) (l
/ sizeof(uint16_t));
558 int efi_set_boot_order(uint16_t *order
, size_t n
) {
559 return efi_set_variable(EFI_VENDOR_GLOBAL
, "BootOrder", order
, n
* sizeof(uint16_t));
562 static int boot_id_hex(const char s
[4]) {
566 for (i
= 0; i
< 4; i
++)
567 if (s
[i
] >= '0' && s
[i
] <= '9')
568 id
|= (s
[i
] - '0') << (3 - i
) * 4;
569 else if (s
[i
] >= 'A' && s
[i
] <= 'F')
570 id
|= (s
[i
] - 'A' + 10) << (3 - i
) * 4;
577 static int cmp_uint16(const void *_a
, const void *_b
) {
578 const uint16_t *a
= _a
, *b
= _b
;
580 return (int)*a
- (int)*b
;
583 int efi_get_boot_options(uint16_t **options
) {
584 _cleanup_closedir_
DIR *dir
= NULL
;
586 _cleanup_free_
uint16_t *list
= NULL
;
592 dir
= opendir("/sys/firmware/efi/efivars/");
596 FOREACH_DIRENT(de
, dir
, return -errno
) {
599 if (strncmp(de
->d_name
, "Boot", 4) != 0)
602 if (strlen(de
->d_name
) != 45)
605 if (strcmp(de
->d_name
+ 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
608 id
= boot_id_hex(de
->d_name
+ 4);
612 if (!GREEDY_REALLOC(list
, alloc
, count
+ 1))
618 qsort_safe(list
, count
, sizeof(uint16_t), cmp_uint16
);
625 static int read_usec(sd_id128_t vendor
, const char *name
, usec_t
*u
) {
626 _cleanup_free_
char *j
= NULL
;
633 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, name
, &j
);
637 r
= safe_atou64(j
, &x
);
645 int efi_loader_get_boot_usec(usec_t
*firmware
, usec_t
*loader
) {
652 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeInitUSec", &x
);
656 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeExecUSec", &y
);
663 if (y
> USEC_PER_HOUR
)
672 int efi_loader_get_device_part_uuid(sd_id128_t
*u
) {
673 _cleanup_free_
char *p
= NULL
;
676 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, "LoaderDevicePartUUID", &p
);
680 if (sscanf(p
, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
681 &parsed
[0], &parsed
[1], &parsed
[2], &parsed
[3],
682 &parsed
[4], &parsed
[5], &parsed
[6], &parsed
[7],
683 &parsed
[8], &parsed
[9], &parsed
[10], &parsed
[11],
684 &parsed
[12], &parsed
[13], &parsed
[14], &parsed
[15]) != 16)
690 for (i
= 0; i
< ELEMENTSOF(parsed
); i
++)
691 u
->bytes
[i
] = parsed
[i
];
699 char *efi_tilt_backslashes(char *s
) {