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/>.
29 #include "parse-util.h"
36 #define LOAD_OPTION_ACTIVE 0x00000001
37 #define MEDIA_DEVICE_PATH 0x04
38 #define MEDIA_HARDDRIVE_DP 0x01
39 #define MEDIA_FILEPATH_DP 0x04
40 #define SIGNATURE_TYPE_GUID 0x02
41 #define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
42 #define END_DEVICE_PATH_TYPE 0x7f
43 #define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
44 #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
58 uint8_t signature_type
;
67 struct drive_path drive
;
71 bool is_efi_boot(void) {
72 return access("/sys/firmware/efi", F_OK
) >= 0;
75 static int read_flag(const char *varname
) {
77 _cleanup_free_
void *v
= NULL
;
81 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, varname
, NULL
, &v
, &s
);
93 bool is_efi_secure_boot(void) {
94 return read_flag("SecureBoot") > 0;
97 bool is_efi_secure_boot_setup_mode(void) {
98 return read_flag("SetupMode") > 0;
101 int efi_reboot_to_firmware_supported(void) {
105 _cleanup_free_
void *v
= NULL
;
107 if (!is_efi_boot() || detect_container() > 0)
110 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndicationsSupported", NULL
, &v
, &s
);
113 else if (s
!= sizeof(uint64_t))
117 b
&= EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
118 return b
> 0 ? 0 : -EOPNOTSUPP
;
121 static int get_os_indications(uint64_t *os_indication
) {
124 _cleanup_free_
void *v
= NULL
;
126 r
= efi_reboot_to_firmware_supported();
130 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "OsIndications", NULL
, &v
, &s
);
132 /* Some firmware implementations that do support
133 * OsIndications and report that with
134 * OsIndicationsSupported will remove the
135 * OsIndications variable when it is unset. Let's
136 * pretend it's 0 then, to hide this implementation
137 * detail. Note that this call will return -ENOENT
138 * then only if the support for OsIndications is
139 * missing entirely, as determined by
140 * efi_reboot_to_firmware_supported() above. */
145 else if (s
!= sizeof(uint64_t))
148 *os_indication
= *(uint64_t *)v
;
152 int efi_get_reboot_to_firmware(void) {
156 r
= get_os_indications(&b
);
160 return !!(b
& EFI_OS_INDICATIONS_BOOT_TO_FW_UI
);
163 int efi_set_reboot_to_firmware(bool value
) {
167 r
= get_os_indications(&b
);
172 b_new
= b
| EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
174 b_new
= b
& ~EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
176 /* Avoid writing to efi vars store if we can due to firmware bugs. */
178 return efi_set_variable(EFI_VENDOR_GLOBAL
, "OsIndications", &b_new
, sizeof(uint64_t));
183 int efi_get_variable(
190 _cleanup_close_
int fd
= -1;
191 _cleanup_free_
char *p
= NULL
;
195 _cleanup_free_
void *buf
= NULL
;
202 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
203 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
206 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
210 if (fstat(fd
, &st
) < 0)
214 if (st
.st_size
> 4*1024*1024 + 4)
217 n
= read(fd
, &a
, sizeof(a
));
223 buf
= malloc(st
.st_size
- 4 + 2);
227 n
= read(fd
, buf
, (size_t) st
.st_size
- 4);
230 if (n
!= (ssize_t
) st
.st_size
- 4)
233 /* Always NUL terminate (2 bytes, to protect UTF-16) */
234 ((char*) buf
)[st
.st_size
- 4] = 0;
235 ((char*) buf
)[st
.st_size
- 4 + 1] = 0;
239 *size
= (size_t) st
.st_size
- 4;
247 int efi_set_variable(
256 } _packed_
* _cleanup_free_ buf
= NULL
;
257 _cleanup_free_
char *p
= NULL
;
258 _cleanup_close_
int fd
= -1;
263 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
264 name
, SD_ID128_FORMAT_VAL(vendor
)) < 0)
273 fd
= open(p
, O_WRONLY
|O_CREAT
|O_NOCTTY
|O_CLOEXEC
, 0644);
277 buf
= malloc(sizeof(uint32_t) + size
);
281 buf
->attr
= EFI_VARIABLE_NON_VOLATILE
|EFI_VARIABLE_BOOTSERVICE_ACCESS
|EFI_VARIABLE_RUNTIME_ACCESS
;
282 memcpy(buf
->buf
, value
, size
);
284 return loop_write(fd
, buf
, sizeof(uint32_t) + size
, false);
287 int efi_get_variable_string(sd_id128_t vendor
, const char *name
, char **p
) {
288 _cleanup_free_
void *s
= NULL
;
293 r
= efi_get_variable(vendor
, name
, NULL
, &s
, &ss
);
297 x
= utf16_to_utf8(s
, ss
);
305 static size_t utf16_size(const uint16_t *s
) {
311 return (l
+1) * sizeof(uint16_t);
314 static void efi_guid_to_id128(const void *guid
, sd_id128_t
*id128
) {
321 const struct uuid
*uuid
= guid
;
323 id128
->bytes
[0] = (uuid
->u1
>> 24) & 0xff;
324 id128
->bytes
[1] = (uuid
->u1
>> 16) & 0xff;
325 id128
->bytes
[2] = (uuid
->u1
>> 8) & 0xff;
326 id128
->bytes
[3] = (uuid
->u1
) & 0xff;
327 id128
->bytes
[4] = (uuid
->u2
>> 8) & 0xff;
328 id128
->bytes
[5] = (uuid
->u2
) & 0xff;
329 id128
->bytes
[6] = (uuid
->u3
>> 8) & 0xff;
330 id128
->bytes
[7] = (uuid
->u3
) & 0xff;
331 memcpy(&id128
->bytes
[8], uuid
->u4
, sizeof(uuid
->u4
));
334 int efi_get_boot_option(
337 sd_id128_t
*part_uuid
,
342 _cleanup_free_
uint8_t *buf
= NULL
;
344 struct boot_option
*header
;
346 _cleanup_free_
char *s
= NULL
, *p
= NULL
;
347 sd_id128_t p_uuid
= SD_ID128_NULL
;
350 xsprintf(boot_id
, "Boot%04X", id
);
351 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, (void **)&buf
, &l
);
354 if (l
< sizeof(struct boot_option
))
357 header
= (struct boot_option
*)buf
;
358 title_size
= utf16_size(header
->title
);
359 if (title_size
> l
- offsetof(struct boot_option
, title
))
363 s
= utf16_to_utf8(header
->title
, title_size
);
368 if (header
->path_len
> 0) {
372 dbuf
= buf
+ offsetof(struct boot_option
, title
) + title_size
;
374 while (dnext
< header
->path_len
) {
375 struct device_path
*dpath
;
377 dpath
= (struct device_path
*)(dbuf
+ dnext
);
378 if (dpath
->length
< 4)
381 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
382 if (dpath
->type
== END_DEVICE_PATH_TYPE
&& dpath
->sub_type
== END_ENTIRE_DEVICE_PATH_SUBTYPE
)
385 dnext
+= dpath
->length
;
387 /* Type 0x04 – Media Device Path */
388 if (dpath
->type
!= MEDIA_DEVICE_PATH
)
391 /* Sub-Type 1 – Hard Drive */
392 if (dpath
->sub_type
== MEDIA_HARDDRIVE_DP
) {
393 /* 0x02 – GUID Partition Table */
394 if (dpath
->drive
.mbr_type
!= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
)
397 /* 0x02 – GUID signature */
398 if (dpath
->drive
.signature_type
!= SIGNATURE_TYPE_GUID
)
402 efi_guid_to_id128(dpath
->drive
.signature
, &p_uuid
);
406 /* Sub-Type 4 – File Path */
407 if (dpath
->sub_type
== MEDIA_FILEPATH_DP
&& !p
&& path
) {
408 p
= utf16_to_utf8(dpath
->path
, dpath
->length
-4);
409 efi_tilt_backslashes(p
);
426 *active
= !!(header
->attr
& LOAD_OPTION_ACTIVE
);
431 static void to_utf16(uint16_t *dest
, const char *src
) {
434 for (i
= 0; src
[i
] != '\0'; i
++)
446 static void id128_to_efi_guid(sd_id128_t id
, void *guid
) {
447 struct guid
*uuid
= guid
;
449 uuid
->u1
= id
.bytes
[0] << 24 | id
.bytes
[1] << 16 | id
.bytes
[2] << 8 | id
.bytes
[3];
450 uuid
->u2
= id
.bytes
[4] << 8 | id
.bytes
[5];
451 uuid
->u3
= id
.bytes
[6] << 8 | id
.bytes
[7];
452 memcpy(uuid
->u4
, id
.bytes
+8, sizeof(uuid
->u4
));
455 static uint16_t *tilt_slashes(uint16_t *s
) {
465 int efi_add_boot_option(uint16_t id
, const char *title
,
466 uint32_t part
, uint64_t pstart
, uint64_t psize
,
467 sd_id128_t part_uuid
, const char *path
) {
472 struct boot_option
*option
;
473 struct device_path
*devicep
;
474 _cleanup_free_
char *buf
= NULL
;
476 title_len
= (strlen(title
)+1) * 2;
477 path_len
= (strlen(path
)+1) * 2;
479 buf
= calloc(sizeof(struct boot_option
) + title_len
+
480 sizeof(struct drive_path
) +
481 sizeof(struct device_path
) + path_len
, 1);
486 option
= (struct boot_option
*)buf
;
487 option
->attr
= LOAD_OPTION_ACTIVE
;
488 option
->path_len
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
) +
489 offsetof(struct device_path
, path
) + path_len
+
490 offsetof(struct device_path
, path
);
491 to_utf16(option
->title
, title
);
492 size
= offsetof(struct boot_option
, title
) + title_len
;
495 devicep
= (struct device_path
*)(buf
+ size
);
496 devicep
->type
= MEDIA_DEVICE_PATH
;
497 devicep
->sub_type
= MEDIA_HARDDRIVE_DP
;
498 devicep
->length
= offsetof(struct device_path
, drive
) + sizeof(struct drive_path
);
499 devicep
->drive
.part_nr
= part
;
500 devicep
->drive
.part_start
= pstart
;
501 devicep
->drive
.part_size
= psize
;
502 devicep
->drive
.signature_type
= SIGNATURE_TYPE_GUID
;
503 devicep
->drive
.mbr_type
= MBR_TYPE_EFI_PARTITION_TABLE_HEADER
;
504 id128_to_efi_guid(part_uuid
, devicep
->drive
.signature
);
505 size
+= devicep
->length
;
508 devicep
= (struct device_path
*)(buf
+ size
);
509 devicep
->type
= MEDIA_DEVICE_PATH
;
510 devicep
->sub_type
= MEDIA_FILEPATH_DP
;
511 devicep
->length
= offsetof(struct device_path
, path
) + path_len
;
512 to_utf16(devicep
->path
, path
);
513 tilt_slashes(devicep
->path
);
514 size
+= devicep
->length
;
517 devicep
= (struct device_path
*)(buf
+ size
);
518 devicep
->type
= END_DEVICE_PATH_TYPE
;
519 devicep
->sub_type
= END_ENTIRE_DEVICE_PATH_SUBTYPE
;
520 devicep
->length
= offsetof(struct device_path
, path
);
521 size
+= devicep
->length
;
523 xsprintf(boot_id
, "Boot%04X", id
);
524 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, buf
, size
);
527 int efi_remove_boot_option(uint16_t id
) {
530 xsprintf(boot_id
, "Boot%04X", id
);
531 return efi_set_variable(EFI_VENDOR_GLOBAL
, boot_id
, NULL
, 0);
534 int efi_get_boot_order(uint16_t **order
) {
535 _cleanup_free_
void *buf
= NULL
;
539 r
= efi_get_variable(EFI_VENDOR_GLOBAL
, "BootOrder", NULL
, &buf
, &l
);
546 if (l
% sizeof(uint16_t) > 0 ||
547 l
/ sizeof(uint16_t) > INT_MAX
)
552 return (int) (l
/ sizeof(uint16_t));
555 int efi_set_boot_order(uint16_t *order
, size_t n
) {
556 return efi_set_variable(EFI_VENDOR_GLOBAL
, "BootOrder", order
, n
* sizeof(uint16_t));
559 static int boot_id_hex(const char s
[4]) {
563 for (i
= 0; i
< 4; i
++)
564 if (s
[i
] >= '0' && s
[i
] <= '9')
565 id
|= (s
[i
] - '0') << (3 - i
) * 4;
566 else if (s
[i
] >= 'A' && s
[i
] <= 'F')
567 id
|= (s
[i
] - 'A' + 10) << (3 - i
) * 4;
574 static int cmp_uint16(const void *_a
, const void *_b
) {
575 const uint16_t *a
= _a
, *b
= _b
;
577 return (int)*a
- (int)*b
;
580 int efi_get_boot_options(uint16_t **options
) {
581 _cleanup_closedir_
DIR *dir
= NULL
;
583 _cleanup_free_
uint16_t *list
= NULL
;
589 dir
= opendir("/sys/firmware/efi/efivars/");
593 FOREACH_DIRENT(de
, dir
, return -errno
) {
596 if (strncmp(de
->d_name
, "Boot", 4) != 0)
599 if (strlen(de
->d_name
) != 45)
602 if (strcmp(de
->d_name
+ 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
605 id
= boot_id_hex(de
->d_name
+ 4);
609 if (!GREEDY_REALLOC(list
, alloc
, count
+ 1))
615 qsort_safe(list
, count
, sizeof(uint16_t), cmp_uint16
);
622 static int read_usec(sd_id128_t vendor
, const char *name
, usec_t
*u
) {
623 _cleanup_free_
char *j
= NULL
;
630 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, name
, &j
);
634 r
= safe_atou64(j
, &x
);
642 int efi_loader_get_boot_usec(usec_t
*firmware
, usec_t
*loader
) {
649 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeInitUSec", &x
);
653 r
= read_usec(EFI_VENDOR_LOADER
, "LoaderTimeExecUSec", &y
);
660 if (y
> USEC_PER_HOUR
)
669 int efi_loader_get_device_part_uuid(sd_id128_t
*u
) {
670 _cleanup_free_
char *p
= NULL
;
673 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, "LoaderDevicePartUUID", &p
);
677 if (sscanf(p
, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
678 &parsed
[0], &parsed
[1], &parsed
[2], &parsed
[3],
679 &parsed
[4], &parsed
[5], &parsed
[6], &parsed
[7],
680 &parsed
[8], &parsed
[9], &parsed
[10], &parsed
[11],
681 &parsed
[12], &parsed
[13], &parsed
[14], &parsed
[15]) != 16)
687 for (i
= 0; i
< ELEMENTSOF(parsed
); i
++)
688 u
->bytes
[i
] = parsed
[i
];
696 char *efi_tilt_backslashes(char *s
) {