diff options
| author | Toomas Soome <tsoome@FreeBSD.org> | 2017-06-16 20:08:44 +0000 |
|---|---|---|
| committer | Toomas Soome <tsoome@FreeBSD.org> | 2017-06-16 20:08:44 +0000 |
| commit | 769bad9f8a55c05abac59cbf35df663a79eb7436 (patch) | |
| tree | 4fc254d1768e7f9f77522eeceaa9f2741237cfb0 /sys/boot/efi/loader/main.c | |
| parent | a4110f9ffabd212bcf998eed0703389a3252ec11 (diff) | |
Notes
Diffstat (limited to 'sys/boot/efi/loader/main.c')
| -rw-r--r-- | sys/boot/efi/loader/main.c | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/sys/boot/efi/loader/main.c b/sys/boot/efi/loader/main.c index 043306f691393..6fab757be5f1e 100644 --- a/sys/boot/efi/loader/main.c +++ b/sys/boot/efi/loader/main.c @@ -795,6 +795,100 @@ command_fdt(int argc, char *argv[]) COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); #endif +/* + * Chain load another efi loader. + */ +static int +command_chain(int argc, char *argv[]) +{ + EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; + EFI_HANDLE loaderhandle; + EFI_LOADED_IMAGE *loaded_image; + EFI_STATUS status; + struct stat st; + struct devdesc *dev; + char *name, *path; + void *buf; + int fd; + + if (argc < 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } + + name = argv[1]; + + if ((fd = open(name, O_RDONLY)) < 0) { + command_errmsg = "no such file"; + return (CMD_ERROR); + } + + if (fstat(fd, &st) < -1) { + command_errmsg = "stat failed"; + close(fd); + return (CMD_ERROR); + } + + status = BS->AllocatePool(EfiLoaderCode, (UINTN)st.st_size, &buf); + if (status != EFI_SUCCESS) { + command_errmsg = "failed to allocate buffer"; + close(fd); + return (CMD_ERROR); + } + if (read(fd, buf, st.st_size) != st.st_size) { + command_errmsg = "error while reading the file"; + (void)BS->FreePool(buf); + close(fd); + return (CMD_ERROR); + } + close(fd); + status = BS->LoadImage(FALSE, IH, NULL, buf, st.st_size, &loaderhandle); + (void)BS->FreePool(buf); + if (status != EFI_SUCCESS) { + command_errmsg = "LoadImage failed"; + return (CMD_ERROR); + } + status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID, + (void **)&loaded_image); + + if (argc > 2) { + int i, len = 0; + CHAR16 *argp; + + for (i = 2; i < argc; i++) + len += strlen(argv[i]) + 1; + + len *= sizeof (*argp); + loaded_image->LoadOptions = argp = malloc (len); + loaded_image->LoadOptionsSize = len; + for (i = 2; i < argc; i++) { + char *ptr = argv[i]; + while (*ptr) + *(argp++) = *(ptr++); + *(argp++) = ' '; + } + *(--argv) = 0; + } + + if (efi_getdev((void **)&dev, name, (const char **)&path) == 0) + loaded_image->DeviceHandle = + efi_find_handle(dev->d_dev, dev->d_unit); + + dev_cleanup(); + status = BS->StartImage(loaderhandle, NULL, NULL); + if (status != EFI_SUCCESS) { + command_errmsg = "StartImage failed"; + free(loaded_image->LoadOptions); + loaded_image->LoadOptions = NULL; + status = BS->UnloadImage(loaded_image); + return (CMD_ERROR); + } + + return (CMD_ERROR); /* not reached */ +} + +COMMAND_SET(chain, "chain", "chain load file", command_chain); + #ifdef EFI_ZFS_BOOT static void efi_zfs_probe(void) |
