release 3.4
https://sourceforge.net/projects/elilo/files/elilo/elilo-3.4/
This commit is contained in:
commit
fb6ce0d596
100 changed files with 20247 additions and 0 deletions
338
ChangeLog
Normal file
338
ChangeLog
Normal file
|
@ -0,0 +1,338 @@
|
||||||
|
2003-08-20 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* released 3.4
|
||||||
|
2003-08-19 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* integrated ia32 updates from Matt
|
||||||
|
Tolentino <matthew.e.tolentino@intel.com>
|
||||||
|
2003-08-13 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* updated elilo.txt and netbooting.txt
|
||||||
|
* fix a bug in choosers/simple.c:print_infos().
|
||||||
|
it needs to check if config file path is absolute
|
||||||
|
when printing filename.
|
||||||
|
* move definitions of CHAR_SLASH CHAR_BACKSLASH to elilo.h
|
||||||
|
* fix a bug in read_config() where it would try other
|
||||||
|
filename even when the user explicitely specified one
|
||||||
|
via -C, now it fails it that file cannot be opened.
|
||||||
|
* updated simple chooser set of builtin command keys
|
||||||
|
* command keys are only valid if first on the line
|
||||||
|
* increase default buffer size and increment when netbooting
|
||||||
|
2003-06-04 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* fix fs/netfs.c to work with recent version
|
||||||
|
of EFI (14.61 or higher) which do not have the
|
||||||
|
TFTP problem anymore. fix submitted by Guy Laborde
|
||||||
|
2003-04-21 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* ext2fs support is turned off by default to avoid
|
||||||
|
problems with ext3-formatted partitions.
|
||||||
|
* added gcc version check. MUST use 3.0 or higher
|
||||||
|
2003-03-03 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* added check on dev_tab in fs/*fs.c:*_uninstall()
|
||||||
|
2003-02-07 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* clean up in glue_localfs.c w.r.t. CHAR16 in set_default_path()
|
||||||
|
* added support for extracting basename of bootloader path
|
||||||
|
when using BOOTP (DHCP) only. The prefix is then used for all files
|
||||||
|
open via netfs. Suggestion and initial patch by Guy Laborde from HP.
|
||||||
|
2003-01-28 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* fix the set_default_path() routine in glue_localfs.c. It would not
|
||||||
|
correctly get the basename of the devpath. This caused the
|
||||||
|
elilo.conf not to be found sometimes.
|
||||||
|
2003-01-21 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* fix bug in glue_netfs.c convert_ip2decstr() which caused some IP
|
||||||
|
addresses to be incorrectly converted to strings.
|
||||||
|
2002-11-01 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* fix bug in -r option for IA64. There is no argument to this option.
|
||||||
|
2002-10-15 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* fixed a double free bug for the kernel memory in case of abort.
|
||||||
|
(bug spotted by Levent Akyl from Intel)
|
||||||
|
* released 3.3a
|
||||||
|
2002-09-14 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* applied patch from Andreas Schwab <schwab@suse.de> to eliloalt.c.
|
||||||
|
eliloalt dynamically selects a variable in /proc/efi/vars.
|
||||||
|
2002-09-12 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* removed extra free() from fs/ext2fs.c:ext2fs_init_state().
|
||||||
|
Bug report and fix by NOMURA Jun'ichi <j-nomura@ce.jp.nec.com>
|
||||||
|
* rewrote fs/ext2fs.c:read_bytes() to large memory stack buffer which
|
||||||
|
was bigger than the 128KB limit of EFI causing some weird fimrware
|
||||||
|
errors. bug reported by OMURA Jun'ichi <j-nomura@ce.jp.nec.com>
|
||||||
|
* on IA-64 forbid the use of f32-f127 by the compiler (EFI spec)
|
||||||
|
2002-09-10 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* fix a bug in argify() that was causing an EFI assertion
|
||||||
|
when aborting at the elilo prompt when netbooted.
|
||||||
|
2002-08-26 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* fixed devschemes/simple.c to use SPrint() instead of its own buggy
|
||||||
|
conversion code (spotted by Richard Hirst).
|
||||||
|
* fix bug in argify() when there was no NULL character in the string.
|
||||||
|
* released 3.3
|
||||||
|
2002-08-19 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* added fpswa.txt in the docs directory
|
||||||
|
* updated elilo.txt
|
||||||
|
2002-08-15 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* added -F file option for IA-64 to allow a specific fpswa driver to be loaded
|
||||||
|
* fixed fpswa.c to try and load the driver from all accessible partitions
|
||||||
|
* added support to load (plain or gzipped) big-endian ELF/ia64 binaries using p_paddr.
|
||||||
|
* fixed problem in fs/netfs.c causing large (>4MB) binaries to fail the Mftp() call
|
||||||
|
2002-06-13 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* Changed the despecialization character for the variables from \\ to &
|
||||||
|
to avoid conflicts with \\ as a path separator
|
||||||
|
2002-06-11 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* fixed the return value in efi_main(). elilo was always returning
|
||||||
|
success even in case of failure. Bug reported by Egan Ford <egan@sense.net>
|
||||||
|
* applied patch from Richard Hirst <rhirst@linuxcare.com> to fix an
|
||||||
|
initialization bug in choosers/textmenu.c
|
||||||
|
* applied patch from Richard Hirst <rhirst@linuxcare.com> to make elilo
|
||||||
|
compliant with EFI spec with regards to where it looks for files.
|
||||||
|
With this patch, elilo will look in the directory it was loaded
|
||||||
|
from, not on the root of the partition anymore.
|
||||||
|
2002-03-04 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* released version 3.2
|
||||||
|
* cleanup some GNU extension in fs/ext2fs.c (variable size array)
|
||||||
|
* updated all documentation. Added netbooting.txt, simple_chooser.txt,
|
||||||
|
eliloalt.txt, elilovar.txt
|
||||||
|
2002-02-21 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* added a Linux utility program (elilovar in tools) to set/read/delete
|
||||||
|
the EliloAlt EFI variable used to specify an alternate kernel to boot.
|
||||||
|
* rename DBG_PRINT() to DBG_PRT, PRINT_ERR() to ERR_PRT()
|
||||||
|
* added support for hostname,domain name extraction in fs/netfs.c
|
||||||
|
* fixed all known bugs in alternate.c
|
||||||
|
* integrated patch from SGI to fix load offset for relocatable kernels (Jack Steiner, Brent Casavant)
|
||||||
|
2002-02-21 Michael Johnston <michael.johnston@intel.com> and Chris Ahna <christopher.j.ahna@intel.com>
|
||||||
|
* major update to ia32 support: can now boot 2.4.x, and 2.2.x kernels
|
||||||
|
2002-02-20 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* fixed missing netfs_fd_free() in case of file not found in netfs.c
|
||||||
|
2002-02-19 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* added support for substitution variables (vars.c)
|
||||||
|
* changed the bootparam structure size back to 4kB
|
||||||
|
* added support to simple to print final command line option with tab key
|
||||||
|
* got rid of all the \r characters in strings use only \n (adjust emulator)
|
||||||
|
* added EFICRT0 variable in Makefile to indicate location of loader script+crt0
|
||||||
|
2002-02-14 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* added support for message= option to simple chooser
|
||||||
|
* added support for description= option to simple chooser
|
||||||
|
2002-02-13 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* choosers/textmenu.c: new textmenu chooser (by rhirst@linuxcare.com) used by Debian
|
||||||
|
* config.c: added support for dynamic global/per-image option management
|
||||||
|
* ia64/plain_loader.c,ia64/gzip.c: fix load_offset (<bcasavan@sgi.com>)
|
||||||
|
* added cmd line (-E) and config option (noedd30) to not set EDD30 EFI variable to
|
||||||
|
true if not already TRUE (request by Matt_Domsch@dell.com)
|
||||||
|
* added support for multiple devname schemes and probing
|
||||||
|
|
||||||
|
2002-01-31 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* cleaned up alternate.c
|
||||||
|
* added support for ctrl-U (clear line) in chooser/simple.c
|
||||||
|
|
||||||
|
2002-01-25 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* added support for architecture specific config file (elilo-ia64.conf, elilo-ia32.conf).
|
||||||
|
|
||||||
|
2002-01-13 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* removed call to Reset() in ext2fs.c
|
||||||
|
|
||||||
|
2001-08-17 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* released 3.1
|
||||||
|
* added support for command line architecture specific options:
|
||||||
|
sysdeps_get_cmdline_opts(), sysdeps_print_cmdline_opts(),
|
||||||
|
syspdeps_getopt()
|
||||||
|
* added IA-64 command line option (-r) for relocation
|
||||||
|
* fix behavior when kernel specified on command line but prompt
|
||||||
|
mode was specified in config file. In this case, we now autoboot
|
||||||
|
and ignore the prompt directive.
|
||||||
|
* updated elilo.txt
|
||||||
|
2001-08-15 Brent Casavant <bcasavan@sgi.com>
|
||||||
|
* fix a bug in config.c:find_option() where it would do
|
||||||
|
a strXcmp() on a NULL string.
|
||||||
|
|
||||||
|
2001-08-01 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* fixed bug in fs/netfs.c where it would not handle the small buffer
|
||||||
|
error correctly. The retry path was not allocating a bigger buffer.
|
||||||
|
* Global config options are now used if the user specifies a non-label
|
||||||
|
load target, i.e. a kernel image file.
|
||||||
|
* added support for architecture dependent config file image options (sys_img_options_t).
|
||||||
|
* added support for setjmp/longjmp.
|
||||||
|
* added support for aborting during a compressed load
|
||||||
|
* added support for user to abort a load of a compressed file.
|
||||||
|
* added 2 new ia-64 only config file options allowing kernel relocation:
|
||||||
|
'relocatable' as a global or per image option.
|
||||||
|
* added support for kernel relocation on memory error. Based on code from
|
||||||
|
Brent Casavant <bcasavan@sgi.com>.
|
||||||
|
* added slash/backslash conversion for filenames on vfat filesystems.
|
||||||
|
|
||||||
|
2001-07-23 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* fixed error in netfs.c where the kernel name was not correctly set in
|
||||||
|
netfs_query_layer()
|
||||||
|
* fixed to wait_timeout() to correct the problem with the interactive prompt when
|
||||||
|
return is hit directly when no text
|
||||||
|
* fixed command line argument destruction problem, now we make a copy of them. This
|
||||||
|
was affecting elilo when called directly from bootmanager with NVRAM options.
|
||||||
|
|
||||||
|
2001-06-28 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* removed W2U() hack to get from wide-char to unicode. Use -fshort-wchar option instead.
|
||||||
|
* split gnu-efi package in two different packages: the libary+include+crt and the bootloader.
|
||||||
|
* restructured the fileops module. Now use direct function calls.
|
||||||
|
* added support for accessing files on different devices.
|
||||||
|
* fixed a buffer leak in simple_chooser.c. Renamed simple_chooser.c to simple.c.
|
||||||
|
* created a strops.c file to incorporate all string operations functions.
|
||||||
|
* added support for ext2fs filesystem.
|
||||||
|
* restructured code to allow additional filesystems to be added easily.
|
||||||
|
* cleaned up add-on chooser interface.
|
||||||
|
* restructured code to use the EFI protocol interface to install filesystems.
|
||||||
|
* added compile-time options to turn on and off specific filesystems.
|
||||||
|
* added support for architecture specific configuration options (elilo.conf).
|
||||||
|
* added fpswa option to IA-64 to designate a fpswa driver file.
|
||||||
|
* incoporated IA-32 support from Mike Johnston <michael.johnston@intel.com>
|
||||||
|
* incorporated rewritten gzip.c:flush_window() from Tony Luck <tony.luck@intel.com>
|
||||||
|
* added interface for custom device naming schemes (devnames directory).
|
||||||
|
* added support for 2 possible config file (now just on netboot). The first
|
||||||
|
(primary) choice uses a host specific filename based on the IP address. Suggestion
|
||||||
|
from Egan Ford <egan@sense.net>.
|
||||||
|
|
||||||
|
2001-04-06 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
|
||||||
|
* incorporated patches from David and Michael Johnston at Intel
|
||||||
|
to get the package to compile for IA-32 linux target.
|
||||||
|
|
||||||
|
* Fixed ELILO to compile for Ia-32 (does not execute yet, though):
|
||||||
|
Makefile and start_kernel() function.
|
||||||
|
|
||||||
|
2001-04-06 Andreas Schwab <schwab@suse.de>
|
||||||
|
|
||||||
|
* Fixed config.c to
|
||||||
|
get the timeout directive to do something. implemented the global
|
||||||
|
root= directive.
|
||||||
|
|
||||||
|
* Fix the efi_main() to deal with the -C option properly
|
||||||
|
|
||||||
|
2001-04-05 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
|
||||||
|
* update efi library to latest EFI toolkit 1.02 as distributed
|
||||||
|
by Intel. Fixed header + library files to compile with GCC
|
||||||
|
|
||||||
|
* merged ELI and LILO (as of gnu-efi-1.1) together, mostly
|
||||||
|
taking the config file feature of ELI.
|
||||||
|
|
||||||
|
* renamed LILO to ELILO to make the distinction
|
||||||
|
|
||||||
|
* restructured code to make it easier to understand and maintain
|
||||||
|
|
||||||
|
* fixed FPSWA driver checking and loading: we try all possible
|
||||||
|
files and let the driver itself figure out if it is the most
|
||||||
|
recent.
|
||||||
|
* added support for compression (gzip) but keep support for plain
|
||||||
|
ELF image. ELILO autodetects the format
|
||||||
|
|
||||||
|
* change the way the kernel is invoked. Now we call it in
|
||||||
|
physical memory mode. This breaks the dependency between the
|
||||||
|
kernel code and the loader. No more lilo_start.c madness.
|
||||||
|
|
||||||
|
* changed the way the boot_params are passed. We don't use the
|
||||||
|
ZERO_PAGE_ADDR trick anymore. Instead we use EFI runtime memory.
|
||||||
|
The address of the structure is passed to the kernel in r28
|
||||||
|
by our convention.
|
||||||
|
|
||||||
|
* released as gnu-efi-2.0
|
||||||
|
|
||||||
|
2001-04-03 David Mosberger <davidm@hpl.hp.com>
|
||||||
|
|
||||||
|
* gnuefi/reloc_ia32.c (_relocate): Change return type from "void"
|
||||||
|
to "int". Return error status if relocation fails for some
|
||||||
|
reason.
|
||||||
|
|
||||||
|
* gnuefi/elf_ia32_efi.lds: Drop unneeded ".rel.reloc" section.
|
||||||
|
|
||||||
|
* gnuefi/crt0-efi-ia32.S (_start): Exit if _relocate() returns with
|
||||||
|
non-zero exit status.
|
||||||
|
|
||||||
|
* inc/ia32/efibind.h [__GNUC__]: Force 8-byte alignment for 64-bit
|
||||||
|
types as that is what EFI appears to be expecting, despite the
|
||||||
|
"#pragma pack()" at the beginning of the file!
|
||||||
|
|
||||||
|
2001-03-29 David Mosberger <davidm@hpl.hp.com>
|
||||||
|
|
||||||
|
* gnuefi/reloc_ia32.c: Add a couple of defines to work around
|
||||||
|
libc/efilib collision on uint64_t et al.
|
||||||
|
(_relocate): Use ELF32_R_TYPE() instead of ELFW(R_TYPE)().
|
||||||
|
|
||||||
|
* gnuefi/crt0-efi-ia32.S (dummy): Add a dummy relocation entry.
|
||||||
|
|
||||||
|
2001-03-29 David Mosberger <davidm@hpl.hp.com>
|
||||||
|
|
||||||
|
* gnuefi/reloc_ia32.c: Add a couple of defines to work around
|
||||||
|
libc/efilib collision on uint64_t et al.
|
||||||
|
(_relocate): Use ELF32_R_TYPE() instead of ELFW(R_TYPE)().
|
||||||
|
|
||||||
|
* gnuefi/crt0-efi-ia32.S (dummy): Add a dummy relocation entry.
|
||||||
|
|
||||||
|
2000-10-26 David Mosberger <davidm@hpl.hp.com>
|
||||||
|
|
||||||
|
* gnuefi/elf_ia64_efi.lds: Mention .rela.sdata.
|
||||||
|
|
||||||
|
* Make.defaults (CFLAGS): Remove -nostdinc flags so we can pick
|
||||||
|
up the C compiler's stdarg.h.
|
||||||
|
|
||||||
|
* inc/stdarg.h: Remove this file. It's not correct for gcc (nor
|
||||||
|
most other optimizing compilers).
|
||||||
|
|
||||||
|
2000-10-10 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
|
||||||
|
* cleaned up the error message and printing of those.
|
||||||
|
* added support to load the FPSWA from a file in case support is not
|
||||||
|
present in the firmware already
|
||||||
|
* fixed split_args() to do the right thing when you have leading spaces
|
||||||
|
before kernel name
|
||||||
|
* changed the argify() function to rely on \0 instead of LoadOptionSize
|
||||||
|
as the field seems to be broken with current firmware
|
||||||
|
* bumped version to 1.0
|
||||||
|
|
||||||
|
2000-10-04 David Mosberger <davidm@hpl.hp.com>
|
||||||
|
|
||||||
|
* gnuefi/reloc_ia64.S: Reserve space for up to 750 function descriptors.
|
||||||
|
|
||||||
|
* gnuefi/elf_ia64_efi.lds: Add .sdata section for small data and
|
||||||
|
put __gp in the "middle" of it.
|
||||||
|
|
||||||
|
* gnuefi/crt0-efi-ia64.S (_start): Use movl/add to load
|
||||||
|
gp-relative addresses that could be out of the range of the addl
|
||||||
|
offset.
|
||||||
|
* gnuefi/reloc_ia64.S (_relocate): Ditto.
|
||||||
|
|
||||||
|
* apps/Makefile: Remove standard rules and include Make.rules instead.
|
||||||
|
* lilo/Makefile: Ditto.
|
||||||
|
|
||||||
|
* Make.rules: New file.
|
||||||
|
|
||||||
|
2000-08-04 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* released version 0.9
|
||||||
|
* incorporated ACPI changes for Asuza by NEC < kouchi@hpc.bs1.fc.nec.co.jp>
|
||||||
|
* added support for initrd (-i option) original ELI code from Bill Nottingham <notting@redhat.com>)
|
||||||
|
* lots of cleanups
|
||||||
|
* got rid of #ifdef LILO_DEBUG and uses macro instead
|
||||||
|
* fix a few extra memory leaks in create_boot_params()
|
||||||
|
* added exit capability just before starting the kernel
|
||||||
|
|
||||||
|
2000-06-22 David Mosberger <davidm@hpl.hp.com>
|
||||||
|
|
||||||
|
* gnuefi/elf_ia64_efi.lds: Add .srodata, .ctors, .IA64.unwind,
|
||||||
|
.IA64.unwind_info to .data section and .rela.ctors to .rela
|
||||||
|
section.
|
||||||
|
|
||||||
|
2000-04-03 David Mosberger <davidm@hpl.hp.com>
|
||||||
|
|
||||||
|
* lilo/lilo.c (LILO_VERSION): Up version number to 0.9.
|
||||||
|
|
||||||
|
* gnuefi/elf_ia64_efi.lds: Include .IA_64.unwind and
|
||||||
|
.IA_64.unwind_info in .data segment to avoid EFI load error
|
||||||
|
"ImageAddress: pointer outside of image" error due to the .dynsym
|
||||||
|
relocations against these sections.
|
||||||
|
|
||||||
|
* ChangeLog: Moved from lilo/ChangeLogs.
|
||||||
|
|
||||||
|
* gnuefi/reloc_ia64.S: fixed typo: .space directive had constant
|
||||||
|
100 hardcoded instead of using MAX_FUNCTION_DESCRIPTORS
|
||||||
|
macro. Duh.
|
||||||
|
|
||||||
|
Fri Mar 17 15:19:18 PST 2000 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
|
||||||
|
* Released 0.8
|
||||||
|
* replace the getopt.c with new version free with better license
|
||||||
|
* created a documentation file
|
||||||
|
* fix a couple of memory leaks
|
||||||
|
* code cleanups
|
||||||
|
* created a separate directory for lilo in the gnu-efi package.
|
||||||
|
* added support for the BOOT_IMAGE argument to kernel
|
||||||
|
* default is to build natively now
|
3
LIMITATIONS
Normal file
3
LIMITATIONS
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
See the TODO file, for more on the known limitations of this version of elilo.
|
||||||
|
|
131
Make.defaults
Normal file
131
Make.defaults
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
#
|
||||||
|
# Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
# Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
#
|
||||||
|
# This file is part of ELILO, the LINUX EFI boot loader.
|
||||||
|
#
|
||||||
|
# ELILO is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# ELILO is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
# Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
# 02111-1307, USA.
|
||||||
|
#
|
||||||
|
# Please check out the elilo.txt for complete documentation on how
|
||||||
|
# to use this program.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# File system selection. At least one filesystem must be enabled
|
||||||
|
#
|
||||||
|
CONFIG_localfs=y
|
||||||
|
CONFIG_netfs=y
|
||||||
|
|
||||||
|
#
|
||||||
|
# WARNING WARNING WARNING
|
||||||
|
#
|
||||||
|
# Use this option with caution. This filesystem module does not
|
||||||
|
# support ext3 formatted partitions, i.e., it does not know how
|
||||||
|
# to recover from failures (ignores the log).
|
||||||
|
#
|
||||||
|
CONFIG_ext2fs=n
|
||||||
|
|
||||||
|
#
|
||||||
|
# Chooser selection(at least one must be defined)
|
||||||
|
#
|
||||||
|
CONFIG_chooser_simple=y
|
||||||
|
CONFIG_chooser_textmenu=y
|
||||||
|
|
||||||
|
#
|
||||||
|
# Enable IP-address based config file (elilo.conf) when netbooted
|
||||||
|
#
|
||||||
|
CONFIG_machspec_netconfig=y
|
||||||
|
|
||||||
|
#
|
||||||
|
# Indicate where the EFI include and libaries are.
|
||||||
|
# They are installed as part of the GNU-EFI package installation
|
||||||
|
#
|
||||||
|
EFIINC = /usr/include/efi
|
||||||
|
GNUEFILIB = /usr/lib
|
||||||
|
EFILIB = /usr/lib
|
||||||
|
EFICRT0 = /usr/lib
|
||||||
|
|
||||||
|
CDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
|
||||||
|
TOPDIR =
|
||||||
|
|
||||||
|
ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,)
|
||||||
|
INCDIR = -I. -I$(TOPDIR) -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol
|
||||||
|
CPPFLAGS = -DCONFIG_$(ARCH)
|
||||||
|
|
||||||
|
OPTIMFLAGS = -O2
|
||||||
|
DEBUGFLAGS = -Wall
|
||||||
|
CFLAGS = $(OPTIMFLAGS) -fpic -fshort-wchar $(DEBUGFLAGS)
|
||||||
|
LDFLAGS = -nostdlib
|
||||||
|
INSTALL = install
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_machspec_netconfig),y)
|
||||||
|
CFLAGS += -DENABLE_MACHINE_SPECIFIC_NETCONFIG
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_localfs),y)
|
||||||
|
CFLAGS += -DCONFIG_LOCALFS
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_netfs),y)
|
||||||
|
CFLAGS += -DCONFIG_NETFS
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_ext2fs),y)
|
||||||
|
CFLAGS += -DCONFIG_EXT2FS
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_chooser_simple),y)
|
||||||
|
CFLAGS += -DCONFIG_CHOOSER_SIMPLE
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_chooser_textmenu),y)
|
||||||
|
CFLAGS += -DCONFIG_CHOOSER_TEXTMENU
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ARCH),ia64)
|
||||||
|
prefix =
|
||||||
|
prefix = /opt/gcc3.1/bin/
|
||||||
|
CC = $(prefix)gcc
|
||||||
|
AS = $(prefix)as
|
||||||
|
LD = $(prefix)ld
|
||||||
|
LD = ld
|
||||||
|
AR = $(prefix)ar
|
||||||
|
RANLIB = $(prefix)ranlib
|
||||||
|
OBJCOPY = $(prefix)objcopy
|
||||||
|
|
||||||
|
GCC_VERSION=$(shell $(CROSS_COMPILE)$(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.')
|
||||||
|
|
||||||
|
ifneq ($(GCC_VERSION),2)
|
||||||
|
CFLAGS += -frename-registers
|
||||||
|
endif
|
||||||
|
#
|
||||||
|
# EFI specs allows only lower floating point partition to be used
|
||||||
|
#
|
||||||
|
# Redhat 8.0 gcc-3.x version is reported to produce working EFI binaries.
|
||||||
|
# Redhat 9.0 gcc-3.x version is reported to produce BAD binaries.
|
||||||
|
#
|
||||||
|
CFLAGS += -mfixed-range=f32-f127
|
||||||
|
else
|
||||||
|
ifeq ($(ARCH),ia32)
|
||||||
|
prefix =
|
||||||
|
CC = $(prefix)gcc3
|
||||||
|
AS = $(prefix)as
|
||||||
|
LD = $(prefix)ld
|
||||||
|
AR = $(prefix)ar
|
||||||
|
RANLIB = $(prefix)ranlib
|
||||||
|
OBJCOPY = $(prefix)objcopy
|
||||||
|
endif
|
||||||
|
endif
|
35
Make.rules
Normal file
35
Make.rules
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#
|
||||||
|
# Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
# Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
#
|
||||||
|
# This file is part of ELILO, the LINUX EFI boot loader.
|
||||||
|
#
|
||||||
|
# ELILO is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# ELILO is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
# Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
# 02111-1307, USA.
|
||||||
|
#
|
||||||
|
# Please check out the elilo.txt for complete documentation on how
|
||||||
|
# to use this program.
|
||||||
|
#
|
||||||
|
|
||||||
|
%.efi: %.so
|
||||||
|
$(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \
|
||||||
|
-j .rela -j .reloc --target=$(FORMAT) $*.so $@
|
||||||
|
|
||||||
|
%.so: %.o
|
||||||
|
$(LD) $(LDFLAGS) $^ -o $@ $(LOADLIBES)
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||||
|
|
103
Makefile
Normal file
103
Makefile
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
#
|
||||||
|
# Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
# Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
#
|
||||||
|
# This file is part of ELILO, the LINUX EFI boot loader.
|
||||||
|
#
|
||||||
|
# ELILO is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# ELILO is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
# Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
# 02111-1307, USA.
|
||||||
|
#
|
||||||
|
# Please check out the elilo.txt for complete documentation on how
|
||||||
|
# to use this program.
|
||||||
|
#
|
||||||
|
|
||||||
|
include Make.defaults
|
||||||
|
TOPDIR=.
|
||||||
|
|
||||||
|
|
||||||
|
CRTOBJS = $(EFICRT0)/crt0-efi-$(ARCH).o
|
||||||
|
LDSCRIPT = $(EFICRT0)/elf_$(ARCH)_efi.lds
|
||||||
|
|
||||||
|
LDFLAGS += -T $(LDSCRIPT) -shared -Bsymbolic -L$(EFILIB) -L$(GNUEFILIB) $(CRTOBJS)
|
||||||
|
LOADLIBES = -lefi -lgnuefi $(shell $(CC) -print-libgcc-file-name)
|
||||||
|
FORMAT = efi-app-$(ARCH)
|
||||||
|
|
||||||
|
FILESYSTEM =
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_localfs),y)
|
||||||
|
FILESYSTEMS += glue_localfs.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_ext2fs),y)
|
||||||
|
FILESYSTEMS += glue_ext2fs.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_netfs),y)
|
||||||
|
FILESYSTEMS += glue_netfs.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
SUBDIRS = fs choosers devschemes tools
|
||||||
|
|
||||||
|
ifeq ($(ARCH),ia64)
|
||||||
|
SUBDIRS += ia64
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ARCH),ia32)
|
||||||
|
SUBDIRS += ia32
|
||||||
|
endif
|
||||||
|
|
||||||
|
FILES = elilo.o getopt.o strops.o loader.o \
|
||||||
|
fileops.o util.o vars.o alloc.o chooser.o \
|
||||||
|
config.o initrd.o alternate.o bootparams.o \
|
||||||
|
fs/fs.o \
|
||||||
|
choosers/choosers.o \
|
||||||
|
devschemes/devschemes.o \
|
||||||
|
$(ARCH)/sysdeps.o \
|
||||||
|
$(FILESYSTEMS)
|
||||||
|
|
||||||
|
TARGETS = elilo.efi
|
||||||
|
|
||||||
|
all: check_gcc $(SUBDIRS) $(TARGETS)
|
||||||
|
|
||||||
|
elilo.efi: elilo.so
|
||||||
|
|
||||||
|
elilo.so: $(FILES)
|
||||||
|
|
||||||
|
elilo.o : elilo.c
|
||||||
|
|
||||||
|
fileops.o : Make.defaults
|
||||||
|
chooser.o : Make.defaults
|
||||||
|
|
||||||
|
$(SUBDIRS): dummy
|
||||||
|
$(MAKE) -C $@
|
||||||
|
|
||||||
|
dummy:
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@set -e ; for d in $(SUBDIRS) ; do $(MAKE) -C $$d $@ ; done
|
||||||
|
rm -f $(TARGETS) *~ *.so $(FILES)
|
||||||
|
|
||||||
|
.PRECIOUS: elilo.so
|
||||||
|
|
||||||
|
#
|
||||||
|
# on both platforms you must use gcc 3.0 or higher
|
||||||
|
#
|
||||||
|
check_gcc:
|
||||||
|
ifeq ($(GCC_VERSION),2)
|
||||||
|
@echo "you need to use a version of gcc >= 3.0, you are using `$(CC) --version`"
|
||||||
|
@exit 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
include Make.rules
|
74
README
Normal file
74
README
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
ELILO: the IA-32 and IA-64 Linux Loader
|
||||||
|
---------------------------------------
|
||||||
|
Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
|
||||||
|
August 2003
|
||||||
|
|
||||||
|
Copyright (C) 2000-2003 Hewlett-Packard Co.
|
||||||
|
|
||||||
|
|
||||||
|
This package contains version 3.4 of elilo, the EFI boot loader
|
||||||
|
for IA-64(IPF) and IA-32(x86) EFI-based platforms.
|
||||||
|
|
||||||
|
|
||||||
|
RELEASE NOTES:
|
||||||
|
--------------
|
||||||
|
Take a look at the Changelog for a detailed list of changes
|
||||||
|
since 3.3a.
|
||||||
|
|
||||||
|
- The major new feature of this release pertains to netbooting.
|
||||||
|
With elilo-3.4, the bootloader will look for files ONLY in the
|
||||||
|
directory if was downloaded from on the TFTP server. Of course,
|
||||||
|
if you specific absolute path, files can be placed anywhere in
|
||||||
|
the TFTP directory structure. This may break some setup but
|
||||||
|
an explicit error message is printed warning the user.
|
||||||
|
|
||||||
|
- There were a bunch of important bug fixes, including handling
|
||||||
|
of paths when booting from the local disk.
|
||||||
|
|
||||||
|
- Downloading of large files work with EFI versions prior to 14.60
|
||||||
|
where there was a bug but also with the fixed version of EFI
|
||||||
|
starting at 14.60.
|
||||||
|
|
||||||
|
- There were also some updates for elilo on IA-32. The loader
|
||||||
|
can load unmodified Linux kernel/initrd image from either the
|
||||||
|
local disk or via netbooting. Thanks to Matt Tolentino at Intel
|
||||||
|
for the IA-32 updates.
|
||||||
|
|
||||||
|
- The ext2fs support code is still present but is not compiled in
|
||||||
|
anymore. This code does not understand ext3fs and might lead to
|
||||||
|
errors because it does not understand the journal.
|
||||||
|
|
||||||
|
This package is known to compile and produce working binaries
|
||||||
|
when used in conjunction with gnu-efi-3.0a. This package is
|
||||||
|
available from the HP Labs FTP site:
|
||||||
|
|
||||||
|
ftp://ftp.hpl.hp.com/pub/linux-ia64/gnu-efi-3.0a.tar.gz
|
||||||
|
|
||||||
|
For IA-64, a toolchain know to produce working binaries is:
|
||||||
|
gcc-3.1
|
||||||
|
binutiuls 2.13.90
|
||||||
|
|
||||||
|
Your may have problems with newer toolchains due to some
|
||||||
|
dependencies in the gnu-efi package. Those dependencies
|
||||||
|
will be fixed eventually.
|
||||||
|
|
||||||
|
For IA-32, the Redhat 8.0 toolchain is known to produce
|
||||||
|
working binaries when used with gnu-efi-3.0a + loader
|
||||||
|
script patch which is included in the gnu-efi-3.0a-ia32.patch
|
||||||
|
in this package. The toolchain includes:
|
||||||
|
|
||||||
|
gcc: gcc version 3.2 20020903 (Red Hat Linux 8.0 3.2-7)
|
||||||
|
as : GNU assembler version 2.13.90.0.2 (i386-redhat-linux)
|
||||||
|
using BFD version 2.13.90.0.2 20020802
|
||||||
|
ld : GNU ld version 2.13.90.0.2 20020802
|
||||||
|
|
||||||
|
The Redhat 9.0 toolchain does not work at the moment.
|
||||||
|
|
||||||
|
DOCUMENTATION:
|
||||||
|
--------------
|
||||||
|
PLEASE READ THE docs/elilo.txt file for some documentation on how
|
||||||
|
to use this program. For netbooting refer to docs/netbooting.txt.
|
||||||
|
|
||||||
|
Make sure you read the README.gnu-efi file for required packages.
|
||||||
|
|
31
README.gnu-efi
Normal file
31
README.gnu-efi
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
IMPORTANT Information related to the gnu-efi package
|
||||||
|
----------------------------------------------------
|
||||||
|
August 2003
|
||||||
|
|
||||||
|
As of version elilo-3.0, the gnu-efi package is now split in two different packages:
|
||||||
|
|
||||||
|
-> gnu-efi-X.y: contains the EFI library, header, files, and crt0.
|
||||||
|
|
||||||
|
-> elilo-X.y : contains the ELILO bootloader.
|
||||||
|
|
||||||
|
Note that X.y don't need to match for both packages. However elilo-3.x requires at
|
||||||
|
least gnu-efi >= 3.0. When using a version of gcc >3.0 you MUST use at least gnu-efi-3.0a.
|
||||||
|
|
||||||
|
IMPORTANT NOTE FOR IA-32:
|
||||||
|
-------------------------
|
||||||
|
For IA-32, the Redhat 8.0 toolchain is known to produce
|
||||||
|
working binaries when used with gnu-efi-3.0a + loader
|
||||||
|
script patch which is included in the gnu-efi-3.0a-ia32.patch
|
||||||
|
in this package. The toolchain includes:
|
||||||
|
|
||||||
|
gcc: gcc version 3.2 20020903 (Red Hat Linux 8.0 3.2-7)
|
||||||
|
as: GNU assembler version 2.13.90.0.2 (i386-redhat-linux) using BFD version
|
||||||
|
2.13.90.0.2 20020802
|
||||||
|
ld: GNU ld version 2.13.90.0.2 20020802
|
||||||
|
|
||||||
|
The Redhat 9.0 toolchain does not work at the moment.
|
||||||
|
|
||||||
|
The gnu-efi package can be downloaded from:
|
||||||
|
|
||||||
|
ftp://ftp.hpl.hp.com/pub/linux-ia64/gnu-efi-X.y.tar.gz
|
18
TODO
Normal file
18
TODO
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
Some of the things TO DO:
|
||||||
|
-------------------------
|
||||||
|
- a better device naming scheme (take into account removable media)
|
||||||
|
|
||||||
|
- ability to rescan devices like when something gets inserted just
|
||||||
|
before invoking elilo and the efi shell is not used (the mount())
|
||||||
|
|
||||||
|
- ability to list files from the interactive mode
|
||||||
|
|
||||||
|
- GUI-based chooser (a la RH9.x)!
|
||||||
|
|
||||||
|
- UGA support?
|
||||||
|
|
||||||
|
- Convert all filesystems (ext2fs, netfs) to use the FilesystemProtocol interface instead
|
||||||
|
|
||||||
|
- cleanup x86 loader: use the same structure as IA-64
|
||||||
|
|
||||||
|
- support for subnetting in the config file when netbooting
|
240
alloc.c
Normal file
240
alloc.c
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
|
||||||
|
#define NALLOC 512
|
||||||
|
|
||||||
|
typedef enum { ALLOC_POOL, ALLOC_PAGES } alloc_types_t;
|
||||||
|
|
||||||
|
typedef struct _alloc_entry {
|
||||||
|
struct _alloc_entry *next;
|
||||||
|
struct _alloc_entry *prev;
|
||||||
|
VOID *addr;
|
||||||
|
UINTN size; /* bytes for pool, page count for pages */
|
||||||
|
alloc_types_t type;
|
||||||
|
} alloc_entry_t;
|
||||||
|
|
||||||
|
static alloc_entry_t allocs[NALLOC];
|
||||||
|
static alloc_entry_t *free_allocs, *used_allocs;
|
||||||
|
|
||||||
|
static VOID *kmem_addr;
|
||||||
|
static UINTN kmem_pgcnt;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initializes the free list which is singly linked
|
||||||
|
*/
|
||||||
|
INTN
|
||||||
|
alloc_init(VOID)
|
||||||
|
{
|
||||||
|
UINTN i;
|
||||||
|
|
||||||
|
for(i=0; i < NALLOC-1; i++) {
|
||||||
|
allocs[i].next = allocs+i+1;
|
||||||
|
}
|
||||||
|
allocs[i].next = NULL;
|
||||||
|
|
||||||
|
free_allocs = allocs;
|
||||||
|
used_allocs = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
alloc_add(VOID * addr, UINTN size, alloc_types_t type)
|
||||||
|
{
|
||||||
|
alloc_entry_t *alloc;
|
||||||
|
|
||||||
|
/* remove from freelist */
|
||||||
|
alloc = free_allocs;
|
||||||
|
free_allocs = free_allocs->next;
|
||||||
|
|
||||||
|
alloc->prev = NULL;
|
||||||
|
alloc->next = used_allocs;
|
||||||
|
alloc->addr = addr;
|
||||||
|
alloc->type = type;
|
||||||
|
alloc->size = size;
|
||||||
|
|
||||||
|
/* add to used list */
|
||||||
|
if (used_allocs) used_allocs->prev = alloc;
|
||||||
|
|
||||||
|
used_allocs = alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID *
|
||||||
|
alloc(UINTN size, EFI_MEMORY_TYPE type)
|
||||||
|
{
|
||||||
|
EFI_STATUS status;
|
||||||
|
VOID *tmp = 0;
|
||||||
|
|
||||||
|
/* no more free slots */
|
||||||
|
if (free_allocs == NULL) {
|
||||||
|
ERR_PRT((L"allocator: no more slots\n"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == 0) type = EfiLoaderData;
|
||||||
|
|
||||||
|
status = BS->AllocatePool (type, size, &tmp);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"allocator: AllocatePool(%d, %d, 0x%x) failed (%r)\n", type, size, status));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
alloc_add(tmp, size, ALLOC_POOL);
|
||||||
|
|
||||||
|
DBG_PRT((L"alloc: allocated %d bytes @[0x%lx-0x%lx]\n", size, tmp, tmp+size));
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* no possibility to partially free an allocated group of pages
|
||||||
|
*/
|
||||||
|
VOID *
|
||||||
|
alloc_pages(UINTN pgcnt, EFI_MEMORY_TYPE type, EFI_ALLOCATE_TYPE where, VOID *addr)
|
||||||
|
{
|
||||||
|
EFI_STATUS status;
|
||||||
|
EFI_PHYSICAL_ADDRESS tmp = (EFI_PHYSICAL_ADDRESS)addr;
|
||||||
|
|
||||||
|
/* no more free slots */
|
||||||
|
if (free_allocs == NULL) {
|
||||||
|
ERR_PRT((L"allocator: no more slots\n"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = BS->AllocatePages(where, type , pgcnt, &tmp);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"allocator: AllocatePages(%d, %d, %d, 0x%lx) failed (%r)\n", where, type, pgcnt, tmp, status));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* XXX: will cause warning on IA-32 */
|
||||||
|
addr = (VOID *)tmp;
|
||||||
|
|
||||||
|
alloc_add(addr, pgcnt, ALLOC_PAGES);
|
||||||
|
|
||||||
|
DBG_PRT((L"allocator: allocated %d pages @0x%lx\n", pgcnt, tmp));
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* free previously allocated slot
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
free(VOID *addr)
|
||||||
|
{
|
||||||
|
alloc_entry_t *p;
|
||||||
|
|
||||||
|
/* find allocation record */
|
||||||
|
for(p=used_allocs; p ; p = p->next) {
|
||||||
|
if (p->addr == addr) goto found;
|
||||||
|
}
|
||||||
|
/* not found */
|
||||||
|
ERR_PRT((L"allocator: invalid free @ 0x%lx\n", addr));
|
||||||
|
return;
|
||||||
|
found:
|
||||||
|
DBG_PRT((L"free: %s @0x%lx size=%ld\n",
|
||||||
|
p->type == ALLOC_POOL ? L"Pool": L"Page",
|
||||||
|
addr, p->size));
|
||||||
|
|
||||||
|
if (p->type == ALLOC_POOL)
|
||||||
|
BS->FreePool(addr);
|
||||||
|
else
|
||||||
|
BS->FreePages((EFI_PHYSICAL_ADDRESS)addr, p->size);
|
||||||
|
|
||||||
|
/* remove from used list */
|
||||||
|
if (p->next)
|
||||||
|
p->next->prev = p->prev;
|
||||||
|
|
||||||
|
if (p->prev)
|
||||||
|
p->prev->next = p->next;
|
||||||
|
else
|
||||||
|
used_allocs = p->next;
|
||||||
|
|
||||||
|
/* put back on free list */
|
||||||
|
p->next = free_allocs;
|
||||||
|
free_allocs = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* garbage collect all used allocations.
|
||||||
|
* will put the allocator in initial state
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
free_all(VOID)
|
||||||
|
{
|
||||||
|
alloc_entry_t *tmp;
|
||||||
|
|
||||||
|
while(used_allocs) {
|
||||||
|
|
||||||
|
DBG_PRT((L"free_all %a @ 0x%lx\n", used_allocs->type == ALLOC_POOL ? "pool" : "pages", used_allocs->addr));
|
||||||
|
|
||||||
|
if (used_allocs->type == ALLOC_POOL)
|
||||||
|
BS->FreePool(used_allocs->addr);
|
||||||
|
else
|
||||||
|
BS->FreePages((EFI_PHYSICAL_ADDRESS)used_allocs->addr, used_allocs->size);
|
||||||
|
|
||||||
|
tmp = used_allocs->next;
|
||||||
|
|
||||||
|
/* put back on free list */
|
||||||
|
used_allocs->next = free_allocs;
|
||||||
|
free_allocs = used_allocs;
|
||||||
|
|
||||||
|
used_allocs = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
alloc_kmem(VOID *start_addr, UINTN pgcnt)
|
||||||
|
{
|
||||||
|
if (alloc_pages(pgcnt, EfiLoaderData, AllocateAddress, start_addr) == 0) return -1;
|
||||||
|
|
||||||
|
kmem_addr = start_addr;
|
||||||
|
kmem_pgcnt = pgcnt;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
free_kmem(VOID)
|
||||||
|
{
|
||||||
|
DBG_PRT((L"free_kmem before (%lx, %ld)\n", kmem_addr, kmem_pgcnt));
|
||||||
|
if (kmem_addr && kmem_pgcnt != 0) {
|
||||||
|
free(kmem_addr);
|
||||||
|
kmem_addr = NULL;
|
||||||
|
kmem_pgcnt = 0;
|
||||||
|
}
|
||||||
|
DBG_PRT((L"free_kmem after (%lx, %ld)\n", kmem_addr, kmem_pgcnt));
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
free_all_memory(VOID)
|
||||||
|
{
|
||||||
|
free_all();
|
||||||
|
free_kmem();
|
||||||
|
}
|
118
alternate.c
Normal file
118
alternate.c
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
|
||||||
|
#define ELILO_ALTK_VAR L"EliloAlt"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we use a NULL GUID for now because it is more convenient
|
||||||
|
*/
|
||||||
|
static EFI_GUID altk_guid={0,};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for the existence of an EFI variable named EliloAlt.
|
||||||
|
* It contains the name of an alternate kernel (and possible options)
|
||||||
|
* to boot ONLY once.
|
||||||
|
* The variable is then deleted. This ensures that next reboot won't
|
||||||
|
* pick it up.
|
||||||
|
*
|
||||||
|
* The content of the variable is assumed to be Unicode string. It is
|
||||||
|
* preferrably NULL terminated but the code can deal with this as well.
|
||||||
|
*
|
||||||
|
* The size of the buffer MUST be expressed in bytes (not CHAR16).
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* - 0 if successful
|
||||||
|
* - -1 in case nothing happened (no variable found)
|
||||||
|
* Please note that no fatal error is reported by this function
|
||||||
|
*/
|
||||||
|
INTN
|
||||||
|
alternate_kernel(CHAR16 *buffer, INTN size)
|
||||||
|
{
|
||||||
|
EFI_STATUS status;
|
||||||
|
INTN ret = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* size of the buffer is expressed in bytes
|
||||||
|
*
|
||||||
|
* we reserve one Unicode for CHAR_NULL (forced), so
|
||||||
|
* the buffer must be at least 2 more bytes to accomodate one Unicode
|
||||||
|
*/
|
||||||
|
if (size < 4) return -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reserve for CHAR_NULL
|
||||||
|
*/
|
||||||
|
size-=2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look if the variable exists.
|
||||||
|
* We may fail because:
|
||||||
|
* - the variable does not exist
|
||||||
|
* - our buffer size is too small.
|
||||||
|
*/
|
||||||
|
status = RT->GetVariable(ELILO_ALTK_VAR, &altk_guid, NULL, &size, buffer);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
DBG_PRT((L"cannot access variable %s: %r", ELILO_ALTK_VAR, status));
|
||||||
|
|
||||||
|
/* if buffer is too small, erase variable because it's unuseable */
|
||||||
|
if (status == EFI_BUFFER_TOO_SMALL) goto delete_var;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* sanity check
|
||||||
|
*
|
||||||
|
* verify that size (expressed in bytes) is multiple of 2. If
|
||||||
|
* not then it can't possibly be representing a UNICODE string
|
||||||
|
* (2bytes/character).
|
||||||
|
*
|
||||||
|
* We also consider empty as useless (2nd test).
|
||||||
|
*/
|
||||||
|
if (size & 0x1) {
|
||||||
|
Print(L"invalid content for %s variable, erasing variable\n", ELILO_ALTK_VAR);
|
||||||
|
goto delete_var;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We also consider empty as useless (2nd test) */
|
||||||
|
if (size == 2) goto delete_var;
|
||||||
|
|
||||||
|
buffer[size] = CHAR_NULL;
|
||||||
|
|
||||||
|
VERB_PRT(2, Print(L"found alternate variable %s : %s\n", ELILO_ALTK_VAR, buffer));
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
delete_var:
|
||||||
|
status = RT->SetVariable(ELILO_ALTK_VAR, &altk_guid, 0, 0, NULL);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"cannot erase variable %s", ELILO_ALTK_VAR));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
123
bootparams.c
Normal file
123
bootparams.c
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the generic part of the boot parameters and call the architecture specific
|
||||||
|
* subroutine.
|
||||||
|
* Output:
|
||||||
|
* cookie: the memory map cookie to use with ExitBootServices()
|
||||||
|
* Return:
|
||||||
|
* NULL: if an error occured
|
||||||
|
* bp : the address of the bootparams otherwise (opaque type)
|
||||||
|
*/
|
||||||
|
VOID *
|
||||||
|
create_boot_params(CHAR16 *args, memdesc_t *initrd, UINTN *cookie)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* XXX: need cleanup
|
||||||
|
* See ia32 code for explanation on why it is so big.
|
||||||
|
*/
|
||||||
|
#define BOOT_PARAM_MEMSIZE 16384
|
||||||
|
UINTN bpsize, cmdline_size;
|
||||||
|
boot_params_t *bp;
|
||||||
|
CHAR8 *cp;
|
||||||
|
CHAR16 ch;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate runtime services memory to hold memory descriptor table and
|
||||||
|
* command line arguments and fetch memory map:
|
||||||
|
*
|
||||||
|
* arg_size = number of character in ASCII form
|
||||||
|
*/
|
||||||
|
cmdline_size = StrLen(args) + 1;
|
||||||
|
bpsize = sizeof(boot_params_t) + cmdline_size;
|
||||||
|
|
||||||
|
if (bpsize > BOOT_PARAM_MEMSIZE) {
|
||||||
|
ERR_PRT((L"BOOT_PARAM_MEMSIZE too small, need at least %d bytes", bpsize));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate memory for boot parameters.
|
||||||
|
* This CANNOT be EfiLoaderData or EfiLoaderCode as the kernel
|
||||||
|
* frees this region when initializing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bp = (boot_params_t *)alloc(BOOT_PARAM_MEMSIZE, EfiLoaderData);
|
||||||
|
if (bp == NULL) {
|
||||||
|
ERR_PRT((L"can't allocate boot params"));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VERB_PRT(3, Print(L"boot params @ 0x%lx\n", bp));
|
||||||
|
|
||||||
|
/* XXX: need to fix this for 3.5 */
|
||||||
|
#ifdef CONFIG_ia64
|
||||||
|
cp = ((CHAR8 *)bp) + BOOT_PARAM_MEMSIZE - cmdline_size;
|
||||||
|
#elif defined CONFIG_ia32
|
||||||
|
cp = ((CHAR8 *)bp) + BOOT_PARAM_MEMSIZE - 2048;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clear entire buffer. The boot param structure is bigger than
|
||||||
|
* needs be but this allows the kernel bootparam structure to grow
|
||||||
|
* (up to BOOT_PARAM_MEMSIZE) without having to worry about fixing the bootloader.
|
||||||
|
* By convention between the laoder and the kernel, the value 0 means
|
||||||
|
* don't care or not set.
|
||||||
|
*/
|
||||||
|
Memset(bp, 0, BOOT_PARAM_MEMSIZE);
|
||||||
|
|
||||||
|
if (sysdeps_create_boot_params(bp, cp, initrd, cookie) == -1) return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert kernel command line args from UNICODE to ASCII and put them where
|
||||||
|
* the kernel expects them:
|
||||||
|
*/
|
||||||
|
while (1) {
|
||||||
|
ch = *args++;
|
||||||
|
if (!ch) break;
|
||||||
|
*cp++ = ch;
|
||||||
|
}
|
||||||
|
*cp++ = '\0';
|
||||||
|
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
free_boot_params(VOID *bp)
|
||||||
|
{
|
||||||
|
boot_params_t *real_bp = (boot_params_t *)bp;
|
||||||
|
|
||||||
|
sysdeps_free_boot_params(real_bp);
|
||||||
|
|
||||||
|
free(real_bp);
|
||||||
|
}
|
||||||
|
|
114
chooser.c
Normal file
114
chooser.c
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_CHOOSER_SIMPLE
|
||||||
|
#include "choosers/simple.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_CHOOSER_TEXTMENU
|
||||||
|
#include "choosers/textmenu.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static chooser_t *choosers_tab[]={
|
||||||
|
#ifdef CONFIG_CHOOSER_SIMPLE
|
||||||
|
&simple_chooser,
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_CHOOSER_TEXTMENU
|
||||||
|
&textmenu_chooser,
|
||||||
|
#endif
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
* The intent of this module is to provide a mechanism by which alternate
|
||||||
|
* choosers can be installed. Developers can write new choosers and
|
||||||
|
* add them to the list. They will be probe and the best match
|
||||||
|
* will be started first. It should be possible to switch to another
|
||||||
|
* chooser using a key combination. There is a default simple text-based
|
||||||
|
* chooser that must always be present.
|
||||||
|
*
|
||||||
|
* Currently you can specify a chooser via "-c name" when you invoke elilo,
|
||||||
|
* or via "chooser=name" in the config file. If the specified chooser
|
||||||
|
* probes ok it will be selected, otherwise the first one that probes ok
|
||||||
|
* will be used.
|
||||||
|
*
|
||||||
|
* XXX: at this time, not all chooser functionalities are implemented.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
chooser_func_t *kernel_chooser;
|
||||||
|
|
||||||
|
INTN
|
||||||
|
init_chooser(EFI_HANDLE dev)
|
||||||
|
{
|
||||||
|
chooser_t **p;
|
||||||
|
CHAR16 *chooser_name = L"none";
|
||||||
|
|
||||||
|
kernel_chooser = NULL;
|
||||||
|
|
||||||
|
for (p=choosers_tab; *p; p++) {
|
||||||
|
|
||||||
|
VERB_PRT(4, Print(L"trying chooser %s\n", (*p)->chooser_name));
|
||||||
|
|
||||||
|
if ((*p)->chooser_probe(dev) == 0) {
|
||||||
|
/*
|
||||||
|
* if that's the one we asked for, then go for it
|
||||||
|
*/
|
||||||
|
if (!StrCmp(elilo_opt.chooser, (*p)->chooser_name)) {
|
||||||
|
kernel_chooser = (*p)->chooser_func;
|
||||||
|
chooser_name = (*p)->chooser_name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kernel_chooser == NULL) {
|
||||||
|
kernel_chooser = (*p)->chooser_func;
|
||||||
|
chooser_name = (*p)->chooser_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kernel_chooser) {
|
||||||
|
VERB_PRT(2, Print(L"selected chooser %s\n", chooser_name));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_PRT((L"No chooser selected. Impossible to proceed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
exist_chooser(CHAR16 *name)
|
||||||
|
{
|
||||||
|
chooser_t **p;
|
||||||
|
|
||||||
|
for (p=choosers_tab; *p; p++) {
|
||||||
|
if (!StrCmp(name, (*p)->chooser_name)) return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
60
chooser.h
Normal file
60
chooser.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* GNU EFI is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* GNU EFI is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU EFI; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ELILO_CHOOSER_H__
|
||||||
|
#define __ELILO_CHOOSER_H__
|
||||||
|
|
||||||
|
typedef INTN chooser_func_t(CHAR16 **argv, INTN arc, INTN index, CHAR16 *kname, CHAR16 *cmdline);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* structure to interface to generic chooser selection code.
|
||||||
|
*
|
||||||
|
* XXX: must add support for moer than one choice (rating scheme)
|
||||||
|
*
|
||||||
|
* Interface for probe:
|
||||||
|
* dev: boot device handle
|
||||||
|
* return: -1, if not support, 0 if supported
|
||||||
|
*
|
||||||
|
* Interface for chooser:
|
||||||
|
* argv,argc: command line argument passed to elilo
|
||||||
|
* index : position of first non-option argument (min value=1)
|
||||||
|
* kname : selected kernel name
|
||||||
|
* cmdline : requested kernel command line
|
||||||
|
* return:
|
||||||
|
* -1: if error
|
||||||
|
* 0: if successful
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
CHAR16 *chooser_name;
|
||||||
|
INTN (*chooser_probe)(EFI_HANDLE dev);
|
||||||
|
chooser_func_t *chooser_func;
|
||||||
|
} chooser_t;
|
||||||
|
|
||||||
|
extern INTN init_chooser(EFI_HANDLE);
|
||||||
|
extern INTN exist_chooser(CHAR16 *name);
|
||||||
|
|
||||||
|
extern chooser_func_t *kernel_chooser;
|
||||||
|
|
||||||
|
#endif /* __ELILO_CHOOSER_H__ */
|
58
choosers/Makefile
Normal file
58
choosers/Makefile
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#
|
||||||
|
# Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
# Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
#
|
||||||
|
# This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
#
|
||||||
|
# ELILO is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# ELILO is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
# Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
# 02111-1307, USA.
|
||||||
|
#
|
||||||
|
# Please check out the elilo.txt for complete documentation on how
|
||||||
|
# to use this program.
|
||||||
|
#
|
||||||
|
|
||||||
|
include ../Make.defaults
|
||||||
|
include ../Make.rules
|
||||||
|
|
||||||
|
TOPDIR=$(CDIR)/..
|
||||||
|
|
||||||
|
FILES=
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_chooser_simple),y)
|
||||||
|
FILES +=simple.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_chooser_textmenu),y)
|
||||||
|
FILES +=textmenu.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
TARGET=choosers.o
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): check-choosers $(TOPDIR)/Make.defaults $(FILES)
|
||||||
|
$(LD) -o $@ -r $(FILES)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) -f $(TARGET) $(FILES)
|
||||||
|
|
||||||
|
check-choosers:
|
||||||
|
@if [ -n "$(FILES)" ]; then \
|
||||||
|
exit 0; \
|
||||||
|
else \
|
||||||
|
echo "You need to define at least one chooser in Make.defaults"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
|
410
choosers/simple.c
Normal file
410
choosers/simple.c
Normal file
|
@ -0,0 +1,410 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
#include "vars.h"
|
||||||
|
|
||||||
|
/* static is ugly but does the job here! */
|
||||||
|
static CHAR16 **alt_argv;
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
display_label_info(CHAR16 *name)
|
||||||
|
{
|
||||||
|
CHAR16 *desc;
|
||||||
|
CHAR16 initrd_name[CMDLINE_MAXLEN];
|
||||||
|
CHAR16 options_tmp[CMDLINE_MAXLEN];
|
||||||
|
CHAR16 options[CMDLINE_MAXLEN];
|
||||||
|
CHAR16 kname[FILENAME_MAXLEN];
|
||||||
|
|
||||||
|
desc = find_description(name);
|
||||||
|
if (desc) {
|
||||||
|
Print(L"desc : %s\n", desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
initrd_name[0] = options_tmp[0] = kname[0] = CHAR_NULL;
|
||||||
|
|
||||||
|
if (find_label(name, kname, options_tmp, initrd_name) == -1) {
|
||||||
|
StrCpy(kname, name);
|
||||||
|
Print(L"\n");
|
||||||
|
}
|
||||||
|
subst_vars(options_tmp, options, CMDLINE_MAXLEN);
|
||||||
|
|
||||||
|
Print(L"cmdline: %s %s\n", kname, options);
|
||||||
|
if (initrd_name[0]) Print(L"initrd : %s\n", initrd_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
print_infos(int force)
|
||||||
|
{
|
||||||
|
CHAR16 *config_file;
|
||||||
|
CHAR16 dpath[FILENAME_MAXLEN];
|
||||||
|
CHAR16 *boot_dev_name;
|
||||||
|
UINT8 is_abs;
|
||||||
|
|
||||||
|
boot_dev_name = fops_bootdev_name();
|
||||||
|
config_file = get_config_file();
|
||||||
|
|
||||||
|
fops_getdefault_path(dpath, FILENAME_MAXLEN);
|
||||||
|
|
||||||
|
if (force || elilo_opt.verbose > 0)
|
||||||
|
Print(L"default file path: %s:%s\n", boot_dev_name, dpath);
|
||||||
|
|
||||||
|
is_abs = config_file && (config_file[0] == CHAR_BACKSLASH || config_file[0] == CHAR_SLASH) ? 1 : 0;
|
||||||
|
|
||||||
|
if (force || elilo_opt.verbose > 0)
|
||||||
|
Print(L"config file : %s%s\n", config_file && is_abs == 0 ? dpath : L"", config_file ? config_file : L"none used");
|
||||||
|
|
||||||
|
if (alt_argv) {
|
||||||
|
CHAR16 **p = alt_argv;
|
||||||
|
Print(L"found alternate default choice :");
|
||||||
|
while (*p) Print(L" %s", *p++);
|
||||||
|
Print(L"\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
print_help(int force)
|
||||||
|
{
|
||||||
|
if (force || elilo_opt.verbose > 0)
|
||||||
|
Print(L"command list (must be first character):\n=:print device list, %%:print variable list, &:print paths, ?:help\nTAB:print label information\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* interactively select a kernel image and options.
|
||||||
|
* The kernel can be an actual filename or a label in the config file
|
||||||
|
* Return:
|
||||||
|
* -1: if unsucessful
|
||||||
|
* 0: otherwise
|
||||||
|
*/
|
||||||
|
static INTN
|
||||||
|
select_kernel(CHAR16 *buffer, INTN size)
|
||||||
|
{
|
||||||
|
#define CHAR_CTRL_C L'\003' /* Unicode CTRL-C */
|
||||||
|
#define CHAR_CTRL_D L'\004' /* Unicode CTRL-D */
|
||||||
|
#define CHAR_CTRL_U L'\025' /* Unicode CTRL-U */
|
||||||
|
//#define CHAR_TAB L'\t'
|
||||||
|
SIMPLE_INPUT_INTERFACE *ip = systab->ConIn;
|
||||||
|
EFI_INPUT_KEY key;
|
||||||
|
EFI_STATUS status;
|
||||||
|
INTN pos = 0, ret;
|
||||||
|
INT8 first_time = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* let's give some help first
|
||||||
|
*/
|
||||||
|
print_help(0);
|
||||||
|
|
||||||
|
print_infos(0);
|
||||||
|
|
||||||
|
reprint:
|
||||||
|
buffer[pos] = CHAR_NULL;
|
||||||
|
|
||||||
|
Print(L"\nELILO boot: %s", buffer);
|
||||||
|
/*
|
||||||
|
* autoboot with default choice after timeout expires
|
||||||
|
*/
|
||||||
|
if (first_time && (ret=wait_timeout(elilo_opt.timeout)) != 1) {
|
||||||
|
return ret == -1 ? -1: 0;
|
||||||
|
}
|
||||||
|
first_time = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
while ((status=ip->ReadKeyStroke(ip, &key)) == EFI_NOT_READY);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"select_kernel readkey: %r", status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
switch (key.UnicodeChar) {
|
||||||
|
case CHAR_TAB:
|
||||||
|
Print(L"\n");
|
||||||
|
if (pos == 0) {
|
||||||
|
print_label_list();
|
||||||
|
Print(L"(or a kernel file name: [[dev_name:/]path/]kernel_image cmdline options)\n");
|
||||||
|
} else {
|
||||||
|
buffer[pos] = CHAR_NULL;
|
||||||
|
display_label_info(buffer);
|
||||||
|
}
|
||||||
|
goto reprint;
|
||||||
|
case L'%':
|
||||||
|
if (pos>0) goto normal_char;
|
||||||
|
Print(L"\n");
|
||||||
|
print_vars();
|
||||||
|
goto reprint;
|
||||||
|
case L'?':
|
||||||
|
if (pos>0) goto normal_char;
|
||||||
|
Print(L"\n");
|
||||||
|
print_help(1);
|
||||||
|
goto reprint;
|
||||||
|
case L'&':
|
||||||
|
if (pos>0) goto normal_char;
|
||||||
|
Print(L"\n");
|
||||||
|
print_infos(1);
|
||||||
|
goto reprint;
|
||||||
|
case L'=':
|
||||||
|
if (pos>0) goto normal_char;
|
||||||
|
Print(L"\n");
|
||||||
|
print_devices();
|
||||||
|
goto reprint;
|
||||||
|
case CHAR_BACKSPACE:
|
||||||
|
if (pos == 0) break;
|
||||||
|
pos--;
|
||||||
|
Print(L"\b \b");
|
||||||
|
break;
|
||||||
|
case CHAR_CTRL_U: /* clear line */
|
||||||
|
while (pos) {
|
||||||
|
Print(L"\b \b");
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHAR_CTRL_C: /* kill line */
|
||||||
|
pos = 0;
|
||||||
|
goto reprint;
|
||||||
|
case CHAR_LINEFEED:
|
||||||
|
case CHAR_CARRIAGE_RETURN:
|
||||||
|
buffer[pos] = CHAR_NULL;
|
||||||
|
Print(L"\n");
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
normal_char:
|
||||||
|
if (key.UnicodeChar == CHAR_CTRL_D || key.ScanCode == 0x17 ) {
|
||||||
|
Print(L"\nGiving up then...\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (key.UnicodeChar == CHAR_NULL) break;
|
||||||
|
|
||||||
|
if (pos > size-1) break;
|
||||||
|
|
||||||
|
buffer[pos++] = key.UnicodeChar;
|
||||||
|
|
||||||
|
/* Write the character out */
|
||||||
|
Print(L"%c", key.UnicodeChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
display_message(VOID)
|
||||||
|
{
|
||||||
|
fops_fd_t fd;
|
||||||
|
EFI_STATUS status;
|
||||||
|
INTN len, i;
|
||||||
|
CHAR16 *filename;
|
||||||
|
CHAR8 buf[256];
|
||||||
|
|
||||||
|
if ((filename = get_message_filename(0)) == NULL) return;
|
||||||
|
|
||||||
|
if (*filename == CHAR_NULL) return;
|
||||||
|
|
||||||
|
VERB_PRT(3, Print(L"opening message file %s\n", filename));
|
||||||
|
|
||||||
|
status = fops_open(filename, &fd);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
VERB_PRT(3, Print(L"message file %s not found\n", filename));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
len = 256;
|
||||||
|
Print(L"\n");
|
||||||
|
while ((status = fops_read(fd, buf, &len)) == EFI_SUCCESS) {
|
||||||
|
/* XXX: ugly ! */
|
||||||
|
for (i=0; i < len; i++) {
|
||||||
|
Print(L"%c", (CHAR16)buf[i]);
|
||||||
|
}
|
||||||
|
if (len < 256) break;
|
||||||
|
}
|
||||||
|
fops_close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
simple_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmdline)
|
||||||
|
{
|
||||||
|
# define BOOT_IMG_STR L"BOOT_IMAGE="
|
||||||
|
CHAR16 buffer[CMDLINE_MAXLEN];
|
||||||
|
CHAR16 alt_buffer[CMDLINE_MAXLEN];
|
||||||
|
CHAR16 initrd_name[CMDLINE_MAXLEN];
|
||||||
|
CHAR16 args[CMDLINE_MAXLEN];
|
||||||
|
CHAR16 devname[CMDLINE_MAXLEN];
|
||||||
|
CHAR16 dpath[FILENAME_MAXLEN];
|
||||||
|
CHAR16 *slash_pos, *colon_pos, *backslash_pos;
|
||||||
|
UINTN len;
|
||||||
|
INTN ret;
|
||||||
|
|
||||||
|
buffer[0] = alt_buffer[0] = CHAR_NULL;
|
||||||
|
|
||||||
|
display_message();
|
||||||
|
|
||||||
|
restart:
|
||||||
|
initrd_name[0] = kname[0] = cmdline[0] = args[0] = CHAR_NULL;
|
||||||
|
|
||||||
|
/* reset per image loader options */
|
||||||
|
Memset(&elilo_opt.img_opt, 0, sizeof(elilo_opt.img_opt));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check for alternate kernel image and params in EFI variable
|
||||||
|
*/
|
||||||
|
if (elilo_opt.alt_check && alternate_kernel(alt_buffer, sizeof(alt_buffer)) == 0) {
|
||||||
|
argc = argify(alt_buffer,sizeof(alt_buffer), argv);
|
||||||
|
alt_argv = argv;
|
||||||
|
index = 0;
|
||||||
|
args[0] = initrd_name[0] = 0;
|
||||||
|
/*
|
||||||
|
* don't check twice because the variable is deleted after
|
||||||
|
* first access
|
||||||
|
*/
|
||||||
|
elilo_opt.alt_check = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elilo_opt.prompt) {
|
||||||
|
ret = select_kernel(buffer, sizeof(buffer));
|
||||||
|
if (ret == -1) return -1;
|
||||||
|
argc = argify(buffer,sizeof(buffer), argv);
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if we found an alternate choice and the user
|
||||||
|
* did not force it manually, then use the alternate
|
||||||
|
* option.
|
||||||
|
*/
|
||||||
|
if (alt_buffer[0] && buffer[0] == CHAR_NULL) {
|
||||||
|
StrCpy(buffer, alt_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First search for matching label in the config file
|
||||||
|
* if options were specified on command line, they take
|
||||||
|
* precedence over the ones in the config file
|
||||||
|
*
|
||||||
|
* if no match is found, the args and initrd arguments may
|
||||||
|
* still be modified by global options in the config file.
|
||||||
|
*/
|
||||||
|
ret = find_label(argv[index], kname, args, initrd_name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* not found, so assume first argument is kernel name and
|
||||||
|
* not label name
|
||||||
|
*/
|
||||||
|
if (ret == -1) {
|
||||||
|
if (argv[index])
|
||||||
|
StrCpy(kname, argv[index]);
|
||||||
|
else
|
||||||
|
StrCpy(kname, elilo_opt.default_kernel);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* no matter what happened for kname, if user specified
|
||||||
|
* additional options, they override the ones in the
|
||||||
|
* config file
|
||||||
|
*/
|
||||||
|
if (argc > 1+index) {
|
||||||
|
/*StrCpy(args, argv[++index]);*/
|
||||||
|
while (++index < argc) {
|
||||||
|
StrCat(args, L" ");
|
||||||
|
StrCat(args, argv[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* if initrd specified on command line, it overrides
|
||||||
|
* the one defined in config file, if any
|
||||||
|
*/
|
||||||
|
if (elilo_opt.initrd[0] == CHAR_NULL && initrd_name[0] != CHAR_NULL) {
|
||||||
|
StrCpy(elilo_opt.initrd, initrd_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
VERB_PRT(1, { Print(L"kernel is '%s'\n", kname);
|
||||||
|
Print(L"arguments are '%s'\n", args);
|
||||||
|
if (elilo_opt.initrd[0]) Print(L"initrd is '%s'\n", elilo_opt.initrd);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (elilo_opt.prompt == 0) {
|
||||||
|
/* minimal printing */
|
||||||
|
Print(L"ELILO\n");
|
||||||
|
ret = wait_timeout(elilo_opt.delay);
|
||||||
|
if (ret != 0) {
|
||||||
|
elilo_opt.prompt = 1;
|
||||||
|
elilo_opt.timeout = ELILO_TIMEOUT_INFINITY;
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* add the device name, if not already specified,
|
||||||
|
* so that we know where we came from
|
||||||
|
*/
|
||||||
|
slash_pos = StrChr(kname, L'/');
|
||||||
|
backslash_pos = StrChr(kname, L'\\');
|
||||||
|
colon_pos = StrChr(kname, L':');
|
||||||
|
|
||||||
|
if (backslash_pos && backslash_pos < slash_pos) slash_pos = backslash_pos;
|
||||||
|
|
||||||
|
if (colon_pos == NULL || (slash_pos && (slash_pos < colon_pos))) {
|
||||||
|
StrCpy(devname, fops_bootdev_name());
|
||||||
|
StrCat(devname, L":");
|
||||||
|
|
||||||
|
/* the default path is always terminated with a separator */
|
||||||
|
if (kname[0] != L'/' && kname[0] != L'\\') {
|
||||||
|
fops_getdefault_path(dpath,FILENAME_MAXLEN);
|
||||||
|
StrCat(devname, dpath);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
devname[0] = CHAR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create final argument list to the kernel
|
||||||
|
*/
|
||||||
|
len = StrLen(BOOT_IMG_STR) /* BOOT_IMAGE= */
|
||||||
|
+StrLen(devname) /* device name */
|
||||||
|
+StrLen(kname) /* kernel name */
|
||||||
|
+1 /* space */
|
||||||
|
+StrLen(args); /* args length */
|
||||||
|
|
||||||
|
if (len >= CMDLINE_MAXLEN-1) {
|
||||||
|
ERR_PRT((L" arguments list too long cannot fit BOOT_IMAGE\n"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
StrCpy(cmdline, L"BOOT_IMAGE=");
|
||||||
|
StrCat(cmdline, devname);
|
||||||
|
StrCat(cmdline, kname);
|
||||||
|
StrCat(cmdline, L" ");
|
||||||
|
StrCat(cmdline, args);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
simple_probe(EFI_HANDLE dev)
|
||||||
|
{
|
||||||
|
/* this chooser always work */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
chooser_t simple_chooser={
|
||||||
|
L"simple",
|
||||||
|
simple_probe,
|
||||||
|
simple_choose
|
||||||
|
};
|
||||||
|
|
35
choosers/simple.h
Normal file
35
choosers/simple.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* GNU EFI is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* GNU EFI is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU EFI; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ELILO_CHOOSER_SIMPLE_H__
|
||||||
|
#define __ELILO_CHOOSER_SIMPLE_H__
|
||||||
|
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
|
extern chooser_t simple_chooser;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
528
choosers/textmenu.c
Normal file
528
choosers/textmenu.c
Normal file
|
@ -0,0 +1,528 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Richard Hirst <rhirst@linuxcare.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
|
||||||
|
#define MAX_LABELS 16
|
||||||
|
#define MSGBUFLEN 4096
|
||||||
|
|
||||||
|
static UINT8 msgbuf[MSGBUFLEN];
|
||||||
|
static CHAR16 *labels[MAX_LABELS];
|
||||||
|
static CHAR16 *descriptions[MAX_LABELS];
|
||||||
|
static INTN nlabels;
|
||||||
|
static INTN CursorRow, CursorCol, PromptRow, PromptCol;
|
||||||
|
static INTN MenuRow, MenuCol, MenuWidth, MenuHeight;
|
||||||
|
static INTN DisplayParsed, CurrentAttr, PromptAttr;
|
||||||
|
static INTN PromptWidth, MenuHiAttr, MenuLoAttr;
|
||||||
|
static INTN PromptLen, MenuActive, MenuFirst;
|
||||||
|
static CHAR16 PromptBuf[CMDLINE_MAXLEN];
|
||||||
|
|
||||||
|
#define DEF_ATTR EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK)
|
||||||
|
|
||||||
|
|
||||||
|
#define ClearScreen() ST->ConOut->ClearScreen(ST->ConOut)
|
||||||
|
#define SetTextAttr(a) ST->ConOut->SetAttribute(ST->ConOut, a)
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
tohex(INTN c)
|
||||||
|
{
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
return c - '0';
|
||||||
|
else if (c >= 'A' && c <= 'F')
|
||||||
|
return c = c - 'A' + 10;
|
||||||
|
else if (c >= 'a' && c <= 'f')
|
||||||
|
return c = c - 'a' + 10;
|
||||||
|
else
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
paint_msg(UINT8 *msg)
|
||||||
|
{
|
||||||
|
INTN c;
|
||||||
|
|
||||||
|
CursorCol = CursorRow = 0;
|
||||||
|
CurrentAttr = DEF_ATTR;
|
||||||
|
SetTextAttr(CurrentAttr);
|
||||||
|
ClearScreen();
|
||||||
|
while ((c = *msg++)) {
|
||||||
|
/* First map VGA to EFI line drawing chars */
|
||||||
|
if (c == 0xda) c = BOXDRAW_DOWN_RIGHT;
|
||||||
|
else if (c == 0xc4) c = BOXDRAW_HORIZONTAL;
|
||||||
|
else if (c == 0xbf) c = BOXDRAW_DOWN_LEFT;
|
||||||
|
else if (c == 0xb3) c = BOXDRAW_VERTICAL;
|
||||||
|
else if (c == 0xd9) c = BOXDRAW_UP_LEFT;
|
||||||
|
else if (c == 0xc0) c = BOXDRAW_UP_RIGHT;
|
||||||
|
else if (c == 0xb4) c = BOXDRAW_VERTICAL_LEFT;
|
||||||
|
else if (c == 0xc3) c = BOXDRAW_VERTICAL_RIGHT;
|
||||||
|
else if (c == 0x1e) c = GEOMETRICSHAPE_UP_TRIANGLE;
|
||||||
|
else if (c == 0x1f) c = GEOMETRICSHAPE_DOWN_TRIANGLE;
|
||||||
|
else if (c > 0x7f) c = '?';
|
||||||
|
|
||||||
|
/* Now print the printable chars, then process controls */
|
||||||
|
if (c >= ' ') {
|
||||||
|
Print(L"%c", c);
|
||||||
|
CursorCol++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (c) {
|
||||||
|
case '\r': /* Ignore CR */
|
||||||
|
break;
|
||||||
|
case '\n': /* LF treated as cr/lf */
|
||||||
|
CursorRow++;
|
||||||
|
CursorCol = 0;
|
||||||
|
Print(L"\n");
|
||||||
|
break;
|
||||||
|
case 0x0c: /* FF - Clear screen */
|
||||||
|
CursorCol = CursorRow = 0;
|
||||||
|
ClearScreen();
|
||||||
|
break;
|
||||||
|
case 0x0f: /* ^O - Attributes */
|
||||||
|
if (msg[0] && msg[1]) {
|
||||||
|
INTN bg = tohex(*msg++);
|
||||||
|
INTN fg = tohex(*msg++);
|
||||||
|
|
||||||
|
if (bg < 16 || fg < 16) {
|
||||||
|
CurrentAttr = EFI_TEXT_ATTR(fg, bg);
|
||||||
|
SetTextAttr(CurrentAttr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x01: /* ^A - Prompt */
|
||||||
|
if (!DisplayParsed) {
|
||||||
|
if (!PromptRow) {
|
||||||
|
PromptRow = CursorRow;
|
||||||
|
PromptCol = CursorCol;
|
||||||
|
PromptAttr = CurrentAttr;
|
||||||
|
}
|
||||||
|
else if (!PromptWidth)
|
||||||
|
PromptWidth = CursorCol - PromptCol;
|
||||||
|
/* else bad syntax */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x02: /* ^B - Menu */
|
||||||
|
if (!DisplayParsed) {
|
||||||
|
if (!MenuRow) {
|
||||||
|
MenuRow = CursorRow;
|
||||||
|
MenuCol = CursorCol;
|
||||||
|
MenuLoAttr = CurrentAttr;
|
||||||
|
}
|
||||||
|
else if (!MenuWidth) {
|
||||||
|
MenuWidth = CursorCol - MenuCol;
|
||||||
|
MenuHeight = CursorRow - MenuRow + 1;
|
||||||
|
MenuHiAttr = CurrentAttr;
|
||||||
|
}
|
||||||
|
/* else bad syntax */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Print(L"?");
|
||||||
|
CursorCol++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
paint_prompt(VOID)
|
||||||
|
{
|
||||||
|
INTN offset = PromptLen > PromptWidth - 1 ? PromptLen - PromptWidth + 1: 0;
|
||||||
|
SetTextAttr(PromptAttr);
|
||||||
|
PrintAt(PromptCol, PromptRow, L"%s%s", PromptBuf + offset, L" \b");
|
||||||
|
SetTextAttr(CurrentAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
paint_menu(VOID)
|
||||||
|
{
|
||||||
|
INTN i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < MenuHeight; i++) {
|
||||||
|
INTN attr = (i + MenuFirst == MenuActive) ? MenuHiAttr: MenuLoAttr;
|
||||||
|
CHAR16 description[80];
|
||||||
|
|
||||||
|
for (j = 0; j < MenuWidth; j++)
|
||||||
|
description[j] = ' ';
|
||||||
|
description[MenuWidth] = '\0';
|
||||||
|
if (i + MenuFirst < nlabels) {
|
||||||
|
for (j = 0; descriptions[i + MenuFirst][j] && j < MenuWidth; j++)
|
||||||
|
description[j+1] = descriptions[i + MenuFirst][j];
|
||||||
|
}
|
||||||
|
SetTextAttr(attr);
|
||||||
|
PrintAt(MenuCol, MenuRow + i, L"%-.*s", MenuWidth, description);
|
||||||
|
SetTextAttr(CurrentAttr);
|
||||||
|
}
|
||||||
|
paint_prompt();
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
read_message_file(INTN msg, INT8 *buf, INTN max)
|
||||||
|
{
|
||||||
|
CHAR16 *filename;
|
||||||
|
fops_fd_t message_fd;
|
||||||
|
EFI_STATUS status;
|
||||||
|
INTN len = max;
|
||||||
|
|
||||||
|
if (msg > 10) return 0;
|
||||||
|
|
||||||
|
if ((filename = get_message_filename(msg)) == NULL) {
|
||||||
|
VERB_PRT(3, Print(L"no message file specified\n"));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VERB_PRT(3, Print(L"opening message file %s\n", filename));
|
||||||
|
|
||||||
|
status = fops_open(filename, &message_fd);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
VERB_PRT(3, Print(L"message file %s not found\n", filename));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = fops_read(message_fd, buf, &len);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
VERB_PRT(3, Print(L"Error reading message file\n"));
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fops_close(message_fd);
|
||||||
|
|
||||||
|
VERB_PRT(3, Print(L"done reading message file %s\n", filename));
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* interactively select a kernel image and options.
|
||||||
|
* The kernel can be an actual filename or a label in the config file
|
||||||
|
* Return:
|
||||||
|
* -1: if unsucessful
|
||||||
|
* 0: otherwise
|
||||||
|
*/
|
||||||
|
static INTN
|
||||||
|
select_kernel(CHAR16 *label, INTN lsize)
|
||||||
|
{
|
||||||
|
#define CHAR_CTRL_C (L'\003') /* Unicode CTRL-C */
|
||||||
|
#define CHAR_CTRL_D (L'\004') /* Unicode CTRL-D */
|
||||||
|
#define CHAR_CTRL_F (L'\006') /* Unicode CTRL-F */
|
||||||
|
#define CHAR_DEL (L'\177') /* Unicode DEL */
|
||||||
|
SIMPLE_INPUT_INTERFACE *ip = systab->ConIn;
|
||||||
|
EFI_INPUT_KEY key;
|
||||||
|
EFI_STATUS status;
|
||||||
|
INT8 first_time = 1;
|
||||||
|
INTN i;
|
||||||
|
INT8 fn = 0;
|
||||||
|
|
||||||
|
reprint:
|
||||||
|
i = read_message_file(0, msgbuf, MSGBUFLEN-1);
|
||||||
|
msgbuf[i] = 0;
|
||||||
|
paint_msg(msgbuf);
|
||||||
|
DisplayParsed = 1;
|
||||||
|
paint_menu();
|
||||||
|
CurrentAttr = PromptAttr;
|
||||||
|
SetTextAttr(CurrentAttr);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
while ((status=ip->ReadKeyStroke(ip, &key)) == EFI_NOT_READY);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
SetTextAttr(EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK));
|
||||||
|
ClearScreen();
|
||||||
|
ERR_PRT((L"select_kernel readkey: %r", status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (key.UnicodeChar == CHAR_CTRL_F) {
|
||||||
|
fn = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (fn) {
|
||||||
|
if (key.UnicodeChar >= '0' && key.UnicodeChar <= '9') {
|
||||||
|
if (key.UnicodeChar == '0')
|
||||||
|
key.ScanCode = SCAN_F10;
|
||||||
|
else
|
||||||
|
key.ScanCode = SCAN_F1 + key.UnicodeChar - '1';
|
||||||
|
key.UnicodeChar = 0;
|
||||||
|
}
|
||||||
|
fn = 0;
|
||||||
|
}
|
||||||
|
if (key.ScanCode == SCAN_UP) {
|
||||||
|
if (MenuActive)
|
||||||
|
MenuActive--;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
if (MenuActive < MenuFirst)
|
||||||
|
MenuFirst = MenuActive;
|
||||||
|
paint_menu();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (key.ScanCode == SCAN_DOWN) {
|
||||||
|
if (MenuActive < nlabels - 1)
|
||||||
|
MenuActive++;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
if (MenuActive >= MenuFirst + MenuHeight)
|
||||||
|
MenuFirst = MenuActive - MenuHeight + 1;
|
||||||
|
paint_menu();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (key.ScanCode >= SCAN_F1 && key.ScanCode <= SCAN_F10) {
|
||||||
|
i = read_message_file(key.ScanCode - SCAN_F1 + 1, msgbuf, MSGBUFLEN-1);
|
||||||
|
if (i) {
|
||||||
|
msgbuf[i] = 0;
|
||||||
|
paint_msg(msgbuf);
|
||||||
|
while ((status=ip->ReadKeyStroke(ip, &key)) == EFI_NOT_READY);
|
||||||
|
goto reprint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (key.UnicodeChar) {
|
||||||
|
/* XXX Do we really want this in textmenual mode? */
|
||||||
|
case L'?':
|
||||||
|
Print(L"\n");
|
||||||
|
print_devices();
|
||||||
|
first_time = 0;
|
||||||
|
goto reprint;
|
||||||
|
case CHAR_BACKSPACE:
|
||||||
|
case CHAR_DEL:
|
||||||
|
if (PromptLen == 0) break;
|
||||||
|
PromptLen--;
|
||||||
|
PromptBuf[PromptLen] = 0;
|
||||||
|
if (PromptLen >= PromptWidth-2)
|
||||||
|
paint_prompt();
|
||||||
|
else
|
||||||
|
Print(L"\b \b");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHAR_LINEFEED:
|
||||||
|
case CHAR_CARRIAGE_RETURN:
|
||||||
|
StrCpy(label, labels[MenuActive]);
|
||||||
|
SetTextAttr(EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK));
|
||||||
|
ClearScreen();
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if ( key.UnicodeChar == CHAR_CTRL_D
|
||||||
|
|| key.UnicodeChar == CHAR_CTRL_C) {
|
||||||
|
SetTextAttr(EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK));
|
||||||
|
ClearScreen();
|
||||||
|
Print(L"\nGiving up then...\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (key.UnicodeChar == CHAR_NULL) break;
|
||||||
|
|
||||||
|
if (PromptLen > CMDLINE_MAXLEN-1) break;
|
||||||
|
|
||||||
|
if (key.UnicodeChar < ' ' || key.UnicodeChar > 0x7e)
|
||||||
|
key.UnicodeChar = '?';
|
||||||
|
PromptBuf[PromptLen++] = key.UnicodeChar;
|
||||||
|
PromptBuf[PromptLen] = 0;
|
||||||
|
|
||||||
|
/* Write the character out */
|
||||||
|
if (PromptLen >= PromptWidth-1)
|
||||||
|
paint_prompt();
|
||||||
|
else
|
||||||
|
Print(L"%c", key.UnicodeChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
textmenu_choose(CHAR16 **argv, INTN argc, INTN index, CHAR16 *kname, CHAR16 *cmdline)
|
||||||
|
{
|
||||||
|
# define BOOT_IMG_STR L"BOOT_IMAGE="
|
||||||
|
CHAR16 label[CMDLINE_MAXLEN];
|
||||||
|
CHAR16 initrd_name[CMDLINE_MAXLEN];
|
||||||
|
CHAR16 args[CMDLINE_MAXLEN];
|
||||||
|
CHAR16 devname[CMDLINE_MAXLEN];
|
||||||
|
CHAR16 dpath[FILENAME_MAXLEN];
|
||||||
|
CHAR16 *slash_pos, *colon_pos, *backslash_pos;
|
||||||
|
UINTN len;
|
||||||
|
INTN ret;
|
||||||
|
VOID *handle = NULL;
|
||||||
|
|
||||||
|
/* Clear all static variables, as we might be called more than once */
|
||||||
|
|
||||||
|
CursorRow = CursorCol = PromptRow = PromptCol = 0;
|
||||||
|
MenuRow = MenuCol = MenuWidth = MenuHeight = 0;
|
||||||
|
DisplayParsed = CurrentAttr = PromptAttr = 0;
|
||||||
|
PromptWidth = MenuHiAttr = MenuLoAttr = 0;
|
||||||
|
PromptLen = MenuActive = MenuFirst = 0;
|
||||||
|
PromptBuf[0] = CHAR_NULL;
|
||||||
|
|
||||||
|
nlabels = 0;
|
||||||
|
while (nlabels < MAX_LABELS && (handle = get_next_description(handle, labels + nlabels, descriptions + nlabels))) {
|
||||||
|
if (descriptions[nlabels][0] == 0)
|
||||||
|
descriptions[nlabels] = labels[nlabels];
|
||||||
|
nlabels++;
|
||||||
|
}
|
||||||
|
restart:
|
||||||
|
initrd_name[0] = kname[0] = cmdline[0] = args[0] = CHAR_NULL;
|
||||||
|
|
||||||
|
/* reset per image loader options */
|
||||||
|
Memset(&elilo_opt.img_opt, 0, sizeof(elilo_opt.img_opt));
|
||||||
|
|
||||||
|
if (elilo_opt.prompt) {
|
||||||
|
ret = select_kernel(label, sizeof(label));
|
||||||
|
if (ret == -1) return -1;
|
||||||
|
argc = argify(PromptBuf,sizeof(PromptBuf), argv);
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check for alternate kernel image and params in EFI variable
|
||||||
|
*/
|
||||||
|
if (elilo_opt.alt_check && alternate_kernel(PromptBuf, sizeof(PromptBuf)) == 0) {
|
||||||
|
argc = argify(PromptBuf,sizeof(PromptBuf), argv);
|
||||||
|
index = 0;
|
||||||
|
label[0] = args[0] = initrd_name[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First search for matching label in the config file
|
||||||
|
* if options were specified on command line, they take
|
||||||
|
* precedence over the ones in the config file
|
||||||
|
*
|
||||||
|
* if no match is found, the args and initrd arguments may
|
||||||
|
* still be modified by global options in the config file.
|
||||||
|
*/
|
||||||
|
if (label[0])
|
||||||
|
ret = find_label(label, kname, args, initrd_name);
|
||||||
|
else
|
||||||
|
ret = find_label(argv[index], kname, args, initrd_name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* not found, so assume first argument is kernel name and
|
||||||
|
* not label name
|
||||||
|
*/
|
||||||
|
if (ret == -1) {
|
||||||
|
if (argv[index])
|
||||||
|
StrCpy(kname, argv[index]);
|
||||||
|
else
|
||||||
|
StrCpy(kname, elilo_opt.default_kernel);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* no matter what happened for kname, if user specified
|
||||||
|
* additional options, they override the ones in the
|
||||||
|
* config file
|
||||||
|
*/
|
||||||
|
if (label[0])
|
||||||
|
index--;
|
||||||
|
if (argc > 1+index) {
|
||||||
|
/*StrCpy(args, argv[++index]);*/
|
||||||
|
while (++index < argc) {
|
||||||
|
StrCat(args, L" ");
|
||||||
|
StrCat(args, argv[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* if initrd specified on command line, it overrides
|
||||||
|
* the one defined in config file, if any
|
||||||
|
*/
|
||||||
|
if (elilo_opt.initrd[0] == CHAR_NULL && initrd_name[0] != CHAR_NULL) {
|
||||||
|
StrCpy(elilo_opt.initrd, initrd_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
VERB_PRT(1, { Print(L"kernel is '%s'\n", kname);
|
||||||
|
Print(L"arguments are '%s'\n", args);
|
||||||
|
if (elilo_opt.initrd[0]) Print(L"initrd is '%s'\n", elilo_opt.initrd);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (elilo_opt.prompt == 0) {
|
||||||
|
/* minimal printing */
|
||||||
|
Print(L"ELILO\n");
|
||||||
|
ret = wait_timeout(elilo_opt.delay);
|
||||||
|
if (ret != 0) {
|
||||||
|
elilo_opt.prompt = 1;
|
||||||
|
elilo_opt.timeout = ELILO_TIMEOUT_INFINITY;
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* add the device name, if not already specified,
|
||||||
|
* so that we know where we came from
|
||||||
|
*/
|
||||||
|
slash_pos = StrChr(kname, L'/');
|
||||||
|
backslash_pos = StrChr(kname, L'\\');
|
||||||
|
colon_pos = StrChr(kname, L':');
|
||||||
|
|
||||||
|
if (backslash_pos && backslash_pos < slash_pos) slash_pos = backslash_pos;
|
||||||
|
|
||||||
|
if (colon_pos == NULL || (slash_pos && (slash_pos < colon_pos))) {
|
||||||
|
StrCpy(devname, fops_bootdev_name());
|
||||||
|
StrCat(devname, L":");
|
||||||
|
|
||||||
|
/* the default path is always terminated with a separator */
|
||||||
|
if (kname[0] != L'/' && kname[0] != L'\\') {
|
||||||
|
fops_getdefault_path(dpath,FILENAME_MAXLEN);
|
||||||
|
StrCat(devname, dpath);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
devname[0] = CHAR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create final argument list to the kernel
|
||||||
|
*/
|
||||||
|
len = StrLen(BOOT_IMG_STR) /* BOOT_IMAGE= */
|
||||||
|
+StrLen(devname) /* device name */
|
||||||
|
+StrLen(kname) /* kernel name */
|
||||||
|
+1 /* space */
|
||||||
|
+StrLen(args); /* args length */
|
||||||
|
|
||||||
|
if (len >= CMDLINE_MAXLEN-1) {
|
||||||
|
SetTextAttr(EFI_TEXT_ATTR(EFI_LIGHTGRAY,EFI_BLACK));
|
||||||
|
ClearScreen();
|
||||||
|
ERR_PRT((L" arguments list too long cannot fit BOOT_IMAGE\n"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
StrCpy(cmdline, L"BOOT_IMAGE=");
|
||||||
|
StrCat(cmdline, devname);
|
||||||
|
StrCat(cmdline, kname);
|
||||||
|
StrCat(cmdline, L" ");
|
||||||
|
StrCat(cmdline, args);
|
||||||
|
|
||||||
|
VERB_PRT(3, Print(L"final command line is '%s'\n", cmdline));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
textmenu_probe(EFI_HANDLE dev)
|
||||||
|
{
|
||||||
|
/* this chooser always works */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
chooser_t textmenu_chooser={
|
||||||
|
L"textmenu",
|
||||||
|
textmenu_probe,
|
||||||
|
textmenu_choose
|
||||||
|
};
|
||||||
|
|
35
choosers/textmenu.h
Normal file
35
choosers/textmenu.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Richard Hirst <rhirst@linuxcare.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* GNU EFI is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* GNU EFI is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU EFI; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ELILO_CHOOSER_TEXTMENU_H__
|
||||||
|
#define __ELILO_CHOOSER_TEXTMENU_H__
|
||||||
|
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
|
extern chooser_t textmenu_chooser;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
56
config.h
Normal file
56
config.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ELILO_CONFIG_H__
|
||||||
|
#define __ELILO_CONFIG_H__
|
||||||
|
|
||||||
|
#define opt_offsetof(opt) (&((boot_image_t *)(0x0))->opt)
|
||||||
|
|
||||||
|
typedef enum { OPT_NOTUSED, OPT_STR, OPT_CMD, OPT_BOOL, OPT_NUM, OPT_FILE } config_option_type_t;
|
||||||
|
|
||||||
|
typedef enum { OPT_GLOBAL, /* global and shared among architectures */
|
||||||
|
OPT_IMAGE, /* per image only and shared among architectures */
|
||||||
|
OPT_IMAGE_SYS /* per image and architecture specific (offset base in sys_img_opts) */
|
||||||
|
} config_option_scope_t;
|
||||||
|
|
||||||
|
typedef enum { OPTIONS_GROUP_GLOBAL, /* group must be added to global set of options */
|
||||||
|
OPTIONS_GROUP_IMAGE, /* group must be added to per-image set of options */
|
||||||
|
} config_option_group_scope_t;
|
||||||
|
|
||||||
|
struct _config_option_t;
|
||||||
|
typedef INTN option_action_t(struct _config_option_t *, VOID *);
|
||||||
|
|
||||||
|
typedef struct _config_option_t {
|
||||||
|
config_option_type_t type; /* option type: OPT_CMD, OPT_BOOL, ... */
|
||||||
|
config_option_scope_t scope; /* option scope: global, per image, per image_sys */
|
||||||
|
CHAR16 *name; /* unicode string for the option */
|
||||||
|
option_action_t *action; /* option specific action */
|
||||||
|
INTN (*check)(void *); /* check valid arguments, NULL=don't need */
|
||||||
|
VOID *data; /* which data structure to record the option */
|
||||||
|
} config_option_t;
|
||||||
|
|
||||||
|
extern INTN register_config_options(config_option_t *opt, UINTN nentries, config_option_group_scope_t);
|
||||||
|
|
||||||
|
#endif /* __ELILO_CONFIG_H__ */
|
46
devschemes/Makefile
Normal file
46
devschemes/Makefile
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#
|
||||||
|
# Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
# Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
#
|
||||||
|
# This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
#
|
||||||
|
# ELILO is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# ELILO is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
# Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
# 02111-1307, USA.
|
||||||
|
#
|
||||||
|
# Please check out the elilo.txt for complete documentation on how
|
||||||
|
# to use this program.
|
||||||
|
#
|
||||||
|
|
||||||
|
include ../Make.defaults
|
||||||
|
include ../Make.rules
|
||||||
|
|
||||||
|
TOPDIR=$(CDIR)/..
|
||||||
|
|
||||||
|
FILES=simple.o
|
||||||
|
|
||||||
|
|
||||||
|
TARGET=devschemes.o
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
#
|
||||||
|
# XXX: does not trigger recompile when changing filesystem selection
|
||||||
|
# without doing make clean.
|
||||||
|
#
|
||||||
|
$(TARGET): $(FILES)
|
||||||
|
$(LD) -r -o $@ $(FILES)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) -f $(TARGET) $(FILES)
|
152
devschemes/simple.c
Normal file
152
devschemes/simple.c
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Look at the README.devschemes for more explanations on how
|
||||||
|
* to use devschemes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
|
#define NAMING_SCHEME L"simple"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
INT8 type;
|
||||||
|
INT8 subtype;
|
||||||
|
INTN (*device_func)(device_t *dev, EFI_DEVICE_PATH *dp);
|
||||||
|
} devices_types_t;
|
||||||
|
|
||||||
|
|
||||||
|
static UINT32 atapi_count, scsi_count, net_count;
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
atapi_device(device_t *dev, EFI_DEVICE_PATH *dp)
|
||||||
|
{
|
||||||
|
//ATAPI_DEVICE_PATH *atapi = (ATAPI_DEVICE_PATH *)dp;
|
||||||
|
|
||||||
|
dev->name[0] = L'a';
|
||||||
|
dev->name[1] = L't';
|
||||||
|
dev->name[2] = L'a';
|
||||||
|
dev->name[3] = L'p';
|
||||||
|
dev->name[4] = L'i';
|
||||||
|
|
||||||
|
SPrint(dev->name+5,FILEOPS_DEVNAME_MAXLEN-5-1, L"%d", atapi_count);
|
||||||
|
atapi_count++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
scsi_device(device_t *dev, EFI_DEVICE_PATH *dp)
|
||||||
|
{
|
||||||
|
//SCSI_DEVICE_PATH *scsi = (SCSI_DEVICE_PATH *)dp;
|
||||||
|
|
||||||
|
dev->name[0] = L's';
|
||||||
|
dev->name[1] = L'c';
|
||||||
|
dev->name[2] = L's';
|
||||||
|
dev->name[3] = L'i';
|
||||||
|
|
||||||
|
SPrint(dev->name+4, FILEOPS_DEVNAME_MAXLEN-4-1, L"%d", scsi_count);
|
||||||
|
scsi_count++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
network_device(device_t *dev, EFI_DEVICE_PATH *dp)
|
||||||
|
{
|
||||||
|
//MAC_ADDR_DEVICE_PATH *mac = (MAC_ADDR_DEVICE_PATH *)dp;
|
||||||
|
|
||||||
|
dev->name[0] = L'n';
|
||||||
|
dev->name[1] = L'e';
|
||||||
|
dev->name[2] = L't';
|
||||||
|
|
||||||
|
SPrint(dev->name+3, FILEOPS_DEVNAME_MAXLEN-3-1, L"%d", net_count);
|
||||||
|
net_count++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* what we are looking for in the device path
|
||||||
|
*/
|
||||||
|
static devices_types_t dev_types[]={
|
||||||
|
{ MESSAGING_DEVICE_PATH, MSG_ATAPI_DP, atapi_device},
|
||||||
|
{ MESSAGING_DEVICE_PATH, MSG_SCSI_DP, scsi_device},
|
||||||
|
{ MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, network_device},
|
||||||
|
{ 0, 0 , NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
simple_scheme(device_t *tab, UINTN n)
|
||||||
|
{
|
||||||
|
EFI_DEVICE_PATH *dp1, *dp;
|
||||||
|
devices_types_t *p;
|
||||||
|
UINTN i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* note that this test is necessary but not sufficient to guarantee that this scheme
|
||||||
|
* will work because, we have no way of detecting that the machine got actually
|
||||||
|
* rebooted if the EDD30 variable was forced. this comes from the fact, that elilo
|
||||||
|
* can be invoked once, aborted and then restarted with no machine reboot.
|
||||||
|
*
|
||||||
|
* XXX: there may be a way to detect this with the another variable which would
|
||||||
|
* be in volatile memory only
|
||||||
|
*/
|
||||||
|
if (elilo_opt.edd30_on == 0) {
|
||||||
|
VERB_PRT(4, Print(L"%s device naming scheme only works with EDD3.0 enabled\n", NAMING_SCHEME));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i=0; i < n; i++) {
|
||||||
|
dp = DevicePathFromHandle(tab[i].dev);
|
||||||
|
if (dp == NULL) {
|
||||||
|
ERR_PRT((L"cannot get device path for device %d", i));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dp1 = dp = UnpackDevicePath(dp);
|
||||||
|
|
||||||
|
while (!IsDevicePathEnd(dp)) {
|
||||||
|
p = dev_types;
|
||||||
|
while (p->type) {
|
||||||
|
if ( p->type == DevicePathType(dp)
|
||||||
|
&& p->subtype == DevicePathSubType(dp)) {
|
||||||
|
(*p->device_func)(tab+i, dp);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
dp = NextDevicePathNode(dp);
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
FreePool(dp1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
devname_scheme_t simple_devname_scheme={
|
||||||
|
NAMING_SCHEME,
|
||||||
|
simple_scheme
|
||||||
|
};
|
106
docs/devschemes.txt
Normal file
106
docs/devschemes.txt
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
|
||||||
|
Some explanations of what the devschemes are for:
|
||||||
|
-------------------------------------------------
|
||||||
|
Copyright (c) 2001-2003 Hewlett-Packard Co
|
||||||
|
Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
|
||||||
|
|
||||||
|
Whether or not EDD3.0 is enabled, EFI uses a device naming scheme which is
|
||||||
|
somewhat detailed. It tries to follow the hardware path from the System bus
|
||||||
|
down to the actual partition on the media. The following example shows
|
||||||
|
a typical block device path from a SCSI disk:
|
||||||
|
|
||||||
|
blk2 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part1,Sig00000000).
|
||||||
|
|
||||||
|
Elilo allows the user to load files from any device. This means that it
|
||||||
|
must provide a way for the user to specify a file path which include
|
||||||
|
the device name. While it is theoritically possible to specify the
|
||||||
|
path mentioned above, it is far from practical because the names
|
||||||
|
are too long. There is too much details which the user (especially of
|
||||||
|
a boot loader) does not care about.
|
||||||
|
|
||||||
|
So Elilo, just like the EFI shell, must have a way of assigning logical
|
||||||
|
names to device names (paths). The EFI shell uses the fsX notation wherever
|
||||||
|
it finds a block devices for which it has detected a valid EFI filesystem
|
||||||
|
(i.e. a Fat32+ filesystem). This assignment is done on the fly, and depending
|
||||||
|
on the status of the removable media (like CDROM or floppy) the mapping can
|
||||||
|
change.
|
||||||
|
|
||||||
|
Those fsX: names are a pure abstraction of the EFI shell and have nothing to
|
||||||
|
do with the EFI specification.
|
||||||
|
|
||||||
|
Now Elilo could try to emulate then, i.e. try to reproduce the way the EFI shell
|
||||||
|
assigns names. However the problem is that, AT THIS POINT, Elilo recognized more
|
||||||
|
device from which it can load files from than the Shell does. This comes from the
|
||||||
|
fact that it can load files from the network or from an Ext2fs, for instance.
|
||||||
|
We plan on fixing those issues in the next releases of Elilo. Anyway, the problem
|
||||||
|
would still be to make sure that if we follow the same naming scheme, they match
|
||||||
|
at all times, i.e. fs0: maps to the same device in both the EFI shell and Elilo
|
||||||
|
which may be tricky as both EFI and Elilo continue to evolve. Also the Shell
|
||||||
|
naming schemes as some problems which removable devices which would not make it
|
||||||
|
easy from the bootloader.
|
||||||
|
|
||||||
|
Another possible solution would be to use the Linux kernel naming scheme, i.e.,
|
||||||
|
hda, hda1, fd0, sda... Of course, we would drop the /dev prefix in this case.
|
||||||
|
While it would make it very convenient for users and easy to configure from
|
||||||
|
a running system, it is even more difficult that the EFI Shell scheme. Again,
|
||||||
|
to succeed, the loader scheme would have to match EXACTLY what the Linux kernel
|
||||||
|
does for all possible devices. This is a very complicated task as his any
|
||||||
|
naming problem. The recent discussions about the devfs support in the kernel is
|
||||||
|
just yet another proof of the complexity. Another issue here is that this would
|
||||||
|
create a dependency between the loader and the kernel because we would need the
|
||||||
|
way the naming is done in the kernel. Again, this is very complicated, just thinnking
|
||||||
|
about how the PCI buses are scanned looking from devices.
|
||||||
|
|
||||||
|
So it looks like there is single solutions. Clearly, that is not easy and there are
|
||||||
|
multiple schemes possible. For now, we felt that it was better for Elilo to use its
|
||||||
|
own naming scheme independent from the EFI shell and the Linux kernel. While this introduces
|
||||||
|
yet another scheme, we believe its advantages outweight the software complexity associated
|
||||||
|
with the two schemes described above.
|
||||||
|
|
||||||
|
However, we recognize the need for flexibilty and that is exactly why, this version
|
||||||
|
of Elilo provide an internal interface which can used to develop custom naming schemes.
|
||||||
|
|
||||||
|
The way the filepaths are translated by Elilo is very basic and based on a simple
|
||||||
|
string matching algorithm. A full pathname is specified as follows:
|
||||||
|
|
||||||
|
dev_name:/path/to/my/file.
|
||||||
|
|
||||||
|
The 'dev_name' is created by Elilo and can be anything relevant to the user. There is
|
||||||
|
an internal binding from the name to the actual EFI device handle and more precisely
|
||||||
|
the filsystem interface associated to it (the device handle is never exposed to the
|
||||||
|
boot loader).
|
||||||
|
|
||||||
|
By default, Elilo uses an extremely simple scheme which is similar to the EFI shell.
|
||||||
|
if simply builds the device names as follows:
|
||||||
|
|
||||||
|
devXXX.
|
||||||
|
|
||||||
|
The XXX is just the number of the device. It is incremented by one each time recognized
|
||||||
|
filesystem is detected on that device. The clear advantage is simplicity. The downside
|
||||||
|
is that is creates a 'flat' namespace where every new device detected (like a floppy
|
||||||
|
is inserted) will show up anywhere in the set of devices and may push some fixed
|
||||||
|
devices up or down. So it hard to rely on devXXX to always mean the same things.
|
||||||
|
|
||||||
|
Now custom naming schemes can be added on top of this, which would partially or totally
|
||||||
|
replace this default scheme. Elilo is shipped with one such scheme called 'simple'.
|
||||||
|
It provides an example of how one can develop a new scheme. The main characteristic
|
||||||
|
of 'simple' is that it tries to group devices by controller (Messaging Device in
|
||||||
|
EFI terminology). Hence, all the ATAPI devices show up as atapiXXX and the SCSI
|
||||||
|
device show up as SCSIXXX. This implicitely shields the SCSI (fixed most likely) devices
|
||||||
|
from the removable media coming from ATAPI (like floppy or CDROM). So it is slightly
|
||||||
|
better but far from perfect.
|
||||||
|
|
||||||
|
Here is an example of what it looks like on an actual system:
|
||||||
|
|
||||||
|
scsi0 : vfat : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part1,Sig00000000)
|
||||||
|
scsi1 : vfat : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part1,Sig00000000)
|
||||||
|
atapi0 : vfat : Acpi(PNP0A03,0)/Pci(3|1)/Ata(Secondary,Master)/CDROM(Entry1)
|
||||||
|
scsi2 : ext2fs : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part2,Sig00000000)
|
||||||
|
scsi3 : ext2fs : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part2,Sig00000000)
|
||||||
|
net0 : netfs : Acpi(PNP0A03,0)/Pci(5|0)/Mac(00D0B7A6FC25)
|
||||||
|
|
||||||
|
|
||||||
|
The 'simple' scheme is not fully satifactory but developers are strongly encouraged
|
||||||
|
to enhance it or better create new schemes.
|
||||||
|
|
102
docs/edd30.txt
Normal file
102
docs/edd30.txt
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
Information related to EDD3.0 and ELILO
|
||||||
|
---------------------------------------
|
||||||
|
Last updated: 02/02/14
|
||||||
|
|
||||||
|
As of elilo-3.0, the filesystem/device naming scheme takes advantage
|
||||||
|
of the EDD3.0 support present in the underlying EFI/BIOS firmware layers.
|
||||||
|
|
||||||
|
The EDD3.0 support is supposedly turned on by default in all version of the
|
||||||
|
EFI firmware on IA-64 (and possibly IA-32).
|
||||||
|
|
||||||
|
Support can be enabled or disabled dynamically using an EFI environment
|
||||||
|
variable called "EDD30". The GUID of the variable is as follows:
|
||||||
|
|
||||||
|
#define EDD30_GUID \
|
||||||
|
{0x964e5b21, 0x6459, 0x11d2, { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}}
|
||||||
|
|
||||||
|
This is a boolean variable. When true, support is enabled.
|
||||||
|
You can check if support is enabled by typing:
|
||||||
|
|
||||||
|
Shell> edd30
|
||||||
|
Usage edd30 [On | Off]
|
||||||
|
Used to support OS Loader debug
|
||||||
|
EDD30 DevicePath Mode is On
|
||||||
|
|
||||||
|
at this EFI shell prompt. You can enable support by forcing the variable
|
||||||
|
to TRUE. This can be accomplished by typing:
|
||||||
|
|
||||||
|
Shell> edd30 on
|
||||||
|
EDD30 DevicePath Mode is On
|
||||||
|
|
||||||
|
Alternatively an EFI application can use RT->SetVariable() to set the
|
||||||
|
value of the EDD30 variable.
|
||||||
|
|
||||||
|
If the variable was set to false, then to take advantage of EDD3.0
|
||||||
|
support after switching the variablle to TRUE, the system MUST be
|
||||||
|
rebooted as EDD affects the core of EFI naming scheme.
|
||||||
|
|
||||||
|
Elilo will check if the variable is defined and valid. If it is set
|
||||||
|
to true, then the device name schemes that rely on it will work properly.
|
||||||
|
That's the case for the 'simple' scheme. If the variable is not set to true
|
||||||
|
or does not exist, elilo will use a generic builtin scheme with names
|
||||||
|
such as dev001, dev002 and so on. The "EDD30" variable is like a system
|
||||||
|
variable therefore it is expected not to be overloaded by users for others
|
||||||
|
purposes. Elilo is fully functional even when EDD30 is off.
|
||||||
|
|
||||||
|
By default, if EDD30 is off, elilo will try and set the variable to TRUE.
|
||||||
|
However, some controllers do not support EDD30 and forcing the variable
|
||||||
|
may cause problems. Therefore as of elilo-3.2, there is an option to
|
||||||
|
avoid forcing the variable. In the config file, you can use 'noedd30' option
|
||||||
|
and on the command line, you can use the -E option.
|
||||||
|
|
||||||
|
When the variable is forced back to TRUE, th effect will only be seen after
|
||||||
|
a reboot. Shall you decide not to reboot immediately, elilo
|
||||||
|
will system still operate using the generic naming scheme.
|
||||||
|
|
||||||
|
When EDD3.0 is enabled the output of the EFI shell 'map' command looks similar
|
||||||
|
to this:
|
||||||
|
|
||||||
|
Device mapping table
|
||||||
|
fs0 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part1,Sig00000000)
|
||||||
|
fs1 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part1,Sig00000000)
|
||||||
|
fs2 : Acpi(PNP0A03,0)/Pci(3|1)/Ata(Secondary,Master)/CDROM(Entry1)
|
||||||
|
blk0 : Acpi(PNP0A03,0)/Pci(3|1)/Ata(Primary,Master)
|
||||||
|
blk1 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)
|
||||||
|
blk2 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part1,Sig00000000)
|
||||||
|
blk3 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part2,Sig00000000)
|
||||||
|
blk4 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun0,Lun0)/HD(Part3,Sig00000000)
|
||||||
|
blk5 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)
|
||||||
|
blk6 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part1,Sig00000000)
|
||||||
|
blk7 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part2,Sig00000000)
|
||||||
|
blk8 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part3,Sig00000000)
|
||||||
|
blk9 : Acpi(PNP0A03,2)/Pci(0|0)/Scsi(Pun6,Lun0)/HD(Part3,Sig00000000)/HD(Part1,Sig00000200)
|
||||||
|
blkA : Acpi(PNP0A03,0)/Pci(3|1)/Ata(Secondary,Master)
|
||||||
|
blkB : Acpi(PNP0A03,0)/Pci(3|1)/Ata(Secondary,Master)/CDROM(Entry1)
|
||||||
|
Shell>
|
||||||
|
|
||||||
|
The same system with EDD3.0 disabled will look like this:
|
||||||
|
Device mapping table
|
||||||
|
fs0 : VenHw(Unknown Device:80)/HD(Part1,Sig00000000)
|
||||||
|
fs1 : VenHw(Unknown Device:81)/HD(Part1,Sig00000000)
|
||||||
|
fs2 : VenHw(Unknown Device:FF)/CDROM(Entry1)
|
||||||
|
blk0 : VenHw(Unknown Device:00)
|
||||||
|
blk1 : VenHw(Unknown Device:80)
|
||||||
|
blk2 : VenHw(Unknown Device:80)/HD(Part1,Sig00000000)
|
||||||
|
blk3 : VenHw(Unknown Device:80)/HD(Part2,Sig00000000)
|
||||||
|
blk4 : VenHw(Unknown Device:80)/HD(Part3,Sig00000000)
|
||||||
|
blk5 : VenHw(Unknown Device:81)
|
||||||
|
blk6 : VenHw(Unknown Device:81)/HD(Part1,Sig00000000)
|
||||||
|
blk7 : VenHw(Unknown Device:81)/HD(Part2,Sig00000000)
|
||||||
|
blk8 : VenHw(Unknown Device:81)/HD(Part3,Sig00000000)
|
||||||
|
blk9 : VenHw(Unknown Device:81)/HD(Part3,Sig00000000)/HD(Part1,Sig00000200)
|
||||||
|
blkA : VenHw(Unknown Device:FF)
|
||||||
|
blkB : VenHw(Unknown Device:FF)/CDROM(Entry1)
|
||||||
|
Shell>
|
||||||
|
|
||||||
|
|
||||||
|
EDD3.0 is an industry standard and the working draft can be downloaded from the
|
||||||
|
following web site:
|
||||||
|
http://www.t13.org/
|
||||||
|
|
||||||
|
The document reference is D1386 (Enhanced Disk Drive Services 3.0).
|
||||||
|
|
478
docs/elilo.txt
Normal file
478
docs/elilo.txt
Normal file
|
@ -0,0 +1,478 @@
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
ELILO.EFI: Linux boot loader for EFI/IA-64 and EFI/IA-32 based systems
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
|
||||||
|
August 2003
|
||||||
|
|
||||||
|
Copyright (C) 2000-2003 Hewlett-Packard Co.
|
||||||
|
|
||||||
|
|
||||||
|
I/ Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
This document describes how to use ELILO on for both IA-64 and IA-32 EFI-based platforms.
|
||||||
|
This document describes ELILO version 3.4.
|
||||||
|
|
||||||
|
II/ Command line options
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
elilo [-hDpPVvaE] [-d nsec] [-C config] [-i initrd] [-c chooser] [kernel [kernel options...]]
|
||||||
|
|
||||||
|
-h Display a list of all possible command line options.
|
||||||
|
|
||||||
|
-V Print the version number and exit.
|
||||||
|
|
||||||
|
-d nsec Specify the number of 10th of seconds before loading the
|
||||||
|
kernel.
|
||||||
|
|
||||||
|
-C file Specify the config file to use. The default is elilo.conf in the directory
|
||||||
|
that elilo.efi was loaded from.
|
||||||
|
|
||||||
|
-P Verify config file syntax only. this option causes ELILO to
|
||||||
|
parse the config file and generate a report on the console.
|
||||||
|
No kernel is loaded.
|
||||||
|
|
||||||
|
-v Turn on verbose mode. ELILO prints more message about what it
|
||||||
|
is doing. For each occurrence of this option the verbosity level
|
||||||
|
is increased by one. The maximum level is 5.
|
||||||
|
|
||||||
|
-a Always check for alternate kernel image. The default behavior
|
||||||
|
of ELILO is to NOT look for an alternate image. This
|
||||||
|
option overrides this behavior and ELILO is checking for
|
||||||
|
alternate images no matter what. Alternate images are
|
||||||
|
specified using the EliloAlt EFI variable.
|
||||||
|
|
||||||
|
-p force interactive prompt mode. Valid when no kernel image is
|
||||||
|
specified on the command line.
|
||||||
|
|
||||||
|
-D print debug output.
|
||||||
|
|
||||||
|
-E don't force EDD30 variable to TRUE when FALSE.
|
||||||
|
|
||||||
|
-i file Use file as the initial ramdisk (initrd).
|
||||||
|
|
||||||
|
-c name Specify which kernel chooser to use. Default is 'simple', and
|
||||||
|
the only other choice at present is 'textmenu'.
|
||||||
|
|
||||||
|
In addition, elilo supports platform specific options:
|
||||||
|
|
||||||
|
For IA-64:
|
||||||
|
----------
|
||||||
|
-r the kernel image can be relocated if initial load address is not
|
||||||
|
available. This options requires a special version of the kernel.
|
||||||
|
|
||||||
|
-F file will try to load the FPSWA driver indicated by 'file'. Only this file
|
||||||
|
will be attempted. When no specific file is given, elilo will try
|
||||||
|
loading \efi\intel firmware\fpswa.efi from all accessible EFI system
|
||||||
|
partitions.
|
||||||
|
For IA-32:
|
||||||
|
----------
|
||||||
|
no option defined.
|
||||||
|
|
||||||
|
All file names (including the kernel file) can include a device name using the
|
||||||
|
following syntax:
|
||||||
|
|
||||||
|
dev_name:/path/to/my/kernel
|
||||||
|
|
||||||
|
The 'dev_name' component depends on the naming scheme selected and the detected
|
||||||
|
devices for your system. Some choosers may print the information automatically
|
||||||
|
or on demand, see chooser specific documentation for more on this. See README.devschemes
|
||||||
|
for more information on device naming schemes. The slash character '/' can be used as
|
||||||
|
a directory separator on any file systems including the EFI file system (FAT32).
|
||||||
|
|
||||||
|
|
||||||
|
III/ Configuration File
|
||||||
|
------------------
|
||||||
|
|
||||||
|
ELILO supports a config file with options similar to the LILO/x86 boot loader.
|
||||||
|
|
||||||
|
Elilo will use the following sequence (shown in order) when looking for its config
|
||||||
|
file when none is specified on the command line:
|
||||||
|
|
||||||
|
1/ AABBCCDD.conf (netbooting with regular DHCP)
|
||||||
|
where AABBCCDD is the hexadecimal representation
|
||||||
|
of the IP address assigned during the DHCP phase.
|
||||||
|
|
||||||
|
2/ elilo-ia64.conf or elilo-ia32.conf
|
||||||
|
The choice depends on the client platform. This step allows
|
||||||
|
the same DHCP/PXE server to provide files for both types of clients.
|
||||||
|
|
||||||
|
3/ elilo.conf
|
||||||
|
|
||||||
|
Unless explicitly specified on the command line, elilo looks for its config file
|
||||||
|
in the filesystem and directory it was loaded from. For instance, if elilo.efi
|
||||||
|
is invoked as:
|
||||||
|
|
||||||
|
fs0:\> \efi\debian\elilo.efi
|
||||||
|
|
||||||
|
Then elilo will look for its configuration file in fs0:\efi\debian and not
|
||||||
|
in the root directory of fs0:. The prefix fs0:\efi\debian will be used for
|
||||||
|
all other files that elilo needs to download when their paths are specified
|
||||||
|
as being relative.
|
||||||
|
|
||||||
|
IMPORTANT:
|
||||||
|
This rule also applies when a specific config file is passed via the -C
|
||||||
|
option. For example:
|
||||||
|
|
||||||
|
fs0:\> \efi\debian\elilo.efi -C elilo.conf
|
||||||
|
|
||||||
|
This will look for elilo.conf in fs0:\efi\debian and not in fs0:\.
|
||||||
|
To get to the elilo.conf in fs0:\, you need to specify the absolute
|
||||||
|
path:
|
||||||
|
|
||||||
|
fs0:\> \efi\debian\elilo.efi -C \elilo.conf
|
||||||
|
|
||||||
|
|
||||||
|
The configuration file is an ASCII file and not a UNICODE file.
|
||||||
|
|
||||||
|
The config file contains additional options to change the behavior of the loader.
|
||||||
|
If the same option is specified in the config file AND on the command line, the
|
||||||
|
latter takes precedence. Not all options available in the config file have an
|
||||||
|
equivalent on command line.
|
||||||
|
|
||||||
|
When elilo is invoked with the -h option, it prints the list of support command line
|
||||||
|
options but also the list of config file options. For each option it also prints
|
||||||
|
the type of data expected.
|
||||||
|
|
||||||
|
The config file options are divided in 2 groups:
|
||||||
|
|
||||||
|
|
||||||
|
- image options which are specific to a particular kernel image. Each kernel image
|
||||||
|
must be identified with a logical name called a label.
|
||||||
|
|
||||||
|
- global options which affect the behavior of ELILO and apply to all images.
|
||||||
|
|
||||||
|
The ELILO config file follows the LILO/x86 syntax. First come the global
|
||||||
|
options, then the list of images and options for each of them, if
|
||||||
|
necessary. At least one image MUST be defined and it is possible to have
|
||||||
|
an empty list of global options.
|
||||||
|
|
||||||
|
Options have types. Three types are defined:
|
||||||
|
- boolean: set or not set
|
||||||
|
- string : a string of characters which can be quoted if necessary
|
||||||
|
- number (in decimal)
|
||||||
|
- filename: a string interpreted as a file name
|
||||||
|
|
||||||
|
|
||||||
|
The config file supports the following options:
|
||||||
|
|
||||||
|
Global Options:
|
||||||
|
---------------
|
||||||
|
default=value Name the default image to boot. If not defined ELILO
|
||||||
|
will boot the first defined image.
|
||||||
|
|
||||||
|
timeout=number The number of 10th of seconds to wait while in
|
||||||
|
interactive mode before auto booting default kernel.
|
||||||
|
Default is infinity.
|
||||||
|
|
||||||
|
delay=number The number of 10th of seconds to wait before
|
||||||
|
auto booting when not in interactive mode.
|
||||||
|
Default is 0.
|
||||||
|
|
||||||
|
prompt Force interactive mode
|
||||||
|
|
||||||
|
verbose=number Set level of verbosity [0-5]. Default 0 (no verbose)
|
||||||
|
|
||||||
|
root=filename Set global root filesystem for Linux/ia64
|
||||||
|
|
||||||
|
read-only Force root filesystem to be mounted read-only
|
||||||
|
|
||||||
|
append=string Append a string of options to kernel command line
|
||||||
|
|
||||||
|
initrd=filename Name of initrd file
|
||||||
|
|
||||||
|
image=filename Define a new image
|
||||||
|
|
||||||
|
chooser=name Specify kernel chooser to use: 'simple' or 'textmenu'.
|
||||||
|
|
||||||
|
message=filename a message that is printed on the main screen if supported by
|
||||||
|
the chooser.
|
||||||
|
|
||||||
|
fX=filename Some choosers may take advantage of this option to
|
||||||
|
display the content of a file when a certain function
|
||||||
|
key X is pressed. X can vary from 1-12 to cover
|
||||||
|
function keys F1 to F12.
|
||||||
|
|
||||||
|
noedd30 do not force the EDD30 EFI variable to TRUE when FALSE. In other
|
||||||
|
words, don't force the EDD30 mode if not set.
|
||||||
|
|
||||||
|
Image options:
|
||||||
|
--------------
|
||||||
|
root=filename Set root filesystem for kernel
|
||||||
|
|
||||||
|
read-only Force root filesystem to be mounted read-only
|
||||||
|
|
||||||
|
append=string Append a string of options to kernel command line
|
||||||
|
|
||||||
|
initrd=filename Name of initrd file
|
||||||
|
|
||||||
|
label=string Logical name of image (used in interactive mode)
|
||||||
|
|
||||||
|
description=string One line text description of the image.
|
||||||
|
|
||||||
|
IA-64 specific options:
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Global options:
|
||||||
|
---------------
|
||||||
|
fpswa=file Specify the filename for a specific FPSWA to load.
|
||||||
|
If this option is used then no other file will be tried.
|
||||||
|
|
||||||
|
relocatable In case of memory allocation error at initial load point of
|
||||||
|
kernel, allow attempt to relocate (assume kernels is relocatable)
|
||||||
|
|
||||||
|
Image options:
|
||||||
|
--------------
|
||||||
|
relocatable In case of memory allocation error at initial load point of
|
||||||
|
kernel, allow attempt to relocate (assume this kernel is relocatable)
|
||||||
|
|
||||||
|
IA-32 specific options:
|
||||||
|
-----------------------
|
||||||
|
legacy-free Indicate that the host machine does not have a legacy BIOS at all.
|
||||||
|
|
||||||
|
|
||||||
|
The user can specify a kernel and related kernel options using the image label. Alternatively,
|
||||||
|
the user can also specify a kernel file that is not specified in the config file. In any case,
|
||||||
|
some of the global options (such as append) are always concatenated to whatever the user type.
|
||||||
|
|
||||||
|
|
||||||
|
IV/ Booting from the local system
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
The elilo.efi binary must be in an EFI system partition (FAT32). The config
|
||||||
|
file, kernel image, and optional initrd ramdisk can be on the same partition
|
||||||
|
or even another EFI partition. In the following discussion we assume that all
|
||||||
|
files are on the same EFI partition which is recognized by the EFI shell (nshell)
|
||||||
|
as fs0. The kernel and initrd can be copied from the any linux filesystems to the
|
||||||
|
EFI partition using either the mtools (mcopy) or by mounting the EFI partition as
|
||||||
|
a vfat partition. However you do not really need this because most linux
|
||||||
|
distributions install both files in the EFI partition and mount this partition in /boot/efi.
|
||||||
|
|
||||||
|
To boot a kernel, simply power cycle the machine. Once you get to the EFI
|
||||||
|
shell prompt, change to the filesystem that maps to the partition where elilo is.
|
||||||
|
|
||||||
|
Shell> fs0:
|
||||||
|
fs0:\>
|
||||||
|
|
||||||
|
You might need to make sure that the Shell Path is set such that it will load
|
||||||
|
ELILO from fs0:. You can verify this by typing:
|
||||||
|
fs0:\> set
|
||||||
|
path : fs0:\
|
||||||
|
|
||||||
|
At this point you can invoke ELILO:
|
||||||
|
|
||||||
|
fs0:\> elilo
|
||||||
|
|
||||||
|
If there is no config file, then it will:
|
||||||
|
- pick up the kernel image named vmlinux if it exists, otherwise it will abort.
|
||||||
|
- pass no argument to the kernel.
|
||||||
|
|
||||||
|
You can specify the kernel image and its options on the command line.
|
||||||
|
For instance you can do:
|
||||||
|
|
||||||
|
fs0:\> elilo vmlinux root=/dev/sda5
|
||||||
|
|
||||||
|
You can specify as many parameters as you want. The syntax follows the kernel
|
||||||
|
rule, i.e., list of value pairs (or even single values) separated by space.
|
||||||
|
A more complicated example would be:
|
||||||
|
|
||||||
|
fs0:\> elilo -i initrd-2.4.9 vmlinuz-2.4.9 root=/dev/sda2 console=tty0 console="ttyS0,115200n8"
|
||||||
|
|
||||||
|
In this example, notice the double quotes. They are required because the comma is a control
|
||||||
|
character for nshell.
|
||||||
|
|
||||||
|
In the case a config file is found, then elilo will behave according to
|
||||||
|
the options in that file. However if elilo is invoked with command line options, they
|
||||||
|
will be combined or they will override (if conflicting) what is defined in the config file.
|
||||||
|
|
||||||
|
As of version 3.3, elilo is fully compliant with the EFI specification (1.10) with regards
|
||||||
|
to where the bootloader (elilo.efi) must be located in the EFI system partition. In
|
||||||
|
section 11.2.1.3 of the EFI1.10 specification, it is said that in order to avoid conflicts
|
||||||
|
between various loaders for various OSes or distributions of the same OS, every vendor MUST
|
||||||
|
use a dedicated directory: \EFI\vendor\. The bootloader must be placed in this directory.
|
||||||
|
This has always been possible as this is a matter of creating the directory and copying
|
||||||
|
the elilo.efi file in it. However up until version 3.3, elilo would look for its config file
|
||||||
|
and kernel/initrd in the root (/) of the partition it was loaded from. As of version 3.3,
|
||||||
|
elilo will now ONLY look for its configuration file FROM THE DIRECTORY IT WAS LOADED FROM.
|
||||||
|
The same applies to the kernel and initrd files unless absolute paths are specified. Let us
|
||||||
|
look at a simple example:
|
||||||
|
|
||||||
|
- suppose elilo.efi is in \EFI\DIST if fs0: (for the EFI Shell)
|
||||||
|
|
||||||
|
- if you invoke elilo as follows:
|
||||||
|
|
||||||
|
fs0:\> \efi\dist\elilo -v -p
|
||||||
|
default file path: \efi\dist\
|
||||||
|
config file : \efi\dist\elilo.conf
|
||||||
|
ELILO boot:
|
||||||
|
|
||||||
|
|
||||||
|
Note that this is the same if you invoke elilo directly from \efi or \efi\dist.
|
||||||
|
|
||||||
|
File references in the configuration file are treated as relative to the directory
|
||||||
|
elilo was loaded from except if they use an absolute path.
|
||||||
|
|
||||||
|
As of version 3.4 a similar rule applies to the network boot sequence, see netbooting.txt
|
||||||
|
for details.
|
||||||
|
|
||||||
|
V/ Interactive mode
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Elilo can be forced into interactive mode using the "prompt" option in the config
|
||||||
|
file or with the -p option. In this mode, the user can select a kernel to load.
|
||||||
|
|
||||||
|
The interface depends on the chooser, it may be a simple command line prompt as provided
|
||||||
|
by the simple chooser or a more sophisticated screen with scroll menus as provided by
|
||||||
|
textmenu. Most choosers depends on the elilo config file to get the information they
|
||||||
|
display. The simple chooser can operated without the elilo config file. However it
|
||||||
|
is always better to have this file, to create handy logical names for each possible
|
||||||
|
boot choices. The logical names are specified with the "label" option in the config
|
||||||
|
file. They represent a specific kernel "image" and its specific options.
|
||||||
|
|
||||||
|
In elilo, the user can select a particular kernel image using the corresponding label
|
||||||
|
name. A simple example is as follows:
|
||||||
|
|
||||||
|
If we suppose that the following is defined in elilo.conf:
|
||||||
|
|
||||||
|
image=vmlinuz-2.4.9
|
||||||
|
label=linux-up
|
||||||
|
initrd=initrd-2.4.9
|
||||||
|
root=/dev/sda2
|
||||||
|
append="console=tty0 console=ttyS0,115200n8"
|
||||||
|
|
||||||
|
then the user can specify linux-up at the prompt and elilo will load the
|
||||||
|
vmlinuz-2.4.9 kernel file and the initrd-2.4.9 ramdisk and will pass
|
||||||
|
|
||||||
|
"root=/dev/sda2 console=tty0 console=ttyS0,115200n8"
|
||||||
|
|
||||||
|
as command line arguments to the kernel.
|
||||||
|
|
||||||
|
This behavior is identical to Lilo/x86. However, elilo further allows the user
|
||||||
|
to specify actual kernel files names as well, i.e., kernels that are not defined
|
||||||
|
in the configuration file. If we reuse the above example and the simple chooser,
|
||||||
|
the user can type:
|
||||||
|
|
||||||
|
ELILO boot: vmlinux-2.4.18 root=/dev/sda2
|
||||||
|
|
||||||
|
and elilo will boot the vmlinuz-2.4.18 kernel if it exists.
|
||||||
|
|
||||||
|
VI/ The alternate kernel image
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
Oftentimes when debugging kernels you want to reboot the machine once with
|
||||||
|
your test kernel and, if something goes wrong, you want to fall back to a more
|
||||||
|
stable kernel. In addition you want to be able to do this from a remote machine.
|
||||||
|
Many things can go wrong when doing kernel debugging. It could be that you don't
|
||||||
|
even reach user-mode. In this case however, you still want to fall back to
|
||||||
|
a stable kernel. The feature you'd like from a boot loader is 'boot once and
|
||||||
|
then fall back to safe kernel'.
|
||||||
|
|
||||||
|
Elilo offers this feature and it's called 'alternate kernel image'.
|
||||||
|
You can configure elilo to load a kernel only once and then whatever
|
||||||
|
happens the next reboot falls back to a different kernel hopefully more stable.
|
||||||
|
|
||||||
|
To do this, elilo relies on an EFI variable called 'EliloAlt' with a NULL GUID.
|
||||||
|
The content of this variable is a UNICODE string containing the kernel file name
|
||||||
|
and its command line options.
|
||||||
|
|
||||||
|
When the -a option is specified on the command line or if the "checkalt" option
|
||||||
|
is present in the config file, elilo will check for the presence of this variable.
|
||||||
|
If found and the content is a valid UNICODE string, elilo will use it as the kernel
|
||||||
|
to boot. There is no verification made on the validity of the kernel name or options.
|
||||||
|
Then the variable is deleted. If the variable is rejected because it does not look
|
||||||
|
sane, it is also deleted.
|
||||||
|
|
||||||
|
The variable can be set from a running Linux system using the /proc/efi/vars
|
||||||
|
interface. In the tools directory of this package, there is a Linux tool called
|
||||||
|
elilovar which can be used to create, modify, print, and delete the EliloAlt
|
||||||
|
variable. Refer to eliloalt.txt for more information on this tool.
|
||||||
|
|
||||||
|
VII/ Auto booting the machine
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Once you're satisfied with your machine setup, it is good to install an
|
||||||
|
auto boot procedure. You have two options to do this:
|
||||||
|
- from the EFI boot manager menu
|
||||||
|
- from the EFI shell
|
||||||
|
|
||||||
|
The first option is preferred and is used by most Linux distributions.
|
||||||
|
Elilo can be invoked directly from the boot manager. You need to get into
|
||||||
|
the 'boot maintenance' menu and use load file a file. This can be tedious
|
||||||
|
so instead it is recommended that you use a Linux tool called efibootmgr
|
||||||
|
which is also shipped in most distributions. With this tool, you can
|
||||||
|
create your own boot option and change the boot order.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The second approach use the EFI shell and a shell script with a special name: 'startup.nsh'.
|
||||||
|
|
||||||
|
When the system boots, it looks for EFI partitions and if it finds
|
||||||
|
a 'startup.nsh' file in ANY of these it will jumpstart execution from it.
|
||||||
|
|
||||||
|
So the typical way of auto booting your Linux/ia64 system is to simply create
|
||||||
|
such a file with the following content:
|
||||||
|
|
||||||
|
# cat /boot/startup.nsh
|
||||||
|
elilo vmlinuz root=/dev/sda2
|
||||||
|
|
||||||
|
Of course, this can be simplified if there is a configuration file.
|
||||||
|
|
||||||
|
|
||||||
|
VII/ Netbooting
|
||||||
|
----------
|
||||||
|
|
||||||
|
Please refer to netbooting.txt for a complete description of how to boot
|
||||||
|
from the network.
|
||||||
|
|
||||||
|
|
||||||
|
XII/ Booting on EFI/ia32 platforms
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Until PC comes with the EFI firmware built in, you need to boot from a
|
||||||
|
floppy that has the EFI firmware on it. Such floppy can be
|
||||||
|
constructed from the EFI sample implementation and toolkit that is
|
||||||
|
available from the Intel Developer Web site at:
|
||||||
|
|
||||||
|
http://developer.intel.com/technology/efi/
|
||||||
|
|
||||||
|
To use elilo on IA-32, you can put it on a floppy and
|
||||||
|
on a FAT32 partition (msdos partition). You can also
|
||||||
|
netbooting if you network adapter has support for UNDI/PXE.
|
||||||
|
|
||||||
|
Elilo/ia32 is capable of booting unmodified 2.2.x. and 2.4.x kernels
|
||||||
|
as they are shipped by distributors today (such as Redhat7.2). You don't need
|
||||||
|
to recompile the kernel with special options. Elilo ONLY takes compressed kernel
|
||||||
|
image which are typically obtained via a 'make bzImage'. Plain elf/32 kernel can't
|
||||||
|
be booted (plain vmlinux will not work). Similarly, existing initial ramdisks can
|
||||||
|
be used without modifications.
|
||||||
|
|
||||||
|
IX/ Credits
|
||||||
|
-------
|
||||||
|
|
||||||
|
Intel Corp.
|
||||||
|
Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
David Mosberger <davidm@hpl.hp.com>
|
||||||
|
Johannes Erdfelt <jerdfelt@valinux.com>
|
||||||
|
Richard Hirst <rhirst@linuxcare.com>
|
||||||
|
Chris Ahna <christopher.j.ahna@intel.com>
|
||||||
|
Mike Johnston <michael.johnston@intel.com>
|
||||||
|
|
||||||
|
X/ Bug reports
|
||||||
|
-----------
|
||||||
|
|
||||||
|
You can submit bugs to <eranian@hpl.hp.com> or to the Linux/ia64
|
||||||
|
mailing list at linux-ia64@linuxia64.org. Visit http://www.linuxia64.org
|
||||||
|
to subscribe to this list.
|
||||||
|
|
||||||
|
XIII/ Reference
|
||||||
|
---------
|
||||||
|
|
||||||
|
EFI v1.02 specifications are available from the following web site:
|
||||||
|
|
||||||
|
http://developer.intel.com/technology/efi/
|
||||||
|
|
||||||
|
The latest sources of ELILO can be downloaded at:
|
||||||
|
|
||||||
|
ftp://ftp.hpl.hp.com/pub/linux-ia64
|
||||||
|
|
77
docs/eliloalt.txt
Normal file
77
docs/eliloalt.txt
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
Information related to the eliloalt Linux tool
|
||||||
|
---------------------------------------------
|
||||||
|
(c) 2002-2003 Hewlett Packard Co
|
||||||
|
Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
|
||||||
|
Last updated: March 1st, 2002
|
||||||
|
|
||||||
|
|
||||||
|
The elilo alternate image feature uses an EFI variable called EliloAlt.
|
||||||
|
The content of this variable is a UNICODE string containing a kernel
|
||||||
|
image file and its command line options. The variable has a NULL GUID.
|
||||||
|
|
||||||
|
To create, read, or modify the variable you need to use the EFI variable
|
||||||
|
service and the SetVariable() or GetVariable() interface. The service
|
||||||
|
is available when EFI is in boot service mode, i.e., prior to loading
|
||||||
|
the kernel but it is also available at runtime when the Linux kernel
|
||||||
|
has taken over the control of the machine.
|
||||||
|
|
||||||
|
In order to modify the variable, you can either write a small EFI applications
|
||||||
|
or use the Linux/ia64 interface to the EFI variables which use the /proc filesystem.
|
||||||
|
|
||||||
|
The elilalt tool included in this package uses the /proc interface to EFI variables
|
||||||
|
to create, read, or modify the EliloAlt variable. This tool is a Linux/ia64 application
|
||||||
|
and NOT an EFI application.
|
||||||
|
|
||||||
|
|
||||||
|
Because modiyfing the EliloAlt can influence how the machine is booted, you must
|
||||||
|
be root to run the program, even when you simply want to read the content of
|
||||||
|
the variable.
|
||||||
|
|
||||||
|
Eliloalt provides the following options:
|
||||||
|
|
||||||
|
-h, --help display this help and exit
|
||||||
|
--version output version information and exit
|
||||||
|
-s, --set cmdline set elilo alternate variable to cmdline
|
||||||
|
-p, --print print elilo alternate variable
|
||||||
|
-d, --delete print elilo alternate variable
|
||||||
|
|
||||||
|
1/ Creation of the variable
|
||||||
|
|
||||||
|
To create the variable you can type:
|
||||||
|
|
||||||
|
# eliloalt -s "vmlinuz-2.4.9 root=/dev/sdb2 hdc=ide-scsi"
|
||||||
|
|
||||||
|
It is VERY important to use quotes to make sure that the entire list of arguments is
|
||||||
|
treated as a single argument to the program. Otherwise only the first element
|
||||||
|
(here vmlinuz-2.4.9) will be used.
|
||||||
|
|
||||||
|
|
||||||
|
2/ Printing the content of the variable
|
||||||
|
|
||||||
|
To print the content of the variable you need to type:
|
||||||
|
|
||||||
|
# eliloalt -p
|
||||||
|
EliloAlt="vmlinuz-2.4.9 root=/dev/sdb2 hdc=ide-scsi"
|
||||||
|
|
||||||
|
3/ Modifying the variable
|
||||||
|
|
||||||
|
You can simply use the -s option:
|
||||||
|
# eliloalt -s "vmlinuz-2.4.18 root=/dev/sdb2"
|
||||||
|
# eliloalt -p
|
||||||
|
EliloAlt="vmlinuz-2.4.18 root=/dev/sdb2"
|
||||||
|
|
||||||
|
3/ Deleting the variable
|
||||||
|
|
||||||
|
You must use the -d option:
|
||||||
|
# eliloalt -p
|
||||||
|
EliloAlt="vmlinuz-2.4.18 root=/dev/sdb2"
|
||||||
|
# eliloalt -d
|
||||||
|
# eliloalt -p
|
||||||
|
variable not defined
|
||||||
|
|
||||||
|
Keep in mind that the variable is automatically deleted by elilo if:
|
||||||
|
- the checkalt option is specified in the config file
|
||||||
|
OR
|
||||||
|
- the -a is used on the command line
|
||||||
|
|
53
docs/elilovars.txt
Normal file
53
docs/elilovars.txt
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
Information related to variable support in ELILO
|
||||||
|
------------------------------------------------
|
||||||
|
(c) 2002-2003 Hewlett Packard Co
|
||||||
|
Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
|
||||||
|
Last updated: 06/13/2002
|
||||||
|
|
||||||
|
As of version 3.2, elilo has internal variables which can be programmed
|
||||||
|
by any module inside the bootloader code. These variables are used
|
||||||
|
to parametrize some of the arguments passed on the kernel command line.
|
||||||
|
|
||||||
|
The value of a variable is a Unicode string. Variables names are composed
|
||||||
|
of a single Unicode character, such as 'I' for instance. Variable names
|
||||||
|
are case sensitive. Elilo has support for 52 variables: A-Z and a-z.
|
||||||
|
|
||||||
|
The '%' sign is used to name a variable. For instance, '%I' indicates
|
||||||
|
variable 'I'. If '%I' is present on the command line to the kernel,
|
||||||
|
it will be replaced (string replacement) with the value (a string) of 'I'.
|
||||||
|
By default, the Elilo core does not assign any values to any variables.
|
||||||
|
It is up to each module to do so. When a variable is not used, its content
|
||||||
|
is the empty string "", which means that the '%d' notation, for instance, will
|
||||||
|
be replaced with the empty string.
|
||||||
|
|
||||||
|
Let us look at an example:
|
||||||
|
Supposing that the following variables are defined:
|
||||||
|
'I' -> "192.168.2.5"
|
||||||
|
'G' -> "192.168.2.1"
|
||||||
|
'M' -> "255.255.255.0"
|
||||||
|
'z' -> ""
|
||||||
|
|
||||||
|
Then a command line of this form (provided as an append= option in elilo.conf):
|
||||||
|
|
||||||
|
root=/dev/nfs nfsroot=15.4.88.178:/mnt2 ip=%I:%z:%G:%N:jung:eth0:on
|
||||||
|
|
||||||
|
Would pass the following to the kernel:
|
||||||
|
|
||||||
|
root=/dev/nfs nfsroot=15.4.88.178:/mnt2 ip=192.168.2.5::192.168.2.1:255.255.255.0:jung:eth0:on
|
||||||
|
|
||||||
|
Of course, the meaning of each variable is up to each individual module, the
|
||||||
|
names used here are not necessarily representative of the actual names used
|
||||||
|
by elilo.
|
||||||
|
|
||||||
|
Some choosers, (such as simple) have support to print the list of
|
||||||
|
defined variables. For instance, in simple (the default chooser) you
|
||||||
|
can press '%' to see the list of defined variables.
|
||||||
|
|
||||||
|
Variables can be useful when netbooting, for instance, to get the
|
||||||
|
dynamically assigned IP, netmask, and gateway addresses.
|
||||||
|
|
||||||
|
In case the % character needs to be passed to the kernel, it is possible
|
||||||
|
to "despecialize" a character using the & symbol in front of it.
|
||||||
|
|
||||||
|
See netbooting.txt for more information on this.
|
22
docs/fpswa.txt
Normal file
22
docs/fpswa.txt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Information related to the FPSWA driver for EFI/ia64 platforms
|
||||||
|
--------------------------------------------------------------
|
||||||
|
(c) 2002-2003 Hewlett Packard Co
|
||||||
|
Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
|
||||||
|
This document is irrelevant for EFI/ia32 platforms.
|
||||||
|
|
||||||
|
On all EFI/ia64 platforms, the bootloader is responsible for checking for
|
||||||
|
the presence on the EFI system partition of an updated version of the
|
||||||
|
Floating-Point Software Assist (FPSWA) EFI driver (fpswa.efi). For every
|
||||||
|
instance found, elilo will load the driver and let EFI decide if it is
|
||||||
|
newer than the currently installed version. In the end at most one driver
|
||||||
|
is kept in memory.
|
||||||
|
|
||||||
|
Elilo will look for a file called fpswa.efi in the \EFI\Intel Firmware
|
||||||
|
(there is a space between l and F) directory on ALL accessible EFI system
|
||||||
|
partitions (including on removable media). It will do so even when elilo
|
||||||
|
is downloaded from the network. It does not look for the driver in the
|
||||||
|
ext2fs partitions.
|
||||||
|
|
||||||
|
The FPSWA reference document is available from the Intel developer's web
|
||||||
|
site at http://developer.intel.com/design/itanium.
|
396
docs/netbooting.txt
Normal file
396
docs/netbooting.txt
Normal file
|
@ -0,0 +1,396 @@
|
||||||
|
How to netboot using ELILO
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
Copyright (C) 2002-2003 Hewlett-Packard Co.
|
||||||
|
Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
|
||||||
|
Last updated: 03/08/11
|
||||||
|
|
||||||
|
EFI has full support for the PXE and DHCP protocol. As such
|
||||||
|
it is relatively easy to boot a machine from the network using EFI.
|
||||||
|
The elilo loader has full support for both PXE and DHCP, therefore
|
||||||
|
it is possible to download the elilo config file, the Linux kernel image
|
||||||
|
and the initial ramdisk from a remote server. There are many ways
|
||||||
|
netbooting can be configured but in this document we focus
|
||||||
|
only on two very common cases:
|
||||||
|
|
||||||
|
- netboot but use local root filesystem.
|
||||||
|
- booting a diskless machine, i.e., use a NFS root filesystem.
|
||||||
|
|
||||||
|
1/ How to get EFI to netboot?
|
||||||
|
|
||||||
|
You do not need any additional software to get EFI to start a netboot session.
|
||||||
|
Any EFI machine can be configured to start a PXE/DHCP session IF it has a network
|
||||||
|
adapter that has support for the UNDI/PXE protocol. Most modern cards do have such
|
||||||
|
support.
|
||||||
|
|
||||||
|
To enable netbooting, you need to go into the EFI boot manager maintenance menu
|
||||||
|
and 'Add a boot option'. On the screen you see the list of devices to boot from.
|
||||||
|
At least one of them should be of the form:
|
||||||
|
|
||||||
|
Load File [Acpi(PNP0A03,0)/Pci(5|0)/Mac(00D0B7A6FC25)]
|
||||||
|
|
||||||
|
which represent Ethernet card (Mac address). If you don't have such option, it means that
|
||||||
|
you either do not have a network adapter in your machine or it does not have the
|
||||||
|
UNDI/PXE support in its option ROM.
|
||||||
|
|
||||||
|
You need to select this option and give it a logical name such as 'netboot', for instance.
|
||||||
|
Next, you leave the maintenance menu and go back to the main menu. You now have a new
|
||||||
|
boot menu option. If you select 'netboot' then EFI will start the PXE/DCHP discovery
|
||||||
|
request and look for a server to get an IP address.
|
||||||
|
|
||||||
|
On the server side, you can use a standard DHCP server, such as the one shipped on
|
||||||
|
Redhat7.2 (dhcpd) or a PXE server (not yet available for Linux, probably available for Windows).
|
||||||
|
In this document we show both options. You also need a TFTP server somewhere on the network,
|
||||||
|
it will be used to download the actual files.
|
||||||
|
|
||||||
|
|
||||||
|
2/ Netbooting using DHCP
|
||||||
|
|
||||||
|
There is nothing specific to EFI that needs to be set in the /etc/dhcpd.conf file.
|
||||||
|
Clearly the filename option must contains the path to the elilo.efi binary.
|
||||||
|
|
||||||
|
Elilo will auto-detect whether it was downloaded via PXE or DHCP and it will adapt
|
||||||
|
the kind of requests it makes to download the other files that it needs, such as
|
||||||
|
its config file.
|
||||||
|
|
||||||
|
A simple dhcpd.conf file which uses fixed IP addresses could be as follows:
|
||||||
|
|
||||||
|
subnet 192.168.2.0 netmask 255.255.255.0 {
|
||||||
|
host test_machine {
|
||||||
|
hardware ethernet 00:D0:B7:A6:FC:25;
|
||||||
|
fixed-address 192.168.2.10;
|
||||||
|
filename "elilo.efi";
|
||||||
|
option domain-name "mydomain.com";
|
||||||
|
option host-name "test_machine";
|
||||||
|
option routers 192.168.2.1;
|
||||||
|
option subnet-mask 255.255.255.0;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
For the tftp server, you need to make sure that it is ACTIVATED by inetd or xinetd depending
|
||||||
|
on your distribution. In most distributions, it is disabled by default for security reasons.
|
||||||
|
On distributions using xinetd, you need to check /etc/xinet.d/tftp. For inetd you need to
|
||||||
|
check /etc/inetd.conf. It is typical to have the root directory for tftp be /tftpboot but it
|
||||||
|
can be anything. In this document we will use /tftpboot as the root directory. The files
|
||||||
|
that we need are as follows:
|
||||||
|
- elilo.efi
|
||||||
|
- the elilo config file
|
||||||
|
- the kernel image
|
||||||
|
- the initial ramdisk (optional)
|
||||||
|
|
||||||
|
|
||||||
|
a/ Location of the files in the tftp directory tree
|
||||||
|
|
||||||
|
For elilo version 3.3b or higher, it is possible to place the files listed above
|
||||||
|
in any subdirectory below the tftp root. Of course the dhcpd.conf file must
|
||||||
|
point to the location of elilo.efi and provide the path from the tftp root
|
||||||
|
directory.
|
||||||
|
|
||||||
|
Elilo will look for its config file, the kernel image, the initial ramdisk (optional)
|
||||||
|
only from the directory it was loaded from. This is useful when the same tftp server
|
||||||
|
is used to services many different kind of clients.
|
||||||
|
|
||||||
|
Here is a simple example, suppose the dhcpd.conf file contains the following definition:
|
||||||
|
|
||||||
|
subnet 192.168.2.0 netmask 255.255.255.0 {
|
||||||
|
host test_machine {
|
||||||
|
hardware ethernet 00:D0:B7:A6:FC:25;
|
||||||
|
fixed-address 192.168.2.10;
|
||||||
|
|
||||||
|
filename "/rx6000/elilo.efi";
|
||||||
|
|
||||||
|
option domain-name "mydomain.com";
|
||||||
|
option host-name "test_machine";
|
||||||
|
option routers 192.168.2.1;
|
||||||
|
option subnet-mask 255.255.255.0;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Elilo will be downloaded from /tftpboot/rx6000. Then elilo will look
|
||||||
|
for all the other files it needs in /tftpboot/rx6000. This rule is
|
||||||
|
applied to all files, including the all the variation of the config
|
||||||
|
file.
|
||||||
|
|
||||||
|
b/ Getting the config file
|
||||||
|
|
||||||
|
With DHCP, elilo will first try to download its configuration file. It will try
|
||||||
|
several file names and they are as follows:
|
||||||
|
|
||||||
|
1) AABBCCDD.conf
|
||||||
|
where AABBCCDD is the hexadecimal representation of the IP address assigned to
|
||||||
|
the machine by DHCP. The hexadecimal string (AABBCCDD) MUST use upper case
|
||||||
|
characters.
|
||||||
|
|
||||||
|
This filename is an opportunity to specify a machine specific configuration file.
|
||||||
|
|
||||||
|
2) elilo-ia32.config or elilo-ia64.conf
|
||||||
|
|
||||||
|
Depending on the machine (client side) architecture elilo will try the IA-32 or
|
||||||
|
IA-64 file.
|
||||||
|
|
||||||
|
This filename is an opportunity to specify a architecture specific configuration file.
|
||||||
|
This distinction between the architectures is useful when the same TFTP server services
|
||||||
|
the two types of clients : IA32- and IA-64 machines.
|
||||||
|
|
||||||
|
3) elilo.conf
|
||||||
|
|
||||||
|
All files use the same format. Elilo will stop at the first match. In case no file is found,
|
||||||
|
it will try to download a default kernel file name (vmlinux).
|
||||||
|
|
||||||
|
c/ Getting the kernel
|
||||||
|
|
||||||
|
The second request from elilo is typically the kernel image. The filename is based on what
|
||||||
|
is in the elilo config file. The path name depends on how the TFTP server is configured.
|
||||||
|
For security reasons it is customary to have the server do a change root in /tftpboot.
|
||||||
|
Hence filenames are relative to /tftpboot and therefore you don't need to specify it.
|
||||||
|
|
||||||
|
For instance if elilo.conf contains:
|
||||||
|
image=vmlinuz.249
|
||||||
|
label=linux-up
|
||||||
|
root=/dev/sdb2
|
||||||
|
|
||||||
|
and the user selects linux-up, then elilo will request a filename of 'vmlinux.249'
|
||||||
|
which must therefore be in /tftpboot. Check the configuration of your TFTP server for
|
||||||
|
more on this.
|
||||||
|
|
||||||
|
d/ Getting the initial ramdisk
|
||||||
|
|
||||||
|
This step is optional. It follows exactly the same naming rules explained for the kernel image.
|
||||||
|
The initial ramdisk file must therefore be somewhere under /tftpboot.
|
||||||
|
|
||||||
|
For instance if elilo.conf contains:
|
||||||
|
image=vmlinuz.249
|
||||||
|
label=linux-up
|
||||||
|
root=/dev/sdb2
|
||||||
|
initrd=ramdisk/initrd.249
|
||||||
|
|
||||||
|
and the user selects linux-up, then elilo will request a filename of 'ramdisk/initrd.249'
|
||||||
|
which must therefore be under /tftpboot.
|
||||||
|
|
||||||
|
|
||||||
|
e/ Getting IP address information
|
||||||
|
|
||||||
|
When elilo is netbooted, the network filesystem module initializes some elilo variables
|
||||||
|
with the information it received from the DHCP server. At a minimum, it received the
|
||||||
|
IP address.
|
||||||
|
|
||||||
|
The following information is stored in the elilo variables indicated below:
|
||||||
|
- assigned IP address -> %I
|
||||||
|
- assigned netmask -> %M
|
||||||
|
- assigned domainname -> %D
|
||||||
|
- assigned gateway -> %G
|
||||||
|
|
||||||
|
These variables can be used to dynamically adjust the command line arguments passed to the kernel.
|
||||||
|
See section 5/ below for an example.
|
||||||
|
|
||||||
|
3/ Netbooting using PXE
|
||||||
|
|
||||||
|
EFI has builtin support for PXE. In fact it first tries PXE and then default to DHCP
|
||||||
|
when it does not find a valid PXE server.
|
||||||
|
|
||||||
|
There is a PXE server package available from Linux/ia32 however this package does not
|
||||||
|
have the necessary extensions to talk to the EFI side, at least on IA-64 platforms.
|
||||||
|
|
||||||
|
There is no need for special options or compile time flags to get elilo to work
|
||||||
|
with PXE instead of standard DHCP. When netbooted, elilo will automatically detect
|
||||||
|
if it has been downloaded via PXE or DHCP and it will adujst how subsequent files
|
||||||
|
are requested.
|
||||||
|
|
||||||
|
You need a special version of the DHCPD server developed by the Internet Software Consortium
|
||||||
|
(http://www.isc.org) with a special patch to add the PXE extensions. Unfortunately as of
|
||||||
|
version 3.0xx, the patch has not yet made it into the official tree. It is supposed to show
|
||||||
|
up in version 3.1 of the dhcpd server.
|
||||||
|
|
||||||
|
In any case, the elilo package contains a simple example of how you can configure the
|
||||||
|
/etc/dhcpd.conf file for a PXE-aware DHCP server using the extensions provided in the
|
||||||
|
patch. You can look in examples/dhcpd-pxe.conf. The syntax is very different from
|
||||||
|
a standard dhcpd server.
|
||||||
|
|
||||||
|
The key elements to keep in mind are the PXE layers used by elilo to request the different
|
||||||
|
files:
|
||||||
|
|
||||||
|
Layer 0 : to get the name of the boot loader (elilo.efi)
|
||||||
|
Layer 1 : to get the name of the elilo config file
|
||||||
|
Layer 2 : to get the name of the kernel image
|
||||||
|
|
||||||
|
There is an IMPORTANT distinction between those layers. The first two (0,1) and requested
|
||||||
|
systematically whereas the last one is used only when the configuration file is not found, i.e.,
|
||||||
|
what is the default kernel to boot. The actual files are STILL downloaded via TFTP. Therefore
|
||||||
|
the TFTP server must also be configured (see previous section for more on this).
|
||||||
|
|
||||||
|
|
||||||
|
a/ Getting the config file
|
||||||
|
|
||||||
|
In this mode, elilo use the PXE layer 1 to get the config file to use. Therefore this must
|
||||||
|
be set on the server side. Elilo will use the following sequence when
|
||||||
|
looking for a config file:
|
||||||
|
|
||||||
|
- use the name provide by the PXE server Layer 1 or
|
||||||
|
|
||||||
|
- elilo-ia64.conf/elilo-ia32.conf or
|
||||||
|
|
||||||
|
- elilo.conf
|
||||||
|
|
||||||
|
Elilo stops at the first match. With PXE, elilo does not try to download a config file named after
|
||||||
|
the assigned IP address as it does for DHCP because there is enough flexibility in the PXE server
|
||||||
|
configuration to do this.
|
||||||
|
|
||||||
|
b/ Getting the kernel image
|
||||||
|
|
||||||
|
When there is no config file, elilo will use the kernel name returned by
|
||||||
|
PXE layer 2. If it is not specified there, then it default to 'vmlinux'.
|
||||||
|
|
||||||
|
c/ Getting the initial ramdisk
|
||||||
|
|
||||||
|
The filename for the ramdisk MUST come from the config file. Elilo does not use a PXE layer
|
||||||
|
to ask for a default name.
|
||||||
|
|
||||||
|
d/ Getting IP address information
|
||||||
|
|
||||||
|
When elilo is netbooted, the network filesystem module initializes some elilo variables
|
||||||
|
with the information it received from the DHCP server. At a minimum, it received the
|
||||||
|
IP address.
|
||||||
|
|
||||||
|
The following information is stored in the variables indicated below:
|
||||||
|
- assigned IP address -> %I
|
||||||
|
- assigned netmask -> %M
|
||||||
|
- assigned domainname -> %D
|
||||||
|
- assigned gateway -> %G
|
||||||
|
|
||||||
|
These variables can be used to dynamically adjust the command line arguments passed to the kernel.
|
||||||
|
See section 5/ below for an example of how to use the variable.
|
||||||
|
|
||||||
|
|
||||||
|
4/ Netbooting and using a local root filesystem
|
||||||
|
|
||||||
|
This is the simplest configuration where the boot loader, its config file, the kernel
|
||||||
|
and its optional initial ramdisk are downloaded from the network BUT the kernel uses
|
||||||
|
the local disk for its root filesystem.
|
||||||
|
|
||||||
|
For such configuration there is no special option necessary in the elilo config file.
|
||||||
|
You simply need to specify which partition is the root partition. A typical elilo.conf
|
||||||
|
would look as follows:
|
||||||
|
|
||||||
|
image=vmlinuz.249
|
||||||
|
label=linux-up
|
||||||
|
root=/dev/sdb2
|
||||||
|
initrd=ramdisk/initrd.249
|
||||||
|
|
||||||
|
5/ Netbooting a diskless machine
|
||||||
|
|
||||||
|
In this configuration we do not use the local machine's disks but instead rely on
|
||||||
|
a remote server to provide the root filesystem via NFS.
|
||||||
|
|
||||||
|
a/ Prerequisites
|
||||||
|
|
||||||
|
By default most kernels shipped by distributors do not have the support
|
||||||
|
compiled in for such configuration. This means that you need to recompile
|
||||||
|
your own kernel. For instance, vmlinuz-2.4.9 as shipped in Redhat7.2 on
|
||||||
|
both ia32 and ia64 platforms does not have the support builtin.
|
||||||
|
|
||||||
|
To get this configuration to work, you need to have a kernel compiled
|
||||||
|
such that it accepts a root filesystem over NFS (CONFIG_ROOT_NFS). This
|
||||||
|
necessitates that the network stack be configured with the, so called,
|
||||||
|
IP plug-and-play support (CONFIG_IP_PNP).
|
||||||
|
|
||||||
|
b/ On the server side
|
||||||
|
|
||||||
|
You need to have:
|
||||||
|
- a NFS file server to provide the root filesystem.
|
||||||
|
- a DHCP/PXE server to get the IP address and download the boot loader.
|
||||||
|
|
||||||
|
Note that both do not need to be on the same machine. There is no special
|
||||||
|
DHCP/PXE configuration option required to get this working. All you need
|
||||||
|
is a kernel compiled with the options mentioned in a/. You also need to
|
||||||
|
make sure that the permission on the NFS server are set appropriately
|
||||||
|
to allow root access from the client machine (no_root_squash), see
|
||||||
|
man 'exports' for more on this.
|
||||||
|
|
||||||
|
c/ The elilo configuration file
|
||||||
|
|
||||||
|
To boot successfully, the kernel needs to:
|
||||||
|
- get an IP address and related networking parameters
|
||||||
|
- contact the NFS server to get its root filesystem
|
||||||
|
|
||||||
|
The 2.4.x kernel series provides several options to get the IP address:
|
||||||
|
- it can do an internal DHCP request (CONFIG_IP_PNP_DHCP)
|
||||||
|
- it can do an internal RARP request (CONFIG_IP_PNP_RARP)
|
||||||
|
- it can do an internal BOOTP request (CONFIG_IP_PNP_BOOTP)
|
||||||
|
- it can get the IP address from the command line
|
||||||
|
|
||||||
|
The choice is up to you but it is a little bit stupid to go through a
|
||||||
|
DHCP/BOOTP/RARP phase again when this is already done by the EFI firmware.
|
||||||
|
So in this document, we describe how you can pass the information provided
|
||||||
|
by EFI on the command line of the kernel.
|
||||||
|
|
||||||
|
The syntax used to pass IP information on the command line is described in
|
||||||
|
the kernel source tree in Documentation/nfsroot.txt. The option is called
|
||||||
|
"ip=" and has the following syntax:
|
||||||
|
|
||||||
|
ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>
|
||||||
|
|
||||||
|
To designate the NFS server, you must use the "nfsroot=" option. It has the
|
||||||
|
following syntax:
|
||||||
|
nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>]
|
||||||
|
|
||||||
|
Depending on how you want your system configured you can hardcode the
|
||||||
|
values of the parameters in the elilo configuration file. For instance:
|
||||||
|
|
||||||
|
image=/vmlinuz
|
||||||
|
label=nfsroot
|
||||||
|
description="kernel with NFS root"
|
||||||
|
append="root=/dev/nfs nfsroot=192.168.2.22:/ia64_rootfs ip=192.168.2.5::192.168.2.1:255.255.255.0:test_machine:eth0:on"
|
||||||
|
|
||||||
|
Note the root=/dev/nfs indicates that the root filesystem is over NFS.
|
||||||
|
|
||||||
|
This example works fine however, it is not very flexible because the IP
|
||||||
|
address, the gateway, netmask and hostname are fixed and do not used the
|
||||||
|
values EFI used to download the boot loader and the kernel.
|
||||||
|
|
||||||
|
Elilo provides a way to dynamically customize the parameters passed on the
|
||||||
|
command line using substitution variables. We describe those variables in
|
||||||
|
elilovar.txt. The basic idea is to allow the parameters to use the dynamic
|
||||||
|
information obtained by the DHCP/PXE phase.
|
||||||
|
|
||||||
|
The network support in elilo defines several variables which contained
|
||||||
|
network related information produced by the DHCP/PXE phase. The set of
|
||||||
|
variable is:
|
||||||
|
%I -> the IP address obtained by DHCP/PXE
|
||||||
|
%M -> the netmask obtained by DHCP/PXE
|
||||||
|
%G -> the gateway obtained by DHCP/PXE
|
||||||
|
%H -> the hostname obtained by DHCP/PXE
|
||||||
|
%D -> the domain name obtained by DHCP/PXE
|
||||||
|
|
||||||
|
So, the configuration file can then be customized as follows:
|
||||||
|
image=/vmlinuz
|
||||||
|
label=nfsroot
|
||||||
|
description="kernel with NFS root"
|
||||||
|
append="root=/dev/nfs nfsroot=192.168.2.22:/ia64_rootfs ip=%I::%G:%M:%H:eth0:on"
|
||||||
|
|
||||||
|
Not all parameters are necessary or even used by the kernel or the user level
|
||||||
|
configuration scripts. There is no variable to substitute the NFS server or
|
||||||
|
the mount point on that server.
|
||||||
|
|
||||||
|
|
||||||
|
In the case of a DHCP boot, this type of customization makes sense only for
|
||||||
|
the shared configuration file, elilo-ia64.conf/elilo-ia32.conf or elilo.conf.
|
||||||
|
The configuration file based on the IP address (such as C0A80205.conf in this
|
||||||
|
case) would provide another way of customizing parameters for a specific
|
||||||
|
client (IP address). The same thing holds if the name of the config file
|
||||||
|
returned by the PXE server is specific to a client.
|
||||||
|
|
||||||
|
|
||||||
|
6/ References
|
||||||
|
|
||||||
|
More information on the PXE protocol can be found at the following web site:
|
||||||
|
|
||||||
|
http://developer.intel.com/ial/wfm/
|
||||||
|
|
||||||
|
The source code for the standard and (possibly) PXE-enhanced DHCPD can be
|
||||||
|
downloaded from:
|
||||||
|
|
||||||
|
http://www.isc.org/
|
||||||
|
|
156
docs/simple_chooser.txt
Normal file
156
docs/simple_chooser.txt
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
Information about the simple chooser
|
||||||
|
--------------------------------------
|
||||||
|
Copyright (C) 2002-2003 Hewlett-Packard Co.
|
||||||
|
Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
|
||||||
|
Last updated: 02/02/14
|
||||||
|
|
||||||
|
Chooser name: simple
|
||||||
|
Command line option: -C simple
|
||||||
|
Config file option: chooser=simple, description, message
|
||||||
|
|
||||||
|
The simple chooser is the default chooser. However it is possible
|
||||||
|
to disable it at compile time, it is highly recommended to keep it
|
||||||
|
in. Elilo must have at least one chooser compiled in.
|
||||||
|
|
||||||
|
The simple chooser is very basic as its name indicates! It provides
|
||||||
|
a simple one line text mode command prompt similar to what you get
|
||||||
|
with Lilo/x86.
|
||||||
|
|
||||||
|
Any chooser becomes visible to the user ONLY when the interactive
|
||||||
|
mode is entered.
|
||||||
|
|
||||||
|
The simple chooser allows the user to select a kernel to boot.
|
||||||
|
The user can use a label as specified in the elilo config file
|
||||||
|
or a kernel file name. File names can be specified with
|
||||||
|
absolute names in the form dev_name:/path/to/my_kernel.
|
||||||
|
|
||||||
|
1/ Activation
|
||||||
|
|
||||||
|
The chooser is activated from:
|
||||||
|
|
||||||
|
- command line with the -c simple
|
||||||
|
- the config file with the chooser=simple option
|
||||||
|
|
||||||
|
2/ Supported options
|
||||||
|
|
||||||
|
The simple chooser supports the following options in the config file:
|
||||||
|
|
||||||
|
message=filename : display a message before the prompt. The filename
|
||||||
|
must be an ASCII file
|
||||||
|
|
||||||
|
description=string: a description of the kernel image (ASCII)
|
||||||
|
|
||||||
|
All other options have their standard meaning. The chooser does not recognize
|
||||||
|
the fX (X varies from 1-12) options
|
||||||
|
|
||||||
|
2/ Builtin commands
|
||||||
|
|
||||||
|
The simple chooser has some builtin command which the user can
|
||||||
|
get to by typing certain keys as the first character on the command line:
|
||||||
|
|
||||||
|
TAB: shows the list of defined labels and their descriptions.
|
||||||
|
|
||||||
|
If the user did not type anything, i.e., the line is empty,
|
||||||
|
pressing TAB will print the list of labels defined in the
|
||||||
|
elilo config file.
|
||||||
|
|
||||||
|
If the user already typed a name and if the name corresponds
|
||||||
|
to a specified label, the chooser will show how the label
|
||||||
|
is expanded and what the final command line to the kernel will
|
||||||
|
look like.
|
||||||
|
|
||||||
|
If the line is empty pressing TAB generates something similar to:
|
||||||
|
ELILO boot:
|
||||||
|
linux-up linux nfsroot (or any kernel file name: [dev_name:]/path/file)
|
||||||
|
|
||||||
|
Note that first label correspond to the default label used if the user
|
||||||
|
hits the enter key with an empty line. This label is not necessarily
|
||||||
|
the first one in the config file.
|
||||||
|
|
||||||
|
Now pressing TAB with a full label name:
|
||||||
|
|
||||||
|
ELILO boot: linux-up
|
||||||
|
desc : my default UP kernel
|
||||||
|
cmdline: vmlinuz root=/dev/sdb2 console=ttyS0,115200n8 console=tty0 ro
|
||||||
|
|
||||||
|
The desc line shows whatever was specified in the "description" option
|
||||||
|
for this particular image in the config file.
|
||||||
|
|
||||||
|
= : shows the list of accessible devices
|
||||||
|
|
||||||
|
this key force elilo to print the list of detected devices. Elilo will
|
||||||
|
auto-detect the devices which are accessible to load a config file, the kernel, the
|
||||||
|
initrd from. Those devices typically represent disk partition, CDROM, floppy, or
|
||||||
|
a network path. The list of devices is highly system dependent.
|
||||||
|
It also depends on the filesystem support compiled into elilo.
|
||||||
|
|
||||||
|
The way the devices are named depends on the device naming scheme
|
||||||
|
selected. It also depends on whether the EDD30 support is activated.
|
||||||
|
For instance, pressing the ? could look as follows:
|
||||||
|
|
||||||
|
ELILO boot:
|
||||||
|
scsi0 : vfat : Acpi(PNP0A03,2)/Pci(1|0)/Scsi(Pun0,Lun0)/HD(Part1,Sig72040800)
|
||||||
|
scsi1 : vfat : Acpi(PNP0A03,2)/Pci(1|0)/Scsi(Pun6,Lun0)/HD(Part1,Sig00000000)
|
||||||
|
scsi2 : ext2fs : Acpi(PNP0A03,2)/Pci(1|0)/Scsi(Pun0,Lun0)/HD(Part2,Sig72040800)
|
||||||
|
scsi3 : ext2fs : Acpi(PNP0A03,2)/Pci(1|0)/Scsi(Pun6,Lun0)/HD(Part2,Sig00000000)
|
||||||
|
net0 : netfs : Acpi(PNP0A03,0)/Pci(5|0)/Mac(00D0B7A6FC25)
|
||||||
|
5 devices available for booting
|
||||||
|
boot device net0: netfs
|
||||||
|
|
||||||
|
Here the vfat (EFI partition type), ext2fs and network filesysten (not to be confused
|
||||||
|
with NFS) were compiled into elilo and were detected on the machine. The left handside
|
||||||
|
of the colon show the logical name associated with the device. For instance,
|
||||||
|
scsi0 corresponds to the first partition of SCSI disk ID 0 and is an EFI partition.
|
||||||
|
The net0 correspond to a network device, here the Ethernet adapter. The last line
|
||||||
|
show the device used to load elilo itself, in the case elilo was downloaded from the
|
||||||
|
network.
|
||||||
|
|
||||||
|
To get a kernel from scsi0, the user can simply type:
|
||||||
|
|
||||||
|
ELILO boot: scsi0:/usr/src/linux/vmlinux
|
||||||
|
|
||||||
|
Note that even though elilo was not downloaded from the network, it is still possible
|
||||||
|
to get the kernel and initrd from a remote machine.
|
||||||
|
|
||||||
|
% : shows the list of defined variables
|
||||||
|
|
||||||
|
Elilo has builtin variables which are used to dynamically customized the command line
|
||||||
|
parameters passed to the kernel. The list of variables depends on the support compiled
|
||||||
|
into elilo. Not all elilo subsystems use variables. Typically the network file system
|
||||||
|
does. Pressing '%' only prints the variables that are defined with their current values.
|
||||||
|
Some variables are only defined once the subsystem that creates them has been used.
|
||||||
|
In other words, if the network filesystem was not used to load elilo, then the variables
|
||||||
|
defined by it are not created.
|
||||||
|
|
||||||
|
If the network was actually used, pressing '%' could generate the following output:
|
||||||
|
ELILO boot:
|
||||||
|
D = "mydomain.com
|
||||||
|
G = "192.168.3.1"
|
||||||
|
H = "test_machine"
|
||||||
|
I = "192.168.3.4"
|
||||||
|
M = "255.255.255.0"
|
||||||
|
|
||||||
|
& : shows the list default path
|
||||||
|
|
||||||
|
The path is used as a prefix for all filenames specified as
|
||||||
|
relative.
|
||||||
|
|
||||||
|
? : shows the list of supported command keys
|
||||||
|
|
||||||
|
|
||||||
|
The simple chooser has also some builtin command line editing commands:
|
||||||
|
|
||||||
|
ESC : abort (leave elilo)
|
||||||
|
|
||||||
|
CTRL-D : abort (leave elilo)
|
||||||
|
|
||||||
|
CTRL-C : kill line
|
||||||
|
empty current line and prompt for new input
|
||||||
|
|
||||||
|
CTRL-H : erase the previous character
|
||||||
|
|
||||||
|
CTRL-U : clear current line
|
||||||
|
reset the buffer (does not display correctly if buffer spans more than one line)
|
||||||
|
|
||||||
|
Backspace: erase character
|
61
docs/textmenu_chooser.txt
Normal file
61
docs/textmenu_chooser.txt
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
Information about the textmenu chooser
|
||||||
|
--------------------------------------
|
||||||
|
Copyright (C) 2002-2003 Hewlett-Packard Co.
|
||||||
|
Contributed by <rhirst@linuxcare.com>
|
||||||
|
|
||||||
|
Last updated: 02/02/14
|
||||||
|
|
||||||
|
Chooser name: textmenu
|
||||||
|
Command line option: -C textmenu
|
||||||
|
Config file option: chooser=textmenu
|
||||||
|
|
||||||
|
The textmenu chooser provides a facility whereby you can draw a colour
|
||||||
|
boot screen, using line-drawing characters to give the impression of a
|
||||||
|
dialog box, with a scrollable menu from which a boot image can be chosen
|
||||||
|
via cursor up/down keys. A one-line input field is provided for additional
|
||||||
|
parameter input. Menu entries are taken from the description= fields in
|
||||||
|
the config file.
|
||||||
|
|
||||||
|
The message file format is based on that used for syslinux/isolinux on ia32
|
||||||
|
platforms, which is copyright H. Peter Anvin. It is basically a text file
|
||||||
|
containing text and graphic characters, along with some control codes to
|
||||||
|
specify colour attributes, menu, and prompt field positions. There are two
|
||||||
|
classes of message files; the main file, specified via message=, which
|
||||||
|
includes menu and prompt field markers, and the additional help files which
|
||||||
|
are invoked via function keys. Graphic characters are taken from the
|
||||||
|
standard IBM VGA character set, and using an appropriate font makes file
|
||||||
|
creation easier. Under Linux you can find a VGA font in the dosemu package.
|
||||||
|
Included in the elilo source is sys2ansi.pl (taken from syslinux), which can
|
||||||
|
be used to translate colour attributes such that they display correctly in an
|
||||||
|
xterm.
|
||||||
|
|
||||||
|
Valid control codes:
|
||||||
|
|
||||||
|
0x01 ^A Mark top left or bottom right of menu area. Current attributes
|
||||||
|
at top left marker are used for inactive menu entries, current
|
||||||
|
attributes when bottom right marker is found are used for the
|
||||||
|
currently active menu attributes.
|
||||||
|
|
||||||
|
0x02 ^B Mark left- or right-hand end of the prompt field. Current attributes
|
||||||
|
at the left had end are used to display and parameters entered.
|
||||||
|
|
||||||
|
0x0A ^J Linefeed, does implied carriage return.
|
||||||
|
|
||||||
|
0x0C ^L Clear screen
|
||||||
|
|
||||||
|
0x0D ^M Carriage return; ignored so files can be 'DOS' or 'UNIX' format.
|
||||||
|
|
||||||
|
0x0F ^O Attribute specfication; Two hex digits should follow this code, the
|
||||||
|
first being the background colour required, the second the foreground.
|
||||||
|
|
||||||
|
0 = black 8 = dark grey
|
||||||
|
1 = dark blue 9 = bright blue
|
||||||
|
2 = dark green a = bright green
|
||||||
|
3 = dark cyan b = bright cyan
|
||||||
|
4 = dark red c = bright red
|
||||||
|
5 = dark purple d = bright purple
|
||||||
|
6 = brown e = yellow
|
||||||
|
7 = light grey f = white
|
||||||
|
|
||||||
|
An example of a config file and message file are included in the examples
|
||||||
|
directory.
|
632
elf.h
Normal file
632
elf.h
Normal file
|
@ -0,0 +1,632 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* GNU EFI is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* GNU EFI is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU EFI; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*
|
||||||
|
* Portions of this file are derived from the LILO/x86
|
||||||
|
* Copyright 1992-1997 Werner Almesberger.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINUX_ELF_H__
|
||||||
|
#define __LINUX_ELF_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file was derived from <linux/elf.h>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
|
||||||
|
/* 32-bit ELF base types. */
|
||||||
|
typedef UINT32 Elf32_Addr;
|
||||||
|
typedef UINT16 Elf32_Half;
|
||||||
|
typedef UINT32 Elf32_Off;
|
||||||
|
typedef INT32 Elf32_Sword;
|
||||||
|
typedef UINT32 Elf32_Word;
|
||||||
|
|
||||||
|
/* 64-bit ELF base types. */
|
||||||
|
typedef UINT64 Elf64_Addr;
|
||||||
|
typedef UINT16 Elf64_Half;
|
||||||
|
typedef INT16 Elf64_SHalf;
|
||||||
|
typedef UINT64 Elf64_Off;
|
||||||
|
typedef INT64 Elf64_Sword;
|
||||||
|
typedef UINT64 Elf64_Word;
|
||||||
|
|
||||||
|
/* These constants are for the segment types stored in the image headers */
|
||||||
|
#define PT_NULL 0
|
||||||
|
#define PT_LOAD 1
|
||||||
|
#define PT_DYNAMIC 2
|
||||||
|
#define PT_INTERP 3
|
||||||
|
#define PT_NOTE 4
|
||||||
|
#define PT_SHLIB 5
|
||||||
|
#define PT_PHDR 6
|
||||||
|
#define PT_LOPROC 0x70000000
|
||||||
|
#define PT_HIPROC 0x7fffffff
|
||||||
|
#define PT_MIPS_REGINFO 0x70000000
|
||||||
|
|
||||||
|
/* Flags in the e_flags field of the header */
|
||||||
|
#define EF_MIPS_NOREORDER 0x00000001
|
||||||
|
#define EF_MIPS_PIC 0x00000002
|
||||||
|
#define EF_MIPS_CPIC 0x00000004
|
||||||
|
#define EF_MIPS_ARCH 0xf0000000
|
||||||
|
|
||||||
|
/* These constants define the different elf file types */
|
||||||
|
#define ET_NONE 0
|
||||||
|
#define ET_REL 1
|
||||||
|
#define ET_EXEC 2
|
||||||
|
#define ET_DYN 3
|
||||||
|
#define ET_CORE 4
|
||||||
|
#define ET_LOPROC 0xff00
|
||||||
|
#define ET_HIPROC 0xffff
|
||||||
|
|
||||||
|
/* These constants define the various ELF target machines */
|
||||||
|
#define EM_NONE 0
|
||||||
|
#define EM_M32 1
|
||||||
|
#define EM_SPARC 2
|
||||||
|
#define EM_386 3
|
||||||
|
#define EM_68K 4
|
||||||
|
#define EM_88K 5
|
||||||
|
#define EM_486 6 /* Perhaps disused */
|
||||||
|
#define EM_860 7
|
||||||
|
|
||||||
|
#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */
|
||||||
|
|
||||||
|
#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */
|
||||||
|
|
||||||
|
#define EM_PARISC 15 /* HPPA */
|
||||||
|
|
||||||
|
#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
|
||||||
|
|
||||||
|
#define EM_PPC 20 /* PowerPC */
|
||||||
|
|
||||||
|
#define EM_SH 42 /* SuperH */
|
||||||
|
|
||||||
|
#define EM_SPARCV9 43 /* SPARC v9 64-bit */
|
||||||
|
|
||||||
|
#define EM_IA_64 50 /* HP/Intel IA-64 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an interim value that we will use until the committee comes
|
||||||
|
* up with a final number.
|
||||||
|
*/
|
||||||
|
#define EM_ALPHA 0x9026
|
||||||
|
|
||||||
|
|
||||||
|
/* This is the info that is needed to parse the dynamic section of the file */
|
||||||
|
#define DT_NULL 0
|
||||||
|
#define DT_NEEDED 1
|
||||||
|
#define DT_PLTRELSZ 2
|
||||||
|
#define DT_PLTGOT 3
|
||||||
|
#define DT_HASH 4
|
||||||
|
#define DT_STRTAB 5
|
||||||
|
#define DT_SYMTAB 6
|
||||||
|
#define DT_RELA 7
|
||||||
|
#define DT_RELASZ 8
|
||||||
|
#define DT_RELAENT 9
|
||||||
|
#define DT_STRSZ 10
|
||||||
|
#define DT_SYMENT 11
|
||||||
|
#define DT_INIT 12
|
||||||
|
#define DT_FINI 13
|
||||||
|
#define DT_SONAME 14
|
||||||
|
#define DT_RPATH 15
|
||||||
|
#define DT_SYMBOLIC 16
|
||||||
|
#define DT_REL 17
|
||||||
|
#define DT_RELSZ 18
|
||||||
|
#define DT_RELENT 19
|
||||||
|
#define DT_PLTREL 20
|
||||||
|
#define DT_DEBUG 21
|
||||||
|
#define DT_TEXTREL 22
|
||||||
|
#define DT_JMPREL 23
|
||||||
|
#define DT_LOPROC 0x70000000
|
||||||
|
#define DT_HIPROC 0x7fffffff
|
||||||
|
#define DT_MIPS_RLD_VERSION 0x70000001
|
||||||
|
#define DT_MIPS_TIME_STAMP 0x70000002
|
||||||
|
#define DT_MIPS_ICHECKSUM 0x70000003
|
||||||
|
#define DT_MIPS_IVERSION 0x70000004
|
||||||
|
#define DT_MIPS_FLAGS 0x70000005
|
||||||
|
# define RHF_NONE 0
|
||||||
|
# define RHF_HARDWAY 1
|
||||||
|
# define RHF_NOTPOT 2
|
||||||
|
#define DT_MIPS_BASE_ADDRESS 0x70000006
|
||||||
|
#define DT_MIPS_CONFLICT 0x70000008
|
||||||
|
#define DT_MIPS_LIBLIST 0x70000009
|
||||||
|
#define DT_MIPS_LOCAL_GOTNO 0x7000000a
|
||||||
|
#define DT_MIPS_CONFLICTNO 0x7000000b
|
||||||
|
#define DT_MIPS_LIBLISTNO 0x70000010
|
||||||
|
#define DT_MIPS_SYMTABNO 0x70000011
|
||||||
|
#define DT_MIPS_UNREFEXTNO 0x70000012
|
||||||
|
#define DT_MIPS_GOTSYM 0x70000013
|
||||||
|
#define DT_MIPS_HIPAGENO 0x70000014
|
||||||
|
#define DT_MIPS_RLD_MAP 0x70000016
|
||||||
|
|
||||||
|
/* This info is needed when parsing the symbol table */
|
||||||
|
#define STB_LOCAL 0
|
||||||
|
#define STB_GLOBAL 1
|
||||||
|
#define STB_WEAK 2
|
||||||
|
|
||||||
|
#define STT_NOTYPE 0
|
||||||
|
#define STT_OBJECT 1
|
||||||
|
#define STT_FUNC 2
|
||||||
|
#define STT_SECTION 3
|
||||||
|
#define STT_FILE 4
|
||||||
|
|
||||||
|
#define ELF32_ST_BIND(x) ((x) >> 4)
|
||||||
|
#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf)
|
||||||
|
|
||||||
|
/* Symbolic values for the entries in the auxiliary table
|
||||||
|
put on the initial stack */
|
||||||
|
#define AT_NULL 0 /* end of vector */
|
||||||
|
#define AT_IGNORE 1 /* entry should be ignored */
|
||||||
|
#define AT_EXECFD 2 /* file descriptor of program */
|
||||||
|
#define AT_PHDR 3 /* program headers for program */
|
||||||
|
#define AT_PHENT 4 /* size of program header entry */
|
||||||
|
#define AT_PHNUM 5 /* number of program headers */
|
||||||
|
#define AT_PAGESZ 6 /* system page size */
|
||||||
|
#define AT_BASE 7 /* base address of interpreter */
|
||||||
|
#define AT_FLAGS 8 /* flags */
|
||||||
|
#define AT_ENTRY 9 /* entry point of program */
|
||||||
|
#define AT_NOTELF 10 /* program is not ELF */
|
||||||
|
#define AT_UID 11 /* real uid */
|
||||||
|
#define AT_EUID 12 /* effective uid */
|
||||||
|
#define AT_GID 13 /* real gid */
|
||||||
|
#define AT_EGID 14 /* effective gid */
|
||||||
|
#define AT_PLATFORM 15 /* string identifying CPU for optimizations */
|
||||||
|
#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
|
||||||
|
|
||||||
|
typedef struct dynamic{
|
||||||
|
Elf32_Sword d_tag;
|
||||||
|
union{
|
||||||
|
Elf32_Sword d_val;
|
||||||
|
Elf32_Addr d_ptr;
|
||||||
|
} d_un;
|
||||||
|
} Elf32_Dyn;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Elf64_Word d_tag; /* entry tag value */
|
||||||
|
union {
|
||||||
|
Elf64_Word d_val;
|
||||||
|
Elf64_Word d_ptr;
|
||||||
|
} d_un;
|
||||||
|
} Elf64_Dyn;
|
||||||
|
|
||||||
|
/* The following are used with relocations */
|
||||||
|
#define ELF32_R_SYM(x) ((x) >> 8)
|
||||||
|
#define ELF32_R_TYPE(x) ((x) & 0xff)
|
||||||
|
|
||||||
|
#define R_386_NONE 0
|
||||||
|
#define R_386_32 1
|
||||||
|
#define R_386_PC32 2
|
||||||
|
#define R_386_GOT32 3
|
||||||
|
#define R_386_PLT32 4
|
||||||
|
#define R_386_COPY 5
|
||||||
|
#define R_386_GLOB_DAT 6
|
||||||
|
#define R_386_JMP_SLOT 7
|
||||||
|
#define R_386_RELATIVE 8
|
||||||
|
#define R_386_GOTOFF 9
|
||||||
|
#define R_386_GOTPC 10
|
||||||
|
#define R_386_NUM 11
|
||||||
|
|
||||||
|
#define R_MIPS_NONE 0
|
||||||
|
#define R_MIPS_16 1
|
||||||
|
#define R_MIPS_32 2
|
||||||
|
#define R_MIPS_REL32 3
|
||||||
|
#define R_MIPS_26 4
|
||||||
|
#define R_MIPS_HI16 5
|
||||||
|
#define R_MIPS_LO16 6
|
||||||
|
#define R_MIPS_GPREL16 7
|
||||||
|
#define R_MIPS_LITERAL 8
|
||||||
|
#define R_MIPS_GOT16 9
|
||||||
|
#define R_MIPS_PC16 10
|
||||||
|
#define R_MIPS_CALL16 11
|
||||||
|
#define R_MIPS_GPREL32 12
|
||||||
|
/* The remaining relocs are defined on Irix, although they are not
|
||||||
|
in the MIPS ELF ABI. */
|
||||||
|
#define R_MIPS_UNUSED1 13
|
||||||
|
#define R_MIPS_UNUSED2 14
|
||||||
|
#define R_MIPS_UNUSED3 15
|
||||||
|
#define R_MIPS_SHIFT5 16
|
||||||
|
#define R_MIPS_SHIFT6 17
|
||||||
|
#define R_MIPS_64 18
|
||||||
|
#define R_MIPS_GOT_DISP 19
|
||||||
|
#define R_MIPS_GOT_PAGE 20
|
||||||
|
#define R_MIPS_GOT_OFST 21
|
||||||
|
/*
|
||||||
|
* The following two relocation types are specified in the the MIPS ABI
|
||||||
|
* conformance guide version 1.2 but not yet in the psABI.
|
||||||
|
*/
|
||||||
|
#define R_MIPS_GOTHI16 22
|
||||||
|
#define R_MIPS_GOTLO16 23
|
||||||
|
#define R_MIPS_SUB 24
|
||||||
|
#define R_MIPS_INSERT_A 25
|
||||||
|
#define R_MIPS_INSERT_B 26
|
||||||
|
#define R_MIPS_DELETE 27
|
||||||
|
#define R_MIPS_HIGHER 28
|
||||||
|
#define R_MIPS_HIGHEST 29
|
||||||
|
/*
|
||||||
|
* The following two relocation types are specified in the the MIPS ABI
|
||||||
|
* conformance guide version 1.2 but not yet in the psABI.
|
||||||
|
*/
|
||||||
|
#define R_MIPS_CALLHI16 30
|
||||||
|
#define R_MIPS_CALLLO16 31
|
||||||
|
/*
|
||||||
|
* This range is reserved for vendor specific relocations.
|
||||||
|
*/
|
||||||
|
#define R_MIPS_LOVENDOR 100
|
||||||
|
#define R_MIPS_HIVENDOR 127
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sparc ELF relocation types
|
||||||
|
*/
|
||||||
|
#define R_SPARC_NONE 0
|
||||||
|
#define R_SPARC_8 1
|
||||||
|
#define R_SPARC_16 2
|
||||||
|
#define R_SPARC_32 3
|
||||||
|
#define R_SPARC_DISP8 4
|
||||||
|
#define R_SPARC_DISP16 5
|
||||||
|
#define R_SPARC_DISP32 6
|
||||||
|
#define R_SPARC_WDISP30 7
|
||||||
|
#define R_SPARC_WDISP22 8
|
||||||
|
#define R_SPARC_HI22 9
|
||||||
|
#define R_SPARC_22 10
|
||||||
|
#define R_SPARC_13 11
|
||||||
|
#define R_SPARC_LO10 12
|
||||||
|
#define R_SPARC_GOT10 13
|
||||||
|
#define R_SPARC_GOT13 14
|
||||||
|
#define R_SPARC_GOT22 15
|
||||||
|
#define R_SPARC_PC10 16
|
||||||
|
#define R_SPARC_PC22 17
|
||||||
|
#define R_SPARC_WPLT30 18
|
||||||
|
#define R_SPARC_COPY 19
|
||||||
|
#define R_SPARC_GLOB_DAT 20
|
||||||
|
#define R_SPARC_JMP_SLOT 21
|
||||||
|
#define R_SPARC_RELATIVE 22
|
||||||
|
#define R_SPARC_UA32 23
|
||||||
|
#define R_SPARC_PLT32 24
|
||||||
|
#define R_SPARC_HIPLT22 25
|
||||||
|
#define R_SPARC_LOPLT10 26
|
||||||
|
#define R_SPARC_PCPLT32 27
|
||||||
|
#define R_SPARC_PCPLT22 28
|
||||||
|
#define R_SPARC_PCPLT10 29
|
||||||
|
#define R_SPARC_10 30
|
||||||
|
#define R_SPARC_11 31
|
||||||
|
#define R_SPARC_WDISP16 40
|
||||||
|
#define R_SPARC_WDISP19 41
|
||||||
|
#define R_SPARC_7 43
|
||||||
|
#define R_SPARC_5 44
|
||||||
|
#define R_SPARC_6 45
|
||||||
|
|
||||||
|
/* Bits present in AT_HWCAP, primarily for Sparc32. */
|
||||||
|
|
||||||
|
#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */
|
||||||
|
#define HWCAP_SPARC_STBAR 2
|
||||||
|
#define HWCAP_SPARC_SWAP 4
|
||||||
|
#define HWCAP_SPARC_MULDIV 8
|
||||||
|
#define HWCAP_SPARC_V9 16
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 68k ELF relocation types
|
||||||
|
*/
|
||||||
|
#define R_68K_NONE 0
|
||||||
|
#define R_68K_32 1
|
||||||
|
#define R_68K_16 2
|
||||||
|
#define R_68K_8 3
|
||||||
|
#define R_68K_PC32 4
|
||||||
|
#define R_68K_PC16 5
|
||||||
|
#define R_68K_PC8 6
|
||||||
|
#define R_68K_GOT32 7
|
||||||
|
#define R_68K_GOT16 8
|
||||||
|
#define R_68K_GOT8 9
|
||||||
|
#define R_68K_GOT32O 10
|
||||||
|
#define R_68K_GOT16O 11
|
||||||
|
#define R_68K_GOT8O 12
|
||||||
|
#define R_68K_PLT32 13
|
||||||
|
#define R_68K_PLT16 14
|
||||||
|
#define R_68K_PLT8 15
|
||||||
|
#define R_68K_PLT32O 16
|
||||||
|
#define R_68K_PLT16O 17
|
||||||
|
#define R_68K_PLT8O 18
|
||||||
|
#define R_68K_COPY 19
|
||||||
|
#define R_68K_GLOB_DAT 20
|
||||||
|
#define R_68K_JMP_SLOT 21
|
||||||
|
#define R_68K_RELATIVE 22
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Alpha ELF relocation types
|
||||||
|
*/
|
||||||
|
#define R_ALPHA_NONE 0 /* No reloc */
|
||||||
|
#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
|
||||||
|
#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */
|
||||||
|
#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */
|
||||||
|
#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */
|
||||||
|
#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */
|
||||||
|
#define R_ALPHA_GPDISP 6 /* Add displacement to GP */
|
||||||
|
#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */
|
||||||
|
#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */
|
||||||
|
#define R_ALPHA_SREL16 9 /* PC relative 16 bit */
|
||||||
|
#define R_ALPHA_SREL32 10 /* PC relative 32 bit */
|
||||||
|
#define R_ALPHA_SREL64 11 /* PC relative 64 bit */
|
||||||
|
#define R_ALPHA_OP_PUSH 12 /* OP stack push */
|
||||||
|
#define R_ALPHA_OP_STORE 13 /* OP stack pop and store */
|
||||||
|
#define R_ALPHA_OP_PSUB 14 /* OP stack subtract */
|
||||||
|
#define R_ALPHA_OP_PRSHIFT 15 /* OP stack right shift */
|
||||||
|
#define R_ALPHA_GPVALUE 16
|
||||||
|
#define R_ALPHA_GPRELHIGH 17
|
||||||
|
#define R_ALPHA_GPRELLOW 18
|
||||||
|
#define R_ALPHA_IMMED_GP_16 19
|
||||||
|
#define R_ALPHA_IMMED_GP_HI32 20
|
||||||
|
#define R_ALPHA_IMMED_SCN_HI32 21
|
||||||
|
#define R_ALPHA_IMMED_BR_HI32 22
|
||||||
|
#define R_ALPHA_IMMED_LO32 23
|
||||||
|
#define R_ALPHA_COPY 24 /* Copy symbol at runtime */
|
||||||
|
#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */
|
||||||
|
#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */
|
||||||
|
#define R_ALPHA_RELATIVE 27 /* Adjust by program base */
|
||||||
|
|
||||||
|
/* Legal values for e_flags field of Elf64_Ehdr. */
|
||||||
|
|
||||||
|
#define EF_ALPHA_32BIT 1 /* All addresses are below 2GB */
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct elf32_rel {
|
||||||
|
Elf32_Addr r_offset;
|
||||||
|
Elf32_Word r_info;
|
||||||
|
} Elf32_Rel;
|
||||||
|
|
||||||
|
typedef struct elf64_rel {
|
||||||
|
Elf64_Addr r_offset; /* Location at which to apply the action */
|
||||||
|
Elf64_Word r_info; /* index and type of relocation */
|
||||||
|
} Elf64_Rel;
|
||||||
|
|
||||||
|
typedef struct elf32_rela{
|
||||||
|
Elf32_Addr r_offset;
|
||||||
|
Elf32_Word r_info;
|
||||||
|
Elf32_Sword r_addend;
|
||||||
|
} Elf32_Rela;
|
||||||
|
|
||||||
|
typedef struct elf64_rela {
|
||||||
|
Elf64_Addr r_offset; /* Location at which to apply the action */
|
||||||
|
Elf64_Word r_info; /* index and type of relocation */
|
||||||
|
Elf64_Word r_addend; /* Constant addend used to compute value */
|
||||||
|
} Elf64_Rela;
|
||||||
|
|
||||||
|
typedef struct elf32_sym{
|
||||||
|
Elf32_Word st_name;
|
||||||
|
Elf32_Addr st_value;
|
||||||
|
Elf32_Word st_size;
|
||||||
|
unsigned char st_info;
|
||||||
|
unsigned char st_other;
|
||||||
|
Elf32_Half st_shndx;
|
||||||
|
} Elf32_Sym;
|
||||||
|
|
||||||
|
typedef struct elf64_sym {
|
||||||
|
Elf32_Word st_name; /* Symbol name, index in string tbl (yes, Elf32) */
|
||||||
|
unsigned char st_info; /* Type and binding attributes */
|
||||||
|
unsigned char st_other; /* No defined meaning, 0 */
|
||||||
|
Elf64_Half st_shndx; /* Associated section index */
|
||||||
|
Elf64_Addr st_value; /* Value of the symbol */
|
||||||
|
Elf64_Word st_size; /* Associated symbol size */
|
||||||
|
} Elf64_Sym;
|
||||||
|
|
||||||
|
|
||||||
|
#define EI_NIDENT 16
|
||||||
|
|
||||||
|
typedef struct elf32_hdr{
|
||||||
|
unsigned char e_ident[EI_NIDENT];
|
||||||
|
Elf32_Half e_type;
|
||||||
|
Elf32_Half e_machine;
|
||||||
|
Elf32_Word e_version;
|
||||||
|
Elf32_Addr e_entry; /* Entry point */
|
||||||
|
Elf32_Off e_phoff;
|
||||||
|
Elf32_Off e_shoff;
|
||||||
|
Elf32_Word e_flags;
|
||||||
|
Elf32_Half e_ehsize;
|
||||||
|
Elf32_Half e_phentsize;
|
||||||
|
Elf32_Half e_phnum;
|
||||||
|
Elf32_Half e_shentsize;
|
||||||
|
Elf32_Half e_shnum;
|
||||||
|
Elf32_Half e_shstrndx;
|
||||||
|
} Elf32_Ehdr;
|
||||||
|
|
||||||
|
typedef struct elf64_hdr {
|
||||||
|
unsigned char e_ident[16]; /* ELF "magic number" */
|
||||||
|
Elf64_SHalf e_type;
|
||||||
|
Elf64_Half e_machine;
|
||||||
|
INT32 e_version;
|
||||||
|
Elf64_Addr e_entry; /* Entry point virtual address */
|
||||||
|
Elf64_Off e_phoff; /* Program header table file offset */
|
||||||
|
Elf64_Off e_shoff; /* Section header table file offset */
|
||||||
|
INT32 e_flags;
|
||||||
|
Elf64_SHalf e_ehsize;
|
||||||
|
Elf64_SHalf e_phentsize;
|
||||||
|
Elf64_SHalf e_phnum;
|
||||||
|
Elf64_SHalf e_shentsize;
|
||||||
|
Elf64_SHalf e_shnum;
|
||||||
|
Elf64_SHalf e_shstrndx;
|
||||||
|
} Elf64_Ehdr;
|
||||||
|
|
||||||
|
/* These constants define the permissions on sections in the program
|
||||||
|
header, p_flags. */
|
||||||
|
#define PF_R 0x4
|
||||||
|
#define PF_W 0x2
|
||||||
|
#define PF_X 0x1
|
||||||
|
|
||||||
|
typedef struct elf32_phdr{
|
||||||
|
Elf32_Word p_type;
|
||||||
|
Elf32_Off p_offset;
|
||||||
|
Elf32_Addr p_vaddr;
|
||||||
|
Elf32_Addr p_paddr;
|
||||||
|
Elf32_Word p_filesz;
|
||||||
|
Elf32_Word p_memsz;
|
||||||
|
Elf32_Word p_flags;
|
||||||
|
Elf32_Word p_align;
|
||||||
|
} Elf32_Phdr;
|
||||||
|
|
||||||
|
typedef struct elf64_phdr {
|
||||||
|
INT32 p_type;
|
||||||
|
INT32 p_flags;
|
||||||
|
Elf64_Off p_offset; /* Segment file offset */
|
||||||
|
Elf64_Addr p_vaddr; /* Segment virtual address */
|
||||||
|
Elf64_Addr p_paddr; /* Segment physical address */
|
||||||
|
Elf64_Word p_filesz; /* Segment size in file */
|
||||||
|
Elf64_Word p_memsz; /* Segment size in memory */
|
||||||
|
Elf64_Word p_align; /* Segment alignment, file & memory */
|
||||||
|
} Elf64_Phdr;
|
||||||
|
|
||||||
|
/* sh_type */
|
||||||
|
#define SHT_NULL 0
|
||||||
|
#define SHT_PROGBITS 1
|
||||||
|
#define SHT_SYMTAB 2
|
||||||
|
#define SHT_STRTAB 3
|
||||||
|
#define SHT_RELA 4
|
||||||
|
#define SHT_HASH 5
|
||||||
|
#define SHT_DYNAMIC 6
|
||||||
|
#define SHT_NOTE 7
|
||||||
|
#define SHT_NOBITS 8
|
||||||
|
#define SHT_REL 9
|
||||||
|
#define SHT_SHLIB 10
|
||||||
|
#define SHT_DYNSYM 11
|
||||||
|
#define SHT_NUM 12
|
||||||
|
#define SHT_LOPROC 0x70000000
|
||||||
|
#define SHT_HIPROC 0x7fffffff
|
||||||
|
#define SHT_LOUSER 0x80000000
|
||||||
|
#define SHT_HIUSER 0xffffffff
|
||||||
|
#define SHT_MIPS_LIST 0x70000000
|
||||||
|
#define SHT_MIPS_CONFLICT 0x70000002
|
||||||
|
#define SHT_MIPS_GPTAB 0x70000003
|
||||||
|
#define SHT_MIPS_UCODE 0x70000004
|
||||||
|
|
||||||
|
/* sh_flags */
|
||||||
|
#define SHF_WRITE 0x1
|
||||||
|
#define SHF_ALLOC 0x2
|
||||||
|
#define SHF_EXECINSTR 0x4
|
||||||
|
#define SHF_MASKPROC 0xf0000000
|
||||||
|
#define SHF_MIPS_GPREL 0x10000000
|
||||||
|
|
||||||
|
/* special section indexes */
|
||||||
|
#define SHN_UNDEF 0
|
||||||
|
#define SHN_LORESERVE 0xff00
|
||||||
|
#define SHN_LOPROC 0xff00
|
||||||
|
#define SHN_HIPROC 0xff1f
|
||||||
|
#define SHN_ABS 0xfff1
|
||||||
|
#define SHN_COMMON 0xfff2
|
||||||
|
#define SHN_HIRESERVE 0xffff
|
||||||
|
#define SHN_MIPS_ACCOMON 0xff00
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Elf32_Word sh_name;
|
||||||
|
Elf32_Word sh_type;
|
||||||
|
Elf32_Word sh_flags;
|
||||||
|
Elf32_Addr sh_addr;
|
||||||
|
Elf32_Off sh_offset;
|
||||||
|
Elf32_Word sh_size;
|
||||||
|
Elf32_Word sh_link;
|
||||||
|
Elf32_Word sh_info;
|
||||||
|
Elf32_Word sh_addralign;
|
||||||
|
Elf32_Word sh_entsize;
|
||||||
|
} Elf32_Shdr;
|
||||||
|
|
||||||
|
typedef struct elf64_shdr {
|
||||||
|
Elf32_Word sh_name; /* Section name, index in string tbl (yes Elf32) */
|
||||||
|
Elf32_Word sh_type; /* Type of section (yes Elf32) */
|
||||||
|
Elf64_Word sh_flags; /* Miscellaneous section attributes */
|
||||||
|
Elf64_Addr sh_addr; /* Section virtual addr at execution */
|
||||||
|
Elf64_Off sh_offset; /* Section file offset */
|
||||||
|
Elf64_Word sh_size; /* Size of section in bytes */
|
||||||
|
Elf32_Word sh_link; /* Index of another section (yes Elf32) */
|
||||||
|
Elf32_Word sh_info; /* Additional section information (yes Elf32) */
|
||||||
|
Elf64_Word sh_addralign; /* Section alignment */
|
||||||
|
Elf64_Word sh_entsize; /* Entry size if section holds table */
|
||||||
|
} Elf64_Shdr;
|
||||||
|
|
||||||
|
#define EI_MAG0 0 /* e_ident[] indexes */
|
||||||
|
#define EI_MAG1 1
|
||||||
|
#define EI_MAG2 2
|
||||||
|
#define EI_MAG3 3
|
||||||
|
#define EI_CLASS 4
|
||||||
|
#define EI_DATA 5
|
||||||
|
#define EI_VERSION 6
|
||||||
|
#define EI_PAD 7
|
||||||
|
|
||||||
|
#define ELFMAG0 0x7f /* EI_MAG */
|
||||||
|
#define ELFMAG1 'E'
|
||||||
|
#define ELFMAG2 'L'
|
||||||
|
#define ELFMAG3 'F'
|
||||||
|
#define ELFMAG "\177ELF"
|
||||||
|
#define SELFMAG 4
|
||||||
|
|
||||||
|
#define ELFCLASSNONE 0 /* EI_CLASS */
|
||||||
|
#define ELFCLASS32 1
|
||||||
|
#define ELFCLASS64 2
|
||||||
|
#define ELFCLASSNUM 3
|
||||||
|
|
||||||
|
#define ELFDATANONE 0 /* e_ident[EI_DATA] */
|
||||||
|
#define ELFDATA2LSB 1
|
||||||
|
#define ELFDATA2MSB 2
|
||||||
|
|
||||||
|
#define EV_NONE 0 /* e_version, EI_VERSION */
|
||||||
|
#define EV_CURRENT 1
|
||||||
|
#define EV_NUM 2
|
||||||
|
|
||||||
|
/* Notes used in ET_CORE */
|
||||||
|
#define NT_PRSTATUS 1
|
||||||
|
#define NT_PRFPREG 2
|
||||||
|
#define NT_PRPSINFO 3
|
||||||
|
#define NT_TASKSTRUCT 4
|
||||||
|
|
||||||
|
/* Note header in a PT_NOTE section */
|
||||||
|
typedef struct elf32_note {
|
||||||
|
Elf32_Word n_namesz; /* Name size */
|
||||||
|
Elf32_Word n_descsz; /* Content size */
|
||||||
|
Elf32_Word n_type; /* Content type */
|
||||||
|
} Elf32_Nhdr;
|
||||||
|
|
||||||
|
/* Note header in a PT_NOTE section */
|
||||||
|
/*
|
||||||
|
* For now we use the 32 bit version of the structure until we figure
|
||||||
|
* out whether we need anything better. Note - on the Alpha, "unsigned int"
|
||||||
|
* is only 32 bits.
|
||||||
|
*/
|
||||||
|
typedef struct elf64_note {
|
||||||
|
Elf32_Word n_namesz; /* Name size */
|
||||||
|
Elf32_Word n_descsz; /* Content size */
|
||||||
|
Elf32_Word n_type; /* Content type */
|
||||||
|
} Elf64_Nhdr;
|
||||||
|
|
||||||
|
#if ELF_CLASS == ELFCLASS32
|
||||||
|
|
||||||
|
extern Elf32_Dyn _DYNAMIC [];
|
||||||
|
#define elfhdr elf32_hdr
|
||||||
|
#define elf_phdr elf32_phdr
|
||||||
|
#define elf_note elf32_note
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
extern Elf64_Dyn _DYNAMIC [];
|
||||||
|
#define elfhdr elf64_hdr
|
||||||
|
#define elf_phdr elf64_phdr
|
||||||
|
#define elf_note elf64_note
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __LINUX_ELF_H__ */
|
BIN
elilo-ia32.efi
Executable file
BIN
elilo-ia32.efi
Executable file
Binary file not shown.
BIN
elilo-ia64.efi
Executable file
BIN
elilo-ia64.efi
Executable file
Binary file not shown.
654
elilo.c
Normal file
654
elilo.c
Normal file
|
@ -0,0 +1,654 @@
|
||||||
|
/*
|
||||||
|
* elilo.c - IA-64/IA-32 EFI Linux loader
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by David Mosberger <davidm@hpl.hp.com>.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999-2000 VA Linux Systems
|
||||||
|
* Contributed by Johannes Erdfelt <jerdfelt@valinux.com>.
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
#include "vars.h"
|
||||||
|
|
||||||
|
#include "getopt.h"
|
||||||
|
#include "fileops.h"
|
||||||
|
#include "loader.h"
|
||||||
|
#include "config.h" /* for config_init() */
|
||||||
|
|
||||||
|
#define ELILO_VERSION L"3.4"
|
||||||
|
#define ELILO_SHARED_CMDLINE_OPTS L"pPMC:aDhd:i:vVc:E"
|
||||||
|
|
||||||
|
elilo_config_t elilo_opt;
|
||||||
|
|
||||||
|
EFI_SYSTEM_TABLE *systab; /* pointer to EFI system table */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the Linux kernel in memory from the boot media
|
||||||
|
* Output:
|
||||||
|
* kd = address of kernel entry point
|
||||||
|
* + end address of kernel code+data+bss
|
||||||
|
* + kernel entry point
|
||||||
|
* Return:
|
||||||
|
* ELILO_LOAD_ERROR : if something went wrong
|
||||||
|
* ELILO_LOAD_ABORTED : user interruption while loading
|
||||||
|
* ELILO_LOAD_SUCCESS : otherwise
|
||||||
|
*/
|
||||||
|
static INTN
|
||||||
|
do_kernel_load(CHAR16 *kname, kdesc_t *kd)
|
||||||
|
{
|
||||||
|
loader_ops_t *ldops;
|
||||||
|
EFI_STATUS status;
|
||||||
|
fops_fd_t fd;
|
||||||
|
|
||||||
|
status = fops_open(kname, &fd);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"Kernel file not found %s", kname));
|
||||||
|
return ELILO_LOAD_ERROR;
|
||||||
|
}
|
||||||
|
fops_close(fd);
|
||||||
|
|
||||||
|
ldops = loader_probe(kname);
|
||||||
|
if (ldops == NULL) {
|
||||||
|
ERR_PRT((L"Cannot find a loader for %s", kname));
|
||||||
|
return ELILO_LOAD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
VERB_PRT(1,Print(L"Using %s loader\n", ldops->ld_name));
|
||||||
|
|
||||||
|
return ldops->ld_load_kernel(kname, kd);
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
kernel_load(EFI_HANDLE image, CHAR16 *kname, kdesc_t *kd, memdesc_t *imem)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now let's try to load the kernel !
|
||||||
|
*/
|
||||||
|
switch(do_kernel_load(kname, kd)) {
|
||||||
|
case ELILO_LOAD_SUCCESS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ELILO_LOAD_ERROR:
|
||||||
|
/* XXX: add fallback support */
|
||||||
|
return ELILO_LOAD_ERROR;
|
||||||
|
|
||||||
|
case ELILO_LOAD_ABORTED:
|
||||||
|
/* we drop initrd in case we aborted the load */
|
||||||
|
elilo_opt.initrd[0] = CHAR_NULL;
|
||||||
|
|
||||||
|
/* will go back to interactive selection */
|
||||||
|
elilo_opt.prompt = 1;
|
||||||
|
elilo_opt.timeout = ELILO_DEFAULT_TIMEOUT;
|
||||||
|
elilo_opt.delay = 0;
|
||||||
|
|
||||||
|
return ELILO_LOAD_RETRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
VERB_PRT(3, Print(L"kernel loaded in [0x%lx-0x%lx] entry=0x%lx\n",
|
||||||
|
(UINT64)kd->kstart, (UINT64)kd->kend, (UINT64)kd->kentry));
|
||||||
|
|
||||||
|
if (elilo_opt.initrd[0]) {
|
||||||
|
|
||||||
|
if (sysdeps_initrd_get_addr(kd, imem) == -1) goto exit_error;
|
||||||
|
|
||||||
|
switch(load_initrd(elilo_opt.initrd, imem)) {
|
||||||
|
case ELILO_LOAD_SUCCESS:
|
||||||
|
break;
|
||||||
|
case ELILO_LOAD_ERROR:
|
||||||
|
goto exit_error;
|
||||||
|
case ELILO_LOAD_ABORTED:
|
||||||
|
/* the free_kmem() is the responsibility of the loader */
|
||||||
|
|
||||||
|
/* we drop initrd in case we aborted the load */
|
||||||
|
elilo_opt.initrd[0] = CHAR_NULL;
|
||||||
|
elilo_opt.prompt = 1;
|
||||||
|
elilo_opt.timeout = ELILO_DEFAULT_TIMEOUT;
|
||||||
|
elilo_opt.delay = 0;
|
||||||
|
|
||||||
|
return ELILO_LOAD_RETRY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ELILO_LOAD_SUCCESS;
|
||||||
|
exit_error:
|
||||||
|
free_kmem();
|
||||||
|
if (imem->start_addr) free(imem->start_addr);
|
||||||
|
|
||||||
|
return ELILO_LOAD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
main_loop(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image)
|
||||||
|
{
|
||||||
|
CHAR16 kname[FILENAME_MAXLEN];
|
||||||
|
CHAR16 cmdline_tmp[CMDLINE_MAXLEN];
|
||||||
|
CHAR16 cmdline[CMDLINE_MAXLEN];
|
||||||
|
VOID *bp;
|
||||||
|
UINTN cookie;
|
||||||
|
EFI_STATUS status = EFI_SUCCESS;
|
||||||
|
kdesc_t kd;
|
||||||
|
memdesc_t imem;
|
||||||
|
INTN r;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First place where we potentially do system dependent
|
||||||
|
* operations. It is a one time opportunity before entering
|
||||||
|
* the main loop
|
||||||
|
*/
|
||||||
|
if (sysdeps_preloop_actions(dev, argv, argc, index, image) == -1) return -1;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
kname[0] = cmdline_tmp[0] = cmdline[0] = CHAR_NULL;
|
||||||
|
imem.start_addr = 0; imem.pgcnt = 0;
|
||||||
|
elilo_opt.sys_img_opts = NULL;
|
||||||
|
|
||||||
|
if (kernel_chooser(argv, argc, index, kname, cmdline_tmp) == -1) goto exit_error;
|
||||||
|
|
||||||
|
switch (kernel_load(image, kname, &kd, &imem)) {
|
||||||
|
case ELILO_LOAD_SUCCESS:
|
||||||
|
goto do_launch;
|
||||||
|
case ELILO_LOAD_ERROR:
|
||||||
|
goto exit_error;
|
||||||
|
/* otherwise we retry ! */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_launch:
|
||||||
|
r =subst_vars(cmdline_tmp, cmdline, CMDLINE_MAXLEN);
|
||||||
|
|
||||||
|
VERB_PRT(3, Print(L"final cmdline(%d): %s\n", r, cmdline));
|
||||||
|
|
||||||
|
/* free resources associated with file accesses (before ExitBootServices) */
|
||||||
|
close_devices();
|
||||||
|
|
||||||
|
/* No console output permitted after create_boot_params()! */
|
||||||
|
if ((bp=create_boot_params(cmdline, &imem, &cookie)) == 0) goto error;
|
||||||
|
|
||||||
|
/* terminate bootservices */
|
||||||
|
status = BS->ExitBootServices(image, cookie);
|
||||||
|
if (EFI_ERROR(status)) goto bad_exit;
|
||||||
|
|
||||||
|
start_kernel(kd.kentry, bp);
|
||||||
|
/* NOT REACHED */
|
||||||
|
|
||||||
|
ERR_PRT((L"start_kernel() return !"));
|
||||||
|
bad_exit:
|
||||||
|
/*
|
||||||
|
* we are still in BootService mode
|
||||||
|
*/
|
||||||
|
ERR_PRT((L"ExitBootServices failed %r", status));
|
||||||
|
error:
|
||||||
|
free_kmem();
|
||||||
|
if (imem.start_addr) free(imem.start_addr);
|
||||||
|
if (bp) free_boot_params(bp);
|
||||||
|
exit_error:
|
||||||
|
return ELILO_LOAD_ERROR;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
elilo_help(VOID)
|
||||||
|
{
|
||||||
|
|
||||||
|
Print(L"-d secs timeout in 10th of second before booting\n");
|
||||||
|
Print(L"-h this help text\n");
|
||||||
|
Print(L"-V print version\n");
|
||||||
|
Print(L"-v verbose level(can appear multiple times)\n");
|
||||||
|
Print(L"-a always check for alternate kernel image\n");
|
||||||
|
Print(L"-i file load file as the initial ramdisk\n");
|
||||||
|
Print(L"-C file indicate the config file to use\n");
|
||||||
|
Print(L"-P parse config file only (verify syntax)\n");
|
||||||
|
Print(L"-D enable debug prints\n");
|
||||||
|
Print(L"-p force interactive mode\n");
|
||||||
|
Print(L"-c name image chooser to use\n");
|
||||||
|
Print(L"-E do not force EDD30 variable\n");
|
||||||
|
|
||||||
|
sysdeps_print_cmdline_opts();
|
||||||
|
|
||||||
|
Print(L"\n");
|
||||||
|
|
||||||
|
print_config_options();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX: hack to work around a problem with EFI command line argument when booted
|
||||||
|
* from network. In this case, it looks like LoadOptions/LoadOptionsSize contain
|
||||||
|
* garbage
|
||||||
|
*/
|
||||||
|
static CHAR16 *default_load_options;
|
||||||
|
static UINTN default_load_options_size;
|
||||||
|
static INTN done_fixups;
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
fixupargs(EFI_LOADED_IMAGE *info)
|
||||||
|
{
|
||||||
|
EFI_STATUS status;
|
||||||
|
EFI_PXE_BASE_CODE *pxe;
|
||||||
|
|
||||||
|
#define FAKE_ELILONAME L"elilo-forced"
|
||||||
|
|
||||||
|
status = BS->HandleProtocol (info->DeviceHandle, &PxeBaseCodeProtocol, (VOID **)&pxe);
|
||||||
|
if (EFI_ERROR(status)) return;
|
||||||
|
|
||||||
|
default_load_options = info->LoadOptions;
|
||||||
|
default_load_options_size = info->LoadOptionsSize;
|
||||||
|
|
||||||
|
info->LoadOptions = FAKE_ELILONAME;
|
||||||
|
info->LoadOptionsSize = StrLen(info->LoadOptions)*sizeof(CHAR16);
|
||||||
|
|
||||||
|
done_fixups = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we restore the arguments in case we modified them just to make sure
|
||||||
|
* we don't confuse caller.
|
||||||
|
*/
|
||||||
|
static VOID
|
||||||
|
unfixupargs(EFI_LOADED_IMAGE *info)
|
||||||
|
{
|
||||||
|
if (done_fixups == 0) return;
|
||||||
|
|
||||||
|
info->LoadOptions = default_load_options;
|
||||||
|
info->LoadOptionsSize = default_load_options_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* in order to get fully detailed EFI path names to devices, EDD3.0 specification must
|
||||||
|
* be turned on. On new versions of EFI, this is the default. An environment variable
|
||||||
|
* called EDD30 reflects the current settings. If true, then EDD3.0 is enabled
|
||||||
|
* and device path names show the detailed device types. If false, then a default
|
||||||
|
* generic name is used instead. This has some implications of ELILO's ability to
|
||||||
|
* provide a better naming scheme for detected devices. If EDD3.0 is enabled
|
||||||
|
* then much more precise names can be used which makes it easy to use.
|
||||||
|
* If EDD3.0 is nont enabled, ELILO will still work but will use very generic names
|
||||||
|
* for devices.
|
||||||
|
*
|
||||||
|
* ELILO will check the value of the variable. If not true, then it will force it to
|
||||||
|
* true. This will require a reboot for EFI to make use of the new value.
|
||||||
|
* Return:
|
||||||
|
* EFI_SUCCESS: if variable is already true or was set to true
|
||||||
|
* EFI error code: otherwise, like when could not forced variable or unrecognized variable content
|
||||||
|
*/
|
||||||
|
#define EDD30_GUID \
|
||||||
|
{0x964e5b21, 0x6459, 0x11d2, { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}}
|
||||||
|
|
||||||
|
#define EDD30_ATTR (EFI_VARIABLE_RUNTIME_ACCESS|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_NON_VOLATILE)
|
||||||
|
|
||||||
|
static EFI_GUID edd30_guid = EDD30_GUID;
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
check_edd30(VOID)
|
||||||
|
{
|
||||||
|
EFI_STATUS status;
|
||||||
|
UINTN l = sizeof(BOOLEAN);
|
||||||
|
UINT8 bool = FALSE;
|
||||||
|
INTN ret = -1;
|
||||||
|
|
||||||
|
status = RT->GetVariable(L"EDD30", &edd30_guid, NULL, &l, &bool);
|
||||||
|
if (status == EFI_BUFFER_TOO_SMALL || (bool != TRUE && bool != FALSE)) {
|
||||||
|
ERR_PRT((L"Warning: EDD30 EFI variable is not boolean value: forcing it to TRUE"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (status == EFI_SUCCESS && bool == TRUE) {
|
||||||
|
VERB_PRT(3, Print(L"EDD30 is TRUE\n"));
|
||||||
|
elilo_opt.edd30_on = TRUE;
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
VERB_PRT(4,
|
||||||
|
if (status != EFI_SUCCESS) {
|
||||||
|
Print(L"EDD30 EFI variable not defined\n");
|
||||||
|
} else {
|
||||||
|
Print(L"EDD30 EFI variable is false\n");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
force_edd30(VOID)
|
||||||
|
{
|
||||||
|
EFI_STATUS status;
|
||||||
|
UINTN l = sizeof(BOOLEAN);
|
||||||
|
UINT8 bool;
|
||||||
|
|
||||||
|
bool = TRUE;
|
||||||
|
status = RT->SetVariable(L"EDD30", &edd30_guid, EDD30_ATTR, l, &bool);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"can't set EDD30 variable: ignoring it"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
VERB_PRT(3, Print(L"EDD30 variable forced to TRUE. You should reboot to take advantage of EDD3.0.\n"));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* That's equivalent of main(): main entry point
|
||||||
|
*/
|
||||||
|
EFI_STATUS
|
||||||
|
efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab)
|
||||||
|
{
|
||||||
|
CHAR16 *argv[MAX_ARGS];
|
||||||
|
CHAR16 optstring[MAX_ARGS];
|
||||||
|
EFI_LOADED_IMAGE *info;
|
||||||
|
EFI_STATUS status, ret = EFI_LOAD_ERROR;
|
||||||
|
INTN argc = 0, c;
|
||||||
|
INTN edd30_status, retry;
|
||||||
|
CHAR16 *ptr, *arglist = NULL;
|
||||||
|
BOOLEAN devices_initialized = FALSE;
|
||||||
|
CHAR16 dpath[FILENAME_MAXLEN];
|
||||||
|
CHAR16 *devpath;
|
||||||
|
|
||||||
|
//elilo_opt.verbose=3;
|
||||||
|
//elilo_opt.debug=1;
|
||||||
|
|
||||||
|
/* initialize global variable */
|
||||||
|
systab = system_tab;
|
||||||
|
|
||||||
|
/* initialize EFI library */
|
||||||
|
InitializeLib(image, systab);
|
||||||
|
/*
|
||||||
|
* disable the platform watchdog timer if we go interactive
|
||||||
|
* XXX: we should reinstate it once we're done
|
||||||
|
* It seems like with PXE, the timer is set to a few minutes
|
||||||
|
* and sometimes triggers if we stay too long in interactive
|
||||||
|
* mode.
|
||||||
|
* XXX: clean this up !
|
||||||
|
*/
|
||||||
|
BS->SetWatchdogTimer(0, 0x0, 0, NULL);
|
||||||
|
|
||||||
|
/* initialize memory allocator */
|
||||||
|
if (alloc_init() == -1) return EFI_LOAD_ERROR;
|
||||||
|
|
||||||
|
status = BS->HandleProtocol(image, &LoadedImageProtocol, (VOID **) &info);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"image handle does not support LOADED_IMAGE protocol"));
|
||||||
|
return EFI_LOAD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
VERB_PRT(5,Print(L"Loaded at 0x%lx size=%d bytes code=%d data=%d\n", info->ImageBase, info->ImageSize, info->ImageCodeType, info->ImageDataType));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* verify EDD3.0 status. Users may have to reboot
|
||||||
|
*/
|
||||||
|
edd30_status = check_edd30();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initialize configuration empire
|
||||||
|
*/
|
||||||
|
if (config_init() == -1) goto do_exit;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* architecture-specific initializations
|
||||||
|
*/
|
||||||
|
if (sysdeps_init(info->DeviceHandle) == -1) goto do_exit;
|
||||||
|
if (sysdeps_register_options() == -1) goto do_exit;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This may be required in case Elilo was booted with absolutely no arguments
|
||||||
|
* Elilo's logic is that just like normal Linux programs at least one argument
|
||||||
|
* (argv[0]) exists at all times and that it usually gives the name of the program
|
||||||
|
* (the command used to start it).
|
||||||
|
ERR_PRT((L"LoadOptions=%x OpenSize=%d", info->LoadOptions, info->LoadOptionsSize));
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* in case there is something wrong with the default boot_device
|
||||||
|
* we default to basic fixups and we need to force interactive
|
||||||
|
* mode to make sure the user has a chance of specifying a kernel
|
||||||
|
*/
|
||||||
|
fixupargs(info);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
Print(L"LoadOptions=%x OpenSize=%d\n", info->LoadOptions, info->LoadOptionsSize);
|
||||||
|
{ INTN i; for (i=0; i< info->LoadOptionsSize>>1; i++) Print(L"options[%d]=%d (%c)\n", i, ((CHAR16 *)info->LoadOptions)[i], ((CHAR16 *)info->LoadOptions)[i]); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we must copy argument because argify modifies the string.
|
||||||
|
* This caused problems when arguments are coming from NVRAM
|
||||||
|
* as passed by the EFI boot manager
|
||||||
|
*
|
||||||
|
* We add an extra character to the buffer in case the LoadOptions is not
|
||||||
|
* NULL terminated. The extra space will be used to ADD the extra terminator.
|
||||||
|
*/
|
||||||
|
arglist = alloc(info->LoadOptionsSize+sizeof(CHAR16), EfiLoaderData);
|
||||||
|
if (arglist == NULL) {
|
||||||
|
ERR_PRT((L"cannot copy argument list"));
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
Memcpy(arglist, info->LoadOptions, info->LoadOptionsSize);
|
||||||
|
|
||||||
|
argc = argify(arglist,info->LoadOptionsSize, argv);
|
||||||
|
|
||||||
|
StrCpy(optstring, ELILO_SHARED_CMDLINE_OPTS);
|
||||||
|
StrCat(optstring, sysdeps_get_cmdline_opts());
|
||||||
|
|
||||||
|
while ((c=Getopt(argc, argv, optstring)) != -1 ) {
|
||||||
|
switch(c) {
|
||||||
|
case 'a':
|
||||||
|
elilo_opt.alt_check = 1;
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
elilo_opt.debug = 1;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
elilo_opt.prompt = 1;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
elilo_opt.verbose++;
|
||||||
|
if (elilo_opt.verbose > 5) elilo_opt.verbose = 5;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
elilo_help();
|
||||||
|
ret = EFI_SUCCESS;
|
||||||
|
goto do_exit;
|
||||||
|
case 'd':
|
||||||
|
/*
|
||||||
|
* zero is a valid value here, so we use the delay-set to mark the
|
||||||
|
* fact that the user specified a value on cmdline. See config.c
|
||||||
|
*/
|
||||||
|
elilo_opt.delay = Atoi(Optarg);
|
||||||
|
elilo_opt.delay_set = 1;
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
/* don't force EDD30 EFI variable if not already set */
|
||||||
|
elilo_opt.edd30_no_force = 1;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
if (StrLen(Optarg) >= FILENAME_MAXLEN-1) {
|
||||||
|
Print(L"initrd filename is limited to %d characters\n", FILENAME_MAXLEN);
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
StrCpy(elilo_opt.initrd, Optarg);
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
if (StrLen(Optarg) >= FILENAME_MAXLEN-1) {
|
||||||
|
Print(L"config filename is limited to %d characters\n", FILENAME_MAXLEN);
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
StrCpy(elilo_opt.config, Optarg);
|
||||||
|
break;
|
||||||
|
case 'M': /* builtin debug tool */
|
||||||
|
{ mmap_desc_t mdesc;
|
||||||
|
if (get_memmap(&mdesc) == -1) {
|
||||||
|
Print(L"Cannot get memory map\n");
|
||||||
|
return EFI_LOAD_ERROR;
|
||||||
|
}
|
||||||
|
print_memmap(&mdesc);
|
||||||
|
ret = EFI_SUCCESS;
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
case 'V':
|
||||||
|
Print(L"ELILO v%s for EFI/%a\n", ELILO_VERSION, ELILO_ARCH);
|
||||||
|
ret = EFI_SUCCESS;
|
||||||
|
goto do_exit;
|
||||||
|
case 'P':
|
||||||
|
/* cmdline only option */
|
||||||
|
elilo_opt.parse_only = 1;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
if (StrLen(Optarg) >= FILENAME_MAXLEN-1) {
|
||||||
|
Print(L"chooser name is limited to %d characters\n", FILENAME_MAXLEN);
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
StrCpy(elilo_opt.chooser, Optarg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/*
|
||||||
|
* try system dependent options before declaring error
|
||||||
|
*/
|
||||||
|
if (sysdeps_getopt(c, Optind, Optarg) == 0) continue;
|
||||||
|
|
||||||
|
Print(L"Unknown option -%c\n", (CHAR16)c);
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBG_PRT((L"Optind=%d optarg=%x argc=%d", Optind, Optarg, argc));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we can't defer this phase any longer...
|
||||||
|
* Must be done after the elilo_opt are initialized (at least partially)
|
||||||
|
*/
|
||||||
|
if (init_devices(info->DeviceHandle) == -1) goto do_exit;
|
||||||
|
|
||||||
|
devices_initialized = TRUE;
|
||||||
|
|
||||||
|
devpath = DevicePathToStr(info->FilePath);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set per fileops defaults files for configuration and kernel
|
||||||
|
*/
|
||||||
|
fops_setdefaults(elilo_opt.default_config, elilo_opt.default_kernel, FILENAME_MAXLEN, devpath);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX: won't be visible if verbose not required from command line
|
||||||
|
*/
|
||||||
|
VERB_PRT(2,Print(L"Default config: %s\nDefault_kernel: %s\n",
|
||||||
|
elilo_opt.default_config,elilo_opt.default_kernel));
|
||||||
|
/*
|
||||||
|
* use default config file if not specified by user
|
||||||
|
*/
|
||||||
|
ptr = elilo_opt.config[0] == CHAR_NULL ? (retry=1,elilo_opt.default_config) : (retry=0,elilo_opt.config);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* parse config file (verbose becomes visible if set)
|
||||||
|
*/
|
||||||
|
ret = read_config(ptr, retry);
|
||||||
|
Print(L"read_config=%r\n", ret);
|
||||||
|
/*
|
||||||
|
* when the config file is not found, we fail only if:
|
||||||
|
* - the user did not specified interactive mode
|
||||||
|
* - the user did not explicitely specify the config file
|
||||||
|
*/
|
||||||
|
if (ret == EFI_NOT_FOUND || ret == EFI_TFTP_ERROR) {
|
||||||
|
if (elilo_opt.prompt == 0 && elilo_opt.config[0] != CHAR_NULL) {
|
||||||
|
Print(L"config file %s not found\n", ptr);
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
fops_getdefault_path(dpath, FILENAME_MAXLEN);
|
||||||
|
if (ret == EFI_TFTP_ERROR)
|
||||||
|
Print(L"no config file found on TFTP server in %s\n", dpath);
|
||||||
|
else
|
||||||
|
Print(L"no config file found in %s\n", dpath);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* stop if just doing parsing
|
||||||
|
*/
|
||||||
|
if (elilo_opt.parse_only) {
|
||||||
|
if (ret == EFI_SUCCESS)
|
||||||
|
Print(L"Config file %s parsed successfully\n", ptr);
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* if there was an error when parsing the config file, then
|
||||||
|
* we force interactive mode to give a chance to the user.
|
||||||
|
* We also clear the error.
|
||||||
|
*/
|
||||||
|
if (ret && argc == 1) {
|
||||||
|
Print(L"forcing interactive mode because of errors\n");
|
||||||
|
elilo_opt.prompt = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If EDD30 EFI variable was not set to TRUE (or not defined), we
|
||||||
|
* we try to force it. This will take effect at the next reboot.
|
||||||
|
*
|
||||||
|
* Some controllers don't have EDD30 support, in this case forcing it
|
||||||
|
* may cause problems, therefore we check the edd_no_force option
|
||||||
|
* before making the call.
|
||||||
|
*/
|
||||||
|
if (edd30_status == -1 && elilo_opt.edd30_no_force == 0) {
|
||||||
|
force_edd30();
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = EFI_LOAD_ERROR;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if the user specified a kernel on the command line
|
||||||
|
* then we don't go to interactive mode even if it
|
||||||
|
* was set in the config file or set because of an
|
||||||
|
* error parsing the config file.
|
||||||
|
*/
|
||||||
|
if (argc > Optind) elilo_opt.prompt = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/* set default timeout if going interactive */
|
||||||
|
if ((elilo_opt.prompt && elilo_opt.timeout == 0)) {
|
||||||
|
elilo_opt.timeout = ELILO_DEFAULT_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* which chooser we will use
|
||||||
|
*/
|
||||||
|
if (init_chooser(info->DeviceHandle) == -1) {
|
||||||
|
ERR_PRT((L"Cannot find a decent chooser\n"));
|
||||||
|
goto do_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (elilo_opt.prompt == 0) VERB_PRT(1, print_devices());
|
||||||
|
|
||||||
|
main_loop(info->DeviceHandle, argv, argc, Optind, image);
|
||||||
|
/* should not return */
|
||||||
|
do_exit:
|
||||||
|
unfixupargs(info);
|
||||||
|
|
||||||
|
//if (arglist) free(arglist);
|
||||||
|
|
||||||
|
/* free all resources assiocated with file accesses */
|
||||||
|
if (devices_initialized) close_devices();
|
||||||
|
|
||||||
|
/* garbage collect all remaining allocations */
|
||||||
|
free_all_memory();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
201
elilo.h
Normal file
201
elilo.h
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001 Silicon Graphics, Inc.
|
||||||
|
* Contributed by Brent Casavant <bcasavan@sgi.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* GNU EFI is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* GNU EFI is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU EFI; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ELILO_H__
|
||||||
|
#define __ELILO_H__
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
|
||||||
|
#include "elilo_debug.h"
|
||||||
|
|
||||||
|
#include "fileops.h"
|
||||||
|
#include "chooser.h"
|
||||||
|
|
||||||
|
#include "strops.h"
|
||||||
|
|
||||||
|
#include "sysdeps.h"
|
||||||
|
|
||||||
|
#define MB (1024*1024) /* 1 megabyte */
|
||||||
|
|
||||||
|
/* Round X up/down to A, which must be an integer power of two. */
|
||||||
|
#define ROUNDUP(x,a) (((x) + (a) - 1) & ~((a) - 1))
|
||||||
|
#define ROUNDDOWN(x,a) ((x) & ~((a) - 1))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Elilo Boot modes
|
||||||
|
*/
|
||||||
|
#define ELILO_LOAD_SUCCESS 0
|
||||||
|
#define ELILO_LOAD_ABORTED 1
|
||||||
|
#define ELILO_LOAD_ERROR 2
|
||||||
|
#define ELILO_LOAD_RETRY 3
|
||||||
|
|
||||||
|
#define ELILO_DEFAULT_TIMEOUT ELILO_TIMEOUT_INFINITY
|
||||||
|
#define ELILO_TIMEOUT_INFINITY (~0UL)
|
||||||
|
|
||||||
|
#define CMDLINE_MAXLEN 512 /* needed by ia32 */
|
||||||
|
#define FILENAME_MAXLEN 256
|
||||||
|
#define MAX_ARGS 256
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINT8 nothing_yet;
|
||||||
|
} image_opt_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/*
|
||||||
|
* list of options controllable from both the command line
|
||||||
|
* and the config file
|
||||||
|
*/
|
||||||
|
UINTN alt_check; /* always check for alternate kernel */
|
||||||
|
UINTN debug; /* debug print() on */
|
||||||
|
UINTN delay; /* delay before booting the image */
|
||||||
|
UINTN verbose; /* verbosity level [1-5] */
|
||||||
|
CHAR16 initrd[FILENAME_MAXLEN]; /* name of file for initial ramdisk */
|
||||||
|
UINT8 delay_set; /* mark whether or not delay was specified on cmdline */
|
||||||
|
UINT8 edd30_on; /* true is EDD30 variable is TRUE */
|
||||||
|
UINT8 edd30_no_force; /* don't force EDD30 variable to true */
|
||||||
|
/*
|
||||||
|
* list of options controllable from either the command line
|
||||||
|
* or the config file
|
||||||
|
*/
|
||||||
|
UINTN prompt; /* enter interactive mode */
|
||||||
|
UINTN parse_only; /* only parses the config file */
|
||||||
|
UINTN timeout; /* timeout before leaving interactive mode*/
|
||||||
|
|
||||||
|
image_opt_t img_opt; /* architecture independent per image options*/
|
||||||
|
|
||||||
|
sys_img_options_t *sys_img_opts; /* architecture depdendent per image options */
|
||||||
|
|
||||||
|
CHAR16 default_kernel[FILENAME_MAXLEN];
|
||||||
|
CHAR16 default_config[FILENAME_MAXLEN];
|
||||||
|
|
||||||
|
CHAR16 config[FILENAME_MAXLEN]; /* name of config file */
|
||||||
|
CHAR16 chooser[FILENAME_MAXLEN]; /* image chooser to use */
|
||||||
|
} elilo_config_t;
|
||||||
|
|
||||||
|
|
||||||
|
extern elilo_config_t elilo_opt;
|
||||||
|
|
||||||
|
extern EFI_SYSTEM_TABLE *systab;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
VOID *start_addr;
|
||||||
|
UINTN pgcnt;
|
||||||
|
} memdesc_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
VOID *kstart;
|
||||||
|
VOID *kend;
|
||||||
|
VOID *kentry;
|
||||||
|
} kdesc_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EFI_MEMORY_DESCRIPTOR *md;
|
||||||
|
UINTN map_size;
|
||||||
|
UINTN desc_size;
|
||||||
|
UINTN cookie;
|
||||||
|
UINT32 desc_version;
|
||||||
|
} mmap_desc_t;
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(a,b) ((a)>(b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a,b) ((a)>(b) ? (b) : (a))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define VERB_PRT(n,cmd) \
|
||||||
|
{ if (elilo_opt.verbose >= (n)) { cmd; } }
|
||||||
|
|
||||||
|
|
||||||
|
/* from alloc.c */
|
||||||
|
extern INTN alloc_init(VOID);
|
||||||
|
extern VOID *alloc(UINTN, EFI_MEMORY_TYPE);
|
||||||
|
extern VOID free(VOID *);
|
||||||
|
extern VOID *alloc_pages(UINTN, EFI_MEMORY_TYPE, EFI_ALLOCATE_TYPE, VOID *);
|
||||||
|
extern VOID free_pages(VOID *);
|
||||||
|
extern VOID free_all(VOID);
|
||||||
|
extern INTN alloc_kmem(VOID *, UINTN);
|
||||||
|
extern VOID free_kmem(VOID);
|
||||||
|
extern VOID free_all_memory(VOID);
|
||||||
|
|
||||||
|
/* from util.c */
|
||||||
|
extern INTN read_file(UINTN fd, UINTN, CHAR8 *);
|
||||||
|
extern EFI_STATUS check_abort(VOID);
|
||||||
|
extern VOID reset_input(VOID);
|
||||||
|
extern INTN wait_timeout(UINTN);
|
||||||
|
extern INTN argify(CHAR16 *, UINTN, CHAR16 **);
|
||||||
|
extern VOID unargify(CHAR16 **, CHAR16 **);
|
||||||
|
extern void split_args(CHAR16 *, CHAR16 *, CHAR16 *);
|
||||||
|
extern INTN get_memmap(mmap_desc_t *);
|
||||||
|
extern VOID free_memmap(mmap_desc_t *);
|
||||||
|
extern INTN find_kernel_memory(VOID *low_addr, VOID *max_addr, UINTN alignment, VOID ** start);
|
||||||
|
extern VOID print_memmap(mmap_desc_t *);
|
||||||
|
extern VOID ascii2U(CHAR8 *, CHAR16 *, UINTN);
|
||||||
|
extern VOID U2ascii(CHAR16 *, CHAR8 *, UINTN);
|
||||||
|
|
||||||
|
/* from config.c (more in config.h) */
|
||||||
|
extern EFI_STATUS read_config(CHAR16 *, INTN retry);
|
||||||
|
extern VOID print_config_options(VOID);
|
||||||
|
extern INTN find_label(CHAR16 *, CHAR16 *, CHAR16 *, CHAR16 *);
|
||||||
|
extern VOID print_label_list(VOID);
|
||||||
|
extern INTN config_init(VOID);
|
||||||
|
extern CHAR16 *get_message_filename(INTN which);
|
||||||
|
extern CHAR16 *find_description(CHAR16 *label);
|
||||||
|
extern VOID *get_next_description(VOID *prev, CHAR16 **label, CHAR16 **description);
|
||||||
|
extern CHAR16 *get_config_file(VOID);
|
||||||
|
|
||||||
|
/* from initrd.c */
|
||||||
|
extern INTN load_initrd(CHAR16 *, memdesc_t *);
|
||||||
|
|
||||||
|
/* from alternate.c */
|
||||||
|
extern INTN alternate_kernel(CHAR16 *, INTN);
|
||||||
|
|
||||||
|
/* from bootparams.c */
|
||||||
|
extern VOID *create_boot_params (CHAR16 *, memdesc_t *, UINTN *);
|
||||||
|
extern VOID free_boot_params(VOID *bp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* architecture-specific API
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
extern INTN sysdeps_create_boot_params(boot_params_t *, CHAR8 *, memdesc_t *, UINTN *);
|
||||||
|
extern VOID sysdeps_free_boot_params(boot_params_t *);
|
||||||
|
extern INTN sysdeps_init(EFI_HANDLE dev);
|
||||||
|
extern INTN sysdeps_initrd_get_addr(kdesc_t *, memdesc_t *);
|
||||||
|
extern INTN sysdeps_preloop_actions(EFI_HANDLE, CHAR16 **, INTN, INTN, EFI_HANDLE);
|
||||||
|
extern CHAR16 *sysdeps_get_cmdline_opts(VOID);
|
||||||
|
extern INTN sysdeps_getopt(INTN, INTN, CHAR16 *);
|
||||||
|
extern VOID sysdeps_print_cmdline_opts(VOID);
|
||||||
|
extern INTN sysdeps_register_options(VOID);
|
||||||
|
|
||||||
|
#define CHAR_SLASH L'/'
|
||||||
|
#define CHAR_BACKSLASH L'\\'
|
||||||
|
|
||||||
|
#endif /* __ELILO_H__ */
|
44
elilo_debug.h
Normal file
44
elilo_debug.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* GNU EFI is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* GNU EFI is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU EFI; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ELILO_DEBUG__
|
||||||
|
#define __ELILO_DEBUG__
|
||||||
|
|
||||||
|
#define ELILO_DEBUG 1
|
||||||
|
|
||||||
|
#define ERR_PRT(a) do { Print(L"%a(line %d):", __FILE__, __LINE__); Print a; Print(L"\n"); } while (0);
|
||||||
|
|
||||||
|
#ifdef ELILO_DEBUG
|
||||||
|
#define DBG_PRT(a) do { \
|
||||||
|
if (elilo_opt.debug) { \
|
||||||
|
Print(L"%a(line %d):", __FILE__, __LINE__); \
|
||||||
|
Print a; \
|
||||||
|
Print(L"\n"); \
|
||||||
|
} } while (0);
|
||||||
|
#else
|
||||||
|
#define DBG_PRT(a)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __ELILO_DEBUG_H__ */
|
188
examples/netboot/dhcpd-pxe.conf
Normal file
188
examples/netboot/dhcpd-pxe.conf
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
#
|
||||||
|
# Enable proxyDHCP operation.
|
||||||
|
#
|
||||||
|
dhcpd-operation normal;
|
||||||
|
|
||||||
|
#
|
||||||
|
# BootServer is turned on
|
||||||
|
#
|
||||||
|
bootserver-operation on;
|
||||||
|
|
||||||
|
ddns-update-style ad-hoc;
|
||||||
|
|
||||||
|
#
|
||||||
|
# if this dhcpd server is not "master"
|
||||||
|
#
|
||||||
|
not authoritative;
|
||||||
|
|
||||||
|
#-------------------------------------------------------------
|
||||||
|
# For each of the 3 servers (builtin) define the DHCPD option
|
||||||
|
# tags we are interested in.
|
||||||
|
#-------------------------------------------------------------
|
||||||
|
|
||||||
|
#
|
||||||
|
# Define DHCPD request option tags
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# This option is used to determine the client boot-time binary runtime
|
||||||
|
# environment.
|
||||||
|
#
|
||||||
|
option client-architecture code 93 =
|
||||||
|
unsigned integer 16;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Now go to the DHCPD proxy option tags
|
||||||
|
#
|
||||||
|
option space proxy;
|
||||||
|
|
||||||
|
option proxy.boot-prompt code 10 =
|
||||||
|
{ unsigned integer 8, text };
|
||||||
|
|
||||||
|
option proxy.boot-menu code 9 = array of
|
||||||
|
{ unsigned integer 16, unsigned integer 8, text };
|
||||||
|
|
||||||
|
option proxy.boot-servers code 8 = array of
|
||||||
|
{ unsigned integer 16, unsigned integer 8, array of ip-address };
|
||||||
|
|
||||||
|
option proxy.discovery-control code 6 = unsigned integer 8;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Now go to the PXE Bootserver options
|
||||||
|
#
|
||||||
|
option space bs;
|
||||||
|
|
||||||
|
option bs.boot-item code 71 =
|
||||||
|
{ unsigned integer 16, unsigned integer 16 };
|
||||||
|
|
||||||
|
#-------------------------------------------------------------
|
||||||
|
# Actual configuration
|
||||||
|
#-------------------------------------------------------------
|
||||||
|
|
||||||
|
subnet 192.168.2.0 netmask 255.255.255.0 {
|
||||||
|
#
|
||||||
|
# In this section define regular DHCPD options
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Here we show settings with fixed addresses, but dynamic
|
||||||
|
# allocation is possible as well
|
||||||
|
#
|
||||||
|
host test1 {
|
||||||
|
hardware ethernet 00:d0:b7:c7:fb:f8;
|
||||||
|
fixed-address 192.168.2.10;
|
||||||
|
}
|
||||||
|
host test2 {
|
||||||
|
hardware ethernet 00:d0:b7:aa:f0:e3;
|
||||||
|
fixed-address 192.168.2.11;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Now we look at options for every possible type of requests
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# If requets was received by the ProxyDHCPD
|
||||||
|
if proxy {
|
||||||
|
|
||||||
|
#
|
||||||
|
# Provide proxyDHCP information for Intel ia64
|
||||||
|
# architecture machines.
|
||||||
|
#
|
||||||
|
if option client-architecture = 00:02 {
|
||||||
|
#
|
||||||
|
# Notify of PXE aware server
|
||||||
|
#
|
||||||
|
option vendor-class-identifier "PXEClient";
|
||||||
|
|
||||||
|
#
|
||||||
|
# Force unicast
|
||||||
|
#
|
||||||
|
option proxy.discovery-control 3;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Print a nice boot menu
|
||||||
|
#
|
||||||
|
# ServerTypes:
|
||||||
|
# 14 -> means Redhat install
|
||||||
|
# 13 -> means Redhat Boot
|
||||||
|
# 23 & 26 are length of string following.
|
||||||
|
#
|
||||||
|
option proxy.boot-menu
|
||||||
|
14 23 "Remote Redhat/ia64 boot",
|
||||||
|
13 26 "Remote Redhat/ia64 install";
|
||||||
|
|
||||||
|
#
|
||||||
|
# list of possible bootservers for a ServerType
|
||||||
|
#
|
||||||
|
# Currently not possible to define more than one type
|
||||||
|
#
|
||||||
|
option proxy.boot-servers
|
||||||
|
14 1 192.168.2.32;
|
||||||
|
|
||||||
|
#
|
||||||
|
# A boot prompt
|
||||||
|
# 30 is timeout in seconds
|
||||||
|
#
|
||||||
|
option proxy.boot-prompt
|
||||||
|
30 "Press <F8> or <M> for menu. Press <Esc> to local boot.";
|
||||||
|
|
||||||
|
#
|
||||||
|
#
|
||||||
|
vendor-option-space proxy;
|
||||||
|
}
|
||||||
|
} else if bootserver {
|
||||||
|
|
||||||
|
if option client-architecture = 00:02 {
|
||||||
|
#
|
||||||
|
# Now analyze bootserver request option tags
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# ELILO Layering:
|
||||||
|
# Layer 0: bootloader binary (elilo.efi)
|
||||||
|
# Layer 1: elilo configuration file (elilo.conf)
|
||||||
|
# Layer 2: Linux/ia64 kernel
|
||||||
|
|
||||||
|
if substring(option bs.boot-item, 2, 2) = 00:00 {
|
||||||
|
|
||||||
|
filename "/tftpboot/elilo.efi";
|
||||||
|
|
||||||
|
#
|
||||||
|
# identify reply layer & server type
|
||||||
|
#
|
||||||
|
option bs.boot-item 14 0;
|
||||||
|
|
||||||
|
} else if substring(option bs.boot-item, 2, 2) = 00:01 {
|
||||||
|
|
||||||
|
filename "/tftpboot/elilo.conf";
|
||||||
|
|
||||||
|
#
|
||||||
|
# identify reply layer & server type
|
||||||
|
#
|
||||||
|
option bs.boot-item 14 1;
|
||||||
|
|
||||||
|
} else if substring(option bs.boot-item, 2, 3) = 00:02 {
|
||||||
|
|
||||||
|
filename "/tftpboot/vmlinux";
|
||||||
|
|
||||||
|
#
|
||||||
|
# identify reply layer & server type
|
||||||
|
#
|
||||||
|
option bs.boot-item 14 2;
|
||||||
|
}
|
||||||
|
#
|
||||||
|
#
|
||||||
|
vendor-option-space bs;
|
||||||
|
|
||||||
|
option vendor-class-identifier "PXEClient";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#
|
||||||
|
# notify of PXE aware DHCPD server
|
||||||
|
#
|
||||||
|
option vendor-class-identifier "PXEClient";
|
||||||
|
}
|
||||||
|
}
|
14
examples/netboot/dhcpd.conf
Normal file
14
examples/netboot/dhcpd.conf
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
subnet 192.168.2.0 netmask 255.255.255.0 {
|
||||||
|
|
||||||
|
option domain-name "mydomain.com";
|
||||||
|
option subnet-mask 255.255.255.0;
|
||||||
|
option routers 15.4.88.1;
|
||||||
|
|
||||||
|
# here we use a fixed address
|
||||||
|
host test_machine {
|
||||||
|
hardware ethernet 00:D0:B7:C7:FB:F8;
|
||||||
|
fixed-address 192.168.2.10;
|
||||||
|
filename "/tftpboot/elilo.efi";
|
||||||
|
option host-name "test_machine";
|
||||||
|
}
|
||||||
|
}
|
45
examples/textmenu_chooser/elilo-textmenu.conf
Normal file
45
examples/textmenu_chooser/elilo-textmenu.conf
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#
|
||||||
|
# force chooser to textmenu
|
||||||
|
chooser=textmenu
|
||||||
|
|
||||||
|
delay=20
|
||||||
|
prompt
|
||||||
|
|
||||||
|
#
|
||||||
|
# the files containing the text (with attributes) to display
|
||||||
|
#
|
||||||
|
message=textmenu-message.msg
|
||||||
|
|
||||||
|
#
|
||||||
|
# files to load when the corresponding function key is pressed
|
||||||
|
#
|
||||||
|
f1=general.msg
|
||||||
|
f2=params.msg
|
||||||
|
|
||||||
|
image=debian/linux
|
||||||
|
label=debian
|
||||||
|
description="Install Debian GNU/Linux"
|
||||||
|
read-only
|
||||||
|
initrd=debian/root.bin
|
||||||
|
root=/dev/ram
|
||||||
|
|
||||||
|
image=debian/linux
|
||||||
|
label=sda1
|
||||||
|
description="Boot Debian Linux, root on sda1"
|
||||||
|
read-only
|
||||||
|
root=/dev/sda1
|
||||||
|
|
||||||
|
image=debian/linux.old
|
||||||
|
label=old
|
||||||
|
description="Boot Debian Linux, old kernel"
|
||||||
|
read-only
|
||||||
|
root=/dev/sda1
|
||||||
|
|
||||||
|
image=debian/linux
|
||||||
|
label=shell
|
||||||
|
description="Execute a shell"
|
||||||
|
read-only
|
||||||
|
initrd=debian/root.bin
|
||||||
|
root=/dev/ram
|
||||||
|
append="init=/bin/sh"
|
||||||
|
|
25
examples/textmenu_chooser/general.msg
Normal file
25
examples/textmenu_chooser/general.msg
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß
|
||||||
|
10
|
||||||
|
7fÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ 74General Screen7f ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ70¿10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 This is the general screen. You entered by pressing F1 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 Press any key to return to main screen ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 Help: [71F170-General] [71F270-Params] ³10
|
||||||
|
7fÀ70ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ10
|
25
examples/textmenu_chooser/params.msg
Normal file
25
examples/textmenu_chooser/params.msg
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß
|
||||||
|
10
|
||||||
|
7fÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ 74Params Screen7f ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ70¿10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 This is the params screen. You entered by pressing F2 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 Press any key to return to main screen ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 Help: [71F170-General] [71F270-Params] ³10
|
||||||
|
7fÀ70ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ10
|
25
examples/textmenu_chooser/textmenu-message.msg
Normal file
25
examples/textmenu_chooser/textmenu-message.msg
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß
|
||||||
|
10
|
||||||
|
7fÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ 74Install and Recovery Disk7f ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ70¿10
|
||||||
|
7f³70 This CD demonstrates the elilo textmenu chooser. You can select an entry ³10
|
||||||
|
7f³70 from the menu with the curosr keys, enter exptra parameters at the propmt, ³10
|
||||||
|
7f³70 and press <return> to start the process. Help can be made available via ³10
|
||||||
|
7f³70 the function keys. On a serial console, use Ctrl-F followed by the ³10
|
||||||
|
7f³70 relevant function key number. ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 7eBeware that this is an install disk, and misuse can result in the loss of 70³10
|
||||||
|
7f³70 7eany data currently on your disks. 70³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ7f¿70 ³10
|
||||||
|
7f³70 ³70 This is where the menu goes 7f³70 ³10
|
||||||
|
7f³70 ³701e (active colour) 7f³70 ³10
|
||||||
|
7f³70 ³70 (inactive colour) 7f³70 ³10
|
||||||
|
7f³70 ³70 1e7f³70 ³10
|
||||||
|
7f³70 À7fÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 Boot: 35 70 ³10
|
||||||
|
7f³70 ³10
|
||||||
|
7f³70 Help: [71F170-General] [71F270-Params] ³10
|
||||||
|
7fÀ70ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ10
|
628
fileops.c
Normal file
628
fileops.c
Normal file
|
@ -0,0 +1,628 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* import filesystems
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_LOCALFS
|
||||||
|
#include "glue_localfs.h"
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_NETFS
|
||||||
|
#include "glue_netfs.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_EXT2FS
|
||||||
|
#include "glue_ext2fs.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* table of device naming schemes.
|
||||||
|
* we will probe each one in sequential order and stop at first match.
|
||||||
|
*/
|
||||||
|
extern devname_scheme_t simple_devname_scheme;
|
||||||
|
|
||||||
|
static devname_scheme_t *devname_scheme_tab[]={
|
||||||
|
&simple_devname_scheme,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Once we are able to create Boot Services drivers we won't need
|
||||||
|
* this hack and we'll be able to load the driver from the boot manager
|
||||||
|
* or EFI shell. So for now we explicitely invoke the probe routine
|
||||||
|
* of each driver that we know about
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef EFI_STATUS (fops_fixups_t)(EFI_HANDLE dev, device_t *d);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List of filesystem we currently support
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static fileops_fs_t *fs_tab[]={
|
||||||
|
#ifdef CONFIG_LOCALFS
|
||||||
|
&localfs_glue,
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_EXT2FS
|
||||||
|
&ext2fs_glue,
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_NETFS
|
||||||
|
&netfs_glue,
|
||||||
|
#endif
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static device_t *dev_tab;
|
||||||
|
static UINTN ndev, ndev_boot;
|
||||||
|
static device_t *boot_dev;
|
||||||
|
|
||||||
|
typedef struct _fdesc_t {
|
||||||
|
struct _fdesc_t *next; /* pointer to next free (when in free list) */
|
||||||
|
fileops_t *fops; /* pointer to filesystem-specific glue interface */
|
||||||
|
UINTN fh; /* file descriptor from lower level protocol */
|
||||||
|
} fdesc_t;
|
||||||
|
|
||||||
|
#define FILEOPS_FD_MAX 16
|
||||||
|
|
||||||
|
static fdesc_t fd_tab[FILEOPS_FD_MAX];
|
||||||
|
static fdesc_t *free_fd;
|
||||||
|
|
||||||
|
static devname_scheme_t *current_devname_scheme;
|
||||||
|
|
||||||
|
#define FDESC_IDX(f) (fops_fd_t)(f-fd_tab)
|
||||||
|
#define FDESC_INVALID_FD(fd) (fd >= FILEOPS_FD_MAX || fd_tab[(fd)].fops == NULL)
|
||||||
|
#define FDESC_F(fd) (fd_tab+(fd))
|
||||||
|
|
||||||
|
static fdesc_t *
|
||||||
|
fd_alloc(VOID)
|
||||||
|
{
|
||||||
|
fdesc_t *tmp = NULL;
|
||||||
|
|
||||||
|
if (free_fd == NULL) {
|
||||||
|
ERR_PRT((L"out of file descriptor"));
|
||||||
|
} else {
|
||||||
|
tmp = free_fd;
|
||||||
|
free_fd = free_fd->next;
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
fd_free(fdesc_t *fd)
|
||||||
|
{
|
||||||
|
if (fd == NULL) {
|
||||||
|
ERR_PRT((L"invalid fd"));
|
||||||
|
}
|
||||||
|
fd->fops = NULL; /* mark as invalid */
|
||||||
|
fd->next = free_fd;
|
||||||
|
free_fd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fileops_t *
|
||||||
|
glue_filesystem(EFI_GUID *proto, EFI_HANDLE dev, fops_fs_glue_t glue)
|
||||||
|
{
|
||||||
|
fileops_t *fops;
|
||||||
|
VOID *intf = NULL;
|
||||||
|
EFI_STATUS status;
|
||||||
|
|
||||||
|
status = BS->HandleProtocol(dev, proto, &intf);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"unable to locate %g: should not happen", proto));
|
||||||
|
return NULL; /* should not happen */
|
||||||
|
}
|
||||||
|
fops = (fileops_t *)alloc(sizeof(*fops), EfiLoaderData);
|
||||||
|
if (fops == NULL) {
|
||||||
|
ERR_PRT((L"failed to allocate fileops"));
|
||||||
|
return NULL; /* XXX uninstall protocol */
|
||||||
|
}
|
||||||
|
Memset(fops, 0, sizeof(*fops));
|
||||||
|
|
||||||
|
fops->dev = dev;
|
||||||
|
|
||||||
|
/* initialize private interface now */
|
||||||
|
glue(fops, intf);
|
||||||
|
|
||||||
|
return fops;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
fops_split_path(CHAR16 *path, CHAR16 *dev)
|
||||||
|
{
|
||||||
|
CHAR16 *p, *d = dev;
|
||||||
|
UINTN len = FILEOPS_DEVNAME_MAXLEN;
|
||||||
|
# define CHAR_COLON L':'
|
||||||
|
|
||||||
|
p = StrChr(path, CHAR_COLON);
|
||||||
|
if (p == NULL) {
|
||||||
|
*dev = CHAR_NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* copy device part of the name */
|
||||||
|
for (d = dev ; path != p ;) {
|
||||||
|
if (--len == 0) return -1; /* too long */
|
||||||
|
*d++ = *path++;
|
||||||
|
}
|
||||||
|
*d = CHAR_NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static device_t *
|
||||||
|
find_device_byname(CHAR16 *dev)
|
||||||
|
{
|
||||||
|
UINTN i;
|
||||||
|
for(i=0; i < ndev; i++) {
|
||||||
|
if (!StrCmp(dev, dev_tab[i].name)) return dev_tab+i;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is used to walk through the device list and get names.
|
||||||
|
* arguments:
|
||||||
|
* - pidx = opaque cookie returned by previous call (must be zero for initial call)
|
||||||
|
* - type is the type of filesystem to look for, e.g., vfat or ext2fs. NULL means ANY
|
||||||
|
* - maxlen is the size in bytes of the returned string buffer
|
||||||
|
* - idx is the opaque cookie returned (can be reused by next call)
|
||||||
|
* - name a string buffer to hold the name of the next matching device
|
||||||
|
* - dev will receive the EFI_HANDLE corresponding to the device if not NULL
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* - EFI_INVALID_PARAMETER: when NULL values are passed for required arguments.
|
||||||
|
* - EFI_NOT_FOUND: when reached the end of the list of invalid cookie
|
||||||
|
* - EFI_BUFFER_TOO_SMALL is device name does not fit into string buffer
|
||||||
|
* - EFI_SUCCESS otherwise
|
||||||
|
*/
|
||||||
|
EFI_STATUS
|
||||||
|
fops_get_next_device(UINTN pidx, CHAR16 *type, UINTN maxlen, UINTN *idx, CHAR16 *name, EFI_HANDLE *dev)
|
||||||
|
{
|
||||||
|
UINTN i;
|
||||||
|
|
||||||
|
if (name == NULL || idx == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
for(i=pidx; i < ndev; i++) {
|
||||||
|
if (type == NULL || !StrCmp(dev_tab[i].fops->name, type)) goto found;
|
||||||
|
}
|
||||||
|
return EFI_NOT_FOUND;
|
||||||
|
found:
|
||||||
|
if (StrLen(dev_tab[i].name) >= maxlen) {
|
||||||
|
*idx = pidx; /* will restart from same place! */
|
||||||
|
return EFI_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
StrCpy(name, dev_tab[i].name);
|
||||||
|
*idx = i+1;
|
||||||
|
if (dev) *dev = dev_tab[i].dev;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
fops_get_device_handle(CHAR16 *name, EFI_HANDLE *dev)
|
||||||
|
{
|
||||||
|
UINTN i;
|
||||||
|
|
||||||
|
if (name == NULL || dev == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
for(i=0; i < ndev; i++) {
|
||||||
|
if (!StrCmp(dev_tab[i].name, name)) goto found;
|
||||||
|
}
|
||||||
|
return EFI_NOT_FOUND;
|
||||||
|
found:
|
||||||
|
*dev = dev_tab[i].dev;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
fops_open(CHAR16 *fullname, fops_fd_t *fd)
|
||||||
|
{
|
||||||
|
fdesc_t *f;
|
||||||
|
EFI_STATUS status;
|
||||||
|
fileops_t *fops;
|
||||||
|
device_t *dev;
|
||||||
|
CHAR16 dev_name[FILEOPS_DEVNAME_MAXLEN];
|
||||||
|
CHAR16 *name;
|
||||||
|
|
||||||
|
|
||||||
|
if (fd == NULL || fullname == NULL || *fullname == CHAR_NULL || fops_split_path(fullname, dev_name) == -1)
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
DBG_PRT((L"fops_open(%s), dev:%s:", fullname ? fullname : L"(NULL)", dev_name));
|
||||||
|
|
||||||
|
name = fullname;
|
||||||
|
if (dev_name[0] == CHAR_NULL) {
|
||||||
|
if (boot_dev == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
fops = boot_dev->fops;
|
||||||
|
} else {
|
||||||
|
if ((dev=find_device_byname(dev_name)) == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
name += StrLen(dev_name)+1;
|
||||||
|
|
||||||
|
fops = dev->fops;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fops == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if ((f=fd_alloc()) == NULL) return EFI_OUT_OF_RESOURCES;
|
||||||
|
|
||||||
|
DBG_PRT((L"dev:%s: fullname:%s: name:%s: f=%d", dev_name, fullname, name, f - fd_tab));
|
||||||
|
|
||||||
|
status = fops->open(fops->intf, name, &f->fh);
|
||||||
|
if (EFI_ERROR(status)) goto error;
|
||||||
|
|
||||||
|
f->fops = fops;
|
||||||
|
|
||||||
|
*fd = FDESC_IDX(f);
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
error:
|
||||||
|
fd_free(f);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
fops_read(fops_fd_t fd, VOID *buf, UINTN *size)
|
||||||
|
{
|
||||||
|
fdesc_t *f;
|
||||||
|
|
||||||
|
if (buf == NULL || FDESC_INVALID_FD(fd) || size == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
f = FDESC_F(fd);
|
||||||
|
|
||||||
|
return f->fops->read(f->fops->intf, f->fh, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
fops_close(fops_fd_t fd)
|
||||||
|
{
|
||||||
|
fdesc_t *f;
|
||||||
|
EFI_STATUS status;
|
||||||
|
|
||||||
|
if (FDESC_INVALID_FD(fd)) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
f = FDESC_F(fd);
|
||||||
|
|
||||||
|
status = f->fops->close(f->fops->intf, f->fh);
|
||||||
|
|
||||||
|
fd_free(f);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
fops_infosize(fops_fd_t fd, UINT64 *size)
|
||||||
|
{
|
||||||
|
fdesc_t *f;
|
||||||
|
|
||||||
|
if (FDESC_INVALID_FD(fd) || size == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
f = FDESC_F(fd);
|
||||||
|
|
||||||
|
return f->fops->infosize(f->fops->intf, f->fh, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
fops_seek(fops_fd_t fd, UINT64 newpos)
|
||||||
|
{
|
||||||
|
fdesc_t *f;
|
||||||
|
|
||||||
|
if (FDESC_INVALID_FD(fd)) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
f = FDESC_F(fd);
|
||||||
|
|
||||||
|
return f->fops->seek(f->fops->intf, f->fh, newpos);
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
fops_setdefaults(CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
|
||||||
|
{
|
||||||
|
#define FILEOPS_DEFAULT_KERNEL L"vmlinux"
|
||||||
|
#define FILEOPS_DEFAULT_CONFIG L"elilo.conf"
|
||||||
|
|
||||||
|
if (config == NULL || kname == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (boot_dev == NULL || boot_dev->fops == NULL) {
|
||||||
|
if (boot_dev == NULL)
|
||||||
|
Print(L"Warning boot device not recognized\n");
|
||||||
|
else
|
||||||
|
Print(L"Unknown filesystem on boot device\n");
|
||||||
|
|
||||||
|
Print(L"Using builtin defaults for kernel and config file\n");
|
||||||
|
|
||||||
|
StrnCpy(config, FILEOPS_DEFAULT_CONFIG, maxlen-1);
|
||||||
|
StrnCpy(kname, FILEOPS_DEFAULT_KERNEL, maxlen-1);
|
||||||
|
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return boot_dev->fops->setdefaults(boot_dev->fops->intf, config, kname, maxlen, devpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
fops_getdefault_path(CHAR16 *path, UINTN maxlen)
|
||||||
|
{
|
||||||
|
if (path == NULL || maxlen == 0) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if underlying filesystem implements the call, then we call
|
||||||
|
* otherwise we return an empty string
|
||||||
|
*/
|
||||||
|
if (boot_dev->fops->getdefault_path)
|
||||||
|
return boot_dev->fops->getdefault_path(path, maxlen);
|
||||||
|
|
||||||
|
path[0] = CHAR_NULL;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHAR16 *
|
||||||
|
fops_bootdev_name(VOID)
|
||||||
|
{
|
||||||
|
return boot_dev ? boot_dev->name : L"not supported";
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
add_dev_tab(EFI_GUID *proto, EFI_HANDLE boot_handle, UINTN size, fops_fs_glue_t glue)
|
||||||
|
{
|
||||||
|
EFI_STATUS status;
|
||||||
|
EFI_HANDLE *tab;
|
||||||
|
UINTN i;
|
||||||
|
static UINTN idx;
|
||||||
|
|
||||||
|
if (size == 0) return 0;
|
||||||
|
|
||||||
|
tab = (EFI_HANDLE *)alloc(size, EfiLoaderData);
|
||||||
|
if (tab == NULL) {
|
||||||
|
ERR_PRT((L"failed to allocate handle table"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Memset(tab, 0, size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get the actual device handles now
|
||||||
|
*/
|
||||||
|
status = BS->LocateHandle(ByProtocol, proto, NULL, &size, tab);
|
||||||
|
if (status != EFI_SUCCESS) {
|
||||||
|
ERR_PRT((L"failed to get handles for proto %g size=%d: %r", proto, size, status));
|
||||||
|
free(tab);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
size /= sizeof(EFI_HANDLE);
|
||||||
|
|
||||||
|
for(i=0; i < size; i++) {
|
||||||
|
dev_tab[idx].dev = tab[i];
|
||||||
|
dev_tab[idx].fops = glue_filesystem(proto, tab[i], glue);
|
||||||
|
|
||||||
|
if (tab[i] == boot_handle) boot_dev = dev_tab+idx;
|
||||||
|
|
||||||
|
/* count the ones we recognized */
|
||||||
|
if (dev_tab[idx].fops) ndev_boot++;
|
||||||
|
|
||||||
|
/* assign a generic name for now */
|
||||||
|
dev_tab[idx].name[0] = L'd';
|
||||||
|
dev_tab[idx].name[1] = L'e';
|
||||||
|
dev_tab[idx].name[2] = L'v';
|
||||||
|
dev_tab[idx].name[3] = L'0' + idx/100;
|
||||||
|
dev_tab[idx].name[4] = L'0' + (idx%100)/10;
|
||||||
|
dev_tab[idx].name[5] = L'0' + (idx%100) % 10;
|
||||||
|
dev_tab[idx].name[6] = CHAR_NULL;
|
||||||
|
|
||||||
|
#ifdef ELILO_DEBUG
|
||||||
|
if (elilo_opt.debug) {
|
||||||
|
EFI_DEVICE_PATH *dp;
|
||||||
|
CHAR16 *str, *str2;
|
||||||
|
|
||||||
|
str = NULL;
|
||||||
|
dp = DevicePathFromHandle(dev_tab[idx].dev);
|
||||||
|
if (dp) str = DevicePathToStr(dp);
|
||||||
|
|
||||||
|
str2 = str == NULL ? L"Unknown" : str;
|
||||||
|
|
||||||
|
DBG_PRT((L"%s : %-8s : %s\n", dev_tab[idx].name,
|
||||||
|
(dev_tab[idx].fops ? dev_tab[idx].fops->name: L"N/A"), str2));
|
||||||
|
|
||||||
|
if (str) FreePool(str);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
free(tab);
|
||||||
|
|
||||||
|
/* remember actual number of bootable devices */
|
||||||
|
ndev = idx;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
probe_devname_schemes(device_t *dev_tab, INTN ndev)
|
||||||
|
{
|
||||||
|
devname_scheme_t **p;
|
||||||
|
|
||||||
|
for (p = devname_scheme_tab; *p ; p++) {
|
||||||
|
if ((*p)->install_scheme(dev_tab, ndev) == 0) goto found;
|
||||||
|
}
|
||||||
|
ERR_PRT((L"No devname schemes worked, using builtin\n"));
|
||||||
|
return -1;
|
||||||
|
found:
|
||||||
|
VERB_PRT(3, Print(L"devname scheme: %s\n", (*p)->name));
|
||||||
|
current_devname_scheme = *p;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
find_filesystems(EFI_HANDLE boot_handle)
|
||||||
|
{
|
||||||
|
UINTN size, total = 0;
|
||||||
|
fileops_fs_t **fs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1st pass, figure out how big a table we need
|
||||||
|
*/
|
||||||
|
for(fs = fs_tab; *fs; fs++) {
|
||||||
|
size = 0;
|
||||||
|
BS->LocateHandle(ByProtocol, &(*fs)->proto, NULL, &size, NULL);
|
||||||
|
total += size;
|
||||||
|
}
|
||||||
|
if (total == 0) {
|
||||||
|
ERR_PRT((L"No useable filesystem found"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
total /= sizeof(EFI_HANDLE);
|
||||||
|
DBG_PRT((L"found %d filesystems", total));
|
||||||
|
|
||||||
|
dev_tab = (device_t *)alloc(total*sizeof(device_t), EfiLoaderData);
|
||||||
|
if (dev_tab == NULL) {
|
||||||
|
ERR_PRT((L"failed to allocate handle table"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Memset(dev_tab, 0, total*sizeof(device_t));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* do a 2nd pass to initialize the table now
|
||||||
|
*/
|
||||||
|
for(fs = fs_tab; *fs; fs++) {
|
||||||
|
size = 0;
|
||||||
|
|
||||||
|
BS->LocateHandle(ByProtocol, &(*fs)->proto, NULL, &size, NULL);
|
||||||
|
if (size == 0) continue;
|
||||||
|
|
||||||
|
add_dev_tab(&(*fs)->proto, boot_handle, size, (*fs)->glue);
|
||||||
|
}
|
||||||
|
probe_devname_schemes(dev_tab, ndev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
fileops_init(VOID)
|
||||||
|
{
|
||||||
|
UINTN i;
|
||||||
|
|
||||||
|
for (i=0; i < FILEOPS_FD_MAX-1; i++) {
|
||||||
|
fd_tab[i].next = &fd_tab[i+1];
|
||||||
|
}
|
||||||
|
fd_tab[i].next = NULL;
|
||||||
|
free_fd = fd_tab;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* both functions will go away once we go with boottime drivers
|
||||||
|
*/
|
||||||
|
static INTN
|
||||||
|
install_filesystems(VOID)
|
||||||
|
{
|
||||||
|
fileops_fs_t **fs;
|
||||||
|
|
||||||
|
for(fs = fs_tab; *fs; fs++) (*fs)->install();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
uninstall_filesystems(VOID)
|
||||||
|
{
|
||||||
|
fileops_fs_t **fs;
|
||||||
|
|
||||||
|
for(fs = fs_tab; *fs; fs++) (*fs)->uninstall();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
init_devices(EFI_HANDLE boot_handle)
|
||||||
|
{
|
||||||
|
/* simulate driver installation */
|
||||||
|
install_filesystems();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* now let's do our part
|
||||||
|
*/
|
||||||
|
fileops_init();
|
||||||
|
|
||||||
|
return find_filesystems(boot_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
close_devices(VOID)
|
||||||
|
{
|
||||||
|
INTN i;
|
||||||
|
|
||||||
|
for(i=0; i < FILEOPS_FD_MAX; i++) {
|
||||||
|
fops_close(i);
|
||||||
|
}
|
||||||
|
free(dev_tab);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* simulate driver removal
|
||||||
|
*/
|
||||||
|
uninstall_filesystems();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
print_devices(VOID)
|
||||||
|
{
|
||||||
|
UINTN idx;
|
||||||
|
EFI_DEVICE_PATH *dp;
|
||||||
|
CHAR16 *str, *str2;
|
||||||
|
|
||||||
|
for(idx=0; idx< ndev; idx++) {
|
||||||
|
str = NULL;
|
||||||
|
|
||||||
|
dp = DevicePathFromHandle(dev_tab[idx].dev);
|
||||||
|
if (dp) str = DevicePathToStr(dp);
|
||||||
|
|
||||||
|
str2 = str == NULL ? L"Unknown" : str;
|
||||||
|
|
||||||
|
Print(L"%8s : %-6s : %s\n", dev_tab[idx].name,
|
||||||
|
(dev_tab[idx].fops ? dev_tab[idx].fops->name: L"N/A"), str2);
|
||||||
|
|
||||||
|
if (str) FreePool(str);
|
||||||
|
}
|
||||||
|
Print(L"%d devices available for booting\n", ndev_boot);
|
||||||
|
|
||||||
|
if (boot_dev == NULL) {
|
||||||
|
Print(L"boot device not detected\n");
|
||||||
|
} else {
|
||||||
|
Print(L"boot device %s: %s\n", boot_dev->name,
|
||||||
|
(boot_dev->fops ? boot_dev->fops->name : L"No file access"));
|
||||||
|
}
|
||||||
|
}
|
123
fileops.h
Normal file
123
fileops.h
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* GNU EFI is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* GNU EFI is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU EFI; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FILEOPS_H__
|
||||||
|
#define __FILEOPS_H__
|
||||||
|
|
||||||
|
#define FILEOPS_NAME_MAXLEN 32 /* length of filesystem name */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* upper-level interface used by the bootloader
|
||||||
|
*/
|
||||||
|
typedef UINTN fops_fd_t;
|
||||||
|
|
||||||
|
extern EFI_STATUS fops_open(CHAR16 *name, fops_fd_t *fd);
|
||||||
|
extern EFI_STATUS fops_read(fops_fd_t fd,VOID *buf, UINTN *size);
|
||||||
|
extern EFI_STATUS fops_close(fops_fd_t fd);
|
||||||
|
extern EFI_STATUS fops_infosize(fops_fd_t fd, UINT64 *size);
|
||||||
|
extern EFI_STATUS fops_seek(fops_fd_t fd, UINT64 newpos);
|
||||||
|
extern EFI_STATUS fops_setdefaults(CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath);
|
||||||
|
extern EFI_STATUS fops_getdefault_path(CHAR16 *path, UINTN maxlen);
|
||||||
|
extern CHAR16 *fops_bootdev_name(VOID);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fileops interface used by underlying filesystems layer
|
||||||
|
*/
|
||||||
|
typedef EFI_STATUS (*fops_open_t)(VOID *intf, CHAR16 *name, fops_fd_t *fd);
|
||||||
|
typedef EFI_STATUS (*fops_read_t)(VOID *intf, fops_fd_t fd, VOID *buf, UINTN *size);
|
||||||
|
typedef EFI_STATUS (*fops_close_t)(VOID *intf, fops_fd_t fd);
|
||||||
|
typedef EFI_STATUS (*fops_infosize_t)(VOID *intf, fops_fd_t fd, UINT64 *size);
|
||||||
|
typedef EFI_STATUS (*fops_seek_t)(VOID *intf, fops_fd_t fd, UINT64 newpos);
|
||||||
|
typedef EFI_STATUS (*fops_setdefaults_t)(VOID *intf, CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath);
|
||||||
|
typedef EFI_STATUS (*fops_getdefault_path_t)(CHAR16 *path, UINTN maxlen);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
VOID *intf; /* pointer to underlying interface */
|
||||||
|
|
||||||
|
fops_open_t open;
|
||||||
|
fops_read_t read;
|
||||||
|
fops_close_t close;
|
||||||
|
fops_infosize_t infosize;
|
||||||
|
fops_seek_t seek;
|
||||||
|
fops_setdefaults_t setdefaults;
|
||||||
|
fops_getdefault_path_t getdefault_path;
|
||||||
|
|
||||||
|
EFI_HANDLE dev; /* handle on device on which proto is installed */
|
||||||
|
CHAR16 name[FILEOPS_NAME_MAXLEN];
|
||||||
|
} fileops_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* used to register a new filsystem
|
||||||
|
*/
|
||||||
|
typedef INTN (*fops_fs_glue_t)(fileops_t *this, VOID *intf);
|
||||||
|
typedef EFI_STATUS (*fops_fs_install_t)(VOID);
|
||||||
|
typedef EFI_STATUS (*fops_fs_uninstall_t)(VOID);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EFI_GUID proto; /* GUID of filesystem */
|
||||||
|
fops_fs_glue_t glue; /* glue routine */
|
||||||
|
fops_fs_install_t install; /* to go away with real EFI drivers */
|
||||||
|
fops_fs_uninstall_t uninstall; /* to go away with real EFI drivers */
|
||||||
|
} fileops_fs_t;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* device description
|
||||||
|
*/
|
||||||
|
#define FILEOPS_DEVNAME_MAXLEN 16
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EFI_HANDLE dev;
|
||||||
|
fileops_t *fops;
|
||||||
|
CHAR16 name[FILEOPS_DEVNAME_MAXLEN];
|
||||||
|
} device_t;
|
||||||
|
|
||||||
|
extern INTN init_devices(EFI_HANDLE boot_handle);
|
||||||
|
extern INTN close_devices(VOID);
|
||||||
|
extern VOID print_devices(VOID);
|
||||||
|
extern EFI_STATUS fops_get_next_device(UINTN pidx, CHAR16 *type, UINTN maxlen, UINTN *idx, CHAR16 *name, EFI_HANDLE *dev);
|
||||||
|
extern INTN fops_split_path(CHAR16 *path, CHAR16 *dev);
|
||||||
|
extern EFI_STATUS fops_get_device_handle(CHAR16 *name, EFI_HANDLE *dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* device naming schemes
|
||||||
|
*
|
||||||
|
* Interface:
|
||||||
|
* the scheme() function arguments are:
|
||||||
|
* - the list of detected bootable device
|
||||||
|
* - the number of entries in that table as argument
|
||||||
|
*
|
||||||
|
* There is no expected return value. If the scheme() cannot perform
|
||||||
|
* its tasks, then IT MUST NOT OVERWRITE the generic naming scheme (devXXX) that
|
||||||
|
* is ALWAYS installed by default. Partial modifications are possible, although
|
||||||
|
* not recommended.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
CHAR16 *name;
|
||||||
|
INTN (*install_scheme)(device_t *tab, UINTN ndev);
|
||||||
|
} devname_scheme_t;
|
||||||
|
|
||||||
|
#endif /* __FILEOPS_H__ */
|
70
fs/Makefile
Normal file
70
fs/Makefile
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#
|
||||||
|
# Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
# Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
#
|
||||||
|
# This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
#
|
||||||
|
# ELILO is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# ELILO is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
# Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
# 02111-1307, USA.
|
||||||
|
#
|
||||||
|
# Please check out the elilo.txt for complete documentation on how
|
||||||
|
# to use this program.
|
||||||
|
#
|
||||||
|
|
||||||
|
include ../Make.defaults
|
||||||
|
include ../Make.rules
|
||||||
|
|
||||||
|
TOPDIR=$(CDIR)/..
|
||||||
|
|
||||||
|
FILES=
|
||||||
|
ifeq ($(CONFIG_localfs),y)
|
||||||
|
FILES += localfs.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
# Ext2 is now disabled by default. See top level Makefile
|
||||||
|
# for details
|
||||||
|
#
|
||||||
|
ifeq ($(CONFIG_ext2fs),y)
|
||||||
|
FILES += ext2fs.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_netfs),y)
|
||||||
|
FILES += netfs.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
TARGET=fs.o
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
#
|
||||||
|
# XXX: does not trigger recompile when changing filesystem selection
|
||||||
|
# without doing make clean.
|
||||||
|
#
|
||||||
|
$(TARGET): check-filesystems $(TOPDIR)/Make.defaults $(FILES)
|
||||||
|
$(LD) -r -o $@ $(FILES)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) -f $(TARGET) $(FILES)
|
||||||
|
|
||||||
|
check-filesystems:
|
||||||
|
@if [ -n "$(FILES)" ]; then \
|
||||||
|
exit 0; \
|
||||||
|
else \
|
||||||
|
echo "You need to define at least one filesystem in Make.defaults"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
|
626
fs/ext2_fs.h
Normal file
626
fs/ext2_fs.h
Normal file
|
@ -0,0 +1,626 @@
|
||||||
|
/*
|
||||||
|
* linux/include/linux/ext2_fs.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 1992, 1993, 1994, 1995
|
||||||
|
* Remy Card (card@masi.ibp.fr)
|
||||||
|
* Laboratoire MASI - Institut Blaise Pascal
|
||||||
|
* Universite Pierre et Marie Curie (Paris VI)
|
||||||
|
*
|
||||||
|
* from
|
||||||
|
*
|
||||||
|
* linux/include/linux/minix_fs.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LINUX_EXT2_FS_H
|
||||||
|
#define _LINUX_EXT2_FS_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The second extended filesystem constants/structures
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define EXT2FS_DEBUG to produce debug messages
|
||||||
|
*/
|
||||||
|
#undef EXT2FS_DEBUG
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
|
||||||
|
*/
|
||||||
|
#define EXT2_PREALLOCATE
|
||||||
|
#define EXT2_DEFAULT_PREALLOC_BLOCKS 8
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The second extended file system version
|
||||||
|
*/
|
||||||
|
#define EXT2FS_DATE "95/08/09"
|
||||||
|
#define EXT2FS_VERSION "0.5b"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Debug code
|
||||||
|
*/
|
||||||
|
#ifdef EXT2FS_DEBUG
|
||||||
|
# define ext2_debug(f, a...) { \
|
||||||
|
printk ("EXT2-fs DEBUG (%s, %d): %s:", \
|
||||||
|
__FILE__, __LINE__, __FUNCTION__); \
|
||||||
|
printk (f, ## a); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define ext2_debug(f, a...) /**/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Special inodes numbers
|
||||||
|
*/
|
||||||
|
#define EXT2_BAD_INO 1 /* Bad blocks inode */
|
||||||
|
#define EXT2_ROOT_INO 2 /* Root inode */
|
||||||
|
#define EXT2_ACL_IDX_INO 3 /* ACL inode */
|
||||||
|
#define EXT2_ACL_DATA_INO 4 /* ACL inode */
|
||||||
|
#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
|
||||||
|
#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
|
||||||
|
|
||||||
|
/* First non-reserved inode for old ext2 filesystems */
|
||||||
|
#define EXT2_GOOD_OLD_FIRST_INO 11
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The second extended file system magic number
|
||||||
|
*/
|
||||||
|
#define EXT2_SUPER_MAGIC 0xEF53
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximal count of links to a file
|
||||||
|
*/
|
||||||
|
#define EXT2_LINK_MAX 32000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macro-instructions used to manage several block sizes
|
||||||
|
*/
|
||||||
|
#define EXT2_MIN_BLOCK_SIZE 1024
|
||||||
|
#define EXT2_MAX_BLOCK_SIZE 4096
|
||||||
|
#define EXT2_MIN_BLOCK_LOG_SIZE 10
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
# define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize)
|
||||||
|
#else
|
||||||
|
# define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
|
||||||
|
#endif
|
||||||
|
#define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))
|
||||||
|
#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
|
||||||
|
#else
|
||||||
|
# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
|
||||||
|
#endif
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
#define EXT2_ADDR_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_addr_per_block_bits)
|
||||||
|
#define EXT2_INODE_SIZE(s) ((s)->u.ext2_sb.s_inode_size)
|
||||||
|
#define EXT2_FIRST_INO(s) ((s)->u.ext2_sb.s_first_ino)
|
||||||
|
#else
|
||||||
|
#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
|
||||||
|
EXT2_GOOD_OLD_INODE_SIZE : \
|
||||||
|
(s)->s_inode_size)
|
||||||
|
#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
|
||||||
|
EXT2_GOOD_OLD_FIRST_INO : \
|
||||||
|
(s)->s_first_ino)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macro-instructions used to manage fragments
|
||||||
|
*/
|
||||||
|
#define EXT2_MIN_FRAG_SIZE 1024
|
||||||
|
#define EXT2_MAX_FRAG_SIZE 4096
|
||||||
|
#define EXT2_MIN_FRAG_LOG_SIZE 10
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
# define EXT2_FRAG_SIZE(s) ((s)->u.ext2_sb.s_frag_size)
|
||||||
|
# define EXT2_FRAGS_PER_BLOCK(s) ((s)->u.ext2_sb.s_frags_per_block)
|
||||||
|
#else
|
||||||
|
# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
|
||||||
|
# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ACL structures
|
||||||
|
*/
|
||||||
|
struct ext2_acl_header /* Header of Access Control Lists */
|
||||||
|
{
|
||||||
|
__u32 aclh_size;
|
||||||
|
__u32 aclh_file_count;
|
||||||
|
__u32 aclh_acle_count;
|
||||||
|
__u32 aclh_first_acle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ext2_acl_entry /* Access Control List Entry */
|
||||||
|
{
|
||||||
|
__u32 acle_size;
|
||||||
|
__u16 acle_perms; /* Access permissions */
|
||||||
|
__u16 acle_type; /* Type of entry */
|
||||||
|
__u16 acle_tag; /* User or group identity */
|
||||||
|
__u16 acle_pad1;
|
||||||
|
__u32 acle_next; /* Pointer on next entry for the */
|
||||||
|
/* same inode or on next free entry */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure of a blocks group descriptor
|
||||||
|
*/
|
||||||
|
struct ext2_group_desc
|
||||||
|
{
|
||||||
|
__u32 bg_block_bitmap; /* Blocks bitmap block */
|
||||||
|
__u32 bg_inode_bitmap; /* Inodes bitmap block */
|
||||||
|
__u32 bg_inode_table; /* Inodes table block */
|
||||||
|
__u16 bg_free_blocks_count; /* Free blocks count */
|
||||||
|
__u16 bg_free_inodes_count; /* Free inodes count */
|
||||||
|
__u16 bg_used_dirs_count; /* Directories count */
|
||||||
|
__u16 bg_pad;
|
||||||
|
__u32 bg_reserved[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macro-instructions used to manage group descriptors
|
||||||
|
*/
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
# define EXT2_BLOCKS_PER_GROUP(s) ((s)->u.ext2_sb.s_blocks_per_group)
|
||||||
|
# define EXT2_DESC_PER_BLOCK(s) ((s)->u.ext2_sb.s_desc_per_block)
|
||||||
|
# define EXT2_INODES_PER_GROUP(s) ((s)->u.ext2_sb.s_inodes_per_group)
|
||||||
|
# define EXT2_DESC_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_desc_per_block_bits)
|
||||||
|
#else
|
||||||
|
# define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group)
|
||||||
|
# define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
|
||||||
|
# define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constants relative to the data blocks
|
||||||
|
*/
|
||||||
|
#define EXT2_NDIR_BLOCKS 12
|
||||||
|
#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
|
||||||
|
#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
|
||||||
|
#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
|
||||||
|
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inode flags
|
||||||
|
*/
|
||||||
|
#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */
|
||||||
|
#define EXT2_UNRM_FL 0x00000002 /* Undelete */
|
||||||
|
#define EXT2_COMPR_FL 0x00000004 /* Compress file */
|
||||||
|
#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */
|
||||||
|
#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
|
||||||
|
#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
|
||||||
|
#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
|
||||||
|
#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
|
||||||
|
/* Reserved for compression usage... */
|
||||||
|
#define EXT2_DIRTY_FL 0x00000100
|
||||||
|
#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
|
||||||
|
#define EXT2_NOCOMP_FL 0x00000400 /* Don't compress */
|
||||||
|
#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
|
||||||
|
/* End compression flags --- maybe not all used */
|
||||||
|
#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
|
||||||
|
#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
|
||||||
|
|
||||||
|
#define EXT2_FL_USER_VISIBLE 0x00001FFF /* User visible flags */
|
||||||
|
#define EXT2_FL_USER_MODIFIABLE 0x000000FF /* User modifiable flags */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ioctl commands
|
||||||
|
*/
|
||||||
|
#define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
|
||||||
|
#define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
|
||||||
|
#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
|
||||||
|
#define EXT2_IOC_SETVERSION _IOW('v', 2, long)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure of an inode on the disk
|
||||||
|
*/
|
||||||
|
struct ext2_inode {
|
||||||
|
__u16 i_mode; /* File mode */
|
||||||
|
__u16 i_uid; /* Low 16 bits of Owner Uid */
|
||||||
|
__u32 i_size; /* Size in bytes */
|
||||||
|
__u32 i_atime; /* Access time */
|
||||||
|
__u32 i_ctime; /* Creation time */
|
||||||
|
__u32 i_mtime; /* Modification time */
|
||||||
|
__u32 i_dtime; /* Deletion Time */
|
||||||
|
__u16 i_gid; /* Low 16 bits of Group Id */
|
||||||
|
__u16 i_links_count; /* Links count */
|
||||||
|
__u32 i_blocks; /* Blocks count */
|
||||||
|
__u32 i_flags; /* File flags */
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
__u32 l_i_reserved1;
|
||||||
|
} linux1;
|
||||||
|
struct {
|
||||||
|
__u32 h_i_translator;
|
||||||
|
} hurd1;
|
||||||
|
struct {
|
||||||
|
__u32 m_i_reserved1;
|
||||||
|
} masix1;
|
||||||
|
} osd1; /* OS dependent 1 */
|
||||||
|
__u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
|
||||||
|
__u32 i_generation; /* File version (for NFS) */
|
||||||
|
__u32 i_file_acl; /* File ACL */
|
||||||
|
__u32 i_dir_acl; /* Directory ACL */
|
||||||
|
__u32 i_faddr; /* Fragment address */
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
__u8 l_i_frag; /* Fragment number */
|
||||||
|
__u8 l_i_fsize; /* Fragment size */
|
||||||
|
__u16 i_pad1;
|
||||||
|
__u16 l_i_uid_high; /* these 2 fields */
|
||||||
|
__u16 l_i_gid_high; /* were reserved2[0] */
|
||||||
|
__u32 l_i_reserved2;
|
||||||
|
} linux2;
|
||||||
|
struct {
|
||||||
|
__u8 h_i_frag; /* Fragment number */
|
||||||
|
__u8 h_i_fsize; /* Fragment size */
|
||||||
|
__u16 h_i_mode_high;
|
||||||
|
__u16 h_i_uid_high;
|
||||||
|
__u16 h_i_gid_high;
|
||||||
|
__u32 h_i_author;
|
||||||
|
} hurd2;
|
||||||
|
struct {
|
||||||
|
__u8 m_i_frag; /* Fragment number */
|
||||||
|
__u8 m_i_fsize; /* Fragment size */
|
||||||
|
__u16 m_pad1;
|
||||||
|
__u32 m_i_reserved2[2];
|
||||||
|
} masix2;
|
||||||
|
} osd2; /* OS dependent 2 */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define i_size_high i_dir_acl
|
||||||
|
|
||||||
|
#if defined(__KERNEL__) || defined(__linux__)
|
||||||
|
#define i_reserved1 osd1.linux1.l_i_reserved1
|
||||||
|
#define i_frag osd2.linux2.l_i_frag
|
||||||
|
#define i_fsize osd2.linux2.l_i_fsize
|
||||||
|
#define i_uid_low i_uid
|
||||||
|
#define i_gid_low i_gid
|
||||||
|
#define i_uid_high osd2.linux2.l_i_uid_high
|
||||||
|
#define i_gid_high osd2.linux2.l_i_gid_high
|
||||||
|
#define i_reserved2 osd2.linux2.l_i_reserved2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __hurd__
|
||||||
|
#define i_translator osd1.hurd1.h_i_translator
|
||||||
|
#define i_frag osd2.hurd2.h_i_frag;
|
||||||
|
#define i_fsize osd2.hurd2.h_i_fsize;
|
||||||
|
#define i_uid_high osd2.hurd2.h_i_uid_high
|
||||||
|
#define i_gid_high osd2.hurd2.h_i_gid_high
|
||||||
|
#define i_author osd2.hurd2.h_i_author
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __masix__
|
||||||
|
#define i_reserved1 osd1.masix1.m_i_reserved1
|
||||||
|
#define i_frag osd2.masix2.m_i_frag
|
||||||
|
#define i_fsize osd2.masix2.m_i_fsize
|
||||||
|
#define i_reserved2 osd2.masix2.m_i_reserved2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File system states
|
||||||
|
*/
|
||||||
|
#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */
|
||||||
|
#define EXT2_ERROR_FS 0x0002 /* Errors detected */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mount flags
|
||||||
|
*/
|
||||||
|
#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */
|
||||||
|
#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
|
||||||
|
#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
|
||||||
|
#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
|
||||||
|
#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
|
||||||
|
#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
|
||||||
|
#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
|
||||||
|
#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */
|
||||||
|
|
||||||
|
#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
|
||||||
|
#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
|
||||||
|
#define test_opt(sb, opt) ((sb)->u.ext2_sb.s_mount_opt & \
|
||||||
|
EXT2_MOUNT_##opt)
|
||||||
|
/*
|
||||||
|
* Maximal mount counts between two filesystem checks
|
||||||
|
*/
|
||||||
|
#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
|
||||||
|
#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Behaviour when detecting errors
|
||||||
|
*/
|
||||||
|
#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
|
||||||
|
#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
|
||||||
|
#define EXT2_ERRORS_PANIC 3 /* Panic */
|
||||||
|
#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure of the super block
|
||||||
|
*/
|
||||||
|
struct ext2_super_block {
|
||||||
|
__u32 s_inodes_count; /* Inodes count */
|
||||||
|
__u32 s_blocks_count; /* Blocks count */
|
||||||
|
__u32 s_r_blocks_count; /* Reserved blocks count */
|
||||||
|
__u32 s_free_blocks_count; /* Free blocks count */
|
||||||
|
__u32 s_free_inodes_count; /* Free inodes count */
|
||||||
|
__u32 s_first_data_block; /* First Data Block */
|
||||||
|
__u32 s_log_block_size; /* Block size */
|
||||||
|
__s32 s_log_frag_size; /* Fragment size */
|
||||||
|
__u32 s_blocks_per_group; /* # Blocks per group */
|
||||||
|
__u32 s_frags_per_group; /* # Fragments per group */
|
||||||
|
__u32 s_inodes_per_group; /* # Inodes per group */
|
||||||
|
__u32 s_mtime; /* Mount time */
|
||||||
|
__u32 s_wtime; /* Write time */
|
||||||
|
__u16 s_mnt_count; /* Mount count */
|
||||||
|
__s16 s_max_mnt_count; /* Maximal mount count */
|
||||||
|
__u16 s_magic; /* Magic signature */
|
||||||
|
__u16 s_state; /* File system state */
|
||||||
|
__u16 s_errors; /* Behaviour when detecting errors */
|
||||||
|
__u16 s_minor_rev_level; /* minor revision level */
|
||||||
|
__u32 s_lastcheck; /* time of last check */
|
||||||
|
__u32 s_checkinterval; /* max. time between checks */
|
||||||
|
__u32 s_creator_os; /* OS */
|
||||||
|
__u32 s_rev_level; /* Revision level */
|
||||||
|
__u16 s_def_resuid; /* Default uid for reserved blocks */
|
||||||
|
__u16 s_def_resgid; /* Default gid for reserved blocks */
|
||||||
|
/*
|
||||||
|
* These fields are for EXT2_DYNAMIC_REV superblocks only.
|
||||||
|
*
|
||||||
|
* Note: the difference between the compatible feature set and
|
||||||
|
* the incompatible feature set is that if there is a bit set
|
||||||
|
* in the incompatible feature set that the kernel doesn't
|
||||||
|
* know about, it should refuse to mount the filesystem.
|
||||||
|
*
|
||||||
|
* e2fsck's requirements are more strict; if it doesn't know
|
||||||
|
* about a feature in either the compatible or incompatible
|
||||||
|
* feature set, it must abort and not try to meddle with
|
||||||
|
* things it doesn't understand...
|
||||||
|
*/
|
||||||
|
__u32 s_first_ino; /* First non-reserved inode */
|
||||||
|
__u16 s_inode_size; /* size of inode structure */
|
||||||
|
__u16 s_block_group_nr; /* block group # of this superblock */
|
||||||
|
__u32 s_feature_compat; /* compatible feature set */
|
||||||
|
__u32 s_feature_incompat; /* incompatible feature set */
|
||||||
|
__u32 s_feature_ro_compat; /* readonly-compatible feature set */
|
||||||
|
__u8 s_uuid[16]; /* 128-bit uuid for volume */
|
||||||
|
char s_volume_name[16]; /* volume name */
|
||||||
|
char s_last_mounted[64]; /* directory where last mounted */
|
||||||
|
__u32 s_algorithm_usage_bitmap; /* For compression */
|
||||||
|
/*
|
||||||
|
* Performance hints. Directory preallocation should only
|
||||||
|
* happen if the EXT2_COMPAT_PREALLOC flag is on.
|
||||||
|
*/
|
||||||
|
__u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
|
||||||
|
__u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
|
||||||
|
__u16 s_padding1;
|
||||||
|
__u32 s_reserved[204]; /* Padding to the end of the block */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
#define EXT2_SB(sb) (&((sb)->u.ext2_sb))
|
||||||
|
#else
|
||||||
|
/* Assume that user mode programs are passing in an ext2fs superblock, not
|
||||||
|
* a kernel struct super_block. This will allow us to call the feature-test
|
||||||
|
* macros from user land. */
|
||||||
|
#define EXT2_SB(sb) (sb)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Codes for operating systems
|
||||||
|
*/
|
||||||
|
#define EXT2_OS_LINUX 0
|
||||||
|
#define EXT2_OS_HURD 1
|
||||||
|
#define EXT2_OS_MASIX 2
|
||||||
|
#define EXT2_OS_FREEBSD 3
|
||||||
|
#define EXT2_OS_LITES 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Revision levels
|
||||||
|
*/
|
||||||
|
#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
|
||||||
|
#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
|
||||||
|
|
||||||
|
#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV
|
||||||
|
#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV
|
||||||
|
|
||||||
|
#define EXT2_GOOD_OLD_INODE_SIZE 128
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Feature set definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
|
||||||
|
( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
|
||||||
|
#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
|
||||||
|
( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
|
||||||
|
#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
|
||||||
|
( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
|
||||||
|
#define EXT2_SET_COMPAT_FEATURE(sb,mask) \
|
||||||
|
EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
|
||||||
|
#define EXT2_SET_RO_COMPAT_FEATURE(sb,mask) \
|
||||||
|
EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
|
||||||
|
#define EXT2_SET_INCOMPAT_FEATURE(sb,mask) \
|
||||||
|
EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
|
||||||
|
#define EXT2_CLEAR_COMPAT_FEATURE(sb,mask) \
|
||||||
|
EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
|
||||||
|
#define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask) \
|
||||||
|
EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
|
||||||
|
#define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask) \
|
||||||
|
EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
|
||||||
|
|
||||||
|
#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
|
||||||
|
|
||||||
|
#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
|
||||||
|
#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
|
||||||
|
#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
|
||||||
|
|
||||||
|
#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
|
||||||
|
#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
|
||||||
|
|
||||||
|
#define EXT2_FEATURE_COMPAT_SUPP 0
|
||||||
|
#define EXT2_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_FILETYPE
|
||||||
|
#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
|
||||||
|
EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
|
||||||
|
EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default values for user and/or group using reserved blocks
|
||||||
|
*/
|
||||||
|
#define EXT2_DEF_RESUID 0
|
||||||
|
#define EXT2_DEF_RESGID 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure of a directory entry
|
||||||
|
*/
|
||||||
|
#define EXT2_NAME_LEN 255
|
||||||
|
|
||||||
|
struct ext2_dir_entry {
|
||||||
|
__u32 inode; /* Inode number */
|
||||||
|
__u16 rec_len; /* Directory entry length */
|
||||||
|
__u16 name_len; /* Name length */
|
||||||
|
char name[EXT2_NAME_LEN]; /* File name */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The new version of the directory entry. Since EXT2 structures are
|
||||||
|
* stored in intel byte order, and the name_len field could never be
|
||||||
|
* bigger than 255 chars, it's safe to reclaim the extra byte for the
|
||||||
|
* file_type field.
|
||||||
|
*/
|
||||||
|
struct ext2_dir_entry_2 {
|
||||||
|
__u32 inode; /* Inode number */
|
||||||
|
__u16 rec_len; /* Directory entry length */
|
||||||
|
__u8 name_len; /* Name length */
|
||||||
|
__u8 file_type;
|
||||||
|
char name[EXT2_NAME_LEN]; /* File name */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ext2 directory file types. Only the low 3 bits are used. The
|
||||||
|
* other bits are reserved for now.
|
||||||
|
*/
|
||||||
|
#define EXT2_FT_UNKNOWN 0
|
||||||
|
#define EXT2_FT_REG_FILE 1
|
||||||
|
#define EXT2_FT_DIR 2
|
||||||
|
#define EXT2_FT_CHRDEV 3
|
||||||
|
#define EXT2_FT_BLKDEV 4
|
||||||
|
#define EXT2_FT_FIFO 5
|
||||||
|
#define EXT2_FT_SOCK 6
|
||||||
|
#define EXT2_FT_SYMLINK 7
|
||||||
|
|
||||||
|
#define EXT2_FT_MAX 8
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EXT2_DIR_PAD defines the directory entries boundaries
|
||||||
|
*
|
||||||
|
* NOTE: It must be a multiple of 4
|
||||||
|
*/
|
||||||
|
#define EXT2_DIR_PAD 4
|
||||||
|
#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
|
||||||
|
#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
|
||||||
|
~EXT2_DIR_ROUND)
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
/*
|
||||||
|
* Function prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ok, these declarations are also in <linux/kernel.h> but none of the
|
||||||
|
* ext2 source programs needs to include it so they are duplicated here.
|
||||||
|
*/
|
||||||
|
# define NORET_TYPE /**/
|
||||||
|
# define ATTRIB_NORET __attribute__((noreturn))
|
||||||
|
# define NORET_AND noreturn,
|
||||||
|
|
||||||
|
/* acl.c */
|
||||||
|
extern int ext2_permission (struct inode *, int);
|
||||||
|
|
||||||
|
/* balloc.c */
|
||||||
|
extern int ext2_bg_has_super(struct super_block *sb, int group);
|
||||||
|
extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group);
|
||||||
|
extern int ext2_new_block (const struct inode *, unsigned long,
|
||||||
|
__u32 *, __u32 *, int *);
|
||||||
|
extern void ext2_free_blocks (const struct inode *, unsigned long,
|
||||||
|
unsigned long);
|
||||||
|
extern unsigned long ext2_count_free_blocks (struct super_block *);
|
||||||
|
extern void ext2_check_blocks_bitmap (struct super_block *);
|
||||||
|
extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
|
||||||
|
unsigned int block_group,
|
||||||
|
struct buffer_head ** bh);
|
||||||
|
|
||||||
|
/* bitmap.c */
|
||||||
|
extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
|
||||||
|
|
||||||
|
/* dir.c */
|
||||||
|
extern int ext2_check_dir_entry (const char *, struct inode *,
|
||||||
|
struct ext2_dir_entry_2 *, struct buffer_head *,
|
||||||
|
unsigned long);
|
||||||
|
|
||||||
|
/* file.c */
|
||||||
|
extern int ext2_read (struct inode *, struct file *, char *, int);
|
||||||
|
extern int ext2_write (struct inode *, struct file *, char *, int);
|
||||||
|
|
||||||
|
/* fsync.c */
|
||||||
|
extern int ext2_sync_file (struct file *, struct dentry *, int);
|
||||||
|
extern int ext2_fsync_inode (struct inode *, int);
|
||||||
|
|
||||||
|
/* ialloc.c */
|
||||||
|
extern struct inode * ext2_new_inode (const struct inode *, int);
|
||||||
|
extern void ext2_free_inode (struct inode *);
|
||||||
|
extern unsigned long ext2_count_free_inodes (struct super_block *);
|
||||||
|
extern void ext2_check_inodes_bitmap (struct super_block *);
|
||||||
|
|
||||||
|
/* inode.c */
|
||||||
|
|
||||||
|
extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *);
|
||||||
|
extern struct buffer_head * ext2_bread (struct inode *, int, int, int *);
|
||||||
|
|
||||||
|
extern void ext2_read_inode (struct inode *);
|
||||||
|
extern void ext2_write_inode (struct inode *, int);
|
||||||
|
extern void ext2_put_inode (struct inode *);
|
||||||
|
extern void ext2_delete_inode (struct inode *);
|
||||||
|
extern int ext2_sync_inode (struct inode *);
|
||||||
|
extern void ext2_discard_prealloc (struct inode *);
|
||||||
|
|
||||||
|
/* ioctl.c */
|
||||||
|
extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
|
||||||
|
unsigned long);
|
||||||
|
|
||||||
|
/* namei.c */
|
||||||
|
extern struct inode_operations ext2_dir_inode_operations;
|
||||||
|
|
||||||
|
/* super.c */
|
||||||
|
extern void ext2_error (struct super_block *, const char *, const char *, ...)
|
||||||
|
__attribute__ ((format (printf, 3, 4)));
|
||||||
|
extern NORET_TYPE void ext2_panic (struct super_block *, const char *,
|
||||||
|
const char *, ...)
|
||||||
|
__attribute__ ((NORET_AND format (printf, 3, 4)));
|
||||||
|
extern void ext2_warning (struct super_block *, const char *, const char *, ...)
|
||||||
|
__attribute__ ((format (printf, 3, 4)));
|
||||||
|
extern void ext2_update_dynamic_rev (struct super_block *sb);
|
||||||
|
extern void ext2_put_super (struct super_block *);
|
||||||
|
extern void ext2_write_super (struct super_block *);
|
||||||
|
extern int ext2_remount (struct super_block *, int *, char *);
|
||||||
|
extern struct super_block * ext2_read_super (struct super_block *,void *,int);
|
||||||
|
extern int ext2_statfs (struct super_block *, struct statfs *);
|
||||||
|
|
||||||
|
/* truncate.c */
|
||||||
|
extern void ext2_truncate (struct inode *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inodes and files operations
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* dir.c */
|
||||||
|
extern struct file_operations ext2_dir_operations;
|
||||||
|
|
||||||
|
/* file.c */
|
||||||
|
extern struct inode_operations ext2_file_inode_operations;
|
||||||
|
extern struct file_operations ext2_file_operations;
|
||||||
|
|
||||||
|
/* symlink.c */
|
||||||
|
extern struct inode_operations ext2_fast_symlink_inode_operations;
|
||||||
|
|
||||||
|
extern struct address_space_operations ext2_aops;
|
||||||
|
|
||||||
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
|
#endif /* _LINUX_EXT2_FS_H */
|
42
fs/ext2_fs_i.h
Normal file
42
fs/ext2_fs_i.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* linux/include/linux/ext2_fs_i.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 1992, 1993, 1994, 1995
|
||||||
|
* Remy Card (card@masi.ibp.fr)
|
||||||
|
* Laboratoire MASI - Institut Blaise Pascal
|
||||||
|
* Universite Pierre et Marie Curie (Paris VI)
|
||||||
|
*
|
||||||
|
* from
|
||||||
|
*
|
||||||
|
* linux/include/linux/minix_fs_i.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LINUX_EXT2_FS_I
|
||||||
|
#define _LINUX_EXT2_FS_I
|
||||||
|
|
||||||
|
/*
|
||||||
|
* second extended file system inode data in memory
|
||||||
|
*/
|
||||||
|
struct ext2_inode_info {
|
||||||
|
__u32 i_data[15];
|
||||||
|
__u32 i_flags;
|
||||||
|
__u32 i_faddr;
|
||||||
|
__u8 i_frag_no;
|
||||||
|
__u8 i_frag_size;
|
||||||
|
__u16 i_osync;
|
||||||
|
__u32 i_file_acl;
|
||||||
|
__u32 i_dir_acl;
|
||||||
|
__u32 i_dtime;
|
||||||
|
__u32 not_used_1; /* FIX: not used/ 2.2 placeholder */
|
||||||
|
__u32 i_block_group;
|
||||||
|
__u32 i_next_alloc_block;
|
||||||
|
__u32 i_next_alloc_goal;
|
||||||
|
__u32 i_prealloc_block;
|
||||||
|
__u32 i_prealloc_count;
|
||||||
|
__u32 i_high_size;
|
||||||
|
int i_new_inode:1; /* Is a freshly allocated inode */
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _LINUX_EXT2_FS_I */
|
61
fs/ext2_fs_sb.h
Normal file
61
fs/ext2_fs_sb.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* linux/include/linux/ext2_fs_sb.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 1992, 1993, 1994, 1995
|
||||||
|
* Remy Card (card@masi.ibp.fr)
|
||||||
|
* Laboratoire MASI - Institut Blaise Pascal
|
||||||
|
* Universite Pierre et Marie Curie (Paris VI)
|
||||||
|
*
|
||||||
|
* from
|
||||||
|
*
|
||||||
|
* linux/include/linux/minix_fs_sb.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LINUX_EXT2_FS_SB
|
||||||
|
#define _LINUX_EXT2_FS_SB
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following is not needed anymore since the descriptors buffer
|
||||||
|
* heads are now dynamically allocated
|
||||||
|
*/
|
||||||
|
/* #define EXT2_MAX_GROUP_DESC 8 */
|
||||||
|
|
||||||
|
#define EXT2_MAX_GROUP_LOADED 8
|
||||||
|
|
||||||
|
/*
|
||||||
|
* second extended-fs super-block data in memory
|
||||||
|
*/
|
||||||
|
struct ext2_sb_info {
|
||||||
|
unsigned long s_frag_size; /* Size of a fragment in bytes */
|
||||||
|
unsigned long s_frags_per_block;/* Number of fragments per block */
|
||||||
|
unsigned long s_inodes_per_block;/* Number of inodes per block */
|
||||||
|
unsigned long s_frags_per_group;/* Number of fragments in a group */
|
||||||
|
unsigned long s_blocks_per_group;/* Number of blocks in a group */
|
||||||
|
unsigned long s_inodes_per_group;/* Number of inodes in a group */
|
||||||
|
unsigned long s_itb_per_group; /* Number of inode table blocks per group */
|
||||||
|
unsigned long s_gdb_count; /* Number of group descriptor blocks */
|
||||||
|
unsigned long s_desc_per_block; /* Number of group descriptors per block */
|
||||||
|
unsigned long s_groups_count; /* Number of groups in the fs */
|
||||||
|
struct buffer_head * s_sbh; /* Buffer containing the super block */
|
||||||
|
struct ext2_super_block * s_es; /* Pointer to the super block in the buffer */
|
||||||
|
struct buffer_head ** s_group_desc;
|
||||||
|
unsigned short s_loaded_inode_bitmaps;
|
||||||
|
unsigned short s_loaded_block_bitmaps;
|
||||||
|
unsigned long s_inode_bitmap_number[EXT2_MAX_GROUP_LOADED];
|
||||||
|
struct buffer_head * s_inode_bitmap[EXT2_MAX_GROUP_LOADED];
|
||||||
|
unsigned long s_block_bitmap_number[EXT2_MAX_GROUP_LOADED];
|
||||||
|
struct buffer_head * s_block_bitmap[EXT2_MAX_GROUP_LOADED];
|
||||||
|
unsigned long s_mount_opt;
|
||||||
|
uid_t s_resuid;
|
||||||
|
gid_t s_resgid;
|
||||||
|
unsigned short s_mount_state;
|
||||||
|
unsigned short s_pad;
|
||||||
|
int s_addr_per_block_bits;
|
||||||
|
int s_desc_per_block_bits;
|
||||||
|
int s_inode_size;
|
||||||
|
int s_first_ino;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _LINUX_EXT2_FS_SB */
|
70
fs/ext2_private.h
Normal file
70
fs/ext2_private.h
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FS_EXT2FS_PRIVATE_H__
|
||||||
|
#define __FS_EXT2FS_PRIVATE_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implement the Linux kernel internal data types
|
||||||
|
* used by ext2
|
||||||
|
*/
|
||||||
|
typedef UINT32 __u32;
|
||||||
|
typedef INT32 __s32;
|
||||||
|
typedef UINT16 __u16;
|
||||||
|
typedef INT16 __s16;
|
||||||
|
typedef UINT8 __u8;
|
||||||
|
typedef INT8 __s8;
|
||||||
|
typedef UINT32 uid_t;
|
||||||
|
typedef UINT32 gid_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get some constant from linux/stat.h
|
||||||
|
*/
|
||||||
|
#define S_IFMT 00170000
|
||||||
|
#define S_IFSOCK 0140000
|
||||||
|
#define S_IFLNK 0120000
|
||||||
|
#define S_IFREG 0100000
|
||||||
|
#define S_IFBLK 0060000
|
||||||
|
#define S_IFDIR 0040000
|
||||||
|
#define S_IFCHR 0020000
|
||||||
|
#define S_IFIFO 0010000
|
||||||
|
#define S_ISUID 0004000
|
||||||
|
#define S_ISGID 0002000
|
||||||
|
#define S_ISVTX 0001000
|
||||||
|
|
||||||
|
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
|
||||||
|
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||||
|
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||||
|
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
|
||||||
|
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
|
||||||
|
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
|
||||||
|
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
|
||||||
|
|
||||||
|
|
||||||
|
#include "fs/ext2_fs.h"
|
||||||
|
#include "fs/ext2_fs_sb.h"
|
||||||
|
#include "fs/ext2_fs_i.h"
|
||||||
|
|
||||||
|
#endif /* __FS_EXT2FS_PRIVATE_H__*/
|
1004
fs/ext2fs.c
Normal file
1004
fs/ext2fs.c
Normal file
File diff suppressed because it is too large
Load diff
63
fs/ext2fs.h
Normal file
63
fs/ext2fs.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
#ifndef __EXT2FS_H__
|
||||||
|
#define __EXT2FS_H__
|
||||||
|
|
||||||
|
INTERFACE_DECL(_ext2fs_interface_t);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* simplified stat structure
|
||||||
|
* XXX: need to cleanup types !
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
unsigned long st_ino;
|
||||||
|
unsigned long st_nlink;
|
||||||
|
unsigned int st_mode;
|
||||||
|
unsigned int st_uid;
|
||||||
|
unsigned int st_gid;
|
||||||
|
unsigned long st_size;
|
||||||
|
unsigned long st_atime;
|
||||||
|
unsigned long st_mtime;
|
||||||
|
unsigned long st_ctime;
|
||||||
|
} ext2fs_stat_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _ext2fs_interface_t {
|
||||||
|
EFI_STATUS (*ext2fs_name)(struct _ext2fs_interface_t *this, CHAR16 *name, UINTN maxlen);
|
||||||
|
EFI_STATUS (*ext2fs_open)(struct _ext2fs_interface_t *this, CHAR16 *name, UINTN *fd);
|
||||||
|
EFI_STATUS (*ext2fs_read)(struct _ext2fs_interface_t *this, UINTN fd, VOID *buf, UINTN *size);
|
||||||
|
EFI_STATUS (*ext2fs_close)(struct _ext2fs_interface_t *this, UINTN fd);
|
||||||
|
EFI_STATUS (*ext2fs_fstat)(struct _ext2fs_interface_t *this, UINTN fd, ext2fs_stat_t *st);
|
||||||
|
EFI_STATUS (*ext2fs_seek)(struct _ext2fs_interface_t *this, UINTN fd, UINT64 newpos);
|
||||||
|
} ext2fs_interface_t;
|
||||||
|
|
||||||
|
#define EXT2FS_PROTOCOL \
|
||||||
|
{ 0x6ea924f6, 0xc9f2, 0x4331, {0x83, 0x54, 0x19, 0xd0, 0x17, 0x50, 0xd9, 0xc7} }
|
||||||
|
|
||||||
|
extern EFI_STATUS ext2fs_install(VOID);
|
||||||
|
extern EFI_STATUS ext2fs_uninstall(VOID);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __EXT2FS_H__ */
|
297
fs/localfs.c
Normal file
297
fs/localfs.c
Normal file
|
@ -0,0 +1,297 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
#include "fs/localfs.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LocalFS is just a shim layer on top of the
|
||||||
|
* FileSystem Protocol which gives access to FAT32,16,12
|
||||||
|
*/
|
||||||
|
#define FS_NAME L"vfat"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EFI_HANDLE dev; /* device we're attached to */
|
||||||
|
EFI_FILE_HANDLE volume; /* root of volume */
|
||||||
|
} localfs_priv_state_t;
|
||||||
|
|
||||||
|
#define LOCALFS_F2FD(f) ((UINTN)(f))
|
||||||
|
#define LOCALFS_FD2F(fd) ((EFI_FILE_HANDLE)(fd))
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
localfs_interface_t pub_intf;
|
||||||
|
struct {
|
||||||
|
localfs_interface_t pub_intf;
|
||||||
|
localfs_priv_state_t priv_data;
|
||||||
|
} localfs_priv;
|
||||||
|
} localfs_t;
|
||||||
|
|
||||||
|
#define FS_PRIVATE(n) (&(((localfs_t *)n)->localfs_priv.priv_data))
|
||||||
|
|
||||||
|
|
||||||
|
static EFI_GUID LocalFsProtocol = LOCALFS_PROTOCOL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* let's be clean here
|
||||||
|
*/
|
||||||
|
typedef union {
|
||||||
|
EFI_HANDLE *dev;
|
||||||
|
localfs_t *intf;
|
||||||
|
} dev_tab_t;
|
||||||
|
|
||||||
|
static dev_tab_t *dev_tab; /* holds all devices we found */
|
||||||
|
static UINTN ndev; /* how many entries in dev_tab */
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
localfs_name(localfs_interface_t *this, CHAR16 *name, UINTN maxlen)
|
||||||
|
{
|
||||||
|
if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
StrnCpy(name, FS_NAME, maxlen-1);
|
||||||
|
|
||||||
|
name[maxlen-1] = CHAR_NULL;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
localfs_open(localfs_interface_t *this, CHAR16 *name, UINTN *fd)
|
||||||
|
{
|
||||||
|
localfs_priv_state_t *lfs;
|
||||||
|
EFI_STATUS status;
|
||||||
|
EFI_FILE_HANDLE fh;
|
||||||
|
|
||||||
|
if (this == NULL || name == NULL || fd == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
lfs = FS_PRIVATE(this);
|
||||||
|
|
||||||
|
DBG_PRT((L"localfs_open on %s\n", name));
|
||||||
|
|
||||||
|
status = lfs->volume->Open(lfs->volume, &fh, name, EFI_FILE_MODE_READ, 0);
|
||||||
|
if (status == EFI_SUCCESS) {
|
||||||
|
*fd = LOCALFS_F2FD(fh);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
localfs_read(localfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size)
|
||||||
|
{
|
||||||
|
localfs_priv_state_t *lfs;
|
||||||
|
|
||||||
|
if (this == NULL || fd == 0 || buf == NULL || size == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
lfs = FS_PRIVATE(this);
|
||||||
|
|
||||||
|
return lfs->volume->Read(LOCALFS_FD2F(fd), size, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
localfs_close(localfs_interface_t *this, UINTN fd)
|
||||||
|
{
|
||||||
|
localfs_priv_state_t *lfs;
|
||||||
|
|
||||||
|
if (this == NULL || fd == 0) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
lfs = FS_PRIVATE(this);
|
||||||
|
|
||||||
|
return lfs->volume->Close(LOCALFS_FD2F(fd));
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
localfs_infosize(localfs_interface_t *this, UINTN fd, UINT64 *sz)
|
||||||
|
{
|
||||||
|
localfs_priv_state_t *lfs;
|
||||||
|
EFI_FILE_INFO *info;
|
||||||
|
|
||||||
|
if (this == NULL || fd == 0 || sz == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
lfs = FS_PRIVATE(this);
|
||||||
|
|
||||||
|
info = LibFileInfo(LOCALFS_FD2F(fd));
|
||||||
|
if (info == NULL) return EFI_UNSUPPORTED;
|
||||||
|
|
||||||
|
*sz = info->FileSize;
|
||||||
|
|
||||||
|
FreePool(info);
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
localfs_seek(localfs_interface_t *this, UINTN fd, UINT64 newpos)
|
||||||
|
{
|
||||||
|
localfs_priv_state_t *lfs;
|
||||||
|
|
||||||
|
if (this == NULL || fd == 0) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
lfs = FS_PRIVATE(this);
|
||||||
|
|
||||||
|
return lfs->volume->SetPosition(LOCALFS_FD2F(fd), newpos);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
localfs_init_state(localfs_t *localfs, EFI_HANDLE dev, EFI_FILE_HANDLE volume)
|
||||||
|
{
|
||||||
|
localfs_priv_state_t *lfs = FS_PRIVATE(localfs);
|
||||||
|
|
||||||
|
/* need to do some init here on localfs_intf */
|
||||||
|
Memset(localfs, 0, sizeof(*localfs));
|
||||||
|
|
||||||
|
localfs->pub_intf.localfs_name = localfs_name;
|
||||||
|
localfs->pub_intf.localfs_open = localfs_open;
|
||||||
|
localfs->pub_intf.localfs_read = localfs_read;
|
||||||
|
localfs->pub_intf.localfs_close = localfs_close;
|
||||||
|
localfs->pub_intf.localfs_infosize = localfs_infosize;
|
||||||
|
localfs->pub_intf.localfs_seek = localfs_seek;
|
||||||
|
|
||||||
|
lfs->dev = dev;
|
||||||
|
lfs->volume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
localfs_install_one(EFI_HANDLE dev, VOID **intf)
|
||||||
|
{
|
||||||
|
|
||||||
|
EFI_STATUS status;
|
||||||
|
localfs_t *localfs;
|
||||||
|
EFI_FILE_IO_INTERFACE *volume;
|
||||||
|
EFI_FILE_HANDLE volume_fh;
|
||||||
|
|
||||||
|
status = BS->HandleProtocol (dev, &LocalFsProtocol, (VOID **)&localfs);
|
||||||
|
if (status == EFI_SUCCESS) {
|
||||||
|
ERR_PRT((L"Warning: found existing %s protocol on device", FS_NAME));
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = BS->HandleProtocol (dev, &FileSystemProtocol, (VOID **)&volume);
|
||||||
|
if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
status = volume->OpenVolume(volume, &volume_fh);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"cannot open volume"));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
localfs = (localfs_t *)alloc(sizeof(*localfs), EfiLoaderData);
|
||||||
|
if (localfs == NULL) {
|
||||||
|
ERR_PRT((L"failed to allocate %s", FS_NAME));
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
localfs_init_state(localfs, dev, volume_fh);
|
||||||
|
|
||||||
|
status = LibInstallProtocolInterfaces(&dev, &LocalFsProtocol, localfs, NULL);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"Cannot install %s protocol: %r", FS_NAME, status));
|
||||||
|
free(localfs);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
found:
|
||||||
|
if (intf) *intf = (VOID *)localfs;
|
||||||
|
|
||||||
|
VERB_PRT(3,
|
||||||
|
{ EFI_DEVICE_PATH *dp; CHAR16 *str;
|
||||||
|
dp = DevicePathFromHandle(dev);
|
||||||
|
str = DevicePathToStr(dp);
|
||||||
|
Print(L"attached %s to %s\n", FS_NAME, str);
|
||||||
|
FreePool(str);
|
||||||
|
});
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
localfs_install(VOID)
|
||||||
|
{
|
||||||
|
UINTN size = 0;
|
||||||
|
UINTN i;
|
||||||
|
EFI_STATUS status;
|
||||||
|
VOID *intf;
|
||||||
|
|
||||||
|
BS->LocateHandle(ByProtocol, &FileSystemProtocol, NULL, &size, NULL);
|
||||||
|
if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */
|
||||||
|
|
||||||
|
DBG_PRT((L"size=%d", size));
|
||||||
|
|
||||||
|
dev_tab = (dev_tab_t *)alloc(size, EfiLoaderData);
|
||||||
|
if (dev_tab == NULL) {
|
||||||
|
ERR_PRT((L"failed to allocate handle table"));
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = BS->LocateHandle(ByProtocol, &FileSystemProtocol, NULL, &size, (VOID **)dev_tab);
|
||||||
|
if (status != EFI_SUCCESS) {
|
||||||
|
ERR_PRT((L"failed to get handles: %r", status));
|
||||||
|
free(dev_tab);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
ndev = size / sizeof(EFI_HANDLE);
|
||||||
|
|
||||||
|
for(i=0; i < ndev; i++) {
|
||||||
|
intf = NULL;
|
||||||
|
localfs_install_one(dev_tab[i].dev, &intf);
|
||||||
|
/* override device handle with interface pointer */
|
||||||
|
dev_tab[i].intf = intf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
localfs_uninstall(VOID)
|
||||||
|
{
|
||||||
|
|
||||||
|
localfs_priv_state_t *lfs;
|
||||||
|
EFI_STATUS status;
|
||||||
|
UINTN i;
|
||||||
|
|
||||||
|
for(i=0; i < ndev; i++) {
|
||||||
|
if (dev_tab[i].intf == NULL) continue;
|
||||||
|
lfs = FS_PRIVATE(dev_tab[i].intf);
|
||||||
|
status = BS->UninstallProtocolInterface(lfs->dev, &LocalFsProtocol, dev_tab[i].intf);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
VERB_PRT(3,
|
||||||
|
{ EFI_DEVICE_PATH *dp; CHAR16 *str;
|
||||||
|
dp = DevicePathFromHandle(lfs->dev);
|
||||||
|
str = DevicePathToStr(dp);
|
||||||
|
Print(L"uninstalled %s on %s\n", FS_NAME, str);
|
||||||
|
FreePool(str);
|
||||||
|
});
|
||||||
|
free(dev_tab[i].intf);
|
||||||
|
}
|
||||||
|
if (dev_tab) free(dev_tab);
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
46
fs/localfs.h
Normal file
46
fs/localfs.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LOCALFS_H__
|
||||||
|
#define __LOCALFS_H__
|
||||||
|
|
||||||
|
INTERFACE_DECL(_localfs_interface_t);
|
||||||
|
|
||||||
|
typedef struct _localfs_interface_t {
|
||||||
|
EFI_STATUS (*localfs_name)(struct _localfs_interface_t *this, CHAR16 *name, UINTN maxlen);
|
||||||
|
EFI_STATUS (*localfs_open)(struct _localfs_interface_t *this, CHAR16 *name, UINTN *fd);
|
||||||
|
EFI_STATUS (*localfs_read)(struct _localfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size);
|
||||||
|
EFI_STATUS (*localfs_close)(struct _localfs_interface_t *this, UINTN fd);
|
||||||
|
EFI_STATUS (*localfs_infosize)(struct _localfs_interface_t *this, UINTN fd, UINT64 *size);
|
||||||
|
EFI_STATUS (*localfs_seek)(struct _localfs_interface_t *this, UINTN fd, UINT64 newpos);
|
||||||
|
} localfs_interface_t;
|
||||||
|
|
||||||
|
#define LOCALFS_PROTOCOL \
|
||||||
|
{ 0x3a42ff5d, 0x43c9, 0x4db8, {0x82, 0x4e, 0xb8, 0x5b, 0xab, 0x97, 0x63, 0xcc} }
|
||||||
|
|
||||||
|
extern EFI_STATUS localfs_install(VOID);
|
||||||
|
extern EFI_STATUS localfs_uninstall(VOID);
|
||||||
|
|
||||||
|
#endif /* __LOCALFS_H__ */
|
790
fs/netfs.c
Normal file
790
fs/netfs.c
Normal file
|
@ -0,0 +1,790 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "fs/netfs.h"
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
|
||||||
|
#define FS_NAME L"netfs"
|
||||||
|
|
||||||
|
#define NETFS_DEFAULT_BUFSIZE 16*MB
|
||||||
|
#define NETFS_DEFAULT_BUFSIZE_INC 8*MB
|
||||||
|
|
||||||
|
#define NETFS_DEFAULT_SERVER_TYPE EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP
|
||||||
|
#define NETFS_FD_MAX 2
|
||||||
|
|
||||||
|
typedef struct _netfs_fd {
|
||||||
|
struct _netfs_fd *next;
|
||||||
|
|
||||||
|
CHAR8 *netbuf;
|
||||||
|
UINT64 netbuf_maxsize; /* currently allocated buffer */
|
||||||
|
UINTN netbuf_size; /* number of bytes currently used in the buffer */
|
||||||
|
UINT64 netbuf_pos; /* current position in the buffer */
|
||||||
|
BOOLEAN is_valid; /* avoid conflicting opens */
|
||||||
|
BOOLEAN netbuf_reuse;
|
||||||
|
|
||||||
|
CHAR16 last_file[FILENAME_MAXLEN];
|
||||||
|
} netfs_fd_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EFI_PXE_BASE_CODE *pxe;
|
||||||
|
EFI_HANDLE dev; /* handle to device we're attached to */
|
||||||
|
BOOLEAN using_pxe; /* true if downloaded using the PXE protocol vs. regular DHCP */
|
||||||
|
|
||||||
|
EFI_IP_ADDRESS srv_ip;
|
||||||
|
EFI_IP_ADDRESS cln_ip;
|
||||||
|
EFI_IP_ADDRESS gw_ip;
|
||||||
|
EFI_IP_ADDRESS netmask;
|
||||||
|
UINT8 hw_addr[16];
|
||||||
|
|
||||||
|
netfs_fd_t fd_tab[NETFS_FD_MAX];
|
||||||
|
netfs_fd_t *free_fd;
|
||||||
|
UINTN free_fd_count;
|
||||||
|
|
||||||
|
} netfs_priv_state_t;
|
||||||
|
|
||||||
|
#define NETFS_F2FD(l,f) (UINTN)((f)-(l)->fd_tab)
|
||||||
|
#define NETFS_FD2F(l,fd) ((l)->fd_tab+fd)
|
||||||
|
#define NETFS_F_INVALID(f) ((f)->is_valid == FALSE)
|
||||||
|
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
netfs_interface_t pub_intf;
|
||||||
|
struct {
|
||||||
|
netfs_interface_t pub_intf;
|
||||||
|
netfs_priv_state_t priv_data;
|
||||||
|
} netfs_priv;
|
||||||
|
} netfs_t;
|
||||||
|
|
||||||
|
#define FS_PRIVATE(n) (&(((netfs_t *)n)->netfs_priv.priv_data))
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
EFI_HANDLE *dev;
|
||||||
|
netfs_t *intf;
|
||||||
|
} dev_tab_t;
|
||||||
|
|
||||||
|
static dev_tab_t *dev_tab; /* holds all devices we found */
|
||||||
|
static UINTN ndev; /* how many entries in dev_tab */
|
||||||
|
|
||||||
|
static EFI_GUID NetFsProtocol = NETFS_PROTOCOL;
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static EFI_PXE_BASE_CODE_CALLBACK_STATUS
|
||||||
|
netfs_callback_func(
|
||||||
|
IN EFI_PXE_BASE_CODE_CALLBACK *this,
|
||||||
|
IN EFI_PXE_BASE_CODE_FUNCTION function,
|
||||||
|
IN BOOLEAN received,
|
||||||
|
IN UINT32 packet_len,
|
||||||
|
IN EFI_PXE_BASE_CODE_PACKET *packet OPTIONAL
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Print(L"netfs_callback called received=%d packet_len=%d\n", received, packet_len);
|
||||||
|
return EFI_ABORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_PXE_BASE_CODE_CALLBACK netfs_callback = {
|
||||||
|
EFI_PXE_BASE_CODE_CALLBACK_INTERFACE_REVISION,
|
||||||
|
&netfs_callback_func
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static netfs_fd_t *
|
||||||
|
netfs_fd_alloc(netfs_priv_state_t *nfs, CHAR16 *name)
|
||||||
|
{
|
||||||
|
netfs_fd_t *tmp = NULL, *prev = NULL, *match;
|
||||||
|
UINT8 netbuf_reuse = 0;
|
||||||
|
|
||||||
|
if (nfs->free_fd == NULL) {
|
||||||
|
ERR_PRT((L"out of file descriptor"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
match = nfs->free_fd;
|
||||||
|
for (tmp = nfs->free_fd; tmp; tmp = tmp->next) {
|
||||||
|
if (!StrCmp(name, tmp->last_file)) {
|
||||||
|
DBG_PRT((L"Using cached file %s netbuf_size=%d", tmp->last_file, tmp->netbuf_size));
|
||||||
|
netbuf_reuse = 1;
|
||||||
|
match = tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev = tmp;
|
||||||
|
}
|
||||||
|
/* indicate whether or not we got a match in caching */
|
||||||
|
match->netbuf_reuse = netbuf_reuse;
|
||||||
|
|
||||||
|
if (match == nfs->free_fd)
|
||||||
|
nfs->free_fd = match->next;
|
||||||
|
else
|
||||||
|
prev->next = match->next;
|
||||||
|
|
||||||
|
nfs->free_fd_count--;
|
||||||
|
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
netfs_fd_free(netfs_priv_state_t *nfs, netfs_fd_t *f)
|
||||||
|
{
|
||||||
|
if (f == NULL) {
|
||||||
|
ERR_PRT((L"invalid fd"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
f->next = nfs->free_fd;
|
||||||
|
|
||||||
|
/* we keep the netbuf, in case we can reuse it */
|
||||||
|
f->is_valid = FALSE;
|
||||||
|
|
||||||
|
nfs->free_fd = f;
|
||||||
|
nfs->free_fd_count++;
|
||||||
|
|
||||||
|
if (nfs->free_fd_count > NETFS_FD_MAX) {
|
||||||
|
ERR_PRT((L"too many free descriptors %d", nfs->free_fd_count));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
netbuf_alloc(netfs_fd_t *f)
|
||||||
|
{
|
||||||
|
/* we will try to reuse the existing buffer first */
|
||||||
|
if (f->netbuf != 0) return 0;
|
||||||
|
|
||||||
|
f->netbuf_pos = 0;
|
||||||
|
|
||||||
|
f->netbuf = (CHAR8 *)alloc_pages(EFI_SIZE_TO_PAGES(f->netbuf_maxsize), EfiLoaderData, AllocateAnyPages, 0);
|
||||||
|
|
||||||
|
return f->netbuf == 0 ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
netfs_name(netfs_interface_t *this, CHAR16 *name, UINTN maxlen)
|
||||||
|
{
|
||||||
|
if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
StrnCpy(name, FS_NAME, maxlen-1);
|
||||||
|
|
||||||
|
name[maxlen-1] = CHAR_NULL;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
netfs_extract_ip(netfs_priv_state_t *nfs)
|
||||||
|
{
|
||||||
|
EFI_PXE_BASE_CODE *pxe = nfs->pxe;
|
||||||
|
|
||||||
|
if (pxe->Mode->PxeDiscoverValid) {
|
||||||
|
nfs->using_pxe = TRUE;
|
||||||
|
Memcpy(&nfs->srv_ip, pxe->Mode->PxeReply.Dhcpv4.BootpSiAddr, sizeof(EFI_IP_ADDRESS));
|
||||||
|
Memcpy(&nfs->hw_addr, pxe->Mode->PxeReply.Dhcpv4.BootpHwAddr, 16*sizeof(UINT8));
|
||||||
|
} else {
|
||||||
|
Memcpy(&nfs->srv_ip, pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr, sizeof(EFI_IP_ADDRESS));
|
||||||
|
Memcpy(&nfs->hw_addr, pxe->Mode->DhcpAck.Dhcpv4.BootpHwAddr, sizeof(nfs->hw_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
Memcpy(&nfs->cln_ip, &pxe->Mode->StationIp, sizeof(EFI_IP_ADDRESS));
|
||||||
|
Memcpy(&nfs->netmask, &pxe->Mode->SubnetMask, sizeof(EFI_IP_ADDRESS));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the fact that we use index 0, is just a guess
|
||||||
|
*/
|
||||||
|
if (pxe->Mode->RouteTableEntries>0)
|
||||||
|
Memcpy(&nfs->gw_ip, &pxe->Mode->RouteTable[0].GwAddr, sizeof(EFI_IP_ADDRESS));
|
||||||
|
|
||||||
|
VERB_PRT(1, Print(L"PXE PxeDiscoverValid: %s\n", pxe->Mode->PxeDiscoverValid? L"Yes (PXE-aware DHCPD)" : L"No (Regular DHCPD)"));
|
||||||
|
#if 0
|
||||||
|
status = BS->HandleProtocol(dev, &PxeCallbackProtocol, (VOID **)&netfs_callback);
|
||||||
|
status = LibInstallProtocolInterfaces(&dev, &PxeCallbackProtocol, &netfs_callback, NULL);
|
||||||
|
Print(L"PXE Callback support : %r\n", status);
|
||||||
|
if (status == EFI_SUCCESS) {
|
||||||
|
BOOLEAN doit = TRUE;
|
||||||
|
status = pxe->SetParameters(pxe, NULL, NULL, NULL, NULL, &doit);
|
||||||
|
Print(L"PXE Callback SetParameters: %r\n", status);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* XXX: TFTPD server not quite right when using PXE, need to extract bootservers...
|
||||||
|
*/
|
||||||
|
VERB_PRT(1, Print(L"Local IP: %d.%d.%d.%d\n",
|
||||||
|
pxe->Mode->StationIp.v4.Addr[0] & 0xff,
|
||||||
|
pxe->Mode->StationIp.v4.Addr[1] & 0xff,
|
||||||
|
pxe->Mode->StationIp.v4.Addr[2] & 0xff,
|
||||||
|
pxe->Mode->StationIp.v4.Addr[3] & 0xff));
|
||||||
|
|
||||||
|
VERB_PRT(1, Print(L"SM: %d.%d.%d.%d\n",
|
||||||
|
pxe->Mode->SubnetMask.v4.Addr[0] & 0xff,
|
||||||
|
pxe->Mode->SubnetMask.v4.Addr[1] & 0xff,
|
||||||
|
pxe->Mode->SubnetMask.v4.Addr[2] & 0xff,
|
||||||
|
pxe->Mode->SubnetMask.v4.Addr[3] & 0xff));
|
||||||
|
|
||||||
|
VERB_PRT(1, Print(L"TFTPD IP: %d.%d.%d.%d\n",
|
||||||
|
nfs->srv_ip.v4.Addr[0] & 0xff,
|
||||||
|
nfs->srv_ip.v4.Addr[1] & 0xff,
|
||||||
|
nfs->srv_ip.v4.Addr[2] & 0xff,
|
||||||
|
nfs->srv_ip.v4.Addr[3] & 0xff));
|
||||||
|
|
||||||
|
VERB_PRT(1, Print(L"Gateway IP: %d.%d.%d.%d\n",
|
||||||
|
nfs->gw_ip.v4.Addr[0] & 0xff,
|
||||||
|
nfs->gw_ip.v4.Addr[1] & 0xff,
|
||||||
|
nfs->gw_ip.v4.Addr[2] & 0xff,
|
||||||
|
nfs->gw_ip.v4.Addr[3] & 0xff));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
netfs_start(EFI_PXE_BASE_CODE *pxe)
|
||||||
|
{
|
||||||
|
EFI_STATUS status;
|
||||||
|
|
||||||
|
status = pxe->Start(pxe, FALSE);
|
||||||
|
if (EFI_ERROR(status)) return status;
|
||||||
|
|
||||||
|
return pxe->Dhcp(pxe, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
netfs_open(netfs_interface_t *this, CHAR16 *name, UINTN *fd)
|
||||||
|
{
|
||||||
|
netfs_priv_state_t *nfs;
|
||||||
|
netfs_fd_t *f;
|
||||||
|
EFI_STATUS status;
|
||||||
|
CHAR8 ascii_name[FILENAME_MAXLEN];
|
||||||
|
UINTN blocksize = 0, prev_netbufsize;
|
||||||
|
|
||||||
|
if (this == NULL || name == NULL || fd == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
nfs = FS_PRIVATE(this);
|
||||||
|
|
||||||
|
if (nfs->pxe == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to start protocol if not already active
|
||||||
|
*/
|
||||||
|
if (nfs->pxe->Mode->Started == FALSE) {
|
||||||
|
status = netfs_start(nfs->pxe);
|
||||||
|
if (EFI_ERROR(status)) return status;
|
||||||
|
netfs_extract_ip(nfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((f=netfs_fd_alloc(nfs, name)) == NULL) return EFI_OUT_OF_RESOURCES;
|
||||||
|
|
||||||
|
if (f->netbuf_reuse) {
|
||||||
|
f->netbuf_pos = 0;
|
||||||
|
f->is_valid = TRUE;
|
||||||
|
*fd = NETFS_F2FD(nfs, f);
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
f->netbuf_maxsize = NETFS_DEFAULT_BUFSIZE;
|
||||||
|
|
||||||
|
if (f->netbuf == NULL && netbuf_alloc(f) == -1) {
|
||||||
|
netfs_fd_free(nfs, f);
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* well, we need to download ! */
|
||||||
|
|
||||||
|
U2ascii(name, ascii_name, FILENAME_MAXLEN);
|
||||||
|
|
||||||
|
VERB_PRT(2, Print(L"downloading %a from %d.%d.%d.%d...", ascii_name,
|
||||||
|
nfs->srv_ip.v4.Addr[0],
|
||||||
|
nfs->srv_ip.v4.Addr[1],
|
||||||
|
nfs->srv_ip.v4.Addr[2],
|
||||||
|
nfs->srv_ip.v4.Addr[3]));
|
||||||
|
retry:
|
||||||
|
f->netbuf_size = f->netbuf_maxsize;
|
||||||
|
|
||||||
|
DBG_PRT((L"\nbefore netbuf:0x%lx netbuf_size=%ld\n", f->netbuf, f->netbuf_size));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For EFI versions older than 14.61:
|
||||||
|
* it seems like there is an EFI bug (or undocumented behavior) when the buffer size
|
||||||
|
* is too small AND the blocksize parameter is NULL, i.e., used the largest possible.
|
||||||
|
* In this case, Mtftp() never returns EFI_BUFFER_TOO_SMALL but EFI_TIMEOUT instead.
|
||||||
|
* This is true for 1.02 and also 1.10 it seems. Here we set it to the minimal value (512).
|
||||||
|
*
|
||||||
|
* Also it seems like on a READ_FILE which returns EFI_BUFFER_TOO_SMALL, the buffersize
|
||||||
|
* is NOT updated to reflect the required size for the next attempt.
|
||||||
|
*
|
||||||
|
* For EFI versions 14.61 and higher:
|
||||||
|
* In case the buffer is too small AND the TFTP server reports the file size (see RFC 2349),
|
||||||
|
* the f->netbuf_size will report the exact size for the buffer.
|
||||||
|
*/
|
||||||
|
prev_netbufsize = f->netbuf_size;
|
||||||
|
|
||||||
|
status = nfs->pxe->Mtftp(nfs->pxe, EFI_PXE_BASE_CODE_TFTP_READ_FILE, f->netbuf, FALSE,
|
||||||
|
&(f->netbuf_size),
|
||||||
|
blocksize > 0 ? &blocksize : NULL,
|
||||||
|
&nfs->srv_ip,
|
||||||
|
ascii_name,
|
||||||
|
NULL,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
DBG_PRT((L"after Mftp=%r netbuf:0x%lx netbuf_size=%ld blocksize=%ld\n",
|
||||||
|
status,
|
||||||
|
f->netbuf,
|
||||||
|
f->netbuf_size,
|
||||||
|
blocksize));
|
||||||
|
|
||||||
|
if (status == EFI_TIMEOUT && blocksize == 0) {
|
||||||
|
/*
|
||||||
|
* XXX: if blocksize is not adjusted we could loop forever here
|
||||||
|
*/
|
||||||
|
//blocksize = 512;
|
||||||
|
status = EFI_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* check if we need to increase our buffer size
|
||||||
|
*/
|
||||||
|
if (status == EFI_BUFFER_TOO_SMALL) {
|
||||||
|
DBG_PRT((L"buffer too small, need netbuf_size=%d", f->netbuf_size));
|
||||||
|
/*
|
||||||
|
* if the TFTP server supports TFTP options, then we should
|
||||||
|
* get the required size. So we test to see if the size
|
||||||
|
* we set has changed. If so, we got the required size.
|
||||||
|
* If not, we increase the buffer size and retry.
|
||||||
|
*/
|
||||||
|
if (f->netbuf_size == prev_netbufsize) {
|
||||||
|
f->netbuf_maxsize += NETFS_DEFAULT_BUFSIZE_INC;
|
||||||
|
} else {
|
||||||
|
/* we got an answer from the TFTP server, let's try it */
|
||||||
|
f->netbuf_maxsize = f->netbuf_size;
|
||||||
|
}
|
||||||
|
free(f->netbuf);
|
||||||
|
|
||||||
|
f->netbuf = NULL; /* will force reallocation */
|
||||||
|
|
||||||
|
if (netbuf_alloc(f) == 0) goto retry;
|
||||||
|
|
||||||
|
/* fall through in case of error */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == EFI_SUCCESS) {
|
||||||
|
/* start at the beginning of the file */
|
||||||
|
f->netbuf_pos = 0;
|
||||||
|
|
||||||
|
/* cache file name */
|
||||||
|
StrCpy(f->last_file, name);
|
||||||
|
|
||||||
|
f->is_valid = 1;
|
||||||
|
|
||||||
|
*fd = NETFS_F2FD(nfs, f);
|
||||||
|
VERB_PRT(2, Print(L"Done\n"));
|
||||||
|
} else {
|
||||||
|
netfs_fd_free(nfs, f);
|
||||||
|
VERB_PRT(2, Print(L"Failed: %r\n", status));
|
||||||
|
}
|
||||||
|
DBG_PRT((L"File %s netbuf_size=%d: %r", name, f->netbuf_size, status));
|
||||||
|
#if 0
|
||||||
|
Print(L"\n---\n");
|
||||||
|
{ INTN i;
|
||||||
|
for(i=0; i < netbuf_size; i++) {
|
||||||
|
Print(L"%c", (CHAR16)netbuf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Print(L"\n---\n");
|
||||||
|
#endif
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
netfs_read(netfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size)
|
||||||
|
{
|
||||||
|
netfs_priv_state_t *nfs;
|
||||||
|
netfs_fd_t *f;
|
||||||
|
UINTN count;
|
||||||
|
|
||||||
|
if (this == NULL || fd >= NETFS_FD_MAX || buf == NULL || size == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
nfs = FS_PRIVATE(this);
|
||||||
|
f = NETFS_FD2F(nfs, fd);
|
||||||
|
|
||||||
|
if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
count = MIN(*size, f->netbuf_size - f->netbuf_pos);
|
||||||
|
|
||||||
|
if (count) Memcpy(buf, f->netbuf+f->netbuf_pos, count);
|
||||||
|
|
||||||
|
*size = count;
|
||||||
|
f->netbuf_pos += count;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
netfs_close(netfs_interface_t *this, UINTN fd)
|
||||||
|
{
|
||||||
|
netfs_priv_state_t *nfs;
|
||||||
|
netfs_fd_t *f;
|
||||||
|
|
||||||
|
if (this == NULL || fd >= NETFS_FD_MAX) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
nfs = FS_PRIVATE(this);
|
||||||
|
f = NETFS_FD2F(nfs, fd);
|
||||||
|
|
||||||
|
if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
netfs_fd_free(nfs, f);
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
netfs_seek(netfs_interface_t *this, UINTN fd, UINT64 newpos)
|
||||||
|
{
|
||||||
|
netfs_priv_state_t *nfs;
|
||||||
|
netfs_fd_t *f;
|
||||||
|
|
||||||
|
if (this == NULL || fd >= NETFS_FD_MAX) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
nfs = FS_PRIVATE(this);
|
||||||
|
f = NETFS_FD2F(nfs, fd);
|
||||||
|
|
||||||
|
if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (newpos > f->netbuf_size) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
f->netbuf_pos = newpos;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
netfs_infosize(netfs_interface_t *this, UINTN fd, UINT64 *sz)
|
||||||
|
{
|
||||||
|
netfs_priv_state_t *nfs;
|
||||||
|
netfs_fd_t *f;
|
||||||
|
|
||||||
|
if (this == NULL || fd >= NETFS_FD_MAX || sz == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
nfs = FS_PRIVATE(this);
|
||||||
|
f = NETFS_FD2F(nfs, fd);
|
||||||
|
|
||||||
|
if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
*sz = f->netbuf_size;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
find_dhcp_option(EFI_PXE_BASE_CODE_PACKET *packet, UINT8 use_ipv6, UINT8 option, CHAR8 *str, INTN *len)
|
||||||
|
{
|
||||||
|
INTN i = 0;
|
||||||
|
UINT8 tag, length;
|
||||||
|
UINT8 *opts = packet->Dhcpv4.DhcpOptions;
|
||||||
|
|
||||||
|
*len = 0;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
if (i >= 56) {
|
||||||
|
DBG_PRT((L"reach end of options (no marker)\n"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tag = opts[i++];
|
||||||
|
|
||||||
|
if (tag == 0) continue;
|
||||||
|
if (tag == 255) break;
|
||||||
|
|
||||||
|
length = opts[i++];
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
{ UINT8 l = length, k = 0;
|
||||||
|
Print(L"found option %d len=%d: ", tag, length);
|
||||||
|
while (l--) { Print(L"%c(%d)\n", (CHAR16)opts[k], opts[k]); k++; }
|
||||||
|
Print(L"\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (tag == option) {
|
||||||
|
*len = length;
|
||||||
|
while (length--) { *str++ = opts[i++]; }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
i += length;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
netfs_getinfo(netfs_interface_t *this, netfs_info_t *info)
|
||||||
|
{
|
||||||
|
netfs_priv_state_t *nfs;
|
||||||
|
CHAR8 str[256];
|
||||||
|
INTN len, r;
|
||||||
|
|
||||||
|
if (this == NULL || info == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
nfs = FS_PRIVATE(this);
|
||||||
|
|
||||||
|
Memcpy(&info->cln_ipaddr, &nfs->cln_ip, sizeof(EFI_IP_ADDRESS));
|
||||||
|
Memcpy(&info->srv_ipaddr, &nfs->srv_ip, sizeof(EFI_IP_ADDRESS));
|
||||||
|
Memcpy(&info->netmask, &nfs->netmask, sizeof(EFI_IP_ADDRESS));
|
||||||
|
Memcpy(&info->gw_ipaddr, &nfs->gw_ip, sizeof(EFI_IP_ADDRESS));
|
||||||
|
Memcpy(&info->hw_addr, &nfs->hw_addr, sizeof(info->hw_addr));
|
||||||
|
|
||||||
|
info->using_pxe = nfs->using_pxe;
|
||||||
|
info->started = nfs->pxe->Mode->Started;
|
||||||
|
info->using_ipv6 = nfs->pxe->Mode->UsingIpv6;
|
||||||
|
|
||||||
|
if (nfs->pxe->Mode->UsingIpv6) goto skip_options;
|
||||||
|
|
||||||
|
r = find_dhcp_option(&nfs->pxe->Mode->DhcpAck,nfs->pxe->Mode->UsingIpv6, 15, str, &len);
|
||||||
|
str[len] = '\0';
|
||||||
|
ascii2U(str, info->domainame, 255);
|
||||||
|
|
||||||
|
VERB_PRT(3, Print(L"domain(15): %a\n", str));
|
||||||
|
|
||||||
|
r = find_dhcp_option(&nfs->pxe->Mode->DhcpAck,nfs->pxe->Mode->UsingIpv6, 12, str, &len);
|
||||||
|
str[len] = '\0';
|
||||||
|
ascii2U(str, info->hostname, 255);
|
||||||
|
|
||||||
|
VERB_PRT(3, Print(L"hostname(12): %a\n", str));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extract bootfile name from DHCP exchanges
|
||||||
|
*/
|
||||||
|
if (nfs->using_pxe == 0) {
|
||||||
|
ascii2U(nfs->pxe->Mode->DhcpAck.Dhcpv4.BootpBootFile, info->bootfile, NETFS_BOOTFILE_MAXLEN);
|
||||||
|
VERB_PRT(3, Print(L"bootfile: %s\n", info->bootfile));
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_options:
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT16
|
||||||
|
find_pxe_server_type(EFI_PXE_BASE_CODE *pxe)
|
||||||
|
{
|
||||||
|
INTN i = 0, max;
|
||||||
|
UINT8 tag, length;
|
||||||
|
UINT8 *opts = pxe->Mode->PxeReply.Dhcpv4.DhcpOptions;
|
||||||
|
UINT16 server_type;
|
||||||
|
|
||||||
|
while(i < 55) {
|
||||||
|
tag = opts[i];
|
||||||
|
length = opts[i+1];
|
||||||
|
|
||||||
|
DBG_PRT((L"Tag #%d Length %d\n",tag, length));
|
||||||
|
|
||||||
|
if (tag == 43) goto found;
|
||||||
|
|
||||||
|
i += 2 + length;
|
||||||
|
}
|
||||||
|
return NETFS_DEFAULT_SERVER_TYPE;
|
||||||
|
found:
|
||||||
|
max = i+2+length;
|
||||||
|
i += 2;
|
||||||
|
while (i < max) {
|
||||||
|
tag = opts[i];
|
||||||
|
length = opts[i+1];
|
||||||
|
if (tag == 71) {
|
||||||
|
server_type =(opts[i+2]<<8) | opts[i+3];
|
||||||
|
DBG_PRT((L"ServerType: %d\n", server_type));
|
||||||
|
return server_type;
|
||||||
|
}
|
||||||
|
i+= 2 + length;
|
||||||
|
}
|
||||||
|
return NETFS_DEFAULT_SERVER_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
netfs_query_layer(netfs_interface_t *this, UINT16 server_type, UINT16 layer, UINTN maxlen, CHAR16 *str)
|
||||||
|
{
|
||||||
|
netfs_priv_state_t *nfs;
|
||||||
|
EFI_STATUS status;
|
||||||
|
|
||||||
|
if (this == NULL || str == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
nfs = FS_PRIVATE(this);
|
||||||
|
|
||||||
|
if (nfs->using_pxe == FALSE) return EFI_UNSUPPORTED;
|
||||||
|
|
||||||
|
if (server_type == 0) server_type = find_pxe_server_type(nfs->pxe);
|
||||||
|
|
||||||
|
status = nfs->pxe->Discover(nfs->pxe, server_type, &layer, FALSE, 0);
|
||||||
|
if(status == EFI_SUCCESS) {
|
||||||
|
ascii2U(nfs->pxe->Mode->PxeReply.Dhcpv4.BootpBootFile, str, maxlen);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
netfs_init_state(netfs_t *netfs, EFI_HANDLE dev, EFI_PXE_BASE_CODE *pxe)
|
||||||
|
{
|
||||||
|
netfs_priv_state_t *nfs = FS_PRIVATE(netfs);
|
||||||
|
UINTN i;
|
||||||
|
|
||||||
|
/* need to do some init here on netfs_intf */
|
||||||
|
Memset(netfs, 0, sizeof(*netfs));
|
||||||
|
|
||||||
|
|
||||||
|
netfs->pub_intf.netfs_name = netfs_name;
|
||||||
|
netfs->pub_intf.netfs_open = netfs_open;
|
||||||
|
netfs->pub_intf.netfs_read = netfs_read;
|
||||||
|
netfs->pub_intf.netfs_close = netfs_close;
|
||||||
|
netfs->pub_intf.netfs_infosize = netfs_infosize;
|
||||||
|
netfs->pub_intf.netfs_seek = netfs_seek;
|
||||||
|
netfs->pub_intf.netfs_query_layer = netfs_query_layer;
|
||||||
|
netfs->pub_intf.netfs_getinfo = netfs_getinfo;
|
||||||
|
|
||||||
|
nfs->dev = dev;
|
||||||
|
nfs->pxe = pxe;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we defer DHCP request until it is really necessary (netfs_open)
|
||||||
|
*/
|
||||||
|
if (pxe->Mode->Started == TRUE) netfs_extract_ip(nfs);
|
||||||
|
|
||||||
|
Memset(nfs->fd_tab, 0, sizeof(nfs->fd_tab));
|
||||||
|
|
||||||
|
for (i=0; i < NETFS_FD_MAX-1; i++) {
|
||||||
|
nfs->fd_tab[i].next = &nfs->fd_tab[i+1];
|
||||||
|
}
|
||||||
|
/* null on last element is done by memset */
|
||||||
|
|
||||||
|
nfs->free_fd = nfs->fd_tab;
|
||||||
|
nfs->free_fd_count = NETFS_FD_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
netfs_install_one(EFI_HANDLE dev, VOID **intf)
|
||||||
|
{
|
||||||
|
|
||||||
|
EFI_STATUS status;
|
||||||
|
netfs_t *netfs;
|
||||||
|
EFI_PXE_BASE_CODE *pxe;
|
||||||
|
|
||||||
|
status = BS->HandleProtocol (dev, &NetFsProtocol, (VOID **)&netfs);
|
||||||
|
if (status == EFI_SUCCESS) {
|
||||||
|
ERR_PRT((L"Warning: found existing %s protocol on device", FS_NAME));
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = BS->HandleProtocol (dev, &PxeBaseCodeProtocol, (VOID **)&pxe);
|
||||||
|
if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
|
||||||
|
netfs = (netfs_t *)alloc(sizeof(*netfs), EfiLoaderData);
|
||||||
|
if (netfs == NULL) {
|
||||||
|
ERR_PRT((L"failed to allocate %s", FS_NAME));
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
netfs_init_state(netfs, dev, pxe);
|
||||||
|
|
||||||
|
status = LibInstallProtocolInterfaces(&dev, &NetFsProtocol, netfs, NULL);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"Cannot install %s protocol: %r", FS_NAME, status));
|
||||||
|
free(netfs);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
found:
|
||||||
|
if (intf) *intf = (VOID *)netfs;
|
||||||
|
|
||||||
|
VERB_PRT(3,
|
||||||
|
{ EFI_DEVICE_PATH *dp; CHAR16 *str;
|
||||||
|
dp = DevicePathFromHandle(dev);
|
||||||
|
str = DevicePathToStr(dp);
|
||||||
|
Print(L"attached %s to %s\n", FS_NAME, str);
|
||||||
|
FreePool(str);
|
||||||
|
});
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
netfs_install(VOID)
|
||||||
|
{
|
||||||
|
UINTN size = 0;
|
||||||
|
UINTN i;
|
||||||
|
EFI_STATUS status;
|
||||||
|
VOID *intf;
|
||||||
|
|
||||||
|
BS->LocateHandle(ByProtocol, &PxeBaseCodeProtocol, NULL, &size, NULL);
|
||||||
|
if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */
|
||||||
|
|
||||||
|
DBG_PRT((L"size=%d", size));
|
||||||
|
|
||||||
|
dev_tab = (dev_tab_t *)alloc(size, EfiLoaderData);
|
||||||
|
if (dev_tab == NULL) {
|
||||||
|
ERR_PRT((L"failed to allocate handle table"));
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = BS->LocateHandle(ByProtocol, &PxeBaseCodeProtocol, NULL, &size, (VOID **)dev_tab);
|
||||||
|
if (status != EFI_SUCCESS) {
|
||||||
|
ERR_PRT((L"failed to get handles: %r", status));
|
||||||
|
free(dev_tab);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
ndev = size / sizeof(EFI_HANDLE);
|
||||||
|
|
||||||
|
for(i=0; i < ndev; i++) {
|
||||||
|
intf = NULL;
|
||||||
|
netfs_install_one(dev_tab[i].dev, &intf);
|
||||||
|
/* override device handle with interface pointer */
|
||||||
|
dev_tab[i].intf = intf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
netfs_uninstall(VOID)
|
||||||
|
{
|
||||||
|
|
||||||
|
netfs_priv_state_t *nfs;
|
||||||
|
EFI_STATUS status;
|
||||||
|
UINTN i;
|
||||||
|
|
||||||
|
for(i=0; i < ndev; i++) {
|
||||||
|
if (dev_tab[i].intf == NULL) continue;
|
||||||
|
nfs = FS_PRIVATE(dev_tab[i].intf);
|
||||||
|
status = BS->UninstallProtocolInterface(nfs->dev, &NetFsProtocol, dev_tab[i].intf);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
VERB_PRT(3,
|
||||||
|
{ EFI_DEVICE_PATH *dp; CHAR16 *str;
|
||||||
|
dp = DevicePathFromHandle(nfs->dev);
|
||||||
|
str = DevicePathToStr(dp);
|
||||||
|
Print(L"uninstalled %s on %s\n", FS_NAME, str);
|
||||||
|
FreePool(str);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (nfs->pxe->Mode->Started == TRUE) nfs->pxe->Stop(nfs->pxe);
|
||||||
|
|
||||||
|
free(dev_tab[i].intf);
|
||||||
|
}
|
||||||
|
if (dev_tab) free(dev_tab);
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
68
fs/netfs.h
Normal file
68
fs/netfs.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NETLFS_H__
|
||||||
|
#define __NETLFS_H__
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#define NETFS_BOOTFILE_MAXLEN 256
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EFI_IP_ADDRESS cln_ipaddr;
|
||||||
|
EFI_IP_ADDRESS srv_ipaddr;
|
||||||
|
EFI_IP_ADDRESS netmask;
|
||||||
|
EFI_IP_ADDRESS gw_ipaddr;
|
||||||
|
UINT8 hw_addr[16];
|
||||||
|
CHAR16 hostname[255]; /* 255 limitation of DHCP protocol */
|
||||||
|
CHAR16 domainame[255]; /* 255 limitation of DHCP protocol */
|
||||||
|
CHAR16 bootfile[NETFS_BOOTFILE_MAXLEN]; /* name of file downloaded (BOOTP/DHCP) */
|
||||||
|
BOOLEAN using_pxe;
|
||||||
|
BOOLEAN started;
|
||||||
|
BOOLEAN using_ipv6;
|
||||||
|
} netfs_info_t;
|
||||||
|
|
||||||
|
|
||||||
|
INTERFACE_DECL(_netfs_interface_t);
|
||||||
|
|
||||||
|
typedef struct _netfs_interface_t {
|
||||||
|
EFI_STATUS (*netfs_name)(struct _netfs_interface_t *this, CHAR16 *name, UINTN maxlen);
|
||||||
|
EFI_STATUS (*netfs_open)(struct _netfs_interface_t *this, CHAR16 *name, UINTN *fd);
|
||||||
|
EFI_STATUS (*netfs_read)(struct _netfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size);
|
||||||
|
EFI_STATUS (*netfs_close)(struct _netfs_interface_t *this, UINTN fd);
|
||||||
|
EFI_STATUS (*netfs_infosize)(struct _netfs_interface_t *this, UINTN fd, UINT64 *size);
|
||||||
|
EFI_STATUS (*netfs_seek)(struct _netfs_interface_t *this, UINTN fd, UINT64 newpos);
|
||||||
|
EFI_STATUS (*netfs_query_layer)(struct _netfs_interface_t *this, UINT16 server_type, UINT16 layer, UINTN maxlen, CHAR16 *str);
|
||||||
|
EFI_STATUS (*netfs_getinfo)(struct _netfs_interface_t *this, netfs_info_t *info);
|
||||||
|
} netfs_interface_t;
|
||||||
|
|
||||||
|
#define NETFS_PROTOCOL \
|
||||||
|
{ 0x6746de4f, 0xcc1e, 0x4c5f, {0xb7, 0xfb, 0x85, 0x6a, 0x5d, 0x69, 0x0f, 0x06} }
|
||||||
|
|
||||||
|
extern EFI_STATUS netfs_install(VOID);
|
||||||
|
extern EFI_STATUS netfs_uninstall(VOID);
|
||||||
|
|
||||||
|
#endif /* __NETFS_H__ */
|
99
getopt.c
Normal file
99
getopt.c
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* Simplistic getopt() function for EFI
|
||||||
|
*
|
||||||
|
* This function provides the basic functionality of the POSIX getopt() function.
|
||||||
|
* No long options are supported.
|
||||||
|
*
|
||||||
|
* This code is meant for EFI programs and therefore deals with Unicode characters.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2000 Hewlett-Packard Co
|
||||||
|
* Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define DASH (CHAR16)'-'
|
||||||
|
#define COLON (CHAR16)':'
|
||||||
|
#define EOS (CHAR16)'\0'
|
||||||
|
#define BADCH (INTN)'?'
|
||||||
|
#define BADARG (INTN)':'
|
||||||
|
|
||||||
|
extern CHAR16 * StrChr(IN const CHAR16 *s, INT16 c);
|
||||||
|
|
||||||
|
CHAR16 *Optarg;
|
||||||
|
INTN Optind = 1;
|
||||||
|
INTN Optopt;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This simple version of getopt supports:
|
||||||
|
* - option with no argument (no :)
|
||||||
|
* - option with REQUIRED argument (single :)
|
||||||
|
* it does not support:
|
||||||
|
* - long options
|
||||||
|
* - optional arguments to options
|
||||||
|
* - optreset
|
||||||
|
*/
|
||||||
|
INTN
|
||||||
|
Getopt(INTN argc, CHAR16 *const argv[], const CHAR16 *optstring)
|
||||||
|
{
|
||||||
|
static CHAR16 *cur_chr = NULL;
|
||||||
|
CHAR16 *opt;
|
||||||
|
|
||||||
|
if (Optind >= argc) { /* no option or end of argument list */
|
||||||
|
cur_chr = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (cur_chr == NULL || *cur_chr == EOS) {
|
||||||
|
cur_chr = argv[Optind];
|
||||||
|
if (*cur_chr++ != DASH) { /* missing DASH */
|
||||||
|
cur_chr = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (*cur_chr == DASH) {
|
||||||
|
cur_chr = NULL;
|
||||||
|
Optind++;
|
||||||
|
return -1; /* -- case, we're done */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Optopt = *cur_chr++;
|
||||||
|
opt = StrChr(optstring, Optopt);
|
||||||
|
if (!opt) {
|
||||||
|
Print(L"%s: illegal option -- %c\n", argv[0], Optopt);
|
||||||
|
if (*cur_chr == EOS) Optind++;
|
||||||
|
return BADCH;
|
||||||
|
}
|
||||||
|
if (*(opt+1) != COLON) {
|
||||||
|
Optarg = NULL;
|
||||||
|
if (*cur_chr == EOS) Optind++;
|
||||||
|
} else {
|
||||||
|
if (*cur_chr) {
|
||||||
|
Optarg = cur_chr;
|
||||||
|
} else if ( ++Optind >= argc ) {
|
||||||
|
Print(L"%s: option `%s' requires an argument\n", argv[0], argv[Optind-1]),
|
||||||
|
cur_chr = NULL;
|
||||||
|
return BADARG;
|
||||||
|
} else {
|
||||||
|
Optarg = argv[Optind];
|
||||||
|
}
|
||||||
|
Optind++;
|
||||||
|
}
|
||||||
|
return Optopt;
|
||||||
|
}
|
33
getopt.h
Normal file
33
getopt.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Simplistic getopt() function header file for EFI
|
||||||
|
*
|
||||||
|
* Copyright (C) 2000 Hewlett-Packard Co
|
||||||
|
* Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __EFI_GETOPT_H__
|
||||||
|
#define __EFI_GETOPT_H__
|
||||||
|
|
||||||
|
extern CHAR16 *Optarg;
|
||||||
|
extern INTN Optind, Optopt;
|
||||||
|
|
||||||
|
extern INTN Getopt(INTN argc, CHAR16 *const argv[], const CHAR16 *optstring);
|
||||||
|
|
||||||
|
#endif /* __EFI_GETOPT_H__ */
|
73
glue_ext2fs.c
Normal file
73
glue_ext2fs.c
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "glue_ext2fs.h"
|
||||||
|
#include "fs/ext2fs.h"
|
||||||
|
#include "strops.h"
|
||||||
|
|
||||||
|
|
||||||
|
static INTN glue(fileops_t *this, VOID *intf);
|
||||||
|
|
||||||
|
/* object exported to fileops */
|
||||||
|
|
||||||
|
fileops_fs_t ext2fs_glue = { EXT2FS_PROTOCOL , glue, ext2fs_install, ext2fs_uninstall};
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
ext2fs_infosize(ext2fs_interface_t *this, fops_fd_t fd, UINT64 *sz)
|
||||||
|
{
|
||||||
|
ext2fs_stat_t st;
|
||||||
|
EFI_STATUS status;
|
||||||
|
|
||||||
|
if (this == NULL || sz == NULL) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
status = this->ext2fs_fstat(this, fd, &st);
|
||||||
|
if (status != EFI_SUCCESS) return status;
|
||||||
|
|
||||||
|
*sz = (UINT64)st.st_size;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
glue(fileops_t *fp, VOID *intf)
|
||||||
|
{
|
||||||
|
ext2fs_interface_t *ext2fs = (ext2fs_interface_t *)intf;
|
||||||
|
|
||||||
|
/* record underlying interface */
|
||||||
|
fp->intf = intf;
|
||||||
|
|
||||||
|
fp->open = (fops_open_t)ext2fs->ext2fs_open;
|
||||||
|
fp->read = (fops_read_t)ext2fs->ext2fs_read;
|
||||||
|
fp->close = (fops_close_t)ext2fs->ext2fs_close;
|
||||||
|
fp->infosize = (fops_infosize_t)ext2fs_infosize; /* local override */
|
||||||
|
fp->seek = (fops_seek_t)ext2fs->ext2fs_seek;
|
||||||
|
|
||||||
|
/* fill out the name of the underlying file system */
|
||||||
|
ext2fs->ext2fs_name(ext2fs, fp->name, FILEOPS_NAME_MAXLEN);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
33
glue_ext2fs.h
Normal file
33
glue_ext2fs.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GLUE_EXT2FS_H__
|
||||||
|
#define __GLUE_EXT2FS_H__
|
||||||
|
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
|
extern fileops_fs_t ext2fs_glue;
|
||||||
|
|
||||||
|
#endif /* __GLUE_EXT2FS_H__ */
|
173
glue_localfs.c
Normal file
173
glue_localfs.c
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "fs/localfs.h"
|
||||||
|
#include "glue_localfs.h"
|
||||||
|
#include "strops.h"
|
||||||
|
#include "elilo.h"
|
||||||
|
|
||||||
|
static INTN glue(fileops_t *this, VOID *intf);
|
||||||
|
|
||||||
|
/* object exported to fileops */
|
||||||
|
|
||||||
|
fileops_fs_t localfs_glue = { LOCALFS_PROTOCOL, glue, localfs_install, localfs_uninstall};
|
||||||
|
|
||||||
|
|
||||||
|
static CHAR16 localfs_default_path[FILENAME_MAXLEN];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* remove /.\ pattern from path name:
|
||||||
|
*
|
||||||
|
* Example 1: I am in fs0:\efi\debian, which contains elilo.efi, and I
|
||||||
|
* have typed 'elilo' at the efishell prompt. set_default_path() gets
|
||||||
|
* called with string "\EFI\debian/.\elilo.efi". The final path name
|
||||||
|
* must then be set to "\EFI\debian\".
|
||||||
|
*
|
||||||
|
* Example 2: I am in fs0:\ and type 'efi\debian\elilo' at the shell
|
||||||
|
* prompt. set_default_path() is called with "\/.\efi\debian\elilo.efi",
|
||||||
|
* the path must then be set to "\efi\debian\".
|
||||||
|
*
|
||||||
|
* Example 3: I am in fs0:\efi and type '\efi\debian\elilo'.
|
||||||
|
* set_default_path() is called with "\efi\debian\elilo.efi", the
|
||||||
|
* path is "\efi\debian".
|
||||||
|
*/
|
||||||
|
static VOID
|
||||||
|
set_default_path(CHAR16 *sptr)
|
||||||
|
{
|
||||||
|
#define is_sep(h) (h == CHAR_SLASH || h == CHAR_BACKSLASH)
|
||||||
|
CHAR16 *dptr, *last_sep = NULL;
|
||||||
|
UINTN len = FILENAME_MAXLEN - 1;
|
||||||
|
UINTN last_was_sep = 0;
|
||||||
|
CHAR16 c;
|
||||||
|
|
||||||
|
dptr = localfs_default_path;
|
||||||
|
|
||||||
|
while (len-- && *sptr) {
|
||||||
|
c = sptr[0];
|
||||||
|
|
||||||
|
if (is_sep(c)) {
|
||||||
|
if (last_was_sep) {
|
||||||
|
sptr++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
c = CHAR_BACKSLASH;
|
||||||
|
last_was_sep = 1;
|
||||||
|
last_sep = dptr;
|
||||||
|
} else {
|
||||||
|
last_was_sep = 0;
|
||||||
|
}
|
||||||
|
*dptr++ = c;
|
||||||
|
sptr++;
|
||||||
|
}
|
||||||
|
if (last_sep)
|
||||||
|
*++last_sep = CHAR_NULL;
|
||||||
|
else
|
||||||
|
*dptr = CHAR_NULL;
|
||||||
|
|
||||||
|
DBG_PRT((L"localfs_default_path=%s\n", localfs_default_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following glue functions are the only ones which need
|
||||||
|
* to know about the way the underlying interface is working
|
||||||
|
*/
|
||||||
|
#define LOCALFS_DEFAULT_KERNEL L"vmlinux"
|
||||||
|
#define LOCALFS_DEFAULT_CONFIG L"elilo.conf"
|
||||||
|
static EFI_STATUS
|
||||||
|
localfs_setdefaults(VOID *this, CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
|
||||||
|
{
|
||||||
|
StrnCpy(kname, LOCALFS_DEFAULT_KERNEL, maxlen-1);
|
||||||
|
kname[maxlen-1] = CHAR_NULL;
|
||||||
|
|
||||||
|
StrnCpy(config, LOCALFS_DEFAULT_CONFIG, maxlen-1);
|
||||||
|
config[maxlen-1] = CHAR_NULL;
|
||||||
|
|
||||||
|
set_default_path(devpath);
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
localfs_getdefault_path(CHAR16 *path, UINTN maxlen)
|
||||||
|
{
|
||||||
|
if (maxlen <= StrLen(localfs_default_path)) return EFI_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
|
StrCpy(path, localfs_default_path);
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the supplied path is a relative path, then prepend the path to
|
||||||
|
* the elilo.efi executable. This ensures that elilo will look in
|
||||||
|
* its own directory for its config file, kernel images, etc, rather
|
||||||
|
* than the root directory of the disk. Also * convert forward slashes
|
||||||
|
* into backward slashes.
|
||||||
|
*/
|
||||||
|
static EFI_STATUS
|
||||||
|
glue_open(VOID *intf, CHAR16 *name, fops_fd_t *fd)
|
||||||
|
{
|
||||||
|
CHAR16 *p;
|
||||||
|
localfs_interface_t *localfs = (localfs_interface_t *)intf;
|
||||||
|
CHAR16 fullname[FILENAME_MAXLEN];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX: modification to passed argument (name)
|
||||||
|
*/
|
||||||
|
for (p= name; *p != CHAR_NULL; p++) {
|
||||||
|
if (*p == CHAR_SLASH) *p = CHAR_BACKSLASH;
|
||||||
|
}
|
||||||
|
if (name[0] != CHAR_BACKSLASH && localfs_default_path[0] != CHAR_NULL) {
|
||||||
|
if (StrLen(localfs_default_path) + StrLen(name) + 1 >= FILENAME_MAXLEN)
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
StrCpy(fullname, localfs_default_path);
|
||||||
|
StrCat(fullname, name);
|
||||||
|
name = fullname;
|
||||||
|
}
|
||||||
|
return localfs->localfs_open(intf, name, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
glue(fileops_t *fp, VOID *intf)
|
||||||
|
{
|
||||||
|
localfs_interface_t *localfs = (localfs_interface_t *)intf;
|
||||||
|
|
||||||
|
fp->open = glue_open;
|
||||||
|
fp->read = (fops_read_t)localfs->localfs_read;
|
||||||
|
fp->close = (fops_close_t)localfs->localfs_close;
|
||||||
|
fp->infosize = (fops_infosize_t)localfs->localfs_infosize;
|
||||||
|
fp->seek = (fops_seek_t)localfs->localfs_seek;
|
||||||
|
fp->setdefaults = (fops_setdefaults_t)localfs_setdefaults;
|
||||||
|
fp->getdefault_path = (fops_getdefault_path_t)localfs_getdefault_path;
|
||||||
|
fp->intf = intf;
|
||||||
|
|
||||||
|
/* fill out the name of the underlying file system */
|
||||||
|
localfs->localfs_name(localfs, fp->name, FILEOPS_NAME_MAXLEN);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
33
glue_localfs.h
Normal file
33
glue_localfs.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GLUE_LOCALFS_H__
|
||||||
|
#define __GLUE_LOCALFS_H__
|
||||||
|
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
|
extern fileops_fs_t localfs_glue;
|
||||||
|
|
||||||
|
#endif /* __GLUE_LOCALFS_H__ */
|
242
glue_netfs.c
Normal file
242
glue_netfs.c
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "glue_netfs.h"
|
||||||
|
#include "fs/netfs.h"
|
||||||
|
#include "strops.h"
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
#include "vars.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* disable this if you only want the default config file (elilo.conf)
|
||||||
|
* and not the ip-address based first file attempt
|
||||||
|
*/
|
||||||
|
|
||||||
|
static INTN glue(fileops_t *this, VOID *intf);
|
||||||
|
|
||||||
|
/* object exported to fileops */
|
||||||
|
fileops_fs_t netfs_glue = { NETFS_PROTOCOL , glue, netfs_install, netfs_uninstall};
|
||||||
|
|
||||||
|
|
||||||
|
#define NETFS_DEFAULT_KERNEL L"vmlinux"
|
||||||
|
#define NETFS_DEFAULT_CONFIG L"elilo.conf"
|
||||||
|
#define NETFS_DEFAULT_SERVER_TYPE EFI_PXE_BASE_CODE_BOOT_TYPE_REDHAT_BOOT
|
||||||
|
|
||||||
|
|
||||||
|
static CHAR16 netfs_default_path[FILENAME_MAXLEN];
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pxe Discovery protocol layers
|
||||||
|
* Layer 0 is used to download the boot loader
|
||||||
|
*/
|
||||||
|
#define NETFS_CONFIG_LAYER 1
|
||||||
|
#define NETFS_KERNEL_LAYER 2
|
||||||
|
|
||||||
|
static CHAR16 *hexa=L"0123456789ABCDEF";
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
convert_ip2hex(UINT8 *ip, INTN l, CHAR16 *str)
|
||||||
|
{
|
||||||
|
UINTN i;
|
||||||
|
|
||||||
|
for(i=0; i < l; i++) {
|
||||||
|
str[2*i] = hexa[(ip[i] & 0xf0)>>4];
|
||||||
|
str[2*i+1] = hexa[ip[i] & 0x0f];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
convert_ip2decstr(UINT8 *ip, INTN l, CHAR16 *str)
|
||||||
|
{
|
||||||
|
UINTN i, j;
|
||||||
|
UINTN v, val;
|
||||||
|
|
||||||
|
for(i=0, j=0; i < l; i++) {
|
||||||
|
val = ip[i];
|
||||||
|
v = val / 100;
|
||||||
|
if (v) {
|
||||||
|
str[j++] = L'0'+v;
|
||||||
|
}
|
||||||
|
val = val % 100;
|
||||||
|
v = val / 10;
|
||||||
|
if (v || ip[i] >= 100) {
|
||||||
|
str[j++] = L'0'+v;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = val % 10;
|
||||||
|
str[j++] = L'0'+v;
|
||||||
|
if (i < l-1) str[j++] = L'.';
|
||||||
|
}
|
||||||
|
str[j] = CHAR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
netfs_set_default_path(netfs_interface_t *netfs, netfs_info_t *info)
|
||||||
|
{
|
||||||
|
INTN len;
|
||||||
|
|
||||||
|
StrnCpy(netfs_default_path, info->bootfile, FILENAME_MAXLEN);
|
||||||
|
|
||||||
|
len = StrLen(netfs_default_path) - 1;
|
||||||
|
|
||||||
|
while (len >= 0) {
|
||||||
|
if (netfs_default_path[len] == CHAR_SLASH || netfs_default_path[len] == CHAR_BACKSLASH) break;
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
netfs_default_path[len+1] = CHAR_NULL;
|
||||||
|
|
||||||
|
DBG_PRT((L"netfs_default_path=%s\n", netfs_default_path));
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
netfs_setdefaults(VOID *intf, CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
|
||||||
|
{
|
||||||
|
netfs_interface_t *netfs = (netfs_interface_t *)intf;
|
||||||
|
netfs_info_t info;
|
||||||
|
EFI_STATUS status;
|
||||||
|
UINT8 *ipaddr;
|
||||||
|
UINTN m;
|
||||||
|
CHAR16 ip_var[64], str[64];
|
||||||
|
UINT8 *ip;
|
||||||
|
|
||||||
|
if (config == NULL || kname == NULL || maxlen < 1) return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
netfs->netfs_getinfo(netfs, &info);
|
||||||
|
|
||||||
|
m = info.using_ipv6 ? 16 : 4;
|
||||||
|
ipaddr = info.using_ipv6 ? info.cln_ipaddr.v6.Addr: info.cln_ipaddr.v4.Addr;
|
||||||
|
|
||||||
|
convert_ip2decstr(ipaddr, m, ip_var);
|
||||||
|
set_var(VAR_NETFS_IPADDR, ip_var);
|
||||||
|
|
||||||
|
ip = info.using_ipv6 ? info.netmask.v6.Addr: info.netmask.v4.Addr;
|
||||||
|
convert_ip2decstr(ip, m, str);
|
||||||
|
set_var(VAR_NETFS_NETMASK, str);
|
||||||
|
|
||||||
|
ip = info.using_ipv6 ? info.gw_ipaddr.v6.Addr: info.gw_ipaddr.v4.Addr;
|
||||||
|
convert_ip2decstr(ip, m, str);
|
||||||
|
set_var(VAR_NETFS_GATEWAY, str);
|
||||||
|
|
||||||
|
set_var(VAR_NETFS_HOSTNAME, info.hostname);
|
||||||
|
set_var(VAR_NETFS_DOMAINAME, info.domainame);
|
||||||
|
|
||||||
|
if (info.using_pxe) {
|
||||||
|
status = netfs->netfs_query_layer(netfs, 0, NETFS_CONFIG_LAYER, maxlen, config);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
StrnCpy(config, NETFS_DEFAULT_CONFIG, maxlen-1);
|
||||||
|
config[maxlen-1] = CHAR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = netfs->netfs_query_layer(netfs, 0, NETFS_KERNEL_LAYER, maxlen, kname);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
StrnCpy(kname, NETFS_DEFAULT_KERNEL, maxlen-1);
|
||||||
|
kname[maxlen-1] = CHAR_NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#ifdef ENABLE_MACHINE_SPECIFIC_NETCONFIG
|
||||||
|
/*
|
||||||
|
* will try a machine specific file first.
|
||||||
|
* the file is constructed based on the IP(v4) address
|
||||||
|
*/
|
||||||
|
convert_ip2hex(ipaddr, m, config);
|
||||||
|
|
||||||
|
config[8] = L'.';
|
||||||
|
config[9] = L'c';
|
||||||
|
config[10] = L'o';
|
||||||
|
config[11] = L'n';
|
||||||
|
config[12] = L'f';
|
||||||
|
config[13] = CHAR_NULL;
|
||||||
|
#else
|
||||||
|
StrnCpy(config, NETFS_DEFAULT_CONFIG, maxlen-1);
|
||||||
|
config[maxlen-1] = CHAR_NULL;
|
||||||
|
#endif
|
||||||
|
StrnCpy(kname, NETFS_DEFAULT_KERNEL, maxlen-1);
|
||||||
|
kname[maxlen-1] = CHAR_NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extract bootloader path prefix to be used for
|
||||||
|
* the config file (and possibly the other files we
|
||||||
|
* need to download)
|
||||||
|
*/
|
||||||
|
netfs_set_default_path(netfs, &info);
|
||||||
|
}
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
netfs_getdefault_path(CHAR16 *path, UINTN maxlen)
|
||||||
|
{
|
||||||
|
if (maxlen <= StrLen(netfs_default_path)) return EFI_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
|
StrCpy(path, netfs_default_path);
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static EFI_STATUS
|
||||||
|
glue_open(VOID *intf, CHAR16 *name, fops_fd_t *fd)
|
||||||
|
{
|
||||||
|
netfs_interface_t *netfs = (netfs_interface_t *)intf;
|
||||||
|
CHAR16 fullname[FILENAME_MAXLEN];
|
||||||
|
|
||||||
|
if (name[0] != CHAR_SLASH && name[0] != CHAR_BACKSLASH && netfs_default_path[0] != CHAR_NULL) {
|
||||||
|
if (StrLen(netfs_default_path) + StrLen(name) + 1 >= FILENAME_MAXLEN)
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
StrCpy(fullname, netfs_default_path);
|
||||||
|
StrCat(fullname, name);
|
||||||
|
name = fullname;
|
||||||
|
}
|
||||||
|
return netfs->netfs_open(intf, name, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
glue(fileops_t *fp, VOID *intf)
|
||||||
|
{
|
||||||
|
netfs_interface_t *netfs = (netfs_interface_t *)intf;
|
||||||
|
|
||||||
|
/* record underlying interface */
|
||||||
|
fp->intf = intf;
|
||||||
|
|
||||||
|
fp->open = glue_open;
|
||||||
|
fp->read = (fops_read_t)netfs->netfs_read;
|
||||||
|
fp->close = (fops_close_t)netfs->netfs_close;
|
||||||
|
fp->infosize = (fops_infosize_t)netfs->netfs_infosize;
|
||||||
|
fp->seek = (fops_seek_t)netfs->netfs_seek;
|
||||||
|
fp->setdefaults = (fops_setdefaults_t)netfs_setdefaults;
|
||||||
|
fp->getdefault_path = (fops_getdefault_path_t)netfs_getdefault_path;
|
||||||
|
fp->intf = intf;
|
||||||
|
|
||||||
|
/* fill out the name of the underlying file system */
|
||||||
|
netfs->netfs_name(netfs, fp->name, FILEOPS_NAME_MAXLEN);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
33
glue_netfs.h
Normal file
33
glue_netfs.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GLUE_NETFS_H__
|
||||||
|
#define __GLUE_NETFS_H__
|
||||||
|
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
|
extern fileops_fs_t netfs_glue;
|
||||||
|
|
||||||
|
#endif /* __GLUE_NETFS_H__ */
|
19
gnu-efi-3.0a-ia32.patch
Normal file
19
gnu-efi-3.0a-ia32.patch
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
diff -urN gnu-efi-3.0a/gnuefi/elf_ia32_efi.lds gnu-efi-3.0a-ia32/gnuefi/elf_ia32_efi.lds
|
||||||
|
--- gnu-efi-3.0a/gnuefi/elf_ia32_efi.lds 2002-02-22 15:43:28.000000000 -0800
|
||||||
|
+++ gnu-efi-3.0a-ia32/gnuefi/elf_ia32_efi.lds 2003-08-21 13:36:51.000000000 -0700
|
||||||
|
@@ -17,6 +17,7 @@
|
||||||
|
*(.rodata*)
|
||||||
|
*(.data)
|
||||||
|
*(.data1)
|
||||||
|
+ *(.data.*)
|
||||||
|
*(.sdata)
|
||||||
|
*(.got.plt)
|
||||||
|
*(.got)
|
||||||
|
@@ -34,6 +35,7 @@
|
||||||
|
.rel :
|
||||||
|
{
|
||||||
|
*(.rel.data)
|
||||||
|
+ *(.rel.data.*)
|
||||||
|
*(.rel.got)
|
||||||
|
*(.rel.stab)
|
||||||
|
}
|
51
ia32/Makefile
Normal file
51
ia32/Makefile
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#
|
||||||
|
# Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
# Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
#
|
||||||
|
# This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
#
|
||||||
|
# ELILO is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# ELILO is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
# Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
# 02111-1307, USA.
|
||||||
|
#
|
||||||
|
# Please check out the elilo.txt for complete documentation on how
|
||||||
|
# to use this program.
|
||||||
|
#
|
||||||
|
|
||||||
|
include ../Make.defaults
|
||||||
|
include ../Make.rules
|
||||||
|
|
||||||
|
TOPDIR=$(CDIR)/..
|
||||||
|
|
||||||
|
FILES=system.o config.o
|
||||||
|
|
||||||
|
TARGET=sysdeps.o
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
system.o: rmswitch.h
|
||||||
|
|
||||||
|
rmswitch.h: bin_to_h.c rmswitch.S
|
||||||
|
$(CC) -o bin_to_h bin_to_h.c
|
||||||
|
$(AS) -o rmswitch.o rmswitch.S
|
||||||
|
$(LD) -Ttext 0x0 -s --oformat binary -o rmswitch rmswitch.o
|
||||||
|
./bin_to_h <rmswitch >rmswitch.h
|
||||||
|
|
||||||
|
$(TARGET): $(FILES)
|
||||||
|
$(LD) -r -o $@ $(FILES)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) -f $(TARGET) $(FILES)
|
||||||
|
$(RM) -f bin_to_h.o bin_to_h
|
||||||
|
$(RM) -f rmswitch.h rmswitch.o rmswitch
|
27
ia32/bin_to_h.c
Normal file
27
ia32/bin_to_h.c
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
unsigned n = 0;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
printf("UINT8 rmswitch_image[] = {\n");
|
||||||
|
|
||||||
|
while ((c = getchar()) != EOF) {
|
||||||
|
printf("0x%02x,%s",
|
||||||
|
c & 0xFF,
|
||||||
|
(++n & 0x07) ? " " : "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n & 0x07) {
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(
|
||||||
|
"};\n"
|
||||||
|
"UINTN rmswitch_size = sizeof rmswitch_image;\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
103
ia32/config.c
Normal file
103
ia32/config.c
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* Contributed by Chris Ahna <christopher.j.ahna@intel.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "private.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINTN legacy_free_boot;
|
||||||
|
} ia32_global_config_t;
|
||||||
|
|
||||||
|
|
||||||
|
static ia32_global_config_t ia32_gconf;
|
||||||
|
|
||||||
|
static config_option_t sysdeps_global_options[]={
|
||||||
|
{OPT_BOOL, OPT_GLOBAL, L"legacy-free", NULL, NULL, &ia32_gconf.legacy_free_boot}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IA-32 operations that need to be done only once and just before
|
||||||
|
* entering the main loop of the loader
|
||||||
|
* Return:
|
||||||
|
* 0 if sucessful
|
||||||
|
* -1 otherwise (will abort execution)
|
||||||
|
*/
|
||||||
|
INTN
|
||||||
|
sysdeps_preloop_actions(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IA32_CMDLINE_OPTIONS L""
|
||||||
|
|
||||||
|
CHAR16 *
|
||||||
|
sysdeps_get_cmdline_opts(VOID)
|
||||||
|
{
|
||||||
|
return IA32_CMDLINE_OPTIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
sysdeps_getopt(INTN c, INTN optind, CHAR16 *optarg)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
sysdeps_print_cmdline_opts(VOID)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
INTN
|
||||||
|
ia32_use_legacy_free_boot(VOID)
|
||||||
|
{
|
||||||
|
return ia32_gconf.legacy_free_boot ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
sysdeps_register_options(VOID)
|
||||||
|
{
|
||||||
|
INTN ret;
|
||||||
|
|
||||||
|
ret = register_config_options(sysdeps_global_options,
|
||||||
|
sizeof(sysdeps_global_options)/sizeof(config_option_t),
|
||||||
|
OPTIONS_GROUP_GLOBAL);
|
||||||
|
#if 0
|
||||||
|
/* no per image options yet */
|
||||||
|
if (ret == -1 ) return ret;
|
||||||
|
|
||||||
|
ret = register_config_options(sysdeps_image_options,
|
||||||
|
sizeof(sysdeps_image_options)/sizeof(config_option_t),
|
||||||
|
OPTIONS_GROUP_IMAGE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
30
ia32/private.h
Normal file
30
ia32/private.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ELILO_PRIVATE_IA32_H__
|
||||||
|
#define __ELILO_PRIVATE_IA32_H__
|
||||||
|
|
||||||
|
#endif /* __ELILO_PRIVATE_IA32_H__ */
|
||||||
|
|
118
ia32/rmswitch.S
Normal file
118
ia32/rmswitch.S
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
#
|
||||||
|
# Switch from protected mode to real mode and jump to setup.S
|
||||||
|
# image located at %cx:0.
|
||||||
|
#
|
||||||
|
# This module must be placed into physical memory at 0:7C00h.
|
||||||
|
# EFI has some real mode thunking code at 2000:0h.
|
||||||
|
#
|
||||||
|
# Processor and non-maskable interrupts should be disabled
|
||||||
|
# before control is passed to this module.
|
||||||
|
#
|
||||||
|
|
||||||
|
.global _start
|
||||||
|
|
||||||
|
.code32
|
||||||
|
.text
|
||||||
|
_start:
|
||||||
|
#
|
||||||
|
# Load identity mapped GDT & real mode IDT.
|
||||||
|
# Add 7C00h to the addresses since this is linked to start
|
||||||
|
# at 0h and it is being placed at 7C00h.
|
||||||
|
#
|
||||||
|
|
||||||
|
lgdt %cs:gdt_48 + 0x7C00
|
||||||
|
lidt %cs:idt_48 + 0x7C00
|
||||||
|
|
||||||
|
#
|
||||||
|
# Turn off PG bit in CR0 and set CR3 to zero.
|
||||||
|
#
|
||||||
|
|
||||||
|
movl %cr0, %eax
|
||||||
|
andl $0x7FFFFFFF, %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
xorl %eax, %eax
|
||||||
|
movl %eax, %cr3
|
||||||
|
|
||||||
|
#
|
||||||
|
# Reload CS.
|
||||||
|
# Now we add 7B00h because we need to force the segment
|
||||||
|
# address and selector to be the same.
|
||||||
|
#
|
||||||
|
|
||||||
|
.byte 0xEA
|
||||||
|
.long pm_reload + 0x7B00
|
||||||
|
.word 0x10
|
||||||
|
|
||||||
|
pm_reload:
|
||||||
|
|
||||||
|
.code16
|
||||||
|
|
||||||
|
#
|
||||||
|
# Reload DS, ES, FS, GS & SS.
|
||||||
|
#
|
||||||
|
|
||||||
|
movw $0x18, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %fs
|
||||||
|
movw %ax, %gs
|
||||||
|
movw %ax, %ss
|
||||||
|
|
||||||
|
#
|
||||||
|
# Switch to real mode. Clear PE bit in CR0.
|
||||||
|
#
|
||||||
|
|
||||||
|
movl %cr0, %eax
|
||||||
|
andl $0xFFFFFFFE, %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
#
|
||||||
|
# Reload CS.
|
||||||
|
#
|
||||||
|
|
||||||
|
.byte 0xEA
|
||||||
|
.word rm_reload + 0x7C00
|
||||||
|
.word 0
|
||||||
|
|
||||||
|
rm_reload:
|
||||||
|
|
||||||
|
#
|
||||||
|
# Reload SS & SP.
|
||||||
|
#
|
||||||
|
|
||||||
|
xorw %ax, %ax
|
||||||
|
movw %ax, %ss
|
||||||
|
movw $0x7BFE, %sp
|
||||||
|
|
||||||
|
#
|
||||||
|
# Start running setup.S
|
||||||
|
#
|
||||||
|
|
||||||
|
.byte 0xEA
|
||||||
|
.word 0
|
||||||
|
.word 0x9020
|
||||||
|
|
||||||
|
#
|
||||||
|
# GDT & IDT stuff for switching into real mode.
|
||||||
|
#
|
||||||
|
|
||||||
|
gdt: .word 0, 0, 0, 0 # unused (00h)
|
||||||
|
.word 0, 0, 0, 0 # dummy (08h)
|
||||||
|
.word 0xFFFF, 0x100 # code (10h)
|
||||||
|
.word 0x9A00, 0
|
||||||
|
.word 0xFFFF, 0x180 # data (18h)
|
||||||
|
.word 0x9200, 0
|
||||||
|
|
||||||
|
gdt_48: .word 0x08 * 0x400
|
||||||
|
.long gdt + 0x7C00
|
||||||
|
|
||||||
|
idt_48: .word 0x400
|
||||||
|
.long 0
|
||||||
|
|
||||||
|
#
|
||||||
|
# Be careful not to exceed 1F0h or the the bootsect.S
|
||||||
|
# parameters will be lost!
|
||||||
|
#
|
||||||
|
|
||||||
|
.end
|
440
ia32/sysdeps.h
Normal file
440
ia32/sysdeps.h
Normal file
|
@ -0,0 +1,440 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* Contributed by Mike Johnston <johnston@intel.com>
|
||||||
|
* Contributed by Chris Ahna <christopher.j.ahna@intel.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is used to define all the IA32-specific data structures
|
||||||
|
* and constant used by the generic ELILO
|
||||||
|
*/
|
||||||
|
#ifndef __ELILO_SYSDEPS_IA32_H__
|
||||||
|
#define __ELILO_SYSDEPS_IA32_H__
|
||||||
|
|
||||||
|
#define ELILO_ARCH "IA-32" /* ASCII string */
|
||||||
|
|
||||||
|
/* for now use library versions */
|
||||||
|
#define Memset(a,v,n) SetMem((a),(n),(v))
|
||||||
|
#define Memcpy(a,b,n) CopyMem((a),(b),(n))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This version must match the one in the kernel.
|
||||||
|
*
|
||||||
|
* This table was put together using information from the
|
||||||
|
* following Linux kernel source files:
|
||||||
|
* linux/include/tty.h
|
||||||
|
* linux/arch/i386/kernel/setup.c
|
||||||
|
* linux/arch/i386/boot/bootsect.S
|
||||||
|
* linux/arch/i386/boot/setup.S
|
||||||
|
* linux/arch/i386/boot/video.S
|
||||||
|
*
|
||||||
|
* New fields in this structure for EFI and ELILO are:
|
||||||
|
* efi_loader_sig
|
||||||
|
* efi_st_addr
|
||||||
|
*
|
||||||
|
* A new bit, LDRFLAG_BOOT_PARAM_RELOC, in the loader_flags
|
||||||
|
* field is also defined in this file.
|
||||||
|
*/
|
||||||
|
typedef struct efi_ia32_boot_params {
|
||||||
|
UINT32 size;
|
||||||
|
UINT32 command_line;
|
||||||
|
UINT32 efi_sys_tbl;
|
||||||
|
UINT32 efi_mem_map;
|
||||||
|
UINT32 efi_mem_map_size;
|
||||||
|
UINT32 efi_mem_desc_size;
|
||||||
|
UINT32 efi_mem_desc_version;
|
||||||
|
UINT32 initrd_start;
|
||||||
|
UINT32 initrd_size;
|
||||||
|
UINT32 loader_start;
|
||||||
|
UINT32 loader_size;
|
||||||
|
UINT32 kernel_start;
|
||||||
|
UINT32 kernel_size;
|
||||||
|
UINT16 num_cols;
|
||||||
|
UINT16 num_rows;
|
||||||
|
UINT16 orig_x;
|
||||||
|
UINT16 orig_y;
|
||||||
|
} efi_ia32_boot_params_t;
|
||||||
|
|
||||||
|
extern efi_ia32_boot_params_t efi_ia32_bp;
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
typedef union ia32_boot_params {
|
||||||
|
UINT8 raw[0x2000];
|
||||||
|
struct {
|
||||||
|
/* Cursor position before passing control to kernel. */
|
||||||
|
/* 0x00 */ UINT8 orig_cursor_col; /* LDR */
|
||||||
|
/* 0x01 */ UINT8 orig_cursor_row; /* LDR */
|
||||||
|
|
||||||
|
/* Available contiguous extended memory in KB. */
|
||||||
|
/* 0x02 */ UINT16 ext_mem_k; /* LDR */
|
||||||
|
|
||||||
|
/* Video page, mode and screen width before passing control to kernel. */
|
||||||
|
/* 0x04 */ UINT16 orig_video_page; /* LDR */
|
||||||
|
/* 0x06 */ UINT8 orig_video_mode; /* LDR */
|
||||||
|
/* 0x07 */ UINT8 orig_video_cols; /* LDR */
|
||||||
|
|
||||||
|
/* 0x08 */ UINT16 unused_1; /* unused */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x0A */ UINT16 orig_ega_bx; /* LDR */
|
||||||
|
|
||||||
|
/* 0x0C */ UINT16 unused_2; /* unused */
|
||||||
|
|
||||||
|
/* Screen height before passing control to kernel. */
|
||||||
|
/* 0x0E */ UINT8 orig_video_rows; /* LDR */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x0F */ UINT8 is_vga; /* LDR */
|
||||||
|
/* 0x10 */ UINT16 orig_video_points; /* LDR */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x12 */ UINT16 lfb_width; /* LDR */
|
||||||
|
/* 0x14 */ UINT16 lfb_height; /* LDR */
|
||||||
|
/* 0x16 */ UINT16 lfb_depth; /* LDR */
|
||||||
|
/* 0x18 */ UINT32 lfb_base; /* LDR */
|
||||||
|
/* 0x1C */ UINT32 lfb_size; /* LDR */
|
||||||
|
|
||||||
|
/* Offset of command line (from start of ia32_boot_param struct). */
|
||||||
|
/* The command line magik number must be set for the kernel setup */
|
||||||
|
/* code to use the command line offset. */
|
||||||
|
/* 0x20 */ UINT16 cmdline_magik; /* LDR */
|
||||||
|
#define CMDLINE_MAGIK 0xA33F
|
||||||
|
/* 0x22 */ UINT16 cmdline_offset; /* LDR */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x24 */ UINT16 lfb_line_len; /* LDR */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x26 */ UINT8 lfb_red_size; /* LDR */
|
||||||
|
/* 0x27 */ UINT8 lfb_red_pos; /* LDR */
|
||||||
|
/* 0x28 */ UINT8 lfb_green_size; /* LDR */
|
||||||
|
/* 0x29 */ UINT8 lfb_green_pos; /* LDR */
|
||||||
|
/* 0x2A */ UINT8 lfb_blue_size; /* LDR */
|
||||||
|
/* 0x2B */ UINT8 lfb_blue_pos; /* LDR */
|
||||||
|
/* 0x2C */ UINT8 lfb_rsvd_size; /* LDR */
|
||||||
|
/* 0x2D */ UINT8 lfb_rsvd_pos; /* LDR */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x2E */ UINT16 vesa_seg; /* LDR */
|
||||||
|
/* 0x30 */ UINT16 vesa_off; /* LDR */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x32 */ UINT16 lfb_pages; /* LDR */
|
||||||
|
/* 0x34 */ UINT8 lfb_reserved[0x0C]; /* reserved */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x40 */ UINT16 apm_bios_ver; /* LDR */
|
||||||
|
#define NO_APM_BIOS 0x0000
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x42 */ UINT16 bios_code_seg; /* LDR */
|
||||||
|
/* 0x44 */ UINT32 bios_entry_point; /* LDR */
|
||||||
|
/* 0x48 */ UINT16 bios_code_seg16; /* LDR */
|
||||||
|
/* 0x4A */ UINT16 bios_data_seg; /* LDR */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x4C */ UINT16 apm_bios_flags; /* LDR */
|
||||||
|
#define NO_32BIT_APM_MASK 0xFFFD
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x4E */ UINT32 bios_code_len; /* LDR */
|
||||||
|
/* 0x52 */ UINT16 bios_data_len; /* LDR */
|
||||||
|
|
||||||
|
/* 0x54 */ UINT8 unused_3[0x2C]; /* unused */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x80 */ UINT8 hd0_info[0x10]; /* LDR */
|
||||||
|
/* 0x90 */ UINT8 hd1_info[0x10]; /* LDR */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0xA0 */ UINT16 mca_info_len; /* LDR */
|
||||||
|
/* 0xA2 */ UINT8 mca_info_buf[0x10]; /* LDR */
|
||||||
|
|
||||||
|
/* 0xB2 */ UINT8 unused_4[0x10E]; /* unused */
|
||||||
|
|
||||||
|
/* EFI boot loader signature. */
|
||||||
|
/* 0x1C0 */ UINT8 efi_loader_sig[4]; /* LDR */
|
||||||
|
#define EFI_LOADER_SIG "EFIL"
|
||||||
|
|
||||||
|
/* Address of the EFI system table. */
|
||||||
|
/* 0x1C4 */ UINT32 efi_sys_tbl; /* LDR */
|
||||||
|
|
||||||
|
/* EFI memory descriptor size. */
|
||||||
|
/* 0x1C8 */ UINT32 efi_mem_desc_size; /* LDR */
|
||||||
|
|
||||||
|
/* EFI memory descriptor version. */
|
||||||
|
/* 0x1CC */ UINT32 efi_mem_desc_ver; /* LDR */
|
||||||
|
|
||||||
|
/* Address & size of EFI memory map. */
|
||||||
|
/* 0x1D0 */ UINT32 efi_mem_map; /* LDR */
|
||||||
|
/* 0x1D4 */ UINT32 efi_mem_map_size; /* LDR */
|
||||||
|
|
||||||
|
/* Address & size of loader. */
|
||||||
|
/* 0x1D8 */ UINT32 loader_start; /* LDR */
|
||||||
|
/* 0x1DC */ UINT32 loader_size; /* LDR */
|
||||||
|
|
||||||
|
/* Available contiguous extended memory in KB. */
|
||||||
|
/* 0x1E0 */ UINT32 alt_mem_k; /* LDR */
|
||||||
|
|
||||||
|
/* 0x1E4 */ UINT8 unused_5[0x0D]; /* unused */
|
||||||
|
|
||||||
|
/* Size of setup code in sectors (1 sector == 512 bytes). */
|
||||||
|
/* 0x1F1 */ UINT8 setup_sectors; /* BLD */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x1F2 */ UINT16 mount_root_rdonly; /* BLD */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x1F4 */ UINT16 sys_size; /* BLD */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x1F6 */ UINT16 swap_dev; /* BLD */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x1F8 */ UINT16 ramdisk_flags; /* BLD */
|
||||||
|
#define RAMDISK_PROMPT 0x8000
|
||||||
|
#define RAMDISK_LOAD 0x4000
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x1FA */ UINT16 video_mode_flag; /* BLD */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x1FC */ UINT16 orig_root_dev; /* BLD */
|
||||||
|
|
||||||
|
/* 0x1FE */ UINT8 unused_6; /* unused */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x1FF */ UINT8 aux_dev_info; /* LDR */
|
||||||
|
#define NO_MOUSE 0x00
|
||||||
|
#define FOUND_MOUSE 0xAA
|
||||||
|
|
||||||
|
/* Jump past setup data (not used in EFI). */
|
||||||
|
/* 0x200 */ UINT16 jump; /* BLD */
|
||||||
|
|
||||||
|
/* Setup data signature. */
|
||||||
|
/* 0x202 */ UINT8 setup_sig[4]; /* BLD */
|
||||||
|
#define SETUP_SIG "HdrS"
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x206 */ UINT8 hdr_minor; /* BLD */
|
||||||
|
/* 0x207 */ UINT8 hdr_major; /* BLD */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x208 */ UINT32 rm_switch; /* LDD */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x20C */ UINT16 start_sys_seg; /* BLD */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x20E */ UINT16 kernel_verstr_offset; /* BLD */
|
||||||
|
|
||||||
|
/* Loader type & version. */
|
||||||
|
/* 0x210 */ UINT8 loader_type; /* LDR */
|
||||||
|
#define LDRTYPE_ELILO 0x50 /* 5?h == elilo */
|
||||||
|
/* ?0h == revision */
|
||||||
|
|
||||||
|
/* 0x211 */ UINT8 loader_flags; /* BLD and LDR */
|
||||||
|
#define LDRFLAG_CAN_USE_HEAP 0x80
|
||||||
|
#define LDRFLAG_BOOT_PARAM_RELOC 0x40
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x212 */ UINT16 setup_move_size; /* BLD */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x214 */ UINT32 kernel_start; /* LDR */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x218 */ UINT32 initrd_start; /* LDR */
|
||||||
|
/* 0x21C */ UINT32 initrd_size; /* LDR */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x220 */ UINT32 bootsect_helper; /* BLD */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x224 */ UINT16 heap_end_ptr; /* LDR */
|
||||||
|
|
||||||
|
/* %%TBD */
|
||||||
|
/* 0x226 */ UINT32 base_mem_size; /* LDR */
|
||||||
|
} s;
|
||||||
|
} boot_params_t;
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The stuff below here is for jumping to the kernel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some macros to copy and set memory after EFI has been
|
||||||
|
* stopped.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MEMCPY(to, from, cnt) { \
|
||||||
|
UINT8 *t = (UINT8 *)(to); \
|
||||||
|
UINT8 *f = (UINT8 *)(from); \
|
||||||
|
UINTN n = cnt; \
|
||||||
|
if (t && f && n) { \
|
||||||
|
while (n--) { \
|
||||||
|
*t++ = *f++; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MEMSET(ptr, size, val) { \
|
||||||
|
UINT8 *p = (UINT8 *)(ptr); \
|
||||||
|
UINTN n = (UINTN)(size); \
|
||||||
|
UINT8 v = (UINT8)(val); \
|
||||||
|
if (p && n) { \
|
||||||
|
while (n--) { \
|
||||||
|
*p++ = v; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Descriptor table pointer format.
|
||||||
|
*/
|
||||||
|
#pragma pack(1)
|
||||||
|
typedef struct {
|
||||||
|
UINT16 limit;
|
||||||
|
UINT32 base;
|
||||||
|
} dt_addr_t;
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
extern UINTN high_base_mem;
|
||||||
|
extern UINTN high_ext_mem;
|
||||||
|
|
||||||
|
extern boot_params_t *param_start;
|
||||||
|
extern UINTN param_size;
|
||||||
|
|
||||||
|
extern VOID *kernel_start;
|
||||||
|
extern UINTN kernel_size;
|
||||||
|
|
||||||
|
extern VOID *initrd_start;
|
||||||
|
extern UINTN initrd_size;
|
||||||
|
|
||||||
|
extern dt_addr_t gdt_addr;
|
||||||
|
extern dt_addr_t idt_addr;
|
||||||
|
|
||||||
|
extern UINT16 init_gdt[];
|
||||||
|
extern UINTN sizeof_init_gdt;
|
||||||
|
|
||||||
|
extern UINT8 rmswitch_image[];
|
||||||
|
extern UINTN rmswitch_size;
|
||||||
|
|
||||||
|
extern INTN ia32_use_legacy_free_boot();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How to jump to kernel code
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
start_kernel(VOID *kentry, boot_params_t *bp)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Disable interrupts.
|
||||||
|
*/
|
||||||
|
|
||||||
|
asm volatile ( "cli" : : );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Relocate initrd, if present.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (bp->s.initrd_start) {
|
||||||
|
/* %%TBD */
|
||||||
|
MEMCPY(15 * 1024 * 1024, bp->s.initrd_start, bp->s.initrd_size);
|
||||||
|
bp->s.initrd_start = 15 * 1024 * 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy boot sector, setup data and command line
|
||||||
|
* to final resting place. We need to copy
|
||||||
|
* BOOT_PARAM_MEMSIZE bytes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
MEMCPY(high_base_mem, bp, 0x4000);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initialize efi ia32 boot params and place them at 1kb up from
|
||||||
|
* the start of the boot command line param. This results in the
|
||||||
|
* efi ia32 boot params to be copied to 0x00104c00. See bootparams.c
|
||||||
|
* for details on how this is arranged. EFI enabled
|
||||||
|
* kernels will look for the efi boot params here to know if the
|
||||||
|
* kernel is booting on an EFI platform or legacy BIOS based platfrom
|
||||||
|
*/
|
||||||
|
|
||||||
|
efi_ia32_bp.initrd_start = bp->s.initrd_start;
|
||||||
|
efi_ia32_bp.initrd_size = bp->s.initrd_size;
|
||||||
|
|
||||||
|
MEMCPY(high_base_mem + 0x4000 - 0x0400, &efi_ia32_bp, sizeof(efi_ia32_bp));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize Linux GDT.
|
||||||
|
*/
|
||||||
|
|
||||||
|
MEMSET(gdt_addr.base, gdt_addr.limit, 0);
|
||||||
|
MEMCPY(gdt_addr.base, init_gdt, sizeof_init_gdt);
|
||||||
|
|
||||||
|
if (! ia32_use_legacy_free_boot()) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy our real mode transition code to 0x7C00.
|
||||||
|
*/
|
||||||
|
|
||||||
|
MEMCPY(0x7C00, rmswitch_image, rmswitch_size);
|
||||||
|
|
||||||
|
asm volatile ( "movl $0x7C00, %%ebx" : : );
|
||||||
|
asm volatile ( "jmp *%%ebx" : : );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load descriptor table pointers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
asm volatile ( "lidt %0" : : "m" (idt_addr) );
|
||||||
|
asm volatile ( "lgdt %0" : : "m" (gdt_addr) );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ebx := 0 (%%TBD - do not know why, yet)
|
||||||
|
* ecx := kernel entry point
|
||||||
|
* esi := address of boot sector and setup data
|
||||||
|
*/
|
||||||
|
|
||||||
|
asm volatile ( "movl %0, %%esi" : : "m" (high_base_mem) );
|
||||||
|
asm volatile ( "movl %0, %%ecx" : : "m" (kentry) );
|
||||||
|
asm volatile ( "xorl %%ebx, %%ebx" : : );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Jump to kernel entry point.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
asm volatile ( "jmp *%%ecx" : : );
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct sys_img_options {
|
||||||
|
UINT8 nothing_yet;
|
||||||
|
} sys_img_options_t;
|
||||||
|
|
||||||
|
#endif /* __ELILO_SYSDEPS_IA32_H__ */
|
798
ia32/system.c
Normal file
798
ia32/system.c
Normal file
|
@ -0,0 +1,798 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* Contributed by Mike Johnston <johnston@intel.com>
|
||||||
|
* Contributed by Chris Ahna <christopher.j.ahna@intel.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this file contains all the IA-32 specific code expected by generic loader
|
||||||
|
*/
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
#include "loader.h"
|
||||||
|
|
||||||
|
#include "rmswitch.h"
|
||||||
|
|
||||||
|
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
/* extern loader_ops_t plain_loader, gzip_loader; */
|
||||||
|
|
||||||
|
efi_ia32_boot_params_t efi_ia32_bp;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Descriptor table base addresses & limits for Linux startup.
|
||||||
|
*/
|
||||||
|
|
||||||
|
dt_addr_t gdt_addr = { 0x800, 0x94000 };
|
||||||
|
dt_addr_t idt_addr = { 0, 0 };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initial GDT layout for Linux startup.
|
||||||
|
*/
|
||||||
|
|
||||||
|
UINT16 init_gdt[] = {
|
||||||
|
/* gdt[0]: dummy */
|
||||||
|
0, 0, 0, 0,
|
||||||
|
|
||||||
|
/* gdt[1]: unused */
|
||||||
|
0, 0, 0, 0,
|
||||||
|
|
||||||
|
/* gdt[2]: code */
|
||||||
|
0xFFFF, /* 4Gb - (0x100000*0x1000 = 4Gb) */
|
||||||
|
0x0000, /* base address=0 */
|
||||||
|
0x9A00, /* code read/exec */
|
||||||
|
0x00CF, /* granularity=4096, 386 (+5th nibble of limit) */
|
||||||
|
|
||||||
|
/* gdt[3]: data */
|
||||||
|
0xFFFF, /* 4Gb - (0x100000*0x1000 = 4Gb) */
|
||||||
|
0x0000, /* base address=0 */
|
||||||
|
0x9200, /* data read/write */
|
||||||
|
0x00CF, /* granularity=4096, 386 (+5th nibble of limit) */
|
||||||
|
};
|
||||||
|
|
||||||
|
UINTN sizeof_init_gdt = sizeof init_gdt;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Highest available base memory address.
|
||||||
|
*
|
||||||
|
* For traditional kernels and loaders this is always at 0x90000.
|
||||||
|
* For updated kernels and loaders this is computed by taking the
|
||||||
|
* highest available base memory address and rounding down to the
|
||||||
|
* nearest 64 kB boundary and then subtracting 64 kB.
|
||||||
|
*
|
||||||
|
* A non-compressed kernel is automatically assumed to be an updated
|
||||||
|
* kernel. A compressed kernel that has bit 6 (0x40) set in the
|
||||||
|
* loader_flags field is also assumed to be an updated kernel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
UINTN high_base_mem = 0x90000;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Highest available extended memory address.
|
||||||
|
*
|
||||||
|
* This is computed by taking the highest available extended memory
|
||||||
|
* address and rounding down to the nearest EFI_PAGE_SIZE (usually
|
||||||
|
* 4 kB) boundary. The ia32 Linux kernel can only support up to
|
||||||
|
* 2 GB (AFAIK).
|
||||||
|
*/
|
||||||
|
|
||||||
|
UINTN high_ext_mem = 32 * 1024 * 1024;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Starting location and size of runtime memory blocks.
|
||||||
|
*/
|
||||||
|
|
||||||
|
boot_params_t *param_start = NULL;
|
||||||
|
UINTN param_size = 0;
|
||||||
|
|
||||||
|
VOID *kernel_start = (VOID *)0x100000; /* 1M */
|
||||||
|
UINTN kernel_size = 0x200000; /* 2M (largest x86 kernel image) */
|
||||||
|
|
||||||
|
VOID *initrd_start = NULL;
|
||||||
|
UINTN initrd_size = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Boot parameters can be relocated if TRUE.
|
||||||
|
* Boot parameters must be placed at 0x90000 if FALSE.
|
||||||
|
*
|
||||||
|
* This will be set to TRUE if bit 6 (0x40) is set in the loader_flags
|
||||||
|
* field in a compressed x86 boot format kernel. This will also be set
|
||||||
|
* to TRUE if the kernel is an uncompressed ELF32 image.
|
||||||
|
*
|
||||||
|
* To remote boot w/ the universal network driver and a 16-bit UNDI
|
||||||
|
* this must be set to TRUE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
BOOLEAN can_reloc_boot_params = FALSE;
|
||||||
|
|
||||||
|
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
static INTN
|
||||||
|
probe_bzImage_boot(CHAR16 *kname)
|
||||||
|
{
|
||||||
|
EFI_STATUS efi_status;
|
||||||
|
UINTN size;
|
||||||
|
fops_fd_t fd;
|
||||||
|
UINT8 bootsect[512];
|
||||||
|
|
||||||
|
DBG_PRT((L"probe_bzImage_boot()\n"));
|
||||||
|
|
||||||
|
if (!kname) {
|
||||||
|
ERR_PRT((L"kname == %xh", kname));
|
||||||
|
free_kmem();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open kernel image.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DBG_PRT((L"opening %s...\n", kname));
|
||||||
|
|
||||||
|
efi_status = fops_open(kname, &fd);
|
||||||
|
|
||||||
|
if (EFI_ERROR(efi_status)) {
|
||||||
|
ERR_PRT((L"Could not open %s.", kname));
|
||||||
|
free_kmem();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read boot sector.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DBG_PRT((L"\nreading boot sector...\n"));
|
||||||
|
|
||||||
|
size = sizeof bootsect;
|
||||||
|
efi_status = fops_read(fd, bootsect, &size);
|
||||||
|
|
||||||
|
if (EFI_ERROR(efi_status) || size != sizeof bootsect) {
|
||||||
|
ERR_PRT((L"Could not read boot sector from %s.", kname));
|
||||||
|
fops_close(fd);
|
||||||
|
free_kmem();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify boot sector signature.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (bootsect[0x1FE] != 0x55 || bootsect[0x1FF] != 0xAA) {
|
||||||
|
ERR_PRT((L"%s is not a bzImage kernel image.\n", kname));
|
||||||
|
fops_close(fd);
|
||||||
|
free_kmem();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for out of range setup data size.
|
||||||
|
* Will almost always be 7, but we will accept 1 to 64.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DBG_PRT((L"bootsect[1F1h] == %d setup sectors\n", bootsect[0x1F1]));
|
||||||
|
|
||||||
|
if (bootsect[0x1F1] < 1 || bootsect[0x1F1] > 64) {
|
||||||
|
ERR_PRT((L"%s is not a valid bzImage kernel image.",
|
||||||
|
kname));
|
||||||
|
|
||||||
|
fops_close(fd);
|
||||||
|
free_kmem();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and read setup data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DBG_PRT((L"reading setup data...\n"));
|
||||||
|
|
||||||
|
param_size = (bootsect[0x1F1] + 1) * 512;
|
||||||
|
//param_start = alloc(param_size, EfiBootServicesData);
|
||||||
|
param_start = alloc(param_size, EfiLoaderData);
|
||||||
|
|
||||||
|
DBG_PRT((L"param_size=%d param_start=%x", param_size, param_start));
|
||||||
|
|
||||||
|
if (!param_start) {
|
||||||
|
ERR_PRT((L"Could not allocate %d bytes of setup data.",
|
||||||
|
param_size));
|
||||||
|
|
||||||
|
fops_close(fd);
|
||||||
|
free_kmem();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyMem(param_start, bootsect, sizeof bootsect);
|
||||||
|
|
||||||
|
size = param_size - 512;
|
||||||
|
efi_status = fops_read(fd, ((UINT8 *)param_start) + 512, &size);
|
||||||
|
|
||||||
|
if (EFI_ERROR(efi_status) || size != param_size - 512) {
|
||||||
|
ERR_PRT((L"Could not read %d bytes of setup data.",
|
||||||
|
param_size - 512));
|
||||||
|
|
||||||
|
free(param_start);
|
||||||
|
param_start = NULL;
|
||||||
|
param_size = 0;
|
||||||
|
fops_close(fd);
|
||||||
|
free_kmem();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for setup data signature.
|
||||||
|
*/
|
||||||
|
|
||||||
|
{ UINT8 *c = ((UINT8 *)param_start)+514;
|
||||||
|
DBG_PRT((L"param_start(c=%x): %c-%c-%c-%c", c, (CHAR16)c[0],(CHAR16) c[1], (CHAR16)c[2], (CHAR16)c[3]));
|
||||||
|
}
|
||||||
|
if (CompareMem(((UINT8 *)param_start) + 514, "HdrS", 4)) {
|
||||||
|
ERR_PRT((L"%s does not have a setup signature.",
|
||||||
|
kname));
|
||||||
|
|
||||||
|
free(param_start);
|
||||||
|
param_start = NULL;
|
||||||
|
param_size = 0;
|
||||||
|
fops_close(fd);
|
||||||
|
free_kmem();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate memory for kernel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (alloc_kmem(kernel_start, EFI_SIZE_TO_PAGES(kernel_size))) {
|
||||||
|
ERR_PRT((L"Could not allocate kernel memory."));
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
VERB_PRT(3, Print(L"kernel_start: 0x%x kernel_size: %d\n", kernel_start, kernel_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now read the rest of the kernel image into memory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DBG_PRT((L"reading kernel image...\n"));
|
||||||
|
|
||||||
|
size = kernel_size;
|
||||||
|
|
||||||
|
efi_status = fops_read(fd, kernel_start, &size);
|
||||||
|
|
||||||
|
if (EFI_ERROR(efi_status) || size < 0x10000) {
|
||||||
|
ERR_PRT((L"Error reading kernel image %s.", kname));
|
||||||
|
free(param_start);
|
||||||
|
param_start = NULL;
|
||||||
|
param_size = 0;
|
||||||
|
fops_close(fd);
|
||||||
|
free_kmem();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG_PRT((L"kernel image read: %d bytes, %d Kbytes\n", size, size / 1024));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Boot sector, setup data and kernel image loaded.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fops_close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
static INTN
|
||||||
|
load_bzImage_boot(CHAR16 *kname, kdesc_t *kd)
|
||||||
|
{
|
||||||
|
DBG_PRT((L"load_bzImage_boot()\n"));
|
||||||
|
|
||||||
|
if (!kname || !kd) {
|
||||||
|
ERR_PRT((L"kname=0x%x kd=0x%x", kname, kd));
|
||||||
|
|
||||||
|
free(param_start);
|
||||||
|
param_start = NULL;
|
||||||
|
param_size = 0;
|
||||||
|
free_kmem();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
kd->kstart = kd->kentry = kernel_start;
|
||||||
|
kd->kend = ((UINT8 *)kd->kstart) + kernel_size;
|
||||||
|
|
||||||
|
DBG_PRT((L"kstart=0x%x kentry=0x%x kend=0x%x\n", kd->kstart, kd->kentry, kd->kend));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
static loader_ops_t loader_bzImage_boot = {
|
||||||
|
NULL,
|
||||||
|
L"loader_bzImage_boot",
|
||||||
|
&probe_bzImage_boot,
|
||||||
|
&load_bzImage_boot
|
||||||
|
};
|
||||||
|
|
||||||
|
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
INTN
|
||||||
|
sysdeps_init(EFI_HANDLE dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
DBG_PRT((L"sysdeps_init()\n"));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register our loader(s)...
|
||||||
|
*/
|
||||||
|
|
||||||
|
loader_register(&loader_bzImage_boot);
|
||||||
|
/* loader_register(&plain_loader); */
|
||||||
|
/* loader_register(&gzip_loader); */
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
/*
|
||||||
|
* initrd_get_addr()
|
||||||
|
* Compute a starting address for the initial RAMdisk image.
|
||||||
|
* For now, this image is placed immediately after the end of
|
||||||
|
* the kernel memory. Inside the start_kernel() code, the
|
||||||
|
* RAMdisk image will be relocated to the top of available
|
||||||
|
* extended memory.
|
||||||
|
*/
|
||||||
|
INTN
|
||||||
|
sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem)
|
||||||
|
{
|
||||||
|
DBG_PRT((L"initrd_get_addr()\n"));
|
||||||
|
|
||||||
|
if (!kd || !imem) {
|
||||||
|
ERR_PRT((L"kd=0x%x imem=0x%x", kd, imem));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
VERB_PRT(3, Print(L"kstart=0x%x kentry=0x%x kend=0x%x\n",
|
||||||
|
kd->kstart, kd->kentry, kd->kend));
|
||||||
|
|
||||||
|
imem->start_addr = kd->kend;
|
||||||
|
|
||||||
|
VERB_PRT(3, Print(L"initrd start_addr=0x%x pgcnt=%d\n", imem->start_addr, imem->pgcnt));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
VOID
|
||||||
|
sysdeps_free_boot_params(boot_params_t *bp)
|
||||||
|
{
|
||||||
|
mmap_desc_t md;
|
||||||
|
|
||||||
|
ZeroMem(&md, sizeof md);
|
||||||
|
md.md = (VOID *)bp->s.efi_mem_map;
|
||||||
|
free_memmap(&md);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
/*
|
||||||
|
* IA-32 specific boot parameters initialization routine
|
||||||
|
*/
|
||||||
|
INTN
|
||||||
|
sysdeps_create_boot_params(
|
||||||
|
boot_params_t *bp,
|
||||||
|
CHAR8 *cmdline,
|
||||||
|
memdesc_t *initrd,
|
||||||
|
UINTN *cookie)
|
||||||
|
{
|
||||||
|
mmap_desc_t mdesc;
|
||||||
|
EFI_STATUS efi_status;
|
||||||
|
UINTN rows, cols;
|
||||||
|
UINT8 row, col;
|
||||||
|
UINT8 mode;
|
||||||
|
UINT16 hdr_version;
|
||||||
|
|
||||||
|
DBG_PRT((L"fill_boot_params()\n"));
|
||||||
|
|
||||||
|
if (!bp || !cmdline || !initrd || !cookie) {
|
||||||
|
ERR_PRT((L"bp=0x%x cmdline=0x%x initrd=0x%x cookie=0x%x",
|
||||||
|
bp, cmdline, initrd, cookie));
|
||||||
|
|
||||||
|
free(param_start);
|
||||||
|
param_start = NULL;
|
||||||
|
param_size = 0;
|
||||||
|
free_kmem();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy temporary boot sector and setup data storage to
|
||||||
|
* elilo allocated boot parameter storage. We only need
|
||||||
|
* the first two sectors (1K). The rest of the storage
|
||||||
|
* can be used by the command line.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CopyMem(bp, param_start, 0x2000);
|
||||||
|
|
||||||
|
free(param_start);
|
||||||
|
param_start = NULL;
|
||||||
|
param_size = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save off our header revision information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
hdr_version = (bp->s.hdr_major << 8) | bp->s.hdr_minor;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear out unused memory in boot sector image.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bp->s.unused_1 = 0;
|
||||||
|
bp->s.unused_2 = 0;
|
||||||
|
ZeroMem(bp->s.unused_3, sizeof bp->s.unused_3);
|
||||||
|
ZeroMem(bp->s.unused_4, sizeof bp->s.unused_4);
|
||||||
|
ZeroMem(bp->s.unused_5, sizeof bp->s.unused_5);
|
||||||
|
bp->s.unused_6 = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tell kernel this was loaded by an advanced loader type.
|
||||||
|
* If this field is zero, the initrd_start and initrd_size
|
||||||
|
* fields are ignored by the kernel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bp->s.loader_type = LDRTYPE_ELILO;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup command line information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bp->s.cmdline_magik = CMDLINE_MAGIK;
|
||||||
|
bp->s.cmdline_offset = (UINT8 *)cmdline - (UINT8 *)bp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup hard drive parameters.
|
||||||
|
* %%TBD - It should be okay to zero fill the hard drive
|
||||||
|
* info buffers. The kernel should do its own detection.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ZeroMem(bp->s.hd0_info, sizeof bp->s.hd0_info);
|
||||||
|
ZeroMem(bp->s.hd1_info, sizeof bp->s.hd1_info);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
CopyMem(bp->s.hd0_info, *((VOID **)(0x41 * 4)),
|
||||||
|
sizeof bp->s.hd0_info);
|
||||||
|
|
||||||
|
CopyMem(bp->s.hd1_info, *((VOID **)(0x46 * 4)),
|
||||||
|
sizeof bp->s.hd1_info);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Memory info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bp->s.alt_mem_k = high_ext_mem / 1024;
|
||||||
|
|
||||||
|
if (bp->s.alt_mem_k <= 65535) {
|
||||||
|
bp->s.ext_mem_k = (UINT16)bp->s.alt_mem_k;
|
||||||
|
} else {
|
||||||
|
bp->s.ext_mem_k = 65535;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr_version < 0x0202)
|
||||||
|
bp->s.base_mem_size = high_base_mem;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initial RAMdisk and root device stuff.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DBG_PRT((L"initrd->start_addr=0x%x initrd->pgcnt=%d\n",
|
||||||
|
initrd->start_addr, initrd->pgcnt));
|
||||||
|
|
||||||
|
/* These RAMdisk flags are not needed, just zero them. */
|
||||||
|
bp->s.ramdisk_flags = 0;
|
||||||
|
|
||||||
|
if (initrd->start_addr && initrd->pgcnt) {
|
||||||
|
/* %%TBD - This will probably have to be changed. */
|
||||||
|
bp->s.initrd_start = (UINT32)initrd->start_addr;
|
||||||
|
bp->s.initrd_size = (UINT32)(initrd->pgcnt * EFI_PAGE_SIZE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the RAMdisk root device for RedHat 2.2.x
|
||||||
|
* kernels (major 0x01, minor 0x00).
|
||||||
|
* %%TBD - Will this work for other distributions and
|
||||||
|
* 2.3.x and 2.4.x kernels? I do not know, yet.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bp->s.orig_root_dev = 0x0100;
|
||||||
|
} else {
|
||||||
|
bp->s.initrd_start = 0;
|
||||||
|
bp->s.initrd_size = 0;
|
||||||
|
|
||||||
|
/* Do not change the root device if there is no RAMdisk. */
|
||||||
|
/* bp->s.orig_root_dev = 0; */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* APM BIOS info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* %%TBD - How to do Int 15h calls to get this info? */
|
||||||
|
bp->s.apm_bios_ver = NO_APM_BIOS;
|
||||||
|
bp->s.bios_code_seg = 0;
|
||||||
|
bp->s.bios_entry_point = 0;
|
||||||
|
bp->s.bios_code_seg16 = 0;
|
||||||
|
bp->s.bios_data_seg = 0;
|
||||||
|
bp->s.apm_bios_flags = 0;
|
||||||
|
bp->s.bios_code_len = 0;
|
||||||
|
bp->s.bios_data_len = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MCA BIOS info (misnomer).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* %%TBD - How to do Int 15h call to get this info? */
|
||||||
|
bp->s.mca_info_len = 0;
|
||||||
|
ZeroMem(bp->s.mca_info_buf, sizeof bp->s.mca_info_buf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pointing device presence.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* %%TBD - How to do Int 11h call to get this info? */
|
||||||
|
bp->s.aux_dev_info = NO_MOUSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EFI loader signature and address of EFI system table.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG, 4);
|
||||||
|
bp->s.efi_sys_tbl = 0; /* %%TBD */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Kernel entry point.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bp->s.kernel_start = (UINT32)kernel_start;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When changing stuff in the parameter structure compare
|
||||||
|
* the offsets of the fields with the offsets used in the
|
||||||
|
* boot sector and setup source files.
|
||||||
|
* arch/i386/boot/bootsect.S
|
||||||
|
* arch/i386/boot/setup.S
|
||||||
|
* arch/i386/kernel/setup.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CHECK_OFFSET(n, o, f) \
|
||||||
|
{ \
|
||||||
|
UINTN p = (UINT8 *)&bp->s.n - (UINT8 *)bp; \
|
||||||
|
UINTN q = (UINTN)(o); \
|
||||||
|
if (p != q) { \
|
||||||
|
test |= 1; \
|
||||||
|
Print(L"%20a: %3xh %3xh ", #n, p, q); \
|
||||||
|
if (*f) { \
|
||||||
|
Print(f, bp->s.n); \
|
||||||
|
} \
|
||||||
|
Print(L"\n"); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define WAIT_FOR_KEY() \
|
||||||
|
{ \
|
||||||
|
EFI_INPUT_KEY key; \
|
||||||
|
while (ST->ConIn->ReadKeyStroke(ST->ConIn, &key) != EFI_SUCCESS) { \
|
||||||
|
; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
UINTN test = 0;
|
||||||
|
|
||||||
|
CHECK_OFFSET(orig_cursor_col, 0x00, L"%xh");
|
||||||
|
CHECK_OFFSET(orig_cursor_row, 0x01, L"%xh");
|
||||||
|
CHECK_OFFSET(ext_mem_k, 0x02, L"%xh");
|
||||||
|
CHECK_OFFSET(orig_video_page, 0x04, L"%xh");
|
||||||
|
CHECK_OFFSET(orig_video_mode, 0x06, L"%xh");
|
||||||
|
CHECK_OFFSET(orig_video_cols, 0x07, L"%xh");
|
||||||
|
CHECK_OFFSET(orig_ega_bx, 0x0A, L"%xh");
|
||||||
|
CHECK_OFFSET(orig_video_rows, 0x0E, L"%xh");
|
||||||
|
CHECK_OFFSET(is_vga, 0x0F, L"%xh");
|
||||||
|
CHECK_OFFSET(orig_video_points, 0x10, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_width, 0x12, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_height, 0x14, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_depth, 0x16, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_base, 0x18, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_size, 0x1C, L"%xh");
|
||||||
|
CHECK_OFFSET(cmdline_magik, 0x20, L"%xh");
|
||||||
|
CHECK_OFFSET(cmdline_offset, 0x22, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_line_len, 0x24, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_red_size, 0x26, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_red_pos, 0x27, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_green_size, 0x28, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_green_pos, 0x29, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_blue_size, 0x2A, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_blue_pos, 0x2B, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_rsvd_size, 0x2C, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_rsvd_pos, 0x2D, L"%xh");
|
||||||
|
CHECK_OFFSET(vesa_seg, 0x2E, L"%xh");
|
||||||
|
CHECK_OFFSET(vesa_off, 0x30, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_pages, 0x32, L"%xh");
|
||||||
|
CHECK_OFFSET(lfb_reserved, 0x34, L"");
|
||||||
|
CHECK_OFFSET(apm_bios_ver, 0x40, L"%xh");
|
||||||
|
CHECK_OFFSET(bios_code_seg, 0x42, L"%xh");
|
||||||
|
CHECK_OFFSET(bios_entry_point, 0x44, L"%xh");
|
||||||
|
CHECK_OFFSET(bios_code_seg16, 0x48, L"%xh");
|
||||||
|
CHECK_OFFSET(bios_data_seg, 0x4A, L"%xh");
|
||||||
|
CHECK_OFFSET(apm_bios_flags, 0x4C, L"%xh");
|
||||||
|
CHECK_OFFSET(bios_code_len, 0x4E, L"%xh");
|
||||||
|
CHECK_OFFSET(bios_data_len, 0x52, L"%xh");
|
||||||
|
CHECK_OFFSET(hd0_info, 0x80, L"");
|
||||||
|
CHECK_OFFSET(hd1_info, 0x90, L"");
|
||||||
|
CHECK_OFFSET(mca_info_len, 0xA0, L"%xh");
|
||||||
|
CHECK_OFFSET(mca_info_buf, 0xA2, L"");
|
||||||
|
CHECK_OFFSET(efi_loader_sig, 0x1C0, L"'%-4.4a'");
|
||||||
|
CHECK_OFFSET(efi_sys_tbl, 0x1C4, L"%xh");
|
||||||
|
CHECK_OFFSET(efi_mem_desc_size, 0x1C8, L"%xh");
|
||||||
|
CHECK_OFFSET(efi_mem_desc_ver, 0x1CC, L"%xh");
|
||||||
|
CHECK_OFFSET(efi_mem_map, 0x1D0, L"%xh");
|
||||||
|
CHECK_OFFSET(efi_mem_map_size, 0x1D4, L"%xh");
|
||||||
|
CHECK_OFFSET(loader_start, 0x1D8, L"%xh");
|
||||||
|
CHECK_OFFSET(loader_size, 0x1DC, L"%xh");
|
||||||
|
CHECK_OFFSET(alt_mem_k, 0x1E0, L"%xh");
|
||||||
|
CHECK_OFFSET(setup_sectors, 0x1F1, L"%xh");
|
||||||
|
CHECK_OFFSET(mount_root_rdonly, 0x1F2, L"%xh");
|
||||||
|
CHECK_OFFSET(sys_size, 0x1F4, L"%xh");
|
||||||
|
CHECK_OFFSET(swap_dev, 0x1F6, L"%xh");
|
||||||
|
CHECK_OFFSET(ramdisk_flags, 0x1F8, L"%xh");
|
||||||
|
CHECK_OFFSET(video_mode_flag, 0x1FA, L"%xh");
|
||||||
|
CHECK_OFFSET(orig_root_dev, 0x1FC, L"%xh");
|
||||||
|
CHECK_OFFSET(aux_dev_info, 0x1FF, L"%xh");
|
||||||
|
CHECK_OFFSET(jump, 0x200, L"%xh");
|
||||||
|
CHECK_OFFSET(setup_sig, 0x202, L"'%-4.4a'");
|
||||||
|
CHECK_OFFSET(hdr_minor, 0x206, L"%xh");
|
||||||
|
CHECK_OFFSET(hdr_major, 0x207, L"%xh");
|
||||||
|
CHECK_OFFSET(rm_switch, 0x208, L"%xh");
|
||||||
|
CHECK_OFFSET(start_sys_seg, 0x20C, L"%xh");
|
||||||
|
CHECK_OFFSET(kernel_verstr_offset, 0x20E, L"%xh");
|
||||||
|
CHECK_OFFSET(loader_type, 0x210, L"%xh");
|
||||||
|
CHECK_OFFSET(loader_flags, 0x211, L"%xh");
|
||||||
|
CHECK_OFFSET(setup_move_size, 0x212, L"%xh");
|
||||||
|
CHECK_OFFSET(kernel_start, 0x214, L"%xh");
|
||||||
|
CHECK_OFFSET(initrd_start, 0x218, L"%xh");
|
||||||
|
CHECK_OFFSET(initrd_size, 0x21C, L"%xh");
|
||||||
|
CHECK_OFFSET(bootsect_helper, 0x220, L"%xh");
|
||||||
|
CHECK_OFFSET(heap_end_ptr, 0x224, L"%xh");
|
||||||
|
CHECK_OFFSET(base_mem_size, 0x226, L"%xh");
|
||||||
|
|
||||||
|
if (test) {
|
||||||
|
ERR_PRT((L"Boot sector and/or setup parameter alignment error."));
|
||||||
|
free_kmem();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get video information.
|
||||||
|
* Do this last so that any other cursor positioning done
|
||||||
|
* in the fill routine gets accounted for.
|
||||||
|
*/
|
||||||
|
|
||||||
|
efi_status = ST->ConOut->QueryMode(
|
||||||
|
ST->ConOut,
|
||||||
|
ST->ConOut->Mode->Mode,
|
||||||
|
&cols,
|
||||||
|
&rows);
|
||||||
|
|
||||||
|
if (EFI_ERROR(efi_status)) {
|
||||||
|
ERR_PRT((L"QueryMode failed. Fake it."));
|
||||||
|
|
||||||
|
mode = 3;
|
||||||
|
rows = 25;
|
||||||
|
cols = 80;
|
||||||
|
row = 24;
|
||||||
|
col = 0;
|
||||||
|
} else {
|
||||||
|
mode = (UINT8)ST->ConOut->Mode->Mode;
|
||||||
|
col = (UINT8)ST->ConOut->Mode->CursorColumn;
|
||||||
|
row = (UINT8)ST->ConOut->Mode->CursorRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
bp->s.orig_cursor_col = col;
|
||||||
|
bp->s.orig_cursor_row = row;
|
||||||
|
bp->s.orig_video_page = 0;
|
||||||
|
bp->s.orig_video_mode = mode;
|
||||||
|
bp->s.orig_video_cols = (UINT8)cols;
|
||||||
|
bp->s.orig_video_rows = (UINT8)rows;
|
||||||
|
|
||||||
|
/* %%TBD - How to do Int 10h calls to get video info? */
|
||||||
|
bp->s.orig_ega_bx = 0;
|
||||||
|
bp->s.is_vga = 0;
|
||||||
|
bp->s.orig_video_points = 0;
|
||||||
|
|
||||||
|
/* %%TBD - How to do Int 10h calls to get frame buffer info? */
|
||||||
|
bp->s.lfb_width = 0;
|
||||||
|
bp->s.lfb_height = 0;
|
||||||
|
bp->s.lfb_depth = 0;
|
||||||
|
bp->s.lfb_base = 0;
|
||||||
|
bp->s.lfb_size = 0;
|
||||||
|
bp->s.lfb_line_len = 0;
|
||||||
|
bp->s.lfb_red_size = 0;
|
||||||
|
bp->s.lfb_red_pos = 0;
|
||||||
|
bp->s.lfb_green_size = 0;
|
||||||
|
bp->s.lfb_green_pos = 0;
|
||||||
|
bp->s.lfb_blue_size = 0;
|
||||||
|
bp->s.lfb_blue_pos = 0;
|
||||||
|
bp->s.lfb_rsvd_size = 0;
|
||||||
|
bp->s.lfb_rsvd_pos = 0;
|
||||||
|
bp->s.lfb_pages = 0;
|
||||||
|
bp->s.vesa_seg = 0;
|
||||||
|
bp->s.vesa_off = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get memory map description and cookie for ExitBootServices()
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (get_memmap(&mdesc)) {
|
||||||
|
ERR_PRT((L"Could not get memory map."));
|
||||||
|
free_kmem();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*cookie = mdesc.cookie;
|
||||||
|
bp->s.efi_mem_map = (UINTN)mdesc.md;
|
||||||
|
bp->s.efi_mem_map_size = mdesc.map_size;
|
||||||
|
bp->s.efi_mem_desc_size = mdesc.desc_size;
|
||||||
|
bp->s.efi_mem_desc_ver = mdesc.desc_version;
|
||||||
|
bp->s.efi_sys_tbl = (UINTN)systab;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* my_ia32_boot_params and get ready to slap them into 0x00104c00
|
||||||
|
*/
|
||||||
|
|
||||||
|
efi_ia32_bp.size= sizeof(efi_ia32_bp);
|
||||||
|
efi_ia32_bp.command_line = (UINT32) cmdline;
|
||||||
|
efi_ia32_bp.efi_sys_tbl = bp->s.efi_sys_tbl;
|
||||||
|
efi_ia32_bp.efi_mem_map = bp->s.efi_mem_map;
|
||||||
|
efi_ia32_bp.efi_mem_map_size = bp->s.efi_mem_map_size;
|
||||||
|
efi_ia32_bp.efi_mem_desc_size = bp->s.efi_mem_desc_size;
|
||||||
|
efi_ia32_bp.efi_mem_desc_version = bp->s.efi_mem_desc_ver;
|
||||||
|
efi_ia32_bp.initrd_start = (UINTN)initrd->start_addr;
|
||||||
|
efi_ia32_bp.initrd_size = initrd->pgcnt * EFI_PAGE_SIZE;
|
||||||
|
efi_ia32_bp.loader_start = 0;
|
||||||
|
efi_ia32_bp.loader_size = 0;
|
||||||
|
efi_ia32_bp.kernel_start = bp->s.kernel_start;
|
||||||
|
efi_ia32_bp.kernel_size = kernel_size;
|
||||||
|
efi_ia32_bp.num_cols = cols;
|
||||||
|
efi_ia32_bp.num_rows = rows;
|
||||||
|
efi_ia32_bp.orig_x = col;
|
||||||
|
efi_ia32_bp.orig_y = row;
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
42
ia64/Makefile
Normal file
42
ia64/Makefile
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#
|
||||||
|
# Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
# Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
#
|
||||||
|
# This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
#
|
||||||
|
# ELILO is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# ELILO is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
# Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
# 02111-1307, USA.
|
||||||
|
#
|
||||||
|
# Please check out the elilo.txt for complete documentation on how
|
||||||
|
# to use this program.
|
||||||
|
#
|
||||||
|
|
||||||
|
include ../Make.defaults
|
||||||
|
include ../Make.rules
|
||||||
|
|
||||||
|
TOPDIR=$(CDIR)/..
|
||||||
|
|
||||||
|
FILES=system.o config.o fpswa.o plain_loader.o gzip_loader.o \
|
||||||
|
gzip.o memset.o memcpy.o setjmp.o longjmp.o
|
||||||
|
|
||||||
|
TARGET=sysdeps.o
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(FILES)
|
||||||
|
$(LD) -o $@ -r $(FILES)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) -f $(TARGET) $(FILES)
|
154
ia64/config.c
Normal file
154
ia64/config.c
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "private.h"
|
||||||
|
#include "sysdeps.h"
|
||||||
|
#include "getopt.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
CHAR16 fpswa[FILENAME_MAXLEN];
|
||||||
|
CHAR16 cmd_fpswa[FILENAME_MAXLEN];
|
||||||
|
UINTN allow_relocation;
|
||||||
|
} ia64_global_config_t;
|
||||||
|
|
||||||
|
#define ia64_opt_offsetof(option) (&((sys_img_options_t *)(0x0))->option)
|
||||||
|
|
||||||
|
static ia64_global_config_t ia64_gconf;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No IA-64 specific options at this point
|
||||||
|
* The last entry in each table MUST be use the OPT_NULL type to terminate
|
||||||
|
* the chain.
|
||||||
|
*/
|
||||||
|
config_option_t sysdeps_global_options[]={
|
||||||
|
{OPT_FILE, OPT_GLOBAL, L"fpswa", NULL, NULL, ia64_gconf.fpswa},
|
||||||
|
{OPT_BOOL, OPT_GLOBAL, L"relocatable", NULL, NULL, &ia64_gconf.allow_relocation},
|
||||||
|
};
|
||||||
|
|
||||||
|
config_option_t sysdeps_image_options[]={
|
||||||
|
{OPT_BOOL, OPT_IMAGE_SYS, L"relocatable", NULL, NULL, ia64_opt_offsetof(allow_relocation)},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IA-64 operations that need to be done only once and just before
|
||||||
|
* entering the main loop of the loader
|
||||||
|
* Return:
|
||||||
|
* 0 if sucessful
|
||||||
|
* -1 otherwise (will abort execution)
|
||||||
|
*/
|
||||||
|
INTN
|
||||||
|
sysdeps_preloop_actions(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* we have separate string to make sure that the command line take precedence over
|
||||||
|
* the config file
|
||||||
|
*/
|
||||||
|
if (ia64_gconf.cmd_fpswa[0] != CHAR_NULL) {
|
||||||
|
check_fpswa(image, dev, ia64_gconf.cmd_fpswa);
|
||||||
|
} else if (ia64_gconf.fpswa[0] != CHAR_NULL)
|
||||||
|
check_fpswa(image, dev, ia64_gconf.fpswa);
|
||||||
|
else
|
||||||
|
check_fpswa(image, dev, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return:
|
||||||
|
* 1: if image or global configuration allows relocation
|
||||||
|
* 0: otherwise
|
||||||
|
*
|
||||||
|
* It is written has a function rather than a macro to avoid
|
||||||
|
* exposing config data structure to the rest of the code in ia64
|
||||||
|
*/
|
||||||
|
INTN
|
||||||
|
ia64_can_relocate(VOID)
|
||||||
|
{
|
||||||
|
return ia64_gconf.allow_relocation == TRUE
|
||||||
|
|| (elilo_opt.sys_img_opts && elilo_opt.sys_img_opts->allow_relocation ==TRUE) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IA64_CMDLINE_OPTIONS L"rF:"
|
||||||
|
|
||||||
|
CHAR16 *
|
||||||
|
sysdeps_get_cmdline_opts(VOID)
|
||||||
|
{
|
||||||
|
return IA64_CMDLINE_OPTIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
sysdeps_getopt(INTN c, INTN optind, CHAR16 *optarg)
|
||||||
|
{
|
||||||
|
INTN ret = 0; /* let's be optimistic ! */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX: for now these command line options have to be global
|
||||||
|
*/
|
||||||
|
switch(c) {
|
||||||
|
case L'r':
|
||||||
|
ia64_gconf.allow_relocation = 1;
|
||||||
|
break;
|
||||||
|
case L'F':
|
||||||
|
if (StrLen(Optarg) >= FILENAME_MAXLEN) {
|
||||||
|
Print(L"FPSWA filename is limited to %d characters\n", FILENAME_MAXLEN);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
StrCpy(ia64_gconf.cmd_fpswa, Optarg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
sysdeps_print_cmdline_opts(VOID)
|
||||||
|
{
|
||||||
|
Print(L"-r kernel image can be relocated if load address inexistent\n");
|
||||||
|
Print(L"-F file name of a specific FPSWA EFI driver to load\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
sysdeps_register_options(VOID)
|
||||||
|
{
|
||||||
|
INTN ret;
|
||||||
|
|
||||||
|
ret = register_config_options(sysdeps_global_options,
|
||||||
|
sizeof(sysdeps_global_options)/sizeof(config_option_t),
|
||||||
|
OPTIONS_GROUP_GLOBAL);
|
||||||
|
if (ret == -1 ) return ret;
|
||||||
|
|
||||||
|
ret = register_config_options(sysdeps_image_options,
|
||||||
|
sizeof(sysdeps_image_options)/sizeof(config_option_t),
|
||||||
|
OPTIONS_GROUP_IMAGE);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
167
ia64/fpswa.c
Normal file
167
ia64/fpswa.c
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINT32 revision;
|
||||||
|
UINT32 reserved;
|
||||||
|
VOID *fpswa;
|
||||||
|
} fpswa_interface_t;
|
||||||
|
|
||||||
|
INTN
|
||||||
|
query_fpswa(VOID **fpswa)
|
||||||
|
{
|
||||||
|
EFI_HANDLE fpswa_image;
|
||||||
|
UINTN size;
|
||||||
|
EFI_STATUS status;
|
||||||
|
EFI_GUID FpswaProtocol = FPSWA_PROTOCOL;
|
||||||
|
|
||||||
|
DBG_PRT((L"Querying FpswaProtocol"));
|
||||||
|
|
||||||
|
size = sizeof(EFI_HANDLE);
|
||||||
|
|
||||||
|
status = BS->LocateHandle(ByProtocol, &FpswaProtocol, NULL, &size, &fpswa_image);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"boot_params could not locate FPSWA driver", status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
status = BS->HandleProtocol(fpswa_image, &FpswaProtocol, fpswa);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"boot_params FpswaProtocol not able find the interface"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
VERB_PRT(3, Print(L"FpswaProtocol = 0x%lx revision=%x\n", *fpswa,
|
||||||
|
((fpswa_interface_t *)*fpswa)->revision));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
do_check_fpswa(EFI_HANDLE image, EFI_HANDLE dev, CHAR16 *fpswa_file)
|
||||||
|
{
|
||||||
|
EFI_STATUS status;
|
||||||
|
EFI_HANDLE handle;
|
||||||
|
EFI_DEVICE_PATH *dp;
|
||||||
|
|
||||||
|
|
||||||
|
dp = FileDevicePath(dev, fpswa_file);
|
||||||
|
if (dp == NULL) {
|
||||||
|
ERR_PRT((L"Cannot create FilePath for %s", fpswa_file));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
status = BS->LoadImage(0, image, dp, NULL, 0, &handle);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
VERB_PRT(3, Print(L"..not found\n"));
|
||||||
|
FreePool(dp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
VERB_PRT(3, Print(L"..starting.."));
|
||||||
|
|
||||||
|
status = BS->StartImage(handle, 0, 0);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
VERB_PRT(3, Print(L"failed (%r)\n", status));
|
||||||
|
/*
|
||||||
|
* StartImage() automatically unloads if error
|
||||||
|
* FPSWA init code will automatically abort if newer revision
|
||||||
|
* is already installed
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
VERB_PRT(3, Print(L"..ok\n"));
|
||||||
|
}
|
||||||
|
FreePool(dp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the caller specifies a fpswa filename, then it used instead of the
|
||||||
|
* defaults.
|
||||||
|
* Return:
|
||||||
|
* 0 : indicates that one fpswa driver was loaded, i.e. an update could be done
|
||||||
|
* -1: no update was found that would have a more recent version of the driver. This is
|
||||||
|
* not a fatal return value.
|
||||||
|
*/
|
||||||
|
INTN
|
||||||
|
check_fpswa(EFI_HANDLE image, EFI_HANDLE dev, CHAR16 *fpswa_file)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* we must use \\ here as this is given to LoadImage() directly
|
||||||
|
*
|
||||||
|
* The FPSWA driver MUST be called fpswa.efi and the FPSWA document
|
||||||
|
* (see developer.intel.com/design/itanium) stipulates that the
|
||||||
|
* file must be placed in \EFI\Intel Firmware\ (no mention of which
|
||||||
|
* EFI system partition). So elilo will check on all accessible
|
||||||
|
* Fat32+ partition for the existence of this directory and file.
|
||||||
|
*/
|
||||||
|
static CHAR16 *fpswa_filenames[] ={
|
||||||
|
L"\\efi\\intel firmware\\fpswa.efi",
|
||||||
|
#if 0
|
||||||
|
L"\\fpswa.efi",
|
||||||
|
L"\\fw\\fpswa.efi",
|
||||||
|
L"\\efi\\fpswa.efi",
|
||||||
|
L"\\efi\\tools\\fpswa.efi",
|
||||||
|
L"\\fpswa.efi",
|
||||||
|
L"fpswa.efi",
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
UINTN j, count = sizeof(fpswa_filenames)/sizeof(CHAR16 *);
|
||||||
|
INTN cookie;
|
||||||
|
CHAR16 devname[FILENAME_MAXLEN];
|
||||||
|
|
||||||
|
if (fpswa_file) {
|
||||||
|
INTN r;
|
||||||
|
devname[0] = CHAR_NULL;
|
||||||
|
r = fops_split_path(fpswa_file, devname);
|
||||||
|
if (r == -1) {
|
||||||
|
ERR_PRT((L"FPSWA driver filename too long %s", fpswa_file));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (devname[0] != CHAR_NULL) {
|
||||||
|
if (fops_get_device_handle(devname, &dev) != EFI_SUCCESS) {
|
||||||
|
ERR_PRT((L"cannot find device %s for FPSWA driver", devname));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return do_check_fpswa(image, dev, fpswa_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
cookie = 0;
|
||||||
|
while (fops_get_next_device(cookie, L"vfat", FILENAME_MAXLEN, &cookie, devname, &dev) == EFI_SUCCESS) {
|
||||||
|
for (j = 0; j < count; j++) {
|
||||||
|
VERB_PRT(3, Print(L"Trying FPSWA driver %s:%s..", devname, fpswa_filenames[j]));
|
||||||
|
/*
|
||||||
|
* we need to do all choices to make sure we pickup
|
||||||
|
* the latest version.
|
||||||
|
*/
|
||||||
|
do_check_fpswa(image, dev, fpswa_filenames[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
651
ia64/gzip.c
Normal file
651
ia64/gzip.c
Normal file
|
@ -0,0 +1,651 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001 Silicon Graphics, Inc.
|
||||||
|
* Contributed by Brent Casavant <bcasavan@sgi.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elf.h"
|
||||||
|
#include "elilo.h"
|
||||||
|
|
||||||
|
#include "gzip.h"
|
||||||
|
|
||||||
|
#include "private.h"
|
||||||
|
#include "setjmp.h"
|
||||||
|
|
||||||
|
#define memzero(s, n) Memset((VOID *)(s), 0, (n))
|
||||||
|
#define memcpy(a,b,n) Memcpy((VOID *)(a),(b),(n))
|
||||||
|
|
||||||
|
/* size of output buffer */
|
||||||
|
#define WSIZE 0x8000 /* Window size must be at least 32k, */
|
||||||
|
/* and a power of two */
|
||||||
|
/* size of input buffer */
|
||||||
|
#define INBUFSIZE 0x8000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gzip declarations
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define OF(args) args
|
||||||
|
#define FUNC_STATIC static
|
||||||
|
|
||||||
|
typedef unsigned char uch;
|
||||||
|
typedef unsigned short ush;
|
||||||
|
typedef unsigned long ulg;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct segment {
|
||||||
|
unsigned long addr; /* start address */
|
||||||
|
unsigned long offset; /* file offset */
|
||||||
|
unsigned long size; /* file size */
|
||||||
|
unsigned long bss_sz; /* BSS size */
|
||||||
|
UINT8 flags; /* indicates whether to load or not */
|
||||||
|
} segment_t;
|
||||||
|
|
||||||
|
#define CHUNK_FL_VALID 0x1
|
||||||
|
#define CHUNK_FL_LOAD 0x2
|
||||||
|
|
||||||
|
#define CHUNK_CAN_LOAD(n) chunks[(n)].flags |= CHUNK_FL_LOAD
|
||||||
|
#define CHUNK_NO_LOAD(n) chunks[(n)].flags &= ~CHUNK_FL_LOAD
|
||||||
|
#define CHUNK_IS_LOAD(n) (chunks[(n)].flags & CHUNK_FL_LOAD)
|
||||||
|
|
||||||
|
#define CHUNK_VALIDATE(n) chunks[(n)].flags |= CHUNK_FL_VALID
|
||||||
|
#define CHUNK_INVALIDATE(n) chunks[(n)].flags = 0
|
||||||
|
#define CHUNK_IS_VALID(n) (chunks[(n)].flags & CHUNK_FL_VALID)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* static parameters to gzip helper functions
|
||||||
|
* we cannot use paramters because API was not
|
||||||
|
* designed that way
|
||||||
|
*/
|
||||||
|
static segment_t *chunks; /* holds the list of segments */
|
||||||
|
static segment_t *cur_chunk;
|
||||||
|
static UINTN nchunks;
|
||||||
|
static UINTN chunk; /* current segment */
|
||||||
|
static UINTN input_fd;
|
||||||
|
static VOID *kernel_entry, *kernel_base, *kernel_end;
|
||||||
|
|
||||||
|
static uch *inbuf; /* input buffer (compressed data) */
|
||||||
|
static uch *window; /* output buffer (uncompressed data) */
|
||||||
|
static unsigned long file_offset; /* position in the file */
|
||||||
|
|
||||||
|
static unsigned insize = 0; /* valid bytes in inbuf */
|
||||||
|
static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
|
||||||
|
static unsigned outcnt = 0; /* bytes in output buffer */
|
||||||
|
|
||||||
|
/* gzip flag byte */
|
||||||
|
#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
|
||||||
|
#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
|
||||||
|
#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
|
||||||
|
#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
|
||||||
|
#define COMMENT 0x10 /* bit 4 set: file comment present */
|
||||||
|
#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
|
||||||
|
#define RESERVED 0xC0 /* bit 6,7: reserved */
|
||||||
|
|
||||||
|
#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
|
||||||
|
|
||||||
|
/* Diagnostic functions */
|
||||||
|
#ifdef INFLATE_DEBUG
|
||||||
|
# define Assert(cond,msg) {if(!(cond)) error(msg);}
|
||||||
|
int stderr;
|
||||||
|
# define Trace(x) Print(L"line %d:\n", __LINE__);
|
||||||
|
# define Tracev(x) {if (verbose) Print(L"line %d:\n", __LINE__) ;}
|
||||||
|
# define Tracevv(x) {if (verbose>1) Print(L"line %d:\n", __LINE__) ;}
|
||||||
|
# define Tracec(c,x) {if (verbose && (c)) Print(L"line %d:\n", __LINE__) ;}
|
||||||
|
# define Tracecv(c,x) {if (verbose>1 && (c)) Print(L"line %d:\n", __LINE__) ;}
|
||||||
|
#else
|
||||||
|
# define Assert(cond,msg)
|
||||||
|
# define Trace(x)
|
||||||
|
# define Tracev(x)
|
||||||
|
# define Tracevv(x)
|
||||||
|
# define Tracec(c,x)
|
||||||
|
# define Tracecv(c,x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int fill_inbuf(void);
|
||||||
|
static void flush_window(void);
|
||||||
|
static void error(char *m);
|
||||||
|
static long bytes_out;
|
||||||
|
|
||||||
|
static void error(char *m);
|
||||||
|
|
||||||
|
static jmp_buf jbuf;
|
||||||
|
static int error_return;
|
||||||
|
static UINTN elf_is_big_endian; /* true if ELF file is big endian */
|
||||||
|
|
||||||
|
static void *
|
||||||
|
gzip_malloc(int size)
|
||||||
|
{
|
||||||
|
return (void *)alloc(size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gzip_free(void *where)
|
||||||
|
{
|
||||||
|
return free(where);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "inflate.c"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fill the input buffer and return the first byte in it. This is called
|
||||||
|
* only when the buffer is empty and at least one byte is really needed.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
fill_inbuf(void)
|
||||||
|
{
|
||||||
|
INTN expected, nread;
|
||||||
|
EFI_STATUS status;
|
||||||
|
|
||||||
|
expected = nread = INBUFSIZE;
|
||||||
|
|
||||||
|
status = fops_read(input_fd, inbuf, &nread);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
error("elilo: Read failed");
|
||||||
|
}
|
||||||
|
DBG_PRT((L"%s : read %d bytes of %d bytes\n", LD_NAME, nread, expected));
|
||||||
|
|
||||||
|
insize = nread;
|
||||||
|
inptr = 1;
|
||||||
|
|
||||||
|
return inbuf[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================================================================
|
||||||
|
* Write the output window window[0..outcnt-1] and update crc and bytes_out.
|
||||||
|
* (Used for the decompressed data only.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run a set of bytes through the crc shift register. If s is a NULL
|
||||||
|
* pointer, then initialize the crc shift register contents instead.
|
||||||
|
* Return the current crc in either case.
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* S pointer to bytes to pump through.
|
||||||
|
* N number of bytes in S[].
|
||||||
|
*/
|
||||||
|
unsigned long
|
||||||
|
updcrc(unsigned char *s, unsigned n)
|
||||||
|
{
|
||||||
|
register unsigned long c;
|
||||||
|
/* crc is defined in inflate.c */
|
||||||
|
|
||||||
|
if (!s) {
|
||||||
|
c = 0xffffffffL;
|
||||||
|
} else {
|
||||||
|
c = crc;
|
||||||
|
while (n--) {
|
||||||
|
c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
crc = c;
|
||||||
|
return c ^ 0xffffffffUL; /* (instead of ~c for 64-bit machines) */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear input and output buffers
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
clear_bufs(void)
|
||||||
|
{
|
||||||
|
outcnt = 0;
|
||||||
|
inptr = 0;
|
||||||
|
chunk = 0;
|
||||||
|
cur_chunk = NULL;
|
||||||
|
file_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline UINT64
|
||||||
|
bswap64(UINT64 v)
|
||||||
|
{
|
||||||
|
if(elf_is_big_endian) v = __ia64_swab64(v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline UINT32
|
||||||
|
bswap32(UINT32 v)
|
||||||
|
{
|
||||||
|
if(elf_is_big_endian) v = __ia64_swab32(v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline UINT16
|
||||||
|
bswap16(UINT16 v)
|
||||||
|
{
|
||||||
|
if(elf_is_big_endian) v = __ia64_swab16(v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
is_valid_header(Elf64_Ehdr *ehdr)
|
||||||
|
{
|
||||||
|
UINT16 type, machine;
|
||||||
|
|
||||||
|
if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
|
||||||
|
type = __ia64_swab16(ehdr->e_type);
|
||||||
|
machine = __ia64_swab16(ehdr->e_machine);
|
||||||
|
} else {
|
||||||
|
type = ehdr->e_type;
|
||||||
|
machine = ehdr->e_machine;
|
||||||
|
}
|
||||||
|
VERB_PRT(3, Print(L"class=%d type=%d data=%d machine=%d\n",
|
||||||
|
ehdr->e_ident[EI_CLASS],
|
||||||
|
type,
|
||||||
|
ehdr->e_ident[EI_DATA],
|
||||||
|
machine));
|
||||||
|
|
||||||
|
return ehdr->e_ident[EI_MAG0] == 0x7f
|
||||||
|
&& ehdr->e_ident[EI_MAG1] == 'E'
|
||||||
|
&& ehdr->e_ident[EI_MAG2] == 'L'
|
||||||
|
&& ehdr->e_ident[EI_MAG3] == 'F'
|
||||||
|
&& ehdr->e_ident[EI_CLASS] == ELFCLASS64
|
||||||
|
&& type == ET_EXEC /* must be executable */
|
||||||
|
&& machine == EM_IA_64 ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* will invalidate loadble segments which overlap with others
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
check_overlap(int i)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
unsigned long iend = chunks[i].addr + chunks[i].size;
|
||||||
|
|
||||||
|
for(j=0; j < nchunks; j++) {
|
||||||
|
if (j ==i) continue;
|
||||||
|
if (chunks[i].addr >= chunks[j].addr && iend < (chunks[j].addr + chunks[j].size)) {
|
||||||
|
DBG_PRT((L"%s : segment %d fully included in segment %d\n", LD_NAME, i, j));
|
||||||
|
CHUNK_INVALIDATE(i); /* nullyify segment */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
analyze_chunks(void)
|
||||||
|
{
|
||||||
|
INTN i;
|
||||||
|
|
||||||
|
for(i=0; i < nchunks; i++) {
|
||||||
|
if (CHUNK_IS_VALID(i) && !CHUNK_IS_LOAD(i)) check_overlap(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The decompression code calls this function after decompressing the
|
||||||
|
* first block of the object file. The first block must contain all
|
||||||
|
* the relevant header information.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
first_block (const char *buf, long blocksize)
|
||||||
|
{
|
||||||
|
Elf64_Ehdr *elf;
|
||||||
|
Elf64_Phdr *phdrs;
|
||||||
|
UINTN total_size, pages;
|
||||||
|
UINTN low_addr, max_addr;
|
||||||
|
UINTN load_offset = 0;
|
||||||
|
UINTN offs = 0;
|
||||||
|
UINT16 phnum;
|
||||||
|
UINTN paddr, memsz;
|
||||||
|
INTN i;
|
||||||
|
|
||||||
|
elf = (Elf64_Ehdr *)buf;
|
||||||
|
|
||||||
|
if (is_valid_header(elf) == -1) return -1;
|
||||||
|
|
||||||
|
/* determine file endianess */
|
||||||
|
elf_is_big_endian = elf->e_ident[EI_DATA] == ELFDATA2MSB ? 1 : 0;
|
||||||
|
|
||||||
|
|
||||||
|
offs = bswap64(elf->e_phoff);
|
||||||
|
phnum = bswap16(elf->e_phnum);
|
||||||
|
|
||||||
|
VERB_PRT(3, {
|
||||||
|
Print(L"ELF file is %s\n", elf_is_big_endian ? L"big endian" : L"little endian");
|
||||||
|
Print(L"Entry point 0x%lx\n", bswap64(elf->e_entry));
|
||||||
|
Print(L"%d program headers\n", phnum);
|
||||||
|
Print(L"%d segment headers\n", bswap16(elf->e_shnum));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* XXX: need to check on this */
|
||||||
|
if (offs + phnum * sizeof(*phdrs) > (unsigned) blocksize) {
|
||||||
|
ERR_PRT((L"%s : ELF program headers not in first block (%ld)\n", LD_NAME, offs));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel_entry = (void *)bswap64(elf->e_entry);
|
||||||
|
|
||||||
|
if (((UINTN)kernel_entry >> 61) != 0) {
|
||||||
|
ERR_PRT((L"%s: <<ERROR>> entry point is a virtual address 0x%lx : not supported anymore\n", LD_NAME, kernel_entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
phdrs = (Elf64_Phdr *) (buf + offs);
|
||||||
|
|
||||||
|
low_addr = ~0;
|
||||||
|
max_addr = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* allocate chunk table
|
||||||
|
* Convention: a segment that does not need loading will
|
||||||
|
* have chunk[].addr = 0.
|
||||||
|
*/
|
||||||
|
chunks = (void *)alloc(sizeof(struct segment)*phnum, 0);
|
||||||
|
if (chunks == NULL) {
|
||||||
|
ERR_PRT((L"%s : failed alloc chunks %r\n", LD_NAME));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
nchunks = phnum;
|
||||||
|
/*
|
||||||
|
* find lowest and higest virtual addresses
|
||||||
|
* don't assume FULLY sorted !
|
||||||
|
*/
|
||||||
|
for (i = 0; i < phnum; ++i) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* record chunk no matter what because no load may happen
|
||||||
|
* anywhere in archive, not just as the last segment
|
||||||
|
*/
|
||||||
|
paddr = bswap64(phdrs[i].p_paddr);
|
||||||
|
memsz = bswap64(phdrs[i].p_memsz),
|
||||||
|
|
||||||
|
chunks[i].addr = paddr;
|
||||||
|
chunks[i].offset = bswap64(phdrs[i].p_offset);
|
||||||
|
chunks[i].size = bswap64(phdrs[i].p_filesz);
|
||||||
|
chunks[i].bss_sz = bswap64(phdrs[i].p_memsz) - bswap64(phdrs[i].p_filesz);
|
||||||
|
|
||||||
|
CHUNK_VALIDATE(i);
|
||||||
|
|
||||||
|
if (bswap32(phdrs[i].p_type) != PT_LOAD) {
|
||||||
|
CHUNK_NO_LOAD(i); /* mark no load chunk */
|
||||||
|
DBG_PRT((L"%s : skipping segment %ld\n", LD_NAME, i));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHUNK_CAN_LOAD(i); /* mark no load chunk */
|
||||||
|
|
||||||
|
VERB_PRT(3,
|
||||||
|
Print(L"\n%s : segment %ld vaddr [0x%lx-0x%lx] offset %ld filesz %ld memsz=%ld bss_sz=%ld\n",
|
||||||
|
LD_NAME,
|
||||||
|
1+i,
|
||||||
|
chunks[i].addr,
|
||||||
|
chunks[i].addr+bswap64(phdrs[i].p_filesz),
|
||||||
|
chunks[i].offset,
|
||||||
|
chunks[i].size,
|
||||||
|
memsz,
|
||||||
|
chunks[i].bss_sz));
|
||||||
|
|
||||||
|
if (paddr < low_addr) low_addr = paddr;
|
||||||
|
|
||||||
|
if (paddr + memsz > max_addr) max_addr = paddr + memsz;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (low_addr & (EFI_PAGE_SIZE - 1)) {
|
||||||
|
ERR_PRT((L"%s : low_addr not page aligned 0x%lx\n", LD_NAME, low_addr));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
analyze_chunks();
|
||||||
|
|
||||||
|
DBG_PRT((L"%s : %d program headers entry=0x%lx\nlowest_addr=0x%lx highest_addr=0x%lx\n",
|
||||||
|
LD_NAME,
|
||||||
|
phnum, kernel_entry, low_addr, max_addr));
|
||||||
|
|
||||||
|
total_size = (UINTN)max_addr - (UINTN)low_addr;
|
||||||
|
pages = EFI_SIZE_TO_PAGES(total_size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Record end of kernel for initrd
|
||||||
|
*/
|
||||||
|
kernel_base = (void *)low_addr;
|
||||||
|
kernel_end = (void *)(low_addr + (pages << EFI_PAGE_SHIFT));
|
||||||
|
|
||||||
|
/* allocate memory for the kernel */
|
||||||
|
if (alloc_kmem((void *)low_addr, pages) == -1) {
|
||||||
|
VOID *new_addr;
|
||||||
|
|
||||||
|
ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
|
||||||
|
|
||||||
|
if (ia64_can_relocate() == 0) {
|
||||||
|
ERR_PRT((L"relocation is disabled, cannot load kernel"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* could not allocate at requested spot, try to find a
|
||||||
|
* suitable location to relocate the kernel
|
||||||
|
*
|
||||||
|
* The maximum sized Itanium TLB translation entry is 256 MB.
|
||||||
|
* If we relocate the kernel by this amount we know for sure
|
||||||
|
* that alignment constraints will be satisified, regardless
|
||||||
|
* of the kernel used.
|
||||||
|
*/
|
||||||
|
VERB_PRT(1, Print(L"Attempting to relocate kernel.\n"));
|
||||||
|
|
||||||
|
if (find_kernel_memory((VOID*) low_addr, (VOID*) max_addr, 256*MB, &new_addr) == -1) {
|
||||||
|
ERR_PRT((L"%s : find_kernel_memory(0x%lx, 0x%lx, 0x%lx, 0x%lx) failed\n", LD_NAME, low_addr, max_addr, 256*MB, &load_offset));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
/* unsigned arithmetic */
|
||||||
|
load_offset = (UINTN) (new_addr - ROUNDDOWN((UINTN) low_addr,256*MB));
|
||||||
|
|
||||||
|
ERR_PRT((L"low_addr=0x%lx new_addr=0x%lx offset=0x%lx", low_addr, new_addr, load_offset));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* correct various addresses for non-zero load_offset
|
||||||
|
*/
|
||||||
|
kernel_base = (void *) ((UINTN) kernel_base + load_offset);
|
||||||
|
kernel_end = (void *) ((UINTN) kernel_end + load_offset);
|
||||||
|
kernel_entry = (void*) ((UINTN) kernel_entry + load_offset);
|
||||||
|
|
||||||
|
for (i = 0; i < phnum; ++i) {
|
||||||
|
chunks[i].addr += load_offset;
|
||||||
|
phdrs[i].p_paddr = (Elf64_Addr) ((UINT64) phdrs[i].p_paddr + load_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* try one last time to get memory for the kernel
|
||||||
|
*/
|
||||||
|
if (alloc_kmem((void *)low_addr+load_offset, pages) == -1) {
|
||||||
|
ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr+load_offset));
|
||||||
|
ERR_PRT((L"Relocation by 0x%lx bytes failed.\n", load_offset));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
if (chunks) free(chunks);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine which chunk in the Elf file will be coming out of the expand
|
||||||
|
* code next.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
nextchunk(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
segment_t *cp;
|
||||||
|
|
||||||
|
cp = NULL;
|
||||||
|
for(i=0; i < nchunks; i++) {
|
||||||
|
|
||||||
|
if (!CHUNK_IS_VALID(i) || !CHUNK_IS_LOAD(i)) continue;
|
||||||
|
|
||||||
|
if (file_offset > chunks[i].offset) continue;
|
||||||
|
|
||||||
|
if (cp == NULL || chunks[i].offset < cp->offset) cp = &chunks[i];
|
||||||
|
}
|
||||||
|
cur_chunk = cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the output window window[0..outcnt-1] holding uncompressed
|
||||||
|
* data and update crc.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
flush_window(void)
|
||||||
|
{
|
||||||
|
static const CHAR8 helicopter[4] = { '|' , '/' , '-' , '\\' };
|
||||||
|
static UINTN heli_count;
|
||||||
|
struct segment *cp;
|
||||||
|
char *src, *dst;
|
||||||
|
long cnt;
|
||||||
|
|
||||||
|
if (!outcnt) return;
|
||||||
|
|
||||||
|
DBG_PRT((L"%s : flush_window outnct=%d file_offset=%ld\n", LD_NAME, outcnt, file_offset));
|
||||||
|
|
||||||
|
Print(L"%c\b",helicopter[heli_count++%4]);
|
||||||
|
|
||||||
|
updcrc(window, outcnt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* first time, we extract the headers
|
||||||
|
*/
|
||||||
|
if (!bytes_out) {
|
||||||
|
if (first_block(window, outcnt) < 0) error("invalid exec header");
|
||||||
|
nextchunk();
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_out += outcnt;
|
||||||
|
src = window;
|
||||||
|
tail:
|
||||||
|
/* check if user wants to abort */
|
||||||
|
if (check_abort() == EFI_SUCCESS) goto load_abort;
|
||||||
|
|
||||||
|
cp = cur_chunk;
|
||||||
|
if (cp == NULL || file_offset + outcnt <= cp->offset) {
|
||||||
|
file_offset += outcnt;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does this window begin before the current chunk?
|
||||||
|
if (file_offset < cp->offset) {
|
||||||
|
unsigned long skip = cp->offset - file_offset;
|
||||||
|
|
||||||
|
src += skip;
|
||||||
|
file_offset += skip;
|
||||||
|
outcnt -= skip;
|
||||||
|
}
|
||||||
|
dst = (char *)cp->addr + (file_offset - cp->offset);
|
||||||
|
|
||||||
|
cnt = cp->offset + cp->size - file_offset;
|
||||||
|
|
||||||
|
if (cnt > outcnt) cnt = outcnt;
|
||||||
|
|
||||||
|
Memcpy(dst, src, cnt);
|
||||||
|
|
||||||
|
file_offset += cnt;
|
||||||
|
outcnt -= cnt;
|
||||||
|
src += cnt;
|
||||||
|
|
||||||
|
/* See if we are at the end of this chunk */
|
||||||
|
if (file_offset == cp->offset + cp->size) {
|
||||||
|
if (cp->bss_sz) {
|
||||||
|
dst = (char *)cp->addr + cp->size;
|
||||||
|
Memset(dst, 0, cp->bss_sz);
|
||||||
|
}
|
||||||
|
nextchunk();
|
||||||
|
/* handle remaining bytes */
|
||||||
|
if (outcnt) goto tail;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
load_abort:
|
||||||
|
free_kmem();
|
||||||
|
error_return = ELILO_LOAD_ABORTED;
|
||||||
|
longjmp(jbuf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
error(char *x)
|
||||||
|
{
|
||||||
|
ERR_PRT((L"%s : %a", LD_NAME, x));
|
||||||
|
/* will eventually exit with error from gunzip() */
|
||||||
|
longjmp(jbuf,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32
|
||||||
|
decompress_kernel(VOID)
|
||||||
|
{
|
||||||
|
INT32 ret;
|
||||||
|
|
||||||
|
clear_bufs();
|
||||||
|
makecrc();
|
||||||
|
Print(L"Uncompressing Linux... ");
|
||||||
|
ret = gunzip();
|
||||||
|
if (ret == 0) Print(L"done\n");
|
||||||
|
return ret == 0 ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gunzip_kernel(fops_fd_t fd, kdesc_t *kd)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
error_return = ELILO_LOAD_ERROR;
|
||||||
|
|
||||||
|
window = (void *)alloc(WSIZE, 0);
|
||||||
|
if (window == NULL) {
|
||||||
|
ERR_PRT((L"%s : allocate output window failed\n", LD_NAME));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inbuf = (void *)alloc(INBUFSIZE, 0);
|
||||||
|
if (inbuf == NULL) {
|
||||||
|
ERR_PRT((L"%s : allocate input window failedr\n", LD_NAME));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
input_fd = fd;
|
||||||
|
insize = 0;
|
||||||
|
bytes_out = 0;
|
||||||
|
|
||||||
|
if (setjmp(jbuf) == 1) goto error;
|
||||||
|
|
||||||
|
|
||||||
|
ret = decompress_kernel();
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (window) free(window);
|
||||||
|
if (inbuf) free(inbuf);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
kd->kentry = kernel_entry;
|
||||||
|
kd->kend = kernel_end;
|
||||||
|
kd->kstart = kernel_base;
|
||||||
|
error_return = ELILO_LOAD_SUCCESS;
|
||||||
|
}
|
||||||
|
return error_return;
|
||||||
|
}
|
35
ia64/gzip.h
Normal file
35
ia64/gzip.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GZIP_H__
|
||||||
|
#define __GZIP_H__
|
||||||
|
|
||||||
|
|
||||||
|
int gzip_probe(unsigned char *, unsigned long);
|
||||||
|
int gunzip_kernel(fops_fd_t, kdesc_t *);
|
||||||
|
|
||||||
|
#define LD_NAME L"gzip_ia64"
|
||||||
|
|
||||||
|
#endif /* __GZIP_H__ */
|
79
ia64/gzip_loader.c
Normal file
79
ia64/gzip_loader.c
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
#include "loader.h"
|
||||||
|
#include "gzip.h"
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
gzip_probe_format(CHAR16 *kname)
|
||||||
|
{
|
||||||
|
UINT8 buf[4];
|
||||||
|
EFI_STATUS status;
|
||||||
|
INTN ret = -1;
|
||||||
|
UINTN size;
|
||||||
|
fops_fd_t fd;
|
||||||
|
|
||||||
|
status = fops_open(kname, &fd);
|
||||||
|
if (EFI_ERROR(status)) return -1;
|
||||||
|
|
||||||
|
size = sizeof(buf);
|
||||||
|
status = fops_read(fd, buf, &size);
|
||||||
|
|
||||||
|
if (EFI_ERROR(status) || size != sizeof(buf)) goto error;
|
||||||
|
|
||||||
|
ret = gzip_probe(buf, sizeof(buf));
|
||||||
|
error:
|
||||||
|
fops_close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
gzip_load_kernel(CHAR16 *kname, kdesc_t *kd)
|
||||||
|
{
|
||||||
|
EFI_STATUS status;
|
||||||
|
INT32 ret;
|
||||||
|
fops_fd_t fd;
|
||||||
|
|
||||||
|
status = fops_open(kname, &fd);
|
||||||
|
if (EFI_ERROR(status)) return ELILO_LOAD_ERROR;
|
||||||
|
|
||||||
|
ret = gunzip_kernel(fd, kd);
|
||||||
|
|
||||||
|
fops_close(fd);
|
||||||
|
|
||||||
|
return ret; /* could be success, error, or abort */
|
||||||
|
}
|
||||||
|
|
||||||
|
loader_ops_t gzip_loader={
|
||||||
|
NULL,
|
||||||
|
LD_NAME,
|
||||||
|
gzip_probe_format,
|
||||||
|
gzip_load_kernel
|
||||||
|
};
|
1204
ia64/inflate.c
Normal file
1204
ia64/inflate.c
Normal file
File diff suppressed because it is too large
Load diff
162
ia64/longjmp.S
Normal file
162
ia64/longjmp.S
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
/* Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||||
|
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
02111-1307 USA.
|
||||||
|
|
||||||
|
Note that __sigsetjmp() did NOT flush the register stack. Instead,
|
||||||
|
we do it here since __longjmp() is usually much less frequently
|
||||||
|
invoked than __sigsetjmp(). The only difficulty is that __sigsetjmp()
|
||||||
|
didn't (and wouldn't be able to) save ar.rnat either. This is a problem
|
||||||
|
because if we're not careful, we could end up loading random NaT bits.
|
||||||
|
There are two cases:
|
||||||
|
|
||||||
|
(i) ar.bsp < ia64_rse_rnat_addr(jmpbuf.ar_bsp)
|
||||||
|
ar.rnat contains the desired bits---preserve ar.rnat
|
||||||
|
across loadrs and write to ar.bspstore
|
||||||
|
|
||||||
|
(ii) ar.bsp >= ia64_rse_rnat_addr(jmpbuf.ar_bsp)
|
||||||
|
The desired ar.rnat is stored in
|
||||||
|
ia64_rse_rnat_addr(jmpbuf.ar_bsp). Load those
|
||||||
|
bits into ar.rnat after setting ar.bspstore. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# define pPos p6 /* is rotate count positive? */
|
||||||
|
# define pNeg p7 /* is rotate count negative? */
|
||||||
|
|
||||||
|
|
||||||
|
/* __longjmp(__jmp_buf buf, int val) */
|
||||||
|
|
||||||
|
.text
|
||||||
|
.global longjmp
|
||||||
|
.proc longjmp
|
||||||
|
longjmp:
|
||||||
|
alloc r8=ar.pfs,2,1,0,0
|
||||||
|
mov r27=ar.rsc
|
||||||
|
add r2=0x98,in0 // r2 <- &jmpbuf.orig_jmp_buf_addr
|
||||||
|
;;
|
||||||
|
ld8 r8=[r2],-16 // r8 <- orig_jmp_buf_addr
|
||||||
|
mov r10=ar.bsp
|
||||||
|
and r11=~0x3,r27 // clear ar.rsc.mode
|
||||||
|
;;
|
||||||
|
flushrs // flush dirty regs to backing store (must be first in insn grp)
|
||||||
|
ld8 r23=[r2],8 // r23 <- jmpbuf.ar_bsp
|
||||||
|
sub r8=r8,in0 // r8 <- &orig_jmpbuf - &jmpbuf
|
||||||
|
;;
|
||||||
|
ld8 r25=[r2] // r25 <- jmpbuf.ar_unat
|
||||||
|
extr.u r8=r8,3,6 // r8 <- (&orig_jmpbuf - &jmpbuf)/8 & 0x3f
|
||||||
|
;;
|
||||||
|
cmp.lt pNeg,pPos=r8,r0
|
||||||
|
mov r2=in0
|
||||||
|
;;
|
||||||
|
(pPos) mov r16=r8
|
||||||
|
(pNeg) add r16=64,r8
|
||||||
|
(pPos) sub r17=64,r8
|
||||||
|
(pNeg) sub r17=r0,r8
|
||||||
|
;;
|
||||||
|
mov ar.rsc=r11 // put RSE in enforced lazy mode
|
||||||
|
shr.u r8=r25,r16
|
||||||
|
add r3=8,in0 // r3 <- &jmpbuf.r1
|
||||||
|
shl r9=r25,r17
|
||||||
|
;;
|
||||||
|
or r25=r8,r9
|
||||||
|
;;
|
||||||
|
mov r26=ar.rnat
|
||||||
|
mov ar.unat=r25 // setup ar.unat (NaT bits for r1, r4-r7, and r12)
|
||||||
|
;;
|
||||||
|
ld8.fill.nta sp=[r2],16 // r12 (sp)
|
||||||
|
ld8.fill.nta gp=[r3],16 // r1 (gp)
|
||||||
|
dep r11=-1,r23,3,6 // r11 <- ia64_rse_rnat_addr(jmpbuf.ar_bsp)
|
||||||
|
;;
|
||||||
|
ld8.nta r16=[r2],16 // caller's unat
|
||||||
|
ld8.nta r17=[r3],16 // fpsr
|
||||||
|
;;
|
||||||
|
ld8.fill.nta r4=[r2],16 // r4
|
||||||
|
ld8.fill.nta r5=[r3],16 // r5 (gp)
|
||||||
|
cmp.geu p8,p0=r10,r11 // p8 <- (ar.bsp >= jmpbuf.ar_bsp)
|
||||||
|
;;
|
||||||
|
ld8.fill.nta r6=[r2],16 // r6
|
||||||
|
ld8.fill.nta r7=[r3],16 // r7
|
||||||
|
;;
|
||||||
|
mov ar.unat=r16 // restore caller's unat
|
||||||
|
mov ar.fpsr=r17 // restore fpsr
|
||||||
|
;;
|
||||||
|
ld8.nta r16=[r2],16 // b0
|
||||||
|
ld8.nta r17=[r3],16 // b1
|
||||||
|
;;
|
||||||
|
(p8) ld8 r26=[r11] // r26 <- *ia64_rse_rnat_addr(jmpbuf.ar_bsp)
|
||||||
|
mov ar.bspstore=r23 // restore ar.bspstore
|
||||||
|
;;
|
||||||
|
ld8.nta r18=[r2],16 // b2
|
||||||
|
ld8.nta r19=[r3],16 // b3
|
||||||
|
;;
|
||||||
|
ld8.nta r20=[r2],16 // b4
|
||||||
|
ld8.nta r21=[r3],16 // b5
|
||||||
|
;;
|
||||||
|
ld8.nta r11=[r2],16 // ar.pfs
|
||||||
|
ld8.nta r22=[r3],56 // ar.lc
|
||||||
|
;;
|
||||||
|
ld8.nta r24=[r2],32 // pr
|
||||||
|
mov b0=r16
|
||||||
|
;;
|
||||||
|
ldf.fill.nta f2=[r2],32
|
||||||
|
ldf.fill.nta f3=[r3],32
|
||||||
|
mov b1=r17
|
||||||
|
;;
|
||||||
|
ldf.fill.nta f4=[r2],32
|
||||||
|
ldf.fill.nta f5=[r3],32
|
||||||
|
mov b2=r18
|
||||||
|
;;
|
||||||
|
ldf.fill.nta f16=[r2],32
|
||||||
|
ldf.fill.nta f17=[r3],32
|
||||||
|
mov b3=r19
|
||||||
|
;;
|
||||||
|
ldf.fill.nta f18=[r2],32
|
||||||
|
ldf.fill.nta f19=[r3],32
|
||||||
|
mov b4=r20
|
||||||
|
;;
|
||||||
|
ldf.fill.nta f20=[r2],32
|
||||||
|
ldf.fill.nta f21=[r3],32
|
||||||
|
mov b5=r21
|
||||||
|
;;
|
||||||
|
ldf.fill.nta f22=[r2],32
|
||||||
|
ldf.fill.nta f23=[r3],32
|
||||||
|
mov ar.lc=r22
|
||||||
|
;;
|
||||||
|
ldf.fill.nta f24=[r2],32
|
||||||
|
ldf.fill.nta f25=[r3],32
|
||||||
|
cmp.eq p8,p9=0,in1
|
||||||
|
;;
|
||||||
|
ldf.fill.nta f26=[r2],32
|
||||||
|
ldf.fill.nta f27=[r3],32
|
||||||
|
mov ar.pfs=r11
|
||||||
|
;;
|
||||||
|
ldf.fill.nta f28=[r2],32
|
||||||
|
ldf.fill.nta f29=[r3],32
|
||||||
|
;;
|
||||||
|
ldf.fill.nta f30=[r2]
|
||||||
|
ldf.fill.nta f31=[r3]
|
||||||
|
(p8) mov r8=1
|
||||||
|
|
||||||
|
mov ar.rnat=r26 // restore ar.rnat
|
||||||
|
;;
|
||||||
|
mov ar.rsc=r27 // restore ar.rsc
|
||||||
|
(p9) mov r8=in1
|
||||||
|
|
||||||
|
invala // virt. -> phys. regnum mapping may change
|
||||||
|
mov pr=r24,-1
|
||||||
|
br.ret.dptk.few rp
|
||||||
|
.endp __longjmp
|
339
ia64/memcpy.S
Normal file
339
ia64/memcpy.S
Normal file
|
@ -0,0 +1,339 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*
|
||||||
|
* This file is derived from the Linux/ia64 kernel source code
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Optimized version of the standard memcpy() function
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* in0: destination address
|
||||||
|
* in1: source address
|
||||||
|
* in2: number of bytes to copy
|
||||||
|
* Output:
|
||||||
|
* no return value
|
||||||
|
*
|
||||||
|
* Copyright (C) 2000 Hewlett-Packard Co
|
||||||
|
* Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
* Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* be pessimistic for now... */
|
||||||
|
#define CONFIG_ITANIUM_B0_SPECIFIC 1
|
||||||
|
|
||||||
|
#if defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)
|
||||||
|
# define BRP(args...) nop.b 0
|
||||||
|
#else
|
||||||
|
# define BRP(args...) brp.loop.imp args
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.text
|
||||||
|
// FALL THROUGH
|
||||||
|
.global Memcpy
|
||||||
|
.proc Memcpy
|
||||||
|
Memcpy:
|
||||||
|
# define MEM_LAT 21 /* latency to memory */
|
||||||
|
|
||||||
|
# define dst r2
|
||||||
|
# define src r3
|
||||||
|
# define retval r8
|
||||||
|
# define saved_pfs r9
|
||||||
|
# define saved_lc r10
|
||||||
|
# define saved_pr r11
|
||||||
|
# define cnt r16
|
||||||
|
# define src2 r17
|
||||||
|
# define t0 r18
|
||||||
|
# define t1 r19
|
||||||
|
# define t2 r20
|
||||||
|
# define t3 r21
|
||||||
|
# define t4 r22
|
||||||
|
# define src_end r23
|
||||||
|
|
||||||
|
# define N (MEM_LAT + 4)
|
||||||
|
# define Nrot ((N + 7) & ~7)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First, check if everything (src, dst, len) is a multiple of eight. If
|
||||||
|
* so, we handle everything with no taken branches (other than the loop
|
||||||
|
* itself) and a small icache footprint. Otherwise, we jump off to
|
||||||
|
* the more general copy routine handling arbitrary
|
||||||
|
* sizes/alignment etc.
|
||||||
|
*/
|
||||||
|
.prologue
|
||||||
|
.save ar.pfs, saved_pfs
|
||||||
|
alloc saved_pfs=ar.pfs,3,Nrot,0,Nrot
|
||||||
|
.save ar.lc, saved_lc
|
||||||
|
mov saved_lc=ar.lc
|
||||||
|
or t0=in0,in1
|
||||||
|
;;
|
||||||
|
|
||||||
|
or t0=t0,in2
|
||||||
|
.save pr, saved_pr
|
||||||
|
mov saved_pr=pr
|
||||||
|
|
||||||
|
.body
|
||||||
|
|
||||||
|
cmp.eq p6,p0=in2,r0 // zero length?
|
||||||
|
mov retval=in0 // return dst
|
||||||
|
(p6) br.ret.spnt.many rp // zero length, return immediately
|
||||||
|
;;
|
||||||
|
|
||||||
|
mov dst=in0 // copy because of rotation
|
||||||
|
shr.u cnt=in2,3 // number of 8-byte words to copy
|
||||||
|
mov pr.rot=1<<16
|
||||||
|
;;
|
||||||
|
|
||||||
|
adds cnt=-1,cnt // br.ctop is repeat/until
|
||||||
|
cmp.gtu p7,p0=16,in2 // copying less than 16 bytes?
|
||||||
|
mov ar.ec=N
|
||||||
|
;;
|
||||||
|
|
||||||
|
and t0=0x7,t0
|
||||||
|
mov ar.lc=cnt
|
||||||
|
;;
|
||||||
|
cmp.ne p6,p0=t0,r0
|
||||||
|
|
||||||
|
mov src=in1 // copy because of rotation
|
||||||
|
(p7) br.cond.spnt.few memcpy_short
|
||||||
|
(p6) br.cond.spnt.few memcpy_long
|
||||||
|
;;
|
||||||
|
nop.m 0
|
||||||
|
;;
|
||||||
|
nop.m 0
|
||||||
|
nop.i 0
|
||||||
|
;;
|
||||||
|
nop.m 0
|
||||||
|
;;
|
||||||
|
.rotr val[N]
|
||||||
|
.rotp p[N]
|
||||||
|
.align 32
|
||||||
|
1: { .mib
|
||||||
|
(p[0]) ld8 val[0]=[src],8
|
||||||
|
nop.i 0
|
||||||
|
BRP(1b, 2f)
|
||||||
|
}
|
||||||
|
2: { .mfb
|
||||||
|
(p[N-1])st8 [dst]=val[N-1],8
|
||||||
|
nop.f 0
|
||||||
|
br.ctop.dptk.few 1b
|
||||||
|
}
|
||||||
|
;;
|
||||||
|
mov ar.lc=saved_lc
|
||||||
|
mov pr=saved_pr,-1
|
||||||
|
mov ar.pfs=saved_pfs
|
||||||
|
br.ret.sptk.many rp
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Small (<16 bytes) unaligned copying is done via a simple byte-at-the-time
|
||||||
|
* copy loop. This performs relatively poorly on Itanium, but it doesn't
|
||||||
|
* get used very often (gcc inlines small copies) and due to atomicity
|
||||||
|
* issues, we want to avoid read-modify-write of entire words.
|
||||||
|
*/
|
||||||
|
.align 32
|
||||||
|
memcpy_short:
|
||||||
|
adds cnt=-1,in2 // br.ctop is repeat/until
|
||||||
|
mov ar.ec=MEM_LAT
|
||||||
|
BRP(1f, 2f)
|
||||||
|
;;
|
||||||
|
mov ar.lc=cnt
|
||||||
|
;;
|
||||||
|
nop.m 0
|
||||||
|
;;
|
||||||
|
nop.m 0
|
||||||
|
nop.i 0
|
||||||
|
;;
|
||||||
|
nop.m 0
|
||||||
|
;;
|
||||||
|
nop.m 0
|
||||||
|
;;
|
||||||
|
/*
|
||||||
|
* It is faster to put a stop bit in the loop here because it makes
|
||||||
|
* the pipeline shorter (and latency is what matters on short copies).
|
||||||
|
*/
|
||||||
|
.align 32
|
||||||
|
1: { .mib
|
||||||
|
(p[0]) ld1 val[0]=[src],1
|
||||||
|
nop.i 0
|
||||||
|
BRP(1b, 2f)
|
||||||
|
} ;;
|
||||||
|
2: { .mfb
|
||||||
|
(p[MEM_LAT-1])st1 [dst]=val[MEM_LAT-1],1
|
||||||
|
nop.f 0
|
||||||
|
br.ctop.dptk.few 1b
|
||||||
|
} ;;
|
||||||
|
mov ar.lc=saved_lc
|
||||||
|
mov pr=saved_pr,-1
|
||||||
|
mov ar.pfs=saved_pfs
|
||||||
|
br.ret.sptk.many rp
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Large (>= 16 bytes) copying is done in a fancy way. Latency isn't
|
||||||
|
* an overriding concern here, but throughput is. We first do
|
||||||
|
* sub-word copying until the destination is aligned, then we check
|
||||||
|
* if the source is also aligned. If so, we do a simple load/store-loop
|
||||||
|
* until there are less than 8 bytes left over and then we do the tail,
|
||||||
|
* by storing the last few bytes using sub-word copying. If the source
|
||||||
|
* is not aligned, we branch off to the non-congruent loop.
|
||||||
|
*
|
||||||
|
* stage: op:
|
||||||
|
* 0 ld
|
||||||
|
* :
|
||||||
|
* MEM_LAT+3 shrp
|
||||||
|
* MEM_LAT+4 st
|
||||||
|
*
|
||||||
|
* On Itanium, the pipeline itself runs without stalls. However, br.ctop
|
||||||
|
* seems to introduce an unavoidable bubble in the pipeline so the overall
|
||||||
|
* latency is 2 cycles/iteration. This gives us a _copy_ throughput
|
||||||
|
* of 4 byte/cycle. Still not bad.
|
||||||
|
*/
|
||||||
|
# undef N
|
||||||
|
# undef Nrot
|
||||||
|
# define N (MEM_LAT + 5) /* number of stages */
|
||||||
|
# define Nrot ((N+1 + 2 + 7) & ~7) /* number of rotating regs */
|
||||||
|
|
||||||
|
#define LOG_LOOP_SIZE 6
|
||||||
|
|
||||||
|
memcpy_long:
|
||||||
|
alloc t3=ar.pfs,3,Nrot,0,Nrot // resize register frame
|
||||||
|
and t0=-8,src // t0 = src & ~7
|
||||||
|
and t2=7,src // t2 = src & 7
|
||||||
|
;;
|
||||||
|
ld8 t0=[t0] // t0 = 1st source word
|
||||||
|
adds src2=7,src // src2 = (src + 7)
|
||||||
|
sub t4=r0,dst // t4 = -dst
|
||||||
|
;;
|
||||||
|
and src2=-8,src2 // src2 = (src + 7) & ~7
|
||||||
|
shl t2=t2,3 // t2 = 8*(src & 7)
|
||||||
|
shl t4=t4,3 // t4 = 8*(dst & 7)
|
||||||
|
;;
|
||||||
|
ld8 t1=[src2] // t1 = 1st source word if src is 8-byte aligned, 2nd otherwise
|
||||||
|
sub t3=64,t2 // t3 = 64-8*(src & 7)
|
||||||
|
shr.u t0=t0,t2
|
||||||
|
;;
|
||||||
|
add src_end=src,in2
|
||||||
|
shl t1=t1,t3
|
||||||
|
mov pr=t4,0x38 // (p5,p4,p3)=(dst & 7)
|
||||||
|
;;
|
||||||
|
or t0=t0,t1
|
||||||
|
mov cnt=r0
|
||||||
|
adds src_end=-1,src_end
|
||||||
|
;;
|
||||||
|
(p3) st1 [dst]=t0,1
|
||||||
|
(p3) shr.u t0=t0,8
|
||||||
|
(p3) adds cnt=1,cnt
|
||||||
|
;;
|
||||||
|
(p4) st2 [dst]=t0,2
|
||||||
|
(p4) shr.u t0=t0,16
|
||||||
|
(p4) adds cnt=2,cnt
|
||||||
|
;;
|
||||||
|
(p5) st4 [dst]=t0,4
|
||||||
|
(p5) adds cnt=4,cnt
|
||||||
|
and src_end=-8,src_end // src_end = last word of source buffer
|
||||||
|
;;
|
||||||
|
|
||||||
|
// At this point, dst is aligned to 8 bytes and there at least 16-7=9 bytes left to copy:
|
||||||
|
|
||||||
|
1:{ add src=cnt,src // make src point to remainder of source buffer
|
||||||
|
sub cnt=in2,cnt // cnt = number of bytes left to copy
|
||||||
|
mov t4=ip
|
||||||
|
} ;;
|
||||||
|
and src2=-8,src // align source pointer
|
||||||
|
adds t4=memcpy_loops-1b,t4
|
||||||
|
mov ar.ec=N
|
||||||
|
|
||||||
|
and t0=7,src // t0 = src & 7
|
||||||
|
shr.u t2=cnt,3 // t2 = number of 8-byte words left to copy
|
||||||
|
shl cnt=cnt,3 // move bits 0-2 to 3-5
|
||||||
|
;;
|
||||||
|
|
||||||
|
.rotr val[N+1], w[2]
|
||||||
|
.rotp p[N]
|
||||||
|
|
||||||
|
cmp.ne p6,p0=t0,r0 // is src aligned, too?
|
||||||
|
shl t0=t0,LOG_LOOP_SIZE // t0 = 8*(src & 7)
|
||||||
|
adds t2=-1,t2 // br.ctop is repeat/until
|
||||||
|
;;
|
||||||
|
add t4=t0,t4
|
||||||
|
mov pr=cnt,0x38 // set (p5,p4,p3) to # of bytes last-word bytes to copy
|
||||||
|
mov ar.lc=t2
|
||||||
|
;;
|
||||||
|
nop.m 0
|
||||||
|
;;
|
||||||
|
nop.m 0
|
||||||
|
nop.i 0
|
||||||
|
;;
|
||||||
|
nop.m 0
|
||||||
|
;;
|
||||||
|
(p6) ld8 val[1]=[src2],8 // prime the pump...
|
||||||
|
mov b6=t4
|
||||||
|
br.sptk.few b6
|
||||||
|
;;
|
||||||
|
|
||||||
|
memcpy_tail:
|
||||||
|
// At this point, (p5,p4,p3) are set to the number of bytes left to copy (which is
|
||||||
|
// less than 8) and t0 contains the last few bytes of the src buffer:
|
||||||
|
(p5) st4 [dst]=t0,4
|
||||||
|
(p5) shr.u t0=t0,32
|
||||||
|
mov ar.lc=saved_lc
|
||||||
|
;;
|
||||||
|
(p4) st2 [dst]=t0,2
|
||||||
|
(p4) shr.u t0=t0,16
|
||||||
|
mov ar.pfs=saved_pfs
|
||||||
|
;;
|
||||||
|
(p3) st1 [dst]=t0
|
||||||
|
mov pr=saved_pr,-1
|
||||||
|
br.ret.sptk.many rp
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
|
.align 64
|
||||||
|
|
||||||
|
#define COPY(shift,index) \
|
||||||
|
1: { .mib \
|
||||||
|
(p[0]) ld8 val[0]=[src2],8; \
|
||||||
|
(p[MEM_LAT+3]) shrp w[0]=val[MEM_LAT+3],val[MEM_LAT+4-index],shift; \
|
||||||
|
BRP(1b, 2f) \
|
||||||
|
}; \
|
||||||
|
2: { .mfb \
|
||||||
|
(p[MEM_LAT+4]) st8 [dst]=w[1],8; \
|
||||||
|
nop.f 0; \
|
||||||
|
br.ctop.dptk.few 1b; \
|
||||||
|
}; \
|
||||||
|
;; \
|
||||||
|
ld8 val[N-1]=[src_end]; /* load last word (may be same as val[N]) */ \
|
||||||
|
;; \
|
||||||
|
shrp t0=val[N-1],val[N-index],shift; \
|
||||||
|
br memcpy_tail
|
||||||
|
memcpy_loops:
|
||||||
|
COPY(0, 1) /* no point special casing this---it doesn't go any faster without shrp */
|
||||||
|
COPY(8, 0)
|
||||||
|
COPY(16, 0)
|
||||||
|
COPY(24, 0)
|
||||||
|
COPY(32, 0)
|
||||||
|
COPY(40, 0)
|
||||||
|
COPY(48, 0)
|
||||||
|
COPY(56, 0)
|
||||||
|
.endp Memcpy
|
||||||
|
|
133
ia64/memset.S
Normal file
133
ia64/memset.S
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 1999-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*
|
||||||
|
* This code is derived from the Linux/ia64 source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Optimized version of the standard memset() function
|
||||||
|
*
|
||||||
|
* Return: none
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* in0: address of buffer
|
||||||
|
* in1: byte value to use for storing
|
||||||
|
* in2: length of the buffer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// arguments
|
||||||
|
//
|
||||||
|
#define buf r32
|
||||||
|
#define val r33
|
||||||
|
#define len r34
|
||||||
|
|
||||||
|
//
|
||||||
|
// local registers
|
||||||
|
//
|
||||||
|
#define saved_pfs r14
|
||||||
|
#define cnt r18
|
||||||
|
#define buf2 r19
|
||||||
|
#define saved_lc r20
|
||||||
|
#define tmp r21
|
||||||
|
.text
|
||||||
|
.global Memset
|
||||||
|
.proc Memset
|
||||||
|
Memset:
|
||||||
|
.prologue
|
||||||
|
.save ar.pfs, saved_pfs
|
||||||
|
alloc saved_pfs=ar.pfs,3,0,0,0 // cnt is sink here
|
||||||
|
cmp.eq p8,p0=r0,len // check for zero length
|
||||||
|
.save ar.lc, saved_lc
|
||||||
|
mov saved_lc=ar.lc // preserve ar.lc (slow)
|
||||||
|
;;
|
||||||
|
|
||||||
|
.body
|
||||||
|
|
||||||
|
adds tmp=-1,len // br.ctop is repeat/until
|
||||||
|
tbit.nz p6,p0=buf,0 // odd alignment
|
||||||
|
(p8) br.ret.spnt.few rp
|
||||||
|
|
||||||
|
cmp.lt p7,p0=16,len // if len > 16 then long memset
|
||||||
|
mux1 val=val,@brcst // prepare value
|
||||||
|
(p7) br.cond.dptk.few long_memset
|
||||||
|
;;
|
||||||
|
mov ar.lc=tmp // initialize lc for small count
|
||||||
|
;; // avoid RAW and WAW on ar.lc
|
||||||
|
1: // worst case 15 cyles, avg 8 cycles
|
||||||
|
st1 [buf]=val,1
|
||||||
|
br.cloop.dptk.few 1b
|
||||||
|
;; // avoid RAW on ar.lc
|
||||||
|
mov ar.lc=saved_lc
|
||||||
|
mov ar.pfs=saved_pfs
|
||||||
|
br.ret.sptk.few rp // end of short memset
|
||||||
|
|
||||||
|
// at this point we know we have more than 16 bytes to copy
|
||||||
|
// so we focus on alignment
|
||||||
|
long_memset:
|
||||||
|
(p6) st1 [buf]=val,1 // 1-byte aligned
|
||||||
|
(p6) adds len=-1,len;; // sync because buf is modified
|
||||||
|
tbit.nz p6,p0=buf,1
|
||||||
|
;;
|
||||||
|
(p6) st2 [buf]=val,2 // 2-byte aligned
|
||||||
|
(p6) adds len=-2,len;;
|
||||||
|
tbit.nz p6,p0=buf,2
|
||||||
|
;;
|
||||||
|
(p6) st4 [buf]=val,4 // 4-byte aligned
|
||||||
|
(p6) adds len=-4,len;;
|
||||||
|
tbit.nz p6,p0=buf,3
|
||||||
|
;;
|
||||||
|
(p6) st8 [buf]=val,8 // 8-byte aligned
|
||||||
|
(p6) adds len=-8,len;;
|
||||||
|
shr.u cnt=len,4 // number of 128-bit (2x64bit) words
|
||||||
|
;;
|
||||||
|
cmp.eq p6,p0=r0,cnt
|
||||||
|
adds tmp=-1,cnt
|
||||||
|
(p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left
|
||||||
|
;;
|
||||||
|
adds buf2=8,buf // setup second base pointer
|
||||||
|
mov ar.lc=tmp
|
||||||
|
;;
|
||||||
|
2: // 16bytes/iteration
|
||||||
|
st8 [buf]=val,16
|
||||||
|
st8 [buf2]=val,16
|
||||||
|
br.cloop.dptk.few 2b
|
||||||
|
;;
|
||||||
|
.dotail: // tail correction based on len only
|
||||||
|
tbit.nz p6,p0=len,3
|
||||||
|
;;
|
||||||
|
(p6) st8 [buf]=val,8 // at least 8 bytes
|
||||||
|
tbit.nz p6,p0=len,2
|
||||||
|
;;
|
||||||
|
(p6) st4 [buf]=val,4 // at least 4 bytes
|
||||||
|
tbit.nz p6,p0=len,1
|
||||||
|
;;
|
||||||
|
(p6) st2 [buf]=val,2 // at least 2 bytes
|
||||||
|
tbit.nz p6,p0=len,0
|
||||||
|
mov ar.lc=saved_lc
|
||||||
|
;;
|
||||||
|
(p6) st1 [buf]=val // only 1 byte left
|
||||||
|
br.ret.dptk.few rp
|
||||||
|
.endp Memset
|
453
ia64/plain_loader.c
Normal file
453
ia64/plain_loader.c
Normal file
|
@ -0,0 +1,453 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001 Silicon Graphics, Inc.
|
||||||
|
* Contributed by Brent Casavant <bcasavan@sgi.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
#include "loader.h"
|
||||||
|
#include "elf.h"
|
||||||
|
#include "private.h"
|
||||||
|
|
||||||
|
#define LD_NAME L"plain_elf64"
|
||||||
|
|
||||||
|
#define PLAIN_MIN_BLOCK_SIZE sizeof(Elf64_Ehdr) /* see load_elf() for details */
|
||||||
|
|
||||||
|
#define SKIPBUFSIZE 2048 /* minimal default size of the skip buffer */
|
||||||
|
static CHAR8 *skip_buffer; /* used to skip over unneeded data */
|
||||||
|
static UINTN skip_bufsize;
|
||||||
|
static UINTN elf_is_big_endian; /* true if ELF file is big endian */
|
||||||
|
|
||||||
|
static inline UINT64
|
||||||
|
bswap64(UINT64 v)
|
||||||
|
{
|
||||||
|
if(elf_is_big_endian) v = __ia64_swab64(v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline UINT32
|
||||||
|
bswap32(UINT32 v)
|
||||||
|
{
|
||||||
|
if(elf_is_big_endian) v = __ia64_swab32(v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline UINT16
|
||||||
|
bswap16(UINT16 v)
|
||||||
|
{
|
||||||
|
if(elf_is_big_endian) v = __ia64_swab16(v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
is_valid_header(Elf64_Ehdr *ehdr)
|
||||||
|
{
|
||||||
|
UINT16 type, machine;
|
||||||
|
|
||||||
|
if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
|
||||||
|
type = __ia64_swab16(ehdr->e_type);
|
||||||
|
machine = __ia64_swab16(ehdr->e_machine);
|
||||||
|
} else {
|
||||||
|
type = ehdr->e_type;
|
||||||
|
machine = ehdr->e_machine;
|
||||||
|
}
|
||||||
|
DBG_PRT((L"class=%d type=%d data=%d machine=%d\n",
|
||||||
|
ehdr->e_ident[EI_CLASS],
|
||||||
|
type,
|
||||||
|
ehdr->e_ident[EI_DATA],
|
||||||
|
machine));
|
||||||
|
|
||||||
|
return ehdr->e_ident[EI_MAG0] == 0x7f
|
||||||
|
&& ehdr->e_ident[EI_MAG1] == 'E'
|
||||||
|
&& ehdr->e_ident[EI_MAG2] == 'L'
|
||||||
|
&& ehdr->e_ident[EI_MAG3] == 'F'
|
||||||
|
&& ehdr->e_ident[EI_CLASS] == ELFCLASS64
|
||||||
|
&& type == ET_EXEC /* must be executable */
|
||||||
|
&& machine == EM_IA_64 ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
plain_probe(CHAR16 *kname)
|
||||||
|
{
|
||||||
|
Elf64_Ehdr ehdr;
|
||||||
|
EFI_STATUS status;
|
||||||
|
INTN ret = -1;
|
||||||
|
fops_fd_t fd;
|
||||||
|
UINTN size = sizeof(ehdr);
|
||||||
|
|
||||||
|
status = fops_open(kname, &fd);
|
||||||
|
if (EFI_ERROR(status)) return -1;
|
||||||
|
|
||||||
|
status = fops_read(fd, &ehdr, &size);
|
||||||
|
|
||||||
|
if (EFI_ERROR(status) || size != sizeof(ehdr)) goto error;
|
||||||
|
|
||||||
|
ret = is_valid_header(&ehdr);
|
||||||
|
error:
|
||||||
|
fops_close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* move skip bytes forward in the file
|
||||||
|
* this is required because we cannot assume fileops has
|
||||||
|
* seek() capabilities.
|
||||||
|
*/
|
||||||
|
static INTN
|
||||||
|
skip_bytes(fops_fd_t fd, UINTN curpos, UINTN newpos)
|
||||||
|
{
|
||||||
|
EFI_STATUS status;
|
||||||
|
UINTN n, skip;
|
||||||
|
|
||||||
|
skip = newpos - curpos;
|
||||||
|
/* check if seek capability exists */
|
||||||
|
|
||||||
|
status = fops_seek(fd, newpos);
|
||||||
|
if (status == EFI_SUCCESS) return 0;
|
||||||
|
|
||||||
|
if (status != EFI_UNSUPPORTED) goto error;
|
||||||
|
|
||||||
|
/* unsupported case */
|
||||||
|
|
||||||
|
if (skip_buffer == NULL) {
|
||||||
|
skip_bufsize = MAX(skip, SKIPBUFSIZE);
|
||||||
|
skip_buffer= (CHAR8 *)alloc(skip_bufsize, EfiLoaderData);
|
||||||
|
if (skip_buffer == NULL) return -1;
|
||||||
|
}
|
||||||
|
while (skip) {
|
||||||
|
n = skip > skip_bufsize? skip_bufsize : skip;
|
||||||
|
|
||||||
|
status = fops_read(fd, skip_buffer, &n);
|
||||||
|
if (EFI_ERROR(status)) goto error;
|
||||||
|
|
||||||
|
skip -=n;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
ERR_PRT((L"%s : cannot skip %d bytes\n", LD_NAME, n));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
load_elf(fops_fd_t fd, kdesc_t *kd)
|
||||||
|
{
|
||||||
|
Elf64_Ehdr ehdr;
|
||||||
|
Elf64_Phdr *phdrs;
|
||||||
|
EFI_STATUS status;
|
||||||
|
INTN ret = ELILO_LOAD_ERROR;
|
||||||
|
UINTN i, total_size = 0;
|
||||||
|
UINTN pages, size, bss_sz, osize;
|
||||||
|
UINTN offs = 0;
|
||||||
|
VOID *low_addr = (VOID *)~0;
|
||||||
|
VOID *max_addr = (VOID *)0;
|
||||||
|
UINTN load_offset = 0;
|
||||||
|
UINTN paddr, memsz, filesz, poffs;
|
||||||
|
UINT16 phnum;
|
||||||
|
|
||||||
|
Print(L"Loading Linux... ");
|
||||||
|
|
||||||
|
size = sizeof(ehdr);
|
||||||
|
|
||||||
|
status = fops_read(fd, &ehdr, &size);
|
||||||
|
if (EFI_ERROR(status) ||size < sizeof(ehdr)) return ELILO_LOAD_ERROR;
|
||||||
|
|
||||||
|
offs += size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* do some sanity checking on the file
|
||||||
|
*/
|
||||||
|
if (is_valid_header(&ehdr) == -1) {
|
||||||
|
ERR_PRT((L"%s : not an elf 64-bit file\n", LD_NAME));
|
||||||
|
return ELILO_LOAD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* determine file endianess */
|
||||||
|
elf_is_big_endian = ehdr.e_ident[EI_DATA] == ELFDATA2MSB ? 1 : 0;
|
||||||
|
|
||||||
|
VERB_PRT(3, {
|
||||||
|
Print(L"ELF file is %s\n", elf_is_big_endian ? L"big endian" : L"little endian");
|
||||||
|
Print(L"Entry point 0x%lx\n", bswap64(ehdr.e_entry));
|
||||||
|
Print(L"%d program headers\n", bswap16(ehdr.e_phnum));
|
||||||
|
Print(L"%d segment headers\n", bswap16(ehdr.e_shnum));
|
||||||
|
});
|
||||||
|
|
||||||
|
phnum = bswap16(ehdr.e_phnum);
|
||||||
|
|
||||||
|
if (skip_bytes(fd, offs, bswap64(ehdr.e_phoff)) != 0) {
|
||||||
|
ERR_PRT((L"%s : skip tp %ld for phdrs failed", LD_NAME, offs));
|
||||||
|
return ELILO_LOAD_ERROR;
|
||||||
|
}
|
||||||
|
offs = bswap64(ehdr.e_phoff);
|
||||||
|
|
||||||
|
size = osize = phnum*sizeof(Elf64_Phdr);
|
||||||
|
|
||||||
|
DBG_PRT((L"%s : phdrs allocate %d bytes sizeof=%d entsize=%d\n", LD_NAME, size,sizeof(Elf64_Phdr), bswap16(ehdr.e_phentsize)));
|
||||||
|
|
||||||
|
phdrs = (Elf64_Phdr *)alloc(size, 0);
|
||||||
|
if (phdrs == NULL) {
|
||||||
|
ERR_PRT((L"%s : allocate phdrs failed", LD_NAME));
|
||||||
|
return ELILO_LOAD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = fops_read(fd, phdrs, &size);
|
||||||
|
if (EFI_ERROR(status) || size != osize) {
|
||||||
|
ERR_PRT((L"%s : load phdrs failed", LD_NAME, status));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
offs += size;
|
||||||
|
/*
|
||||||
|
* First pass to figure out:
|
||||||
|
* - lowest physical address
|
||||||
|
* - total memory footprint
|
||||||
|
*/
|
||||||
|
for (i = 0; i < phnum; i++) {
|
||||||
|
|
||||||
|
paddr = bswap64(phdrs[i].p_paddr);
|
||||||
|
memsz = bswap64(phdrs[i].p_memsz);
|
||||||
|
|
||||||
|
DBG_PRT((L"Phdr %d paddr [0x%lx-0x%lx] offset %ld"
|
||||||
|
" filesz %ld memsz=%ld bss_sz=%ld p_type=%d\n",
|
||||||
|
1+i,
|
||||||
|
paddr,
|
||||||
|
paddr+bswap64(phdrs[i].p_filesz),
|
||||||
|
bswap64(phdrs[i].p_offset),
|
||||||
|
bswap64(phdrs[i].p_filesz),
|
||||||
|
memsz,
|
||||||
|
memsz - bswap64(phdrs[i].p_filesz), bswap32(phdrs[i].p_type)));
|
||||||
|
|
||||||
|
if (bswap32(phdrs[i].p_type) != PT_LOAD) continue;
|
||||||
|
|
||||||
|
|
||||||
|
if (paddr < (UINTN)low_addr) low_addr = (VOID *)paddr;
|
||||||
|
|
||||||
|
if (paddr + memsz > (UINTN)max_addr)
|
||||||
|
max_addr = (VOID *)paddr + memsz;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((UINTN)low_addr & (EFI_PAGE_SIZE - 1)) {
|
||||||
|
ERR_PRT((L"%s : kernel low address 0x%lx not page aligned\n", LD_NAME, low_addr));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* how many bytes are needed to hold the kernel */
|
||||||
|
total_size = (UINTN)max_addr - (UINTN)low_addr;
|
||||||
|
|
||||||
|
/* round up to get required number of pages */
|
||||||
|
pages = EFI_SIZE_TO_PAGES(total_size);
|
||||||
|
|
||||||
|
/* keep track of location where kernel ends for
|
||||||
|
* the initrd ramdisk (it will be put right after the kernel)
|
||||||
|
*/
|
||||||
|
kd->kstart = low_addr;
|
||||||
|
kd->kend = low_addr+ (pages << EFI_PAGE_SHIFT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* that's the kernel entry point (virtual address)
|
||||||
|
*/
|
||||||
|
kd->kentry = (VOID *)bswap64(ehdr.e_entry);
|
||||||
|
|
||||||
|
if (((UINTN)kd->kentry >> 61) != 0) {
|
||||||
|
ERR_PRT((L"%s: <<ERROR>> entry point is a virtual address 0x%lx : not supported anymore\n", LD_NAME, kd->kentry));
|
||||||
|
}
|
||||||
|
|
||||||
|
VERB_PRT(3, {
|
||||||
|
Print(L"Lowest PhysAddr: 0x%lx\nTotalMemSize:%d bytes (%d pages)\n",
|
||||||
|
low_addr, total_size, pages);
|
||||||
|
Print(L"Kernel entry @ 0x%lx\n", kd->kentry);
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* now allocate memory for the kernel at the exact requested spot
|
||||||
|
*/
|
||||||
|
if (alloc_kmem(low_addr, pages) == -1) {
|
||||||
|
VOID *new_addr;
|
||||||
|
|
||||||
|
ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
|
||||||
|
|
||||||
|
if (ia64_can_relocate() == 0) {
|
||||||
|
ERR_PRT((L"relocation is disabled, cannot load kernel"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* could not allocate at requested spot, try to find a
|
||||||
|
* suitable location to relocate the kernel
|
||||||
|
*
|
||||||
|
* The maximum sized Itanium TLB translation entry is 256 MB.
|
||||||
|
* If we relocate the kernel by this amount we know for sure
|
||||||
|
* that alignment constraints will be satisified, regardless
|
||||||
|
* of the kernel used.
|
||||||
|
*/
|
||||||
|
Print(L"Attempting to relocate kernel.\n");
|
||||||
|
if (find_kernel_memory(low_addr, max_addr, 256*MB, &new_addr) == -1) {
|
||||||
|
ERR_PRT((L"%s : find_kernel_memory(0x%lx, 0x%lx, 0x%lx, 0x%lx) failed\n", LD_NAME, low_addr, max_addr, 256*MB, &load_offset));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* unsigned arithmetic */
|
||||||
|
load_offset = (UINTN) (new_addr - ROUNDDOWN((UINTN) low_addr,256*MB));
|
||||||
|
|
||||||
|
VERB_PRT(3, Print(L"low_addr=0x%lx new_addr=0x%lx offset=0x%lx", low_addr, new_addr, load_offset));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* correct various addesses for non-zero load_offset
|
||||||
|
*/
|
||||||
|
low_addr = (VOID*) ((UINTN) low_addr + load_offset);
|
||||||
|
max_addr = (VOID*) ((UINTN) max_addr + load_offset);
|
||||||
|
kd->kstart = (VOID *) ((UINTN) kd->kstart + load_offset);
|
||||||
|
kd->kend = (VOID *) ((UINTN) kd->kend + load_offset);
|
||||||
|
kd->kentry = (VOID *) ((UINTN) kd->kentry + load_offset);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* try one last time to get memory for the kernel
|
||||||
|
*/
|
||||||
|
if (alloc_kmem(low_addr, pages) == -1) {
|
||||||
|
ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
|
||||||
|
ERR_PRT((L"Relocation by 0x%lx bytes failed.\n", load_offset));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VERB_PRT(1, Print(L"Press any key to interrupt\n"));
|
||||||
|
|
||||||
|
/* Second pass:
|
||||||
|
* Walk through the program headers
|
||||||
|
* and actually load data into physical memory
|
||||||
|
*/
|
||||||
|
for (i = 0; i < phnum; i++) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for pure loadable segment; ignore if not loadable
|
||||||
|
*/
|
||||||
|
if (bswap32(phdrs[i].p_type) != PT_LOAD) continue;
|
||||||
|
|
||||||
|
poffs = bswap64(phdrs[i].p_offset);
|
||||||
|
|
||||||
|
size = poffs - offs;
|
||||||
|
|
||||||
|
VERB_PRT(3, Print(L"\noff=%ld poffs=%ld size=%ld\n", offs, poffs, size));
|
||||||
|
|
||||||
|
filesz = bswap64(phdrs[i].p_filesz);
|
||||||
|
/*
|
||||||
|
* correct p_paddr for non-zero load offset
|
||||||
|
*/
|
||||||
|
phdrs[i].p_paddr = (Elf64_Addr) ((UINTN) bswap64(phdrs[i].p_paddr) + load_offset);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move to the right position
|
||||||
|
*/
|
||||||
|
if (size && skip_bytes(fd, offs, poffs) != 0) goto out_kernel;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Keep track of current position in file
|
||||||
|
*/
|
||||||
|
offs += size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How many BSS bytes to clear
|
||||||
|
*/
|
||||||
|
bss_sz = bswap64(phdrs[i].p_memsz) - filesz;
|
||||||
|
|
||||||
|
VERB_PRT(4, {
|
||||||
|
Print(L"\nHeader #%d\n", i);
|
||||||
|
Print(L"offset %ld\n", poffs);
|
||||||
|
Print(L"Phys addr 0x%lx\n", phdrs[i].p_paddr); /* already endian adjusted */
|
||||||
|
Print(L"BSS size %ld bytes\n", bss_sz);
|
||||||
|
Print(L"skip=%ld offs=%ld\n", size, offs);
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read actual segment into memory
|
||||||
|
*/
|
||||||
|
ret = read_file(fd, filesz, (CHAR8 *)phdrs[i].p_paddr);
|
||||||
|
if (ret == ELILO_LOAD_ABORTED) goto load_abort;
|
||||||
|
if (ret == ELILO_LOAD_ERROR) goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* update file position
|
||||||
|
*/
|
||||||
|
offs += filesz;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear bss section
|
||||||
|
*/
|
||||||
|
if (bss_sz) Memset((VOID *) phdrs[i].p_paddr+filesz, 0, bss_sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(phdrs);
|
||||||
|
|
||||||
|
Print(L"..done\n");
|
||||||
|
return ELILO_LOAD_SUCCESS;
|
||||||
|
|
||||||
|
load_abort:
|
||||||
|
Print(L"..Aborted\n");
|
||||||
|
ret = ELILO_LOAD_ABORTED;
|
||||||
|
out_kernel:
|
||||||
|
/* free kernel memory */
|
||||||
|
free_kmem();
|
||||||
|
out:
|
||||||
|
free(phdrs);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
plain_load_kernel(CHAR16 *kname, kdesc_t *kd)
|
||||||
|
{
|
||||||
|
INTN ret;
|
||||||
|
fops_fd_t fd;
|
||||||
|
EFI_STATUS status;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Moving the open here simplifies the load_elf() error handling
|
||||||
|
*/
|
||||||
|
status = fops_open(kname, &fd);
|
||||||
|
if (EFI_ERROR(status)) return ELILO_LOAD_ERROR;
|
||||||
|
|
||||||
|
Print(L"Loading %s...", kname);
|
||||||
|
|
||||||
|
ret = load_elf(fd, kd);
|
||||||
|
|
||||||
|
fops_close(fd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if the skip buffer was ever used, free it
|
||||||
|
*/
|
||||||
|
if (skip_buffer) {
|
||||||
|
free(skip_buffer);
|
||||||
|
/* in case we come back */
|
||||||
|
skip_buffer = NULL;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
loader_ops_t plain_loader={
|
||||||
|
NULL,
|
||||||
|
LD_NAME,
|
||||||
|
plain_probe,
|
||||||
|
plain_load_kernel
|
||||||
|
};
|
35
ia64/private.h
Normal file
35
ia64/private.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ELILO_PRIVATE_IA64_H__
|
||||||
|
#define __ELILO_PRIVATE_IA64_H__
|
||||||
|
|
||||||
|
extern INTN check_fpswa(EFI_HANDLE, EFI_HANDLE, CHAR16 *);
|
||||||
|
extern INTN query_fpswa(VOID **);
|
||||||
|
|
||||||
|
extern INTN ia64_can_relocate();
|
||||||
|
|
||||||
|
#endif /* __ELILO_PRIVATE_IA64_H__ */
|
||||||
|
|
170
ia64/setjmp.S
Normal file
170
ia64/setjmp.S
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
/* Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||||
|
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
02111-1307 USA.
|
||||||
|
|
||||||
|
The layout of the jmp_buf is as follows. This is subject to change
|
||||||
|
and user-code should never depend on the particular layout of
|
||||||
|
jmp_buf!
|
||||||
|
|
||||||
|
|
||||||
|
offset: description:
|
||||||
|
------- ------------
|
||||||
|
0x000 stack pointer (r12) ; unchangeable (see _JMPBUF_UNWINDS)
|
||||||
|
0x008 r1 (gp)
|
||||||
|
0x010 caller's unat
|
||||||
|
0x018 fpsr
|
||||||
|
0x020 r4
|
||||||
|
0x028 r5
|
||||||
|
0x030 r6
|
||||||
|
0x038 r7
|
||||||
|
0x040 rp (b0)
|
||||||
|
0x048 b1
|
||||||
|
0x050 b2
|
||||||
|
0x058 b3
|
||||||
|
0x060 b4
|
||||||
|
0x068 b5
|
||||||
|
0x070 ar.pfs
|
||||||
|
0x078 ar.lc
|
||||||
|
0x080 pr
|
||||||
|
0x088 ar.bsp ; unchangeable (see __longjmp.S)
|
||||||
|
0x090 ar.unat
|
||||||
|
0x098 &__jmp_buf ; address of the jmpbuf (needed to locate NaT bits in unat)
|
||||||
|
0x0a0 f2
|
||||||
|
0x0b0 f3
|
||||||
|
0x0c0 f4
|
||||||
|
0x0d0 f5
|
||||||
|
0x0e0 f16
|
||||||
|
0x0f0 f17
|
||||||
|
0x100 f18
|
||||||
|
0x110 f19
|
||||||
|
0x120 f20
|
||||||
|
0x130 f21
|
||||||
|
0x130 f22
|
||||||
|
0x140 f23
|
||||||
|
0x150 f24
|
||||||
|
0x160 f25
|
||||||
|
0x170 f26
|
||||||
|
0x180 f27
|
||||||
|
0x190 f28
|
||||||
|
0x1a0 f29
|
||||||
|
0x1b0 f30
|
||||||
|
0x1c0 f31 */
|
||||||
|
|
||||||
|
|
||||||
|
/* The following two entry points are the traditional entry points: */
|
||||||
|
|
||||||
|
.text
|
||||||
|
.global setjmp
|
||||||
|
.proc setjmp
|
||||||
|
setjmp:
|
||||||
|
alloc r8=ar.pfs,2,0,0,0
|
||||||
|
mov in1=1
|
||||||
|
br.cond.sptk.many __sigsetjmp
|
||||||
|
.endp setjmp
|
||||||
|
|
||||||
|
/* __sigsetjmp(__jmp_buf buf, int savemask) */
|
||||||
|
|
||||||
|
__sigsetjmp:
|
||||||
|
//.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
|
||||||
|
alloc loc1=ar.pfs,2,2,2,0
|
||||||
|
mov r16=ar.unat
|
||||||
|
;;
|
||||||
|
mov r17=ar.fpsr
|
||||||
|
mov r2=in0
|
||||||
|
add r3=8,in0
|
||||||
|
;;
|
||||||
|
st8.spill.nta [r2]=sp,16 // r12 (sp)
|
||||||
|
st8.spill.nta [r3]=gp,16 // r1 (gp)
|
||||||
|
;;
|
||||||
|
st8.nta [r2]=r16,16 // save caller's unat
|
||||||
|
st8.nta [r3]=r17,16 // save fpsr
|
||||||
|
add r8=0xa0,in0
|
||||||
|
;;
|
||||||
|
st8.spill.nta [r2]=r4,16 // r4
|
||||||
|
st8.spill.nta [r3]=r5,16 // r5
|
||||||
|
add r9=0xb0,in0
|
||||||
|
;;
|
||||||
|
stf.spill.nta [r8]=f2,32
|
||||||
|
stf.spill.nta [r9]=f3,32
|
||||||
|
mov loc0=rp
|
||||||
|
.body
|
||||||
|
;;
|
||||||
|
stf.spill.nta [r8]=f4,32
|
||||||
|
stf.spill.nta [r9]=f5,32
|
||||||
|
mov r17=b1
|
||||||
|
;;
|
||||||
|
stf.spill.nta [r8]=f16,32
|
||||||
|
stf.spill.nta [r9]=f17,32
|
||||||
|
mov r18=b2
|
||||||
|
;;
|
||||||
|
stf.spill.nta [r8]=f18,32
|
||||||
|
stf.spill.nta [r9]=f19,32
|
||||||
|
mov r19=b3
|
||||||
|
;;
|
||||||
|
stf.spill.nta [r8]=f20,32
|
||||||
|
stf.spill.nta [r9]=f21,32
|
||||||
|
mov r20=b4
|
||||||
|
;;
|
||||||
|
stf.spill.nta [r8]=f22,32
|
||||||
|
stf.spill.nta [r9]=f23,32
|
||||||
|
mov r21=b5
|
||||||
|
;;
|
||||||
|
stf.spill.nta [r8]=f24,32
|
||||||
|
stf.spill.nta [r9]=f25,32
|
||||||
|
mov r22=ar.lc
|
||||||
|
;;
|
||||||
|
stf.spill.nta [r8]=f26,32
|
||||||
|
stf.spill.nta [r9]=f27,32
|
||||||
|
mov r24=pr
|
||||||
|
;;
|
||||||
|
stf.spill.nta [r8]=f28,32
|
||||||
|
stf.spill.nta [r9]=f29,32
|
||||||
|
;;
|
||||||
|
stf.spill.nta [r8]=f30
|
||||||
|
stf.spill.nta [r9]=f31
|
||||||
|
|
||||||
|
st8.spill.nta [r2]=r6,16 // r6
|
||||||
|
st8.spill.nta [r3]=r7,16 // r7
|
||||||
|
;;
|
||||||
|
mov r23=ar.bsp
|
||||||
|
mov r25=ar.unat
|
||||||
|
mov out0=in0
|
||||||
|
|
||||||
|
st8.nta [r2]=loc0,16 // b0
|
||||||
|
st8.nta [r3]=r17,16 // b1
|
||||||
|
mov out1=in1
|
||||||
|
;;
|
||||||
|
st8.nta [r2]=r18,16 // b2
|
||||||
|
st8.nta [r3]=r19,16 // b3
|
||||||
|
;;
|
||||||
|
st8.nta [r2]=r20,16 // b4
|
||||||
|
st8.nta [r3]=r21,16 // b5
|
||||||
|
;;
|
||||||
|
st8.nta [r2]=loc1,16 // ar.pfs
|
||||||
|
st8.nta [r3]=r22,16 // ar.lc
|
||||||
|
;;
|
||||||
|
st8.nta [r2]=r24,16 // pr
|
||||||
|
st8.nta [r3]=r23,16 // ar.bsp
|
||||||
|
;;
|
||||||
|
st8.nta [r2]=r25 // ar.unat
|
||||||
|
st8.nta [r3]=in0 // &__jmp_buf
|
||||||
|
mov r8=0
|
||||||
|
mov rp=loc0
|
||||||
|
mov ar.pfs=loc1
|
||||||
|
br.ret.sptk.many rp
|
||||||
|
|
||||||
|
.endp __sigsetjmp
|
28
ia64/setjmp.h
Normal file
28
ia64/setjmp.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/* Define the machine-dependent type `jmp_buf'. Linux/IA-64 version.
|
||||||
|
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
|
||||||
|
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public
|
||||||
|
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||||
|
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
Boston, MA 02111-1307, USA. */
|
||||||
|
|
||||||
|
/* User code must not depend on the internal representation of jmp_buf. */
|
||||||
|
|
||||||
|
#define _JBLEN 70
|
||||||
|
|
||||||
|
/* the __jmp_buf element type should be __float80 per ABI... */
|
||||||
|
typedef long jmp_buf[_JBLEN] __attribute__ ((aligned (16))); /* guarantees 128-bit alignment! */
|
||||||
|
|
||||||
|
extern int setjmp (jmp_buf __env);
|
||||||
|
extern void longjmp (jmp_buf __env, int __val);
|
107
ia64/sysdeps.h
Normal file
107
ia64/sysdeps.h
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is used to define all the IA64-specific data structures, functions,
|
||||||
|
* and constants used by the generic ELILO.
|
||||||
|
*
|
||||||
|
* For things specific to this platform use private.h instead
|
||||||
|
*/
|
||||||
|
#ifndef __ELILO_SYSDEPS_IA64_H__
|
||||||
|
#define __ELILO_SYSDEPS_IA64_H__
|
||||||
|
|
||||||
|
#define ELILO_ARCH "IA-64" /* ASCII string ! */
|
||||||
|
|
||||||
|
/* in respective assembly files */
|
||||||
|
extern VOID Memset(VOID *, INTN, UINTN);
|
||||||
|
extern VOID Memcpy(VOID *, VOID *, UINTN);
|
||||||
|
|
||||||
|
extern VOID sysdep_register_options(VOID);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This version must match the one in the kernel
|
||||||
|
*/
|
||||||
|
typedef struct ia64_boot_params {
|
||||||
|
/*
|
||||||
|
* The following three pointers MUST point to memory that is marked
|
||||||
|
* as EfiRuntimeServicesData so that the kernel doesn't think the
|
||||||
|
* underlying memory is free.
|
||||||
|
*/
|
||||||
|
UINTN command_line; /* physical address of command line arguments */
|
||||||
|
UINTN efi_systab; /* physical address of EFI system table */
|
||||||
|
UINTN efi_memmap; /* physical address of EFI memory map */
|
||||||
|
UINTN efi_memmap_size; /* size of EFI memory map */
|
||||||
|
UINTN efi_memdesc_size; /* size of an EFI memory map descriptor */
|
||||||
|
UINT32 efi_memdesc_version; /* descriptor version */
|
||||||
|
struct {
|
||||||
|
UINT16 num_cols; /* number of columns on console output device */
|
||||||
|
UINT16 num_rows; /* number of rows on console output device */
|
||||||
|
UINT16 orig_x; /* cursor's x position */
|
||||||
|
UINT16 orig_y; /* cursor's y position */
|
||||||
|
} console_info;
|
||||||
|
UINTN fpswa; /* physical address of fpswa interface */
|
||||||
|
UINTN initrd_start; /* virtual address where the initial ramdisk begins */
|
||||||
|
UINTN initrd_size; /* how big is the initial ramdisk */
|
||||||
|
|
||||||
|
UINTN loader_addr; /* start address of boot loader */
|
||||||
|
UINTN loader_size; /* size of loader code & data */
|
||||||
|
} boot_params_t;
|
||||||
|
|
||||||
|
typedef struct sys_img_options {
|
||||||
|
UINT8 dummy; /* forces non-zero offset for first field */
|
||||||
|
UINT8 allow_relocation; /* allow kernel relocation on allocation error */
|
||||||
|
} sys_img_options_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How to jump to kernel code
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
start_kernel(VOID *kentry, VOID *bp)
|
||||||
|
{
|
||||||
|
asm volatile ("mov r28=%1; br.sptk.few %0" :: "b"(kentry),"r"(bp));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const UINT64
|
||||||
|
__ia64_swab64 (UINT64 x)
|
||||||
|
{
|
||||||
|
UINT64 result;
|
||||||
|
|
||||||
|
asm volatile ("mux1 %0=%1,@rev" : "=r" (result) : "r" (x));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const UINT32
|
||||||
|
__ia64_swab32 (UINT32 x)
|
||||||
|
{
|
||||||
|
return __ia64_swab64(x) >> 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const UINT16
|
||||||
|
__ia64_swab16(UINT16 x)
|
||||||
|
{
|
||||||
|
return __ia64_swab64(x) >> 48;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __ELILO_SYSDEPS_IA64_H__ */
|
137
ia64/system.c
Normal file
137
ia64/system.c
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this file contains all the IA-64 specific code expected by generic loader
|
||||||
|
*/
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
#include "loader.h"
|
||||||
|
#include "private.h"
|
||||||
|
|
||||||
|
extern loader_ops_t plain_loader, gzip_loader;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IA-64 specific boot paramters initialization routine
|
||||||
|
*/
|
||||||
|
INTN
|
||||||
|
sysdeps_create_boot_params(boot_params_t *bp, CHAR8 *cmdline, memdesc_t *initrd, UINTN *cookie)
|
||||||
|
{
|
||||||
|
UINTN cols, rows;
|
||||||
|
SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
|
||||||
|
EFI_STATUS status;
|
||||||
|
mmap_desc_t mdesc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* retrieve address of FPSWA interface
|
||||||
|
* if not found, argument is not touched
|
||||||
|
* will be 0 because of Memset()
|
||||||
|
*/
|
||||||
|
query_fpswa((VOID **)&bp->fpswa);
|
||||||
|
|
||||||
|
if (get_memmap(&mdesc) == -1) return -1;
|
||||||
|
|
||||||
|
DBG_PRT((L"Got memory map @ 0x%lx (%d bytes)", mdesc.md, mdesc.map_size));
|
||||||
|
|
||||||
|
bp->efi_systab = (UINTN)systab;
|
||||||
|
bp->efi_memmap = (UINTN)mdesc.md;
|
||||||
|
bp->efi_memmap_size = mdesc.map_size;
|
||||||
|
bp->efi_memdesc_size = mdesc.desc_size;
|
||||||
|
bp->efi_memdesc_version = mdesc.desc_version;
|
||||||
|
bp->command_line = (UINTN)cmdline;
|
||||||
|
bp->initrd_start = (UINTN) initrd->start_addr;
|
||||||
|
bp->initrd_size = initrd->pgcnt << EFI_PAGE_SHIFT;
|
||||||
|
|
||||||
|
/* fetch console parameters: */
|
||||||
|
conout = systab->ConOut;
|
||||||
|
status = conout->QueryMode(conout, conout->Mode->Mode, &cols, &rows);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"boot_params QueryMode failed %r", status));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
DBG_PRT((L"Got console info: cols=%d rows=%d x=%d y=%d",
|
||||||
|
cols, rows, conout->Mode->CursorColumn, conout->Mode->CursorRow));
|
||||||
|
|
||||||
|
bp->console_info.num_cols = cols;
|
||||||
|
bp->console_info.num_rows = rows;
|
||||||
|
bp->console_info.orig_x = conout->Mode->CursorColumn;
|
||||||
|
bp->console_info.orig_y = conout->Mode->CursorRow;
|
||||||
|
|
||||||
|
*cookie = mdesc.cookie;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
/* free descriptors' memory */
|
||||||
|
free_memmap(&mdesc);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
sysdeps_free_boot_params(boot_params_t *bp)
|
||||||
|
{
|
||||||
|
mmap_desc_t md;
|
||||||
|
|
||||||
|
Memset(&md, 0, sizeof(md));
|
||||||
|
|
||||||
|
md.md = (VOID *)bp->efi_memmap;
|
||||||
|
|
||||||
|
free_memmap(&md);
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
sysdeps_init(EFI_HANDLE dev)
|
||||||
|
{
|
||||||
|
loader_register(&plain_loader);
|
||||||
|
loader_register(&gzip_loader);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We currently place the initrd at the next page aligned boundary
|
||||||
|
* after the kernel.
|
||||||
|
*
|
||||||
|
* Current kernel implementation requires this (see arch/ia64/kernel/setup.c).
|
||||||
|
*
|
||||||
|
* IMPORTANT: EFI & kernel page sizes may differ. We have no way
|
||||||
|
* of guessing what size the kernel uses. It is the responsibility
|
||||||
|
* of the kernel to adjust.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
imem->start_addr = (VOID *)ROUNDUP((UINTN)kd->kend, EFI_PAGE_SIZE);
|
||||||
|
#else
|
||||||
|
imem->start_addr = 0; /* let the allocator decide */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
112
initrd.c
Normal file
112
initrd.c
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function allocates memory for the initial ramdisk (initrd) and loads it to memory
|
||||||
|
* OUTPUTS:
|
||||||
|
* - ELILO_LOAD_SUCCESS: if everything works
|
||||||
|
* - ELILO_LOAD_ABORTED: in case the user decided to abort loading
|
||||||
|
* - ELILO_LOAD_ERROR: there was an error during alloc/read
|
||||||
|
*
|
||||||
|
* Adapted from Bill Nottingham <notting@redhat.com> patch for ELI.
|
||||||
|
*/
|
||||||
|
INTN
|
||||||
|
load_initrd(CHAR16 *filename, memdesc_t *initrd)
|
||||||
|
{
|
||||||
|
EFI_STATUS status;
|
||||||
|
VOID *start_addr = initrd->start_addr;
|
||||||
|
UINT64 size = 0;
|
||||||
|
UINTN pgcnt;
|
||||||
|
fops_fd_t fd;
|
||||||
|
INTN ret = ELILO_LOAD_ERROR;
|
||||||
|
|
||||||
|
|
||||||
|
if (filename == NULL || filename[0] == 0) return -1;
|
||||||
|
|
||||||
|
/* Open the file */
|
||||||
|
status = fops_open(filename, &fd);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"Open initrd file %s failed: %r", filename, status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG_PRT((L"initrd_open %s worked", filename));
|
||||||
|
|
||||||
|
/* warning: this function allocates memory */
|
||||||
|
status = fops_infosize(fd, &size);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"Couldn't read initrd file %s info %r",filename, status));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* round up to get required number of pages (4KB) */
|
||||||
|
initrd->pgcnt = pgcnt = EFI_SIZE_TO_PAGES(size);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
start_addr = alloc_pages(pgcnt, EfiLoaderData, start_addr ? AllocateAddress : AllocateAnyPages, start_addr);
|
||||||
|
if (start_addr == NULL) {
|
||||||
|
ERR_PRT((L"Failed to allocate %d pages for initrd", pgcnt));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
VERB_PRT(2, Print(L"initrd: total_size: %ld bytes base: 0x%lx pages %d\n",
|
||||||
|
size, (UINT64)start_addr, pgcnt));
|
||||||
|
|
||||||
|
Print(L"Loading initrd %s...", filename);
|
||||||
|
|
||||||
|
ret = read_file(fd, size, start_addr);
|
||||||
|
|
||||||
|
fops_close(fd);
|
||||||
|
|
||||||
|
if (ret != ELILO_LOAD_SUCCESS) {
|
||||||
|
ERR_PRT((L"read initrd(%s) failed: %d", filename, ret));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Print(L"done\n");
|
||||||
|
|
||||||
|
initrd->start_addr = start_addr;
|
||||||
|
|
||||||
|
return ELILO_LOAD_SUCCESS;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (start_addr) free(start_addr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* make sure nothing is passed to kernel
|
||||||
|
* in case of error.
|
||||||
|
*/
|
||||||
|
initrd->start_addr = 0;
|
||||||
|
initrd->pgcnt = 0;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
68
loader.c
Normal file
68
loader.c
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
#include "loader.h"
|
||||||
|
|
||||||
|
extern loader_ops_t plain_loader;
|
||||||
|
extern loader_ops_t gzip_loader;
|
||||||
|
|
||||||
|
static loader_ops_t *ldops_list;
|
||||||
|
|
||||||
|
loader_ops_t *
|
||||||
|
loader_probe(CHAR16 *kname)
|
||||||
|
{
|
||||||
|
loader_ops_t *ops;
|
||||||
|
|
||||||
|
for (ops= ldops_list; ops; ops = ops->next) {
|
||||||
|
if (ops->ld_probe(kname) == 0) {
|
||||||
|
return ops;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
loader_register(loader_ops_t *ldops)
|
||||||
|
{
|
||||||
|
if (ldops == NULL) return -1;
|
||||||
|
|
||||||
|
/* cheap sanity check */
|
||||||
|
if (ldops->next) {
|
||||||
|
ERR_PRT((L"loader %s is already registered", ldops->ld_name));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ldops->next = ldops_list;
|
||||||
|
ldops_list = ldops;
|
||||||
|
|
||||||
|
VERB_PRT(3, Print(L"New loader registered: %s\n", ldops->ld_name));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
41
loader.h
Normal file
41
loader.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LOADER_H__
|
||||||
|
#define __LOADER_H__
|
||||||
|
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
|
typedef struct __loader_ops_t {
|
||||||
|
struct __loader_ops_t *next;
|
||||||
|
CHAR16 *ld_name;
|
||||||
|
INTN (*ld_probe)(CHAR16 *kname);
|
||||||
|
INTN (*ld_load_kernel)(CHAR16 *kname, kdesc_t *kd);
|
||||||
|
} loader_ops_t;
|
||||||
|
|
||||||
|
extern loader_ops_t *loader_probe(CHAR16 *kname);
|
||||||
|
extern INTN loader_register(loader_ops_t *ldops);
|
||||||
|
|
||||||
|
#endif /* __LOADER_H__ */
|
165
strops.c
Normal file
165
strops.c
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 1999-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
//#define CHAR_NULL (CHAR16)'\0'
|
||||||
|
|
||||||
|
CHAR16 *
|
||||||
|
StrChr(IN const CHAR16 *s, IN const CHAR16 c)
|
||||||
|
{
|
||||||
|
for(; *s != c; ++s) if (*s == CHAR_NULL) return NULL;
|
||||||
|
|
||||||
|
return (CHAR16 *)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHAR16 *
|
||||||
|
StrnCpy(OUT CHAR16 *dst, IN const CHAR16 *src, IN UINTN size)
|
||||||
|
{
|
||||||
|
CHAR16 *res = dst;
|
||||||
|
|
||||||
|
while (size-- && (*dst++ = *src++) != CHAR_NULL);
|
||||||
|
/*
|
||||||
|
* does the null padding
|
||||||
|
*/
|
||||||
|
while (size-- > 0) *dst++ = CHAR_NULL;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHAR8 *
|
||||||
|
StrnXCpy(OUT CHAR8 *dst, IN const CHAR16 *src, IN UINTN size)
|
||||||
|
{
|
||||||
|
CHAR8 *res = dst;
|
||||||
|
|
||||||
|
while (size-- && (*dst++ = (CHAR8)*src++) != '\0');
|
||||||
|
/*
|
||||||
|
* does the null padding
|
||||||
|
*/
|
||||||
|
while (size-- > 0) *dst++ = '\0';
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
U2ascii(CHAR16 *in, CHAR8 *out, UINTN maxlen)
|
||||||
|
{
|
||||||
|
while(maxlen-- > 1 && (*out++ = *in++));
|
||||||
|
*out = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
CHAR8 *
|
||||||
|
strncpya(OUT CHAR8 *dst, IN const CHAR8 *src, IN UINTN size)
|
||||||
|
{
|
||||||
|
CHAR8 *res = dst;
|
||||||
|
|
||||||
|
while (size-- && (*dst++ = *src++) != '\0');
|
||||||
|
/*
|
||||||
|
* does the null padding
|
||||||
|
*/
|
||||||
|
while (size-- > 0) *dst++ = '\0';
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHAR8 *
|
||||||
|
strcpya(CHAR8 *dst, const CHAR8 *src)
|
||||||
|
{
|
||||||
|
CHAR8 *tmp = dst;
|
||||||
|
|
||||||
|
while (*src) {
|
||||||
|
*(dst++) = *(src++);
|
||||||
|
}
|
||||||
|
*dst = 0;
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CHAR8 *
|
||||||
|
strchra(IN const CHAR8 *s, IN const CHAR8 c)
|
||||||
|
{
|
||||||
|
for(; *s != c; ++s)
|
||||||
|
if (*s == 0) return NULL;
|
||||||
|
return (CHAR8 *)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHAR8 *
|
||||||
|
strcata(IN CHAR8 *dst,IN CHAR8 *src)
|
||||||
|
{
|
||||||
|
return strcpya(dst+strlena(dst), src);
|
||||||
|
}
|
||||||
|
|
||||||
|
CHAR8 *
|
||||||
|
strrchra(IN const CHAR8 *s, const INTN c)
|
||||||
|
{
|
||||||
|
CHAR8 *found, *p, ch = (CHAR8)c;
|
||||||
|
|
||||||
|
/* Since strchr is fast, we use it rather than the obvious loop. */
|
||||||
|
|
||||||
|
if (ch == '\0') return strchra(s, '\0');
|
||||||
|
|
||||||
|
found = NULL;
|
||||||
|
while ((p = strchra(s, ch)) != NULL)
|
||||||
|
{
|
||||||
|
found = p;
|
||||||
|
s = p + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (CHAR8 *) found;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHAR8 *
|
||||||
|
strtok_simple(CHAR8 *in, CHAR8 c)
|
||||||
|
{
|
||||||
|
static CHAR8 *last;
|
||||||
|
CHAR8 *tmp;
|
||||||
|
|
||||||
|
if (in == NULL) in = last;
|
||||||
|
|
||||||
|
if (in == NULL) return NULL;
|
||||||
|
|
||||||
|
if (*in == c) in++;
|
||||||
|
|
||||||
|
tmp = strchra(in, c);
|
||||||
|
if (tmp) {
|
||||||
|
*tmp = '\0';
|
||||||
|
last = tmp+1;
|
||||||
|
} else {
|
||||||
|
last = NULL;
|
||||||
|
}
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
ascii2U(CHAR8 *in, CHAR16 *out, UINTN maxlen)
|
||||||
|
{
|
||||||
|
while(maxlen-- > 1 && (*out++ = *in++));
|
||||||
|
|
||||||
|
*out = (CHAR16)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
41
strops.h
Normal file
41
strops.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __STROPS_H__
|
||||||
|
#define __STROPS_H__
|
||||||
|
|
||||||
|
extern CHAR16 *StrChr(IN const CHAR16 *s, const CHAR16 c);
|
||||||
|
extern CHAR16 *StrnCpy(OUT CHAR16 *dst, IN const CHAR16 *src, UINTN count);
|
||||||
|
extern CHAR8 *StrnXCpy(OUT CHAR8 *dst, IN const CHAR16 *src, UINTN count);
|
||||||
|
|
||||||
|
extern CHAR8 *strtok_simple(CHAR8 *in, CHAR8 c);
|
||||||
|
extern CHAR8 *strrchra(IN const CHAR8 *s, const INTN c);
|
||||||
|
extern CHAR8 *strcata(IN CHAR8 *dst,IN CHAR8 *src);
|
||||||
|
extern CHAR8 *strchra(IN const CHAR8 *s, IN const CHAR8 c);
|
||||||
|
extern CHAR8 *strcpya(CHAR8 *dst, const CHAR8 *src);
|
||||||
|
extern CHAR8 *strncpya(OUT CHAR8 *dst, IN const CHAR8 *src, IN UINTN size);
|
||||||
|
extern VOID U2ascii(CHAR16 *in, CHAR8 *out, UINTN maxlen);
|
||||||
|
|
||||||
|
#endif /* __LOADER_H__ */
|
35
sysdeps.h
Normal file
35
sysdeps.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ELILO_SYSDEPS_H__
|
||||||
|
#define __ELILO_SYSDEPS_H__
|
||||||
|
|
||||||
|
#ifdef CONFIG_ia64
|
||||||
|
#include "ia64/sysdeps.h"
|
||||||
|
#elif defined CONFIG_ia32
|
||||||
|
#include "ia32/sysdeps.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __ELILO_SYSDEPS_H__ */
|
47
tools/Makefile
Normal file
47
tools/Makefile
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#
|
||||||
|
# Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
# Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
#
|
||||||
|
# This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
#
|
||||||
|
# ELILO is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# ELILO is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
# Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
# 02111-1307, USA.
|
||||||
|
#
|
||||||
|
# Please check out the elilo.txt for complete documentation on how
|
||||||
|
# to use this program.
|
||||||
|
#
|
||||||
|
|
||||||
|
include ../Make.defaults
|
||||||
|
include ../Make.rules
|
||||||
|
|
||||||
|
TOPDIR=$(CDIR)/..
|
||||||
|
|
||||||
|
FILES=eliloalt.o
|
||||||
|
TARGET=eliloalt
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
#
|
||||||
|
# redefine local rule (we build a Linux/ia64 binary here)
|
||||||
|
#
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(OPTIMFLAGS) $(DEBUGFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(TARGET): %:%.o
|
||||||
|
$(CC) -o $@ $(OPTIMFLAGS) $(DEBUGFLAGS) $^
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) -f $(TARGET) $(FILES)
|
||||||
|
|
298
tools/eliloalt.c
Normal file
298
tools/eliloalt.c
Normal file
|
@ -0,0 +1,298 @@
|
||||||
|
/*
|
||||||
|
* eliloalt.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2003 Hewlett-Packard Co
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This program is used to set the EliloAlt EFI variable to influence
|
||||||
|
* how elilo will behave at the next reboot. This variable is used
|
||||||
|
* to boot a certain kernel/configuration only once (debug, for instance).
|
||||||
|
*
|
||||||
|
* This is is supposed to be installed in /usr/sbin/eliloalt and must only
|
||||||
|
* be run by root.
|
||||||
|
*/
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define ELILOALT_VERSION "0.02"
|
||||||
|
|
||||||
|
#define ELILO_ALT_NAME "EliloAlt"
|
||||||
|
#define EFIVAR_DIR "/proc/efi/vars"
|
||||||
|
#define ELILO_ALTVAR EFIVAR_DIR"/"ELILO_ALT_NAME"-00000000-0000-0000-0000-000000000000"
|
||||||
|
|
||||||
|
#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001
|
||||||
|
#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
|
||||||
|
#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004
|
||||||
|
|
||||||
|
typedef unsigned long efi_status_t;
|
||||||
|
typedef uint8_t efi_bool_t;
|
||||||
|
typedef uint16_t efi_char16_t; /* UNICODE character */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EFI GUID type definition
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t data1;
|
||||||
|
uint16_t data2;
|
||||||
|
uint16_t data3;
|
||||||
|
uint8_t data4[8];
|
||||||
|
} efi_guid_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EFI variable structure
|
||||||
|
*/
|
||||||
|
typedef struct _efi_variable_t {
|
||||||
|
efi_char16_t variablename[1024/sizeof(efi_char16_t)];
|
||||||
|
efi_guid_t vendorguid;
|
||||||
|
uint64_t datasize;
|
||||||
|
uint8_t data[1024];
|
||||||
|
efi_status_t status;
|
||||||
|
uint32_t attributes;
|
||||||
|
} __attribute__((packed)) efi_variable_t;
|
||||||
|
|
||||||
|
static char *elilo_alt_name = ELILO_ALT_NAME;
|
||||||
|
|
||||||
|
static struct option cmd_options[]={
|
||||||
|
{ "version", 0, 0, 1},
|
||||||
|
{ "help", 0, 0, 2},
|
||||||
|
{ "delete", 0, 0, 3},
|
||||||
|
{ "print", 0, 0, 4},
|
||||||
|
{ "set", 1, 0, 5},
|
||||||
|
{ 0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void fatal_error(char *fmt,...) __attribute__((noreturn));
|
||||||
|
|
||||||
|
static void
|
||||||
|
fatal_error(char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(char **argv)
|
||||||
|
{
|
||||||
|
printf("Usage: %s [OPTIONS] cmdline\n", argv[0]);
|
||||||
|
|
||||||
|
printf( "-h, --help\t\tdisplay this help and exit\n"
|
||||||
|
"--version\t\toutput version information and exit\n"
|
||||||
|
"-s, --set cmdline\tset elilo alternate variable to cmdline\n"
|
||||||
|
"-p, --print\t\tprint elilo alternate variable\n"
|
||||||
|
"-d, --delete\t\tprint elilo alternate variable\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
check_proc_efi(int find_entry)
|
||||||
|
{
|
||||||
|
DIR *efi_vars;
|
||||||
|
struct dirent *entry;
|
||||||
|
static char name[1024];
|
||||||
|
|
||||||
|
if (getuid() != 0) {
|
||||||
|
fatal_error("This program must be run as root\n");
|
||||||
|
}
|
||||||
|
efi_vars = opendir(EFIVAR_DIR);
|
||||||
|
if (efi_vars == NULL) {
|
||||||
|
fatal_error("Cannot access %s\n", EFIVAR_DIR);
|
||||||
|
}
|
||||||
|
if (!find_entry) {
|
||||||
|
closedir(efi_vars);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* Find one entry we can open */
|
||||||
|
while ((entry = readdir(efi_vars)) != NULL) {
|
||||||
|
if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (entry == NULL) {
|
||||||
|
fatal_error("Cannot find entry in %s\n", EFIVAR_DIR);
|
||||||
|
}
|
||||||
|
sprintf(name, "%s/%s", EFIVAR_DIR, entry->d_name);
|
||||||
|
closedir(efi_vars);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_var(void)
|
||||||
|
{
|
||||||
|
efi_variable_t var;
|
||||||
|
int fd, r, i;
|
||||||
|
|
||||||
|
check_proc_efi(0);
|
||||||
|
|
||||||
|
fd = open(ELILO_ALTVAR, O_WRONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
fatal_error("variable not defined\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&var, 0, sizeof(var));
|
||||||
|
|
||||||
|
for (i=0; i < sizeof(elilo_alt_name); i++) {
|
||||||
|
var.variablename[i] = (efi_char16_t)elilo_alt_name[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we use NULL GUID so no need to initialize it now memset() did it
|
||||||
|
* writing with a datasize=0 will effectively delete the variable.
|
||||||
|
*/
|
||||||
|
|
||||||
|
r = write(fd, &var, sizeof(var));
|
||||||
|
if (r != sizeof(var)) {
|
||||||
|
fatal_error("Variable %s defined but invalid content\n", ELILO_ALTVAR);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_var(void)
|
||||||
|
{
|
||||||
|
efi_variable_t var;
|
||||||
|
int fd, r, i;
|
||||||
|
|
||||||
|
|
||||||
|
check_proc_efi(0);
|
||||||
|
|
||||||
|
fd = open(ELILO_ALTVAR, O_RDONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
fatal_error("variable not defined\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&var, 0, sizeof(var));
|
||||||
|
|
||||||
|
r = read(fd, &var, sizeof(var));
|
||||||
|
if (r != sizeof(var)) {
|
||||||
|
fatal_error("Variable %s defined but invalid content\n", ELILO_ALTVAR);
|
||||||
|
}
|
||||||
|
printf("EliloAlt=\"");
|
||||||
|
for(i=0; i < var.datasize; i+=1){
|
||||||
|
printf("%c", var.data[i]);
|
||||||
|
}
|
||||||
|
printf("\"\n");
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_var(char *cmdline)
|
||||||
|
{
|
||||||
|
efi_variable_t var;
|
||||||
|
int fd, r, i, j, l;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
name = check_proc_efi(1);
|
||||||
|
|
||||||
|
if (cmdline == NULL) {
|
||||||
|
fatal_error("invalid cmdline argument\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
l = strlen(cmdline);
|
||||||
|
|
||||||
|
if (l >= 1024) {
|
||||||
|
fatal_error("Variable content is too long, must be <= 512 characters\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open(name, O_WRONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
fatal_error("can't open %s: %s\n", ELILO_ALTVAR, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&var, 0, sizeof(var));
|
||||||
|
|
||||||
|
for (i=0; i < sizeof(elilo_alt_name); i++) {
|
||||||
|
var.variablename[i] = (efi_char16_t)elilo_alt_name[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0, j=0; i < l; i++, j+=2) {
|
||||||
|
var.data[j] = (efi_char16_t)cmdline[i];
|
||||||
|
}
|
||||||
|
/* +2 = include char16 for null termination */
|
||||||
|
var.datasize = j+2;
|
||||||
|
|
||||||
|
var.attributes = EFI_VARIABLE_NON_VOLATILE
|
||||||
|
| EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we use NULL GUID so no need to initialize it now memset() did it
|
||||||
|
* writing with a datasize=0 will effectively delete the variable.
|
||||||
|
*/
|
||||||
|
|
||||||
|
r = write(fd, &var, sizeof(var));
|
||||||
|
if (r != sizeof(var)) {
|
||||||
|
fatal_error("Variable %s defined but invalid content %d\n", ELILO_ALTVAR, r);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
while ((c=getopt_long(argc, argv,"hdps:", cmd_options, 0)) != -1) {
|
||||||
|
switch(c) {
|
||||||
|
case 0: continue; /* fast path for options */
|
||||||
|
case 1:
|
||||||
|
printf("Version %s Date: %s\n", ELILOALT_VERSION, __DATE__);
|
||||||
|
exit(0);
|
||||||
|
case 2:
|
||||||
|
case 'h':
|
||||||
|
usage(argv);
|
||||||
|
exit(0);
|
||||||
|
case 3:
|
||||||
|
case 'd':
|
||||||
|
delete_var();
|
||||||
|
exit(0);
|
||||||
|
case 4:
|
||||||
|
case 'p':
|
||||||
|
print_var();
|
||||||
|
exit(0);
|
||||||
|
case 5:
|
||||||
|
case 's':
|
||||||
|
set_var(optarg);
|
||||||
|
exit(0);
|
||||||
|
default:
|
||||||
|
fatal_error("Unknown option\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print_var();
|
||||||
|
return 0;
|
||||||
|
}
|
503
util.c
Normal file
503
util.c
Normal file
|
@ -0,0 +1,503 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001 Silicon Graphics, Inc.
|
||||||
|
* Contributed by Brent Casavant <bcasavan@sgi.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "elilo.h"
|
||||||
|
|
||||||
|
#define TENTH_SEC 1000000 /* 1/10th second in 100ns unit */
|
||||||
|
#define READ_BLOCK_SIZE (4*EFI_PAGE_SIZE) /* block size for read_file */
|
||||||
|
|
||||||
|
#define is_cr(k) (((k)==CHAR_LINEFEED)||((k)==CHAR_CARRIAGE_RETURN))
|
||||||
|
#define CHAR_SPACE L' '
|
||||||
|
|
||||||
|
static INTN
|
||||||
|
read_keypress(EFI_INPUT_KEY *key)
|
||||||
|
{
|
||||||
|
return systab->ConIn->ReadKeyStroke(systab->ConIn, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
check_abort(VOID)
|
||||||
|
{
|
||||||
|
EFI_INPUT_KEY key;
|
||||||
|
|
||||||
|
return read_keypress(&key);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VOID
|
||||||
|
reset_input(VOID)
|
||||||
|
{
|
||||||
|
systab->ConIn->Reset(systab->ConIn, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
INTN
|
||||||
|
wait_keypress_abort(VOID)
|
||||||
|
{
|
||||||
|
SIMPLE_INPUT_INTERFACE *conin = systab->ConIn;
|
||||||
|
EFI_INPUT_KEY key;
|
||||||
|
EFI_STATUS status;
|
||||||
|
|
||||||
|
reset_input();
|
||||||
|
|
||||||
|
Print(L"Hit ENTER to continue or ANY other key to cancel");
|
||||||
|
|
||||||
|
/* cleanup buffer first */
|
||||||
|
while (conin->ReadKeyStroke(conin, &key) == EFI_SUCCESS);
|
||||||
|
|
||||||
|
while ((status=conin->ReadKeyStroke(conin, &key)) == EFI_NOT_READY );
|
||||||
|
|
||||||
|
if (EFI_ERROR(status)) return ELILO_LOAD_ERROR;
|
||||||
|
|
||||||
|
Print(L"\n");
|
||||||
|
|
||||||
|
return is_cr(key.UnicodeChar) ? ELILO_LOAD_SUCCESS: ELILO_BOOT_ABORTED;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wait for timeout to expire or keypress
|
||||||
|
* Return:
|
||||||
|
* 0 : timeout expired
|
||||||
|
* 1 : a key was pressed (still input stream to process)
|
||||||
|
* -1: an error occured
|
||||||
|
*/
|
||||||
|
INTN
|
||||||
|
wait_timeout(UINTN timeout)
|
||||||
|
{
|
||||||
|
EFI_STATUS status;
|
||||||
|
EFI_EVENT timer;
|
||||||
|
EFI_EVENT list[2];
|
||||||
|
UINTN idx;
|
||||||
|
|
||||||
|
|
||||||
|
if (timeout == 0) return 0;
|
||||||
|
|
||||||
|
/* Create a timeout timer */
|
||||||
|
status = BS->CreateEvent(EVT_TIMER, 0, NULL, NULL, &timer);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L" waitkey CreateEvent failed %r", status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* In 100ns increments */
|
||||||
|
status = BS->SetTimer(timer, TimerPeriodic, TENTH_SEC);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"waitkey SetTimer failed %r", status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
list[0] = timer;
|
||||||
|
list[1] = systab->ConIn->WaitForKey;
|
||||||
|
|
||||||
|
do {
|
||||||
|
status = BS->WaitForEvent(2, list, &idx);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"waitkey WaitForEvent failed %r", status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (timeout-- && idx == 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SetTimer(timer, TimerCancel, 0) is causing problems on IA-32 and gcc3
|
||||||
|
* I do not know why it dies with EFI12.35. So let's fake a key stroke.
|
||||||
|
*/
|
||||||
|
status = BS->SetTimer(timer, TimerCancel, 0);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"waitkey SetTimer(TimerCancel) failed %r", status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BS->CloseEvent(timer);
|
||||||
|
|
||||||
|
return idx ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
argify(CHAR16 *buf, UINTN len, CHAR16 **argv)
|
||||||
|
{
|
||||||
|
|
||||||
|
UINTN i=0, j=0;
|
||||||
|
CHAR16 *p = buf;
|
||||||
|
|
||||||
|
if (buf == 0) {
|
||||||
|
argv[0] = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* len represents the number of bytes, not the number of 16 bytes chars */
|
||||||
|
len = len >> 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Here we use CHAR_NULL as the terminator rather than the length
|
||||||
|
* because it seems like the EFI shell return rather bogus values for it.
|
||||||
|
* Apparently, we are guaranteed to find the '\0' character in the buffer
|
||||||
|
* where the real input arguments stop, so we use it instead.
|
||||||
|
*/
|
||||||
|
for(;;) {
|
||||||
|
while (buf[i] == CHAR_SPACE && buf[i] != CHAR_NULL && i < len) i++;
|
||||||
|
|
||||||
|
if (buf[i] == CHAR_NULL || i == len) goto end;
|
||||||
|
|
||||||
|
p = buf+i;
|
||||||
|
i++;
|
||||||
|
|
||||||
|
while (buf[i] != CHAR_SPACE && buf[i] != CHAR_NULL && i < len) i++;
|
||||||
|
|
||||||
|
argv[j++] = p;
|
||||||
|
|
||||||
|
if (buf[i] == CHAR_NULL) goto end;
|
||||||
|
|
||||||
|
buf[i] = CHAR_NULL;
|
||||||
|
|
||||||
|
if (i == len) goto end;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (j == MAX_ARGS-1) {
|
||||||
|
ERR_PRT((L"too many arguments (%d) truncating", j));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
#if 0
|
||||||
|
if (i != len) {
|
||||||
|
ERR_PRT((L"ignoring trailing %d characters on command line", len-i));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
argv[j] = NULL;
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
unargify(CHAR16 **argv, CHAR16 **args)
|
||||||
|
{
|
||||||
|
if ( *argv == 0 ) {
|
||||||
|
*args = L"";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*args = *argv;
|
||||||
|
while ( argv[1] ) {
|
||||||
|
(*argv)[StrLen(*argv)] = CHAR_SPACE;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
split_args(CHAR16 *buffer, CHAR16 *kname, CHAR16 *args)
|
||||||
|
{
|
||||||
|
CHAR16 *tmp;
|
||||||
|
|
||||||
|
/* find beginning of kernel name */
|
||||||
|
while (*buffer && *buffer == CHAR_SPACE) buffer++;
|
||||||
|
|
||||||
|
tmp = buffer;
|
||||||
|
|
||||||
|
/* scan through kernel name */
|
||||||
|
while (*buffer && *buffer != CHAR_SPACE) buffer++;
|
||||||
|
|
||||||
|
if (*buffer) {
|
||||||
|
*buffer++ = CHAR_NULL;
|
||||||
|
StrCpy(kname, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skip space between kernel and args */
|
||||||
|
while (*buffer && *buffer == CHAR_SPACE) buffer++;
|
||||||
|
|
||||||
|
StrCpy(args, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
read_file(UINTN fd, UINTN total_size, CHAR8 *buffer)
|
||||||
|
{
|
||||||
|
INTN size, j=0;
|
||||||
|
EFI_STATUS status;
|
||||||
|
CHAR16 helicopter[4] = { L'|' , L'/' , L'-' , L'\\' };
|
||||||
|
INTN ret = ELILO_LOAD_SUCCESS;
|
||||||
|
UINTN sum = 0;
|
||||||
|
/*
|
||||||
|
* We load by chunks rather than a single big read because
|
||||||
|
* early versions of EFI had troubles loading files
|
||||||
|
* from floppies in a single big request. Breaking
|
||||||
|
* the read down into chunks of 4KB fixed that
|
||||||
|
* problem. While this problem has been fixed, we still prefer
|
||||||
|
* this method because it tells us whether or not we're making
|
||||||
|
* forward progress.
|
||||||
|
*/
|
||||||
|
|
||||||
|
while (total_size > 0) {
|
||||||
|
size = total_size < READ_BLOCK_SIZE? total_size : READ_BLOCK_SIZE;
|
||||||
|
|
||||||
|
status = fops_read(fd, buffer, &size);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"read_file failed %r", status));
|
||||||
|
return ELILO_LOAD_ERROR;
|
||||||
|
}
|
||||||
|
sum += size;
|
||||||
|
|
||||||
|
Print(L"%c\b",helicopter[j++%4]);
|
||||||
|
|
||||||
|
buffer += size;
|
||||||
|
total_size -= size;
|
||||||
|
|
||||||
|
if (check_abort() == EFI_SUCCESS) {
|
||||||
|
ret = ELILO_LOAD_ABORTED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
get_memmap(mmap_desc_t *desc)
|
||||||
|
{
|
||||||
|
#define ELILO_MEMMAP_SIZE_DEFAULT EFI_PAGE_SIZE
|
||||||
|
#define ELILO_MEMMAP_INC (sizeof(EFI_MEMORY_DESCRIPTOR)<<1)
|
||||||
|
|
||||||
|
EFI_STATUS status;
|
||||||
|
|
||||||
|
desc->map_size = ELILO_MEMMAP_SIZE_DEFAULT;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
desc->md = (EFI_MEMORY_DESCRIPTOR *)alloc(desc->map_size, EfiLoaderData);
|
||||||
|
|
||||||
|
if (desc->md == NULL) {
|
||||||
|
ERR_PRT((L"failed to allocate memory map buffer"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
status = (*BS->GetMemoryMap)(&desc->map_size, desc->md, &desc->cookie, &desc->desc_size, &desc->desc_version);
|
||||||
|
if (status == EFI_SUCCESS) break;
|
||||||
|
|
||||||
|
free(desc->md);
|
||||||
|
|
||||||
|
if (status != EFI_BUFFER_TOO_SMALL) {
|
||||||
|
ERR_PRT((L"failed to obtain memory map %r"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
desc->map_size += ELILO_MEMMAP_INC;
|
||||||
|
}
|
||||||
|
DBG_PRT((L"final get_memmap map_size=%ld", desc->map_size));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
INTN
|
||||||
|
get_memmap(mmap_desc_t *desc)
|
||||||
|
{
|
||||||
|
EFI_STATUS status;
|
||||||
|
|
||||||
|
/* will get the right size in return */
|
||||||
|
desc->map_size = 0;
|
||||||
|
|
||||||
|
status = BS->GetMemoryMap(&desc->map_size, desc->md, &desc->cookie, &desc->desc_size, &desc->desc_version);
|
||||||
|
if (status != EFI_BUFFER_TOO_SMALL) return -1;
|
||||||
|
|
||||||
|
desc->md = (EFI_MEMORY_DESCRIPTOR *)alloc(desc->map_size, EfiLoaderData);
|
||||||
|
if (desc->md == NULL) {
|
||||||
|
ERR_PRT((L"failed to allocate memory map buffer"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status = BS->GetMemoryMap(&desc->map_size, desc->md, &desc->cookie, &desc->desc_size, &desc->desc_version);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
ERR_PRT((L"failed to obtain memory map %d: %r", desc->map_size, status));
|
||||||
|
free(desc->md);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
DBG_PRT((L"final get_memmap map_size=%d", desc->map_size));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
free_memmap(mmap_desc_t *desc)
|
||||||
|
{
|
||||||
|
if (desc->md) {
|
||||||
|
free(desc->md);
|
||||||
|
desc->md = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
print_memmap(mmap_desc_t *desc)
|
||||||
|
{
|
||||||
|
EFI_MEMORY_DESCRIPTOR *md;
|
||||||
|
UINTN desc_size;
|
||||||
|
VOID *p;
|
||||||
|
VOID *md_end;
|
||||||
|
INT8 printed;
|
||||||
|
UINTN ntypes;
|
||||||
|
CHAR16* str;
|
||||||
|
|
||||||
|
static CHAR16 *memtypes[]={
|
||||||
|
L"ReservedMemoryType",
|
||||||
|
L"LoaderCode",
|
||||||
|
L"LoaderData",
|
||||||
|
L"BootServicesCode",
|
||||||
|
L"BootServicesData",
|
||||||
|
L"RuntimeServicesCode",
|
||||||
|
L"RuntimeServicesData",
|
||||||
|
L"ConventionalMemory",
|
||||||
|
L"UnusableMemory",
|
||||||
|
L"ACPIReclaimMemory",
|
||||||
|
L"ACPIMemoryNVS",
|
||||||
|
L"MemoryMappedIO",
|
||||||
|
L"MemoryMappedIOPortSpace",
|
||||||
|
L"PalCode"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
md_end = ((VOID *)desc->md)+desc->map_size;
|
||||||
|
desc_size = desc->desc_size;
|
||||||
|
|
||||||
|
ntypes = sizeof(memtypes)/sizeof(CHAR16 *);
|
||||||
|
|
||||||
|
for(p = desc->md; p < md_end; p += desc_size) {
|
||||||
|
md = p;
|
||||||
|
|
||||||
|
str = md->Type < ntypes ? memtypes[md->Type] : L"Unknown";
|
||||||
|
|
||||||
|
Print(L"%24s %lx-%lx %8lx", str, md->PhysicalStart,
|
||||||
|
md->PhysicalStart+(md->NumberOfPages<<EFI_PAGE_SHIFT),
|
||||||
|
md->NumberOfPages);
|
||||||
|
|
||||||
|
printed=0;
|
||||||
|
#define P_FLG(f) { \
|
||||||
|
Print(L" %s %s", printed ? L"|":L"", f); \
|
||||||
|
printed=1; \
|
||||||
|
}
|
||||||
|
|
||||||
|
if (md->Attribute & EFI_MEMORY_UC) {
|
||||||
|
P_FLG(L"UC");
|
||||||
|
}
|
||||||
|
if (md->Attribute & EFI_MEMORY_WC) {
|
||||||
|
P_FLG(L"WC");
|
||||||
|
}
|
||||||
|
if (md->Attribute & EFI_MEMORY_WT) {
|
||||||
|
P_FLG(L"WT");
|
||||||
|
}
|
||||||
|
if (md->Attribute & EFI_MEMORY_WB) {
|
||||||
|
P_FLG(L"WB");
|
||||||
|
}
|
||||||
|
if (md->Attribute & EFI_MEMORY_UCE) {
|
||||||
|
P_FLG(L"UCE");
|
||||||
|
}
|
||||||
|
if (md->Attribute & EFI_MEMORY_WP) {
|
||||||
|
P_FLG(L"WP");
|
||||||
|
}
|
||||||
|
if (md->Attribute & EFI_MEMORY_RP) {
|
||||||
|
P_FLG(L"RP");
|
||||||
|
}
|
||||||
|
if (md->Attribute & EFI_MEMORY_XP) {
|
||||||
|
P_FLG(L"XP");
|
||||||
|
}
|
||||||
|
if (md->Attribute & EFI_MEMORY_RUNTIME) {
|
||||||
|
P_FLG(L"RT");
|
||||||
|
}
|
||||||
|
Print(L"\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INTN
|
||||||
|
find_kernel_memory(VOID* low_addr, VOID* max_addr, UINTN alignment, VOID** start)
|
||||||
|
{
|
||||||
|
#define HIGHEST_ADDR (VOID*)(~0)
|
||||||
|
mmap_desc_t mdesc;
|
||||||
|
EFI_MEMORY_DESCRIPTOR *md;
|
||||||
|
UINT64 size;
|
||||||
|
VOID *p, *addr;
|
||||||
|
VOID *desc_end, *md_end, *best_addr = HIGHEST_ADDR;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* first get up-to-date memory map
|
||||||
|
*
|
||||||
|
* XXX: is there a danger of not seeing the latest version if interrupted
|
||||||
|
* during our scan ?
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (get_memmap(&mdesc) == -1) {
|
||||||
|
ERR_PRT((L"find_kernel_memory :GetMemoryMap() failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc_end = ((VOID *)mdesc.md) + mdesc.map_size;
|
||||||
|
size = max_addr - low_addr;
|
||||||
|
/*
|
||||||
|
* Find memory which covers the desired range
|
||||||
|
*/
|
||||||
|
for(p = mdesc.md; p < desc_end; p += mdesc.desc_size) {
|
||||||
|
md = p;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* restrict to decent memory types.
|
||||||
|
*
|
||||||
|
* the EFI memory map report where memory is and how it is currently used
|
||||||
|
* using types.
|
||||||
|
*
|
||||||
|
* EfiLoaderData which is used by the AllocatePages() cannot be used
|
||||||
|
* here because it may hold some valid information. Same thing for most
|
||||||
|
* of the memory types with the exception of EfiConventional which
|
||||||
|
* can be assumed as being free to use.
|
||||||
|
*/
|
||||||
|
if (md->Type != EfiConventionalMemory) continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* compute aligned address and upper boundary for range
|
||||||
|
*/
|
||||||
|
md_end = (VOID*)(md->PhysicalStart + md->NumberOfPages * EFI_PAGE_SIZE);
|
||||||
|
addr = (VOID*)ROUNDUP(md->PhysicalStart, alignment);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* need to check if:
|
||||||
|
* - aligned address still in the range
|
||||||
|
* - the range [addr-addr+size) still fits into memory range
|
||||||
|
* if so we have a match. We do not assume that the memory ranges
|
||||||
|
* are sorted by EFI, therefore we must record the match and only
|
||||||
|
* keep the lowest possible one.
|
||||||
|
*/
|
||||||
|
if (addr < best_addr && addr < md_end && addr+size <= md_end) best_addr = addr;
|
||||||
|
}
|
||||||
|
if (best_addr == HIGHEST_ADDR) {
|
||||||
|
free_memmap(&mdesc);
|
||||||
|
ERR_PRT((L"Could not find memory suitable for loading image"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*start = best_addr;
|
||||||
|
|
||||||
|
free_memmap(&mdesc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
130
vars.c
Normal file
130
vars.c
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001 Silicon Graphics, Inc.
|
||||||
|
* Contributed by Brent Casavant <bcasavan@sgi.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* ELILO is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* ELILO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A variable name is 1 character long and case sensitive. So
|
||||||
|
* we actually have 52 (26*2) possible variables.
|
||||||
|
*/
|
||||||
|
#define MAX_VARIABLES (26<<1)
|
||||||
|
#define MAX_VARIABLE_LENGTH 128
|
||||||
|
#define VAR_IDX(a) (((a) >= 'a' && (a) <= 'z') ? 26-'a'+(a) : (a)-'A')
|
||||||
|
#define IDX_VAR(i) ((i) < 26 ? 'A'+(i) : 'a'+ ((i)-26))
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
CHAR16 value[MAX_VARIABLE_LENGTH];
|
||||||
|
} elilo_var_t;
|
||||||
|
|
||||||
|
static elilo_var_t vars[MAX_VARIABLES]; /* set of variables */
|
||||||
|
|
||||||
|
INTN
|
||||||
|
set_var(CHAR16 v, CHAR16 *value)
|
||||||
|
{
|
||||||
|
/* invalid variable name */
|
||||||
|
if (v < 'A' || (v > 'Z' && v < 'a') || v > 'z') return -1;
|
||||||
|
|
||||||
|
StrCpy(vars[VAR_IDX(v)].value, value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHAR16 *
|
||||||
|
get_var(CHAR16 v)
|
||||||
|
{
|
||||||
|
/* invalid variable name */
|
||||||
|
if (v < L'A' || (v > L'Z' && v < L'a') || v > L'z') return NULL;
|
||||||
|
|
||||||
|
return vars[VAR_IDX(v)].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
print_vars(VOID)
|
||||||
|
{
|
||||||
|
INTN i;
|
||||||
|
UINTN cnt = 0;
|
||||||
|
|
||||||
|
for(i=0; i < MAX_VARIABLES; i++) {
|
||||||
|
if (vars[i].value[0]) {
|
||||||
|
cnt++;
|
||||||
|
Print(L"%c = \"%s\"\n", IDX_VAR(i), vars[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cnt == 0) Print(L"no variable defined\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
INTN
|
||||||
|
subst_vars(CHAR16 *in, CHAR16 *out, INTN maxlen)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* we cannot use \\ for the despecialization character because
|
||||||
|
* it is also used as a path separator in EFI.
|
||||||
|
*/
|
||||||
|
#define DSPEC_CHAR L'&'
|
||||||
|
INTN i, l, j, cnt;
|
||||||
|
INTN m = 0, d = 0;
|
||||||
|
CHAR16 *val;
|
||||||
|
|
||||||
|
if (in == NULL || out == NULL || maxlen <= 1) return -1;
|
||||||
|
|
||||||
|
l = StrLen(in);
|
||||||
|
|
||||||
|
maxlen--;
|
||||||
|
|
||||||
|
for (i=0, j=0;i < l; i++) {
|
||||||
|
cnt = 1;
|
||||||
|
val = in+i;
|
||||||
|
|
||||||
|
if (*val == DSPEC_CHAR && d == 0) {
|
||||||
|
d = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(m == 1) {
|
||||||
|
m = 0;
|
||||||
|
val = get_var(*val);
|
||||||
|
|
||||||
|
if (val == NULL) continue;
|
||||||
|
|
||||||
|
cnt = StrLen(val);
|
||||||
|
|
||||||
|
} else if (*val == L'%' && d == 0) {
|
||||||
|
m = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
d = 0;
|
||||||
|
while (j < maxlen && cnt) {
|
||||||
|
out[j++] = *val++;
|
||||||
|
cnt--;
|
||||||
|
}
|
||||||
|
if (j == maxlen) break;
|
||||||
|
}
|
||||||
|
out[j] = CHAR_NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
55
vars.h
Normal file
55
vars.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||||||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001 Silicon Graphics, Inc.
|
||||||
|
* Contributed by Brent Casavant <bcasavan@sgi.com>
|
||||||
|
*
|
||||||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||||||
|
*
|
||||||
|
* GNU EFI is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* GNU EFI is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU EFI; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Please check out the elilo.txt for complete documentation on how
|
||||||
|
* to use this program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ELILO_VARS_H__
|
||||||
|
#define __ELILO_VARS_H__
|
||||||
|
/*
|
||||||
|
* This file contains the list of defined variables.
|
||||||
|
* It is expected that every module which uses a variable add its entry
|
||||||
|
* here.
|
||||||
|
* The syntax for the name is: VAR_modulename_meaning L'X'
|
||||||
|
* where:
|
||||||
|
* - modulename: a string representing the module that uses the variable
|
||||||
|
* - meaning : a string representing the meaning of the variable for the module
|
||||||
|
* - X : the variable name [A-Za-z]
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* from glue_netfs.c */
|
||||||
|
#define VAR_NETFS_IPADDR L'I' /* the IP address obtained by DHCP/PXE */
|
||||||
|
#define VAR_NETFS_NETMASK L'M' /* the netmask obtained by DHCP/PXE */
|
||||||
|
#define VAR_NETFS_GATEWAY L'G' /* the gateway obtained by DHCP/PXE */
|
||||||
|
#define VAR_NETFS_HOSTNAME L'H' /* the hostname obtained by DHCP/PXE */
|
||||||
|
#define VAR_NETFS_DOMAINAME L'D' /* the domain name obtained by DHCP/PXE */
|
||||||
|
|
||||||
|
extern INTN set_var(CHAR16 v, CHAR16 *value);
|
||||||
|
extern CHAR16 * get_var(CHAR16 v);
|
||||||
|
extern VOID print_vars(VOID);
|
||||||
|
extern INTN subst_vars(CHAR16 *in, CHAR16 *out, INTN maxlen);
|
||||||
|
|
||||||
|
#endif /* __ELILO_VARS_H__ */
|
||||||
|
|
Loading…
Reference in a new issue