Commit 37279ad3eeed5285c2fee4ed9eb24d110515fe3f
Committed by
Heinrich Schuchardt
1 parent
b0c3c346c6
Exists in
smarc_8mq_lf_v2020.04
and in
10 other branches
efi_loader: bootmgr: support BootNext and BootCurrent variable behavior
See UEFI v2.7, section 3.1.2 for details of the specification. With efidebug command, you can run any EFI boot option as follows: => efi boot add 1 SHELL ... => efi boot add 2 HELLO ... => efi boot order 1 2 => efi bootmgr (starting SHELL ...) => efi boot next 2 => efi bootmgr (starting HELLO ...) => env print -e <snip ...> BootCurrent: {boot,run}(blob) 00000000: 02 00 .. BootOrder: {boot,run}(blob) 00000000: 01 00 02 00 .... Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Showing 1 changed file with 47 additions and 4 deletions Side-by-side Diff
lib/efi_loader/efi_bootmgr.c
... | ... | @@ -141,6 +141,7 @@ |
141 | 141 | efi_deserialize_load_option(&lo, load_option); |
142 | 142 | |
143 | 143 | if (lo.attributes & LOAD_OPTION_ACTIVE) { |
144 | + u32 attributes; | |
144 | 145 | efi_status_t ret; |
145 | 146 | |
146 | 147 | debug("%s: trying to load \"%ls\" from %pD\n", |
... | ... | @@ -151,6 +152,16 @@ |
151 | 152 | if (ret != EFI_SUCCESS) |
152 | 153 | goto error; |
153 | 154 | |
155 | + attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | | |
156 | + EFI_VARIABLE_RUNTIME_ACCESS; | |
157 | + size = sizeof(n); | |
158 | + ret = EFI_CALL(efi_set_variable( | |
159 | + L"BootCurrent", | |
160 | + (efi_guid_t *)&efi_global_variable_guid, | |
161 | + attributes, size, &n)); | |
162 | + if (ret != EFI_SUCCESS) | |
163 | + goto error; | |
164 | + | |
154 | 165 | printf("Booting: %ls\n", lo.label); |
155 | 166 | efi_dp_split_file_path(lo.file_path, device_path, file_path); |
156 | 167 | } |
157 | 168 | |
158 | 169 | |
159 | 170 | |
... | ... | @@ -162,21 +173,53 @@ |
162 | 173 | } |
163 | 174 | |
164 | 175 | /* |
165 | - * Attempt to load, in the order specified by BootOrder EFI variable, the | |
166 | - * available load-options, finding and returning the first one that can | |
167 | - * be loaded successfully. | |
176 | + * Attempt to load from BootNext or in the order specified by BootOrder | |
177 | + * EFI variable, the available load-options, finding and returning | |
178 | + * the first one that can be loaded successfully. | |
168 | 179 | */ |
169 | 180 | void *efi_bootmgr_load(struct efi_device_path **device_path, |
170 | 181 | struct efi_device_path **file_path) |
171 | 182 | { |
172 | - uint16_t *bootorder; | |
183 | + u16 bootnext, *bootorder; | |
173 | 184 | efi_uintn_t size; |
174 | 185 | void *image = NULL; |
175 | 186 | int i, num; |
187 | + efi_status_t ret; | |
176 | 188 | |
177 | 189 | bs = systab.boottime; |
178 | 190 | rs = systab.runtime; |
179 | 191 | |
192 | + /* BootNext */ | |
193 | + bootnext = 0; | |
194 | + size = sizeof(bootnext); | |
195 | + ret = EFI_CALL(efi_get_variable(L"BootNext", | |
196 | + (efi_guid_t *)&efi_global_variable_guid, | |
197 | + NULL, &size, &bootnext)); | |
198 | + if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) { | |
199 | + /* BootNext does exist here */ | |
200 | + if (ret == EFI_BUFFER_TOO_SMALL || size != sizeof(u16)) | |
201 | + printf("BootNext must be 16-bit integer\n"); | |
202 | + | |
203 | + /* delete BootNext */ | |
204 | + ret = EFI_CALL(efi_set_variable( | |
205 | + L"BootNext", | |
206 | + (efi_guid_t *)&efi_global_variable_guid, | |
207 | + 0, 0, &bootnext)); | |
208 | + | |
209 | + /* load BootNext */ | |
210 | + if (ret == EFI_SUCCESS) { | |
211 | + if (size == sizeof(u16)) { | |
212 | + image = try_load_entry(bootnext, device_path, | |
213 | + file_path); | |
214 | + if (image) | |
215 | + return image; | |
216 | + } | |
217 | + } else { | |
218 | + printf("Deleting BootNext failed\n"); | |
219 | + } | |
220 | + } | |
221 | + | |
222 | + /* BootOrder */ | |
180 | 223 | bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size); |
181 | 224 | if (!bootorder) { |
182 | 225 | printf("BootOrder not defined\n"); |