Patrick Masotta
2015-Feb-20 13:08 UTC
[syslinux] [PATCH 0/1] EFI image booting capabilities
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>
Geert Stappers
2015-Feb-20 14:03 UTC
[syslinux] [PATCH 0/1] EFI image booting capabilities
On Fri, Feb 20, 2015 at 05:08:26AM -0800, Patrick Masotta via Syslinux wrote:> 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><bigsnip/>> --- 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"); > > /*I think that change should go into another commit. Groeten Geert Stappers -- Leven en laten leven ------------- volgend deel ------------ Een niet-tekst bijlage is gescrubt... Naam: signature.asc Type: application/pgp-signature Grootte: 836 bytes Omschrijving: Digital signature URL : <http://www.zytor.com/pipermail/syslinux/attachments/20150220/83f2b266/attachment.sig>
Patrick Masotta
2015-Feb-20 14:36 UTC
[syslinux] [PATCH 0/1] EFI image booting capabilities
>> +? ? if(&mode->ProxyOfferReceived) >> +? ? ? ? parse_dhcp(&mode->ProxyOffer.Dhcpv4,pkt_len); >> +? ? else > > I think that change should go into another commit. > Geert StappersYou may be right; but as I've said, all the testing was conducted on PXE (proxyDHCP) environments where those lines are mandatory to my patch. I just tried to keep things simple for the ones giving the patch a try. Best Patrick
Patrick Masotta
2015-Mar-14 11:23 UTC
[syslinux] [PATCH 0/1] EFI access from Com32 modules
This patch adds to Com32 modules the capabilities of accessing the EFI environment The idea is simple, the EFI parameters "image" and "table" received by syslinux.efi's efi_main() are stored in the "firmware" structure, next they are retrieved from the Com32 module which is linked against the gnu-efi static library. The Com32 module can use the EFI environment after calling InitializeLib(image, systab); With this patch coding i.e. pxechn.c32 able to run on EFI environments should be a trivial job. It was tested on VMware BIOS/EFI clients and HP Elitebook EFI/BIOS notebooks, Feedback appreciated. Best, Patrick Signed-off-by: Patrick Masotta <masottaus at yahoo.com> --- 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-03-13 12:59:12.147356419 -0600 @@ -62,6 +62,8 @@ struct firmware { struct setup_data *, char *); struct vesa_ops *vesa; struct mem_ops *mem; + void* image; + void** table; }; extern struct firmware *firmware; diff -uprN a/com32/modules/elf_bios_efi.c b/com32/modules/elf_bios_efi.c --- a/com32/modules/elf_bios_efi.c 1969-12-31 17:00:00.000000000 -0700 +++ b/com32/modules/elf_bios_efi.c 2015-03-13 14:43:18.266718706 -0600 @@ -0,0 +1,116 @@ +/* + * Demo module showing EFI access from a com32 module + * by Patrick Masotta (Serva) (c) 2015 + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <consoles.h> +#include <console.h> +#include <errno.h> +#include <string.h> +#include <syslinux/config.h> +#include <syslinux/loadfile.h> +#include <syslinux/bootrm.h> +#include <syslinux/video.h> +#include <com32.h> +#include <stdint.h> +#include <syslinux/pxe.h> +#include <sys/gpxe.h> +#include <unistd.h> +#include <getkey.h> +#include <dhcp.h> +#include <limits.h> + +#ifndef __FIRMWARE_BIOS__ + +#include <syslinux/firmware.h> +#include "../../efi/efi.h" + +#endif + + + +#ifdef __FIRMWARE_BIOS__ + +int pressanykey(void) { + int inc; + + printf("Press any key to continue. "); + inc = KEY_NONE; + while (inc == KEY_NONE) + inc = get_key(stdin, 6000); + puts(""); + return inc; +} + +int doTheJob(void) +{ + + printf("This Com32 instance of elf_bios_efi.c32 is running on a BIOS environment\n"); + pressanykey(); + + return 0; +} + +#else + +char efi_getchar(char *hi) +{ + SIMPLE_INPUT_INTERFACE *in = ST->ConIn; + EFI_INPUT_KEY key; + EFI_STATUS status; + + + status = WaitForSingleEvent(in->WaitForKey, 0); // 0=> no timeout + status = uefi_call_wrapper(in->ReadKeyStroke, 2, in, &key); // get the char + + if (!key.ScanCode) + return (char)key.UnicodeChar; + + /* + * We currently only handle scan codes that fit in 8 bits. + */ + if(hi) + *hi = (char)key.ScanCode; + + return 0; + +} + +EFI_HANDLE image = NULL; +EFI_SYSTEM_TABLE* systab = NULL; + +int doTheJob(void) +{ + + + image = (EFI_HANDLE) firmware->image; + systab = (EFI_SYSTEM_TABLE*) firmware->table; + + InitializeLib(image, systab); + + //Clear screen + uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); + + Print(L"This Com32 instance of elf_bios_efi.c32 is running on an EFI environment\nPress any key to continue..."); + efi_getchar(NULL); + + return 0; +} + + +#endif + + + + +int main(int argc, char *argv[]) +{ + + + return doTheJob(); + + +} diff -uprN a/com32/modules/Makefile b/com32/modules/Makefile --- a/com32/modules/Makefile 2014-10-06 10:27:44.000000000 -0600 +++ b/com32/modules/Makefile 2015-03-13 13:37:44.416274394 -0600 @@ -18,13 +18,17 @@ VPATH = $(SRC) include $(MAKEDIR)/elf.mk +ifneq "$(FIRMWARE)" "BIOS" +include $(MAKEDIR)/elf_efi.mk +endif + MODULES = config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \ disk.c32 pcitest.c32 elf.c32 linux.c32 reboot.c32 pmload.c32 \ meminfo.c32 sdi.c32 sanboot.c32 ifcpu64.c32 vesainfo.c32 \ kbdmap.c32 cmd.c32 vpdtest.c32 host.c32 ls.c32 gpxecmd.c32 \ ifcpu.c32 cpuid.c32 cat.c32 pwd.c32 ifplop.c32 zzjson.c32 \ whichsys.c32 prdhcp.c32 pxechn.c32 kontron_wdt.c32 ifmemdsk.c32 \ - hexdump.c32 poweroff.c32 cptime.c32 debug.c32 + hexdump.c32 poweroff.c32 cptime.c32 debug.c32 elf_bios_efi.c32 TESTFILES diff -uprN a/efi/build-gnu-efi.sh b/efi/build-gnu-efi.sh --- a/efi/build-gnu-efi.sh 2014-10-06 10:27:44.000000000 -0600 +++ b/efi/build-gnu-efi.sh 2015-03-13 13:07:51.577939127 -0600 @@ -21,23 +21,23 @@ fi ARCH="$1" objdir="$(readlink -f $2)" -if [ ! -e ../version.h ]; then - printf "build-gnu-efi.sh: Cannot be run outside Syslinux object tree\n" - pwd - exit 1 -fi - -( - cd ../.. - git submodule update --init -) +#if [ ! -e ../version.h ]; then +# printf "build-gnu-efi.sh: Cannot be run outside Syslinux object tree\n" +# pwd +# exit 1 +#fi +# +#( +# cd ../.. +# git submodule update --init +#) mkdir -p "$objdir/gnu-efi" cd "$objdir/gnu-efi" -EFIDIR="$(readlink -f "$objdir/../gnu-efi/gnu-efi-3.0")" +EFIDIR="$(readlink -f "$topdir/gnu-efi/gnu-efi-3.0")" make SRCDIR="$EFIDIR" TOPDIR="$EFIDIR" -f "$EFIDIR/Makefile" ARCH=$ARCH make SRCDIR="$EFIDIR" TOPDIR="$EFIDIR" -f "$EFIDIR/Makefile" ARCH=$ARCH PREFIX="$objdir" install -cd "$objdir/efi" +cd "$objdir" diff -uprN a/efi/check-gnu-efi.sh b/efi/check-gnu-efi.sh --- a/efi/check-gnu-efi.sh 2014-10-06 10:27:44.000000000 -0600 +++ b/efi/check-gnu-efi.sh 2015-03-13 13:11:01.575274084 -0600 @@ -25,7 +25,8 @@ if [ ! \( -f "$objdir/include/efi/$ARCH/ # Syslinux disables built-in implicit rules. export MAKEFLAGS - ../../efi/build-gnu-efi.sh $ARCH "$objdir" > /dev/null 2>&1 + $topdir/efi/build-gnu-efi.sh $ARCH "$objdir" + if [ $? -ne 0 ]; then printf "Failed to build gnu-efi. " printf "Execute the following command for full details: \n\n" diff -uprN a/efi/clean-gnu-efi.sh b/efi/clean-gnu-efi.sh --- a/efi/clean-gnu-efi.sh 2014-10-06 10:27:44.000000000 -0600 +++ b/efi/clean-gnu-efi.sh 2015-03-13 13:11:33.200161911 -0600 @@ -21,10 +21,10 @@ fi ARCH="$1" objdir=$(readlink -f "$2") -( - cd ../.. - git submodule update --init -) +#( +# cd ../.. +# git submodule update --init +#) if [ -d "$objdir/gnu-efi" ];then cd "$objdir/gnu-efi" 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-03-13 12:56:38.747049818 -0600 @@ -1202,6 +1202,8 @@ struct firmware efi_fw = { .boot_linux = efi_boot_linux, .vesa = &efi_vesa_ops, .mem = &efi_mem_ops, + .image = NULL, + .table = NULL }; static inline void syslinux_register_efi(void) @@ -1265,6 +1267,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EF InitializeLib(image, table); image_handle = image; + efi_fw.image = (void*) image; + efi_fw.table = (void**) table; syslinux_register_efi(); efi_console_save(); diff -uprN a/mk/elf_efi.mk b/mk/elf_efi.mk --- a/mk/elf_efi.mk 1969-12-31 17:00:00.000000000 -0700 +++ b/mk/elf_efi.mk 2015-03-13 13:03:27.630529153 -0600 @@ -0,0 +1,76 @@ +#/* +# * EFI access from a com32 module by Patrick Masotta (Serva) (c) 2015 +# */ + + +com32 = $(topdir)/com32 +core = $(topdir)/core + +# Support IA32 and x86_64 platforms with one build +# Set up architecture specifics; for cross compilation, set ARCH as apt +# gnuefi sets up architecture specifics in ia32 or x86_64 sub directories +# set up the LIBDIR and EFIINC for building for the appropriate architecture + +GCCOPT := $(call gcc_ok,-fno-stack-protector,) + +EFIINC = $(objdir)/include/efi +LIBDIR = $(objdir)/lib + +ifeq ($(ARCH),i386) + ARCHOPT = -m32 -march=i386 + EFI_SUBARCH = ia32 +endif +ifeq ($(ARCH),x86_64) + ARCHOPT = -m64 -march=x86-64 + EFI_SUBARCH = $(ARCH) +endif + + + +CFLAGS := $(CFLAGS) +CFLAGS += -I$(EFIINC) -I$(EFIINC)/$(EFI_SUBARCH) \ + -DEFI_FUNCTION_WRAPPER -fPIC -fshort-wchar -ffreestanding \ + -Wall \ + -I$(core)/ $(ARCHOPT) \ + -I$(com32)/lib/ -I$(com32)/libutil/include -std=gnu99 \ + -DELF_DEBUG -DSYSLINUX_EFI -I$(objdir) \ + $(GCCWARN) -D__COM32__ -D__FIRMWARE_$(FIRMWARE)__ -mno-red-zone \ + -Wno-unused-parameter $(GCCOPT) + + + + +## granular test pat +LDFLAGS += -Bsymbolic -pie -nostdlib -znocombreloc \ + -L$(LIBDIR) -m elf_$(ARCH) -E +# +# +SFLAGS += $(GCCOPT) $(GCCWARN) $(ARCHOPT) \ + -fomit-frame-pointer -D__COM32__ -D__FIRMWARE_$(FIRMWARE)__ \ + -nostdinc -iwithprefix include \ + -I$(com32)/libutil/include -I$(com32)/include -I$(com32)/include/sys $(GPLINCLUDE) + + + + +LIBEFI = $(objdir)/lib/libefi.a + +$(LIBEFI): + @echo Building gnu-efi for $(EFI_SUBARCH) + $(topdir)/efi/check-gnu-efi.sh $(EFI_SUBARCH) $(objdir) + + + +%.o: %.S # Cancel old rule + +%.o: %.c + +.PRECIOUS: %.o +%.o: %.S $(LIBEFI) + $(CC) $(SFLAGS) -c -o $@ $< + +.PRECIOUS: %.o +%.o: %.c $(LIBEFI) + $(CC) $(CFLAGS) -c -o $@ $< + +
Patrick Masotta
2015-Mar-16 16:22 UTC
[syslinux] [PATCH 0/1] EFI PXE DHCP/proxyDHCP issues fix
This patch fixes some problems when parsing DHCP/proxyDHCP answers on PXE scenarios. Before the patch proxyDHCP answers were ignored, and the IPinfo structure was populated based on a DhcpDiscover pkt instead of DhcpAck The BootFile detection now follows the EDKII function PxeBcImpl.c\DiscoverBootFile() It was tested on VMware BIOS/EFI clients and HP Elitebook EFI notebooks, Feedback appreciated. Best, Patrick Signed-off-by: Patrick Masotta <masottaus at yahoo.com> --- 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-03-14 06:22:20.840557180 -0600 @@ -123,7 +123,7 @@ void net_parse_dhcp(void) * Get the DHCP client identifiers (query info 1) */ Print(L"Getting cached packet "); - parse_dhcp(&mode->DhcpDiscover.Dhcpv4, pkt_len); + parse_dhcp(&mode->DhcpAck.Dhcpv4, pkt_len); /* * We don't use flags from the request packet, so * this is a good time to initialize DHCPMagic... @@ -135,26 +135,28 @@ void net_parse_dhcp(void) */ *(char *)&DHCPMagic = 1; - /* - * Get the BOOTP/DHCP packet that brought us file (and an IP - * address). This lives in the DHCPACK packet (query info 2) - */ - parse_dhcp(&mode->DhcpAck.Dhcpv4, pkt_len); - /* - * Save away MAC address (assume this is in query info 2. If this - * turns out to be problematic it might be better getting it from - * the query info 1 packet + /* + * Get the boot file and other info. + * Based on EDKII PxeBcImpl.c\DiscoverBootFile() */ - hardlen = mode->DhcpAck.Dhcpv4.BootpHwAddrLen; - MAC_len = hardlen > 16 ? 0 : hardlen; - MAC_type = mode->DhcpAck.Dhcpv4.BootpHwType; - memcpy(MAC, mode->DhcpAck.Dhcpv4.BootpHwAddr, MAC_len); - /* - * Get the boot file and other info. This lives in the CACHED_REPLY - * packet (query info 3) - */ - parse_dhcp(&mode->PxeReply.Dhcpv4, pkt_len); + EFI_PXE_BASE_CODE_DHCPV4_PACKET* pkt_v4; + + if(mode->PxeReplyReceived) + pkt_v4 = &mode->PxeReply.Dhcpv4; + else + if(mode->ProxyOfferReceived) + pkt_v4 = &mode->ProxyOffer.Dhcpv4; + else + pkt_v4 = &mode->DhcpAck.Dhcpv4; + + parse_dhcp(pkt_v4, pkt_len); + + hardlen = pkt_v4->BootpHwAddrLen; + MAC_len = hardlen > 16 ? 0 : hardlen; + MAC_type = pkt_v4->BootpHwType; + memcpy(MAC, pkt_v4->BootpHwAddr, MAC_len); + Print(L"\n"); /*
On Fri, Feb 20, 2015 at 8:08 AM, Patrick Masotta via Syslinux <syslinux at zytor.com> wrote:> 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.If you've made any changes to this, I'd definitely like to see it. If you have any interest in working with git and want some help, feel free to email me privately. For starters, this deserves to be split, unrelated changes to their own commits, the body and then finally a glue commit to put it together. Changing existing functionality like this may have negative consequences and splitting helps if a bisection is needed. I have a very strong preference towards micro-commits of changing functionality for this reason. It helps point to fewer lines of changes. On the other hand, adding new functionality is sometimes better done in fewer commits, often 1-2 and if two, the first adds the code while the second adds the glue to tie it into the existing code.> 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.Looks good. Glue.> 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)The firmware NULL check seems first, unnecessary, and second, inconsistent.> @@ -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; > +}Body. Needs some styling.> 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 }, > }; >Looks good. Glue> 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,Looks good. Body.> 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; > };This change I was uncertain on at first. Extend the firmware struct instead of exporting the functions and doing an #ifdef. It seems the struct is the cleaner way considering the source is partially split. Body.> 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 > + */Why not put the copyright as the 5th line of a single comment and let the file name and description go first?> + > +#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> > +Seems like a lot of unnecessary #includes.> + > + > +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; > +}Seems good otherwise.> 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 > */I'm not a legal expert but I've more typically seen newer lines below the old lines and as a part of the same comment.> @@ -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; > }This pair of changes warrant their own commits. For starters, I see you added a NULL check that should have been there in the second chunk. However, the first chunk changes the underlying behavior and warrants some notes for the commit message as to why it's better, especially if the old behavior violated the EFI spec or caused a busy-wait state.> +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;This probably deserves a NULL terminator but perhaps calling EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen() may be better.> @@ -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 fromBody. Style changes warranted.> @@ -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, > };Looks good. Glue.> 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"); > > /*Already changed. Discard chunk.> 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 \Looks good. Body. -- -Gene
Patrick Masotta
2016-Mar-20 17:47 UTC
[syslinux] [PATCH 0/1] EFI image booting capabilities
>>><syslinux at zytor.com> wrote:> 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.If you've made any changes to this, I'd definitely like to see it. If you have any interest in working with git and want some help, feel free to email me privately. <<< I posted this code time ago, there were some changes, I have tried removing the ones not really related to the EFI boot capability. (at that moment they were needed; if not SL was not working.) see here: https://github.com/ppatpat/syslinux/tree/boot_efi Please consider: 1)I've copied the source from my work repository but I have no tested the just uploaded github sources. 2) This code was only tested on PXE boot scenarios. 3) The easiest way to test this code would be something like kernel = /Shell.efi append = -nomap -nostartup>>>For starters, this deserves to be split, unrelated changes to their own commits, the body and then finally a glue commit to put it together. <<< I removed The tiny bits of non-related code present in the original patch>>>Changing existing functionality like this may have negative consequences and splitting helps if a bisection is needed. <<< I think you cannot split anything else; the present code is all needed for EFI boot.>>>I have avery strong preference towards micro-commits of changing functionality for this reason. It helps point to fewer lines of changes. On the other hand, adding new functionality is sometimes better done in fewer commits, often 1-2 and if two, the first adds the code while the second adds the glue to tie it into the existing code. - --Gene <<< Well I think you just cannot add EFI boot with micro commits. Give it a try and let me know. (I still do not receive the list) Best, Patrick