[syslinux] [PATCH 0/1] EFI image booting capabilities

Patrick Masotta
Fri, 20 Feb 2015 13:08:26 -0000

This patch adds to the core EFI image booting capabilities.
It was tested on VMware EFI clients and HP Elitebook EFI notebooks,
only on PXE environments but it should work on non-PXE scenarios as well.

Feedback appreciated.

Best,
Patrick

Signed-off-by: Patrick Masotta <masottaus at yahoo.com>
---
diff -uprN a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c
--- a/com32/elflink/ldlinux/execute.c	2014-10-06 10:27:44.000000000 -0600
+++ b/com32/elflink/ldlinux/execute.c	2015-02-18 18:46:02.193886584 -0700
@@ -41,6 +41,7 @@ const struct image_types image_boot_type
     { "fdimage", IMAGE_TYPE_FDIMAGE },
     { "com32", IMAGE_TYPE_COM32 },
     { "config", IMAGE_TYPE_CONFIG },
+    { "efi", IMAGE_TYPE_EFI },
     { NULL, 0 },
 };

@@ -89,6 +90,13 @@ __export void execute(const char *cmdlin
 		do_sysappend(q);
 	}

+#ifdef __FIRMWARE_BIOS__
+        if(type==IMAGE_TYPE_EFI) {
+                printf("Bios core cannot load efi image
%s\n",kernel);
+                return;
+        }
+#endif
+
 	dprintf("kernel is %s, args = %s  type = %d \n", kernel, args,
type);

 	if (kernel[0] == '.') {
@@ -114,7 +122,9 @@ __export void execute(const char *cmdlin
 		}
 	}

-	if (type == IMAGE_TYPE_COM32) {
+        if (type == IMAGE_TYPE_EFI) {
+                new_efi_image((char *)kernel, (char *)args);
+        } else if (type == IMAGE_TYPE_COM32) {
 		/*
 		 * We may be called with the console in an unknown
 		 * state, so initialise it.
diff -uprN a/com32/elflink/ldlinux/kernel.c b/com32/elflink/ldlinux/kernel.c
--- a/com32/elflink/ldlinux/kernel.c	2014-10-06 10:27:44.000000000 -0600
+++ b/com32/elflink/ldlinux/kernel.c	2015-02-18 19:16:02.569004945 -0700
@@ -1,3 +1,7 @@
+/*
+ * EFI image boot capabilities by Patrick Masotta (Serva) (c)2015
+ */
+
 #include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -7,6 +11,7 @@
 #include <syslinux/loadfile.h>
 #include <syslinux/linux.h>
 #include <syslinux/pxe.h>
+#include <syslinux/firmware.h>
 #include "core.h"

 const char *globaldefault = NULL;
@@ -23,6 +28,9 @@ int new_linux_kernel(char *okernel, char
 	bool opt_quiet = false;
 	char *initrd_name, *cmdline;

+        if(firmware && firmware->clear_screen)
+                firmware->clear_screen();
+
 	dprintf("okernel = %s, ocmdline = %s", okernel, ocmdline);

 	if (okernel)
@@ -129,3 +137,70 @@ bail:
 	printf("%s\n", strerror(errno));
 	return 1;
 }
+
+
+int new_efi_image(char *okernel, char *ocmdline)
+{
+    const char *kernel_name = NULL, *args = NULL;
+    char *temp;
+    void *kernel_data;
+    size_t kernel_len, cmdline_len;
+    char *cmdline=NULL;
+
+
+    //lets clear the screen before loading the efi image
+    if(firmware && firmware->clear_screen)
+	firmware->clear_screen();
+
+
+    dprintf("okernel = %s, ocmdline = %s", okernel, ocmdline);
+
+    if (okernel)
+	kernel_name = okernel;
+    else if (globaldefault)
+	kernel_name = globaldefault;
+
+    if (ocmdline)
+	args = ocmdline;
+    else
+    if (append)
+	args = append;
+
+    if(args!=NULL && *args!=0)
+	{
+	    int i;
+	    int args_len;
+	    args_len = strlen(args);
+	    cmdline_len = (args_len+1) * 2 ;
+	    cmdline = malloc(cmdline_len);
+	    if (!cmdline)
+		{
+		    printf("Failed to alloc memory for cmdline\n");
+		    return 1;
+		}
+	    memset(cmdline,0,cmdline_len);
+	    for(i=0; i < args_len ; i++) cmdline[2*i]=args[i];
+
+	}
+    else
+	cmdline_len=0;
+
+
+    printf("Loading %s... ", kernel_name);
+    if (loadfile(kernel_name, &kernel_data, &kernel_len)) {
+	printf("failed: ");
+	goto bail;
+    }
+    printf("ok\n");
+
+
+    /* This should not return... */
+    syslinux_boot_efi(kernel_data, kernel_len, cmdline, cmdline_len);
+    printf("Booting efi image failed: ");
+
+bail:
+    if(cmdline)
+	free(cmdline);
+    printf("%s\n", strerror(errno));
+    return 1;
+}
diff -uprN a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c
--- a/com32/elflink/ldlinux/ldlinux.c	2014-10-06 10:27:44.000000000 -0600
+++ b/com32/elflink/ldlinux/ldlinux.c	2015-02-18 18:33:39.370445843 -0700
@@ -28,6 +28,7 @@ static const struct file_ext file_extens
 	{ ".bin", IMAGE_TYPE_BOOT },
 	{ ".bs", IMAGE_TYPE_BOOT },
 	{ ".0", IMAGE_TYPE_PXE },
+	{ ".efi", IMAGE_TYPE_EFI },
 	{ NULL, 0 },
 };

diff -uprN a/com32/include/syslinux/boot.h b/com32/include/syslinux/boot.h
--- a/com32/include/syslinux/boot.h	2014-10-06 10:27:44.000000000 -0600
+++ b/com32/include/syslinux/boot.h	2015-02-18 18:38:09.045503622 -0700
@@ -67,6 +67,8 @@ extern const struct image_types image_bo
 #define IMAGE_TYPE_COM32	7
 #define IMAGE_TYPE_CONFIG	8
 #define IMAGE_TYPE_LOCALBOOT	9
+#define IMAGE_TYPE_EFI         10
+

 uint32_t parse_image_type(const char *cmdline);
 void syslinux_run_kernel_image(const char *filename, const char *cmdline,
diff -uprN a/com32/include/syslinux/firmware.h
b/com32/include/syslinux/firmware.h
--- a/com32/include/syslinux/firmware.h	2014-10-06 10:27:44.000000000 -0600
+++ b/com32/include/syslinux/firmware.h	2015-02-18 18:36:46.155334267 -0700
@@ -60,6 +60,8 @@ struct firmware {
 	struct adv_ops *adv_ops;
 	int (*boot_linux)(void *, size_t, struct initramfs *,
 			  struct setup_data *, char *);
+        int (*boot_efi)(void *, size_t, char *, int);
+        void (*clear_screen)(void);
 	struct vesa_ops *vesa;
 	struct mem_ops *mem;
 };
diff -uprN a/com32/lib/syslinux/load_efi.c b/com32/lib/syslinux/load_efi.c
--- a/com32/lib/syslinux/load_efi.c	1969-12-31 17:00:00.000000000 -0700
+++ b/com32/lib/syslinux/load_efi.c	2015-02-18 20:08:04.430708483 -0700
@@ -0,0 +1,37 @@
+/*
+ * EFI image boot capabilities by Patrick Masotta (Serva) (c)2015
+ */
+
+/*
+ * load_efi.c
+ *
+ * Load an efi image
+ */
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <minmax.h>
+#include <errno.h>
+#include <suffix_number.h>
+#include <dprintf.h>
+
+#include <syslinux/align.h>
+#include <syslinux/linux.h>
+#include <syslinux/bootrm.h>
+#include <syslinux/movebits.h>
+#include <syslinux/firmware.h>
+#include <syslinux/video.h>
+
+
+
+int syslinux_boot_efi(void *kernel_buf, size_t kernel_size,
+			char *cmdline, int cmdlineSize)
+{
+    if (firmware->boot_efi)
+		return firmware->boot_efi(kernel_buf, kernel_size, cmdline, cmdlineSize);
+
+    return -1;
+}
diff -uprN a/efi/main.c b/efi/main.c
--- a/efi/main.c	2014-10-06 10:27:44.000000000 -0600
+++ b/efi/main.c	2015-02-18 19:48:27.215899105 -0700
@@ -1,4 +1,8 @@
 /*
+ * EFI image boot capabilities by Patrick Masotta (Serva) (c)2015
+ */
+
+/*
  * Copyright 2011-2014 Intel Corporation - All Rights Reserved
  */

@@ -348,7 +352,11 @@ char efi_getchar(char *hi)

 	do {
 		status = uefi_call_wrapper(in->ReadKeyStroke, 2, in, &key);
-	} while (status == EFI_NOT_READY);
+	} while (status != EFI_NOT_READY);
+
+        status = WaitForSingleEvent(in->WaitForKey, 0);
+        status = uefi_call_wrapper(in->ReadKeyStroke, 2, in, &key);
+

 	if (!key.ScanCode)
 		return (char)key.UnicodeChar;
@@ -356,10 +364,21 @@ char efi_getchar(char *hi)
 	/*
 	 * We currently only handle scan codes that fit in 8 bits.
 	 */
-	*hi = (char)key.ScanCode;
+	if(hi)
+	    *hi = (char)key.ScanCode;
 	return 0;
 }

+void efi_clear_screen(void)
+{
+
+        //simple form feed leaving only the background if any
+        char buf[55];
+        memset(&buf,'\n',sizeof(buf));
+        printf("%s",buf);
+
+}
+
 int efi_pollchar(void)
 {
 	SIMPLE_INPUT_INTERFACE *in = ST->ConIn;
@@ -1042,6 +1061,97 @@ static int exit_boot(struct boot_params
 	return 0;
 }

+
+/* efi_boot_efi:
+ * Boots an efi image
+ */
+int efi_boot_efi(void *kernel_buf, size_t kernel_size,
+		char *cmdline, int cmdlineSize)
+{
+
+char* szLoadImage	= "LoadImage()";
+char* szHandleProtocol	= "HandleProtocol()";
+char* szStartImage 	= "StartImage()";
+
+char* action = NULL;
+
+EFI_LOADED_IMAGE *	image_info = NULL;
+EFI_HANDLE 		Child_image_handle;
+EFI_LOADED_IMAGE *	Child_image_info = NULL;
+EFI_STATUS 		status;
+
+CHAR16 w_emptyCmdLine [4]={0,0,0,0};
+
+
+
+status = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle,
+				&LoadedImageProtocol,(void**)&image_info);
+if(status != EFI_SUCCESS)
+    {
+	action=szHandleProtocol;
+	goto bail;
+    }
+
+status = uefi_call_wrapper(BS->LoadImage, 6, 	TRUE,
+						image_handle,
+						NULL,
+						kernel_buf,
+						kernel_size,
+						&Child_image_handle);
+if(status != EFI_SUCCESS)
+    {
+	action=szLoadImage;
+	goto bail;
+    }
+
+
+status = uefi_call_wrapper(BS->HandleProtocol, 3,	Child_image_handle,
+				&LoadedImageProtocol,(void**)&Child_image_info);
+if(status != EFI_SUCCESS)
+    {
+	uefi_call_wrapper(BS->UnloadImage,1, Child_image_handle );
+	action=szHandleProtocol;
+	goto bail;
+    }
+
+
+
+Child_image_info->ParentHandle = image_info;
+Child_image_info->DeviceHandle = image_info->DeviceHandle;
+Child_image_info->LoadOptionsSize = (UINT32)cmdlineSize;
+if(cmdline!=NULL && cmdlineSize != 0)
+    Child_image_info->LoadOptions = (VOID *)cmdline;
+else
+    Child_image_info->LoadOptions = (VOID *)w_emptyCmdLine;
+
+
+
+
+status = uefi_call_wrapper(BS->StartImage, 3,	Child_image_handle,
+						NULL,
+						NULL);
+if(status != EFI_SUCCESS)
+    {
+	uefi_call_wrapper(BS->UnloadImage,1, Child_image_handle );
+	action=szStartImage;
+	goto bail;
+    }
+
+
+//If we are here the child image has run/finished/returned
+efi_console_restore();
+
+return 0;
+
+bail:
+	printf("EFI Err: %s failed; EFI_STATUS=%d\n", action,status);
+	printf("Press any key...\n");
+	efi_getchar(NULL);
+	return -1;
+
+}
+
+
 /* efi_boot_linux:
  * Boots the linux kernel using the image and parameters to boot with.
  * The EFI boot loader is reworked taking the cue from
@@ -1200,6 +1310,8 @@ struct firmware efi_fw = {
 	.get_serial_console_info = serialcfg,
 	.adv_ops = &efi_adv_ops,
 	.boot_linux = efi_boot_linux,
+	.boot_efi = efi_boot_efi,
+	.clear_screen = efi_clear_screen,
 	.vesa = &efi_vesa_ops,
 	.mem = &efi_mem_ops,
 };
diff -uprN a/efi/pxe.c b/efi/pxe.c
--- a/efi/pxe.c	2014-10-06 10:27:44.000000000 -0600
+++ b/efi/pxe.c	2015-02-18 19:39:43.118182728 -0700
@@ -154,7 +154,12 @@ void net_parse_dhcp(void)
      * Get the boot file and other info. This lives in the CACHED_REPLY
      * packet (query info 3)
      */
-    parse_dhcp(&mode->PxeReply.Dhcpv4, pkt_len);
+
+    if(&mode->ProxyOfferReceived)
+        parse_dhcp(&mode->ProxyOffer.Dhcpv4, pkt_len);
+    else
+	parse_dhcp(&mode->PxeReply.Dhcpv4, pkt_len);
+
     Print(L"\n");

     /*
diff -uprN a/mk/lib.mk b/mk/lib.mk
--- a/mk/lib.mk	2014-10-06 10:27:44.000000000 -0600
+++ b/mk/lib.mk	2015-02-18 20:15:07.333776455 -0700
@@ -161,7 +161,9 @@ LIBLOAD_OBJS = \
 	\
 	syslinux/load_linux.o syslinux/initramfs.o			\
 	syslinux/initramfs_file.o syslinux/initramfs_loadfile.o		\
-	syslinux/initramfs_archive.o
+	syslinux/initramfs_archive.o					\
+	syslinux/load_efi.o
+

 LIBMODULE_OBJS = \
 	sys/module/common.o sys/module/$(ARCH)/elf_module.o		\
-------------- next part --------------
A non-text attachment was scrubbed...
Name: boot_efi_image.patch
Type: application/octet-stream
Size: 10701 bytes
Desc: not available
URL:
<http://www.zytor.com/pipermail/syslinux/attachments/20150220/76b43ebc/attachment.obj>