--- /dev/null
+2003-08-20 Stephane Eranian <eranian@hpl.hp.com>
+ * released 3.4
+2003-08-19 Stephane Eranian <eranian@hpl.hp.com>
+ * integrated ia32 updates from Matt
+ Tolentino <matthew.e.tolentino@intel.com>
+2003-08-13 Stephane Eranian <eranian@hpl.hp.com>
+ * updated elilo.txt and netbooting.txt
+ * fix a bug in choosers/simple.c:print_infos().
+ it needs to check if config file path is absolute
+ when printing filename.
+ * move definitions of CHAR_SLASH CHAR_BACKSLASH to elilo.h
+ * fix a bug in read_config() where it would try other
+ filename even when the user explicitely specified one
+ via -C, now it fails it that file cannot be opened.
+ * updated simple chooser set of builtin command keys
+ * command keys are only valid if first on the line
+ * increase default buffer size and increment when netbooting
+2003-06-04 Stephane Eranian <eranian@hpl.hp.com>
+ * fix fs/netfs.c to work with recent version
+ of EFI (14.61 or higher) which do not have the
+ TFTP problem anymore. fix submitted by Guy Laborde
+2003-04-21 Stephane Eranian <eranian@hpl.hp.com>
+ * ext2fs support is turned off by default to avoid
+ problems with ext3-formatted partitions.
+ * added gcc version check. MUST use 3.0 or higher
+2003-03-03 Stephane Eranian <eranian@hpl.hp.com>
+ * added check on dev_tab in fs/*fs.c:*_uninstall()
+2003-02-07 Stephane Eranian <eranian@hpl.hp.com>
+ * clean up in glue_localfs.c w.r.t. CHAR16 in set_default_path()
+ * added support for extracting basename of bootloader path
+ when using BOOTP (DHCP) only. The prefix is then used for all files
+ open via netfs. Suggestion and initial patch by Guy Laborde from HP.
+2003-01-28 Stephane Eranian <eranian@hpl.hp.com>
+ * fix the set_default_path() routine in glue_localfs.c. It would not
+ correctly get the basename of the devpath. This caused the
+ elilo.conf not to be found sometimes.
+2003-01-21 Stephane Eranian <eranian@hpl.hp.com>
+ * fix bug in glue_netfs.c convert_ip2decstr() which caused some IP
+ addresses to be incorrectly converted to strings.
+2002-11-01 Stephane Eranian <eranian@hpl.hp.com>
+ * fix bug in -r option for IA64. There is no argument to this option.
+2002-10-15 Stephane Eranian <eranian@hpl.hp.com>
+ * fixed a double free bug for the kernel memory in case of abort.
+ (bug spotted by Levent Akyl from Intel)
+ * released 3.3a
+2002-09-14 Stephane Eranian <eranian@hpl.hp.com>
+ * applied patch from Andreas Schwab <schwab@suse.de> to eliloalt.c.
+ eliloalt dynamically selects a variable in /proc/efi/vars.
+2002-09-12 Stephane Eranian <eranian@hpl.hp.com>
+ * removed extra free() from fs/ext2fs.c:ext2fs_init_state().
+ Bug report and fix by NOMURA Jun'ichi <j-nomura@ce.jp.nec.com>
+ * rewrote fs/ext2fs.c:read_bytes() to large memory stack buffer which
+ was bigger than the 128KB limit of EFI causing some weird fimrware
+ errors. bug reported by OMURA Jun'ichi <j-nomura@ce.jp.nec.com>
+ * on IA-64 forbid the use of f32-f127 by the compiler (EFI spec)
+2002-09-10 Stephane Eranian <eranian@hpl.hp.com>
+ * fix a bug in argify() that was causing an EFI assertion
+ when aborting at the elilo prompt when netbooted.
+2002-08-26 Stephane Eranian <eranian@hpl.hp.com>
+ * fixed devschemes/simple.c to use SPrint() instead of its own buggy
+ conversion code (spotted by Richard Hirst).
+ * fix bug in argify() when there was no NULL character in the string.
+ * released 3.3
+2002-08-19 Stephane Eranian <eranian@hpl.hp.com>
+ * added fpswa.txt in the docs directory
+ * updated elilo.txt
+2002-08-15 Stephane Eranian <eranian@hpl.hp.com>
+ * added -F file option for IA-64 to allow a specific fpswa driver to be loaded
+ * fixed fpswa.c to try and load the driver from all accessible partitions
+ * added support to load (plain or gzipped) big-endian ELF/ia64 binaries using p_paddr.
+ * fixed problem in fs/netfs.c causing large (>4MB) binaries to fail the Mftp() call
+2002-06-13 Stephane Eranian <eranian@hpl.hp.com>
+ * Changed the despecialization character for the variables from \\ to &
+ to avoid conflicts with \\ as a path separator
+2002-06-11 Stephane Eranian <eranian@hpl.hp.com>
+ * fixed the return value in efi_main(). elilo was always returning
+ success even in case of failure. Bug reported by Egan Ford <egan@sense.net>
+ * applied patch from Richard Hirst <rhirst@linuxcare.com> to fix an
+ initialization bug in choosers/textmenu.c
+ * applied patch from Richard Hirst <rhirst@linuxcare.com> to make elilo
+ compliant with EFI spec with regards to where it looks for files.
+ With this patch, elilo will look in the directory it was loaded
+ from, not on the root of the partition anymore.
+2002-03-04 Stephane Eranian <eranian@hpl.hp.com>
+ * released version 3.2
+ * cleanup some GNU extension in fs/ext2fs.c (variable size array)
+ * updated all documentation. Added netbooting.txt, simple_chooser.txt,
+ eliloalt.txt, elilovar.txt
+2002-02-21 Stephane Eranian <eranian@hpl.hp.com>
+ * added a Linux utility program (elilovar in tools) to set/read/delete
+ the EliloAlt EFI variable used to specify an alternate kernel to boot.
+ * rename DBG_PRINT() to DBG_PRT, PRINT_ERR() to ERR_PRT()
+ * added support for hostname,domain name extraction in fs/netfs.c
+ * fixed all known bugs in alternate.c
+ * integrated patch from SGI to fix load offset for relocatable kernels (Jack Steiner, Brent Casavant)
+2002-02-21 Michael Johnston <michael.johnston@intel.com> and Chris Ahna <christopher.j.ahna@intel.com>
+ * major update to ia32 support: can now boot 2.4.x, and 2.2.x kernels
+2002-02-20 Stephane Eranian <eranian@hpl.hp.com>
+ * fixed missing netfs_fd_free() in case of file not found in netfs.c
+2002-02-19 Stephane Eranian <eranian@hpl.hp.com>
+ * added support for substitution variables (vars.c)
+ * changed the bootparam structure size back to 4kB
+ * added support to simple to print final command line option with tab key
+ * got rid of all the \r characters in strings use only \n (adjust emulator)
+ * added EFICRT0 variable in Makefile to indicate location of loader script+crt0
+2002-02-14 Stephane Eranian <eranian@hpl.hp.com>
+ * added support for message= option to simple chooser
+ * added support for description= option to simple chooser
+2002-02-13 Stephane Eranian <eranian@hpl.hp.com>
+ * choosers/textmenu.c: new textmenu chooser (by rhirst@linuxcare.com) used by Debian
+ * config.c: added support for dynamic global/per-image option management
+ * ia64/plain_loader.c,ia64/gzip.c: fix load_offset (<bcasavan@sgi.com>)
+ * added cmd line (-E) and config option (noedd30) to not set EDD30 EFI variable to
+ true if not already TRUE (request by Matt_Domsch@dell.com)
+ * added support for multiple devname schemes and probing
+
+2002-01-31 Stephane Eranian <eranian@hpl.hp.com>
+ * cleaned up alternate.c
+ * added support for ctrl-U (clear line) in chooser/simple.c
+
+2002-01-25 Stephane Eranian <eranian@hpl.hp.com>
+ * added support for architecture specific config file (elilo-ia64.conf, elilo-ia32.conf).
+
+2002-01-13 Stephane Eranian <eranian@hpl.hp.com>
+ * removed call to Reset() in ext2fs.c
+
+2001-08-17 Stephane Eranian <eranian@hpl.hp.com>
+ * released 3.1
+ * added support for command line architecture specific options:
+ sysdeps_get_cmdline_opts(), sysdeps_print_cmdline_opts(),
+ syspdeps_getopt()
+ * added IA-64 command line option (-r) for relocation
+ * fix behavior when kernel specified on command line but prompt
+ mode was specified in config file. In this case, we now autoboot
+ and ignore the prompt directive.
+ * updated elilo.txt
+2001-08-15 Brent Casavant <bcasavan@sgi.com>
+ * fix a bug in config.c:find_option() where it would do
+ a strXcmp() on a NULL string.
+
+2001-08-01 Stephane Eranian <eranian@hpl.hp.com>
+ * fixed bug in fs/netfs.c where it would not handle the small buffer
+ error correctly. The retry path was not allocating a bigger buffer.
+ * Global config options are now used if the user specifies a non-label
+ load target, i.e. a kernel image file.
+ * added support for architecture dependent config file image options (sys_img_options_t).
+ * added support for setjmp/longjmp.
+ * added support for aborting during a compressed load
+ * added support for user to abort a load of a compressed file.
+ * added 2 new ia-64 only config file options allowing kernel relocation:
+ 'relocatable' as a global or per image option.
+ * added support for kernel relocation on memory error. Based on code from
+ Brent Casavant <bcasavan@sgi.com>.
+ * added slash/backslash conversion for filenames on vfat filesystems.
+
+2001-07-23 Stephane Eranian <eranian@hpl.hp.com>
+ * fixed error in netfs.c where the kernel name was not correctly set in
+ netfs_query_layer()
+ * fixed to wait_timeout() to correct the problem with the interactive prompt when
+ return is hit directly when no text
+ * fixed command line argument destruction problem, now we make a copy of them. This
+ was affecting elilo when called directly from bootmanager with NVRAM options.
+
+2001-06-28 Stephane Eranian <eranian@hpl.hp.com>
+ * removed W2U() hack to get from wide-char to unicode. Use -fshort-wchar option instead.
+ * split gnu-efi package in two different packages: the libary+include+crt and the bootloader.
+ * restructured the fileops module. Now use direct function calls.
+ * added support for accessing files on different devices.
+ * fixed a buffer leak in simple_chooser.c. Renamed simple_chooser.c to simple.c.
+ * created a strops.c file to incorporate all string operations functions.
+ * added support for ext2fs filesystem.
+ * restructured code to allow additional filesystems to be added easily.
+ * cleaned up add-on chooser interface.
+ * restructured code to use the EFI protocol interface to install filesystems.
+ * added compile-time options to turn on and off specific filesystems.
+ * added support for architecture specific configuration options (elilo.conf).
+ * added fpswa option to IA-64 to designate a fpswa driver file.
+ * incoporated IA-32 support from Mike Johnston <michael.johnston@intel.com>
+ * incorporated rewritten gzip.c:flush_window() from Tony Luck <tony.luck@intel.com>
+ * added interface for custom device naming schemes (devnames directory).
+ * added support for 2 possible config file (now just on netboot). The first
+ (primary) choice uses a host specific filename based on the IP address. Suggestion
+ from Egan Ford <egan@sense.net>.
+
+2001-04-06 Stephane Eranian <eranian@hpl.hp.com>
+
+ * incorporated patches from David and Michael Johnston at Intel
+ to get the package to compile for IA-32 linux target.
+
+ * Fixed ELILO to compile for Ia-32 (does not execute yet, though):
+ Makefile and start_kernel() function.
+
+2001-04-06 Andreas Schwab <schwab@suse.de>
+
+ * Fixed config.c to
+ get the timeout directive to do something. implemented the global
+ root= directive.
+
+ * Fix the efi_main() to deal with the -C option properly
+
+2001-04-05 Stephane Eranian <eranian@hpl.hp.com>
+
+ * update efi library to latest EFI toolkit 1.02 as distributed
+ by Intel. Fixed header + library files to compile with GCC
+
+ * merged ELI and LILO (as of gnu-efi-1.1) together, mostly
+ taking the config file feature of ELI.
+
+ * renamed LILO to ELILO to make the distinction
+
+ * restructured code to make it easier to understand and maintain
+
+ * fixed FPSWA driver checking and loading: we try all possible
+ files and let the driver itself figure out if it is the most
+ recent.
+ * added support for compression (gzip) but keep support for plain
+ ELF image. ELILO autodetects the format
+
+ * change the way the kernel is invoked. Now we call it in
+ physical memory mode. This breaks the dependency between the
+ kernel code and the loader. No more lilo_start.c madness.
+
+ * changed the way the boot_params are passed. We don't use the
+ ZERO_PAGE_ADDR trick anymore. Instead we use EFI runtime memory.
+ The address of the structure is passed to the kernel in r28
+ by our convention.
+
+ * released as gnu-efi-2.0
+
+2001-04-03 David Mosberger <davidm@hpl.hp.com>
+
+ * gnuefi/reloc_ia32.c (_relocate): Change return type from "void"
+ to "int". Return error status if relocation fails for some
+ reason.
+
+ * gnuefi/elf_ia32_efi.lds: Drop unneeded ".rel.reloc" section.
+
+ * gnuefi/crt0-efi-ia32.S (_start): Exit if _relocate() returns with
+ non-zero exit status.
+
+ * inc/ia32/efibind.h [__GNUC__]: Force 8-byte alignment for 64-bit
+ types as that is what EFI appears to be expecting, despite the
+ "#pragma pack()" at the beginning of the file!
+
+2001-03-29 David Mosberger <davidm@hpl.hp.com>
+
+ * gnuefi/reloc_ia32.c: Add a couple of defines to work around
+ libc/efilib collision on uint64_t et al.
+ (_relocate): Use ELF32_R_TYPE() instead of ELFW(R_TYPE)().
+
+ * gnuefi/crt0-efi-ia32.S (dummy): Add a dummy relocation entry.
+
+2001-03-29 David Mosberger <davidm@hpl.hp.com>
+
+ * gnuefi/reloc_ia32.c: Add a couple of defines to work around
+ libc/efilib collision on uint64_t et al.
+ (_relocate): Use ELF32_R_TYPE() instead of ELFW(R_TYPE)().
+
+ * gnuefi/crt0-efi-ia32.S (dummy): Add a dummy relocation entry.
+
+2000-10-26 David Mosberger <davidm@hpl.hp.com>
+
+ * gnuefi/elf_ia64_efi.lds: Mention .rela.sdata.
+
+ * Make.defaults (CFLAGS): Remove -nostdinc flags so we can pick
+ up the C compiler's stdarg.h.
+
+ * inc/stdarg.h: Remove this file. It's not correct for gcc (nor
+ most other optimizing compilers).
+
+2000-10-10 Stephane Eranian <eranian@hpl.hp.com>
+
+ * cleaned up the error message and printing of those.
+ * added support to load the FPSWA from a file in case support is not
+ present in the firmware already
+ * fixed split_args() to do the right thing when you have leading spaces
+ before kernel name
+ * changed the argify() function to rely on \0 instead of LoadOptionSize
+ as the field seems to be broken with current firmware
+ * bumped version to 1.0
+
+2000-10-04 David Mosberger <davidm@hpl.hp.com>
+
+ * gnuefi/reloc_ia64.S: Reserve space for up to 750 function descriptors.
+
+ * gnuefi/elf_ia64_efi.lds: Add .sdata section for small data and
+ put __gp in the "middle" of it.
+
+ * gnuefi/crt0-efi-ia64.S (_start): Use movl/add to load
+ gp-relative addresses that could be out of the range of the addl
+ offset.
+ * gnuefi/reloc_ia64.S (_relocate): Ditto.
+
+ * apps/Makefile: Remove standard rules and include Make.rules instead.
+ * lilo/Makefile: Ditto.
+
+ * Make.rules: New file.
+
+2000-08-04 Stephane Eranian <eranian@hpl.hp.com>
+ * released version 0.9
+ * incorporated ACPI changes for Asuza by NEC < kouchi@hpc.bs1.fc.nec.co.jp>
+ * added support for initrd (-i option) original ELI code from Bill Nottingham <notting@redhat.com>)
+ * lots of cleanups
+ * got rid of #ifdef LILO_DEBUG and uses macro instead
+ * fix a few extra memory leaks in create_boot_params()
+ * added exit capability just before starting the kernel
+
+2000-06-22 David Mosberger <davidm@hpl.hp.com>
+
+ * gnuefi/elf_ia64_efi.lds: Add .srodata, .ctors, .IA64.unwind,
+ .IA64.unwind_info to .data section and .rela.ctors to .rela
+ section.
+
+2000-04-03 David Mosberger <davidm@hpl.hp.com>
+
+ * lilo/lilo.c (LILO_VERSION): Up version number to 0.9.
+
+ * gnuefi/elf_ia64_efi.lds: Include .IA_64.unwind and
+ .IA_64.unwind_info in .data segment to avoid EFI load error
+ "ImageAddress: pointer outside of image" error due to the .dynsym
+ relocations against these sections.
+
+ * ChangeLog: Moved from lilo/ChangeLogs.
+
+ * gnuefi/reloc_ia64.S: fixed typo: .space directive had constant
+ 100 hardcoded instead of using MAX_FUNCTION_DESCRIPTORS
+ macro. Duh.
+
+Fri Mar 17 15:19:18 PST 2000 Stephane Eranian <eranian@hpl.hp.com>
+
+ * Released 0.8
+ * replace the getopt.c with new version free with better license
+ * created a documentation file
+ * fix a couple of memory leaks
+ * code cleanups
+ * created a separate directory for lilo in the gnu-efi package.
+ * added support for the BOOT_IMAGE argument to kernel
+ * default is to build natively now
--- /dev/null
+
+See the TODO file, for more on the known limitations of this version of elilo.
+
--- /dev/null
+#
+# Copyright (C) 2001-2003 Hewlett-Packard Co.
+# Contributed by Stephane Eranian <eranian@hpl.hp.com>
+#
+# This file is part of ELILO, the LINUX EFI 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.
+#
+
+#
+# File system selection. At least one filesystem must be enabled
+#
+CONFIG_localfs=y
+CONFIG_netfs=y
+
+#
+# WARNING WARNING WARNING
+#
+# Use this option with caution. This filesystem module does not
+# support ext3 formatted partitions, i.e., it does not know how
+# to recover from failures (ignores the log).
+#
+CONFIG_ext2fs=n
+
+#
+# Chooser selection(at least one must be defined)
+#
+CONFIG_chooser_simple=y
+CONFIG_chooser_textmenu=y
+
+#
+# Enable IP-address based config file (elilo.conf) when netbooted
+#
+CONFIG_machspec_netconfig=y
+
+#
+# Indicate where the EFI include and libaries are.
+# They are installed as part of the GNU-EFI package installation
+#
+EFIINC = /usr/include/efi
+GNUEFILIB = /usr/lib
+EFILIB = /usr/lib
+EFICRT0 = /usr/lib
+
+CDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
+TOPDIR =
+
+ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,)
+INCDIR = -I. -I$(TOPDIR) -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol
+CPPFLAGS = -DCONFIG_$(ARCH)
+
+OPTIMFLAGS = -O2
+DEBUGFLAGS = -Wall
+CFLAGS = $(OPTIMFLAGS) -fpic -fshort-wchar $(DEBUGFLAGS)
+LDFLAGS = -nostdlib
+INSTALL = install
+
+ifeq ($(CONFIG_machspec_netconfig),y)
+CFLAGS += -DENABLE_MACHINE_SPECIFIC_NETCONFIG
+endif
+
+ifeq ($(CONFIG_localfs),y)
+CFLAGS += -DCONFIG_LOCALFS
+endif
+
+ifeq ($(CONFIG_netfs),y)
+CFLAGS += -DCONFIG_NETFS
+endif
+
+ifeq ($(CONFIG_ext2fs),y)
+CFLAGS += -DCONFIG_EXT2FS
+endif
+
+ifeq ($(CONFIG_chooser_simple),y)
+CFLAGS += -DCONFIG_CHOOSER_SIMPLE
+endif
+
+ifeq ($(CONFIG_chooser_textmenu),y)
+CFLAGS += -DCONFIG_CHOOSER_TEXTMENU
+endif
+
+ifeq ($(ARCH),ia64)
+ prefix =
+ prefix = /opt/gcc3.1/bin/
+ CC = $(prefix)gcc
+ AS = $(prefix)as
+ LD = $(prefix)ld
+ LD = ld
+ AR = $(prefix)ar
+ RANLIB = $(prefix)ranlib
+ OBJCOPY = $(prefix)objcopy
+
+GCC_VERSION=$(shell $(CROSS_COMPILE)$(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.')
+
+ifneq ($(GCC_VERSION),2)
+ CFLAGS += -frename-registers
+endif
+#
+# EFI specs allows only lower floating point partition to be used
+#
+# Redhat 8.0 gcc-3.x version is reported to produce working EFI binaries.
+# Redhat 9.0 gcc-3.x version is reported to produce BAD binaries.
+#
+CFLAGS += -mfixed-range=f32-f127
+else
+ ifeq ($(ARCH),ia32)
+ prefix =
+ CC = $(prefix)gcc3
+ AS = $(prefix)as
+ LD = $(prefix)ld
+ AR = $(prefix)ar
+ RANLIB = $(prefix)ranlib
+ OBJCOPY = $(prefix)objcopy
+ endif
+endif
--- /dev/null
+#
+# Copyright (C) 2001-2003 Hewlett-Packard Co.
+# Contributed by Stephane Eranian <eranian@hpl.hp.com>
+#
+# This file is part of ELILO, the LINUX EFI 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.
+#
+
+%.efi: %.so
+ $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \
+ -j .rela -j .reloc --target=$(FORMAT) $*.so $@
+
+%.so: %.o
+ $(LD) $(LDFLAGS) $^ -o $@ $(LOADLIBES)
+
+%.o: %.c
+ $(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
+
--- /dev/null
+#
+# Copyright (C) 2001-2003 Hewlett-Packard Co.
+# Contributed by Stephane Eranian <eranian@hpl.hp.com>
+#
+# This file is part of ELILO, the LINUX EFI 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 Make.defaults
+TOPDIR=.
+
+
+CRTOBJS = $(EFICRT0)/crt0-efi-$(ARCH).o
+LDSCRIPT = $(EFICRT0)/elf_$(ARCH)_efi.lds
+
+LDFLAGS += -T $(LDSCRIPT) -shared -Bsymbolic -L$(EFILIB) -L$(GNUEFILIB) $(CRTOBJS)
+LOADLIBES = -lefi -lgnuefi $(shell $(CC) -print-libgcc-file-name)
+FORMAT = efi-app-$(ARCH)
+
+FILESYSTEM =
+
+ifeq ($(CONFIG_localfs),y)
+FILESYSTEMS += glue_localfs.o
+endif
+
+ifeq ($(CONFIG_ext2fs),y)
+FILESYSTEMS += glue_ext2fs.o
+endif
+
+ifeq ($(CONFIG_netfs),y)
+FILESYSTEMS += glue_netfs.o
+endif
+
+SUBDIRS = fs choosers devschemes tools
+
+ifeq ($(ARCH),ia64)
+SUBDIRS += ia64
+endif
+
+ifeq ($(ARCH),ia32)
+SUBDIRS += ia32
+endif
+
+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 \
+ fs/fs.o \
+ choosers/choosers.o \
+ devschemes/devschemes.o \
+ $(ARCH)/sysdeps.o \
+ $(FILESYSTEMS)
+
+TARGETS = elilo.efi
+
+all: check_gcc $(SUBDIRS) $(TARGETS)
+
+elilo.efi: elilo.so
+
+elilo.so: $(FILES)
+
+elilo.o : elilo.c
+
+fileops.o : Make.defaults
+chooser.o : Make.defaults
+
+$(SUBDIRS): dummy
+ $(MAKE) -C $@
+
+dummy:
+
+clean:
+ @set -e ; for d in $(SUBDIRS) ; do $(MAKE) -C $$d $@ ; done
+ rm -f $(TARGETS) *~ *.so $(FILES)
+
+.PRECIOUS: elilo.so
+
+#
+# on both platforms you must use gcc 3.0 or higher
+#
+check_gcc:
+ifeq ($(GCC_VERSION),2)
+ @echo "you need to use a version of gcc >= 3.0, you are using `$(CC) --version`"
+ @exit 1
+endif
+
+include Make.rules
--- /dev/null
+ ELILO: the IA-32 and IA-64 Linux Loader
+ ---------------------------------------
+ Stephane Eranian <eranian@hpl.hp.com>
+
+ August 2003
+
+ Copyright (C) 2000-2003 Hewlett-Packard Co.
+
+
+This package contains version 3.4 of elilo, the EFI boot loader
+for IA-64(IPF) and IA-32(x86) EFI-based platforms.
+
+
+RELEASE NOTES:
+--------------
+ Take a look at the Changelog for a detailed list of changes
+ since 3.3a.
+
+ - The major new feature of this release pertains to netbooting.
+ With elilo-3.4, the bootloader will look for files ONLY in the
+ directory if was downloaded from on the TFTP server. Of course,
+ if you specific absolute path, files can be placed anywhere in
+ the TFTP directory structure. This may break some setup but
+ an explicit error message is printed warning the user.
+
+ - There were a bunch of important bug fixes, including handling
+ of paths when booting from the local disk.
+
+ - Downloading of large files work with EFI versions prior to 14.60
+ where there was a bug but also with the fixed version of EFI
+ starting at 14.60.
+
+ - There were also some updates for elilo on IA-32. The loader
+ can load unmodified Linux kernel/initrd image from either the
+ local disk or via netbooting. Thanks to Matt Tolentino at Intel
+ for the IA-32 updates.
+
+ - The ext2fs support code is still present but is not compiled in
+ anymore. This code does not understand ext3fs and might lead to
+ errors because it does not understand the journal.
+
+ This package is known to compile and produce working binaries
+ when used in conjunction with gnu-efi-3.0a. This package is
+ available from the HP Labs FTP site:
+
+ ftp://ftp.hpl.hp.com/pub/linux-ia64/gnu-efi-3.0a.tar.gz
+
+ For IA-64, a toolchain know to produce working binaries is:
+ gcc-3.1
+ binutiuls 2.13.90
+
+ Your may have problems with newer toolchains due to some
+ dependencies in the gnu-efi package. Those dependencies
+ will be fixed eventually.
+
+ For IA-32, the Redhat 8.0 toolchain is known to produce
+ working binaries when used with gnu-efi-3.0a + loader
+ script patch which is included in the gnu-efi-3.0a-ia32.patch
+ in this package. The toolchain includes:
+
+ gcc: gcc version 3.2 20020903 (Red Hat Linux 8.0 3.2-7)
+ as : GNU assembler version 2.13.90.0.2 (i386-redhat-linux)
+ using BFD version 2.13.90.0.2 20020802
+ ld : GNU ld version 2.13.90.0.2 20020802
+
+ The Redhat 9.0 toolchain does not work at the moment.
+
+DOCUMENTATION:
+--------------
+ PLEASE READ THE docs/elilo.txt file for some documentation on how
+ to use this program. For netbooting refer to docs/netbooting.txt.
+
+ Make sure you read the README.gnu-efi file for required packages.
+
--- /dev/null
+
+ IMPORTANT Information related to the gnu-efi package
+ ----------------------------------------------------
+ August 2003
+
+As of version elilo-3.0, the gnu-efi package is now split in two different packages:
+
+ -> gnu-efi-X.y: contains the EFI library, header, files, and crt0.
+
+ -> elilo-X.y : contains the ELILO bootloader.
+
+Note that X.y don't need to match for both packages. However elilo-3.x requires at
+least gnu-efi >= 3.0. When using a version of gcc >3.0 you MUST use at least gnu-efi-3.0a.
+
+IMPORTANT NOTE FOR IA-32:
+-------------------------
+ For IA-32, the Redhat 8.0 toolchain is known to produce
+ working binaries when used with gnu-efi-3.0a + loader
+ script patch which is included in the gnu-efi-3.0a-ia32.patch
+ in this package. The toolchain includes:
+
+ gcc: gcc version 3.2 20020903 (Red Hat Linux 8.0 3.2-7)
+ as: GNU assembler version 2.13.90.0.2 (i386-redhat-linux) using BFD version
+ 2.13.90.0.2 20020802
+ ld: GNU ld version 2.13.90.0.2 20020802
+
+ The Redhat 9.0 toolchain does not work at the moment.
+
+The gnu-efi package can be downloaded from:
+
+ ftp://ftp.hpl.hp.com/pub/linux-ia64/gnu-efi-X.y.tar.gz
--- /dev/null
+Some of the things TO DO:
+-------------------------
+ - a better device naming scheme (take into account removable media)
+
+ - ability to rescan devices like when something gets inserted just
+ before invoking elilo and the efi shell is not used (the mount())
+
+ - ability to list files from the interactive mode
+
+ - GUI-based chooser (a la RH9.x)!
+
+ - UGA support?
+
+ - Convert all filesystems (ext2fs, netfs) to use the FilesystemProtocol interface instead
+
+ - cleanup x86 loader: use the same structure as IA-64
+
+ - support for subnetting in the config file when netbooting
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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"
+
+#define NALLOC 512
+
+typedef enum { ALLOC_POOL, ALLOC_PAGES } alloc_types_t;
+
+typedef struct _alloc_entry {
+ struct _alloc_entry *next;
+ struct _alloc_entry *prev;
+ VOID *addr;
+ UINTN size; /* bytes for pool, page count for pages */
+ alloc_types_t type;
+} alloc_entry_t;
+
+static alloc_entry_t allocs[NALLOC];
+static alloc_entry_t *free_allocs, *used_allocs;
+
+static VOID *kmem_addr;
+static UINTN kmem_pgcnt;
+
+/*
+ * initializes the free list which is singly linked
+ */
+INTN
+alloc_init(VOID)
+{
+ UINTN i;
+
+ for(i=0; i < NALLOC-1; i++) {
+ allocs[i].next = allocs+i+1;
+ }
+ allocs[i].next = NULL;
+
+ free_allocs = allocs;
+ used_allocs = NULL;
+
+ return 0;
+}
+
+static VOID
+alloc_add(VOID * addr, UINTN size, alloc_types_t type)
+{
+ alloc_entry_t *alloc;
+
+ /* remove from freelist */
+ alloc = free_allocs;
+ free_allocs = free_allocs->next;
+
+ alloc->prev = NULL;
+ alloc->next = used_allocs;
+ alloc->addr = addr;
+ alloc->type = type;
+ alloc->size = size;
+
+ /* add to used list */
+ if (used_allocs) used_allocs->prev = alloc;
+
+ used_allocs = alloc;
+}
+
+VOID *
+alloc(UINTN size, EFI_MEMORY_TYPE type)
+{
+ EFI_STATUS status;
+ VOID *tmp = 0;
+
+ /* no more free slots */
+ if (free_allocs == NULL) {
+ ERR_PRT((L"allocator: no more slots\n"));
+ return NULL;
+ }
+
+ if (type == 0) type = EfiLoaderData;
+
+ status = BS->AllocatePool (type, size, &tmp);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"allocator: AllocatePool(%d, %d, 0x%x) failed (%r)\n", type, size, status));
+ return NULL;
+ }
+ alloc_add(tmp, size, ALLOC_POOL);
+
+ DBG_PRT((L"alloc: allocated %d bytes @[0x%lx-0x%lx]\n", size, tmp, tmp+size));
+
+ return tmp;
+}
+
+/*
+ * no possibility to partially free an allocated group of pages
+ */
+VOID *
+alloc_pages(UINTN pgcnt, EFI_MEMORY_TYPE type, EFI_ALLOCATE_TYPE where, VOID *addr)
+{
+ EFI_STATUS status;
+ EFI_PHYSICAL_ADDRESS tmp = (EFI_PHYSICAL_ADDRESS)addr;
+
+ /* no more free slots */
+ if (free_allocs == NULL) {
+ ERR_PRT((L"allocator: no more slots\n"));
+ return NULL;
+ }
+
+ status = BS->AllocatePages(where, type , pgcnt, &tmp);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"allocator: AllocatePages(%d, %d, %d, 0x%lx) failed (%r)\n", where, type, pgcnt, tmp, status));
+ return NULL;
+ }
+ /* XXX: will cause warning on IA-32 */
+ addr = (VOID *)tmp;
+
+ alloc_add(addr, pgcnt, ALLOC_PAGES);
+
+ DBG_PRT((L"allocator: allocated %d pages @0x%lx\n", pgcnt, tmp));
+
+ return addr;
+}
+
+/*
+ * free previously allocated slot
+ */
+VOID
+free(VOID *addr)
+{
+ alloc_entry_t *p;
+
+ /* find allocation record */
+ for(p=used_allocs; p ; p = p->next) {
+ if (p->addr == addr) goto found;
+ }
+ /* not found */
+ ERR_PRT((L"allocator: invalid free @ 0x%lx\n", addr));
+ return;
+found:
+ DBG_PRT((L"free: %s @0x%lx size=%ld\n",
+ p->type == ALLOC_POOL ? L"Pool": L"Page",
+ addr, p->size));
+
+ if (p->type == ALLOC_POOL)
+ BS->FreePool(addr);
+ else
+ BS->FreePages((EFI_PHYSICAL_ADDRESS)addr, p->size);
+
+ /* remove from used list */
+ if (p->next)
+ p->next->prev = p->prev;
+
+ if (p->prev)
+ p->prev->next = p->next;
+ else
+ used_allocs = p->next;
+
+ /* put back on free list */
+ p->next = free_allocs;
+ free_allocs = p;
+}
+
+/*
+ * garbage collect all used allocations.
+ * will put the allocator in initial state
+ */
+VOID
+free_all(VOID)
+{
+ alloc_entry_t *tmp;
+
+ while(used_allocs) {
+
+ DBG_PRT((L"free_all %a @ 0x%lx\n", used_allocs->type == ALLOC_POOL ? "pool" : "pages", used_allocs->addr));
+
+ if (used_allocs->type == ALLOC_POOL)
+ BS->FreePool(used_allocs->addr);
+ else
+ BS->FreePages((EFI_PHYSICAL_ADDRESS)used_allocs->addr, used_allocs->size);
+
+ tmp = used_allocs->next;
+
+ /* put back on free list */
+ used_allocs->next = free_allocs;
+ free_allocs = used_allocs;
+
+ used_allocs = tmp;
+ }
+}
+
+INTN
+alloc_kmem(VOID *start_addr, UINTN pgcnt)
+{
+ if (alloc_pages(pgcnt, EfiLoaderData, AllocateAddress, start_addr) == 0) return -1;
+
+ kmem_addr = start_addr;
+ kmem_pgcnt = pgcnt;
+
+ return 0;
+}
+
+VOID
+free_kmem(VOID)
+{
+ DBG_PRT((L"free_kmem before (%lx, %ld)\n", kmem_addr, kmem_pgcnt));
+ if (kmem_addr && kmem_pgcnt != 0) {
+ free(kmem_addr);
+ kmem_addr = NULL;
+ kmem_pgcnt = 0;
+ }
+ DBG_PRT((L"free_kmem after (%lx, %ld)\n", kmem_addr, kmem_pgcnt));
+}
+
+VOID
+free_all_memory(VOID)
+{
+ free_all();
+ free_kmem();
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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"
+
+#define ELILO_ALTK_VAR L"EliloAlt"
+
+/*
+ * we use a NULL GUID for now because it is more convenient
+ */
+static EFI_GUID altk_guid={0,};
+
+/*
+ * Check for the existence of an EFI variable named EliloAlt.
+ * It contains the name of an alternate kernel (and possible options)
+ * to boot ONLY once.
+ * The variable is then deleted. This ensures that next reboot won't
+ * pick it up.
+ *
+ * The content of the variable is assumed to be Unicode string. It is
+ * preferrably NULL terminated but the code can deal with this as well.
+ *
+ * The size of the buffer MUST be expressed in bytes (not CHAR16).
+ *
+ * Return:
+ * - 0 if successful
+ * - -1 in case nothing happened (no variable found)
+ * Please note that no fatal error is reported by this function
+ */
+INTN
+alternate_kernel(CHAR16 *buffer, INTN size)
+{
+ EFI_STATUS status;
+ INTN ret = -1;
+
+ /*
+ * size of the buffer is expressed in bytes
+ *
+ * we reserve one Unicode for CHAR_NULL (forced), so
+ * the buffer must be at least 2 more bytes to accomodate one Unicode
+ */
+ if (size < 4) return -1;
+
+ /*
+ * reserve for CHAR_NULL
+ */
+ size-=2;
+
+ /*
+ * Look if the variable exists.
+ * We may fail because:
+ * - the variable does not exist
+ * - our buffer size is too small.
+ */
+ status = RT->GetVariable(ELILO_ALTK_VAR, &altk_guid, NULL, &size, buffer);
+ if (EFI_ERROR(status)) {
+ DBG_PRT((L"cannot access variable %s: %r", ELILO_ALTK_VAR, status));
+
+ /* if buffer is too small, erase variable because it's unuseable */
+ if (status == EFI_BUFFER_TOO_SMALL) goto delete_var;
+
+ return -1;
+ }
+
+ /*
+ * sanity check
+ *
+ * verify that size (expressed in bytes) is multiple of 2. If
+ * not then it can't possibly be representing a UNICODE string
+ * (2bytes/character).
+ *
+ * We also consider empty as useless (2nd test).
+ */
+ if (size & 0x1) {
+ Print(L"invalid content for %s variable, erasing variable\n", ELILO_ALTK_VAR);
+ goto delete_var;
+ }
+
+ /* We also consider empty as useless (2nd test) */
+ if (size == 2) goto delete_var;
+
+ buffer[size] = CHAR_NULL;
+
+ VERB_PRT(2, Print(L"found alternate variable %s : %s\n", ELILO_ALTK_VAR, buffer));
+
+ ret = 0;
+delete_var:
+ status = RT->SetVariable(ELILO_ALTK_VAR, &altk_guid, 0, 0, NULL);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"cannot erase variable %s", ELILO_ALTK_VAR));
+ }
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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"
+
+/*
+ * Initialize the generic part of the boot parameters and call the architecture specific
+ * subroutine.
+ * Output:
+ * cookie: the memory map cookie to use with ExitBootServices()
+ * Return:
+ * NULL: if an error occured
+ * bp : the address of the bootparams otherwise (opaque type)
+ */
+VOID *
+create_boot_params(CHAR16 *args, memdesc_t *initrd, UINTN *cookie)
+{
+/*
+ * XXX: need cleanup
+ * See ia32 code for explanation on why it is so big.
+ */
+#define BOOT_PARAM_MEMSIZE 16384
+ UINTN bpsize, cmdline_size;
+ boot_params_t *bp;
+ CHAR8 *cp;
+ CHAR16 ch;
+
+ /*
+ * Allocate runtime services memory to hold memory descriptor table and
+ * command line arguments and fetch memory map:
+ *
+ * arg_size = number of character in ASCII form
+ */
+ cmdline_size = StrLen(args) + 1;
+ bpsize = sizeof(boot_params_t) + cmdline_size;
+
+ if (bpsize > BOOT_PARAM_MEMSIZE) {
+ ERR_PRT((L"BOOT_PARAM_MEMSIZE too small, need at least %d bytes", bpsize));
+ return NULL;
+ }
+
+
+ /*
+ * Allocate memory for boot parameters.
+ * This CANNOT be EfiLoaderData or EfiLoaderCode as the kernel
+ * frees this region when initializing.
+ */
+
+ bp = (boot_params_t *)alloc(BOOT_PARAM_MEMSIZE, EfiLoaderData);
+ if (bp == NULL) {
+ ERR_PRT((L"can't allocate boot params"));
+ return 0;
+ }
+
+ VERB_PRT(3, Print(L"boot params @ 0x%lx\n", bp));
+
+/* XXX: need to fix this for 3.5 */
+#ifdef CONFIG_ia64
+ cp = ((CHAR8 *)bp) + BOOT_PARAM_MEMSIZE - cmdline_size;
+#elif defined CONFIG_ia32
+ cp = ((CHAR8 *)bp) + BOOT_PARAM_MEMSIZE - 2048;
+#endif
+
+ /*
+ * clear entire buffer. The boot param structure is bigger than
+ * needs be but this allows the kernel bootparam structure to grow
+ * (up to BOOT_PARAM_MEMSIZE) without having to worry about fixing the bootloader.
+ * By convention between the laoder and the kernel, the value 0 means
+ * don't care or not set.
+ */
+ Memset(bp, 0, BOOT_PARAM_MEMSIZE);
+
+ if (sysdeps_create_boot_params(bp, cp, initrd, 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;
+}
+
+VOID
+free_boot_params(VOID *bp)
+{
+ boot_params_t *real_bp = (boot_params_t *)bp;
+
+ sysdeps_free_boot_params(real_bp);
+
+ free(real_bp);
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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"
+
+#ifdef CONFIG_CHOOSER_SIMPLE
+#include "choosers/simple.h"
+#endif
+
+#ifdef CONFIG_CHOOSER_TEXTMENU
+#include "choosers/textmenu.h"
+#endif
+
+static chooser_t *choosers_tab[]={
+#ifdef CONFIG_CHOOSER_SIMPLE
+ &simple_chooser,
+#endif
+#ifdef CONFIG_CHOOSER_TEXTMENU
+ &textmenu_chooser,
+#endif
+ NULL
+};
+/*
+ * The intent of this module is to provide a mechanism by which alternate
+ * choosers can be installed. Developers can write new choosers and
+ * add them to the list. They will be probe and the best match
+ * will be started first. It should be possible to switch to another
+ * chooser using a key combination. There is a default simple text-based
+ * chooser that must always be present.
+ *
+ * Currently you can specify a chooser via "-c name" when you invoke elilo,
+ * or via "chooser=name" in the config file. If the specified chooser
+ * probes ok it will be selected, otherwise the first one that probes ok
+ * will be used.
+ *
+ * XXX: at this time, not all chooser functionalities are implemented.
+ *
+ */
+chooser_func_t *kernel_chooser;
+
+INTN
+init_chooser(EFI_HANDLE dev)
+{
+ chooser_t **p;
+ CHAR16 *chooser_name = L"none";
+
+ kernel_chooser = NULL;
+
+ for (p=choosers_tab; *p; p++) {
+
+ VERB_PRT(4, Print(L"trying chooser %s\n", (*p)->chooser_name));
+
+ if ((*p)->chooser_probe(dev) == 0) {
+ /*
+ * if that's the one we asked for, then go for it
+ */
+ if (!StrCmp(elilo_opt.chooser, (*p)->chooser_name)) {
+ kernel_chooser = (*p)->chooser_func;
+ chooser_name = (*p)->chooser_name;
+ break;
+ }
+
+ if (kernel_chooser == NULL) {
+ kernel_chooser = (*p)->chooser_func;
+ chooser_name = (*p)->chooser_name;
+ }
+ }
+ }
+
+ if (kernel_chooser) {
+ VERB_PRT(2, Print(L"selected chooser %s\n", chooser_name));
+ return 0;
+ }
+
+ ERR_PRT((L"No chooser selected. Impossible to proceed"));
+ return -1;
+}
+
+INTN
+exist_chooser(CHAR16 *name)
+{
+ chooser_t **p;
+
+ for (p=choosers_tab; *p; p++) {
+ if (!StrCmp(name, (*p)->chooser_name)) return 0;
+ }
+ return -1;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ * GNU EFI 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.
+ *
+ * GNU EFI 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 GNU EFI; 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_CHOOSER_H__
+#define __ELILO_CHOOSER_H__
+
+typedef INTN chooser_func_t(CHAR16 **argv, INTN arc, INTN index, CHAR16 *kname, CHAR16 *cmdline);
+
+/*
+ * structure to interface to generic chooser selection code.
+ *
+ * XXX: must add support for moer than one choice (rating scheme)
+ *
+ * Interface for probe:
+ * dev: boot device handle
+ * return: -1, if not support, 0 if supported
+ *
+ * Interface for chooser:
+ * argv,argc: command line argument passed to elilo
+ * index : position of first non-option argument (min value=1)
+ * kname : selected kernel name
+ * cmdline : requested kernel command line
+ * return:
+ * -1: if error
+ * 0: if successful
+ */
+typedef struct {
+ CHAR16 *chooser_name;
+ INTN (*chooser_probe)(EFI_HANDLE dev);
+ chooser_func_t *chooser_func;
+} chooser_t;
+
+extern INTN init_chooser(EFI_HANDLE);
+extern INTN exist_chooser(CHAR16 *name);
+
+extern chooser_func_t *kernel_chooser;
+
+#endif /* __ELILO_CHOOSER_H__ */
--- /dev/null
+#
+# Copyright (C) 2001-2003 Hewlett-Packard Co.
+# Contributed by Stephane Eranian <eranian@hpl.hp.com>
+#
+# 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 ../Make.defaults
+include ../Make.rules
+
+TOPDIR=$(CDIR)/..
+
+FILES=
+
+ifeq ($(CONFIG_chooser_simple),y)
+FILES +=simple.o
+endif
+
+ifeq ($(CONFIG_chooser_textmenu),y)
+FILES +=textmenu.o
+endif
+
+TARGET=choosers.o
+
+all: $(TARGET)
+
+$(TARGET): check-choosers $(TOPDIR)/Make.defaults $(FILES)
+ $(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
+
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 "vars.h"
+
+/* static is ugly but does the job here! */
+static CHAR16 **alt_argv;
+
+static VOID
+display_label_info(CHAR16 *name)
+{
+ CHAR16 *desc;
+ CHAR16 initrd_name[CMDLINE_MAXLEN];
+ CHAR16 options_tmp[CMDLINE_MAXLEN];
+ CHAR16 options[CMDLINE_MAXLEN];
+ CHAR16 kname[FILENAME_MAXLEN];
+
+ desc = find_description(name);
+ if (desc) {
+ Print(L"desc : %s\n", desc);
+ }
+
+ initrd_name[0] = options_tmp[0] = kname[0] = CHAR_NULL;
+
+ if (find_label(name, kname, options_tmp, initrd_name) == -1) {
+ StrCpy(kname, name);
+ Print(L"\n");
+ }
+ subst_vars(options_tmp, options, CMDLINE_MAXLEN);
+
+ Print(L"cmdline: %s %s\n", kname, options);
+ if (initrd_name[0]) Print(L"initrd : %s\n", initrd_name);
+}
+
+static VOID
+print_infos(int force)
+{
+ CHAR16 *config_file;
+ CHAR16 dpath[FILENAME_MAXLEN];
+ CHAR16 *boot_dev_name;
+ UINT8 is_abs;
+
+ boot_dev_name = fops_bootdev_name();
+ config_file = get_config_file();
+
+ fops_getdefault_path(dpath, FILENAME_MAXLEN);
+
+ if (force || elilo_opt.verbose > 0)
+ Print(L"default file path: %s:%s\n", boot_dev_name, dpath);
+
+ is_abs = config_file && (config_file[0] == CHAR_BACKSLASH || config_file[0] == CHAR_SLASH) ? 1 : 0;
+
+ if (force || elilo_opt.verbose > 0)
+ Print(L"config file : %s%s\n", config_file && is_abs == 0 ? dpath : L"", config_file ? config_file : L"none used");
+
+ if (alt_argv) {
+ CHAR16 **p = alt_argv;
+ Print(L"found alternate default choice :");
+ while (*p) Print(L" %s", *p++);
+ Print(L"\n");
+ }
+}
+
+static VOID
+print_help(int force)
+{
+ if (force || elilo_opt.verbose > 0)
+ Print(L"command list (must be first character):\n=:print device list, %%:print variable list, &:print paths, ?:help\nTAB:print label information\n");
+}
+
+/*
+ * interactively select a kernel image and options.
+ * The kernel can be an actual filename or a label in the config file
+ * Return:
+ * -1: if unsucessful
+ * 0: otherwise
+ */
+static INTN
+select_kernel(CHAR16 *buffer, INTN size)
+{
+#define CHAR_CTRL_C L'\003' /* Unicode CTRL-C */
+#define CHAR_CTRL_D L'\004' /* Unicode CTRL-D */
+#define CHAR_CTRL_U L'\025' /* Unicode CTRL-U */
+//#define CHAR_TAB L'\t'
+ SIMPLE_INPUT_INTERFACE *ip = systab->ConIn;
+ EFI_INPUT_KEY key;
+ EFI_STATUS status;
+ INTN pos = 0, ret;
+ INT8 first_time = 1;
+
+ /*
+ * let's give some help first
+ */
+ print_help(0);
+
+ print_infos(0);
+
+reprint:
+ buffer[pos] = CHAR_NULL;
+
+ Print(L"\nELILO boot: %s", buffer);
+ /*
+ * autoboot with default choice after timeout expires
+ */
+ if (first_time && (ret=wait_timeout(elilo_opt.timeout)) != 1) {
+ return ret == -1 ? -1: 0;
+ }
+ first_time = 0;
+
+ for (;;) {
+ while ((status=ip->ReadKeyStroke(ip, &key)) == EFI_NOT_READY);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"select_kernel readkey: %r", status));
+ return -1;
+ }
+ switch (key.UnicodeChar) {
+ case CHAR_TAB:
+ Print(L"\n");
+ if (pos == 0) {
+ print_label_list();
+ Print(L"(or a kernel file name: [[dev_name:/]path/]kernel_image cmdline options)\n");
+ } else {
+ buffer[pos] = CHAR_NULL;
+ display_label_info(buffer);
+ }
+ goto reprint;
+ case L'%':
+ if (pos>0) goto normal_char;
+ Print(L"\n");
+ print_vars();
+ goto reprint;
+ case L'?':
+ if (pos>0) goto normal_char;
+ Print(L"\n");
+ print_help(1);
+ goto reprint;
+ case L'&':
+ if (pos>0) goto normal_char;
+ Print(L"\n");
+ print_infos(1);
+ goto reprint;
+ case L'=':
+ if (pos>0) goto normal_char;
+ Print(L"\n");
+ print_devices();
+ goto reprint;
+ case CHAR_BACKSPACE:
+ if (pos == 0) break;
+ pos--;
+ Print(L"\b \b");
+ break;
+ case CHAR_CTRL_U: /* clear line */
+ while (pos) {
+ Print(L"\b \b");
+ pos--;
+ }
+ break;
+ case CHAR_CTRL_C: /* kill line */
+ pos = 0;
+ goto reprint;
+ case CHAR_LINEFEED:
+ case CHAR_CARRIAGE_RETURN:
+ buffer[pos] = CHAR_NULL;
+ Print(L"\n");
+ return 0;
+ default:
+normal_char:
+ if (key.UnicodeChar == CHAR_CTRL_D || key.ScanCode == 0x17 ) {
+ Print(L"\nGiving up then...\n");
+ return -1;
+ }
+ if (key.UnicodeChar == CHAR_NULL) break;
+
+ if (pos > size-1) break;
+
+ buffer[pos++] = key.UnicodeChar;
+
+ /* Write the character out */
+ Print(L"%c", key.UnicodeChar);
+ }
+ }
+ return 0;
+}
+
+static VOID
+display_message(VOID)
+{
+ fops_fd_t fd;
+ EFI_STATUS status;
+ INTN len, i;
+ CHAR16 *filename;
+ CHAR8 buf[256];
+
+ if ((filename = get_message_filename(0)) == NULL) return;
+
+ if (*filename == CHAR_NULL) return;
+
+ VERB_PRT(3, Print(L"opening message file %s\n", filename));
+
+ status = fops_open(filename, &fd);
+ if (EFI_ERROR(status)) {
+ VERB_PRT(3, Print(L"message file %s not found\n", filename));
+ return;
+ }
+ len = 256;
+ Print(L"\n");
+ while ((status = fops_read(fd, buf, &len)) == EFI_SUCCESS) {
+ /* XXX: ugly ! */
+ for (i=0; i < len; i++) {
+ Print(L"%c", (CHAR16)buf[i]);
+ }
+ if (len < 256) break;
+ }
+ fops_close(fd);
+}
+
+static INTN
+simple_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmdline)
+{
+# define BOOT_IMG_STR L"BOOT_IMAGE="
+ CHAR16 buffer[CMDLINE_MAXLEN];
+ CHAR16 alt_buffer[CMDLINE_MAXLEN];
+ CHAR16 initrd_name[CMDLINE_MAXLEN];
+ CHAR16 args[CMDLINE_MAXLEN];
+ CHAR16 devname[CMDLINE_MAXLEN];
+ CHAR16 dpath[FILENAME_MAXLEN];
+ CHAR16 *slash_pos, *colon_pos, *backslash_pos;
+ UINTN len;
+ INTN ret;
+
+ buffer[0] = alt_buffer[0] = CHAR_NULL;
+
+ display_message();
+
+restart:
+ initrd_name[0] = kname[0] = cmdline[0] = args[0] = CHAR_NULL;
+
+ /* reset per image loader options */
+ Memset(&elilo_opt.img_opt, 0, sizeof(elilo_opt.img_opt));
+
+ /*
+ * check for alternate kernel image and params in EFI variable
+ */
+ if (elilo_opt.alt_check && alternate_kernel(alt_buffer, sizeof(alt_buffer)) == 0) {
+ argc = argify(alt_buffer,sizeof(alt_buffer), argv);
+ alt_argv = argv;
+ index = 0;
+ args[0] = initrd_name[0] = 0;
+ /*
+ * don't check twice because the variable is deleted after
+ * first access
+ */
+ elilo_opt.alt_check = 0;
+ }
+
+ if (elilo_opt.prompt) {
+ ret = select_kernel(buffer, sizeof(buffer));
+ if (ret == -1) return -1;
+ argc = argify(buffer,sizeof(buffer), argv);
+ index = 0;
+ }
+
+ /*
+ * if we found an alternate choice and the user
+ * did not force it manually, then use the alternate
+ * option.
+ */
+ if (alt_buffer[0] && buffer[0] == CHAR_NULL) {
+ StrCpy(buffer, alt_buffer);
+ }
+
+ /*
+ * First search for matching label in the config file
+ * if options were specified on command line, they take
+ * precedence over the ones in the config file
+ *
+ * if no match is found, the args and initrd arguments may
+ * still be modified by global options in the config file.
+ */
+ ret = find_label(argv[index], kname, args, initrd_name);
+
+ /*
+ * not found, so assume first argument is kernel name and
+ * not label name
+ */
+ if (ret == -1) {
+ if (argv[index])
+ StrCpy(kname, argv[index]);
+ else
+ StrCpy(kname, elilo_opt.default_kernel);
+ }
+ /*
+ * no matter what happened for kname, if user specified
+ * additional options, they override the ones in the
+ * config file
+ */
+ if (argc > 1+index) {
+ /*StrCpy(args, argv[++index]);*/
+ while (++index < argc) {
+ StrCat(args, L" ");
+ StrCat(args, argv[index]);
+ }
+ }
+ /*
+ * if initrd specified on command line, it overrides
+ * the one defined in config file, if any
+ */
+ if (elilo_opt.initrd[0] == CHAR_NULL && initrd_name[0] != CHAR_NULL) {
+ StrCpy(elilo_opt.initrd, initrd_name);
+ }
+
+ VERB_PRT(1, { Print(L"kernel is '%s'\n", kname);
+ Print(L"arguments are '%s'\n", args);
+ if (elilo_opt.initrd[0]) Print(L"initrd is '%s'\n", elilo_opt.initrd);
+ });
+
+ if (elilo_opt.prompt == 0) {
+ /* minimal printing */
+ Print(L"ELILO\n");
+ ret = wait_timeout(elilo_opt.delay);
+ if (ret != 0) {
+ elilo_opt.prompt = 1;
+ elilo_opt.timeout = ELILO_TIMEOUT_INFINITY;
+ goto restart;
+ }
+ }
+ /*
+ * add the device name, if not already specified,
+ * so that we know where we came from
+ */
+ slash_pos = StrChr(kname, L'/');
+ backslash_pos = StrChr(kname, L'\\');
+ colon_pos = StrChr(kname, L':');
+
+ if (backslash_pos && backslash_pos < slash_pos) slash_pos = backslash_pos;
+
+ if (colon_pos == NULL || (slash_pos && (slash_pos < colon_pos))) {
+ StrCpy(devname, fops_bootdev_name());
+ StrCat(devname, L":");
+
+ /* the default path is always terminated with a separator */
+ if (kname[0] != L'/' && kname[0] != L'\\') {
+ fops_getdefault_path(dpath,FILENAME_MAXLEN);
+ StrCat(devname, dpath);
+ }
+ } else {
+ devname[0] = CHAR_NULL;
+ }
+
+ /*
+ * create final argument list to the kernel
+ */
+ len = StrLen(BOOT_IMG_STR) /* BOOT_IMAGE= */
+ +StrLen(devname) /* device name */
+ +StrLen(kname) /* kernel name */
+ +1 /* space */
+ +StrLen(args); /* args length */
+
+ if (len >= CMDLINE_MAXLEN-1) {
+ ERR_PRT((L" arguments list too long cannot fit BOOT_IMAGE\n"));
+ return -1;
+ }
+ StrCpy(cmdline, L"BOOT_IMAGE=");
+ StrCat(cmdline, devname);
+ StrCat(cmdline, kname);
+ StrCat(cmdline, L" ");
+ StrCat(cmdline, args);
+
+ return 0;
+}
+
+static INTN
+simple_probe(EFI_HANDLE dev)
+{
+ /* this chooser always work */
+ return 0;
+}
+
+chooser_t simple_chooser={
+ L"simple",
+ simple_probe,
+ simple_choose
+};
+
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ * GNU EFI 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.
+ *
+ * GNU EFI 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 GNU EFI; 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_CHOOSER_SIMPLE_H__
+#define __ELILO_CHOOSER_SIMPLE_H__
+
+#include "fileops.h"
+
+extern chooser_t simple_chooser;
+
+#endif
+
+
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Richard Hirst <rhirst@linuxcare.com>
+ *
+ * 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"
+
+#define MAX_LABELS 16
+#define MSGBUFLEN 4096
+
+static UINT8 msgbuf[MSGBUFLEN];
+static CHAR16 *labels[MAX_LABELS];
+static CHAR16 *descriptions[MAX_LABELS];
+static INTN nlabels;
+static INTN CursorRow, CursorCol, PromptRow, PromptCol;
+static INTN MenuRow, MenuCol, MenuWidth, MenuHeight;
+static INTN DisplayParsed, CurrentAttr, PromptAttr;
+static INTN PromptWidth, MenuHiAttr, MenuLoAttr;
+static INTN PromptLen, MenuActive, MenuFirst;
+static CHAR16 PromptBuf[CMDLINE_MAXLEN];
+
+#define DEF_ATTR EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK)
+
+
+#define ClearScreen() ST->ConOut->ClearScreen(ST->ConOut)
+#define SetTextAttr(a) ST->ConOut->SetAttribute(ST->ConOut, a)
+
+static INTN
+tohex(INTN c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'A' && c <= 'F')
+ return c = c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ return c = c - 'a' + 10;
+ else
+ return 16;
+}
+
+static VOID
+paint_msg(UINT8 *msg)
+{
+ INTN c;
+
+ CursorCol = CursorRow = 0;
+ CurrentAttr = DEF_ATTR;
+ SetTextAttr(CurrentAttr);
+ ClearScreen();
+ while ((c = *msg++)) {
+ /* First map VGA to EFI line drawing chars */
+ if (c == 0xda) c = BOXDRAW_DOWN_RIGHT;
+ else if (c == 0xc4) c = BOXDRAW_HORIZONTAL;
+ else if (c == 0xbf) c = BOXDRAW_DOWN_LEFT;
+ else if (c == 0xb3) c = BOXDRAW_VERTICAL;
+ else if (c == 0xd9) c = BOXDRAW_UP_LEFT;
+ else if (c == 0xc0) c = BOXDRAW_UP_RIGHT;
+ else if (c == 0xb4) c = BOXDRAW_VERTICAL_LEFT;
+ else if (c == 0xc3) c = BOXDRAW_VERTICAL_RIGHT;
+ else if (c == 0x1e) c = GEOMETRICSHAPE_UP_TRIANGLE;
+ else if (c == 0x1f) c = GEOMETRICSHAPE_DOWN_TRIANGLE;
+ else if (c > 0x7f) c = '?';
+
+ /* Now print the printable chars, then process controls */
+ if (c >= ' ') {
+ Print(L"%c", c);
+ CursorCol++;
+ }
+ else {
+ switch (c) {
+ case '\r': /* Ignore CR */
+ break;
+ case '\n': /* LF treated as cr/lf */
+ CursorRow++;
+ CursorCol = 0;
+ Print(L"\n");
+ break;
+ case 0x0c: /* FF - Clear screen */
+ CursorCol = CursorRow = 0;
+ ClearScreen();
+ break;
+ case 0x0f: /* ^O - Attributes */
+ if (msg[0] && msg[1]) {
+ INTN bg = tohex(*msg++);
+ INTN fg = tohex(*msg++);
+
+ if (bg < 16 || fg < 16) {
+ CurrentAttr = EFI_TEXT_ATTR(fg, bg);
+ SetTextAttr(CurrentAttr);
+ }
+ }
+ break;
+ case 0x01: /* ^A - Prompt */
+ if (!DisplayParsed) {
+ if (!PromptRow) {
+ PromptRow = CursorRow;
+ PromptCol = CursorCol;
+ PromptAttr = CurrentAttr;
+ }
+ else if (!PromptWidth)
+ PromptWidth = CursorCol - PromptCol;
+ /* else bad syntax */
+ }
+ break;
+ case 0x02: /* ^B - Menu */
+ if (!DisplayParsed) {
+ if (!MenuRow) {
+ MenuRow = CursorRow;
+ MenuCol = CursorCol;
+ MenuLoAttr = CurrentAttr;
+ }
+ else if (!MenuWidth) {
+ MenuWidth = CursorCol - MenuCol;
+ MenuHeight = CursorRow - MenuRow + 1;
+ MenuHiAttr = CurrentAttr;
+ }
+ /* else bad syntax */
+ }
+ break;
+ default:
+ Print(L"?");
+ CursorCol++;
+ }
+ }
+ }
+}
+
+
+static VOID
+paint_prompt(VOID)
+{
+ INTN offset = PromptLen > PromptWidth - 1 ? PromptLen - PromptWidth + 1: 0;
+ SetTextAttr(PromptAttr);
+ PrintAt(PromptCol, PromptRow, L"%s%s", PromptBuf + offset, L" \b");
+ SetTextAttr(CurrentAttr);
+}
+
+static VOID
+paint_menu(VOID)
+{
+ INTN i, j;
+
+ for (i = 0; i < MenuHeight; i++) {
+ INTN attr = (i + MenuFirst == MenuActive) ? MenuHiAttr: MenuLoAttr;
+ CHAR16 description[80];
+
+ for (j = 0; j < MenuWidth; j++)
+ description[j] = ' ';
+ description[MenuWidth] = '\0';
+ if (i + MenuFirst < nlabels) {
+ for (j = 0; descriptions[i + MenuFirst][j] && j < MenuWidth; j++)
+ description[j+1] = descriptions[i + MenuFirst][j];
+ }
+ SetTextAttr(attr);
+ PrintAt(MenuCol, MenuRow + i, L"%-.*s", MenuWidth, description);
+ SetTextAttr(CurrentAttr);
+ }
+ paint_prompt();
+}
+
+static INTN
+read_message_file(INTN msg, INT8 *buf, INTN max)
+{
+ CHAR16 *filename;
+ fops_fd_t message_fd;
+ EFI_STATUS status;
+ INTN len = max;
+
+ if (msg > 10) return 0;
+
+ if ((filename = get_message_filename(msg)) == NULL) {
+ VERB_PRT(3, Print(L"no message file specified\n"));
+ return 0;
+ }
+
+ VERB_PRT(3, Print(L"opening message file %s\n", filename));
+
+ status = fops_open(filename, &message_fd);
+ if (EFI_ERROR(status)) {
+ VERB_PRT(3, Print(L"message file %s not found\n", filename));
+ return 0;
+ }
+
+ status = fops_read(message_fd, buf, &len);
+ if (EFI_ERROR(status)) {
+ VERB_PRT(3, Print(L"Error reading message file\n"));
+ len = 0;
+ }
+
+ fops_close(message_fd);
+
+ VERB_PRT(3, Print(L"done reading message file %s\n", filename));
+
+ return len;
+}
+
+
+/*
+ * interactively select a kernel image and options.
+ * The kernel can be an actual filename or a label in the config file
+ * Return:
+ * -1: if unsucessful
+ * 0: otherwise
+ */
+static INTN
+select_kernel(CHAR16 *label, INTN lsize)
+{
+#define CHAR_CTRL_C (L'\003') /* Unicode CTRL-C */
+#define CHAR_CTRL_D (L'\004') /* Unicode CTRL-D */
+#define CHAR_CTRL_F (L'\006') /* Unicode CTRL-F */
+#define CHAR_DEL (L'\177') /* Unicode DEL */
+ SIMPLE_INPUT_INTERFACE *ip = systab->ConIn;
+ EFI_INPUT_KEY key;
+ EFI_STATUS status;
+ INT8 first_time = 1;
+ INTN i;
+ INT8 fn = 0;
+
+reprint:
+ i = read_message_file(0, msgbuf, MSGBUFLEN-1);
+ msgbuf[i] = 0;
+ paint_msg(msgbuf);
+ DisplayParsed = 1;
+ paint_menu();
+ CurrentAttr = PromptAttr;
+ SetTextAttr(CurrentAttr);
+
+ for (;;) {
+ while ((status=ip->ReadKeyStroke(ip, &key)) == EFI_NOT_READY);
+ if (EFI_ERROR(status)) {
+ SetTextAttr(EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK));
+ ClearScreen();
+ ERR_PRT((L"select_kernel readkey: %r", status));
+ return -1;
+ }
+ if (key.UnicodeChar == CHAR_CTRL_F) {
+ fn = 1;
+ continue;
+ }
+ if (fn) {
+ if (key.UnicodeChar >= '0' && key.UnicodeChar <= '9') {
+ if (key.UnicodeChar == '0')
+ key.ScanCode = SCAN_F10;
+ else
+ key.ScanCode = SCAN_F1 + key.UnicodeChar - '1';
+ key.UnicodeChar = 0;
+ }
+ fn = 0;
+ }
+ if (key.ScanCode == SCAN_UP) {
+ if (MenuActive)
+ MenuActive--;
+ else
+ continue;
+ if (MenuActive < MenuFirst)
+ MenuFirst = MenuActive;
+ paint_menu();
+ continue;
+ }
+ else if (key.ScanCode == SCAN_DOWN) {
+ if (MenuActive < nlabels - 1)
+ MenuActive++;
+ else
+ continue;
+ if (MenuActive >= MenuFirst + MenuHeight)
+ MenuFirst = MenuActive - MenuHeight + 1;
+ paint_menu();
+ continue;
+ }
+ else if (key.ScanCode >= SCAN_F1 && key.ScanCode <= SCAN_F10) {
+ i = read_message_file(key.ScanCode - SCAN_F1 + 1, msgbuf, MSGBUFLEN-1);
+ if (i) {
+ msgbuf[i] = 0;
+ paint_msg(msgbuf);
+ while ((status=ip->ReadKeyStroke(ip, &key)) == EFI_NOT_READY);
+ goto reprint;
+ }
+ }
+
+ switch (key.UnicodeChar) {
+ /* XXX Do we really want this in textmenual mode? */
+ case L'?':
+ Print(L"\n");
+ print_devices();
+ first_time = 0;
+ goto reprint;
+ case CHAR_BACKSPACE:
+ case CHAR_DEL:
+ if (PromptLen == 0) break;
+ PromptLen--;
+ PromptBuf[PromptLen] = 0;
+ if (PromptLen >= PromptWidth-2)
+ paint_prompt();
+ else
+ Print(L"\b \b");
+ break;
+
+ case CHAR_LINEFEED:
+ case CHAR_CARRIAGE_RETURN:
+ StrCpy(label, labels[MenuActive]);
+ SetTextAttr(EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK));
+ ClearScreen();
+ return 0;
+
+ default:
+ if ( key.UnicodeChar == CHAR_CTRL_D
+ || key.UnicodeChar == CHAR_CTRL_C) {
+ SetTextAttr(EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK));
+ ClearScreen();
+ Print(L"\nGiving up then...\n");
+ return -1;
+ }
+ if (key.UnicodeChar == CHAR_NULL) break;
+
+ if (PromptLen > CMDLINE_MAXLEN-1) break;
+
+ if (key.UnicodeChar < ' ' || key.UnicodeChar > 0x7e)
+ key.UnicodeChar = '?';
+ PromptBuf[PromptLen++] = key.UnicodeChar;
+ PromptBuf[PromptLen] = 0;
+
+ /* Write the character out */
+ if (PromptLen >= PromptWidth-1)
+ paint_prompt();
+ else
+ Print(L"%c", key.UnicodeChar);
+ }
+ }
+ return 0;
+}
+
+INTN
+textmenu_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmdline)
+{
+# define BOOT_IMG_STR L"BOOT_IMAGE="
+ CHAR16 label[CMDLINE_MAXLEN];
+ CHAR16 initrd_name[CMDLINE_MAXLEN];
+ CHAR16 args[CMDLINE_MAXLEN];
+ CHAR16 devname[CMDLINE_MAXLEN];
+ CHAR16 dpath[FILENAME_MAXLEN];
+ CHAR16 *slash_pos, *colon_pos, *backslash_pos;
+ UINTN len;
+ INTN ret;
+ VOID *handle = NULL;
+
+ /* Clear all static variables, as we might be called more than once */
+
+ CursorRow = CursorCol = PromptRow = PromptCol = 0;
+ MenuRow = MenuCol = MenuWidth = MenuHeight = 0;
+ DisplayParsed = CurrentAttr = PromptAttr = 0;
+ PromptWidth = MenuHiAttr = MenuLoAttr = 0;
+ PromptLen = MenuActive = MenuFirst = 0;
+ PromptBuf[0] = CHAR_NULL;
+
+ nlabels = 0;
+ while (nlabels < MAX_LABELS && (handle = get_next_description(handle, labels + nlabels, descriptions + nlabels))) {
+ if (descriptions[nlabels][0] == 0)
+ descriptions[nlabels] = labels[nlabels];
+ nlabels++;
+ }
+restart:
+ initrd_name[0] = kname[0] = cmdline[0] = args[0] = CHAR_NULL;
+
+ /* reset per image loader options */
+ Memset(&elilo_opt.img_opt, 0, sizeof(elilo_opt.img_opt));
+
+ if (elilo_opt.prompt) {
+ ret = select_kernel(label, sizeof(label));
+ if (ret == -1) return -1;
+ argc = argify(PromptBuf,sizeof(PromptBuf), argv);
+ index = 0;
+ }
+
+ /*
+ * check for alternate kernel image and params in EFI variable
+ */
+ if (elilo_opt.alt_check && alternate_kernel(PromptBuf, sizeof(PromptBuf)) == 0) {
+ argc = argify(PromptBuf,sizeof(PromptBuf), argv);
+ index = 0;
+ label[0] = args[0] = initrd_name[0] = 0;
+ }
+
+ /*
+ * First search for matching label in the config file
+ * if options were specified on command line, they take
+ * precedence over the ones in the config file
+ *
+ * if no match is found, the args and initrd arguments may
+ * still be modified by global options in the config file.
+ */
+ if (label[0])
+ ret = find_label(label, kname, args, initrd_name);
+ else
+ ret = find_label(argv[index], kname, args, initrd_name);
+
+ /*
+ * not found, so assume first argument is kernel name and
+ * not label name
+ */
+ if (ret == -1) {
+ if (argv[index])
+ StrCpy(kname, argv[index]);
+ else
+ StrCpy(kname, elilo_opt.default_kernel);
+ }
+ /*
+ * no matter what happened for kname, if user specified
+ * additional options, they override the ones in the
+ * config file
+ */
+ if (label[0])
+ index--;
+ if (argc > 1+index) {
+ /*StrCpy(args, argv[++index]);*/
+ while (++index < argc) {
+ StrCat(args, L" ");
+ StrCat(args, argv[index]);
+ }
+ }
+ /*
+ * if initrd specified on command line, it overrides
+ * the one defined in config file, if any
+ */
+ if (elilo_opt.initrd[0] == CHAR_NULL && initrd_name[0] != CHAR_NULL) {
+ StrCpy(elilo_opt.initrd, initrd_name);
+ }
+
+ VERB_PRT(1, { Print(L"kernel is '%s'\n", kname);
+ Print(L"arguments are '%s'\n", args);
+ if (elilo_opt.initrd[0]) Print(L"initrd is '%s'\n", elilo_opt.initrd);
+ });
+
+ if (elilo_opt.prompt == 0) {
+ /* minimal printing */
+ Print(L"ELILO\n");
+ ret = wait_timeout(elilo_opt.delay);
+ if (ret != 0) {
+ elilo_opt.prompt = 1;
+ elilo_opt.timeout = ELILO_TIMEOUT_INFINITY;
+ goto restart;
+ }
+ }
+
+ /*
+ * add the device name, if not already specified,
+ * so that we know where we came from
+ */
+ slash_pos = StrChr(kname, L'/');
+ backslash_pos = StrChr(kname, L'\\');
+ colon_pos = StrChr(kname, L':');
+
+ if (backslash_pos && backslash_pos < slash_pos) slash_pos = backslash_pos;
+
+ if (colon_pos == NULL || (slash_pos && (slash_pos < colon_pos))) {
+ StrCpy(devname, fops_bootdev_name());
+ StrCat(devname, L":");
+
+ /* the default path is always terminated with a separator */
+ if (kname[0] != L'/' && kname[0] != L'\\') {
+ fops_getdefault_path(dpath,FILENAME_MAXLEN);
+ StrCat(devname, dpath);
+ }
+ } else {
+ devname[0] = CHAR_NULL;
+ }
+
+ /*
+ * create final argument list to the kernel
+ */
+ len = StrLen(BOOT_IMG_STR) /* BOOT_IMAGE= */
+ +StrLen(devname) /* device name */
+ +StrLen(kname) /* kernel name */
+ +1 /* space */
+ +StrLen(args); /* args length */
+
+ if (len >= CMDLINE_MAXLEN-1) {
+ SetTextAttr(EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK));
+ ClearScreen();
+ ERR_PRT((L" arguments list too long cannot fit BOOT_IMAGE\n"));
+ return -1;
+ }
+ StrCpy(cmdline, L"BOOT_IMAGE=");
+ StrCat(cmdline, devname);
+ StrCat(cmdline, kname);
+ StrCat(cmdline, L" ");
+ StrCat(cmdline, args);
+
+ VERB_PRT(3, Print(L"final command line is '%s'\n", cmdline));
+
+ return 0;
+}
+
+static INTN
+textmenu_probe(EFI_HANDLE dev)
+{
+ /* this chooser always works */
+ return 0;
+}
+
+chooser_t textmenu_chooser={
+ L"textmenu",
+ textmenu_probe,
+ textmenu_choose
+};
+
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Richard Hirst <rhirst@linuxcare.com>
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ * GNU EFI 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.
+ *
+ * GNU EFI 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 GNU EFI; 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_CHOOSER_TEXTMENU_H__
+#define __ELILO_CHOOSER_TEXTMENU_H__
+
+#include "fileops.h"
+
+extern chooser_t textmenu_chooser;
+
+#endif
+
+
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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.
+ *
+ * Portions of this file are derived from the LILO/x86
+ * Copyright 1992-1997 Werner Almesberger.
+ */
+
+#include <efi.h>
+#include <efilib.h>
+#include <efistdarg.h>
+
+#include "elilo.h"
+#include "config.h"
+
+/*
+ * The first default config file is architecture dependent. This is useful
+ * in case of network booting where the server is used for both types of
+ * architectures.
+ */
+#if defined(CONFIG_ia64)
+#define ELILO_ARCH_DEFAULT_CONFIG L"elilo-ia64.conf"
+#elif defined (CONFIG_ia32)
+#define ELILO_ARCH_DEFAULT_CONFIG L"elilo-ia32.conf"
+#else
+#error "You need to specfy your default arch config file"
+#endif
+
+/*
+ * last resort config file. Common to all architectures
+ */
+#define ELILO_DEFAULT_CONFIG L"elilo.conf"
+
+#define MAX_STRING CMDLINE_MAXLEN
+#define CONFIG_BUFSIZE 512 /* input buffer size */
+
+/*
+ * maximum number of message files.
+ *
+ * main message= goes at entry 0, entries [1-12] are used for function keys
+ *
+ */
+#define MAX_MESSAGES 13
+
+typedef struct boot_image {
+ struct boot_image *next;
+ CHAR16 label[MAX_STRING];
+ CHAR16 kname[FILENAME_MAXLEN];
+ CHAR16 options[MAX_STRING];
+ CHAR16 initrd[FILENAME_MAXLEN];
+ CHAR16 root[FILENAME_MAXLEN];
+ CHAR16 fallback[MAX_STRING];
+ CHAR16 description[MAX_STRING];
+
+ UINTN ramdisk;
+ UINTN readonly;
+ UINTN literal;
+
+ sys_img_options_t sys_img_opts; /* architecture specific image options */
+} boot_image_t;
+
+typedef enum {
+ TOK_ERR,
+ TOK_EQUAL,
+ TOK_STR,
+ TOK_EOF
+} token_t;
+
+/*
+ * global shared options
+ * architecture specific global options are private to each architecture
+ */
+typedef struct {
+ CHAR16 root[FILENAME_MAXLEN]; /* globally defined root fs */
+ CHAR16 initrd[FILENAME_MAXLEN];/* globally defined initrd */
+ CHAR16 options[MAX_STRING];
+ CHAR16 default_image_name[MAX_STRING];
+ CHAR16 message_file[MAX_MESSAGES][FILENAME_MAXLEN];
+ CHAR16 chooser[FILENAME_MAXLEN];/* which image chooser to use */
+ CHAR16 config_file[FILENAME_MAXLEN];
+ boot_image_t *default_image;
+
+ UINTN readonly;
+
+ /*
+ * options that may affect global elilo options
+ */
+ UINTN alt_check;
+ UINTN debug;
+ UINTN delay;
+ UINTN prompt;
+ UINTN timeout;
+ UINTN verbose;
+ UINTN edd30_no_force; /* don't force EDD30 if not set */
+} global_config_t;
+
+/*
+ * structure used to point to a group of options.
+ * Several group for the same category are supported via a linked list.
+ */
+typedef struct _config_option_group {
+ struct _config_option_group *next; /* pointer to next group */
+ config_option_t *options; /* the table of options for this group */
+ UINTN nentries; /* number of entries for this group */
+} config_option_group_t;
+
+static option_action_t do_image, do_literal, do_options;
+static INTN check_verbosity(VOID *), check_chooser(VOID *);
+
+static global_config_t global_config; /* options shared by all images */
+
+/*
+ * Core global options: shared by all architectures, all modules
+ */
+static config_option_t global_common_options[]={
+{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_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},
+{OPT_FILE, OPT_GLOBAL, L"root", NULL, NULL, global_config.root},
+{OPT_BOOL, OPT_GLOBAL, L"read-only", NULL, NULL, &global_config.readonly},
+{OPT_BOOL, OPT_GLOBAL, L"noedd30", NULL, NULL, &global_config.edd30_no_force},
+{OPT_CMD, OPT_GLOBAL, L"append", NULL, NULL, global_config.options},
+{OPT_FILE, OPT_GLOBAL, L"initrd", NULL, NULL, global_config.initrd},
+{OPT_FILE, OPT_GLOBAL, L"image", do_image, NULL, opt_offsetof(kname)},
+{OPT_BOOL, OPT_GLOBAL, L"checkalt", NULL, NULL, &global_config.alt_check},
+{OPT_STR, OPT_GLOBAL, L"chooser", NULL, check_chooser, global_config.chooser},
+{OPT_FILE, OPT_GLOBAL, L"message", NULL, NULL, global_config.message_file[0]},
+{OPT_FILE, OPT_GLOBAL, L"f1", NULL, NULL, global_config.message_file[1]},
+{OPT_FILE, OPT_GLOBAL, L"f2", NULL, NULL, global_config.message_file[2]},
+{OPT_FILE, OPT_GLOBAL, L"f3", NULL, NULL, global_config.message_file[3]},
+{OPT_FILE, OPT_GLOBAL, L"f4", NULL, NULL, global_config.message_file[4]},
+{OPT_FILE, OPT_GLOBAL, L"f5", NULL, NULL, global_config.message_file[5]},
+{OPT_FILE, OPT_GLOBAL, L"f6", NULL, NULL, global_config.message_file[6]},
+{OPT_FILE, OPT_GLOBAL, L"f7", NULL, NULL, global_config.message_file[7]},
+{OPT_FILE, OPT_GLOBAL, L"f8", NULL, NULL, global_config.message_file[8]},
+{OPT_FILE, OPT_GLOBAL, L"f9", NULL, NULL, global_config.message_file[9]},
+{OPT_FILE, OPT_GLOBAL, L"f10", NULL, NULL, global_config.message_file[10]},
+{OPT_FILE, OPT_GLOBAL, L"f11", NULL, NULL, global_config.message_file[11]},
+{OPT_FILE, OPT_GLOBAL, L"f12", NULL, NULL, global_config.message_file[12]}
+};
+
+static config_option_t image_common_options[]={
+ {OPT_FILE, OPT_IMAGE, L"root", NULL, NULL, opt_offsetof(root)},
+ {OPT_BOOL, OPT_IMAGE, L"read-only", NULL, NULL, opt_offsetof(readonly)},
+ {OPT_CMD, OPT_IMAGE, L"append", do_options, NULL, opt_offsetof(options)},
+ {OPT_CMD, OPT_IMAGE, L"literal", do_literal, NULL, NULL},
+ {OPT_FILE, OPT_IMAGE, L"initrd", NULL, NULL, opt_offsetof(initrd)},
+ {OPT_STR, OPT_IMAGE, L"label", NULL, NULL, opt_offsetof(label)},
+ {OPT_FILE, OPT_IMAGE, L"image", do_image, NULL, opt_offsetof(kname)},
+ {OPT_STR, OPT_IMAGE, L"description", NULL, NULL, opt_offsetof(description)},
+};
+
+#define OPTION_IS_GLOBAL(p) ((p)->scope == OPT_GLOBAL)
+#define OPTION_IS_IMG_SYS(p) ((p)->scope == OPT_IMAGE_SYS)
+
+#define CHAR_EOF (CHAR16)-1 /* Unicode version of EOF */
+#define CHAR_NUM0 L'0'
+#define CHAR_NUM9 L'9'
+
+static UINTN line_num;
+static INTN back; /* can go back by one char */
+
+static config_option_group_t *global_option_list;
+static config_option_group_t *image_option_list;
+
+
+static config_option_group_t *current_options;
+
+static boot_image_t *image_list, *first_image;
+static boot_image_t *current_img;
+
+static INT8 config_buf[CONFIG_BUFSIZE]; /* input buffer: file must be in ASCII! */
+static UINTN buf_max, buf_pos;
+
+static fops_fd_t config_fd;
+
+static VOID
+config_error(CHAR16 *msg,...)
+{
+ va_list ap;
+ extern UINTN _IPrint (UINTN, UINTN, SIMPLE_TEXT_OUTPUT_INTERFACE *, CHAR16 *, CHAR8 *, va_list);
+
+ Print(L"near line %d: ",line_num);
+
+ va_start(ap,msg);
+ _IPrint((UINTN)-1, (UINTN)-1, systab->ConOut, msg, NULL, ap);
+ va_end(ap);
+ Print(L"\n");
+}
+
+/*
+ * low level read routine
+ * Return:
+ *
+ * Success:
+ * - the next available unicode character
+ * Error:
+ * - CHAR_EOF : indicating error or EOF
+ *
+ * XXX: we suppose that the file is in ASCII format!
+ */
+static CHAR16
+getc(VOID)
+{
+ EFI_STATUS status;
+
+ if (buf_pos == 0 || buf_pos == buf_max) {
+ buf_max = CONFIG_BUFSIZE;
+ status = fops_read(config_fd, config_buf, &buf_max);
+ if (EFI_ERROR(status) || buf_max == 0) return CHAR_EOF;
+
+ buf_pos = 0;
+ }
+ return (CHAR16)config_buf[buf_pos++];
+}
+
+
+/*
+ * get the next unicode character with a one character
+ * rewind buffer.
+ */
+static CHAR16
+next(VOID)
+{
+ CHAR16 ch;
+
+ if (back) {
+ ch = back;
+ back = 0;
+ return ch;
+ }
+ return getc();
+}
+
+/*
+ * rewind by one character
+ */
+static VOID
+again(CHAR16 ch)
+{
+ if (back) { config_error(L"config: again invoked twice"); }
+ back = ch;
+}
+
+/*
+ * Look for matching option in the current group
+ *
+ * Return:
+ * - pointer to option if found
+ * - NULL if not found
+ */
+static config_option_t *
+find_option(config_option_group_t *grp, CHAR16 *str)
+{
+ config_option_t *p = NULL;
+ config_option_t *end;
+
+ while(grp) {
+ p = grp->options;
+ end = grp->options+grp->nentries;
+
+ while (p != end) {
+ if (!StrCmp(str, p->name)) return p;
+ p++;
+ }
+ grp = grp->next;
+ }
+ return NULL;
+}
+
+/*
+ * main parser function
+ * Return:
+ * - a token code representing the kind of element found
+ * - TOK_EOF: end-of-file (or error) detected
+ * - TOK_STR: if string is found
+ * - TOK_EQUAL: for the '=' sign
+ * - TOK_ERR: in case of (parsing) error
+ */
+static token_t
+get_token(CHAR16 *str, UINTN maxlen)
+{
+ INTN ch, escaped;
+ CHAR16 *here;
+
+ for (;;) {
+ while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n') if (ch == '\n') line_num++;
+
+ if (ch == CHAR_EOF) return TOK_EOF;
+
+ if (ch != '#') break;
+
+ /* skip comment line */
+ while ((ch = next()), ch != '\n') if (ch == CHAR_EOF) return TOK_EOF;
+ line_num++;
+ }
+ if (ch == '=') return TOK_EQUAL;
+
+ if (ch == '"') {
+ here = str;
+ while (here-str < maxlen) {
+ if ((ch = next()) == CHAR_EOF) {
+ config_error(L"EOF in quoted string");
+ return TOK_ERR;
+ }
+ if (ch == '"') {
+ *here = 0;
+ return TOK_STR;
+ }
+ if (ch == '\\') {
+ ch = next();
+ if (ch != '"' && ch != '\\' && ch != '\n') {
+ config_error(L"Bad use of \\ in quoted string");
+ return TOK_ERR;
+ }
+ if (ch == '\n') continue;
+#if 0
+ while ((ch = next()), ch == ' ' || ch == '\t');
+ if (!ch) continue;
+ again(ch);
+ ch = ' ';
+ }
+#endif
+ }
+ if (ch == '\n' || ch == '\t') {
+ config_error(L"\\n and \\t are not allowed in quoted strings");
+ return TOK_ERR;
+ }
+ *here++ = ch;
+ }
+ config_error(L"Quoted string is too long");
+ return TOK_ERR;
+ }
+
+ here = str;
+ escaped = 0;
+
+ while (here-str < maxlen) {
+ if (escaped) {
+ if (ch == CHAR_EOF) {
+ config_error(L"\\ precedes EOF");
+ return TOK_ERR;
+ }
+ if (ch == '\n') line_num++;
+ else *here++ = ch == '\t' ? ' ' : ch;
+ escaped = 0;
+ }
+ else {
+ if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '#' ||
+ ch == '=' || ch == CHAR_EOF) {
+ again(ch);
+ *here = 0;
+ return TOK_STR;
+ }
+ if (!(escaped = (ch == '\\'))) *here++ = ch;
+ }
+ ch = next();
+ }
+ config_error(L"Token is too long");
+ return TOK_ERR;
+}
+
+static INTN
+image_check(boot_image_t *img)
+{
+ boot_image_t *b;
+
+ if (img == NULL) return -1;
+
+ /* do the obvious first */
+ if (img->label[0] == '\0') {
+ config_error(L"image has no label");
+ return -1;
+ }
+
+ /* image_list points to the */
+ for(b=image_list; b; b = b->next) {
+ if (img == b) continue;
+ if (!StrCmp(img->label, b->label)) {
+ config_error(L"image with label %s already defined", img->label);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static INTN
+global_check(VOID)
+{
+ return 0;
+}
+
+static INTN
+final_check(VOID)
+{
+ boot_image_t *b;
+
+ if (global_config.default_image_name[0]) {
+ for(b=image_list; b; b = b->next) {
+ if (!StrCmp(b->label, global_config.default_image_name)) goto found;
+ }
+ config_error(L"default image '%s' not defined ", global_config.default_image_name);
+ return -1;
+ }
+ global_config.default_image = first_image;
+ return 0;
+found:
+ global_config.default_image = b;
+ return 0;
+}
+
+/*
+ * depending on the active set of options
+ * adjust the option data pointer to:
+ * if global option set:
+ * - just the straight value from p->data
+ * if image option set:
+ * - adjust as offset to image
+ * Return:
+ * - the adjusted pointer
+ */
+static inline VOID *
+adjust_pointer(config_option_t *p)
+{
+ /*
+ * adjust pointer
+ */
+ if (OPTION_IS_GLOBAL(p)) return p->data;
+
+ if (OPTION_IS_IMG_SYS(p)) return (VOID *)((UINTN)¤t_img->sys_img_opts + p->data);
+
+ return (VOID *)((UINTN)current_img + p->data);
+}
+
+/*
+ * create a new image entry
+ */
+static INTN
+do_image(config_option_t *p, VOID *str)
+{
+ boot_image_t *img;
+
+ /*
+ * if we move to a new image from the current one
+ * then we need to check for validity of current.
+ *
+ * if this is the first image, then check the global
+ * options.
+ */
+ if (current_img) {
+ if (image_check(current_img) == -1) return -1;
+ } else if (global_check() == -1) return -1;
+
+ img = (boot_image_t *)alloc(sizeof(boot_image_t), EfiLoaderData);
+ if (img == NULL) return -1;
+
+ Memset(img, 0, sizeof(boot_image_t));
+
+ DBG_PRT((L"must do image on %s", (CHAR16 *)str));
+
+ /* copy kernel file name */
+ StrCpy(img->kname, str);
+
+ /* switch to image mode */
+ current_options = image_option_list;
+
+ /* keep track of first image in case no default is defined */
+ if (image_list == NULL) first_image = img;
+
+ /* append to end of image list, so when a chooser asks for the list
+ * it gets them in the order they were in in the config file
+ */
+ if (image_list == NULL)
+ image_list = img;
+ else {
+ boot_image_t * p = image_list;
+
+ while (p->next)
+ p = p->next;
+ p->next = img;
+ }
+
+ /* update current image */
+ current_img = img;
+
+ return 0;
+}
+
+/*
+ * by default all boolean options are defined
+ * as false. This function sets the boolean
+ * to true
+ */
+static INTN
+do_boolean(config_option_t *p)
+{
+ INT8 *buf;
+
+ buf = adjust_pointer(p);
+
+ if (p->action) return p->action(p, NULL);
+
+ /* set the field to true, overwrite if already defined */
+ *buf = 1;
+
+ return 0;
+}
+
+/*
+ * the image option 'literal' requires special handling
+ * because it overrides any defined option be it global or
+ * local. so we use the option field and record the fact that
+ * it should be interpreted as literal
+ */
+static INTN
+do_literal(config_option_t *p, VOID *str)
+{
+ /*
+ * we know we have a valid current image at this point
+ */
+ StrCpy(current_img->options, str);
+
+ current_img->literal = 1;
+
+ return 0;
+}
+
+static INTN
+do_options(config_option_t *p, VOID *str)
+{
+ /* we ignore append if literal is already defined */
+ if (current_img->literal) return 0;
+
+ /*
+ * we know we have a valid current image at this point
+ */
+ StrCpy(current_img->options, str);
+
+ return 0;
+}
+
+static INTN
+do_numeric(config_option_t *p)
+{
+ CHAR16 numstr[MAX_STRING];
+ CHAR16 *str;
+ token_t tok;
+ UINTN *buf;
+ UINTN tmp;
+
+ /*
+ * match the '=' sign
+ */
+ tok = get_token(numstr, MAX_STRING);
+ if (tok != TOK_EQUAL) {
+ config_error(L"Option %s expects an equal signal + value", p->name);
+ return -1;
+ }
+
+ /*
+ * now get the value
+ * XXX: = lexer should return TOK_NUM (and we'd be done)
+ */
+ tok = get_token(numstr, MAX_STRING);
+ if (tok != TOK_STR) {
+ config_error(L"Option %s expects a value", p->name);
+ return -1;
+ }
+ str = numstr;
+ /*
+ * if there is a customized way of doing the operation
+ * do it and bypass generic
+ */
+ if (p->action) return p->action(p, str);
+
+ /*
+ * no field to update
+ */
+ if (p->data == NULL) return 0;
+
+ buf = (UINTN *)adjust_pointer(p);
+
+ while (*str && *str >= CHAR_NUM0 && *str <= CHAR_NUM9) str++;
+ if (*str) {
+ config_error(L"%s is expecting a numeric decimal value", p->name);
+ return -1;
+ }
+
+ tmp = Atoi(numstr);
+
+ if (p->check && p->check(&tmp) == -1) return -1;
+
+ /*
+ * check for multiple definitions in the same context
+ * XXX: zero must not be a valid number !
+ */
+ if (*buf) {
+ config_error(L"option %s is already defined in this context", p->name);
+ return -1;
+ }
+
+ *buf = tmp;
+
+ return 0;
+}
+
+static INTN
+check_verbosity(VOID *data)
+{
+ UINTN *val = (UINTN *)data;
+
+ if (*val > 5) {
+ config_error(L"Verbosity level must be in [0-5] and not %d", *val);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * here we simply check if chooser is compiled in. At this point, the chooser
+ * initialization is not done, so we don't know if that chooser will even be
+ * useable.
+ */
+static INTN
+check_chooser(VOID *data)
+{
+ CHAR16 *chooser = (CHAR16 *)data;
+
+ if (exist_chooser(chooser) == -1) {
+ config_error(L"chooser %s is unknown\n", chooser);
+ return -1;
+ }
+ return 0;
+}
+
+
+static INTN
+do_string_core(config_option_t *p, CHAR16 *str, UINTN maxlen, CHAR16 *msg)
+{
+ token_t tok;
+ CHAR16 *buf;
+
+ /*
+ * match the '=' sign
+ */
+ tok = get_token(str, maxlen);
+ if (tok != TOK_EQUAL) {
+ config_error(L"Option %s expects an equal signal + %s", p->name, msg);
+ return -1;
+ }
+
+ /*
+ * now get the value
+ */
+ tok = get_token(str, maxlen);
+ if (tok != TOK_STR) {
+ config_error(L"Option %s expects %s", p->name, msg);
+ return -1;
+ }
+
+ /*
+ * if there is a customized way of doing the operation
+ * do it and bypass generic
+ */
+ if (p->action) return p->action(p, str);
+
+ /*
+ * no field to update
+ */
+ if (p->data == NULL) return 0;
+
+ buf = adjust_pointer(p);
+
+ if (*buf != CHAR_NULL) {
+ config_error(L"'%s' already defined", p->name);
+ return -1;
+ }
+ if (p->check && p->check(str) == -1) return -1;
+
+ /*
+ * initialize field
+ */
+ StrCpy(buf, str);
+
+ return 0;
+}
+
+static INTN
+do_string(config_option_t *p)
+{
+ CHAR16 str[MAX_STRING];
+
+ return do_string_core(p, str, MAX_STRING, L"string");
+}
+
+static INTN
+do_file(config_option_t *p)
+{
+ CHAR16 str[FILENAME_MAXLEN];
+
+ return do_string_core(p, str, FILENAME_MAXLEN, L"filename");
+}
+
+
+static INTN
+do_cmd(config_option_t *p)
+{
+ CHAR16 str[CMDLINE_MAXLEN];
+ return do_string_core(p, str, CMDLINE_MAXLEN, L"kernel options");
+}
+
+
+INTN
+config_parse(VOID)
+{
+ CHAR16 str[MAX_STRING];
+ INTN ret = -1;
+ token_t tok;
+ config_option_t *p;
+
+ for (;;) {
+ tok = get_token(str, MAX_STRING);
+
+ if (tok == TOK_EOF) break;
+
+ if (tok == TOK_ERR) return -1;
+
+ if ( (p = find_option(current_options, str)) == NULL) {
+ config_error(L"Unkown option %s", str);
+ return -1;
+ }
+
+ /* make sure we trap in case of error */
+ ret = -1;
+
+ switch(p->type) {
+ case OPT_BOOL:
+ ret = do_boolean(p);
+ break;
+ case OPT_STR:
+ ret = do_string(p);
+ break;
+ case OPT_NUM:
+ ret = do_numeric(p);
+ break;
+ case OPT_FILE:
+ ret = do_file(p);
+ break;
+ case OPT_CMD:
+ ret = do_cmd(p);
+ break;
+ default:
+ config_error(L"Unkown option type %d", p->type);
+ }
+ if (ret == -1) goto error;
+ }
+ if (current_img) {
+ ret = image_check(current_img);
+ } else {
+ config_error(L"No image defined !");
+ }
+ if (ret == 0) ret = final_check();
+error:
+ return ret;
+}
+
+static VOID
+update_elilo_opt(VOID)
+{
+ /*
+ * update boolean options first
+ * Rule: by default not set unless explcitely requested on command line
+ * therefore we can just update from global_config is set there.
+ */
+ if (global_config.alt_check) elilo_opt.alt_check = 1;
+
+ if (global_config.debug) elilo_opt.debug = 1;
+ if (global_config.prompt) elilo_opt.prompt = 1;
+
+ /*
+ * update only if not set on command line
+ * XXX: rely on the existence of a non-valid value as a marker than
+ * the option was not specified on the command line
+ */
+ if (global_config.verbose && elilo_opt.verbose == 0)
+ elilo_opt.verbose = global_config.verbose;
+
+ if (global_config.chooser[0] && elilo_opt.chooser[0] == 0)
+ StrCpy(elilo_opt.chooser, global_config.chooser);
+
+ /*
+ * if edd30_no_force not set by command line option but via config
+ * file, then propagate
+ */
+ if (global_config.edd30_no_force && elilo_opt.edd30_no_force == 0)
+ elilo_opt.edd30_no_force = 1;
+
+ /*
+ * Difficult case of numeric where 0 can be a valid value
+ * XXX: find a better way of handling these options!
+ */
+ if (global_config.delay && elilo_opt.delay_set == 0)
+ elilo_opt.delay = global_config.delay;
+
+ /* readjusted by caller if necessary. 0 not a valid value here */
+ elilo_opt.timeout = global_config.timeout;
+
+ /* initrd is updated later when we have an image match */
+}
+
+/*
+ * When called after read_config(), this function returns the config file
+ * used by the loader, or NULL if no file was found.
+ */
+CHAR16 *
+get_config_file(VOID)
+{
+ return global_config.config_file[0] ? global_config.config_file : NULL;
+}
+
+EFI_STATUS
+read_config(CHAR16 *filename, INTN retry)
+{
+ EFI_STATUS status;
+ INTN ret;
+
+ if (filename == NULL) return EFI_INVALID_PARAMETER;
+
+ VERB_PRT(3, Print(L"trying config file %s\n", filename));
+
+ StrCpy(global_config.config_file, filename);
+
+ status = fops_open(filename, &config_fd);
+ if (EFI_ERROR(status)) {
+ /*
+ * if the user explicitely specified a filename and we can't
+ * find it, then we must fail.
+ */
+ if (elilo_opt.parse_only || retry == 0) {
+ VERB_PRT(3, Print(L"cannot open config file %s\n", filename));
+ return status;
+ }
+ /*
+ * if not already submitted filename,
+ */
+ if (StrCmp(filename, ELILO_ARCH_DEFAULT_CONFIG)) {
+ /*
+ * try the arch default file, now
+ */
+ VERB_PRT(3,Print(L"config file %s not found, trying %s\n",
+ filename, ELILO_ARCH_DEFAULT_CONFIG));
+
+ StrCpy(global_config.config_file,ELILO_ARCH_DEFAULT_CONFIG);
+
+ status = fops_open(ELILO_ARCH_DEFAULT_CONFIG, &config_fd);
+ }
+ /*
+ * if arch specific did not work, try generic
+ */
+ if (EFI_ERROR(status) && StrCmp(filename, ELILO_DEFAULT_CONFIG)) {
+ /*
+ * try the default file as a last resort
+ */
+ VERB_PRT(3,Print(L"config file %s not found, trying %s\n",
+ ELILO_ARCH_DEFAULT_CONFIG, ELILO_DEFAULT_CONFIG));
+
+ StrCpy(global_config.config_file, ELILO_DEFAULT_CONFIG);
+ status = fops_open(ELILO_DEFAULT_CONFIG, &config_fd);
+ }
+ /*
+ * if nothing worked, then bail out
+ */
+ if (EFI_ERROR(status)) {
+ VERB_PRT(3, Print(L"no valid config file found\n"));
+ global_config.config_file[0] = CHAR_NULL;
+ return status;
+ }
+ }
+ /*
+ * start numbering at line 1
+ */
+ line_num = 1;
+
+ ret = config_parse();
+
+ fops_close(config_fd);
+
+ DBG_PRT((L"done parsing config file\n"));
+
+ if (ret != 0) return EFI_INVALID_PARAMETER;
+
+ update_elilo_opt();
+
+ return EFI_SUCCESS;
+}
+
+VOID
+print_label_list(VOID)
+{
+ boot_image_t *img, *dfl = global_config.default_image;
+
+ if (dfl) Print(L"%s ", dfl->label);
+
+ for (img = image_list; img; img = img->next) {
+ if (img != dfl) Print(L"%s ", img->label);
+ }
+}
+
+/* Make labels and corresponding descriptions available to choosers. The
+ * idea is that the caller passes NULL for 'prev'; the first time, and
+ * passes the previously returned value on subsequent calls. The caller
+ * repeats until this fn returns NULL.
+ */
+
+VOID *
+get_next_description(VOID *prev, CHAR16 **label, CHAR16 **description)
+{
+ boot_image_t *img = (boot_image_t *)prev;
+
+ if (img == NULL)
+ img = image_list;
+ else
+ img = img->next;
+
+ if (img) {
+ *label = img->label;
+ *description = img->description;
+ return (void *)img;
+ }
+ else
+ return NULL;
+}
+
+/*
+ * find a description using the label name
+ * return NULL if label not found or no description defined
+ */
+CHAR16 *
+find_description(CHAR16 *label)
+{
+ boot_image_t *img;
+
+ /* Attempt to find the image name now */
+ for (img = image_list; img; img = img->next) {
+ if (StriCmp(img->label, label) == 0) {
+ return img->description;
+ }
+ }
+ return NULL;
+}
+
+INTN
+find_label(CHAR16 *label, CHAR16 *kname, CHAR16 *options, CHAR16 *initrd)
+{
+ boot_image_t *img;
+
+ if (label == NULL) {
+ if (global_config.default_image == NULL) return -1;
+ img = global_config.default_image;
+ goto found;
+ }
+
+ options[0] = 0;
+
+ /* Attempt to find the image name now */
+ for (img = image_list; img; img = img->next) {
+ if (StriCmp(img->label, label) == 0) {
+ goto found;
+ }
+ }
+ /*
+ * when the label does not exist, we still propagate the global options
+ */
+ if (global_config.root[0]) {
+ StrCpy(options, L" root=");
+ StrCat(options, global_config.root);
+ }
+
+ if (global_config.options[0]) {
+ StrCat(options, L" ");
+ StrCat(options, global_config.options);
+ }
+ if (global_config.readonly) StrCat(options, L" ro");
+
+ if (global_config.initrd[0]) StrCpy(initrd, global_config.initrd);
+
+ /* make sure we don't get garbage here */
+ elilo_opt.sys_img_opts = NULL;
+
+ return -1;
+found:
+ StrCpy(kname, img->kname);
+
+ /*
+ * literal option overrides any other image-based or global option
+ *
+ * In any case, the image option has priority over the global option
+ */
+ if (img->literal == 0) {
+ if (img->root[0] || global_config.root[0]) {
+ StrCat(options, L"root=");
+ StrCat(options, img->root[0] ? img->root : global_config.root);
+ }
+ /* XXX: check max length */
+ if (img->options[0] || global_config.options[0]) {
+ StrCat(options, L" ");
+ StrCat(options, img->options[0] ? img->options: global_config.options);
+ }
+ if (img->readonly || global_config.readonly) {
+ StrCat(options, L" ro");
+ }
+ } else {
+ /* literal options replace everything */
+ StrCpy(options, img->options);
+ }
+
+ /* per image initrd has precedence over global initrd */
+ if (img->initrd[0])
+ StrCpy(initrd, img->initrd);
+ else if (global_config.initrd[0])
+ StrCpy(initrd, global_config.initrd);
+
+ /*
+ * point to architecture dependent options for this image
+ */
+ elilo_opt.sys_img_opts = &img->sys_img_opts;
+
+ DBG_PRT((L"label %s: kname=%s options=%s initrd=%s", img->label, kname, options, initrd));
+
+ return 0;
+}
+
+static VOID
+print_options(config_option_group_t *grp, BOOLEAN first)
+{
+ config_option_t *end, *p;
+ CHAR16 *str;
+
+ while (grp) {
+ p = grp->options;
+ end = grp->options+grp->nentries;
+ while (p != end) {
+ str = NULL;
+ switch(p->type) {
+ case OPT_BOOL:
+ str = L"%s";
+ break;
+ case OPT_STR :
+ str = L"%s=string";
+ break;
+ case OPT_FILE :
+ str = L"%s=filename";
+ break;
+ case OPT_CMD :
+ str = L"%s=kernel_options";
+ break;
+ case OPT_NUM :
+ str = L"%s=number";
+ break;
+ default:
+ break;
+ }
+ if (str && first == FALSE) Print(L", ");
+ if (str) Print(str, p->name);
+ first = FALSE;
+ p++;
+ }
+ grp = grp->next;
+ }
+}
+
+
+VOID
+print_config_options(VOID)
+{
+ Print(L"Global options supported:\n");
+
+ print_options(global_option_list, TRUE);
+ Print(L"\n\n");
+
+ Print(L"Image options supported:\n");
+ print_options(image_option_list, TRUE);
+ Print(L"\n");
+}
+
+
+/*
+ * returns a pointer to filename used for message N (which). NULL if it does
+ * not exist.
+ */
+CHAR16 *
+get_message_filename(INTN which)
+{
+ if (which < 0 || which >= MAX_MESSAGES) return NULL;
+ return global_config.message_file[which];
+}
+
+INTN
+register_config_options(config_option_t *opt, UINTN n, config_option_group_scope_t group)
+{
+ config_option_group_t *newgrp, **grp;
+
+ if (opt == NULL || n == 0 || (group != OPTIONS_GROUP_GLOBAL && group != OPTIONS_GROUP_IMAGE)) return -1;
+
+ VERB_PRT(3, Print(L"registering %d options for group %s\n", n, group == OPTIONS_GROUP_GLOBAL ? L"global" : L"image"));
+
+ newgrp = alloc(sizeof(config_option_group_t), EfiLoaderData);
+ if (newgrp == NULL) return -1;
+
+ grp = group == OPTIONS_GROUP_GLOBAL ? &global_option_list : &image_option_list;
+
+ if (*grp) while ((*grp)->next) grp = &(*grp)->next;
+
+ newgrp->options = opt;
+ newgrp->next = NULL;
+ newgrp->nentries = n;
+
+ if (*grp) {
+ (*grp)->next = newgrp;
+ } else {
+ *grp = newgrp;
+ }
+ return 0;
+}
+
+/*
+ * initialize config options: register global and per image options
+ */
+INTN
+config_init(VOID)
+{
+ INTN ret;
+
+ ret = register_config_options(global_common_options,
+ sizeof(global_common_options)/sizeof(config_option_t),
+ OPTIONS_GROUP_GLOBAL);
+ if (ret == -1) return -1;
+
+ ret = register_config_options(image_common_options,
+ sizeof(image_common_options)/sizeof(config_option_t),
+ OPTIONS_GROUP_IMAGE);
+
+ current_options = global_option_list;
+
+ return ret;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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_CONFIG_H__
+#define __ELILO_CONFIG_H__
+
+#define opt_offsetof(opt) (&((boot_image_t *)(0x0))->opt)
+
+typedef enum { OPT_NOTUSED, OPT_STR, OPT_CMD, OPT_BOOL, OPT_NUM, OPT_FILE } config_option_type_t;
+
+typedef enum { OPT_GLOBAL, /* global and shared among architectures */
+ OPT_IMAGE, /* per image only and shared among architectures */
+ OPT_IMAGE_SYS /* per image and architecture specific (offset base in sys_img_opts) */
+} config_option_scope_t;
+
+typedef enum { OPTIONS_GROUP_GLOBAL, /* group must be added to global set of options */
+ OPTIONS_GROUP_IMAGE, /* group must be added to per-image set of options */
+} config_option_group_scope_t;
+
+struct _config_option_t;
+typedef INTN option_action_t(struct _config_option_t *, VOID *);
+
+typedef struct _config_option_t {
+ config_option_type_t type; /* option type: OPT_CMD, OPT_BOOL, ... */
+ config_option_scope_t scope; /* option scope: global, per image, per image_sys */
+ CHAR16 *name; /* unicode string for the option */
+ option_action_t *action; /* option specific action */
+ INTN (*check)(void *); /* check valid arguments, NULL=don't need */
+ VOID *data; /* which data structure to record the option */
+} config_option_t;
+
+extern INTN register_config_options(config_option_t *opt, UINTN nentries, config_option_group_scope_t);
+
+#endif /* __ELILO_CONFIG_H__ */
--- /dev/null
+#
+# Copyright (C) 2001-2003 Hewlett-Packard Co.
+# Contributed by Stephane Eranian <eranian@hpl.hp.com>
+#
+# 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 ../Make.defaults
+include ../Make.rules
+
+TOPDIR=$(CDIR)/..
+
+FILES=simple.o
+
+
+TARGET=devschemes.o
+
+all: $(TARGET)
+
+#
+# XXX: does not trigger recompile when changing filesystem selection
+# without doing make clean.
+#
+$(TARGET): $(FILES)
+ $(LD) -r -o $@ $(FILES)
+
+clean:
+ $(RM) -f $(TARGET) $(FILES)
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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.
+ *
+ * Look at the README.devschemes for more explanations on how
+ * to use devschemes.
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "elilo.h"
+#include "fileops.h"
+
+#define NAMING_SCHEME L"simple"
+
+typedef struct {
+ INT8 type;
+ INT8 subtype;
+ INTN (*device_func)(device_t *dev, EFI_DEVICE_PATH *dp);
+} devices_types_t;
+
+
+static UINT32 atapi_count, scsi_count, net_count;
+
+static INTN
+atapi_device(device_t *dev, EFI_DEVICE_PATH *dp)
+{
+ //ATAPI_DEVICE_PATH *atapi = (ATAPI_DEVICE_PATH *)dp;
+
+ dev->name[0] = L'a';
+ dev->name[1] = L't';
+ dev->name[2] = L'a';
+ dev->name[3] = L'p';
+ dev->name[4] = L'i';
+
+ SPrint(dev->name+5,FILEOPS_DEVNAME_MAXLEN-5-1, L"%d", atapi_count);
+ atapi_count++;
+
+ return 0;
+}
+
+static INTN
+scsi_device(device_t *dev, EFI_DEVICE_PATH *dp)
+{
+ //SCSI_DEVICE_PATH *scsi = (SCSI_DEVICE_PATH *)dp;
+
+ dev->name[0] = L's';
+ dev->name[1] = L'c';
+ dev->name[2] = L's';
+ dev->name[3] = L'i';
+
+ SPrint(dev->name+4, FILEOPS_DEVNAME_MAXLEN-4-1, L"%d", scsi_count);
+ scsi_count++;
+
+ return 0;
+}
+
+static INTN
+network_device(device_t *dev, EFI_DEVICE_PATH *dp)
+{
+ //MAC_ADDR_DEVICE_PATH *mac = (MAC_ADDR_DEVICE_PATH *)dp;
+
+ dev->name[0] = L'n';
+ dev->name[1] = L'e';
+ dev->name[2] = L't';
+
+ SPrint(dev->name+3, FILEOPS_DEVNAME_MAXLEN-3-1, L"%d", net_count);
+ net_count++;
+
+ return 0;
+}
+
+/*
+ * what we are looking for in the device path
+ */
+static devices_types_t dev_types[]={
+ { MESSAGING_DEVICE_PATH, MSG_ATAPI_DP, atapi_device},
+ { MESSAGING_DEVICE_PATH, MSG_SCSI_DP, scsi_device},
+ { MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, network_device},
+ { 0, 0 , NULL}
+};
+
+static INTN
+simple_scheme(device_t *tab, UINTN n)
+{
+ EFI_DEVICE_PATH *dp1, *dp;
+ devices_types_t *p;
+ UINTN i;
+
+ /*
+ * note that this test is necessary but not sufficient to guarantee that this scheme
+ * will work because, we have no way of detecting that the machine got actually
+ * rebooted if the EDD30 variable was forced. this comes from the fact, that elilo
+ * can be invoked once, aborted and then restarted with no machine reboot.
+ *
+ * XXX: there may be a way to detect this with the another variable which would
+ * be in volatile memory only
+ */
+ if (elilo_opt.edd30_on == 0) {
+ VERB_PRT(4, Print(L"%s device naming scheme only works with EDD3.0 enabled\n", NAMING_SCHEME));
+ return -1;
+ }
+
+ for(i=0; i < n; i++) {
+ dp = DevicePathFromHandle(tab[i].dev);
+ if (dp == NULL) {
+ ERR_PRT((L"cannot get device path for device %d", i));
+ continue;
+ }
+ dp1 = dp = UnpackDevicePath(dp);
+
+ while (!IsDevicePathEnd(dp)) {
+ p = dev_types;
+ while (p->type) {
+ if ( p->type == DevicePathType(dp)
+ && p->subtype == DevicePathSubType(dp)) {
+ (*p->device_func)(tab+i, dp);
+ goto done;
+ }
+
+ p++;
+ }
+ dp = NextDevicePathNode(dp);
+ }
+done:
+ FreePool(dp1);
+ }
+ return 0;
+}
+
+devname_scheme_t simple_devname_scheme={
+ NAMING_SCHEME,
+ simple_scheme
+};
--- /dev/null
+
+Some explanations of what the devschemes are for:
+-------------------------------------------------
+Copyright (c) 2001-2003 Hewlett-Packard Co
+Contributed by Stephane Eranian <eranian@hpl.hp.com>
+
+
+ Whether or not EDD3.0 is enabled, EFI uses a device naming scheme which is
+ somewhat detailed. It tries to follow the hardware path from the System bus
+ down to the actual partition on the media. The following example shows
+ a typical block device path from a SCSI disk:
+
+ blk2 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part1,Sig00000000).
+
+ Elilo allows the user to load files from any device. This means that it
+ must provide a way for the user to specify a file path which include
+ the device name. While it is theoritically possible to specify the
+ path mentioned above, it is far from practical because the names
+ are too long. There is too much details which the user (especially of
+ a boot loader) does not care about.
+
+ So Elilo, just like the EFI shell, must have a way of assigning logical
+ names to device names (paths). The EFI shell uses the fsX notation wherever
+ it finds a block devices for which it has detected a valid EFI filesystem
+ (i.e. a Fat32+ filesystem). This assignment is done on the fly, and depending
+ on the status of the removable media (like CDROM or floppy) the mapping can
+ change.
+
+ Those fsX: names are a pure abstraction of the EFI shell and have nothing to
+ do with the EFI specification.
+
+ Now Elilo could try to emulate then, i.e. try to reproduce the way the EFI shell
+ assigns names. However the problem is that, AT THIS POINT, Elilo recognized more
+ device from which it can load files from than the Shell does. This comes from the
+ fact that it can load files from the network or from an Ext2fs, for instance.
+ We plan on fixing those issues in the next releases of Elilo. Anyway, the problem
+ would still be to make sure that if we follow the same naming scheme, they match
+ at all times, i.e. fs0: maps to the same device in both the EFI shell and Elilo
+ which may be tricky as both EFI and Elilo continue to evolve. Also the Shell
+ naming schemes as some problems which removable devices which would not make it
+ easy from the bootloader.
+
+ Another possible solution would be to use the Linux kernel naming scheme, i.e.,
+ hda, hda1, fd0, sda... Of course, we would drop the /dev prefix in this case.
+ While it would make it very convenient for users and easy to configure from
+ a running system, it is even more difficult that the EFI Shell scheme. Again,
+ to succeed, the loader scheme would have to match EXACTLY what the Linux kernel
+ does for all possible devices. This is a very complicated task as his any
+ naming problem. The recent discussions about the devfs support in the kernel is
+ just yet another proof of the complexity. Another issue here is that this would
+ create a dependency between the loader and the kernel because we would need the
+ way the naming is done in the kernel. Again, this is very complicated, just thinnking
+ about how the PCI buses are scanned looking from devices.
+
+ So it looks like there is single solutions. Clearly, that is not easy and there are
+ multiple schemes possible. For now, we felt that it was better for Elilo to use its
+ own naming scheme independent from the EFI shell and the Linux kernel. While this introduces
+ yet another scheme, we believe its advantages outweight the software complexity associated
+ with the two schemes described above.
+
+ However, we recognize the need for flexibilty and that is exactly why, this version
+ of Elilo provide an internal interface which can used to develop custom naming schemes.
+
+ The way the filepaths are translated by Elilo is very basic and based on a simple
+ string matching algorithm. A full pathname is specified as follows:
+
+ dev_name:/path/to/my/file.
+
+ The 'dev_name' is created by Elilo and can be anything relevant to the user. There is
+ an internal binding from the name to the actual EFI device handle and more precisely
+ the filsystem interface associated to it (the device handle is never exposed to the
+ boot loader).
+
+ By default, Elilo uses an extremely simple scheme which is similar to the EFI shell.
+ if simply builds the device names as follows:
+
+ devXXX.
+
+ The XXX is just the number of the device. It is incremented by one each time recognized
+ filesystem is detected on that device. The clear advantage is simplicity. The downside
+ is that is creates a 'flat' namespace where every new device detected (like a floppy
+ is inserted) will show up anywhere in the set of devices and may push some fixed
+ devices up or down. So it hard to rely on devXXX to always mean the same things.
+
+ Now custom naming schemes can be added on top of this, which would partially or totally
+ replace this default scheme. Elilo is shipped with one such scheme called 'simple'.
+ It provides an example of how one can develop a new scheme. The main characteristic
+ of 'simple' is that it tries to group devices by controller (Messaging Device in
+ EFI terminology). Hence, all the ATAPI devices show up as atapiXXX and the SCSI
+ device show up as SCSIXXX. This implicitely shields the SCSI (fixed most likely) devices
+ from the removable media coming from ATAPI (like floppy or CDROM). So it is slightly
+ better but far from perfect.
+
+ Here is an example of what it looks like on an actual system:
+
+ scsi0 : vfat : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part1,Sig00000000)
+ scsi1 : vfat : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part1,Sig00000000)
+ atapi0 : vfat : Acpi(PNP0A03,0)/Pci(3|1)/Ata(Secondary,Master)/CDROM(Entry1)
+ scsi2 : ext2fs : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part2,Sig00000000)
+ scsi3 : ext2fs : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part2,Sig00000000)
+ net0 : netfs : Acpi(PNP0A03,0)/Pci(5|0)/Mac(00D0B7A6FC25)
+
+
+ The 'simple' scheme is not fully satifactory but developers are strongly encouraged
+ to enhance it or better create new schemes.
+
--- /dev/null
+Information related to EDD3.0 and ELILO
+---------------------------------------
+Last updated: 02/02/14
+
+As of elilo-3.0, the filesystem/device naming scheme takes advantage
+of the EDD3.0 support present in the underlying EFI/BIOS firmware layers.
+
+The EDD3.0 support is supposedly turned on by default in all version of the
+EFI firmware on IA-64 (and possibly IA-32).
+
+Support can be enabled or disabled dynamically using an EFI environment
+variable called "EDD30". The GUID of the variable is as follows:
+
+#define EDD30_GUID \
+{0x964e5b21, 0x6459, 0x11d2, { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}}
+
+This is a boolean variable. When true, support is enabled.
+You can check if support is enabled by typing:
+
+ Shell> edd30
+ Usage edd30 [On | Off]
+ Used to support OS Loader debug
+ EDD30 DevicePath Mode is On
+
+at this EFI shell prompt. You can enable support by forcing the variable
+to TRUE. This can be accomplished by typing:
+
+ Shell> edd30 on
+ EDD30 DevicePath Mode is On
+
+Alternatively an EFI application can use RT->SetVariable() to set the
+value of the EDD30 variable.
+
+If the variable was set to false, then to take advantage of EDD3.0
+support after switching the variablle to TRUE, the system MUST be
+rebooted as EDD affects the core of EFI naming scheme.
+
+Elilo will check if the variable is defined and valid. If it is set
+to true, then the device name schemes that rely on it will work properly.
+That's the case for the 'simple' scheme. If the variable is not set to true
+or does not exist, elilo will use a generic builtin scheme with names
+such as dev001, dev002 and so on. The "EDD30" variable is like a system
+variable therefore it is expected not to be overloaded by users for others
+purposes. Elilo is fully functional even when EDD30 is off.
+
+By default, if EDD30 is off, elilo will try and set the variable to TRUE.
+However, some controllers do not support EDD30 and forcing the variable
+may cause problems. Therefore as of elilo-3.2, there is an option to
+avoid forcing the variable. In the config file, you can use 'noedd30' option
+and on the command line, you can use the -E option.
+
+When the variable is forced back to TRUE, th effect will only be seen after
+a reboot. Shall you decide not to reboot immediately, elilo
+will system still operate using the generic naming scheme.
+
+When EDD3.0 is enabled the output of the EFI shell 'map' command looks similar
+to this:
+
+Device mapping table
+ fs0 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part1,Sig00000000)
+ fs1 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part1,Sig00000000)
+ fs2 : Acpi(PNP0A03,0)/Pci(3|1)/Ata(Secondary,Master)/CDROM(Entry1)
+ blk0 : Acpi(PNP0A03,0)/Pci(3|1)/Ata(Primary,Master)
+ blk1 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)
+ blk2 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part1,Sig00000000)
+ blk3 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part2,Sig00000000)
+ blk4 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part3,Sig00000000)
+ blk5 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)
+ blk6 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part1,Sig00000000)
+ blk7 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part2,Sig00000000)
+ blk8 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part3,Sig00000000)
+ blk9 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part3,Sig00000000)/HD(Part1,Sig00000200)
+ blkA : Acpi(PNP0A03,0)/Pci(3|1)/Ata(Secondary,Master)
+ blkB : Acpi(PNP0A03,0)/Pci(3|1)/Ata(Secondary,Master)/CDROM(Entry1)
+Shell>
+
+The same system with EDD3.0 disabled will look like this:
+Device mapping table
+ fs0 : VenHw(Unknown Device:80)/HD(Part1,Sig00000000)
+ fs1 : VenHw(Unknown Device:81)/HD(Part1,Sig00000000)
+ fs2 : VenHw(Unknown Device:FF)/CDROM(Entry1)
+ blk0 : VenHw(Unknown Device:00)
+ blk1 : VenHw(Unknown Device:80)
+ blk2 : VenHw(Unknown Device:80)/HD(Part1,Sig00000000)
+ blk3 : VenHw(Unknown Device:80)/HD(Part2,Sig00000000)
+ blk4 : VenHw(Unknown Device:80)/HD(Part3,Sig00000000)
+ blk5 : VenHw(Unknown Device:81)
+ blk6 : VenHw(Unknown Device:81)/HD(Part1,Sig00000000)
+ blk7 : VenHw(Unknown Device:81)/HD(Part2,Sig00000000)
+ blk8 : VenHw(Unknown Device:81)/HD(Part3,Sig00000000)
+ blk9 : VenHw(Unknown Device:81)/HD(Part3,Sig00000000)/HD(Part1,Sig00000200)
+ blkA : VenHw(Unknown Device:FF)
+ blkB : VenHw(Unknown Device:FF)/CDROM(Entry1)
+Shell>
+
+
+EDD3.0 is an industry standard and the working draft can be downloaded from the
+following web site:
+ http://www.t13.org/
+
+The document reference is D1386 (Enhanced Disk Drive Services 3.0).
+
--- /dev/null
+ --------------------------------------------------------------------
+ ELILO.EFI: Linux boot loader for EFI/IA-64 and EFI/IA-32 based systems
+ --------------------------------------------------------------------
+ Stephane Eranian <eranian@hpl.hp.com>
+
+ August 2003
+
+ Copyright (C) 2000-2003 Hewlett-Packard Co.
+
+
+I/ Introduction
+ ------------
+
+This document describes how to use ELILO on for both IA-64 and IA-32 EFI-based platforms.
+This document describes ELILO version 3.4.
+
+II/ Command line options
+ --------------------
+
+ elilo [-hDpPVvaE] [-d nsec] [-C config] [-i initrd] [-c chooser] [kernel [kernel options...]]
+
+ -h Display a list of all possible command line options.
+
+ -V Print the version number and exit.
+
+ -d nsec Specify the number of 10th of seconds before loading the
+ kernel.
+
+ -C file Specify the config file to use. The default is elilo.conf in the directory
+ that elilo.efi was loaded from.
+
+ -P Verify config file syntax only. this option causes ELILO to
+ parse the config file and generate a report on the console.
+ No kernel is loaded.
+
+ -v Turn on verbose mode. ELILO prints more message about what it
+ is doing. For each occurrence of this option the verbosity level
+ is increased by one. The maximum level is 5.
+
+ -a Always check for alternate kernel image. The default behavior
+ of ELILO is to NOT look for an alternate image. This
+ option overrides this behavior and ELILO is checking for
+ alternate images no matter what. Alternate images are
+ specified using the EliloAlt EFI variable.
+
+ -p force interactive prompt mode. Valid when no kernel image is
+ specified on the command line.
+
+ -D print debug output.
+
+ -E don't force EDD30 variable to TRUE when FALSE.
+
+ -i file Use file as the initial ramdisk (initrd).
+
+ -c name Specify which kernel chooser to use. Default is 'simple', and
+ the only other choice at present is 'textmenu'.
+
+ In addition, elilo supports platform specific options:
+
+ For IA-64:
+ ----------
+ -r the kernel image can be relocated if initial load address is not
+ available. This options requires a special version of the kernel.
+
+ -F file will try to load the FPSWA driver indicated by 'file'. Only this file
+ will be attempted. When no specific file is given, elilo will try
+ loading \efi\intel firmware\fpswa.efi from all accessible EFI system
+ partitions.
+ For IA-32:
+ ----------
+ no option defined.
+
+ All file names (including the kernel file) can include a device name using the
+ following syntax:
+
+ dev_name:/path/to/my/kernel
+
+ The 'dev_name' component depends on the naming scheme selected and the detected
+ devices for your system. Some choosers may print the information automatically
+ or on demand, see chooser specific documentation for more on this. See README.devschemes
+ for more information on device naming schemes. The slash character '/' can be used as
+ a directory separator on any file systems including the EFI file system (FAT32).
+
+
+III/ Configuration File
+ ------------------
+
+ ELILO supports a config file with options similar to the LILO/x86 boot loader.
+
+ Elilo will use the following sequence (shown in order) when looking for its config
+ file when none is specified on the command line:
+
+ 1/ AABBCCDD.conf (netbooting with regular DHCP)
+ where AABBCCDD is the hexadecimal representation
+ of the IP address assigned during the DHCP phase.
+
+ 2/ elilo-ia64.conf or elilo-ia32.conf
+ The choice depends on the client platform. This step allows
+ the same DHCP/PXE server to provide files for both types of clients.
+
+ 3/ elilo.conf
+
+ Unless explicitly specified on the command line, elilo looks for its config file
+ in the filesystem and directory it was loaded from. For instance, if elilo.efi
+ is invoked as:
+
+ fs0:\> \efi\debian\elilo.efi
+
+ Then elilo will look for its configuration file in fs0:\efi\debian and not
+ in the root directory of fs0:. The prefix fs0:\efi\debian will be used for
+ all other files that elilo needs to download when their paths are specified
+ as being relative.
+
+ IMPORTANT:
+ This rule also applies when a specific config file is passed via the -C
+ option. For example:
+
+ fs0:\> \efi\debian\elilo.efi -C elilo.conf
+
+ This will look for elilo.conf in fs0:\efi\debian and not in fs0:\.
+ To get to the elilo.conf in fs0:\, you need to specify the absolute
+ path:
+
+ fs0:\> \efi\debian\elilo.efi -C \elilo.conf
+
+
+ The configuration file is an ASCII file and not a UNICODE file.
+
+ The config file contains additional options to change the behavior of the loader.
+ If the same option is specified in the config file AND on the command line, the
+ latter takes precedence. Not all options available in the config file have an
+ equivalent on command line.
+
+ When elilo is invoked with the -h option, it prints the list of support command line
+ options but also the list of config file options. For each option it also prints
+ the type of data expected.
+
+ The config file options are divided in 2 groups:
+
+
+ - image options which are specific to a particular kernel image. Each kernel image
+ must be identified with a logical name called a label.
+
+ - global options which affect the behavior of ELILO and apply to all images.
+
+ The ELILO config file follows the LILO/x86 syntax. First come the global
+ options, then the list of images and options for each of them, if
+ necessary. At least one image MUST be defined and it is possible to have
+ an empty list of global options.
+
+ Options have types. Three types are defined:
+ - boolean: set or not set
+ - string : a string of characters which can be quoted if necessary
+ - number (in decimal)
+ - filename: a string interpreted as a file name
+
+
+ The config file supports the following options:
+
+ Global Options:
+ ---------------
+ default=value Name the default image to boot. If not defined ELILO
+ will boot the first defined image.
+
+ timeout=number The number of 10th of seconds to wait while in
+ interactive mode before auto booting default kernel.
+ Default is infinity.
+
+ delay=number The number of 10th of seconds to wait before
+ auto booting when not in interactive mode.
+ Default is 0.
+
+ prompt Force interactive mode
+
+ verbose=number Set level of verbosity [0-5]. Default 0 (no verbose)
+
+ root=filename Set global root filesystem for Linux/ia64
+
+ read-only Force root filesystem to be mounted read-only
+
+ append=string Append a string of options to kernel command line
+
+ initrd=filename Name of initrd file
+
+ image=filename Define a new image
+
+ chooser=name Specify kernel chooser to use: 'simple' or 'textmenu'.
+
+ message=filename a message that is printed on the main screen if supported by
+ the chooser.
+
+ fX=filename Some choosers may take advantage of this option to
+ display the content of a file when a certain function
+ key X is pressed. X can vary from 1-12 to cover
+ function keys F1 to F12.
+
+ noedd30 do not force the EDD30 EFI variable to TRUE when FALSE. In other
+ words, don't force the EDD30 mode if not set.
+
+ Image options:
+ --------------
+ root=filename Set root filesystem for kernel
+
+ read-only Force root filesystem to be mounted read-only
+
+ append=string Append a string of options to kernel command line
+
+ initrd=filename Name of initrd file
+
+ label=string Logical name of image (used in interactive mode)
+
+ description=string One line text description of the image.
+
+ IA-64 specific options:
+ -----------------------
+
+ Global options:
+ ---------------
+ fpswa=file Specify the filename for a specific FPSWA to load.
+ If this option is used then no other file will be tried.
+
+ relocatable In case of memory allocation error at initial load point of
+ kernel, allow attempt to relocate (assume kernels is relocatable)
+
+ Image options:
+ --------------
+ relocatable In case of memory allocation error at initial load point of
+ kernel, allow attempt to relocate (assume this kernel is relocatable)
+
+ IA-32 specific options:
+ -----------------------
+ legacy-free Indicate that the host machine does not have a legacy BIOS at all.
+
+
+ The user can specify a kernel and related kernel options using the image label. Alternatively,
+ the user can also specify a kernel file that is not specified in the config file. In any case,
+ some of the global options (such as append) are always concatenated to whatever the user type.
+
+
+IV/ Booting from the local system
+ -----------------------------
+
+ The elilo.efi binary must be in an EFI system partition (FAT32). The config
+ file, kernel image, and optional initrd ramdisk can be on the same partition
+ or even another EFI partition. In the following discussion we assume that all
+ files are on the same EFI partition which is recognized by the EFI shell (nshell)
+ as fs0. The kernel and initrd can be copied from the any linux filesystems to the
+ EFI partition using either the mtools (mcopy) or by mounting the EFI partition as
+ a vfat partition. However you do not really need this because most linux
+ distributions install both files in the EFI partition and mount this partition in /boot/efi.
+
+ To boot a kernel, simply power cycle the machine. Once you get to the EFI
+ shell prompt, change to the filesystem that maps to the partition where elilo is.
+
+ Shell> fs0:
+ fs0:\>
+
+ You might need to make sure that the Shell Path is set such that it will load
+ ELILO from fs0:. You can verify this by typing:
+ fs0:\> set
+ path : fs0:\
+
+ At this point you can invoke ELILO:
+
+ fs0:\> elilo
+
+ If there is no config file, then it will:
+ - pick up the kernel image named vmlinux if it exists, otherwise it will abort.
+ - pass no argument to the kernel.
+
+ You can specify the kernel image and its options on the command line.
+ For instance you can do:
+
+ fs0:\> elilo vmlinux root=/dev/sda5
+
+ You can specify as many parameters as you want. The syntax follows the kernel
+ rule, i.e., list of value pairs (or even single values) separated by space.
+ A more complicated example would be:
+
+ fs0:\> elilo -i initrd-2.4.9 vmlinuz-2.4.9 root=/dev/sda2 console=tty0 console="ttyS0,115200n8"
+
+ In this example, notice the double quotes. They are required because the comma is a control
+ character for nshell.
+
+ In the case a config file is found, then elilo will behave according to
+ the options in that file. However if elilo is invoked with command line options, they
+ will be combined or they will override (if conflicting) what is defined in the config file.
+
+ As of version 3.3, elilo is fully compliant with the EFI specification (1.10) with regards
+ to where the bootloader (elilo.efi) must be located in the EFI system partition. In
+ section 11.2.1.3 of the EFI1.10 specification, it is said that in order to avoid conflicts
+ between various loaders for various OSes or distributions of the same OS, every vendor MUST
+ use a dedicated directory: \EFI\vendor\. The bootloader must be placed in this directory.
+ This has always been possible as this is a matter of creating the directory and copying
+ the elilo.efi file in it. However up until version 3.3, elilo would look for its config file
+ and kernel/initrd in the root (/) of the partition it was loaded from. As of version 3.3,
+ elilo will now ONLY look for its configuration file FROM THE DIRECTORY IT WAS LOADED FROM.
+ The same applies to the kernel and initrd files unless absolute paths are specified. Let us
+ look at a simple example:
+
+ - suppose elilo.efi is in \EFI\DIST if fs0: (for the EFI Shell)
+
+ - if you invoke elilo as follows:
+
+ fs0:\> \efi\dist\elilo -v -p
+ default file path: \efi\dist\
+ config file : \efi\dist\elilo.conf
+ ELILO boot:
+
+
+ Note that this is the same if you invoke elilo directly from \efi or \efi\dist.
+
+ File references in the configuration file are treated as relative to the directory
+ elilo was loaded from except if they use an absolute path.
+
+ As of version 3.4 a similar rule applies to the network boot sequence, see netbooting.txt
+ for details.
+
+V/ Interactive mode
+ ----------------
+
+ Elilo can be forced into interactive mode using the "prompt" option in the config
+ file or with the -p option. In this mode, the user can select a kernel to load.
+
+ The interface depends on the chooser, it may be a simple command line prompt as provided
+ by the simple chooser or a more sophisticated screen with scroll menus as provided by
+ textmenu. Most choosers depends on the elilo config file to get the information they
+ display. The simple chooser can operated without the elilo config file. However it
+ is always better to have this file, to create handy logical names for each possible
+ boot choices. The logical names are specified with the "label" option in the config
+ file. They represent a specific kernel "image" and its specific options.
+
+ In elilo, the user can select a particular kernel image using the corresponding label
+ name. A simple example is as follows:
+
+ If we suppose that the following is defined in elilo.conf:
+
+ image=vmlinuz-2.4.9
+ label=linux-up
+ initrd=initrd-2.4.9
+ root=/dev/sda2
+ append="console=tty0 console=ttyS0,115200n8"
+
+ then the user can specify linux-up at the prompt and elilo will load the
+ vmlinuz-2.4.9 kernel file and the initrd-2.4.9 ramdisk and will pass
+
+ "root=/dev/sda2 console=tty0 console=ttyS0,115200n8"
+
+ as command line arguments to the kernel.
+
+ This behavior is identical to Lilo/x86. However, elilo further allows the user
+ to specify actual kernel files names as well, i.e., kernels that are not defined
+ in the configuration file. If we reuse the above example and the simple chooser,
+ the user can type:
+
+ ELILO boot: vmlinux-2.4.18 root=/dev/sda2
+
+ and elilo will boot the vmlinuz-2.4.18 kernel if it exists.
+
+VI/ The alternate kernel image
+ --------------------------
+
+ Oftentimes when debugging kernels you want to reboot the machine once with
+ your test kernel and, if something goes wrong, you want to fall back to a more
+ stable kernel. In addition you want to be able to do this from a remote machine.
+ Many things can go wrong when doing kernel debugging. It could be that you don't
+ even reach user-mode. In this case however, you still want to fall back to
+ a stable kernel. The feature you'd like from a boot loader is 'boot once and
+ then fall back to safe kernel'.
+
+ Elilo offers this feature and it's called 'alternate kernel image'.
+ You can configure elilo to load a kernel only once and then whatever
+ happens the next reboot falls back to a different kernel hopefully more stable.
+
+ To do this, elilo relies on an EFI variable called 'EliloAlt' with a NULL GUID.
+ The content of this variable is a UNICODE string containing the kernel file name
+ and its command line options.
+
+ When the -a option is specified on the command line or if the "checkalt" option
+ is present in the config file, elilo will check for the presence of this variable.
+ If found and the content is a valid UNICODE string, elilo will use it as the kernel
+ to boot. There is no verification made on the validity of the kernel name or options.
+ Then the variable is deleted. If the variable is rejected because it does not look
+ sane, it is also deleted.
+
+ The variable can be set from a running Linux system using the /proc/efi/vars
+ interface. In the tools directory of this package, there is a Linux tool called
+ elilovar which can be used to create, modify, print, and delete the EliloAlt
+ variable. Refer to eliloalt.txt for more information on this tool.
+
+VII/ Auto booting the machine
+ -----------------------
+
+ Once you're satisfied with your machine setup, it is good to install an
+ auto boot procedure. You have two options to do this:
+ - from the EFI boot manager menu
+ - from the EFI shell
+
+ The first option is preferred and is used by most Linux distributions.
+ Elilo can be invoked directly from the boot manager. You need to get into
+ the 'boot maintenance' menu and use load file a file. This can be tedious
+ so instead it is recommended that you use a Linux tool called efibootmgr
+ which is also shipped in most distributions. With this tool, you can
+ create your own boot option and change the boot order.
+
+
+
+ The second approach use the EFI shell and a shell script with a special name: 'startup.nsh'.
+
+ When the system boots, it looks for EFI partitions and if it finds
+ a 'startup.nsh' file in ANY of these it will jumpstart execution from it.
+
+ So the typical way of auto booting your Linux/ia64 system is to simply create
+ such a file with the following content:
+
+ # cat /boot/startup.nsh
+ elilo vmlinuz root=/dev/sda2
+
+ Of course, this can be simplified if there is a configuration file.
+
+
+VII/ Netbooting
+ ----------
+
+ Please refer to netbooting.txt for a complete description of how to boot
+ from the network.
+
+
+XII/ Booting on EFI/ia32 platforms
+ -----------------------------
+
+ Until PC comes with the EFI firmware built in, you need to boot from a
+ floppy that has the EFI firmware on it. Such floppy can be
+ constructed from the EFI sample implementation and toolkit that is
+ available from the Intel Developer Web site at:
+
+ http://developer.intel.com/technology/efi/
+
+ To use elilo on IA-32, you can put it on a floppy and
+ on a FAT32 partition (msdos partition). You can also
+ netbooting if you network adapter has support for UNDI/PXE.
+
+ Elilo/ia32 is capable of booting unmodified 2.2.x. and 2.4.x kernels
+ as they are shipped by distributors today (such as Redhat7.2). You don't need
+ to recompile the kernel with special options. Elilo ONLY takes compressed kernel
+ image which are typically obtained via a 'make bzImage'. Plain elf/32 kernel can't
+ be booted (plain vmlinux will not work). Similarly, existing initial ramdisks can
+ be used without modifications.
+
+IX/ Credits
+ -------
+
+ Intel Corp.
+ Stephane Eranian <eranian@hpl.hp.com>
+ David Mosberger <davidm@hpl.hp.com>
+ Johannes Erdfelt <jerdfelt@valinux.com>
+ Richard Hirst <rhirst@linuxcare.com>
+ Chris Ahna <christopher.j.ahna@intel.com>
+ Mike Johnston <michael.johnston@intel.com>
+
+X/ Bug reports
+ -----------
+
+ You can submit bugs to <eranian@hpl.hp.com> or to the Linux/ia64
+ mailing list at linux-ia64@linuxia64.org. Visit http://www.linuxia64.org
+ to subscribe to this list.
+
+XIII/ Reference
+ ---------
+
+ EFI v1.02 specifications are available from the following web site:
+
+ http://developer.intel.com/technology/efi/
+
+ The latest sources of ELILO can be downloaded at:
+
+ ftp://ftp.hpl.hp.com/pub/linux-ia64
+
--- /dev/null
+Information related to the eliloalt Linux tool
+---------------------------------------------
+(c) 2002-2003 Hewlett Packard Co
+ Contributed by Stephane Eranian <eranian@hpl.hp.com>
+
+ Last updated: March 1st, 2002
+
+
+The elilo alternate image feature uses an EFI variable called EliloAlt.
+The content of this variable is a UNICODE string containing a kernel
+image file and its command line options. The variable has a NULL GUID.
+
+To create, read, or modify the variable you need to use the EFI variable
+service and the SetVariable() or GetVariable() interface. The service
+is available when EFI is in boot service mode, i.e., prior to loading
+the kernel but it is also available at runtime when the Linux kernel
+has taken over the control of the machine.
+
+In order to modify the variable, you can either write a small EFI applications
+or use the Linux/ia64 interface to the EFI variables which use the /proc filesystem.
+
+The elilalt tool included in this package uses the /proc interface to EFI variables
+to create, read, or modify the EliloAlt variable. This tool is a Linux/ia64 application
+and NOT an EFI application.
+
+
+Because modiyfing the EliloAlt can influence how the machine is booted, you must
+be root to run the program, even when you simply want to read the content of
+the variable.
+
+Eliloalt provides the following options:
+
+ -h, --help display this help and exit
+ --version output version information and exit
+ -s, --set cmdline set elilo alternate variable to cmdline
+ -p, --print print elilo alternate variable
+ -d, --delete print elilo alternate variable
+
+1/ Creation of the variable
+
+ To create the variable you can type:
+
+ # eliloalt -s "vmlinuz-2.4.9 root=/dev/sdb2 hdc=ide-scsi"
+
+ It is VERY important to use quotes to make sure that the entire list of arguments is
+ treated as a single argument to the program. Otherwise only the first element
+ (here vmlinuz-2.4.9) will be used.
+
+
+2/ Printing the content of the variable
+
+ To print the content of the variable you need to type:
+
+ # eliloalt -p
+ EliloAlt="vmlinuz-2.4.9 root=/dev/sdb2 hdc=ide-scsi"
+
+3/ Modifying the variable
+
+ You can simply use the -s option:
+ # eliloalt -s "vmlinuz-2.4.18 root=/dev/sdb2"
+ # eliloalt -p
+ EliloAlt="vmlinuz-2.4.18 root=/dev/sdb2"
+
+3/ Deleting the variable
+
+ You must use the -d option:
+ # eliloalt -p
+ EliloAlt="vmlinuz-2.4.18 root=/dev/sdb2"
+ # eliloalt -d
+ # eliloalt -p
+ variable not defined
+
+ Keep in mind that the variable is automatically deleted by elilo if:
+ - the checkalt option is specified in the config file
+ OR
+ - the -a is used on the command line
+
--- /dev/null
+Information related to variable support in ELILO
+------------------------------------------------
+(c) 2002-2003 Hewlett Packard Co
+ Contributed by Stephane Eranian <eranian@hpl.hp.com>
+
+ Last updated: 06/13/2002
+
+As of version 3.2, elilo has internal variables which can be programmed
+by any module inside the bootloader code. These variables are used
+to parametrize some of the arguments passed on the kernel command line.
+
+The value of a variable is a Unicode string. Variables names are composed
+of a single Unicode character, such as 'I' for instance. Variable names
+are case sensitive. Elilo has support for 52 variables: A-Z and a-z.
+
+The '%' sign is used to name a variable. For instance, '%I' indicates
+variable 'I'. If '%I' is present on the command line to the kernel,
+it will be replaced (string replacement) with the value (a string) of 'I'.
+By default, the Elilo core does not assign any values to any variables.
+It is up to each module to do so. When a variable is not used, its content
+is the empty string "", which means that the '%d' notation, for instance, will
+be replaced with the empty string.
+
+Let us look at an example:
+ Supposing that the following variables are defined:
+ 'I' -> "192.168.2.5"
+ 'G' -> "192.168.2.1"
+ 'M' -> "255.255.255.0"
+ 'z' -> ""
+
+ Then a command line of this form (provided as an append= option in elilo.conf):
+
+ root=/dev/nfs nfsroot=15.4.88.178:/mnt2 ip=%I:%z:%G:%N:jung:eth0:on
+
+ Would pass the following to the kernel:
+
+ root=/dev/nfs nfsroot=15.4.88.178:/mnt2 ip=192.168.2.5::192.168.2.1:255.255.255.0:jung:eth0:on
+
+Of course, the meaning of each variable is up to each individual module, the
+names used here are not necessarily representative of the actual names used
+by elilo.
+
+Some choosers, (such as simple) have support to print the list of
+defined variables. For instance, in simple (the default chooser) you
+can press '%' to see the list of defined variables.
+
+Variables can be useful when netbooting, for instance, to get the
+dynamically assigned IP, netmask, and gateway addresses.
+
+In case the % character needs to be passed to the kernel, it is possible
+to "despecialize" a character using the & symbol in front of it.
+
+See netbooting.txt for more information on this.
--- /dev/null
+Information related to the FPSWA driver for EFI/ia64 platforms
+--------------------------------------------------------------
+(c) 2002-2003 Hewlett Packard Co
+ Contributed by Stephane Eranian <eranian@hpl.hp.com>
+
+This document is irrelevant for EFI/ia32 platforms.
+
+On all EFI/ia64 platforms, the bootloader is responsible for checking for
+the presence on the EFI system partition of an updated version of the
+Floating-Point Software Assist (FPSWA) EFI driver (fpswa.efi). For every
+instance found, elilo will load the driver and let EFI decide if it is
+newer than the currently installed version. In the end at most one driver
+is kept in memory.
+
+Elilo will look for a file called fpswa.efi in the \EFI\Intel Firmware
+(there is a space between l and F) directory on ALL accessible EFI system
+partitions (including on removable media). It will do so even when elilo
+is downloaded from the network. It does not look for the driver in the
+ext2fs partitions.
+
+The FPSWA reference document is available from the Intel developer's web
+site at http://developer.intel.com/design/itanium.
--- /dev/null
+How to netboot using ELILO
+--------------------------
+
+Copyright (C) 2002-2003 Hewlett-Packard Co.
+Contributed by Stephane Eranian <eranian@hpl.hp.com>
+
+Last updated: 03/08/11
+
+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.
+The elilo loader has full support for both PXE and DHCP, therefore
+it is possible to download the elilo config file, the Linux kernel image
+and the initial ramdisk from a remote server. There are many ways
+netbooting can be configured but in this document we focus
+only on two very common cases:
+
+ - netboot but use local root filesystem.
+ - booting a diskless machine, i.e., use a NFS root filesystem.
+
+1/ How to get EFI to netboot?
+
+ You do not need any additional software to get EFI to start a netboot session.
+ Any EFI machine can be configured to start a PXE/DHCP session IF it has a network
+ adapter that has support for the UNDI/PXE protocol. Most modern cards do have such
+ support.
+
+ To enable netbooting, you need to go into the EFI boot manager maintenance menu
+ and 'Add a boot option'. On the screen you see the list of devices to boot from.
+ At least one of them should be of the form:
+
+ Load File [Acpi(PNP0A03,0)/Pci(5|0)/Mac(00D0B7A6FC25)]
+
+ which represent Ethernet card (Mac address). If you don't have such option, it means that
+ you either do not have a network adapter in your machine or it does not have the
+ UNDI/PXE support in its option ROM.
+
+ You need to select this option and give it a logical name such as 'netboot', for instance.
+ Next, you leave the maintenance menu and go back to the main menu. You now have a new
+ boot menu option. If you select 'netboot' then EFI will start the PXE/DCHP discovery
+ request and look for a server to get an IP address.
+
+ On the server side, you can use a standard DHCP server, such as the one shipped on
+ Redhat7.2 (dhcpd) or a PXE server (not yet available for Linux, probably available for Windows).
+ In this document we show both options. You also need a TFTP server somewhere on the network,
+ it will be used to download the actual files.
+
+
+2/ Netbooting using DHCP
+
+ There is nothing specific to EFI that needs to be set in the /etc/dhcpd.conf file.
+ Clearly the filename option must contains the path to the elilo.efi binary.
+
+ Elilo will auto-detect whether it was downloaded via PXE or DHCP and it will adapt
+ the kind of requests it makes to download the other files that it needs, such as
+ its config file.
+
+ A simple dhcpd.conf file which uses fixed IP addresses could be as follows:
+
+ subnet 192.168.2.0 netmask 255.255.255.0 {
+ host test_machine {
+ hardware ethernet 00:D0:B7:A6:FC:25;
+ fixed-address 192.168.2.10;
+ filename "elilo.efi";
+ option domain-name "mydomain.com";
+ option host-name "test_machine";
+ option routers 192.168.2.1;
+ option subnet-mask 255.255.255.0;
+
+ }
+ }
+
+ For the tftp server, you need to make sure that it is ACTIVATED by inetd or xinetd depending
+ on your distribution. In most distributions, it is disabled by default for security reasons.
+ On distributions using xinetd, you need to check /etc/xinet.d/tftp. For inetd you need to
+ check /etc/inetd.conf. It is typical to have the root directory for tftp be /tftpboot but it
+ can be anything. In this document we will use /tftpboot as the root directory. The files
+ that we need are as follows:
+ - elilo.efi
+ - the elilo config file
+ - the kernel image
+ - the initial ramdisk (optional)
+
+
+ a/ Location of the files in the tftp directory tree
+
+ For elilo version 3.3b or higher, it is possible to place the files listed above
+ in any subdirectory below the tftp root. Of course the dhcpd.conf file must
+ point to the location of elilo.efi and provide the path from the tftp root
+ directory.
+
+ Elilo will look for its config file, the kernel image, the initial ramdisk (optional)
+ only from the directory it was loaded from. This is useful when the same tftp server
+ is used to services many different kind of clients.
+
+ Here is a simple example, suppose the dhcpd.conf file contains the following definition:
+
+ subnet 192.168.2.0 netmask 255.255.255.0 {
+ host test_machine {
+ hardware ethernet 00:D0:B7:A6:FC:25;
+ fixed-address 192.168.2.10;
+
+ filename "/rx6000/elilo.efi";
+
+ option domain-name "mydomain.com";
+ option host-name "test_machine";
+ option routers 192.168.2.1;
+ option subnet-mask 255.255.255.0;
+
+ }
+ }
+
+ Elilo will be downloaded from /tftpboot/rx6000. Then elilo will look
+ for all the other files it needs in /tftpboot/rx6000. This rule is
+ applied to all files, including the all the variation of the config
+ file.
+
+ b/ Getting the config file
+
+ With DHCP, elilo will first try to download its configuration file. It will try
+ several file names and they are as follows:
+
+ 1) AABBCCDD.conf
+ where AABBCCDD is the hexadecimal representation of the IP address assigned to
+ the machine by DHCP. The hexadecimal string (AABBCCDD) MUST use upper case
+ characters.
+
+ This filename is an opportunity to specify a machine specific configuration file.
+
+ 2) elilo-ia32.config or elilo-ia64.conf
+
+ Depending on the machine (client side) architecture elilo will try the IA-32 or
+ IA-64 file.
+
+ 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.
+
+ 3) elilo.conf
+
+ All files use the same format. Elilo will stop at the first match. In case no file is found,
+ it will try to download a default kernel file name (vmlinux).
+
+ c/ Getting the kernel
+
+ The second request from elilo is typically the kernel image. The filename is based on what
+ is in the elilo config file. The path name depends on how the TFTP server is configured.
+ For security reasons it is customary to have the server do a change root in /tftpboot.
+ Hence filenames are relative to /tftpboot and therefore you don't need to specify it.
+
+ For instance if elilo.conf contains:
+ image=vmlinuz.249
+ label=linux-up
+ root=/dev/sdb2
+
+ and the user selects linux-up, then elilo will request a filename of 'vmlinux.249'
+ which must therefore be in /tftpboot. Check the configuration of your TFTP server for
+ more on this.
+
+ d/ Getting the initial ramdisk
+
+ This step is optional. It follows exactly the same naming rules explained for the kernel image.
+ The initial ramdisk file must therefore be somewhere under /tftpboot.
+
+ For instance if elilo.conf contains:
+ image=vmlinuz.249
+ label=linux-up
+ root=/dev/sdb2
+ initrd=ramdisk/initrd.249
+
+ and the user selects linux-up, then elilo will request a filename of 'ramdisk/initrd.249'
+ which must therefore be under /tftpboot.
+
+
+ e/ Getting IP address information
+
+ When elilo is netbooted, the network filesystem module initializes some elilo variables
+ with the information it received from the DHCP server. At a minimum, it received the
+ IP address.
+
+ The following information is stored in the elilo variables indicated below:
+ - assigned IP address -> %I
+ - assigned netmask -> %M
+ - assigned domainname -> %D
+ - assigned gateway -> %G
+
+ These variables can be used to dynamically adjust the command line arguments passed to the kernel.
+ See section 5/ below for an example.
+
+3/ Netbooting using PXE
+
+ EFI has builtin support for PXE. In fact it first tries PXE and then default to DHCP
+ when it does not find a valid PXE server.
+
+ There is a PXE server package available from Linux/ia32 however this package does not
+ have the necessary extensions to talk to the EFI side, at least on IA-64 platforms.
+
+ There is no need for special options or compile time flags to get elilo to work
+ with PXE instead of standard DHCP. When netbooted, elilo will automatically detect
+ if it has been downloaded via PXE or DHCP and it will adujst how subsequent files
+ are requested.
+
+ You need a special version of the DHCPD server developed by the Internet Software Consortium
+ (http://www.isc.org) with a special patch to add the PXE extensions. Unfortunately as of
+ version 3.0xx, the patch has not yet made it into the official tree. It is supposed to show
+ up in version 3.1 of the dhcpd server.
+
+ In any case, the elilo package contains a simple example of how you can configure the
+ /etc/dhcpd.conf file for a PXE-aware DHCP server using the extensions provided in the
+ patch. You can look in examples/dhcpd-pxe.conf. The syntax is very different from
+ a standard dhcpd server.
+
+ The key elements to keep in mind are the PXE layers used by elilo to request the different
+ files:
+
+ Layer 0 : to get the name of the boot loader (elilo.efi)
+ Layer 1 : to get the name of the elilo config file
+ Layer 2 : to get the name of the kernel image
+
+ There is an IMPORTANT distinction between those layers. The first two (0,1) and requested
+ systematically whereas the last one is used only when the configuration file is not found, i.e.,
+ what is the default kernel to boot. The actual files are STILL downloaded via TFTP. Therefore
+ the TFTP server must also be configured (see previous section for more on this).
+
+
+ a/ Getting the config file
+
+ In this mode, elilo use the PXE layer 1 to get the config file to use. Therefore this must
+ be set on the server side. Elilo will use the following sequence when
+ looking for a config file:
+
+ - use the name provide by the PXE server Layer 1 or
+
+ - elilo-ia64.conf/elilo-ia32.conf or
+
+ - elilo.conf
+
+ Elilo stops at the first match. With PXE, elilo does not try to download a config file named after
+ the assigned IP address as it does for DHCP because there is enough flexibility in the PXE server
+ configuration to do this.
+
+ b/ Getting the kernel image
+
+ When there is no config file, elilo will use the kernel name returned by
+ PXE layer 2. If it is not specified there, then it default to 'vmlinux'.
+
+ c/ Getting the initial ramdisk
+
+ The filename for the ramdisk MUST come from the config file. Elilo does not use a PXE layer
+ to ask for a default name.
+
+ d/ Getting IP address information
+
+ When elilo is netbooted, the network filesystem module initializes some elilo variables
+ with the information it received from the DHCP server. At a minimum, it received the
+ IP address.
+
+ The following information is stored in the variables indicated below:
+ - assigned IP address -> %I
+ - assigned netmask -> %M
+ - assigned domainname -> %D
+ - assigned gateway -> %G
+
+ These variables can be used to dynamically adjust the command line arguments passed to the kernel.
+ See section 5/ below for an example of how to use the variable.
+
+
+4/ Netbooting and using a local root filesystem
+
+ This is the simplest configuration where the boot loader, its config file, the kernel
+ and its optional initial ramdisk are downloaded from the network BUT the kernel uses
+ the local disk for its root filesystem.
+
+ For such configuration there is no special option necessary in the elilo config file.
+ You simply need to specify which partition is the root partition. A typical elilo.conf
+ would look as follows:
+
+ image=vmlinuz.249
+ label=linux-up
+ root=/dev/sdb2
+ initrd=ramdisk/initrd.249
+
+5/ Netbooting a diskless machine
+
+ In this configuration we do not use the local machine's disks but instead rely on
+ a remote server to provide the root filesystem via NFS.
+
+ a/ Prerequisites
+
+ By default most kernels shipped by distributors do not have the support
+ compiled in for such configuration. This means that you need to recompile
+ your own kernel. For instance, vmlinuz-2.4.9 as shipped in Redhat7.2 on
+ both ia32 and ia64 platforms does not have the support builtin.
+
+ To get this configuration to work, you need to have a kernel compiled
+ such that it accepts a root filesystem over NFS (CONFIG_ROOT_NFS). This
+ necessitates that the network stack be configured with the, so called,
+ IP plug-and-play support (CONFIG_IP_PNP).
+
+ b/ On the server side
+
+ You need to have:
+ - a NFS file server to provide the root filesystem.
+ - a DHCP/PXE server to get the IP address and download the boot loader.
+
+ Note that both do not need to be on the same machine. There is no special
+ DHCP/PXE configuration option required to get this working. All you need
+ is a kernel compiled with the options mentioned in a/. You also need to
+ make sure that the permission on the NFS server are set appropriately
+ to allow root access from the client machine (no_root_squash), see
+ man 'exports' for more on this.
+
+ c/ The elilo configuration file
+
+ To boot successfully, the kernel needs to:
+ - get an IP address and related networking parameters
+ - contact the NFS server to get its root filesystem
+
+ The 2.4.x kernel series provides several options to get the IP address:
+ - it can do an internal DHCP request (CONFIG_IP_PNP_DHCP)
+ - it can do an internal RARP request (CONFIG_IP_PNP_RARP)
+ - it can do an internal BOOTP request (CONFIG_IP_PNP_BOOTP)
+ - it can get the IP address from the command line
+
+ The choice is up to you but it is a little bit stupid to go through a
+ DHCP/BOOTP/RARP phase again when this is already done by the EFI firmware.
+ So in this document, we describe how you can pass the information provided
+ by EFI on the command line of the kernel.
+
+ The syntax used to pass IP information on the command line is described in
+ the kernel source tree in Documentation/nfsroot.txt. The option is called
+ "ip=" and has the following syntax:
+
+ ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>
+
+ To designate the NFS server, you must use the "nfsroot=" option. It has the
+ following syntax:
+ nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>]
+
+ Depending on how you want your system configured you can hardcode the
+ values of the parameters in the elilo configuration file. For instance:
+
+ image=/vmlinuz
+ label=nfsroot
+ description="kernel with NFS root"
+ append="root=/dev/nfs nfsroot=192.168.2.22:/ia64_rootfs ip=192.168.2.5::192.168.2.1:255.255.255.0:test_machine:eth0:on"
+
+ Note the root=/dev/nfs indicates that the root filesystem is over NFS.
+
+ This example works fine however, it is not very flexible because the IP
+ address, the gateway, netmask and hostname are fixed and do not used the
+ values EFI used to download the boot loader and the kernel.
+
+ Elilo provides a way to dynamically customize the parameters passed on the
+ command line using substitution variables. We describe those variables in
+ elilovar.txt. The basic idea is to allow the parameters to use the dynamic
+ information obtained by the DHCP/PXE phase.
+
+ The network support in elilo defines several variables which contained
+ network related information produced by the DHCP/PXE phase. The set of
+ variable is:
+ %I -> the IP address obtained by DHCP/PXE
+ %M -> the netmask obtained by DHCP/PXE
+ %G -> the gateway obtained by DHCP/PXE
+ %H -> the hostname obtained by DHCP/PXE
+ %D -> the domain name obtained by DHCP/PXE
+
+ So, the configuration file can then be customized as follows:
+ image=/vmlinuz
+ label=nfsroot
+ description="kernel with NFS root"
+ append="root=/dev/nfs nfsroot=192.168.2.22:/ia64_rootfs ip=%I::%G:%M:%H:eth0:on"
+
+ Not all parameters are necessary or even used by the kernel or the user level
+ configuration scripts. There is no variable to substitute the NFS server or
+ the mount point on that server.
+
+
+ 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 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
+ returned by the PXE server is specific to a client.
+
+
+6/ References
+
+ More information on the PXE protocol can be found at the following web site:
+
+ http://developer.intel.com/ial/wfm/
+
+ The source code for the standard and (possibly) PXE-enhanced DHCPD can be
+ downloaded from:
+
+ http://www.isc.org/
+
--- /dev/null
+Information about the simple chooser
+--------------------------------------
+Copyright (C) 2002-2003 Hewlett-Packard Co.
+Contributed by Stephane Eranian <eranian@hpl.hp.com>
+
+Last updated: 02/02/14
+
+Chooser name: simple
+Command line option: -C simple
+Config file option: chooser=simple, description, message
+
+The simple chooser is the default chooser. However it is possible
+to disable it at compile time, it is highly recommended to keep it
+in. Elilo must have at least one chooser compiled in.
+
+The simple chooser is very basic as its name indicates! It provides
+a simple one line text mode command prompt similar to what you get
+with Lilo/x86.
+
+Any chooser becomes visible to the user ONLY when the interactive
+mode is entered.
+
+The simple chooser allows the user to select a kernel to boot.
+The user can use a label as specified in the elilo config file
+or a kernel file name. File names can be specified with
+absolute names in the form dev_name:/path/to/my_kernel.
+
+1/ Activation
+
+ The chooser is activated from:
+
+ - command line with the -c simple
+ - the config file with the chooser=simple option
+
+2/ Supported options
+
+ The simple chooser supports the following options in the config file:
+
+ message=filename : display a message before the prompt. The filename
+ must be an ASCII file
+
+ description=string: a description of the kernel image (ASCII)
+
+ All other options have their standard meaning. The chooser does not recognize
+ the fX (X varies from 1-12) options
+
+2/ Builtin commands
+
+The simple chooser has some builtin command which the user can
+get to by typing certain keys as the first character on the command line:
+
+ TAB: shows the list of defined labels and their descriptions.
+
+ If the user did not type anything, i.e., the line is empty,
+ pressing TAB will print the list of labels defined in the
+ elilo config file.
+
+ If the user already typed a name and if the name corresponds
+ to a specified label, the chooser will show how the label
+ is expanded and what the final command line to the kernel will
+ look like.
+
+ If the line is empty pressing TAB generates something similar to:
+ ELILO boot:
+ linux-up linux nfsroot (or any kernel file name: [dev_name:]/path/file)
+
+ Note that first label correspond to the default label used if the user
+ hits the enter key with an empty line. This label is not necessarily
+ the first one in the config file.
+
+ Now pressing TAB with a full label name:
+
+ ELILO boot: linux-up
+ desc : my default UP kernel
+ cmdline: vmlinuz root=/dev/sdb2 console=ttyS0,115200n8 console=tty0 ro
+
+ The desc line shows whatever was specified in the "description" option
+ for this particular image in the config file.
+
+ = : shows the list of accessible devices
+
+ this key force elilo to print the list of detected devices. Elilo will
+ auto-detect the devices which are accessible to load a config file, the kernel, the
+ initrd from. Those devices typically represent disk partition, CDROM, floppy, or
+ a network path. The list of devices is highly system dependent.
+ It also depends on the filesystem support compiled into elilo.
+
+ The way the devices are named depends on the device naming scheme
+ selected. It also depends on whether the EDD30 support is activated.
+ For instance, pressing the ? could look as follows:
+
+ ELILO boot:
+ scsi0 : vfat : Acpi(PNP0A03,2)/Pci(1|0)/Scsi(Pun0,Lun0)/HD(Part1,Sig72040800)
+ scsi1 : vfat : Acpi(PNP0A03,2)/Pci(1|0)/Scsi(Pun6,Lun0)/HD(Part1,Sig00000000)
+ scsi2 : ext2fs : Acpi(PNP0A03,2)/Pci(1|0)/Scsi(Pun0,Lun0)/HD(Part2,Sig72040800)
+ scsi3 : ext2fs : Acpi(PNP0A03,2)/Pci(1|0)/Scsi(Pun6,Lun0)/HD(Part2,Sig00000000)
+ net0 : netfs : Acpi(PNP0A03,0)/Pci(5|0)/Mac(00D0B7A6FC25)
+ 5 devices available for booting
+ boot device net0: netfs
+
+ Here the vfat (EFI partition type), ext2fs and network filesysten (not to be confused
+ with NFS) were compiled into elilo and were detected on the machine. The left handside
+ of the colon show the logical name associated with the device. For instance,
+ scsi0 corresponds to the first partition of SCSI disk ID 0 and is an EFI partition.
+ The net0 correspond to a network device, here the Ethernet adapter. The last line
+ show the device used to load elilo itself, in the case elilo was downloaded from the
+ network.
+
+ To get a kernel from scsi0, the user can simply type:
+
+ ELILO boot: scsi0:/usr/src/linux/vmlinux
+
+ Note that even though elilo was not downloaded from the network, it is still possible
+ to get the kernel and initrd from a remote machine.
+
+ % : shows the list of defined variables
+
+ Elilo has builtin variables which are used to dynamically customized the command line
+ parameters passed to the kernel. The list of variables depends on the support compiled
+ into elilo. Not all elilo subsystems use variables. Typically the network file system
+ does. Pressing '%' only prints the variables that are defined with their current values.
+ Some variables are only defined once the subsystem that creates them has been used.
+ In other words, if the network filesystem was not used to load elilo, then the variables
+ defined by it are not created.
+
+ If the network was actually used, pressing '%' could generate the following output:
+ ELILO boot:
+ D = "mydomain.com
+ G = "192.168.3.1"
+ H = "test_machine"
+ I = "192.168.3.4"
+ M = "255.255.255.0"
+
+ & : shows the list default path
+
+ The path is used as a prefix for all filenames specified as
+ relative.
+
+ ? : shows the list of supported command keys
+
+
+The simple chooser has also some builtin command line editing commands:
+
+ ESC : abort (leave elilo)
+
+ CTRL-D : abort (leave elilo)
+
+ CTRL-C : kill line
+ empty current line and prompt for new input
+
+ CTRL-H : erase the previous character
+
+ CTRL-U : clear current line
+ reset the buffer (does not display correctly if buffer spans more than one line)
+
+ Backspace: erase character
--- /dev/null
+Information about the textmenu chooser
+--------------------------------------
+Copyright (C) 2002-2003 Hewlett-Packard Co.
+Contributed by <rhirst@linuxcare.com>
+
+Last updated: 02/02/14
+
+Chooser name: textmenu
+Command line option: -C textmenu
+Config file option: chooser=textmenu
+
+The textmenu chooser provides a facility whereby you can draw a colour
+boot screen, using line-drawing characters to give the impression of a
+dialog box, with a scrollable menu from which a boot image can be chosen
+via cursor up/down keys. A one-line input field is provided for additional
+parameter input. Menu entries are taken from the description= fields in
+the config file.
+
+The message file format is based on that used for syslinux/isolinux on ia32
+platforms, which is copyright H. Peter Anvin. It is basically a text file
+containing text and graphic characters, along with some control codes to
+specify colour attributes, menu, and prompt field positions. There are two
+classes of message files; the main file, specified via message=, which
+includes menu and prompt field markers, and the additional help files which
+are invoked via function keys. Graphic characters are taken from the
+standard IBM VGA character set, and using an appropriate font makes file
+creation easier. Under Linux you can find a VGA font in the dosemu package.
+Included in the elilo source is sys2ansi.pl (taken from syslinux), which can
+be used to translate colour attributes such that they display correctly in an
+xterm.
+
+Valid control codes:
+
+0x01 ^A Mark top left or bottom right of menu area. Current attributes
+ at top left marker are used for inactive menu entries, current
+ attributes when bottom right marker is found are used for the
+ currently active menu attributes.
+
+0x02 ^B Mark left- or right-hand end of the prompt field. Current attributes
+ at the left had end are used to display and parameters entered.
+
+0x0A ^J Linefeed, does implied carriage return.
+
+0x0C ^L Clear screen
+
+0x0D ^M Carriage return; ignored so files can be 'DOS' or 'UNIX' format.
+
+0x0F ^O Attribute specfication; Two hex digits should follow this code, the
+ first being the background colour required, the second the foreground.
+
+ 0 = black 8 = dark grey
+ 1 = dark blue 9 = bright blue
+ 2 = dark green a = bright green
+ 3 = dark cyan b = bright cyan
+ 4 = dark red c = bright red
+ 5 = dark purple d = bright purple
+ 6 = brown e = yellow
+ 7 = light grey f = white
+
+An example of a config file and message file are included in the examples
+directory.
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ * GNU EFI 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.
+ *
+ * GNU EFI 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 GNU EFI; 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.
+ *
+ * Portions of this file are derived from the LILO/x86
+ * Copyright 1992-1997 Werner Almesberger.
+ */
+
+#ifndef __LINUX_ELF_H__
+#define __LINUX_ELF_H__
+
+/*
+ * This file was derived from <linux/elf.h>.
+ */
+
+#include <efi.h>
+
+/* 32-bit ELF base types. */
+typedef UINT32 Elf32_Addr;
+typedef UINT16 Elf32_Half;
+typedef UINT32 Elf32_Off;
+typedef INT32 Elf32_Sword;
+typedef UINT32 Elf32_Word;
+
+/* 64-bit ELF base types. */
+typedef UINT64 Elf64_Addr;
+typedef UINT16 Elf64_Half;
+typedef INT16 Elf64_SHalf;
+typedef UINT64 Elf64_Off;
+typedef INT64 Elf64_Sword;
+typedef UINT64 Elf64_Word;
+
+/* These constants are for the segment types stored in the image headers */
+#define PT_NULL 0
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_LOPROC 0x70000000
+#define PT_HIPROC 0x7fffffff
+#define PT_MIPS_REGINFO 0x70000000
+
+/* Flags in the e_flags field of the header */
+#define EF_MIPS_NOREORDER 0x00000001
+#define EF_MIPS_PIC 0x00000002
+#define EF_MIPS_CPIC 0x00000004
+#define EF_MIPS_ARCH 0xf0000000
+
+/* These constants define the different elf file types */
+#define ET_NONE 0
+#define ET_REL 1
+#define ET_EXEC 2
+#define ET_DYN 3
+#define ET_CORE 4
+#define ET_LOPROC 0xff00
+#define ET_HIPROC 0xffff
+
+/* These constants define the various ELF target machines */
+#define EM_NONE 0
+#define EM_M32 1
+#define EM_SPARC 2
+#define EM_386 3
+#define EM_68K 4
+#define EM_88K 5
+#define EM_486 6 /* Perhaps disused */
+#define EM_860 7
+
+#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */
+
+#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */
+
+#define EM_PARISC 15 /* HPPA */
+
+#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
+
+#define EM_PPC 20 /* PowerPC */
+
+#define EM_SH 42 /* SuperH */
+
+#define EM_SPARCV9 43 /* SPARC v9 64-bit */
+
+#define EM_IA_64 50 /* HP/Intel IA-64 */
+
+/*
+ * This is an interim value that we will use until the committee comes
+ * up with a final number.
+ */
+#define EM_ALPHA 0x9026
+
+
+/* This is the info that is needed to parse the dynamic section of the file */
+#define DT_NULL 0
+#define DT_NEEDED 1
+#define DT_PLTRELSZ 2
+#define DT_PLTGOT 3
+#define DT_HASH 4
+#define DT_STRTAB 5
+#define DT_SYMTAB 6
+#define DT_RELA 7
+#define DT_RELASZ 8
+#define DT_RELAENT 9
+#define DT_STRSZ 10
+#define DT_SYMENT 11
+#define DT_INIT 12
+#define DT_FINI 13
+#define DT_SONAME 14
+#define DT_RPATH 15
+#define DT_SYMBOLIC 16
+#define DT_REL 17
+#define DT_RELSZ 18
+#define DT_RELENT 19
+#define DT_PLTREL 20
+#define DT_DEBUG 21
+#define DT_TEXTREL 22
+#define DT_JMPREL 23
+#define DT_LOPROC 0x70000000
+#define DT_HIPROC 0x7fffffff
+#define DT_MIPS_RLD_VERSION 0x70000001
+#define DT_MIPS_TIME_STAMP 0x70000002
+#define DT_MIPS_ICHECKSUM 0x70000003
+#define DT_MIPS_IVERSION 0x70000004
+#define DT_MIPS_FLAGS 0x70000005
+# define RHF_NONE 0
+# define RHF_HARDWAY 1
+# define RHF_NOTPOT 2
+#define DT_MIPS_BASE_ADDRESS 0x70000006
+#define DT_MIPS_CONFLICT 0x70000008
+#define DT_MIPS_LIBLIST 0x70000009
+#define DT_MIPS_LOCAL_GOTNO 0x7000000a
+#define DT_MIPS_CONFLICTNO 0x7000000b
+#define DT_MIPS_LIBLISTNO 0x70000010
+#define DT_MIPS_SYMTABNO 0x70000011
+#define DT_MIPS_UNREFEXTNO 0x70000012
+#define DT_MIPS_GOTSYM 0x70000013
+#define DT_MIPS_HIPAGENO 0x70000014
+#define DT_MIPS_RLD_MAP 0x70000016
+
+/* This info is needed when parsing the symbol table */
+#define STB_LOCAL 0
+#define STB_GLOBAL 1
+#define STB_WEAK 2
+
+#define STT_NOTYPE 0
+#define STT_OBJECT 1
+#define STT_FUNC 2
+#define STT_SECTION 3
+#define STT_FILE 4
+
+#define ELF32_ST_BIND(x) ((x) >> 4)
+#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf)
+
+/* Symbolic values for the entries in the auxiliary table
+ put on the initial stack */
+#define AT_NULL 0 /* end of vector */
+#define AT_IGNORE 1 /* entry should be ignored */
+#define AT_EXECFD 2 /* file descriptor of program */
+#define AT_PHDR 3 /* program headers for program */
+#define AT_PHENT 4 /* size of program header entry */
+#define AT_PHNUM 5 /* number of program headers */
+#define AT_PAGESZ 6 /* system page size */
+#define AT_BASE 7 /* base address of interpreter */
+#define AT_FLAGS 8 /* flags */
+#define AT_ENTRY 9 /* entry point of program */
+#define AT_NOTELF 10 /* program is not ELF */
+#define AT_UID 11 /* real uid */
+#define AT_EUID 12 /* effective uid */
+#define AT_GID 13 /* real gid */
+#define AT_EGID 14 /* effective gid */
+#define AT_PLATFORM 15 /* string identifying CPU for optimizations */
+#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
+
+typedef struct dynamic{
+ Elf32_Sword d_tag;
+ union{
+ Elf32_Sword d_val;
+ Elf32_Addr d_ptr;
+ } d_un;
+} Elf32_Dyn;
+
+typedef struct {
+ Elf64_Word d_tag; /* entry tag value */
+ union {
+ Elf64_Word d_val;
+ Elf64_Word d_ptr;
+ } d_un;
+} Elf64_Dyn;
+
+/* The following are used with relocations */
+#define ELF32_R_SYM(x) ((x) >> 8)
+#define ELF32_R_TYPE(x) ((x) & 0xff)
+
+#define R_386_NONE 0
+#define R_386_32 1
+#define R_386_PC32 2
+#define R_386_GOT32 3
+#define R_386_PLT32 4
+#define R_386_COPY 5
+#define R_386_GLOB_DAT 6
+#define R_386_JMP_SLOT 7
+#define R_386_RELATIVE 8
+#define R_386_GOTOFF 9
+#define R_386_GOTPC 10
+#define R_386_NUM 11
+
+#define R_MIPS_NONE 0
+#define R_MIPS_16 1
+#define R_MIPS_32 2
+#define R_MIPS_REL32 3
+#define R_MIPS_26 4
+#define R_MIPS_HI16 5
+#define R_MIPS_LO16 6
+#define R_MIPS_GPREL16 7
+#define R_MIPS_LITERAL 8
+#define R_MIPS_GOT16 9
+#define R_MIPS_PC16 10
+#define R_MIPS_CALL16 11
+#define R_MIPS_GPREL32 12
+/* The remaining relocs are defined on Irix, although they are not
+ in the MIPS ELF ABI. */
+#define R_MIPS_UNUSED1 13
+#define R_MIPS_UNUSED2 14
+#define R_MIPS_UNUSED3 15
+#define R_MIPS_SHIFT5 16
+#define R_MIPS_SHIFT6 17
+#define R_MIPS_64 18
+#define R_MIPS_GOT_DISP 19
+#define R_MIPS_GOT_PAGE 20
+#define R_MIPS_GOT_OFST 21
+/*
+ * The following two relocation types are specified in the the MIPS ABI
+ * conformance guide version 1.2 but not yet in the psABI.
+ */
+#define R_MIPS_GOTHI16 22
+#define R_MIPS_GOTLO16 23
+#define R_MIPS_SUB 24
+#define R_MIPS_INSERT_A 25
+#define R_MIPS_INSERT_B 26
+#define R_MIPS_DELETE 27
+#define R_MIPS_HIGHER 28
+#define R_MIPS_HIGHEST 29
+/*
+ * The following two relocation types are specified in the the MIPS ABI
+ * conformance guide version 1.2 but not yet in the psABI.
+ */
+#define R_MIPS_CALLHI16 30
+#define R_MIPS_CALLLO16 31
+/*
+ * This range is reserved for vendor specific relocations.
+ */
+#define R_MIPS_LOVENDOR 100
+#define R_MIPS_HIVENDOR 127
+
+
+/*
+ * Sparc ELF relocation types
+ */
+#define R_SPARC_NONE 0
+#define R_SPARC_8 1
+#define R_SPARC_16 2
+#define R_SPARC_32 3
+#define R_SPARC_DISP8 4
+#define R_SPARC_DISP16 5
+#define R_SPARC_DISP32 6
+#define R_SPARC_WDISP30 7
+#define R_SPARC_WDISP22 8
+#define R_SPARC_HI22 9
+#define R_SPARC_22 10
+#define R_SPARC_13 11
+#define R_SPARC_LO10 12
+#define R_SPARC_GOT10 13
+#define R_SPARC_GOT13 14
+#define R_SPARC_GOT22 15
+#define R_SPARC_PC10 16
+#define R_SPARC_PC22 17
+#define R_SPARC_WPLT30 18
+#define R_SPARC_COPY 19
+#define R_SPARC_GLOB_DAT 20
+#define R_SPARC_JMP_SLOT 21
+#define R_SPARC_RELATIVE 22
+#define R_SPARC_UA32 23
+#define R_SPARC_PLT32 24
+#define R_SPARC_HIPLT22 25
+#define R_SPARC_LOPLT10 26
+#define R_SPARC_PCPLT32 27
+#define R_SPARC_PCPLT22 28
+#define R_SPARC_PCPLT10 29
+#define R_SPARC_10 30
+#define R_SPARC_11 31
+#define R_SPARC_WDISP16 40
+#define R_SPARC_WDISP19 41
+#define R_SPARC_7 43
+#define R_SPARC_5 44
+#define R_SPARC_6 45
+
+/* Bits present in AT_HWCAP, primarily for Sparc32. */
+
+#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */
+#define HWCAP_SPARC_STBAR 2
+#define HWCAP_SPARC_SWAP 4
+#define HWCAP_SPARC_MULDIV 8
+#define HWCAP_SPARC_V9 16
+
+
+/*
+ * 68k ELF relocation types
+ */
+#define R_68K_NONE 0
+#define R_68K_32 1
+#define R_68K_16 2
+#define R_68K_8 3
+#define R_68K_PC32 4
+#define R_68K_PC16 5
+#define R_68K_PC8 6
+#define R_68K_GOT32 7
+#define R_68K_GOT16 8
+#define R_68K_GOT8 9
+#define R_68K_GOT32O 10
+#define R_68K_GOT16O 11
+#define R_68K_GOT8O 12
+#define R_68K_PLT32 13
+#define R_68K_PLT16 14
+#define R_68K_PLT8 15
+#define R_68K_PLT32O 16
+#define R_68K_PLT16O 17
+#define R_68K_PLT8O 18
+#define R_68K_COPY 19
+#define R_68K_GLOB_DAT 20
+#define R_68K_JMP_SLOT 21
+#define R_68K_RELATIVE 22
+
+/*
+ * Alpha ELF relocation types
+ */
+#define R_ALPHA_NONE 0 /* No reloc */
+#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
+#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */
+#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */
+#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */
+#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */
+#define R_ALPHA_GPDISP 6 /* Add displacement to GP */
+#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */
+#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */
+#define R_ALPHA_SREL16 9 /* PC relative 16 bit */
+#define R_ALPHA_SREL32 10 /* PC relative 32 bit */
+#define R_ALPHA_SREL64 11 /* PC relative 64 bit */
+#define R_ALPHA_OP_PUSH 12 /* OP stack push */
+#define R_ALPHA_OP_STORE 13 /* OP stack pop and store */
+#define R_ALPHA_OP_PSUB 14 /* OP stack subtract */
+#define R_ALPHA_OP_PRSHIFT 15 /* OP stack right shift */
+#define R_ALPHA_GPVALUE 16
+#define R_ALPHA_GPRELHIGH 17
+#define R_ALPHA_GPRELLOW 18
+#define R_ALPHA_IMMED_GP_16 19
+#define R_ALPHA_IMMED_GP_HI32 20
+#define R_ALPHA_IMMED_SCN_HI32 21
+#define R_ALPHA_IMMED_BR_HI32 22
+#define R_ALPHA_IMMED_LO32 23
+#define R_ALPHA_COPY 24 /* Copy symbol at runtime */
+#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */
+#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */
+#define R_ALPHA_RELATIVE 27 /* Adjust by program base */
+
+/* Legal values for e_flags field of Elf64_Ehdr. */
+
+#define EF_ALPHA_32BIT 1 /* All addresses are below 2GB */
+
+
+typedef struct elf32_rel {
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+} Elf32_Rel;
+
+typedef struct elf64_rel {
+ Elf64_Addr r_offset; /* Location at which to apply the action */
+ Elf64_Word r_info; /* index and type of relocation */
+} Elf64_Rel;
+
+typedef struct elf32_rela{
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+ Elf32_Sword r_addend;
+} Elf32_Rela;
+
+typedef struct elf64_rela {
+ Elf64_Addr r_offset; /* Location at which to apply the action */
+ Elf64_Word r_info; /* index and type of relocation */
+ Elf64_Word r_addend; /* Constant addend used to compute value */
+} Elf64_Rela;
+
+typedef struct elf32_sym{
+ Elf32_Word st_name;
+ Elf32_Addr st_value;
+ Elf32_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf32_Half st_shndx;
+} Elf32_Sym;
+
+typedef struct elf64_sym {
+ Elf32_Word st_name; /* Symbol name, index in string tbl (yes, Elf32) */
+ unsigned char st_info; /* Type and binding attributes */
+ unsigned char st_other; /* No defined meaning, 0 */
+ Elf64_Half st_shndx; /* Associated section index */
+ Elf64_Addr st_value; /* Value of the symbol */
+ Elf64_Word st_size; /* Associated symbol size */
+} Elf64_Sym;
+
+
+#define EI_NIDENT 16
+
+typedef struct elf32_hdr{
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry; /* Entry point */
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct elf64_hdr {
+ unsigned char e_ident[16]; /* ELF "magic number" */
+ Elf64_SHalf e_type;
+ Elf64_Half e_machine;
+ INT32 e_version;
+ Elf64_Addr e_entry; /* Entry point virtual address */
+ Elf64_Off e_phoff; /* Program header table file offset */
+ Elf64_Off e_shoff; /* Section header table file offset */
+ INT32 e_flags;
+ Elf64_SHalf e_ehsize;
+ Elf64_SHalf e_phentsize;
+ Elf64_SHalf e_phnum;
+ Elf64_SHalf e_shentsize;
+ Elf64_SHalf e_shnum;
+ Elf64_SHalf e_shstrndx;
+} Elf64_Ehdr;
+
+/* These constants define the permissions on sections in the program
+ header, p_flags. */
+#define PF_R 0x4
+#define PF_W 0x2
+#define PF_X 0x1
+
+typedef struct elf32_phdr{
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+} Elf32_Phdr;
+
+typedef struct elf64_phdr {
+ INT32 p_type;
+ INT32 p_flags;
+ Elf64_Off p_offset; /* Segment file offset */
+ Elf64_Addr p_vaddr; /* Segment virtual address */
+ Elf64_Addr p_paddr; /* Segment physical address */
+ Elf64_Word p_filesz; /* Segment size in file */
+ Elf64_Word p_memsz; /* Segment size in memory */
+ Elf64_Word p_align; /* Segment alignment, file & memory */
+} Elf64_Phdr;
+
+/* sh_type */
+#define SHT_NULL 0
+#define SHT_PROGBITS 1
+#define SHT_SYMTAB 2
+#define SHT_STRTAB 3
+#define SHT_RELA 4
+#define SHT_HASH 5
+#define SHT_DYNAMIC 6
+#define SHT_NOTE 7
+#define SHT_NOBITS 8
+#define SHT_REL 9
+#define SHT_SHLIB 10
+#define SHT_DYNSYM 11
+#define SHT_NUM 12
+#define SHT_LOPROC 0x70000000
+#define SHT_HIPROC 0x7fffffff
+#define SHT_LOUSER 0x80000000
+#define SHT_HIUSER 0xffffffff
+#define SHT_MIPS_LIST 0x70000000
+#define SHT_MIPS_CONFLICT 0x70000002
+#define SHT_MIPS_GPTAB 0x70000003
+#define SHT_MIPS_UCODE 0x70000004
+
+/* sh_flags */
+#define SHF_WRITE 0x1
+#define SHF_ALLOC 0x2
+#define SHF_EXECINSTR 0x4
+#define SHF_MASKPROC 0xf0000000
+#define SHF_MIPS_GPREL 0x10000000
+
+/* special section indexes */
+#define SHN_UNDEF 0
+#define SHN_LORESERVE 0xff00
+#define SHN_LOPROC 0xff00
+#define SHN_HIPROC 0xff1f
+#define SHN_ABS 0xfff1
+#define SHN_COMMON 0xfff2
+#define SHN_HIRESERVE 0xffff
+#define SHN_MIPS_ACCOMON 0xff00
+
+typedef struct {
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+typedef struct elf64_shdr {
+ Elf32_Word sh_name; /* Section name, index in string tbl (yes Elf32) */
+ Elf32_Word sh_type; /* Type of section (yes Elf32) */
+ Elf64_Word sh_flags; /* Miscellaneous section attributes */
+ Elf64_Addr sh_addr; /* Section virtual addr at execution */
+ Elf64_Off sh_offset; /* Section file offset */
+ Elf64_Word sh_size; /* Size of section in bytes */
+ Elf32_Word sh_link; /* Index of another section (yes Elf32) */
+ Elf32_Word sh_info; /* Additional section information (yes Elf32) */
+ Elf64_Word sh_addralign; /* Section alignment */
+ Elf64_Word sh_entsize; /* Entry size if section holds table */
+} Elf64_Shdr;
+
+#define EI_MAG0 0 /* e_ident[] indexes */
+#define EI_MAG1 1
+#define EI_MAG2 2
+#define EI_MAG3 3
+#define EI_CLASS 4
+#define EI_DATA 5
+#define EI_VERSION 6
+#define EI_PAD 7
+
+#define ELFMAG0 0x7f /* EI_MAG */
+#define ELFMAG1 'E'
+#define ELFMAG2 'L'
+#define ELFMAG3 'F'
+#define ELFMAG "\177ELF"
+#define SELFMAG 4
+
+#define ELFCLASSNONE 0 /* EI_CLASS */
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+#define ELFCLASSNUM 3
+
+#define ELFDATANONE 0 /* e_ident[EI_DATA] */
+#define ELFDATA2LSB 1
+#define ELFDATA2MSB 2
+
+#define EV_NONE 0 /* e_version, EI_VERSION */
+#define EV_CURRENT 1
+#define EV_NUM 2
+
+/* Notes used in ET_CORE */
+#define NT_PRSTATUS 1
+#define NT_PRFPREG 2
+#define NT_PRPSINFO 3
+#define NT_TASKSTRUCT 4
+
+/* Note header in a PT_NOTE section */
+typedef struct elf32_note {
+ Elf32_Word n_namesz; /* Name size */
+ Elf32_Word n_descsz; /* Content size */
+ Elf32_Word n_type; /* Content type */
+} Elf32_Nhdr;
+
+/* Note header in a PT_NOTE section */
+/*
+ * For now we use the 32 bit version of the structure until we figure
+ * out whether we need anything better. Note - on the Alpha, "unsigned int"
+ * is only 32 bits.
+ */
+typedef struct elf64_note {
+ Elf32_Word n_namesz; /* Name size */
+ Elf32_Word n_descsz; /* Content size */
+ Elf32_Word n_type; /* Content type */
+} Elf64_Nhdr;
+
+#if ELF_CLASS == ELFCLASS32
+
+extern Elf32_Dyn _DYNAMIC [];
+#define elfhdr elf32_hdr
+#define elf_phdr elf32_phdr
+#define elf_note elf32_note
+
+#else
+
+extern Elf64_Dyn _DYNAMIC [];
+#define elfhdr elf64_hdr
+#define elf_phdr elf64_phdr
+#define elf_note elf64_note
+
+#endif
+
+
+#endif /* __LINUX_ELF_H__ */
--- /dev/null
+/*
+ * elilo.c - IA-64/IA-32 EFI Linux loader
+ *
+ * Copyright (C) 1999-2003 Hewlett-Packard Co.
+ * Contributed by David Mosberger <davidm@hpl.hp.com>.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * Copyright (C) 1999-2000 VA Linux Systems
+ * Contributed by Johannes Erdfelt <jerdfelt@valinux.com>.
+ *
+ * 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 "vars.h"
+
+#include "getopt.h"
+#include "fileops.h"
+#include "loader.h"
+#include "config.h" /* for config_init() */
+
+#define ELILO_VERSION L"3.4"
+#define ELILO_SHARED_CMDLINE_OPTS L"pPMC:aDhd:i:vVc:E"
+
+elilo_config_t elilo_opt;
+
+EFI_SYSTEM_TABLE *systab; /* pointer to EFI system table */
+
+/*
+ * Load the Linux kernel in memory from the boot media
+ * Output:
+ * kd = address of kernel entry point
+ * + end address of kernel code+data+bss
+ * + kernel entry point
+ * Return:
+ * ELILO_LOAD_ERROR : if something went wrong
+ * ELILO_LOAD_ABORTED : user interruption while loading
+ * ELILO_LOAD_SUCCESS : otherwise
+ */
+static INTN
+do_kernel_load(CHAR16 *kname, kdesc_t *kd)
+{
+ loader_ops_t *ldops;
+ EFI_STATUS status;
+ fops_fd_t fd;
+
+ status = fops_open(kname, &fd);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"Kernel file not found %s", kname));
+ return ELILO_LOAD_ERROR;
+ }
+ fops_close(fd);
+
+ ldops = loader_probe(kname);
+ if (ldops == NULL) {
+ ERR_PRT((L"Cannot find a loader for %s", kname));
+ return ELILO_LOAD_ERROR;
+ }
+
+ VERB_PRT(1,Print(L"Using %s loader\n", ldops->ld_name));
+
+ return ldops->ld_load_kernel(kname, kd);
+}
+
+INTN
+kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem)
+{
+
+ /*
+ * Now let's try to load the kernel !
+ */
+ switch(do_kernel_load(kname, kd)) {
+ case ELILO_LOAD_SUCCESS:
+ break;
+
+ case ELILO_LOAD_ERROR:
+ /* XXX: add fallback support */
+ return ELILO_LOAD_ERROR;
+
+ case ELILO_LOAD_ABORTED:
+ /* we drop initrd in case we aborted the load */
+ elilo_opt.initrd[0] = CHAR_NULL;
+
+ /* will go back to interactive selection */
+ elilo_opt.prompt = 1;
+ elilo_opt.timeout = ELILO_DEFAULT_TIMEOUT;
+ elilo_opt.delay = 0;
+
+ return ELILO_LOAD_RETRY;
+ }
+
+ VERB_PRT(3, Print(L"kernel loaded in [0x%lx-0x%lx] entry=0x%lx\n",
+ (UINT64)kd->kstart, (UINT64)kd->kend, (UINT64)kd->kentry));
+
+ if (elilo_opt.initrd[0]) {
+
+ if (sysdeps_initrd_get_addr(kd, imem) == -1) goto exit_error;
+
+ switch(load_initrd(elilo_opt.initrd, imem)) {
+ case ELILO_LOAD_SUCCESS:
+ break;
+ case ELILO_LOAD_ERROR:
+ goto exit_error;
+ case ELILO_LOAD_ABORTED:
+ /* the free_kmem() is the responsibility of the loader */
+
+ /* we drop initrd in case we aborted the load */
+ elilo_opt.initrd[0] = CHAR_NULL;
+ elilo_opt.prompt = 1;
+ elilo_opt.timeout = ELILO_DEFAULT_TIMEOUT;
+ elilo_opt.delay = 0;
+
+ return ELILO_LOAD_RETRY;
+ }
+ }
+ return ELILO_LOAD_SUCCESS;
+exit_error:
+ free_kmem();
+ if (imem->start_addr) free(imem->start_addr);
+
+ return ELILO_LOAD_ERROR;
+}
+
+static INTN
+main_loop(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image)
+{
+ CHAR16 kname[FILENAME_MAXLEN];
+ CHAR16 cmdline_tmp[CMDLINE_MAXLEN];
+ CHAR16 cmdline[CMDLINE_MAXLEN];
+ VOID *bp;
+ UINTN cookie;
+ EFI_STATUS status = EFI_SUCCESS;
+ kdesc_t kd;
+ memdesc_t imem;
+ INTN r;
+
+ /*
+ * First place where we potentially do system dependent
+ * operations. It is a one time opportunity before entering
+ * the main loop
+ */
+ if (sysdeps_preloop_actions(dev, argv, argc, index, image) == -1) return -1;
+
+ for(;;) {
+ kname[0] = cmdline_tmp[0] = cmdline[0] = CHAR_NULL;
+ imem.start_addr = 0; imem.pgcnt = 0;
+ elilo_opt.sys_img_opts = NULL;
+
+ if (kernel_chooser(argv, argc, index, kname, cmdline_tmp) == -1) goto exit_error;
+
+ switch (kernel_load(image, kname, &kd, &imem)) {
+ case ELILO_LOAD_SUCCESS:
+ goto do_launch;
+ case ELILO_LOAD_ERROR:
+ goto exit_error;
+ /* otherwise we retry ! */
+ }
+ }
+
+do_launch:
+ r =subst_vars(cmdline_tmp, cmdline, CMDLINE_MAXLEN);
+
+ VERB_PRT(3, Print(L"final cmdline(%d): %s\n", r, cmdline));
+
+ /* 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, &cookie)) == 0) goto error;
+
+ /* terminate bootservices */
+ status = BS->ExitBootServices(image, cookie);
+ if (EFI_ERROR(status)) goto bad_exit;
+
+ start_kernel(kd.kentry, bp);
+ /* NOT REACHED */
+
+ ERR_PRT((L"start_kernel() return !"));
+bad_exit:
+ /*
+ * we are still in BootService mode
+ */
+ ERR_PRT((L"ExitBootServices failed %r", status));
+error:
+ free_kmem();
+ if (imem.start_addr) free(imem.start_addr);
+ if (bp) free_boot_params(bp);
+exit_error:
+ return ELILO_LOAD_ERROR;
+
+}
+
+static VOID
+elilo_help(VOID)
+{
+
+ Print(L"-d secs timeout in 10th of second before booting\n");
+ Print(L"-h this help text\n");
+ Print(L"-V print version\n");
+ Print(L"-v verbose level(can appear multiple times)\n");
+ Print(L"-a always check for alternate kernel image\n");
+ Print(L"-i file load file as the initial ramdisk\n");
+ Print(L"-C file indicate the config file to use\n");
+ Print(L"-P parse config file only (verify syntax)\n");
+ Print(L"-D enable debug prints\n");
+ Print(L"-p force interactive mode\n");
+ Print(L"-c name image chooser to use\n");
+ Print(L"-E do not force EDD30 variable\n");
+
+ sysdeps_print_cmdline_opts();
+
+ Print(L"\n");
+
+ print_config_options();
+}
+
+/*
+ * XXX: hack to work around a problem with EFI command line argument when booted
+ * from network. In this case, it looks like LoadOptions/LoadOptionsSize contain
+ * garbage
+ */
+static CHAR16 *default_load_options;
+static UINTN default_load_options_size;
+static INTN done_fixups;
+
+static VOID
+fixupargs(EFI_LOADED_IMAGE *info)
+{
+ EFI_STATUS status;
+ EFI_PXE_BASE_CODE *pxe;
+
+#define FAKE_ELILONAME L"elilo-forced"
+
+ status = BS->HandleProtocol (info->DeviceHandle, &PxeBaseCodeProtocol, (VOID **)&pxe);
+ if (EFI_ERROR(status)) return;
+
+ default_load_options = info->LoadOptions;
+ default_load_options_size = info->LoadOptionsSize;
+
+ info->LoadOptions = FAKE_ELILONAME;
+ info->LoadOptionsSize = StrLen(info->LoadOptions)*sizeof(CHAR16);
+
+ done_fixups = 1;
+}
+
+/*
+ * we restore the arguments in case we modified them just to make sure
+ * we don't confuse caller.
+ */
+static VOID
+unfixupargs(EFI_LOADED_IMAGE *info)
+{
+ if (done_fixups == 0) return;
+
+ info->LoadOptions = default_load_options;
+ info->LoadOptionsSize = default_load_options_size;
+}
+
+
+/*
+ * in order to get fully detailed EFI path names to devices, EDD3.0 specification must
+ * be turned on. On new versions of EFI, this is the default. An environment variable
+ * called EDD30 reflects the current settings. If true, then EDD3.0 is enabled
+ * and device path names show the detailed device types. If false, then a default
+ * generic name is used instead. This has some implications of ELILO's ability to
+ * provide a better naming scheme for detected devices. If EDD3.0 is enabled
+ * then much more precise names can be used which makes it easy to use.
+ * If EDD3.0 is nont enabled, ELILO will still work but will use very generic names
+ * for devices.
+ *
+ * ELILO will check the value of the variable. If not true, then it will force it to
+ * true. This will require a reboot for EFI to make use of the new value.
+ * Return:
+ * EFI_SUCCESS: if variable is already true or was set to true
+ * EFI error code: otherwise, like when could not forced variable or unrecognized variable content
+ */
+#define EDD30_GUID \
+{0x964e5b21, 0x6459, 0x11d2, { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}}
+
+#define EDD30_ATTR (EFI_VARIABLE_RUNTIME_ACCESS|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_NON_VOLATILE)
+
+static EFI_GUID edd30_guid = EDD30_GUID;
+
+static INTN
+check_edd30(VOID)
+{
+ EFI_STATUS status;
+ UINTN l = sizeof(BOOLEAN);
+ UINT8 bool = FALSE;
+ INTN ret = -1;
+
+ status = RT->GetVariable(L"EDD30", &edd30_guid, NULL, &l, &bool);
+ if (status == EFI_BUFFER_TOO_SMALL || (bool != TRUE && bool != FALSE)) {
+ ERR_PRT((L"Warning: EDD30 EFI variable is not boolean value: forcing it to TRUE"));
+ return -1;
+ }
+ if (status == EFI_SUCCESS && bool == TRUE) {
+ VERB_PRT(3, Print(L"EDD30 is TRUE\n"));
+ elilo_opt.edd30_on = TRUE;
+ ret = 0;
+ } else {
+ VERB_PRT(4,
+ if (status != EFI_SUCCESS) {
+ Print(L"EDD30 EFI variable not defined\n");
+ } else {
+ Print(L"EDD30 EFI variable is false\n");
+ }
+ );
+ }
+
+ return ret;
+}
+
+static INTN
+force_edd30(VOID)
+{
+ EFI_STATUS status;
+ UINTN l = sizeof(BOOLEAN);
+ UINT8 bool;
+
+ bool = TRUE;
+ status = RT->SetVariable(L"EDD30", &edd30_guid, EDD30_ATTR, l, &bool);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"can't set EDD30 variable: ignoring it"));
+ return -1;
+ }
+
+ VERB_PRT(3, Print(L"EDD30 variable forced to TRUE. You should reboot to take advantage of EDD3.0.\n"));
+
+ return 0;
+}
+
+/*
+ * That's equivalent of main(): main entry point
+ */
+EFI_STATUS
+efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab)
+{
+ CHAR16 *argv[MAX_ARGS];
+ CHAR16 optstring[MAX_ARGS];
+ EFI_LOADED_IMAGE *info;
+ EFI_STATUS status, ret = EFI_LOAD_ERROR;
+ INTN argc = 0, c;
+ INTN edd30_status, retry;
+ CHAR16 *ptr, *arglist = NULL;
+ BOOLEAN devices_initialized = FALSE;
+ CHAR16 dpath[FILENAME_MAXLEN];
+ CHAR16 *devpath;
+
+ //elilo_opt.verbose=3;
+ //elilo_opt.debug=1;
+
+ /* initialize global variable */
+ systab = system_tab;
+
+ /* initialize EFI library */
+ InitializeLib(image, systab);
+ /*
+ * disable the platform watchdog timer if we go interactive
+ * XXX: we should reinstate it once we're done
+ * It seems like with PXE, the timer is set to a few minutes
+ * and sometimes triggers if we stay too long in interactive
+ * mode.
+ * XXX: clean this up !
+ */
+ BS->SetWatchdogTimer(0, 0x0, 0, NULL);
+
+ /* initialize memory allocator */
+ if (alloc_init() == -1) return EFI_LOAD_ERROR;
+
+ status = BS->HandleProtocol(image, &LoadedImageProtocol, (VOID **) &info);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"image handle does not support LOADED_IMAGE protocol"));
+ return EFI_LOAD_ERROR;
+ }
+
+ VERB_PRT(5,Print(L"Loaded at 0x%lx size=%d bytes code=%d data=%d\n", info->ImageBase, info->ImageSize, info->ImageCodeType, info->ImageDataType));
+
+ /*
+ * verify EDD3.0 status. Users may have to reboot
+ */
+ edd30_status = check_edd30();
+
+ /*
+ * initialize configuration empire
+ */
+ if (config_init() == -1) goto do_exit;
+
+ /*
+ * architecture-specific initializations
+ */
+ if (sysdeps_init(info->DeviceHandle) == -1) goto do_exit;
+ if (sysdeps_register_options() == -1) goto do_exit;
+
+ /*
+ * This may be required in case Elilo was booted with absolutely no arguments
+ * Elilo's logic is that just like normal Linux programs at least one argument
+ * (argv[0]) exists at all times and that it usually gives the name of the program
+ * (the command used to start it).
+ ERR_PRT((L"LoadOptions=%x OpenSize=%d", info->LoadOptions, info->LoadOptionsSize));
+ */
+
+ /*
+ * in case there is something wrong with the default boot_device
+ * we default to basic fixups and we need to force interactive
+ * mode to make sure the user has a chance of specifying a kernel
+ */
+ fixupargs(info);
+
+#if 0
+ Print(L"LoadOptions=%x OpenSize=%d\n", info->LoadOptions, info->LoadOptionsSize);
+ { INTN i; for (i=0; i< info->LoadOptionsSize>>1; i++) Print(L"options[%d]=%d (%c)\n", i, ((CHAR16 *)info->LoadOptions)[i], ((CHAR16 *)info->LoadOptions)[i]); }
+#endif
+
+ /*
+ * we must copy argument because argify modifies the string.
+ * This caused problems when arguments are coming from NVRAM
+ * as passed by the EFI boot manager
+ *
+ * We add an extra character to the buffer in case the LoadOptions is not
+ * NULL terminated. The extra space will be used to ADD the extra terminator.
+ */
+ arglist = alloc(info->LoadOptionsSize+sizeof(CHAR16), EfiLoaderData);
+ if (arglist == NULL) {
+ ERR_PRT((L"cannot copy argument list"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Memcpy(arglist, info->LoadOptions, info->LoadOptionsSize);
+
+ argc = argify(arglist,info->LoadOptionsSize, argv);
+
+ StrCpy(optstring, ELILO_SHARED_CMDLINE_OPTS);
+ StrCat(optstring, sysdeps_get_cmdline_opts());
+
+ while ((c=Getopt(argc, argv, optstring)) != -1 ) {
+ switch(c) {
+ case 'a':
+ elilo_opt.alt_check = 1;
+ break;
+ case 'D':
+ elilo_opt.debug = 1;
+ break;
+ case 'p':
+ elilo_opt.prompt = 1;
+ break;
+ case 'v':
+ elilo_opt.verbose++;
+ if (elilo_opt.verbose > 5) elilo_opt.verbose = 5;
+ break;
+ case 'h':
+ elilo_help();
+ ret = EFI_SUCCESS;
+ goto do_exit;
+ case 'd':
+ /*
+ * zero is a valid value here, so we use the delay-set to mark the
+ * fact that the user specified a value on cmdline. See config.c
+ */
+ elilo_opt.delay = Atoi(Optarg);
+ elilo_opt.delay_set = 1;
+ break;
+ case 'E':
+ /* don't force EDD30 EFI variable if not already set */
+ elilo_opt.edd30_no_force = 1;
+ break;
+ case 'i':
+ if (StrLen(Optarg) >= FILENAME_MAXLEN-1) {
+ Print(L"initrd filename is limited to %d characters\n", FILENAME_MAXLEN);
+ goto do_exit;
+ }
+ StrCpy(elilo_opt.initrd, Optarg);
+ break;
+ case 'C':
+ if (StrLen(Optarg) >= FILENAME_MAXLEN-1) {
+ Print(L"config filename is limited to %d characters\n", FILENAME_MAXLEN);
+ goto do_exit;
+ }
+ StrCpy(elilo_opt.config, Optarg);
+ break;
+ case 'M': /* builtin debug tool */
+ { mmap_desc_t mdesc;
+ if (get_memmap(&mdesc) == -1) {
+ Print(L"Cannot get memory map\n");
+ return EFI_LOAD_ERROR;
+ }
+ print_memmap(&mdesc);
+ ret = EFI_SUCCESS;
+ goto do_exit;
+ }
+ case 'V':
+ Print(L"ELILO v%s for EFI/%a\n", ELILO_VERSION, ELILO_ARCH);
+ ret = EFI_SUCCESS;
+ goto do_exit;
+ case 'P':
+ /* cmdline only option */
+ elilo_opt.parse_only = 1;
+ break;
+ case 'c':
+ if (StrLen(Optarg) >= FILENAME_MAXLEN-1) {
+ Print(L"chooser name is limited to %d characters\n", FILENAME_MAXLEN);
+ goto do_exit;
+ }
+ StrCpy(elilo_opt.chooser, Optarg);
+ break;
+ default:
+ /*
+ * try system dependent options before declaring error
+ */
+ if (sysdeps_getopt(c, Optind, Optarg) == 0) continue;
+
+ Print(L"Unknown option -%c\n", (CHAR16)c);
+ goto do_exit;
+ }
+ }
+ DBG_PRT((L"Optind=%d optarg=%x argc=%d", Optind, Optarg, argc));
+
+ /*
+ * we can't defer this phase any longer...
+ * Must be done after the elilo_opt are initialized (at least partially)
+ */
+ if (init_devices(info->DeviceHandle) == -1) goto do_exit;
+
+ devices_initialized = TRUE;
+
+ devpath = DevicePathToStr(info->FilePath);
+
+ /*
+ * set per fileops defaults files for configuration and kernel
+ */
+ fops_setdefaults(elilo_opt.default_config, elilo_opt.default_kernel, FILENAME_MAXLEN, devpath);
+
+ /*
+ * XXX: won't be visible if verbose not required from command line
+ */
+ VERB_PRT(2,Print(L"Default config: %s\nDefault_kernel: %s\n",
+ elilo_opt.default_config,elilo_opt.default_kernel));
+ /*
+ * use default config file if not specified by user
+ */
+ ptr = elilo_opt.config[0] == CHAR_NULL ? (retry=1,elilo_opt.default_config) : (retry=0,elilo_opt.config);
+
+ /*
+ * parse config file (verbose becomes visible if set)
+ */
+ ret = read_config(ptr, retry);
+ Print(L"read_config=%r\n", ret);
+ /*
+ * when the config file is not found, we fail only if:
+ * - the user did not specified interactive mode
+ * - the user did not explicitely specify the config file
+ */
+ if (ret == EFI_NOT_FOUND || ret == EFI_TFTP_ERROR) {
+ if (elilo_opt.prompt == 0 && elilo_opt.config[0] != CHAR_NULL) {
+ Print(L"config file %s not found\n", ptr);
+ goto do_exit;
+ }
+ fops_getdefault_path(dpath, FILENAME_MAXLEN);
+ if (ret == EFI_TFTP_ERROR)
+ Print(L"no config file found on TFTP server in %s\n", dpath);
+ else
+ Print(L"no config file found in %s\n", dpath);
+ }
+ /*
+ * stop if just doing parsing
+ */
+ if (elilo_opt.parse_only) {
+ if (ret == EFI_SUCCESS)
+ Print(L"Config file %s parsed successfully\n", ptr);
+ goto do_exit;
+ }
+ /*
+ * if there was an error when parsing the config file, then
+ * we force interactive mode to give a chance to the user.
+ * We also clear the error.
+ */
+ if (ret && argc == 1) {
+ Print(L"forcing interactive mode because of errors\n");
+ elilo_opt.prompt = 1;
+ }
+
+ /*
+ * If EDD30 EFI variable was not set to TRUE (or not defined), we
+ * we try to force it. This will take effect at the next reboot.
+ *
+ * Some controllers don't have EDD30 support, in this case forcing it
+ * may cause problems, therefore we check the edd_no_force option
+ * before making the call.
+ */
+ if (edd30_status == -1 && elilo_opt.edd30_no_force == 0) {
+ force_edd30();
+ }
+
+ ret = EFI_LOAD_ERROR;
+
+ /*
+ * if the user specified a kernel on the command line
+ * then we don't go to interactive mode even if it
+ * was set in the config file or set because of an
+ * error parsing the config file.
+ */
+ if (argc > Optind) elilo_opt.prompt = 0;
+
+
+ /* set default timeout if going interactive */
+ if ((elilo_opt.prompt && elilo_opt.timeout == 0)) {
+ elilo_opt.timeout = ELILO_DEFAULT_TIMEOUT;
+ }
+
+ /*
+ * which chooser we will use
+ */
+ if (init_chooser(info->DeviceHandle) == -1) {
+ ERR_PRT((L"Cannot find a decent chooser\n"));
+ goto do_exit;
+ }
+
+ //if (elilo_opt.prompt == 0) VERB_PRT(1, print_devices());
+
+ main_loop(info->DeviceHandle, argv, argc, Optind, image);
+ /* should not return */
+do_exit:
+ unfixupargs(info);
+
+ //if (arglist) free(arglist);
+
+ /* free all resources assiocated with file accesses */
+ if (devices_initialized) close_devices();
+
+ /* garbage collect all remaining allocations */
+ free_all_memory();
+
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * Copyright (C) 2001 Silicon Graphics, Inc.
+ * Contributed by Brent Casavant <bcasavan@sgi.com>
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ * GNU EFI 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.
+ *
+ * GNU EFI 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 GNU EFI; 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_H__
+#define __ELILO_H__
+
+#include <efi.h>
+
+#include "elilo_debug.h"
+
+#include "fileops.h"
+#include "chooser.h"
+
+#include "strops.h"
+
+#include "sysdeps.h"
+
+#define MB (1024*1024) /* 1 megabyte */
+
+/* Round X up/down to A, which must be an integer power of two. */
+#define ROUNDUP(x,a) (((x) + (a) - 1) & ~((a) - 1))
+#define ROUNDDOWN(x,a) ((x) & ~((a) - 1))
+
+/*
+ * Elilo Boot modes
+ */
+#define ELILO_LOAD_SUCCESS 0
+#define ELILO_LOAD_ABORTED 1
+#define ELILO_LOAD_ERROR 2
+#define ELILO_LOAD_RETRY 3
+
+#define ELILO_DEFAULT_TIMEOUT ELILO_TIMEOUT_INFINITY
+#define ELILO_TIMEOUT_INFINITY (~0UL)
+
+#define CMDLINE_MAXLEN 512 /* needed by ia32 */
+#define FILENAME_MAXLEN 256
+#define MAX_ARGS 256
+
+typedef struct {
+ UINT8 nothing_yet;
+} image_opt_t;
+
+typedef struct {
+ /*
+ * list of options controllable from both the command line
+ * and the config file
+ */
+ UINTN alt_check; /* always check for alternate kernel */
+ UINTN debug; /* debug print() on */
+ UINTN delay; /* delay before booting the image */
+ UINTN verbose; /* verbosity level [1-5] */
+ CHAR16 initrd[FILENAME_MAXLEN]; /* name of file for initial ramdisk */
+ UINT8 delay_set; /* mark whether or not delay was specified on cmdline */
+ UINT8 edd30_on; /* true is EDD30 variable is TRUE */
+ UINT8 edd30_no_force; /* don't force EDD30 variable to true */
+ /*
+ * list of options controllable from either the command line
+ * or the config file
+ */
+ UINTN prompt; /* enter interactive mode */
+ UINTN parse_only; /* only parses the config file */
+ UINTN timeout; /* timeout before leaving interactive mode*/
+
+ image_opt_t img_opt; /* architecture independent per image options*/
+
+ sys_img_options_t *sys_img_opts; /* architecture depdendent per image options */
+
+ CHAR16 default_kernel[FILENAME_MAXLEN];
+ CHAR16 default_config[FILENAME_MAXLEN];
+
+ CHAR16 config[FILENAME_MAXLEN]; /* name of config file */
+ CHAR16 chooser[FILENAME_MAXLEN]; /* image chooser to use */
+} elilo_config_t;
+
+
+extern elilo_config_t elilo_opt;
+
+extern EFI_SYSTEM_TABLE *systab;
+
+typedef struct {
+ VOID *start_addr;
+ UINTN pgcnt;
+} memdesc_t;
+
+typedef struct {
+ VOID *kstart;
+ VOID *kend;
+ VOID *kentry;
+} kdesc_t;
+
+typedef struct {
+ EFI_MEMORY_DESCRIPTOR *md;
+ UINTN map_size;
+ UINTN desc_size;
+ UINTN cookie;
+ UINT32 desc_version;
+} mmap_desc_t;
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a)>(b) ? (b) : (a))
+#endif
+
+#define VERB_PRT(n,cmd) \
+ { if (elilo_opt.verbose >= (n)) { cmd; } }
+
+
+/* from alloc.c */
+extern INTN alloc_init(VOID);
+extern VOID *alloc(UINTN, EFI_MEMORY_TYPE);
+extern VOID free(VOID *);
+extern VOID *alloc_pages(UINTN, EFI_MEMORY_TYPE, EFI_ALLOCATE_TYPE, VOID *);
+extern VOID free_pages(VOID *);
+extern VOID free_all(VOID);
+extern INTN alloc_kmem(VOID *, UINTN);
+extern VOID free_kmem(VOID);
+extern VOID free_all_memory(VOID);
+
+/* from util.c */
+extern INTN read_file(UINTN fd, UINTN, CHAR8 *);
+extern EFI_STATUS check_abort(VOID);
+extern VOID reset_input(VOID);
+extern INTN wait_timeout(UINTN);
+extern INTN argify(CHAR16 *, UINTN, CHAR16 **);
+extern VOID unargify(CHAR16 **, CHAR16 **);
+extern void split_args(CHAR16 *, CHAR16 *, CHAR16 *);
+extern INTN get_memmap(mmap_desc_t *);
+extern VOID free_memmap(mmap_desc_t *);
+extern INTN find_kernel_memory(VOID *low_addr, VOID *max_addr, UINTN alignment, VOID ** start);
+extern VOID print_memmap(mmap_desc_t *);
+extern VOID ascii2U(CHAR8 *, CHAR16 *, UINTN);
+extern VOID U2ascii(CHAR16 *, CHAR8 *, UINTN);
+
+/* from config.c (more in config.h) */
+extern EFI_STATUS read_config(CHAR16 *, INTN retry);
+extern VOID print_config_options(VOID);
+extern INTN find_label(CHAR16 *, CHAR16 *, CHAR16 *, CHAR16 *);
+extern VOID print_label_list(VOID);
+extern INTN config_init(VOID);
+extern CHAR16 *get_message_filename(INTN which);
+extern CHAR16 *find_description(CHAR16 *label);
+extern VOID *get_next_description(VOID *prev, CHAR16 **label, CHAR16 **description);
+extern CHAR16 *get_config_file(VOID);
+
+/* from initrd.c */
+extern INTN load_initrd(CHAR16 *, memdesc_t *);
+
+/* from alternate.c */
+extern INTN alternate_kernel(CHAR16 *, INTN);
+
+/* from bootparams.c */
+extern VOID *create_boot_params (CHAR16 *, memdesc_t *, UINTN *);
+extern VOID free_boot_params(VOID *bp);
+
+/*
+ * architecture-specific API
+ */
+
+
+extern INTN sysdeps_create_boot_params(boot_params_t *, CHAR8 *, memdesc_t *, UINTN *);
+extern VOID sysdeps_free_boot_params(boot_params_t *);
+extern INTN sysdeps_init(EFI_HANDLE dev);
+extern INTN sysdeps_initrd_get_addr(kdesc_t *, memdesc_t *);
+extern INTN sysdeps_preloop_actions(EFI_HANDLE, CHAR16 **, INTN, INTN, EFI_HANDLE);
+extern CHAR16 *sysdeps_get_cmdline_opts(VOID);
+extern INTN sysdeps_getopt(INTN, INTN, CHAR16 *);
+extern VOID sysdeps_print_cmdline_opts(VOID);
+extern INTN sysdeps_register_options(VOID);
+
+#define CHAR_SLASH L'/'
+#define CHAR_BACKSLASH L'\\'
+
+#endif /* __ELILO_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ * GNU EFI 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.
+ *
+ * GNU EFI 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 GNU EFI; 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_DEBUG__
+#define __ELILO_DEBUG__
+
+#define ELILO_DEBUG 1
+
+#define ERR_PRT(a) do { Print(L"%a(line %d):", __FILE__, __LINE__); Print a; Print(L"\n"); } while (0);
+
+#ifdef ELILO_DEBUG
+#define DBG_PRT(a) do { \
+ if (elilo_opt.debug) { \
+ Print(L"%a(line %d):", __FILE__, __LINE__); \
+ Print a; \
+ Print(L"\n"); \
+} } while (0);
+#else
+#define DBG_PRT(a)
+#endif
+
+#endif /* __ELILO_DEBUG_H__ */
--- /dev/null
+#
+# Enable proxyDHCP operation.
+#
+dhcpd-operation normal;
+
+#
+# BootServer is turned on
+#
+bootserver-operation on;
+
+ddns-update-style ad-hoc;
+
+#
+# if this dhcpd server is not "master"
+#
+not authoritative;
+
+#-------------------------------------------------------------
+# For each of the 3 servers (builtin) define the DHCPD option
+# tags we are interested in.
+#-------------------------------------------------------------
+
+#
+# Define DHCPD request option tags
+#
+
+#
+# This option is used to determine the client boot-time binary runtime
+# environment.
+#
+option client-architecture code 93 =
+ unsigned integer 16;
+
+#
+# Now go to the DHCPD proxy option tags
+#
+option space proxy;
+
+option proxy.boot-prompt code 10 =
+ { unsigned integer 8, text };
+
+option proxy.boot-menu code 9 = array of
+ { unsigned integer 16, unsigned integer 8, text };
+
+option proxy.boot-servers code 8 = array of
+ { unsigned integer 16, unsigned integer 8, array of ip-address };
+
+option proxy.discovery-control code 6 = unsigned integer 8;
+
+#
+# Now go to the PXE Bootserver options
+#
+option space bs;
+
+option bs.boot-item code 71 =
+ { unsigned integer 16, unsigned integer 16 };
+
+#-------------------------------------------------------------
+# Actual configuration
+#-------------------------------------------------------------
+
+subnet 192.168.2.0 netmask 255.255.255.0 {
+#
+# In this section define regular DHCPD options
+#
+
+ #
+ # Here we show settings with fixed addresses, but dynamic
+ # allocation is possible as well
+ #
+ host test1 {
+ hardware ethernet 00:d0:b7:c7:fb:f8;
+ fixed-address 192.168.2.10;
+ }
+ host test2 {
+ hardware ethernet 00:d0:b7:aa:f0:e3;
+ fixed-address 192.168.2.11;
+ }
+
+ #
+ # Now we look at options for every possible type of requests
+ #
+
+
+ #
+ #
+ # If requets was received by the ProxyDHCPD
+ if proxy {
+
+ #
+ # Provide proxyDHCP information for Intel ia64
+ # architecture machines.
+ #
+ if option client-architecture = 00:02 {
+ #
+ # Notify of PXE aware server
+ #
+ option vendor-class-identifier "PXEClient";
+
+ #
+ # Force unicast
+ #
+ option proxy.discovery-control 3;
+
+ #
+ # Print a nice boot menu
+ #
+ # ServerTypes:
+ # 14 -> means Redhat install
+ # 13 -> means Redhat Boot
+ # 23 & 26 are length of string following.
+ #
+ option proxy.boot-menu
+ 14 23 "Remote Redhat/ia64 boot",
+ 13 26 "Remote Redhat/ia64 install";
+
+ #
+ # list of possible bootservers for a ServerType
+ #
+ # Currently not possible to define more than one type
+ #
+ option proxy.boot-servers
+ 14 1 192.168.2.32;
+
+ #
+ # A boot prompt
+ # 30 is timeout in seconds
+ #
+ option proxy.boot-prompt
+ 30 "Press <F8> or <M> for menu. Press <Esc> to local boot.";
+
+ #
+ #
+ vendor-option-space proxy;
+ }
+ } else if bootserver {
+
+ if option client-architecture = 00:02 {
+ #
+ # Now analyze bootserver request option tags
+ #
+
+
+ # ELILO Layering:
+ # Layer 0: bootloader binary (elilo.efi)
+ # Layer 1: elilo configuration file (elilo.conf)
+ # Layer 2: Linux/ia64 kernel
+
+ if substring(option bs.boot-item, 2, 2) = 00:00 {
+
+ filename "/tftpboot/elilo.efi";
+
+ #
+ # identify reply layer & server type
+ #
+ option bs.boot-item 14 0;
+
+ } else if substring(option bs.boot-item, 2, 2) = 00:01 {
+
+ filename "/tftpboot/elilo.conf";
+
+ #
+ # identify reply layer & server type
+ #
+ option bs.boot-item 14 1;
+
+ } else if substring(option bs.boot-item, 2, 3) = 00:02 {
+
+ filename "/tftpboot/vmlinux";
+
+ #
+ # identify reply layer & server type
+ #
+ option bs.boot-item 14 2;
+ }
+ #
+ #
+ vendor-option-space bs;
+
+ option vendor-class-identifier "PXEClient";
+ }
+ } else {
+ #
+ # notify of PXE aware DHCPD server
+ #
+ option vendor-class-identifier "PXEClient";
+ }
+}
--- /dev/null
+subnet 192.168.2.0 netmask 255.255.255.0 {
+
+ option domain-name "mydomain.com";
+ option subnet-mask 255.255.255.0;
+ option routers 15.4.88.1;
+
+ # here we use a fixed address
+ host test_machine {
+ hardware ethernet 00:D0:B7:C7:FB:F8;
+ fixed-address 192.168.2.10;
+ filename "/tftpboot/elilo.efi";
+ option host-name "test_machine";
+ }
+}
--- /dev/null
+#
+# force chooser to textmenu
+chooser=textmenu
+
+delay=20
+prompt
+
+#
+# the files containing the text (with attributes) to display
+#
+message=textmenu-message.msg
+
+#
+# files to load when the corresponding function key is pressed
+#
+f1=general.msg
+f2=params.msg
+
+image=debian/linux
+ label=debian
+ description="Install Debian GNU/Linux"
+ read-only
+ initrd=debian/root.bin
+ root=/dev/ram
+
+image=debian/linux
+ label=sda1
+ description="Boot Debian Linux, root on sda1"
+ read-only
+ root=/dev/sda1
+
+image=debian/linux.old
+ label=old
+ description="Boot Debian Linux, old kernel"
+ read-only
+ root=/dev/sda1
+
+image=debian/linux
+ label=shell
+ description="Execute a shell"
+ read-only
+ initrd=debian/root.bin
+ root=/dev/ram
+ append="init=/bin/sh"
+
--- /dev/null
+\f ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß
+\ f10\f
+ \ f7fÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ \ f74General Screen\ f7f ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\ f70¿\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 This is the general screen. You entered by pressing F1 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 Press any key to return to main screen ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 Help: [\ f71F1\ f70-General] [\ f71F2\ f70-Params] ³\ f10
+ \ f7fÀ\ f70ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\ f10
--- /dev/null
+\f ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß
+\ f10\f
+ \ f7fÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ \ f74Params Screen\ f7f ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\ f70¿\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 This is the params screen. You entered by pressing F2 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 Press any key to return to main screen ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 Help: [\ f71F1\ f70-General] [\ f71F2\ f70-Params] ³\ f10
+ \ f7fÀ\ f70ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\ f10
--- /dev/null
+\f ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß
+\ f10\f
+ \ f7fÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ \ f74Install and Recovery Disk\ f7f ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\ f70¿\ f10
+ \ f7f³\ f70 This CD demonstrates the elilo textmenu chooser. You can select an entry ³\ f10
+ \ f7f³\ f70 from the menu with the curosr keys, enter exptra parameters at the propmt, ³\ f10
+ \ f7f³\ f70 and press <return> to start the process. Help can be made available via ³\ f10
+ \ f7f³\ f70 the function keys. On a serial console, use Ctrl-F followed by the ³\ f10
+ \ f7f³\ f70 relevant function key number. ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 \ f7eBeware that this is an install disk, and misuse can result in the loss of \ f70³\ f10
+ \ f7f³\ f70 \ f7eany data currently on your disks. \ f70³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\ f7f¿\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f70\ 2 This is where the menu goes \ f7f³\ f70\1e ³\ f10
+ \ f7f³\ f70 ³\ f70\ f1e (active colour) \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f70 (inactive colour) \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f70 \ f1e\ 2\ f7f³\ f70\1f ³\ f10
+ \ f7f³\ f70 À\ f7fÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 Boot: \ f35\ 1 \ 1\ f70 ³\ f10
+ \ f7f³\ f70 ³\ f10
+ \ f7f³\ f70 Help: [\ f71F1\ f70-General] [\ f71F2\ f70-Params] ³\ f10
+ \ f7fÀ\ f70ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\ f10
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 "fileops.h"
+
+/*
+ * import filesystems
+ */
+#ifdef CONFIG_LOCALFS
+#include "glue_localfs.h"
+#endif
+#ifdef CONFIG_NETFS
+#include "glue_netfs.h"
+#endif
+
+#ifdef CONFIG_EXT2FS
+#include "glue_ext2fs.h"
+#endif
+
+/*
+ * table of device naming schemes.
+ * we will probe each one in sequential order and stop at first match.
+ */
+extern devname_scheme_t simple_devname_scheme;
+
+static devname_scheme_t *devname_scheme_tab[]={
+ &simple_devname_scheme,
+ NULL
+};
+
+
+/*
+ * Once we are able to create Boot Services drivers we won't need
+ * this hack and we'll be able to load the driver from the boot manager
+ * or EFI shell. So for now we explicitely invoke the probe routine
+ * of each driver that we know about
+ */
+
+typedef EFI_STATUS (fops_fixups_t)(EFI_HANDLE dev, device_t *d);
+
+/*
+ * List of filesystem we currently support
+ */
+
+
+static fileops_fs_t *fs_tab[]={
+#ifdef CONFIG_LOCALFS
+ &localfs_glue,
+#endif
+#ifdef CONFIG_EXT2FS
+ &ext2fs_glue,
+#endif
+#ifdef CONFIG_NETFS
+ &netfs_glue,
+#endif
+ NULL
+};
+
+static device_t *dev_tab;
+static UINTN ndev, ndev_boot;
+static device_t *boot_dev;
+
+typedef struct _fdesc_t {
+ struct _fdesc_t *next; /* pointer to next free (when in free list) */
+ fileops_t *fops; /* pointer to filesystem-specific glue interface */
+ UINTN fh; /* file descriptor from lower level protocol */
+} fdesc_t;
+
+#define FILEOPS_FD_MAX 16
+
+static fdesc_t fd_tab[FILEOPS_FD_MAX];
+static fdesc_t *free_fd;
+
+static devname_scheme_t *current_devname_scheme;
+
+#define FDESC_IDX(f) (fops_fd_t)(f-fd_tab)
+#define FDESC_INVALID_FD(fd) (fd >= FILEOPS_FD_MAX || fd_tab[(fd)].fops == NULL)
+#define FDESC_F(fd) (fd_tab+(fd))
+
+static fdesc_t *
+fd_alloc(VOID)
+{
+ fdesc_t *tmp = NULL;
+
+ if (free_fd == NULL) {
+ ERR_PRT((L"out of file descriptor"));
+ } else {
+ tmp = free_fd;
+ free_fd = free_fd->next;
+ }
+ return tmp;
+}
+
+static VOID
+fd_free(fdesc_t *fd)
+{
+ if (fd == NULL) {
+ ERR_PRT((L"invalid fd"));
+ }
+ fd->fops = NULL; /* mark as invalid */
+ fd->next = free_fd;
+ free_fd = fd;
+}
+
+static fileops_t *
+glue_filesystem(EFI_GUID *proto, EFI_HANDLE dev, fops_fs_glue_t glue)
+{
+ fileops_t *fops;
+ VOID *intf = NULL;
+ EFI_STATUS status;
+
+ status = BS->HandleProtocol(dev, proto, &intf);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"unable to locate %g: should not happen", proto));
+ return NULL; /* should not happen */
+ }
+ fops = (fileops_t *)alloc(sizeof(*fops), EfiLoaderData);
+ if (fops == NULL) {
+ ERR_PRT((L"failed to allocate fileops"));
+ return NULL; /* XXX uninstall protocol */
+ }
+ Memset(fops, 0, sizeof(*fops));
+
+ fops->dev = dev;
+
+ /* initialize private interface now */
+ glue(fops, intf);
+
+ return fops;
+}
+
+INTN
+fops_split_path(CHAR16 *path, CHAR16 *dev)
+{
+ CHAR16 *p, *d = dev;
+ UINTN len = FILEOPS_DEVNAME_MAXLEN;
+# define CHAR_COLON L':'
+
+ p = StrChr(path, CHAR_COLON);
+ if (p == NULL) {
+ *dev = CHAR_NULL;
+ return 0;
+ }
+ /* copy device part of the name */
+ for (d = dev ; path != p ;) {
+ if (--len == 0) return -1; /* too long */
+ *d++ = *path++;
+ }
+ *d = CHAR_NULL;
+ return 0;
+}
+
+static device_t *
+find_device_byname(CHAR16 *dev)
+{
+ UINTN i;
+ for(i=0; i < ndev; i++) {
+ if (!StrCmp(dev, dev_tab[i].name)) return dev_tab+i;
+ }
+ return NULL;
+}
+
+
+/*
+ * This function is used to walk through the device list and get names.
+ * arguments:
+ * - pidx = opaque cookie returned by previous call (must be zero for initial call)
+ * - type is the type of filesystem to look for, e.g., vfat or ext2fs. NULL means ANY
+ * - maxlen is the size in bytes of the returned string buffer
+ * - idx is the opaque cookie returned (can be reused by next call)
+ * - name a string buffer to hold the name of the next matching device
+ * - dev will receive the EFI_HANDLE corresponding to the device if not NULL
+ *
+ * return:
+ * - EFI_INVALID_PARAMETER: when NULL values are passed for required arguments.
+ * - EFI_NOT_FOUND: when reached the end of the list of invalid cookie
+ * - EFI_BUFFER_TOO_SMALL is device name does not fit into string buffer
+ * - EFI_SUCCESS otherwise
+ */
+EFI_STATUS
+fops_get_next_device(UINTN pidx, CHAR16 *type, UINTN maxlen, UINTN *idx, CHAR16 *name, EFI_HANDLE *dev)
+{
+ UINTN i;
+
+ if (name == NULL || idx == NULL) return EFI_INVALID_PARAMETER;
+
+ for(i=pidx; i < ndev; i++) {
+ if (type == NULL || !StrCmp(dev_tab[i].fops->name, type)) goto found;
+ }
+ return EFI_NOT_FOUND;
+found:
+ if (StrLen(dev_tab[i].name) >= maxlen) {
+ *idx = pidx; /* will restart from same place! */
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ StrCpy(name, dev_tab[i].name);
+ *idx = i+1;
+ if (dev) *dev = dev_tab[i].dev;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+fops_get_device_handle(CHAR16 *name, EFI_HANDLE *dev)
+{
+ UINTN i;
+
+ if (name == NULL || dev == NULL) return EFI_INVALID_PARAMETER;
+
+ for(i=0; i < ndev; i++) {
+ if (!StrCmp(dev_tab[i].name, name)) goto found;
+ }
+ return EFI_NOT_FOUND;
+found:
+ *dev = dev_tab[i].dev;
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+fops_open(CHAR16 *fullname, fops_fd_t *fd)
+{
+ fdesc_t *f;
+ EFI_STATUS status;
+ fileops_t *fops;
+ device_t *dev;
+ CHAR16 dev_name[FILEOPS_DEVNAME_MAXLEN];
+ CHAR16 *name;
+
+
+ if (fd == NULL || fullname == NULL || *fullname == CHAR_NULL || fops_split_path(fullname, dev_name) == -1)
+ return EFI_INVALID_PARAMETER;
+
+ DBG_PRT((L"fops_open(%s), dev:%s:", fullname ? fullname : L"(NULL)", dev_name));
+
+ name = fullname;
+ if (dev_name[0] == CHAR_NULL) {
+ if (boot_dev == NULL) return EFI_INVALID_PARAMETER;
+ fops = boot_dev->fops;
+ } else {
+ if ((dev=find_device_byname(dev_name)) == NULL) return EFI_INVALID_PARAMETER;
+
+ name += StrLen(dev_name)+1;
+
+ fops = dev->fops;
+ }
+
+ if (fops == NULL) return EFI_INVALID_PARAMETER;
+
+ if ((f=fd_alloc()) == NULL) return EFI_OUT_OF_RESOURCES;
+
+ DBG_PRT((L"dev:%s: fullname:%s: name:%s: f=%d", dev_name, fullname, name, f - fd_tab));
+
+ status = fops->open(fops->intf, name, &f->fh);
+ if (EFI_ERROR(status)) goto error;
+
+ f->fops = fops;
+
+ *fd = FDESC_IDX(f);
+
+ return EFI_SUCCESS;
+error:
+ fd_free(f);
+ return status;
+}
+
+EFI_STATUS
+fops_read(fops_fd_t fd, VOID *buf, UINTN *size)
+{
+ fdesc_t *f;
+
+ if (buf == NULL || FDESC_INVALID_FD(fd) || size == NULL) return EFI_INVALID_PARAMETER;
+
+ f = FDESC_F(fd);
+
+ return f->fops->read(f->fops->intf, f->fh, buf, size);
+}
+
+EFI_STATUS
+fops_close(fops_fd_t fd)
+{
+ fdesc_t *f;
+ EFI_STATUS status;
+
+ if (FDESC_INVALID_FD(fd)) return EFI_INVALID_PARAMETER;
+
+ f = FDESC_F(fd);
+
+ status = f->fops->close(f->fops->intf, f->fh);
+
+ fd_free(f);
+
+ return status;
+}
+
+EFI_STATUS
+fops_infosize(fops_fd_t fd, UINT64 *size)
+{
+ fdesc_t *f;
+
+ if (FDESC_INVALID_FD(fd) || size == NULL) return EFI_INVALID_PARAMETER;
+
+ f = FDESC_F(fd);
+
+ return f->fops->infosize(f->fops->intf, f->fh, size);
+}
+
+EFI_STATUS
+fops_seek(fops_fd_t fd, UINT64 newpos)
+{
+ fdesc_t *f;
+
+ if (FDESC_INVALID_FD(fd)) return EFI_INVALID_PARAMETER;
+
+ f = FDESC_F(fd);
+
+ return f->fops->seek(f->fops->intf, f->fh, newpos);
+}
+
+EFI_STATUS
+fops_setdefaults(CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
+{
+#define FILEOPS_DEFAULT_KERNEL L"vmlinux"
+#define FILEOPS_DEFAULT_CONFIG L"elilo.conf"
+
+ if (config == NULL || kname == NULL) return EFI_INVALID_PARAMETER;
+
+ if (boot_dev == NULL || boot_dev->fops == NULL) {
+ if (boot_dev == NULL)
+ Print(L"Warning boot device not recognized\n");
+ else
+ Print(L"Unknown filesystem on boot device\n");
+
+ Print(L"Using builtin defaults for kernel and config file\n");
+
+ StrnCpy(config, FILEOPS_DEFAULT_CONFIG, maxlen-1);
+ StrnCpy(kname, FILEOPS_DEFAULT_KERNEL, maxlen-1);
+
+ return EFI_UNSUPPORTED;
+ }
+
+ return boot_dev->fops->setdefaults(boot_dev->fops->intf, config, kname, maxlen, devpath);
+}
+
+EFI_STATUS
+fops_getdefault_path(CHAR16 *path, UINTN maxlen)
+{
+ if (path == NULL || maxlen == 0) return EFI_INVALID_PARAMETER;
+
+ /*
+ * if underlying filesystem implements the call, then we call
+ * otherwise we return an empty string
+ */
+ if (boot_dev->fops->getdefault_path)
+ return boot_dev->fops->getdefault_path(path, maxlen);
+
+ path[0] = CHAR_NULL;
+
+ return EFI_SUCCESS;
+}
+
+CHAR16 *
+fops_bootdev_name(VOID)
+{
+ return boot_dev ? boot_dev->name : L"not supported";
+}
+
+static INTN
+add_dev_tab(EFI_GUID *proto, EFI_HANDLE boot_handle, UINTN size, fops_fs_glue_t glue)
+{
+ EFI_STATUS status;
+ EFI_HANDLE *tab;
+ UINTN i;
+ static UINTN idx;
+
+ if (size == 0) return 0;
+
+ tab = (EFI_HANDLE *)alloc(size, EfiLoaderData);
+ if (tab == NULL) {
+ ERR_PRT((L"failed to allocate handle table"));
+ return -1;
+ }
+
+ Memset(tab, 0, size);
+
+ /*
+ * get the actual device handles now
+ */
+ status = BS->LocateHandle(ByProtocol, proto, NULL, &size, tab);
+ if (status != EFI_SUCCESS) {
+ ERR_PRT((L"failed to get handles for proto %g size=%d: %r", proto, size, status));
+ free(tab);
+ return -1;
+ }
+ size /= sizeof(EFI_HANDLE);
+
+ for(i=0; i < size; i++) {
+ dev_tab[idx].dev = tab[i];
+ dev_tab[idx].fops = glue_filesystem(proto, tab[i], glue);
+
+ if (tab[i] == boot_handle) boot_dev = dev_tab+idx;
+
+ /* count the ones we recognized */
+ if (dev_tab[idx].fops) ndev_boot++;
+
+ /* assign a generic name for now */
+ dev_tab[idx].name[0] = L'd';
+ dev_tab[idx].name[1] = L'e';
+ dev_tab[idx].name[2] = L'v';
+ dev_tab[idx].name[3] = L'0' + idx/100;
+ dev_tab[idx].name[4] = L'0' + (idx%100)/10;
+ dev_tab[idx].name[5] = L'0' + (idx%100) % 10;
+ dev_tab[idx].name[6] = CHAR_NULL;
+
+#ifdef ELILO_DEBUG
+ if (elilo_opt.debug) {
+ EFI_DEVICE_PATH *dp;
+ CHAR16 *str, *str2;
+
+ str = NULL;
+ dp = DevicePathFromHandle(dev_tab[idx].dev);
+ if (dp) str = DevicePathToStr(dp);
+
+ str2 = str == NULL ? L"Unknown" : str;
+
+ DBG_PRT((L"%s : %-8s : %s\n", dev_tab[idx].name,
+ (dev_tab[idx].fops ? dev_tab[idx].fops->name: L"N/A"), str2));
+
+ if (str) FreePool(str);
+ }
+#endif
+
+ idx++;
+ }
+ free(tab);
+
+ /* remember actual number of bootable devices */
+ ndev = idx;
+
+ return 0;
+}
+
+static INTN
+probe_devname_schemes(device_t *dev_tab, INTN ndev)
+{
+ devname_scheme_t **p;
+
+ for (p = devname_scheme_tab; *p ; p++) {
+ if ((*p)->install_scheme(dev_tab, ndev) == 0) goto found;
+ }
+ ERR_PRT((L"No devname schemes worked, using builtin\n"));
+ return -1;
+found:
+ VERB_PRT(3, Print(L"devname scheme: %s\n", (*p)->name));
+ current_devname_scheme = *p;
+ return 0;
+}
+
+static INTN
+find_filesystems(EFI_HANDLE boot_handle)
+{
+ UINTN size, total = 0;
+ fileops_fs_t **fs;
+
+ /*
+ * 1st pass, figure out how big a table we need
+ */
+ for(fs = fs_tab; *fs; fs++) {
+ size = 0;
+ BS->LocateHandle(ByProtocol, &(*fs)->proto, NULL, &size, NULL);
+ total += size;
+ }
+ if (total == 0) {
+ ERR_PRT((L"No useable filesystem found"));
+ return -1;
+ }
+ total /= sizeof(EFI_HANDLE);
+ DBG_PRT((L"found %d filesystems", total));
+
+ dev_tab = (device_t *)alloc(total*sizeof(device_t), EfiLoaderData);
+ if (dev_tab == NULL) {
+ ERR_PRT((L"failed to allocate handle table"));
+ return -1;
+ }
+
+ Memset(dev_tab, 0, total*sizeof(device_t));
+
+ /*
+ * do a 2nd pass to initialize the table now
+ */
+ for(fs = fs_tab; *fs; fs++) {
+ size = 0;
+
+ BS->LocateHandle(ByProtocol, &(*fs)->proto, NULL, &size, NULL);
+ if (size == 0) continue;
+
+ add_dev_tab(&(*fs)->proto, boot_handle, size, (*fs)->glue);
+ }
+ probe_devname_schemes(dev_tab, ndev);
+
+ return 0;
+}
+
+static INTN
+fileops_init(VOID)
+{
+ UINTN i;
+
+ for (i=0; i < FILEOPS_FD_MAX-1; i++) {
+ fd_tab[i].next = &fd_tab[i+1];
+ }
+ fd_tab[i].next = NULL;
+ free_fd = fd_tab;
+
+ return 0;
+}
+
+/*
+ * both functions will go away once we go with boottime drivers
+ */
+static INTN
+install_filesystems(VOID)
+{
+ fileops_fs_t **fs;
+
+ for(fs = fs_tab; *fs; fs++) (*fs)->install();
+
+ return 0;
+}
+
+static INTN
+uninstall_filesystems(VOID)
+{
+ fileops_fs_t **fs;
+
+ for(fs = fs_tab; *fs; fs++) (*fs)->uninstall();
+
+ return 0;
+}
+
+INTN
+init_devices(EFI_HANDLE boot_handle)
+{
+ /* simulate driver installation */
+ install_filesystems();
+
+ /*
+ * now let's do our part
+ */
+ fileops_init();
+
+ return find_filesystems(boot_handle);
+}
+
+INTN
+close_devices(VOID)
+{
+ INTN i;
+
+ for(i=0; i < FILEOPS_FD_MAX; i++) {
+ fops_close(i);
+ }
+ free(dev_tab);
+
+ /*
+ * simulate driver removal
+ */
+ uninstall_filesystems();
+
+ return 0;
+}
+
+VOID
+print_devices(VOID)
+{
+ UINTN idx;
+ EFI_DEVICE_PATH *dp;
+ CHAR16 *str, *str2;
+
+ for(idx=0; idx< ndev; idx++) {
+ str = NULL;
+
+ dp = DevicePathFromHandle(dev_tab[idx].dev);
+ if (dp) str = DevicePathToStr(dp);
+
+ str2 = str == NULL ? L"Unknown" : str;
+
+ Print(L"%8s : %-6s : %s\n", dev_tab[idx].name,
+ (dev_tab[idx].fops ? dev_tab[idx].fops->name: L"N/A"), str2);
+
+ if (str) FreePool(str);
+ }
+ Print(L"%d devices available for booting\n", ndev_boot);
+
+ if (boot_dev == NULL) {
+ Print(L"boot device not detected\n");
+ } else {
+ Print(L"boot device %s: %s\n", boot_dev->name,
+ (boot_dev->fops ? boot_dev->fops->name : L"No file access"));
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ * GNU EFI 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.
+ *
+ * GNU EFI 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 GNU EFI; 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 __FILEOPS_H__
+#define __FILEOPS_H__
+
+#define FILEOPS_NAME_MAXLEN 32 /* length of filesystem name */
+
+/*
+ * upper-level interface used by the bootloader
+ */
+typedef UINTN fops_fd_t;
+
+extern EFI_STATUS fops_open(CHAR16 *name, fops_fd_t *fd);
+extern EFI_STATUS fops_read(fops_fd_t fd,VOID *buf, UINTN *size);
+extern EFI_STATUS fops_close(fops_fd_t fd);
+extern EFI_STATUS fops_infosize(fops_fd_t fd, UINT64 *size);
+extern EFI_STATUS fops_seek(fops_fd_t fd, UINT64 newpos);
+extern EFI_STATUS fops_setdefaults(CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath);
+extern EFI_STATUS fops_getdefault_path(CHAR16 *path, UINTN maxlen);
+extern CHAR16 *fops_bootdev_name(VOID);
+
+
+/*
+ * fileops interface used by underlying filesystems layer
+ */
+typedef EFI_STATUS (*fops_open_t)(VOID *intf, CHAR16 *name, fops_fd_t *fd);
+typedef EFI_STATUS (*fops_read_t)(VOID *intf, fops_fd_t fd, VOID *buf, UINTN *size);
+typedef EFI_STATUS (*fops_close_t)(VOID *intf, fops_fd_t fd);
+typedef EFI_STATUS (*fops_infosize_t)(VOID *intf, fops_fd_t fd, UINT64 *size);
+typedef EFI_STATUS (*fops_seek_t)(VOID *intf, fops_fd_t fd, UINT64 newpos);
+typedef EFI_STATUS (*fops_setdefaults_t)(VOID *intf, CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath);
+typedef EFI_STATUS (*fops_getdefault_path_t)(CHAR16 *path, UINTN maxlen);
+
+typedef struct {
+ VOID *intf; /* pointer to underlying interface */
+
+ fops_open_t open;
+ fops_read_t read;
+ fops_close_t close;
+ fops_infosize_t infosize;
+ fops_seek_t seek;
+ fops_setdefaults_t setdefaults;
+ fops_getdefault_path_t getdefault_path;
+
+ EFI_HANDLE dev; /* handle on device on which proto is installed */
+ CHAR16 name[FILEOPS_NAME_MAXLEN];
+} fileops_t;
+
+/*
+ * used to register a new filsystem
+ */
+typedef INTN (*fops_fs_glue_t)(fileops_t *this, VOID *intf);
+typedef EFI_STATUS (*fops_fs_install_t)(VOID);
+typedef EFI_STATUS (*fops_fs_uninstall_t)(VOID);
+
+typedef struct {
+ EFI_GUID proto; /* GUID of filesystem */
+ fops_fs_glue_t glue; /* glue routine */
+ fops_fs_install_t install; /* to go away with real EFI drivers */
+ fops_fs_uninstall_t uninstall; /* to go away with real EFI drivers */
+} fileops_fs_t;
+
+
+/*
+ * device description
+ */
+#define FILEOPS_DEVNAME_MAXLEN 16
+
+typedef struct {
+ EFI_HANDLE dev;
+ fileops_t *fops;
+ CHAR16 name[FILEOPS_DEVNAME_MAXLEN];
+} device_t;
+
+extern INTN init_devices(EFI_HANDLE boot_handle);
+extern INTN close_devices(VOID);
+extern VOID print_devices(VOID);
+extern EFI_STATUS fops_get_next_device(UINTN pidx, CHAR16 *type, UINTN maxlen, UINTN *idx, CHAR16 *name, EFI_HANDLE *dev);
+extern INTN fops_split_path(CHAR16 *path, CHAR16 *dev);
+extern EFI_STATUS fops_get_device_handle(CHAR16 *name, EFI_HANDLE *dev);
+
+/*
+ * device naming schemes
+ *
+ * Interface:
+ * the scheme() function arguments are:
+ * - the list of detected bootable device
+ * - the number of entries in that table as argument
+ *
+ * There is no expected return value. If the scheme() cannot perform
+ * its tasks, then IT MUST NOT OVERWRITE the generic naming scheme (devXXX) that
+ * is ALWAYS installed by default. Partial modifications are possible, although
+ * not recommended.
+ */
+typedef struct {
+ CHAR16 *name;
+ INTN (*install_scheme)(device_t *tab, UINTN ndev);
+} devname_scheme_t;
+
+#endif /* __FILEOPS_H__ */
--- /dev/null
+#
+# Copyright (C) 2001-2003 Hewlett-Packard Co.
+# Contributed by Stephane Eranian <eranian@hpl.hp.com>
+#
+# 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 ../Make.defaults
+include ../Make.rules
+
+TOPDIR=$(CDIR)/..
+
+FILES=
+ifeq ($(CONFIG_localfs),y)
+FILES += localfs.o
+endif
+
+#
+# Ext2 is now disabled by default. See top level Makefile
+# for details
+#
+ifeq ($(CONFIG_ext2fs),y)
+FILES += ext2fs.o
+endif
+
+ifeq ($(CONFIG_netfs),y)
+FILES += netfs.o
+endif
+
+
+TARGET=fs.o
+
+all: $(TARGET)
+
+#
+# XXX: does not trigger recompile when changing filesystem selection
+# without doing make clean.
+#
+$(TARGET): check-filesystems $(TOPDIR)/Make.defaults $(FILES)
+ $(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
+
--- /dev/null
+/*
+ * linux/include/linux/ext2_fs.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/include/linux/minix_fs.h
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#ifndef _LINUX_EXT2_FS_H
+#define _LINUX_EXT2_FS_H
+
+/*
+ * The second extended filesystem constants/structures
+ */
+
+/*
+ * Define EXT2FS_DEBUG to produce debug messages
+ */
+#undef EXT2FS_DEBUG
+
+/*
+ * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
+ */
+#define EXT2_PREALLOCATE
+#define EXT2_DEFAULT_PREALLOC_BLOCKS 8
+
+/*
+ * The second extended file system version
+ */
+#define EXT2FS_DATE "95/08/09"
+#define EXT2FS_VERSION "0.5b"
+
+/*
+ * Debug code
+ */
+#ifdef EXT2FS_DEBUG
+# define ext2_debug(f, a...) { \
+ printk ("EXT2-fs DEBUG (%s, %d): %s:", \
+ __FILE__, __LINE__, __FUNCTION__); \
+ printk (f, ## a); \
+ }
+#else
+# define ext2_debug(f, a...) /**/
+#endif
+
+/*
+ * Special inodes numbers
+ */
+#define EXT2_BAD_INO 1 /* Bad blocks inode */
+#define EXT2_ROOT_INO 2 /* Root inode */
+#define EXT2_ACL_IDX_INO 3 /* ACL inode */
+#define EXT2_ACL_DATA_INO 4 /* ACL inode */
+#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
+#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
+
+/* First non-reserved inode for old ext2 filesystems */
+#define EXT2_GOOD_OLD_FIRST_INO 11
+
+/*
+ * The second extended file system magic number
+ */
+#define EXT2_SUPER_MAGIC 0xEF53
+
+/*
+ * Maximal count of links to a file
+ */
+#define EXT2_LINK_MAX 32000
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT2_MIN_BLOCK_SIZE 1024
+#define EXT2_MAX_BLOCK_SIZE 4096
+#define EXT2_MIN_BLOCK_LOG_SIZE 10
+#ifdef __KERNEL__
+# define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize)
+#else
+# define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+#endif
+#define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))
+#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
+#ifdef __KERNEL__
+# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
+#else
+# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
+#endif
+#ifdef __KERNEL__
+#define EXT2_ADDR_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_addr_per_block_bits)
+#define EXT2_INODE_SIZE(s) ((s)->u.ext2_sb.s_inode_size)
+#define EXT2_FIRST_INO(s) ((s)->u.ext2_sb.s_first_ino)
+#else
+#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+ EXT2_GOOD_OLD_INODE_SIZE : \
+ (s)->s_inode_size)
+#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+ EXT2_GOOD_OLD_FIRST_INO : \
+ (s)->s_first_ino)
+#endif
+
+/*
+ * Macro-instructions used to manage fragments
+ */
+#define EXT2_MIN_FRAG_SIZE 1024
+#define EXT2_MAX_FRAG_SIZE 4096
+#define EXT2_MIN_FRAG_LOG_SIZE 10
+#ifdef __KERNEL__
+# define EXT2_FRAG_SIZE(s) ((s)->u.ext2_sb.s_frag_size)
+# define EXT2_FRAGS_PER_BLOCK(s) ((s)->u.ext2_sb.s_frags_per_block)
+#else
+# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
+# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
+#endif
+
+/*
+ * ACL structures
+ */
+struct ext2_acl_header /* Header of Access Control Lists */
+{
+ __u32 aclh_size;
+ __u32 aclh_file_count;
+ __u32 aclh_acle_count;
+ __u32 aclh_first_acle;
+};
+
+struct ext2_acl_entry /* Access Control List Entry */
+{
+ __u32 acle_size;
+ __u16 acle_perms; /* Access permissions */
+ __u16 acle_type; /* Type of entry */
+ __u16 acle_tag; /* User or group identity */
+ __u16 acle_pad1;
+ __u32 acle_next; /* Pointer on next entry for the */
+ /* same inode or on next free entry */
+};
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext2_group_desc
+{
+ __u32 bg_block_bitmap; /* Blocks bitmap block */
+ __u32 bg_inode_bitmap; /* Inodes bitmap block */
+ __u32 bg_inode_table; /* Inodes table block */
+ __u16 bg_free_blocks_count; /* Free blocks count */
+ __u16 bg_free_inodes_count; /* Free inodes count */
+ __u16 bg_used_dirs_count; /* Directories count */
+ __u16 bg_pad;
+ __u32 bg_reserved[3];
+};
+
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+#ifdef __KERNEL__
+# define EXT2_BLOCKS_PER_GROUP(s) ((s)->u.ext2_sb.s_blocks_per_group)
+# define EXT2_DESC_PER_BLOCK(s) ((s)->u.ext2_sb.s_desc_per_block)
+# define EXT2_INODES_PER_GROUP(s) ((s)->u.ext2_sb.s_inodes_per_group)
+# define EXT2_DESC_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_desc_per_block_bits)
+#else
+# define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group)
+# define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
+# define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group)
+#endif
+
+/*
+ * Constants relative to the data blocks
+ */
+#define EXT2_NDIR_BLOCKS 12
+#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
+#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
+#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
+
+/*
+ * Inode flags
+ */
+#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */
+#define EXT2_UNRM_FL 0x00000002 /* Undelete */
+#define EXT2_COMPR_FL 0x00000004 /* Compress file */
+#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */
+#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
+#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
+#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
+#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define EXT2_DIRTY_FL 0x00000100
+#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
+#define EXT2_NOCOMP_FL 0x00000400 /* Don't compress */
+#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
+/* End compression flags --- maybe not all used */
+#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
+#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
+
+#define EXT2_FL_USER_VISIBLE 0x00001FFF /* User visible flags */
+#define EXT2_FL_USER_MODIFIABLE 0x000000FF /* User modifiable flags */
+
+/*
+ * ioctl commands
+ */
+#define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
+#define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
+#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
+#define EXT2_IOC_SETVERSION _IOW('v', 2, long)
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext2_inode {
+ __u16 i_mode; /* File mode */
+ __u16 i_uid; /* Low 16 bits of Owner Uid */
+ __u32 i_size; /* Size in bytes */
+ __u32 i_atime; /* Access time */
+ __u32 i_ctime; /* Creation time */
+ __u32 i_mtime; /* Modification time */
+ __u32 i_dtime; /* Deletion Time */
+ __u16 i_gid; /* Low 16 bits of Group Id */
+ __u16 i_links_count; /* Links count */
+ __u32 i_blocks; /* Blocks count */
+ __u32 i_flags; /* File flags */
+ union {
+ struct {
+ __u32 l_i_reserved1;
+ } linux1;
+ struct {
+ __u32 h_i_translator;
+ } hurd1;
+ struct {
+ __u32 m_i_reserved1;
+ } masix1;
+ } osd1; /* OS dependent 1 */
+ __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+ __u32 i_generation; /* File version (for NFS) */
+ __u32 i_file_acl; /* File ACL */
+ __u32 i_dir_acl; /* Directory ACL */
+ __u32 i_faddr; /* Fragment address */
+ union {
+ struct {
+ __u8 l_i_frag; /* Fragment number */
+ __u8 l_i_fsize; /* Fragment size */
+ __u16 i_pad1;
+ __u16 l_i_uid_high; /* these 2 fields */
+ __u16 l_i_gid_high; /* were reserved2[0] */
+ __u32 l_i_reserved2;
+ } linux2;
+ struct {
+ __u8 h_i_frag; /* Fragment number */
+ __u8 h_i_fsize; /* Fragment size */
+ __u16 h_i_mode_high;
+ __u16 h_i_uid_high;
+ __u16 h_i_gid_high;
+ __u32 h_i_author;
+ } hurd2;
+ struct {
+ __u8 m_i_frag; /* Fragment number */
+ __u8 m_i_fsize; /* Fragment size */
+ __u16 m_pad1;
+ __u32 m_i_reserved2[2];
+ } masix2;
+ } osd2; /* OS dependent 2 */
+};
+
+#define i_size_high i_dir_acl
+
+#if defined(__KERNEL__) || defined(__linux__)
+#define i_reserved1 osd1.linux1.l_i_reserved1
+#define i_frag osd2.linux2.l_i_frag
+#define i_fsize osd2.linux2.l_i_fsize
+#define i_uid_low i_uid
+#define i_gid_low i_gid
+#define i_uid_high osd2.linux2.l_i_uid_high
+#define i_gid_high osd2.linux2.l_i_gid_high
+#define i_reserved2 osd2.linux2.l_i_reserved2
+#endif
+
+#ifdef __hurd__
+#define i_translator osd1.hurd1.h_i_translator
+#define i_frag osd2.hurd2.h_i_frag;
+#define i_fsize osd2.hurd2.h_i_fsize;
+#define i_uid_high osd2.hurd2.h_i_uid_high
+#define i_gid_high osd2.hurd2.h_i_gid_high
+#define i_author osd2.hurd2.h_i_author
+#endif
+
+#ifdef __masix__
+#define i_reserved1 osd1.masix1.m_i_reserved1
+#define i_frag osd2.masix2.m_i_frag
+#define i_fsize osd2.masix2.m_i_fsize
+#define i_reserved2 osd2.masix2.m_i_reserved2
+#endif
+
+/*
+ * File system states
+ */
+#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */
+#define EXT2_ERROR_FS 0x0002 /* Errors detected */
+
+/*
+ * Mount flags
+ */
+#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */
+#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
+#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
+#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
+#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
+#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
+#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
+#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */
+
+#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
+#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
+#define test_opt(sb, opt) ((sb)->u.ext2_sb.s_mount_opt & \
+ EXT2_MOUNT_##opt)
+/*
+ * Maximal mount counts between two filesystem checks
+ */
+#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
+#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */
+
+/*
+ * Behaviour when detecting errors
+ */
+#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
+#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
+#define EXT2_ERRORS_PANIC 3 /* Panic */
+#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
+
+/*
+ * Structure of the super block
+ */
+struct ext2_super_block {
+ __u32 s_inodes_count; /* Inodes count */
+ __u32 s_blocks_count; /* Blocks count */
+ __u32 s_r_blocks_count; /* Reserved blocks count */
+ __u32 s_free_blocks_count; /* Free blocks count */
+ __u32 s_free_inodes_count; /* Free inodes count */
+ __u32 s_first_data_block; /* First Data Block */
+ __u32 s_log_block_size; /* Block size */
+ __s32 s_log_frag_size; /* Fragment size */
+ __u32 s_blocks_per_group; /* # Blocks per group */
+ __u32 s_frags_per_group; /* # Fragments per group */
+ __u32 s_inodes_per_group; /* # Inodes per group */
+ __u32 s_mtime; /* Mount time */
+ __u32 s_wtime; /* Write time */
+ __u16 s_mnt_count; /* Mount count */
+ __s16 s_max_mnt_count; /* Maximal mount count */
+ __u16 s_magic; /* Magic signature */
+ __u16 s_state; /* File system state */
+ __u16 s_errors; /* Behaviour when detecting errors */
+ __u16 s_minor_rev_level; /* minor revision level */
+ __u32 s_lastcheck; /* time of last check */
+ __u32 s_checkinterval; /* max. time between checks */
+ __u32 s_creator_os; /* OS */
+ __u32 s_rev_level; /* Revision level */
+ __u16 s_def_resuid; /* Default uid for reserved blocks */
+ __u16 s_def_resgid; /* Default gid for reserved blocks */
+ /*
+ * These fields are for EXT2_DYNAMIC_REV superblocks only.
+ *
+ * Note: the difference between the compatible feature set and
+ * the incompatible feature set is that if there is a bit set
+ * in the incompatible feature set that the kernel doesn't
+ * know about, it should refuse to mount the filesystem.
+ *
+ * e2fsck's requirements are more strict; if it doesn't know
+ * about a feature in either the compatible or incompatible
+ * feature set, it must abort and not try to meddle with
+ * things it doesn't understand...
+ */
+ __u32 s_first_ino; /* First non-reserved inode */
+ __u16 s_inode_size; /* size of inode structure */
+ __u16 s_block_group_nr; /* block group # of this superblock */
+ __u32 s_feature_compat; /* compatible feature set */
+ __u32 s_feature_incompat; /* incompatible feature set */
+ __u32 s_feature_ro_compat; /* readonly-compatible feature set */
+ __u8 s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ __u32 s_algorithm_usage_bitmap; /* For compression */
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT2_COMPAT_PREALLOC flag is on.
+ */
+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
+ __u16 s_padding1;
+ __u32 s_reserved[204]; /* Padding to the end of the block */
+};
+
+#ifdef __KERNEL__
+#define EXT2_SB(sb) (&((sb)->u.ext2_sb))
+#else
+/* Assume that user mode programs are passing in an ext2fs superblock, not
+ * a kernel struct super_block. This will allow us to call the feature-test
+ * macros from user land. */
+#define EXT2_SB(sb) (sb)
+#endif
+
+/*
+ * Codes for operating systems
+ */
+#define EXT2_OS_LINUX 0
+#define EXT2_OS_HURD 1
+#define EXT2_OS_MASIX 2
+#define EXT2_OS_FREEBSD 3
+#define EXT2_OS_LITES 4
+
+/*
+ * Revision levels
+ */
+#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
+#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
+
+#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV
+#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV
+
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Feature set definitions
+ */
+
+#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
+#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
+#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
+#define EXT2_SET_COMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
+#define EXT2_SET_RO_COMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
+#define EXT2_SET_INCOMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
+#define EXT2_CLEAR_COMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
+#define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
+#define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
+
+#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
+
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+
+#define EXT2_FEATURE_COMPAT_SUPP 0
+#define EXT2_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_FILETYPE
+#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+
+/*
+ * Default values for user and/or group using reserved blocks
+ */
+#define EXT2_DEF_RESUID 0
+#define EXT2_DEF_RESGID 0
+
+/*
+ * Structure of a directory entry
+ */
+#define EXT2_NAME_LEN 255
+
+struct ext2_dir_entry {
+ __u32 inode; /* Inode number */
+ __u16 rec_len; /* Directory entry length */
+ __u16 name_len; /* Name length */
+ char name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*
+ * The new version of the directory entry. Since EXT2 structures are
+ * stored in intel byte order, and the name_len field could never be
+ * bigger than 255 chars, it's safe to reclaim the extra byte for the
+ * file_type field.
+ */
+struct ext2_dir_entry_2 {
+ __u32 inode; /* Inode number */
+ __u16 rec_len; /* Directory entry length */
+ __u8 name_len; /* Name length */
+ __u8 file_type;
+ char name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*
+ * Ext2 directory file types. Only the low 3 bits are used. The
+ * other bits are reserved for now.
+ */
+#define EXT2_FT_UNKNOWN 0
+#define EXT2_FT_REG_FILE 1
+#define EXT2_FT_DIR 2
+#define EXT2_FT_CHRDEV 3
+#define EXT2_FT_BLKDEV 4
+#define EXT2_FT_FIFO 5
+#define EXT2_FT_SOCK 6
+#define EXT2_FT_SYMLINK 7
+
+#define EXT2_FT_MAX 8
+
+/*
+ * EXT2_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 4
+ */
+#define EXT2_DIR_PAD 4
+#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
+#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
+ ~EXT2_DIR_ROUND)
+
+#ifdef __KERNEL__
+/*
+ * Function prototypes
+ */
+
+/*
+ * Ok, these declarations are also in <linux/kernel.h> but none of the
+ * ext2 source programs needs to include it so they are duplicated here.
+ */
+# define NORET_TYPE /**/
+# define ATTRIB_NORET __attribute__((noreturn))
+# define NORET_AND noreturn,
+
+/* acl.c */
+extern int ext2_permission (struct inode *, int);
+
+/* balloc.c */
+extern int ext2_bg_has_super(struct super_block *sb, int group);
+extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group);
+extern int ext2_new_block (const struct inode *, unsigned long,
+ __u32 *, __u32 *, int *);
+extern void ext2_free_blocks (const struct inode *, unsigned long,
+ unsigned long);
+extern unsigned long ext2_count_free_blocks (struct super_block *);
+extern void ext2_check_blocks_bitmap (struct super_block *);
+extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
+ unsigned int block_group,
+ struct buffer_head ** bh);
+
+/* bitmap.c */
+extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
+
+/* dir.c */
+extern int ext2_check_dir_entry (const char *, struct inode *,
+ struct ext2_dir_entry_2 *, struct buffer_head *,
+ unsigned long);
+
+/* file.c */
+extern int ext2_read (struct inode *, struct file *, char *, int);
+extern int ext2_write (struct inode *, struct file *, char *, int);
+
+/* fsync.c */
+extern int ext2_sync_file (struct file *, struct dentry *, int);
+extern int ext2_fsync_inode (struct inode *, int);
+
+/* ialloc.c */
+extern struct inode * ext2_new_inode (const struct inode *, int);
+extern void ext2_free_inode (struct inode *);
+extern unsigned long ext2_count_free_inodes (struct super_block *);
+extern void ext2_check_inodes_bitmap (struct super_block *);
+
+/* inode.c */
+
+extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *);
+extern struct buffer_head * ext2_bread (struct inode *, int, int, int *);
+
+extern void ext2_read_inode (struct inode *);
+extern void ext2_write_inode (struct inode *, int);
+extern void ext2_put_inode (struct inode *);
+extern void ext2_delete_inode (struct inode *);
+extern int ext2_sync_inode (struct inode *);
+extern void ext2_discard_prealloc (struct inode *);
+
+/* ioctl.c */
+extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
+ unsigned long);
+
+/* namei.c */
+extern struct inode_operations ext2_dir_inode_operations;
+
+/* super.c */
+extern void ext2_error (struct super_block *, const char *, const char *, ...)
+ __attribute__ ((format (printf, 3, 4)));
+extern NORET_TYPE void ext2_panic (struct super_block *, const char *,
+ const char *, ...)
+ __attribute__ ((NORET_AND format (printf, 3, 4)));
+extern void ext2_warning (struct super_block *, const char *, const char *, ...)
+ __attribute__ ((format (printf, 3, 4)));
+extern void ext2_update_dynamic_rev (struct super_block *sb);
+extern void ext2_put_super (struct super_block *);
+extern void ext2_write_super (struct super_block *);
+extern int ext2_remount (struct super_block *, int *, char *);
+extern struct super_block * ext2_read_super (struct super_block *,void *,int);
+extern int ext2_statfs (struct super_block *, struct statfs *);
+
+/* truncate.c */
+extern void ext2_truncate (struct inode *);
+
+/*
+ * Inodes and files operations
+ */
+
+/* dir.c */
+extern struct file_operations ext2_dir_operations;
+
+/* file.c */
+extern struct inode_operations ext2_file_inode_operations;
+extern struct file_operations ext2_file_operations;
+
+/* symlink.c */
+extern struct inode_operations ext2_fast_symlink_inode_operations;
+
+extern struct address_space_operations ext2_aops;
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_EXT2_FS_H */
--- /dev/null
+/*
+ * linux/include/linux/ext2_fs_i.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/include/linux/minix_fs_i.h
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#ifndef _LINUX_EXT2_FS_I
+#define _LINUX_EXT2_FS_I
+
+/*
+ * second extended file system inode data in memory
+ */
+struct ext2_inode_info {
+ __u32 i_data[15];
+ __u32 i_flags;
+ __u32 i_faddr;
+ __u8 i_frag_no;
+ __u8 i_frag_size;
+ __u16 i_osync;
+ __u32 i_file_acl;
+ __u32 i_dir_acl;
+ __u32 i_dtime;
+ __u32 not_used_1; /* FIX: not used/ 2.2 placeholder */
+ __u32 i_block_group;
+ __u32 i_next_alloc_block;
+ __u32 i_next_alloc_goal;
+ __u32 i_prealloc_block;
+ __u32 i_prealloc_count;
+ __u32 i_high_size;
+ int i_new_inode:1; /* Is a freshly allocated inode */
+};
+
+#endif /* _LINUX_EXT2_FS_I */
--- /dev/null
+/*
+ * linux/include/linux/ext2_fs_sb.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/include/linux/minix_fs_sb.h
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#ifndef _LINUX_EXT2_FS_SB
+#define _LINUX_EXT2_FS_SB
+
+/*
+ * The following is not needed anymore since the descriptors buffer
+ * heads are now dynamically allocated
+ */
+/* #define EXT2_MAX_GROUP_DESC 8 */
+
+#define EXT2_MAX_GROUP_LOADED 8
+
+/*
+ * second extended-fs super-block data in memory
+ */
+struct ext2_sb_info {
+ unsigned long s_frag_size; /* Size of a fragment in bytes */
+ unsigned long s_frags_per_block;/* Number of fragments per block */
+ unsigned long s_inodes_per_block;/* Number of inodes per block */
+ unsigned long s_frags_per_group;/* Number of fragments in a group */
+ unsigned long s_blocks_per_group;/* Number of blocks in a group */
+ unsigned long s_inodes_per_group;/* Number of inodes in a group */
+ unsigned long s_itb_per_group; /* Number of inode table blocks per group */
+ unsigned long s_gdb_count; /* Number of group descriptor blocks */
+ unsigned long s_desc_per_block; /* Number of group descriptors per block */
+ unsigned long s_groups_count; /* Number of groups in the fs */
+ struct buffer_head * s_sbh; /* Buffer containing the super block */
+ struct ext2_super_block * s_es; /* Pointer to the super block in the buffer */
+ struct buffer_head ** s_group_desc;
+ unsigned short s_loaded_inode_bitmaps;
+ unsigned short s_loaded_block_bitmaps;
+ unsigned long s_inode_bitmap_number[EXT2_MAX_GROUP_LOADED];
+ struct buffer_head * s_inode_bitmap[EXT2_MAX_GROUP_LOADED];
+ unsigned long s_block_bitmap_number[EXT2_MAX_GROUP_LOADED];
+ struct buffer_head * s_block_bitmap[EXT2_MAX_GROUP_LOADED];
+ unsigned long s_mount_opt;
+ uid_t s_resuid;
+ gid_t s_resgid;
+ unsigned short s_mount_state;
+ unsigned short s_pad;
+ int s_addr_per_block_bits;
+ int s_desc_per_block_bits;
+ int s_inode_size;
+ int s_first_ino;
+};
+
+#endif /* _LINUX_EXT2_FS_SB */
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 __FS_EXT2FS_PRIVATE_H__
+#define __FS_EXT2FS_PRIVATE_H__
+
+/*
+ * Implement the Linux kernel internal data types
+ * used by ext2
+ */
+typedef UINT32 __u32;
+typedef INT32 __s32;
+typedef UINT16 __u16;
+typedef INT16 __s16;
+typedef UINT8 __u8;
+typedef INT8 __s8;
+typedef UINT32 uid_t;
+typedef UINT32 gid_t;
+
+/*
+ * Get some constant from linux/stat.h
+ */
+#define S_IFMT 00170000
+#define S_IFSOCK 0140000
+#define S_IFLNK 0120000
+#define S_IFREG 0100000
+#define S_IFBLK 0060000
+#define S_IFDIR 0040000
+#define S_IFCHR 0020000
+#define S_IFIFO 0010000
+#define S_ISUID 0004000
+#define S_ISGID 0002000
+#define S_ISVTX 0001000
+
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+
+
+#include "fs/ext2_fs.h"
+#include "fs/ext2_fs_sb.h"
+#include "fs/ext2_fs_i.h"
+
+#endif /* __FS_EXT2FS_PRIVATE_H__*/
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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.
+ *
+ * The ext2 code in this file is derived from aboot-0.7 (the Linux/Alpha
+ * bootloader) and credits are attributed to:
+ *
+ * This file has been ported from the DEC 32-bit Linux version
+ * by David Mosberger (davidm@cs.arizona.edu).
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "elilo.h"
+
+#define FS_NAME L"ext2fs"
+
+#ifdef PATH_MAX
+#error You must have included some Linux header file by error
+#endif
+
+#define PATH_MAX 4095
+#define EXT2FS_PATH_MAXLEN PATH_MAX
+
+#include "fs/ext2fs.h"
+#include "fs/ext2_private.h"
+
+/*
+ * should we decide to spin off ext2, let's say to a boottime driver
+ * we would have to change this
+ */
+#define EXT2FS_MEMTYPE EfiLoaderData
+
+/* ext2 file size is __u32 */
+#define EXT2_FILESIZE_MAX (0x100000000UL)
+
+/*
+ * Number of simultaneous open files. This needs to be high because
+ * directories are kept open while traversing long path names.
+ */
+#define MAX_OPEN_FILES 32
+
+typedef struct inode_table_entry {
+ struct ext2_inode inode;
+ int inumber;
+ int free;
+ unsigned short old_mode;
+
+ UINT32 pos; /* current position in file ext2 uses __u32 !*/
+} inode_entry_t;
+
+
+typedef struct {
+ struct ext2_super_block sb;
+ struct ext2_group_desc *gds;
+ struct ext2_inode *root_inode;
+ int ngroups;
+ int directlim; /* Maximum direct blkno */
+ int ind1lim; /* Maximum single-indir blkno */
+ int ind2lim; /* Maximum double-indir blkno */
+ int ptrs_per_blk; /* ptrs/indirect block */
+ CHAR8 blkbuf[EXT2_MAX_BLOCK_SIZE];
+ int cached_iblkno;
+ CHAR8 iblkbuf[EXT2_MAX_BLOCK_SIZE];
+ int cached_diblkno;
+ CHAR8 diblkbuf[EXT2_MAX_BLOCK_SIZE];
+ long blocksize;
+
+
+ inode_entry_t inode_table[MAX_OPEN_FILES];
+
+ /* fields added to fit the protocol construct */
+ EFI_BLOCK_IO *blkio;
+ UINT32 mediaid;
+ EFI_HANDLE dev;
+} ext2fs_priv_state_t;
+
+
+typedef union {
+ ext2fs_interface_t pub_intf;
+ struct {
+ ext2fs_interface_t pub_intf;
+ ext2fs_priv_state_t priv_data;
+ } ext2fs_priv;
+} ext2fs_t;
+
+#define FS_PRIVATE(n) (&(((ext2fs_t *)n)->ext2fs_priv.priv_data))
+
+typedef union {
+ EFI_HANDLE *dev;
+ ext2fs_t *intf;
+} dev_tab_t;
+
+static dev_tab_t *dev_tab; /* holds all devices we found */
+static UINTN ndev; /* how many entries in dev_tab */
+
+
+static EFI_GUID Ext2FsProtocol = EXT2FS_PROTOCOL;
+
+static INTN
+read_bytes(EFI_BLOCK_IO *blkio, UINT32 mediaid, UINTN offset, VOID *addr, UINTN size)
+{
+ EFI_STATUS status;
+ UINT8 *buffer;
+ UINTN count, buffer_size;
+ EFI_LBA base;
+ INTN ret = EFI_INVALID_PARAMETER;
+
+ base = offset / blkio->Media->BlockSize;
+ count = (size + blkio->Media->BlockSize -1) / blkio->Media->BlockSize;
+ buffer_size = count * blkio->Media->BlockSize;
+
+ DBG_PRT((L"readblock(%x, %d,%d) base=%d count=%d", blkio, offset, size, base, count));
+
+ /*
+ * slow but avoid large buffer on the stack
+ */
+ buffer = (UINT8 *)alloc(buffer_size, EfiLoaderData);
+ if (buffer == NULL) {
+ ERR_PRT((L"cannot allocate ext2fs buffer size=%d", buffer_size));
+ return ret;
+ }
+
+ DBG_PRT((L"readblock(%x, %d, %d, %d, %x)", blkio, mediaid, base, buffer_size, buffer));
+
+ status = blkio->ReadBlocks(blkio, mediaid, base, buffer_size, buffer);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"readblock(%d,%d)=%r", base, buffer_size, status));
+ goto error;
+ }
+
+ DBG_PRT((L"readblock(%d,%d)->%r", offset, buffer_size, status));
+
+ Memcpy(addr, buffer+(offset-(base*blkio->Media->BlockSize)), size);
+
+ ret = 0;
+
+error:
+ free(buffer);
+
+ return ret;
+}
+
+/*
+ * Read the specified inode from the disk and return it to the user.
+ * Returns NULL if the inode can't be read...
+ */
+static struct ext2_inode *
+ext2_iget(ext2fs_priv_state_t *e2fs, int ino)
+{
+ int i;
+ struct ext2_inode *ip;
+ struct inode_table_entry *itp = 0;
+ int group;
+ long offset;
+
+ ip = 0;
+ for (i = 0; i < MAX_OPEN_FILES; i++) {
+ DBG_PRT((L"ext2_iget: looping, entry %d inode %d free %d",
+ i, e2fs->inode_table[i].inumber, e2fs->inode_table[i].free));
+ if (e2fs->inode_table[i].free) {
+ itp = &e2fs->inode_table[i];
+ ip = &itp->inode;
+ break;
+ }
+ }
+ if (!ip) {
+ ERR_PRT((L"ext2_iget: no free inodes"));
+ return NULL;
+ }
+
+
+ group = (ino-1) / e2fs->sb.s_inodes_per_group;
+
+ DBG_PRT((L" itp-inode_table=%d bg_inode_table=%d group=%d ino=%d\n", (UINTN)(itp-e2fs->inode_table),
+ (UINTN)(e2fs->gds[group].bg_inode_table), (UINTN)group, (UINTN)ino));
+
+ offset = ((long) e2fs->gds[group].bg_inode_table * e2fs->blocksize)
+ + (((ino - 1) % EXT2_INODES_PER_GROUP(&e2fs->sb)) * EXT2_INODE_SIZE(&e2fs->sb));
+
+ DBG_PRT((L"ext2_iget: reading %d bytes at offset %d"
+ " ((%d * %d) + ((%d) %% %d) * %d) "
+ "(inode %d -> table %d)",
+ sizeof(struct ext2_inode),
+ (UINTN)offset,
+ (UINTN)e2fs->gds[group].bg_inode_table, (UINTN)e2fs->blocksize,
+ (UINTN)(ino - 1), (UINTN)EXT2_INODES_PER_GROUP(&e2fs->sb), EXT2_INODE_SIZE(&e2fs->sb),
+ (UINTN)ino, (UINTN) (itp - e2fs->inode_table)));
+
+ if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, ip, sizeof(struct ext2_inode))) {
+ ERR_PRT((L"ext2_iget: read error"));
+ return NULL;
+ }
+
+ DBG_PRT((L"mode=%x uid=%d size=%d gid=%d links=%d flags=%d",
+ (UINTN)ip->i_mode,
+ (UINTN)ip->i_uid,
+ (UINTN)ip->i_size,
+ (UINTN)ip->i_gid,
+ (UINTN)ip->i_flags));
+
+ itp->free = 0;
+ itp->inumber = ino;
+ itp->old_mode = ip->i_mode;
+
+ return ip;
+}
+
+
+/*
+ * Release our hold on an inode. Since this is a read-only application,
+ * don't worry about putting back any changes...
+ */
+static void
+ext2_iput(ext2fs_priv_state_t *e2fs, struct ext2_inode *ip)
+{
+ struct inode_table_entry *itp;
+
+ /* Find and free the inode table slot we used... */
+ itp = (struct inode_table_entry *)ip;
+
+ DBG_PRT((L"ext2_iput: inode %d table %d", itp->inumber, (int) (itp - e2fs->inode_table)));
+
+ itp->inumber = 0;
+ itp->free = 1;
+}
+
+
+/*
+ * Map a block offset into a file into an absolute block number.
+ * (traverse the indirect blocks if necessary). Note: Double-indirect
+ * blocks allow us to map over 64Mb on a 1k file system. Therefore, for
+ * our purposes, we will NOT bother with triple indirect blocks.
+ *
+ * The "allocate" argument is set if we want to *allocate* a block
+ * and we don't already have one allocated.
+ */
+static int
+ext2_blkno(ext2fs_priv_state_t *e2fs, struct ext2_inode *ip, int blkoff)
+{
+ unsigned int *lp;
+ unsigned int *ilp;
+ unsigned int *dlp;
+ int blkno;
+ int iblkno;
+ int diblkno;
+ long offset;
+
+ ilp = (unsigned int *)e2fs->iblkbuf;
+ dlp = (unsigned int *)e2fs->diblkbuf;
+ lp = (unsigned int *)e2fs->blkbuf;
+
+ /* If it's a direct block, it's easy! */
+ if (blkoff <= e2fs->directlim) {
+ return ip->i_block[blkoff];
+ }
+
+ /* Is it a single-indirect? */
+ if (blkoff <= e2fs->ind1lim) {
+ iblkno = ip->i_block[EXT2_IND_BLOCK];
+
+ if (iblkno == 0) {
+ return 0;
+ }
+
+ /* Read the indirect block */
+ if (e2fs->cached_iblkno != iblkno) {
+ offset = iblkno * e2fs->blocksize;
+ if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, e2fs->iblkbuf, e2fs->blocksize)) {
+ ERR_PRT((L"ext2_blkno: error on iblk read"));
+ return 0;
+ }
+ e2fs->cached_iblkno = iblkno;
+ }
+
+ blkno = ilp[blkoff-(e2fs->directlim+1)];
+ return blkno;
+ }
+
+ /* Is it a double-indirect? */
+ if (blkoff <= e2fs->ind2lim) {
+ /* Find the double-indirect block */
+ diblkno = ip->i_block[EXT2_DIND_BLOCK];
+
+ if (diblkno == 0) {
+ return 0;
+ }
+
+ /* Read in the double-indirect block */
+ if (e2fs->cached_diblkno != diblkno) {
+ offset = diblkno * e2fs->blocksize;
+ if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, e2fs->diblkbuf, e2fs->blocksize)) {
+ ERR_PRT((L"ext2_blkno: err reading dindr blk"));
+ return 0;
+ }
+ e2fs->cached_diblkno = diblkno;
+ }
+
+ /* Find the single-indirect block pointer ... */
+ iblkno = dlp[(blkoff - (e2fs->ind1lim+1)) / e2fs->ptrs_per_blk];
+
+ if (iblkno == 0) {
+ return 0;
+ }
+
+ /* Read the indirect block */
+
+ if (e2fs->cached_iblkno != iblkno) {
+ offset = iblkno * e2fs->blocksize;
+ if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, e2fs->iblkbuf, e2fs->blocksize)) {
+ ERR_PRT((L"ext2_blkno: err on iblk read"));
+ return 0;
+ }
+ e2fs->cached_iblkno = iblkno;
+ }
+
+ /* Find the block itself. */
+ blkno = ilp[(blkoff-(e2fs->ind1lim+1)) % e2fs->ptrs_per_blk];
+ return blkno;
+ }
+
+ if (blkoff > e2fs->ind2lim) {
+ ERR_PRT((L"ext2_blkno: block number too large: %d", blkoff));
+ return 0;
+ }
+ return -1;
+}
+
+
+static int
+ext2_breadi(ext2fs_priv_state_t *e2fs, struct ext2_inode *ip, long blkno, long nblks, CHAR8 *buffer)
+{
+ long dev_blkno, ncontig, offset, nbytes, tot_bytes;
+
+ tot_bytes = 0;
+ if ((blkno+nblks)*e2fs->blocksize > ip->i_size)
+ nblks = (ip->i_size + e2fs->blocksize) / e2fs->blocksize - blkno;
+
+ while (nblks) {
+ /*
+ * Contiguous reads are a lot faster, so we try to group
+ * as many blocks as possible:
+ */
+ ncontig = 0; nbytes = 0;
+ dev_blkno = ext2_blkno(e2fs,ip, blkno);
+ do {
+ ++blkno; ++ncontig; --nblks;
+ nbytes += e2fs->blocksize;
+ } while (nblks &&
+ ext2_blkno(e2fs, ip, blkno) == dev_blkno + ncontig);
+
+ if (dev_blkno == 0) {
+ /* This is a "hole" */
+ Memset(buffer, 0, nbytes);
+ } else {
+ /* Read it for real */
+ offset = dev_blkno*e2fs->blocksize;
+ DBG_PRT((L"ext2_bread: reading %d bytes at offset %d", nbytes, offset));
+
+ if (read_bytes(e2fs->blkio, e2fs->mediaid, offset, buffer, nbytes)) {
+ ERR_PRT((L"ext2_bread: read error"));
+ return -1;
+ }
+ }
+ buffer += nbytes;
+ tot_bytes += nbytes;
+ }
+ return tot_bytes;
+}
+
+static struct ext2_dir_entry_2 *
+ext2_readdiri(ext2fs_priv_state_t *e2fs, struct ext2_inode *dir_inode, int rewind)
+{
+ struct ext2_dir_entry_2 *dp;
+ static int diroffset = 0, blockoffset = 0;
+
+ /* Reading a different directory, invalidate previous state */
+ if (rewind) {
+ diroffset = 0;
+ blockoffset = 0;
+ /* read first block */
+ if (ext2_breadi(e2fs, dir_inode, 0, 1, e2fs->blkbuf) < 0)
+ return NULL;
+ }
+
+ DBG_PRT((L"ext2_readdiri: blkoffset %d diroffset %d len %d", blockoffset, diroffset, dir_inode->i_size));
+
+ if (blockoffset >= e2fs->blocksize) {
+ diroffset += e2fs->blocksize;
+ if (diroffset >= dir_inode->i_size)
+ return NULL;
+ ERR_PRT((L"ext2_readdiri: reading block at %d", diroffset));
+ /* assume that this will read the whole block */
+ if (ext2_breadi(e2fs, dir_inode, diroffset / e2fs->blocksize, 1, e2fs->blkbuf) < 0) return NULL;
+ blockoffset = 0;
+ }
+
+ dp = (struct ext2_dir_entry_2 *) (e2fs->blkbuf + blockoffset);
+ blockoffset += dp->rec_len;
+
+#if 0
+ Print(L"ext2_readdiri: returning %x = ");
+ { INTN i; for(i=0; i < dp->name_len; i++) Print(L"%c", (CHAR16)dp->name[i]); Print(L"\n");}
+#endif
+ return dp;
+}
+
+/*
+ * the string 'name' is modified by this call as per the parsing that
+ * is done in strtok_simple()
+ */
+static struct ext2_inode *
+ext2_namei(ext2fs_priv_state_t *e2fs, CHAR8 *name)
+{
+ CHAR8 *component;
+ struct ext2_inode *dir_inode;
+ struct ext2_dir_entry_2 *dp;
+ int next_ino;
+
+ /* start at the root: */
+ if (!e2fs->root_inode)
+ e2fs->root_inode = ext2_iget(e2fs, EXT2_ROOT_INO);
+ dir_inode = e2fs->root_inode;
+ if (!dir_inode)
+ return NULL;
+
+ component = strtok_simple(name, '/');
+ while (component) {
+ int component_length;
+ int rewind = 0;
+ /*
+ * Search for the specified component in the current
+ * directory inode.
+ */
+ next_ino = -1;
+ component_length = strlena(component);
+
+ DBG_PRT((L"ext2_namei: component = %a", component));
+
+ /* rewind the first time through */
+ while ((dp = ext2_readdiri(e2fs, dir_inode, !rewind++))) {
+ if ((dp->name_len == component_length) &&
+ (strncmpa(component, dp->name,
+ component_length) == 0))
+ {
+ /* Found it! */
+ DBG_PRT((L"ext2_namei: found entry %a", component));
+ next_ino = dp->inode;
+ break;
+ }
+ DBG_PRT((L"ext2_namei: looping"));
+ }
+
+ DBG_PRT((L"ext2_namei: next_ino = %d", next_ino));
+
+ /*
+ * At this point, we're done with this directory whether
+ * we've succeeded or failed...
+ */
+ if (dir_inode != e2fs->root_inode) ext2_iput(e2fs, dir_inode);
+
+ /*
+ * If next_ino is negative, then we've failed (gone
+ * all the way through without finding anything)
+ */
+ if (next_ino < 0) {
+ return NULL;
+ }
+
+ /*
+ * Otherwise, we can get this inode and find the next
+ * component string...
+ */
+ dir_inode = ext2_iget(e2fs, next_ino);
+ if (!dir_inode)
+ return NULL;
+
+ component = strtok_simple(NULL, '/');
+ }
+
+ /*
+ * If we get here, then we got through all the components.
+ * Whatever we got must match up with the last one.
+ */
+ return dir_inode;
+}
+
+
+/*
+ * Read block number "blkno" from the specified file.
+ */
+static int
+ext2_bread(ext2fs_priv_state_t *e2fs, int fd, long blkno, long nblks, char *buffer)
+{
+ struct ext2_inode * ip;
+ ip = &e2fs->inode_table[fd].inode;
+ return ext2_breadi(e2fs, ip, blkno, nblks, buffer);
+}
+
+#if 0
+/*
+ * Note: don't mix any kind of file lookup or other I/O with this or
+ * you will lose horribly (as it reuses blkbuf)
+ */
+static const char *
+ext2_readdir(ext2fs_priv_state_t *e2fs, int fd, int rewind)
+{
+ struct ext2_inode * ip = &e2fs->inode_table[fd].inode;
+ struct ext2_dir_entry_2 * ent;
+ if (!S_ISDIR(ip->i_mode)) {
+ ERR_PRT((L"fd %d (inode %d) is not a directory (mode %x)",
+ fd, e2fs->inode_table[fd].inumber, ip->i_mode));
+ return NULL;
+ }
+ ent = ext2_readdiri(e2fs, ip, rewind);
+ if (ent) {
+ ent->name[ent->name_len] = '\0';
+ return ent->name;
+ } else {
+ return NULL;
+ }
+}
+#endif
+
+static int
+ext2_fstat(ext2fs_priv_state_t *e2fs, int fd, ext2fs_stat_t *buf)
+{
+ struct ext2_inode * ip = &e2fs->inode_table[fd].inode;
+
+ Memset(buf, 0, sizeof(*buf));
+
+ /* fill in relevant fields */
+ buf->st_ino = e2fs->inode_table[fd].inumber;
+ buf->st_mode = ip->i_mode;
+ buf->st_nlink = ip->i_links_count;
+ buf->st_uid = ip->i_uid;
+ buf->st_gid = ip->i_gid;
+ buf->st_size = ip->i_size;
+ buf->st_atime = ip->i_atime;
+ buf->st_mtime = ip->i_mtime;
+ buf->st_ctime = ip->i_ctime;
+
+ return 0; /* NOTHING CAN GO WROGN! */
+}
+
+static EFI_STATUS
+ext2fs_fstat(ext2fs_interface_t *this, UINTN fd, ext2fs_stat_t *st)
+{
+ ext2fs_priv_state_t *e2fs;
+
+ if (this == NULL || fd > MAX_OPEN_FILES || st == NULL) return EFI_INVALID_PARAMETER;
+
+ e2fs = FS_PRIVATE(this);
+
+ ext2_fstat(e2fs, fd, st);
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS
+ext2fs_seek(ext2fs_interface_t *this, UINTN fd, UINT64 newpos)
+{
+ ext2fs_priv_state_t *e2fs;
+
+ if (this == NULL || fd > MAX_OPEN_FILES || newpos >= EXT2_FILESIZE_MAX) return EFI_INVALID_PARAMETER;
+
+ e2fs = FS_PRIVATE(this);
+ if (newpos > (UINT64)e2fs->inode_table[fd].inode.i_size) return EFI_INVALID_PARAMETER;
+
+ e2fs->inode_table[fd].pos = newpos;
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS
+ext2fs_read(ext2fs_interface_t *this, UINTN fd, VOID *buf, UINTN *size)
+{
+ ext2fs_priv_state_t *e2fs;
+ UINTN count, nc, bofs, bnum, pos;
+ EFI_STATUS ret = EFI_INVALID_PARAMETER;
+ CHAR8 *block;
+
+ if (this == NULL || size == NULL || buf == NULL || fd > MAX_OPEN_FILES) return EFI_INVALID_PARAMETER;
+
+ e2fs = FS_PRIVATE(this);
+
+ count = MIN(*size, e2fs->inode_table[fd].inode.i_size - e2fs->inode_table[fd].pos);
+
+ if (count == 0) {
+ *size = 0;
+ return EFI_SUCCESS;
+ }
+ block = e2fs->blkbuf;
+
+ *size = 0;
+
+ pos = e2fs->inode_table[fd].pos;
+ DBG_PRT((L"size=%d i_size=%d count=%d pos=%ld", *size,e2fs->inode_table[fd].inode.i_size, count, pos));
+ while (count) {
+ bnum = pos / e2fs->blocksize;
+ bofs = pos % e2fs->blocksize;
+ nc = MIN(count, e2fs->blocksize - bofs);
+
+ DBG_PRT((L"bnum =%d bofs=%d nc=%d *size=%d", bnum, bofs, nc, *size));
+
+ if (ext2_bread(e2fs, fd, bnum, 1, block) == -1) goto error;
+#if 0
+ { int i; char *p = block+bofs;
+ for(i=MIN(nc, 64); i>=0 ; i--, p++) {
+ if (i % 16 == 0) Print(L"\n");
+ Print(L"%02x ", (UINTN)*p & 0xff);
+ }
+ }
+#endif
+
+ Memcpy(buf, block+bofs, nc);
+ count -= nc;
+ pos += nc;
+ buf += nc;
+ *size += nc;
+ }
+
+ e2fs->inode_table[fd].pos += *size;
+ ret = EFI_SUCCESS;
+error:
+ DBG_PRT((L"*size=%d ret=%r", *size, ret));
+ return ret;
+}
+
+static struct ext2_inode *
+ext2_follow_link(ext2fs_priv_state_t *e2fs, struct ext2_inode * from, const char * base)
+{
+ char *linkto;
+
+ if (from->i_blocks) {
+ linkto = e2fs->blkbuf;
+ if (ext2_breadi(e2fs, from, 0, 1, e2fs->blkbuf) == -1)
+ return NULL;
+ DBG_PRT((L"long link!"));
+ } else {
+ linkto = (char*)from->i_block;
+ }
+ DBG_PRT((L"symlink to %s", linkto));
+
+ /* Resolve relative links */
+ if (linkto[0] != '/') {
+ char *end = strrchra(base, '/');
+ if (end) {
+ //char fullname[(end - base + 1) + strlena(linkto) + 1];
+ char fullname[EXT2FS_PATH_MAXLEN];
+
+ if (((end - base + 1) + strlena(linkto) + 1) >= EXT2FS_PATH_MAXLEN) {
+ Print(L"%s: filename too long, can't resolve\n", __FUNCTION__);
+ return NULL;
+ }
+
+ strncpya(fullname, base, end - base + 1);
+ fullname[end - base + 1] = '\0';
+ strcata(fullname, linkto);
+ DBG_PRT((L"resolved to %s", fullname));
+ return ext2_namei(e2fs, fullname);
+ } else {
+ /* Assume it's in the root */
+ return ext2_namei(e2fs, linkto);
+ }
+ } else {
+ return ext2_namei(e2fs, linkto);
+ }
+}
+
+static int
+ext2_open(ext2fs_priv_state_t *e2fs, char *filename)
+{
+ /*
+ * Unix-like open routine. Returns a small integer (actually
+ * an index into the inode table...
+ */
+ struct ext2_inode * ip;
+
+ ip = ext2_namei(e2fs, filename);
+ if (ip) {
+ struct inode_table_entry *itp;
+
+ while (S_ISLNK(ip->i_mode)) {
+ ip = ext2_follow_link(e2fs, ip, filename);
+ if (!ip) return -1;
+ }
+ itp = (struct inode_table_entry *)ip;
+ return itp - e2fs->inode_table;
+ } else
+ return -1;
+}
+
+static void ext2_close(ext2fs_priv_state_t *e2fs, int fd)
+{
+ /* blah, hack, don't close the root inode ever */
+ if (&e2fs->inode_table[fd].inode != e2fs->root_inode)
+ ext2_iput(e2fs, &e2fs->inode_table[fd].inode);
+}
+
+static EFI_STATUS
+ext2fs_close(ext2fs_interface_t *this, UINTN fd)
+{
+ ext2fs_priv_state_t *e2fs;
+
+ if (this == NULL || fd > MAX_OPEN_FILES) return EFI_INVALID_PARAMETER;
+
+ e2fs = FS_PRIVATE(this);
+
+ ext2_close(e2fs, fd);
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS
+ext2fs_open(ext2fs_interface_t *this, CHAR16 *name, UINTN *fd)
+{
+ ext2fs_priv_state_t *e2fs;
+ CHAR8 filename[EXT2FS_PATH_MAXLEN]; /* XXX: kind of big for a stack object */
+ INTN tmp;
+
+ DBG_PRT((L"name:%s fd=%x", name, fd));
+
+ if (this == NULL || name == NULL || fd == NULL || StrLen(name) >=EXT2FS_PATH_MAXLEN) return EFI_INVALID_PARAMETER;
+
+ e2fs = FS_PRIVATE(this);
+
+ /*
+ * XXX: for security reasons, we may have to force a prefix like /boot to all filenames
+ */
+ StrnXCpy(filename, name, EXT2FS_PATH_MAXLEN);
+
+ DBG_PRT((L"ASCII name:%a UTF-name:%s", filename, name));
+
+ tmp = ext2_open(e2fs, filename);
+ if (tmp != -1) {
+ *fd = (UINTN)tmp;
+ e2fs->inode_table[tmp].pos = 0; /* reset file position */
+ }
+
+ DBG_PRT((L"name: %s fd=%d tmp=%d", name, *fd, tmp));
+
+ return tmp == -1 ? EFI_NOT_FOUND : EFI_SUCCESS;
+}
+
+static EFI_STATUS
+ext2fs_name(ext2fs_interface_t *this, CHAR16 *name, UINTN maxlen)
+{
+ if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER;
+
+ StrnCpy(name, FS_NAME, maxlen-1);
+
+ name[maxlen-1] = CHAR_NULL;
+
+ return EFI_SUCCESS;
+}
+
+static INTN
+ext2fs_init_state(ext2fs_t *ext2fs, EFI_HANDLE dev, EFI_BLOCK_IO *blkio, struct ext2_super_block *sb)
+{
+ ext2fs_priv_state_t *e2fs = FS_PRIVATE(ext2fs);
+ UINTN i;
+ EFI_STATUS status;
+
+ Memset(ext2fs, 0, sizeof(*ext2fs));
+
+ e2fs->dev = dev;
+ e2fs->blkio = blkio;
+ e2fs->mediaid = blkio->Media->MediaId;
+
+ /* fools gcc builtin memcpy */
+ Memcpy(&e2fs->sb, sb, sizeof(*sb));
+
+ e2fs->ngroups = (sb->s_blocks_count - sb->s_first_data_block + EXT2_BLOCKS_PER_GROUP(sb) - 1) / EXT2_BLOCKS_PER_GROUP(sb);
+
+ e2fs->gds = (struct ext2_group_desc *)alloc(e2fs->ngroups * sizeof(struct ext2_group_desc), EXT2FS_MEMTYPE);
+ if (e2fs->gds == NULL) {
+ ERR_PRT((L"failed to allocate gds"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ e2fs->blocksize = EXT2_BLOCK_SIZE(sb);
+
+ DBG_PRT((L"gds_size=%d gds_offset=%d ngroups=%d blocksize=%d",
+ e2fs->ngroups * sizeof(struct ext2_group_desc),
+ e2fs->blocksize * (EXT2_MIN_BLOCK_SIZE/e2fs->blocksize + 1),
+ e2fs->ngroups, (UINTN)e2fs->blocksize));
+
+ /* read in the group descriptors (immediately follows superblock) */
+ status = read_bytes(blkio, e2fs->mediaid, e2fs->blocksize * (EXT2_MIN_BLOCK_SIZE/e2fs->blocksize + 1),
+ e2fs->gds, e2fs->ngroups * sizeof(struct ext2_group_desc));
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"cannot read gds: %r", status));
+ free(e2fs->gds);
+ return EFI_INVALID_PARAMETER;
+ }
+#if 0
+ { int i; char *p = (char *)e2fs->gds;
+ for(i=e2fs->ngroups*sizeof(*e2fs->gds); i ; i--, p++) {
+ if (i % 16 == 0) Print(L"\n");
+ Print(L"%02x ", (UINTN)*p & 0xff);
+
+ }
+ }
+#endif
+
+ e2fs->cached_diblkno = -1;
+ e2fs->cached_iblkno = -1;
+
+ /* initialize the inode table */
+ for (i = 0; i < MAX_OPEN_FILES; i++) {
+ e2fs->inode_table[i].free = 1;
+ e2fs->inode_table[i].inumber = 0;
+ }
+ /* clear the root inode pointer (very important!) */
+ e2fs->root_inode = NULL;
+
+ /*
+ * Calculate direct/indirect block limits for this file system
+ * (blocksize dependent):
+ ext2_blocksize = EXT2_BLOCK_SIZE(&sb);
+ */
+ e2fs->directlim = EXT2_NDIR_BLOCKS - 1;
+ e2fs->ptrs_per_blk = e2fs->blocksize/sizeof(unsigned int);
+ e2fs->ind1lim = e2fs->ptrs_per_blk + e2fs->directlim;
+ e2fs->ind2lim = (e2fs->ptrs_per_blk * e2fs->ptrs_per_blk) + e2fs->directlim;
+
+ ext2fs->pub_intf.ext2fs_name = ext2fs_name;
+ ext2fs->pub_intf.ext2fs_open = ext2fs_open;
+ ext2fs->pub_intf.ext2fs_read = ext2fs_read;
+ ext2fs->pub_intf.ext2fs_close = ext2fs_close;
+ ext2fs->pub_intf.ext2fs_seek = ext2fs_seek;
+ ext2fs->pub_intf.ext2fs_fstat = ext2fs_fstat;
+
+ return EFI_SUCCESS;
+}
+
+
+static EFI_STATUS
+ext2fs_install_one(EFI_HANDLE dev, VOID **intf)
+{
+ struct ext2_super_block sb;
+ long sb_block = 1;
+ EFI_STATUS status;
+ EFI_BLOCK_IO *blkio;
+ ext2fs_t *ext2fs;
+
+ status = BS->HandleProtocol (dev, &Ext2FsProtocol, (VOID **)&ext2fs);
+ if (status == EFI_SUCCESS) {
+ ERR_PRT((L"Warning: found existing %s protocol on device", FS_NAME));
+ goto found;
+ }
+
+ status = BS->HandleProtocol(dev, &BlockIoProtocol, (VOID **)&blkio);
+ if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER;
+
+ VERB_PRT(5,
+ { EFI_DEVICE_PATH *dp; CHAR16 *str;
+ dp = DevicePathFromHandle(dev);
+ str = DevicePathToStr(dp);
+ Print(L"dev:%s\nLogical partition: %s BlockSize: %d WriteCaching: %s \n", str,
+ blkio->Media->LogicalPartition ? L"Yes": L"No",
+ blkio->Media->BlockSize,
+ blkio->Media->WriteCaching ? L"Yes":L"No");
+ FreePool(str);
+ });
+ if (blkio->Media->LogicalPartition == FALSE) return EFI_INVALID_PARAMETER;
+
+#if 0
+ /*
+ * Used to be necessary on some older versions of EFI to avoid getting
+ * stuck. Now can cause problems with some SCSI controllers when enabled.
+ * Does not seem necessary with EFI 12.38
+ */
+ blkio->Reset(blkio, FALSE);
+#endif
+
+ status = read_bytes(blkio, blkio->Media->MediaId, sb_block * EXT2_MIN_BLOCK_SIZE, &sb, sizeof(sb));
+ if (EFI_ERROR(status)) {
+ DBG_PRT((L"cannot read superblock: %r", status));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (sb.s_magic != EXT2_SUPER_MAGIC) {
+ DBG_PRT((L"bad magic 0x%x\n", sb.s_magic));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ext2fs = (ext2fs_t *)alloc(sizeof(*ext2fs), EXT2FS_MEMTYPE);
+ if (ext2fs == NULL) return EFI_OUT_OF_RESOURCES;
+
+ status = ext2fs_init_state(ext2fs, dev, blkio, &sb);
+ if (status != EFI_SUCCESS) {
+ free(ext2fs);
+ return status;
+ }
+
+ status = LibInstallProtocolInterfaces(&dev, &Ext2FsProtocol, ext2fs, NULL);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"Cannot install %s protocol: %r", FS_NAME, status));
+ free(ext2fs);
+ return status;
+ }
+found:
+ if (intf) *intf = (VOID *)ext2fs;
+
+ VERB_PRT(3,
+ { EFI_DEVICE_PATH *dp; CHAR16 *str;
+ dp = DevicePathFromHandle(dev);
+ str = DevicePathToStr(dp);
+ Print(L"dev:%s %s detected\n", str, FS_NAME);
+ FreePool(str);
+ });
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+ext2fs_install(VOID)
+{
+ UINTN size = 0;
+ UINTN i;
+ EFI_STATUS status;
+ VOID *intf;
+
+ BS->LocateHandle(ByProtocol, &BlockIoProtocol, NULL, &size, NULL);
+ if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */
+
+ DBG_PRT((L"size=%d", size));
+
+ dev_tab = (dev_tab_t *)alloc(size, EfiLoaderData);
+ if (dev_tab == NULL) {
+ ERR_PRT((L"failed to allocate handle table"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ status = BS->LocateHandle(ByProtocol, &BlockIoProtocol, NULL, &size, (VOID **)dev_tab);
+ if (status != EFI_SUCCESS) {
+ ERR_PRT((L"failed to get handles: %r", status));
+ free(dev_tab);
+ return status;
+ }
+ ndev = size / sizeof(EFI_HANDLE);
+
+ for(i=0; i < ndev; i++) {
+ intf = NULL;
+ ext2fs_install_one(dev_tab[i].dev, &intf);
+ /* override device handle with interface pointer */
+ dev_tab[i].intf = intf;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+ext2fs_uninstall(VOID)
+{
+
+ ext2fs_priv_state_t *e2fs;
+ EFI_STATUS status;
+ UINTN i;
+
+ for(i=0; i < ndev; i++) {
+ if (dev_tab[i].intf == NULL) continue;
+ e2fs = FS_PRIVATE(dev_tab[i].intf);
+ status = BS->UninstallProtocolInterface(e2fs->dev, &Ext2FsProtocol, dev_tab[i].intf);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status));
+ continue;
+ }
+ VERB_PRT(3,
+ { EFI_DEVICE_PATH *dp; CHAR16 *str;
+ dp = DevicePathFromHandle(e2fs->dev);
+ str = DevicePathToStr(dp);
+ Print(L"uninstalled %s on %s\n", FS_NAME, str);
+ FreePool(str);
+ });
+ free(dev_tab[i].intf);
+ }
+ if (dev_tab) free(dev_tab);
+
+ return EFI_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 __EXT2FS_H__
+#define __EXT2FS_H__
+
+INTERFACE_DECL(_ext2fs_interface_t);
+
+/*
+ * simplified stat structure
+ * XXX: need to cleanup types !
+ */
+typedef struct {
+ unsigned long st_ino;
+ unsigned long st_nlink;
+ unsigned int st_mode;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ unsigned long st_size;
+ unsigned long st_atime;
+ unsigned long st_mtime;
+ unsigned long st_ctime;
+} ext2fs_stat_t;
+
+
+typedef struct _ext2fs_interface_t {
+ EFI_STATUS (*ext2fs_name)(struct _ext2fs_interface_t *this, CHAR16 *name, UINTN maxlen);
+ EFI_STATUS (*ext2fs_open)(struct _ext2fs_interface_t *this, CHAR16 *name, UINTN *fd);
+ EFI_STATUS (*ext2fs_read)(struct _ext2fs_interface_t *this, UINTN fd, VOID *buf, UINTN *size);
+ EFI_STATUS (*ext2fs_close)(struct _ext2fs_interface_t *this, UINTN fd);
+ EFI_STATUS (*ext2fs_fstat)(struct _ext2fs_interface_t *this, UINTN fd, ext2fs_stat_t *st);
+ EFI_STATUS (*ext2fs_seek)(struct _ext2fs_interface_t *this, UINTN fd, UINT64 newpos);
+} ext2fs_interface_t;
+
+#define EXT2FS_PROTOCOL \
+ { 0x6ea924f6, 0xc9f2, 0x4331, {0x83, 0x54, 0x19, 0xd0, 0x17, 0x50, 0xd9, 0xc7} }
+
+extern EFI_STATUS ext2fs_install(VOID);
+extern EFI_STATUS ext2fs_uninstall(VOID);
+
+
+#endif /* __EXT2FS_H__ */
--- /dev/null
+#ifndef _LINUX_FS_H
+#define _LINUX_FS_H
+
+/*
+ * This file has definitions for some important file table
+ * structures etc.
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <linux/limits.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/vfs.h>
+#include <linux/net.h>
+#include <linux/kdev_t.h>
+#include <linux/ioctl.h>
+#include <linux/list.h>
+#include <linux/dcache.h>
+#include <linux/stat.h>
+#include <linux/cache.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+
+struct poll_table_struct;
+
+
+/*
+ * It's silly to have NR_OPEN bigger than NR_FILE, but you can change
+ * the file limit at runtime and only root can increase the per-process
+ * nr_file rlimit, so it's safe to set up a ridiculously high absolute
+ * upper limit on files-per-process.
+ *
+ * Some programs (notably those using select()) may have to be
+ * recompiled to take full advantage of the new limits..
+ */
+
+/* Fixed constants first: */
+#undef NR_OPEN
+#define NR_OPEN (1024*1024) /* Absolute upper limit on fd num */
+#define INR_OPEN 1024 /* Initial setting for nfile rlimits */
+
+#define BLOCK_SIZE_BITS 10
+#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
+
+/* And dynamically-tunable limits and defaults: */
+struct files_stat_struct {
+ int nr_files; /* read only */
+ int nr_free_files; /* read only */
+ int max_files; /* tunable */
+};
+extern struct files_stat_struct files_stat;
+
+struct inodes_stat_t {
+ int nr_inodes;
+ int nr_unused;
+ int dummy[5];
+};
+extern struct inodes_stat_t inodes_stat;
+
+extern int max_super_blocks, nr_super_blocks;
+extern int leases_enable, dir_notify_enable, lease_break_time;
+
+#define NR_FILE 8192 /* this can well be larger on a larger system */
+#define NR_RESERVED_FILES 10 /* reserved for root */
+#define NR_SUPER 256
+
+#define MAY_EXEC 1
+#define MAY_WRITE 2
+#define MAY_READ 4
+
+#define FMODE_READ 1
+#define FMODE_WRITE 2
+
+#define READ 0
+#define WRITE 1
+#define READA 2 /* read-ahead - don't block if no resources */
+#define SPECIAL 4 /* For non-blockdevice requests in request queue */
+
+#define SEL_IN 1
+#define SEL_OUT 2
+#define SEL_EX 4
+
+/* public flags for file_system_type */
+#define FS_REQUIRES_DEV 1
+#define FS_NO_DCACHE 2 /* Only dcache the necessary things. */
+#define FS_NO_PRELIM 4 /* prevent preloading of dentries, even if
+ * FS_NO_DCACHE is not set.
+ */
+#define FS_SINGLE 8 /*
+ * Filesystem that can have only one superblock;
+ * kernel-wide vfsmnt is placed in ->kern_mnt by
+ * kern_mount() which must be called _after_
+ * register_filesystem().
+ */
+#define FS_NOMOUNT 16 /* Never mount from userland */
+#define FS_LITTER 32 /* Keeps the tree in dcache */
+#define FS_ODD_RENAME 32768 /* Temporary stuff; will go away as soon
+ * as nfs_rename() will be cleaned up
+ */
+/*
+ * These are the fs-independent mount-flags: up to 32 flags are supported
+ */
+#define MS_RDONLY 1 /* Mount read-only */
+#define MS_NOSUID 2 /* Ignore suid and sgid bits */
+#define MS_NODEV 4 /* Disallow access to device special files */
+#define MS_NOEXEC 8 /* Disallow program execution */
+#define MS_SYNCHRONOUS 16 /* Writes are synced at once */
+#define MS_REMOUNT 32 /* Alter flags of a mounted FS */
+#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */
+#define MS_NOATIME 1024 /* Do not update access times. */
+#define MS_NODIRATIME 2048 /* Do not update directory access times */
+#define MS_BIND 4096
+
+/*
+ * Flags that can be altered by MS_REMOUNT
+ */
+#define MS_RMT_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|\
+ MS_SYNCHRONOUS|MS_MANDLOCK|MS_NOATIME|MS_NODIRATIME)
+
+/*
+ * Old magic mount flag and mask
+ */
+#define MS_MGC_VAL 0xC0ED0000
+#define MS_MGC_MSK 0xffff0000
+
+/* Inode flags - they have nothing to superblock flags now */
+
+#define S_SYNC 1 /* Writes are synced at once */
+#define S_NOATIME 2 /* Do not update access times */
+#define S_QUOTA 4 /* Quota initialized for file */
+#define S_APPEND 8 /* Append-only file */
+#define S_IMMUTABLE 16 /* Immutable file */
+#define S_DEAD 32 /* removed, but still open directory */
+
+/*
+ * Note that nosuid etc flags are inode-specific: setting some file-system
+ * flags just means all the inodes inherit those flags by default. It might be
+ * possible to override it selectively if you really wanted to with some
+ * ioctl() that is not currently implemented.
+ *
+ * Exception: MS_RDONLY is always applied to the entire file system.
+ *
+ * Unfortunately, it is possible to change a filesystems flags with it mounted
+ * with files in use. This means that all of the inodes will not have their
+ * i_flags updated. Hence, i_flags no longer inherit the superblock mount
+ * flags, so these have to be checked separately. -- rmk@arm.uk.linux.org
+ */
+#define __IS_FLG(inode,flg) ((inode)->i_sb->s_flags & (flg))
+
+#define IS_RDONLY(inode) ((inode)->i_sb->s_flags & MS_RDONLY)
+#define IS_NOSUID(inode) __IS_FLG(inode, MS_NOSUID)
+#define IS_NODEV(inode) __IS_FLG(inode, MS_NODEV)
+#define IS_NOEXEC(inode) __IS_FLG(inode, MS_NOEXEC)
+#define IS_SYNC(inode) (__IS_FLG(inode, MS_SYNCHRONOUS) || ((inode)->i_flags & S_SYNC))
+#define IS_MANDLOCK(inode) __IS_FLG(inode, MS_MANDLOCK)
+
+#define IS_QUOTAINIT(inode) ((inode)->i_flags & S_QUOTA)
+#define IS_APPEND(inode) ((inode)->i_flags & S_APPEND)
+#define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE)
+#define IS_NOATIME(inode) (__IS_FLG(inode, MS_NOATIME) || ((inode)->i_flags & S_NOATIME))
+#define IS_NODIRATIME(inode) __IS_FLG(inode, MS_NODIRATIME)
+
+#define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD)
+
+/* the read-only stuff doesn't really belong here, but any other place is
+ probably as bad and I don't want to create yet another include file. */
+
+#define BLKROSET _IO(0x12,93) /* set device read-only (0 = read-write) */
+#define BLKROGET _IO(0x12,94) /* get read-only status (0 = read_write) */
+#define BLKRRPART _IO(0x12,95) /* re-read partition table */
+#define BLKGETSIZE _IO(0x12,96) /* return device size */
+#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
+#define BLKRASET _IO(0x12,98) /* Set read ahead for block device */
+#define BLKRAGET _IO(0x12,99) /* get current read ahead setting */
+#define BLKFRASET _IO(0x12,100)/* set filesystem (mm/filemap.c) read-ahead */
+#define BLKFRAGET _IO(0x12,101)/* get filesystem (mm/filemap.c) read-ahead */
+#define BLKSECTSET _IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */
+#define BLKSECTGET _IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */
+#define BLKSSZGET _IO(0x12,104)/* get block device sector size */
+#if 0
+#define BLKPG _IO(0x12,105)/* See blkpg.h */
+#define BLKELVGET _IOR(0x12,106,sizeof(blkelv_ioctl_arg_t))/* elevator get */
+#define BLKELVSET _IOW(0x12,107,sizeof(blkelv_ioctl_arg_t))/* elevator set */
+/* This was here just to show that the number is taken -
+ probably all these _IO(0x12,*) ioctls should be moved to blkpg.h. */
+#endif
+
+
+#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */
+#define FIBMAP _IO(0x00,1) /* bmap access */
+#define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */
+
+#ifdef __KERNEL__
+
+#include <asm/semaphore.h>
+#include <asm/byteorder.h>
+
+extern void update_atime (struct inode *);
+#define UPDATE_ATIME(inode) update_atime (inode)
+
+extern void buffer_init(unsigned long);
+extern void inode_init(unsigned long);
+
+/* bh state bits */
+#define BH_Uptodate 0 /* 1 if the buffer contains valid data */
+#define BH_Dirty 1 /* 1 if the buffer is dirty */
+#define BH_Lock 2 /* 1 if the buffer is locked */
+#define BH_Req 3 /* 0 if the buffer has been invalidated */
+#define BH_Mapped 4 /* 1 if the buffer has a disk mapping */
+#define BH_New 5 /* 1 if the buffer is new and not yet written out */
+#define BH_Protected 6 /* 1 if the buffer is protected */
+
+/*
+ * Try to keep the most commonly used fields in single cache lines (16
+ * bytes) to improve performance. This ordering should be
+ * particularly beneficial on 32-bit processors.
+ *
+ * We use the first 16 bytes for the data which is used in searches
+ * over the block hash lists (ie. getblk() and friends).
+ *
+ * The second 16 bytes we use for lru buffer scans, as used by
+ * sync_buffers() and refill_freelist(). -- sct
+ */
+struct buffer_head {
+ /* First cache line: */
+ struct buffer_head *b_next; /* Hash queue list */
+ unsigned long b_blocknr; /* block number */
+ unsigned short b_size; /* block size */
+ unsigned short b_list; /* List that this buffer appears */
+ kdev_t b_dev; /* device (B_FREE = free) */
+
+ atomic_t b_count; /* users using this block */
+ kdev_t b_rdev; /* Real device */
+ unsigned long b_state; /* buffer state bitmap (see above) */
+ unsigned long b_flushtime; /* Time when (dirty) buffer should be written */
+
+ struct buffer_head *b_next_free;/* lru/free list linkage */
+ struct buffer_head *b_prev_free;/* doubly linked list of buffers */
+ struct buffer_head *b_this_page;/* circular list of buffers in one page */
+ struct buffer_head *b_reqnext; /* request queue */
+
+ struct buffer_head **b_pprev; /* doubly linked list of hash-queue */
+ char * b_data; /* pointer to data block */
+ struct page *b_page; /* the page this bh is mapped to */
+ void (*b_end_io)(struct buffer_head *bh, int uptodate); /* I/O completion */
+ void *b_private; /* reserved for b_end_io */
+
+ unsigned long b_rsector; /* Real buffer location on disk */
+ wait_queue_head_t b_wait;
+
+ struct inode * b_inode;
+ struct list_head b_inode_buffers; /* doubly linked list of inode dirty buffers */
+};
+
+typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
+void init_buffer(struct buffer_head *, bh_end_io_t *, void *);
+
+#define __buffer_state(bh, state) (((bh)->b_state & (1UL << BH_##state)) != 0)
+
+#define buffer_uptodate(bh) __buffer_state(bh,Uptodate)
+#define buffer_dirty(bh) __buffer_state(bh,Dirty)
+#define buffer_locked(bh) __buffer_state(bh,Lock)
+#define buffer_req(bh) __buffer_state(bh,Req)
+#define buffer_mapped(bh) __buffer_state(bh,Mapped)
+#define buffer_new(bh) __buffer_state(bh,New)
+#define buffer_protected(bh) __buffer_state(bh,Protected)
+
+#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK)
+
+extern void set_bh_page(struct buffer_head *bh, struct page *page, unsigned long offset);
+
+#define touch_buffer(bh) SetPageReferenced(bh->b_page)
+
+
+#include <linux/pipe_fs_i.h>
+#include <linux/minix_fs_i.h>
+#include <linux/ext2_fs_i.h>
+#include <linux/hpfs_fs_i.h>
+#include <linux/ntfs_fs_i.h>
+#include <linux/msdos_fs_i.h>
+#include <linux/umsdos_fs_i.h>
+#include <linux/iso_fs_i.h>
+#include <linux/nfs_fs_i.h>
+#include <linux/sysv_fs_i.h>
+#include <linux/affs_fs_i.h>
+#include <linux/ufs_fs_i.h>
+#include <linux/efs_fs_i.h>
+#include <linux/coda_fs_i.h>
+#include <linux/romfs_fs_i.h>
+#include <linux/shmem_fs.h>
+#include <linux/smb_fs_i.h>
+#include <linux/hfs_fs_i.h>
+#include <linux/adfs_fs_i.h>
+#include <linux/qnx4_fs_i.h>
+#include <linux/reiserfs_fs_i.h>
+#include <linux/bfs_fs_i.h>
+#include <linux/udf_fs_i.h>
+#include <linux/ncp_fs_i.h>
+#include <linux/proc_fs_i.h>
+#include <linux/usbdev_fs_i.h>
+
+/*
+ * Attribute flags. These should be or-ed together to figure out what
+ * has been changed!
+ */
+#define ATTR_MODE 1
+#define ATTR_UID 2
+#define ATTR_GID 4
+#define ATTR_SIZE 8
+#define ATTR_ATIME 16
+#define ATTR_MTIME 32
+#define ATTR_CTIME 64
+#define ATTR_ATIME_SET 128
+#define ATTR_MTIME_SET 256
+#define ATTR_FORCE 512 /* Not a change, but a change it */
+#define ATTR_ATTR_FLAG 1024
+
+/*
+ * This is the Inode Attributes structure, used for notify_change(). It
+ * uses the above definitions as flags, to know which values have changed.
+ * Also, in this manner, a Filesystem can look at only the values it cares
+ * about. Basically, these are the attributes that the VFS layer can
+ * request to change from the FS layer.
+ *
+ * Derek Atkins <warlord@MIT.EDU> 94-10-20
+ */
+struct iattr {
+ unsigned int ia_valid;
+ umode_t ia_mode;
+ uid_t ia_uid;
+ gid_t ia_gid;
+ loff_t ia_size;
+ time_t ia_atime;
+ time_t ia_mtime;
+ time_t ia_ctime;
+ unsigned int ia_attr_flags;
+};
+
+/*
+ * This is the inode attributes flag definitions
+ */
+#define ATTR_FLAG_SYNCRONOUS 1 /* Syncronous write */
+#define ATTR_FLAG_NOATIME 2 /* Don't update atime */
+#define ATTR_FLAG_APPEND 4 /* Append-only file */
+#define ATTR_FLAG_IMMUTABLE 8 /* Immutable file */
+#define ATTR_FLAG_NODIRATIME 16 /* Don't update atime for directory */
+
+/*
+ * Includes for diskquotas and mount structures.
+ */
+#include <linux/quota.h>
+#include <linux/mount.h>
+
+/*
+ * oh the beauties of C type declarations.
+ */
+struct page;
+struct address_space;
+
+struct address_space_operations {
+ int (*writepage)(struct page *);
+ int (*readpage)(struct file *, struct page *);
+ int (*sync_page)(struct page *);
+ int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
+ int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
+ /* Unfortunately this kludge is needed for FIBMAP. Don't use it */
+ int (*bmap)(struct address_space *, long);
+};
+
+struct address_space {
+ struct list_head clean_pages; /* list of clean pages */
+ struct list_head dirty_pages; /* list of dirty pages */
+ struct list_head locked_pages; /* list of locked pages */
+ unsigned long nrpages; /* number of total pages */
+ struct address_space_operations *a_ops; /* methods */
+ struct inode *host; /* owner: inode, block_device */
+ struct vm_area_struct *i_mmap; /* list of private mappings */
+ struct vm_area_struct *i_mmap_shared; /* list of shared mappings */
+ spinlock_t i_shared_lock; /* and spinlock protecting it */
+ int gfp_mask; /* how to allocate the pages */
+};
+
+struct char_device {
+ struct list_head hash;
+ atomic_t count;
+ dev_t dev;
+ atomic_t openers;
+ struct semaphore sem;
+};
+
+struct block_device {
+ struct list_head bd_hash;
+ atomic_t bd_count;
+/* struct address_space bd_data; */
+ dev_t bd_dev; /* not a kdev_t - it's a search key */
+ atomic_t bd_openers;
+ const struct block_device_operations *bd_op;
+ struct semaphore bd_sem; /* open/close mutex */
+};
+
+struct inode {
+ struct list_head i_hash;
+ struct list_head i_list;
+ struct list_head i_dentry;
+
+ struct list_head i_dirty_buffers;
+
+ unsigned long i_ino;
+ atomic_t i_count;
+ kdev_t i_dev;
+ umode_t i_mode;
+ nlink_t i_nlink;
+ uid_t i_uid;
+ gid_t i_gid;
+ kdev_t i_rdev;
+ loff_t i_size;
+ time_t i_atime;
+ time_t i_mtime;
+ time_t i_ctime;
+ unsigned long i_blksize;
+ unsigned long i_blocks;
+ unsigned long i_version;
+ struct semaphore i_sem;
+ struct semaphore i_zombie;
+ struct inode_operations *i_op;
+ struct file_operations *i_fop; /* former ->i_op->default_file_ops */
+ struct super_block *i_sb;
+ wait_queue_head_t i_wait;
+ struct file_lock *i_flock;
+ struct address_space *i_mapping;
+ struct address_space i_data;
+ struct dquot *i_dquot[MAXQUOTAS];
+ /* These three should probably be a union */
+ struct pipe_inode_info *i_pipe;
+ struct block_device *i_bdev;
+ struct char_device *i_cdev;
+
+ unsigned long i_dnotify_mask; /* Directory notify events */
+ struct dnotify_struct *i_dnotify; /* for directory notifications */
+
+ unsigned long i_state;
+
+ unsigned int i_flags;
+ unsigned char i_sock;
+
+ atomic_t i_writecount;
+ unsigned int i_attr_flags;
+ __u32 i_generation;
+ union {
+ struct minix_inode_info minix_i;
+ struct ext2_inode_info ext2_i;
+ struct hpfs_inode_info hpfs_i;
+ struct ntfs_inode_info ntfs_i;
+ struct msdos_inode_info msdos_i;
+ struct umsdos_inode_info umsdos_i;
+ struct iso_inode_info isofs_i;
+ struct nfs_inode_info nfs_i;
+ struct sysv_inode_info sysv_i;
+ struct affs_inode_info affs_i;
+ struct ufs_inode_info ufs_i;
+ struct efs_inode_info efs_i;
+ struct romfs_inode_info romfs_i;
+ struct shmem_inode_info shmem_i;
+ struct coda_inode_info coda_i;
+ struct smb_inode_info smbfs_i;
+ struct hfs_inode_info hfs_i;
+ struct adfs_inode_info adfs_i;
+ struct qnx4_inode_info qnx4_i;
+ struct reiserfs_inode_info reiserfs_i;
+ struct bfs_inode_info bfs_i;
+ struct udf_inode_info udf_i;
+ struct ncp_inode_info ncpfs_i;
+ struct proc_inode_info proc_i;
+ struct socket socket_i;
+ struct usbdev_inode_info usbdev_i;
+ void *generic_ip;
+ } u;
+};
+
+struct fown_struct {
+ int pid; /* pid or -pgrp where SIGIO should be sent */
+ uid_t uid, euid; /* uid/euid of process setting the owner */
+ int signum; /* posix.1b rt signal to be delivered on IO */
+};
+
+struct file {
+ struct list_head f_list;
+ struct dentry *f_dentry;
+ struct vfsmount *f_vfsmnt;
+ struct file_operations *f_op;
+ atomic_t f_count;
+ unsigned int f_flags;
+ mode_t f_mode;
+ loff_t f_pos;
+ unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
+ struct fown_struct f_owner;
+ unsigned int f_uid, f_gid;
+ int f_error;
+
+ unsigned long f_version;
+
+ /* needed for tty driver, and maybe others */
+ void *private_data;
+};
+extern spinlock_t files_lock;
+#define file_list_lock() spin_lock(&files_lock);
+#define file_list_unlock() spin_unlock(&files_lock);
+
+#define get_file(x) atomic_inc(&(x)->f_count)
+#define file_count(x) atomic_read(&(x)->f_count)
+
+extern int init_private_file(struct file *, struct dentry *, int);
+
+#define MAX_NON_LFS ((1UL<<31) - 1)
+
+#define FL_POSIX 1
+#define FL_FLOCK 2
+#define FL_BROKEN 4 /* broken flock() emulation */
+#define FL_ACCESS 8 /* for processes suspended by mandatory locking */
+#define FL_LOCKD 16 /* lock held by rpc.lockd */
+#define FL_LEASE 32 /* lease held on this file */
+
+/*
+ * The POSIX file lock owner is determined by
+ * the "struct files_struct" in the thread group
+ * (or NULL for no owner - BSD locks).
+ *
+ * Lockd stuffs a "host" pointer into this.
+ */
+typedef struct files_struct *fl_owner_t;
+
+struct file_lock {
+ struct file_lock *fl_next; /* singly linked list for this inode */
+ struct list_head fl_link; /* doubly linked list of all locks */
+ struct list_head fl_block; /* circular list of blocked processes */
+ fl_owner_t fl_owner;
+ unsigned int fl_pid;
+ wait_queue_head_t fl_wait;
+ struct file *fl_file;
+ unsigned char fl_flags;
+ unsigned char fl_type;
+ loff_t fl_start;
+ loff_t fl_end;
+
+ void (*fl_notify)(struct file_lock *); /* unblock callback */
+ void (*fl_insert)(struct file_lock *); /* lock insertion callback */
+ void (*fl_remove)(struct file_lock *); /* lock removal callback */
+
+ struct fasync_struct * fl_fasync; /* for lease break notifications */
+
+ union {
+ struct nfs_lock_info nfs_fl;
+ } fl_u;
+};
+
+/* The following constant reflects the upper bound of the file/locking space */
+#ifndef OFFSET_MAX
+#define INT_LIMIT(x) (~((x)1 << (sizeof(x)*8 - 1)))
+#define OFFSET_MAX INT_LIMIT(loff_t)
+#define OFFT_OFFSET_MAX INT_LIMIT(off_t)
+#endif
+
+extern struct list_head file_lock_list;
+
+#include <linux/fcntl.h>
+
+extern int fcntl_getlk(unsigned int, struct flock *);
+extern int fcntl_setlk(unsigned int, unsigned int, struct flock *);
+
+extern int fcntl_getlk64(unsigned int, struct flock64 *);
+extern int fcntl_setlk64(unsigned int, unsigned int, struct flock64 *);
+
+/* fs/locks.c */
+extern void locks_init_lock(struct file_lock *);
+extern void locks_copy_lock(struct file_lock *, struct file_lock *);
+extern void locks_remove_posix(struct file *, fl_owner_t);
+extern void locks_remove_flock(struct file *);
+extern struct file_lock *posix_test_lock(struct file *, struct file_lock *);
+extern int posix_lock_file(struct file *, struct file_lock *, unsigned int);
+extern void posix_block_lock(struct file_lock *, struct file_lock *);
+extern void posix_unblock_lock(struct file_lock *);
+extern int __get_lease(struct inode *inode, unsigned int flags);
+extern time_t lease_get_mtime(struct inode *);
+extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
+extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
+
+struct fasync_struct {
+ int magic;
+ int fa_fd;
+ struct fasync_struct *fa_next; /* singly linked list */
+ struct file *fa_file;
+};
+
+#define FASYNC_MAGIC 0x4601
+
+/* SMP safe fasync helpers: */
+extern int fasync_helper(int, struct file *, int, struct fasync_struct **);
+/* can be called from interrupts */
+extern void kill_fasync(struct fasync_struct **, int, int);
+/* only for net: no internal synchronization */
+extern void __kill_fasync(struct fasync_struct *, int, int);
+
+struct nameidata {
+ struct dentry *dentry;
+ struct vfsmount *mnt;
+ struct qstr last;
+ unsigned int flags;
+ int last_type;
+};
+
+#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */
+#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */
+
+struct quota_mount_options
+{
+ unsigned int flags; /* Flags for diskquotas on this device */
+ struct semaphore dqio_sem; /* lock device while I/O in progress */
+ struct semaphore dqoff_sem; /* serialize quota_off() and quota_on() on device */
+ struct file *files[MAXQUOTAS]; /* fp's to quotafiles */
+ time_t inode_expire[MAXQUOTAS]; /* expiretime for inode-quota */
+ time_t block_expire[MAXQUOTAS]; /* expiretime for block-quota */
+ char rsquash[MAXQUOTAS]; /* for quotas threat root as any other user */
+};
+
+/*
+ * Umount options
+ */
+
+#define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */
+
+#include <linux/minix_fs_sb.h>
+#include <linux/ext2_fs_sb.h>
+#include <linux/hpfs_fs_sb.h>
+#include <linux/ntfs_fs_sb.h>
+#include <linux/msdos_fs_sb.h>
+#include <linux/iso_fs_sb.h>
+#include <linux/nfs_fs_sb.h>
+#include <linux/sysv_fs_sb.h>
+#include <linux/affs_fs_sb.h>
+#include <linux/ufs_fs_sb.h>
+#include <linux/efs_fs_sb.h>
+#include <linux/romfs_fs_sb.h>
+#include <linux/smb_fs_sb.h>
+#include <linux/hfs_fs_sb.h>
+#include <linux/adfs_fs_sb.h>
+#include <linux/qnx4_fs_sb.h>
+#include <linux/reiserfs_fs_sb.h>
+#include <linux/bfs_fs_sb.h>
+#include <linux/udf_fs_sb.h>
+#include <linux/ncp_fs_sb.h>
+#include <linux/usbdev_fs_sb.h>
+
+extern struct list_head super_blocks;
+
+#define sb_entry(list) list_entry((list), struct super_block, s_list)
+struct super_block {
+ struct list_head s_list; /* Keep this first */
+ kdev_t s_dev;
+ unsigned long s_blocksize;
+ unsigned char s_blocksize_bits;
+ unsigned char s_dirt;
+ unsigned long long s_maxbytes; /* Max file size */
+ struct file_system_type *s_type;
+ struct super_operations *s_op;
+ struct dquot_operations *dq_op;
+ unsigned long s_flags;
+ unsigned long s_magic;
+ struct dentry *s_root;
+ struct rw_semaphore s_umount;
+ struct semaphore s_lock;
+
+ struct list_head s_dirty; /* dirty inodes */
+ struct list_head s_locked_inodes;/* inodes being synced */
+ struct list_head s_files;
+
+ struct block_device *s_bdev;
+ struct list_head s_mounts; /* vfsmount(s) of this one */
+ struct quota_mount_options s_dquot; /* Diskquota specific options */
+
+ union {
+ struct minix_sb_info minix_sb;
+ struct ext2_sb_info ext2_sb;
+ struct hpfs_sb_info hpfs_sb;
+ struct ntfs_sb_info ntfs_sb;
+ struct msdos_sb_info msdos_sb;
+ struct isofs_sb_info isofs_sb;
+ struct nfs_sb_info nfs_sb;
+ struct sysv_sb_info sysv_sb;
+ struct affs_sb_info affs_sb;
+ struct ufs_sb_info ufs_sb;
+ struct efs_sb_info efs_sb;
+ struct shmem_sb_info shmem_sb;
+ struct romfs_sb_info romfs_sb;
+ struct smb_sb_info smbfs_sb;
+ struct hfs_sb_info hfs_sb;
+ struct adfs_sb_info adfs_sb;
+ struct qnx4_sb_info qnx4_sb;
+ struct reiserfs_sb_info reiserfs_sb;
+ struct bfs_sb_info bfs_sb;
+ struct udf_sb_info udf_sb;
+ struct ncp_sb_info ncpfs_sb;
+ struct usbdev_sb_info usbdevfs_sb;
+ void *generic_sbp;
+ } u;
+ /*
+ * The next field is for VFS *only*. No filesystems have any business
+ * even looking at it. You had been warned.
+ */
+ struct semaphore s_vfs_rename_sem; /* Kludge */
+
+ /* The next field is used by knfsd when converting a (inode number based)
+ * file handle into a dentry. As it builds a path in the dcache tree from
+ * the bottom up, there may for a time be a subpath of dentrys which is not
+ * connected to the main tree. This semaphore ensure that there is only ever
+ * one such free path per filesystem. Note that unconnected files (or other
+ * non-directories) are allowed, but not unconnected diretories.
+ */
+ struct semaphore s_nfsd_free_path_sem;
+};
+
+/*
+ * VFS helper functions..
+ */
+extern int vfs_create(struct inode *, struct dentry *, int);
+extern int vfs_mkdir(struct inode *, struct dentry *, int);
+extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
+extern int vfs_symlink(struct inode *, struct dentry *, const char *);
+extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
+extern int vfs_rmdir(struct inode *, struct dentry *);
+extern int vfs_unlink(struct inode *, struct dentry *);
+extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+
+/*
+ * File types
+ */
+#define DT_UNKNOWN 0
+#define DT_FIFO 1
+#define DT_CHR 2
+#define DT_DIR 4
+#define DT_BLK 6
+#define DT_REG 8
+#define DT_LNK 10
+#define DT_SOCK 12
+#define DT_WHT 14
+
+/*
+ * This is the "filldir" function type, used by readdir() to let
+ * the kernel specify what kind of dirent layout it wants to have.
+ * This allows the kernel to read directories into kernel space or
+ * to have different dirent layouts depending on the binary type.
+ */
+typedef int (*filldir_t)(void *, const char *, int, off_t, ino_t, unsigned);
+
+struct block_device_operations {
+ int (*open) (struct inode *, struct file *);
+ int (*release) (struct inode *, struct file *);
+ int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
+ int (*check_media_change) (kdev_t);
+ int (*revalidate) (kdev_t);
+};
+
+/*
+ * NOTE:
+ * read, write, poll, fsync, readv, writev can be called
+ * without the big kernel lock held in all filesystems.
+ */
+struct file_operations {
+ struct module *owner;
+ loff_t (*llseek) (struct file *, loff_t, int);
+ ssize_t (*read) (struct file *, char *, size_t, loff_t *);
+ ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
+ int (*readdir) (struct file *, void *, filldir_t);
+ unsigned int (*poll) (struct file *, struct poll_table_struct *);
+ int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
+ int (*mmap) (struct file *, struct vm_area_struct *);
+ int (*open) (struct inode *, struct file *);
+ int (*flush) (struct file *);
+ int (*release) (struct inode *, struct file *);
+ int (*fsync) (struct file *, struct dentry *, int datasync);
+ int (*fasync) (int, struct file *, int);
+ int (*lock) (struct file *, int, struct file_lock *);
+ ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
+ ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
+ ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
+ unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+};
+
+struct inode_operations {
+ int (*create) (struct inode *,struct dentry *,int);
+ struct dentry * (*lookup) (struct inode *,struct dentry *);
+ int (*link) (struct dentry *,struct inode *,struct dentry *);
+ int (*unlink) (struct inode *,struct dentry *);
+ int (*symlink) (struct inode *,struct dentry *,const char *);
+ int (*mkdir) (struct inode *,struct dentry *,int);
+ int (*rmdir) (struct inode *,struct dentry *);
+ int (*mknod) (struct inode *,struct dentry *,int,int);
+ int (*rename) (struct inode *, struct dentry *,
+ struct inode *, struct dentry *);
+ int (*readlink) (struct dentry *, char *,int);
+ int (*follow_link) (struct dentry *, struct nameidata *);
+ void (*truncate) (struct inode *);
+ int (*permission) (struct inode *, int);
+ int (*revalidate) (struct dentry *);
+ int (*setattr) (struct dentry *, struct iattr *);
+ int (*getattr) (struct dentry *, struct iattr *);
+};
+
+/*
+ * NOTE: write_inode, delete_inode, clear_inode, put_inode can be called
+ * without the big kernel lock held in all filesystems.
+ */
+struct super_operations {
+ void (*read_inode) (struct inode *);
+
+ /* reiserfs kludge. reiserfs needs 64 bits of information to
+ ** find an inode. We are using the read_inode2 call to get
+ ** that information. We don't like this, and are waiting on some
+ ** VFS changes for the real solution.
+ ** iget4 calls read_inode2, iff it is defined
+ */
+ void (*read_inode2) (struct inode *, void *) ;
+ void (*dirty_inode) (struct inode *);
+ void (*write_inode) (struct inode *, int);
+ void (*put_inode) (struct inode *);
+ void (*delete_inode) (struct inode *);
+ void (*put_super) (struct super_block *);
+ void (*write_super) (struct super_block *);
+ void (*write_super_lockfs) (struct super_block *);
+ void (*unlockfs) (struct super_block *);
+ int (*statfs) (struct super_block *, struct statfs *);
+ int (*remount_fs) (struct super_block *, int *, char *);
+ void (*clear_inode) (struct inode *);
+ void (*umount_begin) (struct super_block *);
+};
+
+/* Inode state bits.. */
+#define I_DIRTY_SYNC 1 /* Not dirty enough for O_DATASYNC */
+#define I_DIRTY_DATASYNC 2 /* Data-related inode changes pending */
+#define I_DIRTY_PAGES 4 /* Data-related inode changes pending */
+#define I_LOCK 8
+#define I_FREEING 16
+#define I_CLEAR 32
+
+#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
+
+extern void __mark_inode_dirty(struct inode *, int);
+static inline void mark_inode_dirty(struct inode *inode)
+{
+ __mark_inode_dirty(inode, I_DIRTY);
+}
+
+static inline void mark_inode_dirty_sync(struct inode *inode)
+{
+ __mark_inode_dirty(inode, I_DIRTY_SYNC);
+}
+
+static inline void mark_inode_dirty_pages(struct inode *inode)
+{
+ __mark_inode_dirty(inode, I_DIRTY_PAGES);
+}
+
+struct dquot_operations {
+ void (*initialize) (struct inode *, short);
+ void (*drop) (struct inode *);
+ int (*alloc_block) (const struct inode *, unsigned long, char);
+ int (*alloc_inode) (const struct inode *, unsigned long);
+ void (*free_block) (const struct inode *, unsigned long);
+ void (*free_inode) (const struct inode *, unsigned long);
+ int (*transfer) (struct dentry *, struct iattr *);
+};
+
+struct file_system_type {
+ const char *name;
+ int fs_flags;
+ struct super_block *(*read_super) (struct super_block *, void *, int);
+ struct module *owner;
+ struct vfsmount *kern_mnt; /* For kernel mount, if it's FS_SINGLE fs */
+ struct file_system_type * next;
+};
+
+#define DECLARE_FSTYPE(var,type,read,flags) \
+struct file_system_type var = { \
+ name: type, \
+ read_super: read, \
+ fs_flags: flags, \
+ owner: THIS_MODULE, \
+}
+
+#define DECLARE_FSTYPE_DEV(var,type,read) \
+ DECLARE_FSTYPE(var,type,read,FS_REQUIRES_DEV)
+
+/* Alas, no aliases. Too much hassle with bringing module.h everywhere */
+#define fops_get(fops) \
+ (((fops) && (fops)->owner) \
+ ? ( try_inc_mod_count((fops)->owner) ? (fops) : NULL ) \
+ : (fops))
+
+#define fops_put(fops) \
+do { \
+ if ((fops) && (fops)->owner) \
+ __MOD_DEC_USE_COUNT((fops)->owner); \
+} while(0)
+
+extern int register_filesystem(struct file_system_type *);
+extern int unregister_filesystem(struct file_system_type *);
+extern struct vfsmount *kern_mount(struct file_system_type *);
+extern int may_umount(struct vfsmount *);
+extern long do_mount(char *, char *, char *, unsigned long, void *);
+
+#define kern_umount mntput
+
+extern int vfs_statfs(struct super_block *, struct statfs *);
+
+/* Return value for VFS lock functions - tells locks.c to lock conventionally
+ * REALLY kosha for root NFS and nfs_lock
+ */
+#define LOCK_USE_CLNT 1
+
+#define FLOCK_VERIFY_READ 1
+#define FLOCK_VERIFY_WRITE 2
+
+extern int locks_mandatory_locked(struct inode *);
+extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t);
+
+/*
+ * Candidates for mandatory locking have the setgid bit set
+ * but no group execute bit - an otherwise meaningless combination.
+ */
+#define MANDATORY_LOCK(inode) \
+ (IS_MANDLOCK(inode) && ((inode)->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+
+static inline int locks_verify_locked(struct inode *inode)
+{
+ if (MANDATORY_LOCK(inode))
+ return locks_mandatory_locked(inode);
+ return 0;
+}
+
+static inline int locks_verify_area(int read_write, struct inode *inode,
+ struct file *filp, loff_t offset,
+ size_t count)
+{
+ if (inode->i_flock && MANDATORY_LOCK(inode))
+ return locks_mandatory_area(read_write, inode, filp, offset, count);
+ return 0;
+}
+
+static inline int locks_verify_truncate(struct inode *inode,
+ struct file *filp,
+ loff_t size)
+{
+ if (inode->i_flock && MANDATORY_LOCK(inode))
+ return locks_mandatory_area(
+ FLOCK_VERIFY_WRITE, inode, filp,
+ size < inode->i_size ? size : inode->i_size,
+ (size < inode->i_size ? inode->i_size - size
+ : size - inode->i_size)
+ );
+ return 0;
+}
+
+extern inline int get_lease(struct inode *inode, unsigned int mode)
+{
+ if (inode->i_flock && (inode->i_flock->fl_flags & FL_LEASE))
+ return __get_lease(inode, mode);
+ return 0;
+}
+
+/* fs/open.c */
+
+asmlinkage long sys_open(const char *, int, int);
+asmlinkage long sys_close(unsigned int); /* yes, it's really unsigned */
+extern int do_truncate(struct dentry *, loff_t start);
+
+extern struct file *filp_open(const char *, int, int);
+extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
+extern int filp_close(struct file *, fl_owner_t id);
+extern char * getname(const char *);
+
+/* fs/dcache.c */
+extern void vfs_caches_init(unsigned long);
+
+#define __getname() kmem_cache_alloc(names_cachep, SLAB_KERNEL)
+#define putname(name) kmem_cache_free(names_cachep, (void *)(name))
+
+enum {BDEV_FILE, BDEV_SWAP, BDEV_FS, BDEV_RAW};
+extern int register_blkdev(unsigned int, const char *, struct block_device_operations *);
+extern int unregister_blkdev(unsigned int, const char *);
+extern struct block_device *bdget(dev_t);
+extern void bdput(struct block_device *);
+extern struct char_device *cdget(dev_t);
+extern void cdput(struct char_device *);
+extern int blkdev_open(struct inode *, struct file *);
+extern struct file_operations def_blk_fops;
+extern struct file_operations def_fifo_fops;
+extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
+extern int blkdev_get(struct block_device *, mode_t, unsigned, int);
+extern int blkdev_put(struct block_device *, int);
+
+/* fs/devices.c */
+extern const struct block_device_operations *get_blkfops(unsigned int);
+extern int register_chrdev(unsigned int, const char *, struct file_operations *);
+extern int unregister_chrdev(unsigned int, const char *);
+extern int chrdev_open(struct inode *, struct file *);
+extern const char * bdevname(kdev_t);
+extern const char * cdevname(kdev_t);
+extern const char * kdevname(kdev_t);
+extern void init_special_inode(struct inode *, umode_t, int);
+
+/* Invalid inode operations -- fs/bad_inode.c */
+extern void make_bad_inode(struct inode *);
+extern int is_bad_inode(struct inode *);
+
+extern struct file_operations read_fifo_fops;
+extern struct file_operations write_fifo_fops;
+extern struct file_operations rdwr_fifo_fops;
+extern struct file_operations read_pipe_fops;
+extern struct file_operations write_pipe_fops;
+extern struct file_operations rdwr_pipe_fops;
+
+extern int fs_may_remount_ro(struct super_block *);
+
+extern int try_to_free_buffers(struct page *, int);
+extern void refile_buffer(struct buffer_head * buf);
+
+/* reiserfs_writepage needs this */
+extern void set_buffer_async_io(struct buffer_head *bh) ;
+
+#define BUF_CLEAN 0
+#define BUF_LOCKED 1 /* Buffers scheduled for write */
+#define BUF_DIRTY 2 /* Dirty buffers, not yet scheduled for write */
+#define BUF_PROTECTED 3 /* Ramdisk persistent storage */
+#define NR_LIST 4
+
+/*
+ * This is called by bh->b_end_io() handlers when I/O has completed.
+ */
+static inline void mark_buffer_uptodate(struct buffer_head * bh, int on)
+{
+ if (on)
+ set_bit(BH_Uptodate, &bh->b_state);
+ else
+ clear_bit(BH_Uptodate, &bh->b_state);
+}
+
+#define atomic_set_buffer_clean(bh) test_and_clear_bit(BH_Dirty, &(bh)->b_state)
+
+static inline void __mark_buffer_clean(struct buffer_head *bh)
+{
+ refile_buffer(bh);
+}
+
+static inline void mark_buffer_clean(struct buffer_head * bh)
+{
+ if (atomic_set_buffer_clean(bh))
+ __mark_buffer_clean(bh);
+}
+
+#define atomic_set_buffer_protected(bh) test_and_set_bit(BH_Protected, &(bh)->b_state)
+
+static inline void __mark_buffer_protected(struct buffer_head *bh)
+{
+ refile_buffer(bh);
+}
+
+static inline void mark_buffer_protected(struct buffer_head * bh)
+{
+ if (!atomic_set_buffer_protected(bh))
+ __mark_buffer_protected(bh);
+}
+
+extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh));
+extern void FASTCALL(mark_buffer_dirty(struct buffer_head *bh));
+
+#define atomic_set_buffer_dirty(bh) test_and_set_bit(BH_Dirty, &(bh)->b_state)
+
+/*
+ * If an error happens during the make_request, this function
+ * has to be recalled. It marks the buffer as clean and not
+ * uptodate, and it notifys the upper layer about the end
+ * of the I/O.
+ */
+static inline void buffer_IO_error(struct buffer_head * bh)
+{
+ mark_buffer_clean(bh);
+ /*
+ * b_end_io has to clear the BH_Uptodate bitflag in the error case!
+ */
+ bh->b_end_io(bh, 0);
+}
+
+extern void buffer_insert_inode_queue(struct buffer_head *, struct inode *);
+static inline void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode)
+{
+ mark_buffer_dirty(bh);
+ buffer_insert_inode_queue(bh, inode);
+}
+
+extern void balance_dirty(kdev_t);
+extern int check_disk_change(kdev_t);
+extern int invalidate_inodes(struct super_block *);
+extern int invalidate_device(kdev_t, int);
+extern void invalidate_inode_pages(struct inode *);
+extern void invalidate_inode_buffers(struct inode *);
+#define invalidate_buffers(dev) __invalidate_buffers((dev), 0)
+#define destroy_buffers(dev) __invalidate_buffers((dev), 1)
+extern void __invalidate_buffers(kdev_t dev, int);
+extern void sync_inodes(kdev_t);
+extern void sync_unlocked_inodes(void);
+extern void write_inode_now(struct inode *, int);
+extern void sync_dev(kdev_t);
+extern int fsync_dev(kdev_t);
+extern int fsync_super(struct super_block *);
+extern void sync_inodes_sb(struct super_block *);
+extern int fsync_inode_buffers(struct inode *);
+extern int osync_inode_buffers(struct inode *);
+extern int inode_has_buffers(struct inode *);
+extern void filemap_fdatasync(struct address_space *);
+extern void filemap_fdatawait(struct address_space *);
+extern void sync_supers(kdev_t);
+extern int bmap(struct inode *, int);
+extern int notify_change(struct dentry *, struct iattr *);
+extern int permission(struct inode *, int);
+extern int vfs_permission(struct inode *, int);
+extern int get_write_access(struct inode *);
+extern int deny_write_access(struct file *);
+static inline void put_write_access(struct inode * inode)
+{
+ atomic_dec(&inode->i_writecount);
+}
+static inline void allow_write_access(struct file *file)
+{
+ if (file)
+ atomic_inc(&file->f_dentry->d_inode->i_writecount);
+}
+extern int do_pipe(int *);
+
+extern int open_namei(const char *, int, int, struct nameidata *);
+
+extern int kernel_read(struct file *, unsigned long, char *, unsigned long);
+extern struct file * open_exec(const char *);
+
+/* fs/dcache.c -- generic fs support functions */
+extern int is_subdir(struct dentry *, struct dentry *);
+extern ino_t find_inode_number(struct dentry *, struct qstr *);
+
+/*
+ * Kernel pointers have redundant information, so we can use a
+ * scheme where we can return either an error code or a dentry
+ * pointer with the same return value.
+ *
+ * This should be a per-architecture thing, to allow different
+ * error and pointer decisions.
+ */
+static inline void *ERR_PTR(long error)
+{
+ return (void *) error;
+}
+
+static inline long PTR_ERR(const void *ptr)
+{
+ return (long) ptr;
+}
+
+static inline long IS_ERR(const void *ptr)
+{
+ return (unsigned long)ptr > (unsigned long)-1000L;
+}
+
+/*
+ * The bitmask for a lookup event:
+ * - follow links at the end
+ * - require a directory
+ * - ending slashes ok even for nonexistent files
+ * - internal "there are more path compnents" flag
+ */
+#define LOOKUP_FOLLOW (1)
+#define LOOKUP_DIRECTORY (2)
+#define LOOKUP_CONTINUE (4)
+#define LOOKUP_POSITIVE (8)
+#define LOOKUP_PARENT (16)
+#define LOOKUP_NOALT (32)
+/*
+ * Type of the last component on LOOKUP_PARENT
+ */
+enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
+
+/*
+ * "descriptor" for what we're up to with a read for sendfile().
+ * This allows us to use the same read code yet
+ * have multiple different users of the data that
+ * we read from a file.
+ *
+ * The simplest case just copies the data to user
+ * mode.
+ */
+typedef struct {
+ size_t written;
+ size_t count;
+ char * buf;
+ int error;
+} read_descriptor_t;
+
+typedef int (*read_actor_t)(read_descriptor_t *, struct page *, unsigned long, unsigned long);
+
+/* needed for stackable file system support */
+extern loff_t default_llseek(struct file *file, loff_t offset, int origin);
+
+extern int __user_walk(const char *, unsigned, struct nameidata *);
+extern int path_init(const char *, unsigned, struct nameidata *);
+extern int path_walk(const char *, struct nameidata *);
+extern void path_release(struct nameidata *);
+extern int follow_down(struct vfsmount **, struct dentry **);
+extern int follow_up(struct vfsmount **, struct dentry **);
+extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
+extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
+#define user_path_walk(name,nd) __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
+#define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
+
+extern void iput(struct inode *);
+extern void force_delete(struct inode *);
+extern struct inode * igrab(struct inode *);
+extern ino_t iunique(struct super_block *, ino_t);
+
+typedef int (*find_inode_t)(struct inode *, unsigned long, void *);
+extern struct inode * iget4(struct super_block *, unsigned long, find_inode_t, void *);
+static inline struct inode *iget(struct super_block *sb, unsigned long ino)
+{
+ return iget4(sb, ino, NULL, NULL);
+}
+
+extern void clear_inode(struct inode *);
+extern struct inode * get_empty_inode(void);
+static inline struct inode * new_inode(struct super_block *sb)
+{
+ struct inode *inode = get_empty_inode();
+ if (inode) {
+ inode->i_sb = sb;
+ inode->i_dev = sb->s_dev;
+ }
+ return inode;
+}
+extern void remove_suid(struct inode *inode);
+
+extern void insert_inode_hash(struct inode *);
+extern void remove_inode_hash(struct inode *);
+extern struct file * get_empty_filp(void);
+extern void file_move(struct file *f, struct list_head *list);
+extern void file_moveto(struct file *new, struct file *old);
+extern struct buffer_head * get_hash_table(kdev_t, int, int);
+extern struct buffer_head * getblk(kdev_t, int, int);
+extern void ll_rw_block(int, int, struct buffer_head * bh[]);
+extern void submit_bh(int, struct buffer_head *);
+extern int is_read_only(kdev_t);
+extern void __brelse(struct buffer_head *);
+static inline void brelse(struct buffer_head *buf)
+{
+ if (buf)
+ __brelse(buf);
+}
+extern void __bforget(struct buffer_head *);
+static inline void bforget(struct buffer_head *buf)
+{
+ if (buf)
+ __bforget(buf);
+}
+extern void set_blocksize(kdev_t, int);
+extern struct buffer_head * bread(kdev_t, int, int);
+extern void wakeup_bdflush(int wait);
+
+extern int brw_page(int, struct page *, kdev_t, int [], int);
+
+typedef int (get_block_t)(struct inode*,long,struct buffer_head*,int);
+
+/* Generic buffer handling for block filesystems.. */
+extern int block_flushpage(struct page *, unsigned long);
+extern int block_symlink(struct inode *, const char *, int);
+extern int block_write_full_page(struct page*, get_block_t*);
+extern int block_read_full_page(struct page*, get_block_t*);
+extern int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
+extern int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*,
+ unsigned long *);
+extern int block_sync_page(struct page *);
+
+int generic_block_bmap(struct address_space *, long, get_block_t *);
+int generic_commit_write(struct file *, struct page *, unsigned, unsigned);
+int block_truncate_page(struct address_space *, loff_t, get_block_t *);
+
+extern int waitfor_one_page(struct page*);
+extern int generic_file_mmap(struct file *, struct vm_area_struct *);
+extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
+extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
+extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *);
+extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t);
+
+extern ssize_t generic_read_dir(struct file *, char *, size_t, loff_t *);
+
+extern struct file_operations generic_ro_fops;
+
+extern int vfs_readlink(struct dentry *, char *, int, const char *);
+extern int vfs_follow_link(struct nameidata *, const char *);
+extern int page_readlink(struct dentry *, char *, int);
+extern int page_follow_link(struct dentry *, struct nameidata *);
+extern struct inode_operations page_symlink_inode_operations;
+
+extern int vfs_readdir(struct file *, filldir_t, void *);
+extern int dcache_readdir(struct file *, void *, filldir_t);
+
+extern struct file_system_type *get_fs_type(const char *name);
+extern struct super_block *get_super(kdev_t);
+extern void put_super(kdev_t);
+static inline int is_mounted(kdev_t dev)
+{
+ struct super_block *sb = get_super(dev);
+ if (sb) {
+ /* drop_super(sb); will go here */
+ return 1;
+ }
+ return 0;
+}
+unsigned long generate_cluster(kdev_t, int b[], int);
+unsigned long generate_cluster_swab32(kdev_t, int b[], int);
+extern kdev_t ROOT_DEV;
+extern char root_device_name[];
+
+
+extern void show_buffers(void);
+extern void mount_root(void);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+extern kdev_t real_root_dev;
+extern int change_root(kdev_t, const char *);
+#endif
+
+extern ssize_t char_read(struct file *, char *, size_t, loff_t *);
+extern ssize_t block_read(struct file *, char *, size_t, loff_t *);
+extern int read_ahead[];
+
+extern ssize_t char_write(struct file *, const char *, size_t, loff_t *);
+extern ssize_t block_write(struct file *, const char *, size_t, loff_t *);
+
+extern int file_fsync(struct file *, struct dentry *, int);
+extern int generic_buffer_fdatasync(struct inode *inode, unsigned long start_idx, unsigned long end_idx);
+extern int generic_osync_inode(struct inode *, int);
+
+extern int inode_change_ok(struct inode *, struct iattr *);
+extern void inode_setattr(struct inode *, struct iattr *);
+
+/*
+ * Common dentry functions for inclusion in the VFS
+ * or in other stackable file systems. Some of these
+ * functions were in linux/fs/ C (VFS) files.
+ *
+ */
+
+/*
+ * Locking the parent is needed to:
+ * - serialize directory operations
+ * - make sure the parent doesn't change from
+ * under us in the middle of an operation.
+ *
+ * NOTE! Right now we'd rather use a "struct inode"
+ * for this, but as I expect things to move toward
+ * using dentries instead for most things it is
+ * probably better to start with the conceptually
+ * better interface of relying on a path of dentries.
+ */
+static inline struct dentry *lock_parent(struct dentry *dentry)
+{
+ struct dentry *dir = dget(dentry->d_parent);
+
+ down(&dir->d_inode->i_sem);
+ return dir;
+}
+
+static inline struct dentry *get_parent(struct dentry *dentry)
+{
+ return dget(dentry->d_parent);
+}
+
+static inline void unlock_dir(struct dentry *dir)
+{
+ up(&dir->d_inode->i_sem);
+ dput(dir);
+}
+
+/*
+ * Whee.. Deadlock country. Happily there are only two VFS
+ * operations that does this..
+ */
+static inline void double_down(struct semaphore *s1, struct semaphore *s2)
+{
+ if (s1 != s2) {
+ if ((unsigned long) s1 < (unsigned long) s2) {
+ struct semaphore *tmp = s2;
+ s2 = s1; s1 = tmp;
+ }
+ down(s1);
+ }
+ down(s2);
+}
+
+/*
+ * Ewwwwwwww... _triple_ lock. We are guaranteed that the 3rd argument is
+ * not equal to 1st and not equal to 2nd - the first case (target is parent of
+ * source) would be already caught, the second is plain impossible (target is
+ * its own parent and that case would be caught even earlier). Very messy.
+ * I _think_ that it works, but no warranties - please, look it through.
+ * Pox on bloody lusers who mandated overwriting rename() for directories...
+ */
+
+static inline void triple_down(struct semaphore *s1,
+ struct semaphore *s2,
+ struct semaphore *s3)
+{
+ if (s1 != s2) {
+ if ((unsigned long) s1 < (unsigned long) s2) {
+ if ((unsigned long) s1 < (unsigned long) s3) {
+ struct semaphore *tmp = s3;
+ s3 = s1; s1 = tmp;
+ }
+ if ((unsigned long) s1 < (unsigned long) s2) {
+ struct semaphore *tmp = s2;
+ s2 = s1; s1 = tmp;
+ }
+ } else {
+ if ((unsigned long) s1 < (unsigned long) s3) {
+ struct semaphore *tmp = s3;
+ s3 = s1; s1 = tmp;
+ }
+ if ((unsigned long) s2 < (unsigned long) s3) {
+ struct semaphore *tmp = s3;
+ s3 = s2; s2 = tmp;
+ }
+ }
+ down(s1);
+ } else if ((unsigned long) s2 < (unsigned long) s3) {
+ struct semaphore *tmp = s3;
+ s3 = s2; s2 = tmp;
+ }
+ down(s2);
+ down(s3);
+}
+
+static inline void double_up(struct semaphore *s1, struct semaphore *s2)
+{
+ up(s1);
+ if (s1 != s2)
+ up(s2);
+}
+
+static inline void triple_up(struct semaphore *s1,
+ struct semaphore *s2,
+ struct semaphore *s3)
+{
+ up(s1);
+ if (s1 != s2)
+ up(s2);
+ up(s3);
+}
+
+static inline void double_lock(struct dentry *d1, struct dentry *d2)
+{
+ double_down(&d1->d_inode->i_sem, &d2->d_inode->i_sem);
+}
+
+static inline void double_unlock(struct dentry *d1, struct dentry *d2)
+{
+ double_up(&d1->d_inode->i_sem,&d2->d_inode->i_sem);
+ dput(d1);
+ dput(d2);
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_FS_H */
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 "fs/localfs.h"
+
+/*
+ * LocalFS is just a shim layer on top of the
+ * FileSystem Protocol which gives access to FAT32,16,12
+ */
+#define FS_NAME L"vfat"
+
+
+typedef struct {
+ EFI_HANDLE dev; /* device we're attached to */
+ EFI_FILE_HANDLE volume; /* root of volume */
+} localfs_priv_state_t;
+
+#define LOCALFS_F2FD(f) ((UINTN)(f))
+#define LOCALFS_FD2F(fd) ((EFI_FILE_HANDLE)(fd))
+
+typedef union {
+ localfs_interface_t pub_intf;
+ struct {
+ localfs_interface_t pub_intf;
+ localfs_priv_state_t priv_data;
+ } localfs_priv;
+} localfs_t;
+
+#define FS_PRIVATE(n) (&(((localfs_t *)n)->localfs_priv.priv_data))
+
+
+static EFI_GUID LocalFsProtocol = LOCALFS_PROTOCOL;
+
+/*
+ * let's be clean here
+ */
+typedef union {
+ EFI_HANDLE *dev;
+ localfs_t *intf;
+} dev_tab_t;
+
+static dev_tab_t *dev_tab; /* holds all devices we found */
+static UINTN ndev; /* how many entries in dev_tab */
+
+static EFI_STATUS
+localfs_name(localfs_interface_t *this, CHAR16 *name, UINTN maxlen)
+{
+ if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER;
+
+ StrnCpy(name, FS_NAME, maxlen-1);
+
+ name[maxlen-1] = CHAR_NULL;
+
+ return EFI_SUCCESS;
+}
+
+
+static EFI_STATUS
+localfs_open(localfs_interface_t *this, CHAR16 *name, UINTN *fd)
+{
+ localfs_priv_state_t *lfs;
+ EFI_STATUS status;
+ EFI_FILE_HANDLE fh;
+
+ if (this == NULL || name == NULL || fd == NULL) return EFI_INVALID_PARAMETER;
+
+ lfs = FS_PRIVATE(this);
+
+ DBG_PRT((L"localfs_open on %s\n", name));
+
+ status = lfs->volume->Open(lfs->volume, &fh, name, EFI_FILE_MODE_READ, 0);
+ if (status == EFI_SUCCESS) {
+ *fd = LOCALFS_F2FD(fh);
+ }
+ return status;
+}
+
+static EFI_STATUS
+localfs_read(localfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size)
+{
+ localfs_priv_state_t *lfs;
+
+ if (this == NULL || fd == 0 || buf == NULL || size == NULL) return EFI_INVALID_PARAMETER;
+
+ lfs = FS_PRIVATE(this);
+
+ return lfs->volume->Read(LOCALFS_FD2F(fd), size, buf);
+}
+
+static EFI_STATUS
+localfs_close(localfs_interface_t *this, UINTN fd)
+{
+ localfs_priv_state_t *lfs;
+
+ if (this == NULL || fd == 0) return EFI_INVALID_PARAMETER;
+
+ lfs = FS_PRIVATE(this);
+
+ return lfs->volume->Close(LOCALFS_FD2F(fd));
+}
+
+static EFI_STATUS
+localfs_infosize(localfs_interface_t *this, UINTN fd, UINT64 *sz)
+{
+ localfs_priv_state_t *lfs;
+ EFI_FILE_INFO *info;
+
+ if (this == NULL || fd == 0 || sz == NULL) return EFI_INVALID_PARAMETER;
+
+ lfs = FS_PRIVATE(this);
+
+ info = LibFileInfo(LOCALFS_FD2F(fd));
+ if (info == NULL) return EFI_UNSUPPORTED;
+
+ *sz = info->FileSize;
+
+ FreePool(info);
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS
+localfs_seek(localfs_interface_t *this, UINTN fd, UINT64 newpos)
+{
+ localfs_priv_state_t *lfs;
+
+ if (this == NULL || fd == 0) return EFI_INVALID_PARAMETER;
+
+ lfs = FS_PRIVATE(this);
+
+ return lfs->volume->SetPosition(LOCALFS_FD2F(fd), newpos);
+}
+
+static VOID
+localfs_init_state(localfs_t *localfs, EFI_HANDLE dev, EFI_FILE_HANDLE volume)
+{
+ localfs_priv_state_t *lfs = FS_PRIVATE(localfs);
+
+ /* need to do some init here on localfs_intf */
+ Memset(localfs, 0, sizeof(*localfs));
+
+ localfs->pub_intf.localfs_name = localfs_name;
+ localfs->pub_intf.localfs_open = localfs_open;
+ localfs->pub_intf.localfs_read = localfs_read;
+ localfs->pub_intf.localfs_close = localfs_close;
+ localfs->pub_intf.localfs_infosize = localfs_infosize;
+ localfs->pub_intf.localfs_seek = localfs_seek;
+
+ lfs->dev = dev;
+ lfs->volume = volume;
+}
+
+static EFI_STATUS
+localfs_install_one(EFI_HANDLE dev, VOID **intf)
+{
+
+ EFI_STATUS status;
+ localfs_t *localfs;
+ EFI_FILE_IO_INTERFACE *volume;
+ EFI_FILE_HANDLE volume_fh;
+
+ status = BS->HandleProtocol (dev, &LocalFsProtocol, (VOID **)&localfs);
+ if (status == EFI_SUCCESS) {
+ ERR_PRT((L"Warning: found existing %s protocol on device", FS_NAME));
+ goto found;
+ }
+
+ status = BS->HandleProtocol (dev, &FileSystemProtocol, (VOID **)&volume);
+ if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER;
+
+ status = volume->OpenVolume(volume, &volume_fh);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"cannot open volume"));
+ return status;
+ }
+
+ localfs = (localfs_t *)alloc(sizeof(*localfs), EfiLoaderData);
+ if (localfs == NULL) {
+ ERR_PRT((L"failed to allocate %s", FS_NAME));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ localfs_init_state(localfs, dev, volume_fh);
+
+ status = LibInstallProtocolInterfaces(&dev, &LocalFsProtocol, localfs, NULL);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"Cannot install %s protocol: %r", FS_NAME, status));
+ free(localfs);
+ return status;
+ }
+found:
+ if (intf) *intf = (VOID *)localfs;
+
+ VERB_PRT(3,
+ { EFI_DEVICE_PATH *dp; CHAR16 *str;
+ dp = DevicePathFromHandle(dev);
+ str = DevicePathToStr(dp);
+ Print(L"attached %s to %s\n", FS_NAME, str);
+ FreePool(str);
+ });
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+localfs_install(VOID)
+{
+ UINTN size = 0;
+ UINTN i;
+ EFI_STATUS status;
+ VOID *intf;
+
+ BS->LocateHandle(ByProtocol, &FileSystemProtocol, NULL, &size, NULL);
+ if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */
+
+ DBG_PRT((L"size=%d", size));
+
+ dev_tab = (dev_tab_t *)alloc(size, EfiLoaderData);
+ if (dev_tab == NULL) {
+ ERR_PRT((L"failed to allocate handle table"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ status = BS->LocateHandle(ByProtocol, &FileSystemProtocol, NULL, &size, (VOID **)dev_tab);
+ if (status != EFI_SUCCESS) {
+ ERR_PRT((L"failed to get handles: %r", status));
+ free(dev_tab);
+ return status;
+ }
+ ndev = size / sizeof(EFI_HANDLE);
+
+ for(i=0; i < ndev; i++) {
+ intf = NULL;
+ localfs_install_one(dev_tab[i].dev, &intf);
+ /* override device handle with interface pointer */
+ dev_tab[i].intf = intf;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+localfs_uninstall(VOID)
+{
+
+ localfs_priv_state_t *lfs;
+ EFI_STATUS status;
+ UINTN i;
+
+ for(i=0; i < ndev; i++) {
+ if (dev_tab[i].intf == NULL) continue;
+ lfs = FS_PRIVATE(dev_tab[i].intf);
+ status = BS->UninstallProtocolInterface(lfs->dev, &LocalFsProtocol, dev_tab[i].intf);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status));
+ continue;
+ }
+ VERB_PRT(3,
+ { EFI_DEVICE_PATH *dp; CHAR16 *str;
+ dp = DevicePathFromHandle(lfs->dev);
+ str = DevicePathToStr(dp);
+ Print(L"uninstalled %s on %s\n", FS_NAME, str);
+ FreePool(str);
+ });
+ free(dev_tab[i].intf);
+ }
+ if (dev_tab) free(dev_tab);
+
+ return EFI_SUCCESS;
+}
+
+
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 __LOCALFS_H__
+#define __LOCALFS_H__
+
+INTERFACE_DECL(_localfs_interface_t);
+
+typedef struct _localfs_interface_t {
+ EFI_STATUS (*localfs_name)(struct _localfs_interface_t *this, CHAR16 *name, UINTN maxlen);
+ EFI_STATUS (*localfs_open)(struct _localfs_interface_t *this, CHAR16 *name, UINTN *fd);
+ EFI_STATUS (*localfs_read)(struct _localfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size);
+ EFI_STATUS (*localfs_close)(struct _localfs_interface_t *this, UINTN fd);
+ EFI_STATUS (*localfs_infosize)(struct _localfs_interface_t *this, UINTN fd, UINT64 *size);
+ EFI_STATUS (*localfs_seek)(struct _localfs_interface_t *this, UINTN fd, UINT64 newpos);
+} localfs_interface_t;
+
+#define LOCALFS_PROTOCOL \
+ { 0x3a42ff5d, 0x43c9, 0x4db8, {0x82, 0x4e, 0xb8, 0x5b, 0xab, 0x97, 0x63, 0xcc} }
+
+extern EFI_STATUS localfs_install(VOID);
+extern EFI_STATUS localfs_uninstall(VOID);
+
+#endif /* __LOCALFS_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 "fs/netfs.h"
+
+#include "elilo.h"
+
+#define FS_NAME L"netfs"
+
+#define NETFS_DEFAULT_BUFSIZE 16*MB
+#define NETFS_DEFAULT_BUFSIZE_INC 8*MB
+
+#define NETFS_DEFAULT_SERVER_TYPE EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP
+#define NETFS_FD_MAX 2
+
+typedef struct _netfs_fd {
+ struct _netfs_fd *next;
+
+ CHAR8 *netbuf;
+ UINT64 netbuf_maxsize; /* currently allocated buffer */
+ UINTN netbuf_size; /* number of bytes currently used in the buffer */
+ UINT64 netbuf_pos; /* current position in the buffer */
+ BOOLEAN is_valid; /* avoid conflicting opens */
+ BOOLEAN netbuf_reuse;
+
+ CHAR16 last_file[FILENAME_MAXLEN];
+} netfs_fd_t;
+
+
+typedef struct {
+ EFI_PXE_BASE_CODE *pxe;
+ EFI_HANDLE dev; /* handle to device we're attached to */
+ BOOLEAN using_pxe; /* true if downloaded using the PXE protocol vs. regular DHCP */
+
+ EFI_IP_ADDRESS srv_ip;
+ EFI_IP_ADDRESS cln_ip;
+ EFI_IP_ADDRESS gw_ip;
+ EFI_IP_ADDRESS netmask;
+ UINT8 hw_addr[16];
+
+ netfs_fd_t fd_tab[NETFS_FD_MAX];
+ netfs_fd_t *free_fd;
+ UINTN free_fd_count;
+
+} netfs_priv_state_t;
+
+#define NETFS_F2FD(l,f) (UINTN)((f)-(l)->fd_tab)
+#define NETFS_FD2F(l,fd) ((l)->fd_tab+fd)
+#define NETFS_F_INVALID(f) ((f)->is_valid == FALSE)
+
+
+typedef union {
+ netfs_interface_t pub_intf;
+ struct {
+ netfs_interface_t pub_intf;
+ netfs_priv_state_t priv_data;
+ } netfs_priv;
+} netfs_t;
+
+#define FS_PRIVATE(n) (&(((netfs_t *)n)->netfs_priv.priv_data))
+
+typedef union {
+ EFI_HANDLE *dev;
+ netfs_t *intf;
+} dev_tab_t;
+
+static dev_tab_t *dev_tab; /* holds all devices we found */
+static UINTN ndev; /* how many entries in dev_tab */
+
+static EFI_GUID NetFsProtocol = NETFS_PROTOCOL;
+
+
+#if 0
+static EFI_PXE_BASE_CODE_CALLBACK_STATUS
+netfs_callback_func(
+ IN EFI_PXE_BASE_CODE_CALLBACK *this,
+ IN EFI_PXE_BASE_CODE_FUNCTION function,
+ IN BOOLEAN received,
+ IN UINT32 packet_len,
+ IN EFI_PXE_BASE_CODE_PACKET *packet OPTIONAL
+)
+{
+ Print(L"netfs_callback called received=%d packet_len=%d\n", received, packet_len);
+ return EFI_ABORTED;
+}
+
+static EFI_PXE_BASE_CODE_CALLBACK netfs_callback = {
+ EFI_PXE_BASE_CODE_CALLBACK_INTERFACE_REVISION,
+ &netfs_callback_func
+};
+#endif
+
+static netfs_fd_t *
+netfs_fd_alloc(netfs_priv_state_t *nfs, CHAR16 *name)
+{
+ netfs_fd_t *tmp = NULL, *prev = NULL, *match;
+ UINT8 netbuf_reuse = 0;
+
+ if (nfs->free_fd == NULL) {
+ ERR_PRT((L"out of file descriptor"));
+ return NULL;
+ }
+ match = nfs->free_fd;
+ for (tmp = nfs->free_fd; tmp; tmp = tmp->next) {
+ if (!StrCmp(name, tmp->last_file)) {
+ DBG_PRT((L"Using cached file %s netbuf_size=%d", tmp->last_file, tmp->netbuf_size));
+ netbuf_reuse = 1;
+ match = tmp;
+ break;
+ }
+ prev = tmp;
+ }
+ /* indicate whether or not we got a match in caching */
+ match->netbuf_reuse = netbuf_reuse;
+
+ if (match == nfs->free_fd)
+ nfs->free_fd = match->next;
+ else
+ prev->next = match->next;
+
+ nfs->free_fd_count--;
+
+ return match;
+}
+
+static VOID
+netfs_fd_free(netfs_priv_state_t *nfs, netfs_fd_t *f)
+{
+ if (f == NULL) {
+ ERR_PRT((L"invalid fd"));
+ return;
+ }
+ f->next = nfs->free_fd;
+
+ /* we keep the netbuf, in case we can reuse it */
+ f->is_valid = FALSE;
+
+ nfs->free_fd = f;
+ nfs->free_fd_count++;
+
+ if (nfs->free_fd_count > NETFS_FD_MAX) {
+ ERR_PRT((L"too many free descriptors %d", nfs->free_fd_count));
+ }
+}
+
+
+static INTN
+netbuf_alloc(netfs_fd_t *f)
+{
+ /* we will try to reuse the existing buffer first */
+ if (f->netbuf != 0) return 0;
+
+ f->netbuf_pos = 0;
+
+ f->netbuf = (CHAR8 *)alloc_pages(EFI_SIZE_TO_PAGES(f->netbuf_maxsize), EfiLoaderData, AllocateAnyPages, 0);
+
+ return f->netbuf == 0 ? -1 : 0;
+}
+
+static EFI_STATUS
+netfs_name(netfs_interface_t *this, CHAR16 *name, UINTN maxlen)
+{
+ if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER;
+
+ StrnCpy(name, FS_NAME, maxlen-1);
+
+ name[maxlen-1] = CHAR_NULL;
+
+ return EFI_SUCCESS;
+}
+
+static VOID
+netfs_extract_ip(netfs_priv_state_t *nfs)
+{
+ EFI_PXE_BASE_CODE *pxe = nfs->pxe;
+
+ if (pxe->Mode->PxeDiscoverValid) {
+ nfs->using_pxe = TRUE;
+ Memcpy(&nfs->srv_ip, pxe->Mode->PxeReply.Dhcpv4.BootpSiAddr, sizeof(EFI_IP_ADDRESS));
+ Memcpy(&nfs->hw_addr, pxe->Mode->PxeReply.Dhcpv4.BootpHwAddr, 16*sizeof(UINT8));
+ } 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));
+ }
+
+ Memcpy(&nfs->cln_ip, &pxe->Mode->StationIp, sizeof(EFI_IP_ADDRESS));
+ Memcpy(&nfs->netmask, &pxe->Mode->SubnetMask, sizeof(EFI_IP_ADDRESS));
+
+ /*
+ * the fact that we use index 0, is just a guess
+ */
+ 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)"));
+#if 0
+ status = BS->HandleProtocol(dev, &PxeCallbackProtocol, (VOID **)&netfs_callback);
+ status = LibInstallProtocolInterfaces(&dev, &PxeCallbackProtocol, &netfs_callback, NULL);
+ Print(L"PXE Callback support : %r\n", status);
+ if (status == EFI_SUCCESS) {
+ BOOLEAN doit = TRUE;
+ status = pxe->SetParameters(pxe, NULL, NULL, NULL, NULL, &doit);
+ Print(L"PXE Callback SetParameters: %r\n", status);
+ }
+#endif
+ /*
+ * XXX: TFTPD server not quite right when using PXE, need to extract bootservers...
+ */
+ VERB_PRT(1, Print(L"Local IP: %d.%d.%d.%d\n",
+ pxe->Mode->StationIp.v4.Addr[0] & 0xff,
+ pxe->Mode->StationIp.v4.Addr[1] & 0xff,
+ pxe->Mode->StationIp.v4.Addr[2] & 0xff,
+ pxe->Mode->StationIp.v4.Addr[3] & 0xff));
+
+ VERB_PRT(1, Print(L"SM: %d.%d.%d.%d\n",
+ pxe->Mode->SubnetMask.v4.Addr[0] & 0xff,
+ pxe->Mode->SubnetMask.v4.Addr[1] & 0xff,
+ pxe->Mode->SubnetMask.v4.Addr[2] & 0xff,
+ pxe->Mode->SubnetMask.v4.Addr[3] & 0xff));
+
+ VERB_PRT(1, Print(L"TFTPD IP: %d.%d.%d.%d\n",
+ nfs->srv_ip.v4.Addr[0] & 0xff,
+ nfs->srv_ip.v4.Addr[1] & 0xff,
+ nfs->srv_ip.v4.Addr[2] & 0xff,
+ nfs->srv_ip.v4.Addr[3] & 0xff));
+
+ VERB_PRT(1, Print(L"Gateway IP: %d.%d.%d.%d\n",
+ nfs->gw_ip.v4.Addr[0] & 0xff,
+ nfs->gw_ip.v4.Addr[1] & 0xff,
+ nfs->gw_ip.v4.Addr[2] & 0xff,
+ nfs->gw_ip.v4.Addr[3] & 0xff));
+
+}
+
+static EFI_STATUS
+netfs_start(EFI_PXE_BASE_CODE *pxe)
+{
+ EFI_STATUS status;
+
+ status = pxe->Start(pxe, FALSE);
+ if (EFI_ERROR(status)) return status;
+
+ return pxe->Dhcp(pxe, FALSE);
+}
+
+static EFI_STATUS
+netfs_open(netfs_interface_t *this, CHAR16 *name, UINTN *fd)
+{
+ netfs_priv_state_t *nfs;
+ netfs_fd_t *f;
+ EFI_STATUS status;
+ CHAR8 ascii_name[FILENAME_MAXLEN];
+ UINTN blocksize = 0, prev_netbufsize;
+
+ if (this == NULL || name == NULL || fd == NULL) return EFI_INVALID_PARAMETER;
+
+ nfs = FS_PRIVATE(this);
+
+ if (nfs->pxe == NULL) return EFI_INVALID_PARAMETER;
+
+ /*
+ * Try to start protocol if not already active
+ */
+ if (nfs->pxe->Mode->Started == FALSE) {
+ status = netfs_start(nfs->pxe);
+ if (EFI_ERROR(status)) return status;
+ netfs_extract_ip(nfs);
+ }
+
+ if ((f=netfs_fd_alloc(nfs, name)) == NULL) return EFI_OUT_OF_RESOURCES;
+
+ if (f->netbuf_reuse) {
+ f->netbuf_pos = 0;
+ f->is_valid = TRUE;
+ *fd = NETFS_F2FD(nfs, f);
+ return EFI_SUCCESS;
+ }
+ f->netbuf_maxsize = NETFS_DEFAULT_BUFSIZE;
+
+ if (f->netbuf == NULL && netbuf_alloc(f) == -1) {
+ netfs_fd_free(nfs, f);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ /* well, we need to download ! */
+
+ U2ascii(name, ascii_name, FILENAME_MAXLEN);
+
+ VERB_PRT(2, Print(L"downloading %a from %d.%d.%d.%d...", 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:0x%lx netbuf_size=%ld\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.
+ */
+ prev_netbufsize = f->netbuf_size;
+
+ status = nfs->pxe->Mtftp(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);
+
+ DBG_PRT((L"after Mftp=%r netbuf:0x%lx netbuf_size=%ld blocksize=%ld\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 the TFTP server supports TFTP options, then we should
+ * get the required size. So we test to see if the size
+ * we set has changed. If so, we got the required size.
+ * If not, we increase the buffer size and retry.
+ */
+ if (f->netbuf_size == prev_netbufsize) {
+ f->netbuf_maxsize += NETFS_DEFAULT_BUFSIZE_INC;
+ } else {
+ /* we got an answer from the TFTP server, let's try it */
+ f->netbuf_maxsize = f->netbuf_size;
+ }
+ free(f->netbuf);
+
+ f->netbuf = NULL; /* will force reallocation */
+
+ if (netbuf_alloc(f) == 0) goto retry;
+
+ /* fall through in case of error */
+ }
+
+ if (status == EFI_SUCCESS) {
+ /* start at the beginning of the file */
+ f->netbuf_pos = 0;
+
+ /* cache file name */
+ StrCpy(f->last_file, name);
+
+ f->is_valid = 1;
+
+ *fd = NETFS_F2FD(nfs, f);
+ VERB_PRT(2, Print(L"Done\n"));
+ } else {
+ netfs_fd_free(nfs, f);
+ VERB_PRT(2, Print(L"Failed: %r\n", status));
+ }
+ DBG_PRT((L"File %s netbuf_size=%d: %r", name, f->netbuf_size, status));
+#if 0
+ Print(L"\n---\n");
+ { INTN i;
+ for(i=0; i < netbuf_size; i++) {
+ Print(L"%c", (CHAR16)netbuf[i]);
+ }
+ }
+ Print(L"\n---\n");
+#endif
+ return status;
+}
+
+
+static EFI_STATUS
+netfs_read(netfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size)
+{
+ netfs_priv_state_t *nfs;
+ netfs_fd_t *f;
+ UINTN count;
+
+ if (this == NULL || fd >= NETFS_FD_MAX || buf == NULL || size == NULL) return EFI_INVALID_PARAMETER;
+
+ nfs = FS_PRIVATE(this);
+ f = NETFS_FD2F(nfs, fd);
+
+ if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;
+
+ count = MIN(*size, f->netbuf_size - f->netbuf_pos);
+
+ if (count) Memcpy(buf, f->netbuf+f->netbuf_pos, count);
+
+ *size = count;
+ f->netbuf_pos += count;
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS
+netfs_close(netfs_interface_t *this, UINTN fd)
+{
+ netfs_priv_state_t *nfs;
+ netfs_fd_t *f;
+
+ if (this == NULL || fd >= NETFS_FD_MAX) return EFI_INVALID_PARAMETER;
+
+ nfs = FS_PRIVATE(this);
+ f = NETFS_FD2F(nfs, fd);
+
+ if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;
+
+ netfs_fd_free(nfs, f);
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS
+netfs_seek(netfs_interface_t *this, UINTN fd, UINT64 newpos)
+{
+ netfs_priv_state_t *nfs;
+ netfs_fd_t *f;
+
+ if (this == NULL || fd >= NETFS_FD_MAX) return EFI_INVALID_PARAMETER;
+
+ nfs = FS_PRIVATE(this);
+ f = NETFS_FD2F(nfs, fd);
+
+ if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;
+
+ if (newpos > f->netbuf_size) return EFI_INVALID_PARAMETER;
+
+ f->netbuf_pos = newpos;
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS
+netfs_infosize(netfs_interface_t *this, UINTN fd, UINT64 *sz)
+{
+ netfs_priv_state_t *nfs;
+ netfs_fd_t *f;
+
+ if (this == NULL || fd >= NETFS_FD_MAX || sz == NULL) return EFI_INVALID_PARAMETER;
+
+ nfs = FS_PRIVATE(this);
+ f = NETFS_FD2F(nfs, fd);
+
+ if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;
+
+ *sz = f->netbuf_size;
+
+ return EFI_SUCCESS;
+}
+
+static INTN
+find_dhcp_option(EFI_PXE_BASE_CODE_PACKET *packet, UINT8 use_ipv6, UINT8 option, CHAR8 *str, INTN *len)
+{
+ INTN i = 0;
+ UINT8 tag, length;
+ UINT8 *opts = packet->Dhcpv4.DhcpOptions;
+
+ *len = 0;
+
+ for(;;) {
+ if (i >= 56) {
+ DBG_PRT((L"reach end of options (no marker)\n"));
+ break;
+ }
+ tag = opts[i++];
+
+ if (tag == 0) continue;
+ if (tag == 255) break;
+
+ length = opts[i++];
+
+#if 0
+ { UINT8 l = length, k = 0;
+ Print(L"found option %d len=%d: ", tag, length);
+ while (l--) { Print(L"%c(%d)\n", (CHAR16)opts[k], opts[k]); k++; }
+ Print(L"\n");
+ }
+#endif
+ if (tag == option) {
+ *len = length;
+ while (length--) { *str++ = opts[i++]; }
+ return 0;
+ }
+ i += length;
+ }
+ return -1;
+}
+
+static EFI_STATUS
+netfs_getinfo(netfs_interface_t *this, netfs_info_t *info)
+{
+ netfs_priv_state_t *nfs;
+ CHAR8 str[256];
+ INTN len, r;
+
+ if (this == NULL || info == NULL) return EFI_INVALID_PARAMETER;
+
+ nfs = FS_PRIVATE(this);
+
+ Memcpy(&info->cln_ipaddr, &nfs->cln_ip, sizeof(EFI_IP_ADDRESS));
+ Memcpy(&info->srv_ipaddr, &nfs->srv_ip, sizeof(EFI_IP_ADDRESS));
+ Memcpy(&info->netmask, &nfs->netmask, sizeof(EFI_IP_ADDRESS));
+ Memcpy(&info->gw_ipaddr, &nfs->gw_ip, sizeof(EFI_IP_ADDRESS));
+ Memcpy(&info->hw_addr, &nfs->hw_addr, sizeof(info->hw_addr));
+
+ info->using_pxe = nfs->using_pxe;
+ info->started = nfs->pxe->Mode->Started;
+ info->using_ipv6 = nfs->pxe->Mode->UsingIpv6;
+
+ if (nfs->pxe->Mode->UsingIpv6) goto skip_options;
+
+ r = find_dhcp_option(&nfs->pxe->Mode->DhcpAck,nfs->pxe->Mode->UsingIpv6, 15, str, &len);
+ str[len] = '\0';
+ ascii2U(str, info->domainame, 255);
+
+ VERB_PRT(3, Print(L"domain(15): %a\n", str));
+
+ r = find_dhcp_option(&nfs->pxe->Mode->DhcpAck,nfs->pxe->Mode->UsingIpv6, 12, str, &len);
+ str[len] = '\0';
+ ascii2U(str, info->hostname, 255);
+
+ 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);
+ VERB_PRT(3, Print(L"bootfile: %s\n", info->bootfile));
+ }
+
+skip_options:
+ return EFI_SUCCESS;
+}
+
+static UINT16
+find_pxe_server_type(EFI_PXE_BASE_CODE *pxe)
+{
+ INTN i = 0, max;
+ UINT8 tag, length;
+ UINT8 *opts = pxe->Mode->PxeReply.Dhcpv4.DhcpOptions;
+ UINT16 server_type;
+
+ while(i < 55) {
+ tag = opts[i];
+ length = opts[i+1];
+
+ DBG_PRT((L"Tag #%d Length %d\n",tag, length));
+
+ if (tag == 43) goto found;
+
+ i += 2 + length;
+ }
+ return NETFS_DEFAULT_SERVER_TYPE;
+found:
+ max = i+2+length;
+ i += 2;
+ while (i < max) {
+ tag = opts[i];
+ length = opts[i+1];
+ if (tag == 71) {
+ server_type =(opts[i+2]<<8) | opts[i+3];
+ DBG_PRT((L"ServerType: %d\n", server_type));
+ return server_type;
+ }
+ i+= 2 + length;
+ }
+ return NETFS_DEFAULT_SERVER_TYPE;
+}
+
+static EFI_STATUS
+netfs_query_layer(netfs_interface_t *this, UINT16 server_type, UINT16 layer, UINTN maxlen, CHAR16 *str)
+{
+ netfs_priv_state_t *nfs;
+ EFI_STATUS status;
+
+ if (this == NULL || str == NULL) return EFI_INVALID_PARAMETER;
+
+ nfs = FS_PRIVATE(this);
+
+ if (nfs->using_pxe == FALSE) return EFI_UNSUPPORTED;
+
+ if (server_type == 0) server_type = find_pxe_server_type(nfs->pxe);
+
+ status = nfs->pxe->Discover(nfs->pxe, server_type, &layer, FALSE, 0);
+ if(status == EFI_SUCCESS) {
+ ascii2U(nfs->pxe->Mode->PxeReply.Dhcpv4.BootpBootFile, str, maxlen);
+ }
+ return status;
+}
+
+static VOID
+netfs_init_state(netfs_t *netfs, EFI_HANDLE dev, EFI_PXE_BASE_CODE *pxe)
+{
+ netfs_priv_state_t *nfs = FS_PRIVATE(netfs);
+ UINTN i;
+
+ /* need to do some init here on netfs_intf */
+ Memset(netfs, 0, sizeof(*netfs));
+
+
+ netfs->pub_intf.netfs_name = netfs_name;
+ netfs->pub_intf.netfs_open = netfs_open;
+ netfs->pub_intf.netfs_read = netfs_read;
+ netfs->pub_intf.netfs_close = netfs_close;
+ netfs->pub_intf.netfs_infosize = netfs_infosize;
+ netfs->pub_intf.netfs_seek = netfs_seek;
+ netfs->pub_intf.netfs_query_layer = netfs_query_layer;
+ netfs->pub_intf.netfs_getinfo = netfs_getinfo;
+
+ nfs->dev = dev;
+ nfs->pxe = pxe;
+
+ /*
+ * we defer DHCP request until it is really necessary (netfs_open)
+ */
+ if (pxe->Mode->Started == TRUE) netfs_extract_ip(nfs);
+
+ Memset(nfs->fd_tab, 0, sizeof(nfs->fd_tab));
+
+ for (i=0; i < NETFS_FD_MAX-1; i++) {
+ nfs->fd_tab[i].next = &nfs->fd_tab[i+1];
+ }
+ /* null on last element is done by memset */
+
+ nfs->free_fd = nfs->fd_tab;
+ nfs->free_fd_count = NETFS_FD_MAX;
+}
+
+static EFI_STATUS
+netfs_install_one(EFI_HANDLE dev, VOID **intf)
+{
+
+ EFI_STATUS status;
+ netfs_t *netfs;
+ EFI_PXE_BASE_CODE *pxe;
+
+ status = BS->HandleProtocol (dev, &NetFsProtocol, (VOID **)&netfs);
+ if (status == EFI_SUCCESS) {
+ ERR_PRT((L"Warning: found existing %s protocol on device", FS_NAME));
+ goto found;
+ }
+
+ status = BS->HandleProtocol (dev, &PxeBaseCodeProtocol, (VOID **)&pxe);
+ if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER;
+
+
+ netfs = (netfs_t *)alloc(sizeof(*netfs), EfiLoaderData);
+ if (netfs == NULL) {
+ ERR_PRT((L"failed to allocate %s", FS_NAME));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ netfs_init_state(netfs, dev, pxe);
+
+ status = LibInstallProtocolInterfaces(&dev, &NetFsProtocol, netfs, NULL);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"Cannot install %s protocol: %r", FS_NAME, status));
+ free(netfs);
+ return status;
+ }
+
+found:
+ if (intf) *intf = (VOID *)netfs;
+
+ VERB_PRT(3,
+ { EFI_DEVICE_PATH *dp; CHAR16 *str;
+ dp = DevicePathFromHandle(dev);
+ str = DevicePathToStr(dp);
+ Print(L"attached %s to %s\n", FS_NAME, str);
+ FreePool(str);
+ });
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+netfs_install(VOID)
+{
+ UINTN size = 0;
+ UINTN i;
+ EFI_STATUS status;
+ VOID *intf;
+
+ BS->LocateHandle(ByProtocol, &PxeBaseCodeProtocol, NULL, &size, NULL);
+ if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */
+
+ DBG_PRT((L"size=%d", size));
+
+ dev_tab = (dev_tab_t *)alloc(size, EfiLoaderData);
+ if (dev_tab == NULL) {
+ ERR_PRT((L"failed to allocate handle table"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ status = BS->LocateHandle(ByProtocol, &PxeBaseCodeProtocol, NULL, &size, (VOID **)dev_tab);
+ if (status != EFI_SUCCESS) {
+ ERR_PRT((L"failed to get handles: %r", status));
+ free(dev_tab);
+ return status;
+ }
+ ndev = size / sizeof(EFI_HANDLE);
+
+ for(i=0; i < ndev; i++) {
+ intf = NULL;
+ netfs_install_one(dev_tab[i].dev, &intf);
+ /* override device handle with interface pointer */
+ dev_tab[i].intf = intf;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+netfs_uninstall(VOID)
+{
+
+ netfs_priv_state_t *nfs;
+ EFI_STATUS status;
+ UINTN i;
+
+ for(i=0; i < ndev; i++) {
+ if (dev_tab[i].intf == NULL) continue;
+ nfs = FS_PRIVATE(dev_tab[i].intf);
+ status = BS->UninstallProtocolInterface(nfs->dev, &NetFsProtocol, dev_tab[i].intf);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status));
+ continue;
+ }
+ VERB_PRT(3,
+ { EFI_DEVICE_PATH *dp; CHAR16 *str;
+ dp = DevicePathFromHandle(nfs->dev);
+ str = DevicePathToStr(dp);
+ Print(L"uninstalled %s on %s\n", FS_NAME, str);
+ FreePool(str);
+ });
+
+ if (nfs->pxe->Mode->Started == TRUE) nfs->pxe->Stop(nfs->pxe);
+
+ free(dev_tab[i].intf);
+ }
+ if (dev_tab) free(dev_tab);
+
+ return EFI_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 __NETLFS_H__
+#define __NETLFS_H__
+
+#include <efi.h>
+#include <efilib.h>
+
+#define NETFS_BOOTFILE_MAXLEN 256
+
+typedef struct {
+ EFI_IP_ADDRESS cln_ipaddr;
+ EFI_IP_ADDRESS srv_ipaddr;
+ EFI_IP_ADDRESS netmask;
+ EFI_IP_ADDRESS gw_ipaddr;
+ UINT8 hw_addr[16];
+ CHAR16 hostname[255]; /* 255 limitation of DHCP protocol */
+ CHAR16 domainame[255]; /* 255 limitation of DHCP protocol */
+ CHAR16 bootfile[NETFS_BOOTFILE_MAXLEN]; /* name of file downloaded (BOOTP/DHCP) */
+ BOOLEAN using_pxe;
+ BOOLEAN started;
+ BOOLEAN using_ipv6;
+} netfs_info_t;
+
+
+INTERFACE_DECL(_netfs_interface_t);
+
+typedef struct _netfs_interface_t {
+ EFI_STATUS (*netfs_name)(struct _netfs_interface_t *this, CHAR16 *name, UINTN maxlen);
+ EFI_STATUS (*netfs_open)(struct _netfs_interface_t *this, CHAR16 *name, UINTN *fd);
+ EFI_STATUS (*netfs_read)(struct _netfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size);
+ EFI_STATUS (*netfs_close)(struct _netfs_interface_t *this, UINTN fd);
+ EFI_STATUS (*netfs_infosize)(struct _netfs_interface_t *this, UINTN fd, UINT64 *size);
+ EFI_STATUS (*netfs_seek)(struct _netfs_interface_t *this, UINTN fd, UINT64 newpos);
+ EFI_STATUS (*netfs_query_layer)(struct _netfs_interface_t *this, UINT16 server_type, UINT16 layer, UINTN maxlen, CHAR16 *str);
+ EFI_STATUS (*netfs_getinfo)(struct _netfs_interface_t *this, netfs_info_t *info);
+} netfs_interface_t;
+
+#define NETFS_PROTOCOL \
+ { 0x6746de4f, 0xcc1e, 0x4c5f, {0xb7, 0xfb, 0x85, 0x6a, 0x5d, 0x69, 0x0f, 0x06} }
+
+extern EFI_STATUS netfs_install(VOID);
+extern EFI_STATUS netfs_uninstall(VOID);
+
+#endif /* __NETFS_H__ */
--- /dev/null
+/*
+ * Simplistic getopt() function for EFI
+ *
+ * This function provides the basic functionality of the POSIX getopt() function.
+ * No long options are supported.
+ *
+ * This code is meant for EFI programs and therefore deals with Unicode characters.
+ *
+ * Copyright (C) 2000 Hewlett-Packard Co
+ * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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.
+ */
+
+
+#include <efi.h>
+#include <efilib.h>
+
+
+#define DASH (CHAR16)'-'
+#define COLON (CHAR16)':'
+#define EOS (CHAR16)'\0'
+#define BADCH (INTN)'?'
+#define BADARG (INTN)':'
+
+extern CHAR16 * StrChr(IN const CHAR16 *s, INT16 c);
+
+CHAR16 *Optarg;
+INTN Optind = 1;
+INTN Optopt;
+
+/*
+ * This simple version of getopt supports:
+ * - option with no argument (no :)
+ * - option with REQUIRED argument (single :)
+ * it does not support:
+ * - long options
+ * - optional arguments to options
+ * - optreset
+ */
+INTN
+Getopt(INTN argc, CHAR16 *const argv[], const CHAR16 *optstring)
+{
+ static CHAR16 *cur_chr = NULL;
+ CHAR16 *opt;
+
+ if (Optind >= argc) { /* no option or end of argument list */
+ cur_chr = NULL;
+ return -1;
+ }
+ if (cur_chr == NULL || *cur_chr == EOS) {
+ cur_chr = argv[Optind];
+ if (*cur_chr++ != DASH) { /* missing DASH */
+ cur_chr = NULL;
+ return -1;
+ }
+ if (*cur_chr == DASH) {
+ cur_chr = NULL;
+ Optind++;
+ return -1; /* -- case, we're done */
+ }
+ }
+ Optopt = *cur_chr++;
+ opt = StrChr(optstring, Optopt);
+ if (!opt) {
+ Print(L"%s: illegal option -- %c\n", argv[0], Optopt);
+ if (*cur_chr == EOS) Optind++;
+ return BADCH;
+ }
+ if (*(opt+1) != COLON) {
+ Optarg = NULL;
+ if (*cur_chr == EOS) Optind++;
+ } else {
+ if (*cur_chr) {
+ Optarg = cur_chr;
+ } else if ( ++Optind >= argc ) {
+ Print(L"%s: option `%s' requires an argument\n", argv[0], argv[Optind-1]),
+ cur_chr = NULL;
+ return BADARG;
+ } else {
+ Optarg = argv[Optind];
+ }
+ Optind++;
+ }
+ return Optopt;
+}
--- /dev/null
+/*
+ * Simplistic getopt() function header file for EFI
+ *
+ * Copyright (C) 2000 Hewlett-Packard Co
+ * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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.
+ */
+
+
+
+#ifndef __EFI_GETOPT_H__
+#define __EFI_GETOPT_H__
+
+extern CHAR16 *Optarg;
+extern INTN Optind, Optopt;
+
+extern INTN Getopt(INTN argc, CHAR16 *const argv[], const CHAR16 *optstring);
+
+#endif /* __EFI_GETOPT_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 "glue_ext2fs.h"
+#include "fs/ext2fs.h"
+#include "strops.h"
+
+
+static INTN glue(fileops_t *this, VOID *intf);
+
+/* object exported to fileops */
+
+fileops_fs_t ext2fs_glue = { EXT2FS_PROTOCOL , glue, ext2fs_install, ext2fs_uninstall};
+
+static EFI_STATUS
+ext2fs_infosize(ext2fs_interface_t *this, fops_fd_t fd, UINT64 *sz)
+{
+ ext2fs_stat_t st;
+ EFI_STATUS status;
+
+ if (this == NULL || sz == NULL) return EFI_INVALID_PARAMETER;
+
+ status = this->ext2fs_fstat(this, fd, &st);
+ if (status != EFI_SUCCESS) return status;
+
+ *sz = (UINT64)st.st_size;
+
+ return EFI_SUCCESS;
+}
+
+static INTN
+glue(fileops_t *fp, VOID *intf)
+{
+ ext2fs_interface_t *ext2fs = (ext2fs_interface_t *)intf;
+
+ /* record underlying interface */
+ fp->intf = intf;
+
+ fp->open = (fops_open_t)ext2fs->ext2fs_open;
+ fp->read = (fops_read_t)ext2fs->ext2fs_read;
+ fp->close = (fops_close_t)ext2fs->ext2fs_close;
+ fp->infosize = (fops_infosize_t)ext2fs_infosize; /* local override */
+ fp->seek = (fops_seek_t)ext2fs->ext2fs_seek;
+
+ /* fill out the name of the underlying file system */
+ ext2fs->ext2fs_name(ext2fs, fp->name, FILEOPS_NAME_MAXLEN);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 __GLUE_EXT2FS_H__
+#define __GLUE_EXT2FS_H__
+
+#include "fileops.h"
+
+extern fileops_fs_t ext2fs_glue;
+
+#endif /* __GLUE_EXT2FS_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 "fs/localfs.h"
+#include "glue_localfs.h"
+#include "strops.h"
+#include "elilo.h"
+
+static INTN glue(fileops_t *this, VOID *intf);
+
+/* object exported to fileops */
+
+fileops_fs_t localfs_glue = { LOCALFS_PROTOCOL, glue, localfs_install, localfs_uninstall};
+
+
+static CHAR16 localfs_default_path[FILENAME_MAXLEN];
+
+/*
+ * remove /.\ pattern from path name:
+ *
+ * Example 1: I am in fs0:\efi\debian, which contains elilo.efi, and I
+ * have typed 'elilo' at the efishell prompt. set_default_path() gets
+ * called with string "\EFI\debian/.\elilo.efi". The final path name
+ * must then be set to "\EFI\debian\".
+ *
+ * Example 2: I am in fs0:\ and type 'efi\debian\elilo' at the shell
+ * prompt. set_default_path() is called with "\/.\efi\debian\elilo.efi",
+ * the path must then be set to "\efi\debian\".
+ *
+ * Example 3: I am in fs0:\efi and type '\efi\debian\elilo'.
+ * set_default_path() is called with "\efi\debian\elilo.efi", the
+ * path is "\efi\debian".
+ */
+static VOID
+set_default_path(CHAR16 *sptr)
+{
+#define is_sep(h) (h == CHAR_SLASH || h == CHAR_BACKSLASH)
+ CHAR16 *dptr, *last_sep = NULL;
+ UINTN len = FILENAME_MAXLEN - 1;
+ UINTN last_was_sep = 0;
+ CHAR16 c;
+
+ dptr = localfs_default_path;
+
+ while (len-- && *sptr) {
+ c = sptr[0];
+
+ if (is_sep(c)) {
+ if (last_was_sep) {
+ sptr++;
+ continue;
+ }
+ c = CHAR_BACKSLASH;
+ last_was_sep = 1;
+ last_sep = dptr;
+ } else {
+ last_was_sep = 0;
+ }
+ *dptr++ = c;
+ sptr++;
+ }
+ if (last_sep)
+ *++last_sep = CHAR_NULL;
+ else
+ *dptr = CHAR_NULL;
+
+ DBG_PRT((L"localfs_default_path=%s\n", localfs_default_path));
+}
+
+
+/*
+ * The following glue functions are the only ones which need
+ * to know about the way the underlying interface is working
+ */
+#define LOCALFS_DEFAULT_KERNEL L"vmlinux"
+#define LOCALFS_DEFAULT_CONFIG L"elilo.conf"
+static EFI_STATUS
+localfs_setdefaults(VOID *this, CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
+{
+ StrnCpy(kname, LOCALFS_DEFAULT_KERNEL, maxlen-1);
+ kname[maxlen-1] = CHAR_NULL;
+
+ StrnCpy(config, LOCALFS_DEFAULT_CONFIG, maxlen-1);
+ config[maxlen-1] = CHAR_NULL;
+
+ set_default_path(devpath);
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS
+localfs_getdefault_path(CHAR16 *path, UINTN maxlen)
+{
+ if (maxlen <= StrLen(localfs_default_path)) return EFI_BUFFER_TOO_SMALL;
+
+ StrCpy(path, localfs_default_path);
+ return EFI_SUCCESS;
+}
+
+/*
+ * If the supplied path is a relative path, then prepend the path to
+ * the elilo.efi executable. This ensures that elilo will look in
+ * its own directory for its config file, kernel images, etc, rather
+ * than the root directory of the disk. Also * convert forward slashes
+ * into backward slashes.
+ */
+static EFI_STATUS
+glue_open(VOID *intf, CHAR16 *name, fops_fd_t *fd)
+{
+ CHAR16 *p;
+ localfs_interface_t *localfs = (localfs_interface_t *)intf;
+ CHAR16 fullname[FILENAME_MAXLEN];
+
+ /*
+ * XXX: modification to passed argument (name)
+ */
+ for (p= name; *p != CHAR_NULL; p++) {
+ if (*p == CHAR_SLASH) *p = CHAR_BACKSLASH;
+ }
+ if (name[0] != CHAR_BACKSLASH && localfs_default_path[0] != CHAR_NULL) {
+ if (StrLen(localfs_default_path) + StrLen(name) + 1 >= FILENAME_MAXLEN)
+ return EFI_INVALID_PARAMETER;
+
+ StrCpy(fullname, localfs_default_path);
+ StrCat(fullname, name);
+ name = fullname;
+ }
+ return localfs->localfs_open(intf, name, fd);
+}
+
+static INTN
+glue(fileops_t *fp, VOID *intf)
+{
+ localfs_interface_t *localfs = (localfs_interface_t *)intf;
+
+ fp->open = glue_open;
+ fp->read = (fops_read_t)localfs->localfs_read;
+ fp->close = (fops_close_t)localfs->localfs_close;
+ fp->infosize = (fops_infosize_t)localfs->localfs_infosize;
+ fp->seek = (fops_seek_t)localfs->localfs_seek;
+ fp->setdefaults = (fops_setdefaults_t)localfs_setdefaults;
+ fp->getdefault_path = (fops_getdefault_path_t)localfs_getdefault_path;
+ fp->intf = intf;
+
+ /* fill out the name of the underlying file system */
+ localfs->localfs_name(localfs, fp->name, FILEOPS_NAME_MAXLEN);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 __GLUE_LOCALFS_H__
+#define __GLUE_LOCALFS_H__
+
+#include "fileops.h"
+
+extern fileops_fs_t localfs_glue;
+
+#endif /* __GLUE_LOCALFS_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 "glue_netfs.h"
+#include "fs/netfs.h"
+#include "strops.h"
+
+#include "elilo.h"
+#include "vars.h"
+
+/*
+ * disable this if you only want the default config file (elilo.conf)
+ * and not the ip-address based first file attempt
+ */
+
+static INTN glue(fileops_t *this, VOID *intf);
+
+/* object exported to fileops */
+fileops_fs_t netfs_glue = { NETFS_PROTOCOL , glue, netfs_install, netfs_uninstall};
+
+
+#define NETFS_DEFAULT_KERNEL L"vmlinux"
+#define NETFS_DEFAULT_CONFIG L"elilo.conf"
+#define NETFS_DEFAULT_SERVER_TYPE EFI_PXE_BASE_CODE_BOOT_TYPE_REDHAT_BOOT
+
+
+static CHAR16 netfs_default_path[FILENAME_MAXLEN];
+
+
+/*
+ * Pxe Discovery protocol layers
+ * Layer 0 is used to download the boot loader
+ */
+#define NETFS_CONFIG_LAYER 1
+#define NETFS_KERNEL_LAYER 2
+
+static CHAR16 *hexa=L"0123456789ABCDEF";
+
+static VOID
+convert_ip2hex(UINT8 *ip, INTN l, CHAR16 *str)
+{
+ UINTN i;
+
+ for(i=0; i < l; i++) {
+ str[2*i] = hexa[(ip[i] & 0xf0)>>4];
+ str[2*i+1] = hexa[ip[i] & 0x0f];
+ }
+}
+
+static VOID
+convert_ip2decstr(UINT8 *ip, INTN l, CHAR16 *str)
+{
+ UINTN i, j;
+ UINTN v, val;
+
+ for(i=0, j=0; i < l; i++) {
+ val = ip[i];
+ v = val / 100;
+ if (v) {
+ str[j++] = L'0'+v;
+ }
+ val = val % 100;
+ v = val / 10;
+ if (v || ip[i] >= 100) {
+ str[j++] = L'0'+v;
+ }
+
+ v = val % 10;
+ str[j++] = L'0'+v;
+ if (i < l-1) str[j++] = L'.';
+ }
+ str[j] = CHAR_NULL;
+}
+
+static int
+netfs_set_default_path(netfs_interface_t *netfs, netfs_info_t *info)
+{
+ INTN len;
+
+ StrnCpy(netfs_default_path, info->bootfile, FILENAME_MAXLEN);
+
+ len = StrLen(netfs_default_path) - 1;
+
+ while (len >= 0) {
+ if (netfs_default_path[len] == CHAR_SLASH || netfs_default_path[len] == CHAR_BACKSLASH) break;
+ len--;
+ }
+ netfs_default_path[len+1] = CHAR_NULL;
+
+ DBG_PRT((L"netfs_default_path=%s\n", netfs_default_path));
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS
+netfs_setdefaults(VOID *intf, CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
+{
+ netfs_interface_t *netfs = (netfs_interface_t *)intf;
+ netfs_info_t info;
+ EFI_STATUS status;
+ UINT8 *ipaddr;
+ UINTN m;
+ CHAR16 ip_var[64], str[64];
+ UINT8 *ip;
+
+ if (config == NULL || kname == NULL || maxlen < 1) return EFI_INVALID_PARAMETER;
+
+ netfs->netfs_getinfo(netfs, &info);
+
+ m = info.using_ipv6 ? 16 : 4;
+ ipaddr = info.using_ipv6 ? info.cln_ipaddr.v6.Addr: info.cln_ipaddr.v4.Addr;
+
+ convert_ip2decstr(ipaddr, m, ip_var);
+ set_var(VAR_NETFS_IPADDR, ip_var);
+
+ ip = info.using_ipv6 ? info.netmask.v6.Addr: info.netmask.v4.Addr;
+ convert_ip2decstr(ip, m, str);
+ set_var(VAR_NETFS_NETMASK, str);
+
+ ip = info.using_ipv6 ? info.gw_ipaddr.v6.Addr: info.gw_ipaddr.v4.Addr;
+ convert_ip2decstr(ip, m, str);
+ set_var(VAR_NETFS_GATEWAY, str);
+
+ set_var(VAR_NETFS_HOSTNAME, info.hostname);
+ set_var(VAR_NETFS_DOMAINAME, info.domainame);
+
+ if (info.using_pxe) {
+ status = netfs->netfs_query_layer(netfs, 0, NETFS_CONFIG_LAYER, maxlen, config);
+ if (EFI_ERROR(status)) {
+ StrnCpy(config, NETFS_DEFAULT_CONFIG, maxlen-1);
+ config[maxlen-1] = CHAR_NULL;
+ }
+
+ status = netfs->netfs_query_layer(netfs, 0, NETFS_KERNEL_LAYER, maxlen, kname);
+ if (EFI_ERROR(status)) {
+ StrnCpy(kname, NETFS_DEFAULT_KERNEL, maxlen-1);
+ kname[maxlen-1] = CHAR_NULL;
+ }
+ } else {
+#ifdef ENABLE_MACHINE_SPECIFIC_NETCONFIG
+ /*
+ * will try a machine specific file first.
+ * the file is constructed based on the IP(v4) address
+ */
+ convert_ip2hex(ipaddr, m, config);
+
+ config[8] = L'.';
+ config[9] = L'c';
+ config[10] = L'o';
+ config[11] = L'n';
+ config[12] = L'f';
+ config[13] = CHAR_NULL;
+#else
+ StrnCpy(config, NETFS_DEFAULT_CONFIG, maxlen-1);
+ config[maxlen-1] = CHAR_NULL;
+#endif
+ StrnCpy(kname, NETFS_DEFAULT_KERNEL, maxlen-1);
+ kname[maxlen-1] = CHAR_NULL;
+
+ /*
+ * extract bootloader path prefix to be used for
+ * the config file (and possibly the other files we
+ * need to download)
+ */
+ netfs_set_default_path(netfs, &info);
+ }
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS
+netfs_getdefault_path(CHAR16 *path, UINTN maxlen)
+{
+ if (maxlen <= StrLen(netfs_default_path)) return EFI_BUFFER_TOO_SMALL;
+
+ StrCpy(path, netfs_default_path);
+ return EFI_SUCCESS;
+}
+
+
+static EFI_STATUS
+glue_open(VOID *intf, CHAR16 *name, fops_fd_t *fd)
+{
+ netfs_interface_t *netfs = (netfs_interface_t *)intf;
+ CHAR16 fullname[FILENAME_MAXLEN];
+
+ if (name[0] != CHAR_SLASH && name[0] != CHAR_BACKSLASH && netfs_default_path[0] != CHAR_NULL) {
+ if (StrLen(netfs_default_path) + StrLen(name) + 1 >= FILENAME_MAXLEN)
+ return EFI_INVALID_PARAMETER;
+
+ StrCpy(fullname, netfs_default_path);
+ StrCat(fullname, name);
+ name = fullname;
+ }
+ return netfs->netfs_open(intf, name, fd);
+}
+
+static INTN
+glue(fileops_t *fp, VOID *intf)
+{
+ netfs_interface_t *netfs = (netfs_interface_t *)intf;
+
+ /* record underlying interface */
+ fp->intf = intf;
+
+ fp->open = glue_open;
+ fp->read = (fops_read_t)netfs->netfs_read;
+ fp->close = (fops_close_t)netfs->netfs_close;
+ fp->infosize = (fops_infosize_t)netfs->netfs_infosize;
+ fp->seek = (fops_seek_t)netfs->netfs_seek;
+ fp->setdefaults = (fops_setdefaults_t)netfs_setdefaults;
+ fp->getdefault_path = (fops_getdefault_path_t)netfs_getdefault_path;
+ fp->intf = intf;
+
+ /* fill out the name of the underlying file system */
+ netfs->netfs_name(netfs, fp->name, FILEOPS_NAME_MAXLEN);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 __GLUE_NETFS_H__
+#define __GLUE_NETFS_H__
+
+#include "fileops.h"
+
+extern fileops_fs_t netfs_glue;
+
+#endif /* __GLUE_NETFS_H__ */
--- /dev/null
+diff -urN gnu-efi-3.0a/gnuefi/elf_ia32_efi.lds gnu-efi-3.0a-ia32/gnuefi/elf_ia32_efi.lds
+--- gnu-efi-3.0a/gnuefi/elf_ia32_efi.lds 2002-02-22 15:43:28.000000000 -0800
++++ gnu-efi-3.0a-ia32/gnuefi/elf_ia32_efi.lds 2003-08-21 13:36:51.000000000 -0700
+@@ -17,6 +17,7 @@
+ *(.rodata*)
+ *(.data)
+ *(.data1)
++ *(.data.*)
+ *(.sdata)
+ *(.got.plt)
+ *(.got)
+@@ -34,6 +35,7 @@
+ .rel :
+ {
+ *(.rel.data)
++ *(.rel.data.*)
+ *(.rel.got)
+ *(.rel.stab)
+ }
--- /dev/null
+#
+# Copyright (C) 2001-2003 Hewlett-Packard Co.
+# Contributed by Stephane Eranian <eranian@hpl.hp.com>
+#
+# 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 ../Make.defaults
+include ../Make.rules
+
+TOPDIR=$(CDIR)/..
+
+FILES=system.o config.o
+
+TARGET=sysdeps.o
+
+all: $(TARGET)
+
+system.o: rmswitch.h
+
+rmswitch.h: bin_to_h.c rmswitch.S
+ $(CC) -o bin_to_h bin_to_h.c
+ $(AS) -o rmswitch.o rmswitch.S
+ $(LD) -Ttext 0x0 -s --oformat binary -o rmswitch rmswitch.o
+ ./bin_to_h <rmswitch >rmswitch.h
+
+$(TARGET): $(FILES)
+ $(LD) -r -o $@ $(FILES)
+
+clean:
+ $(RM) -f $(TARGET) $(FILES)
+ $(RM) -f bin_to_h.o bin_to_h
+ $(RM) -f rmswitch.h rmswitch.o rmswitch
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main(void)
+{
+ unsigned n = 0;
+ int c;
+
+ printf("UINT8 rmswitch_image[] = {\n");
+
+ while ((c = getchar()) != EOF) {
+ printf("0x%02x,%s",
+ c & 0xFF,
+ (++n & 0x07) ? " " : "\n");
+ }
+
+ if (n & 0x07) {
+ printf("\n");
+ }
+
+ printf(
+ "};\n"
+ "UINTN rmswitch_size = sizeof rmswitch_image;\n");
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ * Contributed by Chris Ahna <christopher.j.ahna@intel.com>
+ *
+ * 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 "config.h"
+#include "private.h"
+
+typedef struct {
+ UINTN legacy_free_boot;
+} ia32_global_config_t;
+
+
+static ia32_global_config_t ia32_gconf;
+
+static config_option_t sysdeps_global_options[]={
+ {OPT_BOOL, OPT_GLOBAL, L"legacy-free", NULL, NULL, &ia32_gconf.legacy_free_boot}
+};
+
+
+/*
+ * IA-32 operations that need to be done only once and just before
+ * entering the main loop of the loader
+ * Return:
+ * 0 if sucessful
+ * -1 otherwise (will abort execution)
+ */
+INTN
+sysdeps_preloop_actions(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image)
+{
+ return 0;
+}
+
+#define IA32_CMDLINE_OPTIONS L""
+
+CHAR16 *
+sysdeps_get_cmdline_opts(VOID)
+{
+ return IA32_CMDLINE_OPTIONS;
+}
+
+INTN
+sysdeps_getopt(INTN c, INTN optind, CHAR16 *optarg)
+{
+ return -1;
+}
+
+VOID
+sysdeps_print_cmdline_opts(VOID)
+{
+}
+
+
+INTN
+ia32_use_legacy_free_boot(VOID)
+{
+ return ia32_gconf.legacy_free_boot ? 1 : 0;
+}
+
+INTN
+sysdeps_register_options(VOID)
+{
+ INTN ret;
+
+ 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;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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_PRIVATE_IA32_H__
+#define __ELILO_PRIVATE_IA32_H__
+
+#endif /* __ELILO_PRIVATE_IA32_H__ */
+
--- /dev/null
+#
+# Switch from protected mode to real mode and jump to setup.S
+# image located at %cx:0.
+#
+# This module must be placed into physical memory at 0:7C00h.
+# EFI has some real mode thunking code at 2000:0h.
+#
+# Processor and non-maskable interrupts should be disabled
+# before control is passed to this module.
+#
+
+.global _start
+
+.code32
+.text
+_start:
+ #
+ # Load identity mapped GDT & real mode IDT.
+ # Add 7C00h to the addresses since this is linked to start
+ # at 0h and it is being placed at 7C00h.
+ #
+
+ lgdt %cs:gdt_48 + 0x7C00
+ lidt %cs:idt_48 + 0x7C00
+
+ #
+ # Turn off PG bit in CR0 and set CR3 to zero.
+ #
+
+ movl %cr0, %eax
+ andl $0x7FFFFFFF, %eax
+ movl %eax, %cr0
+
+ xorl %eax, %eax
+ movl %eax, %cr3
+
+ #
+ # Reload CS.
+ # Now we add 7B00h because we need to force the segment
+ # address and selector to be the same.
+ #
+
+ .byte 0xEA
+ .long pm_reload + 0x7B00
+ .word 0x10
+
+pm_reload:
+
+.code16
+
+ #
+ # Reload DS, ES, FS, GS & SS.
+ #
+
+ movw $0x18, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %ss
+
+ #
+ # Switch to real mode. Clear PE bit in CR0.
+ #
+
+ movl %cr0, %eax
+ andl $0xFFFFFFFE, %eax
+ movl %eax, %cr0
+
+ #
+ # Reload CS.
+ #
+
+ .byte 0xEA
+ .word rm_reload + 0x7C00
+ .word 0
+
+rm_reload:
+
+ #
+ # Reload SS & SP.
+ #
+
+ xorw %ax, %ax
+ movw %ax, %ss
+ movw $0x7BFE, %sp
+
+ #
+ # Start running setup.S
+ #
+
+ .byte 0xEA
+ .word 0
+ .word 0x9020
+
+ #
+ # GDT & IDT stuff for switching into real mode.
+ #
+
+gdt: .word 0, 0, 0, 0 # unused (00h)
+ .word 0, 0, 0, 0 # dummy (08h)
+ .word 0xFFFF, 0x100 # code (10h)
+ .word 0x9A00, 0
+ .word 0xFFFF, 0x180 # data (18h)
+ .word 0x9200, 0
+
+gdt_48: .word 0x08 * 0x400
+ .long gdt + 0x7C00
+
+idt_48: .word 0x400
+ .long 0
+
+ #
+ # Be careful not to exceed 1F0h or the the bootsect.S
+ # parameters will be lost!
+ #
+
+.end
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ * Contributed by Mike Johnston <johnston@intel.com>
+ * Contributed by Chris Ahna <christopher.j.ahna@intel.com>
+ *
+ * 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.
+ */
+
+/*
+ * This file is used to define all the IA32-specific data structures
+ * and constant used by the generic ELILO
+ */
+#ifndef __ELILO_SYSDEPS_IA32_H__
+#define __ELILO_SYSDEPS_IA32_H__
+
+#define ELILO_ARCH "IA-32" /* ASCII string */
+
+/* for now use library versions */
+#define Memset(a,v,n) SetMem((a),(n),(v))
+#define Memcpy(a,b,n) CopyMem((a),(b),(n))
+
+/*
+ * This version must match the one in the kernel.
+ *
+ * This table was put together using information from the
+ * following Linux kernel source files:
+ * linux/include/tty.h
+ * linux/arch/i386/kernel/setup.c
+ * linux/arch/i386/boot/bootsect.S
+ * linux/arch/i386/boot/setup.S
+ * linux/arch/i386/boot/video.S
+ *
+ * New fields in this structure for EFI and ELILO are:
+ * efi_loader_sig
+ * efi_st_addr
+ *
+ * A new bit, LDRFLAG_BOOT_PARAM_RELOC, in the loader_flags
+ * field is also defined in this file.
+ */
+typedef struct efi_ia32_boot_params {
+ UINT32 size;
+ UINT32 command_line;
+ UINT32 efi_sys_tbl;
+ UINT32 efi_mem_map;
+ UINT32 efi_mem_map_size;
+ UINT32 efi_mem_desc_size;
+ UINT32 efi_mem_desc_version;
+ UINT32 initrd_start;
+ UINT32 initrd_size;
+ UINT32 loader_start;
+ UINT32 loader_size;
+ UINT32 kernel_start;
+ UINT32 kernel_size;
+ UINT16 num_cols;
+ UINT16 num_rows;
+ UINT16 orig_x;
+ UINT16 orig_y;
+} efi_ia32_boot_params_t;
+
+extern efi_ia32_boot_params_t efi_ia32_bp;
+
+#pragma pack(1)
+typedef union ia32_boot_params {
+ UINT8 raw[0x2000];
+ struct {
+/* Cursor position before passing control to kernel. */
+/* 0x00 */ UINT8 orig_cursor_col; /* LDR */
+/* 0x01 */ UINT8 orig_cursor_row; /* LDR */
+
+/* Available contiguous extended memory in KB. */
+/* 0x02 */ UINT16 ext_mem_k; /* LDR */
+
+/* Video page, mode and screen width before passing control to kernel. */
+/* 0x04 */ UINT16 orig_video_page; /* LDR */
+/* 0x06 */ UINT8 orig_video_mode; /* LDR */
+/* 0x07 */ UINT8 orig_video_cols; /* LDR */
+
+/* 0x08 */ UINT16 unused_1; /* unused */
+
+/* %%TBD */
+/* 0x0A */ UINT16 orig_ega_bx; /* LDR */
+
+/* 0x0C */ UINT16 unused_2; /* unused */
+
+/* Screen height before passing control to kernel. */
+/* 0x0E */ UINT8 orig_video_rows; /* LDR */
+
+/* %%TBD */
+/* 0x0F */ UINT8 is_vga; /* LDR */
+/* 0x10 */ UINT16 orig_video_points; /* LDR */
+
+/* %%TBD */
+/* 0x12 */ UINT16 lfb_width; /* LDR */
+/* 0x14 */ UINT16 lfb_height; /* LDR */
+/* 0x16 */ UINT16 lfb_depth; /* LDR */
+/* 0x18 */ UINT32 lfb_base; /* LDR */
+/* 0x1C */ UINT32 lfb_size; /* LDR */
+
+/* Offset of command line (from start of ia32_boot_param struct). */
+/* The command line magik number must be set for the kernel setup */
+/* code to use the command line offset. */
+/* 0x20 */ UINT16 cmdline_magik; /* LDR */
+#define CMDLINE_MAGIK 0xA33F
+/* 0x22 */ UINT16 cmdline_offset; /* LDR */
+
+/* %%TBD */
+/* 0x24 */ UINT16 lfb_line_len; /* LDR */
+
+/* %%TBD */
+/* 0x26 */ UINT8 lfb_red_size; /* LDR */
+/* 0x27 */ UINT8 lfb_red_pos; /* LDR */
+/* 0x28 */ UINT8 lfb_green_size; /* LDR */
+/* 0x29 */ UINT8 lfb_green_pos; /* LDR */
+/* 0x2A */ UINT8 lfb_blue_size; /* LDR */
+/* 0x2B */ UINT8 lfb_blue_pos; /* LDR */
+/* 0x2C */ UINT8 lfb_rsvd_size; /* LDR */
+/* 0x2D */ UINT8 lfb_rsvd_pos; /* LDR */
+
+/* %%TBD */
+/* 0x2E */ UINT16 vesa_seg; /* LDR */
+/* 0x30 */ UINT16 vesa_off; /* LDR */
+
+/* %%TBD */
+/* 0x32 */ UINT16 lfb_pages; /* LDR */
+/* 0x34 */ UINT8 lfb_reserved[0x0C]; /* reserved */
+
+/* %%TBD */
+/* 0x40 */ UINT16 apm_bios_ver; /* LDR */
+#define NO_APM_BIOS 0x0000
+
+/* %%TBD */
+/* 0x42 */ UINT16 bios_code_seg; /* LDR */
+/* 0x44 */ UINT32 bios_entry_point; /* LDR */
+/* 0x48 */ UINT16 bios_code_seg16; /* LDR */
+/* 0x4A */ UINT16 bios_data_seg; /* LDR */
+
+/* %%TBD */
+/* 0x4C */ UINT16 apm_bios_flags; /* LDR */
+#define NO_32BIT_APM_MASK 0xFFFD
+
+/* %%TBD */
+/* 0x4E */ UINT32 bios_code_len; /* LDR */
+/* 0x52 */ UINT16 bios_data_len; /* LDR */
+
+/* 0x54 */ UINT8 unused_3[0x2C]; /* unused */
+
+/* %%TBD */
+/* 0x80 */ UINT8 hd0_info[0x10]; /* LDR */
+/* 0x90 */ UINT8 hd1_info[0x10]; /* LDR */
+
+/* %%TBD */
+/* 0xA0 */ UINT16 mca_info_len; /* LDR */
+/* 0xA2 */ UINT8 mca_info_buf[0x10]; /* LDR */
+
+/* 0xB2 */ UINT8 unused_4[0x10E]; /* unused */
+
+/* EFI boot loader signature. */
+/* 0x1C0 */ UINT8 efi_loader_sig[4]; /* LDR */
+#define EFI_LOADER_SIG "EFIL"
+
+/* Address of the EFI system table. */
+/* 0x1C4 */ UINT32 efi_sys_tbl; /* LDR */
+
+/* EFI memory descriptor size. */
+/* 0x1C8 */ UINT32 efi_mem_desc_size; /* LDR */
+
+/* EFI memory descriptor version. */
+/* 0x1CC */ UINT32 efi_mem_desc_ver; /* LDR */
+
+/* Address & size of EFI memory map. */
+/* 0x1D0 */ UINT32 efi_mem_map; /* LDR */
+/* 0x1D4 */ UINT32 efi_mem_map_size; /* LDR */
+
+/* Address & size of loader. */
+/* 0x1D8 */ UINT32 loader_start; /* LDR */
+/* 0x1DC */ UINT32 loader_size; /* LDR */
+
+/* Available contiguous extended memory in KB. */
+/* 0x1E0 */ UINT32 alt_mem_k; /* LDR */
+
+/* 0x1E4 */ UINT8 unused_5[0x0D]; /* unused */
+
+/* Size of setup code in sectors (1 sector == 512 bytes). */
+/* 0x1F1 */ UINT8 setup_sectors; /* BLD */
+
+/* %%TBD */
+/* 0x1F2 */ UINT16 mount_root_rdonly; /* BLD */
+
+/* %%TBD */
+/* 0x1F4 */ UINT16 sys_size; /* BLD */
+
+/* %%TBD */
+/* 0x1F6 */ UINT16 swap_dev; /* BLD */
+
+/* %%TBD */
+/* 0x1F8 */ UINT16 ramdisk_flags; /* BLD */
+#define RAMDISK_PROMPT 0x8000
+#define RAMDISK_LOAD 0x4000
+
+/* %%TBD */
+/* 0x1FA */ UINT16 video_mode_flag; /* BLD */
+
+/* %%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
+
+/* Jump past setup data (not used in EFI). */
+/* 0x200 */ UINT16 jump; /* BLD */
+
+/* Setup data signature. */
+/* 0x202 */ UINT8 setup_sig[4]; /* BLD */
+#define SETUP_SIG "HdrS"
+
+/* %%TBD */
+/* 0x206 */ UINT8 hdr_minor; /* BLD */
+/* 0x207 */ UINT8 hdr_major; /* BLD */
+
+/* %%TBD */
+/* 0x208 */ UINT32 rm_switch; /* LDD */
+
+/* %%TBD */
+/* 0x20C */ UINT16 start_sys_seg; /* BLD */
+
+/* %%TBD */
+/* 0x20E */ UINT16 kernel_verstr_offset; /* BLD */
+
+/* Loader type & version. */
+/* 0x210 */ UINT8 loader_type; /* LDR */
+#define LDRTYPE_ELILO 0x50 /* 5?h == elilo */
+ /* ?0h == revision */
+
+/* 0x211 */ UINT8 loader_flags; /* BLD and LDR */
+#define LDRFLAG_CAN_USE_HEAP 0x80
+#define LDRFLAG_BOOT_PARAM_RELOC 0x40
+
+/* %%TBD */
+/* 0x212 */ UINT16 setup_move_size; /* BLD */
+
+/* %%TBD */
+/* 0x214 */ UINT32 kernel_start; /* LDR */
+
+/* %%TBD */
+/* 0x218 */ UINT32 initrd_start; /* LDR */
+/* 0x21C */ UINT32 initrd_size; /* LDR */
+
+/* %%TBD */
+/* 0x220 */ UINT32 bootsect_helper; /* BLD */
+
+/* %%TBD */
+/* 0x224 */ UINT16 heap_end_ptr; /* LDR */
+
+/* %%TBD */
+/* 0x226 */ UINT32 base_mem_size; /* LDR */
+ } s;
+} boot_params_t;
+#pragma pack()
+
+/*
+ * The stuff below here is for jumping to the kernel.
+ */
+
+/*
+ * Some macros to copy and set memory after EFI has been
+ * stopped.
+ */
+
+#define MEMCPY(to, from, cnt) { \
+ UINT8 *t = (UINT8 *)(to); \
+ UINT8 *f = (UINT8 *)(from); \
+ UINTN n = cnt; \
+ if (t && f && n) { \
+ while (n--) { \
+ *t++ = *f++; \
+ } \
+ } \
+}
+
+#define MEMSET(ptr, size, val) { \
+ UINT8 *p = (UINT8 *)(ptr); \
+ UINTN n = (UINTN)(size); \
+ UINT8 v = (UINT8)(val); \
+ if (p && n) { \
+ while (n--) { \
+ *p++ = v; \
+ } \
+ } \
+}
+
+/*
+ * Descriptor table pointer format.
+ */
+#pragma pack(1)
+typedef struct {
+ UINT16 limit;
+ UINT32 base;
+} dt_addr_t;
+#pragma pack()
+
+extern UINTN high_base_mem;
+extern UINTN high_ext_mem;
+
+extern boot_params_t *param_start;
+extern UINTN param_size;
+
+extern VOID *kernel_start;
+extern UINTN kernel_size;
+
+extern VOID *initrd_start;
+extern UINTN initrd_size;
+
+extern dt_addr_t gdt_addr;
+extern dt_addr_t idt_addr;
+
+extern UINT16 init_gdt[];
+extern UINTN sizeof_init_gdt;
+
+extern UINT8 rmswitch_image[];
+extern UINTN rmswitch_size;
+
+extern INTN ia32_use_legacy_free_boot();
+
+/*
+ * How to jump to kernel code
+ */
+
+static inline void
+start_kernel(VOID *kentry, boot_params_t *bp)
+{
+ /*
+ * Disable interrupts.
+ */
+
+ asm volatile ( "cli" : : );
+
+ /*
+ * Relocate initrd, if present.
+ */
+
+ if (bp->s.initrd_start) {
+ /* %%TBD */
+ MEMCPY(15 * 1024 * 1024, bp->s.initrd_start, bp->s.initrd_size);
+ bp->s.initrd_start = 15 * 1024 * 1024;
+ }
+
+ /*
+ * Copy boot sector, setup data and command line
+ * to final resting place. We need to copy
+ * BOOT_PARAM_MEMSIZE bytes.
+ */
+
+ MEMCPY(high_base_mem, bp, 0x4000);
+
+ /*
+ * initialize efi ia32 boot params and place them at 1kb up from
+ * the start of the boot command line param. This results in the
+ * efi ia32 boot params to be copied to 0x00104c00. See bootparams.c
+ * for details on how this is arranged. EFI enabled
+ * kernels will look for the efi boot params here to know if the
+ * kernel is booting on an EFI platform or legacy BIOS based platfrom
+ */
+
+ efi_ia32_bp.initrd_start = bp->s.initrd_start;
+ efi_ia32_bp.initrd_size = bp->s.initrd_size;
+
+ MEMCPY(high_base_mem + 0x4000 - 0x0400, &efi_ia32_bp, sizeof(efi_ia32_bp));
+
+ /*
+ * Initialize Linux GDT.
+ */
+
+ MEMSET(gdt_addr.base, gdt_addr.limit, 0);
+ MEMCPY(gdt_addr.base, init_gdt, sizeof_init_gdt);
+
+ if (! ia32_use_legacy_free_boot()) {
+
+ /*
+ * Copy our real mode transition code to 0x7C00.
+ */
+
+ MEMCPY(0x7C00, rmswitch_image, rmswitch_size);
+
+ asm volatile ( "movl $0x7C00, %%ebx" : : );
+ asm volatile ( "jmp *%%ebx" : : );
+ }
+
+ /*
+ * Load descriptor table pointers.
+ */
+
+ asm volatile ( "lidt %0" : : "m" (idt_addr) );
+ asm volatile ( "lgdt %0" : : "m" (gdt_addr) );
+
+ /*
+ * ebx := 0 (%%TBD - do not know why, yet)
+ * ecx := kernel entry point
+ * esi := address of boot sector and setup data
+ */
+
+ asm volatile ( "movl %0, %%esi" : : "m" (high_base_mem) );
+ asm volatile ( "movl %0, %%ecx" : : "m" (kentry) );
+ asm volatile ( "xorl %%ebx, %%ebx" : : );
+
+ /*
+ * Jump to kernel entry point.
+ */
+
+
+ asm volatile ( "jmp *%%ecx" : : );
+}
+
+typedef struct sys_img_options {
+ UINT8 nothing_yet;
+} sys_img_options_t;
+
+#endif /* __ELILO_SYSDEPS_IA32_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ * Contributed by Mike Johnston <johnston@intel.com>
+ * Contributed by Chris Ahna <christopher.j.ahna@intel.com>
+ *
+ * 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.
+ */
+
+/*
+ * this file contains all the IA-32 specific code expected by generic loader
+ */
+#include <efi.h>
+#include <efilib.h>
+
+#include "elilo.h"
+#include "loader.h"
+
+#include "rmswitch.h"
+
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* extern loader_ops_t plain_loader, gzip_loader; */
+
+efi_ia32_boot_params_t efi_ia32_bp;
+
+
+/*
+ * Descriptor table base addresses & limits for Linux startup.
+ */
+
+dt_addr_t gdt_addr = { 0x800, 0x94000 };
+dt_addr_t idt_addr = { 0, 0 };
+
+/*
+ * Initial GDT layout for Linux startup.
+ */
+
+UINT16 init_gdt[] = {
+ /* gdt[0]: dummy */
+ 0, 0, 0, 0,
+
+ /* gdt[1]: unused */
+ 0, 0, 0, 0,
+
+ /* gdt[2]: code */
+ 0xFFFF, /* 4Gb - (0x100000*0x1000 = 4Gb) */
+ 0x0000, /* base address=0 */
+ 0x9A00, /* code read/exec */
+ 0x00CF, /* granularity=4096, 386 (+5th nibble of limit) */
+
+ /* gdt[3]: data */
+ 0xFFFF, /* 4Gb - (0x100000*0x1000 = 4Gb) */
+ 0x0000, /* base address=0 */
+ 0x9200, /* data read/write */
+ 0x00CF, /* granularity=4096, 386 (+5th nibble of limit) */
+};
+
+UINTN sizeof_init_gdt = sizeof init_gdt;
+
+
+/*
+ * Highest available base memory address.
+ *
+ * For traditional kernels and loaders this is always at 0x90000.
+ * For updated kernels and loaders this is computed by taking the
+ * highest available base memory address and rounding down to the
+ * nearest 64 kB boundary and then subtracting 64 kB.
+ *
+ * A non-compressed kernel is automatically assumed to be an updated
+ * kernel. A compressed kernel that has bit 6 (0x40) set in the
+ * loader_flags field is also assumed to be an updated kernel.
+ */
+
+UINTN high_base_mem = 0x90000;
+
+/*
+ * Highest available extended memory address.
+ *
+ * This is computed by taking the highest available extended memory
+ * address and rounding down to the nearest EFI_PAGE_SIZE (usually
+ * 4 kB) boundary. The ia32 Linux kernel can only support up to
+ * 2 GB (AFAIK).
+ */
+
+UINTN high_ext_mem = 32 * 1024 * 1024;
+
+/*
+ * Starting location and size of runtime memory blocks.
+ */
+
+boot_params_t *param_start = NULL;
+UINTN param_size = 0;
+
+VOID *kernel_start = (VOID *)0x100000; /* 1M */
+UINTN kernel_size = 0x200000; /* 2M (largest x86 kernel image) */
+
+VOID *initrd_start = NULL;
+UINTN initrd_size = 0;
+
+/*
+ * Boot parameters can be relocated if TRUE.
+ * Boot parameters must be placed at 0x90000 if FALSE.
+ *
+ * This will be set to TRUE if bit 6 (0x40) is set in the loader_flags
+ * field in a compressed x86 boot format kernel. This will also be set
+ * to TRUE if the kernel is an uncompressed ELF32 image.
+ *
+ * To remote boot w/ the universal network driver and a 16-bit UNDI
+ * this must be set to TRUE.
+ */
+
+BOOLEAN can_reloc_boot_params = FALSE;
+
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+static INTN
+probe_bzImage_boot(CHAR16 *kname)
+{
+ EFI_STATUS efi_status;
+ UINTN size;
+ fops_fd_t fd;
+ UINT8 bootsect[512];
+
+ DBG_PRT((L"probe_bzImage_boot()\n"));
+
+ if (!kname) {
+ ERR_PRT((L"kname == %xh", kname));
+ free_kmem();
+ return -1;
+ }
+
+ /*
+ * Open kernel image.
+ */
+
+ DBG_PRT((L"opening %s...\n", kname));
+
+ efi_status = fops_open(kname, &fd);
+
+ if (EFI_ERROR(efi_status)) {
+ ERR_PRT((L"Could not open %s.", kname));
+ free_kmem();
+ return -1;
+ }
+
+ /*
+ * Read boot sector.
+ */
+
+ DBG_PRT((L"\nreading boot sector...\n"));
+
+ size = sizeof bootsect;
+ efi_status = fops_read(fd, bootsect, &size);
+
+ if (EFI_ERROR(efi_status) || size != sizeof bootsect) {
+ ERR_PRT((L"Could not read boot sector from %s.", kname));
+ fops_close(fd);
+ free_kmem();
+ return -1;
+ }
+
+ /*
+ * Verify boot sector signature.
+ */
+
+ if (bootsect[0x1FE] != 0x55 || bootsect[0x1FF] != 0xAA) {
+ ERR_PRT((L"%s is not a bzImage kernel image.\n", kname));
+ fops_close(fd);
+ free_kmem();
+ return -1;
+ }
+
+ /*
+ * Check for out of range setup data size.
+ * Will almost always be 7, but we will accept 1 to 64.
+ */
+
+ DBG_PRT((L"bootsect[1F1h] == %d setup sectors\n", bootsect[0x1F1]));
+
+ if (bootsect[0x1F1] < 1 || bootsect[0x1F1] > 64) {
+ ERR_PRT((L"%s is not a valid bzImage kernel image.",
+ kname));
+
+ fops_close(fd);
+ free_kmem();
+ return -1;
+ }
+
+ /*
+ * Allocate and read setup data.
+ */
+
+ DBG_PRT((L"reading setup data...\n"));
+
+ param_size = (bootsect[0x1F1] + 1) * 512;
+ //param_start = alloc(param_size, EfiBootServicesData);
+ param_start = alloc(param_size, EfiLoaderData);
+
+ DBG_PRT((L"param_size=%d param_start=%x", param_size, param_start));
+
+ if (!param_start) {
+ ERR_PRT((L"Could not allocate %d bytes of setup data.",
+ param_size));
+
+ fops_close(fd);
+ free_kmem();
+ return -1;
+ }
+
+ CopyMem(param_start, bootsect, sizeof bootsect);
+
+ size = param_size - 512;
+ efi_status = fops_read(fd, ((UINT8 *)param_start) + 512, &size);
+
+ if (EFI_ERROR(efi_status) || size != param_size - 512) {
+ ERR_PRT((L"Could not read %d bytes of setup data.",
+ param_size - 512));
+
+ free(param_start);
+ param_start = NULL;
+ param_size = 0;
+ fops_close(fd);
+ free_kmem();
+ return -1;
+ }
+
+ /*
+ * Check for setup data signature.
+ */
+
+ { UINT8 *c = ((UINT8 *)param_start)+514;
+ DBG_PRT((L"param_start(c=%x): %c-%c-%c-%c", c, (CHAR16)c[0],(CHAR16) c[1], (CHAR16)c[2], (CHAR16)c[3]));
+ }
+ if (CompareMem(((UINT8 *)param_start) + 514, "HdrS", 4)) {
+ ERR_PRT((L"%s does not have a setup signature.",
+ kname));
+
+ free(param_start);
+ param_start = NULL;
+ param_size = 0;
+ fops_close(fd);
+ free_kmem();
+ return -1;
+ }
+
+ /*
+ * Allocate memory for kernel.
+ */
+
+ if (alloc_kmem(kernel_start, EFI_SIZE_TO_PAGES(kernel_size))) {
+ ERR_PRT((L"Could not allocate kernel memory."));
+ return -1;
+ } else {
+ VERB_PRT(3, Print(L"kernel_start: 0x%x kernel_size: %d\n", kernel_start, kernel_size));
+ }
+
+ /*
+ * Now read the rest of the kernel image into memory.
+ */
+
+ DBG_PRT((L"reading kernel image...\n"));
+
+ size = kernel_size;
+
+ efi_status = fops_read(fd, kernel_start, &size);
+
+ if (EFI_ERROR(efi_status) || size < 0x10000) {
+ ERR_PRT((L"Error reading kernel image %s.", kname));
+ free(param_start);
+ param_start = NULL;
+ param_size = 0;
+ fops_close(fd);
+ free_kmem();
+ return -1;
+ }
+
+ DBG_PRT((L"kernel image read: %d bytes, %d Kbytes\n", size, size / 1024));
+
+ /*
+ * Boot sector, setup data and kernel image loaded.
+ */
+
+ fops_close(fd);
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+static INTN
+load_bzImage_boot(CHAR16 *kname, kdesc_t *kd)
+{
+ DBG_PRT((L"load_bzImage_boot()\n"));
+
+ if (!kname || !kd) {
+ ERR_PRT((L"kname=0x%x kd=0x%x", kname, kd));
+
+ free(param_start);
+ param_start = NULL;
+ param_size = 0;
+ free_kmem();
+ return -1;
+ }
+
+ kd->kstart = kd->kentry = kernel_start;
+ kd->kend = ((UINT8 *)kd->kstart) + kernel_size;
+
+ DBG_PRT((L"kstart=0x%x kentry=0x%x kend=0x%x\n", kd->kstart, kd->kentry, kd->kend));
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+static loader_ops_t loader_bzImage_boot = {
+ NULL,
+ L"loader_bzImage_boot",
+ &probe_bzImage_boot,
+ &load_bzImage_boot
+};
+
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+INTN
+sysdeps_init(EFI_HANDLE dev)
+{
+
+ DBG_PRT((L"sysdeps_init()\n"));
+
+ /*
+ * Register our loader(s)...
+ */
+
+ loader_register(&loader_bzImage_boot);
+ /* loader_register(&plain_loader); */
+ /* loader_register(&gzip_loader); */
+
+
+ return 0;
+}
+
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*
+ * 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.
+ */
+INTN
+sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem)
+{
+ DBG_PRT((L"initrd_get_addr()\n"));
+
+ if (!kd || !imem) {
+ ERR_PRT((L"kd=0x%x imem=0x%x", kd, imem));
+ return -1;
+ }
+
+ VERB_PRT(3, Print(L"kstart=0x%x kentry=0x%x kend=0x%x\n",
+ kd->kstart, kd->kentry, kd->kend));
+
+ imem->start_addr = kd->kend;
+
+ VERB_PRT(3, Print(L"initrd start_addr=0x%x pgcnt=%d\n", imem->start_addr, imem->pgcnt));
+
+ return 0;
+}
+
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+VOID
+sysdeps_free_boot_params(boot_params_t *bp)
+{
+ mmap_desc_t md;
+
+ ZeroMem(&md, sizeof md);
+ md.md = (VOID *)bp->s.efi_mem_map;
+ free_memmap(&md);
+}
+
+/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*
+ * IA-32 specific boot parameters initialization routine
+ */
+INTN
+sysdeps_create_boot_params(
+ boot_params_t *bp,
+ CHAR8 *cmdline,
+ memdesc_t *initrd,
+ UINTN *cookie)
+{
+ mmap_desc_t mdesc;
+ EFI_STATUS efi_status;
+ UINTN rows, cols;
+ UINT8 row, col;
+ UINT8 mode;
+ UINT16 hdr_version;
+
+ DBG_PRT((L"fill_boot_params()\n"));
+
+ if (!bp || !cmdline || !initrd || !cookie) {
+ ERR_PRT((L"bp=0x%x cmdline=0x%x initrd=0x%x cookie=0x%x",
+ bp, cmdline, initrd, cookie));
+
+ free(param_start);
+ param_start = NULL;
+ param_size = 0;
+ free_kmem();
+ return -1;
+ }
+
+ /*
+ * Copy temporary boot sector and setup data storage to
+ * elilo allocated boot parameter storage. We only need
+ * the first two sectors (1K). The rest of the storage
+ * can be used by the command line.
+ */
+
+ CopyMem(bp, param_start, 0x2000);
+
+ free(param_start);
+ param_start = NULL;
+ param_size = 0;
+
+ /*
+ * Save off our header revision information.
+ */
+
+ hdr_version = (bp->s.hdr_major << 8) | bp->s.hdr_minor;
+
+ /*
+ * Clear out unused memory in boot sector image.
+ */
+
+ 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_5, sizeof bp->s.unused_5);
+ bp->s.unused_6 = 0;
+
+ /*
+ * Tell kernel this was loaded by an advanced loader type.
+ * If this field is zero, the initrd_start and initrd_size
+ * fields are ignored by the kernel.
+ */
+
+ bp->s.loader_type = LDRTYPE_ELILO;
+
+ /*
+ * Setup command line information.
+ */
+
+ bp->s.cmdline_magik = CMDLINE_MAGIK;
+ bp->s.cmdline_offset = (UINT8 *)cmdline - (UINT8 *)bp;
+
+ /*
+ * Setup hard drive parameters.
+ * %%TBD - It should be okay to zero fill the hard drive
+ * info buffers. The kernel should do its own detection.
+ */
+
+ ZeroMem(bp->s.hd0_info, sizeof bp->s.hd0_info);
+ ZeroMem(bp->s.hd1_info, sizeof bp->s.hd1_info);
+
+#if 0
+ CopyMem(bp->s.hd0_info, *((VOID **)(0x41 * 4)),
+ sizeof bp->s.hd0_info);
+
+ CopyMem(bp->s.hd1_info, *((VOID **)(0x46 * 4)),
+ sizeof bp->s.hd1_info);
+#endif
+
+ /*
+ * Memory info.
+ */
+
+ bp->s.alt_mem_k = high_ext_mem / 1024;
+
+ if (bp->s.alt_mem_k <= 65535) {
+ bp->s.ext_mem_k = (UINT16)bp->s.alt_mem_k;
+ } else {
+ bp->s.ext_mem_k = 65535;
+ }
+
+ if (hdr_version < 0x0202)
+ bp->s.base_mem_size = high_base_mem;
+
+ /*
+ * Initial RAMdisk and root device stuff.
+ */
+
+ DBG_PRT((L"initrd->start_addr=0x%x initrd->pgcnt=%d\n",
+ initrd->start_addr, initrd->pgcnt));
+
+ /* These RAMdisk flags are not needed, just zero them. */
+ bp->s.ramdisk_flags = 0;
+
+ if (initrd->start_addr && initrd->pgcnt) {
+ /* %%TBD - This will probably have to be changed. */
+ bp->s.initrd_start = (UINT32)initrd->start_addr;
+ bp->s.initrd_size = (UINT32)(initrd->pgcnt * EFI_PAGE_SIZE);
+
+ /*
+ * This is the RAMdisk root device for RedHat 2.2.x
+ * kernels (major 0x01, minor 0x00).
+ * %%TBD - Will this work for other distributions and
+ * 2.3.x and 2.4.x kernels? I do not know, yet.
+ */
+
+ bp->s.orig_root_dev = 0x0100;
+ } else {
+ bp->s.initrd_start = 0;
+ bp->s.initrd_size = 0;
+
+ /* Do not change the root device if there is no RAMdisk. */
+ /* bp->s.orig_root_dev = 0; */
+ }
+
+ /*
+ * APM BIOS info.
+ */
+
+/* %%TBD - How to do Int 15h calls to get this info? */
+ bp->s.apm_bios_ver = NO_APM_BIOS;
+ bp->s.bios_code_seg = 0;
+ bp->s.bios_entry_point = 0;
+ bp->s.bios_code_seg16 = 0;
+ bp->s.bios_data_seg = 0;
+ bp->s.apm_bios_flags = 0;
+ bp->s.bios_code_len = 0;
+ bp->s.bios_data_len = 0;
+
+ /*
+ * MCA BIOS info (misnomer).
+ */
+
+/* %%TBD - How to do Int 15h call to get this info? */
+ bp->s.mca_info_len = 0;
+ ZeroMem(bp->s.mca_info_buf, sizeof bp->s.mca_info_buf);
+
+ /*
+ * Pointing device presence.
+ */
+
+/* %%TBD - How to do Int 11h call to get this info? */
+ bp->s.aux_dev_info = NO_MOUSE;
+
+ /*
+ * EFI loader signature and address of EFI system table.
+ */
+
+ CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG, 4);
+ bp->s.efi_sys_tbl = 0; /* %%TBD */
+
+ /*
+ * Kernel entry point.
+ */
+
+ bp->s.kernel_start = (UINT32)kernel_start;
+
+ /*
+ * When changing stuff in the parameter structure compare
+ * the offsets of the fields with the offsets used in the
+ * boot sector and setup source files.
+ * arch/i386/boot/bootsect.S
+ * arch/i386/boot/setup.S
+ * arch/i386/kernel/setup.c
+ */
+
+#define CHECK_OFFSET(n, o, f) \
+{ \
+ UINTN p = (UINT8 *)&bp->s.n - (UINT8 *)bp; \
+ UINTN q = (UINTN)(o); \
+ if (p != q) { \
+ test |= 1; \
+ Print(L"%20a: %3xh %3xh ", #n, p, q); \
+ if (*f) { \
+ Print(f, bp->s.n); \
+ } \
+ Print(L"\n"); \
+ } \
+}
+
+#define WAIT_FOR_KEY() \
+{ \
+ EFI_INPUT_KEY key; \
+ while (ST->ConIn->ReadKeyStroke(ST->ConIn, &key) != EFI_SUCCESS) { \
+ ; \
+ } \
+}
+
+ {
+ UINTN test = 0;
+
+ CHECK_OFFSET(orig_cursor_col, 0x00, L"%xh");
+ CHECK_OFFSET(orig_cursor_row, 0x01, L"%xh");
+ CHECK_OFFSET(ext_mem_k, 0x02, L"%xh");
+ CHECK_OFFSET(orig_video_page, 0x04, L"%xh");
+ CHECK_OFFSET(orig_video_mode, 0x06, L"%xh");
+ CHECK_OFFSET(orig_video_cols, 0x07, L"%xh");
+ CHECK_OFFSET(orig_ega_bx, 0x0A, L"%xh");
+ CHECK_OFFSET(orig_video_rows, 0x0E, L"%xh");
+ CHECK_OFFSET(is_vga, 0x0F, L"%xh");
+ CHECK_OFFSET(orig_video_points, 0x10, L"%xh");
+ CHECK_OFFSET(lfb_width, 0x12, L"%xh");
+ CHECK_OFFSET(lfb_height, 0x14, L"%xh");
+ CHECK_OFFSET(lfb_depth, 0x16, L"%xh");
+ CHECK_OFFSET(lfb_base, 0x18, L"%xh");
+ CHECK_OFFSET(lfb_size, 0x1C, L"%xh");
+ CHECK_OFFSET(cmdline_magik, 0x20, L"%xh");
+ CHECK_OFFSET(cmdline_offset, 0x22, L"%xh");
+ CHECK_OFFSET(lfb_line_len, 0x24, L"%xh");
+ CHECK_OFFSET(lfb_red_size, 0x26, L"%xh");
+ CHECK_OFFSET(lfb_red_pos, 0x27, L"%xh");
+ CHECK_OFFSET(lfb_green_size, 0x28, L"%xh");
+ CHECK_OFFSET(lfb_green_pos, 0x29, L"%xh");
+ CHECK_OFFSET(lfb_blue_size, 0x2A, L"%xh");
+ CHECK_OFFSET(lfb_blue_pos, 0x2B, L"%xh");
+ CHECK_OFFSET(lfb_rsvd_size, 0x2C, L"%xh");
+ CHECK_OFFSET(lfb_rsvd_pos, 0x2D, L"%xh");
+ CHECK_OFFSET(vesa_seg, 0x2E, L"%xh");
+ CHECK_OFFSET(vesa_off, 0x30, L"%xh");
+ CHECK_OFFSET(lfb_pages, 0x32, L"%xh");
+ CHECK_OFFSET(lfb_reserved, 0x34, L"");
+ CHECK_OFFSET(apm_bios_ver, 0x40, L"%xh");
+ CHECK_OFFSET(bios_code_seg, 0x42, L"%xh");
+ CHECK_OFFSET(bios_entry_point, 0x44, L"%xh");
+ CHECK_OFFSET(bios_code_seg16, 0x48, L"%xh");
+ CHECK_OFFSET(bios_data_seg, 0x4A, L"%xh");
+ CHECK_OFFSET(apm_bios_flags, 0x4C, L"%xh");
+ CHECK_OFFSET(bios_code_len, 0x4E, L"%xh");
+ CHECK_OFFSET(bios_data_len, 0x52, L"%xh");
+ CHECK_OFFSET(hd0_info, 0x80, L"");
+ CHECK_OFFSET(hd1_info, 0x90, L"");
+ CHECK_OFFSET(mca_info_len, 0xA0, L"%xh");
+ CHECK_OFFSET(mca_info_buf, 0xA2, L"");
+ CHECK_OFFSET(efi_loader_sig, 0x1C0, L"'%-4.4a'");
+ CHECK_OFFSET(efi_sys_tbl, 0x1C4, L"%xh");
+ CHECK_OFFSET(efi_mem_desc_size, 0x1C8, L"%xh");
+ CHECK_OFFSET(efi_mem_desc_ver, 0x1CC, L"%xh");
+ CHECK_OFFSET(efi_mem_map, 0x1D0, L"%xh");
+ CHECK_OFFSET(efi_mem_map_size, 0x1D4, L"%xh");
+ CHECK_OFFSET(loader_start, 0x1D8, L"%xh");
+ CHECK_OFFSET(loader_size, 0x1DC, L"%xh");
+ CHECK_OFFSET(alt_mem_k, 0x1E0, L"%xh");
+ 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(jump, 0x200, L"%xh");
+ CHECK_OFFSET(setup_sig, 0x202, L"'%-4.4a'");
+ CHECK_OFFSET(hdr_minor, 0x206, L"%xh");
+ CHECK_OFFSET(hdr_major, 0x207, L"%xh");
+ CHECK_OFFSET(rm_switch, 0x208, L"%xh");
+ CHECK_OFFSET(start_sys_seg, 0x20C, L"%xh");
+ CHECK_OFFSET(kernel_verstr_offset, 0x20E, L"%xh");
+ CHECK_OFFSET(loader_type, 0x210, L"%xh");
+ CHECK_OFFSET(loader_flags, 0x211, L"%xh");
+ CHECK_OFFSET(setup_move_size, 0x212, L"%xh");
+ 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(base_mem_size, 0x226, L"%xh");
+
+ if (test) {
+ ERR_PRT((L"Boot sector and/or setup parameter alignment error."));
+ free_kmem();
+ return -1;
+ }
+ }
+
+ /*
+ * Get video information.
+ * Do this last so that any other cursor positioning done
+ * in the fill routine gets accounted for.
+ */
+
+ efi_status = ST->ConOut->QueryMode(
+ ST->ConOut,
+ ST->ConOut->Mode->Mode,
+ &cols,
+ &rows);
+
+ if (EFI_ERROR(efi_status)) {
+ ERR_PRT((L"QueryMode failed. Fake it."));
+
+ mode = 3;
+ rows = 25;
+ cols = 80;
+ row = 24;
+ col = 0;
+ } else {
+ mode = (UINT8)ST->ConOut->Mode->Mode;
+ col = (UINT8)ST->ConOut->Mode->CursorColumn;
+ row = (UINT8)ST->ConOut->Mode->CursorRow;
+ }
+
+ bp->s.orig_cursor_col = col;
+ bp->s.orig_cursor_row = row;
+ bp->s.orig_video_page = 0;
+ bp->s.orig_video_mode = mode;
+ bp->s.orig_video_cols = (UINT8)cols;
+ bp->s.orig_video_rows = (UINT8)rows;
+
+/* %%TBD - How to do Int 10h calls to get video info? */
+ bp->s.orig_ega_bx = 0;
+ bp->s.is_vga = 0;
+ bp->s.orig_video_points = 0;
+
+/* %%TBD - How to do Int 10h calls to get frame buffer info? */
+ bp->s.lfb_width = 0;
+ bp->s.lfb_height = 0;
+ bp->s.lfb_depth = 0;
+ bp->s.lfb_base = 0;
+ bp->s.lfb_size = 0;
+ bp->s.lfb_line_len = 0;
+ bp->s.lfb_red_size = 0;
+ bp->s.lfb_red_pos = 0;
+ bp->s.lfb_green_size = 0;
+ bp->s.lfb_green_pos = 0;
+ bp->s.lfb_blue_size = 0;
+ bp->s.lfb_blue_pos = 0;
+ bp->s.lfb_rsvd_size = 0;
+ bp->s.lfb_rsvd_pos = 0;
+ bp->s.lfb_pages = 0;
+ bp->s.vesa_seg = 0;
+ bp->s.vesa_off = 0;
+
+ /*
+ * Get memory map description and cookie for ExitBootServices()
+ */
+
+ if (get_memmap(&mdesc)) {
+ ERR_PRT((L"Could not get memory map."));
+ free_kmem();
+ return -1;
+ }
+
+ *cookie = mdesc.cookie;
+ bp->s.efi_mem_map = (UINTN)mdesc.md;
+ bp->s.efi_mem_map_size = mdesc.map_size;
+ bp->s.efi_mem_desc_size = mdesc.desc_size;
+ bp->s.efi_mem_desc_ver = mdesc.desc_version;
+ bp->s.efi_sys_tbl = (UINTN)systab;
+
+ /*
+ * my_ia32_boot_params and get ready to slap them into 0x00104c00
+ */
+
+ efi_ia32_bp.size= sizeof(efi_ia32_bp);
+ efi_ia32_bp.command_line = (UINT32) cmdline;
+ efi_ia32_bp.efi_sys_tbl = bp->s.efi_sys_tbl;
+ efi_ia32_bp.efi_mem_map = bp->s.efi_mem_map;
+ efi_ia32_bp.efi_mem_map_size = bp->s.efi_mem_map_size;
+ efi_ia32_bp.efi_mem_desc_size = bp->s.efi_mem_desc_size;
+ efi_ia32_bp.efi_mem_desc_version = bp->s.efi_mem_desc_ver;
+ efi_ia32_bp.initrd_start = (UINTN)initrd->start_addr;
+ efi_ia32_bp.initrd_size = initrd->pgcnt * EFI_PAGE_SIZE;
+ efi_ia32_bp.loader_start = 0;
+ efi_ia32_bp.loader_size = 0;
+ efi_ia32_bp.kernel_start = bp->s.kernel_start;
+ efi_ia32_bp.kernel_size = kernel_size;
+ efi_ia32_bp.num_cols = cols;
+ efi_ia32_bp.num_rows = rows;
+ efi_ia32_bp.orig_x = col;
+ efi_ia32_bp.orig_y = row;
+
+
+ return 0;
+}
--- /dev/null
+#
+# Copyright (C) 2001-2003 Hewlett-Packard Co.
+# Contributed by Stephane Eranian <eranian@hpl.hp.com>
+#
+# 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 ../Make.defaults
+include ../Make.rules
+
+TOPDIR=$(CDIR)/..
+
+FILES=system.o config.o fpswa.o plain_loader.o gzip_loader.o \
+ gzip.o memset.o memcpy.o setjmp.o longjmp.o
+
+TARGET=sysdeps.o
+
+all: $(TARGET)
+
+$(TARGET): $(FILES)
+ $(LD) -o $@ -r $(FILES)
+
+clean:
+ $(RM) -f $(TARGET) $(FILES)
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 "config.h"
+#include "private.h"
+#include "sysdeps.h"
+#include "getopt.h"
+
+typedef struct {
+ CHAR16 fpswa[FILENAME_MAXLEN];
+ CHAR16 cmd_fpswa[FILENAME_MAXLEN];
+ UINTN allow_relocation;
+} ia64_global_config_t;
+
+#define ia64_opt_offsetof(option) (&((sys_img_options_t *)(0x0))->option)
+
+static ia64_global_config_t ia64_gconf;
+
+/*
+ * No IA-64 specific options at this point
+ * The last entry in each table MUST be use the OPT_NULL type to terminate
+ * the chain.
+ */
+config_option_t sysdeps_global_options[]={
+ {OPT_FILE, OPT_GLOBAL, L"fpswa", NULL, NULL, ia64_gconf.fpswa},
+ {OPT_BOOL, OPT_GLOBAL, L"relocatable", NULL, NULL, &ia64_gconf.allow_relocation},
+};
+
+config_option_t sysdeps_image_options[]={
+ {OPT_BOOL, OPT_IMAGE_SYS, L"relocatable", NULL, NULL, ia64_opt_offsetof(allow_relocation)},
+};
+
+
+/*
+ * IA-64 operations that need to be done only once and just before
+ * entering the main loop of the loader
+ * Return:
+ * 0 if sucessful
+ * -1 otherwise (will abort execution)
+ */
+INTN
+sysdeps_preloop_actions(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image)
+{
+ /*
+ * we have separate string to make sure that the command line take precedence over
+ * the config file
+ */
+ if (ia64_gconf.cmd_fpswa[0] != CHAR_NULL) {
+ check_fpswa(image, dev, ia64_gconf.cmd_fpswa);
+ } else if (ia64_gconf.fpswa[0] != CHAR_NULL)
+ check_fpswa(image, dev, ia64_gconf.fpswa);
+ else
+ check_fpswa(image, dev, NULL);
+
+ return 0;
+}
+
+/*
+ * Return:
+ * 1: if image or global configuration allows relocation
+ * 0: otherwise
+ *
+ * It is written has a function rather than a macro to avoid
+ * exposing config data structure to the rest of the code in ia64
+ */
+INTN
+ia64_can_relocate(VOID)
+{
+ return ia64_gconf.allow_relocation == TRUE
+ || (elilo_opt.sys_img_opts && elilo_opt.sys_img_opts->allow_relocation ==TRUE) ? 1 : 0;
+}
+
+#define IA64_CMDLINE_OPTIONS L"rF:"
+
+CHAR16 *
+sysdeps_get_cmdline_opts(VOID)
+{
+ return IA64_CMDLINE_OPTIONS;
+}
+
+INTN
+sysdeps_getopt(INTN c, INTN optind, CHAR16 *optarg)
+{
+ INTN ret = 0; /* let's be optimistic ! */
+
+ /*
+ * XXX: for now these command line options have to be global
+ */
+ switch(c) {
+ case L'r':
+ ia64_gconf.allow_relocation = 1;
+ break;
+ case L'F':
+ if (StrLen(Optarg) >= FILENAME_MAXLEN) {
+ Print(L"FPSWA filename is limited to %d characters\n", FILENAME_MAXLEN);
+ return -1;
+ }
+ StrCpy(ia64_gconf.cmd_fpswa, Optarg);
+ break;
+ default:
+ ret = -1;
+ }
+ return ret;
+}
+
+VOID
+sysdeps_print_cmdline_opts(VOID)
+{
+ Print(L"-r kernel image can be relocated if load address inexistent\n");
+ Print(L"-F file name of a specific FPSWA EFI driver to load\n");
+}
+
+INTN
+sysdeps_register_options(VOID)
+{
+ INTN ret;
+
+ ret = register_config_options(sysdeps_global_options,
+ sizeof(sysdeps_global_options)/sizeof(config_option_t),
+ OPTIONS_GROUP_GLOBAL);
+ if (ret == -1 ) return ret;
+
+ ret = register_config_options(sysdeps_image_options,
+ sizeof(sysdeps_image_options)/sizeof(config_option_t),
+ OPTIONS_GROUP_IMAGE);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 "fileops.h"
+
+typedef struct {
+ UINT32 revision;
+ UINT32 reserved;
+ VOID *fpswa;
+} fpswa_interface_t;
+
+INTN
+query_fpswa(VOID **fpswa)
+{
+ EFI_HANDLE fpswa_image;
+ UINTN size;
+ EFI_STATUS status;
+ EFI_GUID FpswaProtocol = FPSWA_PROTOCOL;
+
+ DBG_PRT((L"Querying FpswaProtocol"));
+
+ size = sizeof(EFI_HANDLE);
+
+ status = BS->LocateHandle(ByProtocol, &FpswaProtocol, NULL, &size, &fpswa_image);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"boot_params could not locate FPSWA driver", status));
+ return -1;
+ }
+ status = BS->HandleProtocol(fpswa_image, &FpswaProtocol, fpswa);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"boot_params FpswaProtocol not able find the interface"));
+ return -1;
+ }
+ VERB_PRT(3, Print(L"FpswaProtocol = 0x%lx revision=%x\n", *fpswa,
+ ((fpswa_interface_t *)*fpswa)->revision));
+ return 0;
+}
+
+
+static INTN
+do_check_fpswa(EFI_HANDLE image, EFI_HANDLE dev, CHAR16 *fpswa_file)
+{
+ EFI_STATUS status;
+ EFI_HANDLE handle;
+ EFI_DEVICE_PATH *dp;
+
+
+ dp = FileDevicePath(dev, fpswa_file);
+ if (dp == NULL) {
+ ERR_PRT((L"Cannot create FilePath for %s", fpswa_file));
+ return -1;
+ }
+ status = BS->LoadImage(0, image, dp, NULL, 0, &handle);
+ if (EFI_ERROR(status)) {
+ VERB_PRT(3, Print(L"..not found\n"));
+ FreePool(dp);
+ return -1;
+ }
+ VERB_PRT(3, Print(L"..starting.."));
+
+ status = BS->StartImage(handle, 0, 0);
+ if (EFI_ERROR(status)) {
+ VERB_PRT(3, Print(L"failed (%r)\n", status));
+ /*
+ * StartImage() automatically unloads if error
+ * FPSWA init code will automatically abort if newer revision
+ * is already installed
+ */
+ } else {
+ VERB_PRT(3, Print(L"..ok\n"));
+ }
+ FreePool(dp);
+
+ return 0;
+}
+
+/*
+ * If the caller specifies a fpswa filename, then it used instead of the
+ * defaults.
+ * Return:
+ * 0 : indicates that one fpswa driver was loaded, i.e. an update could be done
+ * -1: no update was found that would have a more recent version of the driver. This is
+ * not a fatal return value.
+ */
+INTN
+check_fpswa(EFI_HANDLE image, EFI_HANDLE dev, CHAR16 *fpswa_file)
+{
+ /*
+ * we must use \\ here as this is given to LoadImage() directly
+ *
+ * The FPSWA driver MUST be called fpswa.efi and the FPSWA document
+ * (see developer.intel.com/design/itanium) stipulates that the
+ * file must be placed in \EFI\Intel Firmware\ (no mention of which
+ * EFI system partition). So elilo will check on all accessible
+ * Fat32+ partition for the existence of this directory and file.
+ */
+ static CHAR16 *fpswa_filenames[] ={
+ L"\\efi\\intel firmware\\fpswa.efi",
+#if 0
+ L"\\fpswa.efi",
+ L"\\fw\\fpswa.efi",
+ L"\\efi\\fpswa.efi",
+ L"\\efi\\tools\\fpswa.efi",
+ L"\\fpswa.efi",
+ L"fpswa.efi",
+#endif
+ };
+ UINTN j, count = sizeof(fpswa_filenames)/sizeof(CHAR16 *);
+ INTN cookie;
+ CHAR16 devname[FILENAME_MAXLEN];
+
+ if (fpswa_file) {
+ INTN r;
+ devname[0] = CHAR_NULL;
+ r = fops_split_path(fpswa_file, devname);
+ if (r == -1) {
+ ERR_PRT((L"FPSWA driver filename too long %s", fpswa_file));
+ return -1;
+ }
+ if (devname[0] != CHAR_NULL) {
+ if (fops_get_device_handle(devname, &dev) != EFI_SUCCESS) {
+ ERR_PRT((L"cannot find device %s for FPSWA driver", devname));
+ return -1;
+ }
+ }
+ return do_check_fpswa(image, dev, fpswa_file);
+ }
+
+ cookie = 0;
+ while (fops_get_next_device(cookie, L"vfat", FILENAME_MAXLEN, &cookie, devname, &dev) == EFI_SUCCESS) {
+ for (j = 0; j < count; j++) {
+ VERB_PRT(3, Print(L"Trying FPSWA driver %s:%s..", devname, fpswa_filenames[j]));
+ /*
+ * we need to do all choices to make sure we pickup
+ * the latest version.
+ */
+ do_check_fpswa(image, dev, fpswa_filenames[j]);
+ }
+ }
+ return -1;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * Copyright (C) 2001 Silicon Graphics, Inc.
+ * Contributed by Brent Casavant <bcasavan@sgi.com>
+ *
+ * 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 "elf.h"
+#include "elilo.h"
+
+#include "gzip.h"
+
+#include "private.h"
+#include "setjmp.h"
+
+#define memzero(s, n) Memset((VOID *)(s), 0, (n))
+#define memcpy(a,b,n) Memcpy((VOID *)(a),(b),(n))
+
+/* size of output buffer */
+#define WSIZE 0x8000 /* Window size must be at least 32k, */
+ /* and a power of two */
+/* size of input buffer */
+#define INBUFSIZE 0x8000
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args) args
+#define FUNC_STATIC static
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+
+typedef struct segment {
+ unsigned long addr; /* start address */
+ unsigned long offset; /* file offset */
+ unsigned long size; /* file size */
+ unsigned long bss_sz; /* BSS size */
+ UINT8 flags; /* indicates whether to load or not */
+} segment_t;
+
+#define CHUNK_FL_VALID 0x1
+#define CHUNK_FL_LOAD 0x2
+
+#define CHUNK_CAN_LOAD(n) chunks[(n)].flags |= CHUNK_FL_LOAD
+#define CHUNK_NO_LOAD(n) chunks[(n)].flags &= ~CHUNK_FL_LOAD
+#define CHUNK_IS_LOAD(n) (chunks[(n)].flags & CHUNK_FL_LOAD)
+
+#define CHUNK_VALIDATE(n) chunks[(n)].flags |= CHUNK_FL_VALID
+#define CHUNK_INVALIDATE(n) chunks[(n)].flags = 0
+#define CHUNK_IS_VALID(n) (chunks[(n)].flags & CHUNK_FL_VALID)
+
+/*
+ * static parameters to gzip helper functions
+ * we cannot use paramters because API was not
+ * designed that way
+ */
+static segment_t *chunks; /* holds the list of segments */
+static segment_t *cur_chunk;
+static UINTN nchunks;
+static UINTN chunk; /* current segment */
+static UINTN input_fd;
+static VOID *kernel_entry, *kernel_base, *kernel_end;
+
+static uch *inbuf; /* input buffer (compressed data) */
+static uch *window; /* output buffer (uncompressed data) */
+static unsigned long file_offset; /* position in the file */
+
+static unsigned insize = 0; /* valid bytes in inbuf */
+static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
+static unsigned outcnt = 0; /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* Diagnostic functions */
+#ifdef INFLATE_DEBUG
+# define Assert(cond,msg) {if(!(cond)) error(msg);}
+int stderr;
+# define Trace(x) Print(L"line %d:\n", __LINE__);
+# define Tracev(x) {if (verbose) Print(L"line %d:\n", __LINE__) ;}
+# define Tracevv(x) {if (verbose>1) Print(L"line %d:\n", __LINE__) ;}
+# define Tracec(c,x) {if (verbose && (c)) Print(L"line %d:\n", __LINE__) ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) Print(L"line %d:\n", __LINE__) ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+static int fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static long bytes_out;
+
+static void error(char *m);
+
+static jmp_buf jbuf;
+static int error_return;
+static UINTN elf_is_big_endian; /* true if ELF file is big endian */
+
+static void *
+gzip_malloc(int size)
+{
+ return (void *)alloc(size, 0);
+}
+
+static void
+gzip_free(void *where)
+{
+ return free(where);
+}
+
+#include "inflate.c"
+
+/*
+ * Fill the input buffer and return the first byte in it. This is called
+ * only when the buffer is empty and at least one byte is really needed.
+ */
+int
+fill_inbuf(void)
+{
+ INTN expected, nread;
+ EFI_STATUS status;
+
+ expected = nread = INBUFSIZE;
+
+ status = fops_read(input_fd, inbuf, &nread);
+ if (EFI_ERROR(status)) {
+ error("elilo: Read failed");
+ }
+ DBG_PRT((L"%s : read %d bytes of %d bytes\n", LD_NAME, nread, expected));
+
+ insize = nread;
+ inptr = 1;
+
+ return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+
+/*
+ * Run a set of bytes through the crc shift register. If s is a NULL
+ * pointer, then initialize the crc shift register contents instead.
+ * Return the current crc in either case.
+ *
+ * Input:
+ * S pointer to bytes to pump through.
+ * N number of bytes in S[].
+ */
+unsigned long
+updcrc(unsigned char *s, unsigned n)
+{
+ register unsigned long c;
+ /* crc is defined in inflate.c */
+
+ if (!s) {
+ c = 0xffffffffL;
+ } else {
+ c = crc;
+ while (n--) {
+ c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
+ }
+ }
+ crc = c;
+ return c ^ 0xffffffffUL; /* (instead of ~c for 64-bit machines) */
+}
+
+
+/*
+ * Clear input and output buffers
+ */
+void
+clear_bufs(void)
+{
+ outcnt = 0;
+ inptr = 0;
+ chunk = 0;
+ cur_chunk = NULL;
+ file_offset = 0;
+}
+
+
+static inline UINT64
+bswap64(UINT64 v)
+{
+ if(elf_is_big_endian) v = __ia64_swab64(v);
+ return v;
+}
+
+static inline UINT32
+bswap32(UINT32 v)
+{
+ if(elf_is_big_endian) v = __ia64_swab32(v);
+ return v;
+}
+
+static inline UINT16
+bswap16(UINT16 v)
+{
+ if(elf_is_big_endian) v = __ia64_swab16(v);
+ return v;
+}
+
+static INTN
+is_valid_header(Elf64_Ehdr *ehdr)
+{
+ UINT16 type, machine;
+
+ if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
+ type = __ia64_swab16(ehdr->e_type);
+ machine = __ia64_swab16(ehdr->e_machine);
+ } else {
+ type = ehdr->e_type;
+ machine = ehdr->e_machine;
+ }
+ VERB_PRT(3, Print(L"class=%d type=%d data=%d machine=%d\n",
+ ehdr->e_ident[EI_CLASS],
+ type,
+ ehdr->e_ident[EI_DATA],
+ machine));
+
+ return ehdr->e_ident[EI_MAG0] == 0x7f
+ && ehdr->e_ident[EI_MAG1] == 'E'
+ && ehdr->e_ident[EI_MAG2] == 'L'
+ && ehdr->e_ident[EI_MAG3] == 'F'
+ && ehdr->e_ident[EI_CLASS] == ELFCLASS64
+ && type == ET_EXEC /* must be executable */
+ && machine == EM_IA_64 ? 0 : -1;
+}
+
+/*
+ * will invalidate loadble segments which overlap with others
+ */
+void
+check_overlap(int i)
+{
+ int j;
+ unsigned long iend = chunks[i].addr + chunks[i].size;
+
+ for(j=0; j < nchunks; j++) {
+ if (j ==i) continue;
+ if (chunks[i].addr >= chunks[j].addr && iend < (chunks[j].addr + chunks[j].size)) {
+ DBG_PRT((L"%s : segment %d fully included in segment %d\n", LD_NAME, i, j));
+ CHUNK_INVALIDATE(i); /* nullyify segment */
+ break;
+ }
+ }
+}
+
+void
+analyze_chunks(void)
+{
+ INTN i;
+
+ for(i=0; i < nchunks; i++) {
+ if (CHUNK_IS_VALID(i) && !CHUNK_IS_LOAD(i)) check_overlap(i);
+ }
+}
+
+
+/*
+ * The decompression code calls this function after decompressing the
+ * first block of the object file. The first block must contain all
+ * the relevant header information.
+ */
+int
+first_block (const char *buf, long blocksize)
+{
+ Elf64_Ehdr *elf;
+ Elf64_Phdr *phdrs;
+ UINTN total_size, pages;
+ UINTN low_addr, max_addr;
+ UINTN load_offset = 0;
+ UINTN offs = 0;
+ UINT16 phnum;
+ UINTN paddr, memsz;
+ INTN i;
+
+ elf = (Elf64_Ehdr *)buf;
+
+ if (is_valid_header(elf) == -1) return -1;
+
+ /* determine file endianess */
+ elf_is_big_endian = elf->e_ident[EI_DATA] == ELFDATA2MSB ? 1 : 0;
+
+
+ offs = bswap64(elf->e_phoff);
+ phnum = bswap16(elf->e_phnum);
+
+ VERB_PRT(3, {
+ Print(L"ELF file is %s\n", elf_is_big_endian ? L"big endian" : L"little endian");
+ Print(L"Entry point 0x%lx\n", bswap64(elf->e_entry));
+ Print(L"%d program headers\n", phnum);
+ Print(L"%d segment headers\n", bswap16(elf->e_shnum));
+ });
+
+
+ /* XXX: need to check on this */
+ if (offs + phnum * sizeof(*phdrs) > (unsigned) blocksize) {
+ ERR_PRT((L"%s : ELF program headers not in first block (%ld)\n", LD_NAME, offs));
+ return -1;
+ }
+
+ kernel_entry = (void *)bswap64(elf->e_entry);
+
+ if (((UINTN)kernel_entry >> 61) != 0) {
+ ERR_PRT((L"%s: <<ERROR>> entry point is a virtual address 0x%lx : not supported anymore\n", LD_NAME, kernel_entry));
+ }
+
+ phdrs = (Elf64_Phdr *) (buf + offs);
+
+ low_addr = ~0;
+ max_addr = 0;
+
+ /*
+ * allocate chunk table
+ * Convention: a segment that does not need loading will
+ * have chunk[].addr = 0.
+ */
+ chunks = (void *)alloc(sizeof(struct segment)*phnum, 0);
+ if (chunks == NULL) {
+ ERR_PRT((L"%s : failed alloc chunks %r\n", LD_NAME));
+ return -1;
+ }
+ nchunks = phnum;
+ /*
+ * find lowest and higest virtual addresses
+ * don't assume FULLY sorted !
+ */
+ for (i = 0; i < phnum; ++i) {
+
+ /*
+ * record chunk no matter what because no load may happen
+ * anywhere in archive, not just as the last segment
+ */
+ paddr = bswap64(phdrs[i].p_paddr);
+ memsz = bswap64(phdrs[i].p_memsz),
+
+ chunks[i].addr = paddr;
+ chunks[i].offset = bswap64(phdrs[i].p_offset);
+ chunks[i].size = bswap64(phdrs[i].p_filesz);
+ chunks[i].bss_sz = bswap64(phdrs[i].p_memsz) - bswap64(phdrs[i].p_filesz);
+
+ CHUNK_VALIDATE(i);
+
+ if (bswap32(phdrs[i].p_type) != PT_LOAD) {
+ CHUNK_NO_LOAD(i); /* mark no load chunk */
+ DBG_PRT((L"%s : skipping segment %ld\n", LD_NAME, i));
+ continue;
+ }
+
+ CHUNK_CAN_LOAD(i); /* mark no load chunk */
+
+ VERB_PRT(3,
+ Print(L"\n%s : segment %ld vaddr [0x%lx-0x%lx] offset %ld filesz %ld memsz=%ld bss_sz=%ld\n",
+ LD_NAME,
+ 1+i,
+ chunks[i].addr,
+ chunks[i].addr+bswap64(phdrs[i].p_filesz),
+ chunks[i].offset,
+ chunks[i].size,
+ memsz,
+ chunks[i].bss_sz));
+
+ if (paddr < low_addr) low_addr = paddr;
+
+ if (paddr + memsz > max_addr) max_addr = paddr + memsz;
+ }
+
+ if (low_addr & (EFI_PAGE_SIZE - 1)) {
+ ERR_PRT((L"%s : low_addr not page aligned 0x%lx\n", LD_NAME, low_addr));
+ goto error;
+ }
+
+ analyze_chunks();
+
+ DBG_PRT((L"%s : %d program headers entry=0x%lx\nlowest_addr=0x%lx highest_addr=0x%lx\n",
+ LD_NAME,
+ phnum, kernel_entry, low_addr, max_addr));
+
+ total_size = (UINTN)max_addr - (UINTN)low_addr;
+ pages = EFI_SIZE_TO_PAGES(total_size);
+
+ /*
+ * Record end of kernel for initrd
+ */
+ kernel_base = (void *)low_addr;
+ kernel_end = (void *)(low_addr + (pages << EFI_PAGE_SHIFT));
+
+ /* allocate memory for the kernel */
+ if (alloc_kmem((void *)low_addr, pages) == -1) {
+ VOID *new_addr;
+
+ ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
+
+ if (ia64_can_relocate() == 0) {
+ ERR_PRT((L"relocation is disabled, cannot load kernel"));
+ goto error;
+ }
+
+ /*
+ * could not allocate at requested spot, try to find a
+ * suitable location to relocate the kernel
+ *
+ * The maximum sized Itanium TLB translation entry is 256 MB.
+ * If we relocate the kernel by this amount we know for sure
+ * that alignment constraints will be satisified, regardless
+ * of the kernel used.
+ */
+ VERB_PRT(1, Print(L"Attempting to relocate kernel.\n"));
+
+ if (find_kernel_memory((VOID*) low_addr, (VOID*) max_addr, 256*MB, &new_addr) == -1) {
+ ERR_PRT((L"%s : find_kernel_memory(0x%lx, 0x%lx, 0x%lx, 0x%lx) failed\n", LD_NAME, low_addr, max_addr, 256*MB, &load_offset));
+ goto error;
+ }
+ /* unsigned arithmetic */
+ load_offset = (UINTN) (new_addr - ROUNDDOWN((UINTN) low_addr,256*MB));
+
+ ERR_PRT((L"low_addr=0x%lx new_addr=0x%lx offset=0x%lx", low_addr, new_addr, load_offset));
+
+ /*
+ * correct various addresses for non-zero load_offset
+ */
+ kernel_base = (void *) ((UINTN) kernel_base + load_offset);
+ kernel_end = (void *) ((UINTN) kernel_end + load_offset);
+ kernel_entry = (void*) ((UINTN) kernel_entry + load_offset);
+
+ for (i = 0; i < phnum; ++i) {
+ chunks[i].addr += load_offset;
+ phdrs[i].p_paddr = (Elf64_Addr) ((UINT64) phdrs[i].p_paddr + load_offset);
+ }
+
+ /*
+ * try one last time to get memory for the kernel
+ */
+ if (alloc_kmem((void *)low_addr+load_offset, pages) == -1) {
+ ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr+load_offset));
+ ERR_PRT((L"Relocation by 0x%lx bytes failed.\n", load_offset));
+ goto error;
+ }
+ }
+ return 0;
+error:
+ if (chunks) free(chunks);
+ return -1;
+}
+
+/*
+ * Determine which chunk in the Elf file will be coming out of the expand
+ * code next.
+ */
+static void
+nextchunk(void)
+{
+ int i;
+ segment_t *cp;
+
+ cp = NULL;
+ for(i=0; i < nchunks; i++) {
+
+ if (!CHUNK_IS_VALID(i) || !CHUNK_IS_LOAD(i)) continue;
+
+ if (file_offset > chunks[i].offset) continue;
+
+ if (cp == NULL || chunks[i].offset < cp->offset) cp = &chunks[i];
+ }
+ cur_chunk = cp;
+}
+
+
+/*
+ * Write the output window window[0..outcnt-1] holding uncompressed
+ * data and update crc.
+ */
+void
+flush_window(void)
+{
+ static const CHAR8 helicopter[4] = { '|' , '/' , '-' , '\\' };
+ static UINTN heli_count;
+ struct segment *cp;
+ char *src, *dst;
+ long cnt;
+
+ if (!outcnt) return;
+
+ DBG_PRT((L"%s : flush_window outnct=%d file_offset=%ld\n", LD_NAME, outcnt, file_offset));
+
+ Print(L"%c\b",helicopter[heli_count++%4]);
+
+ updcrc(window, outcnt);
+
+ /*
+ * first time, we extract the headers
+ */
+ if (!bytes_out) {
+ if (first_block(window, outcnt) < 0) error("invalid exec header");
+ nextchunk();
+ }
+
+ bytes_out += outcnt;
+ src = window;
+tail:
+ /* check if user wants to abort */
+ if (check_abort() == EFI_SUCCESS) goto load_abort;
+
+ cp = cur_chunk;
+ if (cp == NULL || file_offset + outcnt <= cp->offset) {
+ file_offset += outcnt;
+ return;
+ }
+
+ // Does this window begin before the current chunk?
+ if (file_offset < cp->offset) {
+ unsigned long skip = cp->offset - file_offset;
+
+ src += skip;
+ file_offset += skip;
+ outcnt -= skip;
+ }
+ dst = (char *)cp->addr + (file_offset - cp->offset);
+
+ cnt = cp->offset + cp->size - file_offset;
+
+ if (cnt > outcnt) cnt = outcnt;
+
+ Memcpy(dst, src, cnt);
+
+ file_offset += cnt;
+ outcnt -= cnt;
+ src += cnt;
+
+ /* See if we are at the end of this chunk */
+ if (file_offset == cp->offset + cp->size) {
+ if (cp->bss_sz) {
+ dst = (char *)cp->addr + cp->size;
+ Memset(dst, 0, cp->bss_sz);
+ }
+ nextchunk();
+ /* handle remaining bytes */
+ if (outcnt) goto tail;
+ }
+ return;
+load_abort:
+ free_kmem();
+ error_return = ELILO_LOAD_ABORTED;
+ longjmp(jbuf, 1);
+}
+
+static void
+error(char *x)
+{
+ ERR_PRT((L"%s : %a", LD_NAME, x));
+ /* will eventually exit with error from gunzip() */
+ longjmp(jbuf,1);
+}
+
+INT32
+decompress_kernel(VOID)
+{
+ INT32 ret;
+
+ clear_bufs();
+ makecrc();
+ Print(L"Uncompressing Linux... ");
+ ret = gunzip();
+ if (ret == 0) Print(L"done\n");
+ return ret == 0 ? 0 : -1;
+}
+
+int
+gunzip_kernel(fops_fd_t fd, kdesc_t *kd)
+{
+ int ret = -1;
+
+ error_return = ELILO_LOAD_ERROR;
+
+ window = (void *)alloc(WSIZE, 0);
+ if (window == NULL) {
+ ERR_PRT((L"%s : allocate output window failed\n", LD_NAME));
+ return -1;
+ }
+
+ inbuf = (void *)alloc(INBUFSIZE, 0);
+ if (inbuf == NULL) {
+ ERR_PRT((L"%s : allocate input window failedr\n", LD_NAME));
+ goto error;
+ }
+
+ input_fd = fd;
+ insize = 0;
+ bytes_out = 0;
+
+ if (setjmp(jbuf) == 1) goto error;
+
+
+ ret = decompress_kernel();
+
+error:
+ if (window) free(window);
+ if (inbuf) free(inbuf);
+
+ if (ret == 0) {
+ kd->kentry = kernel_entry;
+ kd->kend = kernel_end;
+ kd->kstart = kernel_base;
+ error_return = ELILO_LOAD_SUCCESS;
+ }
+ return error_return;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 __GZIP_H__
+#define __GZIP_H__
+
+
+int gzip_probe(unsigned char *, unsigned long);
+int gunzip_kernel(fops_fd_t, kdesc_t *);
+
+#define LD_NAME L"gzip_ia64"
+
+#endif /* __GZIP_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 "loader.h"
+#include "gzip.h"
+
+static INTN
+gzip_probe_format(CHAR16 *kname)
+{
+ UINT8 buf[4];
+ EFI_STATUS status;
+ INTN ret = -1;
+ UINTN size;
+ fops_fd_t fd;
+
+ status = fops_open(kname, &fd);
+ if (EFI_ERROR(status)) return -1;
+
+ size = sizeof(buf);
+ status = fops_read(fd, buf, &size);
+
+ if (EFI_ERROR(status) || size != sizeof(buf)) goto error;
+
+ ret = gzip_probe(buf, sizeof(buf));
+error:
+ fops_close(fd);
+ return ret;
+}
+
+
+static INTN
+gzip_load_kernel(CHAR16 *kname, kdesc_t *kd)
+{
+ EFI_STATUS status;
+ INT32 ret;
+ fops_fd_t fd;
+
+ status = fops_open(kname, &fd);
+ if (EFI_ERROR(status)) return ELILO_LOAD_ERROR;
+
+ ret = gunzip_kernel(fd, kd);
+
+ fops_close(fd);
+
+ return ret; /* could be success, error, or abort */
+}
+
+loader_ops_t gzip_loader={
+ NULL,
+ LD_NAME,
+ gzip_probe_format,
+ gzip_load_kernel
+};
--- /dev/null
+#define DEBG(x)
+#define DEBG1(x)
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+ version c10p1, 10 January 1993 */
+
+/*
+ * Adapted for booting Linux by Hannu Savolainen 1993
+ * based on gzip-1.0.3
+ *
+ * Nicolas Pitre <nico@cam.org>, 1999/04/14 :
+ * Little mods for all variable to reside either into rodata or bss segments
+ * by marking constant variables with 'const' and initializing all the others
+ * at run-time only. This allows for the kernel uncompressor to run
+ * directly from Flash or ROM memory on embeded systems.
+ */
+
+/*
+ Inflate deflated (PKZIP's method 8 compressed) data. The compression
+ method searches for as much of the current string of bytes (up to a
+ length of 258) in the previous 32 K bytes. If it doesn't find any
+ matches (of at least length 3), it codes the next byte. Otherwise, it
+ codes the length of the matched string and its distance backwards from
+ the current position. There is a single Huffman code that codes both
+ single bytes (called "literals") and match lengths. A second Huffman
+ code codes the distance information, which follows a length code. Each
+ length or distance code actually represents a base value and a number
+ of "extra" (sometimes zero) bits to get to add to the base value. At
+ the end of each deflated block is a special end-of-block (EOB) literal/
+ length code. The decoding process is basically: get a literal/length
+ code; if EOB then done; if a literal, emit the decoded byte; if a
+ length then get the distance and emit the referred-to bytes from the
+ sliding window of previously emitted data.
+
+ There are (currently) three kinds of inflate blocks: stored, fixed, and
+ dynamic. The compressor deals with some chunk of data at a time, and
+ decides which method to use on a chunk-by-chunk basis. A chunk might
+ typically be 32 K or 64 K. If the chunk is incompressible, then the
+ "stored" method is used. In this case, the bytes are simply stored as
+ is, eight bits per byte, with none of the above coding. The bytes are
+ preceded by a count, since there is no longer an EOB code.
+
+ If the data is compressible, then either the fixed or dynamic methods
+ are used. In the dynamic method, the compressed data is preceded by
+ an encoding of the literal/length and distance Huffman codes that are
+ to be used to decode this block. The representation is itself Huffman
+ coded, and so is preceded by a description of that code. These code
+ descriptions take up a little space, and so for small blocks, there is
+ a predefined set of codes, called the fixed codes. The fixed method is
+ used if the block codes up smaller that way (usually for quite small
+ chunks), otherwise the dynamic method is used. In the latter case, the
+ codes are customized to the probabilities in the current block, and so
+ can code it much better than the pre-determined fixed codes.
+
+ The Huffman codes themselves are decoded using a multi-level table
+ lookup, in order to maximize the speed of decoding plus the speed of
+ building the decoding tables. See the comments below that precede the
+ lbits and dbits tuning parameters.
+ */
+
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarly, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "#Id: inflate.c,v 0.14 1993/06/10 13:27:04 jloup Exp #";
+#endif
+
+#ifndef FUNC_STATIC
+
+#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H)
+# include <sys/types.h>
+# include <stdlib.h>
+#endif
+
+#include "gzip.h"
+#define FUNC_STATIC
+#endif /* !FUNC_STATIC */
+
+#define slide window
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model).
+ Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16
+ means that v is a literal, 16 < e < 32 means that v is a pointer to
+ the next table, which codes e - 16 bits, and lastly e == 99 indicates
+ an unused code. If a code with e == 99 is looked up, this implies an
+ error in the data. */
+struct huft {
+ uch e; /* number of extra bits or operation */
+ uch b; /* number of bits in this code or subcode */
+ union {
+ ush n; /* literal, length base, or distance base */
+ struct huft *t; /* pointer to next level of table */
+ } v;
+};
+
+
+/* Function prototypes */
+FUNC_STATIC int huft_build OF((unsigned *, unsigned, unsigned,
+ const ush *, const ush *, struct huft **, int *));
+FUNC_STATIC int huft_free OF((struct huft *));
+FUNC_STATIC int inflate_codes OF((struct huft *, struct huft *, int, int));
+FUNC_STATIC int inflate_stored OF((void));
+FUNC_STATIC int inflate_fixed OF((void));
+FUNC_STATIC int inflate_dynamic OF((void));
+FUNC_STATIC int inflate_block OF((int *));
+FUNC_STATIC int inflate OF((void));
+
+
+/* The inflate algorithm uses a sliding 32 K byte window on the uncompressed
+ stream to find repeated byte strings. This is implemented here as a
+ circular buffer. The index is updated simply by incrementing and then
+ ANDing with 0x7fff (32K-1). */
+/* It is left to other modules to supply the 32 K area. It is assumed
+ to be usable as if it were declared "uch slide[32768];" or as just
+ "uch *slide;" and then malloc'ed in the latter case. The definition
+ must be in unzip.h, included above. */
+/* unsigned wp; current position in slide */
+#define wp outcnt
+#define flush_output(w) (wp=(w),flush_window())
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static const unsigned border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+static const ush cplens[] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* note: see note #13 above about the 258 in this list. */
+static const ush cplext[] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
+static const ush cpdist[] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+static const ush cpdext[] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+
+
+/* Macros for inflate() bit peeking and grabbing.
+ The usage is:
+
+ NEEDBITS(j)
+ x = b & mask_bits[j];
+ DUMPBITS(j)
+
+ where NEEDBITS makes sure that b has at least j bits in it, and
+ DUMPBITS removes the bits from b. The macros use the variable k
+ for the number of bits in b. Normally, b and k are register
+ variables for speed, and are initialized at the beginning of a
+ routine that uses these macros from a global bit buffer and count.
+
+ If we assume that EOB will be the longest code, then we will never
+ ask for bits with NEEDBITS that are beyond the end of the stream.
+ So, NEEDBITS should not read any more bytes than are needed to
+ meet the request. Then no bytes need to be "returned" to the buffer
+ at the end of the last block.
+
+ However, this assumption is not true for fixed blocks--the EOB code
+ is 7 bits, but the other literal/length codes can be 8 or 9 bits.
+ (The EOB code is shorter than other codes because fixed blocks are
+ generally short. So, while a block always has an EOB, many other
+ literal/length codes have a significantly lower probability of
+ showing up at all.) However, by making the first table have a
+ lookup of seven bits, the EOB code will be found in that first
+ lookup, and so will not require that too many bits be pulled from
+ the stream.
+ */
+
+FUNC_STATIC ulg bb; /* bit buffer */
+FUNC_STATIC unsigned bk; /* bits in bit buffer */
+
+FUNC_STATIC const ush mask_bits[] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#define NEXTBYTE() (uch)get_byte()
+#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+FUNC_STATIC const int lbits = 9; /* bits in base literal/length lookup table */
+FUNC_STATIC const int dbits = 6; /* bits in base distance lookup table */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16 /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+
+FUNC_STATIC unsigned hufts; /* track memory usage */
+
+
+FUNC_STATIC int huft_build(b, n, s, d, e, t, m)
+unsigned *b; /* code lengths in bits (all assumed <= BMAX) */
+unsigned n; /* number of codes (assumed <= N_MAX) */
+unsigned s; /* number of simple-valued codes (0..s-1) */
+const ush *d; /* list of base values for non-simple codes */
+const ush *e; /* list of extra bits for non-simple codes */
+struct huft **t; /* result: starting table */
+int *m; /* maximum lookup bits, returns actual */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return zero on success, one if
+ the given code set is incomplete (the tables are still built in this
+ case), two if the input is invalid (all zero length codes or an
+ oversubscribed set of lengths), and three if not enough memory. */
+{
+ unsigned a; /* counter for codes of length k */
+ unsigned c[BMAX+1]; /* bit length count table */
+ unsigned f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register unsigned i; /* counter, current code */
+ register unsigned j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ register unsigned *p; /* pointer into c[], b[], or v[] */
+ register struct huft *q; /* points to current table */
+ struct huft r; /* table entry for structure assignment */
+ struct huft *u[BMAX]; /* table stack */
+ unsigned v[N_MAX]; /* values in order of bit length */
+ register int w; /* bits before this table == (l * h) */
+ unsigned x[BMAX+1]; /* bit offsets, then code stack */
+ unsigned *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ unsigned z; /* number of entries in current table */
+
+DEBG("huft1 ");
+
+ /* Generate counts for each bit length */
+ memzero(c, sizeof(c));
+
+ p = b; i = n;
+ do {
+ Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"),
+ n-i, *p));
+ c[*p]++; /* assume all entries <= BMAX */
+ p++; /* Can't combine with above line (Solaris bug) */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (struct huft *)NULL;
+ *m = 0;
+ return 0;
+ }
+
+DEBG("huft2 ");
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((unsigned)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((unsigned)l > i)
+ l = i;
+ *m = l;
+
+DEBG("huft3 ");
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return 2; /* bad input: more codes than bits */
+ if ((y -= c[i]) < 0)
+ return 2;
+ c[i] += y;
+
+DEBG("huft4 ");
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+DEBG("huft5 ");
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+
+DEBG("h6 ");
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (struct huft *)NULL; /* just to keep compilers happy */
+ q = (struct huft *)NULL; /* ditto */
+ z = 0; /* ditto */
+DEBG("h6a ");
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+DEBG("h6b ");
+ a = c[k];
+ while (a--)
+ {
+DEBG("h6b1 ");
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+DEBG1("1 ");
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+DEBG1("2 ");
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+DEBG1("3 ");
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ if ((q = (struct huft *)gzip_malloc((z + 1)*sizeof(struct huft))) ==
+ (struct huft *)NULL)
+ {
+ if (h)
+ huft_free(u[0]);
+ return 3; /* not enough memory */
+ }
+DEBG1("4 ");
+ hufts += z + 1; /* track memory usage */
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->v.t)) = (struct huft *)NULL;
+ u[h] = ++q; /* table starts after link */
+
+DEBG1("5 ");
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.b = (uch)l; /* bits to dump before this table */
+ r.e = (uch)(16 + j); /* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h-1][j] = r; /* connect to last table */
+ }
+DEBG1("6 ");
+ }
+DEBG("h6c ");
+
+ /* set up table entry in r */
+ r.b = (uch)(k - w);
+ if (p >= v + n)
+ r.e = 99; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
+ r.v.n = (ush)(*p); /* simple code is just the value */
+ p++; /* one compiler does not like *p++ */
+ }
+ else
+ {
+ r.e = (uch)e[*p - s]; /* non-simple--look up in lists */
+ r.v.n = d[*p++ - s];
+ }
+DEBG("h6d ");
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+DEBG("h6e ");
+ }
+DEBG("h6f ");
+ }
+
+DEBG("huft7 ");
+
+ /* Return true (1) if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+
+
+FUNC_STATIC int huft_free(t)
+struct huft *t; /* table to free */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+ list of the tables it made, with the links in a dummy first entry of
+ each table. */
+{
+ register struct huft *p, *q;
+
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ p = t;
+ while (p != (struct huft *)NULL)
+ {
+ q = (--p)->v.t;
+ gzip_free((char*)p);
+ p = q;
+ }
+ return 0;
+}
+
+
+FUNC_STATIC int inflate_codes(tl, td, bl, bd)
+struct huft *tl, *td; /* literal/length and distance decoder tables */
+int bl, bd; /* number of bits decoded by tl[] and td[] */
+/* inflate (decompress) the codes in a deflated (compressed) block.
+ Return an error code or zero if it all goes ok. */
+{
+ register unsigned e; /* table entry flag/number of extra bits */
+ unsigned n, d; /* length and index for copy */
+ unsigned w; /* current window position */
+ struct huft *t; /* pointer to table entry */
+ unsigned ml, md; /* masks for bl and bd bits */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+ /* inflate the coded data */
+ ml = mask_bits[bl]; /* precompute masks for speed */
+ md = mask_bits[bd];
+ for (;;) /* do until end of block */
+ {
+ NEEDBITS((unsigned)bl)
+ if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ if (e == 16) /* then it's a literal */
+ {
+ slide[w++] = (uch)t->v.n;
+ Tracevv((stderr, "%c", slide[w-1]));
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ }
+ else /* it's an EOB or a length */
+ {
+ /* exit if end of block */
+ if (e == 15)
+ break;
+
+ /* get length of block to copy */
+ NEEDBITS(e)
+ n = t->v.n + ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e);
+
+ /* decode distance of block to copy */
+ NEEDBITS((unsigned)bd)
+ if ((e = (t = td + ((unsigned)b & md))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ NEEDBITS(e)
+ d = w - t->v.n - ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e)
+ Tracevv((stderr,"\\[%d,%d]", w-d, n));
+
+ /* do the copy */
+ do {
+ n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(INFLATE_DEBUG)
+ if (w - d >= e) /* (this test assumes unsigned comparison) */
+ {
+ memcpy(slide + w, slide + d, e);
+ w += e;
+ d += e;
+ }
+ else /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+ do {
+ slide[w++] = slide[d++];
+ Tracevv((stderr, "%c", slide[w-1]));
+ } while (--e);
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ } while (n);
+ }
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ /* done */
+ return 0;
+}
+
+
+
+FUNC_STATIC int inflate_stored()
+/* "decompress" an inflated type 0 (stored) block. */
+{
+ unsigned n; /* number of bytes in block */
+ unsigned w; /* current window position */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+DEBG("<stor");
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+
+ /* go to byte boundary */
+ n = k & 7;
+ DUMPBITS(n);
+
+
+ /* get the length and its complement */
+ NEEDBITS(16)
+ n = ((unsigned)b & 0xffff);
+ DUMPBITS(16)
+ NEEDBITS(16)
+ if (n != (unsigned)((~b) & 0xffff))
+ return 1; /* error in compressed data */
+ DUMPBITS(16)
+
+
+ /* read and output the compressed data */
+ while (n--)
+ {
+ NEEDBITS(8)
+ slide[w++] = (uch)b;
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ DUMPBITS(8)
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ DEBG(">");
+ return 0;
+}
+
+
+
+FUNC_STATIC int inflate_fixed()
+/* decompress an inflated type 1 (fixed Huffman codes) block. We should
+ either replace this with a custom decoder, or at least precompute the
+ Huffman tables. */
+{
+ int i; /* temporary variable */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned l[288]; /* length list for huft_build */
+
+DEBG("<fix");
+
+ /* set up literal table */
+ for (i = 0; i < 144; i++)
+ l[i] = 8;
+ for (; i < 256; i++)
+ l[i] = 9;
+ for (; i < 280; i++)
+ l[i] = 7;
+ for (; i < 288; i++) /* make a complete, but wrong code set */
+ l[i] = 8;
+ bl = 7;
+ if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+ return i;
+
+
+ /* set up distance table */
+ for (i = 0; i < 30; i++) /* make an incomplete code set */
+ l[i] = 5;
+ bd = 5;
+ if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
+ {
+ huft_free(tl);
+
+ DEBG(">");
+ return i;
+ }
+
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd))
+ return 1;
+
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+}
+
+
+
+FUNC_STATIC int inflate_dynamic()
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+{
+ int i; /* temporary variables */
+ unsigned j;
+ unsigned l; /* last length */
+ unsigned m; /* mask for bit lengths table */
+ unsigned n; /* number of lengths to get */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned nb; /* number of bit length codes */
+ unsigned nl; /* number of literal/length codes */
+ unsigned nd; /* number of distance codes */
+#ifdef PKZIP_BUG_WORKAROUND
+ unsigned ll[288+32]; /* literal/length and distance code lengths */
+#else
+ unsigned ll[286+30]; /* literal/length and distance code lengths */
+#endif
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+DEBG("<dyn");
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+
+ /* read in table lengths */
+ NEEDBITS(5)
+ nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */
+ DUMPBITS(5)
+ NEEDBITS(5)
+ nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */
+ DUMPBITS(5)
+ NEEDBITS(4)
+ nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */
+ DUMPBITS(4)
+#ifdef PKZIP_BUG_WORKAROUND
+ if (nl > 288 || nd > 32)
+#else
+ if (nl > 286 || nd > 30)
+#endif
+ return 1; /* bad lengths */
+
+DEBG("dyn1 ");
+
+ /* read in bit-length-code lengths */
+ for (j = 0; j < nb; j++)
+ {
+ NEEDBITS(3)
+ ll[border[j]] = (unsigned)b & 7;
+ DUMPBITS(3)
+ }
+ for (; j < 19; j++)
+ ll[border[j]] = 0;
+
+DEBG("dyn2 ");
+
+ /* build decoding table for trees--single level, 7 bit lookup */
+ bl = 7;
+ if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
+ {
+ if (i == 1)
+ huft_free(tl);
+ return i; /* incomplete code set */
+ }
+
+DEBG("dyn3 ");
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = mask_bits[bl];
+ i = l = 0;
+ while ((unsigned)i < n)
+ {
+ NEEDBITS((unsigned)bl)
+ j = (td = tl + ((unsigned)b & m))->b;
+ DUMPBITS(j)
+ j = td->v.n;
+ if (j < 16) /* length of code in bits (0..15) */
+ ll[i++] = l = j; /* save last length in l */
+ else if (j == 16) /* repeat last length 3 to 6 times */
+ {
+ NEEDBITS(2)
+ j = 3 + ((unsigned)b & 3);
+ DUMPBITS(2)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = l;
+ }
+ else if (j == 17) /* 3 to 10 zero length codes */
+ {
+ NEEDBITS(3)
+ j = 3 + ((unsigned)b & 7);
+ DUMPBITS(3)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ else /* j == 18: 11 to 138 zero length codes */
+ {
+ NEEDBITS(7)
+ j = 11 + ((unsigned)b & 0x7f);
+ DUMPBITS(7)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ }
+
+DEBG("dyn4 ");
+
+ /* free decoding table for trees */
+ huft_free(tl);
+
+DEBG("dyn5 ");
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+DEBG("dyn5a ");
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = lbits;
+ if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
+ {
+DEBG("dyn5b ");
+ if (i == 1) {
+ error(" incomplete literal tree\n");
+ huft_free(tl);
+ }
+ return i; /* incomplete code set */
+ }
+DEBG("dyn5c ");
+ bd = dbits;
+ if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
+ {
+DEBG("dyn5d ");
+ if (i == 1) {
+ error(" incomplete distance tree\n");
+#ifdef PKZIP_BUG_WORKAROUND
+ i = 0;
+ }
+#else
+ huft_free(td);
+ }
+ huft_free(tl);
+ return i; /* incomplete code set */
+#endif
+ }
+
+DEBG("dyn6 ");
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd))
+ return 1;
+
+DEBG("dyn7 ");
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+
+ DEBG(">");
+ return 0;
+}
+
+
+
+FUNC_STATIC int inflate_block(e)
+int *e; /* last block flag */
+/* decompress an inflated block */
+{
+ unsigned t; /* block type */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+ DEBG("<blk");
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+
+ /* read in last block bit */
+ NEEDBITS(1)
+ *e = (int)b & 1;
+ DUMPBITS(1)
+
+
+ /* read in block type */
+ NEEDBITS(2)
+ t = (unsigned)b & 3;
+ DUMPBITS(2)
+
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+ /* inflate that block type */
+ if (t == 2)
+ return inflate_dynamic();
+ if (t == 0)
+ return inflate_stored();
+ if (t == 1)
+ return inflate_fixed();
+
+ DEBG(">");
+
+ /* bad block type */
+ return 2;
+}
+
+
+
+FUNC_STATIC int inflate()
+/* decompress an inflated entry */
+{
+ int e; /* last block flag */
+ int r; /* result code */
+ unsigned h; /* maximum struct huft's malloc'ed */
+
+ /* initialize window, bit buffer */
+ wp = 0;
+ bk = 0;
+ bb = 0;
+
+
+ /* decompress until the last block */
+ h = 0;
+ do {
+ hufts = 0;
+ if ((r = inflate_block(&e)) != 0) {
+ return r;
+ }
+ if (hufts > h)
+ h = hufts;
+ } while (!e);
+
+ /* Undo too much lookahead. The next read will be byte aligned so we
+ * can discard unused bits in the last meaningful byte.
+ */
+ while (bk >= 8) {
+ bk -= 8;
+ inptr--;
+ }
+
+ /* flush out slide */
+ flush_output(wp);
+
+
+ /* return success */
+#ifdef INFLATE_DEBUG
+#ifdef EFI_COMPILE
+ Print(L"<%d> ", h);
+#else
+ printf("<%d> ", h);
+#endif
+#endif /* INFLATE_DEBUG */
+ return 0;
+}
+
+/**********************************************************************
+ *
+ * The following are support routines for inflate.c
+ *
+ **********************************************************************/
+
+static ulg crc_32_tab[256];
+static ulg crc; /* initialized in makecrc() so it'll reside in bss */
+#define CRC_VALUE (crc ^ 0xffffffffUL)
+
+/*
+ * Code to compute the CRC-32 table. Borrowed from
+ * gzip-1.0.3/makecrc.c.
+ */
+
+static void
+makecrc(void)
+{
+/* Not copyrighted 1990 Mark Adler */
+
+ unsigned long c; /* crc shift register */
+ unsigned long e; /* polynomial exclusive-or pattern */
+ int i; /* counter for all possible eight bit values */
+ int k; /* byte being shifted into crc apparatus */
+
+ /* terms of polynomial defining this crc (except x^32): */
+ static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* Make exclusive-or pattern from polynomial */
+ e = 0;
+ for (i = 0; i < sizeof(p)/sizeof(int); i++)
+ e |= 1L << (31 - p[i]);
+
+ crc_32_tab[0] = 0;
+
+ for (i = 1; i < 256; i++)
+ {
+ c = 0;
+ for (k = i | 256; k != 1; k >>= 1)
+ {
+ c = c & 1 ? (c >> 1) ^ e : c >> 1;
+ if (k & 1)
+ c ^= e;
+ }
+ crc_32_tab[i] = c;
+ }
+
+ /* this is initialized here so this code could reside in ROM */
+ crc = (ulg)0xffffffffUL; /* shift register contents */
+}
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+/*
+ * check for valid gzip signature
+ * return:
+ * 0 : valid gzip archive
+ * -1: invalid gzip archive
+ */
+int
+gzip_probe(uch *buf, unsigned long size)
+{
+ if (size < 4) return -1;
+
+ if (buf[0] != 037 ||
+ ((buf[1] != 0213) && (buf[1] != 0236))) return -1;
+
+ /* We only support method #8, DEFLATED */
+ if (buf[2] != 8) return -1;
+
+ if ((buf[3] & ENCRYPTED) != 0) return -1;
+
+ if ((buf[3] & CONTINUATION) != 0) return -1;
+
+ if ((buf[3] & RESERVED) != 0) return -1;
+
+ return 0;
+}
+
+
+/*
+ * Do the uncompression!
+ */
+static int gunzip(void)
+{
+ uch flags;
+ unsigned char magic[2]; /* magic header */
+ char method;
+ ulg orig_crc = 0; /* original crc */
+ ulg orig_len = 0; /* original uncompressed length */
+ int res;
+
+ magic[0] = (unsigned char)get_byte();
+ magic[1] = (unsigned char)get_byte();
+ method = (unsigned char)get_byte();
+
+ if (magic[0] != 037 ||
+ ((magic[1] != 0213) && (magic[1] != 0236))) {
+ error("bad gzip magic numbers");
+ return -1;
+ }
+
+ /* We only support method #8, DEFLATED */
+ if (method != 8) {
+ error("internal error, invalid method");
+ return -1;
+ }
+
+ flags = (uch)get_byte();
+ if ((flags & ENCRYPTED) != 0) {
+ error("Input is encrypted\n");
+ return -1;
+ }
+ if ((flags & CONTINUATION) != 0) {
+ error("Multi part input\n");
+ return -1;
+ }
+ if ((flags & RESERVED) != 0) {
+ error("Input has invalid flags\n");
+ return -1;
+ }
+ (ulg)get_byte(); /* Get timestamp */
+ ((ulg)get_byte()) << 8;
+ ((ulg)get_byte()) << 16;
+ ((ulg)get_byte()) << 24;
+
+ (void)get_byte(); /* Ignore extra flags for the moment */
+ (void)get_byte(); /* Ignore OS type for the moment */
+
+ if ((flags & EXTRA_FIELD) != 0) {
+ unsigned len = (unsigned)get_byte();
+ len |= ((unsigned)get_byte())<<8;
+ while (len--) (void)get_byte();
+ }
+
+ /* Get original file name if it was truncated */
+ if ((flags & ORIG_NAME) != 0) {
+ /* Discard the old name */
+ while (get_byte() != 0) /* null */ ;
+ }
+
+ /* Discard file comment if any */
+ if ((flags & COMMENT) != 0) {
+ while (get_byte() != 0) /* null */ ;
+ }
+
+ /* Decompress */
+ if ((res = inflate())) {
+ switch (res) {
+ case 0:
+ break;
+ case 1:
+ error("invalid compressed format (err=1)");
+ break;
+ case 2:
+ error("invalid compressed format (err=2)");
+ break;
+ case 3:
+ error("out of memory");
+ break;
+ default:
+ error("invalid compressed format (other)");
+ }
+ return -1;
+ }
+
+ /* Get the crc and original length */
+ /* crc32 (see algorithm.doc)
+ * uncompressed input size modulo 2^32
+ */
+ orig_crc = (ulg) get_byte();
+ orig_crc |= (ulg) get_byte() << 8;
+ orig_crc |= (ulg) get_byte() << 16;
+ orig_crc |= (ulg) get_byte() << 24;
+
+ orig_len = (ulg) get_byte();
+ orig_len |= (ulg) get_byte() << 8;
+ orig_len |= (ulg) get_byte() << 16;
+ orig_len |= (ulg) get_byte() << 24;
+
+ /* Validate decompression */
+ if (orig_crc != CRC_VALUE) {
+ error("crc error");
+ return -1;
+ }
+ if (orig_len != bytes_out) {
+ error("length error");
+ return -1;
+ }
+ return 0;
+}
+
+
--- /dev/null
+/* Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA.
+
+ Note that __sigsetjmp() did NOT flush the register stack. Instead,
+ we do it here since __longjmp() is usually much less frequently
+ invoked than __sigsetjmp(). The only difficulty is that __sigsetjmp()
+ didn't (and wouldn't be able to) save ar.rnat either. This is a problem
+ because if we're not careful, we could end up loading random NaT bits.
+ There are two cases:
+
+ (i) ar.bsp < ia64_rse_rnat_addr(jmpbuf.ar_bsp)
+ ar.rnat contains the desired bits---preserve ar.rnat
+ across loadrs and write to ar.bspstore
+
+ (ii) ar.bsp >= ia64_rse_rnat_addr(jmpbuf.ar_bsp)
+ The desired ar.rnat is stored in
+ ia64_rse_rnat_addr(jmpbuf.ar_bsp). Load those
+ bits into ar.rnat after setting ar.bspstore. */
+
+
+
+# define pPos p6 /* is rotate count positive? */
+# define pNeg p7 /* is rotate count negative? */
+
+
+ /* __longjmp(__jmp_buf buf, int val) */
+
+ .text
+ .global longjmp
+ .proc longjmp
+longjmp:
+ alloc r8=ar.pfs,2,1,0,0
+ mov r27=ar.rsc
+ add r2=0x98,in0 // r2 <- &jmpbuf.orig_jmp_buf_addr
+ ;;
+ ld8 r8=[r2],-16 // r8 <- orig_jmp_buf_addr
+ mov r10=ar.bsp
+ and r11=~0x3,r27 // clear ar.rsc.mode
+ ;;
+ flushrs // flush dirty regs to backing store (must be first in insn grp)
+ ld8 r23=[r2],8 // r23 <- jmpbuf.ar_bsp
+ sub r8=r8,in0 // r8 <- &orig_jmpbuf - &jmpbuf
+ ;;
+ ld8 r25=[r2] // r25 <- jmpbuf.ar_unat
+ extr.u r8=r8,3,6 // r8 <- (&orig_jmpbuf - &jmpbuf)/8 & 0x3f
+ ;;
+ cmp.lt pNeg,pPos=r8,r0
+ mov r2=in0
+ ;;
+(pPos) mov r16=r8
+(pNeg) add r16=64,r8
+(pPos) sub r17=64,r8
+(pNeg) sub r17=r0,r8
+ ;;
+ mov ar.rsc=r11 // put RSE in enforced lazy mode
+ shr.u r8=r25,r16
+ add r3=8,in0 // r3 <- &jmpbuf.r1
+ shl r9=r25,r17
+ ;;
+ or r25=r8,r9
+ ;;
+ mov r26=ar.rnat
+ mov ar.unat=r25 // setup ar.unat (NaT bits for r1, r4-r7, and r12)
+ ;;
+ ld8.fill.nta sp=[r2],16 // r12 (sp)
+ ld8.fill.nta gp=[r3],16 // r1 (gp)
+ dep r11=-1,r23,3,6 // r11 <- ia64_rse_rnat_addr(jmpbuf.ar_bsp)
+ ;;
+ ld8.nta r16=[r2],16 // caller's unat
+ ld8.nta r17=[r3],16 // fpsr
+ ;;
+ ld8.fill.nta r4=[r2],16 // r4
+ ld8.fill.nta r5=[r3],16 // r5 (gp)
+ cmp.geu p8,p0=r10,r11 // p8 <- (ar.bsp >= jmpbuf.ar_bsp)
+ ;;
+ ld8.fill.nta r6=[r2],16 // r6
+ ld8.fill.nta r7=[r3],16 // r7
+ ;;
+ mov ar.unat=r16 // restore caller's unat
+ mov ar.fpsr=r17 // restore fpsr
+ ;;
+ ld8.nta r16=[r2],16 // b0
+ ld8.nta r17=[r3],16 // b1
+ ;;
+(p8) ld8 r26=[r11] // r26 <- *ia64_rse_rnat_addr(jmpbuf.ar_bsp)
+ mov ar.bspstore=r23 // restore ar.bspstore
+ ;;
+ ld8.nta r18=[r2],16 // b2
+ ld8.nta r19=[r3],16 // b3
+ ;;
+ ld8.nta r20=[r2],16 // b4
+ ld8.nta r21=[r3],16 // b5
+ ;;
+ ld8.nta r11=[r2],16 // ar.pfs
+ ld8.nta r22=[r3],56 // ar.lc
+ ;;
+ ld8.nta r24=[r2],32 // pr
+ mov b0=r16
+ ;;
+ ldf.fill.nta f2=[r2],32
+ ldf.fill.nta f3=[r3],32
+ mov b1=r17
+ ;;
+ ldf.fill.nta f4=[r2],32
+ ldf.fill.nta f5=[r3],32
+ mov b2=r18
+ ;;
+ ldf.fill.nta f16=[r2],32
+ ldf.fill.nta f17=[r3],32
+ mov b3=r19
+ ;;
+ ldf.fill.nta f18=[r2],32
+ ldf.fill.nta f19=[r3],32
+ mov b4=r20
+ ;;
+ ldf.fill.nta f20=[r2],32
+ ldf.fill.nta f21=[r3],32
+ mov b5=r21
+ ;;
+ ldf.fill.nta f22=[r2],32
+ ldf.fill.nta f23=[r3],32
+ mov ar.lc=r22
+ ;;
+ ldf.fill.nta f24=[r2],32
+ ldf.fill.nta f25=[r3],32
+ cmp.eq p8,p9=0,in1
+ ;;
+ ldf.fill.nta f26=[r2],32
+ ldf.fill.nta f27=[r3],32
+ mov ar.pfs=r11
+ ;;
+ ldf.fill.nta f28=[r2],32
+ ldf.fill.nta f29=[r3],32
+ ;;
+ ldf.fill.nta f30=[r2]
+ ldf.fill.nta f31=[r3]
+(p8) mov r8=1
+
+ mov ar.rnat=r26 // restore ar.rnat
+ ;;
+ mov ar.rsc=r27 // restore ar.rsc
+(p9) mov r8=in1
+
+ invala // virt. -> phys. regnum mapping may change
+ mov pr=r24,-1
+ br.ret.dptk.few rp
+ .endp __longjmp
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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.
+ *
+ * This file is derived from the Linux/ia64 kernel source code
+ */
+
+/*
+ *
+ * Optimized version of the standard memcpy() function
+ *
+ * Inputs:
+ * in0: destination address
+ * in1: source address
+ * in2: number of bytes to copy
+ * Output:
+ * no return value
+ *
+ * Copyright (C) 2000 Hewlett-Packard Co
+ * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+
+/* be pessimistic for now... */
+#define CONFIG_ITANIUM_B0_SPECIFIC 1
+
+#if defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)
+# define BRP(args...) nop.b 0
+#else
+# define BRP(args...) brp.loop.imp args
+#endif
+
+ .text
+ // FALL THROUGH
+ .global Memcpy
+ .proc Memcpy
+Memcpy:
+# define MEM_LAT 21 /* latency to memory */
+
+# define dst r2
+# define src r3
+# define retval r8
+# define saved_pfs r9
+# define saved_lc r10
+# define saved_pr r11
+# define cnt r16
+# define src2 r17
+# define t0 r18
+# define t1 r19
+# define t2 r20
+# define t3 r21
+# define t4 r22
+# define src_end r23
+
+# define N (MEM_LAT + 4)
+# define Nrot ((N + 7) & ~7)
+
+ /*
+ * First, check if everything (src, dst, len) is a multiple of eight. If
+ * so, we handle everything with no taken branches (other than the loop
+ * itself) and a small icache footprint. Otherwise, we jump off to
+ * the more general copy routine handling arbitrary
+ * sizes/alignment etc.
+ */
+ .prologue
+ .save ar.pfs, saved_pfs
+ alloc saved_pfs=ar.pfs,3,Nrot,0,Nrot
+ .save ar.lc, saved_lc
+ mov saved_lc=ar.lc
+ or t0=in0,in1
+ ;;
+
+ or t0=t0,in2
+ .save pr, saved_pr
+ mov saved_pr=pr
+
+ .body
+
+ cmp.eq p6,p0=in2,r0 // zero length?
+ mov retval=in0 // return dst
+(p6) br.ret.spnt.many rp // zero length, return immediately
+ ;;
+
+ mov dst=in0 // copy because of rotation
+ shr.u cnt=in2,3 // number of 8-byte words to copy
+ mov pr.rot=1<<16
+ ;;
+
+ adds cnt=-1,cnt // br.ctop is repeat/until
+ cmp.gtu p7,p0=16,in2 // copying less than 16 bytes?
+ mov ar.ec=N
+ ;;
+
+ and t0=0x7,t0
+ mov ar.lc=cnt
+ ;;
+ cmp.ne p6,p0=t0,r0
+
+ mov src=in1 // copy because of rotation
+(p7) br.cond.spnt.few memcpy_short
+(p6) br.cond.spnt.few memcpy_long
+ ;;
+ nop.m 0
+ ;;
+ nop.m 0
+ nop.i 0
+ ;;
+ nop.m 0
+ ;;
+ .rotr val[N]
+ .rotp p[N]
+ .align 32
+1: { .mib
+(p[0]) ld8 val[0]=[src],8
+ nop.i 0
+ BRP(1b, 2f)
+}
+2: { .mfb
+(p[N-1])st8 [dst]=val[N-1],8
+ nop.f 0
+ br.ctop.dptk.few 1b
+}
+ ;;
+ mov ar.lc=saved_lc
+ mov pr=saved_pr,-1
+ mov ar.pfs=saved_pfs
+ br.ret.sptk.many rp
+
+ /*
+ * Small (<16 bytes) unaligned copying is done via a simple byte-at-the-time
+ * copy loop. This performs relatively poorly on Itanium, but it doesn't
+ * get used very often (gcc inlines small copies) and due to atomicity
+ * issues, we want to avoid read-modify-write of entire words.
+ */
+ .align 32
+memcpy_short:
+ adds cnt=-1,in2 // br.ctop is repeat/until
+ mov ar.ec=MEM_LAT
+ BRP(1f, 2f)
+ ;;
+ mov ar.lc=cnt
+ ;;
+ nop.m 0
+ ;;
+ nop.m 0
+ nop.i 0
+ ;;
+ nop.m 0
+ ;;
+ nop.m 0
+ ;;
+ /*
+ * It is faster to put a stop bit in the loop here because it makes
+ * the pipeline shorter (and latency is what matters on short copies).
+ */
+ .align 32
+1: { .mib
+(p[0]) ld1 val[0]=[src],1
+ nop.i 0
+ BRP(1b, 2f)
+} ;;
+2: { .mfb
+(p[MEM_LAT-1])st1 [dst]=val[MEM_LAT-1],1
+ nop.f 0
+ br.ctop.dptk.few 1b
+} ;;
+ mov ar.lc=saved_lc
+ mov pr=saved_pr,-1
+ mov ar.pfs=saved_pfs
+ br.ret.sptk.many rp
+
+ /*
+ * Large (>= 16 bytes) copying is done in a fancy way. Latency isn't
+ * an overriding concern here, but throughput is. We first do
+ * sub-word copying until the destination is aligned, then we check
+ * if the source is also aligned. If so, we do a simple load/store-loop
+ * until there are less than 8 bytes left over and then we do the tail,
+ * by storing the last few bytes using sub-word copying. If the source
+ * is not aligned, we branch off to the non-congruent loop.
+ *
+ * stage: op:
+ * 0 ld
+ * :
+ * MEM_LAT+3 shrp
+ * MEM_LAT+4 st
+ *
+ * On Itanium, the pipeline itself runs without stalls. However, br.ctop
+ * seems to introduce an unavoidable bubble in the pipeline so the overall
+ * latency is 2 cycles/iteration. This gives us a _copy_ throughput
+ * of 4 byte/cycle. Still not bad.
+ */
+# undef N
+# undef Nrot
+# define N (MEM_LAT + 5) /* number of stages */
+# define Nrot ((N+1 + 2 + 7) & ~7) /* number of rotating regs */
+
+#define LOG_LOOP_SIZE 6
+
+memcpy_long:
+ alloc t3=ar.pfs,3,Nrot,0,Nrot // resize register frame
+ and t0=-8,src // t0 = src & ~7
+ and t2=7,src // t2 = src & 7
+ ;;
+ ld8 t0=[t0] // t0 = 1st source word
+ adds src2=7,src // src2 = (src + 7)
+ sub t4=r0,dst // t4 = -dst
+ ;;
+ and src2=-8,src2 // src2 = (src + 7) & ~7
+ shl t2=t2,3 // t2 = 8*(src & 7)
+ shl t4=t4,3 // t4 = 8*(dst & 7)
+ ;;
+ ld8 t1=[src2] // t1 = 1st source word if src is 8-byte aligned, 2nd otherwise
+ sub t3=64,t2 // t3 = 64-8*(src & 7)
+ shr.u t0=t0,t2
+ ;;
+ add src_end=src,in2
+ shl t1=t1,t3
+ mov pr=t4,0x38 // (p5,p4,p3)=(dst & 7)
+ ;;
+ or t0=t0,t1
+ mov cnt=r0
+ adds src_end=-1,src_end
+ ;;
+(p3) st1 [dst]=t0,1
+(p3) shr.u t0=t0,8
+(p3) adds cnt=1,cnt
+ ;;
+(p4) st2 [dst]=t0,2
+(p4) shr.u t0=t0,16
+(p4) adds cnt=2,cnt
+ ;;
+(p5) st4 [dst]=t0,4
+(p5) adds cnt=4,cnt
+ and src_end=-8,src_end // src_end = last word of source buffer
+ ;;
+
+ // At this point, dst is aligned to 8 bytes and there at least 16-7=9 bytes left to copy:
+
+1:{ add src=cnt,src // make src point to remainder of source buffer
+ sub cnt=in2,cnt // cnt = number of bytes left to copy
+ mov t4=ip
+ } ;;
+ and src2=-8,src // align source pointer
+ adds t4=memcpy_loops-1b,t4
+ mov ar.ec=N
+
+ and t0=7,src // t0 = src & 7
+ shr.u t2=cnt,3 // t2 = number of 8-byte words left to copy
+ shl cnt=cnt,3 // move bits 0-2 to 3-5
+ ;;
+
+ .rotr val[N+1], w[2]
+ .rotp p[N]
+
+ cmp.ne p6,p0=t0,r0 // is src aligned, too?
+ shl t0=t0,LOG_LOOP_SIZE // t0 = 8*(src & 7)
+ adds t2=-1,t2 // br.ctop is repeat/until
+ ;;
+ add t4=t0,t4
+ mov pr=cnt,0x38 // set (p5,p4,p3) to # of bytes last-word bytes to copy
+ mov ar.lc=t2
+ ;;
+ nop.m 0
+ ;;
+ nop.m 0
+ nop.i 0
+ ;;
+ nop.m 0
+ ;;
+(p6) ld8 val[1]=[src2],8 // prime the pump...
+ mov b6=t4
+ br.sptk.few b6
+ ;;
+
+memcpy_tail:
+ // At this point, (p5,p4,p3) are set to the number of bytes left to copy (which is
+ // less than 8) and t0 contains the last few bytes of the src buffer:
+(p5) st4 [dst]=t0,4
+(p5) shr.u t0=t0,32
+ mov ar.lc=saved_lc
+ ;;
+(p4) st2 [dst]=t0,2
+(p4) shr.u t0=t0,16
+ mov ar.pfs=saved_pfs
+ ;;
+(p3) st1 [dst]=t0
+ mov pr=saved_pr,-1
+ br.ret.sptk.many rp
+
+///////////////////////////////////////////////////////
+ .align 64
+
+#define COPY(shift,index) \
+ 1: { .mib \
+ (p[0]) ld8 val[0]=[src2],8; \
+ (p[MEM_LAT+3]) shrp w[0]=val[MEM_LAT+3],val[MEM_LAT+4-index],shift; \
+ BRP(1b, 2f) \
+ }; \
+ 2: { .mfb \
+ (p[MEM_LAT+4]) st8 [dst]=w[1],8; \
+ nop.f 0; \
+ br.ctop.dptk.few 1b; \
+ }; \
+ ;; \
+ ld8 val[N-1]=[src_end]; /* load last word (may be same as val[N]) */ \
+ ;; \
+ shrp t0=val[N-1],val[N-index],shift; \
+ br memcpy_tail
+memcpy_loops:
+ COPY(0, 1) /* no point special casing this---it doesn't go any faster without shrp */
+ COPY(8, 0)
+ COPY(16, 0)
+ COPY(24, 0)
+ COPY(32, 0)
+ COPY(40, 0)
+ COPY(48, 0)
+ COPY(56, 0)
+ .endp Memcpy
+
--- /dev/null
+/*
+ * Copyright (C) 1999-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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.
+ *
+ * This code is derived from the Linux/ia64 source code.
+ */
+
+/*
+ *
+ * Optimized version of the standard memset() function
+ *
+ * Return: none
+ *
+ * Inputs:
+ * in0: address of buffer
+ * in1: byte value to use for storing
+ * in2: length of the buffer
+ *
+ */
+
+// arguments
+//
+#define buf r32
+#define val r33
+#define len r34
+
+//
+// local registers
+//
+#define saved_pfs r14
+#define cnt r18
+#define buf2 r19
+#define saved_lc r20
+#define tmp r21
+ .text
+ .global Memset
+ .proc Memset
+Memset:
+ .prologue
+ .save ar.pfs, saved_pfs
+ alloc saved_pfs=ar.pfs,3,0,0,0 // cnt is sink here
+ cmp.eq p8,p0=r0,len // check for zero length
+ .save ar.lc, saved_lc
+ mov saved_lc=ar.lc // preserve ar.lc (slow)
+ ;;
+
+ .body
+
+ adds tmp=-1,len // br.ctop is repeat/until
+ tbit.nz p6,p0=buf,0 // odd alignment
+(p8) br.ret.spnt.few rp
+
+ cmp.lt p7,p0=16,len // if len > 16 then long memset
+ mux1 val=val,@brcst // prepare value
+(p7) br.cond.dptk.few long_memset
+ ;;
+ mov ar.lc=tmp // initialize lc for small count
+ ;; // avoid RAW and WAW on ar.lc
+1: // worst case 15 cyles, avg 8 cycles
+ st1 [buf]=val,1
+ br.cloop.dptk.few 1b
+ ;; // avoid RAW on ar.lc
+ mov ar.lc=saved_lc
+ mov ar.pfs=saved_pfs
+ br.ret.sptk.few rp // end of short memset
+
+ // at this point we know we have more than 16 bytes to copy
+ // so we focus on alignment
+long_memset:
+(p6) st1 [buf]=val,1 // 1-byte aligned
+(p6) adds len=-1,len;; // sync because buf is modified
+ tbit.nz p6,p0=buf,1
+ ;;
+(p6) st2 [buf]=val,2 // 2-byte aligned
+(p6) adds len=-2,len;;
+ tbit.nz p6,p0=buf,2
+ ;;
+(p6) st4 [buf]=val,4 // 4-byte aligned
+(p6) adds len=-4,len;;
+ tbit.nz p6,p0=buf,3
+ ;;
+(p6) st8 [buf]=val,8 // 8-byte aligned
+(p6) adds len=-8,len;;
+ shr.u cnt=len,4 // number of 128-bit (2x64bit) words
+ ;;
+ cmp.eq p6,p0=r0,cnt
+ adds tmp=-1,cnt
+(p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left
+ ;;
+ adds buf2=8,buf // setup second base pointer
+ mov ar.lc=tmp
+ ;;
+2: // 16bytes/iteration
+ st8 [buf]=val,16
+ st8 [buf2]=val,16
+ br.cloop.dptk.few 2b
+ ;;
+.dotail: // tail correction based on len only
+ tbit.nz p6,p0=len,3
+ ;;
+(p6) st8 [buf]=val,8 // at least 8 bytes
+ tbit.nz p6,p0=len,2
+ ;;
+(p6) st4 [buf]=val,4 // at least 4 bytes
+ tbit.nz p6,p0=len,1
+ ;;
+(p6) st2 [buf]=val,2 // at least 2 bytes
+ tbit.nz p6,p0=len,0
+ mov ar.lc=saved_lc
+ ;;
+(p6) st1 [buf]=val // only 1 byte left
+ br.ret.dptk.few rp
+ .endp Memset
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * Copyright (C) 2001 Silicon Graphics, Inc.
+ * Contributed by Brent Casavant <bcasavan@sgi.com>
+ *
+ * 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 "loader.h"
+#include "elf.h"
+#include "private.h"
+
+#define LD_NAME L"plain_elf64"
+
+#define PLAIN_MIN_BLOCK_SIZE sizeof(Elf64_Ehdr) /* see load_elf() for details */
+
+#define SKIPBUFSIZE 2048 /* minimal default size of the skip buffer */
+static CHAR8 *skip_buffer; /* used to skip over unneeded data */
+static UINTN skip_bufsize;
+static UINTN elf_is_big_endian; /* true if ELF file is big endian */
+
+static inline UINT64
+bswap64(UINT64 v)
+{
+ if(elf_is_big_endian) v = __ia64_swab64(v);
+ return v;
+}
+
+static inline UINT32
+bswap32(UINT32 v)
+{
+ if(elf_is_big_endian) v = __ia64_swab32(v);
+ return v;
+}
+
+static inline UINT16
+bswap16(UINT16 v)
+{
+ if(elf_is_big_endian) v = __ia64_swab16(v);
+ return v;
+}
+
+static INTN
+is_valid_header(Elf64_Ehdr *ehdr)
+{
+ UINT16 type, machine;
+
+ if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
+ type = __ia64_swab16(ehdr->e_type);
+ machine = __ia64_swab16(ehdr->e_machine);
+ } else {
+ type = ehdr->e_type;
+ machine = ehdr->e_machine;
+ }
+ DBG_PRT((L"class=%d type=%d data=%d machine=%d\n",
+ ehdr->e_ident[EI_CLASS],
+ type,
+ ehdr->e_ident[EI_DATA],
+ machine));
+
+ return ehdr->e_ident[EI_MAG0] == 0x7f
+ && ehdr->e_ident[EI_MAG1] == 'E'
+ && ehdr->e_ident[EI_MAG2] == 'L'
+ && ehdr->e_ident[EI_MAG3] == 'F'
+ && ehdr->e_ident[EI_CLASS] == ELFCLASS64
+ && type == ET_EXEC /* must be executable */
+ && machine == EM_IA_64 ? 0 : -1;
+}
+
+static INTN
+plain_probe(CHAR16 *kname)
+{
+ Elf64_Ehdr ehdr;
+ EFI_STATUS status;
+ INTN ret = -1;
+ fops_fd_t fd;
+ UINTN size = sizeof(ehdr);
+
+ status = fops_open(kname, &fd);
+ if (EFI_ERROR(status)) return -1;
+
+ status = fops_read(fd, &ehdr, &size);
+
+ if (EFI_ERROR(status) || size != sizeof(ehdr)) goto error;
+
+ ret = is_valid_header(&ehdr);
+error:
+ fops_close(fd);
+ return ret;
+}
+
+/*
+ * move skip bytes forward in the file
+ * this is required because we cannot assume fileops has
+ * seek() capabilities.
+ */
+static INTN
+skip_bytes(fops_fd_t fd, UINTN curpos, UINTN newpos)
+{
+ EFI_STATUS status;
+ UINTN n, skip;
+
+ skip = newpos - curpos;
+ /* check if seek capability exists */
+
+ status = fops_seek(fd, newpos);
+ if (status == EFI_SUCCESS) return 0;
+
+ if (status != EFI_UNSUPPORTED) goto error;
+
+ /* unsupported case */
+
+ if (skip_buffer == NULL) {
+ skip_bufsize = MAX(skip, SKIPBUFSIZE);
+ skip_buffer= (CHAR8 *)alloc(skip_bufsize, EfiLoaderData);
+ if (skip_buffer == NULL) return -1;
+ }
+ while (skip) {
+ n = skip > skip_bufsize? skip_bufsize : skip;
+
+ status = fops_read(fd, skip_buffer, &n);
+ if (EFI_ERROR(status)) goto error;
+
+ skip -=n;
+ }
+ return 0;
+
+error:
+ ERR_PRT((L"%s : cannot skip %d bytes\n", LD_NAME, n));
+ return -1;
+}
+
+static INTN
+load_elf(fops_fd_t fd, kdesc_t *kd)
+{
+ Elf64_Ehdr ehdr;
+ Elf64_Phdr *phdrs;
+ EFI_STATUS status;
+ INTN ret = ELILO_LOAD_ERROR;
+ UINTN i, total_size = 0;
+ UINTN pages, size, bss_sz, osize;
+ UINTN offs = 0;
+ VOID *low_addr = (VOID *)~0;
+ VOID *max_addr = (VOID *)0;
+ UINTN load_offset = 0;
+ UINTN paddr, memsz, filesz, poffs;
+ UINT16 phnum;
+
+ Print(L"Loading Linux... ");
+
+ size = sizeof(ehdr);
+
+ status = fops_read(fd, &ehdr, &size);
+ if (EFI_ERROR(status) ||size < sizeof(ehdr)) return ELILO_LOAD_ERROR;
+
+ offs += size;
+
+ /*
+ * do some sanity checking on the file
+ */
+ if (is_valid_header(&ehdr) == -1) {
+ ERR_PRT((L"%s : not an elf 64-bit file\n", LD_NAME));
+ return ELILO_LOAD_ERROR;
+ }
+
+ /* determine file endianess */
+ elf_is_big_endian = ehdr.e_ident[EI_DATA] == ELFDATA2MSB ? 1 : 0;
+
+ VERB_PRT(3, {
+ Print(L"ELF file is %s\n", elf_is_big_endian ? L"big endian" : L"little endian");
+ Print(L"Entry point 0x%lx\n", bswap64(ehdr.e_entry));
+ Print(L"%d program headers\n", bswap16(ehdr.e_phnum));
+ Print(L"%d segment headers\n", bswap16(ehdr.e_shnum));
+ });
+
+ phnum = bswap16(ehdr.e_phnum);
+
+ if (skip_bytes(fd, offs, bswap64(ehdr.e_phoff)) != 0) {
+ ERR_PRT((L"%s : skip tp %ld for phdrs failed", LD_NAME, offs));
+ return ELILO_LOAD_ERROR;
+ }
+ offs = bswap64(ehdr.e_phoff);
+
+ size = osize = phnum*sizeof(Elf64_Phdr);
+
+ DBG_PRT((L"%s : phdrs allocate %d bytes sizeof=%d entsize=%d\n", LD_NAME, size,sizeof(Elf64_Phdr), bswap16(ehdr.e_phentsize)));
+
+ phdrs = (Elf64_Phdr *)alloc(size, 0);
+ if (phdrs == NULL) {
+ ERR_PRT((L"%s : allocate phdrs failed", LD_NAME));
+ return ELILO_LOAD_ERROR;
+ }
+
+ status = fops_read(fd, phdrs, &size);
+ if (EFI_ERROR(status) || size != osize) {
+ ERR_PRT((L"%s : load phdrs failed", LD_NAME, status));
+ goto out;
+ }
+ offs += size;
+ /*
+ * First pass to figure out:
+ * - lowest physical address
+ * - total memory footprint
+ */
+ for (i = 0; i < phnum; i++) {
+
+ paddr = bswap64(phdrs[i].p_paddr);
+ memsz = bswap64(phdrs[i].p_memsz);
+
+ DBG_PRT((L"Phdr %d paddr [0x%lx-0x%lx] offset %ld"
+ " filesz %ld memsz=%ld bss_sz=%ld p_type=%d\n",
+ 1+i,
+ paddr,
+ paddr+bswap64(phdrs[i].p_filesz),
+ bswap64(phdrs[i].p_offset),
+ bswap64(phdrs[i].p_filesz),
+ memsz,
+ memsz - bswap64(phdrs[i].p_filesz), bswap32(phdrs[i].p_type)));
+
+ if (bswap32(phdrs[i].p_type) != PT_LOAD) continue;
+
+
+ if (paddr < (UINTN)low_addr) low_addr = (VOID *)paddr;
+
+ if (paddr + memsz > (UINTN)max_addr)
+ max_addr = (VOID *)paddr + memsz;
+ }
+
+ if ((UINTN)low_addr & (EFI_PAGE_SIZE - 1)) {
+ ERR_PRT((L"%s : kernel low address 0x%lx not page aligned\n", LD_NAME, low_addr));
+ goto out;
+ }
+
+ /* how many bytes are needed to hold the kernel */
+ total_size = (UINTN)max_addr - (UINTN)low_addr;
+
+ /* round up to get required number of pages */
+ pages = EFI_SIZE_TO_PAGES(total_size);
+
+ /* keep track of location where kernel ends for
+ * the initrd ramdisk (it will be put right after the kernel)
+ */
+ kd->kstart = low_addr;
+ kd->kend = low_addr+ (pages << EFI_PAGE_SHIFT);
+
+ /*
+ * that's the kernel entry point (virtual address)
+ */
+ kd->kentry = (VOID *)bswap64(ehdr.e_entry);
+
+ if (((UINTN)kd->kentry >> 61) != 0) {
+ ERR_PRT((L"%s: <<ERROR>> entry point is a virtual address 0x%lx : not supported anymore\n", LD_NAME, kd->kentry));
+ }
+
+ VERB_PRT(3, {
+ Print(L"Lowest PhysAddr: 0x%lx\nTotalMemSize:%d bytes (%d pages)\n",
+ low_addr, total_size, pages);
+ Print(L"Kernel entry @ 0x%lx\n", kd->kentry);
+ });
+
+ /*
+ * now allocate memory for the kernel at the exact requested spot
+ */
+ if (alloc_kmem(low_addr, pages) == -1) {
+ VOID *new_addr;
+
+ ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
+
+ if (ia64_can_relocate() == 0) {
+ ERR_PRT((L"relocation is disabled, cannot load kernel"));
+ goto out;
+ }
+
+ /*
+ * could not allocate at requested spot, try to find a
+ * suitable location to relocate the kernel
+ *
+ * The maximum sized Itanium TLB translation entry is 256 MB.
+ * If we relocate the kernel by this amount we know for sure
+ * that alignment constraints will be satisified, regardless
+ * of the kernel used.
+ */
+ Print(L"Attempting to relocate kernel.\n");
+ if (find_kernel_memory(low_addr, max_addr, 256*MB, &new_addr) == -1) {
+ ERR_PRT((L"%s : find_kernel_memory(0x%lx, 0x%lx, 0x%lx, 0x%lx) failed\n", LD_NAME, low_addr, max_addr, 256*MB, &load_offset));
+ goto out;
+ }
+ /* unsigned arithmetic */
+ load_offset = (UINTN) (new_addr - ROUNDDOWN((UINTN) low_addr,256*MB));
+
+ VERB_PRT(3, Print(L"low_addr=0x%lx new_addr=0x%lx offset=0x%lx", low_addr, new_addr, load_offset));
+
+ /*
+ * correct various addesses for non-zero load_offset
+ */
+ low_addr = (VOID*) ((UINTN) low_addr + load_offset);
+ max_addr = (VOID*) ((UINTN) max_addr + load_offset);
+ kd->kstart = (VOID *) ((UINTN) kd->kstart + load_offset);
+ kd->kend = (VOID *) ((UINTN) kd->kend + load_offset);
+ kd->kentry = (VOID *) ((UINTN) kd->kentry + load_offset);
+
+ /*
+ * try one last time to get memory for the kernel
+ */
+ if (alloc_kmem(low_addr, pages) == -1) {
+ ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
+ ERR_PRT((L"Relocation by 0x%lx bytes failed.\n", load_offset));
+ goto out;
+ }
+ }
+
+ VERB_PRT(1, Print(L"Press any key to interrupt\n"));
+
+ /* Second pass:
+ * Walk through the program headers
+ * and actually load data into physical memory
+ */
+ for (i = 0; i < phnum; i++) {
+
+ /*
+ * Check for pure loadable segment; ignore if not loadable
+ */
+ if (bswap32(phdrs[i].p_type) != PT_LOAD) continue;
+
+ poffs = bswap64(phdrs[i].p_offset);
+
+ size = poffs - offs;
+
+ VERB_PRT(3, Print(L"\noff=%ld poffs=%ld size=%ld\n", offs, poffs, size));
+
+ filesz = bswap64(phdrs[i].p_filesz);
+ /*
+ * correct p_paddr for non-zero load offset
+ */
+ phdrs[i].p_paddr = (Elf64_Addr) ((UINTN) bswap64(phdrs[i].p_paddr) + load_offset);
+
+ /*
+ * Move to the right position
+ */
+ if (size && skip_bytes(fd, offs, poffs) != 0) goto out_kernel;
+
+ /*
+ * Keep track of current position in file
+ */
+ offs += size;
+
+ /*
+ * How many BSS bytes to clear
+ */
+ bss_sz = bswap64(phdrs[i].p_memsz) - filesz;
+
+ VERB_PRT(4, {
+ Print(L"\nHeader #%d\n", i);
+ Print(L"offset %ld\n", poffs);
+ Print(L"Phys addr 0x%lx\n", phdrs[i].p_paddr); /* already endian adjusted */
+ Print(L"BSS size %ld bytes\n", bss_sz);
+ Print(L"skip=%ld offs=%ld\n", size, offs);
+ });
+
+ /*
+ * Read actual segment into memory
+ */
+ ret = read_file(fd, filesz, (CHAR8 *)phdrs[i].p_paddr);
+ if (ret == ELILO_LOAD_ABORTED) goto load_abort;
+ if (ret == ELILO_LOAD_ERROR) goto out;
+
+ /*
+ * update file position
+ */
+ offs += filesz;
+
+ /*
+ * Clear bss section
+ */
+ if (bss_sz) Memset((VOID *) phdrs[i].p_paddr+filesz, 0, bss_sz);
+ }
+
+ free(phdrs);
+
+ Print(L"..done\n");
+ return ELILO_LOAD_SUCCESS;
+
+load_abort:
+ Print(L"..Aborted\n");
+ ret = ELILO_LOAD_ABORTED;
+out_kernel:
+ /* free kernel memory */
+ free_kmem();
+out:
+ free(phdrs);
+ return ret;
+}
+
+static INTN
+plain_load_kernel(CHAR16 *kname, kdesc_t *kd)
+{
+ INTN ret;
+ fops_fd_t fd;
+ EFI_STATUS status;
+
+ /*
+ * Moving the open here simplifies the load_elf() error handling
+ */
+ status = fops_open(kname, &fd);
+ if (EFI_ERROR(status)) return ELILO_LOAD_ERROR;
+
+ Print(L"Loading %s...", kname);
+
+ ret = load_elf(fd, kd);
+
+ fops_close(fd);
+
+ /*
+ * if the skip buffer was ever used, free it
+ */
+ if (skip_buffer) {
+ free(skip_buffer);
+ /* in case we come back */
+ skip_buffer = NULL;
+ }
+ return ret;
+}
+
+loader_ops_t plain_loader={
+ NULL,
+ LD_NAME,
+ plain_probe,
+ plain_load_kernel
+};
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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_PRIVATE_IA64_H__
+#define __ELILO_PRIVATE_IA64_H__
+
+extern INTN check_fpswa(EFI_HANDLE, EFI_HANDLE, CHAR16 *);
+extern INTN query_fpswa(VOID **);
+
+extern INTN ia64_can_relocate();
+
+#endif /* __ELILO_PRIVATE_IA64_H__ */
+
--- /dev/null
+/* Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA.
+
+ The layout of the jmp_buf is as follows. This is subject to change
+ and user-code should never depend on the particular layout of
+ jmp_buf!
+
+
+ offset: description:
+ ------- ------------
+ 0x000 stack pointer (r12) ; unchangeable (see _JMPBUF_UNWINDS)
+ 0x008 r1 (gp)
+ 0x010 caller's unat
+ 0x018 fpsr
+ 0x020 r4
+ 0x028 r5
+ 0x030 r6
+ 0x038 r7
+ 0x040 rp (b0)
+ 0x048 b1
+ 0x050 b2
+ 0x058 b3
+ 0x060 b4
+ 0x068 b5
+ 0x070 ar.pfs
+ 0x078 ar.lc
+ 0x080 pr
+ 0x088 ar.bsp ; unchangeable (see __longjmp.S)
+ 0x090 ar.unat
+ 0x098 &__jmp_buf ; address of the jmpbuf (needed to locate NaT bits in unat)
+ 0x0a0 f2
+ 0x0b0 f3
+ 0x0c0 f4
+ 0x0d0 f5
+ 0x0e0 f16
+ 0x0f0 f17
+ 0x100 f18
+ 0x110 f19
+ 0x120 f20
+ 0x130 f21
+ 0x130 f22
+ 0x140 f23
+ 0x150 f24
+ 0x160 f25
+ 0x170 f26
+ 0x180 f27
+ 0x190 f28
+ 0x1a0 f29
+ 0x1b0 f30
+ 0x1c0 f31 */
+
+
+ /* The following two entry points are the traditional entry points: */
+
+ .text
+ .global setjmp
+ .proc setjmp
+setjmp:
+ alloc r8=ar.pfs,2,0,0,0
+ mov in1=1
+ br.cond.sptk.many __sigsetjmp
+ .endp setjmp
+
+ /* __sigsetjmp(__jmp_buf buf, int savemask) */
+
+__sigsetjmp:
+ //.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
+ alloc loc1=ar.pfs,2,2,2,0
+ mov r16=ar.unat
+ ;;
+ mov r17=ar.fpsr
+ mov r2=in0
+ add r3=8,in0
+ ;;
+ st8.spill.nta [r2]=sp,16 // r12 (sp)
+ st8.spill.nta [r3]=gp,16 // r1 (gp)
+ ;;
+ st8.nta [r2]=r16,16 // save caller's unat
+ st8.nta [r3]=r17,16 // save fpsr
+ add r8=0xa0,in0
+ ;;
+ st8.spill.nta [r2]=r4,16 // r4
+ st8.spill.nta [r3]=r5,16 // r5
+ add r9=0xb0,in0
+ ;;
+ stf.spill.nta [r8]=f2,32
+ stf.spill.nta [r9]=f3,32
+ mov loc0=rp
+ .body
+ ;;
+ stf.spill.nta [r8]=f4,32
+ stf.spill.nta [r9]=f5,32
+ mov r17=b1
+ ;;
+ stf.spill.nta [r8]=f16,32
+ stf.spill.nta [r9]=f17,32
+ mov r18=b2
+ ;;
+ stf.spill.nta [r8]=f18,32
+ stf.spill.nta [r9]=f19,32
+ mov r19=b3
+ ;;
+ stf.spill.nta [r8]=f20,32
+ stf.spill.nta [r9]=f21,32
+ mov r20=b4
+ ;;
+ stf.spill.nta [r8]=f22,32
+ stf.spill.nta [r9]=f23,32
+ mov r21=b5
+ ;;
+ stf.spill.nta [r8]=f24,32
+ stf.spill.nta [r9]=f25,32
+ mov r22=ar.lc
+ ;;
+ stf.spill.nta [r8]=f26,32
+ stf.spill.nta [r9]=f27,32
+ mov r24=pr
+ ;;
+ stf.spill.nta [r8]=f28,32
+ stf.spill.nta [r9]=f29,32
+ ;;
+ stf.spill.nta [r8]=f30
+ stf.spill.nta [r9]=f31
+
+ st8.spill.nta [r2]=r6,16 // r6
+ st8.spill.nta [r3]=r7,16 // r7
+ ;;
+ mov r23=ar.bsp
+ mov r25=ar.unat
+ mov out0=in0
+
+ st8.nta [r2]=loc0,16 // b0
+ st8.nta [r3]=r17,16 // b1
+ mov out1=in1
+ ;;
+ st8.nta [r2]=r18,16 // b2
+ st8.nta [r3]=r19,16 // b3
+ ;;
+ st8.nta [r2]=r20,16 // b4
+ st8.nta [r3]=r21,16 // b5
+ ;;
+ st8.nta [r2]=loc1,16 // ar.pfs
+ st8.nta [r3]=r22,16 // ar.lc
+ ;;
+ st8.nta [r2]=r24,16 // pr
+ st8.nta [r3]=r23,16 // ar.bsp
+ ;;
+ st8.nta [r2]=r25 // ar.unat
+ st8.nta [r3]=in0 // &__jmp_buf
+ mov r8=0
+ mov rp=loc0
+ mov ar.pfs=loc1
+ br.ret.sptk.many rp
+
+ .endp __sigsetjmp
--- /dev/null
+/* Define the machine-dependent type `jmp_buf'. Linux/IA-64 version.
+ Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+ Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* User code must not depend on the internal representation of jmp_buf. */
+
+#define _JBLEN 70
+
+/* the __jmp_buf element type should be __float80 per ABI... */
+typedef long jmp_buf[_JBLEN] __attribute__ ((aligned (16))); /* guarantees 128-bit alignment! */
+
+extern int setjmp (jmp_buf __env);
+extern void longjmp (jmp_buf __env, int __val);
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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.
+ */
+
+/*
+ * This file is used to define all the IA64-specific data structures, functions,
+ * and constants used by the generic ELILO.
+ *
+ * For things specific to this platform use private.h instead
+ */
+#ifndef __ELILO_SYSDEPS_IA64_H__
+#define __ELILO_SYSDEPS_IA64_H__
+
+#define ELILO_ARCH "IA-64" /* ASCII string ! */
+
+/* in respective assembly files */
+extern VOID Memset(VOID *, INTN, UINTN);
+extern VOID Memcpy(VOID *, VOID *, UINTN);
+
+extern VOID sysdep_register_options(VOID);
+
+/*
+ * This version must match the one in the kernel
+ */
+typedef struct ia64_boot_params {
+ /*
+ * The following three pointers MUST point to memory that is marked
+ * as EfiRuntimeServicesData so that the kernel doesn't think the
+ * underlying memory is free.
+ */
+ UINTN command_line; /* physical address of command line arguments */
+ UINTN efi_systab; /* physical address of EFI system table */
+ UINTN efi_memmap; /* physical address of EFI memory map */
+ UINTN efi_memmap_size; /* size of EFI memory map */
+ UINTN efi_memdesc_size; /* size of an EFI memory map descriptor */
+ UINT32 efi_memdesc_version; /* descriptor version */
+ struct {
+ UINT16 num_cols; /* number of columns on console output device */
+ UINT16 num_rows; /* number of rows on console output device */
+ UINT16 orig_x; /* cursor's x position */
+ UINT16 orig_y; /* cursor's y position */
+ } console_info;
+ UINTN fpswa; /* physical address of fpswa interface */
+ UINTN initrd_start; /* virtual address where the initial ramdisk begins */
+ UINTN initrd_size; /* how big is the initial ramdisk */
+
+ UINTN loader_addr; /* start address of boot loader */
+ UINTN loader_size; /* size of loader code & data */
+} boot_params_t;
+
+typedef struct sys_img_options {
+ UINT8 dummy; /* forces non-zero offset for first field */
+ UINT8 allow_relocation; /* allow kernel relocation on allocation error */
+} sys_img_options_t;
+
+/*
+ * How to jump to kernel code
+ */
+static inline void
+start_kernel(VOID *kentry, VOID *bp)
+{
+ asm volatile ("mov r28=%1; br.sptk.few %0" :: "b"(kentry),"r"(bp));
+}
+
+static inline const UINT64
+__ia64_swab64 (UINT64 x)
+{
+ UINT64 result;
+
+ asm volatile ("mux1 %0=%1,@rev" : "=r" (result) : "r" (x));
+ return result;
+}
+
+static inline const UINT32
+__ia64_swab32 (UINT32 x)
+{
+ return __ia64_swab64(x) >> 32;
+}
+
+static inline const UINT16
+__ia64_swab16(UINT16 x)
+{
+ return __ia64_swab64(x) >> 48;
+}
+
+#endif /* __ELILO_SYSDEPS_IA64_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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.
+ */
+
+/*
+ * this file contains all the IA-64 specific code expected by generic loader
+ */
+#include <efi.h>
+#include <efilib.h>
+
+#include "elilo.h"
+#include "loader.h"
+#include "private.h"
+
+extern loader_ops_t plain_loader, gzip_loader;
+
+/*
+ * IA-64 specific boot paramters initialization routine
+ */
+INTN
+sysdeps_create_boot_params(boot_params_t *bp, CHAR8 *cmdline, memdesc_t *initrd, UINTN *cookie)
+{
+ UINTN cols, rows;
+ SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
+ EFI_STATUS status;
+ mmap_desc_t mdesc;
+
+ /*
+ * retrieve address of FPSWA interface
+ * if not found, argument is not touched
+ * will be 0 because of Memset()
+ */
+ query_fpswa((VOID **)&bp->fpswa);
+
+ if (get_memmap(&mdesc) == -1) return -1;
+
+ DBG_PRT((L"Got memory map @ 0x%lx (%d bytes)", mdesc.md, mdesc.map_size));
+
+ bp->efi_systab = (UINTN)systab;
+ bp->efi_memmap = (UINTN)mdesc.md;
+ bp->efi_memmap_size = mdesc.map_size;
+ bp->efi_memdesc_size = mdesc.desc_size;
+ bp->efi_memdesc_version = mdesc.desc_version;
+ bp->command_line = (UINTN)cmdline;
+ bp->initrd_start = (UINTN) initrd->start_addr;
+ bp->initrd_size = initrd->pgcnt << EFI_PAGE_SHIFT;
+
+ /* fetch console parameters: */
+ conout = systab->ConOut;
+ status = conout->QueryMode(conout, conout->Mode->Mode, &cols, &rows);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"boot_params QueryMode failed %r", status));
+ goto error;
+ }
+ DBG_PRT((L"Got console info: cols=%d rows=%d x=%d y=%d",
+ cols, rows, conout->Mode->CursorColumn, conout->Mode->CursorRow));
+
+ bp->console_info.num_cols = cols;
+ bp->console_info.num_rows = rows;
+ bp->console_info.orig_x = conout->Mode->CursorColumn;
+ bp->console_info.orig_y = conout->Mode->CursorRow;
+
+ *cookie = mdesc.cookie;
+
+ return 0;
+error:
+ /* free descriptors' memory */
+ free_memmap(&mdesc);
+
+ return -1;
+}
+
+VOID
+sysdeps_free_boot_params(boot_params_t *bp)
+{
+ mmap_desc_t md;
+
+ Memset(&md, 0, sizeof(md));
+
+ md.md = (VOID *)bp->efi_memmap;
+
+ free_memmap(&md);
+}
+
+INTN
+sysdeps_init(EFI_HANDLE dev)
+{
+ loader_register(&plain_loader);
+ loader_register(&gzip_loader);
+
+ return 0;
+}
+
+INTN
+sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem)
+{
+ /*
+ * We currently place the initrd at the next page aligned boundary
+ * after the kernel.
+ *
+ * Current kernel implementation requires this (see arch/ia64/kernel/setup.c).
+ *
+ * IMPORTANT: EFI & kernel page sizes may differ. We have no way
+ * of guessing what size the kernel uses. It is the responsibility
+ * of the kernel to adjust.
+ *
+ */
+#if 0
+ imem->start_addr = (VOID *)ROUNDUP((UINTN)kd->kend, EFI_PAGE_SIZE);
+#else
+ imem->start_addr = 0; /* let the allocator decide */
+#endif
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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"
+
+/*
+ * This function allocates memory for the initial ramdisk (initrd) and loads it to memory
+ * OUTPUTS:
+ * - ELILO_LOAD_SUCCESS: if everything works
+ * - ELILO_LOAD_ABORTED: in case the user decided to abort loading
+ * - ELILO_LOAD_ERROR: there was an error during alloc/read
+ *
+ * Adapted from Bill Nottingham <notting@redhat.com> patch for ELI.
+ */
+INTN
+load_initrd(CHAR16 *filename, memdesc_t *initrd)
+{
+ EFI_STATUS status;
+ VOID *start_addr = initrd->start_addr;
+ UINT64 size = 0;
+ UINTN pgcnt;
+ fops_fd_t fd;
+ INTN ret = ELILO_LOAD_ERROR;
+
+
+ if (filename == NULL || filename[0] == 0) return -1;
+
+ /* Open the file */
+ status = fops_open(filename, &fd);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"Open initrd file %s failed: %r", filename, status));
+ return -1;
+ }
+
+ DBG_PRT((L"initrd_open %s worked", filename));
+
+ /* warning: this function allocates memory */
+ status = fops_infosize(fd, &size);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"Couldn't read initrd file %s info %r",filename, status));
+ goto error;
+ }
+
+ /* round up to get required number of pages (4KB) */
+ initrd->pgcnt = pgcnt = EFI_SIZE_TO_PAGES(size);
+
+
+
+ start_addr = alloc_pages(pgcnt, EfiLoaderData, start_addr ? AllocateAddress : AllocateAnyPages, start_addr);
+ if (start_addr == NULL) {
+ ERR_PRT((L"Failed to allocate %d pages for initrd", pgcnt));
+ goto error;
+ }
+ VERB_PRT(2, Print(L"initrd: total_size: %ld bytes base: 0x%lx pages %d\n",
+ size, (UINT64)start_addr, pgcnt));
+
+ Print(L"Loading initrd %s...", filename);
+
+ ret = read_file(fd, size, start_addr);
+
+ fops_close(fd);
+
+ if (ret != ELILO_LOAD_SUCCESS) {
+ ERR_PRT((L"read initrd(%s) failed: %d", filename, ret));
+ goto error;
+ }
+
+ Print(L"done\n");
+
+ initrd->start_addr = start_addr;
+
+ return ELILO_LOAD_SUCCESS;
+
+error:
+ if (start_addr) free(start_addr);
+
+ /*
+ * make sure nothing is passed to kernel
+ * in case of error.
+ */
+ initrd->start_addr = 0;
+ initrd->pgcnt = 0;
+
+ return ret;
+}
+
+
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 "loader.h"
+
+extern loader_ops_t plain_loader;
+extern loader_ops_t gzip_loader;
+
+static loader_ops_t *ldops_list;
+
+loader_ops_t *
+loader_probe(CHAR16 *kname)
+{
+ loader_ops_t *ops;
+
+ for (ops= ldops_list; ops; ops = ops->next) {
+ if (ops->ld_probe(kname) == 0) {
+ return ops;
+ }
+ }
+ return NULL;
+}
+
+INTN
+loader_register(loader_ops_t *ldops)
+{
+ if (ldops == NULL) return -1;
+
+ /* cheap sanity check */
+ if (ldops->next) {
+ ERR_PRT((L"loader %s is already registered", ldops->ld_name));
+ return -1;
+ }
+
+ ldops->next = ldops_list;
+ ldops_list = ldops;
+
+ VERB_PRT(3, Print(L"New loader registered: %s\n", ldops->ld_name));
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 __LOADER_H__
+#define __LOADER_H__
+
+#include "fileops.h"
+
+typedef struct __loader_ops_t {
+ struct __loader_ops_t *next;
+ CHAR16 *ld_name;
+ INTN (*ld_probe)(CHAR16 *kname);
+ INTN (*ld_load_kernel)(CHAR16 *kname, kdesc_t *kd);
+} loader_ops_t;
+
+extern loader_ops_t *loader_probe(CHAR16 *kname);
+extern INTN loader_register(loader_ops_t *ldops);
+
+#endif /* __LOADER_H__ */
--- /dev/null
+/*
+ * Copyright (C) 1999-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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>
+
+//#define CHAR_NULL (CHAR16)'\0'
+
+CHAR16 *
+StrChr(IN const CHAR16 *s, IN const CHAR16 c)
+{
+ for(; *s != c; ++s) if (*s == CHAR_NULL) return NULL;
+
+ return (CHAR16 *)s;
+}
+
+CHAR16 *
+StrnCpy(OUT CHAR16 *dst, IN const CHAR16 *src, IN UINTN size)
+{
+ CHAR16 *res = dst;
+
+ while (size-- && (*dst++ = *src++) != CHAR_NULL);
+ /*
+ * does the null padding
+ */
+ while (size-- > 0) *dst++ = CHAR_NULL;
+
+ return res;
+}
+
+CHAR8 *
+StrnXCpy(OUT CHAR8 *dst, IN const CHAR16 *src, IN UINTN size)
+{
+ CHAR8 *res = dst;
+
+ while (size-- && (*dst++ = (CHAR8)*src++) != '\0');
+ /*
+ * does the null padding
+ */
+ while (size-- > 0) *dst++ = '\0';
+
+ return res;
+}
+
+VOID
+U2ascii(CHAR16 *in, CHAR8 *out, UINTN maxlen)
+{
+ while(maxlen-- > 1 && (*out++ = *in++));
+ *out = '\0';
+}
+
+CHAR8 *
+strncpya(OUT CHAR8 *dst, IN const CHAR8 *src, IN UINTN size)
+{
+ CHAR8 *res = dst;
+
+ while (size-- && (*dst++ = *src++) != '\0');
+ /*
+ * does the null padding
+ */
+ while (size-- > 0) *dst++ = '\0';
+
+ return res;
+}
+
+CHAR8 *
+strcpya(CHAR8 *dst, const CHAR8 *src)
+{
+ CHAR8 *tmp = dst;
+
+ while (*src) {
+ *(dst++) = *(src++);
+ }
+ *dst = 0;
+
+ return tmp;
+
+}
+
+CHAR8 *
+strchra(IN const CHAR8 *s, IN const CHAR8 c)
+{
+ for(; *s != c; ++s)
+ if (*s == 0) return NULL;
+ return (CHAR8 *)s;
+}
+
+CHAR8 *
+strcata(IN CHAR8 *dst,IN CHAR8 *src)
+{
+ return strcpya(dst+strlena(dst), src);
+}
+
+CHAR8 *
+strrchra(IN const CHAR8 *s, const INTN c)
+{
+ CHAR8 *found, *p, ch = (CHAR8)c;
+
+ /* Since strchr is fast, we use it rather than the obvious loop. */
+
+ if (ch == '\0') return strchra(s, '\0');
+
+ found = NULL;
+ while ((p = strchra(s, ch)) != NULL)
+ {
+ found = p;
+ s = p + 1;
+ }
+
+ return (CHAR8 *) found;
+}
+
+CHAR8 *
+strtok_simple(CHAR8 *in, CHAR8 c)
+{
+ static CHAR8 *last;
+ CHAR8 *tmp;
+
+ if (in == NULL) in = last;
+
+ if (in == NULL) return NULL;
+
+ if (*in == c) in++;
+
+ tmp = strchra(in, c);
+ if (tmp) {
+ *tmp = '\0';
+ last = tmp+1;
+ } else {
+ last = NULL;
+ }
+ return in;
+}
+
+VOID
+ascii2U(CHAR8 *in, CHAR16 *out, UINTN maxlen)
+{
+ while(maxlen-- > 1 && (*out++ = *in++));
+
+ *out = (CHAR16)0;
+}
+
+
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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 __STROPS_H__
+#define __STROPS_H__
+
+extern CHAR16 *StrChr(IN const CHAR16 *s, const CHAR16 c);
+extern CHAR16 *StrnCpy(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);
+extern CHAR8 *strrchra(IN const CHAR8 *s, const INTN c);
+extern CHAR8 *strcata(IN CHAR8 *dst,IN CHAR8 *src);
+extern CHAR8 *strchra(IN const CHAR8 *s, IN const CHAR8 c);
+extern CHAR8 *strcpya(CHAR8 *dst, const CHAR8 *src);
+extern CHAR8 *strncpya(OUT CHAR8 *dst, IN const CHAR8 *src, IN UINTN size);
+extern VOID U2ascii(CHAR16 *in, CHAR8 *out, UINTN maxlen);
+
+#endif /* __LOADER_H__ */
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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_SYSDEPS_H__
+#define __ELILO_SYSDEPS_H__
+
+#ifdef CONFIG_ia64
+#include "ia64/sysdeps.h"
+#elif defined CONFIG_ia32
+#include "ia32/sysdeps.h"
+#endif
+
+#endif /* __ELILO_SYSDEPS_H__ */
--- /dev/null
+#
+# Copyright (C) 2001-2003 Hewlett-Packard Co.
+# Contributed by Stephane Eranian <eranian@hpl.hp.com>
+#
+# 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 ../Make.defaults
+include ../Make.rules
+
+TOPDIR=$(CDIR)/..
+
+FILES=eliloalt.o
+TARGET=eliloalt
+
+all: $(TARGET)
+
+#
+# redefine local rule (we build a Linux/ia64 binary here)
+#
+%.o: %.c
+ $(CC) $(OPTIMFLAGS) $(DEBUGFLAGS) -c $< -o $@
+
+$(TARGET): %:%.o
+ $(CC) -o $@ $(OPTIMFLAGS) $(DEBUGFLAGS) $^
+
+clean:
+ $(RM) -f $(TARGET) $(FILES)
+
--- /dev/null
+/*
+ * eliloalt.c
+ *
+ * Copyright (C) 2002-2003 Hewlett-Packard Co
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * 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.
+ *
+ */
+
+/*
+ * This program is used to set the EliloAlt EFI variable to influence
+ * how elilo will behave at the next reboot. This variable is used
+ * to boot a certain kernel/configuration only once (debug, for instance).
+ *
+ * This is is supposed to be installed in /usr/sbin/eliloalt and must only
+ * be run by root.
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <dirent.h>
+
+
+#define ELILOALT_VERSION "0.02"
+
+#define ELILO_ALT_NAME "EliloAlt"
+#define EFIVAR_DIR "/proc/efi/vars"
+#define ELILO_ALTVAR EFIVAR_DIR"/"ELILO_ALT_NAME"-00000000-0000-0000-0000-000000000000"
+
+#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
+#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004
+
+typedef unsigned long efi_status_t;
+typedef uint8_t efi_bool_t;
+typedef uint16_t efi_char16_t; /* UNICODE character */
+
+/*
+ * EFI GUID type definition
+ */
+typedef struct {
+ uint32_t data1;
+ uint16_t data2;
+ uint16_t data3;
+ uint8_t data4[8];
+} efi_guid_t;
+
+/*
+ * EFI variable structure
+ */
+typedef struct _efi_variable_t {
+ efi_char16_t variablename[1024/sizeof(efi_char16_t)];
+ efi_guid_t vendorguid;
+ uint64_t datasize;
+ uint8_t data[1024];
+ efi_status_t status;
+ uint32_t attributes;
+} __attribute__((packed)) efi_variable_t;
+
+static char *elilo_alt_name = ELILO_ALT_NAME;
+
+static struct option cmd_options[]={
+ { "version", 0, 0, 1},
+ { "help", 0, 0, 2},
+ { "delete", 0, 0, 3},
+ { "print", 0, 0, 4},
+ { "set", 1, 0, 5},
+ { 0, 0, 0, 0}
+};
+
+static void fatal_error(char *fmt,...) __attribute__((noreturn));
+
+static void
+fatal_error(char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ exit(1);
+}
+
+
+static void
+usage(char **argv)
+{
+ printf("Usage: %s [OPTIONS] cmdline\n", argv[0]);
+
+ printf( "-h, --help\t\tdisplay this help and exit\n"
+ "--version\t\toutput version information and exit\n"
+ "-s, --set cmdline\tset elilo alternate variable to cmdline\n"
+ "-p, --print\t\tprint elilo alternate variable\n"
+ "-d, --delete\t\tprint elilo alternate variable\n"
+ );
+}
+
+static char *
+check_proc_efi(int find_entry)
+{
+ DIR *efi_vars;
+ struct dirent *entry;
+ static char name[1024];
+
+ if (getuid() != 0) {
+ fatal_error("This program must be run as root\n");
+ }
+ efi_vars = opendir(EFIVAR_DIR);
+ if (efi_vars == NULL) {
+ fatal_error("Cannot access %s\n", EFIVAR_DIR);
+ }
+ if (!find_entry) {
+ closedir(efi_vars);
+ return NULL;
+ }
+ /* Find one entry we can open */
+ while ((entry = readdir(efi_vars)) != NULL) {
+ if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
+ break;
+ }
+ if (entry == NULL) {
+ fatal_error("Cannot find entry in %s\n", EFIVAR_DIR);
+ }
+ sprintf(name, "%s/%s", EFIVAR_DIR, entry->d_name);
+ closedir(efi_vars);
+ return name;
+}
+
+static void
+delete_var(void)
+{
+ efi_variable_t var;
+ int fd, r, i;
+
+ check_proc_efi(0);
+
+ fd = open(ELILO_ALTVAR, O_WRONLY);
+ if (fd == -1) {
+ fatal_error("variable not defined\n");
+ }
+
+ memset(&var, 0, sizeof(var));
+
+ for (i=0; i < sizeof(elilo_alt_name); i++) {
+ var.variablename[i] = (efi_char16_t)elilo_alt_name[i];
+ }
+
+ /*
+ * we use NULL GUID so no need to initialize it now memset() did it
+ * writing with a datasize=0 will effectively delete the variable.
+ */
+
+ r = write(fd, &var, sizeof(var));
+ if (r != sizeof(var)) {
+ fatal_error("Variable %s defined but invalid content\n", ELILO_ALTVAR);
+ }
+ close(fd);
+}
+
+
+static void
+print_var(void)
+{
+ efi_variable_t var;
+ int fd, r, i;
+
+
+ check_proc_efi(0);
+
+ fd = open(ELILO_ALTVAR, O_RDONLY);
+ if (fd == -1) {
+ fatal_error("variable not defined\n");
+ }
+
+ memset(&var, 0, sizeof(var));
+
+ r = read(fd, &var, sizeof(var));
+ if (r != sizeof(var)) {
+ fatal_error("Variable %s defined but invalid content\n", ELILO_ALTVAR);
+ }
+ printf("EliloAlt=\"");
+ for(i=0; i < var.datasize; i+=1){
+ printf("%c", var.data[i]);
+ }
+ printf("\"\n");
+ close(fd);
+}
+
+static void
+set_var(char *cmdline)
+{
+ efi_variable_t var;
+ int fd, r, i, j, l;
+ char *name;
+
+ name = check_proc_efi(1);
+
+ if (cmdline == NULL) {
+ fatal_error("invalid cmdline argument\n");
+ }
+
+ l = strlen(cmdline);
+
+ if (l >= 1024) {
+ fatal_error("Variable content is too long, must be <= 512 characters\n");
+ }
+
+ fd = open(name, O_WRONLY);
+ if (fd == -1) {
+ fatal_error("can't open %s: %s\n", ELILO_ALTVAR, strerror(errno));
+ }
+
+ memset(&var, 0, sizeof(var));
+
+ for (i=0; i < sizeof(elilo_alt_name); i++) {
+ var.variablename[i] = (efi_char16_t)elilo_alt_name[i];
+ }
+
+ for (i=0, j=0; i < l; i++, j+=2) {
+ var.data[j] = (efi_char16_t)cmdline[i];
+ }
+ /* +2 = include char16 for null termination */
+ var.datasize = j+2;
+
+ var.attributes = EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
+
+ /*
+ * we use NULL GUID so no need to initialize it now memset() did it
+ * writing with a datasize=0 will effectively delete the variable.
+ */
+
+ r = write(fd, &var, sizeof(var));
+ if (r != sizeof(var)) {
+ fatal_error("Variable %s defined but invalid content %d\n", ELILO_ALTVAR, r);
+ }
+ close(fd);
+
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+
+ while ((c=getopt_long(argc, argv,"hdps:", cmd_options, 0)) != -1) {
+ switch(c) {
+ case 0: continue; /* fast path for options */
+ case 1:
+ printf("Version %s Date: %s\n", ELILOALT_VERSION, __DATE__);
+ exit(0);
+ case 2:
+ case 'h':
+ usage(argv);
+ exit(0);
+ case 3:
+ case 'd':
+ delete_var();
+ exit(0);
+ case 4:
+ case 'p':
+ print_var();
+ exit(0);
+ case 5:
+ case 's':
+ set_var(optarg);
+ exit(0);
+ default:
+ fatal_error("Unknown option\n");
+ }
+ }
+ print_var();
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * Copyright (C) 2001 Silicon Graphics, Inc.
+ * Contributed by Brent Casavant <bcasavan@sgi.com>
+ *
+ * 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"
+
+#define TENTH_SEC 1000000 /* 1/10th second in 100ns unit */
+#define READ_BLOCK_SIZE (4*EFI_PAGE_SIZE) /* block size for read_file */
+
+#define is_cr(k) (((k)==CHAR_LINEFEED)||((k)==CHAR_CARRIAGE_RETURN))
+#define CHAR_SPACE L' '
+
+static INTN
+read_keypress(EFI_INPUT_KEY *key)
+{
+ return systab->ConIn->ReadKeyStroke(systab->ConIn, key);
+}
+
+
+EFI_STATUS
+check_abort(VOID)
+{
+ EFI_INPUT_KEY key;
+
+ return read_keypress(&key);
+}
+
+inline VOID
+reset_input(VOID)
+{
+ systab->ConIn->Reset(systab->ConIn, 1);
+}
+
+#if 0
+INTN
+wait_keypress_abort(VOID)
+{
+ SIMPLE_INPUT_INTERFACE *conin = systab->ConIn;
+ EFI_INPUT_KEY key;
+ EFI_STATUS status;
+
+ reset_input();
+
+ Print(L"Hit ENTER to continue or ANY other key to cancel");
+
+ /* cleanup buffer first */
+ while (conin->ReadKeyStroke(conin, &key) == EFI_SUCCESS);
+
+ while ((status=conin->ReadKeyStroke(conin, &key)) == EFI_NOT_READY );
+
+ if (EFI_ERROR(status)) return ELILO_LOAD_ERROR;
+
+ Print(L"\n");
+
+ return is_cr(key.UnicodeChar) ? ELILO_LOAD_SUCCESS: ELILO_BOOT_ABORTED;
+}
+#endif
+
+/*
+ * wait for timeout to expire or keypress
+ * Return:
+ * 0 : timeout expired
+ * 1 : a key was pressed (still input stream to process)
+ * -1: an error occured
+ */
+INTN
+wait_timeout(UINTN timeout)
+{
+ EFI_STATUS status;
+ EFI_EVENT timer;
+ EFI_EVENT list[2];
+ UINTN idx;
+
+
+ if (timeout == 0) return 0;
+
+ /* Create a timeout timer */
+ status = BS->CreateEvent(EVT_TIMER, 0, NULL, NULL, &timer);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L" waitkey CreateEvent failed %r", status));
+ return -1;
+ }
+ /* In 100ns increments */
+ status = BS->SetTimer(timer, TimerPeriodic, TENTH_SEC);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"waitkey SetTimer failed %r", status));
+ return -1;
+ }
+
+ list[0] = timer;
+ list[1] = systab->ConIn->WaitForKey;
+
+ do {
+ status = BS->WaitForEvent(2, list, &idx);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"waitkey WaitForEvent failed %r", status));
+ return -1;
+ }
+
+ } while (timeout-- && idx == 0);
+
+ /*
+ * SetTimer(timer, TimerCancel, 0) is causing problems on IA-32 and gcc3
+ * I do not know why it dies with EFI12.35. So let's fake a key stroke.
+ */
+ status = BS->SetTimer(timer, TimerCancel, 0);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"waitkey SetTimer(TimerCancel) failed %r", status));
+ return -1;
+ }
+
+ BS->CloseEvent(timer);
+
+ return idx ? 1 : 0;
+}
+
+INTN
+argify(CHAR16 *buf, UINTN len, CHAR16 **argv)
+{
+
+ UINTN i=0, j=0;
+ CHAR16 *p = buf;
+
+ if (buf == 0) {
+ argv[0] = NULL;
+ return 0;
+ }
+ /* len represents the number of bytes, not the number of 16 bytes chars */
+ len = len >> 1;
+
+ /*
+ * Here we use CHAR_NULL as the terminator rather than the length
+ * because it seems like the EFI shell return rather bogus values for it.
+ * Apparently, we are guaranteed to find the '\0' character in the buffer
+ * where the real input arguments stop, so we use it instead.
+ */
+ for(;;) {
+ while (buf[i] == CHAR_SPACE && buf[i] != CHAR_NULL && i < len) i++;
+
+ if (buf[i] == CHAR_NULL || i == len) goto end;
+
+ p = buf+i;
+ i++;
+
+ while (buf[i] != CHAR_SPACE && buf[i] != CHAR_NULL && i < len) i++;
+
+ argv[j++] = p;
+
+ if (buf[i] == CHAR_NULL) goto end;
+
+ buf[i] = CHAR_NULL;
+
+ if (i == len) goto end;
+
+ i++;
+
+ if (j == MAX_ARGS-1) {
+ ERR_PRT((L"too many arguments (%d) truncating", j));
+ goto end;
+ }
+ }
+end:
+#if 0
+ if (i != len) {
+ ERR_PRT((L"ignoring trailing %d characters on command line", len-i));
+ }
+#endif
+ argv[j] = NULL;
+ return j;
+}
+
+VOID
+unargify(CHAR16 **argv, CHAR16 **args)
+{
+ if ( *argv == 0 ) {
+ *args = L"";
+ return;
+ }
+ *args = *argv;
+ while ( argv[1] ) {
+ (*argv)[StrLen(*argv)] = CHAR_SPACE;
+ argv++;
+ }
+}
+
+VOID
+split_args(CHAR16 *buffer, CHAR16 *kname, CHAR16 *args)
+{
+ CHAR16 *tmp;
+
+ /* find beginning of kernel name */
+ while (*buffer && *buffer == CHAR_SPACE) buffer++;
+
+ tmp = buffer;
+
+ /* scan through kernel name */
+ while (*buffer && *buffer != CHAR_SPACE) buffer++;
+
+ if (*buffer) {
+ *buffer++ = CHAR_NULL;
+ StrCpy(kname, tmp);
+ }
+
+ /* skip space between kernel and args */
+ while (*buffer && *buffer == CHAR_SPACE) buffer++;
+
+ StrCpy(args, buffer);
+}
+
+INTN
+read_file(UINTN fd, UINTN total_size, CHAR8 *buffer)
+{
+ INTN size, j=0;
+ EFI_STATUS status;
+ CHAR16 helicopter[4] = { L'|' , L'/' , L'-' , L'\\' };
+ INTN ret = ELILO_LOAD_SUCCESS;
+ UINTN sum = 0;
+ /*
+ * We load by chunks rather than a single big read because
+ * early versions of EFI had troubles loading files
+ * from floppies in a single big request. Breaking
+ * the read down into chunks of 4KB fixed that
+ * problem. While this problem has been fixed, we still prefer
+ * this method because it tells us whether or not we're making
+ * forward progress.
+ */
+
+ while (total_size > 0) {
+ size = total_size < READ_BLOCK_SIZE? total_size : READ_BLOCK_SIZE;
+
+ status = fops_read(fd, buffer, &size);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"read_file failed %r", status));
+ return ELILO_LOAD_ERROR;
+ }
+ sum += size;
+
+ Print(L"%c\b",helicopter[j++%4]);
+
+ buffer += size;
+ total_size -= size;
+
+ if (check_abort() == EFI_SUCCESS) {
+ ret = ELILO_LOAD_ABORTED;
+ break;
+ }
+ }
+ return ret;
+}
+
+INTN
+get_memmap(mmap_desc_t *desc)
+{
+#define ELILO_MEMMAP_SIZE_DEFAULT EFI_PAGE_SIZE
+#define ELILO_MEMMAP_INC (sizeof(EFI_MEMORY_DESCRIPTOR)<<1)
+
+ EFI_STATUS status;
+
+ desc->map_size = ELILO_MEMMAP_SIZE_DEFAULT;
+
+ for(;;) {
+ desc->md = (EFI_MEMORY_DESCRIPTOR *)alloc(desc->map_size, EfiLoaderData);
+
+ if (desc->md == NULL) {
+ ERR_PRT((L"failed to allocate memory map buffer"));
+ return -1;
+ }
+ status = (*BS->GetMemoryMap)(&desc->map_size, desc->md, &desc->cookie, &desc->desc_size, &desc->desc_version);
+ if (status == EFI_SUCCESS) break;
+
+ free(desc->md);
+
+ if (status != EFI_BUFFER_TOO_SMALL) {
+ ERR_PRT((L"failed to obtain memory map %r"));
+ return -1;
+ }
+ desc->map_size += ELILO_MEMMAP_INC;
+ }
+ DBG_PRT((L"final get_memmap map_size=%ld", desc->map_size));
+
+ return 0;
+}
+
+#if 0
+INTN
+get_memmap(mmap_desc_t *desc)
+{
+ EFI_STATUS status;
+
+ /* will get the right size in return */
+ desc->map_size = 0;
+
+ status = BS->GetMemoryMap(&desc->map_size, desc->md, &desc->cookie, &desc->desc_size, &desc->desc_version);
+ if (status != EFI_BUFFER_TOO_SMALL) return -1;
+
+ desc->md = (EFI_MEMORY_DESCRIPTOR *)alloc(desc->map_size, EfiLoaderData);
+ if (desc->md == NULL) {
+ ERR_PRT((L"failed to allocate memory map buffer"));
+ return -1;
+ }
+
+
+ status = BS->GetMemoryMap(&desc->map_size, desc->md, &desc->cookie, &desc->desc_size, &desc->desc_version);
+ if (EFI_ERROR(status)) {
+ ERR_PRT((L"failed to obtain memory map %d: %r", desc->map_size, status));
+ free(desc->md);
+ return -1;
+ }
+ DBG_PRT((L"final get_memmap map_size=%d", desc->map_size));
+
+ return 0;
+}
+#endif
+
+
+VOID
+free_memmap(mmap_desc_t *desc)
+{
+ if (desc->md) {
+ free(desc->md);
+ desc->md = NULL;
+ }
+}
+
+VOID
+print_memmap(mmap_desc_t *desc)
+{
+ EFI_MEMORY_DESCRIPTOR *md;
+ UINTN desc_size;
+ VOID *p;
+ VOID *md_end;
+ INT8 printed;
+ UINTN ntypes;
+ CHAR16* str;
+
+ static CHAR16 *memtypes[]={
+ L"ReservedMemoryType",
+ L"LoaderCode",
+ L"LoaderData",
+ L"BootServicesCode",
+ L"BootServicesData",
+ L"RuntimeServicesCode",
+ L"RuntimeServicesData",
+ L"ConventionalMemory",
+ L"UnusableMemory",
+ L"ACPIReclaimMemory",
+ L"ACPIMemoryNVS",
+ L"MemoryMappedIO",
+ L"MemoryMappedIOPortSpace",
+ L"PalCode"
+ };
+
+
+ md_end = ((VOID *)desc->md)+desc->map_size;
+ desc_size = desc->desc_size;
+
+ ntypes = sizeof(memtypes)/sizeof(CHAR16 *);
+
+ for(p = desc->md; p < md_end; p += desc_size) {
+ md = p;
+
+ str = md->Type < ntypes ? memtypes[md->Type] : L"Unknown";
+
+ Print(L"%24s %lx-%lx %8lx", str, md->PhysicalStart,
+ md->PhysicalStart+(md->NumberOfPages<<EFI_PAGE_SHIFT),
+ md->NumberOfPages);
+
+ printed=0;
+#define P_FLG(f) { \
+ Print(L" %s %s", printed ? L"|":L"", f); \
+ printed=1; \
+}
+
+ if (md->Attribute & EFI_MEMORY_UC) {
+ P_FLG(L"UC");
+ }
+ if (md->Attribute & EFI_MEMORY_WC) {
+ P_FLG(L"WC");
+ }
+ if (md->Attribute & EFI_MEMORY_WT) {
+ P_FLG(L"WT");
+ }
+ if (md->Attribute & EFI_MEMORY_WB) {
+ P_FLG(L"WB");
+ }
+ if (md->Attribute & EFI_MEMORY_UCE) {
+ P_FLG(L"UCE");
+ }
+ if (md->Attribute & EFI_MEMORY_WP) {
+ P_FLG(L"WP");
+ }
+ if (md->Attribute & EFI_MEMORY_RP) {
+ P_FLG(L"RP");
+ }
+ if (md->Attribute & EFI_MEMORY_XP) {
+ P_FLG(L"XP");
+ }
+ if (md->Attribute & EFI_MEMORY_RUNTIME) {
+ P_FLG(L"RT");
+ }
+ Print(L"\n");
+ }
+}
+
+INTN
+find_kernel_memory(VOID* low_addr, VOID* max_addr, UINTN alignment, VOID** start)
+{
+#define HIGHEST_ADDR (VOID*)(~0)
+ mmap_desc_t mdesc;
+ EFI_MEMORY_DESCRIPTOR *md;
+ UINT64 size;
+ VOID *p, *addr;
+ VOID *desc_end, *md_end, *best_addr = HIGHEST_ADDR;
+
+ /*
+ * first get up-to-date memory map
+ *
+ * XXX: is there a danger of not seeing the latest version if interrupted
+ * during our scan ?
+ *
+ */
+ if (get_memmap(&mdesc) == -1) {
+ ERR_PRT((L"find_kernel_memory :GetMemoryMap() failed"));
+ return -1;
+ }
+
+ desc_end = ((VOID *)mdesc.md) + mdesc.map_size;
+ size = max_addr - low_addr;
+ /*
+ * Find memory which covers the desired range
+ */
+ for(p = mdesc.md; p < desc_end; p += mdesc.desc_size) {
+ md = p;
+
+ /*
+ * restrict to decent memory types.
+ *
+ * the EFI memory map report where memory is and how it is currently used
+ * using types.
+ *
+ * EfiLoaderData which is used by the AllocatePages() cannot be used
+ * here because it may hold some valid information. Same thing for most
+ * of the memory types with the exception of EfiConventional which
+ * can be assumed as being free to use.
+ */
+ if (md->Type != EfiConventionalMemory) continue;
+
+ /*
+ * compute aligned address and upper boundary for range
+ */
+ md_end = (VOID*)(md->PhysicalStart + md->NumberOfPages * EFI_PAGE_SIZE);
+ addr = (VOID*)ROUNDUP(md->PhysicalStart, alignment);
+
+ /*
+ * need to check if:
+ * - aligned address still in the range
+ * - the range [addr-addr+size) still fits into memory range
+ * if so we have a match. We do not assume that the memory ranges
+ * are sorted by EFI, therefore we must record the match and only
+ * keep the lowest possible one.
+ */
+ if (addr < best_addr && addr < md_end && addr+size <= md_end) best_addr = addr;
+ }
+ if (best_addr == HIGHEST_ADDR) {
+ free_memmap(&mdesc);
+ ERR_PRT((L"Could not find memory suitable for loading image"));
+ return -1;
+ }
+
+ *start = best_addr;
+
+ free_memmap(&mdesc);
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * Copyright (C) 2001 Silicon Graphics, Inc.
+ * Contributed by Brent Casavant <bcasavan@sgi.com>
+ *
+ * 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>
+
+/*
+ * A variable name is 1 character long and case sensitive. So
+ * we actually have 52 (26*2) possible variables.
+ */
+#define MAX_VARIABLES (26<<1)
+#define MAX_VARIABLE_LENGTH 128
+#define VAR_IDX(a) (((a) >= 'a' && (a) <= 'z') ? 26-'a'+(a) : (a)-'A')
+#define IDX_VAR(i) ((i) < 26 ? 'A'+(i) : 'a'+ ((i)-26))
+
+typedef struct {
+ CHAR16 value[MAX_VARIABLE_LENGTH];
+} elilo_var_t;
+
+static elilo_var_t vars[MAX_VARIABLES]; /* set of variables */
+
+INTN
+set_var(CHAR16 v, CHAR16 *value)
+{
+ /* invalid variable name */
+ if (v < 'A' || (v > 'Z' && v < 'a') || v > 'z') return -1;
+
+ StrCpy(vars[VAR_IDX(v)].value, value);
+ return 0;
+}
+
+CHAR16 *
+get_var(CHAR16 v)
+{
+ /* invalid variable name */
+ if (v < L'A' || (v > L'Z' && v < L'a') || v > L'z') return NULL;
+
+ return vars[VAR_IDX(v)].value;
+}
+
+
+VOID
+print_vars(VOID)
+{
+ INTN i;
+ UINTN cnt = 0;
+
+ for(i=0; i < MAX_VARIABLES; i++) {
+ if (vars[i].value[0]) {
+ cnt++;
+ Print(L"%c = \"%s\"\n", IDX_VAR(i), vars[i].value);
+ }
+ }
+ if (cnt == 0) Print(L"no variable defined\n");
+}
+
+
+INTN
+subst_vars(CHAR16 *in, CHAR16 *out, INTN maxlen)
+{
+ /*
+ * we cannot use \\ for the despecialization character because
+ * it is also used as a path separator in EFI.
+ */
+#define DSPEC_CHAR L'&'
+ INTN i, l, j, cnt;
+ INTN m = 0, d = 0;
+ CHAR16 *val;
+
+ if (in == NULL || out == NULL || maxlen <= 1) return -1;
+
+ l = StrLen(in);
+
+ maxlen--;
+
+ for (i=0, j=0;i < l; i++) {
+ cnt = 1;
+ val = in+i;
+
+ if (*val == DSPEC_CHAR && d == 0) {
+ d = 1;
+ continue;
+ }
+ if(m == 1) {
+ m = 0;
+ val = get_var(*val);
+
+ if (val == NULL) continue;
+
+ cnt = StrLen(val);
+
+ } else if (*val == L'%' && d == 0) {
+ m = 1;
+ continue;
+ }
+ d = 0;
+ while (j < maxlen && cnt) {
+ out[j++] = *val++;
+ cnt--;
+ }
+ if (j == maxlen) break;
+ }
+ out[j] = CHAR_NULL;
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001-2003 Hewlett-Packard Co.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * Copyright (C) 2001 Silicon Graphics, Inc.
+ * Contributed by Brent Casavant <bcasavan@sgi.com>
+ *
+ * This file is part of the ELILO, the EFI Linux boot loader.
+ *
+ * GNU EFI 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.
+ *
+ * GNU EFI 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 GNU EFI; 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_VARS_H__
+#define __ELILO_VARS_H__
+/*
+ * This file contains the list of defined variables.
+ * It is expected that every module which uses a variable add its entry
+ * here.
+ * The syntax for the name is: VAR_modulename_meaning L'X'
+ * where:
+ * - modulename: a string representing the module that uses the variable
+ * - meaning : a string representing the meaning of the variable for the module
+ * - X : the variable name [A-Za-z]
+ */
+
+/* from glue_netfs.c */
+#define VAR_NETFS_IPADDR L'I' /* the IP address obtained by DHCP/PXE */
+#define VAR_NETFS_NETMASK L'M' /* the netmask obtained by DHCP/PXE */
+#define VAR_NETFS_GATEWAY L'G' /* the gateway obtained by DHCP/PXE */
+#define VAR_NETFS_HOSTNAME L'H' /* the hostname obtained by DHCP/PXE */
+#define VAR_NETFS_DOMAINAME L'D' /* the domain name obtained by DHCP/PXE */
+
+extern INTN set_var(CHAR16 v, CHAR16 *value);
+extern CHAR16 * get_var(CHAR16 v);
+extern VOID print_vars(VOID);
+extern INTN subst_vars(CHAR16 *in, CHAR16 *out, INTN maxlen);
+
+#endif /* __ELILO_VARS_H__ */
+