+2009-10-22 signed off by Jason Fleischli <jason.fleischli@hp.com>
+ * elilo 3.12 release commit
+ * Added additional #defines for debug levels to reduce the output
+ * Added Mac console patch rework from Julien Blache @ debian
+ this fixes the invisible console output from elilo on Macs
+ * Moved static ELILO_VERSION variable from elilo.c to elilo.h
+ so that elilo will print its version string and arch on startup.
+ * Fixed bug 2825044 ExitBootServices error handling, correctly deal
+ with changed memory map key if memory map changes from under elilo.
+ * Added memory map key to map debug output.
+ * Fixed bug 2874380 netbooting just flat broken. fixed ia64, x86_64
+ ia32, fixed handling of server side support of tfpt options (get file size)
+ elilo now attempts to get file size before attempting read of file
+ to set the buffers up correctly and deal with tftp servers that dont
+ support options extensions a little better.
+ * netboot, fixed bad blocksize handling
+ * netboot, fixed filename length for elilo-x86_64.conf type on tftp
+ server.
+ * increased bzimage kernel max length sizes to 4mb on i386 and 8mb on
+ x86_64... this is a legacy design hold over from original design and
+ needs to be re-written to do dynamic size memory management based on
+ the size of the actual vmlinuz image, as ia64/gzip does.
2008-04-02 signed off by Jason Fleischli <jason.fleischli@hp.com>
* elilo 3.10 release commit
* Bumped version string to 3.10
TOPDIR =
ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,)
-INCDIR = -I. -I$(TOPDIR) -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol
+INCDIR = -I. -I$(TOPDIR) -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol -I$(TOPDIR)/efi110
CPPFLAGS = -DCONFIG_$(ARCH)
OPTIMFLAGS = -O2
FILES = elilo.o getopt.o strops.o loader.o \
fileops.o util.o vars.o alloc.o chooser.o \
config.o initrd.o alternate.o bootparams.o \
- gunzip.o fs/fs.o \
+ gunzip.o console.o fs/fs.o \
choosers/choosers.o \
devschemes/devschemes.o \
$(ARCH)/sysdeps.o \
return NULL;
}
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));
-
+#endif
return tmp;
}
VERB_PRT(1, Print(L"allocator: invalid free @ " PTR_FMT "\n", addr));
return;
found:
+#ifdef DEBUG_MEM
DBG_PRT((L"free: %s @" PTR_FMT " size=%d\n",
p->type == ALLOC_POOL ? L"Pool": L"Page",
addr, p->size));
-
+#endif
if (p->type == ALLOC_POOL)
uefi_call_wrapper(BS->FreePool, 1, addr);
else
alloc_entry_t *tmp;
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));
-
+#endif
if (used_allocs->type == ALLOC_POOL)
uefi_call_wrapper(BS->FreePool, 1, used_allocs->addr);
else
VOID
free_kmem(VOID)
{
+#ifdef DEBUG_MEM
DBG_PRT((L"free_kmem before (" PTR_FMT ", %d)\n", kmem_addr, kmem_pgcnt));
+#endif
if (kmem_addr && kmem_pgcnt != 0) {
free(kmem_addr);
kmem_addr = NULL;
kmem_pgcnt = 0;
}
+#ifdef DEBUG_MEM
DBG_PRT((L"free_kmem after (" PTR_FMT ", %d)\n", kmem_addr, kmem_pgcnt));
+#endif
}
VOID
+++ /dev/null
-/Makefile/1.1.1.1/Tue Aug 19 16:43:15 2003//
-/simple.h/1.1.1.1/Tue Aug 19 16:43:19 2003//
-/textmenu.h/1.1.1.1/Tue Aug 19 16:43:26 2003//
-/simple.c/1.7/Tue Feb 12 22:16:50 2008//
-/textmenu.c/1.9/Tue Feb 12 22:16:50 2008//
-D
+++ /dev/null
-elilo/choosers
+++ /dev/null
-fleischli@elilo.cvs.sourceforge.net:/cvsroot/elilo
#include "elilo.h"
#include "vars.h"
+#include "console.h"
/* static is ugly but does the job here! */
static CHAR16 **alt_argv;
}
if (elilo_opt.prompt) {
+ console_textmode();
ret = select_kernel(buffer, sizeof(buffer));
if (ret == -1) return -1;
argc = argify(buffer,sizeof(buffer), argv);
if (elilo_opt.prompt == 0) {
/* minimal printing */
- Print(L"ELILO\n");
+ Print(L"ELILO v%s for EFI/%a\n", ELILO_VERSION, ELILO_ARCH);
ret = wait_timeout(elilo_opt.delay);
if (ret != 0) {
elilo_opt.prompt = 1;
#include <efilib.h>
#include "elilo.h"
+#include "console.h"
#define MAX_LABELS 64
#define MSGBUFLEN 4096
Memset(&elilo_opt.img_opt, 0, sizeof(elilo_opt.img_opt));
if (elilo_opt.prompt) {
+ console_textmode();
ret = select_kernel(label, sizeof(label));
if (ret == -1) return -1;
argc = argify(PromptBuf,sizeof(PromptBuf), argv);
if (elilo_opt.prompt == 0) {
/* minimal printing */
- Print(L"ELILO\n");
+ Print(L"ELILO v%s for EFI/%a\n", ELILO_VERSION, ELILO_ARCH);
ret = wait_timeout(elilo_opt.delay);
if (ret != 0) {
elilo_opt.prompt = 1;
back = 0;
return ch;
}
- return getc();
+/*
+ * config files served from pxe/tftpboot windows servers can contain
+ * extraneous '\r' characters, often the first char in the file, and
+ * we need to simply skip over those and continue on
+ */
+ ch = getc();
+ if(ch == '\r')
+ ch = getc();
+
+ return ch;
}
/*
CHAR16 *here;
for (;;) {
- while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n') if (ch == '\n') line_num++;
+ while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n') if (ch == '\n' ) line_num++;
if (ch == CHAR_EOF) return TOK_EOF;
+ /* skip comment line */
if (ch != '#') break;
- /* skip comment line */
while ((ch = next()), ch != '\n') if (ch == CHAR_EOF) return TOK_EOF;
line_num++;
}
if (tok == TOK_EOF) break;
- if (tok == TOK_ERR) return -1;
+ if (tok == TOK_ERR) {
+ Print(L"Bad Token from elilo config file, parser read: %s\n elilo exiting\n", str);
+ return -1;
+ }
if ( (p = find_option(current_options, str)) == NULL) {
config_error(L"Unkown option %s", str);
--- /dev/null
+/*
+ * console.c - Console screen handling functions
+ *
+ * Copyright (C) 2006 Christoph Pfisterer
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ * ELILO is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * ELILO is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with ELILO; see the file COPYING. If not, write to the Free
+ * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Please check out the elilo.txt for complete documentation on how
+ * to use this program.
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "elilo.h"
+
+#include <efiConsoleControl.h>
+
+static EFI_GUID console_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
+
+static BOOLEAN console_inited = FALSE;
+
+static EFI_CONSOLE_CONTROL_PROTOCOL *console_control;
+
+/*
+ * Initialize console functions
+ */
+static VOID console_init(VOID)
+{
+ EFI_STATUS status;
+
+ if (!console_inited) {
+ console_inited = TRUE;
+
+ status = LibLocateProtocol(&console_guid, (VOID **) &console_control);
+ if (EFI_ERROR(status))
+ console_control = NULL;
+ }
+}
+
+/*
+ * Switch the console to text mode
+ */
+
+VOID console_textmode(VOID)
+{
+ EFI_CONSOLE_CONTROL_SCREEN_MODE console_mode;
+
+ console_init();
+
+ if (console_control != NULL) {
+ uefi_call_wrapper(console_control->GetMode, 4, console_control, &console_mode, NULL, NULL);
+ if (console_mode == EfiConsoleControlScreenGraphics)
+ uefi_call_wrapper(console_control->SetMode, 2, console_control, EfiConsoleControlScreenText);
+ }
+}
--- /dev/null
+/*
+ * console.h - Console screen handling functions
+ *
+ * Copyright (C) 2006 Christoph Pfisterer
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ * ELILO is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * ELILO is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with ELILO; see the file COPYING. If not, write to the Free
+ * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Please check out the elilo.txt for complete documentation on how
+ * to use this program.
+ */
+
+#ifndef __ELILO_CONSOLE_H__
+#define __ELILO_CONSOLE_H__
+
+extern VOID console_textmode(VOID);
+
+#endif /* __ELILO_CONSOLE_H__ */
+++ /dev/null
-/Makefile/1.1.1.1/Tue Aug 19 16:43:44 2003//
-/simple.c/1.1.1.1/Tue Aug 19 16:43:40 2003//
-D
+++ /dev/null
-elilo/devschemes
+++ /dev/null
-fleischli@elilo.cvs.sourceforge.net:/cvsroot/elilo
+++ /dev/null
-/devschemes.txt/1.1.1.1/Tue Aug 19 16:43:58 2003//
-/edd30.txt/1.1.1.1/Thu Feb 14 18:35:48 2002//
-/eliloalt.txt/1.1.1.1/Tue Aug 19 16:43:53 2003//
-/elilovars.txt/1.1.1.1/Tue Aug 19 16:44:19 2003//
-/fpswa.txt/1.1.1.1/Tue Aug 19 16:44:26 2003//
-/netbooting.txt/1.2/Fri Feb 20 22:30:38 2004//
-/simple_chooser.txt/1.1.1.1/Tue Aug 19 16:44:13 2003//
-/textmenu_chooser.txt/1.1.1.1/Tue Aug 19 16:44:08 2003//
-/elilo.txt/1.2/Fri Jul 20 19:10:30 2007//
-D
+++ /dev/null
-elilo/docs
+++ /dev/null
-fleischli@elilo.cvs.sourceforge.net:/cvsroot/elilo
Copyright (C) 2002-2003 Hewlett-Packard Co.
Contributed by Stephane Eranian <eranian@hpl.hp.com>
+Updated by Jason Fleischli <jason.fleischli@hp.com>
-Last updated: 03/08/11
+Last updated: 10/19/2009
+
+x86_64 and uefi support was added @ elilo version 3.8 and linux kernel >= 2.6.24
EFI has full support for the PXE and DHCP protocol. As such
it is relatively easy to boot a machine from the network using EFI.
This filename is an opportunity to specify a machine specific configuration file.
- 2) AA[BB[CC]][-ia32|ia64].conf
+ 2) AA[BB[CC]][-ia32|ia64|x86_64].conf
As of version 3.5, elilo will also look for IPv4 class A,B,C
subnet-specific versions of the config file. This is useful when you
want to have a common config file for all machines connected to a
config files first (So for example, on an Itanium system,
"0A0000-ia64.conf" will be tried before "0A0000.conf")
- 3) elilo-ia32.config or elilo-ia64.conf
+ 3) elilo-ia32.conf, elilo-x86_64.conf, or elilo-ia64.conf
- Depending on the machine (client side) architecture elilo will try the IA-32 or
- IA-64 file.
+ Depending on the machine (client side) architecture elilo will try the matching
+ architecture specific filename.
This filename is an opportunity to specify a architecture specific configuration file.
This distinction between the architectures is useful when the same TFTP server services
- the two types of clients : IA32- and IA-64 machines.
+ the three types of clients : ia32, x86_64, and ia64 machines.
4) elilo.conf
- use the name provide by the PXE server Layer 1 or
- - elilo-ia64.conf/elilo-ia32.conf or
+ - elilo-ia64.conf/elilo-ia32.conf/elilo-x86_64 or
- elilo.conf
In the case of a DHCP boot, this type of customization makes sense only for
- the shared configuration file, elilo-ia64.conf/elilo-ia32.conf or elilo.conf.
+ the shared configuration file, elilo-ia64.conf/elilo-ia32.conf/elilo-x86_64 or elilo.conf.
The configuration file based on the IP address (such as C0A80205.conf in this
case) would provide another way of customizing parameters for a specific
client (IP address). The same thing holds if the name of the config file
--- /dev/null
+/*++
+
+Copyright (c) 2004, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ConsoleControl.h
+
+Abstract:
+
+Abstraction of a Text mode or UGA screen
+
+--*/
+
+#ifndef __CONSOLE_CONTROL_H__
+#define __CONSOLE_CONTROL_H__
+
+#define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \
+{ 0xf42f7782, 0x12e, 0x4c12, { 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21 } }
+
+/* typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL EFI_CONSOLE_CONTROL_PROTOCOL; */
+struct _EFI_CONSOLE_CONTROL_PROTOCOL;
+
+
+typedef enum {
+ EfiConsoleControlScreenText,
+ EfiConsoleControlScreenGraphics,
+ EfiConsoleControlScreenMaxValue
+} EFI_CONSOLE_CONTROL_SCREEN_MODE;
+
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE) (
+ IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This,
+ OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode,
+ OUT BOOLEAN *UgaExists, OPTIONAL
+ OUT BOOLEAN *StdInLocked OPTIONAL
+ )
+/*++
+
+Routine Description:
+Return the current video mode information. Also returns info about existence
+of UGA Draw devices in system, and if the Std In device is locked. All the
+arguments are optional and only returned if a non NULL pointer is passed in.
+
+Arguments:
+This - Protocol instance pointer.
+Mode - Are we in text of grahics mode.
+UgaExists - TRUE if UGA Spliter has found a UGA device
+StdInLocked - TRUE if StdIn device is keyboard locked
+
+Returns:
+EFI_SUCCESS - Mode information returned.
+
+--*/
+;
+
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) (
+ IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This,
+ OUT EFI_CONSOLE_CONTROL_SCREEN_MODE Mode
+ )
+/*++
+
+Routine Description:
+Set the current mode to either text or graphics. Graphics is
+for Quiet Boot.
+
+Arguments:
+This - Protocol instance pointer.
+Mode - Mode to set the
+
+Returns:
+EFI_SUCCESS - Mode information returned.
+
+--*/
+;
+
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN) (
+ IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This,
+ IN CHAR16 *Password
+ )
+/*++
+
+Routine Description:
+Lock Std In devices until Password is typed.
+
+Arguments:
+This - Protocol instance pointer.
+Password - Password needed to unlock screen. NULL means unlock keyboard
+
+Returns:
+EFI_SUCCESS - Mode information returned.
+EFI_DEVICE_ERROR - Std In not locked
+
+--*/
+;
+
+
+
+typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL {
+ EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE GetMode;
+ EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode;
+ EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn;
+} EFI_CONSOLE_CONTROL_PROTOCOL;
+
+extern EFI_GUID gEfiConsoleControlProtocolGuid;
+
+#endif
#include "loader.h"
#include "config.h" /* for config_init() */
-#define ELILO_VERSION L"3.10"
#define ELILO_SHARED_CMDLINE_OPTS L"pPMC:aDhd:i:vVc:E"
elilo_config_t elilo_opt;
EFI_STATUS status = EFI_SUCCESS;
kdesc_t kd;
memdesc_t imem, mmem;
- INTN r;
+ INTN r, retries=0;
/*
* First place where we potentially do system dependent
VERB_PRT(3, Print(L"final cmdline(%d): %s\n", r, cmdline));
/* Give user time to see the output before launch */
- if (elilo_opt.debug || elilo_opt.verbose) r = wait_timeout(300);
+ if (elilo_opt.debug || elilo_opt.verbose) {
+ r = wait_timeout(150);
+ /* have to turn off all console output(except error output) now before final get_mmemap()
+ * call or it can cause the efi map key to change and the ExitBootSvc call to fail,
+ * forcing debug and verbose options off is the surest way to enforce this.
+ */
+ elilo_opt.debug=0;
+ elilo_opt.verbose=0;
+ }
/* free resources associated with file accesses (before ExitBootServices) */
close_devices();
/* No console output permitted after create_boot_params()! */
if ((bp=create_boot_params(cmdline, &imem, &mmem, &cookie)) == 0) goto error;
- /* terminate bootservices */
+ /* terminate bootservices
+ * efi ExitBootSvcs spec: *note, get_memmap is called by create_boot_params()
+ * An EFI OS loader must ensure that it has the system's current memory map at the time
+ * it calls ExitBootServices(). This is done by passing in the current memory map's
+ * MapKey value as returned by GetMemoryMap(). Care must be taken to ensure that the
+ * memory map does not change between these two calls. It is suggested that
+ * GetMemoryMap()be called immediately before calling ExitBootServices(). */
+
+retry:
status = uefi_call_wrapper(BS->ExitBootServices, 2, image, cookie);
- if (EFI_ERROR(status)) goto bad_exit;
+ if (EFI_ERROR(status))
+ {
+ ERR_PRT((L"\nExitBootSvcs: failed, memory map has changed.\n"));
+ if (retries < 2)
+ {
+ ERR_PRT((L"Main_Loop: Retrying,... have to rebuild boot params"));
+ retries++;
+ free_boot_params(bp);
+ if ((bp=create_boot_params(cmdline, &imem, &mmem, &cookie)) == 0) goto error;
+ goto retry;
+ } else {
+ ERR_PRT((L"\nMain_Loop: tried ExitBootSvcs 3 times... retries exceeded.... giving up\n"));
+ goto bad_exit;
+ }
+ }
+
start_kernel(kd.kentry, bp);
/* NOT REACHED */
error:
free_kmem();
if (imem.start_addr) free(imem.start_addr);
+ if (mmem.start_addr) free(mmem.start_addr);
if (bp) free_boot_params(bp);
exit_error:
return ELILO_LOAD_ERROR;
#ifndef __ELILO_H__
#define __ELILO_H__
+#define ELILO_VERSION L"3.12"
+
#include <efi.h>
#ifdef CONFIG_ia32
#ifndef __ELILO_DEBUG__
#define __ELILO_DEBUG__
+//#define DEBUG_MEM
+//#define DEBUG_GZIP
+//#define DEBUG_BZ
+
#define ELILO_DEBUG 1
#define ERR_PRT(a) do { Print(L"%a(line %d):", __FILE__, __LINE__); Print a; Print(L"\n"); } while (0);
+++ /dev/null
-D/netboot////
-D/textmenu_chooser////
+++ /dev/null
-elilo/examples
+++ /dev/null
-fleischli@elilo.cvs.sourceforge.net:/cvsroot/elilo
+++ /dev/null
-/dhcpd-pxe.conf/1.1.1.1/Tue Jun 26 19:06:45 2001//
-/dhcpd.conf/1.1.1.1/Mon Mar 4 22:07:25 2002//
-D
+++ /dev/null
-elilo/examples/netboot
+++ /dev/null
-fleischli@elilo.cvs.sourceforge.net:/cvsroot/elilo
+++ /dev/null
-/elilo-textmenu.conf/1.1.1.1/Mon Mar 4 22:25:06 2002//
-/general.msg/1.1.1.1/Mon Mar 4 22:25:32 2002//
-/params.msg/1.1.1.1/Mon Mar 4 22:25:39 2002//
-/textmenu-message.msg/1.1.1.1/Mon Mar 4 22:23:34 2002//
-D
+++ /dev/null
-elilo/examples/textmenu_chooser
+++ /dev/null
-fleischli@elilo.cvs.sourceforge.net:/cvsroot/elilo
+++ /dev/null
-/Makefile/1.1.1.1/Thu Aug 14 00:13:04 2003//
-/ext2_fs.h/1.1.1.1/Tue Jun 26 19:06:45 2001//
-/ext2_fs_i.h/1.1.1.1/Tue Jun 26 19:06:45 2001//
-/ext2_fs_sb.h/1.1.1.1/Tue Jun 26 19:06:45 2001//
-/ext2_private.h/1.1.1.1/Tue Aug 19 16:45:05 2003//
-/ext2fs.h/1.1.1.1/Tue Aug 19 16:45:10 2003//
-/fs.h/1.1.1.1/Tue Jun 26 19:06:45 2001//
-/localfs.h/1.1.1.1/Tue Aug 19 16:44:53 2003//
-/netfs.h/1.1.1.1/Tue Aug 19 16:45:01 2003//
-/localfs.c/1.2/Fri Jul 20 19:09:57 2007//
-/ext2fs.c/1.3/Thu Apr 2 19:49:29 2009//
-/netfs.c/1.3/Thu Apr 2 19:49:29 2009//
-D
+++ /dev/null
-fleischli@elilo.cvs.sourceforge.net:/cvsroot/elilo
/*
- * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Copyright (C) 2001-2009 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ * Contributed by Jason Fleischli <jason.fleischli@hp.com>
* Copyright (C) 2006-2009 Intel Corporation
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
#define NETFS_DEFAULT_BUFSIZE 16*MB
#define NETFS_DEFAULT_BUFSIZE_INC 8*MB
+#define NETFS_DEFAULT_BLOCKSIZE 1024 /* setting to zero is supposed to default the underlying */
+ /* pxe implementation to largest blocksize supported,... */
+ /* in reality on original older efi implementations its */
+ /* never set causing the pxe transfer to timeout. */
+ /* the spec defines the minimum supported blocksize default */
+ /* to be 512 bytes... a bit extreme, 1024 should work for */
+ /* everything */
#define NETFS_DEFAULT_SERVER_TYPE EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP
#define NETFS_FD_MAX 2
if (pxe->Mode->RouteTableEntries>0)
Memcpy(&nfs->gw_ip, &pxe->Mode->RouteTable[0].GwAddr, sizeof(EFI_IP_ADDRESS));
- VERB_PRT(1, Print(L"PXE PxeDiscoverValid: %s\n", pxe->Mode->PxeDiscoverValid? L"Yes (PXE-aware DHCPD)" : L"No (Regular DHCPD)"));
+ VERB_PRT(1, Print(L"PXE PxeDiscoverValid: %s\n", pxe->Mode->PxeDiscoverValid? L"Yes (PXE-aware DHCPD)\n" : L"No (Regular DHCPD)\n"));
#if 0
status = BS->HandleProtocol(dev, &PxeCallbackProtocol, (VOID **)&netfs_callback);
status = LibInstallProtocolInterfaces(&dev, &PxeCallbackProtocol, &netfs_callback, NULL);
netfs_fd_t *f;
EFI_STATUS status;
CHAR8 ascii_name[FILENAME_MAXLEN];
- UINTN blocksize = 0, prev_netbufsize;
+ UINTN blocksize = NETFS_DEFAULT_BLOCKSIZE;
+ UINTN prev_netbufsize, retries = 0;
+ BOOLEAN server_provided_filesize = FALSE;
if (this == NULL || name == NULL || fd == NULL) return EFI_INVALID_PARAMETER;
return EFI_SUCCESS;
}
f->netbuf_maxsize = NETFS_DEFAULT_BUFSIZE;
+ f->netbuf_size = 0;
if (f->netbuf == NULL && netbuf_alloc(f) == -1) {
netfs_fd_free(nfs, f);
U2ascii(name, ascii_name, FILENAME_MAXLEN);
- VERB_PRT(2, Print(L"downloading %a from %d.%d.%d.%d...", ascii_name,
+ 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]));
retry:
- f->netbuf_size = f->netbuf_maxsize;
-
- DBG_PRT((L"\nbefore netbuf:" PTR_FMT " netbuf_size=%d\n", f->netbuf, f->netbuf_size));
-
- /*
- * For EFI versions older than 14.61:
- * it seems like there is an EFI bug (or undocumented behavior) when the buffer size
- * is too small AND the blocksize parameter is NULL, i.e., used the largest possible.
- * In this case, Mtftp() never returns EFI_BUFFER_TOO_SMALL but EFI_TIMEOUT instead.
- * This is true for 1.02 and also 1.10 it seems. Here we set it to the minimal value (512).
- *
- * Also it seems like on a READ_FILE which returns EFI_BUFFER_TOO_SMALL, the buffersize
- * is NOT updated to reflect the required size for the next attempt.
- *
- * For EFI versions 14.61 and higher:
- * In case the buffer is too small AND the TFTP server reports the file size (see RFC 2349),
- * the f->netbuf_size will report the exact size for the buffer.
+ if (retries == 2) {
+ netfs_fd_free(nfs, f);
+ VERB_PRT(2, Print(L"Failed: %r\n", status));
+ return status;
+ }
+
+/*
+ * netboot bugfix SF tracker 2874380
+ * EFI 1.10 spec
+ * For read operations, the return data will be placed in the buffer specified by BufferPtr. If
+ * BufferSize is too small to contain the entire downloaded file, then
+ * EFI_BUFFER_TOO_SMALL will be returned and BufferSize will be set to zero or the size of
+ * the requested file (the size of the requested file is only returned if the TFTP server supports TFTP
+ * options). If BufferSize is large enough for the read operation, then BufferSize will be set to
+ * the size of the downloaded file, and EFI_SUCCESS will be returned. Applications using the
+ * PxeBc.Mtftp() services should use the get-file-size operations to determine the size of the
+ * downloaded file prior to using the read-file operations—especially when downloading large
+ * (greater than 64 MB) files—instead of making two calls to the read-file operation. Following this
+ * recommendation will save time if the file is larger than expected and the TFTP server does not
+ * support TFTP option extensions. Without TFTP option extension support, the client has to
+ * download the entire file, counting and discarding the received packets, to determine the file size.
+ * ...
+ * For TFTP “get file size” operations, the size of the requested file or directory is returned in
+ * BufferSize, and EFI_SUCCESS will be returned. If the TFTP server does not support options,
+ * the file will be downloaded into a bit bucket and the length of the downloaded file will be returned.
+ */
+ status = uefi_call_wrapper(nfs->pxe->Mtftp, 10,
+ nfs->pxe,
+ EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
+ f->netbuf,
+ FALSE,
+ &(f->netbuf_size), // PXE writes size of file from server here
+ &blocksize,
+ &nfs->srv_ip,
+ ascii_name,
+ NULL,
+ FALSE);
+ /*
+ * If options are not supported by this tftp server, according to the spec the file will be
+ * downloaded into a bit bucket, the size calculated by efi fw and returned in the status
+ * field of this call. YUK!!... in this case we will default to currently allocated max
+ * if thats still not big enough it will be caught and increased following the read file attempt
+ * then retried.
+ * XXX need to research how this is handled or changed in the latest UEFI spec.
*/
- prev_netbufsize = f->netbuf_size;
+ if (status != EFI_SUCCESS) {
+ f->netbuf_size = f->netbuf_maxsize;
+ VERB_PRT(2, Print(L"setting default buffer size of %d for %a, no filesize recd from tftp server\n",
+ f->netbuf_size, ascii_name));
+ }
- status = uefi_call_wrapper(nfs->pxe->Mtftp, 10, nfs->pxe, EFI_PXE_BASE_CODE_TFTP_READ_FILE, f->netbuf, FALSE,
- &(f->netbuf_size),
- blocksize > 0 ? &blocksize : NULL,
- &nfs->srv_ip,
- ascii_name,
- NULL,
- FALSE);
+ if (status == EFI_SUCCESS) {
+ server_provided_filesize = TRUE;
+ VERB_PRT(2, Print(L"received file size of %d for %a from tftp server.\n",
+ f->netbuf_size, ascii_name));
+ }
- DBG_PRT((L"after Mftp=%r netbuf:" PTR_FMT " netbuf_size=%d blocksize=%d\n",
+ if (f->netbuf_size > f->netbuf_maxsize) { // we need a bigger buffer
+ VERB_PRT(2, Print(L"allocated buffer too small, attempting to increase\n"));
+ f->netbuf_maxsize += f->netbuf_size;
+ free(f->netbuf);
+ f->netbuf = NULL;
+ if (netbuf_alloc(f) == -1) return EFI_OUT_OF_RESOURCES;
+ }
+
+ /* paranoid catch any corner case missed */
+ if (f->netbuf_size == 0) f->netbuf_size = f->netbuf_maxsize;
+
+ DBG_PRT((L"\nbefore read: netbuf:" PTR_FMT " netbuf_size=%d blocksize=%d\n",
+ f->netbuf,
+ f->netbuf_size,
+ blocksize));
+
+ prev_netbufsize = f->netbuf_size;
+
+ /* now try and download this file from the tftp server */
+ status = uefi_call_wrapper(nfs->pxe->Mtftp, 10,
+ nfs->pxe,
+ EFI_PXE_BASE_CODE_TFTP_READ_FILE,
+ f->netbuf,
+ FALSE,
+ &(f->netbuf_size),
+ &blocksize,
+ &nfs->srv_ip,
+ ascii_name,
+ NULL,
+ FALSE);
+
+ DBG_PRT((L"after: status=%r netbuf:" PTR_FMT " netbuf_size=%d blocksize=%d\n",
status,
f->netbuf,
f->netbuf_size,
blocksize));
- if (status == EFI_TIMEOUT && blocksize == 0) {
- /*
- * XXX: if blocksize is not adjusted we could loop forever here
- */
- //blocksize = 512;
- status = EFI_BUFFER_TOO_SMALL;
- }
- /*
- * check if we need to increase our buffer size
- */
- if (status == EFI_BUFFER_TOO_SMALL) {
- DBG_PRT((L"buffer too small, need netbuf_size=%d", f->netbuf_size));
+ if ((status == EFI_TIMEOUT || status == EFI_BUFFER_TOO_SMALL) && !server_provided_filesize) {
+ Print(L"buffer too small, need netbuf_size=%d\n", f->netbuf_size);
/*
* if the TFTP server supports TFTP options, then we should
* get the required size. So we test to see if the size
} else {
/* we got an answer from the TFTP server, let's try it */
f->netbuf_maxsize = f->netbuf_size;
+ server_provided_filesize = TRUE;
}
free(f->netbuf);
f->netbuf = NULL; /* will force reallocation */
- if (netbuf_alloc(f) == 0) goto retry;
+ if (netbuf_alloc(f) == 0) {
+ retries++;
+ goto retry;
+ }
- /* fall through in case of error */
+ } else if (status == EFI_TIMEOUT) { //if just a simple timeout, buffers are good just retry
+ VERB_PRT(2, Print(L"TFTP returned EFI_TIMEOUT ERROR... %d retries left.\n", (2 - retries)));
+ retries++;
+ goto retry;
}
-
if (status == EFI_SUCCESS) {
/* start at the beginning of the file */
f->netbuf_pos = 0;
# 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"-ia64.conf\0"
+# 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
StrnCpy(config[0].fname+8, CONFIG_EXTENSION, 6);
StrnCpy(config[1].fname, str, maxlen-1);
- StrnCpy(config[1].fname+6, CONFIG_ARCH_EXTENSION, 11);
+ StrnCpy(config[1].fname+6, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH);
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, 11);
+ StrnCpy(config[3].fname+4, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH);
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, 11);
+ StrnCpy(config[5].fname+2, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH);
StrnCpy(config[6].fname, str, maxlen-1);
StrnCpy(config[6].fname+2, CONFIG_EXTENSION, 6);
+++ /dev/null
-/Makefile/1.2/Tue Feb 17 23:42:40 2004//
-/bin_to_h.c/1.1.1.1/Wed Feb 20 01:07:55 2002//
-/config.c/1.1.1.1/Tue Aug 19 16:45:43 2003//
-/gzip_loader.c/1.2/Thu Dec 1 21:42:59 2005//
-/private.h/1.1.1.1/Tue Aug 19 16:45:55 2003//
-/rmswitch.S/1.1.1.1/Wed Feb 20 01:07:55 2002//
-/bzimage.c/1.2/Thu Apr 2 19:49:29 2009//
-/gzip.c/1.4/Thu Apr 2 19:49:29 2009//
-/plain_loader.c/1.2/Thu Apr 2 19:49:29 2009//
-/sysdeps.h/1.4/Thu Apr 2 19:49:29 2009//
-/system.c/1.8/Thu Apr 2 19:49:29 2009//
-D
+++ /dev/null
-elilo/ia32
+++ /dev/null
-fleischli@elilo.cvs.sourceforge.net:/cvsroot/elilo
boot_params_t *param_start = NULL;
UINTN param_size = 0;
-UINTN kernel_size = 0x200000; /* 2M (largest x86 bzImage kernel image) */
+UINTN kernel_size = 0x400000; /* 4M (default x86 bzImage size limit) */
static INTN
bzImage_probe(CHAR16 *kname)
if (EFI_ERROR(status)) {
error("elilo: Read failed");
}
+#ifdef DEBUG_GZIP
DBG_PRT((L"%s : read %d bytes of %d bytes\n", LD_NAME, nread, expected));
+#endif
insize = nread;
inptr = 1;
long cnt;
if (!outcnt) return;
-
+#ifdef DEBUG_GZIP
DBG_PRT((L"%s : flush_window outnct=%d file_offset=%d\n", LD_NAME, outcnt, file_offset));
+#endif
Print(L"%c\b",helicopter[heli_count++%4]);
+++ /dev/null
-/Makefile/1.1.1.1/Tue Aug 19 16:46:53 2003//
-/config.c/1.1.1.1/Tue Aug 19 16:46:58 2003//
-/gzip_loader.c/1.2/Thu Dec 1 21:42:59 2005//
-/memcpy.S/1.1.1.1/Tue Aug 19 16:46:20 2003//
-/memset.S/1.1.1.1/Tue Aug 19 16:46:13 2003//
-/private.h/1.2/Fri Sep 16 16:25:52 2005//
-/setjmp.h/1.1.1.1/Wed Aug 1 08:45:17 2001//
-/system.c/1.4/Thu Dec 1 21:42:59 2005//
-/fpswa.c/1.2/Tue Feb 12 22:16:51 2008//
-/gzip.c/1.5/Tue Feb 12 22:16:51 2008//
-/longjmp.S/1.2/Tue Feb 12 22:16:51 2008//
-/plain_loader.c/1.4/Tue Feb 12 22:16:51 2008//
-/setjmp.S/1.4/Tue Feb 12 22:16:51 2008//
-/sysdeps.h/1.3/Tue Feb 12 22:16:51 2008//
-D
+++ /dev/null
-elilo/ia64
+++ /dev/null
-fleischli@elilo.cvs.sourceforge.net:/cvsroot/elilo
if (EFI_ERROR(status)) {
error("elilo: Read failed");
}
+#ifdef DEBUG_GZIP
DBG_PRT((L"%s : read %d bytes of %d bytes\n", LD_NAME, nread, expected));
+#endif
insize = nread;
inptr = 1;
long cnt;
if (!outcnt) return;
-
+#ifdef DEBUG_GZIP
DBG_PRT((L"%s : flush_window outnct=%d file_offset=%ld\n", LD_NAME, outcnt, file_offset));
+#endif
Print(L"%c\b",helicopter[heli_count++%4]);
if (get_memmap(&mdesc) == -1) return -1;
- DBG_PRT((L"Got memory map @ 0x%lx (%d bytes)", mdesc.md, mdesc.map_size));
+ DBG_PRT((L"Got memory map @ 0x%lx (%d bytes) with key %d", mdesc.md, mdesc.map_size, mdesc.cookie));
bp->efi_systab = (UINTN)systab;
bp->efi_memmap = (UINTN)mdesc.md;
/* Cache line length is at least 32. */
UINT64 a = (UINT64)addr & ~0x1f;
- VERB_PRT(3, Print(L"Flush 0x%lx-", a));
+ DBG_PRT((L"Flush 0x%lx-", a));
/* Flush data. */
for (len = (len + 31) & ~0x1f; len > 0; len -= 0x20, a += 0x20)
/* Sync and serialize. Maybe extra. */
asm volatile (";; sync.i;; srlz.i;;");
- VERB_PRT(3, Print(L"0x%lx\n", a));
+ DBG_PRT((L"0x%lx\n", a));
}
+++ /dev/null
-/Makefile/1.1.1.1/Tue Aug 19 16:47:54 2003//
-/eliloalt.c/1.1.1.1/Tue Aug 19 16:47:59 2003//
-D
+++ /dev/null
-elilo/tools
+++ /dev/null
-fleischli@elilo.cvs.sourceforge.net:/cvsroot/elilo
+++ /dev/null
-elilo/x86_64/CVS
+++ /dev/null
-fleischli@elilo.cvs.sourceforge.net:/cvsroot/elilo
+++ /dev/null
-D/CVS////
-/Makefile/1.1/Fri Jul 20 19:10:01 2007//
-/bin_to_h.c/1.1/Fri Jul 20 19:10:01 2007//
-/config.c/1.1/Fri Jul 20 19:10:01 2007//
-/gzip.h/1.1/Fri Jul 20 19:10:01 2007//
-/gzip_loader.c/1.1/Fri Jul 20 19:10:01 2007//
-/inflate.c/1.1/Fri Jul 20 19:10:01 2007//
-/private.h/1.1/Fri Jul 20 19:10:01 2007//
-/rmswitch.S/1.1/Fri Jul 20 19:10:01 2007//
-/gzip.c/1.2/Tue Feb 12 22:16:51 2008//
-/bzimage.c/1.2/Thu Apr 2 19:49:29 2009//
-/plain_loader.c/1.2/Thu Apr 2 19:49:29 2009//
-/sysdeps.h/1.4/Thu Apr 2 19:49:29 2009//
-/system.c/1.5/Thu Apr 2 19:49:29 2009//
+++ /dev/null
-elilo/x86_64
+++ /dev/null
-fleischli@elilo.cvs.sourceforge.net:/cvsroot/elilo
boot_params_t *param_start = NULL;
UINTN param_size = 0;
-UINTN kernel_size = 0x400000; /* 4M (largest x86 bzImage kernel image) */
+UINTN kernel_size = 0x800000; /* 8M (default x86_64 bzImage size limit) */
static INTN
bzImage_probe(CHAR16 *kname)
if (EFI_ERROR(status)) {
error("elilo: Read failed");
}
+#ifdef DEBUG_GZIP
DBG_PRT((L"%s : read %d bytes of %d bytes\n", LD_NAME, nread, expected));
+#endif
insize = nread;
inptr = 1;
long cnt;
if (!outcnt) return;
-
+#ifdef DEBUG_GZIP
DBG_PRT((L"%s : flush_window outnct=%d file_offset=%ld\n", LD_NAME, outcnt, file_offset));
+#endif
Print(L"%c\b",helicopter[heli_count++%4]);