Stephane Eranian 2004-02-23 08:11:30 -05:00 committed by Vincent Batts
commit fb6ce0d596
100 changed files with 20247 additions and 0 deletions

338
ChangeLog Normal file
View file

@ -0,0 +1,338 @@
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

3
LIMITATIONS Normal file
View file

@ -0,0 +1,3 @@
See the TODO file, for more on the known limitations of this version of elilo.

131
Make.defaults Normal file
View file

@ -0,0 +1,131 @@
#
# 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

35
Make.rules Normal file
View file

@ -0,0 +1,35 @@
#
# 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 $@

103
Makefile Normal file
View file

@ -0,0 +1,103 @@
#
# 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

74
README Normal file
View file

@ -0,0 +1,74 @@
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.

31
README.gnu-efi Normal file
View file

@ -0,0 +1,31 @@
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

18
TODO Normal file
View file

@ -0,0 +1,18 @@
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

240
alloc.c Normal file
View file

@ -0,0 +1,240 @@
/*
* 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();
}

118
alternate.c Normal file
View file

@ -0,0 +1,118 @@
/*
* 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;
}

123
bootparams.c Normal file
View file

@ -0,0 +1,123 @@
/*
* 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);
}

114
chooser.c Normal file
View file

@ -0,0 +1,114 @@
/*
* 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;
}

60
chooser.h Normal file
View file

@ -0,0 +1,60 @@
/*
* 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__ */

58
choosers/Makefile Normal file
View file

@ -0,0 +1,58 @@
#
# 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

410
choosers/simple.c Normal file
View file

@ -0,0 +1,410 @@
/*
* 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
};

35
choosers/simple.h Normal file
View file

@ -0,0 +1,35 @@
/*
* 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

528
choosers/textmenu.c Normal file
View file

@ -0,0 +1,528 @@
/*
* 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
};

35
choosers/textmenu.h Normal file
View file

@ -0,0 +1,35 @@
/*
* 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

1171
config.c Normal file

File diff suppressed because it is too large Load diff

56
config.h Normal file
View file

@ -0,0 +1,56 @@
/*
* 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__ */

46
devschemes/Makefile Normal file
View file

@ -0,0 +1,46 @@
#
# 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)

152
devschemes/simple.c Normal file
View file

@ -0,0 +1,152 @@
/*
* 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
};

106
docs/devschemes.txt Normal file
View file

@ -0,0 +1,106 @@
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.

102
docs/edd30.txt Normal file
View file

@ -0,0 +1,102 @@
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).

478
docs/elilo.txt Normal file
View file

@ -0,0 +1,478 @@
--------------------------------------------------------------------
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

77
docs/eliloalt.txt Normal file
View file

@ -0,0 +1,77 @@
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

53
docs/elilovars.txt Normal file
View file

@ -0,0 +1,53 @@
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.

22
docs/fpswa.txt Normal file
View file

@ -0,0 +1,22 @@
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.

396
docs/netbooting.txt Normal file
View file

@ -0,0 +1,396 @@
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/

156
docs/simple_chooser.txt Normal file
View file

@ -0,0 +1,156 @@
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

61
docs/textmenu_chooser.txt Normal file
View file

@ -0,0 +1,61 @@
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.

632
elf.h Normal file
View file

@ -0,0 +1,632 @@
/*
* 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__ */

BIN
elilo-ia32.efi Executable file

Binary file not shown.

BIN
elilo-ia64.efi Executable file

Binary file not shown.

654
elilo.c Normal file
View file

@ -0,0 +1,654 @@
/*
* 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;
}

201
elilo.h Normal file
View file

@ -0,0 +1,201 @@
/*
* 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__ */

44
elilo_debug.h Normal file
View file

@ -0,0 +1,44 @@
/*
* 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__ */

View file

@ -0,0 +1,188 @@
#
# 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";
}
}

View file

@ -0,0 +1,14 @@
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";
}
}

View file

@ -0,0 +1,45 @@
#
# 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"

