Commit 37279ad3eeed5285c2fee4ed9eb24d110515fe3f

Authored by AKASHI Takahiro
Committed by Heinrich Schuchardt
1 parent b0c3c346c6

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");