]>
git.ipfire.org Git - people/ms/u-boot.git/blob - lib/efi_loader/efi_bootmgr.c
4 * Copyright (c) 2017 Rob Clark
6 * SPDX-License-Identifier: GPL-2.0+
12 #include <efi_loader.h>
14 static const struct efi_boot_services
*bs
;
15 static const struct efi_runtime_services
*rs
;
17 #define LOAD_OPTION_ACTIVE 0x00000001
18 #define LOAD_OPTION_FORCE_RECONNECT 0x00000002
19 #define LOAD_OPTION_HIDDEN 0x00000008
22 * bootmgr implements the logic of trying to find a payload to boot
23 * based on the BootOrder + BootXXXX variables, and then loading it.
25 * TODO detecting a special key held (f9?) and displaying a boot menu
26 * like you would get on a PC would be clever.
28 * TODO if we had a way to write and persist variables after the OS
29 * has started, we'd also want to check OsIndications to see if we
30 * should do normal or recovery boot.
35 * See section 3.1.3 in the v2.7 UEFI spec for more details on
36 * the layout of EFI_LOAD_OPTION. In short it is:
38 * typedef struct _EFI_LOAD_OPTION {
40 * UINT16 FilePathListLength;
41 * // CHAR16 Description[]; <-- variable length, NULL terminated
42 * // EFI_DEVICE_PATH_PROTOCOL FilePathList[]; <-- FilePathListLength bytes
43 * // UINT8 OptionalData[];
50 struct efi_device_path
*file_path
;
54 /* parse an EFI_LOAD_OPTION, as described above */
55 static void parse_load_option(struct load_option
*lo
, void *ptr
)
57 lo
->attributes
= *(u32
*)ptr
;
60 lo
->file_path_length
= *(u16
*)ptr
;
64 ptr
+= (utf16_strlen(lo
->label
) + 1) * 2;
67 ptr
+= lo
->file_path_length
;
69 lo
->optional_data
= ptr
;
72 /* free() the result */
73 static void *get_var(u16
*name
, const efi_guid_t
*vendor
,
76 efi_guid_t
*v
= (efi_guid_t
*)vendor
;
81 EFI_CALL(ret
= rs
->get_variable((s16
*)name
, v
, NULL
, size
, buf
));
82 if (ret
== EFI_BUFFER_TOO_SMALL
) {
84 EFI_CALL(ret
= rs
->get_variable((s16
*)name
, v
, NULL
, size
, buf
));
87 if (ret
!= EFI_SUCCESS
) {
97 * Attempt to load load-option number 'n', returning device_path and file_path
98 * if successful. This checks that the EFI_LOAD_OPTION is active (enabled)
99 * and that the specified file to boot exists.
101 static void *try_load_entry(uint16_t n
, struct efi_device_path
**device_path
,
102 struct efi_device_path
**file_path
)
104 struct load_option lo
;
105 u16 varname
[] = L
"Boot0000";
106 u16 hexmap
[] = L
"0123456789ABCDEF";
107 void *load_option
, *image
= NULL
;
110 varname
[4] = hexmap
[(n
& 0xf000) >> 12];
111 varname
[5] = hexmap
[(n
& 0x0f00) >> 8];
112 varname
[6] = hexmap
[(n
& 0x00f0) >> 4];
113 varname
[7] = hexmap
[(n
& 0x000f) >> 0];
115 load_option
= get_var(varname
, &efi_global_variable_guid
, &size
);
119 parse_load_option(&lo
, load_option
);
121 if (lo
.attributes
& LOAD_OPTION_ACTIVE
) {
125 debug("%s: trying to load \"%ls\" from: %ls\n", __func__
,
126 lo
.label
, (str
= efi_dp_str(lo
.file_path
)));
129 ret
= efi_load_image_from_path(lo
.file_path
, &image
);
131 if (ret
!= EFI_SUCCESS
)
134 printf("Booting: %ls\n", lo
.label
);
135 efi_dp_split_file_path(lo
.file_path
, device_path
, file_path
);
145 * Attempt to load, in the order specified by BootOrder EFI variable, the
146 * available load-options, finding and returning the first one that can
147 * be loaded successfully.
149 void *efi_bootmgr_load(struct efi_device_path
**device_path
,
150 struct efi_device_path
**file_path
)
159 bs
= systab
.boottime
;
162 bootorder
= get_var(L
"BootOrder", &efi_global_variable_guid
, &size
);
166 num
= size
/ sizeof(uint16_t);
167 for (i
= 0; i
< num
; i
++) {
168 debug("%s: trying to load Boot%04X\n", __func__
, bootorder
[i
]);
169 image
= try_load_entry(bootorder
[i
], device_path
, file_path
);