aboutsummaryrefslogtreecommitdiff
path: root/sys/boot/efi/loader/main.c
diff options
context:
space:
mode:
authorToomas Soome <tsoome@FreeBSD.org>2017-06-16 20:08:44 +0000
committerToomas Soome <tsoome@FreeBSD.org>2017-06-16 20:08:44 +0000
commit769bad9f8a55c05abac59cbf35df663a79eb7436 (patch)
tree4fc254d1768e7f9f77522eeceaa9f2741237cfb0 /sys/boot/efi/loader/main.c
parenta4110f9ffabd212bcf998eed0703389a3252ec11 (diff)
Notes
Diffstat (limited to 'sys/boot/efi/loader/main.c')
-rw-r--r--sys/boot/efi/loader/main.c94
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)