View file

@ -0,0 +1,25 @@
° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß
10
7fÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ 74General Screen7f ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ70¿10
7f³70 ³10
7f³70 This is the general screen. You entered by pressing F1 ³10
7f³70 ³10
7f³70 Press any key to return to main screen ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 Help: [71F170-General] [71F270-Params] ³10
7fÀ70ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ10

View file

@ -0,0 +1,25 @@
° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß
10
7fÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ 74Params Screen7f ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ70¿10
7f³70 ³10
7f³70 This is the params screen. You entered by pressing F2 ³10
7f³70 ³10
7f³70 Press any key to return to main screen ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 Help: [71F170-General] [71F270-Params] ³10
7fÀ70ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ10

View file

@ -0,0 +1,25 @@
° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß
10
7fÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ 74Install and Recovery Disk7f ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ70¿10
7f³70 This CD demonstrates the elilo textmenu chooser. You can select an entry ³10
7f³70 from the menu with the curosr keys, enter exptra parameters at the propmt, ³10
7f³70 and press <return> to start the process. Help can be made available via ³10
7f³70 the function keys. On a serial console, use Ctrl-F followed by the ³10
7f³70 relevant function key number. ³10
7f³70 ³10
7f³70 7eBeware that this is an install disk, and misuse can result in the loss of 70³10
7f³70 7eany data currently on your disks. 70³10
7f³70 ³10
7f³70 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ7f¿70 ³10
7f³70 ³70 This is where the menu goes 7f³70 ³10
7f³70 ³701e (active colour) 7f³70 ³10
7f³70 ³70 (inactive colour) 7f³70 ³10
7f³70 ³70 1e7f³70 ³10
7f³70 À7fÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ70 ³10
7f³70 ³10
7f³70 ³10
7f³70 ³10
7f³70 Boot: 35 70 ³10
7f³70 ³10
7f³70 Help: [71F170-General] [71F270-Params] ³10
7fÀ70ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ10

628
fileops.c Normal file
View file

@ -0,0 +1,628 @@
/*
* 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"));
}
}

123
fileops.h Normal file
View file

@ -0,0 +1,123 @@
/*
* 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__ */

70
fs/Makefile Normal file
View file

@ -0,0 +1,70 @@
#
# 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

626
fs/ext2_fs.h Normal file
View file

@ -0,0 +1,626 @@
/*
* 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 */

42
fs/ext2_fs_i.h Normal file
View file

@ -0,0 +1,42 @@
/*
* 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 */

61
fs/ext2_fs_sb.h Normal file
View file

@ -0,0 +1,61 @@
/*
* 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 */

70
fs/ext2_private.h Normal file
View file

@ -0,0 +1,70 @@
/*
* 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__*/

1004
fs/ext2fs.c Normal file

File diff suppressed because it is too large Load diff

63
fs/ext2fs.h Normal file
View file

@ -0,0 +1,63 @@
/*
* 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__ */

1480
fs/fs.h Normal file

File diff suppressed because it is too large Load diff

297
fs/localfs.c Normal file
View file

@ -0,0 +1,297 @@
/*
* 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;
}

46
fs/localfs.h Normal file
View file

@ -0,0 +1,46 @@
/*
* 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__ */

790
fs/netfs.c Normal file
View file

@ -0,0 +1,790 @@
/*
* 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;
}

68
fs/netfs.h Normal file
View file

@ -0,0 +1,68 @@
/*
* 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__ */

99
getopt.c Normal file
View file

@ -0,0 +1,99 @@
/*
* 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;
}

33
getopt.h Normal file
View file

@ -0,0 +1,33 @@
/*
* 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__ */

73
glue_ext2fs.c Normal file
View file

@ -0,0 +1,73 @@
/*
* 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;
}

33
glue_ext2fs.h Normal file
View file

@ -0,0 +1,33 @@
/*
* 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__ */

173
glue_localfs.c Normal file
View file

