Compare commits

...

7 Commits

Author SHA1 Message Date
Stephane Eranian 2b5c5002e1 release 3.16
https://sourceforge.net/projects/elilo/files/elilo/elilo-3.16/
2018-10-31 09:49:53 -04:00
Stephane Eranian 82f7288853 release 3.14
https://sourceforge.net/projects/elilo/files/elilo/elilo-3.14/
2018-10-31 09:46:45 -04:00
Stephane Eranian e351d8fbea release 3.12
https://sourceforge.net/projects/elilo/files/elilo/elilo-3.12/
2018-10-31 09:42:58 -04:00
Stephane Eranian 4e87874a03 release 3.10
https://sourceforge.net/projects/elilo/files/elilo/elilo-3.10/

(sans a few CVS directories)
2018-10-31 09:38:32 -04:00
Stephane Eranian 34d8003a54 release 3.8
https://sourceforge.net/projects/elilo/files/elilo/elilo-3.8/
2018-10-31 09:34:56 -04:00
Stephane Eranian 97b2a7df25 release 3.7
https://sourceforge.net/projects/elilo/files/elilo/3.7/
2018-10-31 09:30:47 -04:00
Stephane Eranian 64cdcfed2c release 3.6
https://sourceforge.net/projects/elilo/files/elilo/3.6/
2018-10-31 09:25:46 -04:00
70 changed files with 6697 additions and 397 deletions

244
ChangeLog
View File

@ -1,3 +1,215 @@
2013-03-27 signed off by Jason Fleischli <fleischli@users.sourceforge.net>
* ADD CROSSBUILD
* intake edited version of Debian x86x crossbuild patches.
* Fixed Makefile clean to include crossbuild envs.
* Fixed ia32 system.c compile warning
* Simplified efi no GOP warning so it doesnt look like an error.
* MAJOR: Fixed Fault crash when EFI memory map changes from under elilo.
(from an outside interrupt in this case). When the EFI Memory map
changes after elilo has already built boot params to pass to the
kernel the EFI call to ExitBootSvcs just prior to boot will fail
because elilo has the old map key. This is valid EFI behavior, elilo
retries to pick up the new memory map and valid key but had already
freed the start params portion of boot params resulting in a NULL
DEREF crash reset.
* Add console reset call during initialization. thanks A. Steinmetz
* minor bugfix, fixed -m option broken. thanks Allan-lsk.
* tag 3_16 for release
2011-1-10 signed off by Jason Fleischli <fleischli@users.sourceforge.net>
* Uptake of SUSE patches
- add sysfs support for efi vars (formerly /proc/efi/vars)
- fix strncpy overflow
- fix bzimage alloc
- cleanups
- support longer command line
- yet some more mac fixes
- align elilo with latest kernel boot protocol format.
- new memory management strategy for initrd and kernel image loading.
* add force text mode command line option.
* replace error output on GOP handle failed, downgraded to normal
print status with more informative output.
2009-10-22 signed off by Jason Fleischli <fleischli@users.sourceforge.net>
* elilo 3.12 release commit
* Added additional #defines for debug levels to reduce the output
* Added Mac console patch rework from Julien Blache @ debian
this fixes the invisible console output from elilo on Macs
* Moved static ELILO_VERSION variable from elilo.c to elilo.h
so that elilo will print its version string and arch on startup.
* Fixed bug 2825044 ExitBootServices error handling, correctly deal
with changed memory map key if memory map changes from under elilo.
* Added memory map key to map debug output.
* Fixed bug 2874380 netbooting just flat broken. fixed ia64, x86_64
ia32, fixed handling of server side support of tfpt options (get file size)
elilo now attempts to get file size before attempting read of file
to set the buffers up correctly and deal with tftp servers that dont
support options extensions a little better.
* netboot, fixed bad blocksize handling
* netboot, fixed filename length for elilo-x86_64.conf type on tftp
server.
* increased bzimage kernel max length sizes to 4mb on i386 and 8mb on
x86_64... this is a legacy design hold over from original design and
needs to be re-written to do dynamic size memory management based on
the size of the actual vmlinuz image, as ia64/gzip does.
2008-04-02 signed off by Jason Fleischli <fleischli@users.sourceforge.net>
* elilo 3.10 release commit
* Bumped version string to 3.10
* added PTR_FMT 32bit & 64bit pointer translation for correct output
* elilo hang bugfix x86_64 non-standard kernels with non-traditional start address
elilo will pull the start address from the kernel elf header for 2.6
or newer kernels, map memory and use that start address, else use standard
1MB default start address. And handle case of overlapping kernels
and initrds in memory. Patch contributor Stuart Hayes @ Dell,
thanks Stuart!
* ported kernel start adress fix to ia32
* eliminated all possible compiler warnings except those actually
caused by gnu-efi that cant be fixed here.
* Debug output improvement, added pauses with visual feedback when
user sets debug & verbose options.
* bugfix added missing find_bits function definition back into ia32
subtree
* bugfix loader_probe now correctly errors out if no loaders
registered.
2008-01-11 signed off by Jason Fleischli <fleischli@users.sourceforge.net>
* Various compile warning cleanups.
2008-01-03 signed off by Jason Fleischli <fleischli@users.sourceforge.net>
* Patch contribution from Scott Davilla <davilla@4pi.com>
when x is zero for the first call to add_memory_region, e820_map[-1]
will access memory outside the bounds of e820_map. While this does
not result in any problems as there is a UINT32 unused_8[41] block
above the e820_map[0] location that should have been zeroed by the
bootloader, the code should not access outside the bounds of
structures.
2008-01-03 Jason Fleischli <fleischli@users.sourceforge.net>
* initrd.c -- Let the allocator decide where to grab the memory from
the efi memory map. Current start_addr=image->start_addr forces the
same efi region everytime, and has a 7mb limit. ramdisk (initrd.img)
files larger than 7MB wouldnt fit into the memory region assumed by
the image->start_addr resulting in an elilo hang. Leaving start_addr
NULL at initialization forces alloc_pages to get a memory region
sufficient for the size of the initrd image.
2007-12-19 Jason Fleischli <fleischli@users.sourceforge.net>
* bumping version string to 3.8
2007-12-19 Jason Fleischli <fleischli@users.sourceforge.net>
* MORE PATCHES FROM INTEL FOR IA32 X86_64.
* Fix compile warning for cmdline_addr assignment.
* Fix an issue caused by uninitialized e820_nr_map in fill_e820map.
* On some machines, there are too many EFI memory map entries, so that,
the number of E820 map entries converted from EFI memory map exceeds
the limit (128). This patch fixes this bug by merging consecutive
memory map entries with the same type.
* CL_MAGIC is not supported by 32-bit boot protocol. So, the kernel
command line passing code is changed accordingly.
* EFI-2.0 boot support patches have been accepted into Linux kernel
2.6.24-rc4 and EFI runtime service patches have been accepted by
Linux kernel 2.6.24-rc4-mm1. There are some changes during the
merging, so there are some updates for elilo ia32/x86_64 too.
* The x86_64 boot parameters of Linux kernel is rearranged to line up
with ia32 boot parameters.
* The boot loader signature of IA32 and x86_64 is redefined to
make it possible for Linux kernel to distinguish whether the
underlying firmware is EFI 32 or EFI 64.
* The EFI framebuffer type ID is changed in Linux kernel to
conform to Linux kernel framebuffer type ID grouping rules. So the
EFI framebuffer type ID setting code in ELILO is changed accordingly.
* E820 memory map is added to IA32 to make it possible for
Linux kernel not to depend on EFI memory map on EFI 32.
2007-09-27 Jason Fleischli <fleischli@users.sourceforge.net>
* updating changelog for last commit that was omitted
* incorporating AGriffis patches to enhance parsing
passes root= option to kernel options and accounts for -- option
designation.
2007-07-19 Jason Fleischli <fleischli@users.sourceforge.net>
* Integrated x86_64 support patches from Chandramouli Narayanan
<mouli@linux.intel.com> changes summarized in following bullets.
* alloc.c -- adds patch contributors credit to copyright
* alloc.c -- adds uefi_call_wrapper around BS->function calls
* alloc.c -- adds call to Print on VERB_PRT
* alternate.c -- adds patch contributors credit around copyright
* alternate.c -- adds uefi_call_wrapper around RT->function calls
* simple.c -- adds patch contributors credit to copyright
* simple.c -- adds uefi_call_wrapper around ip->ReadKeyStroke
* textmenu.c -- adds patch contributors credit to copyright
* textmenu.c -- adds uefi_call_wrapper around ClearScreen &
SetTextAttr
* textmenu.c -- adds uefi_call_wrapper around ip->ReadKeyStroke
* elilo.c -- adds patch contributors credit to copyright
* elilo.c -- fixes version number for ELILO_VERSION macro to current
* elilo.c -- adds uefi_call_wrapper around BS->function calls
* elilo.c -- adds uefi_call_wrapper around RT->function calls
* fileops.c -- adds patch contributors credit to copyright
* fileops.c -- adds uefi_call_wrapper around BS->function calls
* fileops.c -- adds uefi_call_wrapper around RT->function calls
* fileops.c -- adds uefi_call_wrapper around blkio->function calls
* localfs.c -- adds patch contributors credit to copyright
* localfs.c -- changed EFI_HANDLE *dev declaration to non-pointer type
* localfs.c -- adds uefi_call_wrapper around lfs->volume->functions
* localfs.c -- adds uefi_call_wrapper around BS->function calls
* netfs.c -- adds patch contributors credit to copyright
* netfs.c -- adds uefi_call_wrapper around nfs->pxe->function calls
* netfs.c -- adds uefi_call_wrapper around BS->function calls
* getopt.c -- changed int to char in StrChr() function
* Make.defaults -- adds patch contributors credit to copyright
* Make.defaults -- adds cflag for efi function wrapper
* Makefile -- adds patch contributors credit to copyright
* Makefile -- x86_64 subdir and a new rule for .S
* util.c -- adds patch contributors credit to copyright
* util.c -- adds uefi_call_wrapper to systab->functions
* util.c -- adds uefi_call_wrapper to conin->functions
* util.c -- adds uefi_call_wrapper to BS->functions
* util.c -- doubles ELILO_MEMMAP_SIZE_DEFAULT in get_memmap() function
* bootparams.c -- uses ia32 params for x86_64 addition.. hmmmm?
* config.c -- adds patch contributors credit to copyright
* config.c -- adds define reference for x86_64.conf
* config.c -- in config_error() removes use of va_list which maps to
the gnu C-lib iface __gnuc_va_list. Replaces the use of _IPrint on
the va_list with direct use of IPrint(systab->ConOut, msg);
*maintainer note, this probably introduces a bug, in light of this
note from the patch submitter --> "On some x86_64 systems with
EFI1.10 firmware I tested, early boot messages did not appear on console.
However, I didn't encounter this behavior on x86_64 systems with UEFI2.0
firmware"
* elf.h -- adds #def for x86_64
* glue_netfs.c -- adds patch contributors credit to copyright
* glue_netfs.c -- adds define for x86_64.conf
* sysdeps.h -- adds patch contributors credit to copyright
* sysdeps.h -- add include reference for new x86_64 subdir
* x86_64/ -- new subdir - all based on elilo/ia32 subdir
* x86_64/bin_to_h.c -- new file, stream fed binary to hex converter
* x86_64/bzimage.c -- new file, binary compressed kernel support
* x86_64/gzip.c -- new file, embedded gzip
* x86_64/gzip_loader.c -- new file, embedded gzip
* x86_64/gzip.h -- new file, embedded gzip
* x86_64/inflate.c -- new file, a pkzip method 8 embedded decompressor
* x86_64/Makefile -- new file
* x86_64/plain_loader.c -- new file, for loading non-compressed kernels
* x86_64/private.h -- new file
* x86_64/rmswitch.S -- new file, RealMode assembly module
* x86_64/sysdeps.h -- new file, system stuff for x86_64, e820 mapping
added.
* x86_64/sysdeps.c -- new file, system stuff for x86_64
* elilo.txt -- documentation update, add Intel to copyright
* README.gnu-efi -- documentation update for x86_64
2006-01-27 Alex Williamson <alex.williamson@hp.com>
* Found a couple more places where vmcode isn't zeroed, causing the
option to get carried over to labels it shouldn't.
2006-01-09 Brett Johnson <brett@hp.com>
* Released 3.6
2005-12-22 Alex Williamson <alex.williamson@hp.com>
* Fixed vmcode_name initialization in textmenu chooser
2005-12-01 Alex Williamson <alex.williamson@hp.com>
* Applied patch from Fred Yang <fred.yang@intel.com> to support the
vmm= boot option. This option specifies the kernel image for a
@ -11,29 +223,37 @@
image will be uncompressed into memory before it is provided to the
hypervisor. Any combination of compressed and uncompressed images
can be used for the image and vmm options.
2005-09-15 Brett Johnson <brett@hp.com>
* Applied patch from Tristan Gingold to add dcache flush and sync with
icache to gzip and plain loaders. This ommision was just noticed now
due to the much larger caches in Montecito, and the smaller size of
Xen (as compared to the linux kernel).
2004-09-27 Brett Johnson <brett@hp.com>
* Increase the hardcoded size of the texmenu chooser menu from 16 to 64
2004-09-23 Brett Johnson <brett@hp.com>
* Fix for 924147. Thanks to Stephanie Schaaf <sas@sgi.com> for a patch
that the fix is based on.
2004-02-19 Brett Johnson <brett@hp.com>
* Fixed bug where default image initrd would carry over to another
image that was selected interactively (iff the newly selected image
did not have an initrd).
* Added support for subnet-specific config files in netfs.
2004-02-17 Brett Johnson <brett@hp.com>
* integrated ia32 compressed kernel support from Matt Tolentino
<matthew.e.tolentino@intel.com>
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().
@ -46,37 +266,47 @@
* 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>
@ -84,25 +314,31 @@
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>
@ -112,11 +348,13 @@
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.
@ -124,19 +362,24 @@
* 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
@ -165,6 +408,7 @@
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.

View File

