From a2cc45afea018d8328336c13b6223c7caedb0392606b96f2da2f11e62a9820e2 Mon Sep 17 00:00:00 2001 From: Raymund Will Date: Thu, 24 Oct 2013 18:32:17 +0000 Subject: [PATCH 1/2] - Add perl modules to 'PreReq'. (bnc#842183) - Update to elilo-3.14 from SLE11. OBS-URL: https://build.opensuse.org/package/show/Base:System/elilo?expand=0&rev=11 --- 3.14-release-notes.txt | 116 +++ elilo-3.12-source.tar.gz | 3 - elilo-3.14-source.tar.gz | 3 + elilo-MAC.diff | 39 - elilo-auto-add_efi_memmap.diff | 149 ++++ elilo-avoid-tab.diff | 19 - elilo-blocksize.diff | 56 ++ elilo-bzimage-alloc.diff | 47 -- elilo-clean-console.diff | 16 + elilo-cleanup.diff | 183 ----- elilo-fix-possible-overflow.diff | 26 - elilo-fix-strncpy-overflow.diff | 53 -- elilo-ipv6.diff | 458 +++++++++++ elilo-keep-start-params.diff | 19 + elilo-longer-commandline.diff | 109 --- elilo-mac-conf.diff | 67 ++ elilo-max-conf.diff | 33 + elilo-text-mode.diff | 124 +-- elilo-x86-64-bootproto-update.diff | 186 ----- elilo-x86-64-e820-max.diff | 230 ------ elilo-x86-64-initrd.diff | 228 ------ elilo-x86-64-kernel.diff | 257 ------ elilo.changes | 211 ++++- elilo.pl | 1221 +++++++++++++++++++++++----- elilo.spec | 58 +- eliloalt-sysfs.diff | 113 --- 26 files changed, 2212 insertions(+), 1812 deletions(-) create mode 100644 3.14-release-notes.txt delete mode 100644 elilo-3.12-source.tar.gz create mode 100644 elilo-3.14-source.tar.gz delete mode 100644 elilo-MAC.diff create mode 100644 elilo-auto-add_efi_memmap.diff delete mode 100644 elilo-avoid-tab.diff create mode 100644 elilo-blocksize.diff delete mode 100644 elilo-bzimage-alloc.diff create mode 100644 elilo-clean-console.diff delete mode 100644 elilo-cleanup.diff delete mode 100644 elilo-fix-possible-overflow.diff delete mode 100644 elilo-fix-strncpy-overflow.diff create mode 100644 elilo-ipv6.diff create mode 100644 elilo-keep-start-params.diff delete mode 100644 elilo-longer-commandline.diff create mode 100644 elilo-mac-conf.diff create mode 100644 elilo-max-conf.diff delete mode 100644 elilo-x86-64-bootproto-update.diff delete mode 100644 elilo-x86-64-e820-max.diff delete mode 100644 elilo-x86-64-initrd.diff delete mode 100644 elilo-x86-64-kernel.diff delete mode 100644 eliloalt-sysfs.diff diff --git a/3.14-release-notes.txt b/3.14-release-notes.txt new file mode 100644 index 0000000..637493e --- /dev/null +++ b/3.14-release-notes.txt @@ -0,0 +1,116 @@ +3 . 1 4 R E L E A S E N O T E S +=================================== + +QUICK CHANGE SUMMARY +==================== +* Fixes for newly emerging x86_64 UEFI-2 boxes where long standing old + assumptions are borked. +* Uptake of SUSE and community patches + - add sysfs support for efi vars (formerly /proc/efi/vars) + - fix strncpy overflow + - fix bzimage alloc + - cleanups + - support longer command line + - yet some more mac fixes + - align elilo with latest kernel boot protocol format. + - new memory management strategy for initrd and kernel image loading. +* add text-mode command line option, force text-mode (bypass graphics probes). +* replace error output on GOP handle failed, downgraded to normal + print status with more informative output. +* Fix ia32 build issue with new gcc due to stack protector enforcement. + +BUILD NOTES +==================== + You will need the following toolchain to build elilo-3.14 from source + the elilo build environment is optimized for Debian and Debian based distros. + elilo-3.14 was built in the Debian Lenny (Ubuntu 10.04) build environment. + Toolchain versions for this release were: + x86x(32 &64) + * gnu-efi --> 3.0i-2ubuntu1 + * gcc ------> 4.4.3-1ubuntu1 + * binutils -> 2.20.1-3ubuntu7 + ia64 + * gnu-efi --> 3.0e-2 + * gcc ------> 4.3.2-2 + * binutils -> 2.18.1~cvs20080103-7 + + * if you use a debian based (lenny)build environment you will have no problems + and setting it up is simple. you will be able to build elilo in 3 steps: + 1. apt-get install gnu-efi, gcc, binutils + 2. apt-get source elilo (or download elilo-3.14.tar.gz from SourceForge.) + 3. extract source tarball and cd ./elilo-3.14 and type $> make + + + ** If you use the upstream toolchain tarballs(i.e. pre distro) you will need + to move some files around for elilo build to work. + GNU-EFI (provides the efi 1.10 and uefi 2.x libraries & api) + ------- + gnu-efi libraries are installed to /usr/local/lib by the + upstream gnu-efi source package. elilo expects them to be in system location + /usr/lib. efi includes may be located in /usr/local/include/efi. elilo + expects them to be in system location /usr/include/efi. + [ The reason is LSB compliance ]. + + BINUTILS (provides the elf conversion utility to produce efi bins) + -------- + binutils provides objcopy which is installed to /usr/local/bin by binutils, + elilo source expects it to be in /usr/bin. + + again this LSB compliance is taken care of by the distro's that fix + the toolchains to install to the correct compliant system locations + instead of the "user optional" location. + +ELILO ON EFI X86_64 +===================== +HARD REQUIREMENTS + EFI + x86_64 REQUIRES an efi64 enabled linux kernel i.e. 2.6.21 or newer + nothing earlier will work, 2.6.21 was the earliest kernel that efi64 + support went into. You need to compile the kernel with CONFIG_EFI + kernel option ON. + x86_64 platforms with UEFI 2.0 firmware deprecate UGA protocol + and therefore only the Graphics Output Protocol (GOP) is supported. For + such platforms, the kernel must be compiled with EFI_FB option ON. This + will enable early boot messages on the console. Elilo for x86_64 + attempts to query EFI for GOP support and if it fails it defaults to + text mode which may or may not show you early console ouput depends on + your efi console settings and physical setup. Elilo has no way to know + if your console settings are messed up. + +WORKING ELILO.CONF FOR EFI X86_64 EXAMPLE + Here is my elilo.conf from my UEFI2.0/x86_64 (with nvidia pcie add on + card, i.e. your vga= kernel param may be different) workstation which uses GOP. + Here is a partial kernel vga table I was able to find and add here. +Colours 640x400 640x480 800x600 1024x768 1152x864 1280x1024 1600x1200 + -------+-------------------------------------------------------------- + 4 bits | ? ? 0x302 ? ? ? ? + 8 bits | 0x300 0x301 0x303 0x305 0x161 0x307 0x31C + 15 bits | ? 0x310 0x313 0x316 0x162 0x319 0x31D + 16 bits | ? 0x311 0x314 0x317 0x163 0x31A 0x31E + decimal | d785 d788 d791 + 24 bits | ? 0x312 0x315 0x318 ? 0x31B 0x31F + +Additionally from ...kernel-source/Documentation/Boot.txt... + vga= + here is either an integer (in C notation, either + decimal, octal, or hexadecimal) or one of the strings + "normal" (meaning 0xFFFF), "ext" (meaning 0xFFFE) or "ask" + (meaning 0xFFFD). This value should be entered into the + vid_mode field, as it is used by the kernel before the command + line is parsed. + + example below shows me console output, what elilo is doing, and kernel boot. + vga=normal with efi console input output directed to graphics card should + work as well. + + default=UBUNTU + chooser=simple + verbose=5 + delay=30 + append="root=/dev/sda3 vga=0x31e splash showopts" + + image=/vmlinuz-2.6.32-27-generic + label="UBUNTU" + description="Ubuntu 2.6.32-27-generic kernel" + initrd=/initrd.img-2.6.32-27-generic + + diff --git a/elilo-3.12-source.tar.gz b/elilo-3.12-source.tar.gz deleted file mode 100644 index 5ee5cad..0000000 --- a/elilo-3.12-source.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5005534ae972603c65caa8debb2bf3c4a22b895588323bc1b0a7a9f114e030ee -size 215125 diff --git a/elilo-3.14-source.tar.gz b/elilo-3.14-source.tar.gz new file mode 100644 index 0000000..f7026e6 --- /dev/null +++ b/elilo-3.14-source.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:93fb9f9ec22763c3071a19422b3a8073cd020e5d6cca5762a0ff35871f17a4b0 +size 219473 diff --git a/elilo-MAC.diff b/elilo-MAC.diff deleted file mode 100644 index 5708ddb..0000000 --- a/elilo-MAC.diff +++ /dev/null @@ -1,39 +0,0 @@ ---- - glue_netfs.c | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - ---- a/glue_netfs.c -+++ b/glue_netfs.c -@@ -65,6 +65,19 @@ static CHAR16 netfs_default_path[FILENAM - static CHAR16 *hexa=L"0123456789ABCDEF"; - - static VOID -+convert_mac2hex(UINT8 *hw_addr,INTN l, CHAR16 *str) -+{ -+ UINTN i; -+ -+ for (i=0 ; i < l; i++) { -+ str[3*i] = hexa[(hw_addr[i] & 0xf0)>>4]; -+ str[3*i+1] = hexa[hw_addr[i] & 0x0f]; -+ str[3*i+2] = ':'; -+ } -+ str[3*l-1]='\0'; -+} -+ -+static VOID - convert_ip2hex(UINT8 *ip, INTN l, CHAR16 *str) - { - UINTN i; -@@ -210,6 +223,12 @@ netfs_setdefaults(VOID *intf, config_fil - - StrnCpy(config[6].fname, str, maxlen-1); - StrnCpy(config[6].fname+2, CONFIG_EXTENSION, 6); -+ -+ /* use the MAC address as a possible file name as well */ -+ convert_mac2hex(info.hw_addr,6,str); -+ StrnCpy(config[7].fname, str, maxlen-1); -+ StrnCpy(config[7].fname+17, CONFIG_EXTENSION, 6); -+ - #else - StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1); - config[0].fname[maxlen-1] = CHAR_NULL; diff --git a/elilo-auto-add_efi_memmap.diff b/elilo-auto-add_efi_memmap.diff new file mode 100644 index 0000000..592cb6e --- /dev/null +++ b/elilo-auto-add_efi_memmap.diff @@ -0,0 +1,149 @@ +--- + bootparams.c | 15 ++++----------- + x86_64/config.c | 18 ++++++++++++++++++ + x86_64/sysdeps.h | 5 ++++- + x86_64/system.c | 30 +++++++++++++++++++++++++----- + 4 files changed, 51 insertions(+), 17 deletions(-) + +--- a/x86_64/system.c ++++ b/x86_64/system.c +@@ -957,6 +957,11 @@ do_memmap: + #endif + if (e820_map_overflow && !e820_map_overflow_warned) { + CHAR8 *aem = (CHAR8 *)"add_efi_memmap"; ++ UINTN al = strlena( aem) + 1; ++ UINTN cl = strlena( (CHAR8 *)cmdline); ++ INT8 autoadd = (x86_64_auto_add_efi_memmap() && ++ (cl + al) < CMDLINE_MAXLEN); ++ CHAR16 *severity = (autoadd) ? L"Notice" : L"CAUTION"; + e820_map_overflow_warned++; + + #if DEBUG_CREATE_BOOT_PARAMS +@@ -968,11 +973,26 @@ do_memmap: + goto do_memmap; + } + +- Print(L"\nCAUTION: EFI memory map has %d more entr%a" +- " than E820 map supports.\n" +- "To access all memory, '%a' may be necessary.\n\n", +- e820_map_overflow, (e820_map_overflow==1)?"y":"ies", +- aem); ++ Print(L"\n%s: EFI memory map has %d more entr%a than E820 map" ++ " supports.\n", severity, e820_map_overflow, ++ (e820_map_overflow==1)?"y":"ies"); ++ ++ if (autoadd) { ++ strcpya( cmdline + cl, (CHAR8 *)" "); ++ strcpya( cmdline + cl + 1, aem); ++ Print(L"To allow access to all memory, '%a' has been" ++ " auto-added!\n\n", aem); ++ wait_timeout(30); ++ goto do_memmap; ++ } ++ if ((cl + al) >= CMDLINE_MAXLEN) ++ Print(L"But adding '%a' would exceed the maximum" ++ " command-line length", aem); ++ else ++ Print(L"But auto-adding of '%a' is disabled in" ++ " 'elilo.conf'", aem); ++ wait_timeout(60); ++ Print(L"\n\n"); + goto do_memmap; + } + +--- a/x86_64/config.c ++++ b/x86_64/config.c +@@ -34,6 +34,7 @@ + typedef struct { + UINTN legacy_free_boot; + UINTN text_mode; ++ CHAR16 add_efi_memmap[MAX_STRING]; + } x86_64_global_config_t; + + +@@ -42,10 +43,14 @@ typedef struct { + static x86_64_global_config_t x86_64_gconf; + + static config_option_t sysdeps_global_options[]={ ++ {OPT_STR, OPT_GLOBAL, L"add-efi-memmap", ++ NULL, NULL, &x86_64_gconf.add_efi_memmap}, + {OPT_BOOL, OPT_GLOBAL, L"legacy-free", NULL, NULL, &x86_64_gconf.legacy_free_boot} + }; + + static config_option_t sysdeps_image_options[]={ ++ {OPT_STR, OPT_IMAGE_SYS, L"add-efi-memmap", ++ NULL, NULL, x86_64_opt_offsetof(add_efi_memmap)}, + {OPT_BOOL, OPT_IMAGE_SYS, L"text-mode", NULL, NULL, x86_64_opt_offsetof(text_mode)} + }; + +@@ -89,6 +94,19 @@ x86_64_use_legacy_free_boot(VOID) + return x86_64_gconf.legacy_free_boot ? 1 : 0; + } + ++INT8 ++x86_64_auto_add_efi_memmap(VOID) ++{ ++ if (elilo_opt.sys_img_opts) { ++ if (!StrCmp(elilo_opt.sys_img_opts->add_efi_memmap, L"false")) ++ return 0; ++ if (!StrCmp(elilo_opt.sys_img_opts->add_efi_memmap, L"auto")) ++ return 1; ++ } ++ if (!StrCmp(x86_64_gconf.add_efi_memmap, L"false")) ++ return 0; ++ return 1; ++} + + INTN + x86_64_text_mode(VOID) +--- a/x86_64/sysdeps.h ++++ b/x86_64/sysdeps.h +@@ -365,6 +365,7 @@ extern UINTN rmswitch_size; + + extern INTN x86_64_use_legacy_free_boot(); + extern INTN x86_64_text_mode(); ++extern INT8 x86_64_auto_add_efi_memmap(); + + /* + * How to jump to kernel code +@@ -457,9 +458,11 @@ start_kernel(VOID *kentry, boot_params_t + /* Never come back to here. */ + } + ++#define MAX_STRING 512 /* ToDo: move to 'config.h' */ + typedef struct sys_img_options { + UINT8 dummy; /* forces non-zero offset for first field */ +- UINT8 text_mode; /* do not try to initialize Graphics Output Protocol */ ++ UINT8 text_mode; /* don't try to initialize GraphicsOutputProtocol */ ++ CHAR16 add_efi_memmap[MAX_STRING]; /* "false" | "auto" */ + } sys_img_options_t; + + #endif /* __ELILO_SYSDEPS_X86_64_H__ */ +--- a/bootparams.c ++++ b/bootparams.c +@@ -96,21 +96,14 @@ create_boot_params(CHAR16 *args, memdesc + */ + Memset(bp, 0, BOOT_PARAM_MEMSIZE); + ++ /* ++ * Convert kernel command line args from UNICODE to ASCII ++ * and put them where the kernel expects them: ++ */ + U2ascii(args, cp, cmdline_size); + + if (sysdeps_create_boot_params(bp, cp, initrd, vmcode, cookie) == -1) return 0; + +- /* +- * Convert kernel command line args from UNICODE to ASCII and put them where +- * the kernel expects them: +- */ +- while (1) { +- ch = *args++; +- if (!ch) break; +- *cp++ = ch; +- } +- *cp++ = '\0'; +- + return bp; + } + diff --git a/elilo-avoid-tab.diff b/elilo-avoid-tab.diff deleted file mode 100644 index 8cd62fd..0000000 --- a/elilo-avoid-tab.diff +++ /dev/null @@ -1,19 +0,0 @@ ---- - config.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/config.c -+++ b/config.c -@@ -909,10 +909,10 @@ print_label_list(VOID) - { - boot_image_t *img, *dfl = global_config.default_image; - -- if (dfl) Print(L"\t%s\n", dfl->label); -+ if (dfl) Print(L" %s\n", dfl->label); - - for (img = image_list; img; img = img->next) { -- if (img != dfl) Print(L"\t%s\n", img->label); -+ if (img != dfl) Print(L" %s\n", img->label); - } - } - diff --git a/elilo-blocksize.diff b/elilo-blocksize.diff new file mode 100644 index 0000000..3df572c --- /dev/null +++ b/elilo-blocksize.diff @@ -0,0 +1,56 @@ +--- + config.c | 4 ++++ + elilo.h | 2 ++ + fs/netfs.c | 3 ++- + 3 files changed, 8 insertions(+), 1 deletion(-) + +--- a/config.c ++++ b/config.c +@@ -119,6 +119,7 @@ typedef struct { + UINTN timeout; + UINTN verbose; + UINTN edd30_no_force; /* don't force EDD30 if not set */ ++ UINTN blocksize; + } global_config_t; + + /* +@@ -143,6 +144,7 @@ static config_option_t global_common_opt + {OPT_STR, OPT_GLOBAL, L"default", NULL, NULL, global_config.default_image_name}, + {OPT_NUM, OPT_GLOBAL, L"timeout", NULL, NULL, &global_config.timeout}, + {OPT_NUM, OPT_GLOBAL, L"delay", NULL, NULL, &global_config.delay}, ++{OPT_NUM, OPT_GLOBAL, L"block-size", NULL, NULL, &global_config.blocksize}, + {OPT_BOOL, OPT_GLOBAL, L"debug", NULL, NULL, &global_config.debug}, + {OPT_BOOL, OPT_GLOBAL, L"prompt", NULL, NULL, &global_config.prompt}, + {OPT_NUM, OPT_GLOBAL, L"verbose", NULL, check_verbosity, &global_config.verbose}, +@@ -827,6 +829,8 @@ update_elilo_opt(VOID) + + if (global_config.debug) elilo_opt.debug = 1; + if (global_config.prompt) elilo_opt.prompt = 1; ++ if (global_config.blocksize) ++ elilo_opt.blocksize = global_config.blocksize; + + /* + * update only if not set on command line +--- a/elilo.h ++++ b/elilo.h +@@ -105,6 +105,8 @@ typedef struct { + UINTN prompt; /* enter interactive mode */ + UINTN parse_only; /* only parses the config file */ + UINTN timeout; /* timeout before leaving interactive mode*/ ++ UINTN blocksize; /* user-specified block-size for I/O */ ++ /* (currently only used for TFTP!) */ + + image_opt_t img_opt; /* architecture independent per image options*/ + +--- a/fs/netfs.c ++++ b/fs/netfs.c +@@ -522,7 +522,8 @@ netfs_open(netfs_interface_t *this, CHAR + netfs_fd_t *f; + EFI_STATUS status; + CHAR8 ascii_name[FILENAME_MAXLEN]; +- UINTN blocksize = NETFS_DEFAULT_BLOCKSIZE; ++ UINTN blocksize = (elilo_opt.blocksize > 0) ? ++ elilo_opt.blocksize : NETFS_DEFAULT_BLOCKSIZE; + UINTN prev_netbufsize, retries = 0; + BOOLEAN server_provided_filesize = FALSE; + diff --git a/elilo-bzimage-alloc.diff b/elilo-bzimage-alloc.diff deleted file mode 100644 index 789820f..0000000 --- a/elilo-bzimage-alloc.diff +++ /dev/null @@ -1,47 +0,0 @@ -From: Stuart_Hayes@Dell.com -Subject: Re: [elilo-discuss] Follow-Up to 1MB Allocation Problem -Message-ID: - -Here's one solution to the problem, for bzImages in x86_64 (which could -easily be ported to the other image types and architecture). I tried to -make this minimally invasive. If bzImage_probe() can't load the kernel -where it should be, it will just load the kernel anywhere, and it will -be moved to the right address after elilo exits EFI boot services. (I -also made it read where the kernel should be from the kernel header.) -It looks like it was already loading the initrd just anywhere and then -moving it after exiting boot services. - -(I also enhanced the "MEMCPY" macro in x86_64/sysdeps.h so it will copy -to an overlapping area correctly regardless of whether the "from" -address is higher or lower than the "to" address.) - -I originally wrote code that would actually check if the kernel was -relocatable and then relocate it, like the ia64 code does. That worked -fine, except that the address that was found overlapped the area where -elilo copies the initrd in start_kernel() after EFI boot services are -exited! Instead of modifying the initrd addresses, too, I decided it -would be easier and less likely to break anyting else (and would work -with non-relocatable kernels, too) to just do it the other way. - -Any chance we could get this patch into elilo? I can modify and -resubmit if there are any issues with this approach. - -Thanks! - -[ only one change of this patch is still missing... -- rw@suse.de ] - ---- - fs/localfs.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/fs/localfs.c -+++ b/fs/localfs.c -@@ -98,7 +98,7 @@ localfs_open(localfs_interface_t *this, - - DBG_PRT((L"localfs_open on %s\n", name)); - -- status = uefi_call_wrapper(lfs->volume->Open, 5, lfs->volume, &fh, name, EFI_FILE_MODE_READ, 0); -+ status = uefi_call_wrapper(lfs->volume->Open, 5, lfs->volume, &fh, name, EFI_FILE_MODE_READ, (UINT64)0); - if (status == EFI_SUCCESS) { - *fd = LOCALFS_F2FD(fh); - } diff --git a/elilo-clean-console.diff b/elilo-clean-console.diff new file mode 100644 index 0000000..e56550f --- /dev/null +++ b/elilo-clean-console.diff @@ -0,0 +1,16 @@ +--- + elilo.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/elilo.c ++++ b/elilo.c +@@ -483,6 +483,9 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_T + */ + uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x0, 0, NULL); + ++ /* start a clean console */ ++ uefi_call_wrapper(systab->ConOut->Reset, 2, systab->ConOut, FALSE); ++ + /* initialize memory allocator */ + if (alloc_init() == -1) return EFI_LOAD_ERROR; + diff --git a/elilo-cleanup.diff b/elilo-cleanup.diff deleted file mode 100644 index 8d557c0..0000000 --- a/elilo-cleanup.diff +++ /dev/null @@ -1,183 +0,0 @@ ---- - Makefile | 2 +- - alloc.c | 12 ++++++------ - choosers/Makefile | 14 +++++--------- - fileops.c | 2 +- - fs/Makefile | 14 +++++--------- - glue_netfs.c | 4 ++++ - x86_64/bzimage.c | 6 ++++-- - 7 files changed, 26 insertions(+), 28 deletions(-) - ---- a/Makefile -+++ b/Makefile -@@ -81,7 +81,7 @@ elilo.efi: elilo.so - - elilo.so: $(FILES) - --elilo.o : elilo.c -+elilo.o : elilo.c $(ARCH)/sysdeps.h - - fileops.o : Make.defaults - chooser.o : Make.defaults ---- a/alloc.c -+++ b/alloc.c -@@ -110,7 +110,7 @@ alloc(UINTN size, EFI_MEMORY_TYPE type) - } - alloc_add(tmp, size, ALLOC_POOL); - #ifdef DEBUG_MEM -- DBG_PRT((L"alloc: allocated %d bytes @[" PTR_FMT "-" PTR_FMT "]\n", size, tmp, tmp+size)); -+ DBG_PRT((L"alloc: allocated %d bytes @[" PTR_FMT "-" PTR_FMT "]", size, tmp, tmp+size)); - #endif - return tmp; - } -@@ -140,7 +140,7 @@ alloc_pages(UINTN pgcnt, EFI_MEMORY_TYPE - - alloc_add(addr, pgcnt, ALLOC_PAGES); - -- DBG_PRT((L"allocator: allocated %d pages @0x%lx\n", pgcnt, tmp)); -+ DBG_PRT((L"allocator: allocated %d pages @" PTR_FMT, pgcnt, tmp)); - - return addr; - } -@@ -162,7 +162,7 @@ free(VOID *addr) - return; - found: - #ifdef DEBUG_MEM -- DBG_PRT((L"free: %s @" PTR_FMT " size=%d\n", -+ DBG_PRT((L"free: %s @" PTR_FMT " size=%d", - p->type == ALLOC_POOL ? L"Pool": L"Page", - addr, p->size)); - #endif -@@ -196,7 +196,7 @@ free_all(VOID) - - while(used_allocs) { - #ifdef DEBUG_MEM -- DBG_PRT((L"free_all %a @ " PTR_FMT "\n", used_allocs->type == ALLOC_POOL ? "pool" : "pages", used_allocs->addr)); -+ DBG_PRT((L"free_all %a @ " PTR_FMT, used_allocs->type == ALLOC_POOL ? "pool" : "pages", used_allocs->addr)); - #endif - if (used_allocs->type == ALLOC_POOL) - uefi_call_wrapper(BS->FreePool, 1, used_allocs->addr); -@@ -249,7 +249,7 @@ VOID - free_kmem(VOID) - { - #ifdef DEBUG_MEM -- DBG_PRT((L"free_kmem before (" PTR_FMT ", %d)\n", kmem_addr, kmem_pgcnt)); -+ DBG_PRT((L"free_kmem before (" PTR_FMT ", %d)", kmem_addr, kmem_pgcnt)); - #endif - if (kmem_addr && kmem_pgcnt != 0) { - free(kmem_addr); -@@ -257,7 +257,7 @@ free_kmem(VOID) - kmem_pgcnt = 0; - } - #ifdef DEBUG_MEM -- DBG_PRT((L"free_kmem after (" PTR_FMT ", %d)\n", kmem_addr, kmem_pgcnt)); -+ DBG_PRT((L"free_kmem after (" PTR_FMT ", %d)", kmem_addr, kmem_pgcnt)); - #endif - } - ---- a/choosers/Makefile -+++ b/choosers/Makefile -@@ -42,17 +42,13 @@ TARGET=choosers.o - - all: $(TARGET) - --$(TARGET): check-choosers $(TOPDIR)/Make.defaults $(FILES) -+$(TARGET): $(TOPDIR)/Make.defaults $(FILES) -+ @if [ -z "$(FILES)" ]; then \ -+ echo "You need to define at least one chooser in Make.defaults"; \ -+ exit 1; \ -+ fi - $(LD) -o $@ -r $(FILES) - - clean: - $(RM) -f $(TARGET) $(FILES) -- --check-choosers: -- @if [ -n "$(FILES)" ]; then \ -- exit 0; \ -- else \ -- echo "You need to define at least one chooser in Make.defaults"; \ -- exit 1; \ -- fi - ---- a/fileops.c -+++ b/fileops.c -@@ -497,7 +497,7 @@ add_dev_tab(EFI_GUID *proto, EFI_HANDLE - - str2 = str == NULL ? L"Unknown" : str; - -- DBG_PRT((L"%s : %-8s : %s\n", dev_tab[idx].name, -+ DBG_PRT((L"%s : %-8s : %s", dev_tab[idx].name, - (dev_tab[idx].fops ? dev_tab[idx].fops->name: L"N/A"), str2)); - - if (str) FreePool(str); ---- a/fs/Makefile -+++ b/fs/Makefile -@@ -54,17 +54,13 @@ all: $(TARGET) - # XXX: does not trigger recompile when changing filesystem selection - # without doing make clean. - # --$(TARGET): check-filesystems $(TOPDIR)/Make.defaults $(FILES) -+$(TARGET): $(TOPDIR)/Make.defaults $(FILES) -+ @if [ -z "$(FILES)" ]; then \ -+ echo "You need to define at least one filesystem in Make.defaults"; \ -+ exit 1; \ -+ fi - $(LD) -r -o $@ $(FILES) - - clean: - $(RM) -f $(TARGET) $(FILES) - --check-filesystems: -- @if [ -n "$(FILES)" ]; then \ -- exit 0; \ -- else \ -- echo "You need to define at least one filesystem in Make.defaults"; \ -- exit 1; \ -- fi -- ---- a/glue_netfs.c -+++ b/glue_netfs.c -@@ -153,6 +153,8 @@ netfs_setdefaults(VOID *intf, config_fil - set_var(VAR_NETFS_DOMAINAME, info.domainame); - - if (info.using_pxe) { -+ DBG_PRT((L"netfs_setdefaults: using_pxe")); -+ - status = netfs->netfs_query_layer(netfs, 0, NETFS_CONFIG_LAYER, maxlen, config[0].fname); - if (EFI_ERROR(status)) { - StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1); -@@ -181,6 +183,8 @@ netfs_setdefaults(VOID *intf, config_fil - # endif - - # define CONFIG_EXTENSION L".conf\0" -+ -+ DBG_PRT((L"netfs_setdefaults: machine specific (!using_pxe)")); - /* - * will try machine/subnet specific files first. - * the filenames are constructed based on the IP(v4) address ---- a/x86_64/bzimage.c -+++ b/x86_64/bzimage.c -@@ -295,18 +295,20 @@ bzImage_probe(CHAR16 *kname) - * Now read the rest of the kernel image into memory. - */ - -- DBG_PRT((L"reading kernel image...\n")); -+ Print(L"Loading kernel %s... ", kname); - - size = kernel_size; - efi_status = fops_read(fd, kernel_load_address, &size); - if (EFI_ERROR(efi_status) || size < 0x10000) { -- ERR_PRT((L"Error reading kernel image %s.", kname)); -+ ERR_PRT((L"Error reading kernel image (0x%x).", efi_status)); - free(param_start); - param_start = NULL; - param_size = 0; - fops_close(fd); - free_kmem(); - return -1; -+ } else { -+ Print(L" done\n"); - } - - DBG_PRT((L"kernel image read: %d bytes, %d Kbytes\n", size, size / 1024)); diff --git a/elilo-fix-possible-overflow.diff b/elilo-fix-possible-overflow.diff deleted file mode 100644 index 5be8d41..0000000 --- a/elilo-fix-possible-overflow.diff +++ /dev/null @@ -1,26 +0,0 @@ -From: Bernhard Walle -Subject: [PATCH] Fix possible array length overflow -References: bnc#256676 - -Found by dan.yeisley@unisys.com. - - -Signed-off-by: Bernhard Walle - ---- - choosers/simple.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/choosers/simple.c -+++ b/choosers/simple.c -@@ -290,8 +290,9 @@ restart: - - if (elilo_opt.prompt) { - console_textmode(); -- ret = select_kernel(buffer, sizeof(buffer)); -+ ret = select_kernel(buffer, CMDLINE_MAXLEN); - if (ret == -1) return -1; -+ /* this function takes really the number of bytes ... */ - argc = argify(buffer,sizeof(buffer), argv); - index = 0; - } diff --git a/elilo-fix-strncpy-overflow.diff b/elilo-fix-strncpy-overflow.diff deleted file mode 100644 index 48eb79e..0000000 --- a/elilo-fix-strncpy-overflow.diff +++ /dev/null @@ -1,53 +0,0 @@ -From: Jarrod Johnson - -Fix StrnCpy bug that would overflow dst buffer if length of src met or -exceeded passed size value. - ---- - strops.c | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - ---- a/strops.c -+++ b/strops.c -@@ -41,11 +41,11 @@ StrnCpy(OUT CHAR16 *dst, IN const CHAR16 - { - CHAR16 *res = dst; - -- while (size-- && (*dst++ = *src++) != CHAR_NULL); -+ while (size && size-- && (*dst++ = *src++) != CHAR_NULL); - /* - * does the null padding - */ -- while (size-- > 0) *dst++ = CHAR_NULL; -+ while (size && size-- > 0) *dst++ = CHAR_NULL; - - return res; - } -@@ -55,11 +55,11 @@ StrnXCpy(OUT CHAR8 *dst, IN const CHAR16 - { - CHAR8 *res = dst; - -- while (size-- && (*dst++ = (CHAR8)*src++) != '\0'); -+ while (size && size-- && (*dst++ = (CHAR8)*src++) != '\0'); - /* - * does the null padding - */ -- while (size-- > 0) *dst++ = '\0'; -+ while (size && size-- > 0) *dst++ = '\0'; - - return res; - } -@@ -76,11 +76,11 @@ strncpya(OUT CHAR8 *dst, IN const CHAR8 - { - CHAR8 *res = dst; - -- while (size-- && (*dst++ = *src++) != '\0'); -+ while (size && size-- && (*dst++ = *src++) != '\0'); - /* - * does the null padding - */ -- while (size-- > 0) *dst++ = '\0'; -+ while (size && size-- > 0) *dst++ = '\0'; - - return res; - } diff --git a/elilo-ipv6.diff b/elilo-ipv6.diff new file mode 100644 index 0000000..eea8271 --- /dev/null +++ b/elilo-ipv6.diff @@ -0,0 +1,458 @@ +--- + fs/netfs.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- + glue_netfs.c | 53 ++++++++++-- + strops.c | 11 ++ + strops.h | 1 + 4 files changed, 302 insertions(+), 20 deletions(-) + +--- a/glue_netfs.c ++++ b/glue_netfs.c +@@ -133,6 +133,17 @@ netfs_set_default_path(netfs_interface_t + return EFI_SUCCESS; + } + ++static INTN ++non_zero(UINT8 *c, UINTN len) ++{ ++ int i; ++ for (i=0 ; i < len ; i++) { ++ if (c[i]) ++ return 1; ++ } ++ return 0; ++} ++ + static EFI_STATUS + netfs_setdefaults(VOID *intf, config_file_t *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath) + { +@@ -140,7 +151,7 @@ netfs_setdefaults(VOID *intf, config_fil + netfs_info_t info; + EFI_STATUS status; + UINT8 *ipaddr; +- UINTN m; ++ UINTN m, i; + CHAR16 ip_var[64], str[64]; + UINT8 *ip; + +@@ -165,6 +176,9 @@ netfs_setdefaults(VOID *intf, config_fil + set_var(VAR_NETFS_HOSTNAME, info.hostname); + set_var(VAR_NETFS_DOMAINAME, info.domainame); + ++ DBG_PRT((L"netfs_setdefaults: hostname=%s (IPv%a)", info.hostname, ++ (info.using_ipv6 ? "6" : "4"))); ++ + if (info.using_pxe) { + DBG_PRT((L"netfs_setdefaults: using_pxe")); + +@@ -184,13 +198,10 @@ netfs_setdefaults(VOID *intf, config_fil + + # if defined(CONFIG_ia64) + # define CONFIG_ARCH_EXTENSION L"-ia64.conf\0" +-# define EXTENSION_LENGTH 11 + # elif defined (CONFIG_ia32) + # define CONFIG_ARCH_EXTENSION L"-ia32.conf\0" +-# define EXTENSION_LENGTH 11 + # elif defined (CONFIG_x86_64) + # define CONFIG_ARCH_EXTENSION L"-x86_64.conf\0" +-# define EXTENSION_LENGTH 13 + # else + # error "You need to specfy your default arch config file" + # endif +@@ -203,31 +214,57 @@ netfs_setdefaults(VOID *intf, config_fil + * the filenames are constructed based on the IP(v4) address + */ + convert_ip2hex(ipaddr, m, str); ++#if 1 ++ i = 0; ++ if (non_zero(ipaddr, m)) { ++ int nr = (m==16)? 10 : 6; ++ int st = (m==16)? 2 : 1; ++ m <<= 1; ++ StrnCpy(config[i].fname, str, m); ++ StrnCat(config[i++].fname, ++ CONFIG_EXTENSION, maxlen - m); ++ while (i <= nr) { ++ int stub = m - (i+1)*st; ++ StrnCpy(config[i].fname, str, stub); ++ StrnCat(config[i++].fname, ++ CONFIG_ARCH_EXTENSION, maxlen - m); ++ StrnCpy(config[i].fname, str, stub); ++ StrnCat(config[i++].fname, ++ CONFIG_EXTENSION, maxlen - m); ++ } ++ } ++ if (non_zero(info.hw_addr, 6)) { ++ convert_mac2hex(info.hw_addr,6,str); ++ StrnCpy(config[i].fname, str, maxlen-1); ++ StrnCpy(config[i++].fname+17, CONFIG_EXTENSION, 6); ++ } ++#else + StrnCpy(config[0].fname, str, maxlen-1); + StrnCpy(config[0].fname+8, CONFIG_EXTENSION, 6); + + StrnCpy(config[1].fname, str, maxlen-1); +- StrnCpy(config[1].fname+6, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH); ++ StrnCpy(config[1].fname+6, CONFIG_ARCH_EXTENSION, maxlen-7); + + StrnCpy(config[2].fname, str, maxlen-1); + StrnCpy(config[2].fname+6, CONFIG_EXTENSION, 6); + + StrnCpy(config[3].fname, str, maxlen-1); +- StrnCpy(config[3].fname+4, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH); ++ StrnCpy(config[3].fname+4, CONFIG_ARCH_EXTENSION, maxlen-5); + + StrnCpy(config[4].fname, str, maxlen-1); + StrnCpy(config[4].fname+4, CONFIG_EXTENSION, 6); + + StrnCpy(config[5].fname, str, maxlen-1); +- StrnCpy(config[5].fname+2, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH); ++ StrnCpy(config[5].fname+2, CONFIG_ARCH_EXTENSION, maxlen-3); + + StrnCpy(config[6].fname, str, maxlen-1); +- StrnCpy(config[6].fname+2, CONFIG_EXTENSION, 6); ++ StrnCpy(config[6].fname+2, CONFIG_EXTENSION, maxlen-3); + + /* use the MAC address as a possible file name as well */ + convert_mac2hex(info.hw_addr,6,str); + StrnCpy(config[7].fname, str, maxlen-1); + StrnCpy(config[7].fname+17, CONFIG_EXTENSION, 6); ++#endif + + #else + StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1); +--- a/strops.c ++++ b/strops.c +@@ -50,6 +50,17 @@ StrnCpy(OUT CHAR16 *dst, IN const CHAR16 + return res; + } + ++CHAR16 * ++StrnCat(OUT CHAR16 *dst, IN const CHAR16 *src, IN UINTN size) ++{ ++ CHAR16 *res; ++ ++ while (size && size-- && (*dst++) != CHAR_NULL); ++ res = StrnCpy(--dst, src, size); ++ ++ return res; ++} ++ + CHAR8 * + StrnXCpy(OUT CHAR8 *dst, IN const CHAR16 *src, IN UINTN size) + { +--- a/strops.h ++++ b/strops.h +@@ -28,6 +28,7 @@ + + extern CHAR16 *StrChr(IN const CHAR16 *s, const CHAR16 c); + extern CHAR16 *StrnCpy(OUT CHAR16 *dst, IN const CHAR16 *src, UINTN count); ++extern CHAR16 *StrnCat(OUT CHAR16 *dst, IN const CHAR16 *src, UINTN count); + extern CHAR8 *StrnXCpy(OUT CHAR8 *dst, IN const CHAR16 *src, UINTN count); + + extern CHAR8 *strtok_simple(CHAR8 *in, CHAR8 c); +--- a/fs/netfs.c ++++ b/fs/netfs.c +@@ -75,6 +75,8 @@ typedef struct { + EFI_IP_ADDRESS netmask; + UINT8 hw_addr[16]; + ++ CHAR8 bootfile[NETFS_BOOTFILE_MAXLEN]; ++ + netfs_fd_t fd_tab[NETFS_FD_MAX]; + netfs_fd_t *free_fd; + UINTN free_fd_count; +@@ -206,11 +208,239 @@ netfs_name(netfs_interface_t *this, CHAR + return EFI_SUCCESS; + } + ++typedef struct { ++ UINT16 code; ++ UINT16 len; ++ UINT8 data[]; ++} DHCPv6_OPTION; ++ ++#define DHCPv6_REPLY 7 ++#define OPT_BOOTFILE_URL 59 ++#define PROTO "tftp://" /* only TFTP supported for now */ ++ ++static inline UINT16 ++bswap16(UINT16 x) ++{ ++ return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)); ++} ++#if __BYTE_ORDER == __LITTLE_ENDIAN ++# define ntohs(x) bswap16(x) ++# define htons(x) bswap16(x) ++#else ++# if __BYTE_ORDER == __BIG_ENDIAN ++# define ntohs(x) (x) ++# define htons(x) (x) ++# endif ++#endif ++/* string 2 net short */ ++static UINT16 ++stra2ns(CHAR8 *str) ++{ ++ UINT16 ret = 0; ++ UINT8 v; ++ for(;*str;str++) { ++ if ('0' <= *str && *str <= '9') ++ v = *str - '0'; ++ else if ('A' <= *str && *str <= 'F') ++ v = *str - 'A' + 10; ++ else if ('a' <= *str && *str <= 'f') ++ v = *str - 'a' + 10; ++ else ++ v = 0; ++ ret = (ret << 4) + v; ++ } ++ /* DBG_PRT((L"stra2ns: '%a'='%d'", str, ret)); */ ++ return htons(ret); ++} ++ ++/* IPv4/6 address to string */ ++static CHAR8 * ++ip2stra(UINT8 octets, UINT8 *ip) ++{ ++ int i, j; ++ static CHAR8 *hexa= (CHAR8 *)"0123456789ABCDEF"; ++ static CHAR8 str[42]; ++ ++ if (octets == 16) { ++ for(i=j=0; i < 16; i++) { ++ str[j++] = hexa[(ip[i] & 0xf0)>>4]; ++ str[j++] = hexa[ip[i] & 0x0f]; ++ if (i && i%2 == 0) ++ str[j++] = ':'; ++ } ++ } else if (octets == 4) { ++ int val, v; ++ for(i=j=0; i < 4; i++) { ++ val = ip[i]; ++ v = val / 100; ++ if (v) ++ str[j++] = '0' + v; ++ v = (val % 100) / 10; ++ if (v || val > 99) ++ str[j++] = '0' + v; ++ val %= 10; ++ str[j++] = '0' + val; ++ str[j++] = '.'; ++ } ++ } else ++ j = 1; ++ str[--j] = '\0'; ++ /* DBG_PRT((L"ip2stra: '%a'", str)); */ ++ return str; ++} ++ ++/* string 2 IPv6 address */ ++static UINT8 * ++stra2ip6(CHAR8 *str) ++{ ++ UINTN i, j, p, len; ++ CHAR8 *a, *b, t; ++ static UINT16 ip[8]; ++ ++ for(i=0; i < 8; i++) { ++ ip[i] = 0; ++ } ++ len = strlena( str); ++ a = b = str; ++ for(i=p=0; i < len; i++, b++) { ++ if (*b != ':') ++ continue; ++ *b = '\0'; ++ ip[p++] = stra2ns(a); ++ *b = ':'; ++ a = b + 1; ++ if ( *(b+1) == ':' ) ++ break; ++ } ++ a = b = str + len; ++ for(j=len, p=7; j > i; j--, a--) { ++ if (*a != ':') ++ continue; ++ t = *b; ++ *b = '\0'; ++ ip[p--] = stra2ns(a+1); ++ *b = t; ++ b = a; ++ } ++ DBG_PRT((L"stra2ip6: '%a'='%a'", str, ip2stra(16, (UINT8 *)ip))); ++ return (UINT8 *)ip; ++} ++ ++static VOID ++hexdump(UINT8 *dp, int size) ++{ ++ int i = 0, j; ++ unsigned char *d = (unsigned char *)dp; ++ char hex[64], chr[17]; ++ static CHAR8 *hexa= (CHAR8 *)"0123456789ABCDEF"; ++ ++ hex[58] = '\0'; ++ chr[16] = '\0'; ++ while ( i < size ) { ++ if ( i > 0 && i % 16 == 0 ) ++ Print(L"%a >%a<\n", hex, chr); ++ if ( i % 16 == 0 ) { ++ Memset( hex, ' ', 58); ++ hex[56] = '\0'; ++ if (i>0xFFFFFF) return; ++ for (j = 0; j < 6; j++) ++ hex[j] = hexa[(i>>(4*(5-j))) & 0xF]; ++ } ++#define pos(i) ((((i%16)<8)?8:9)+(i%16)*3) ++ hex[pos(i)] = hexa[d[i]>>4&0xF]; ++ hex[pos(i)+1] = hexa[d[i]&0xF]; ++ ++ chr[i%16] = ((d[i]>31&&d[i]<127)?d[i]:'.'); ++ i++; ++ } ++ if ( i % 16 != 1 ) { ++ chr[(i%16)] = '\0'; ++ Print(L"%a >%a<\n", hex, chr); ++ } ++} ++ ++static INTN ++find_dhcp6_option( ++ EFI_PXE_BASE_CODE_PACKET *packet, ++ UINT8 option, ++ CHAR8 *str, ++ INTN *length) ++{ ++ EFI_PXE_BASE_CODE_DHCPV6_PACKET *v6 = ++ (EFI_PXE_BASE_CODE_DHCPV6_PACKET *)packet->Raw; ++ int code, len; ++ DHCPv6_OPTION *p; ++ ++ /* Consistency check */ ++ if (v6->MessageType != DHCPv6_REPLY) { ++ VERB_PRT(2, Print(L"DHCPv6: MessageType: %d != %d\n", ++ v6->MessageType, DHCPv6_REPLY)); ++ VERB_PRT(3, hexdump( (UINT8 *)v6, 1024)); ++ return -1; ++ } ++ p = (DHCPv6_OPTION *)&v6->DhcpOptions; ++ while (0 != (code = ntohs(p->code))) { ++ len = ntohs(p->len); ++ ++ VERB_PRT(4, { Print(L"DHCPv6: REPLY: Code=%d Len=%d\n", ++ code, len); ++ hexdump( p->data, (len<1020)?len:144); ++ }); ++ if ( code == option ) { ++ len = (len > *length - 1) ? *length - 1 : len; ++ Memcpy(str, p->data, len); ++ str[len] = '\0'; ++ *length = len; ++ } ++ p = (DHCPv6_OPTION *)((UINT8 *)p + len + 2*sizeof(UINT16)); ++ } ++ return 0; ++} ++static INTN ++parse_bootfile_url(netfs_priv_state_t *nfs, CHAR8 *url) { ++ CHAR8 *end; ++ VERB_PRT(3, Print(L"DHCPv6: bootfile-url: '%a'\n", url)); ++ ++ /* check protocol */ ++ if (strncmpa(url, (CHAR8 *)PROTO, sizeof(PROTO)-1)) { ++ ERR_PRT((L"Warning: bootfile-url must use TFTP for now! (%a)\n", ++ PROTO)); ++ return -1; ++ } ++ /* fill in v6 address */ ++ end = url+sizeof(PROTO); ++ while (*end != ']' && *end != '\0') ++ ++end; ++ if (url[sizeof(PROTO)-1] != '[' || *end != ']') { ++ ERR_PRT((L"Warning: bootfile-url must use '[IPv6::addr]'!\n")); ++ return -1; ++ } ++ *end = '\0'; ++ Memcpy( nfs->srv_ip.v6.Addr, stra2ip6(url+sizeof(PROTO)), 16); ++ *end = ']'; ++ ++ /* remember bootfile path */ ++ strncpya( nfs->bootfile, end + 1, NETFS_BOOTFILE_MAXLEN); ++ return 0; ++} ++ + static VOID + netfs_extract_ip(netfs_priv_state_t *nfs) + { + EFI_PXE_BASE_CODE *pxe = nfs->pxe; + ++ Memcpy(&nfs->cln_ip, &pxe->Mode->StationIp, sizeof(EFI_IP_ADDRESS)); ++ ++ if (pxe->Mode->UsingIpv6) { ++ CHAR8 str[NETFS_BOOTFILE_MAXLEN]; ++ INTN len = NETFS_BOOTFILE_MAXLEN; ++ if (find_dhcp6_option(&nfs->pxe->Mode->DhcpAck, ++ OPT_BOOTFILE_URL, str, &len) != 0) ++ return; ++ parse_bootfile_url(nfs, str); ++ return; ++ } ++ + if (pxe->Mode->PxeDiscoverValid) { + nfs->using_pxe = TRUE; + Memcpy(&nfs->srv_ip, pxe->Mode->PxeReply.Dhcpv4.BootpSiAddr, sizeof(EFI_IP_ADDRESS)); +@@ -218,9 +453,9 @@ netfs_extract_ip(netfs_priv_state_t *nfs + } else { + Memcpy(&nfs->srv_ip, pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr, sizeof(EFI_IP_ADDRESS)); + Memcpy(&nfs->hw_addr, pxe->Mode->DhcpAck.Dhcpv4.BootpHwAddr, sizeof(nfs->hw_addr)); ++ strncpya(nfs->bootfile, pxe->Mode->DhcpAck.Dhcpv4.BootpBootFile, NETFS_BOOTFILE_MAXLEN); + } + +- Memcpy(&nfs->cln_ip, &pxe->Mode->StationIp, sizeof(EFI_IP_ADDRESS)); + Memcpy(&nfs->netmask, &pxe->Mode->SubnetMask, sizeof(EFI_IP_ADDRESS)); + + /* +@@ -326,11 +561,9 @@ netfs_open(netfs_interface_t *this, CHAR + + U2ascii(name, ascii_name, FILENAME_MAXLEN); + +- VERB_PRT(2, Print(L"downloading %a from %d.%d.%d.%d...\n", ascii_name, +- nfs->srv_ip.v4.Addr[0], +- nfs->srv_ip.v4.Addr[1], +- nfs->srv_ip.v4.Addr[2], +- nfs->srv_ip.v4.Addr[3])); ++ VERB_PRT(2, Print(L"downloading %a from %a...\n", ascii_name, ++ ip2stra((nfs->pxe->Mode->UsingIpv6 ? 16 : 4), ++ (UINT8 *)nfs->srv_ip.Addr))); + retry: + if (retries == 2) { + netfs_fd_free(nfs, f); +@@ -571,6 +804,9 @@ find_dhcp_option(EFI_PXE_BASE_CODE_PACKE + UINT8 tag, length; + UINT8 *opts = packet->Dhcpv4.DhcpOptions; + ++ if (use_ipv6) ++ return find_dhcp6_option(packet, option, str, len); ++ + *len = 0; + + for(;;) { +@@ -637,15 +873,12 @@ netfs_getinfo(netfs_interface_t *this, n + + VERB_PRT(3, Print(L"hostname(12): %a\n", str)); + +- /* +- * extract bootfile name from DHCP exchanges +- */ +- if (nfs->using_pxe == 0) { +- ascii2U(nfs->pxe->Mode->DhcpAck.Dhcpv4.BootpBootFile, info->bootfile, NETFS_BOOTFILE_MAXLEN); ++skip_options: ++ if (!info->using_pxe && nfs->bootfile) { ++ ascii2U(nfs->bootfile, info->bootfile, NETFS_BOOTFILE_MAXLEN); + VERB_PRT(3, Print(L"bootfile: %s\n", info->bootfile)); + } + +-skip_options: + return EFI_SUCCESS; + } + diff --git a/elilo-keep-start-params.diff b/elilo-keep-start-params.diff new file mode 100644 index 0000000..7181af4 --- /dev/null +++ b/elilo-keep-start-params.diff @@ -0,0 +1,19 @@ +--- + x86_64/system.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/x86_64/system.c ++++ b/x86_64/system.c +@@ -641,9 +641,9 @@ sysdeps_create_boot_params( + */ + if (param_start != NULL) { + CopyMem(bp, param_start, 0x2000); +- free(param_start); +- param_start = NULL; +- param_size = 0; ++ /* keeping param_start might lose some RAM, ++ * but doesn't crash... ++ */ + } + /* + * Save off our header revision information. diff --git a/elilo-longer-commandline.diff b/elilo-longer-commandline.diff deleted file mode 100644 index 6b78a8c..0000000 --- a/elilo-longer-commandline.diff +++ /dev/null @@ -1,109 +0,0 @@ -From: Bernhard Walle -Subject: Increase command line size to 2048 chars. -References: bnc#242702 - -Signed-off-by: Bernhard Walle - ---- - choosers/simple.c | 10 +++++----- - choosers/textmenu.c | 6 +++--- - config.c | 6 +++--- - elilo.c | 2 +- - elilo.h | 3 ++- - 5 files changed, 14 insertions(+), 13 deletions(-) - ---- a/choosers/simple.c -+++ b/choosers/simple.c -@@ -41,8 +41,8 @@ static VOID - display_label_info(CHAR16 *name) - { - CHAR16 *desc; -- CHAR16 initrd_name[CMDLINE_MAXLEN]; -- CHAR16 vmcode_name[CMDLINE_MAXLEN]; -+ CHAR16 initrd_name[PATHNAME_MAXLEN]; -+ CHAR16 vmcode_name[PATHNAME_MAXLEN]; - CHAR16 options_tmp[CMDLINE_MAXLEN]; - CHAR16 options[CMDLINE_MAXLEN]; - CHAR16 kname[FILENAME_MAXLEN]; -@@ -254,10 +254,10 @@ simple_choose(CHAR16 **argv, INTN argc, - # define BOOT_IMG_STR L"BOOT_IMAGE=" - CHAR16 buffer[CMDLINE_MAXLEN]; - CHAR16 alt_buffer[CMDLINE_MAXLEN]; -- CHAR16 initrd_name[CMDLINE_MAXLEN]; -- CHAR16 vmcode_name[CMDLINE_MAXLEN]; -+ CHAR16 initrd_name[PATHNAME_MAXLEN]; -+ CHAR16 vmcode_name[PATHNAME_MAXLEN]; - CHAR16 args[CMDLINE_MAXLEN]; -- CHAR16 devname[CMDLINE_MAXLEN]; -+ CHAR16 devname[PATHNAME_MAXLEN]; - CHAR16 dpath[FILENAME_MAXLEN]; - CHAR16 *slash_pos, *colon_pos, *backslash_pos; - UINTN len; ---- a/choosers/textmenu.c -+++ b/choosers/textmenu.c -@@ -363,10 +363,10 @@ textmenu_choose(CHAR16 **argv, INTN argc - { - # define BOOT_IMG_STR L"BOOT_IMAGE=" - CHAR16 label[CMDLINE_MAXLEN]; -- CHAR16 initrd_name[CMDLINE_MAXLEN]; -- CHAR16 vmcode_name[CMDLINE_MAXLEN]; -+ CHAR16 initrd_name[PATHNAME_MAXLEN]; -+ CHAR16 vmcode_name[PATHNAME_MAXLEN]; - CHAR16 args[CMDLINE_MAXLEN]; -- CHAR16 devname[CMDLINE_MAXLEN]; -+ CHAR16 devname[PATHNAME_MAXLEN]; - CHAR16 dpath[FILENAME_MAXLEN]; - CHAR16 *slash_pos, *colon_pos, *backslash_pos; - UINTN len; ---- a/config.c -+++ b/config.c -@@ -56,7 +56,7 @@ - */ - #define ELILO_DEFAULT_CONFIG L"elilo.conf" - --#define MAX_STRING CMDLINE_MAXLEN -+#define MAX_STRING 512 - #define CONFIG_BUFSIZE 512 /* input buffer size */ - - /* -@@ -71,7 +71,7 @@ typedef struct boot_image { - struct boot_image *next; - CHAR16 label[MAX_STRING]; - CHAR16 kname[FILENAME_MAXLEN]; -- CHAR16 options[MAX_STRING]; -+ CHAR16 options[CMDLINE_MAXLEN]; - CHAR16 initrd[FILENAME_MAXLEN]; - CHAR16 vmcode[FILENAME_MAXLEN]; - CHAR16 root[FILENAME_MAXLEN]; -@@ -100,7 +100,7 @@ typedef struct { - CHAR16 root[FILENAME_MAXLEN]; /* globally defined root fs */ - CHAR16 initrd[FILENAME_MAXLEN];/* globally defined initrd */ - CHAR16 vmcode[FILENAME_MAXLEN];/* globally defined boot-time module */ -- CHAR16 options[MAX_STRING]; -+ CHAR16 options[CMDLINE_MAXLEN]; - CHAR16 default_image_name[MAX_STRING]; - CHAR16 message_file[MAX_MESSAGES][FILENAME_MAXLEN]; - CHAR16 chooser[FILENAME_MAXLEN];/* which image chooser to use */ ---- a/elilo.c -+++ b/elilo.c -@@ -93,7 +93,7 @@ do_kernel_load(CHAR16 *kname, kdesc_t *k - INTN - kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem, memdesc_t *mmem) - { -- CHAR16 kernel[CMDLINE_MAXLEN]; -+ CHAR16 kernel[FILENAME_MAXLEN]; - - /* - * Do the vm image switch here ---- a/elilo.h -+++ b/elilo.h -@@ -69,7 +69,8 @@ - #define ELILO_DEFAULT_TIMEOUT ELILO_TIMEOUT_INFINITY - #define ELILO_TIMEOUT_INFINITY (~0UL) - --#define CMDLINE_MAXLEN 512 /* needed by ia32 */ -+#define CMDLINE_MAXLEN 2048 -+#define PATHNAME_MAXLEN 512 - #define FILENAME_MAXLEN 256 - #define MAX_ARGS 256 - /* Just pick an arbitrary number that's high enough for now :o) */ diff --git a/elilo-mac-conf.diff b/elilo-mac-conf.diff new file mode 100644 index 0000000..8017a77 --- /dev/null +++ b/elilo-mac-conf.diff @@ -0,0 +1,67 @@ +--- + glue_netfs.c | 37 ++++++++++++++++++++----------------- + 1 file changed, 20 insertions(+), 17 deletions(-) + +--- a/glue_netfs.c ++++ b/glue_netfs.c +@@ -72,7 +72,7 @@ convert_mac2hex(UINT8 *hw_addr,INTN l, C + for (i=0 ; i < l; i++) { + str[3*i] = hexa[(hw_addr[i] & 0xf0)>>4]; + str[3*i+1] = hexa[hw_addr[i] & 0x0f]; +- str[3*i+2] = ':'; ++ str[3*i+2] = '-'; + } + str[3*l-1]='\0'; + } +@@ -213,32 +213,35 @@ netfs_setdefaults(VOID *intf, config_fil + * will try machine/subnet specific files first. + * the filenames are constructed based on the IP(v4) address + */ +- convert_ip2hex(ipaddr, m, str); + #if 1 + i = 0; ++ if (non_zero(info.hw_addr, 6)) { ++ convert_mac2hex(info.hw_addr,6,str); ++ /* Blindly prepend ARP type code for Ethernet (0x01) ++ * (at least for now...) ++ */ ++ StrnCpy(config[i].fname, L"01-", 3); ++ StrnCat(config[i].fname, str, maxlen-10); ++ StrnCat(config[i++].fname, CONFIG_EXTENSION, maxlen-1); ++ } + if (non_zero(ipaddr, m)) { +- int nr = (m==16)? 10 : 6; +- int st = (m==16)? 2 : 1; +- m <<= 1; +- StrnCpy(config[i].fname, str, m); +- StrnCat(config[i++].fname, +- CONFIG_EXTENSION, maxlen - m); +- while (i <= nr) { +- int stub = m - (i+1)*st; ++ int step = (m==16)? 4 : 2; ++ int stub = m<<1; ++ convert_ip2hex(ipaddr, stub, str); ++ StrnCpy(config[i].fname, str, stub); ++ StrnCat(config[i++].fname, CONFIG_EXTENSION, maxlen-1); ++ while ( i+3 < MAX_DEFAULT_CONFIGS && stub > step) { ++ stub -= step; + StrnCpy(config[i].fname, str, stub); + StrnCat(config[i++].fname, +- CONFIG_ARCH_EXTENSION, maxlen - m); ++ CONFIG_ARCH_EXTENSION, maxlen-1); + StrnCpy(config[i].fname, str, stub); + StrnCat(config[i++].fname, +- CONFIG_EXTENSION, maxlen - m); ++ CONFIG_EXTENSION, maxlen-1); + } + } +- if (non_zero(info.hw_addr, 6)) { +- convert_mac2hex(info.hw_addr,6,str); +- StrnCpy(config[i].fname, str, maxlen-1); +- StrnCpy(config[i++].fname+17, CONFIG_EXTENSION, 6); +- } + #else ++ convert_ip2hex(ipaddr, m, str); + StrnCpy(config[0].fname, str, maxlen-1); + StrnCpy(config[0].fname+8, CONFIG_EXTENSION, 6); + diff --git a/elilo-max-conf.diff b/elilo-max-conf.diff new file mode 100644 index 0000000..07bb4b9 --- /dev/null +++ b/elilo-max-conf.diff @@ -0,0 +1,33 @@ +--- + fileops.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +--- a/fileops.c ++++ b/fileops.c +@@ -396,12 +396,13 @@ fops_setdefaults(struct config_file *def + boot_dev->fops->setdefaults(boot_dev->fops->intf, defconf, kname, maxlen, devpath); + } + i=0; while (i= MAX_DEFAULT_CONFIGS) { + #ifdef ELILO_DEBUG +- if ((i+3) >= MAX_DEFAULT_CONFIGS) { +- Print(L"ERROR: i = %d, MAX_DEFAULT_CONFIGS is not large enough\n", i); +- return EFI_INVALID_PARAMETER; +- } ++ Print(L"Warning: MAX_DEFAULT_CONFIGS(%d) is not large enough\n", ++ MAX_DEFAULT_CONFIGS); + #endif ++ i = MAX_DEFAULT_CONFIGS-2; ++ } + StrnCpy(defconf[i].fname, FILEOPS_ARCH_DEFAULT_CONFIG, maxlen-1); + StrnCpy(defconf[i+1].fname, FILEOPS_DEFAULT_CONFIG, maxlen-1); + +@@ -409,7 +410,7 @@ fops_setdefaults(struct config_file *def + VERB_PRT(3,Print(L"Default config filename list:\n")); + for (i=0; ioption) -+ - static x86_64_global_config_t x86_64_gconf; - - static config_option_t sysdeps_global_options[]={ - {OPT_BOOL, OPT_GLOBAL, L"legacy-free", NULL, NULL, &x86_64_gconf.legacy_free_boot} - }; - -+static config_option_t sysdeps_image_options[]={ -+ {OPT_BOOL, OPT_IMAGE_SYS, L"text-mode", NULL, NULL, x86_64_opt_offsetof(text_mode)} -+}; -+ -+ - /* - * X86_64 operations that need to be done only once and just before - * entering the main loop of the loader -@@ -81,6 +89,14 @@ x86_64_use_legacy_free_boot(VOID) - return x86_64_gconf.legacy_free_boot ? 1 : 0; - } - -+ -+INTN -+x86_64_text_mode(VOID) -+{ -+ return (elilo_opt.sys_img_opts && -+ elilo_opt.sys_img_opts->text_mode == TRUE) ? 1 : 0; -+} -+ - INTN - sysdeps_register_options(VOID) - { -@@ -89,14 +105,11 @@ sysdeps_register_options(VOID) - ret = register_config_options(sysdeps_global_options, - sizeof(sysdeps_global_options)/sizeof(config_option_t), - OPTIONS_GROUP_GLOBAL); --#if 0 -- /* no per image options yet */ - if (ret == -1 ) return ret; - - ret = register_config_options(sysdeps_image_options, - sizeof(sysdeps_image_options)/sizeof(config_option_t), - OPTIONS_GROUP_IMAGE); --#endif - - return ret; - } ---- a/x86_64/sysdeps.h -+++ b/x86_64/sysdeps.h -@@ -364,6 +364,7 @@ extern UINT8 rmswitch_image[]; - extern UINTN rmswitch_size; - - extern INTN x86_64_use_legacy_free_boot(); -+extern INTN x86_64_text_mode(); - - /* - * How to jump to kernel code -@@ -457,7 +458,8 @@ start_kernel(VOID *kentry, boot_params_t - } - - typedef struct sys_img_options { -- UINT8 nothing_yet; -+ UINT8 dummy; /* forces non-zero offset for first field */ -+ UINT8 text_mode; /* do not try to initialize Graphics Output Protocol */ - } sys_img_options_t; - - #endif /* __ELILO_SYSDEPS_X86_64_H__ */ --- a/x86_64/system.c +++ b/x86_64/system.c -@@ -251,6 +251,10 @@ static INTN get_video_info(boot_params_t - UINTN size1; - UINT8 i; - -+ if (x86_64_text_mode() == 1) { -+ Print((L"Skip GOP init, force text-mode.\n")); -+ return -1; -+ } - efi_status = uefi_call_wrapper( - BS->LocateHandle, - 5, +@@ -266,18 +266,18 @@ static INTN get_video_info(boot_params_t + + if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) { + Print(L"LocateHandle GopProtocol failed.\n"); +- Print(L"--Either no graphics head is installed,\n" \ +- "--efi console is set to serial, or,\n" \ +- "--the EFI firmware version of this machine is\n" \ +- "--older than UEFI 2.0. and does not support GOP"); +- Print(L"you can SAFELY IGNORE this error. elilo will\n" \ +- "default to text-mode.\n Alternatively you can " \ +- "now force text mode by setting config variable\n" \ +- "text_mode=1 for x86 in elilo.conf or via cmdline.\n\n"); +- Print(L"However if this is the last text output you see\n" \ +- "ensure that your kernel console command line\n " \ +- "variable matches up with the actual efi boot menu\n" \ +- "console output settings.\n\n"); ++ Print(L"--Either no graphics head is installed,\n" ++ "--EFI console is set to serial, or,\n" ++ "--the EFI firmware version of this machine is\n" ++ " older than UEFI 2.0. and does not support GOP.\n\n"); ++ Print(L"You can SAFELY IGNORE this error. ELILO will " ++ "default to 'text-mode',\n" ++ "which may be enforced by setting that config variable\n" ++ "in elilo.conf or via cmdline.\n\n"); ++ Print(L"However, if this is the last text output you see, " ++ "ensure that your\nkernel console command line" ++ "parameter matches up with the actual\n" ++ "EFI boot manager console output settings.\n\n"); + return -1; + } + Gop_handle = alloc(size, 0); diff --git a/elilo-x86-64-bootproto-update.diff b/elilo-x86-64-bootproto-update.diff deleted file mode 100644 index 6725251..0000000 --- a/elilo-x86-64-bootproto-update.diff +++ /dev/null @@ -1,186 +0,0 @@ ---- - x86_64/sysdeps.h | 34 +++++++++++++--------------------- - x86_64/system.c | 34 +++++++--------------------------- - 2 files changed, 20 insertions(+), 48 deletions(-) - ---- a/x86_64/sysdeps.h -+++ b/x86_64/sysdeps.h -@@ -107,12 +107,12 @@ typedef union x86_64_boot_params { - /* 0x06 */ UINT8 orig_video_mode; /* LDR */ - /* 0x07 */ UINT8 orig_video_cols; /* LDR */ - --/* 0x08 */ UINT16 unused_1; /* unused */ -+/* 0x08 */ UINT16 pad_1; /* unused */ - - /* %%TBD */ - /* 0x0A */ UINT16 orig_ega_bx; /* LDR */ - --/* 0x0C */ UINT16 unused_2; /* unused */ -+/* 0x0C */ UINT16 pad_2; /* unused */ - - /* Screen height before passing control to kernel. */ - /* 0x0E */ UINT8 orig_video_rows; /* LDR */ -@@ -174,7 +174,7 @@ typedef union x86_64_boot_params { - /* 0x4E */ UINT32 bios_code_len; /* LDR */ - /* 0x52 */ UINT16 bios_data_len; /* LDR */ - --/* 0x54 */ UINT8 unused_3[0x2C]; /* unused */ -+/* 0x54 */ UINT8 pad_3[0x2C]; /* unused */ - - /* %%TBD */ - /* 0x80 */ UINT8 hd0_info[0x10]; /* LDR */ -@@ -184,7 +184,7 @@ typedef union x86_64_boot_params { - /* 0xA0 */ UINT16 mca_info_len; /* LDR */ - /* 0xA2 */ UINT8 mca_info_buf[0x10]; /* LDR */ - --/* 0xB2 */ UINT8 unused_4[0x10E]; /* unused */ -+/* 0xB2 */ UINT8 pad_4[0x10E]; /* unused */ - - /* EFI boot loader signature. */ - /* 0x1C0 */ UINT8 efi_loader_sig[4]; /* LDR */ -@@ -209,9 +209,9 @@ typedef union x86_64_boot_params { - /* Available contiguous extended memory in KB. */ - /* 0x1E0 */ UINT32 alt_mem_k; /* LDR */ - --/* 0x1E4 */ UINT32 unused_51; /* unused */ -+/* 0x1E4 */ UINT32 pad_51; /* unused */ - /* 0x1E8 */ UINT8 e820_nrmap; --/* 0x1E9 */ UINT32 unused_52[2]; /* unused */ -+/* 0x1E9 */ UINT32 pad_52[2]; /* unused */ - - /* Size of setup code in sectors (1 sector == 512 bytes). */ - /* 0x1F1 */ UINT8 setup_sectors; /* BLD */ -@@ -220,15 +220,10 @@ typedef union x86_64_boot_params { - /* 0x1F2 */ UINT16 mount_root_rdonly; /* BLD */ - - /* %%TBD */ --/* 0x1F4 */ UINT16 sys_size; /* BLD */ -+/* 0x1F4 */ UINT32 sys_size; /* BLD */ - - /* %%TBD */ --/* 0x1F6 */ UINT16 swap_dev; /* BLD */ -- --/* %%TBD */ --/* 0x1F8 */ UINT16 ramdisk_flags; /* BLD */ --#define RAMDISK_PROMPT 0x8000 --#define RAMDISK_LOAD 0x4000 -+/* 0x1F8 */ UINT16 ram_size_DNU; /* BLD */ - - /* %%TBD */ - /* 0x1FA */ UINT16 video_mode_flag; /* BLD */ -@@ -236,12 +231,8 @@ typedef union x86_64_boot_params { - /* %%TBD */ - /* 0x1FC */ UINT16 orig_root_dev; /* BLD */ - --/* 0x1FE */ UINT8 unused_6; /* unused */ -- - /* %%TBD */ --/* 0x1FF */ UINT8 aux_dev_info; /* LDR */ --#define NO_MOUSE 0x00 --#define FOUND_MOUSE 0xAA -+/* 0x1FE */ UINT16 boot_flag; /* ? */ - - /* Jump past setup data (not used in EFI). */ - /* 0x200 */ UINT16 jump; /* BLD */ -@@ -283,16 +274,17 @@ typedef union x86_64_boot_params { - /* 0x21C */ UINT32 initrd_size; /* LDR */ - - /* %%TBD */ --/* 0x220 */ UINT32 bootsect_helper; /* BLD */ -+/* 0x220 */ UINT32 bootsect_helper_DNU; /* BLD */ - - /* %%TBD */ - /* 0x224 */ UINT16 heap_end_ptr; /* LDR */ - - /* %%TBD */ --/* 0x226 */ UINT16 unused_7; /* LDR */ -+/* 0x226 */ UINT8 ext_loader_ver; /* LDR */ -+/* 0x227 */ UINT8 ext_loader_type; /* LDR */ - - /* 0x228 */ UINT32 cmdline_addr; /* LDR */ --/* 0x22C */ UINT32 unused_8[41]; -+/* 0x22C */ UINT32 pad_8[41]; - /* 0x2D0 */ UINT8 e820_map[2560]; - } s; - } boot_params_t; ---- a/x86_64/system.c -+++ b/x86_64/system.c -@@ -493,17 +493,9 @@ sysdeps_create_boot_params( - hdr_version = (bp->s.hdr_major << 8) | bp->s.hdr_minor; - - /* -- * Clear out unused memory in boot sector image. -+ * Do NOT clear out unknown memory in boot sector image. -+ * This breaks boot protocol >= 2.10 (2.6.31). - */ -- bp->s.unused_1 = 0; -- bp->s.unused_2 = 0; -- ZeroMem(&bp->s.unused_3, sizeof bp->s.unused_3); -- ZeroMem(&bp->s.unused_4, sizeof bp->s.unused_4); -- ZeroMem(&bp->s.unused_51, sizeof bp->s.unused_51); -- ZeroMem(&bp->s.unused_52, sizeof bp->s.unused_52); -- bp->s.unused_6 = 0; -- bp->s.unused_7 = 0; -- ZeroMem(bp->s.unused_8, sizeof bp->s.unused_8); - - /* - * Tell kernel this was loaded by an advanced loader type. -@@ -553,19 +545,14 @@ sysdeps_create_boot_params( - DBG_PRT((L"initrd->start_addr="PTR_FMT" initrd->pgcnt=%d\n", - initrd->start_addr, initrd->pgcnt)); - -- /* These RAMdisk flags are not needed, just zero them. */ -- bp->s.ramdisk_flags = 0; -+ /* These RAMdisk flags are not needed, just zero them. NOT!*/ -+ /* 'ramdisk_flags' (@0x1F8) is called 'ram_size' in the meantime, */ -+ /* see Documentation/x86/boot.txt. */ - - if (initrd->start_addr && initrd->pgcnt) { - /* %%TBD - This will probably have to be changed. */ - bp->s.initrd_start = (UINT32)(UINT64)initrd->start_addr; - bp->s.initrd_size = (UINT32)(initrd->size); -- /* -- * This is the RAMdisk root device for RedHat 2.2.x -- * kernels (major 0x01, minor 0x00). -- */ -- -- bp->s.orig_root_dev = 0x0100; - } else { - bp->s.initrd_start = 0; - bp->s.initrd_size = 0; -@@ -590,11 +577,6 @@ sysdeps_create_boot_params( - ZeroMem(bp->s.mca_info_buf, sizeof bp->s.mca_info_buf); - - /* -- * Pointing device presence. The kernel will detect this. -- */ -- bp->s.aux_dev_info = NO_MOUSE; -- -- /* - * EFI loader signature - */ - CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG_X64, 4); -@@ -692,11 +674,9 @@ sysdeps_create_boot_params( - CHECK_OFFSET(setup_sectors, 0x1F1, L"%xh"); - CHECK_OFFSET(mount_root_rdonly, 0x1F2, L"%xh"); - CHECK_OFFSET(sys_size, 0x1F4, L"%xh"); -- CHECK_OFFSET(swap_dev, 0x1F6, L"%xh"); -- CHECK_OFFSET(ramdisk_flags, 0x1F8, L"%xh"); - CHECK_OFFSET(video_mode_flag, 0x1FA, L"%xh"); - CHECK_OFFSET(orig_root_dev, 0x1FC, L"%xh"); -- CHECK_OFFSET(aux_dev_info, 0x1FF, L"%xh"); -+ CHECK_OFFSET(boot_flag, 0x1FE, L"%xh"); - CHECK_OFFSET(jump, 0x200, L"%xh"); - CHECK_OFFSET(setup_sig, 0x202, L"'%-4.4a'"); - CHECK_OFFSET(hdr_minor, 0x206, L"%xh"); -@@ -710,9 +690,9 @@ sysdeps_create_boot_params( - CHECK_OFFSET(kernel_start, 0x214, L"%xh"); - CHECK_OFFSET(initrd_start, 0x218, L"%xh"); - CHECK_OFFSET(initrd_size, 0x21C, L"%xh"); -- CHECK_OFFSET(bootsect_helper, 0x220, L"%xh"); - CHECK_OFFSET(heap_end_ptr, 0x224, L"%xh"); - CHECK_OFFSET(cmdline_addr, 0x228, L"%xh"); -+ CHECK_OFFSET(e820_map, 0x2D0, L"%xh"); - - if (test) { - ERR_PRT((L"Boot sector and/or setup parameter alignment error.")); diff --git a/elilo-x86-64-e820-max.diff b/elilo-x86-64-e820-max.diff deleted file mode 100644 index f5b6b48..0000000 --- a/elilo-x86-64-e820-max.diff +++ /dev/null @@ -1,230 +0,0 @@ ---- - bootparams.c | 2 - x86_64/system.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- - 2 files changed, 134 insertions(+), 7 deletions(-) - ---- a/bootparams.c -+++ b/bootparams.c -@@ -96,6 +96,8 @@ create_boot_params(CHAR16 *args, memdesc - */ - Memset(bp, 0, BOOT_PARAM_MEMSIZE); - -+ U2ascii(args, cp, cmdline_size); -+ - if (sysdeps_create_boot_params(bp, cp, initrd, vmcode, cookie) == -1) return 0; - - /* ---- a/x86_64/system.c -+++ b/x86_64/system.c -@@ -38,11 +38,19 @@ - */ - #include - #include -+#include - - #include "elilo.h" - #include "loader.h" - #include "rmswitch.h" - -+#define DEBUG_CREATE_BOOT_PARAMS 0 -+#if DEBUG_CREATE_BOOT_PARAMS -+#define DPR(a) do { if (elilo_opt.debug) { Print a; } } while ( 0 ) -+#else -+#define DPR(a) -+#endif -+ - extern loader_ops_t bzimage_loader, plain_loader, gzip_loader; - - /* -@@ -113,6 +121,8 @@ VOID *kernel_load_address = (VOID *)DEFA - VOID *initrd_start = NULL; - UINTN initrd_size = 0; - -+INTN e820_map_overflow = 0; -+ - INTN - sysdeps_init(EFI_HANDLE dev) - { -@@ -368,10 +378,56 @@ static INTN get_video_info(boot_params_t - return 0; - } - -+CHAR16 * -+StrStr(IN const CHAR16 *h, IN const CHAR16 *n) -+{ -+ const CHAR16 *t = h; -+ CHAR16 *res; -+ int len = 0, i; -+ -+ len = StrLen((CHAR16 *)n); -+ while(*t != CHAR_NULL) { -+ res = StrChr( t, n[0]); -+ if (!res) return res; -+ for( i = 1; i < len && res[i] != CHAR_NULL && res[i] == n[i]; i++); -+ if ( i == len ) return res; -+ t = res + 1; -+ if (t > h + CMDLINE_MAXLEN) return (CHAR16 *)0; -+ } -+ -+ return (CHAR16 *)0; -+} -+ -+CHAR8 * -+StrStr8(IN const CHAR8 *h, IN const CHAR8 *n) -+{ -+ const CHAR8 *t = h; -+ CHAR8 *res; -+ int len = 0, i; -+ -+ len = strlena((CHAR8 *)n); -+ while(*t != 0) { -+ res = strchra( t, n[0]); -+ if (!res) return res; -+ for( i = 1; i < len && res[i] != 0 && res[i] == n[i]; i++); -+ if ( i == len ) return res; -+ t = res + 1; -+ if (t > (h + CMDLINE_MAXLEN)) return (CHAR8 *)0; -+ } -+ -+ return (CHAR8 *)0; -+} -+ - /* Convert EFI memory map to E820 map for the operating system - * This code is based on a Linux kernel patch submitted by Edgar Hucek - */ - -+#if DEBUG_CREATE_BOOT_PARAMS -+static int e820_max = 6; -+#else -+static int e820_max = E820_MAX; -+#endif -+ - /* Add a memory region to the e820 map */ - static void add_memory_region (struct e820entry *e820_map, - int *e820_nr_map, -@@ -380,21 +436,56 @@ static void add_memory_region (struct e8 - unsigned int type) - { - int x = *e820_nr_map; -+ static unsigned long long estart = 0ULL; -+ static unsigned long esize = 0L; -+ static unsigned int etype = -1; -+ static int merge = 0; -+ -+ if (x == 0) -+ DPR((L"AMR: %3s %4s %16s/%12s/%s\n", -+ L"idx", L" ", L"start", L"size", L"type")); - -- if (x == E820_MAX) { -- Print(L"Too many entries in the memory map!\n"); -- return; -- } -- -+ /* merge adjacent regions of same type */ - if ((x > 0) && e820_map[x-1].addr + e820_map[x-1].size == start -- && e820_map[x-1].type == type) -+ && e820_map[x-1].type == type) { - e820_map[x-1].size += size; -- else { -+ estart = e820_map[x-1].addr; -+ esize = e820_map[x-1].size; -+ etype = e820_map[x-1].type; -+ merge++; -+ return; -+ } -+ /* fill up to E820_MAX */ -+ if ( x < e820_max ) { - e820_map[x].addr = start; - e820_map[x].size = size; - e820_map[x].type = type; - (*e820_nr_map)++; -+ if (merge) DPR((L"AMR: %3d ==> %016llx/%012lx/%d (%d)\n", -+ x-1, estart, esize, etype, merge)); -+ merge=0; -+ DPR((L"AMR: %3d add %016llx/%012lx/%d\n", -+ x, start, size, type)); -+ return; -+ } -+ /* different type means another region didn't fit */ -+ /* or same type, but there's a hole */ -+ if (etype != type || (estart + esize) != start) { -+ if (merge) DPR((L"AMR: %3d ===> %016llx/%012lx/%d (%d)\n", -+ e820_map_overflow, estart, esize, etype, merge)); -+ merge = 0; -+ estart = start; -+ esize = size; -+ etype = type; -+ e820_map_overflow++; -+ DPR((L"AMR: %3d OVER %016llx/%012lx/%d\n", -+ e820_map_overflow, start, size, type)); -+ return; - } -+ /* same type and no hole, merge it */ -+ estart += esize; -+ esize += size; -+ merge++; - } - - void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc) -@@ -473,6 +564,7 @@ void fill_e820map(boot_params_t *bp, mma - break; - default: - /* We should not hit this case */ -+ DBG_PRT((L"hit default!?")); - add_memory_region(e820_map, &e820_nr_map, - md->PhysicalStart, - md->NumberOfPages << EFI_PAGE_SHIFT, -@@ -486,6 +578,8 @@ void fill_e820map(boot_params_t *bp, mma - - /* - * x86_64 specific boot parameters initialization routine -+ * -+ * Note: debug and verbose messages have already been turned off! - */ - INTN - sysdeps_create_boot_params( -@@ -501,6 +595,12 @@ sysdeps_create_boot_params( - UINT8 row, col; - UINT8 mode; - UINT16 hdr_version; -+ UINT8 e820_map_overflow_warned = 0; -+ -+#if DEBUG_CREATE_BOOT_PARAMS -+ elilo_opt.debug=1; -+ elilo_opt.verbose=5; -+#endif - - DBG_PRT((L"fill_boot_params()\n")); - -@@ -834,6 +934,31 @@ do_memmap: - * and update the bootparam accordingly - */ - fill_e820map(bp, &mdesc); -+ -+#if DEBUG_CREATE_BOOT_PARAMS -+ if ( e820_map_overflow == 0 ) -+ e820_map_overflow = -1; /* force second get_memmap()! */ -+#endif -+ if (e820_map_overflow && !e820_map_overflow_warned) { -+ CHAR8 *aem = (CHAR8 *)"add_efi_memmap"; -+ e820_map_overflow_warned++; -+ -+#if DEBUG_CREATE_BOOT_PARAMS -+ elilo_opt.debug=0; -+ elilo_opt.verbose=0; -+#endif -+ if (e820_map_overflow == -1 || StrStr8(cmdline, aem)) { -+ /* Print(L"...mapping again, silently!\n"); */ -+ goto do_memmap; -+ } -+ -+ Print(L"\nCAUTION: EFI memory map has %d more entr%a" -+ " than E820 map supports.\n" -+ "To access all memory, '%a' may be necessary.\n\n", -+ e820_map_overflow, (e820_map_overflow==1)?"y":"ies", -+ aem); -+ goto do_memmap; -+ } - - return 0; - } diff --git a/elilo-x86-64-initrd.diff b/elilo-x86-64-initrd.diff deleted file mode 100644 index ae2ee79..0000000 --- a/elilo-x86-64-initrd.diff +++ /dev/null @@ -1,228 +0,0 @@ ---- - elilo.h | 5 ++++ - ia32/system.c | 6 +++++ - ia64/system.c | 6 +++++ - initrd.c | 12 +++++++++- - x86_64/sysdeps.h | 20 ++++++------------ - x86_64/system.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++------- - 6 files changed, 88 insertions(+), 22 deletions(-) - ---- a/elilo.h -+++ b/elilo.h -@@ -54,6 +54,10 @@ - #define ROUNDUP(x,a) (((x) + (a) - 1) & ~((a) - 1)) - #define ROUNDDOWN(x,a) ((x) & ~((a) - 1)) - -+#ifndef UINT32_MAX -+#define UINT32_MAX ((UINT32)-1) -+#endif -+ - /* - * Elilo Boot modes - */ -@@ -212,6 +216,7 @@ extern CHAR16 *sysdeps_get_cmdline_opts( - extern INTN sysdeps_getopt(INTN, INTN, CHAR16 *); - extern VOID sysdeps_print_cmdline_opts(VOID); - extern INTN sysdeps_register_options(VOID); -+extern VOID *sysdeps_checkfix_initrd(VOID *, memdesc_t *); - - #define CHAR_SLASH L'/' - #define CHAR_BACKSLASH L'\\' ---- a/ia32/system.c -+++ b/ia32/system.c -@@ -149,6 +149,12 @@ sysdeps_initrd_get_addr(kdesc_t *kd, mem - return 0; - } - -+VOID * -+sysdeps_checkfix_initrd(VOID *start_addr, memdesc_t *imem) -+{ -+ return start_addr; -+} -+ - VOID - sysdeps_free_boot_params(boot_params_t *bp) - { ---- a/ia64/system.c -+++ b/ia64/system.c -@@ -140,6 +140,12 @@ sysdeps_initrd_get_addr(kdesc_t *kd, mem - return 0; - } - -+VOID * -+sysdeps_checkfix_initrd(VOID *start_addr, memdesc_t *imem) -+{ -+ return start_addr; -+} -+ - /* Flush data cache [addr; addr + len], and sync with icache. */ - void - flush_dcache (CHAR8 *addr, UINT64 len) ---- a/initrd.c -+++ b/initrd.c -@@ -41,7 +41,11 @@ INTN - load_file(CHAR16 *filename, memdesc_t *image) - { - EFI_STATUS status; -- VOID *start_addr = NULL; -+ /* -+ * Actually using the value from sysdeps_initrd_get_addr() -+ * instead of NULL is no change for ia64! -+ */ -+ VOID *start_addr = image->start_addr; - UINTN pgcnt; - UINT64 size = 0; - fops_fd_t fd; -@@ -71,7 +75,11 @@ load_file(CHAR16 *filename, memdesc_t *i - /* round up to get required number of pages (4KB) */ - image->pgcnt = pgcnt = EFI_SIZE_TO_PAGES(image->size); - -- start_addr = alloc_pages(pgcnt, EfiLoaderData, start_addr ? AllocateAddress : AllocateAnyPages, 0 ); -+ start_addr = alloc_pages(pgcnt, EfiLoaderData, -+ start_addr ? AllocateAddress : AllocateAnyPages, start_addr); -+ -+ start_addr = sysdeps_checkfix_initrd(start_addr, image); -+ - if (start_addr == NULL) { - ERR_PRT((L"Failed to allocate %d pages for %s image", pgcnt, - filename)); ---- a/x86_64/sysdeps.h -+++ b/x86_64/sysdeps.h -@@ -284,7 +284,8 @@ typedef union x86_64_boot_params { - /* 0x227 */ UINT8 ext_loader_type; /* LDR */ - - /* 0x228 */ UINT32 cmdline_addr; /* LDR */ --/* 0x22C */ UINT32 pad_8[41]; -+/* 0x22C */ UINT32 initrd_addr_max; /* BLD */ -+/* 0x230 */ UINT32 pad_8[40]; - /* 0x2D0 */ UINT8 e820_map[2560]; - } s; - } boot_params_t; -@@ -374,7 +375,6 @@ start_kernel(VOID *kentry, boot_params_t - UINT16 kernel_cs; - } jumpvector; - VOID *jump_start; -- uint64_t temp; - - /* - * Disable interrupts. -@@ -382,22 +382,16 @@ start_kernel(VOID *kentry, boot_params_t - asm volatile ( "cli" : : ); - - /* -- * Relocate kernel (if needed), and initrd (if present). -- * Copy kernel first, in case kernel was loaded overlapping where we're -- * planning to copy the initrd. This assumes that the initrd didn't -- * get loaded overlapping where we're planning to copy the kernel, but -- * that's pretty unlikely since we couldn't alloc that space for the -- * kernel (or the kernel would already be there). -+ * Relocate kernel (if needed). -+ * This assumes that the initrd didn't get loaded overlapping where -+ * we're planning to copy the kernel, but that's pretty unlikely -+ * since we couldn't alloc that space for the kernel (or the kernel -+ * would already be there). - */ - if (kernel_start != kernel_load_address) { - MEMCPY(kernel_start, kernel_load_address, kernel_size); - } - -- if (bp->s.initrd_start) { -- temp = bp->s.initrd_start; -- MEMCPY(INITRD_START, temp , bp->s.initrd_size); -- bp->s.initrd_start = INITRD_START; -- } - /* - * Copy boot sector, setup data and command line - * to final resting place. We need to copy ---- a/x86_64/system.c -+++ b/x86_64/system.c -@@ -131,10 +131,8 @@ sysdeps_init(EFI_HANDLE dev) - /* - * initrd_get_addr() - * Compute a starting address for the initial RAMdisk image. -- * For now, this image is placed immediately after the end of -- * the kernel memory. Inside the start_kernel() code, the -- * RAMdisk image will be relocated to the top of available -- * extended memory. -+ * For now we suggest 'initrd_addr_max' with room for 32MB, -+ * as image->pgcnt is not initialized yet. - */ - INTN - sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem) -@@ -146,10 +144,12 @@ sysdeps_initrd_get_addr(kdesc_t *kd, mem - return -1; - } - -- VERB_PRT(3, Print(L"kstart="PTR_FMT" kentry="PTR_FMT" kend="PTR_FMT"\n", -- kd->kstart, kd->kentry, kd->kend)); -+ VERB_PRT(3, Print(L"initrd_addr_max="PTR_FMT" reserve=%d\n", -+ param_start->s.initrd_addr_max, 32*MB)); - -- imem->start_addr = kd->kend; -+ imem->start_addr = (VOID *) -+ (((UINT64)param_start->s.initrd_addr_max - 32*MB + 1) -+ & ~EFI_PAGE_MASK); - - VERB_PRT(3, Print(L"initrd start_addr="PTR_FMT" pgcnt=%d\n", - imem->start_addr, imem->pgcnt)); -@@ -157,6 +157,48 @@ sysdeps_initrd_get_addr(kdesc_t *kd, mem - return 0; - } - -+ -+/* -+ * checkfix_initrd() -+ * Check and possibly fix allocation of initrd memory. -+ */ -+VOID * -+sysdeps_checkfix_initrd(VOID *start_addr, memdesc_t *imem) -+{ -+ UINTN pgcnt = EFI_SIZE_TO_PAGES(imem->size); -+ UINT64 initrd_addr_max = (UINT64)param_start->s.initrd_addr_max; -+ UINT64 ki_max = initrd_addr_max - imem->size + 1; -+ VOID *ki_max_addr; -+ -+ VERB_PRT( 3, Print(L"loadfile: start_addr="PTR_FMT -+ " ki_max_addr="PTR_FMT"\n", start_addr, (VOID *)ki_max)); -+ if (ki_max > UINT32_MAX) { -+ ERR_PRT((L"Force kernel specified initrd_addr_max="PTR_FMT -+ " below 4GB\n", (VOID *)initrd_addr_max)); -+ ki_max = UINT32_MAX - imem->size + 1; -+ } -+ ki_max_addr = (VOID *)ki_max; -+ -+ if ((UINT64)start_addr > ki_max) { -+ VERB_PRT(1, Print(L"initrd start_addr="PTR_FMT" above " -+ "limit="PTR_FMT"\n", start_addr, ki_max_addr)); -+ free(start_addr); -+ start_addr = NULL; -+ } -+ /* so either the initial allocation failed or it's been to high! */ -+ if (start_addr == NULL) { -+ start_addr = alloc_pages(pgcnt, EfiLoaderData, -+ AllocateMaxAddress, ki_max_addr); -+ } -+ if ((UINT64)start_addr > ki_max) { -+ ERR_PRT((L"Failed to allocate %d pages below %dMB", -+ pgcnt, (param_start->s.initrd_addr_max+1)>>20)); -+ free(start_addr); -+ start_addr = NULL; -+ } -+ return start_addr; -+} -+ - VOID - sysdeps_free_boot_params(boot_params_t *bp) - { -@@ -550,6 +592,11 @@ sysdeps_create_boot_params( - /* see Documentation/x86/boot.txt. */ - - if (initrd->start_addr && initrd->pgcnt) { -+ if ( (UINT64)initrd->start_addr > UINT32_MAX ) { -+ ERR_PRT((L"Start of initrd out of reach (>4GB).")); -+ free_kmem(); -+ return -1; -+ } - /* %%TBD - This will probably have to be changed. */ - bp->s.initrd_start = (UINT32)(UINT64)initrd->start_addr; - bp->s.initrd_size = (UINT32)(initrd->size); diff --git a/elilo-x86-64-kernel.diff b/elilo-x86-64-kernel.diff deleted file mode 100644 index ecb1895..0000000 --- a/elilo-x86-64-kernel.diff +++ /dev/null @@ -1,257 +0,0 @@ ---- - alloc.c | 10 +++ - ia32/bzimage.c | 2 - x86_64/bzimage.c | 160 +++++++++++++++++++++++++++++++++++++++++++++---------- - x86_64/sysdeps.h | 5 + - x86_64/system.c | 9 ++- - 5 files changed, 152 insertions(+), 34 deletions(-) - ---- a/alloc.c -+++ b/alloc.c -@@ -217,7 +217,15 @@ INTN - alloc_kmem_anywhere(VOID **start_addr, UINTN pgcnt) - { - void * tmp; -- if ((tmp = alloc_pages(pgcnt, EfiLoaderData, AllocateAnyPages, *start_addr)) == 0) return -1; -+ /* -+ * During "AllocateAnyPages" *start_addr will be ignored. -+ * Therefore we can safely subvert it to reuse this function with -+ * an alloc_kmem_anyhwere_below() semantic... -+ */ -+ tmp = alloc_pages(pgcnt, EfiLoaderData, -+ (*start_addr) ? AllocateMaxAddress : AllocateAnyPages, -+ *start_addr); -+ if (tmp == NULL) return -1; - - kmem_addr = tmp; - kmem_pgcnt = pgcnt; ---- a/ia32/bzimage.c -+++ b/ia32/bzimage.c -@@ -169,7 +169,7 @@ bzImage_probe(CHAR16 *kname) - kernel_start)); - } - -- kernel_load_address = kernel_start; -+ kernel_load_address = NULL; /* allocate anywhere! */ - - if (alloc_kmem(kernel_start, EFI_SIZE_TO_PAGES(kernel_size)) != 0) { - /* ---- a/x86_64/bzimage.c -+++ b/x86_64/bzimage.c -@@ -36,6 +36,129 @@ UINTN param_size = 0; - - UINTN kernel_size = 0x800000; /* 8M (default x86_64 bzImage size limit) */ - -+static VOID * -+bzImage_alloc() -+{ -+ UINTN pages = EFI_SIZE_TO_PAGES(kernel_size); -+ int reloc_kernel = 0; -+ VOID *kla, *kend = kernel_start + kernel_size; -+ UINT32 kalign, kmask; -+ boot_params_t *ps = param_start; -+ -+ /* -+ * Get address for kernel from header, if applicable & available. -+ */ -+ if ((ps->s.hdr_major < 2) || -+ (ps->s.hdr_major == 2 && ps->s.hdr_minor < 5)) { -+ reloc_kernel = 0; -+ } else { -+ if (ps->s.kernel_start >= DEFAULT_KERNEL_START) -+ kernel_start = (void *)(UINT64)ps->s.kernel_start; -+ reloc_kernel = ps->s.relocatable_kernel; -+ kalign = ps->s.kernel_alignment; -+ kmask = kalign - 1; -+ VERB_PRT(3, Print(L"kernel header (%d.%d) suggests kernel " -+ "start at address "PTR_FMT" (%srelocatable!)\n", -+ ps->s.hdr_major, ps->s.hdr_minor, ps->s.kernel_start, -+ (reloc_kernel ? L"": L"not "))); -+ } -+ -+ /* -+ * Best effort for old (< 2.6.20) and non-relocatable kernels -+ */ -+ if (alloc_kmem(kernel_start, pages) == 0) { -+ VERB_PRT(3, Print(L"kernel_start: "PTR_FMT" kernel_size: %d\n", -+ kernel_start, kernel_size)); -+ return kernel_start; -+ } else if ( ! reloc_kernel ) { -+ /* -+ * Couldn't get desired address--just load it anywhere and -+ * (try to) move it later. It's the only chance for non- -+ * relocatable kernels, but it breaks occassionally... -+ */ -+ ERR_PRT((L"Kernel header (%d.%d) suggests kernel " -+ "start at address "PTR_FMT" (non relocatable!)\n" -+ "This address is not available, so an attempt" -+ "is made to copy the kernel there later on\n" -+ "BEWARE: this is unsupported and may not work. " -+ "Please update your kernel.\n", -+ ps->s.hdr_major, ps->s.hdr_minor, ps->s.kernel_start)); -+ kla = (VOID *)(UINT32_MAX - kernel_size); -+ /* NULL would preserve the "anywhere" semantic, */ -+ /* but it would not prevent allocation above 4GB! */ -+ -+ if (alloc_kmem_anywhere(&kla, pages) != 0) { -+ /* out of luck */ -+ return NULL; -+ } -+ VERB_PRT(3, Print(L"kernel_start: "PTR_FMT -+ " kernel_size: %d loading at: "PTR_FMT"\n", -+ kernel_start, kernel_size, kla)); -+ return kla; -+ } -+ -+ -+ /* Is 'ps->s.kernel_alignment' guaranteed to be sane? */ -+ if (kalign < EFI_PAGE_SIZE) { -+ kalign = EFI_PAGE_SIZE; -+ kmask = EFI_PAGE_MASK; -+ } -+ DBG_PRT((L"alignment: kernel=0x%x efi_page=0x%x : 0x%x\n", -+ ps->s.kernel_alignment, EFI_PAGE_SIZE, kalign)); -+ -+ /* -+ * Couldn't get the preferred address, but luckily it's -+ * a relocatable kernel, so ... -+ * -+ * 1. use 'find_kernel_memory()' (like Itanium) -+ * 2. try out the 16 lowest possible aligned addresses (> 0) -+ * 3. get enough memory to align "creatively" -+ * 4. forget alignment (and start praying)... -+ */ -+ -+ /* 1. */ -+ if ((find_kernel_memory(kernel_start, kend, kalign, &kla) != 0) || -+ (alloc_kmem(kla, pages) != 0)) { -+ kla = NULL; -+ } -+ -+ /* 2. */ -+ if ( ! kla && (UINT64)kernel_start < kalign ) { -+ int i; -+ for ( i = 1; i < 16 && !kla; i++ ) { -+ VOID *tmp = (VOID *)((UINT64)kalign * i); -+ if (alloc_kmem(tmp, pages) == 0) { -+ kla = tmp; -+ } -+ } -+ } -+ -+ /* 3. */ -+ if ( ! kla ) { -+ UINTN apages = EFI_SIZE_TO_PAGES(kernel_size + kmask); -+ kla = (VOID *)(UINT32_MAX - kernel_size - kmask); -+ -+ if (alloc_kmem_anywhere(&kla, apages) == 0) { -+ kla = (VOID *)(((UINT64)kla + kmask) & ~kmask); -+ } else { -+ kla = NULL; -+ } -+ } -+ -+ /* 4. last resort */ -+ if ( ! kla ) { -+ kla = (VOID *)(UINT32_MAX - kernel_size); -+ if (alloc_kmem_anywhere(&kla, pages) != 0) { -+ return NULL; -+ } -+ } -+ -+ kernel_start = kla; -+ VERB_PRT(1, Print(L"relocating kernel_start: "PTR_FMT -+ " kernel_size: %d\n", kernel_start, kernel_size)); -+ return kla; -+} -+ - static INTN - bzImage_probe(CHAR16 *kname) - { -@@ -158,37 +281,16 @@ bzImage_probe(CHAR16 *kname) - * Allocate memory for kernel. - */ - -- /* -- * Get correct address for kernel from header, if applicable & available. -- */ -- if ((param_start->s.hdr_major == 2) && -- (param_start->s.hdr_minor >= 6) && -- (param_start->s.kernel_start >= DEFAULT_KERNEL_START)) { -- kernel_start = (void *)param_start->s.kernel_start; -- VERB_PRT(3, Print(L"kernel header suggests kernel start at address "PTR_FMT"\n", -- kernel_start)); -- } -- -- kernel_load_address = kernel_start; -- -- if (alloc_kmem(kernel_start, EFI_SIZE_TO_PAGES(kernel_size)) != 0) { -- /* -- * Couldn't get desired address--just load it anywhere and move it later. -- * (Easier than relocating kernel, and also works with non-relocatable kernels.) -- */ -- if (alloc_kmem_anywhere(&kernel_load_address, EFI_SIZE_TO_PAGES(kernel_size)) != 0) { -- ERR_PRT((L"Could not allocate memory for kernel.")); -- free(param_start); -- param_start = NULL; -- param_size = 0; -- fops_close(fd); -- return -1; -- } -+ kernel_load_address = bzImage_alloc(); -+ if ( ! kernel_load_address ) { -+ ERR_PRT((L"Could not allocate memory for kernel.")); -+ free(param_start); -+ param_start = NULL; -+ param_size = 0; -+ fops_close(fd); -+ return -1; - } - -- VERB_PRT(3, Print(L"kernel_start: "PTR_FMT" kernel_size: %d loading at: "PTR_FMT"\n", -- kernel_start, kernel_size, kernel_load_address)); -- - /* - * Now read the rest of the kernel image into memory. - */ ---- a/x86_64/sysdeps.h -+++ b/x86_64/sysdeps.h -@@ -285,7 +285,10 @@ typedef union x86_64_boot_params { - - /* 0x228 */ UINT32 cmdline_addr; /* LDR */ - /* 0x22C */ UINT32 initrd_addr_max; /* BLD */ --/* 0x230 */ UINT32 pad_8[40]; -+/* 0x230 */ UINT32 kernel_alignment; /* BLD */ -+/* 0x234 */ UINT8 relocatable_kernel; /* BLD */ -+/* 0x235 */ UINT8 pad_8[3]; -+/* 0x238 */ UINT32 pad_9[38]; - /* 0x2D0 */ UINT8 e820_map[2560]; - } s; - } boot_params_t; ---- a/x86_64/system.c -+++ b/x86_64/system.c -@@ -105,10 +105,10 @@ UINTN high_base_mem = 0x90000; - UINTN high_ext_mem = 32 * 1024 * 1024; - - /* This starting address will hold true for all of the loader types for now */ --VOID *kernel_start = (void *)DEFAULT_KERNEL_START; -+VOID *kernel_start = (VOID *)DEFAULT_KERNEL_START; - - /* The kernel may load elsewhere if EFI firmware reserves kernel_start */ --VOID *kernel_load_address = DEFAULT_KERNEL_START; -+VOID *kernel_load_address = (VOID *)DEFAULT_KERNEL_START; - - VOID *initrd_start = NULL; - UINTN initrd_size = 0; -@@ -631,6 +631,11 @@ sysdeps_create_boot_params( - /* - * Kernel entry point. - */ -+ if ( (UINT64)kernel_start != (UINT32)(UINT64)kernel_start ) { -+ ERR_PRT((L"Start of kernel (will be) out of reach (>4GB).")); -+ free_kmem(); -+ return -1; -+ } - bp->s.kernel_start = (UINT32)(UINT64)kernel_start; - - /* diff --git a/elilo.changes b/elilo.changes index f3f1513..ba5ab46 100644 --- a/elilo.changes +++ b/elilo.changes @@ -1,19 +1,218 @@ +------------------------------------------------------------------- +Thu Oct 24 17:18:48 UTC 2013 - rw@suse.de + +- elilo.spec + * Add perl modules to 'PreReq'. (bnc#842183) +- Update to elilo-3.14 from SLE11. + +------------------------------------------------------------------- +Fri Aug 16 12:01:42 UTC 2013 - rw@suse.de + +- elilo.pl + * SecureBoot: cope with separate '/boot' file-system. (bnc#825932) + * SecureBoot: improve detection of file-system UUIDs. (bnc#828835) + * Correctly handle installation to 'BOOT'. + +------------------------------------------------------------------- +Wed May 29 15:10:40 UTC 2013 - rw@suse.com + +- elilo.pl + * Always delete old EBM entries to fix ordering. (bnc#819900) + * Prevent XEN 'default' in 'elilo.conf'. (bnc#819900c5) + * Add man-page section about '--refresh-EBM' failure. (bnc#821109) + +------------------------------------------------------------------- +Wed May 8 13:30:02 UTC 2013 - rw@suse.com + +- elilo.pl + * SecureBoot: create only one Boot Manager entry. (bnc#818961) + +------------------------------------------------------------------- +Fri Apr 19 13:28:08 UTC 2013 - rw@suse.com + +- elilo.efi + * Clear console on startup. (bnc#812799) + * Avoid crash caused by EFI memory map changes. +- elilo.pl + * Work around chainloading issue with XEN. (bnc#812109) + +------------------------------------------------------------------- +Wed Mar 27 21:40:29 UTC 2013 - rw@suse.com + +- elilo.pl + * Fix handling of missing 'default' again. + +------------------------------------------------------------------- +Wed Mar 27 20:42:50 UTC 2013 - rw@suse.com + +- elilo.pl + * Implement chainloading of XEN for SecureBoot. (bnc#809702) + * Maintain 'default' in SecureBoot config. (bnc#811608c28) + * Handle failure of 'efibootmgr'. (bnc#809702c10) + * Improve verbose messages to be less alarming. + +------------------------------------------------------------------- +Fri Mar 8 14:06:28 UTC 2013 - rw@suse.com + +- elilo.efi + * Force default configs at the end of the network search list. + (bnc#789137) +- elilo.pl + * Disable use of 'shim'-loader options. (bnc#798043) + * Fix solitary 'secure-boot' for real. + +------------------------------------------------------------------- +Tue Feb 12 17:00:32 UTC 2013 - rw@suse.com + +- elilo.pl + * Revert work-around for 'shim'-loader option parsing. (bnc#798043) + * Treat 'secure-boot' identical to 'secure-boot = on'. + * Fix 'SecureBoot' sysfs variable reading. + +------------------------------------------------------------------- +Fri Feb 8 18:42:49 UTC 2013 - rw@suse.com + +- elilo.efi + * Now really introduce 'block-size'. (bnc#681242) + * Clarify warning message on GOP failure. +- elilo.pl + * Synchronize check for "Secure Boot" with YaST. + +------------------------------------------------------------------- +Fri Jan 18 15:00:44 UTC 2013 - rw@suse.com + +- elilo.efi + * Make automatic appending of 'add_efi_memmap' to kernel command + line default, and introduce config-file option (add-efi-memmap) + to control this (auto|false). (fate#314210, bnc#772245) + * Bring network search list more in line with 'PXELINUX'. (bnc#789137) + * Introduce 'block-size' as global option in 'elilo.conf'. (bnc#681242) +- elilo.pl + * Work around limitations in 'shim'-loader option parsing. (bnc#798043) + * Don't use temporary file to establish load options. + +------------------------------------------------------------------- +Wed Dec 19 21:20:25 UTC 2012 - rw@suse.com + +- elilo.pl + * Add support UEFI Secure Boot (via 'grub.efi'). (fate#314485) + * Don't try to write 'xen.cfg', if no valid XEN section is found + and treat "VMM" EFI-binaries as "mandatory". (bnc#792100) + * Support more than 10 EFI Boot Manager (EBM) entries. + * Stop using '--write-signature' for 'efibootmgr' (as non-GPT + disk-labels aren't supported anyway). + * Sort creation of EBM entries according to default boot section. + * Fix initial handling of obsolete files. + +------------------------------------------------------------------- +Mon Jan 16 15:21:24 UTC 2012 - rw@suse.de + +- elilo.pl + * Cope with misguided '/dev/mapper/' entries in 'fstab'. (bnc#717828) + +------------------------------------------------------------------- +Fri Nov 25 17:12:38 UTC 2011 - rw@suse.de + +- elilo.pl + * Allow empty 'vmmopts' for 'xen.efi'. (bnc#731288) + * Implement refreshing of EFI Boot Manager entries. (bnc#717828) + +------------------------------------------------------------------- +Mon Sep 19 14:53:06 UTC 2011 - rw@suse.de + +- elilo.pl + * Fix handling of 'xen.cfg'. (bnc#706110) + * Record installed files and remove only those in the future. + ------------------------------------------------------------------- Sun Sep 18 17:17:12 UTC 2011 - jengelh@medozas.de -- Remove redundant/obsolete tags/sections from specfile - (cf. packaging guidelines) +- elilo.spec + * Remove redundant/obsolete tags/sections from specfile + (cf. packaging guidelines) + +------------------------------------------------------------------- +Mon Aug 1 12:43:45 UTC 2011 - rw@suse.de + +- elilo.efi + * Allow booting in an IPv6 network environment. (fate#311995) +- elilo.pl + * Add support for 'xen.efi'. (fate#311376) + +------------------------------------------------------------------- +Fri Jun 17 12:54:53 UTC 2011 - rw@suse.de + +- elilo.efi + * Update to elilo-3.14. (fate#311532) +- elilo.spec + * Follow openSUSE migration from libexecdir to libdir. +- elilo.pl + * Don't initialize '$[' to 0. + * Adapt to replacement of libexecdir with libdir. ------------------------------------------------------------------- Fri Dec 17 10:51:23 UTC 2010 - coolo@novell.com -* Update to elilo-3.12 from SLE11 to fix EFI boot (bnc#659368) - - see ChangeLog for a detailed log +- Update to elilo-3.12 from SLE11 to fix EFI boot (bnc#659368) + (see ChangeLog for a detailed log) + +------------------------------------------------------------------- +Mon Apr 12 16:59:30 CEST 2010 - rw@suse.de + +- elilo.efi + * Handle EFI memory maps larger than E820_MAX. (bnc#594516) + +------------------------------------------------------------------- +Tue Mar 30 11:42:43 CEST 2010 - rw@suse.de + +- elilo.efi + * Update boot protocol for 2.6.30. (bnc#560443) + * Allocate initrd below kernel specified limit. (bnc#577570) + * Load kernel relocated. (bnc#447843, 516215, 568848, 587858) +- elilo.pl + * Add handling of VMM for XEN. (bnc#578926) + +------------------------------------------------------------------- +Tue Jan 26 12:14:57 CET 2010 - rw@suse.de + +- elilo.efi + * PRELIMINARY debugging patch for x86_64. (bnc#560443) + +------------------------------------------------------------------- +Fri Nov 20 13:10:51 CET 2009 - rw@suse.de + +- elilo.efi + * Update to elilo-3.12. + +------------------------------------------------------------------- +Tue Sep 22 18:30:29 CEST 2009 - rw@suse.de + +- elilo.spec + * Submit to SLE11. (bnc#494042) ------------------------------------------------------------------- Mon Jul 20 08:16:44 CEST 2009 - coolo@novell.com -- replace libexecdir with libdir +- elilo.spec + * replace libexecdir with libdir + +------------------------------------------------------------------- +Thu May 28 13:05:25 CEST 2009 - ro@suse.de + +- elilo.spec + * Use binutils219 on SLE10 SP3. + +------------------------------------------------------------------- +Fri May 15 13:47:44 CEST 2009 - rw@suse.de + +- elilo.efi + * Update to elilo-3.10. (fate#306032) + +------------------------------------------------------------------- +Thu Apr 30 15:24:26 CEST 2009 - ro@suse.de + +- elilo.spec + * Submit to SLE10 SP3. (fate#306032) ------------------------------------------------------------------- Mon Feb 9 15:36:39 CET 2009 - rw@suse.de @@ -30,7 +229,7 @@ Tue Dec 9 16:34:53 CET 2008 - rw@suse.de - elilo.efi * Second attempt to work around firmware problem. (bnc#437486) - elilo.conf - * Provide stub man page. (bnc#435648) + * Provide stub man page. (bnc#435648) ------------------------------------------------------------------- Fri Nov 21 15:56:50 CET 2008 - rw@suse.de diff --git a/elilo.pl b/elilo.pl index ec63e4c..a0ef3cd 100644 --- a/elilo.pl +++ b/elilo.pl @@ -1,5 +1,5 @@ #!/usr/bin/perl -w -# $Id: elilo.pl,v 0.21 2010/12/10 20:31:09 rw Exp $ +# $Id: elilo.pl,v 0.85 2013/08/15 17:38:03 rw Exp $ use strict; my $C = $0; $C =~ s{^.*/}{}; @@ -7,16 +7,35 @@ my $C = $0; $C =~ s{^.*/}{}; my $dbg = (exists( $ENV{"ELILO_DEBUG"})) ? $ENV{"ELILO_DEBUG"} : ""; my $Edition = q(@EDITION@); my $Arch = q(@ARCH@); -my $LibD = q(@LIBEXECDIR@); +my $LibD = q(@LIBDIR@); my $MPold = "$dbg/boot"; my $MPnew = "$dbg/boot/efi"; my $Dlibold = "$dbg$LibD/elilo"; my $Dlib = "$dbg$LibD/efi"; my $Fconf = "elilo.conf"; +my $Flist = "elilo.list"; +my %Flist = (); my $Sconf = "$dbg/etc/" . $Fconf; +my $Xconf = "xen.cfg"; +my $Gconf = "grub.cfg"; -my $Reserved = qr(^(efi-mountpoint|vendor-directory|elilo-origin|precious))o; +my @eBinaries = ("elilo.efi", "xen.efi", "shim.efi"); +my ($elilo, $xen, $shim) = @eBinaries; +my @sBinaries = ($shim, "grub.efi", "MokManager.efi"); # hardcoded for now! + +my $Reserved = qr{(efi-mountpoint|vendor-directory|elilo-origin|precious| + (?:y|e)bm-label|static-description|secure-boot| + SB-(?:fallback|direct2xen|))}ox; my %Sconf = (); +my %Econf = (); +my @Econf = (); +my %Xconf = (); +my %Xsonf = (); +my @Xconf = (); +my @Gconf = (); +my %Labels = (); +my @Labels = (); +my @Files = (); my $keep = -1; my $test = 0; @@ -26,7 +45,7 @@ my $optional = 1; my $MP = ""; # Mount-Point for EFI/FAT partition my $VD = "SuSE"; # vendor-specific directory in $MP/efi my $D = ""; # will be $MP.$VD -my %Labels = (); +my $EFIarch = ""; my $Disclaimer = < ) { - chomp; - next unless ( m/$Reserved\s*(?:\=\s*(.+))?\s*$/xo ); - $r{$1} = (defined($2)) ? $2 : "true"; - Info( 3, ">>> $1 = '$r{$1}'\n"); - } - close( IN); - return( %r ); -} -sub Transfer ($$) { - my( $in, $dir) = @_; - my( $out, $tmp, $c, @f, %f, $opt); - my $default_label = ""; - my $default_loc; - my $image = ""; - my @Out = (); - $out = "$dir/$Fconf"; - $tmp = "$out.tmp"; - $opt = $optional; - - open( IN, "< $in") || Panic(1, "$in: failed to open: $!\n"); - Info( 1, "## filter '$in' to"); - if ( ! $test ) { - Info( 1, " '$tmp'\n"); - open(OUT, "> $tmp") || Panic( 1, "$tmp: failed to create: $!\n"); - push @Out, $Disclaimer; - } elsif ( $verbose >= 2 ) { - Info( 1, " STDOUT\n"); - open( OUT, ">&STDOUT"); - push @Out, $Disclaimer unless ( $verbose < 3 ); - } else { - Info( 1, " /dev/null\n"); - open( OUT, ">/dev/null"); - } - while ( ) { - next if ( m/$Reserved/xo ); - if ( m{^\s*(?:image|initrd|vmm)\s*=\s*} ) { - chomp; - s{^(\s*(image|initrd|vmm)\s*=\s*)(/\S+/)?([^/\s]+)\s*$}{$1$4}; - my( $t, $p, $f) = ($2, $3, $4); - #Info( 0, "$C: $in: $.: t=$t p=$p f=$f\n"); - $_ .= "\n"; - if ( ! defined( $p) ) { - $p = "/boot/"; - } - $image = "" if ( $t eq "image" ); - if ( ! defined( $f) ) { - Warn( "$in: $.: invalid file-specification\n" . - ">> $_"); - $c++; - } elsif ( $opt && ! -r "$dbg$p$f" ) { - Info( 0, "$C: $in: $.: missing optional '$p$f' skipped\n"); - } elsif ( exists( $f{$f}) ) { - $image = $dbg . "$p$f" if ( $t eq "image" ); - Info( 3, "$in: $.: file duplication skipped (previous: $f{$f})\n" . - ">> $_"); - } else { - $image = $dbg . "$p$f" if ( $t eq "image" ); - push @f, $dbg . "$p$f"; - $f{$f} = $.; - } - } elsif ( $image && m{^(\s*description\s*=\s*")([^"]+)(".*)$} ) { - my( $p, $d, $s) = ($1, $2, $3); - my $t = ""; - if ( $d =~ m{\%L} ) { - if ( -l $image ) { - ($t = readlink( $image)) =~ s{^vmlinuz-}{}; - } else { - #($t = $image) =~ s{^.*vmlinux-}{}; - $t = "no symlink"; - } - Info( 2, " \%L => '$t'\n"); - $d =~ s{\%L}{$t}; - } elsif ( $d =~ m{\%G} ) { - my $cmd = "/sbin/get_kernel_version"; - if ( -x $cmd ) { - chomp( $t = `$cmd $image`); - } else { - $t = ""; - } - $d =~ s{\%G}{$t}; - Info( 2, " \%G => '$t'\n"); - } - $_ = $p . $d . $s . "\n"; - } elsif (m{^(\s*label\s*=\s*)(\S+)}) { - my ($pre, $label) = ($1, $2); - if (exists $Labels{$label}) { - my $t = 1; - my $l = $label; - while ( exists $Labels{$l} ) { - $l = sprintf "%s.%d", $label, $t++; - } - Warn( "duplicate label '$label', replaced with '$l'\n"); - $label = $l; - $_ = $pre . $l . "\n"; - } - $Labels{$label} = 1; - } elsif (m{^\s*default\s*=\s*(\S+)}) { - $default_label = $1; - $default_loc = $#Out + 1; - } elsif (m{^\s*read-only\s*$}) { - $_ = "#read-only # Deprecated!" . - " (Add comment in '$Sconf' to overrule.)" . - "\n"; - Info( 2, " $in: $.: deprecated 'read-only' ignored.\n"); - } elsif (m{^\s*relocatable\s*$} && $Arch =~ m{86}) { - $_ = "#relocatable # Unsupported on this architecture!\n" . - "# (May be forced by adding a comment in '$Sconf'.)\n"; - Info( 2, " $in: $.: unsupported 'relocatable' ignored.\n"); - } - push @Out, $_; - } - if ($default_label ne "" && !exists $Labels{$default_label}) { - $Out[$default_loc] = "#" . $Out[$default_loc]; - Warn( "undefined default label '$default_label' discarded\n"); - } - - print OUT @Out; - close( OUT); - close( IN); - Info( 2, "## end of $in\n") unless $test; - foreach ( @f ) { - if ( ! -r $_ ) { - Warn( "$_: not found\n"); - $c++; - } - } - if ( $c ) { - Info( 2, "> unlink( $tmp)\n"); - unlink( $tmp); - Panic( 2, "$in: broken references\n"); - } - if ( ! $test ) { - Info( 1, "> unlink( $out)\n"); - unlink( $out); - Info( 1, "> rename( $tmp, $out)\n"); - rename( $tmp, $out); - # fixme: add failure-detection - } - return( @f ); -} - sub System($@) { my( $fatal, @C) = @_; my $cmd = $C[0]; foreach my $c ( @C[1..$#C] ) { - if ( $c =~ /\s/ ) { + if ( $c =~ /[\s\\]/ ) { $cmd .= " '$c'"; } else { $cmd .= " $c"; @@ -230,22 +100,71 @@ sub System($@) { Panic( $fatal, "$C[0]: failed\n"); } } - -sub Purge($) { - my( $d) = @_; - if ( $keep > 0) { - Info( 1, "## skip removal of old files from '$d'\n"); - return 0; +sub Rename($$$) { + my( $loglvl, $oldname, $newname) = @_; + Info( $loglvl, "> mv $oldname $newname\n"); + if ( -e $newname ) { + Info( $loglvl+1, ">> unlink( $newname)\n"); + unlink( "$newname") unless ($test); } - Info( 1, "## remove old files from '$d'\n"); - my @F = glob( "$d/*"); - foreach my $f ( @F ) { - next unless ( $f =~ m{.*/((vm|)linu(x|z)|initrd)(|[-.]\S+)$} ); - Info( 1, "> rm $f\n"); - unlink( $f) unless ($test); + Info( $loglvl+1, ">> rename( $oldname, $newname)\n"); + rename( $oldname, $newname) unless ($test); + # fixme: add failure-detection and handling? +} +sub Write($$$$@) { + my( $loglvl, $msg, $mode, $file, @lines) = @_; + my $tmp = ($mode ne ">>"); + my $out = ($tmp) ? "$file.tmp" : "$file"; + my $mstr = ($tmp) ? "create" : "append"; + my $fh; + + Info( $loglvl, $msg); + if ( $test && $verbose >= $loglvl + 1 ) { + Info( $loglvl, " STDOUT\n"); + open( $fh, ">&STDOUT"); + } elsif ( $test ) { + Info( $loglvl, " nowhere\n"); + open( $fh, ">> /dev/null"); + } elsif ( ! open( $fh, "$mode $out") ) { + Warn( "$out: failed to $mstr: $!\n"); + return 1; + } elsif ( $verbose > $loglvl ) { + Info( $loglvl, " '$out'\n"); + } else { + Info( $loglvl, " '$file'\n"); + } + + print( $fh @lines) || Panic( 1, "$out: failed to write: $!\n"); + close( $fh); + + if ( ! $test && $mode ne ">>" ) { + Rename( $loglvl+1, $out, $file); } } +sub Merge($$) { + my( $target, $source) = @_; + my $in; + my @l = (); + Info( 2, "### check file list of previous installs:"); + if ( ! open( $in, "< $source") ) { + Warn( "could not open < '$source': $!\n"); + return 1; + } + while ( <$in> ) { + chomp; + next if (m{/} || exists( $Flist{$_})); + push @l, "$_\n"; + } + close( $in); + if ( $#l < 0) { + Info( 2, " none!\n"); + } else { + my $n = $#l + 1; + Info( 2, " $n missing\n"); + Write( 2, "### appending to", ">>", $target, @l); + } +} sub Install($$$$) { my( $f, $o, $s, $d) = @_; my @C = ( "install", $o, $s, $d); @@ -256,6 +175,608 @@ sub Install($$$$) { System( $f, @C); } +my $labelc = 0; +sub mkLabel($$) { + my( $label, $namespace) = @_; + + if (exists( $Labels{$namespace}{$label})) { + my $t = 1; + my $l = $label; + while ( exists $Labels{$namespace}{$l} ) { + $l = sprintf "%s.%d", $label, $t++; + } + Warn( "duplicate label '$label', replaced with '$l' in $namespace\n"); + $label = $l; + } + $Labels{$namespace}{$label} = ++$labelc; + push @Labels, "$namespace $label"; + Info(4,"L($namespace)= ".join(", ",sort(keys(%{$Labels{$namespace}})))."\n"); + return $label; +} +my $sections = 0; +sub section2Econf($$%) { + my( $in, $lnr, %current) = @_; + + if ( $current{xencfg} && ! $current{precious} ) { + Info( 3, "=== Econf: skipping $current{label} for $Fconf.\n"); + return( 0 ); + } + if ( exists( $current{label}) ) { + my $l = mkLabel( $current{label}, "Econf"); + if ( $l ne $current{label} ) { + $current{Econf}[$current{label_loc}] = $current{label_pre} . $l ."\n"; + } + Info( 2, sprintf "=== %2d. Econf: $l\n", ++$sections); + $Econf{$l}{options} = (exists( $current{append}) ? $current{append} : + (exists( $Sconf{append}) ? $Sconf{append} : "")); + $Econf{$l}{kernel} = $current{image}; + $Econf{$l}{ramdisk} = (exists( $current{initrd}) ? $current{initrd} : ""); + $Econf{$l}{root} = (exists( $current{root}) ? $current{root} : + (exists( $Sconf{root}) ? $Sconf{root} : "")); + $Econf{$l}{description} = (exists( $current{description}) ? $current{description} : $l); + if ( exists($Sconf{default}) && $current{label} eq $Sconf{default} ) { + $Sconf{grubdefault} = $Econf{$l}{description}; + } + } + foreach my $l ( @{$current{Econf}} ) { + push @Econf, $l; + } + return( 0 ); +} +my $Xsections = 0; +sub section2Xconf($$%) { + my( $in, $lnr, %current) = @_; + my( $label, $image, $initrd, $append, $root, $vmm, $vmmopts, $desc); + + if ( ! $current{xencfg} ) { + Info( 3, "=== Xconf: skipping ". + (exists( $current{label}) ? $current{label} : "section") + ." for $Xconf.\n"); + return( 0 ); + } + if ( ! exists( $current{image}) ) { + Warn( "$in: $lnr: no image: incomplete section skipped\n"); + return( 1 ); + } + if ( ! exists( $current{image}) || ! exists( $current{label}) ) { + Warn( "$in: $lnr: incomplete section skipped\n"); + return( 1 ); + } + + $label = mkLabel( $current{label}, "Xconf"); + $image = $current{image}; + $initrd = (exists( $current{initrd}) ? $current{initrd} : + (exists( $Sconf{initrd}) ? $Sconf{initrd} : "")); + $append = (exists( $current{append}) ? $current{append} : + (exists( $Sconf{append}) ? $Sconf{append} : "")); + $vmmopts = (exists( $current{vmmopts}) ? $current{vmmopts} : + (exists( $Sconf{vmmopts}) ? $Sconf{vmmopts} : "")); + $root = (exists( $current{root}) ? $current{root} : + (exists( $Sconf{root}) ? $Sconf{root} : "")); + $root = ($root ? " root=$root " : " "); + $vmm = (exists( $current{VMM}) ? $current{VMM} : + (exists( $Sconf{vmm}) ? $Sconf{vmm} : "")); + if ( exists( $current{description}) ) { + $desc = $current{description}; + } else { + my $vers = $image; + $vers =~ s{^[^-]+-}{}; + $desc = "$label ($vers)"; + } + + if ( ! $vmm ) { + Warn( "$in: $lnr: no vmm?!\n"); + return( 1 ); + } + if ( exists( $current{vmm}) ) { + Info( 1, "$in: $lnr: legacy vmm ($current{vmm}) skipped for $Xconf.\n"); + return( 0 ); + } + Info( 2, sprintf "=== %2d. Xconf: $label\n", ++$sections); + $Xconf{$label}{vmm} = $vmm; + $Xconf{$label}{options} = $vmmopts; + $Xconf{$label}{kernel} = $image; + $Xconf{$label}{append} = $root . $append; + $Xconf{$label}{ramdisk} = $initrd if ( $initrd); + $Xconf{$label}{description} = $desc; + if ( exists($Sconf{default}) && $current{label} eq $Sconf{default} ) { + $Xconf{$label}{cfg} = $Xconf; + $Sconf{grubdefault} = $desc; + } elsif ( $Sconf{xencfg} != 2 && $Xsections == 0 ) { + $Xconf{$label}{cfg} = $Xconf; + ++$Xsections; + } else { + $Xconf{$label}{cfg} = "xen". ++$Xsections .".cfg"; + } + + + return( 0 ); +} + +sub Parse($$) { + my( $in, $verbosity) = @_; + my $ov = $verbose; + $verbose = ($verbosity < 0 ) ? $ov : $verbosity; + + $Sconf{xencfg} = 0; + open( IN, "< $in") || Panic(1, "$in: failed to open: $!\n"); + Info( 1, "## parsing '$in'...\n"); + Info( 3, "### pick up global settings...\n"); + while ( ) { + chomp; + s{^##YaST - boot_efilabel =}{ybm-label=}; + if ( m/^$Reserved\s*(?:\=\s*(?|"([^"]+)"|([^"].*?)))?\s*$/xo ) { + $Sconf{$1} = (defined($2)) ? $2 : "true"; + } elsif ( m/^(append|root|timeout)\s*=\s*(?|"([^"]+)"|([^"].*?))\s*$/xo ) { + $Sconf{$1} = $2; + } elsif ( m/^(default|prompt|relocatable)\s*(?:\=\s*(.+))?\s*$/xo ) { + $Sconf{$1} = (defined($2)) ? $2 : "true"; + } elsif ( m/^(vmm)\s*\=\s*(?|"([^"]+)"|([^"].*?))\s*$/xo ) { + my ($k, $v) = ($1, $2); + next unless (defined( $v)); + $Sconf{$k} = $v; + if ( $v =~ m/^(\S+.efi)(?:\s+(.*))?$/ ) { + $Sconf{vmm} = $1; + $Sconf{vmmopts} = (defined( $2) ? $2 : ""); + $Sconf{xencfg} = 1; + } else { + Info( 1, "$C: $in: $.: ignoring non-efi based VMM. ($Sconf{vmm})\n"); + } + } elsif ( m/^image\s*=/ ) { + last; + } else { + next; + } + Info( 3, ">>> $1 = '$Sconf{$1}'\n"); + } + my( $c, %f, $opt); + my $default_label = ""; + my $default_loc; + my $image = ""; + my %current = (); + my %fp = (); + Info( 3, "### start over...\n"); + seek( IN, 0, 0); + $. = 0; + while ( ) { + $opt = $optional; + if ( m/^\s*$Reserved\s*(?:\=\s*(.+))?\s*$/xo ) { + $current{$1} = (defined($2)) ? $2 : "true"; + next; + } + if ( m{^\s*(?:image|initrd|vmm)\s*=\s*} ) { + my $orig = $_; + chomp; + s{(vmm\s*=\s*)"([^"]+)"\s*(#.*)?$}{$1$2}; + s{^(\s*(image|initrd|vmm)\s*=\s*)(/\S+/)?([^/\s]+)\s*(.*?)\s*$}{$1$4}; + my( $k, $p, $f, $o) = ($2, $3, $4, $5); + #Info( 8, ">>> $.: k=$k p=$p f=$f\n"); + $_ .= "\n"; + if ( $k eq "image" ) { + # new "image=" => finish up the previous one... + $c += section2Econf( $in, $., %current); + $c += section2Xconf( $in, $., %current) if (exists( $current{image})); + %current = (); + } + if ( $k eq "vmm" && $f =~ m/\.efi$/ ) { + $k = "VMM"; + $p = $Dlib . "/" unless (defined( $p)); + $p =~ s{^$dbg}{}o if ($dbg); + $current{vmmopts} = $o; + $current{xencfg} = $Sconf{xencfg} = 1; + $opt = 0; # 'xen.efi' is *never* optional! + } elsif ( defined( $o) && $o ) { + Warn( "$in: $.: ignoring trailing garbage...\n"); + } + if ( ! defined( $p) ) { + $p = "/boot/"; + } + if ( ! defined( $f) ) { + Warn( "$in: $.: invalid file-specification\n" . + ">> $orig"); + $c++; + } elsif ( exists( $f{$f}) ) { + if ( "$p$f" eq $fp{$f} ) { + Info( 4, ">>> $.: copy only once (previous: line $f{$f})\n" . + ">> $orig"); + } else { + Warn( "$in: $.: ambigous target '$f' (previous: $f{$f}: $fp{$f})\n" . + ">> $orig" . "=> first wins\n"); + } + $current{$k} = $f; + $current{"path2$k"} = $fp{$f}; + } else { + my $fp = "$dbg$p$f"; + if ( -r $fp ) { + $current{$k} = $f; + $current{"path2$k"} = $fp; + push @Files, $fp; + $fp{$f} = $p . $f; + $f{$f} = $.; + } elsif ( $opt ) { + Info( 0, "$C: Info: $in: $.: missing optional '$p$f' skipped\n"); + } else { + Warn( "$in: $.: missing '$p$f' skipped\n"); + } + } + next if ( $k eq "VMM" ); # omit efi-based "vmm" lines from elilo.conf! + } elsif ( exists( $current{image}) && + m{^(\s*description\s*=\s*)(?|"([^"]+)"|([^"].*?))\s*$}xo ) { + my( $p, $d) = ($1, $2); + my $image = $current{path2image}; + my $t = ""; + my $od = $d; + $d .= " (%G)" if ( $d =~ m{^(Linux|Failsafe)$} ); + if ( $d =~ m{\%L} ) { + if ( -l $image ) { + ($t = readlink( $image)) =~ s{^vmlinuz-}{}; + } else { + #($t = $image) =~ s{^.*vmlinux-}{}; + $t = "no symlink"; + } + Info( 3, ">>> $.: \%L => '$t'\n"); + $d =~ s{\%L}{$t}; + } elsif ( $d =~ m{\%G} ) { + my $cmd = "/sbin/get_kernel_version"; + if ( -x $cmd ) { + chomp( $t = qx{$cmd $image}); + } else { + $t = ""; + } + $d =~ s{\%G}{$t}; + Info( 3, ">>> $.: \%G => '$t'\n"); + } + if ( $Sconf{'static-description'} ) { + $d = $od; + } else { + $_ = $p . q{"} . $d . q{"} . "\n"; + } + $current{description} = $d; + } elsif (m{^\s*(append|root)\s*=\s*(?|"([^"]+)"|([^"].*?))\s*$}xo ) { + my( $k, $v) = ($1, $2); + Info( 0, "$C: $in: $.: duplicate option (last wins)\n") + if (exists( $current{$k})); + $current{$k} = $v; + } elsif (m{^(\s*label\s*=\s*)(\S+)}) { + my ($pre, $label) = ($1, $2); + $current{label_pre} = $pre; + $current{label} = $label; + $current{label_loc} = $#{$current{Econf}} + 1; + } elsif (m{^\s*default\s*=\s*(\S+)}) { + $default_label = $1; + $default_loc = $#{$current{Econf}} + 1; + } elsif (m{^\s*read-only\s*$}) { + $_ = "#read-only # Deprecated!" . + " (Add comment in '$Sconf' to overrule.)" . + "\n"; + Info( 2, " $in: $.: deprecated 'read-only' ignored.\n"); + } elsif (m{^\s*relocatable\s*$} && $Arch =~ m{86}) { + $_ = "#relocatable # Unsupported on this architecture!\n" . + "# (May be forced by adding a comment in '$Sconf'.)\n"; + Info( 2, " $in: $.: unsupported 'relocatable' ignored.\n"); + } + push @{$current{Econf}}, $_; + } + if ( exists( $current{image})) { + $c += section2Econf( $in, $., %current); + $c += section2Xconf( $in, $., %current); + } + if ($default_label ne "" && exists( $Labels{Xconf}{$default_label})) { + $Sconf{xencfg} = 2; + $Econf[$default_loc] = "#" . $Econf[$default_loc]; + Info( 1, ">>> default label '$default_label' points to a XEN section\n"); + } elsif ($default_label ne "" && !exists $Labels{Econf}{$default_label}) { + $Econf[$default_loc] = "#" . $Econf[$default_loc]; + Info( 1, ">>> default label '$default_label' undefined in $Fconf\n"); + } elsif ($default_label eq "" && $Labels[0] =~ m{^Xconf }) { + $Sconf{xencfg} = 2; + Info( 1, ">>> first section (implicit default) points to a XEN section\n"); + } + close( IN); + $Sconf{'__warn-count'} = $c; + + Info( 2, "## end of parsing $in\n") unless $test; + $verbose = $ov; +} + +sub addList($) { + my( $f) = @_; + $f =~ s{^.*/([^/]+)$}{$1}; + print( LIST "$f\n") if ( fileno( LIST) ); + $Flist{$f} = $_[0]; +} +sub Output($$@) { + my( $dir, $file, @lines) = @_; + my $out = "$dir/$file"; + + if ( (! $test || $verbose > 3) && $file ne $Gconf ) { + unshift @lines, $Disclaimer; + } + Write( 1, "## writing '$file' to", ">", $out, @lines); + addList( $out); +} +my %GconfFSuuid = (); +sub canonicalize($$) { + my( $base, $rel) = @_; + + return( $rel ) unless( defined( $rel) ); + Info( 9, "canonicalize($base, $rel): "); + $base = "" if ($rel =~ m{^/}); + $base =~ s{/[^/]+$}{}; + + while ( $rel =~ s{^(\.\.?)/}{} ) { + $base =~ s{/[^/]+$}{} if ( $1 eq ".." ); + } + $rel =~ s{^/}{}; + Info( 9, "'$base/$rel'\n"); + return ( "$base/$rel" ); +} +sub readLink($) { + my( $lnk) = @_; + + my $tgt = readlink( $lnk); + Info( 9, "readLink($lnk): ".(defined($tgt) ? $tgt : "(--undef--)")."\n"); + $tgt = canonicalize( $lnk, $tgt); + Info( 8, "readLink($lnk): ".(defined($tgt) ? $tgt : "(--undef--)")."\n") + unless ($verbose > 8); + return( $tgt ); +} +sub GconfProbeFSuuid($) { + my( $dev) = @_; + my $udir = "/dev/disk/by-uuid"; + my $uuid = ""; + my $tgt = ""; + + Info( 5, "GconfProbeFSuuid($dev): \n"); + while ( -l $dev ) { + $_ = readLink( $dev); + return ( "" ) unless ( defined( $_) ); + Info( 5, " $dev => $_\n"); + $dev = $_; + } + Info( 5, " looking for: $dev\n"); + if ( opendir( my $fh, $udir) ) { + while ( ($_ = readdir( $fh)) ) { + $_ = "$udir/$_"; + next unless ( -l $_ ); + $tgt = readLink( $_); + next unless (defined( $tgt) ); + Info( 5, " looking at: $_ => $tgt\n"); + next unless ( $dev eq $tgt ); + s{^$udir/}{}; + $uuid = $_; + Info( 5, " found: $uuid!\n"); + last; + } + closedir( $fh); + } + return ( $uuid ); +} +sub GconfFSuuid($) { + my( $rdev) = @_; + return ( "" ) unless ( $Sconf{SB} ) ; + return ( $GconfFSuuid{$rdev} ) if ( exists( $GconfFSuuid{$rdev}) ); + + my $ruuid = ""; + my $cmd = "/usr/sbin/grub2-probe"; + if ( -x $cmd ) { + chomp( $ruuid = qx{$cmd --device "$rdev" --target=fs_uuid}) if ( -x $cmd ); + } else { + $ruuid = GconfProbeFSuuid( $rdev); + } + if ( ! $ruuid ) { + Panic( 3, "couldn't determine fs_uuid -- skip Secure Boot (grub) config!\n"); + $Sconf{SB} = ""; + } + $GconfFSuuid{$rdev} = $ruuid; + return ( $ruuid ); +} +sub Gconf() { + my @parts = ("pre", "Econf", "Xconf", "post"); + my @keys = ("label", "kernel", "ramdisk", "options", "description", + "rootfsuuid", "bootfsuuid", "disknr", "partnr", "vmm", "cfg"); + my %S = (); + my $re = join( '|', @parts); + my $current = ""; + my $lines = ""; + my %Gconf; + + $re = qr{^\>\>grub\.($re|.*)\<\<}ox; + + while ( ) { + if ( m{^__(END)__} || ($current && m{$re}o) ) { + Info( 9, "<<$current\n$lines>>$current => $_"); + $S{$current} = $lines; + $lines = ""; + last if ( $1 eq "END" ); + } + if ( m{$re}o ) { + $current = $1; + next; + } + $lines .= $_; + } + + $lines = $S{pre}; + foreach my $k ( "timeout" ) { + my $val = (exists( $Sconf{$k})) ? $Sconf{$k} : "80"; + $val /= 10; + $lines =~ s{\<$k\>}{$val}gm; + } + foreach my $k ( "grubdefault" ) { + if (exists( $Sconf{$k})) { + $lines =~ s{\<$k\>}{$Sconf{$k}}gm; + } else { + $lines =~ s{^set default='\<$k\>'$}{}gm; + } + } + push @Gconf, $lines; + Info( 8, "<>pre\n"); + foreach my $l ( @Labels ) { + my ($ns, $lbl) = ($l =~ m{^(\S+) (.+)$}); + %Gconf = (); + Info( 8, "ns=$ns lbl=$lbl\n"); + if ( $ns eq "Econf" ) { + foreach my $k ( "kernel", "ramdisk", "options", "description") { + $Gconf{$k} = $Econf{$lbl}{$k} if (exists( $Econf{$lbl}{$k})); + } + $Gconf{rootfsuuid} = GconfFSuuid( $Econf{$lbl}{root}); + #TODO: $Gconf{bootfsuuid} = GconfFSuuid( GconfFSdev( "/boot")); + } elsif ( $ns eq "Xconf" ) { + foreach my $k ( "vmm", "kernel", "cfg", "description") { + $Gconf{$k} = $Xconf{$lbl}{$k} if (exists( $Xconf{$lbl}{$k})); + } + $Gconf{cfg} = $Xconf unless ( exists($Gconf{cfg}) ); + } else { + next; + } + + $lines = $S{$ns}; + $Gconf{label} = $lbl; + foreach my $k ( @keys ) { + my $val = (exists( $Gconf{$k})) ? $Gconf{$k} : "{{$k}}"; + $lines =~ s{\<$k\>}{$val}gm; + } + push @Gconf, $lines; + Info( 8, "<<$lbl\n$lines>>$lbl\n"); + } + $lines = $S{post}; + push @Gconf, $lines; + Info( 8, "<>post\n"); +} +sub Xconf() { + my $l = "global"; + my $k = "default"; + my %Xlabels = %{$Labels{Xconf}}; + my @Xgc = (); + + push @Xgc, "[$l]\n"; + push @Xconf, "[$l]\n"; + push @Xconf, "#" if (exists( $Sconf{$k}) && + ! exists( $Xconf{$Sconf{$k}}{kernel})); + push @Xconf, "$k=$Sconf{$k}\n" if (exists( $Sconf{$k})); + foreach my $k ( ("time-out", "gfx-mode") ) { + push @Xgc, "$k=$Sconf{$k}\n" if (exists( $Sconf{$k})); + push @Xconf, "$k=$Sconf{$k}\n" if (exists( $Sconf{$k})); + } + push @Xgc, "\n"; + push @Xconf, "\n"; + foreach my $l ( sort { $Xlabels{$a} <=> $Xlabels{$b} } keys %Xlabels ) { + next unless (exists( $Xconf{$l}{kernel})); + my @Xlc = (); + push @Xlc, "[$l]\n"; + if ( exists($Xconf{$l}{append}) ) { + $Xconf{$l}{kernel} .= " " . $Xconf{$l}{append}; + } + foreach my $k ( sort( keys( %{ $Xconf{$l} })) ) { + next if ( $k =~ m{^(?:append|description|vmm|cfg)$} ); + push @Xlc, "$k=$Xconf{$l}{$k}\n"; + } + push @Xconf, @Xlc; + push @Xconf, "\n"; + if ( $Xconf{$l}{cfg} ne $Xconf ) { + my $cfg = $Xconf{$l}{cfg}; + unshift @Xlc, @Xgc; + @{$Xsonf{$cfg}} = @Xlc; + } + } +} +sub Transfer ($$) { + my( $in, $dir) = @_; + my $c = $Sconf{'__warn-count'}; + + + Gconf() if ( $Sconf{SB} ); + + Warn( "no complete section for $Xconf!\n") + if ( $Sconf{xencfg} && ! exists( $Labels{Xconf}) ); + Xconf() if ( exists( $Labels{Xconf}) ); + + foreach ( @Files ) { + if ( ! -r $_ ) { + Warn( "$_: not found\n"); + $c++; + } + } + if ( $c ) { + Panic( 2, "$in: broken references\n"); + } + + Output( $dir, $Fconf, @Econf); + + # create xen.cfg + if ( $Sconf{xencfg} ) { + Output( $dir, $Xconf, @Xconf); + foreach my $x ( keys( %Xsonf) ) { + Output( $dir, $x, @{$Xsonf{$x}}); + } + } + + # create grub.cfg + Output( $dir, $Gconf, @Gconf) if ( $Sconf{SB} ); + + $Sconf{'__warn-count'} = $c; +} + +# remove old files (legacy!) +sub Purge($) { + my( $d) = @_; + + if ( -r "$d/$Flist" ) { + Info( 6, "## skip pattern-based removal of files from '$d'\n"); + return 0; + } + if ( $keep > 0) { + Info( 1, "## skip pattern-based removal of old files from '$d'\n"); + return 0; + } + Info( 1, "## remove old files from '$d' by pattern\n"); + my @F = glob( "$d/*"); + foreach my $f ( @F ) { + next if ( $f !~ m{.*/(((vm|)linu(x|z)|initrd)(|[-.]\S+)|xen.cfg)$} ); + Info( 1, "> rm $f\n"); + unlink( $f) unless ($test); + } +} + +# remove old files (list-based!) +sub Obsolete($$) { + my( $d, $init) = @_; + my $fh; + my $F = "$d/$Flist"; + my $Fn = "$F.new"; + my $verb = "refresh"; + + if ( $init ) { + $verb = "establish new"; + # skip to end... + } elsif ( $keep > 0 && -r $F ) { + Info( 1, "## skip list-based removal of obsolete files from '$d'\n"); + Merge( $Fn, $F); + } elsif ( ! -r $F ) { + Info( 2, "## no list-based removal of obsolete files during migration\n"); + } else { + my @obs = (); + if ( ! open( $fh, "< $F") ) { + Warn( "could not open '$F' for reading: $!\n"); + } + while ( <$fh> ) { + chomp; + next if (m{/} || exists( $Flist{$_})); + push @obs, $_; + } + close( $fh); + Info( 1, "## remove obsolete files based on '$F'\n") + if ( $#obs >= 0 ); + foreach ( @obs ) { + Info( 1, "> rm $d/$_\n"); + unlink( "$d/$_") unless ($test); + } + } + Info( 2, "## $verb file-list in '$d'\n"); + Rename( 2, $Fn, $F); +} + sub InstallFPSWA($) { my ( $d) = @_; my $Dfpswa = $Dlib; @@ -270,7 +791,7 @@ sub InstallFPSWA($) { # check, if we need to update and failing that do nothing?! my $c = "$Dfpswa/fpswa-cmp-version"; if ( -x $c ) { - my $chk = `$c "$d/fpswa.efi" "$Dfpswa/fpswa.efi"`; + my $chk = qx{$c "$d/fpswa.efi" "$Dfpswa/fpswa.efi"}; if ( $chk =~ /older/ ) { Info( 1, $head . "## Update '$d/fpswa.efi'.\n"); @@ -301,29 +822,231 @@ sub InstallFPSWA($) { } } -sub isMP($) { + +sub isMounted($) { my ( $d) = @_; - my @I = ("/proc/mounts", "/etc/mtab"); - Info( 3, "### isMP($d):"); + my @D = stat( $d); + my @P = stat( $d . "/.."); + return( $D[0] != $P[0] ); +} + +sub MP($) { + my ( $d) = @_; + my @I = ("/etc/fstab", "/proc/mounts", "/etc/mtab"); + Info( 3, "### MP($d):"); foreach my $f ( @I ) { open( IN, "< $f") || next; while ( ) { chomp; + next if ( m{^#} ); my @F = split; if ( $F[1] eq $d ) { Info( 3, " found in '$f' line $. => true\n"); close( IN); - return( 1); + return( $F[0]); } } close( IN); - Info( 3, " not found in '$f' => false\n"); - return( 0); } Info( 3, " not found in [" . join( ", ", @I) . "] => false\n"); return( 0); } +sub backslash($) { + my( $p) = @_; + $p =~ s{\/}{\\}g; + return ( $p ); +} +sub ebc($$$$$) { + my( $label, $dev, $part, $path, $extra) = @_; + my @C = ("efibootmgr", "-v", "-cL", $label, + "-d", "$dev", "-p", $part, "-l", backslash($path)); + my @out; + + if ( $extra ) { + #push @C, "--unicode", $extra; + push @C, "-u", $extra; + } + my $cmd = $C[0]; + foreach my $c ( @C[1..$#C] ) { + if ( $c =~ /[\s\\]/ ) { + $cmd .= " '$c'"; + } else { + $cmd .= " $c"; + } + } + Info( 1, "> $cmd\n"); + return (undef()) if ( $test ); + + open( EBM, "-|", @C) ; + while () { + print if ($verbose > 1); + chomp; + push @out, $_; + } + close( EBM); + return( @out ); +} +sub ebr($) { + my( $num) = @_; + my @C = ("efibootmgr", "-q", "-B", "-b" , sprintf( "%x", $num)); + + $C[1] = "-v" if ( $verbose > 2 ); + System( 0, @C); +} +sub hwpEqual($$) { + my( $s1, $s2) = @_; + my $hex = qr{[0-9a-f]+}i; + my $hexi = qr{[0-9a-f-]+}i; + my @S1 = ($s1 =~ m{HD\(($hex),($hex),($hex),($hexi)\)}o); + my @S2 = ($s2 =~ m{HD\(($hex),($hex),($hex),($hexi)\)}o); + Info( 5, sprintf( "'%s' - '%s'\n", $S1[3], $S2[3])); + return( $s1 eq $s2 ); +} +sub ebm($$$$$); +sub ebm($$$$$) { + my( $label, $dev, $part, $path, $extra) = @_; + my @out; + my $entry; + + if ( ! -r "$MP$path" ) { + #Warn( "refusing to create EBM for non-existant binary ($MP$path).\n"); + Warn( "refusing to create EBM for non-existant binary.\n"); + return unless ( $test ); + Info( 1, "#"); + } + @out = ebc( $label, $dev, $part, $path, $extra); + return if ( $test ); + + $entry = pop @out; + Panic( 2, "Unexpected failure of 'efibootmgr' (see elilo(8)). Giving up!\n") + unless (defined( $entry)); + Panic( 2, "Unexpected output from 'efibootmgr':\n '$entry'\n") + if ($entry !~ m{^Boot([0-9A-F]{4})[\* ] (.*?)\s+((?:HD|ACPI).+)File(.+)$}i); + my ( $num, $lbl, $hwp, $file) = (hex($1), $2, $3, $4); + Info( 1, sprintf( "# num=%d (0x%04X) hwp=%s\n", $num, $num, $hwp)); + + foreach my $e ( @out) { + $e =~ m{^Boot([0-9A-Fa-f]{4})[\* ] (.*?)\s+((?:HD|ACPI).+)File(.+)$} || + next; + next unless ( hwpEqual( $hwp, $3) ); + if ( $file eq $4 ) { + my $c = hex($1); +# This effort below to elliminate holes in the boot entry list voids +# the attempt to order EBM entries by simply calling '--refresh-EBM'. +# The full solution would require adding an interface to 'efibootmgr -o', +# which is unfortunately not feasable this late in the release cycle. +# if ( $lbl eq $2 ) { +# # delete label with higher number +# my $n = ($num < $c) ? $c : $num; +# ebr( $n); +# $num = $c; +# } else { +# # delete old/invalid label +# ebr( $c); +# if ( $num > $c ) { +# # now we have a hole! +# ebr( $num); +# ebm( $label, $dev, $part, $path, $extra); +# return; +# } +# } + # delete old/invalid labels *irrespective* of holes + ebr( $c); + } + } +} + +sub Refresh($$) { + my ( $device, $dir) = @_; + my ($dev, $part, $path, $label, $ret); + my $shim_opts = ""; #$sBinaries[1]; + + # device & partition + if ( $device =~ m{^(.*)-part(\d+)$} ) { + $dev = $1; + $part = $2; + } elsif ( $device =~ m{^(.*)_part(\d+)$} ) { + # /dev/mapper/... should not be used + $dev = $1; + $part = $2; + } elsif ( $device =~ m{^(.*/c\d+d\d+)p(\d+)$} ) { + $dev = $1; + $part = $2; + } elsif ( $device =~ m{^(/dev/\D+)(\d+)$} ) { + $dev = $1; + $part = $2; + } else { + Panic( 2, "parse error on EFI partition $device.\n"); + } + Info( 4, "#### dev=$dev, part=$part\n"); + # path + $path = "/efi/$VD/"; + Info( 4, "#### path=$path\n"); + # label + if ( exists( $Sconf{'ebm-label'}) ) { + $label = $Sconf{'ebm-label'}; + } elsif ( exists( $Sconf{'ybm-label'}) ) { + $label = $Sconf{'ybm-label'}; + } else { + $label = "SUSE Linux Enterprise"; + } + Info( 4, "#### label=$label\n"); + if ( ! $Sconf{SB} || exists($Sconf{'SB-fallback'}) ) { + my $lbl = $label . ($Sconf{'SB'} ? " (fallback)" : ""); + $ret = ebm( "XEN ".$lbl, $dev, $part, $path . $xen, "") + if ( $Sconf{xencfg} == 1 ); + + $ret = ebm( $lbl, $dev, $part, $path . $elilo, ""); + + $ret = ebm( "XEN ".$lbl, $dev, $part, $path . $xen, "") + if ( $Sconf{xencfg} == 2 ); + } + if ( $Sconf{SB} ) { + $ret = ebm( "XEN ".$label, $dev, $part, $path . $shim, " $xen") + if ( $Sconf{xencfg} == 1 && exists( $Sconf{'SB-direct2xen'}) ); + + $ret = ebm( $label, $dev, $part, $path . $shim, $shim_opts); + + $ret = ebm( "XEN ".$label, $dev, $part, $path . $shim, " $xen") + if ( $Sconf{xencfg} == 2 && exists( $Sconf{'SB-direct2xen'}) ); + } +} + +sub CheckSB() { + my $fh; + my $sev = "/sys/firmware/efi/vars"; + my $sbd = "$sev/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data"; + my $comment = ""; + $Sconf{SB} = ""; + $Sconf{'secure-boot'} = "auto" unless ( exists( $Sconf{'secure-boot'}) ); + if ( $Sconf{'secure-boot'} =~ m{^(off|false)$} ) { + $comment = " (forced off)"; + } elsif ( $Sconf{'secure-boot'} =~ m{^(on|true|try)$} ) { + $Sconf{SB} = "forced on"; + } elsif ( ! -r "$sbd" ) { + $comment = " (not supported)"; + } elsif ( ! open( $fh, "< $sbd") ) { + Warn( "$sbd: open: $!\n"); + $Sconf{SB} = "try"; + $comment = " (failed to open)"; + } else { + my $val = <$fh>; + if ( ! defined( $val) ) { + Warn( "$sbd: read: $!\n"); + $Sconf{SB} = "try"; + $comment = " (failed to read)"; + } elsif ( unpack( "c", $val) == 0 ) { + $comment = " (supported but inactive)" + } else { + $Sconf{SB} = "auto"; + $comment = sprintf( " (data=%d)", unpack( "c", $val)) if ($verbose > 2); + } + } + Info( 2, "## SecureBoot: '$Sconf{SB}'$comment\n"); +} + +my %Opt = (); { use Getopt::Long; use Pod::Usage; @@ -331,11 +1054,10 @@ sub isMP($) { $Getopt::Long::ignorecase = 0; $Getopt::Long::bundling = 1; $Getopt::Long::passthrough = 0; - my %Opt = (); pod2usage(2) unless ( GetOptions( \%Opt, 'help|h', 'man|m', 'version|V', 'verbose|v+', - 'test|t', 'keep|k', 'purge|K') && + 'test|t', 'keep|k', 'purge|K', "refresh-EBM") && ( ! $Opt{'purge'} || ! $Opt{'keep'} ) && ! $Opt{'help'} ); @@ -353,7 +1075,12 @@ if ( $Arch =~ m{ARCH} ) { chomp( $Arch = qx{uname -m}); Info( 3, "### Arch: '$Arch'\n"); } -if ( $Dlib =~ m{LIBEXECDIR} ) { +if ( ! $EFIarch ) { + $EFIarch = ( $Arch eq "x86_64" ) ? "x64" : + ( $Arch =~ m{86} ) ? "ia32" : $Arch; + Info( 3, "### EFIarch: '$EFIarch'\n"); +} +if ( $Dlib =~ m{LIBDIR} ) { $Dlib = "$dbg/usr/lib" . (($Arch eq "x86_64") ? "64/" : "/"); $Dlibold = $Dlib . "elilo"; $Dlib = $Dlib . "efi"; @@ -362,14 +1089,17 @@ if ( $Dlib =~ m{LIBEXECDIR} ) { } # try to read variables from $Sconf -%Sconf = Parse( $Sconf); +Parse( $Sconf, ($Opt{'refresh-EBM'}&&!$Opt{test}) ? 0 : -1); + +# check for Secure Boot +CheckSB(); # check environment if ( exists( $Sconf{"efi-mountpoint"}) ) { $MP = $dbg . $Sconf{"efi-mountpoint"}; Panic( 2, "EFI partition specification in $Sconf invalid.\n") unless ( -d $MP ); # or is it "$MP/efi"? -} elsif ( -d $MPnew . "/efi/" . $VD || isMP($MPnew) ) { +} elsif ( -d $MPnew . "/efi/" . $VD || MP($MPnew) ) { $MP = $MPnew; } elsif ( -d $MPold . "/efi/" . $VD ) { $MP = $MPold; @@ -377,31 +1107,60 @@ if ( exists( $Sconf{"efi-mountpoint"}) ) { Info( 1, "## Neither new ($MPnew/efi/$VD) nor old ($MPold/efi/$VD)?\n"); Panic( 2, "EFI partition not found.\n"); } -Info( 2, "## Mount-point '$MP'...\n"); +Info( 3, "### Mountpoint: '$MP'\n"); + if ( exists( $Sconf{"vendor-directory"}) ) { $VD = $Sconf{"vendor-directory"}; - Info( 1, "## Don't forget: '$VD != SuSE'--NVRAM (efibootmgr) issue!\n") - unless ( $VD eq "SuSE" ); + Info( 1, "## To apply changes of '$VD' run 'elilo --refresh-EBM'!\n") + unless ( $VD =~ m{^(SuSE|boot)$}i || $Opt{'refresh-EBM'} ); } if ( exists( $Sconf{"precious"}) && $keep < 0 ) { $keep = 1; } +if ( ! isMounted( $MP) ) { + Panic( 2, "EFI partition (". MP( $MP) .") not mounted at $MP.\n"); +} + $D = $MP . "/efi/" . $VD; -Info( 1, "## Using '$D'...\n"); +Info( 2, "## Output directory: '$D'\n"); System( 2, "mkdir", "-p", $D) unless ( -d $D ); +if ( $Opt{'refresh-EBM'} ) { + Refresh( MP( $MP), $D); + exit 0; +} if ( -r $Sconf ) { - # extract kernels, etc. and write fixed .conf - my @F = Transfer( $Sconf, $D); - # remove old files - Purge( $D); - # copy stuff - Info( 1, "## copy new files to '$D'\n"); - unshift @F, "$Dlib/elilo.efi"; - foreach ( @F ) { - Install( 0, "-p", $_, $D); + my $initializing = ( ! -r "$D/elilo.efi" && ! -r "$D/$Fconf" ); + if ( ! $test ) { + open( LIST, "> $D/$Flist.new") || + Warn( "cannot open '$D/$Flist.new' for writing: $!\n"); } + # extract kernels, etc. and write fixed .conf + Transfer( $Sconf, $D); + # remove old files (legacy!) + Purge( $D) unless ($initializing); + # copy stuff + Info( 1, "## copy files to '$D'\n"); + @sBinaries = () unless ( $Sconf{SB} ); + foreach ( reverse( $elilo, @sBinaries) ) { + unshift @Files, "$Dlib/$_"; + } + foreach ( @Files ) { + Install( 0, "-p", $_, $D); + addList( $_); + } + if ( $VD =~ m{^boot$}i ) { + my $b = ( $Sconf{SB} ) ? $shim : $elilo; + $b = $xen if ($Sconf{xencfg} == 2 && + (!$Sconf{SB} || exists( $Sconf{'SB-direct2xen'}))); + + Install( 0, "-p", "$Dlib/$b", "$D/boot$EFIarch.efi"); + addList( "boot$EFIarch.efi"); + } + close( LIST); + # remove old files (list-based!) + Obsolete( $D, $initializing); # take care of FPSWA InstallFPSWA( $MP); } elsif ( $MP eq $MPold && -r "$D/$Fconf" ) { @@ -421,6 +1180,62 @@ if ( $warn > 0 ) { } exit( 0); +__DATA__ +>>grub.pre<< +# +# DO NOT EDIT THIS FILE +# +# It is automatically generated by /sbin/elilo using +# settings from /etc/elilo.conf (and maybe /etc/default/grub) +# +### BEGIN 00 simplified header ### +if [ x"${feature_menuentry_id}" = xy ]; then + menuentry_id_option="--id" +else + menuentry_id_option="" +fi + +if [ x${boot_once} = xtrue ]; then + set timeout=0 +elif sleep --interruptible 0 ; then + set timeout= +fi + +set efibootdir=$prefix +set default='' +### END 00 simplified header ### + +### BEGIN 10 elilo ### +>>grub.Econf-full<< # TODO: track down "disknr" and "partnr" +menuentry '