blob: dabde127b1dcd5882c5db38acc93941e2fb1dfe1 [file] [log] [blame]
Toomas Soome9f23ea42017-12-12 15:23:09 +02001/*
Toomas Soome199767f2015-10-25 00:06:51 +03002 * Copyright (c) 2008-2010 Rui Paulo
3 * Copyright (c) 2006 Marcel Moolenaar
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
Toomas Soome199767f2015-10-25 00:06:51 +030029
Toomas Soomeedb35042016-11-07 15:37:12 +020030#include <sys/disk.h>
Toomas Soome199767f2015-10-25 00:06:51 +030031#include <sys/param.h>
32#include <sys/reboot.h>
33#include <sys/boot.h>
34#include <stand.h>
Toomas Soomeeee59042016-11-12 00:06:58 +020035#include <inttypes.h>
Toomas Soome199767f2015-10-25 00:06:51 +030036#include <string.h>
37#include <setjmp.h>
Toomas Soomedbacaf52016-11-17 17:02:22 +020038#include <disk.h>
Toomas Soome199767f2015-10-25 00:06:51 +030039
40#include <efi.h>
41#include <efilib.h>
42#include <efigpt.h>
43
Toomas Soomeeee59042016-11-12 00:06:58 +020044#include <uuid.h>
Toomas Soomeeee59042016-11-12 00:06:58 +020045
Toomas Soome199767f2015-10-25 00:06:51 +030046#include <bootstrap.h>
47#include <smbios.h>
48
Toomas Soome199767f2015-10-25 00:06:51 +030049#include <libzfs.h>
Toomas Soome9f23ea42017-12-12 15:23:09 +020050#include <efizfs.h>
Toomas Soome199767f2015-10-25 00:06:51 +030051
52#include "loader_efi.h"
53
Toomas Soome199767f2015-10-25 00:06:51 +030054struct arch_switch archsw; /* MI/MD interface boundary */
55
Toomas Soome199767f2015-10-25 00:06:51 +030056EFI_GUID devid = DEVICE_PATH_PROTOCOL;
57EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
Toomas Soome199767f2015-10-25 00:06:51 +030058EFI_GUID smbios = SMBIOS_TABLE_GUID;
59EFI_GUID smbios3 = SMBIOS3_TABLE_GUID;
Toomas Soome199767f2015-10-25 00:06:51 +030060EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL;
Toomas Soome199767f2015-10-25 00:06:51 +030061
Toomas Soomedcba96f2016-10-09 17:12:23 +030062extern void acpi_detect(void);
Toomas Soomef9feecc2016-10-09 17:30:28 +030063extern void efi_getsmap(void);
Toomas Soome9f23ea42017-12-12 15:23:09 +020064
65static EFI_LOADED_IMAGE *img;
66
Toomas Soomee3026532018-03-08 12:37:51 +020067/*
68 * Number of seconds to wait for a keystroke before exiting with failure
69 * in the event no currdev is found. -2 means always break, -1 means
70 * never break, 0 means poll once and then reboot, > 0 means wait for
71 * that many seconds. "fail_timeout" can be set in the environment as
72 * well.
73 */
74static int fail_timeout = 5;
75
Toomas Soome9f23ea42017-12-12 15:23:09 +020076bool
77efi_zfs_is_preferred(EFI_HANDLE *h)
78{
Toomas Soomee3026532018-03-08 12:37:51 +020079 EFI_DEVICE_PATH *devpath, *dp, *node;
80 HARDDRIVE_DEVICE_PATH *hd;
81 bool ret;
82 extern UINT64 start_sector; /* from multiboot.S */
83
84 /* This check is true for chainloader case. */
85 if (h == img->DeviceHandle)
86 return (true);
87
88 /*
89 * Make sure the image was loaded from the hard disk.
90 */
91 devpath = efi_lookup_devpath(img->DeviceHandle);
92 if (devpath == NULL)
93 return (false);
94 node = efi_devpath_last_node(devpath);
95 if (node == NULL)
96 return (false);
97 if (DevicePathType(node) != MEDIA_DEVICE_PATH &&
98 (DevicePathSubType(node) != MEDIA_FILEPATH_DP ||
99 DevicePathSubType(node) != MEDIA_HARDDRIVE_DP)) {
100 return (false);
101 }
102
103 /*
104 * XXX We ignore the MEDIA_FILEPATH_DP here for now as it is
105 * used on arm and we do not support arm.
106 */
107 ret = false;
108 dp = efi_devpath_trim(devpath);
109 devpath = NULL;
110 if (dp == NULL)
111 goto done;
112
113 devpath = efi_lookup_devpath(h);
114 if (devpath == NULL)
115 goto done;
116 hd = (HARDDRIVE_DEVICE_PATH *)efi_devpath_last_node(devpath);
117 if (hd == NULL) {
118 devpath = NULL;
119 goto done;
120 }
121 devpath = efi_devpath_trim(devpath);
122 if (devpath == NULL)
123 goto done;
124
125 if (!efi_devpath_match(dp, devpath))
126 goto done;
127
128 /* It is the same disk, do we have partition start? */
129 if (start_sector == 0)
130 ret = true;
131 else if (start_sector == hd->PartitionStart)
132 ret = true;
133
134done:
135 free(dp);
136 free(devpath);
137 return (ret);
Toomas Soome9f23ea42017-12-12 15:23:09 +0200138}
Toomas Soome199767f2015-10-25 00:06:51 +0300139
Toomas Soomeafa95be2018-06-16 10:22:42 +0300140static bool
Toomas Soome199767f2015-10-25 00:06:51 +0300141has_keyboard(void)
142{
143 EFI_STATUS status;
144 EFI_DEVICE_PATH *path;
145 EFI_HANDLE *hin, *hin_end, *walker;
146 UINTN sz;
Toomas Soomeafa95be2018-06-16 10:22:42 +0300147 bool retval = false;
Toomas Soome9f23ea42017-12-12 15:23:09 +0200148
Toomas Soome199767f2015-10-25 00:06:51 +0300149 /*
150 * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and
151 * do the typical dance to get the right sized buffer.
152 */
153 sz = 0;
154 hin = NULL;
155 status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0);
156 if (status == EFI_BUFFER_TOO_SMALL) {
157 hin = (EFI_HANDLE *)malloc(sz);
158 status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz,
159 hin);
160 if (EFI_ERROR(status))
161 free(hin);
162 }
163 if (EFI_ERROR(status))
Toomas Soomeafa95be2018-06-16 10:22:42 +0300164 return (retval);
Toomas Soome199767f2015-10-25 00:06:51 +0300165
166 /*
167 * Look at each of the handles. If it supports the device path protocol,
168 * use it to get the device path for this handle. Then see if that
169 * device path matches either the USB device path for keyboards or the
170 * legacy device path for keyboards.
171 */
172 hin_end = &hin[sz / sizeof(*hin)];
173 for (walker = hin; walker < hin_end; walker++) {
174 status = BS->HandleProtocol(*walker, &devid, (VOID **)&path);
175 if (EFI_ERROR(status))
176 continue;
177
178 while (!IsDevicePathEnd(path)) {
179 /*
180 * Check for the ACPI keyboard node. All PNP3xx nodes
181 * are keyboards of different flavors. Note: It is
182 * unclear of there's always a keyboard node when
183 * there's a keyboard controller, or if there's only one
184 * when a keyboard is detected at boot.
185 */
186 if (DevicePathType(path) == ACPI_DEVICE_PATH &&
187 (DevicePathSubType(path) == ACPI_DP ||
188 DevicePathSubType(path) == ACPI_EXTENDED_DP)) {
189 ACPI_HID_DEVICE_PATH *acpi;
190
191 acpi = (ACPI_HID_DEVICE_PATH *)(void *)path;
192 if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == 0x300 &&
193 (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) {
Toomas Soomeafa95be2018-06-16 10:22:42 +0300194 retval = true;
Toomas Soome199767f2015-10-25 00:06:51 +0300195 goto out;
196 }
197 /*
198 * Check for USB keyboard node, if present. Unlike a
199 * PS/2 keyboard, these definitely only appear when
200 * connected to the system.
201 */
202 } else if (DevicePathType(path) == MESSAGING_DEVICE_PATH &&
203 DevicePathSubType(path) == MSG_USB_CLASS_DP) {
204 USB_CLASS_DEVICE_PATH *usb;
Toomas Soomec142ce12018-03-13 14:16:40 +0200205
Toomas Soome199767f2015-10-25 00:06:51 +0300206 usb = (USB_CLASS_DEVICE_PATH *)(void *)path;
207 if (usb->DeviceClass == 3 && /* HID */
208 usb->DeviceSubClass == 1 && /* Boot devices */
209 usb->DeviceProtocol == 1) { /* Boot keyboards */
Toomas Soomeafa95be2018-06-16 10:22:42 +0300210 retval = true;
Toomas Soome199767f2015-10-25 00:06:51 +0300211 goto out;
212 }
213 }
214 path = NextDevicePathNode(path);
215 }
216 }
217out:
218 free(hin);
Toomas Soomeafa95be2018-06-16 10:22:42 +0300219 return (retval);
Toomas Soome199767f2015-10-25 00:06:51 +0300220}
221
Toomas Soomedbacaf52016-11-17 17:02:22 +0200222static void
Toomas Soomee3026532018-03-08 12:37:51 +0200223set_currdev_devdesc(struct devdesc *currdev)
Toomas Soomeab8c1d42016-11-12 13:46:26 +0200224{
Toomas Soomedbacaf52016-11-17 17:02:22 +0200225 char *devname;
226
Toomas Soomee3026532018-03-08 12:37:51 +0200227 devname = efi_fmtdev(currdev);
228
229 printf("Setting currdev to %s\n", devname);
Toomas Soomedbacaf52016-11-17 17:02:22 +0200230
231 env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
232 env_nounset);
233 env_setenv("loaddev", EV_VOLATILE, devname, env_noset, env_nounset);
234}
235
Toomas Soomee3026532018-03-08 12:37:51 +0200236static void
237set_currdev_devsw(struct devsw *dev, int unit)
238{
239 struct devdesc currdev;
240
241 currdev.d_dev = dev;
242 currdev.d_unit = unit;
243
244 set_currdev_devdesc(&currdev);
245}
246
247static void
248set_currdev_pdinfo(pdinfo_t *dp)
249{
250
251 /*
252 * Disks are special: they have partitions. if the parent
253 * pointer is non-null, we're a partition not a full disk
254 * and we need to adjust currdev appropriately.
255 */
256 if (dp->pd_devsw->dv_type == DEVT_DISK) {
257 struct disk_devdesc currdev;
258
259 currdev.dd.d_dev = dp->pd_devsw;
260 if (dp->pd_parent == NULL) {
261 currdev.dd.d_unit = dp->pd_unit;
262 currdev.d_slice = -1;
263 currdev.d_partition = -1;
264 } else {
265 currdev.dd.d_unit = dp->pd_parent->pd_unit;
266 currdev.d_slice = dp->pd_unit;
267 currdev.d_partition = 255; /* Assumes GPT */
268 }
269 set_currdev_devdesc((struct devdesc *)&currdev);
270 } else {
271 set_currdev_devsw(dp->pd_devsw, dp->pd_unit);
272 }
273}
274
275static bool
276sanity_check_currdev(void)
277{
278 struct stat st;
279
280 return (stat("/boot/defaults/loader.conf", &st) == 0);
281}
282
283static bool
284probe_zfs_currdev(uint64_t guid)
285{
286 struct zfs_devdesc currdev;
287
288 currdev.dd.d_dev = &zfs_dev;
289 currdev.dd.d_unit = 0;
290 currdev.pool_guid = guid;
291 currdev.root_guid = 0;
292 set_currdev_devdesc((struct devdesc *)&currdev);
293
294 return (sanity_check_currdev());
295}
296
297static bool
298try_as_currdev(pdinfo_t *pp)
299{
300 uint64_t guid;
301
302 /*
303 * If there's a zpool on this device, try it as a ZFS
304 * filesystem, which has somewhat different setup than all
305 * other types of fs due to imperfect loader integration.
306 * This all stems from ZFS being both a device (zpool) and
307 * a filesystem, plus the boot env feature.
308 */
309 if (efizfs_get_guid_by_handle(pp->pd_handle, &guid))
310 return (probe_zfs_currdev(guid));
311
312 /*
313 * All other filesystems just need the pdinfo
314 * initialized in the standard way.
315 */
316 set_currdev_pdinfo(pp);
317 return (sanity_check_currdev());
318}
319
320static bool
Toomas Soomedbacaf52016-11-17 17:02:22 +0200321find_currdev(EFI_LOADED_IMAGE *img)
322{
Toomas Soomedbacaf52016-11-17 17:02:22 +0200323 pdinfo_t *dp, *pp;
Toomas Soomeab8c1d42016-11-12 13:46:26 +0200324 EFI_DEVICE_PATH *devpath, *copy;
325 EFI_HANDLE h;
Toomas Soomee3026532018-03-08 12:37:51 +0200326 CHAR16 *text;
Toomas Soomedbacaf52016-11-17 17:02:22 +0200327 struct devsw *dev;
328 int unit;
329 uint64_t extra;
330
Toomas Soomee3026532018-03-08 12:37:51 +0200331 /*
332 * Did efi_zfs_probe() detect the boot pool? If so, use the zpool
333 * it found, if it's sane. ZFS is the only thing that looks for
334 * disks and pools to boot.
335 */
Toomas Soomedbacaf52016-11-17 17:02:22 +0200336 if (pool_guid != 0) {
Toomas Soomee3026532018-03-08 12:37:51 +0200337 printf("Trying ZFS pool\n");
338 if (probe_zfs_currdev(pool_guid))
339 return (true);
Toomas Soomedbacaf52016-11-17 17:02:22 +0200340 }
341
Toomas Soomee3026532018-03-08 12:37:51 +0200342 /*
343 * Try to find the block device by its handle based on the
344 * image we're booting. If we can't find a sane partition,
345 * search all the other partitions of the disk. We do not
346 * search other disks because it's a violation of the UEFI
347 * boot protocol to do so. We fail and let UEFI go on to
348 * the next candidate.
349 */
350 dp = efiblk_get_pdinfo_by_handle(img->DeviceHandle);
351 if (dp != NULL) {
352 text = efi_devpath_name(dp->pd_devpath);
353 if (text != NULL) {
354 printf("Trying ESP: %S\n", text);
355 efi_free_devpath_name(text);
Toomas Soomedbacaf52016-11-17 17:02:22 +0200356 }
Toomas Soomee3026532018-03-08 12:37:51 +0200357 set_currdev_pdinfo(dp);
358 if (sanity_check_currdev())
359 return (true);
360 if (dp->pd_parent != NULL) {
361 dp = dp->pd_parent;
362 STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
363 text = efi_devpath_name(pp->pd_devpath);
364 if (text != NULL) {
365 printf("And now the part: %S\n", text);
366 efi_free_devpath_name(text);
367 }
368 /*
369 * Roll up the ZFS special case
370 * for those partitions that have
371 * zpools on them
372 */
373 if (try_as_currdev(pp))
374 return (true);
Toomas Soomedbacaf52016-11-17 17:02:22 +0200375 }
376 }
Toomas Soomee3026532018-03-08 12:37:51 +0200377 } else {
378 printf("Can't find device by handle\n");
Toomas Soomedbacaf52016-11-17 17:02:22 +0200379 }
Toomas Soomeab8c1d42016-11-12 13:46:26 +0200380
381 /*
382 * Try the device handle from our loaded image first. If that
383 * fails, use the device path from the loaded image and see if
384 * any of the nodes in that path match one of the enumerated
Toomas Soomee3026532018-03-08 12:37:51 +0200385 * handles. Currently, this handle list is only for netboot.
Toomas Soomeab8c1d42016-11-12 13:46:26 +0200386 */
Toomas Soomedbacaf52016-11-17 17:02:22 +0200387 if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &extra) == 0) {
Toomas Soomee3026532018-03-08 12:37:51 +0200388 set_currdev_devsw(dev, unit);
389 if (sanity_check_currdev())
390 return (true);
Toomas Soomedbacaf52016-11-17 17:02:22 +0200391 }
Toomas Soomeab8c1d42016-11-12 13:46:26 +0200392
393 copy = NULL;
394 devpath = efi_lookup_image_devpath(IH);
395 while (devpath != NULL) {
396 h = efi_devpath_handle(devpath);
397 if (h == NULL)
398 break;
399
400 free(copy);
401 copy = NULL;
402
Toomas Soomedbacaf52016-11-17 17:02:22 +0200403 if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) {
Toomas Soomee3026532018-03-08 12:37:51 +0200404 set_currdev_devsw(dev, unit);
405 if (sanity_check_currdev())
406 return (true);
Toomas Soomedbacaf52016-11-17 17:02:22 +0200407 }
Toomas Soomeab8c1d42016-11-12 13:46:26 +0200408
409 devpath = efi_lookup_devpath(h);
410 if (devpath != NULL) {
411 copy = efi_devpath_trim(devpath);
412 devpath = copy;
413 }
414 }
415 free(copy);
416
Toomas Soomee3026532018-03-08 12:37:51 +0200417 return (false);
418}
419
420static bool
421interactive_interrupt(const char *msg)
422{
423 time_t now, then, last;
424
425 last = 0;
426 now = then = getsecs();
427 printf("%s\n", msg);
428 if (fail_timeout == -2) /* Always break to OK */
429 return (true);
430 if (fail_timeout == -1) /* Never break to OK */
431 return (false);
432 do {
433 if (last != now) {
434 printf("press any key to interrupt reboot in %d seconds\r",
435 fail_timeout - (int)(now - then));
436 last = now;
437 }
438
439 /* XXX no pause or timeout wait for char */
440 if (ischar())
441 return (true);
442 now = getsecs();
443 } while (now - then < fail_timeout);
444 return (false);
Toomas Soomeab8c1d42016-11-12 13:46:26 +0200445}
446
Toomas Soome199767f2015-10-25 00:06:51 +0300447EFI_STATUS
448main(int argc, CHAR16 *argv[])
449{
450 char var[128];
Toomas Soome8fe0f542018-06-14 10:00:19 +0300451 int i, j, howto;
452 bool vargood;
Toomas Soomedcba96f2016-10-09 17:12:23 +0300453 void *ptr;
Toomas Soomeafa95be2018-06-16 10:22:42 +0300454 bool has_kbd;
Toomas Soomee3026532018-03-08 12:37:51 +0200455 char *s;
456 EFI_DEVICE_PATH *imgpath;
457 CHAR16 *text;
458 EFI_STATUS status;
459 UINT16 boot_current;
460 size_t sz;
461 UINT16 boot_order[100];
Toomas Soome199767f2015-10-25 00:06:51 +0300462
463 archsw.arch_autoload = efi_autoload;
464 archsw.arch_getdev = efi_getdev;
465 archsw.arch_copyin = efi_copyin;
466 archsw.arch_copyout = efi_copyout;
467 archsw.arch_readin = efi_readin;
Toomas Soomef9feecc2016-10-09 17:30:28 +0300468 archsw.arch_loadaddr = efi_loadaddr;
469 archsw.arch_free_loadaddr = efi_free_loadaddr;
Toomas Soome199767f2015-10-25 00:06:51 +0300470 /* Note this needs to be set before ZFS init. */
471 archsw.arch_zfs_probe = efi_zfs_probe;
Toomas Soome9f23ea42017-12-12 15:23:09 +0200472
473 /* Get our loaded image protocol interface structure. */
474 BS->HandleProtocol(IH, &imgid, (VOID**)&img);
Toomas Soome199767f2015-10-25 00:06:51 +0300475
Toomas Soome04f8e092016-11-10 21:05:15 +0200476 /* Init the time source */
477 efi_time_init();
478
Toomas Soome199767f2015-10-25 00:06:51 +0300479 has_kbd = has_keyboard();
480
481 /*
482 * XXX Chicken-and-egg problem; we want to have console output
483 * early, but some console attributes may depend on reading from
484 * eg. the boot device, which we can't do yet. We can use
485 * printf() etc. once this is done.
486 */
487 cons_probe();
Toomas Soomef9feecc2016-10-09 17:30:28 +0300488 efi_getsmap();
Toomas Soome199767f2015-10-25 00:06:51 +0300489
490 /*
491 * Initialise the block cache. Set the upper limit.
492 */
493 bcache_init(32768, 512);
494
495 /*
496 * Parse the args to set the console settings, etc
497 * boot1.efi passes these in, if it can read /boot.config or /boot/config
Toomas Soomee3026532018-03-08 12:37:51 +0200498 * or iPXE may be setup to pass these in. Or the optional argument in the
499 * boot environment was used to pass these arguments in (in which case
500 * neither /boot.config nor /boot/config are consulted).
Toomas Soome199767f2015-10-25 00:06:51 +0300501 *
502 * Loop through the args, and for each one that contains an '=' that is
503 * not the first character, add it to the environment. This allows
504 * loader and kernel env vars to be passed on the command line. Convert
Toomas Soomee3026532018-03-08 12:37:51 +0200505 * args from UCS-2 to ASCII (16 to 8 bit) as they are copied (though this
506 * method is flawed for non-ASCII characters).
Toomas Soome199767f2015-10-25 00:06:51 +0300507 */
508 howto = 0;
509 for (i = 1; i < argc; i++) {
510 if (argv[i][0] == '-') {
511 for (j = 1; argv[i][j] != 0; j++) {
512 int ch;
513
514 ch = argv[i][j];
515 switch (ch) {
516 case 'a':
517 howto |= RB_ASKNAME;
518 break;
519 case 'd':
520 howto |= RB_KDB;
521 break;
522 case 'D':
523 howto |= RB_MULTIPLE;
524 break;
525 case 'h':
526 howto |= RB_SERIAL;
527 break;
528 case 'm':
529 howto |= RB_MUTE;
530 break;
531 case 'p':
532 howto |= RB_PAUSE;
533 break;
534 case 'P':
535 if (!has_kbd)
536 howto |= RB_SERIAL | RB_MULTIPLE;
537 break;
538 case 'r':
539 howto |= RB_DFLTROOT;
540 break;
541 case 's':
542 howto |= RB_SINGLE;
543 break;
544 case 'S':
545 if (argv[i][j + 1] == 0) {
546 if (i + 1 == argc) {
Toomas Soome2aca6c62017-06-02 23:07:12 +0300547 strncpy(var, "115200",
Toomas Soome199767f2015-10-25 00:06:51 +0300548 sizeof(var));
Toomas Soome2aca6c62017-06-02 23:07:12 +0300549 } else {
550 CHAR16 *ptr;
551 ptr = &argv[i + 1][0];
552 cpy16to8(ptr, var,
553 sizeof(var));
Toomas Soome199767f2015-10-25 00:06:51 +0300554 }
555 i++;
Toomas Soome199767f2015-10-25 00:06:51 +0300556 } else {
Toomas Soomeeee59042016-11-12 00:06:58 +0200557 cpy16to8(&argv[i][j + 1], var,
Toomas Soome199767f2015-10-25 00:06:51 +0300558 sizeof(var));
Toomas Soome199767f2015-10-25 00:06:51 +0300559 }
Toomas Soome2aca6c62017-06-02 23:07:12 +0300560 strncat(var, ",8,n,1,-", sizeof(var));
561 setenv("ttya-mode", var, 1);
562 break;
Toomas Soome199767f2015-10-25 00:06:51 +0300563 case 'v':
564 howto |= RB_VERBOSE;
565 break;
566 }
567 }
568 } else {
Toomas Soome8fe0f542018-06-14 10:00:19 +0300569 vargood = false;
Toomas Soome199767f2015-10-25 00:06:51 +0300570 for (j = 0; argv[i][j] != 0; j++) {
571 if (j == sizeof(var)) {
Toomas Soome8fe0f542018-06-14 10:00:19 +0300572 vargood = false;
Toomas Soome199767f2015-10-25 00:06:51 +0300573 break;
574 }
575 if (j > 0 && argv[i][j] == '=')
Toomas Soome8fe0f542018-06-14 10:00:19 +0300576 vargood = true;
Toomas Soome199767f2015-10-25 00:06:51 +0300577 var[j] = (char)argv[i][j];
578 }
579 if (vargood) {
580 var[j] = 0;
581 putenv(var);
582 }
583 }
584 }
585 for (i = 0; howto_names[i].ev != NULL; i++)
586 if (howto & howto_names[i].mask)
587 setenv(howto_names[i].ev, "YES", 1);
Toomas Soomee3026532018-03-08 12:37:51 +0200588
589 /*
590 * XXX we need fallback to this stuff after looking at the ConIn,
591 * ConOut and ConErr variables.
592 */
Toomas Soome199767f2015-10-25 00:06:51 +0300593 if (howto & RB_MULTIPLE) {
594 if (howto & RB_SERIAL)
595 setenv("console", "ttya text" , 1);
596 else
597 setenv("console", "text ttya" , 1);
598 } else if (howto & RB_SERIAL) {
599 setenv("console", "ttya" , 1);
Toomas Soomee3026532018-03-08 12:37:51 +0200600 } else
601 setenv("console", "text" , 1);
602
603 if ((s = getenv("fail_timeout")) != NULL)
604 fail_timeout = strtol(s, NULL, 10);
Toomas Soome199767f2015-10-25 00:06:51 +0300605
Toomas Soome199767f2015-10-25 00:06:51 +0300606 /*
Toomas Soomec00b6c92018-02-19 19:14:22 +0200607 * Scan the BLOCK IO MEDIA handles then
608 * march through the device switch probing for things.
Toomas Soome199767f2015-10-25 00:06:51 +0300609 */
Toomas Soomec00b6c92018-02-19 19:14:22 +0200610 if ((i = efipart_inithandles()) == 0) {
611 for (i = 0; devsw[i] != NULL; i++)
612 if (devsw[i]->dv_init != NULL)
613 (devsw[i]->dv_init)();
614 } else
615 printf("efipart_inithandles failed %d, expect failures", i);
Toomas Soome199767f2015-10-25 00:06:51 +0300616
Toomas Soome199767f2015-10-25 00:06:51 +0300617 printf("Command line arguments:");
618 for (i = 0; i < argc; i++) {
Toomas Soomeeee59042016-11-12 00:06:58 +0200619 printf(" %S", argv[i]);
Toomas Soome199767f2015-10-25 00:06:51 +0300620 }
621 printf("\n");
622
623 printf("Image base: 0x%lx\n", (u_long)img->ImageBase);
624 printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16,
625 ST->Hdr.Revision & 0xffff);
Toomas Soomeeee59042016-11-12 00:06:58 +0200626 printf("EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor,
627 ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
Toomas Soome199767f2015-10-25 00:06:51 +0300628
Toomas Soomef6c94442017-01-03 11:24:09 +0200629 printf("\n%s", bootprog_info);
Toomas Soome199767f2015-10-25 00:06:51 +0300630
Toomas Soomee3026532018-03-08 12:37:51 +0200631 /* Determine the devpath of our image so we can prefer it. */
632 text = efi_devpath_name(img->FilePath);
633 if (text != NULL) {
634 printf(" Load Path: %S\n", text);
635 efi_setenv_illumos_wcs("LoaderPath", text);
636 efi_free_devpath_name(text);
637 }
638
639 status = BS->HandleProtocol(img->DeviceHandle, &devid,
640 (void **)&imgpath);
641 if (status == EFI_SUCCESS) {
642 text = efi_devpath_name(imgpath);
643 if (text != NULL) {
644 printf(" Load Device: %S\n", text);
645 efi_setenv_illumos_wcs("LoaderDev", text);
646 efi_free_devpath_name(text);
647 }
648 }
649
650 boot_current = 0;
651 sz = sizeof(boot_current);
652 efi_global_getenv("BootCurrent", &boot_current, &sz);
653 printf(" BootCurrent: %04x\n", boot_current);
654
655 sz = sizeof(boot_order);
656 efi_global_getenv("BootOrder", &boot_order, &sz);
657 printf(" BootOrder:");
658 for (i = 0; i < sz / sizeof(boot_order[0]); i++)
659 printf(" %04x%s", boot_order[i],
660 boot_order[i] == boot_current ? "[*]" : "");
661 printf("\n");
662
Toomas Soome199767f2015-10-25 00:06:51 +0300663 /*
664 * Disable the watchdog timer. By default the boot manager sets
665 * the timer to 5 minutes before invoking a boot option. If we
666 * want to return to the boot manager, we have to disable the
667 * watchdog timer and since we're an interactive program, we don't
668 * want to wait until the user types "quit". The timer may have
669 * fired by then. We don't care if this fails. It does not prevent
670 * normal functioning in any way...
671 */
672 BS->SetWatchdogTimer(0, 0, 0, NULL);
673
Toomas Soomee3026532018-03-08 12:37:51 +0200674 /*
675 * Try and find a good currdev based on the image that was booted.
676 * It might be desirable here to have a short pause to allow falling
677 * through to the boot loader instead of returning instantly to follow
678 * the boot protocol and also allow an escape hatch for users wishing
679 * to try something different.
680 */
681 if (!find_currdev(img))
682 if (!interactive_interrupt("Failed to find bootable partition"))
683 return (EFI_NOT_FOUND);
Toomas Soome199767f2015-10-25 00:06:51 +0300684
Toomas Soomeeee59042016-11-12 00:06:58 +0200685 efi_init_environment();
Toomas Soome199767f2015-10-25 00:06:51 +0300686 setenv("ISADIR", "amd64", 1); /* we only build 64bit */
Toomas Soomed9256ff2016-07-17 20:39:53 +0300687 bi_isadir(); /* set ISADIR */
Toomas Soomedcba96f2016-10-09 17:12:23 +0300688 acpi_detect();
Toomas Soome199767f2015-10-25 00:06:51 +0300689
Toomas Soomedcba96f2016-10-09 17:12:23 +0300690 if ((ptr = efi_get_table(&smbios3)) == NULL)
691 ptr = efi_get_table(&smbios);
692 smbios_detect(ptr);
Toomas Soome199767f2015-10-25 00:06:51 +0300693
Toomas Soome199767f2015-10-25 00:06:51 +0300694 interact(NULL); /* doesn't return */
695
696 return (EFI_SUCCESS); /* keep compiler happy */
697}
698
699COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
700
701static int
Toomas Soome30c75cb2016-03-13 20:45:57 +0200702command_reboot(int argc __unused, char *argv[] __unused)
Toomas Soome199767f2015-10-25 00:06:51 +0300703{
704 int i;
Toomas Soome199767f2015-10-25 00:06:51 +0300705
706 for (i = 0; devsw[i] != NULL; ++i)
707 if (devsw[i]->dv_cleanup != NULL)
708 (devsw[i]->dv_cleanup)();
709
Toomas Soome48d84432017-04-27 19:19:29 +0300710 RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
Toomas Soome199767f2015-10-25 00:06:51 +0300711
712 /* NOTREACHED */
713 return (CMD_ERROR);
714}
715
Toomas Soomeb31ca802018-10-10 15:29:10 +0300716COMMAND_SET(poweroff, "poweroff", "power off the system", command_poweroff);
717
718static int
719command_poweroff(int argc __unused, char *argv[] __unused)
720{
721 int i;
722
723 for (i = 0; devsw[i] != NULL; ++i)
724 if (devsw[i]->dv_cleanup != NULL)
725 (devsw[i]->dv_cleanup)();
726
727 RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
728
729 /* NOTREACHED */
730 return (CMD_ERROR);
731}
732
Toomas Soome199767f2015-10-25 00:06:51 +0300733COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
734
735static int
Toomas Soome30c75cb2016-03-13 20:45:57 +0200736command_memmap(int argc __unused, char *argv[] __unused)
Toomas Soome199767f2015-10-25 00:06:51 +0300737{
738 UINTN sz;
739 EFI_MEMORY_DESCRIPTOR *map, *p;
740 UINTN key, dsz;
741 UINT32 dver;
742 EFI_STATUS status;
743 int i, ndesc;
744 int rv = 0;
745 char line[80];
Toomas Soome199767f2015-10-25 00:06:51 +0300746
747 sz = 0;
748 status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
749 if (status != EFI_BUFFER_TOO_SMALL) {
750 printf("Can't determine memory map size\n");
751 return (CMD_ERROR);
752 }
753 map = malloc(sz);
754 status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
755 if (EFI_ERROR(status)) {
756 printf("Can't read memory map\n");
757 return (CMD_ERROR);
758 }
759
760 ndesc = sz / dsz;
761 snprintf(line, 80, "%23s %12s %12s %8s %4s\n",
762 "Type", "Physical", "Virtual", "#Pages", "Attr");
763 pager_open();
764 rv = pager_output(line);
765 if (rv) {
766 pager_close();
767 return (CMD_OK);
768 }
769
770 for (i = 0, p = map; i < ndesc;
771 i++, p = NextMemoryDescriptor(p, dsz)) {
Toomas Soome83b46712016-08-16 19:02:42 +0300772 snprintf(line, 80, "%23s %012jx %012jx %08jx ",
773 efi_memory_type(p->Type), p->PhysicalStart,
774 p->VirtualStart, p->NumberOfPages);
Toomas Soome199767f2015-10-25 00:06:51 +0300775 rv = pager_output(line);
776 if (rv)
777 break;
778
779 if (p->Attribute & EFI_MEMORY_UC)
780 printf("UC ");
781 if (p->Attribute & EFI_MEMORY_WC)
782 printf("WC ");
783 if (p->Attribute & EFI_MEMORY_WT)
784 printf("WT ");
785 if (p->Attribute & EFI_MEMORY_WB)
786 printf("WB ");
787 if (p->Attribute & EFI_MEMORY_UCE)
788 printf("UCE ");
789 if (p->Attribute & EFI_MEMORY_WP)
790 printf("WP ");
791 if (p->Attribute & EFI_MEMORY_RP)
792 printf("RP ");
793 if (p->Attribute & EFI_MEMORY_XP)
794 printf("XP ");
Toomas Soomeeee59042016-11-12 00:06:58 +0200795 if (p->Attribute & EFI_MEMORY_NV)
796 printf("NV ");
797 if (p->Attribute & EFI_MEMORY_MORE_RELIABLE)
798 printf("MR ");
799 if (p->Attribute & EFI_MEMORY_RO)
800 printf("RO ");
Toomas Soome199767f2015-10-25 00:06:51 +0300801 rv = pager_output("\n");
802 if (rv)
803 break;
804 }
805
806 pager_close();
807 return (CMD_OK);
808}
809
810COMMAND_SET(configuration, "configuration", "print configuration tables",
811 command_configuration);
812
Toomas Soome199767f2015-10-25 00:06:51 +0300813static int
Toomas Soome30c75cb2016-03-13 20:45:57 +0200814command_configuration(int argc __unused, char *argv[] __unused)
Toomas Soome199767f2015-10-25 00:06:51 +0300815{
816 UINTN i;
Toomas Soomeeee59042016-11-12 00:06:58 +0200817 char *name;
Toomas Soome199767f2015-10-25 00:06:51 +0300818
819 printf("NumberOfTableEntries=%lu\n",
820 (unsigned long)ST->NumberOfTableEntries);
821 for (i = 0; i < ST->NumberOfTableEntries; i++) {
822 EFI_GUID *guid;
823
824 printf(" ");
825 guid = &ST->ConfigurationTable[i].VendorGuid;
Toomas Soomeeee59042016-11-12 00:06:58 +0200826
827 if (efi_guid_to_name(guid, &name) == true) {
828 printf(name);
829 free(name);
830 } else {
831 printf("Error while translating UUID to name");
832 }
Toomas Soome199767f2015-10-25 00:06:51 +0300833 printf(" at %p\n", ST->ConfigurationTable[i].VendorTable);
834 }
835
836 return (CMD_OK);
837}
838
839
840COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode);
841
842static int
843command_mode(int argc, char *argv[])
844{
845 UINTN cols, rows;
846 unsigned int mode;
847 int i;
848 char *cp;
849 char rowenv[8];
850 EFI_STATUS status;
851 SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
852 extern void HO(void);
853
854 conout = ST->ConOut;
855
856 if (argc > 1) {
857 mode = strtol(argv[1], &cp, 0);
858 if (cp[0] != '\0') {
859 printf("Invalid mode\n");
860 return (CMD_ERROR);
861 }
862 status = conout->QueryMode(conout, mode, &cols, &rows);
863 if (EFI_ERROR(status)) {
864 printf("invalid mode %d\n", mode);
865 return (CMD_ERROR);
866 }
867 status = conout->SetMode(conout, mode);
868 if (EFI_ERROR(status)) {
869 printf("couldn't set mode %d\n", mode);
870 return (CMD_ERROR);
871 }
872 sprintf(rowenv, "%u", (unsigned)rows);
873 setenv("LINES", rowenv, 1);
874 sprintf(rowenv, "%u", (unsigned)cols);
875 setenv("COLUMNS", rowenv, 1);
876 HO(); /* set cursor */
877 return (CMD_OK);
878 }
879
880 printf("Current mode: %d\n", conout->Mode->Mode);
881 for (i = 0; i <= conout->Mode->MaxMode; i++) {
882 status = conout->QueryMode(conout, i, &cols, &rows);
883 if (EFI_ERROR(status))
884 continue;
885 printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols,
886 (unsigned)rows);
887 }
888
889 if (i != 0)
890 printf("Select a mode with the command \"mode <number>\"\n");
891
892 return (CMD_OK);
893}
894
Toomas Soome199767f2015-10-25 00:06:51 +0300895COMMAND_SET(lsefi, "lsefi", "list EFI handles", command_lsefi);
896
897static int
Toomas Soome30c75cb2016-03-13 20:45:57 +0200898command_lsefi(int argc __unused, char *argv[] __unused)
Toomas Soome199767f2015-10-25 00:06:51 +0300899{
Toomas Soomeeee59042016-11-12 00:06:58 +0200900 char *name;
Toomas Soome199767f2015-10-25 00:06:51 +0300901 EFI_HANDLE *buffer = NULL;
902 EFI_HANDLE handle;
903 UINTN bufsz = 0, i, j;
904 EFI_STATUS status;
Toomas Soomeeee59042016-11-12 00:06:58 +0200905 int ret;
Toomas Soome199767f2015-10-25 00:06:51 +0300906
907 status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer);
908 if (status != EFI_BUFFER_TOO_SMALL) {
909 snprintf(command_errbuf, sizeof (command_errbuf),
910 "unexpected error: %lld", (long long)status);
911 return (CMD_ERROR);
912 }
913 if ((buffer = malloc(bufsz)) == NULL) {
914 sprintf(command_errbuf, "out of memory");
915 return (CMD_ERROR);
916 }
917
918 status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer);
919 if (EFI_ERROR(status)) {
920 free(buffer);
921 snprintf(command_errbuf, sizeof (command_errbuf),
922 "LocateHandle() error: %lld", (long long)status);
923 return (CMD_ERROR);
924 }
925
926 pager_open();
927 for (i = 0; i < (bufsz / sizeof (EFI_HANDLE)); i++) {
928 UINTN nproto = 0;
929 EFI_GUID **protocols = NULL;
930
931 handle = buffer[i];
932 printf("Handle %p", handle);
933 if (pager_output("\n"))
934 break;
935 /* device path */
936
937 status = BS->ProtocolsPerHandle(handle, &protocols, &nproto);
938 if (EFI_ERROR(status)) {
939 snprintf(command_errbuf, sizeof (command_errbuf),
940 "ProtocolsPerHandle() error: %lld",
941 (long long)status);
942 continue;
943 }
Toomas Soomeeee59042016-11-12 00:06:58 +0200944
Toomas Soome199767f2015-10-25 00:06:51 +0300945 for (j = 0; j < nproto; j++) {
Toomas Soomeeee59042016-11-12 00:06:58 +0200946 if (efi_guid_to_name(protocols[j], &name) == true) {
947 printf(" %s", name);
948 free(name);
949 } else {
950 printf("Error while translating UUID to name");
951 }
952 if ((ret = pager_output("\n")) != 0)
Toomas Soome199767f2015-10-25 00:06:51 +0300953 break;
954 }
955 BS->FreePool(protocols);
Toomas Soomeeee59042016-11-12 00:06:58 +0200956 if (ret != 0)
Toomas Soome199767f2015-10-25 00:06:51 +0300957 break;
958 }
959 pager_close();
960 free(buffer);
961 return (CMD_OK);
962}
963
Toomas Soome199767f2015-10-25 00:06:51 +0300964COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset",
965 command_lszfs);
966
967static int
968command_lszfs(int argc, char *argv[])
969{
970 int err;
971
972 if (argc != 2) {
973 command_errmsg = "wrong number of arguments";
974 return (CMD_ERROR);
975 }
976
977 err = zfs_list(argv[1]);
978 if (err != 0) {
979 command_errmsg = strerror(err);
980 return (CMD_ERROR);
981 }
982 return (CMD_OK);
983}
984
985#ifdef __FreeBSD__
986COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments",
987 command_reloadbe);
988
989static int
990command_reloadbe(int argc, char *argv[])
991{
992 int err;
993 char *root;
994
995 if (argc > 2) {
996 command_errmsg = "wrong number of arguments";
997 return (CMD_ERROR);
998 }
999
1000 if (argc == 2) {
1001 err = zfs_bootenv(argv[1]);
1002 } else {
1003 root = getenv("zfs_be_root");
1004 if (root == NULL) {
1005 return (CMD_OK);
1006 }
1007 err = zfs_bootenv(root);
1008 }
1009
1010 if (err != 0) {
1011 command_errmsg = strerror(err);
1012 return (CMD_ERROR);
1013 }
1014
1015 return (CMD_OK);
1016}
1017#endif /* __FreeBSD__ */
Toomas Soome199767f2015-10-25 00:06:51 +03001018
Toomas Soome199767f2015-10-25 00:06:51 +03001019#ifdef LOADER_FDT_SUPPORT
1020extern int command_fdt_internal(int argc, char *argv[]);
1021
1022/*
1023 * Since proper fdt command handling function is defined in fdt_loader_cmd.c,
1024 * and declaring it as extern is in contradiction with COMMAND_SET() macro
1025 * (which uses static pointer), we're defining wrapper function, which
1026 * calls the proper fdt handling routine.
1027 */
1028static int
1029command_fdt(int argc, char *argv[])
1030{
1031 return (command_fdt_internal(argc, argv));
1032}
1033
1034COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
1035#endif
1036
Toomas Soomef9feecc2016-10-09 17:30:28 +03001037/*
1038 * Chain load another efi loader.
1039 */
1040static int
1041command_chain(int argc, char *argv[])
1042{
1043 EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
1044 EFI_HANDLE loaderhandle;
1045 EFI_LOADED_IMAGE *loaded_image;
1046 EFI_STATUS status;
1047 struct stat st;
1048 struct devdesc *dev;
1049 char *name, *path;
1050 void *buf;
1051 int fd;
1052
1053 if (argc < 2) {
1054 command_errmsg = "wrong number of arguments";
1055 return (CMD_ERROR);
1056 }
1057
1058 name = argv[1];
1059
1060 if ((fd = open(name, O_RDONLY)) < 0) {
1061 command_errmsg = "no such file";
1062 return (CMD_ERROR);
1063 }
1064
1065 if (fstat(fd, &st) < -1) {
1066 command_errmsg = "stat failed";
1067 close(fd);
1068 return (CMD_ERROR);
1069 }
1070
1071 status = BS->AllocatePool(EfiLoaderCode, (UINTN)st.st_size, &buf);
1072 if (status != EFI_SUCCESS) {
1073 command_errmsg = "failed to allocate buffer";
1074 close(fd);
1075 return (CMD_ERROR);
1076 }
1077 if (read(fd, buf, st.st_size) != st.st_size) {
1078 command_errmsg = "error while reading the file";
1079 (void)BS->FreePool(buf);
1080 close(fd);
1081 return (CMD_ERROR);
1082 }
1083 close(fd);
1084 status = BS->LoadImage(FALSE, IH, NULL, buf, st.st_size, &loaderhandle);
1085 (void)BS->FreePool(buf);
1086 if (status != EFI_SUCCESS) {
1087 command_errmsg = "LoadImage failed";
1088 return (CMD_ERROR);
1089 }
1090 status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID,
1091 (void **)&loaded_image);
1092
1093 if (argc > 2) {
1094 int i, len = 0;
1095 CHAR16 *argp;
1096
1097 for (i = 2; i < argc; i++)
1098 len += strlen(argv[i]) + 1;
1099
1100 len *= sizeof (*argp);
1101 loaded_image->LoadOptions = argp = malloc (len);
1102 if (loaded_image->LoadOptions == NULL) {
1103 (void) BS->UnloadImage(loaded_image);
1104 return (CMD_ERROR);
1105 }
1106 loaded_image->LoadOptionsSize = len;
1107 for (i = 2; i < argc; i++) {
1108 char *ptr = argv[i];
1109 while (*ptr)
1110 *(argp++) = *(ptr++);
1111 *(argp++) = ' ';
1112 }
1113 *(--argv) = 0;
1114 }
1115
Toomas Soomeeea30b22017-12-12 18:01:57 +02001116 if (efi_getdev((void **)&dev, name, (const char **)&path) == 0) {
1117 struct zfs_devdesc *z_dev;
1118 struct disk_devdesc *d_dev;
1119 pdinfo_t *hd, *pd;
1120
Toomas Soomec142ce12018-03-13 14:16:40 +02001121 switch (dev->d_dev->dv_type) {
Toomas Soomeeea30b22017-12-12 18:01:57 +02001122 case DEVT_ZFS:
1123 z_dev = (struct zfs_devdesc *)dev;
1124 loaded_image->DeviceHandle =
1125 efizfs_get_handle_by_guid(z_dev->pool_guid);
1126 break;
1127 case DEVT_NET:
1128 loaded_image->DeviceHandle =
1129 efi_find_handle(dev->d_dev, dev->d_unit);
1130 break;
1131 default:
1132 hd = efiblk_get_pdinfo(dev);
1133 if (STAILQ_EMPTY(&hd->pd_part)) {
1134 loaded_image->DeviceHandle = hd->pd_handle;
1135 break;
1136 }
1137 d_dev = (struct disk_devdesc *)dev;
1138 STAILQ_FOREACH(pd, &hd->pd_part, pd_link) {
1139 /*
1140 * d_partition should be 255
1141 */
1142 if (pd->pd_unit == d_dev->d_slice) {
1143 loaded_image->DeviceHandle =
1144 pd->pd_handle;
1145 break;
1146 }
1147 }
1148 break;
1149 }
1150 }
Toomas Soomef9feecc2016-10-09 17:30:28 +03001151
1152 dev_cleanup();
1153 status = BS->StartImage(loaderhandle, NULL, NULL);
1154 if (status != EFI_SUCCESS) {
1155 command_errmsg = "StartImage failed";
1156 free(loaded_image->LoadOptions);
1157 loaded_image->LoadOptions = NULL;
1158 status = BS->UnloadImage(loaded_image);
1159 return (CMD_ERROR);
1160 }
1161
1162 return (CMD_ERROR); /* not reached */
1163}
1164
1165COMMAND_SET(chain, "chain", "chain load file", command_chain);