@ -1,6 +1,7 @@
#
# Copyright (C) 2001-2003 Hewlett-Packard Co.
# Contributed by Stephane Eranian <eranian@hpl.hp.com>
# Contributed by Chandramouli Narayanan<mouli@linux.intel.com>
#
# This file is part of ELILO, the LINUX EFI boot loader.
#
@ -54,20 +55,23 @@ CONFIG_machspec_netconfig=y
# They are installed as part of the GNU-EFI package installation
#
EFIINC = /usr/include/efi
GNUEFILIB = /usr/lib
GNUEFILIB = /usr/lib
EFILIB = /usr/lib
EFICRT0 = /usr/lib
CDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
TOPDIR =
ALLSUBDIRS = ia32 ia64 x86_64 fs choosers devschemes tools
ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,)
INCDIR = -I. -I$(TOPDIR) -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol
HOSTARCH = $(shell dpkg-architecture -qDEB_BUILD_ARCH | sed s,i[3456789]86,ia32, | sed s,amd64,x86_64, )
ARCH := $(shell dpkg-architecture -qDEB_BUILD_ARCH | sed s,i[3456789]86,ia32, | sed s,amd64,x86_64, )
INCDIR = -I. -I$(TOPDIR) -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol -I$(TOPDIR)/efi110
CPPFLAGS = -DCONFIG_$(ARCH)
OPTIMFLAGS = -O2
DEBUGFLAGS = -Wall
CFLAGS = $(OPTIMFLAGS) -fpic -fshort-wchar $(DEBUGFLAGS)
CFLAGS = $(ARCH3264) $(OPTIMFLAGS) -fno-stack-protector -fno-strict-aliasing -fpic -fshort-wchar $(DEBUGFLAGS)
ASFLAGS = $(ARCH3264)
LDFLAGS = -nostdlib -znocombreloc
INSTALL = install
@ -105,6 +109,32 @@ AR = $(prefix)ar
RANLIB = $(prefix)ranlib
OBJCOPY = $(prefix)objcopy
# Use Modified binutils that supports x86_64 using UEFI ABI
ifeq ($(ARCH), x86_64)
ifeq ($(HOSTARCH), ia32)
ARCH3264 = -m64
LD3264 = -melf_x86_64
GNUEFILIB := $(GNUEFILIB)64
EFILIB := $(EFILIB)64
EFICRT0 := $(EFICRT0)64
endif
CFLAGS += -DEFI_FUNCTION_WRAPPER
OBJCOPY = /usr/bin/objcopy
endif
ifeq ($(ARCH), ia32)
ifeq ($(HOSTARCH), x86_64)
ARCH3264 = -m32
LD3264 = -melf_i386
GNUEFILIB := /usr/lib32
EFILIB := /usr/lib32
EFICRT0 := /usr/lib32
endif
endif
ifeq ($(ARCH),ia64)
GCC_VERSION=$(shell $(CROSS_COMPILE)$(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.')

View File

@ -32,4 +32,7 @@
%.o: %.c
$(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
# a rule for .S
%.o: %.S
$(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -c $< -o $@

View File

@ -1,6 +1,8 @@
#
# Copyright (C) 2001-2003 Hewlett-Packard Co.
# Contributed by Stephane Eranian <eranian@hpl.hp.com>
# Contributed by Fenghua Yu<fenghua.yu@intel.com>
# Contributed by Chandramouli Narayanan<mouli@linux.intel.com>
#
# This file is part of ELILO, the LINUX EFI boot loader.
#
@ -23,15 +25,19 @@
# to use this program.
#
include Make.defaults
TOPDIR=.
SRCDIR = .
VPATH = $(SRCDIR)
include $(SRCDIR)/Make.defaults
TOPDIR = $(SRCDIR)
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)
LOADLIBES = -lefi -lgnuefi $(shell $(CC) $(ARCH3264) -print-libgcc-file-name)
FORMAT = efi-app-$(ARCH)
FILESYSTEM =
@ -58,10 +64,14 @@ ifeq ($(ARCH),ia32)
SUBDIRS += ia32
endif
ifeq ($(ARCH),x86_64)
SUBDIRS += x86_64
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 \
gunzip.o fs/fs.o \
gunzip.o console.o fs/fs.o \
choosers/choosers.o \
devschemes/devschemes.o \
$(ARCH)/sysdeps.o \
@ -75,18 +85,19 @@ elilo.efi: elilo.so
elilo.so: $(FILES)
elilo.o : elilo.c
elilo.o : elilo.c $(ARCH)/sysdeps.h
fileops.o : Make.defaults
chooser.o : Make.defaults
$(SUBDIRS): dummy
$(MAKE) -C $@
mkdir -p $@
$(MAKE) -C $@ -f $(SRCDIR)/../$@/Makefile SRCDIR=$(SRCDIR)/../$@ ARCH=$(ARCH)
dummy:
clean:
@set -e ; for d in $(SUBDIRS) ; do $(MAKE) -C $$d $@ ; done
@set -e ; for d in $(ALLSUBDIRS) ; do $(MAKE) -C $$d $@ ; done
rm -f $(TARGETS) *~ *.so $(FILES)
.PRECIOUS: elilo.so
@ -100,4 +111,4 @@ ifeq ($(GCC_VERSION),2)
@exit 1
endif
include Make.rules
include $(SRCDIR)/Make.rules

15
README
View File

@ -1,14 +1,15 @@
ELILO: the IA-32 and IA-64 Linux Loader
---------------------------------------
ELILO: the IA-32,IA-64 and x86_64 Linux Loader
----------------------------------------------
Stephane Eranian <eranian@hpl.hp.com>
August 2003
Copyright (C) 2000-2003 Hewlett-Packard Co.
Copyright (C) 2006-2010 Intel Co.
This package contains version 3.4 of elilo, the EFI boot loader
for IA-64(IPF) and IA-32(x86) EFI-based platforms.
This package contains version 3.7 of elilo, the EFI boot loader
for IA-64(IPF),IA-32(x86) and x86_64 EFI-based platforms.
RELEASE NOTES:
@ -65,6 +66,12 @@ RELEASE NOTES:
The Redhat 9.0 toolchain does not work at the moment.
For x86_64, a toolchain known to produce working binaries is:
gcc-4.1.1 or above
binutils-2.17.50.0.14 with Intel64 EFI support
For x86_64, the following libraries are required for the elilo build
gnu-efi library with x86_64
DOCUMENTATION:
--------------
PLEASE READ THE docs/elilo.txt file for some documentation on how

View File

@ -1,5 +1,6 @@
IMPORTANT Information related to the gnu-efi package
and x86_64 efi support
----------------------------------------------------
August 2003
@ -12,6 +13,10 @@ As of version elilo-3.0, the gnu-efi package is now split in two different packa
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.
Note that EFI support for x86_64 has been added as a patch to gnu-efi-3.0c.
For x86_64, see the important notes under x86_64.
IMPORTANT NOTE FOR IA-32:
-------------------------
For IA-32, the Redhat 8.0 toolchain is known to produce
@ -29,3 +34,32 @@ IMPORTANT NOTE FOR IA-32:
The gnu-efi package can be downloaded from:
ftp://ftp.hpl.hp.com/pub/linux-ia64/gnu-efi-X.y.tar.gz
IMPORTANT NOTE FOR x86_64:
-------------------------
EFI x86_64 elilo support requires the following libraries:
1. gnu-efi-3.0c library with x86_64 support.
2. The toolchain known to produce working x86_64 efi binary are:
gcc-4.1.1 or above
binutils-2.17.50.0.14 with Intel64 EFI support
Implementation:
--------------
Calls to EFI services in x86_64 require a wrapper to pass the arguments
in the appropriate manner. This is implemented with efi wrapper.
For IA32 and IA64, the wrapper is a macro that merely calls the
EFI services directly. The elilo source has been modified to use the
efi wrapper implemented in gnu-efi-3.0c library.
elilo for x86_64 and its dependent libraries are built and the final
ELF image is converted into PE-COFF image using the objcopy supported
by binutils-2.17.50.0.14 or above with Intel64 EFI support.
On UEFI 2.0 firmware, only Graphics Output Protocol (GOP) is supported.
The x86_64 elilo first queries video information from GOP failing which
it queries for text mode support. The video information is passed to
Linux kernel via boot parameter. The GOP support requires
Linux kernel EFI framebuffer driver (kernel configuration option).

69
alloc.c
View File

@ -1,6 +1,9 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
* Contributed by Fenghua Yu <Fenghua.Yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.intel.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
@ -100,15 +103,15 @@ alloc(UINTN size, EFI_MEMORY_TYPE type)
if (type == 0) type = EfiLoaderData;
status = BS->AllocatePool (type, size, &tmp);
status = uefi_call_wrapper(BS->AllocatePool, 3, type, size, &tmp);
if (EFI_ERROR(status)) {
ERR_PRT((L"allocator: AllocatePool(%d, %d, 0x%x) failed (%r)\n", type, size, status));
ERR_PRT((L"allocator: AllocatePool(%d, %d) 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));
#ifdef DEBUG_MEM
DBG_PRT((L"alloc: allocated %d bytes @[" PTR_FMT "-" PTR_FMT "]", size, tmp, tmp+size));
#endif
return tmp;
}
@ -127,9 +130,9 @@ alloc_pages(UINTN pgcnt, EFI_MEMORY_TYPE type, EFI_ALLOCATE_TYPE where, VOID *ad
return NULL;
}
status = BS->AllocatePages(where, type , pgcnt, &tmp);
status = uefi_call_wrapper(BS->AllocatePages, 4, where, type , pgcnt, &tmp);
if (EFI_ERROR(status)) {
VERB_PRT(1, (L"allocator: AllocatePages(%d, %d, %d, 0x%lx) failed (%r)\n", where, type, pgcnt, tmp, status));
VERB_PRT(1, Print(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 */
@ -137,7 +140,7 @@ alloc_pages(UINTN pgcnt, EFI_MEMORY_TYPE type, EFI_ALLOCATE_TYPE where, VOID *ad
alloc_add(addr, pgcnt, ALLOC_PAGES);
DBG_PRT((L"allocator: allocated %d pages @0x%lx\n", pgcnt, tmp));
DBG_PRT((L"allocator: allocated %d pages @" PTR_FMT, pgcnt, tmp));
return addr;
}
@ -155,17 +158,18 @@ free(VOID *addr)
if (p->addr == addr) goto found;
}
/* not found */
VERB_PRT(1, (L"allocator: invalid free @ 0x%lx\n", addr));
VERB_PRT(1, Print(L"allocator: invalid free @ " PTR_FMT "\n", addr));
return;
found:
DBG_PRT((L"free: %s @0x%lx size=%ld\n",
#ifdef DEBUG_MEM
DBG_PRT((L"free: %s @" PTR_FMT " size=%d",
p->type == ALLOC_POOL ? L"Pool": L"Page",
addr, p->size));
#endif
if (p->type == ALLOC_POOL)
BS->FreePool(addr);
uefi_call_wrapper(BS->FreePool, 1, addr);
else
BS->FreePages((EFI_PHYSICAL_ADDRESS)addr, p->size);
uefi_call_wrapper(BS->FreePages, 2, (EFI_PHYSICAL_ADDRESS)addr, p->size);
/* remove from used list */
if (p->next)
@ -191,13 +195,13 @@ 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));
#ifdef DEBUG_MEM
DBG_PRT((L"free_all %a @ " PTR_FMT, used_allocs->type == ALLOC_POOL ? "pool" : "pages", used_allocs->addr));
#endif
if (used_allocs->type == ALLOC_POOL)
BS->FreePool(used_allocs->addr);
uefi_call_wrapper(BS->FreePool, 1, used_allocs->addr);
else
BS->FreePages((EFI_PHYSICAL_ADDRESS)used_allocs->addr, used_allocs->size);
uefi_call_wrapper(BS->FreePages, 2, (EFI_PHYSICAL_ADDRESS)used_allocs->addr, used_allocs->size);
tmp = used_allocs->next;
@ -209,6 +213,27 @@ free_all(VOID)
}
}
INTN
alloc_kmem_anywhere(VOID **start_addr, UINTN pgcnt)
{
void * tmp;
/*
* During "AllocateAnyPages" *start_addr will be ignored.
* Therefore we can safely subvert it to reuse this function with
* an alloc_kmem_anyhwere_below() semantic...
*/
tmp = alloc_pages(pgcnt, EfiLoaderData,
(*start_addr) ? AllocateMaxAddress : AllocateAnyPages,
*start_addr);
if (tmp == NULL) return -1;
kmem_addr = tmp;
kmem_pgcnt = pgcnt;
*start_addr = tmp;
return 0;
}
INTN
alloc_kmem(VOID *start_addr, UINTN pgcnt)
{
@ -223,13 +248,17 @@ alloc_kmem(VOID *start_addr, UINTN pgcnt)
VOID
free_kmem(VOID)
{
DBG_PRT((L"free_kmem before (%lx, %ld)\n", kmem_addr, kmem_pgcnt));
#ifdef DEBUG_MEM
DBG_PRT((L"free_kmem before (" PTR_FMT ", %d)", kmem_addr, kmem_pgcnt));
#endif
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));
#ifdef DEBUG_MEM
DBG_PRT((L"free_kmem after (" PTR_FMT ", %d)", kmem_addr, kmem_pgcnt));
#endif
}
VOID

View File

@ -1,6 +1,9 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan<mouli@linux.intel.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
@ -53,7 +56,7 @@ static EFI_GUID altk_guid={0,};
* Please note that no fatal error is reported by this function
*/
INTN
alternate_kernel(CHAR16 *buffer, INTN size)
alternate_kernel(CHAR16 *buffer, UINTN size)
{
EFI_STATUS status;
INTN ret = -1;
@ -77,7 +80,7 @@ alternate_kernel(CHAR16 *buffer, INTN size)
* - the variable does not exist
* - our buffer size is too small.
*/
status = RT->GetVariable(ELILO_ALTK_VAR, &altk_guid, NULL, &size, buffer);
status = uefi_call_wrapper(RT->GetVariable, 5, ELILO_ALTK_VAR, &altk_guid, NULL, &size, buffer);
if (EFI_ERROR(status)) {
DBG_PRT((L"cannot access variable %s: %r", ELILO_ALTK_VAR, status));
@ -110,7 +113,7 @@ alternate_kernel(CHAR16 *buffer, INTN size)
ret = 0;
delete_var:
status = RT->SetVariable(ELILO_ALTK_VAR, &altk_guid, 0, 0, NULL);
status = uefi_call_wrapper(RT->SetVariable, 5, ELILO_ALTK_VAR, &altk_guid, 0, 0, NULL);
if (EFI_ERROR(status)) {
ERR_PRT((L"cannot erase variable %s", ELILO_ALTK_VAR));
}

View File

@ -67,9 +67,6 @@ create_boot_params(CHAR16 *args, memdesc_t *initrd, memdesc_t *vmcode, UINTN *co
/*
* Allocate memory for boot parameters.
* This CANNOT be EfiLoaderData or EfiLoaderCode as the kernel
* frees this region when initializing.
* FIXME: Is this a bug? (since the memory type *is* EfiLoaderData)
*/
bp = (boot_params_t *)alloc(BOOT_PARAM_MEMSIZE, EfiLoaderData);
@ -78,12 +75,12 @@ create_boot_params(CHAR16 *args, memdesc_t *initrd, memdesc_t *vmcode, UINTN *co
return 0;
}
VERB_PRT(3, Print(L"boot params @ 0x%lx\n", bp));
VERB_PRT(3, Print(L"boot params @ " PTR_FMT "\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
#elif defined CONFIG_ia32 || CONFIG_x86_64
cp = ((CHAR8 *)bp) + BOOT_PARAM_MEMSIZE - 2048;
#endif
@ -96,6 +93,8 @@ create_boot_params(CHAR16 *args, memdesc_t *initrd, memdesc_t *vmcode, UINTN *co
*/
Memset(bp, 0, BOOT_PARAM_MEMSIZE);
U2ascii(args, cp, cmdline_size);
if (sysdeps_create_boot_params(bp, cp, initrd, vmcode, cookie) == -1) return 0;
/*

View File

@ -23,10 +23,15 @@
# to use this program.
#
include ../Make.defaults
include ../Make.rules
SRCDIR = .
VPATH = $(SRCDIR)
include $(SRCDIR)/../Make.defaults
include $(SRCDIR)/../Make.rules
TOPDIR=$(SRCDIR)/..
TOPDIR=$(CDIR)/..
FILES=
@ -42,17 +47,14 @@ 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 \
$(TARGET): $(TOPDIR)/Make.defaults $(FILES)
@if [ -z "$(FILES)" ]; then \
echo "You need to define at least one chooser in Make.defaults"; \
exit 1; \
fi
$(LD) $(LD3264) -o $@ -r $(FILES)
clean:
$(RM) -f $(TARGET) $(FILES)

View File

@ -1,6 +1,10 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
* Copyright (C) 2006-2009 Intel Corporation
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.intel.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
@ -28,6 +32,7 @@
#include "elilo.h"
#include "vars.h"
#include "console.h"
/* static is ugly but does the job here! */
static CHAR16 **alt_argv;
@ -36,8 +41,8 @@ static VOID
display_label_info(CHAR16 *name)
{
CHAR16 *desc;
CHAR16 initrd_name[CMDLINE_MAXLEN];
CHAR16 vmcode_name[CMDLINE_MAXLEN];
CHAR16 initrd_name[PATHNAME_MAXLEN];
CHAR16 vmcode_name[PATHNAME_MAXLEN];
CHAR16 options_tmp[CMDLINE_MAXLEN];
CHAR16 options[CMDLINE_MAXLEN];
CHAR16 kname[FILENAME_MAXLEN];
@ -136,7 +141,8 @@ reprint:
first_time = 0;
for (;;) {
while ((status=ip->ReadKeyStroke(ip, &key)) == EFI_NOT_READY);
while ((status = uefi_call_wrapper(ip->ReadKeyStroke, 2, ip, &key))
== EFI_NOT_READY);
if (EFI_ERROR(status)) {
ERR_PRT((L"select_kernel readkey: %r", status));
return -1;
@ -215,7 +221,7 @@ display_message(VOID)
{
fops_fd_t fd;
EFI_STATUS status;
INTN len, i;
UINTN len, i;
CHAR16 *filename;
CHAR8 buf[256];
@ -248,10 +254,10 @@ simple_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmdli
# define BOOT_IMG_STR L"BOOT_IMAGE="
CHAR16 buffer[CMDLINE_MAXLEN];
CHAR16 alt_buffer[CMDLINE_MAXLEN];
CHAR16 initrd_name[CMDLINE_MAXLEN];
CHAR16 vmcode_name[CMDLINE_MAXLEN];
CHAR16 initrd_name[PATHNAME_MAXLEN];
CHAR16 vmcode_name[PATHNAME_MAXLEN];
CHAR16 args[CMDLINE_MAXLEN];
CHAR16 devname[CMDLINE_MAXLEN];
CHAR16 devname[PATHNAME_MAXLEN];
CHAR16 dpath[FILENAME_MAXLEN];
CHAR16 *slash_pos, *colon_pos, *backslash_pos;
UINTN len;
@ -274,7 +280,7 @@ restart:
argc = argify(alt_buffer,sizeof(alt_buffer), argv);
alt_argv = argv;
index = 0;
args[0] = initrd_name[0] = 0;
args[0] = initrd_name[0] = vmcode_name[0] = 0;
/*
* don't check twice because the variable is deleted after
* first access
@ -283,8 +289,10 @@ restart:
}
if (elilo_opt.prompt) {
ret = select_kernel(buffer, sizeof(buffer));
console_textmode();
ret = select_kernel(buffer, CMDLINE_MAXLEN);
if (ret == -1) return -1;
/* this function takes really the number of bytes ... */
argc = argify(buffer,sizeof(buffer), argv);
index = 0;
}
@ -350,11 +358,11 @@ restart:
if (elilo_opt.prompt == 0) {
/* minimal printing */
Print(L"ELILO\n");
Print(L"ELILO v%s for EFI/%a\n", ELILO_VERSION, ELILO_ARCH);
ret = wait_timeout(elilo_opt.delay);
if (ret != 0) {
elilo_opt.prompt = 1;
elilo_opt.initrd[0] = CHAR_NULL;
elilo_opt.initrd[0] = elilo_opt.vmcode[0] = CHAR_NULL;
elilo_opt.timeout = ELILO_TIMEOUT_INFINITY;
goto restart;
}

View File

@ -1,6 +1,10 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Richard Hirst <rhirst@linuxcare.com>
* Copyright (C) 2006-2009 Intel Corporation
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.intel.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
@ -27,6 +31,7 @@
#include <efilib.h>
#include "elilo.h"
#include "console.h"
#define MAX_LABELS 64
#define MSGBUFLEN 4096
@ -45,8 +50,8 @@ 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)
#define ClearScreen() uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut)
#define SetTextAttr(a) uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, a)
static INTN
tohex(INTN c)
@ -182,12 +187,12 @@ paint_menu(VOID)
}
static INTN
read_message_file(INTN msg, INT8 *buf, INTN max)
read_message_file(INTN msg, UINT8 *buf, UINTN max)
{
CHAR16 *filename;
fops_fd_t message_fd;
EFI_STATUS status;
INTN len = max;
UINTN len = max;
if (msg > 10) return 0;
@ -249,7 +254,8 @@ reprint:
SetTextAttr(CurrentAttr);
for (;;) {
while ((status=ip->ReadKeyStroke(ip, &key)) == EFI_NOT_READY);
while ((status = uefi_call_wrapper(ip->ReadKeyStroke, 2, ip, &key))
== EFI_NOT_READY);
if (EFI_ERROR(status)) {
SetTextAttr(EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK));
ClearScreen();
@ -295,7 +301,7 @@ reprint:
if (i) {
msgbuf[i] = 0;
paint_msg(msgbuf);
while ((status=ip->ReadKeyStroke(ip, &key)) == EFI_NOT_READY);
while ((status= uefi_call_wrapper(ip->ReadKeyStroke, 2, ip, &key)) == EFI_NOT_READY);
goto reprint;
}
}
@ -357,10 +363,10 @@ textmenu_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmd
{
# define BOOT_IMG_STR L"BOOT_IMAGE="
CHAR16 label[CMDLINE_MAXLEN];
CHAR16 initrd_name[CMDLINE_MAXLEN];
CHAR16 vmcode_name[CMDLINE_MAXLEN];
CHAR16 initrd_name[PATHNAME_MAXLEN];
CHAR16 vmcode_name[PATHNAME_MAXLEN];
CHAR16 args[CMDLINE_MAXLEN];
CHAR16 devname[CMDLINE_MAXLEN];
CHAR16 devname[PATHNAME_MAXLEN];
CHAR16 dpath[FILENAME_MAXLEN];
CHAR16 *slash_pos, *colon_pos, *backslash_pos;
UINTN len;
@ -383,12 +389,13 @@ textmenu_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmd
nlabels++;
}
restart:
initrd_name[0] = kname[0] = cmdline[0] = args[0] = CHAR_NULL;
vmcode_name[0] = 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) {
console_textmode();
ret = select_kernel(label, sizeof(label));
if (ret == -1) return -1;
argc = argify(PromptBuf,sizeof(PromptBuf), argv);
@ -401,7 +408,7 @@ restart:
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;
label[0] = args[0] = initrd_name[0] = vmcode_name[0] = 0;
}
/*
@ -461,11 +468,11 @@ restart:
if (elilo_opt.prompt == 0) {
/* minimal printing */
Print(L"ELILO\n");
Print(L"ELILO v%s for EFI/%a\n", ELILO_VERSION, ELILO_ARCH);
ret = wait_timeout(elilo_opt.delay);
if (ret != 0) {
elilo_opt.prompt = 1;
elilo_opt.initrd[0] = CHAR_NULL;
elilo_opt.initrd[0] = elilo_opt.vmcode[0] = CHAR_NULL;
elilo_opt.timeout = ELILO_TIMEOUT_INFINITY;
goto restart;
}

132
config.c
View File

@ -1,6 +1,9 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.intel.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
@ -42,6 +45,8 @@
#define ELILO_ARCH_DEFAULT_CONFIG L"elilo-ia64.conf"
#elif defined (CONFIG_ia32)
#define ELILO_ARCH_DEFAULT_CONFIG L"elilo-ia32.conf"
#elif defined (CONFIG_x86_64)
#define ELILO_ARCH_DEFAULT_CONFIG L"elilo-x86_64.conf"
#else
#error "You need to specfy your default arch config file"
#endif
@ -51,7 +56,7 @@
*/
#define ELILO_DEFAULT_CONFIG L"elilo.conf"
#define MAX_STRING CMDLINE_MAXLEN
#define MAX_STRING 512
#define CONFIG_BUFSIZE 512 /* input buffer size */
/*
@ -66,7 +71,7 @@ typedef struct boot_image {
struct boot_image *next;
CHAR16 label[MAX_STRING];
CHAR16 kname[FILENAME_MAXLEN];
CHAR16 options[MAX_STRING];
CHAR16 options[CMDLINE_MAXLEN];
CHAR16 initrd[FILENAME_MAXLEN];
CHAR16 vmcode[FILENAME_MAXLEN];
CHAR16 root[FILENAME_MAXLEN];
@ -95,7 +100,7 @@ typedef struct {
CHAR16 root[FILENAME_MAXLEN]; /* globally defined root fs */
CHAR16 initrd[FILENAME_MAXLEN];/* globally defined initrd */
CHAR16 vmcode[FILENAME_MAXLEN];/* globally defined boot-time module */
CHAR16 options[MAX_STRING];
CHAR16 options[CMDLINE_MAXLEN];
CHAR16 default_image_name[MAX_STRING];
CHAR16 message_file[MAX_MESSAGES][FILENAME_MAXLEN];
CHAR16 chooser[FILENAME_MAXLEN];/* which image chooser to use */
@ -204,14 +209,8 @@ static fops_fd_t config_fd;
static VOID
config_error(CHAR16 *msg,...)
{
va_list ap;
extern UINTN _IPrint (UINTN, UINTN, SIMPLE_TEXT_OUTPUT_INTERFACE *, CHAR16 *, CHAR8 *, va_list);
Print(L"near line %d: ",line_num);
va_start(ap,msg);
_IPrint((UINTN)-1, (UINTN)-1, systab->ConOut, msg, NULL, ap);
va_end(ap);
IPrint(systab->ConOut, msg);
Print(L"\n");
}
@ -256,7 +255,16 @@ next(VOID)
back = 0;
return ch;
}
return getc();
/*
* config files served from pxe/tftpboot windows servers can contain
* extraneous '\r' characters, often the first char in the file, and
* we need to simply skip over those and continue on
*/
ch = getc();
if(ch == '\r')
ch = getc();
return ch;
}
/*
@ -305,23 +313,23 @@ find_option(config_option_group_t *grp, CHAR16 *str)
* - TOK_ERR: in case of (parsing) error
*/
static token_t
get_token(CHAR16 *str, UINTN maxlen)
get_token_core(CHAR16 *str, UINTN maxlen, BOOLEAN rhs)
{
INTN ch, escaped;
CHAR16 *here;
for (;;) {
while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n') if (ch == '\n') line_num++;
while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n') if (ch == '\n' ) line_num++;
if (ch == CHAR_EOF) return TOK_EOF;
/* skip comment line */
if (ch != '#') break;
/* skip comment line */
while ((ch = next()), ch != '\n') if (ch == CHAR_EOF) return TOK_EOF;
line_num++;
}
if (ch == '=') return TOK_EQUAL;
if (ch == '=' && !rhs) return TOK_EQUAL;
if (ch == '"') {
here = str;
@ -374,7 +382,7 @@ get_token(CHAR16 *str, UINTN maxlen)
}
else {
if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '#' ||
ch == '=' || ch == CHAR_EOF) {
ch == CHAR_EOF || (ch == '=' && !rhs)) {
again(ch);
*here = 0;
return TOK_STR;
@ -387,6 +395,18 @@ get_token(CHAR16 *str, UINTN maxlen)
return TOK_ERR;
}
static token_t
get_token(CHAR16 *str, UINTN maxlen)
{
return get_token_core(str, maxlen, FALSE);
}
static token_t
get_token_rhs(CHAR16 *str, UINTN maxlen)
{
return get_token_core(str, maxlen, TRUE);
}
static INTN
image_check(boot_image_t *img)
{
@ -680,7 +700,7 @@ do_string_core(config_option_t *p, CHAR16 *str, UINTN maxlen, CHAR16 *msg)
/*
* now get the value
*/
tok = get_token(str, maxlen);
tok = get_token_rhs(str, maxlen);
if (tok != TOK_STR) {
config_error(L"Option %s expects %s", p->name, msg);
return -1;
@ -751,7 +771,10 @@ config_parse(VOID)
if (tok == TOK_EOF) break;
if (tok == TOK_ERR) return -1;
if (tok == TOK_ERR) {
Print(L"Bad Token from elilo config file, parser read: %s\n elilo exiting\n", str);
return -1;
}
if ( (p = find_option(current_options, str)) == NULL) {
config_error(L"Unkown option %s", str);
@ -886,10 +909,10 @@ print_label_list(VOID)
{
boot_image_t *img, *dfl = global_config.default_image;
if (dfl) Print(L"\t%s\n", dfl->label);
if (dfl) Print(L" %s\n", dfl->label);
for (img = image_list; img; img = img->next) {
if (img != dfl) Print(L"\t%s\n", img->label);
if (img != dfl) Print(L" %s\n", img->label);
}
}
@ -936,6 +959,37 @@ find_description(CHAR16 *label)
return NULL;
}
static void
add_root_to_options(CHAR16 *options, CHAR16 *root, CHAR16 *vmcode)
{
CHAR16 *o, ko[CMDLINE_MAXLEN];
if (vmcode[0]) {
for (o = options; *o; o++) {
if (*o == '-' && *(o+1) == '-')
break;
}
if (! *o) {
/* no separator found, add one */
StrCpy(o, L" -- ");
o++;
}
/* advance past separator and whitespace */
o += 2;
while (*o == ' ') o++;
} else {
o = options;
}
/* insert root param at this point */
StrCpy(ko, o);
StrCpy(o, L"root=");
StrCat(o, root);
StrCat(o, L" ");
StrCat(o, ko);
}
INTN
find_label(CHAR16 *label, CHAR16 *kname, CHAR16 *options, CHAR16 *initrd, CHAR16 *vmcode)
{
@ -958,15 +1012,12 @@ find_label(CHAR16 *label, CHAR16 *kname, CHAR16 *options, CHAR16 *initrd, CHAR16
/*
* when the label does not exist, we still propagate the global options
*/
if (global_config.root[0]) {
StrCpy(options, L" root=");
StrCat(options, global_config.root);
}
if (global_config.options[0]) {
StrCat(options, L" ");
StrCat(options, global_config.options);
}
if (global_config.root[0])
add_root_to_options(options, global_config.root, global_config.vmcode);
if (global_config.readonly) StrCat(options, L" ro");
if (global_config.initrd[0]) StrCpy(initrd, global_config.initrd);
@ -979,21 +1030,33 @@ find_label(CHAR16 *label, CHAR16 *kname, CHAR16 *options, CHAR16 *initrd, CHAR16
found:
StrCpy(kname, img->kname);
/* per image initrd has precedence over global initrd */
if (img->initrd[0])
StrCpy(initrd, img->initrd);
else
StrCpy(initrd, global_config.initrd);
/* per image vmcode has precedence over global vmcode */
if (img->vmcode[0])
StrCpy(vmcode, img->vmcode);
else
StrCpy(vmcode, global_config.vmcode);
/*
* literal option overrides any other image-based or global option
*
* In any case, the image option has priority over the global option
*/
if (img->literal == 0) {
if (img->root[0] || global_config.root[0]) {
StrCat(options, L"root=");
StrCat(options, img->root[0] ? img->root : global_config.root);
}
/* XXX: check max length */
if (img->options[0] || global_config.options[0]) {
StrCat(options, L" ");
StrCat(options, img->options[0] ? img->options: global_config.options);
}
if (img->root[0] || global_config.root[0]) {
add_root_to_options(options, img->root[0]
? img->root : global_config.root, vmcode);
}
if (img->readonly || global_config.readonly) {
StrCat(options, L" ro");
}
@ -1002,17 +1065,6 @@ found:
StrCpy(options, img->options);
}
/* per image initrd has precedence over global initrd */
if (img->initrd[0])
StrCpy(initrd, img->initrd);
else if (global_config.initrd[0])
StrCpy(initrd, global_config.initrd);
if (img->vmcode[0])
StrCpy(vmcode, img->vmcode);
else if (global_config.vmcode[0])
StrCpy(vmcode, global_config.vmcode);
/*
* point to architecture dependent options for this image
*/

71
console.c Normal file
View File

@ -0,0 +1,71 @@
/*
* console.c - Console screen handling functions
*
* Copyright (C) 2006 Christoph Pfisterer
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
* ELILO is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* ELILO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ELILO; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Please check out the elilo.txt for complete documentation on how
* to use this program.
*/
#include <efi.h>
#include <efilib.h>
#include "elilo.h"
#include <efiConsoleControl.h>
static EFI_GUID console_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
static BOOLEAN console_inited = FALSE;
static EFI_CONSOLE_CONTROL_PROTOCOL *console_control;
/*
* Initialize console functions
*/
static VOID console_init(VOID)
{
EFI_STATUS status;
if (!console_inited) {
console_inited = TRUE;
status = LibLocateProtocol(&console_guid, (VOID **) &console_control);
if (EFI_ERROR(status))
console_control = NULL;
}
}
/*
* Switch the console to text mode
*/
VOID console_textmode(VOID)
{
EFI_CONSOLE_CONTROL_SCREEN_MODE console_mode;
console_init();
if (console_control != NULL) {
uefi_call_wrapper(console_control->GetMode, 4, console_control, &console_mode, NULL, NULL);
if (console_mode == EfiConsoleControlScreenGraphics)
uefi_call_wrapper(console_control->SetMode, 2, console_control, EfiConsoleControlScreenText);
}
}

32
console.h Normal file
View File

@ -0,0 +1,32 @@
/*
* console.h - Console screen handling functions
*
* Copyright (C) 2006 Christoph Pfisterer
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
* ELILO is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* ELILO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ELILO; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Please check out the elilo.txt for complete documentation on how
* to use this program.
*/
#ifndef __ELILO_CONSOLE_H__
#define __ELILO_CONSOLE_H__
extern VOID console_textmode(VOID);
#endif /* __ELILO_CONSOLE_H__ */

View File

@ -23,10 +23,15 @@
# to use this program.
#
include ../Make.defaults
include ../Make.rules
SRCDIR = .
VPATH = $(SRCDIR)
include $(SRCDIR)/../Make.defaults
include $(SRCDIR)/../Make.rules
TOPDIR=$(SRCDIR)/..
TOPDIR=$(CDIR)/..
FILES=simple.o
@ -40,7 +45,7 @@ all: $(TARGET)
# without doing make clean.
#
$(TARGET): $(FILES)
$(LD) -r -o $@ $(FILES)
$(LD) $(LD3264) -r -o $@ $(FILES)
clean:
$(RM) -f $(TARGET) $(FILES)

522
docs/README.txt Normal file
View File

@ -0,0 +1,522 @@
--------------------------------------------------------------------
ELILO.EFI: Linux boot loader for
EFI/IA-64,EFI/IA-32 and EFI/x86_64 based systems
--------------------------------------------------------------------
Stephane Eranian <eranian@hpl.hp.com>
August 2003
Copyright (C) 2000-2012 Hewlett-Packard Co.
Copyright (C) 2006-2010 Intel Co.
I/ Introduction
------------
This document describes how to use ELILO on for IA-64, IA-32 and x86_64 EFI-based platforms.
This document describes ELILO version 3.7 - 3.14.
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).
For x86_64:
----------
none
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 or elilo-x86_64.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.
x86_64 specific options:
-----------------------
text-mode elilo>=3.14 boolean, image config option to force text console mode.
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.
XIII/ Booting on EFI/x86_64 platforms
-----------------------------
To use elilo on x86_64, you can put it on a floppy and
on a FAT32 partition (msdos partition). You can also
netboot if your network adapter has support for UNDI/PXE.
Elilo/x86_64 requires efi64 enabled linux kernel (> 2.6.21).
You need to compile the kernel with CONFIG_EFI option.
x86_64 platforms with UEFI 2.0 firmware deprecate UGA protocol
and therefore only the Graphics Output Protocol (GOP) is supported. For
such platforms, the kernel must be configured with EFI_FB option. This
will enable early boot messages on the console. The elilo for x86_64
attempts to query the firmware for GOP and if it fails it defaults to
text mode. Elilo ONLY takes compressed kernel image which are
typically obtained via a 'make bzImage'. Plain elf/x86_64 kernel can't
be booted (plain vmlinux will not work). Similarly, existing initial
ramdisks can be used without modifications.
The x86_64 implementation converts the EFI memory map into E820 map and
passes it in the bootparameter supplied to the OS. For details on
bootparameter, see x86_64/sysdeps.h.
IX/ Credits
-------
Contributors:
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>
Fenghua Yu <fenghua.yu@intel.com>
Bibo Mao <bibo.mao@intel.com>
Brett Johnson <brett@hp.com>
Jason Fleischli <Jason.Fleischli@hp.com>
Chandramouli Narayanan <mouli@linux.intel.com>
Maintainers:
Jason Fleischli <Jason.Fleischli@hp.com>
X/ Bug reports
-----------
Use the sourceforge bug submission system on the elilo sourceforge
project page for reporting including errors or descrepancies in this
document.
XIII/ Reference
---------
UEFI 2.0 specifications are available from the following web site:
http://www.uefi.org/home
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:
https://sourceforge.net/projects/elilo/files/

View File

@ -1,18 +1,20 @@
--------------------------------------------------------------------
ELILO.EFI: Linux boot loader for EFI/IA-64 and EFI/IA-32 based systems
ELILO.EFI: Linux boot loader for
EFI/IA-64,EFI/IA-32 and EFI/x86_64 based systems
--------------------------------------------------------------------
Stephane Eranian <eranian@hpl.hp.com>
August 2003
Copyright (C) 2000-2003 Hewlett-Packard Co.
Copyright (C) 2000-2012 Hewlett-Packard Co.
Copyright (C) 2006-2010 Intel 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.
This document describes how to use ELILO on for IA-64, IA-32 and x86_64 EFI-based platforms.
This document describes ELILO version 3.7 - 3.14.
II/ Command line options
--------------------
@ -81,6 +83,9 @@ II/ Command line options
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).
For x86_64:
----------
none
III/ Configuration File
------------------
@ -94,7 +99,7 @@ III/ Configuration File
where AABBCCDD is the hexadecimal representation
of the IP address assigned during the DHCP phase.
2/ elilo-ia64.conf or elilo-ia32.conf
2/ elilo-ia64.conf or elilo-ia32.conf or elilo-x86_64.conf
The choice depends on the client platform. This step allows
the same DHCP/PXE server to provide files for both types of clients.
@ -236,6 +241,9 @@ III/ Configuration File
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.
x86_64 specific options:
-----------------------
text-mode elilo>=3.14 boolean, image config option to force text console mode.
IV/ Booting from the local system
-----------------------------
@ -447,9 +455,33 @@ XII/ Booting on EFI/ia32 platforms
be booted (plain vmlinux will not work). Similarly, existing initial ramdisks can
be used without modifications.
XIII/ Booting on EFI/x86_64 platforms
-----------------------------
To use elilo on x86_64, you can put it on a floppy and
on a FAT32 partition (msdos partition). You can also
netboot if your network adapter has support for UNDI/PXE.
Elilo/x86_64 requires efi64 enabled linux kernel (> 2.6.21).
You need to compile the kernel with CONFIG_EFI option.
x86_64 platforms with UEFI 2.0 firmware deprecate UGA protocol
and therefore only the Graphics Output Protocol (GOP) is supported. For
such platforms, the kernel must be configured with EFI_FB option. This
will enable early boot messages on the console. The elilo for x86_64
attempts to query the firmware for GOP and if it fails it defaults to
text mode. Elilo ONLY takes compressed kernel image which are
typically obtained via a 'make bzImage'. Plain elf/x86_64 kernel can't
be booted (plain vmlinux will not work). Similarly, existing initial
ramdisks can be used without modifications.
The x86_64 implementation converts the EFI memory map into E820 map and
passes it in the bootparameter supplied to the OS. For details on
bootparameter, see x86_64/sysdeps.h.
IX/ Credits
-------
Contributors:
Intel Corp.
Stephane Eranian <eranian@hpl.hp.com>
David Mosberger <davidm@hpl.hp.com>
@ -457,22 +489,34 @@ IX/ Credits
Richard Hirst <rhirst@linuxcare.com>
Chris Ahna <christopher.j.ahna@intel.com>
Mike Johnston <michael.johnston@intel.com>
Fenghua Yu <fenghua.yu@intel.com>
Bibo Mao <bibo.mao@intel.com>
Brett Johnson <brett@hp.com>
Jason Fleischli <Jason.Fleischli@hp.com>
Chandramouli Narayanan <mouli@linux.intel.com>
Maintainers:
Jason Fleischli <Jason.Fleischli@hp.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.
Use the sourceforge bug submission system on the elilo sourceforge
project page for reporting including errors or descrepancies in this
document.
XIII/ Reference
---------
UEFI 2.0 specifications are available from the following web site:
http://www.uefi.org/home
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
https://sourceforge.net/projects/elilo/files/

View File

@ -3,8 +3,11 @@ How to netboot using ELILO
Copyright (C) 2002-2003 Hewlett-Packard Co.
Contributed by Stephane Eranian <eranian@hpl.hp.com>
Updated by Jason Fleischli <jason.fleischli@hp.com>
Last updated: 03/08/11
Last updated: 10/19/2009
x86_64 and uefi support was added @ elilo version 3.8 and linux kernel >= 2.6.24
EFI has full support for the PXE and DHCP protocol. As such
it is relatively easy to boot a machine from the network using EFI.
@ -126,7 +129,7 @@ only on two very common cases:
This filename is an opportunity to specify a machine specific configuration file.
2) AA[BB[CC]][-ia32|ia64].conf
2) AA[BB[CC]][-ia32|ia64|x86_64].conf
As of version 3.5, elilo will also look for IPv4 class A,B,C
subnet-specific versions of the config file. This is useful when you
want to have a common config file for all machines connected to a
@ -140,14 +143,14 @@ only on two very common cases:
config files first (So for example, on an Itanium system,
"0A0000-ia64.conf" will be tried before "0A0000.conf")
3) elilo-ia32.config or elilo-ia64.conf
3) elilo-ia32.conf, elilo-x86_64.conf, or elilo-ia64.conf
Depending on the machine (client side) architecture elilo will try the IA-32 or
IA-64 file.
Depending on the machine (client side) architecture elilo will try the matching
architecture specific filename.
This filename is an opportunity to specify a architecture specific configuration file.
This distinction between the architectures is useful when the same TFTP server services
the two types of clients : IA32- and IA-64 machines.
the three types of clients : ia32, x86_64, and ia64 machines.
4) elilo.conf
@ -244,7 +247,7 @@ only on two very common cases:
- use the name provide by the PXE server Layer 1 or
- elilo-ia64.conf/elilo-ia32.conf or
- elilo-ia64.conf/elilo-ia32.conf/elilo-x86_64 or
- elilo.conf
@ -390,7 +393,7 @@ only on two very common cases:
In the case of a DHCP boot, this type of customization makes sense only for
the shared configuration file, elilo-ia64.conf/elilo-ia32.conf or elilo.conf.
the shared configuration file, elilo-ia64.conf/elilo-ia32.conf/elilo-x86_64 or elilo.conf.
The configuration file based on the IP address (such as C0A80205.conf in this
case) would provide another way of customizing parameters for a specific
client (IP address). The same thing holds if the name of the config file

122
efi110/efiConsoleControl.h Normal file
View File

@ -0,0 +1,122 @@
/*++
Copyright (c) 2004, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
ConsoleControl.h
Abstract:
Abstraction of a Text mode or UGA screen
--*/
#ifndef __CONSOLE_CONTROL_H__
#define __CONSOLE_CONTROL_H__
#define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \
{ 0xf42f7782, 0x12e, 0x4c12, { 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21 } }
/* typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL EFI_CONSOLE_CONTROL_PROTOCOL; */
struct _EFI_CONSOLE_CONTROL_PROTOCOL;
typedef enum {
EfiConsoleControlScreenText,
EfiConsoleControlScreenGraphics,
EfiConsoleControlScreenMaxValue
} EFI_CONSOLE_CONTROL_SCREEN_MODE;
typedef
EFI_STATUS
(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE) (
IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This,
OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode,
OUT BOOLEAN *UgaExists, OPTIONAL
OUT BOOLEAN *StdInLocked OPTIONAL
)
/*++
Routine Description:
Return the current video mode information. Also returns info about existence
of UGA Draw devices in system, and if the Std In device is locked. All the
arguments are optional and only returned if a non NULL pointer is passed in.
Arguments:
This - Protocol instance pointer.
Mode - Are we in text of grahics mode.
UgaExists - TRUE if UGA Spliter has found a UGA device
StdInLocked - TRUE if StdIn device is keyboard locked
Returns:
EFI_SUCCESS - Mode information returned.
--*/
;
typedef
EFI_STATUS
(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) (
IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This,
OUT EFI_CONSOLE_CONTROL_SCREEN_MODE Mode
)
/*++
Routine Description:
Set the current mode to either text or graphics. Graphics is
for Quiet Boot.
Arguments:
This - Protocol instance pointer.
Mode - Mode to set the
Returns:
EFI_SUCCESS - Mode information returned.
--*/
;
typedef
EFI_STATUS
(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN) (
IN struct _EFI_CONSOLE_CONTROL_PROTOCOL *This,
IN CHAR16 *Password
)
/*++
Routine Description:
Lock Std In devices until Password is typed.
Arguments:
This - Protocol instance pointer.
Password - Password needed to unlock screen. NULL means unlock keyboard
Returns:
EFI_SUCCESS - Mode information returned.
EFI_DEVICE_ERROR - Std In not locked
--*/
;
typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL {
EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE GetMode;
EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode;
EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn;
} EFI_CONSOLE_CONTROL_PROTOCOL;
extern EFI_GUID gEfiConsoleControlProtocolGuid;
#endif

1
elf.h
View File

@ -103,6 +103,7 @@ typedef UINT64 Elf64_Word;
#define EM_IA_64 50 /* HP/Intel IA-64 */
#define EM_X86_64 62 /* Intel/AMD x86-64 */
/*
* This is an interim value that we will use until the committee comes
* up with a final number.

BIN
elilo-ia32.efi Executable file

Binary file not shown.

BIN
elilo-ia64.efi Normal file → Executable file

Binary file not shown.

BIN
elilo-x86_64.efi Executable file

Binary file not shown.

84
elilo.c
View File

@ -1,5 +1,5 @@
/*
* elilo.c - IA-64/IA-32 EFI Linux loader
* elilo.c - IA-64/IA-32/x86_64 EFI Linux loader
*
* Copyright (C) 1999-2003 Hewlett-Packard Co.
* Contributed by David Mosberger <davidm@hpl.hp.com>.
@ -8,6 +8,11 @@
* Copyright (C) 1999-2000 VA Linux Systems
* Contributed by Johannes Erdfelt <jerdfelt@valinux.com>.
*
* Copyright (C) 2006-2009 Intel Corporation
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.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
@ -41,13 +46,14 @@
#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"
#define ELILO_SHARED_CMDLINE_OPTS L"pPMC:aDhd:i:m:vVc:E"
elilo_config_t elilo_opt;
EFI_SYSTEM_TABLE *systab; /* pointer to EFI system table */
extern INTN wait_timeout (UINTN);
/*
* Load the Linux kernel in memory from the boot media
* Output:
@ -87,7 +93,7 @@ do_kernel_load(CHAR16 *kname, kdesc_t *kd)
INTN
kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem, memdesc_t *mmem)
{
CHAR16 kernel[CMDLINE_MAXLEN];
CHAR16 kernel[FILENAME_MAXLEN];
/*
* Do the vm image switch here
@ -122,11 +128,12 @@ kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem, memde
return ELILO_LOAD_RETRY;
}
VERB_PRT(3, Print(L"kernel loaded in [0x%lx-0x%lx] entry=0x%lx\n",
(unsigned long)kd->kstart, (unsigned long)kd->kend, (unsigned long)kd->kentry));
VERB_PRT(3, Print(L"kernel loaded in [" PTR_FMT "-" PTR_FMT "] entry=" PTR_FMT "\n",
kd->kstart, kd->kend, kd->kentry));
if (elilo_opt.initrd[0]) {
/* ramdisk image is moved to the top of available extended memory later by start_kernel() */
if (sysdeps_initrd_get_addr(kd, imem) == -1) goto exit_error;
switch(load_file(elilo_opt.initrd, imem)) {
@ -207,7 +214,7 @@ main_loop(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image
EFI_STATUS status = EFI_SUCCESS;
kdesc_t kd;
memdesc_t imem, mmem;
INTN r;
INTN r, retries=0;
/*
* First place where we potentially do system dependent
@ -233,19 +240,53 @@ main_loop(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image
}
do_launch:
r =subst_vars(cmdline_tmp, cmdline, CMDLINE_MAXLEN);
r = subst_vars(cmdline_tmp, cmdline, CMDLINE_MAXLEN);
VERB_PRT(3, Print(L"final cmdline(%d): %s\n", r, cmdline));
/* Give user time to see the output before launch */
if (elilo_opt.debug || elilo_opt.verbose) {
r = wait_timeout(150);
/* have to turn off all console output(except error output) now before final get_mmemap()
* call or it can cause the efi map key to change and the ExitBootSvc call to fail,
* forcing debug and verbose options off is the surest way to enforce this.
*/
elilo_opt.debug=0;
elilo_opt.verbose=0;
}
/* free resources associated with file accesses (before ExitBootServices) */
close_devices();
/* No console output permitted after create_boot_params()! */
if ((bp=create_boot_params(cmdline, &imem, &mmem, &cookie)) == 0) goto error;
/* terminate bootservices */
status = BS->ExitBootServices(image, cookie);
if (EFI_ERROR(status)) goto bad_exit;
/* terminate bootservices
* efi ExitBootSvcs spec: *note, get_memmap is called by create_boot_params()
* An EFI OS loader must ensure that it has the system's current memory map at the time
* it calls ExitBootServices(). This is done by passing in the current memory map's
* MapKey value as returned by GetMemoryMap(). Care must be taken to ensure that the
* memory map does not change between these two calls. It is suggested that
* GetMemoryMap()be called immediately before calling ExitBootServices(). */
retry:
status = uefi_call_wrapper(BS->ExitBootServices, 2, image, cookie);
if (EFI_ERROR(status))
{
ERR_PRT((L"\nExitBootSvcs: failed, memory map has changed.\n"));
if (retries < 2)
{
ERR_PRT((L"Main_Loop: Retrying,... have to rebuild boot params"));
retries++;
free_boot_params(bp);
if ((bp=create_boot_params(cmdline, &imem, &mmem, &cookie)) == 0) goto error;
goto retry;
} else {
ERR_PRT((L"\nMain_Loop: tried ExitBootSvcs 3 times... retries exceeded.... giving up\n"));
goto bad_exit;
}
}
start_kernel(kd.kentry, bp);
/* NOT REACHED */
@ -259,6 +300,7 @@ bad_exit:
error:
free_kmem();
if (imem.start_addr) free(imem.start_addr);
if (mmem.start_addr) free(mmem.start_addr);
if (bp) free_boot_params(bp);
exit_error:
return ELILO_LOAD_ERROR;
@ -307,7 +349,7 @@ fixupargs(EFI_LOADED_IMAGE *info)
#define FAKE_ELILONAME L"elilo-forced"
status = BS->HandleProtocol (info->DeviceHandle, &PxeBaseCodeProtocol, (VOID **)&pxe);
status = uefi_call_wrapper(BS->HandleProtocol, 3, info->DeviceHandle, &PxeBaseCodeProtocol, (VOID **)&pxe);
if (EFI_ERROR(status)) return;
default_load_options = info->LoadOptions;
@ -365,7 +407,7 @@ check_edd30(VOID)
UINT8 bool = FALSE;
INTN ret = -1;
status = RT->GetVariable(L"EDD30", &edd30_guid, NULL, &l, &bool);
status = uefi_call_wrapper(RT->GetVariable, 5, 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;
@ -395,7 +437,7 @@ force_edd30(VOID)
UINT8 bool;
bool = TRUE;
status = RT->SetVariable(L"EDD30", &edd30_guid, EDD30_ATTR, l, &bool);
status = uefi_call_wrapper(RT->SetVariable, 5, L"EDD30", &edd30_guid, EDD30_ATTR, l, &bool);
if (EFI_ERROR(status)) {
ERR_PRT((L"can't set EDD30 variable: ignoring it"));
return -1;
@ -439,19 +481,23 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab)
* mode.
* XXX: clean this up !
*/
BS->SetWatchdogTimer(0, 0x0, 0, NULL);
uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x0, 0, NULL);
/*
* start a clean console
*/
uefi_call_wrapper(systab->ConOut->Reset, 2, systab->ConOut, FALSE);
/* initialize memory allocator */
if (alloc_init() == -1) return EFI_LOAD_ERROR;
status = BS->HandleProtocol(image, &LoadedImageProtocol, (VOID **) &info);
status = uefi_call_wrapper(BS->HandleProtocol, 3, 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));
VERB_PRT(5,Print(L"Loaded at " PTR_FMT " size=%ld bytes code=%d data=%d\n", info->ImageBase, info->ImageSize, info->ImageCodeType, info->ImageDataType));
/*
* verify EDD3.0 status. Users may have to reboot
*/
@ -595,7 +641,7 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab)
goto do_exit;
}
}
DBG_PRT((L"Optind=%d optarg=%x argc=%d", Optind, Optarg, argc));
DBG_PRT((L"Optind=%d optarg=" PTR_FMT " argc=%d", Optind, Optarg, argc));
/*
* we can't defer this phase any longer...

19
elilo.h
View File

@ -29,8 +29,16 @@
#ifndef __ELILO_H__
#define __ELILO_H__
#define ELILO_VERSION L"3.16"
#include <efi.h>
#ifdef CONFIG_ia32
#define PTR_FMT L"0x%x"
#else
#define PTR_FMT L"0x%lx"
#endif
#include "elilo_debug.h"
#include "fileops.h"
@ -46,6 +54,10 @@
#define ROUNDUP(x,a) (((x) + (a) - 1) & ~((a) - 1))
#define ROUNDDOWN(x,a) ((x) & ~((a) - 1))
#ifndef UINT32_MAX
#define UINT32_MAX ((UINT32)-1)
#endif
/*
* Elilo Boot modes
*/
@ -57,7 +69,8 @@
#define ELILO_DEFAULT_TIMEOUT ELILO_TIMEOUT_INFINITY
#define ELILO_TIMEOUT_INFINITY (~0UL)
#define CMDLINE_MAXLEN 512 /* needed by ia32 */
#define CMDLINE_MAXLEN 2048
#define PATHNAME_MAXLEN 512
#define FILENAME_MAXLEN 256
#define MAX_ARGS 256
/* Just pick an arbitrary number that's high enough for now :o) */
@ -150,6 +163,7 @@ 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 INTN alloc_kmem_anywhere(VOID **, UINTN);
extern VOID free_kmem(VOID);
extern VOID free_all_memory(VOID);
@ -183,7 +197,7 @@ extern CHAR16 *get_config_file(VOID);
extern INTN load_file(CHAR16 *, memdesc_t *);
/* from alternate.c */
extern INTN alternate_kernel(CHAR16 *, INTN);
extern INTN alternate_kernel(CHAR16 *, UINTN);
/* from bootparams.c */
extern VOID *create_boot_params (CHAR16 *, memdesc_t *, memdesc_t *, UINTN *);
@ -203,6 +217,7 @@ 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);
extern VOID *sysdeps_checkfix_initrd(VOID *, memdesc_t *);
#define CHAR_SLASH L'/'
#define CHAR_BACKSLASH L'\\'

View File

@ -26,6 +26,10 @@
#ifndef __ELILO_DEBUG__
#define __ELILO_DEBUG__
//#define DEBUG_MEM
//#define DEBUG_GZIP
//#define DEBUG_BZ
#define ELILO_DEBUG 1
#define ERR_PRT(a) do { Print(L"%a(line %d):", __FILE__, __LINE__); Print a; Print(L"\n"); } while (0);

View File

@ -1,6 +1,9 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.intel.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
@ -135,7 +138,7 @@ glue_filesystem(EFI_GUID *proto, EFI_HANDLE dev, fops_fs_glue_t glue)
VOID *intf = NULL;
EFI_STATUS status;
status = BS->HandleProtocol(dev, proto, &intf);
status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, proto, &intf);
if (EFI_ERROR(status)) {
ERR_PRT((L"unable to locate %g: should not happen", proto));
return NULL; /* should not happen */
@ -358,6 +361,8 @@ fops_setdefaults(struct config_file *defconf, CHAR16 *kname, UINTN maxlen, CHAR1
#define FILEOPS_ARCH_DEFAULT_CONFIG L"elilo-ia64.conf"
#elif defined (CONFIG_ia32)
#define FILEOPS_ARCH_DEFAULT_CONFIG L"elilo-ia32.conf"
#elif defined (CONFIG_x86_64)
#define FILEOPS_ARCH_DEFAULT_CONFIG L"elilo-x86_64.conf"
#else
#error "You need to specfy your default arch config file"
#endif
@ -455,7 +460,7 @@ add_dev_tab(EFI_GUID *proto, EFI_HANDLE boot_handle, UINTN size, fops_fs_glue_t
/*
* get the actual device handles now
*/
status = BS->LocateHandle(ByProtocol, proto, NULL, &size, tab);
status = uefi_call_wrapper(BS->LocateHandle, 5, 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);
@ -492,7 +497,7 @@ add_dev_tab(EFI_GUID *proto, EFI_HANDLE boot_handle, UINTN size, fops_fs_glue_t
str2 = str == NULL ? L"Unknown" : str;
DBG_PRT((L"%s : %-8s : %s\n", dev_tab[idx].name,
DBG_PRT((L"%s : %-8s : %s", dev_tab[idx].name,
(dev_tab[idx].fops ? dev_tab[idx].fops->name: L"N/A"), str2));
if (str) FreePool(str);
@ -536,7 +541,7 @@ find_filesystems(EFI_HANDLE boot_handle)
*/
for(fs = fs_tab; *fs; fs++) {
size = 0;
BS->LocateHandle(ByProtocol, &(*fs)->proto, NULL, &size, NULL);
uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &(*fs)->proto, NULL, &size, NULL);
total += size;
}
if (total == 0) {
@ -560,7 +565,7 @@ find_filesystems(EFI_HANDLE boot_handle)
for(fs = fs_tab; *fs; fs++) {
size = 0;
BS->LocateHandle(ByProtocol, &(*fs)->proto, NULL, &size, NULL);
uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &(*fs)->proto, NULL, &size, NULL);
if (size == 0) continue;
add_dev_tab(&(*fs)->proto, boot_handle, size, (*fs)->glue);

View File

@ -23,10 +23,15 @@
# to use this program.
#
include ../Make.defaults
include ../Make.rules
SRCDIR = .
VPATH = $(SRCDIR)
include $(SRCDIR)/../Make.defaults
include $(SRCDIR)/../Make.rules
TOPDIR=$(SRCDIR)/..
TOPDIR=$(CDIR)/..
FILES=
ifeq ($(CONFIG_localfs),y)
@ -54,17 +59,13 @@ 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)
$(TARGET): $(TOPDIR)/Make.defaults $(FILES)
@if [ -z "$(FILES)" ]; then \
echo "You need to define at least one filesystem in Make.defaults"; \
exit 1; \
fi
$(LD) $(LD3264) -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

View File

@ -142,9 +142,9 @@ read_bytes(EFI_BLOCK_IO *blkio, UINT32 mediaid, UINTN offset, VOID *addr, UINTN
return ret;
}
DBG_PRT((L"readblock(%x, %d, %d, %d, %x)", blkio, mediaid, base, buffer_size, buffer));
DBG_PRT((L"readblock(PTR_FMT ", %d, %ld, %d, " PTR_FMT ")", blkio, mediaid, base, buffer_size, buffer));
status = blkio->ReadBlocks(blkio, mediaid, base, buffer_size, buffer);
status = uefi_call_wrapper(blkio->ReadBlocks, 5, blkio, mediaid, base, buffer_size, buffer);
if (EFI_ERROR(status)) {
ERR_PRT((L"readblock(%d,%d)=%r", base, buffer_size, status));
goto error;
@ -866,13 +866,13 @@ ext2fs_install_one(EFI_HANDLE dev, VOID **intf)
EFI_BLOCK_IO *blkio;
ext2fs_t *ext2fs;
status = BS->HandleProtocol (dev, &Ext2FsProtocol, (VOID **)&ext2fs);
status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &Ext2FsProtocol, (VOID **)&ext2fs);
if (status == EFI_SUCCESS) {
ERR_PRT((L"Warning: found existing %s protocol on device", FS_NAME));
goto found;
}
status = BS->HandleProtocol(dev, &BlockIoProtocol, (VOID **)&blkio);
status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &BlockIoProtocol, (VOID **)&blkio);
if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER;
VERB_PRT(5,
@ -903,7 +903,7 @@ ext2fs_install_one(EFI_HANDLE dev, VOID **intf)
}
if (sb.s_magic != EXT2_SUPER_MAGIC) {
DBG_PRT((L"bad magic 0x%x\n", sb.s_magic));
DBG_PRT((L"bad magic "PTR_FMT"\n", sb.s_magic));
return EFI_INVALID_PARAMETER;
}
@ -944,7 +944,7 @@ ext2fs_install(VOID)
EFI_STATUS status;
VOID *intf;
BS->LocateHandle(ByProtocol, &BlockIoProtocol, NULL, &size, NULL);
uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &BlockIoProtocol, NULL, &size, NULL);
if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */
DBG_PRT((L"size=%d", size));
@ -955,7 +955,8 @@ ext2fs_install(VOID)
return EFI_OUT_OF_RESOURCES;
}
status = BS->LocateHandle(ByProtocol, &BlockIoProtocol, NULL, &size, (VOID **)dev_tab);
status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &BlockIoProtocol, NULL,
&size, (VOID **)dev_tab);
if (status != EFI_SUCCESS) {
ERR_PRT((L"failed to get handles: %r", status));
free(dev_tab);
@ -984,7 +985,7 @@ ext2fs_uninstall(VOID)
for(i=0; i < ndev; i++) {
if (dev_tab[i].intf == NULL) continue;
e2fs = FS_PRIVATE(dev_tab[i].intf);
status = BS->UninstallProtocolInterface(e2fs->dev, &Ext2FsProtocol, dev_tab[i].intf);
status = uefi_call_wrapper(BS->UninstallProtocolInterface, 3, e2fs->dev, &Ext2FsProtocol, dev_tab[i].intf);
if (EFI_ERROR(status)) {
ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status));
continue;

View File

@ -1,6 +1,10 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
* Copyright (C) 2006-2009 Intel Corporation
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.intel.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
@ -61,7 +65,7 @@ static EFI_GUID LocalFsProtocol = LOCALFS_PROTOCOL;
* let's be clean here
*/
typedef union {
EFI_HANDLE *dev;
EFI_HANDLE dev;
localfs_t *intf;
} dev_tab_t;
@ -94,7 +98,7 @@ localfs_open(localfs_interface_t *this, CHAR16 *name, UINTN *fd)
DBG_PRT((L"localfs_open on %s\n", name));
status = lfs->volume->Open(lfs->volume, &fh, name, EFI_FILE_MODE_READ, 0);
status = uefi_call_wrapper(lfs->volume->Open, 5, lfs->volume, &fh, name, EFI_FILE_MODE_READ, (UINT64)0);
if (status == EFI_SUCCESS) {
*fd = LOCALFS_F2FD(fh);
}
@ -110,7 +114,7 @@ localfs_read(localfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size)
lfs = FS_PRIVATE(this);
return lfs->volume->Read(LOCALFS_FD2F(fd), size, buf);
return uefi_call_wrapper(lfs->volume->Read, 3, LOCALFS_FD2F(fd), size, buf);
}
static EFI_STATUS
@ -122,7 +126,7 @@ localfs_close(localfs_interface_t *this, UINTN fd)
lfs = FS_PRIVATE(this);
return lfs->volume->Close(LOCALFS_FD2F(fd));
return uefi_call_wrapper(lfs->volume->Close, 1, LOCALFS_FD2F(fd));
}
static EFI_STATUS
@ -140,7 +144,7 @@ localfs_infosize(localfs_interface_t *this, UINTN fd, UINT64 *sz)
*sz = info->FileSize;
FreePool(info);
uefi_call_wrapper(BS->FreePool, 1, info);
return EFI_SUCCESS;
}
@ -154,7 +158,7 @@ localfs_seek(localfs_interface_t *this, UINTN fd, UINT64 newpos)
lfs = FS_PRIVATE(this);
return lfs->volume->SetPosition(LOCALFS_FD2F(fd), newpos);
return uefi_call_wrapper(lfs->volume->SetPosition, 2, LOCALFS_FD2F(fd), newpos);
}
static VOID
@ -185,16 +189,16 @@ localfs_install_one(EFI_HANDLE dev, VOID **intf)
EFI_FILE_IO_INTERFACE *volume;
EFI_FILE_HANDLE volume_fh;
status = BS->HandleProtocol (dev, &LocalFsProtocol, (VOID **)&localfs);
status = uefi_call_wrapper(BS->HandleProtocol, 3, 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);
status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &FileSystemProtocol, (VOID **)&volume);
if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER;
status = volume->OpenVolume(volume, &volume_fh);
status = uefi_call_wrapper(volume->OpenVolume, 2, volume, &volume_fh);
if (EFI_ERROR(status)) {
ERR_PRT((L"cannot open volume"));
return status;
@ -221,7 +225,7 @@ found:
dp = DevicePathFromHandle(dev);
str = DevicePathToStr(dp);
Print(L"attached %s to %s\n", FS_NAME, str);
FreePool(str);
uefi_call_wrapper(BS->FreePool, 1, str);
});
return EFI_SUCCESS;
@ -235,7 +239,7 @@ localfs_install(VOID)
EFI_STATUS status;
VOID *intf;
BS->LocateHandle(ByProtocol, &FileSystemProtocol, NULL, &size, NULL);
uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &FileSystemProtocol, NULL, &size, NULL);
if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */
DBG_PRT((L"size=%d", size));
@ -245,8 +249,7 @@ localfs_install(VOID)
ERR_PRT((L"failed to allocate handle table"));
return EFI_OUT_OF_RESOURCES;
}
status = BS->LocateHandle(ByProtocol, &FileSystemProtocol, NULL, &size, (VOID **)dev_tab);
status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &FileSystemProtocol, NULL, &size, (VOID **)dev_tab);
if (status != EFI_SUCCESS) {
ERR_PRT((L"failed to get handles: %r", status));
free(dev_tab);
@ -275,7 +278,7 @@ localfs_uninstall(VOID)
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);
status = uefi_call_wrapper(BS->UninstallProtocolInterface, 3, lfs->dev, &LocalFsProtocol, dev_tab[i].intf);
if (EFI_ERROR(status)) {
ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status));
continue;
@ -285,7 +288,7 @@ localfs_uninstall(VOID)
dp = DevicePathFromHandle(lfs->dev);
str = DevicePathToStr(dp);
Print(L"uninstalled %s on %s\n", FS_NAME, str);
FreePool(str);
uefi_call_wrapper(BS->FreePool, 1, str);
});
free(dev_tab[i].intf);
}