@ -0,0 +1,173 @@
/*
* 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;
}

33
glue_localfs.h Normal file
View file

@ -0,0 +1,33 @@
/*
* 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__ */

242
glue_netfs.c Normal file
View file

@ -0,0 +1,242 @@
/*
* 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;
}

33
glue_netfs.h Normal file
View file

@ -0,0 +1,33 @@
/*
* 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__ */

19
gnu-efi-3.0a-ia32.patch Normal file
View file

@ -0,0 +1,19 @@
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)
}

51
ia32/Makefile Normal file
View file

@ -0,0 +1,51 @@
#
# 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

27
ia32/bin_to_h.c Normal file
View file

@ -0,0 +1,27 @@
#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;
}

103
ia32/config.c Normal file
View file

@ -0,0 +1,103 @@
/*
* 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;
}

30
ia32/private.h Normal file
View file

@ -0,0 +1,30 @@
/*
* 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__ */

118
ia32/rmswitch.S Normal file
View file

@ -0,0 +1,118 @@
#
# 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

440
ia32/sysdeps.h Normal file
View file

@ -0,0 +1,440 @@
/*
* 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__ */

798
ia32/system.c Normal file
View file

@ -0,0 +1,798 @@
/*
* 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;
}

42
ia64/Makefile Normal file
View file

@ -0,0 +1,42 @@
#
# 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)

154
ia64/config.c Normal file
View file

@ -0,0 +1,154 @@
/*
* 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;
}

167
ia64/fpswa.c Normal file
View file

@ -0,0 +1,167 @@
/*
* 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;
}

651
ia64/gzip.c Normal file
View file

@ -0,0 +1,651 @@
/*
* 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;
}

35
ia64/gzip.h Normal file
View file

@ -0,0 +1,35 @@
/*
* 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__ */

79
ia64/gzip_loader.c Normal file
View file

@ -0,0 +1,79 @@
/*
* 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
};

1204
ia64/inflate.c Normal file

File diff suppressed because it is too large Load diff

162
ia64/longjmp.S Normal file
View file

@ -0,0 +1,162 @@
/* 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

339
ia64/memcpy.S Normal file
View file

@ -0,0 +1,339 @@
/*
* 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

133
ia64/memset.S Normal file
View file

@ -0,0 +1,133 @@
/*
* 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

453
ia64/plain_loader.c Normal file
View file

@ -0,0 +1,453 @@
/*
* 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
};

35
ia64/private.h Normal file
View file

@ -0,0 +1,35 @@
/*
* 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__ */

170
ia64/setjmp.S Normal file
View file

@ -0,0 +1,170 @@
/* 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

28
ia64/setjmp.h Normal file
View file

@ -0,0 +1,28 @@
/* 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);

107
ia64/sysdeps.h Normal file
View file

@ -0,0 +1,107 @@
/*
* 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__ */

137
ia64/system.c Normal file
View file

@ -0,0 +1,137 @@
/*
* 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;
}

112
initrd.c Normal file
View file

@ -0,0 +1,112 @@
/*
* 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;
}

68
loader.c Normal file
View file

@ -0,0 +1,68 @@
/*
* 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;
}

41
loader.h Normal file
View file

@ -0,0 +1,41 @@
/*
* 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__ */

165
strops.c Normal file
View file

@ -0,0 +1,165 @@
/*
* 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;
}

41
strops.h Normal file
View file

@ -0,0 +1,41 @@
/*
* 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__ */

35
sysdeps.h Normal file
View file

@ -0,0 +1,35 @@
/*
* 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__ */

47
tools/Makefile Normal file
View file

@ -0,0 +1,47 @@
#
# 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)

298
tools/eliloalt.c Normal file
View file

@ -0,0 +1,298 @@
/*
* 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;
}

503
util.c Normal file
View file

@ -0,0 +1,503 @@
/*
* 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;
}

130
vars.c Normal file
View file

@ -0,0 +1,130 @@
/*
* 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;
}

55
vars.h Normal file
View file

@ -0,0 +1,55 @@
/*
* 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__ */