View File

@ -1,6 +1,11 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Copyright (C) 2001-2009 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
* Contributed by Jason Fleischli <jason.fleischli@hp.com>
* Copyright (C) 2006-2009 Intel Corporation
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.intel.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
@ -34,6 +39,13 @@
#define NETFS_DEFAULT_BUFSIZE 16*MB
#define NETFS_DEFAULT_BUFSIZE_INC 8*MB
#define NETFS_DEFAULT_BLOCKSIZE 1024 /* setting to zero is supposed to default the underlying */
/* pxe implementation to largest blocksize supported,... */
/* in reality on original older efi implementations its */
/* never set causing the pxe transfer to timeout. */
/* the spec defines the minimum supported blocksize default */
/* to be 512 bytes... a bit extreme, 1024 should work for */
/* everything */
#define NETFS_DEFAULT_SERVER_TYPE EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP
#define NETFS_FD_MAX 2
@ -217,7 +229,7 @@ netfs_extract_ip(netfs_priv_state_t *nfs)
if (pxe->Mode->RouteTableEntries>0)
Memcpy(&nfs->gw_ip, &pxe->Mode->RouteTable[0].GwAddr, sizeof(EFI_IP_ADDRESS));
VERB_PRT(1, Print(L"PXE PxeDiscoverValid: %s\n", pxe->Mode->PxeDiscoverValid? L"Yes (PXE-aware DHCPD)" : L"No (Regular DHCPD)"));
VERB_PRT(1, Print(L"PXE PxeDiscoverValid: %s\n", pxe->Mode->PxeDiscoverValid? L"Yes (PXE-aware DHCPD)\n" : L"No (Regular DHCPD)\n"));
#if 0
status = BS->HandleProtocol(dev, &PxeCallbackProtocol, (VOID **)&netfs_callback);
status = LibInstallProtocolInterfaces(&dev, &PxeCallbackProtocol, &netfs_callback, NULL);
@ -262,7 +274,7 @@ netfs_start(EFI_PXE_BASE_CODE *pxe)
{
EFI_STATUS status;
status = pxe->Start(pxe, FALSE);
status = uefi_call_wrapper(pxe->Start, 2, pxe, FALSE);
if (EFI_ERROR(status)) return status;
return pxe->Dhcp(pxe, FALSE);
@ -275,7 +287,9 @@ netfs_open(netfs_interface_t *this, CHAR16 *name, UINTN *fd)
netfs_fd_t *f;
EFI_STATUS status;
CHAR8 ascii_name[FILENAME_MAXLEN];
UINTN blocksize = 0, prev_netbufsize;
UINTN blocksize = NETFS_DEFAULT_BLOCKSIZE;
UINTN prev_netbufsize, retries = 0;
BOOLEAN server_provided_filesize = FALSE;
if (this == NULL || name == NULL || fd == NULL) return EFI_INVALID_PARAMETER;
@ -301,6 +315,7 @@ netfs_open(netfs_interface_t *this, CHAR16 *name, UINTN *fd)
return EFI_SUCCESS;
}
f->netbuf_maxsize = NETFS_DEFAULT_BUFSIZE;
f->netbuf_size = 0;
if (f->netbuf == NULL && netbuf_alloc(f) == -1) {
netfs_fd_free(nfs, f);
@ -311,58 +326,108 @@ netfs_open(netfs_interface_t *this, CHAR16 *name, UINTN *fd)
U2ascii(name, ascii_name, FILENAME_MAXLEN);
VERB_PRT(2, Print(L"downloading %a from %d.%d.%d.%d...", ascii_name,
VERB_PRT(2, Print(L"downloading %a from %d.%d.%d.%d...\n", ascii_name,
nfs->srv_ip.v4.Addr[0],
nfs->srv_ip.v4.Addr[1],
nfs->srv_ip.v4.Addr[2],
nfs->srv_ip.v4.Addr[3]));
retry:
f->netbuf_size = f->netbuf_maxsize;
if (retries == 2) {
netfs_fd_free(nfs, f);
VERB_PRT(2, Print(L"Failed: %r\n", status));
return status;
}
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.
/*
* netboot bugfix SF tracker 2874380
* EFI 1.10 spec
* For read operations, the return data will be placed in the buffer specified by BufferPtr. If
* BufferSize is too small to contain the entire downloaded file, then
* EFI_BUFFER_TOO_SMALL will be returned and BufferSize will be set to zero or the size of
* the requested file (the size of the requested file is only returned if the TFTP server supports TFTP
* options). If BufferSize is large enough for the read operation, then BufferSize will be set to
* the size of the downloaded file, and EFI_SUCCESS will be returned. Applications using the
* PxeBc.Mtftp() services should use the get-file-size operations to determine the size of the
* downloaded file prior to using the read-file operationsespecially when downloading large
* (greater than 64 MB) filesinstead of making two calls to the read-file operation. Following this
* recommendation will save time if the file is larger than expected and the TFTP server does not
* support TFTP option extensions. Without TFTP option extension support, the client has to
* download the entire file, counting and discarding the received packets, to determine the file size.
* ...
* For TFTP get file size operations, the size of the requested file or directory is returned in
* BufferSize, and EFI_SUCCESS will be returned. If the TFTP server does not support options,
* the file will be downloaded into a bit bucket and the length of the downloaded file will be returned.
*/
status = uefi_call_wrapper(nfs->pxe->Mtftp, 10,
nfs->pxe,
EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
f->netbuf,
FALSE,
&(f->netbuf_size), // PXE writes size of file from server here
&blocksize,
&nfs->srv_ip,
ascii_name,
NULL,
FALSE);
/*
* If options are not supported by this tftp server, according to the spec the file will be
* downloaded into a bit bucket, the size calculated by efi fw and returned in the status
* field of this call. YUK!!... in this case we will default to currently allocated max
* if thats still not big enough it will be caught and increased following the read file attempt
* then retried.
* XXX need to research how this is handled or changed in the latest UEFI spec.
*/
if (status != EFI_SUCCESS) {
f->netbuf_size = f->netbuf_maxsize;
VERB_PRT(2, Print(L"setting default buffer size of %d for %a, no filesize recd from tftp server\n",
f->netbuf_size, ascii_name));
}
if (status == EFI_SUCCESS) {
server_provided_filesize = TRUE;
VERB_PRT(2, Print(L"received file size of %d for %a from tftp server.\n",
f->netbuf_size, ascii_name));
}
if (f->netbuf_size > f->netbuf_maxsize) { // we need a bigger buffer
VERB_PRT(2, Print(L"allocated buffer too small, attempting to increase\n"));
f->netbuf_maxsize += f->netbuf_size;
free(f->netbuf);
f->netbuf = NULL;
if (netbuf_alloc(f) == -1) return EFI_OUT_OF_RESOURCES;
}
/* paranoid catch any corner case missed */
if (f->netbuf_size == 0) f->netbuf_size = f->netbuf_maxsize;
DBG_PRT((L"\nbefore read: netbuf:" PTR_FMT " netbuf_size=%d blocksize=%d\n",
f->netbuf,
f->netbuf_size,
blocksize));
prev_netbufsize = f->netbuf_size;
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);
/* now try and download this file from the tftp server */
status = uefi_call_wrapper(nfs->pxe->Mtftp, 10,
nfs->pxe,
EFI_PXE_BASE_CODE_TFTP_READ_FILE,
f->netbuf,
FALSE,
&(f->netbuf_size),
&blocksize,
&nfs->srv_ip,
ascii_name,
NULL,
FALSE);
DBG_PRT((L"after Mftp=%r netbuf:0x%lx netbuf_size=%ld blocksize=%ld\n",
DBG_PRT((L"after: status=%r netbuf:" PTR_FMT " netbuf_size=%d blocksize=%d\n",
status,
f->netbuf,
f->netbuf_size,
blocksize));
if (status == EFI_TIMEOUT && blocksize == 0) {
/*
* XXX: if blocksize is not adjusted we could loop forever here
*/
//blocksize = 512;
status = EFI_BUFFER_TOO_SMALL;
}
/*
* check if we need to increase our buffer size
*/
if (status == EFI_BUFFER_TOO_SMALL) {
DBG_PRT((L"buffer too small, need netbuf_size=%d", f->netbuf_size));
if ((status == EFI_TIMEOUT || status == EFI_BUFFER_TOO_SMALL) && !server_provided_filesize) {
Print(L"buffer too small, need netbuf_size=%d\n", f->netbuf_size);
/*
* if the TFTP server supports TFTP options, then we should
* get the required size. So we test to see if the size
@ -374,16 +439,22 @@ retry:
} else {
/* we got an answer from the TFTP server, let's try it */
f->netbuf_maxsize = f->netbuf_size;
server_provided_filesize = TRUE;
}
free(f->netbuf);
f->netbuf = NULL; /* will force reallocation */
if (netbuf_alloc(f) == 0) goto retry;
if (netbuf_alloc(f) == 0) {
retries++;
goto retry;
}
/* fall through in case of error */
} else if (status == EFI_TIMEOUT) { //if just a simple timeout, buffers are good just retry
VERB_PRT(2, Print(L"TFTP returned EFI_TIMEOUT ERROR... %d retries left.\n", (2 - retries)));
retries++;
goto retry;
}
if (status == EFI_SUCCESS) {
/* start at the beginning of the file */
f->netbuf_pos = 0;
@ -627,7 +698,7 @@ netfs_query_layer(netfs_interface_t *this, UINT16 server_type, UINT16 layer, UIN
if (server_type == 0) server_type = find_pxe_server_type(nfs->pxe);
status = nfs->pxe->Discover(nfs->pxe, server_type, &layer, FALSE, 0);
status = uefi_call_wrapper(nfs->pxe->Discover, 5, nfs->pxe, server_type, &layer, FALSE, 0);
if(status == EFI_SUCCESS) {
ascii2U(nfs->pxe->Mode->PxeReply.Dhcpv4.BootpBootFile, str, maxlen);
}
@ -680,13 +751,13 @@ netfs_install_one(EFI_HANDLE dev, VOID **intf)
netfs_t *netfs;
EFI_PXE_BASE_CODE *pxe;
status = BS->HandleProtocol (dev, &NetFsProtocol, (VOID **)&netfs);
status = uefi_call_wrapper(BS->HandleProtocol, 3, 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);
status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &PxeBaseCodeProtocol, (VOID **)&pxe);
if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER;
@ -727,7 +798,7 @@ netfs_install(VOID)
EFI_STATUS status;
VOID *intf;
BS->LocateHandle(ByProtocol, &PxeBaseCodeProtocol, NULL, &size, NULL);
uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &PxeBaseCodeProtocol, NULL, &size, NULL);
if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */
DBG_PRT((L"size=%d", size));
@ -738,7 +809,7 @@ netfs_install(VOID)
return EFI_OUT_OF_RESOURCES;
}
status = BS->LocateHandle(ByProtocol, &PxeBaseCodeProtocol, NULL, &size, (VOID **)dev_tab);
status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &PxeBaseCodeProtocol, NULL, &size, (VOID **)dev_tab);
if (status != EFI_SUCCESS) {
ERR_PRT((L"failed to get handles: %r", status));
free(dev_tab);
@ -767,7 +838,7 @@ netfs_uninstall(VOID)
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);
status = uefi_call_wrapper(BS->UninstallProtocolInterface, 3, nfs->dev, &NetFsProtocol, dev_tab[i].intf);
if (EFI_ERROR(status)) {
ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status));
continue;
@ -780,7 +851,8 @@ netfs_uninstall(VOID)
FreePool(str);
});
if (nfs->pxe->Mode->Started == TRUE) nfs->pxe->Stop(nfs->pxe);
if (nfs->pxe->Mode->Started == TRUE)
uefi_call_wrapper(nfs->pxe->Stop, 1, nfs->pxe);
free(dev_tab[i].intf);
}

View File

@ -25,7 +25,6 @@
* 02111-1307, USA.
*/
#include <efi.h>
#include <efilib.h>
@ -36,7 +35,7 @@
#define BADCH (INTN)'?'
#define BADARG (INTN)':'
extern CHAR16 * StrChr(IN const CHAR16 *s, INT16 c);
extern CHAR16 * StrChr(IN const CHAR16 *s, CHAR16 c);
CHAR16 *Optarg;
INTN Optind = 1;

View File

@ -1,6 +1,10 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
* Copyright (C) 2006-2009 Intel Corporation
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.intel.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
@ -60,6 +64,19 @@ static CHAR16 netfs_default_path[FILENAME_MAXLEN];
static CHAR16 *hexa=L"0123456789ABCDEF";
static VOID
convert_mac2hex(UINT8 *hw_addr,INTN l, CHAR16 *str)
{
UINTN i;
for (i=0 ; i < l; i++) {
str[3*i] = hexa[(hw_addr[i] & 0xf0)>>4];
str[3*i+1] = hexa[hw_addr[i] & 0x0f];
str[3*i+2] = ':';
}
str[3*l-1]='\0';
}
static VOID
convert_ip2hex(UINT8 *ip, INTN l, CHAR16 *str)
{
@ -149,6 +166,8 @@ netfs_setdefaults(VOID *intf, config_file_t *config, CHAR16 *kname, UINTN maxlen
set_var(VAR_NETFS_DOMAINAME, info.domainame);
if (info.using_pxe) {
DBG_PRT((L"netfs_setdefaults: using_pxe"));
status = netfs->netfs_query_layer(netfs, 0, NETFS_CONFIG_LAYER, maxlen, config[0].fname);
if (EFI_ERROR(status)) {
StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1);
@ -165,13 +184,20 @@ netfs_setdefaults(VOID *intf, config_file_t *config, CHAR16 *kname, UINTN maxlen
# if defined(CONFIG_ia64)
# define CONFIG_ARCH_EXTENSION L"-ia64.conf\0"
# define EXTENSION_LENGTH 11
# elif defined (CONFIG_ia32)
# define CONFIG_ARCH_EXTENSION L"-ia64.conf\0"
# define CONFIG_ARCH_EXTENSION L"-ia32.conf\0"
# define EXTENSION_LENGTH 11
# elif defined (CONFIG_x86_64)
# define CONFIG_ARCH_EXTENSION L"-x86_64.conf\0"
# define EXTENSION_LENGTH 13
# else
# error "You need to specfy your default arch config file"
# endif
# define CONFIG_EXTENSION L".conf\0"
DBG_PRT((L"netfs_setdefaults: machine specific (!using_pxe)"));
/*
* will try machine/subnet specific files first.
* the filenames are constructed based on the IP(v4) address
@ -181,22 +207,28 @@ netfs_setdefaults(VOID *intf, config_file_t *config, CHAR16 *kname, UINTN maxlen
StrnCpy(config[0].fname+8, CONFIG_EXTENSION, 6);
StrnCpy(config[1].fname, str, maxlen-1);
StrnCpy(config[1].fname+6, CONFIG_ARCH_EXTENSION, 11);
StrnCpy(config[1].fname+6, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH);
StrnCpy(config[2].fname, str, maxlen-1);
StrnCpy(config[2].fname+6, CONFIG_EXTENSION, 6);
StrnCpy(config[3].fname, str, maxlen-1);
StrnCpy(config[3].fname+4, CONFIG_ARCH_EXTENSION, 11);
StrnCpy(config[3].fname+4, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH);
StrnCpy(config[4].fname, str, maxlen-1);
StrnCpy(config[4].fname+4, CONFIG_EXTENSION, 6);
StrnCpy(config[5].fname, str, maxlen-1);
StrnCpy(config[5].fname+2, CONFIG_ARCH_EXTENSION, 11);
StrnCpy(config[5].fname+2, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH);
StrnCpy(config[6].fname, str, maxlen-1);
StrnCpy(config[6].fname+2, CONFIG_EXTENSION, 6);
/* use the MAC address as a possible file name as well */
convert_mac2hex(info.hw_addr,6,str);
StrnCpy(config[7].fname, str, maxlen-1);
StrnCpy(config[7].fname+17, CONFIG_EXTENSION, 6);
#else
StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1);
config[0].fname[maxlen-1] = CHAR_NULL;

View File

@ -23,10 +23,15 @@
# to use this program.
#
include ../Make.defaults
include ../Make.rules
SRCDIR = .
VPATH = $(SRCDIR)
include $(SRCDIR)/../Make.defaults
include $(SRCDIR)/../Make.rules
TOPDIR=$(SRCDIR)/..
TOPDIR=$(CDIR)/..
FILES=system.o config.o bzimage.o plain_loader.o gzip_loader.o gzip.o
@ -37,13 +42,13 @@ 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
$(CC) -o bin_to_h $(SRCDIR)/bin_to_h.c
$(AS) -o rmswitch.o $(SRCDIR)/rmswitch.S
$(LD) -Ttext 0x0 -s --oformat binary -o rmswitch rmswitch.o
./bin_to_h <rmswitch >rmswitch.h
$(TARGET): $(FILES)
$(LD) -r -o $@ $(FILES)
$(LD) $(LD3264) -r -o $@ $(FILES)
clean:
$(RM) -f $(TARGET) $(FILES)

View File

@ -34,7 +34,7 @@
boot_params_t *param_start = NULL;
UINTN param_size = 0;
UINTN kernel_size = 0x200000; /* 2M (largest x86 bzImage kernel image) */
UINTN kernel_size = 0x400000; /* 4M (default x86 bzImage size limit) */
static INTN
bzImage_probe(CHAR16 *kname)
@ -47,7 +47,7 @@ bzImage_probe(CHAR16 *kname)
DBG_PRT((L"probe_bzImage_boot()\n"));
if (!kname) {
ERR_PRT((L"kname == %xh", kname));
ERR_PRT((L"kname == " PTR_FMT, kname));
free_kmem();
return -1;
}
@ -110,7 +110,7 @@ bzImage_probe(CHAR16 *kname)
param_size = (bootsect[0x1F1] + 1) * 512;
param_start = alloc(param_size, EfiLoaderData);
DBG_PRT((L"param_size=%d param_start=%x", param_size, param_start));
DBG_PRT((L"param_size=%d param_start=" PTR_FMT, param_size, param_start));
if (!param_start) {
ERR_PRT((L"Could not allocate %d bytes of setup data.",
@ -141,7 +141,7 @@ bzImage_probe(CHAR16 *kname)
{
UINT8 *c = ((UINT8 *)param_start)+514;
DBG_PRT((L"param_start(c=%x): %c-%c-%c-%c",
DBG_PRT((L"param_start(c=" PTR_FMT "): %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)) {
@ -158,13 +158,38 @@ bzImage_probe(CHAR16 *kname)
* 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));
}
/*
* Get correct address for kernel from header, if applicable & available.
*/
if ((param_start->s.hdr_major == 2) &&
(param_start->s.hdr_minor >= 6) &&
(param_start->s.kernel_start >= DEFAULT_KERNEL_START)) {
kernel_start = (void *)param_start->s.kernel_start;
VERB_PRT(3, Print(L"kernel header suggests kernel start at address "PTR_FMT"\n",
kernel_start));
}
kernel_load_address = NULL; /* allocate anywhere! */
if (alloc_kmem(kernel_start, EFI_SIZE_TO_PAGES(kernel_size)) != 0) {
/*
* Couldn't get desired address--just load it anywhere and move it later.
* (Easier than relocating kernel, and also works with non-relocatable kernels.)
*/
if (alloc_kmem_anywhere(&kernel_load_address, EFI_SIZE_TO_PAGES(kernel_size)) != 0) {
ERR_PRT((L"Could not allocate memory for kernel."));
free(param_start);
param_start = NULL;
param_size = 0;
fops_close(fd);
return -1;
}
}
VERB_PRT(3, Print(L"kernel_start: "PTR_FMT" kernel_size: %d loading at: "PTR_FMT"\n",
kernel_start, kernel_size, kernel_load_address));
/*
* Now read the rest of the kernel image into memory.
*/
@ -172,7 +197,7 @@ bzImage_probe(CHAR16 *kname)
DBG_PRT((L"reading kernel image...\n"));
size = kernel_size;
efi_status = fops_read(fd, kernel_start, &size);
efi_status = fops_read(fd, kernel_load_address, &size);
if (EFI_ERROR(efi_status) || size < 0x10000) {
ERR_PRT((L"Error reading kernel image %s.", kname));
free(param_start);
@ -200,7 +225,7 @@ bzImage_load(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));
ERR_PRT((L"kname=" PTR_FMT " kd=" PTR_FMT, kname, kd));
free(param_start);
param_start = NULL;
param_size = 0;
@ -210,7 +235,7 @@ bzImage_load(CHAR16 *kname, kdesc_t *kd)
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));
DBG_PRT((L"kstart=" PTR_FMT " kentry=" PTR_FMT " kend=" PTR_FMT "\n", kd->kstart, kd->kentry, kd->kend));
return 0;
}

View File

@ -153,7 +153,7 @@ gzip_free(void *where)
int
fill_inbuf(void)
{
INTN expected, nread;
UINTN expected, nread;
EFI_STATUS status;
expected = nread = INBUFSIZE;
@ -162,7 +162,9 @@ fill_inbuf(void)
if (EFI_ERROR(status)) {
error("elilo: Read failed");
}
#ifdef DEBUG_GZIP
DBG_PRT((L"%s : read %d bytes of %d bytes\n", LD_NAME, nread, expected));
#endif
insize = nread;
inptr = 1;
@ -277,7 +279,7 @@ analyze_chunks(void)
* the relevant header information.
*/
int
first_block (const char *buf, long blocksize)
first_block (const unsigned char *buf, long blocksize)
{
Elf32_Ehdr *elf;
Elf32_Phdr *phdrs;
@ -297,13 +299,13 @@ first_block (const char *buf, long blocksize)
phnum = elf->e_phnum;
VERB_PRT(3, {
Print(L"Entry point 0x%lx\n", elf->e_entry);
Print(L"Entry point "PTR_FMT"\n", elf->e_entry);
Print(L"%d program headers\n", phnum);
Print(L"%d segment headers\n", elf->e_shnum);
});
if (offs + phnum * sizeof(*phdrs) > (unsigned) blocksize) {
ERR_PRT((L"%s : ELF program headers not in first block (%ld)\n", LD_NAME, offs));
ERR_PRT((L"%s : ELF program headers not in first block (%d)\n", LD_NAME, offs));
return -1;
}
@ -345,15 +347,15 @@ first_block (const char *buf, long blocksize)
if (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));
DBG_PRT((L"%s : skipping segment %d\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",
Print(L"\n%s : segment %d vaddr ["PTR_FMT"-"PTR_FMT"] offset %d filesz %d "
"memsz=%d bss_sz=%d\n",
LD_NAME, 1+i, chunks[i].addr, chunks[i].addr+phdrs[i].p_filesz,
chunks[i].offset, chunks[i].size, memsz, chunks[i].bss_sz));
@ -364,12 +366,12 @@ first_block (const char *buf, long blocksize)
}
if (low_addr & (EFI_PAGE_SIZE - 1)) {
ERR_PRT((L"%s : low_addr not page aligned 0x%lx\n", LD_NAME, low_addr));
ERR_PRT((L"%s : low_addr not page aligned "PTR_FMT"\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",
DBG_PRT((L"%s : %d program headers entry=" PTR_FMT "\nlowest_addr="PTR_FMT" highest_addr="PTR_FMT"\n",
LD_NAME,
phnum, kernel_entry, low_addr, max_addr));
@ -384,9 +386,9 @@ first_block (const char *buf, long blocksize)
/* allocate memory for the kernel */
if (alloc_kmem((void *)low_addr, pages) == -1) {
ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n",
ERR_PRT((L"%s : AllocatePages(%d, "PTR_FMT") for kernel failed\n",
LD_NAME, pages, low_addr));
ERR_PRT((L"%s : Could not load kernel at 0x%lx\n", LD_NAME, low_addr));
ERR_PRT((L"%s : Could not load kernel at "PTR_FMT"\n", LD_NAME, low_addr));
ERR_PRT((L"%s : Bailing\n", LD_NAME));
goto error;
}
@ -430,12 +432,13 @@ flush_window(void)
static const CHAR8 helicopter[4] = { '|' , '/' , '-' , '\\' };
static UINTN heli_count;
struct segment *cp;
char *src, *dst;
unsigned 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));
#ifdef DEBUG_GZIP
DBG_PRT((L"%s : flush_window outnct=%d file_offset=%d\n", LD_NAME, outcnt, file_offset));
#endif
Print(L"%c\b",helicopter[heli_count++%4]);
@ -468,7 +471,7 @@ tail:
file_offset += skip;
outcnt -= skip;
}
dst = (char *)cp->addr + (file_offset - cp->offset);
dst = (unsigned char *)cp->addr + (file_offset - cp->offset);
cnt = cp->offset + cp->size - file_offset;
if (cnt > outcnt)
cnt = outcnt;
@ -482,7 +485,7 @@ tail:
/* 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;
dst = (unsigned char *)cp->addr + cp->size;
Memset(dst, 0, cp->bss_sz);
}
nextchunk();

View File

@ -111,7 +111,7 @@ load_elf(fops_fd_t fd, kdesc_t *kd)
}
VERB_PRT(3, {
Print(L"ELF Header information: \n");
Print(L"\tEntry point 0x%x\n", (ehdr.e_entry & PADDR_MASK));
Print(L"\tEntry point "PTR_FMT"\n", (ehdr.e_entry & PADDR_MASK));
Print(L"\t%d program headers\n", ehdr.e_phnum);
Print(L"\t%d segment headers\n", ehdr.e_shnum);
});
@ -145,8 +145,8 @@ load_elf(fops_fd_t fd, kdesc_t *kd)
paddr = (phdrs[i].p_paddr & PADDR_MASK);
memsz = phdrs[i].p_memsz;
DBG_PRT((L"Phdr %d paddr [0x%x-0x%x] offset 0x%x"
" filesz 0x%x memsz=0x%x bss_sz=0x%x p_type=0x%x\n",
DBG_PRT((L"Phdr %d paddr ["PTR_FMT"-"PTR_FMT"] offset "PTR_FMT""
" filesz "PTR_FMT" memsz="PTR_FMT" bss_sz="PTR_FMT" p_type="PTR_FMT"\n",
1+i, paddr, paddr+phdrs[i].p_filesz, phdrs[i].p_offset,
phdrs[i].p_filesz, memsz,
(memsz - phdrs[i].p_filesz), phdrs[i].p_type));
@ -160,7 +160,7 @@ load_elf(fops_fd_t fd, kdesc_t *kd)
}
if ((UINTN)low_addr & (EFI_PAGE_SIZE - 1)) {
ERR_PRT((L"%s : kernel low address 0x%x not page aligned\n",
ERR_PRT((L"%s : kernel low address "PTR_FMT" not page aligned\n",
LD_NAME, low_addr));
goto out;
}
@ -176,16 +176,16 @@ load_elf(fops_fd_t fd, kdesc_t *kd)
kd->kentry = (VOID *)(ehdr.e_entry & PADDR_MASK);
VERB_PRT(3, {
Print(L"Lowest PhysAddr: 0x%x\nTotalMemSize:%d bytes (%d pages)\n",
Print(L"Lowest PhysAddr: "PTR_FMT"\nTotalMemSize:%d bytes (%d pages)\n",
low_addr, total_size, pages);
Print(L"Kernel entry @ 0x%x\n", kd->kentry);
Print(L"Kernel entry @ "PTR_FMT"\n", kd->kentry);
});
/* now allocate memory for the kernel at the exact requested spot */
if (alloc_kmem(low_addr, pages) == -1) {
ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n",
ERR_PRT((L"%s : AllocatePages(%d, "PTR_FMT") for kernel failed\n",
LD_NAME, pages, low_addr));
ERR_PRT((L"%s : Could not alloc %d pages for the kernel at 0x%lx "
ERR_PRT((L"%s : Could not alloc %d pages for the kernel at "PTR_FMT""
" and relocation is not not been implemented!\n",
LD_NAME, pages, low_addr));
goto load_abort;
@ -206,7 +206,7 @@ load_elf(fops_fd_t fd, kdesc_t *kd)
if (phdrs[i].p_type != PT_LOAD)
continue;
VERB_PRT(3, Print(L"poffs: 0x%x (phdrs[%d].p_offset)\n",
VERB_PRT(3, Print(L"poffs: "PTR_FMT" (phdrs[%d].p_offset)\n",
phdrs[i].p_offset, i));
filesz = phdrs[i].p_filesz;
@ -221,9 +221,9 @@ load_elf(fops_fd_t fd, kdesc_t *kd)
VERB_PRT(4, {
Print(L"\nHeader #%d\n", i);
Print(L"Offset in file 0x%x\n", phdrs[i].p_offset);
Print(L"Physical addr 0x%x\n", low_addr);
Print(L"BSS size 0x%x bytes\n", bss_sz);
Print(L"Offset in file "PTR_FMT"\n", phdrs[i].p_offset);
Print(L"Physical addr "PTR_FMT"\n", low_addr);
Print(L"BSS size %d bytes\n", bss_sz);
});
/*

View File

@ -35,6 +35,9 @@
#define ELILO_ARCH "IA-32" /* ASCII string */
#define PADDR_MASK 0xfffffff
#define INITRD_START (15*1024*1024)
#define DEFAULT_KERNEL_START 0x100000
/* for now use library versions */
#define Memset(a,v,n) SetMem((a),(n),(v))
#define Memcpy(a,b,n) CopyMem((a),(b),(n))
@ -59,6 +62,26 @@
*/
#pragma pack(1)
/* Definitions for converting EFI memory map to E820 map for Linux
* These definitions are from include/linux/asm-x86/e820.h
* The structure ia32_boot_params below is updated to accommodate E820 map
* EFI memory map is converted to E820 map in this structure and passed
* to Linux. This way the OS does not need to do the conversion.
*/
#define E820_RAM 1
#define E820_RESERVED 2
#define E820_ACPI 3
#define E820_NVS 4
#define E820_MAX 128
struct e820entry {
UINT64 addr; /* start of memory segment */
UINT64 size; /* size of memory segment */
UINT32 type; /* type of memory segment */
} __attribute__((packed));
typedef union ia32_boot_params {
UINT8 raw[0x2000];
struct {
@ -155,7 +178,7 @@ typedef union ia32_boot_params {
/* EFI boot loader signature. */
/* 0x1C0 */ UINT8 efi_loader_sig[4]; /* LDR */
#define EFI_LOADER_SIG "EFIL"
#define EFI_LOADER_SIG_IA32 "EL32"
/* Address of the EFI system table. */
/* 0x1C4 */ UINT32 efi_sys_tbl; /* LDR */
@ -177,7 +200,9 @@ typedef union ia32_boot_params {
/* Available contiguous extended memory in KB. */
/* 0x1E0 */ UINT32 alt_mem_k; /* LDR */
/* 0x1E4 */ UINT8 unused_5[0x0D]; /* unused */
/* 0x1E4 */ UINT32 unused_51; /* unused */
/* 0x1E8 */ UINT8 e820_nrmap;
/* 0x1E9 */ UINT32 unused_52[2]; /* unused */
/* Size of setup code in sectors (1 sector == 512 bytes). */
/* 0x1F1 */ UINT8 setup_sectors; /* BLD */
@ -258,6 +283,8 @@ typedef union ia32_boot_params {
/* 0x226 */ UINT16 unused_7; /* LDR */
/* 0x228 */ UINT32 cmdline_addr; /* LDR */
/* 0x22C */ UINT32 unused_8[41];
/* 0x2D0 */ UINT8 e820_map[2560];
} s;
} boot_params_t;
#pragma pack()
@ -275,11 +302,17 @@ typedef union ia32_boot_params {
UINT8 *t = (UINT8 *)(to); \
UINT8 *f = (UINT8 *)(from); \
UINTN n = cnt; \
if (t && f && n) { \
while (n--) { \
*t++ = *f++; \
} \
} \
if (t && f && n && (t<f)) { \
while (n--) { \
*t++ = *f++; \
} \
} else if (t && f && n && (t>f)) { \
t += n; \
f += n; \
while (n--) { \
*t-- = *f--; \
} \
} \
}
#define MEMSET(ptr, size, val) { \
@ -314,6 +347,7 @@ extern UINTN kernel_size;
extern VOID *initrd_start;
extern UINTN initrd_size;
extern VOID *kernel_load_address;
extern dt_addr_t gdt_addr;
extern dt_addr_t idt_addr;
@ -333,19 +367,31 @@ extern INTN ia32_use_legacy_free_boot();
static inline void
start_kernel(VOID *kentry, boot_params_t *bp)
{
UINT32 temp;
/*
* Disable interrupts.
*/
asm volatile ( "cli" : : );
/*
* Relocate initrd, if present.
*/
/*
* Relocate kernel (if needed), and initrd (if present).
* Copy kernel first, in case kernel was loaded overlapping where we're
* planning to copy the initrd. This assumes that the initrd didn't
* get loaded overlapping where we're planning to copy the kernel, but
* that's pretty unlikely since we couldn't alloc that space for the
* kernel (or the kernel would already be there).
*/
if (kernel_start != kernel_load_address) {
MEMCPY(kernel_start, kernel_load_address, kernel_size);
}
if (bp->s.initrd_start) {
temp = bp->s.initrd_start;
MEMCPY(INITRD_START, temp , bp->s.initrd_size);
bp->s.initrd_start = INITRD_START;
}
if (bp->s.initrd_start) {
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
@ -354,6 +400,9 @@ start_kernel(VOID *kentry, boot_params_t *bp)
MEMCPY(high_base_mem, bp, 0x4000);
bp = (boot_params_t *)high_base_mem;
bp->s.cmdline_addr = high_base_mem + bp->s.cmdline_offset;
/*
* Initialize Linux GDT.
*/

View File

@ -97,7 +97,10 @@ UINTN high_base_mem = 0x90000;
UINTN high_ext_mem = 32 * 1024 * 1024;
/* This starting address will hold true for all of the loader types for now */
VOID *kernel_start = (VOID *)0x100000; /* 1M */
VOID *kernel_start = (VOID *)DEFAULT_KERNEL_START;
/* The kernel may load elsewhere if EFI firmware reserves kernel_start */
VOID *kernel_load_address = (VOID *)DEFAULT_KERNEL_START;
VOID *initrd_start = NULL;
UINTN initrd_size = 0;
@ -131,21 +134,27 @@ 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));
ERR_PRT((L"kd=" PTR_FMT " imem=" PTR_FMT, kd, imem));
return -1;
}
VERB_PRT(3, Print(L"kstart=0x%x kentry=0x%x kend=0x%x\n",
VERB_PRT(3, Print(L"kstart=" PTR_FMT " kentry=" PTR_FMT " kend=" PTR_FMT "\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",
VERB_PRT(3, Print(L"initrd start_addr=" PTR_FMT " pgcnt=%d\n",
imem->start_addr, imem->pgcnt));
return 0;
}
VOID *
sysdeps_checkfix_initrd(VOID *start_addr, memdesc_t *imem)
{
return start_addr;
}
VOID
sysdeps_free_boot_params(boot_params_t *bp)
{
@ -156,6 +165,277 @@ sysdeps_free_boot_params(boot_params_t *bp)
free_memmap(&md);
}
static VOID find_bits(unsigned long mask, UINT8 *first, UINT8* len) {
unsigned char bit_pos = 0, bit_len = 0;
*first =0;
*len = 0;
if (mask == 0)
return;
while (!(mask & 0x1)) {
mask = mask >> 1;
bit_pos++;
}
while (mask & 0x1) {
mask = mask >> 1;
bit_len++;
}
*first = bit_pos;
*len = bit_len;
}
/*
* Get video information.
*/
static INTN get_video_info(boot_params_t * bp) {
EFI_GUID GopProtocol = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop_interface;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Gop_info;
EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Gop_mode = NULL;
EFI_HANDLE *Gop_handle = NULL;
EFI_STATUS efi_status;
UINTN size = 0;
UINTN size1;
UINT8 i;
efi_status = uefi_call_wrapper(
BS->LocateHandle,
5,
ByProtocol,
&GopProtocol,
NULL,
&size,
(VOID **)Gop_handle);
if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) {
Print(L"EFI returned no GoP handle, No Graphics Output Device?\n");
Print(L"--Elilo will try to default to console text mode.\n");
return -1;
}
Gop_handle = alloc(size, 0);
efi_status = uefi_call_wrapper(
BS->LocateHandle,
5,
ByProtocol,
&GopProtocol,
NULL,
&size,
(VOID **)Gop_handle);
if (EFI_ERROR(efi_status)) {
ERR_PRT((L"LocateHandle GopProtocol failed."));
free(Gop_handle);
return -1;
}
for (i=0; i < size/sizeof(EFI_HANDLE); i++) {
Gop_handle += i;
efi_status = uefi_call_wrapper(
BS->HandleProtocol,
3,
*Gop_handle,
&GopProtocol,
(VOID **) &Gop_interface);
if (EFI_ERROR(efi_status)) {
continue;
}
Gop_mode = Gop_interface->Mode;
efi_status = uefi_call_wrapper(
Gop_interface->QueryMode,
4,
Gop_interface,
Gop_mode->Mode,
&size1,
&Gop_info);
if (!EFI_ERROR(efi_status))
break;
if (EFI_ERROR(efi_status)) {
continue;
}
}
if (EFI_ERROR(efi_status) || i > (size/sizeof(EFI_HANDLE))) {
ERR_PRT((L"HandleProtocol GopProtocol failed."));
free(Gop_handle);
return -1;
}
bp->s.is_vga = 0x70;
bp->s.orig_cursor_col = 0;
bp->s.orig_cursor_row = 0;
bp->s.orig_video_page = 0;
bp->s.orig_video_mode = 0;
bp->s.orig_video_cols = 0;
bp->s.orig_video_rows = 0;
bp->s.orig_ega_bx = 0;
bp->s.orig_video_points = 0;
bp->s.lfb_width = Gop_info->HorizontalResolution;
bp->s.lfb_height = Gop_info->VerticalResolution;
bp->s.lfb_base = Gop_mode->FrameBufferBase;
bp->s.lfb_size = Gop_mode->FrameBufferSize;
bp->s.lfb_pages = 1;
bp->s.vesa_seg = 0;
bp->s.vesa_off = 0;
if (Gop_info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
bp->s.lfb_depth = 32;
bp->s.lfb_red_size = 8;
bp->s.lfb_red_pos = 0;
bp->s.lfb_green_size = 8;
bp->s.lfb_green_pos = 8;
bp->s.lfb_blue_size = 8;
bp->s.lfb_blue_pos = 16;
bp->s.lfb_rsvd_size = 8;
bp->s.lfb_rsvd_pos = 24;
bp->s.lfb_line_len = Gop_info->PixelsPerScanLine * 4;
} else if (Gop_info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
bp->s.lfb_depth = 32;
bp->s.lfb_red_size = 8;
bp->s.lfb_red_pos = 16;
bp->s.lfb_green_size = 8;
bp->s.lfb_green_pos = 8;
bp->s.lfb_blue_size = 8;
bp->s.lfb_blue_pos = 0;
bp->s.lfb_rsvd_size = 8;
bp->s.lfb_rsvd_pos = 24;
bp->s.lfb_line_len = Gop_info->PixelsPerScanLine * 4;
} else if (Gop_info->PixelFormat == PixelBitMask) {
find_bits(Gop_info->PixelInformation.RedMask,
&bp->s.lfb_red_pos, &bp->s.lfb_red_size);
find_bits(Gop_info->PixelInformation.GreenMask,
&bp->s.lfb_green_pos, &bp->s.lfb_green_size);
find_bits(Gop_info->PixelInformation.BlueMask,
&bp->s.lfb_blue_pos, &bp->s.lfb_blue_size);
find_bits(Gop_info->PixelInformation.ReservedMask,
&bp->s.lfb_rsvd_pos, &bp->s.lfb_rsvd_size);
bp->s.lfb_depth = bp->s.lfb_red_size + bp->s.lfb_green_size +
bp->s.lfb_blue_size + bp->s.lfb_rsvd_size;
bp->s.lfb_line_len = (Gop_info->PixelsPerScanLine * bp->s.lfb_depth) / 8;
} else {
bp->s.lfb_depth = 4;
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_line_len = bp->s.lfb_width / 2;
}
return 0;
}
/* Convert EFI memory map to E820 map for the operating system
* This code is based on a Linux kernel patch submitted by Edgar Hucek
*/
/* Add a memory region to the e820 map */
static void add_memory_region (struct e820entry *e820_map,
int *e820_nr_map,
UINT64 start,
UINT64 size,
UINT32 type)
{
int x = *e820_nr_map;
if (x == E820_MAX) {
Print(L"Too many entries in the memory map!\n");
return;
}
if ((x > 0) && e820_map[x-1].addr + e820_map[x-1].size == start
&& e820_map[x-1].type == type)
e820_map[x-1].size += size;
else {
e820_map[x].addr = start;
e820_map[x].size = size;
e820_map[x].type = type;
(*e820_nr_map)++;
}
}
void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc)
{
int nr_map, e820_nr_map = 0, i;
UINT64 start, end, size;
EFI_MEMORY_DESCRIPTOR *md, *p;
struct e820entry *e820_map;
nr_map = mdesc->map_size/mdesc->desc_size;
e820_map = (struct e820entry *)bp->s.e820_map;
for (i = 0, p = mdesc->md; i < nr_map; i++)
{
md = p;
switch (md->Type) {
case EfiACPIReclaimMemory:
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_ACPI);
break;
case EfiRuntimeServicesCode:
case EfiRuntimeServicesData:
case EfiReservedMemoryType:
case EfiMemoryMappedIO:
case EfiMemoryMappedIOPortSpace:
case EfiUnusableMemory:
case EfiPalCode:
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_RESERVED);
break;
case EfiLoaderCode:
case EfiLoaderData:
case EfiBootServicesCode:
case EfiBootServicesData:
case EfiConventionalMemory:
start = md->PhysicalStart;
size = md->NumberOfPages << EFI_PAGE_SHIFT;
end = start + size;
/* Fix up for BIOS that claims RAM in 640K-1MB region */
if (start < 0x100000ULL && end > 0xA0000ULL) {
if (start < 0xA0000ULL) {
/* start < 640K
* set memory map from start to 640K
*/
add_memory_region(e820_map,
&e820_nr_map,
start,
0xA0000ULL-start,
E820_RAM);
}
if (end <= 0x100000ULL)
continue;
/* end > 1MB
* set memory map avoiding 640K to 1MB hole
*/
start = 0x100000ULL;
size = end - start;
}
add_memory_region(e820_map, &e820_nr_map,
start, size, E820_RAM);
break;
case EfiACPIMemoryNVS:
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_NVS);
break;
default:
/* We should not hit this case */
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_RESERVED);
break;
}
p = NextMemoryDescriptor(p, mdesc->desc_size);
}
bp->s.e820_nrmap = e820_nr_map;
}
/*
* IA-32 specific boot parameters initialization routine
*/
@ -177,7 +457,7 @@ sysdeps_create_boot_params(
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",
ERR_PRT((L"bp=" PTR_FMT " cmdline=" PTR_FMT " initrd=" PTR_FMT " cookie=" PTR_FMT,
bp, cmdline, initrd, cookie));
if (param_start != NULL) {
@ -197,9 +477,6 @@ sysdeps_create_boot_params(
*/
if (param_start != NULL) {
CopyMem(bp, param_start, 0x2000);
free(param_start);
param_start = NULL;
param_size = 0;
}
/*
* Save off our header revision information.
@ -213,9 +490,11 @@ sysdeps_create_boot_params(
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);
ZeroMem(&bp->s.unused_51, sizeof bp->s.unused_51);
ZeroMem(bp->s.unused_52, sizeof bp->s.unused_52);
bp->s.unused_6 = 0;
bp->s.unused_7 = 0;
ZeroMem(bp->s.unused_8, sizeof bp->s.unused_8);
/*
* Tell kernel this was loaded by an advanced loader type.
@ -262,7 +541,7 @@ sysdeps_create_boot_params(
* Initial RAMdisk and root device stuff.
*/
DBG_PRT((L"initrd->start_addr=0x%x initrd->pgcnt=%d\n",
DBG_PRT((L"initrd->start_addr=" PTR_FMT " initrd->pgcnt=%d\n",
initrd->start_addr, initrd->pgcnt));
/* These RAMdisk flags are not needed, just zero them. */
@ -310,7 +589,7 @@ sysdeps_create_boot_params(
/*
* EFI loader signature
*/
CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG, 4);
CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG_IA32, 4);
/*
* Kernel entry point.
@ -344,7 +623,7 @@ sysdeps_create_boot_params(
#define WAIT_FOR_KEY() \
{ \
EFI_INPUT_KEY key; \
while (ST->ConIn->ReadKeyStroke(ST->ConIn, &key) != EFI_SUCCESS) { \
while (uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &key) != EFI_SUCCESS) { \
; \
} \
}
@ -402,6 +681,7 @@ sysdeps_create_boot_params(
CHECK_OFFSET(loader_start, 0x1D8, L"%xh");
CHECK_OFFSET(loader_size, 0x1DC, L"%xh");
CHECK_OFFSET(alt_mem_k, 0x1E0, L"%xh");
CHECK_OFFSET(e820_nrmap, 0x1E8, L"%xh");
CHECK_OFFSET(setup_sectors, 0x1F1, L"%xh");
CHECK_OFFSET(mount_root_rdonly, 0x1F2, L"%xh");
CHECK_OFFSET(sys_size, 0x1F4, L"%xh");
@ -426,6 +706,7 @@ sysdeps_create_boot_params(
CHECK_OFFSET(bootsect_helper, 0x220, L"%xh");
CHECK_OFFSET(heap_end_ptr, 0x224, L"%xh");
CHECK_OFFSET(cmdline_addr, 0x228, L"%xh");
CHECK_OFFSET(e820_map, 0x2D0, L"'%-2560.2560a'");
if (test) {
ERR_PRT((L"Boot sector and/or setup parameter alignment error."));
@ -440,7 +721,11 @@ sysdeps_create_boot_params(
* in the fill routine gets accounted for.
*/
efi_status = ST->ConOut->QueryMode(
if (!get_video_info(bp)) goto do_memmap;
efi_status = uefi_call_wrapper(
ST->ConOut->QueryMode,
4,
ST->ConOut,
ST->ConOut->Mode->Mode,
&cols,
@ -488,6 +773,7 @@ sysdeps_create_boot_params(
bp->s.vesa_seg = 0;
bp->s.vesa_off = 0;
do_memmap:
/*
* Get memory map description and cookie for ExitBootServices()
*/
@ -503,6 +789,10 @@ sysdeps_create_boot_params(
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;
/* Now that we have EFI memory map, convert it to E820 map
* and update the bootparam accordingly
*/
fill_e820map(bp, &mdesc);
return 0;
}

View File

@ -23,10 +23,15 @@
# to use this program.
#
include ../Make.defaults
include ../Make.rules
SRCDIR = .
VPATH = $(SRCDIR)
include $(SRCDIR)/../Make.defaults
include $(SRCDIR)/../Make.rules
TOPDIR=$(SRCDIR)/..
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

View File

@ -132,7 +132,7 @@ check_fpswa(EFI_HANDLE image, EFI_HANDLE dev, CHAR16 *fpswa_file)
#endif
};
UINTN j, count = sizeof(fpswa_filenames)/sizeof(CHAR16 *);
INTN cookie;
UINTN cookie;
CHAR16 devname[FILENAME_MAXLEN];
if (fpswa_file) {

View File

@ -161,7 +161,7 @@ gzip_free(void *where)
int
fill_inbuf(void)
{
INTN expected, nread;
UINTN expected, nread;
EFI_STATUS status;
expected = nread = INBUFSIZE;
@ -170,7 +170,9 @@ fill_inbuf(void)
if (EFI_ERROR(status)) {
error("elilo: Read failed");
}
#ifdef DEBUG_GZIP
DBG_PRT((L"%s : read %d bytes of %d bytes\n", LD_NAME, nread, expected));
#endif
insize = nread;
inptr = 1;
@ -309,7 +311,7 @@ analyze_chunks(void)
* the relevant header information.
*/
int
first_block (const char *buf, long blocksize)
first_block (const unsigned char *buf, long blocksize)
{
Elf64_Ehdr *elf;
Elf64_Phdr *phdrs;
@ -439,7 +441,7 @@ first_block (const char *buf, long blocksize)
if (alloc_kmem((void *)low_addr, pages) == -1) {
VOID *new_addr;
VERB_PRT(1, (L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
VERB_PRT(1, Print(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"));
@ -464,7 +466,7 @@ first_block (const char *buf, long blocksize)
/* unsigned arithmetic */
load_offset = (UINTN) (new_addr - ROUNDDOWN((UINTN) low_addr,256*MB));
VERB_PRT(1, (L"low_addr=0x%lx new_addr=0x%lx offset=0x%lx", low_addr, new_addr, load_offset));
VERB_PRT(1, Print(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
@ -526,12 +528,13 @@ flush_window(void)
static const CHAR8 helicopter[4] = { '|' , '/' , '-' , '\\' };
static UINTN heli_count;
struct segment *cp;
char *src, *dst;
unsigned char *src, *dst;
long cnt;
if (!outcnt) return;
#ifdef DEBUG_GZIP
DBG_PRT((L"%s : flush_window outnct=%d file_offset=%ld\n", LD_NAME, outcnt, file_offset));
#endif
Print(L"%c\b",helicopter[heli_count++%4]);
@ -565,7 +568,7 @@ tail:
file_offset += skip;
outcnt -= skip;
}
dst = (char *)cp->addr + (file_offset - cp->offset);
dst = (unsigned char *)cp->addr + (file_offset - cp->offset);
cnt = cp->offset + cp->size - file_offset;
@ -582,7 +585,7 @@ tail:
/* 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;
dst = (unsigned char *)cp->addr + cp->size;
Memset(dst, 0, cp->bss_sz);
}
nextchunk();

View File

@ -159,4 +159,4 @@ longjmp:
invala // virt. -> phys. regnum mapping may change
mov pr=r24,-1
br.ret.dptk.few rp
.endp __longjmp
.endp longjmp

View File

@ -288,7 +288,7 @@ load_elf(fops_fd_t fd, kdesc_t *kd)
if (alloc_kmem(low_addr, pages) == -1) {
VOID *new_addr;
VERB_PRT(1, (L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
VERB_PRT(1, Print(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"));

View File

@ -81,6 +81,7 @@ setjmp:
.proc __sigsetjmp
__sigsetjmp:
//.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
.body
alloc loc1=ar.pfs,2,2,2,0
mov r16=ar.unat
;;
@ -89,6 +90,7 @@ __sigsetjmp:
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
@ -96,13 +98,13 @@ __sigsetjmp:
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
@ -139,6 +141,7 @@ __sigsetjmp:
stf.spill.nta [r9]=f31
st8.spill.nta [r2]=r6,16 // r6
;;
st8.spill.nta [r3]=r7,16 // r7
;;
mov r23=ar.bsp

View File

@ -86,7 +86,7 @@ start_kernel(VOID *kentry, VOID *bp)
asm volatile ("mov r28=%1; br.sptk.few %0" :: "b"(kentry),"r"(bp));
}
static inline const UINT64
static inline UINT64
__ia64_swab64 (UINT64 x)
{
UINT64 result;
@ -95,13 +95,13 @@ __ia64_swab64 (UINT64 x)
return result;
}
static inline const UINT32
static inline UINT32
__ia64_swab32 (UINT32 x)
{
return __ia64_swab64(x) >> 32;
}
static inline const UINT16
static inline UINT16
__ia64_swab16(UINT16 x)
{
return __ia64_swab64(x) >> 48;

View File

@ -55,7 +55,7 @@ sysdeps_create_boot_params(boot_params_t *bp, CHAR8 *cmdline, memdesc_t *initrd,
if (get_memmap(&mdesc) == -1) return -1;
DBG_PRT((L"Got memory map @ 0x%lx (%d bytes)", mdesc.md, mdesc.map_size));
DBG_PRT((L"Got memory map @ 0x%lx (%d bytes) with key %d", mdesc.md, mdesc.map_size, mdesc.cookie));
bp->efi_systab = (UINTN)systab;
bp->efi_memmap = (UINTN)mdesc.md;
@ -140,6 +140,12 @@ sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem)
return 0;
}
VOID *
sysdeps_checkfix_initrd(VOID *start_addr, memdesc_t *imem)
{
return start_addr;
}
/* Flush data cache [addr; addr + len], and sync with icache. */
void
flush_dcache (CHAR8 *addr, UINT64 len)
@ -147,7 +153,7 @@ flush_dcache (CHAR8 *addr, UINT64 len)
/* Cache line length is at least 32. */
UINT64 a = (UINT64)addr & ~0x1f;
VERB_PRT(3, Print(L"Flush 0x%lx-", a));
DBG_PRT((L"Flush 0x%lx-", a));
/* Flush data. */
for (len = (len + 31) & ~0x1f; len > 0; len -= 0x20, a += 0x20)
@ -155,5 +161,5 @@ flush_dcache (CHAR8 *addr, UINT64 len)
/* Sync and serialize. Maybe extra. */
asm volatile (";; sync.i;; srlz.i;;");
VERB_PRT(3, Print(L"0x%lx\n", a));
DBG_PRT((L"0x%lx\n", a));
}

View File

@ -1094,10 +1094,10 @@ static int gunzip(void)
error("Input has invalid flags\n");
return -1;
}
(ulg)get_byte(); /* Get timestamp */
((ulg)get_byte()) << 8;
((ulg)get_byte()) << 16;
((ulg)get_byte()) << 24;
(void)get_byte(); /* Get timestamp - 4 bytes */
(void)get_byte();
(void)get_byte();
(void)get_byte();
(void)get_byte(); /* Ignore extra flags for the moment */
(void)get_byte(); /* Ignore OS type for the moment */

View File

@ -41,6 +41,10 @@ INTN
load_file(CHAR16 *filename, memdesc_t *image)
{
EFI_STATUS status;
/*
* Actually using the value from sysdeps_initrd_get_addr()
* instead of NULL is no change for ia64!
*/
VOID *start_addr = image->start_addr;
UINTN pgcnt;
UINT64 size = 0;
@ -71,15 +75,19 @@ load_file(CHAR16 *filename, memdesc_t *image)
/* round up to get required number of pages (4KB) */
image->pgcnt = pgcnt = EFI_SIZE_TO_PAGES(image->size);
start_addr = alloc_pages(pgcnt, EfiLoaderData, start_addr ? AllocateAddress : AllocateAnyPages, start_addr);
start_addr = alloc_pages(pgcnt, EfiLoaderData,
start_addr ? AllocateAddress : AllocateAnyPages, start_addr);
start_addr = sysdeps_checkfix_initrd(start_addr, image);
if (start_addr == NULL) {
ERR_PRT((L"Failed to allocate %d pages for %s image", pgcnt,
filename));
goto error;
}
VERB_PRT(2, Print(L"%s image: total_size: %ld bytes base: 0x%lx "
VERB_PRT(2, Print(L"%s image: total_size: %d bytes base: " PTR_FMT " "
"pages %d\n", filename, image->size,
(UINTN)start_addr, pgcnt));
start_addr, pgcnt));
Print(L"Loading file %s...", filename);

View File

@ -38,12 +38,18 @@ loader_ops_t *
loader_probe(CHAR16 *kname)
{
loader_ops_t *ops;
UINTN n = 0;
for (ops= ldops_list; ops; ops = ops->next) {
n++;
VERB_PRT(3, Print(L"Probing loader: %s\n", ops->ld_name));
if (ops->ld_probe(kname) == 0) {
return ops;
}
}
if (!n) {
ERR_PRT((L"No loaders registered"));
}
return NULL;
}

119
release.notes Normal file
View File

@ -0,0 +1,119 @@
3 . 1 6 R E L E A S E N O T E S
===================================
QUICK CHANGE SUMMARY
====================
* Adds native x86x crossbuild functionality
build 32bit or 64bit versions from either environment via
make ARCH=ia32|x86_64 (the ARCH IS case sensitive).
make by itself will default to the native host arch.
* Add console reset call during initialization. thanks A. Steinmetz
* simplify output of no GOP warning text so it no longer looks like an error.
* MAJOR: Fixed Fault crash when EFI memory map changes from under elilo.
(from an outside interrupt in this case). When the EFI Memory map
changes after elilo has already built boot params to pass to the
kernel the EFI call to ExitBootSvcs just prior to boot will fail
because elilo has the old map key. This is valid EFI behavior, elilo
retries to pick up the new memory map and key but had already freed
the start params portion of boot params resulting in a NULL DEREF
crash reset once it hands the now bogus boot params to the kernel on
the 2nd successful call to exit efi and boot.
Thanks to Jerry Hoemann @ HP for reporting this bug.
* minor bugfix, fixed -m option broken. thanks Allan-lsk.
BUILD NOTES
====================
You will need the following toolchain to build elilo-3.14 from source
the elilo build environment is optimized for Debian and Debian based distros.
elilo-3.16 was built in the squeeze+(ubuntu 11.x) build environments except
for itanium which is unchanged to best support legacy enterprise configs.
Toolchain versions for this release were:
x86x(32 & 64bit versions)
* gnu-efi --> 3.0i-3
* gcc ------> 4:4.4.4-1ubuntu2
* binutils -> 2.20.51.20100908-0ubuntu2
ia64
* gnu-efi --> 3.0e-2
* gcc ------> 4.3.2-2
* binutils -> 2.18.1~cvs20080103-7
* if you use a debian based build environment you will have no problems
and setting it up is simple. you will be able to build elilo in 3 steps:
1. apt-get install gnu-efi, gcc, binutils
2. apt-get source elilo (or download elilo-3.16 source from SourceForge.)
3. extract source tarball and cd to ./$your-elilo-source and type $> make
** If you use the upstream toolchain tarballs(i.e. pre distro) you will need
to move some files around for elilo build to work.
GNU-EFI (provides the efi 1.10 and uefi 2.x libraries & api)
-------
gnu-efi libraries are installed to /usr/local/lib by the
upstream gnu-efi source package. elilo expects them to be in system location
/usr/lib. efi includes may be located in /usr/local/include/efi. elilo
expects them to be in system location /usr/include/efi.
[ The reason is LSB compliance ].
BINUTILS (provides the elf conversion utility to produce efi bins)
--------
binutils provides objcopy which is installed to /usr/local/bin by binutils,
elilo source expects it to be in /usr/bin.
again this LSB compliance is taken care of by the distro's that fix
the toolchains to install to the correct compliant system locations
instead of the "user optional" location.
ELILO ON EFI X86_64
=====================
HARD REQUIREMENTS
EFI + x86_64 REQUIRES an efi64 enabled linux kernel i.e. 2.6.21 or newer
nothing earlier will work, 2.6.21 was the earliest kernel that efi64
support went into. You need to compile the kernel with CONFIG_EFI
kernel option ON.
x86_64 platforms with UEFI 2.0 firmware deprecate UGA protocol
and therefore only the Graphics Output Protocol (GOP) is supported. For
such platforms, the kernel must be compiled with EFI_FB option ON. This
will enable early boot messages on the console. Elilo for x86_64
attempts to query EFI for GOP support and if it fails it defaults to
text mode which may or may not show you early console ouput depends on
your efi console settings and physical setup. Elilo has no way to know
if your console settings are messed up.
WORKING ELILO.CONF FOR EFI X86_64 EXAMPLE
Here is my elilo.conf from my UEFI2.0/x86_64 (with nvidia pcie add on
card, i.e. your vga= kernel param may be different) workstation which uses GOP.
Here is a partial kernel vga table I was able to find and add here.
Colours 640x400 640x480 800x600 1024x768 1152x864 1280x1024 1600x1200
-------+--------------------------------------------------------------
4 bits | ? ? 0x302 ? ? ? ?
8 bits | 0x300 0x301 0x303 0x305 0x161 0x307 0x31C
15 bits | ? 0x310 0x313 0x316 0x162 0x319 0x31D
16 bits | ? 0x311 0x314 0x317 0x163 0x31A 0x31E
decimal | d785 d788 d791
24 bits | ? 0x312 0x315 0x318 ? 0x31B 0x31F
Additionally from ...kernel-source/Documentation/Boot.txt...
vga=<mode>
<mode> here is either an integer (in C notation, either
decimal, octal, or hexadecimal) or one of the strings
"normal" (meaning 0xFFFF), "ext" (meaning 0xFFFE) or "ask"
(meaning 0xFFFD). This value should be entered into the
vid_mode field, as it is used by the kernel before the command
line is parsed.
example below shows me console output, what elilo is doing, and kernel boot.
vga=normal with efi console input output directed to graphics card should
work as well.
default=UBUNTU
chooser=simple
verbose=5
delay=30
append="root=/dev/sda3 vga=0x31e splash showopts"
image=/vmlinuz-2.6.32-27-generic
label="UBUNTU"
description="Ubuntu 2.6.32-27-generic kernel"
initrd=/initrd.img-2.6.32-27-generic

View File

@ -41,11 +41,11 @@ StrnCpy(OUT CHAR16 *dst, IN const CHAR16 *src, IN UINTN size)
{
CHAR16 *res = dst;
while (size-- && (*dst++ = *src++) != CHAR_NULL);
while (size && size-- && (*dst++ = *src++) != CHAR_NULL);
/*
* does the null padding
*/
while (size-- > 0) *dst++ = CHAR_NULL;
while (size && size-- > 0) *dst++ = CHAR_NULL;
return res;
}
@ -55,11 +55,11 @@ StrnXCpy(OUT CHAR8 *dst, IN const CHAR16 *src, IN UINTN size)
{
CHAR8 *res = dst;
while (size-- && (*dst++ = (CHAR8)*src++) != '\0');
while (size && size-- && (*dst++ = (CHAR8)*src++) != '\0');
/*
* does the null padding
*/
while (size-- > 0) *dst++ = '\0';
while (size && size-- > 0) *dst++ = '\0';
return res;
}
@ -76,11 +76,11 @@ strncpya(OUT CHAR8 *dst, IN const CHAR8 *src, IN UINTN size)
{
CHAR8 *res = dst;
while (size-- && (*dst++ = *src++) != '\0');
while (size && size-- && (*dst++ = *src++) != '\0');
/*
* does the null padding
*/
while (size-- > 0) *dst++ = '\0';
while (size && size-- > 0) *dst++ = '\0';
return res;
}

View File

@ -1,6 +1,10 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
* Copyright (C) 2006-2009 Intel Corporation
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.intel.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
@ -30,6 +34,8 @@
#include "ia64/sysdeps.h"
#elif defined CONFIG_ia32
#include "ia32/sysdeps.h"
#elif defined CONFIG_x86_64
#include "x86_64/sysdeps.h"
#endif
#endif /* __ELILO_SYSDEPS_H__ */

View File

@ -23,10 +23,15 @@
# to use this program.
#
include ../Make.defaults
include ../Make.rules
SRCDIR = .
VPATH = $(SRCDIR)
include $(SRCDIR)/../Make.defaults
include $(SRCDIR)/../Make.rules
TOPDIR=$(SRCDIR)/..
TOPDIR=$(CDIR)/..
FILES=eliloalt.o
TARGET=eliloalt

View File

@ -47,8 +47,10 @@
#define ELILOALT_VERSION "0.02"
#define ELILO_ALT_NAME "EliloAlt"
#define EFIVAR_DIR "/proc/efi/vars"
#define EFIVAR_DIR "/sys/firmware/efi/vars"
#define OFIVAR_DIR "/proc/efi/vars"
#define ELILO_ALTVAR EFIVAR_DIR"/"ELILO_ALT_NAME"-00000000-0000-0000-0000-000000000000"
#define OLILO_ALTVAR OFIVAR_DIR"/"ELILO_ALT_NAME"-00000000-0000-0000-0000-000000000000"
#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001
#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
@ -80,7 +82,9 @@ typedef struct _efi_variable_t {
uint32_t attributes;
} __attribute__((packed)) efi_variable_t;
static char *efivar_dir = EFIVAR_DIR;
static char *elilo_alt_name = ELILO_ALT_NAME;
static char *elilo_altvar = ELILO_ALTVAR;
static struct option cmd_options[]={
{ "version", 0, 0, 1},
@ -129,9 +133,15 @@ check_proc_efi(int find_entry)
if (getuid() != 0) {
fatal_error("This program must be run as root\n");
}
efi_vars = opendir(EFIVAR_DIR);
efi_vars = opendir(efivar_dir);
if (efi_vars == NULL) {
fatal_error("Cannot access %s\n", EFIVAR_DIR);
efivar_dir = OFIVAR_DIR;
elilo_altvar = OLILO_ALTVAR;
efi_vars = opendir(efivar_dir);
}
if (efi_vars == NULL) {
fatal_error("Can access neither %s nor %s\n",
EFIVAR_DIR, efivar_dir);
}
if (!find_entry) {
closedir(efi_vars);
@ -143,9 +153,10 @@ check_proc_efi(int find_entry)
break;
}
if (entry == NULL) {
fatal_error("Cannot find entry in %s\n", EFIVAR_DIR);
fatal_error("Cannot find entry in %s\n", efivar_dir);
}
sprintf(name, "%s/%s", EFIVAR_DIR, entry->d_name);
snprintf(name, 1023, "%s/%s", efivar_dir, entry->d_name);
name[1023] = 0;
closedir(efi_vars);
return name;
}
@ -158,7 +169,7 @@ delete_var(void)
check_proc_efi(0);
fd = open(ELILO_ALTVAR, O_WRONLY);
fd = open(elilo_altvar, O_WRONLY);
if (fd == -1) {
fatal_error("variable not defined\n");
}
@ -176,7 +187,7 @@ delete_var(void)
r = write(fd, &var, sizeof(var));
if (r != sizeof(var)) {
fatal_error("Variable %s defined but invalid content\n", ELILO_ALTVAR);
fatal_error("Variable %s defined but invalid content\n", elilo_altvar);
}
close(fd);
}
@ -191,7 +202,7 @@ print_var(void)
check_proc_efi(0);
fd = open(ELILO_ALTVAR, O_RDONLY);
fd = open(elilo_altvar, O_RDONLY);
if (fd == -1) {
fatal_error("variable not defined\n");
}
@ -200,7 +211,7 @@ print_var(void)
r = read(fd, &var, sizeof(var));
if (r != sizeof(var)) {
fatal_error("Variable %s defined but invalid content\n", ELILO_ALTVAR);
fatal_error("Variable %s defined but invalid content\n", elilo_altvar);
}
printf("EliloAlt=\"");
for(i=0; i < var.datasize; i+=1){
@ -231,7 +242,7 @@ set_var(char *cmdline)
fd = open(name, O_WRONLY);
if (fd == -1) {
fatal_error("can't open %s: %s\n", ELILO_ALTVAR, strerror(errno));
fatal_error("can't open %s: %s\n", elilo_altvar, strerror(errno));
}
memset(&var, 0, sizeof(var));
@ -256,7 +267,7 @@ set_var(char *cmdline)
r = write(fd, &var, sizeof(var));
if (r != sizeof(var)) {
fatal_error("Variable %s defined but invalid content %d\n", ELILO_ALTVAR, r);
fatal_error("Variable %s defined but invalid content %d\n", elilo_altvar, r);
}
close(fd);

40
util.c
View File

@ -5,6 +5,11 @@
* Copyright (C) 2001 Silicon Graphics, Inc.
* Contributed by Brent Casavant <bcasavan@sgi.com>
*
* Copyright (C) 2006-2009 Intel Corporation
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.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
@ -40,7 +45,10 @@
static INTN
read_keypress(EFI_INPUT_KEY *key)
{
return systab->ConIn->ReadKeyStroke(systab->ConIn, key);
return uefi_call_wrapper(systab->ConIn->ReadKeyStroke,
2,
systab->ConIn,
key);
}
@ -55,7 +63,10 @@ check_abort(VOID)
inline VOID
reset_input(VOID)
{
systab->ConIn->Reset(systab->ConIn, 1);
uefi_call_wrapper(systab->ConIn->Reset,
2,
systab->ConIn,
1);
}
#if 0
@ -71,9 +82,9 @@ wait_keypress_abort(VOID)
Print(L"Hit ENTER to continue or ANY other key to cancel");
/* cleanup buffer first */
while (conin->ReadKeyStroke(conin, &key) == EFI_SUCCESS);
while (uefi_call_wrapper(conin->ReadKeyStroke, 2, conin, &key) == EFI_SUCCESS);
while ((status=conin->ReadKeyStroke(conin, &key)) == EFI_NOT_READY );
while ((status=uefi_call_wrapper(conin->ReadKeyStroke,2, conin, &key)) == EFI_NOT_READY );
if (EFI_ERROR(status)) return ELILO_LOAD_ERROR;
@ -102,13 +113,13 @@ wait_timeout(UINTN timeout)
if (timeout == 0) return 0;
/* Create a timeout timer */
status = BS->CreateEvent(EVT_TIMER, 0, NULL, NULL, &timer);
status = uefi_call_wrapper(BS->CreateEvent, 5, 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);
status = uefi_call_wrapper(BS->SetTimer, 3, timer, TimerPeriodic, TENTH_SEC);
if (EFI_ERROR(status)) {
ERR_PRT((L"waitkey SetTimer failed %r", status));
return -1;
@ -118,25 +129,27 @@ wait_timeout(UINTN timeout)
list[1] = systab->ConIn->WaitForKey;
do {
status = BS->WaitForEvent(2, list, &idx);
status = uefi_call_wrapper(BS->WaitForEvent, 3, 2, list, &idx);
if (EFI_ERROR(status)) {
ERR_PRT((L"waitkey WaitForEvent failed %r", status));
return -1;
}
if (timeout % 10 == 1) Print(L".");
} while (timeout-- && idx == 0);
Print(L"\n");
/*
* 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);
status = uefi_call_wrapper(BS->SetTimer, 3, timer, TimerCancel, 0);
if (EFI_ERROR(status)) {
ERR_PRT((L"waitkey SetTimer(TimerCancel) failed %r", status));
return -1;
}
BS->CloseEvent(timer);
uefi_call_wrapper(BS->CloseEvent, 1, timer);
return idx ? 1 : 0;
}
@ -237,7 +250,7 @@ split_args(CHAR16 *buffer, CHAR16 *kname, CHAR16 *args)
INTN
read_file(UINTN fd, UINTN total_size, CHAR8 *buffer)
{
INTN size, j=0;
UINTN size, j=0;
EFI_STATUS status;
CHAR16 helicopter[4] = { L'|' , L'/' , L'-' , L'\\' };
INTN ret = ELILO_LOAD_SUCCESS;
@ -278,7 +291,7 @@ read_file(UINTN fd, UINTN total_size, CHAR8 *buffer)
INTN
get_memmap(mmap_desc_t *desc)
{
#define ELILO_MEMMAP_SIZE_DEFAULT EFI_PAGE_SIZE
#define ELILO_MEMMAP_SIZE_DEFAULT (EFI_PAGE_SIZE*2)
#define ELILO_MEMMAP_INC (sizeof(EFI_MEMORY_DESCRIPTOR)<<1)
EFI_STATUS status;
@ -292,7 +305,8 @@ get_memmap(mmap_desc_t *desc)
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);
status = uefi_call_wrapper(BS->GetMemoryMap, 5, &desc->map_size, desc->md,
&desc->cookie, &desc->desc_size, &desc->desc_version);
if (status == EFI_SUCCESS) break;
free(desc->md);
@ -303,7 +317,7 @@ get_memmap(mmap_desc_t *desc)
}
desc->map_size += ELILO_MEMMAP_INC;
}
DBG_PRT((L"final get_memmap map_size=%ld", desc->map_size));
DBG_PRT((L"final get_memmap map_size=%d", desc->map_size));
return 0;
}

57
x86_64/Makefile Normal file
View File

@ -0,0 +1,57 @@
#
# 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.
#
SRCDIR = .
VPATH = $(SRCDIR)
include $(SRCDIR)/../Make.defaults
include $(SRCDIR)/../Make.rules
TOPDIR=$(SRCDIR)/..
FILES=system.o config.o bzimage.o plain_loader.o gzip_loader.o gzip.o
#FILES=system.o config.o plain_loader.o
TARGET=sysdeps.o
all: $(TARGET)
system.o: rmswitch.h
rmswitch.h: bin_to_h.c rmswitch.S
$(CC) -o bin_to_h $(SRCDIR)/bin_to_h.c
$(AS) -o rmswitch.o $(SRCDIR)/rmswitch.S
$(LD) -Ttext 0x0 -s --oformat binary -o rmswitch rmswitch.o
./bin_to_h <rmswitch >rmswitch.h
$(TARGET): $(FILES)
$(LD) $(LD3264) -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
x86_64/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;
}

352
x86_64/bzimage.c Normal file
View File

@ -0,0 +1,352 @@
/*
* 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.
*/
#include <efi.h>
#include <efilib.h>
#include "elilo.h"
#include "loader.h"
boot_params_t *param_start = NULL;
UINTN param_size = 0;
UINTN kernel_size = 0x800000; /* 8M (default x86_64 bzImage size limit) */
static VOID *
bzImage_alloc()
{
UINTN pages = EFI_SIZE_TO_PAGES(kernel_size);
int reloc_kernel = 0;
VOID *kla, *kend = kernel_start + kernel_size;
UINT32 kalign, kmask;
boot_params_t *ps = param_start;
/*
* Get address for kernel from header, if applicable & available.
*/
if ((ps->s.hdr_major < 2) ||
(ps->s.hdr_major == 2 && ps->s.hdr_minor < 5)) {
reloc_kernel = 0;
} else {
if (ps->s.kernel_start >= DEFAULT_KERNEL_START)
kernel_start = (void *)(UINT64)ps->s.kernel_start;
reloc_kernel = ps->s.relocatable_kernel;
kalign = ps->s.kernel_alignment;
kmask = kalign - 1;
VERB_PRT(3, Print(L"kernel header (%d.%d) suggests kernel "
"start at address "PTR_FMT" (%srelocatable!)\n",
ps->s.hdr_major, ps->s.hdr_minor, ps->s.kernel_start,
(reloc_kernel ? L"": L"not ")));
}
/*
* Best effort for old (< 2.6.20) and non-relocatable kernels
*/
if (alloc_kmem(kernel_start, pages) == 0) {
VERB_PRT(3, Print(L"kernel_start: "PTR_FMT" kernel_size: %d\n",
kernel_start, kernel_size));
return kernel_start;
} else if ( ! reloc_kernel ) {
/*
* Couldn't get desired address--just load it anywhere and
* (try to) move it later. It's the only chance for non-
* relocatable kernels, but it breaks occassionally...
*/
ERR_PRT((L"Kernel header (%d.%d) suggests kernel "
"start at address "PTR_FMT" (non relocatable!)\n"
"This address is not available, so an attempt"
"is made to copy the kernel there later on\n"
"BEWARE: this is unsupported and may not work. "
"Please update your kernel.\n",
ps->s.hdr_major, ps->s.hdr_minor, ps->s.kernel_start));
kla = (VOID *)(UINT32_MAX - kernel_size);
/* NULL would preserve the "anywhere" semantic, */
/* but it would not prevent allocation above 4GB! */
if (alloc_kmem_anywhere(&kla, pages) != 0) {
/* out of luck */
return NULL;
}
VERB_PRT(3, Print(L"kernel_start: "PTR_FMT
" kernel_size: %d loading at: "PTR_FMT"\n",
kernel_start, kernel_size, kla));
return kla;
}
/* Is 'ps->s.kernel_alignment' guaranteed to be sane? */
if (kalign < EFI_PAGE_SIZE) {
kalign = EFI_PAGE_SIZE;
kmask = EFI_PAGE_MASK;
}
DBG_PRT((L"alignment: kernel=0x%x efi_page=0x%x : 0x%x\n",
ps->s.kernel_alignment, EFI_PAGE_SIZE, kalign));
/*
* Couldn't get the preferred address, but luckily it's
* a relocatable kernel, so ...
*
* 1. use 'find_kernel_memory()' (like Itanium)
* 2. try out the 16 lowest possible aligned addresses (> 0)
* 3. get enough memory to align "creatively"
* 4. forget alignment (and start praying)...
*/
/* 1. */
if ((find_kernel_memory(kernel_start, kend, kalign, &kla) != 0) ||
(alloc_kmem(kla, pages) != 0)) {
kla = NULL;
}
/* 2. */
if ( ! kla && (UINT64)kernel_start < kalign ) {
int i;
for ( i = 1; i < 16 && !kla; i++ ) {
VOID *tmp = (VOID *)((UINT64)kalign * i);
if (alloc_kmem(tmp, pages) == 0) {
kla = tmp;
}
}
}
/* 3. */
if ( ! kla ) {
UINTN apages = EFI_SIZE_TO_PAGES(kernel_size + kmask);
kla = (VOID *)(UINT32_MAX - kernel_size - kmask);
if (alloc_kmem_anywhere(&kla, apages) == 0) {
kla = (VOID *)(((UINT64)kla + kmask) & ~kmask);
} else {
kla = NULL;
}
}
/* 4. last resort */
if ( ! kla ) {
kla = (VOID *)(UINT32_MAX - kernel_size);
if (alloc_kmem_anywhere(&kla, pages) != 0) {
return NULL;
}
}
kernel_start = kla;
VERB_PRT(1, Print(L"relocating kernel_start: "PTR_FMT
" kernel_size: %d\n", kernel_start, kernel_size));
return kla;
}
static INTN
bzImage_probe(CHAR16 *kname)
{
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, 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.
*/
kernel_load_address = bzImage_alloc();
if ( ! kernel_load_address ) {
ERR_PRT((L"Could not allocate memory for kernel."));
free(param_start);
param_start = NULL;
param_size = 0;
fops_close(fd);
return -1;
}
/*
* Now read the rest of the kernel image into memory.
*/
Print(L"Loading kernel %s... ", kname);
size = kernel_size;
efi_status = fops_read(fd, kernel_load_address, &size);
if (EFI_ERROR(efi_status) || size < 0x10000) {
ERR_PRT((L"Error reading kernel image (0x%x).", efi_status));
free(param_start);
param_start = NULL;
param_size = 0;
fops_close(fd);
free_kmem();
return -1;
} else {
Print(L" done\n");
}
DBG_PRT((L"kernel image read: %d bytes, %d Kbytes\n", size, size / 1024));
/*
* Boot sector, setup data and kernel image loaded.
*/
fops_close(fd);
return 0;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static INTN
bzImage_load(CHAR16 *kname, kdesc_t *kd)
{
DBG_PRT((L"load_bzImage_boot()\n"));
if (!kname || !kd) {
ERR_PRT((L"kname="PTR_FMT" kd="PTR_FMT"", 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="PTR_FMT" kentry="PTR_FMT" kend="PTR_FMT"\n", kd->kstart, kd->kentry, kd->kend));
return 0;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
loader_ops_t bzimage_loader = {
NULL,
L"bzImage_loader",
&bzImage_probe,
&bzImage_load
};

115
x86_64/config.c Normal file
View File

@ -0,0 +1,115 @@
/*
* 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;
UINTN text_mode;
} x86_64_global_config_t;
#define x86_64_opt_offsetof(option) (&((sys_img_options_t *)(0x0))->option)
static x86_64_global_config_t x86_64_gconf;
static config_option_t sysdeps_global_options[]={
{OPT_BOOL, OPT_GLOBAL, L"legacy-free", NULL, NULL, &x86_64_gconf.legacy_free_boot}
};
static config_option_t sysdeps_image_options[]={
{OPT_BOOL, OPT_IMAGE_SYS, L"text-mode", NULL, NULL, x86_64_opt_offsetof(text_mode)}
};
/*
* X86_64 operations that need to be done only once and just before
* entering the main loop of the loader
* 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 X86_64_CMDLINE_OPTIONS L""
CHAR16 *
sysdeps_get_cmdline_opts(VOID)
{
return X86_64_CMDLINE_OPTIONS;
}
INTN
sysdeps_getopt(INTN c, INTN optind, CHAR16 *optarg)
{
return -1;
}
VOID
sysdeps_print_cmdline_opts(VOID)
{
}
INTN
x86_64_use_legacy_free_boot(VOID)
{
return x86_64_gconf.legacy_free_boot ? 1 : 0;
}
INTN
x86_64_text_mode(VOID)
{
return (elilo_opt.sys_img_opts &&
elilo_opt.sys_img_opts->text_mode == TRUE) ? 1 : 0;
}
INTN
sysdeps_register_options(VOID)
{
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;
}

560
x86_64/gzip.c Normal file
View File

@ -0,0 +1,560 @@
/*
* Copyright (C) 2001-2002 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* Copyright (C) 2001 Silicon Graphics, Inc.
* Contributed by Brent Casavant <bcasavan@sgi.com>
*
* Copyright (C) 2006-2009 Intel Corporation
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.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 "elf.h"
#include "elilo.h"
#include "gzip.h"
#include "private.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 int error_return;
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)
{
UINTN expected, nread;
EFI_STATUS status;
expected = nread = INBUFSIZE;
status = fops_read(input_fd, inbuf, &nread);
if (EFI_ERROR(status)) {
error("elilo: Read failed");
}
#ifdef DEBUG_GZIP
DBG_PRT((L"%s : read %d bytes of %d bytes\n", LD_NAME, nread, expected));
#endif
insize = nread;
inptr = 1;
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 INTN
is_valid_header(Elf64_Ehdr *ehdr)
{
UINT16 type, machine;
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_X86_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 unsigned char *buf, long blocksize)
{
Elf64_Ehdr *elf;
Elf64_Phdr *phdrs;
UINTN total_size, pages;
UINTN low_addr, max_addr;
UINTN offs = 0;
UINT16 phnum;
UINTN paddr, memsz;
INTN i;
elf = (Elf64_Ehdr *)buf;
if (is_valid_header(elf) == -1)
return -1;
offs = elf->e_phoff;
phnum = elf->e_phnum;
VERB_PRT(3, {
Print(L"Entry point 0x%lx\n", elf->e_entry);
Print(L"%d program headers\n", phnum);
Print(L"%d segment headers\n", elf->e_shnum);
});
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 *)(elf->e_entry & PADDR_MASK);
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 = (phdrs[i].p_paddr & PADDR_MASK);
memsz = phdrs[i].p_memsz,
chunks[i].addr = paddr;
chunks[i].offset = phdrs[i].p_offset;
chunks[i].size = phdrs[i].p_filesz;
chunks[i].bss_sz = phdrs[i].p_memsz - phdrs[i].p_filesz;
CHUNK_VALIDATE(i);
if (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+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) {
ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n",
LD_NAME, pages, low_addr));
ERR_PRT((L"%s : Could not load kernel at 0x%lx\n", LD_NAME, low_addr));
ERR_PRT((L"%s : Bailing\n", LD_NAME));
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;
unsigned char *src, *dst;
long cnt;
if (!outcnt) return;
#ifdef DEBUG_GZIP
DBG_PRT((L"%s : flush_window outnct=%d file_offset=%ld\n", LD_NAME, outcnt, file_offset));
#endif
Print(L"%c\b",helicopter[heli_count++%4]);
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 = (unsigned 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 = (unsigned 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;
}
static void
error(char *x)
{
ERR_PRT((L"%s : %a", LD_NAME, x));
/* will eventually exit with error from gunzip() */
}
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;
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;
}

40
x86_64/gzip.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2001-2002 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* Copyright (C) 2006-2009 Intel Corporation
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.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.
*/
#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_x86_64"
#endif /* __GZIP_H__ */

83
x86_64/gzip_loader.c Normal file
View File

@ -0,0 +1,83 @@
/*
* Copyright (C) 2001-2002 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
* Copyright (C) 2006-2009 Intel Corporation
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.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 "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
};

1205
x86_64/inflate.c Normal file

File diff suppressed because it is too large Load Diff

302
x86_64/plain_loader.c Normal file
View File

@ -0,0 +1,302 @@
/*
* Copyright (C) 2001-2002 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* Copyright (C) 2001 Silicon Graphics, Inc.
* Contributed by Brent Casavant <bcasavan@sgi.com>
*
* Copyright (C) 2006-2009 Intel Corporation
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.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 "loader.h"
#include "elf.h"
#include "private.h"
#define LD_NAME L"plain_elf64"
static INTN
is_valid_header(Elf64_Ehdr *ehdr)
{
UINT16 type, machine;
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_X86_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;
VERB_PRT(3, {
Print(L"plain_probe: kname=%s\n", kname);
});
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;
}
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;
VOID *low_addr = (VOID *)~0;
VOID *max_addr = (VOID *)0;
UINTN paddr, memsz, filesz;
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;
if (is_valid_header(&ehdr) == -1) {
ERR_PRT((L"%s : not a 64-bit ELF image\n", LD_NAME));
return ELILO_LOAD_ERROR;
}
VERB_PRT(3, {
Print(L"ELF Header information: \n");
Print(L"\tEntry point "PTR_FMT"\n", (ehdr.e_entry & PADDR_MASK));
Print(L"\t%d program headers\n", ehdr.e_phnum);
Print(L"\t%d segment headers\n", ehdr.e_shnum);
});
phnum = ehdr.e_phnum;
if (fops_seek(fd, ehdr.e_phoff) < 0) {
ERR_PRT((L"%s : seek to %d for phdrs failed", LD_NAME, ehdr.e_phoff));
return ELILO_LOAD_ERROR;
}
size = osize = (phnum * sizeof(Elf64_Phdr));
DBG_PRT((L"%s : allocate %d bytes for %d pheaders each of size:%d phentsize=%d\n",
LD_NAME, size, phnum, sizeof(Elf64_Phdr), ehdr.e_phentsize));
phdrs = (Elf64_Phdr *)alloc(size, 0);
if (phdrs == NULL) {
ERR_PRT((L"%s : allocate for phdrs failed", LD_NAME));
return ELILO_LOAD_ERROR;
}
status = fops_read(fd, phdrs, &size);
if (EFI_ERROR(status) || size != osize) {
ERR_PRT((L"%s : phdr load failed", LD_NAME, status));
goto out;
}
/*
* First pass to figure out total memory footprint
*/
for (i = 0; i < phnum; i++) {
paddr = (phdrs[i].p_paddr & PADDR_MASK);
memsz = phdrs[i].p_memsz;
DBG_PRT((L"Phdr %d paddr ["PTR_FMT"-"PTR_FMT"] offset "PTR_FMT""
" filesz "PTR_FMT" memsz="PTR_FMT" bss_sz="PTR_FMT" p_type="PTR_FMT"\n",
1+i, paddr, paddr+phdrs[i].p_filesz, phdrs[i].p_offset,
phdrs[i].p_filesz, memsz,
(memsz - phdrs[i].p_filesz), phdrs[i].p_type));
if (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 "PTR_FMT" 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 starts and ends */
kd->kstart = low_addr;
kd->kend = (low_addr + (pages << EFI_PAGE_SHIFT));
kd->kentry = (VOID *)(ehdr.e_entry & PADDR_MASK);
VERB_PRT(3, {
Print(L"Lowest PhysAddr: "PTR_FMT"\nTotalMemSize:%d bytes (%d pages)\n",
low_addr, total_size, pages);
Print(L"Kernel entry @ "PTR_FMT"\n", kd->kentry);
});
/* now allocate memory for the kernel at the exact requested spot */
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"%s : Could not alloc %d pages for the kernel at 0x%lx "
" and relocation is not not been implemented!\n",
LD_NAME, pages, low_addr));
goto load_abort;
}
/* Pure paranoia. Clear the memory first. Just in case... */
Memset(low_addr, 0, (pages << EFI_PAGE_SHIFT));
VERB_PRT(1, Print(L"Press any key to interrupt\n"));
/*
* 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 (phdrs[i].p_type != PT_LOAD)
continue;
VERB_PRT(3, Print(L"poffs: "PTR_FMT" (phdrs[%d].p_offset)\n",
phdrs[i].p_offset, i));
filesz = phdrs[i].p_filesz;
low_addr = (VOID *)((UINTN) phdrs[i].p_paddr & PADDR_MASK);
/* Move to the right position */
if (fops_seek(fd, phdrs[i].p_offset) < 0)
goto out_kernel;
/* How many BSS bytes to clear */
bss_sz = phdrs[i].p_memsz - filesz;
VERB_PRT(4, {
Print(L"\nHeader #%d\n", i);
Print(L"Offset in file "PTR_FMT"\n", phdrs[i].p_offset);
Print(L"Physical addr "PTR_FMT"\n", low_addr);
Print(L"BSS size %d bytes\n", bss_sz);
});
/*
* Read actual segment into memory
*/
ret = fops_read(fd, low_addr, &filesz);
if (ret == ELILO_LOAD_ABORTED) goto load_abort;
if (ret == ELILO_LOAD_ERROR) goto out;
/*
* Clear bss section
*/
if (bss_sz)
Memset((VOID *)low_addr+filesz, 0, bss_sz);
}
free(phdrs);
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);
return ret;
}
loader_ops_t plain_loader={
NULL,
LD_NAME,
plain_probe,
plain_load_kernel
};
/*void plain_loader_init()
{
loader_ops_t plain={
NULL,
LD_NAME,
plain_probe,
plain_load_kernel
};
*plain_loader=*plain;
}*/

35
x86_64/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>
*
* Copyright (C) 2006-2009 Intel Corporation
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.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.
*/
#ifndef __ELILO_PRIVATE_X86_64_H__
#define __ELILO_PRIVATE_X86_64_H__
#endif /* __ELILO_PRIVATE_X86_64_H__ */

118
x86_64/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

465
x86_64/sysdeps.h Normal file
View File

@ -0,0 +1,465 @@
/*
* 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>
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by Chandramouli Narayanan <mouli@linux.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 x86_64-specific data structures
* and constant used by the generic ELILO
*/
#ifndef __ELILO_SYSDEPS_X86_64_H__
#define __ELILO_SYSDEPS_X86_64_H__
#define ELILO_ARCH "x86_64" /* ASCII string */
#define PADDR_MASK 0xfffffff
/* for now use library versions */
#define Memset(a,v,n) SetMem((a),(n),(v))
#define Memcpy(a,b,n) CopyMem((a),(b),(n))
/* Put initrd to far away from kernel image to avoid conflict.
* May need to adjust this number if it is not big enough.
*/
#define INITRD_START (50*1024*1024)
/* Default start address for kernel. */
#define DEFAULT_KERNEL_START 0x100000
/*
* 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.
*/
#pragma pack(1)
/* Definitions for converting EFI memory map to E820 map for Linux
* These definitions are from include/linux/asm-x86_64/e820.h
* The structure x86_64_boot_params below is updated to accommodate E820 map
* EFI memory map is converted to E820 map in this structure and passed
* to Linux. This way the OS does not need to do the conversion.
*/
#define E820_RAM 1
#define E820_RESERVED 2
#define E820_ACPI 3
#define E820_NVS 4
#define E820_EXEC_CODE 5
#define E820_MAX 128
struct e820entry {
UINT64 addr; /* start of memory segment */
UINT64 size; /* size of memory segment */
UINT32 type; /* type of memory segment */
} __attribute__((packed));
typedef union x86_64_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 pad_1; /* unused */
/* %%TBD */
/* 0x0A */ UINT16 orig_ega_bx; /* LDR */
/* 0x0C */ UINT16 pad_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 pad_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 pad_4[0x10E]; /* unused */
/* EFI boot loader signature. */
/* 0x1C0 */ UINT8 efi_loader_sig[4]; /* LDR */
#define EFI_LOADER_SIG_X64 "EL64"
/* 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 */
/* 0x1D8 */ UINT32 efi_sys_tbl_hi; /* LDR */
/* 0x1DC */ UINT32 efi_mem_map_hi; /* LDR */
/* Available contiguous extended memory in KB. */
/* 0x1E0 */ UINT32 alt_mem_k; /* LDR */
/* 0x1E4 */ UINT32 pad_51; /* unused */
/* 0x1E8 */ UINT8 e820_nrmap;
/* 0x1E9 */ UINT32 pad_52[2]; /* 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 */ UINT32 sys_size; /* BLD */
/* %%TBD */
/* 0x1F8 */ UINT16 ram_size_DNU; /* BLD */
/* %%TBD */
/* 0x1FA */ UINT16 video_mode_flag; /* BLD */
/* %%TBD */
/* 0x1FC */ UINT16 orig_root_dev; /* BLD */
/* %%TBD */
/* 0x1FE */ UINT16 boot_flag; /* ? */
/* 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_DNU; /* BLD */
/* %%TBD */
/* 0x224 */ UINT16 heap_end_ptr; /* LDR */
/* %%TBD */
/* 0x226 */ UINT8 ext_loader_ver; /* LDR */
/* 0x227 */ UINT8 ext_loader_type; /* LDR */
/* 0x228 */ UINT32 cmdline_addr; /* LDR */
/* 0x22C */ UINT32 initrd_addr_max; /* BLD */
/* 0x230 */ UINT32 kernel_alignment; /* BLD */
/* 0x234 */ UINT8 relocatable_kernel; /* BLD */
/* 0x235 */ UINT8 pad_8[3];
/* 0x238 */ UINT32 pad_9[38];
/* 0x2D0 */ UINT8 e820_map[2560];
} s;
} boot_params_t;
#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 && (t<f)) { \
while (n--) { \
*t++ = *f++; \
} \
} else if (t && f && n && (t>f)) { \
t += n; \
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;
UINT64 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 *kernel_load_address;
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 x86_64_use_legacy_free_boot();
extern INTN x86_64_text_mode();
/*
* How to jump to kernel code
*/
static inline void
start_kernel(VOID *kentry, boot_params_t *bp)
{
struct {
UINT32 kernel_entry;
UINT16 kernel_cs;
} jumpvector;
VOID *jump_start;
/*
* Disable interrupts.
*/
asm volatile ( "cli" : : );
/*
* Relocate kernel (if needed).
* This assumes that the initrd didn't get loaded overlapping where
* we're planning to copy the kernel, but that's pretty unlikely
* since we couldn't alloc that space for the kernel (or the kernel
* would already be there).
*/
if (kernel_start != kernel_load_address) {
MEMCPY(kernel_start, kernel_load_address, kernel_size);
}
/*
* 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);
bp = (boot_params_t *)high_base_mem;
bp->s.cmdline_addr = high_base_mem + bp->s.cmdline_offset;
/*
* Initialize Linux GDT.
*/
MEMSET(gdt_addr.base, gdt_addr.limit, 0);
MEMCPY(gdt_addr.base, init_gdt, sizeof_init_gdt);
// fixme: why x86_64_use_legacy_free_boot() goes to _relocate?
#if 0
if (! x86_64_use_legacy_free_boot()) {
/*
* Copy our real mode transition code to 0x7C00.
*/
MEMCPY(0x7C00, rmswitch_image, rmswitch_size);
asm volatile ( "mov $0x7C00, %%rbx" : : );
asm volatile ( "jmp *%%rbx" : : );
}
#endif
/*
* Load descriptor table pointers.
*/
asm volatile ( "lidt %0" : : "m" (idt_addr) );
asm volatile ( "lgdt %0" : : "m" (gdt_addr) );
/*
* rsi := address of boot sector and setup data
*/
asm volatile ( "mov %0, %%rsi" : : "m" (high_base_mem) );
/*
* Jump to kernel entry point.
*
* Cast is to tell gcc that we know we're going from
* 64-bit ptr to 32-bit integer.
*/
jumpvector.kernel_entry=(UINT32)((UINT64)kentry);
jumpvector.kernel_cs=0x10;
jump_start = (VOID *)&jumpvector;
//asm volatile ( "mov %0, %%rcx" : : "m" (&jumpvector) );
asm volatile ( "mov %0, %%rcx" : : "m" (jump_start) );
asm volatile ( "ljmp *(%%rcx)" : :);
/* Never come back to here. */
}
typedef struct sys_img_options {
UINT8 dummy; /* forces non-zero offset for first field */
UINT8 text_mode; /* do not try to initialize Graphics Output Protocol */
} sys_img_options_t;
#endif /* __ELILO_SYSDEPS_X86_64_H__ */

976
x86_64/system.c Normal file
View File

@ -0,0 +1,976 @@
/*
* 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>
* Contributed by Fenghua Yu <fenghua.yu@intel.com>
* Contributed by Bibo Mao <bibo.mao@intel.com>
* Contributed by chandramouli narayanan <mouli@linux.intel.com>
* Edgar Hucek <hostmaster@ed-soft.at>
*
* Updated with code to fill bootparam converting EFI memory map to E820
* based on a Linux kernel patch provided by Edgar Hucek
* - mouli 06/20/2007
*
* 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 x86_64 specific code expected by generic loader
*/
#include <efi.h>
#include <efilib.h>
#include <string.h>
#include "elilo.h"
#include "loader.h"
#include "rmswitch.h"
#define DEBUG_CREATE_BOOT_PARAMS 0
#if DEBUG_CREATE_BOOT_PARAMS
#define DPR(a) do { if (elilo_opt.debug) { Print a; } } while ( 0 )
#else
#define DPR(a)
#endif
extern loader_ops_t bzimage_loader, plain_loader, gzip_loader;
/*
* 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.
* This is only used for backward compatibility.
*/
UINTN high_ext_mem = 32 * 1024 * 1024;
/* This starting address will hold true for all of the loader types for now */
VOID *kernel_start = (VOID *)DEFAULT_KERNEL_START;
/* The kernel may load elsewhere if EFI firmware reserves kernel_start */
VOID *kernel_load_address = (VOID *)DEFAULT_KERNEL_START;
VOID *initrd_start = NULL;
UINTN initrd_size = 0;
INTN e820_map_overflow = 0;
INTN
sysdeps_init(EFI_HANDLE dev)
{
DBG_PRT((L"sysdeps_init()\n"));
/*
* Register our loader(s)...
*/
loader_register(&bzimage_loader);
loader_register(&plain_loader);
loader_register(&gzip_loader);
return 0;
}
/*
* initrd_get_addr()
* Compute a starting address for the initial RAMdisk image.
* For now we suggest 'initrd_addr_max' with room for 32MB,
* as image->pgcnt is not initialized yet.
*/
INTN
sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem)
{
DBG_PRT((L"initrd_get_addr()\n"));
if (!kd || !imem) {
ERR_PRT((L"kd="PTR_FMT" imem="PTR_FMT"", kd, imem));
return -1;
}
VERB_PRT(3, Print(L"initrd_addr_max="PTR_FMT" reserve=%d\n",
param_start->s.initrd_addr_max, 32*MB));
imem->start_addr = (VOID *)
(((UINT64)param_start->s.initrd_addr_max - 32*MB + 1)
& ~EFI_PAGE_MASK);
VERB_PRT(3, Print(L"initrd start_addr="PTR_FMT" pgcnt=%d\n",
imem->start_addr, imem->pgcnt));
return 0;
}
/*
* checkfix_initrd()
* Check and possibly fix allocation of initrd memory.
*/
VOID *
sysdeps_checkfix_initrd(VOID *start_addr, memdesc_t *imem)
{
UINTN pgcnt = EFI_SIZE_TO_PAGES(imem->size);
UINT64 initrd_addr_max = (UINT64)param_start->s.initrd_addr_max;
UINT64 ki_max = initrd_addr_max - imem->size + 1;
VOID *ki_max_addr;
VERB_PRT( 3, Print(L"loadfile: start_addr="PTR_FMT
" ki_max_addr="PTR_FMT"\n", start_addr, (VOID *)ki_max));
if (ki_max > UINT32_MAX) {
ERR_PRT((L"Force kernel specified initrd_addr_max="PTR_FMT
" below 4GB\n", (VOID *)initrd_addr_max));
ki_max = UINT32_MAX - imem->size + 1;
}
ki_max_addr = (VOID *)ki_max;
if ((UINT64)start_addr > ki_max) {
VERB_PRT(1, Print(L"initrd start_addr="PTR_FMT" above "
"limit="PTR_FMT"\n", start_addr, ki_max_addr));
free(start_addr);
start_addr = NULL;
}
/* so either the initial allocation failed or it's been to high! */
if (start_addr == NULL) {
start_addr = alloc_pages(pgcnt, EfiLoaderData,
AllocateMaxAddress, ki_max_addr);
}
if ((UINT64)start_addr > ki_max) {
ERR_PRT((L"Failed to allocate %d pages below %dMB",
pgcnt, (param_start->s.initrd_addr_max+1)>>20));
free(start_addr);
start_addr = NULL;
}
return start_addr;
}
VOID
sysdeps_free_boot_params(boot_params_t *bp)
{
mmap_desc_t md;
ZeroMem(&md, sizeof md);
md.md = (VOID *)(UINT64)bp->s.efi_mem_map;
free_memmap(&md);
}
static VOID find_bits(unsigned long mask, UINT8 *first, UINT8* len) {
unsigned char bit_pos = 0, bit_len = 0;
*first =0;
*len = 0;
if (mask == 0)
return;
while (!(mask & 0x1)) {
mask = mask >> 1;
bit_pos++;
}
while (mask & 0x1) {
mask = mask >> 1;
bit_len++;
}
*first = bit_pos;
*len = bit_len;
}
/*
* Get video information.
*/
static INTN get_video_info(boot_params_t * bp) {
EFI_GUID GopProtocol = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop_interface;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Gop_info;
EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Gop_mode = NULL;
EFI_HANDLE *Gop_handle = NULL;
EFI_STATUS efi_status;
UINTN size = 0;
UINTN size1;
UINT8 i;
if (x86_64_text_mode() == 1) {
Print((L"Skip GOP init, force text-mode.\n"));
return -1;
}
efi_status = uefi_call_wrapper(
BS->LocateHandle,
5,
ByProtocol,
&GopProtocol,
NULL,
&size,
(VOID **)Gop_handle);
if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) {
Print(L"LocateHandle GopProtocol failed.\n");
Print(L"--Either no graphics head is installed,\n" \
"--efi console is set to serial, or,\n" \
"--the EFI firmware version of this machine is\n" \
"--older than UEFI 2.0. and does not support GOP");
Print(L"you can SAFELY IGNORE this error. elilo will\n" \
"default to text-mode.\n Alternatively you can " \
"now force text mode by setting config variable\n" \
"text_mode=1 for x86 in elilo.conf or via cmdline.\n\n");
Print(L"However if this is the last text output you see\n" \
"ensure that your kernel console command line\n " \
"variable matches up with the actual efi boot menu\n" \
"console output settings.\n\n");
return -1;
}
Gop_handle = alloc(size, 0);
efi_status = uefi_call_wrapper(
BS->LocateHandle,
5,
ByProtocol,
&GopProtocol,
NULL,
&size,
(VOID **)Gop_handle);
if (EFI_ERROR(efi_status)) {
ERR_PRT((L"LocateHandle GopProtocol failed."));
free(Gop_handle);
return -1;
}
for (i=0; i < size/sizeof(EFI_HANDLE); i++) {
Gop_handle += i;
efi_status = uefi_call_wrapper(
BS->HandleProtocol,
3,
*Gop_handle,
&GopProtocol,
&Gop_interface);
if (EFI_ERROR(efi_status)) {
continue;
}
Gop_mode = Gop_interface->Mode;
efi_status = uefi_call_wrapper(
Gop_interface->QueryMode,
4,
Gop_interface,
Gop_mode->Mode,
&size1,
&Gop_info);
if (!EFI_ERROR(efi_status))
break;
if (EFI_ERROR(efi_status)) {
continue;
}
}
if (EFI_ERROR(efi_status) || i > (size/sizeof(EFI_HANDLE))) {
ERR_PRT((L"HandleProtocol GopProtocol failed."));
free(Gop_handle);
return -1;
}
bp->s.is_vga = 0x70;
bp->s.orig_cursor_col = 0;
bp->s.orig_cursor_row = 0;
bp->s.orig_video_page = 0;
bp->s.orig_video_mode = 0;
bp->s.orig_video_cols = 0;
bp->s.orig_video_rows = 0;
bp->s.orig_ega_bx = 0;
bp->s.orig_video_points = 0;
bp->s.lfb_width = Gop_info->HorizontalResolution;
bp->s.lfb_height = Gop_info->VerticalResolution;
bp->s.lfb_base = Gop_mode->FrameBufferBase;
bp->s.lfb_size = Gop_mode->FrameBufferSize;
bp->s.lfb_pages = 1;
bp->s.vesa_seg = 0;
bp->s.vesa_off = 0;
if (Gop_info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
bp->s.lfb_depth = 32;
bp->s.lfb_red_size = 8;
bp->s.lfb_red_pos = 0;
bp->s.lfb_green_size = 8;
bp->s.lfb_green_pos = 8;
bp->s.lfb_blue_size = 8;
bp->s.lfb_blue_pos = 16;
bp->s.lfb_rsvd_size = 8;
bp->s.lfb_rsvd_pos = 24;
bp->s.lfb_line_len = Gop_info->PixelsPerScanLine * 4;
} else if (Gop_info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
bp->s.lfb_depth = 32;
bp->s.lfb_red_size = 8;
bp->s.lfb_red_pos = 16;
bp->s.lfb_green_size = 8;
bp->s.lfb_green_pos = 8;
bp->s.lfb_blue_size = 8;
bp->s.lfb_blue_pos = 0;
bp->s.lfb_rsvd_size = 8;
bp->s.lfb_rsvd_pos = 24;
bp->s.lfb_line_len = Gop_info->PixelsPerScanLine * 4;
} else if (Gop_info->PixelFormat == PixelBitMask) {
find_bits(Gop_info->PixelInformation.RedMask,
&bp->s.lfb_red_pos, &bp->s.lfb_red_size);
find_bits(Gop_info->PixelInformation.GreenMask,
&bp->s.lfb_green_pos, &bp->s.lfb_green_size);
find_bits(Gop_info->PixelInformation.BlueMask,
&bp->s.lfb_blue_pos, &bp->s.lfb_blue_size);
find_bits(Gop_info->PixelInformation.ReservedMask,
&bp->s.lfb_rsvd_pos, &bp->s.lfb_rsvd_size);
bp->s.lfb_depth = bp->s.lfb_red_size + bp->s.lfb_green_size +
bp->s.lfb_blue_size + bp->s.lfb_rsvd_size;
bp->s.lfb_line_len = (Gop_info->PixelsPerScanLine * bp->s.lfb_depth) / 8;
} else {
bp->s.lfb_depth = 4;
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_line_len = bp->s.lfb_width / 2;
}
return 0;
}
CHAR16 *
StrStr(IN const CHAR16 *h, IN const CHAR16 *n)
{
const CHAR16 *t = h;
CHAR16 *res;
int len = 0, i;
len = StrLen((CHAR16 *)n);
while(*t != CHAR_NULL) {
res = StrChr( t, n[0]);
if (!res) return res;
for( i = 1; i < len && res[i] != CHAR_NULL && res[i] == n[i]; i++);
if ( i == len ) return res;
t = res + 1;
if (t > h + CMDLINE_MAXLEN) return (CHAR16 *)0;
}
return (CHAR16 *)0;
}
CHAR8 *
StrStr8(IN const CHAR8 *h, IN const CHAR8 *n)
{
const CHAR8 *t = h;
CHAR8 *res;
int len = 0, i;
len = strlena((CHAR8 *)n);
while(*t != 0) {
res = strchra( t, n[0]);
if (!res) return res;
for( i = 1; i < len && res[i] != 0 && res[i] == n[i]; i++);
if ( i == len ) return res;
t = res + 1;
if (t > (h + CMDLINE_MAXLEN)) return (CHAR8 *)0;
}
return (CHAR8 *)0;
}
/* Convert EFI memory map to E820 map for the operating system
* This code is based on a Linux kernel patch submitted by Edgar Hucek
*/
#if DEBUG_CREATE_BOOT_PARAMS
static int e820_max = 6;
#else
static int e820_max = E820_MAX;
#endif
/* Add a memory region to the e820 map */
static void add_memory_region (struct e820entry *e820_map,
int *e820_nr_map,
unsigned long long start,
unsigned long size,
unsigned int type)
{
int x = *e820_nr_map;
static unsigned long long estart = 0ULL;
static unsigned long esize = 0L;
static unsigned int etype = -1;
static int merge = 0;
if (x == 0)
DPR((L"AMR: %3s %4s %16s/%12s/%s\n",
L"idx", L" ", L"start", L"size", L"type"));
/* merge adjacent regions of same type */
if ((x > 0) && e820_map[x-1].addr + e820_map[x-1].size == start
&& e820_map[x-1].type == type) {
e820_map[x-1].size += size;
estart = e820_map[x-1].addr;
esize = e820_map[x-1].size;
etype = e820_map[x-1].type;
merge++;
return;
}
/* fill up to E820_MAX */
if ( x < e820_max ) {
e820_map[x].addr = start;
e820_map[x].size = size;
e820_map[x].type = type;
(*e820_nr_map)++;
if (merge) DPR((L"AMR: %3d ==> %016llx/%012lx/%d (%d)\n",
x-1, estart, esize, etype, merge));
merge=0;
DPR((L"AMR: %3d add %016llx/%012lx/%d\n",
x, start, size, type));
return;
}
/* different type means another region didn't fit */
/* or same type, but there's a hole */
if (etype != type || (estart + esize) != start) {
if (merge) DPR((L"AMR: %3d ===> %016llx/%012lx/%d (%d)\n",
e820_map_overflow, estart, esize, etype, merge));
merge = 0;
estart = start;
esize = size;
etype = type;
e820_map_overflow++;
DPR((L"AMR: %3d OVER %016llx/%012lx/%d\n",
e820_map_overflow, start, size, type));
return;
}
/* same type and no hole, merge it */
estart += esize;
esize += size;
merge++;
}
void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc)
{
int nr_map, e820_nr_map = 0, i;
UINT64 start, end, size;
EFI_MEMORY_DESCRIPTOR *md, *p;
struct e820entry *e820_map;
nr_map = mdesc->map_size/mdesc->desc_size;
e820_map = (struct e820entry *)bp->s.e820_map;
for (i = 0, p = mdesc->md; i < nr_map; i++)
{
md = p;
switch (md->Type) {
case EfiACPIReclaimMemory:
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_ACPI);
break;
case EfiRuntimeServicesCode:
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_EXEC_CODE);
break;
case EfiRuntimeServicesData:
case EfiReservedMemoryType:
case EfiMemoryMappedIO:
case EfiMemoryMappedIOPortSpace:
case EfiUnusableMemory:
case EfiPalCode:
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_RESERVED);
break;
case EfiLoaderCode:
case EfiLoaderData:
case EfiBootServicesCode:
case EfiBootServicesData:
case EfiConventionalMemory:
start = md->PhysicalStart;
size = md->NumberOfPages << EFI_PAGE_SHIFT;
end = start + size;
/* Fix up for BIOS that claims RAM in 640K-1MB region */
if (start < 0x100000ULL && end > 0xA0000ULL) {
if (start < 0xA0000ULL) {
/* start < 640K
* set memory map from start to 640K
*/
add_memory_region(e820_map,
&e820_nr_map,
start,
0xA0000ULL-start,
E820_RAM);
}
if (end <= 0x100000ULL)
continue;
/* end > 1MB
* set memory map avoiding 640K to 1MB hole
*/
start = 0x100000ULL;
size = end - start;
}
add_memory_region(e820_map, &e820_nr_map,
start, size, E820_RAM);
break;
case EfiACPIMemoryNVS:
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_NVS);
break;
default:
/* We should not hit this case */
DBG_PRT((L"hit default!?"));
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_RESERVED);
break;
}
p = NextMemoryDescriptor(p, mdesc->desc_size);
}
bp->s.e820_nrmap = e820_nr_map;
}
/*
* x86_64 specific boot parameters initialization routine
*
* Note: debug and verbose messages have already been turned off!
*/
INTN
sysdeps_create_boot_params(
boot_params_t *bp,
CHAR8 *cmdline,
memdesc_t *initrd,
memdesc_t *vmcode,
UINTN *cookie)
{
mmap_desc_t mdesc;
EFI_STATUS efi_status;
UINTN rows, cols;
UINT8 row, col;
UINT8 mode;
UINT16 hdr_version;
UINT8 e820_map_overflow_warned = 0;
#if DEBUG_CREATE_BOOT_PARAMS
elilo_opt.debug=1;
elilo_opt.verbose=5;
#endif
DBG_PRT((L"fill_boot_params()\n"));
if (!bp || !cmdline || !initrd || !cookie) {
ERR_PRT((L"bp="PTR_FMT" cmdline="PTR_FMT" initrd="PTR_FMT" cookie="PTR_FMT"",
bp, cmdline, initrd, cookie));
if (param_start != NULL) {
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.
*/
if (param_start != NULL) {
CopyMem(bp, param_start, 0x2000);
}
/*
* Save off our header revision information.
*/
hdr_version = (bp->s.hdr_major << 8) | bp->s.hdr_minor;
/*
* Do NOT clear out unknown memory in boot sector image.
* This breaks boot protocol >= 2.10 (2.6.31).
*/
/*
* 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;
/*
* Clear out the cmdline_addr field so the kernel can find
* the cmdline.
*/
bp->s.cmdline_addr = 0x0;
/*
* 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);
/*
* 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;
/*
* Initial RAMdisk and root device stuff.
*/
DBG_PRT((L"initrd->start_addr="PTR_FMT" initrd->pgcnt=%d\n",
initrd->start_addr, initrd->pgcnt));
/* 'ramdisk_flags' (@0x1F8) is called 'ram_size' in the meantime, */
/* see Documentation/x86/boot.txt. */
if (initrd->start_addr && initrd->pgcnt) {
if ( (UINT64)initrd->start_addr > UINT32_MAX ) {
ERR_PRT((L"Start of initrd out of reach (>4GB)."));
free_kmem();
return -1;
}
/* %%TBD - This will probably have to be changed. */
bp->s.initrd_start = (UINT32)(UINT64)initrd->start_addr;
bp->s.initrd_size = (UINT32)(initrd->size);
} else {
bp->s.initrd_start = 0;
bp->s.initrd_size = 0;
}
/*
* APM BIOS 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).
*/
bp->s.mca_info_len = 0;
ZeroMem(bp->s.mca_info_buf, sizeof bp->s.mca_info_buf);
/*
* EFI loader signature
*/
CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG_X64, 4);
/*
* Kernel entry point.
*/
if ( (UINT64)kernel_start != (UINT32)(UINT64)kernel_start ) {
ERR_PRT((L"Start of kernel (will be) out of reach (>4GB)."));
free_kmem();
return -1;
}
bp->s.kernel_start = (UINT32)(UINT64)kernel_start;
/*
* 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/x86_64/boot/bootsect.S
* arch/x86_64/boot/setup.S
* arch/x86_64/kernel/setup.c
* include/asm-x86_64/setup.h (2.5/2.6)
*/
#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 (uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, 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(efi_sys_tbl_hi, 0x1D8, L"%xh");
CHECK_OFFSET(efi_mem_map_hi, 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(video_mode_flag, 0x1FA, L"%xh");
CHECK_OFFSET(orig_root_dev, 0x1FC, L"%xh");
CHECK_OFFSET(boot_flag, 0x1FE, L"%xh");
CHECK_OFFSET(jump, 0x200, L"%xh");
CHECK_OFFSET(setup_sig, 0x202, L"'%-4.4a'");
CHECK_OFFSET(hdr_minor, 0x206, L"%xh");
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(heap_end_ptr, 0x224, L"%xh");
CHECK_OFFSET(cmdline_addr, 0x228, L"%xh");
CHECK_OFFSET(e820_map, 0x2D0, L"%xh");
if (test) {
ERR_PRT((L"Boot sector and/or setup parameter alignment error."));
free_kmem();
return -1;
}
}
/*
* Get video information.
* Do this last so that any other cursor positioning done
* in the fill routine gets accounted for.
*/
if (!get_video_info(bp)) goto do_memmap;
/* Do the old text mode */
efi_status = uefi_call_wrapper(
ST->ConOut->QueryMode,
4,
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;
bp->s.orig_ega_bx = 0;
bp->s.is_vga = 0;
bp->s.orig_video_points = 16;
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;
do_memmap:
/*
* 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 = (UINT32)(unsigned long)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 = (UINT32)(unsigned long)systab;
bp->s.efi_mem_map_hi = (unsigned long)mdesc.md >> 32;
bp->s.efi_sys_tbl_hi = (unsigned long)systab >> 32;
/* Now that we have EFI memory map, convert it to E820 map
* and update the bootparam accordingly
*/
fill_e820map(bp, &mdesc);
#if DEBUG_CREATE_BOOT_PARAMS
if ( e820_map_overflow == 0 )
e820_map_overflow = -1; /* force second get_memmap()! */
#endif
if (e820_map_overflow && !e820_map_overflow_warned) {
CHAR8 *aem = (CHAR8 *)"add_efi_memmap";
e820_map_overflow_warned++;
#if DEBUG_CREATE_BOOT_PARAMS
elilo_opt.debug=0;
elilo_opt.verbose=0;
#endif
if (e820_map_overflow == -1 || StrStr8(cmdline, aem)) {
/* Print(L"...mapping again, silently!\n"); */
goto do_memmap;
}
Print(L"\nCAUTION: EFI memory map has %d more entr%a"
" than E820 map supports.\n"
"To access all memory, '%a' may be necessary.\n\n",
e820_map_overflow, (e820_map_overflow==1)?"y":"ies",
aem);
goto do_memmap;
}
return 0;
}