Stephane Eranian 2004-02-24 08:17:30 -05:00 committed by Vincent Batts
parent fb6ce0d596
commit cb533a5de5
25 changed files with 2583 additions and 477 deletions

View file

@ -1,3 +1,11 @@
2004-02-19 Brett Johnson <brett@hp.com>
* Fixed bug where default image initrd would carry over to another
image that was selected interactively (iff the newly selected image
did not have an initrd).
* Added support for subnet-specific config files in netfs.
2004-02-17 Brett Johnson <brett@hp.com>
* integrated ia32 compressed kernel support from Matt Tolentino
<matthew.e.tolentino@intel.com>
2003-08-20 Stephane Eranian <eranian@hpl.hp.com> 2003-08-20 Stephane Eranian <eranian@hpl.hp.com>
* released 3.4 * released 3.4
2003-08-19 Stephane Eranian <eranian@hpl.hp.com> 2003-08-19 Stephane Eranian <eranian@hpl.hp.com>

View file

@ -68,7 +68,7 @@ CPPFLAGS = -DCONFIG_$(ARCH)
OPTIMFLAGS = -O2 OPTIMFLAGS = -O2
DEBUGFLAGS = -Wall DEBUGFLAGS = -Wall
CFLAGS = $(OPTIMFLAGS) -fpic -fshort-wchar $(DEBUGFLAGS) CFLAGS = $(OPTIMFLAGS) -fpic -fshort-wchar $(DEBUGFLAGS)
LDFLAGS = -nostdlib LDFLAGS = -nostdlib -znocombreloc
INSTALL = install INSTALL = install
ifeq ($(CONFIG_machspec_netconfig),y) ifeq ($(CONFIG_machspec_netconfig),y)
@ -121,7 +121,8 @@ CFLAGS += -mfixed-range=f32-f127
else else
ifeq ($(ARCH),ia32) ifeq ($(ARCH),ia32)
prefix = prefix =
CC = $(prefix)gcc3 # CC = $(prefix)gcc3
CC = $(prefix)gcc
AS = $(prefix)as AS = $(prefix)as
LD = $(prefix)ld LD = $(prefix)ld
AR = $(prefix)ar AR = $(prefix)ar

2
TODO
View file

@ -14,5 +14,3 @@ Some of the things TO DO:
- Convert all filesystems (ext2fs, netfs) to use the FilesystemProtocol interface instead - Convert all filesystems (ext2fs, netfs) to use the FilesystemProtocol interface instead
- cleanup x86 loader: use the same structure as IA-64 - cleanup x86 loader: use the same structure as IA-64
- support for subnetting in the config file when netbooting

View file

@ -346,6 +346,7 @@ restart:
ret = wait_timeout(elilo_opt.delay); ret = wait_timeout(elilo_opt.delay);
if (ret != 0) { if (ret != 0) {
elilo_opt.prompt = 1; elilo_opt.prompt = 1;
elilo_opt.initrd[0] = CHAR_NULL;
elilo_opt.timeout = ELILO_TIMEOUT_INFINITY; elilo_opt.timeout = ELILO_TIMEOUT_INFINITY;
goto restart; goto restart;
} }

View file

@ -459,6 +459,7 @@ restart:
ret = wait_timeout(elilo_opt.delay); ret = wait_timeout(elilo_opt.delay);
if (ret != 0) { if (ret != 0) {
elilo_opt.prompt = 1; elilo_opt.prompt = 1;
elilo_opt.initrd[0] = CHAR_NULL;
elilo_opt.timeout = ELILO_TIMEOUT_INFINITY; elilo_opt.timeout = ELILO_TIMEOUT_INFINITY;
goto restart; goto restart;
} }

View file

@ -843,7 +843,7 @@ get_config_file(VOID)
} }
EFI_STATUS EFI_STATUS
read_config(CHAR16 *filename, INTN retry) read_config(CHAR16 *filename)
{ {
EFI_STATUS status; EFI_STATUS status;
INTN ret; INTN ret;
@ -856,49 +856,8 @@ read_config(CHAR16 *filename, INTN retry)
status = fops_open(filename, &config_fd); status = fops_open(filename, &config_fd);
if (EFI_ERROR(status)) { if (EFI_ERROR(status)) {
/* VERB_PRT(3, Print(L"cannot open config file %s\n", filename));
* if the user explicitely specified a filename and we can't return status;
* find it, then we must fail.
*/
if (elilo_opt.parse_only || retry == 0) {
VERB_PRT(3, Print(L"cannot open config file %s\n", filename));
return status;
}
/*
* if not already submitted filename,
*/
if (StrCmp(filename, ELILO_ARCH_DEFAULT_CONFIG)) {
/*
* try the arch default file, now
*/
VERB_PRT(3,Print(L"config file %s not found, trying %s\n",
filename, ELILO_ARCH_DEFAULT_CONFIG));
StrCpy(global_config.config_file,ELILO_ARCH_DEFAULT_CONFIG);
status = fops_open(ELILO_ARCH_DEFAULT_CONFIG, &config_fd);
}
/*
* if arch specific did not work, try generic
*/
if (EFI_ERROR(status) && StrCmp(filename, ELILO_DEFAULT_CONFIG)) {
/*
* try the default file as a last resort
*/
VERB_PRT(3,Print(L"config file %s not found, trying %s\n",
ELILO_ARCH_DEFAULT_CONFIG, ELILO_DEFAULT_CONFIG));
StrCpy(global_config.config_file, ELILO_DEFAULT_CONFIG);
status = fops_open(ELILO_DEFAULT_CONFIG, &config_fd);
}
/*
* if nothing worked, then bail out
*/
if (EFI_ERROR(status)) {
VERB_PRT(3, Print(L"no valid config file found\n"));
global_config.config_file[0] = CHAR_NULL;
return status;
}
} }
/* /*
* start numbering at line 1 * start numbering at line 1

View file

@ -126,7 +126,21 @@ only on two very common cases:
This filename is an opportunity to specify a machine specific configuration file. This filename is an opportunity to specify a machine specific configuration file.
2) elilo-ia32.config or elilo-ia64.conf 2) AA[BB[CC]][-ia32|ia64].conf
As of version 3.5, elilo will also look for IPv4 class A,B,C
subnet-specific versions of the config file. This is useful when you
want to have a common config file for all machines connected to a
particular subnet.
For example, if your IP address is 10.0.0.1 (0A000001 in hex), elilo
will look first for 0A000001.conf, then 0A0000.conf, then 0A00.conf,
and finally 0A.conf.
Elilo will also try architecture-specific versions of subnet-specific
config files first (So for example, on an Itanium system,
"0A0000-ia64.conf" will be tried before "0A0000.conf")
3) elilo-ia32.config or elilo-ia64.conf
Depending on the machine (client side) architecture elilo will try the IA-32 or Depending on the machine (client side) architecture elilo will try the IA-32 or
IA-64 file. IA-64 file.
@ -135,7 +149,7 @@ only on two very common cases:
This distinction between the architectures is useful when the same TFTP server services This distinction between the architectures is useful when the same TFTP server services
the two types of clients : IA32- and IA-64 machines. the two types of clients : IA32- and IA-64 machines.
3) elilo.conf 4) elilo.conf
All files use the same format. Elilo will stop at the first match. In case no file is found, 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). it will try to download a default kernel file name (vmlinux).

BIN
elilo-ia32.efi Executable file → Normal file

Binary file not shown.

BIN
elilo-ia64.efi Executable file → Normal file

Binary file not shown.

28
elilo.c
View file

@ -368,8 +368,8 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab)
CHAR16 dpath[FILENAME_MAXLEN]; CHAR16 dpath[FILENAME_MAXLEN];
CHAR16 *devpath; CHAR16 *devpath;
//elilo_opt.verbose=3; elilo_opt.verbose=0;
//elilo_opt.debug=1; elilo_opt.debug=0;
/* initialize global variable */ /* initialize global variable */
systab = system_tab; systab = system_tab;
@ -548,23 +548,37 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *system_tab)
/* /*
* set per fileops defaults files for configuration and kernel * set per fileops defaults files for configuration and kernel
*/ */
fops_setdefaults(elilo_opt.default_config, elilo_opt.default_kernel, FILENAME_MAXLEN, devpath); fops_setdefaults(elilo_opt.default_configs, elilo_opt.default_kernel, FILENAME_MAXLEN, devpath);
/* /*
* XXX: won't be visible if verbose not required from command line * XXX: won't be visible if verbose not required from command line
*/ */
VERB_PRT(2,Print(L"Default config: %s\nDefault_kernel: %s\n", VERB_PRT(2,Print(L"Default config: %s\nDefault_kernel: %s\n",
elilo_opt.default_config,elilo_opt.default_kernel)); elilo_opt.default_configs[0].fname, elilo_opt.default_kernel));
/* /*
* use default config file if not specified by user * 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); ptr = elilo_opt.config[0] == CHAR_NULL ? (retry=1,elilo_opt.default_configs[0].fname) : (retry=0,elilo_opt.config);
/* /*
* parse config file (verbose becomes visible if set) * parse config file (verbose becomes visible if set)
*/ */
ret = read_config(ptr, retry); ret = read_config(ptr);
Print(L"read_config=%r\n", ret); VERB_PRT(1,Print(L"read_config=%r\n", ret));
/* Only try the default config filenames if user did not specify a
* config filename on the command line */
if (elilo_opt.config[0] == CHAR_NULL) {
while ((ret != EFI_SUCCESS) &&
(retry < MAX_DEFAULT_CONFIGS) &&
(elilo_opt.default_configs[retry].fname[0] != CHAR_NULL)) {
ptr = elilo_opt.default_configs[retry].fname;
ret = read_config(ptr);
VERB_PRT(1,Print(L"read_config=%r\n", ret));
retry += 1;
}
}
/* /*
* when the config file is not found, we fail only if: * when the config file is not found, we fail only if:
* - the user did not specified interactive mode * - the user did not specified interactive mode

11
elilo.h
View file

@ -60,11 +60,17 @@
#define CMDLINE_MAXLEN 512 /* needed by ia32 */ #define CMDLINE_MAXLEN 512 /* needed by ia32 */
#define FILENAME_MAXLEN 256 #define FILENAME_MAXLEN 256
#define MAX_ARGS 256 #define MAX_ARGS 256
/* Just pick an arbitrary number that's high enough for now :o) */
#define MAX_DEFAULT_CONFIGS 16
typedef struct { typedef struct {
UINT8 nothing_yet; UINT8 nothing_yet;
} image_opt_t; } image_opt_t;
typedef struct config_file {
CHAR16 fname[FILENAME_MAXLEN];
} config_file_t;
typedef struct { typedef struct {
/* /*
* list of options controllable from both the command line * list of options controllable from both the command line
@ -91,7 +97,8 @@ typedef struct {
sys_img_options_t *sys_img_opts; /* architecture depdendent per image options */ sys_img_options_t *sys_img_opts; /* architecture depdendent per image options */
CHAR16 default_kernel[FILENAME_MAXLEN]; CHAR16 default_kernel[FILENAME_MAXLEN];
CHAR16 default_config[FILENAME_MAXLEN]; /* CHAR16 default_config[FILENAME_MAXLEN]; */
config_file_t default_configs[MAX_DEFAULT_CONFIGS];
CHAR16 config[FILENAME_MAXLEN]; /* name of config file */ CHAR16 config[FILENAME_MAXLEN]; /* name of config file */
CHAR16 chooser[FILENAME_MAXLEN]; /* image chooser to use */ CHAR16 chooser[FILENAME_MAXLEN]; /* image chooser to use */
@ -160,7 +167,7 @@ extern VOID ascii2U(CHAR8 *, CHAR16 *, UINTN);
extern VOID U2ascii(CHAR16 *, CHAR8 *, UINTN); extern VOID U2ascii(CHAR16 *, CHAR8 *, UINTN);
/* from config.c (more in config.h) */ /* from config.c (more in config.h) */
extern EFI_STATUS read_config(CHAR16 *, INTN retry); extern EFI_STATUS read_config(CHAR16 *);
extern VOID print_config_options(VOID); extern VOID print_config_options(VOID);
extern INTN find_label(CHAR16 *, CHAR16 *, CHAR16 *, CHAR16 *); extern INTN find_label(CHAR16 *, CHAR16 *, CHAR16 *, CHAR16 *);
extern VOID print_label_list(VOID); extern VOID print_label_list(VOID);

View file

@ -345,12 +345,37 @@ fops_seek(fops_fd_t fd, UINT64 newpos)
} }
EFI_STATUS EFI_STATUS
fops_setdefaults(CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath) fops_setdefaults(struct config_file *defconf, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
{ {
#define FILEOPS_DEFAULT_KERNEL L"vmlinux" INTN i;
#define FILEOPS_DEFAULT_CONFIG L"elilo.conf"
if (config == NULL || kname == NULL) return EFI_INVALID_PARAMETER; /*
* The first default config file is architecture dependent. This is useful
* in case of network booting where the server is used for both types of
* architectures.
*/
#if defined(CONFIG_ia64)
#define FILEOPS_ARCH_DEFAULT_CONFIG L"elilo-ia64.conf"
#elif defined (CONFIG_ia32)
#define FILEOPS_ARCH_DEFAULT_CONFIG L"elilo-ia32.conf"
#else
#error "You need to specfy your default arch config file"
#endif
/*
* last resort config file. Common to all architectures
*/
#define FILEOPS_DEFAULT_CONFIG L"elilo.conf"
#define FILEOPS_DEFAULT_KERNEL L"vmlinux"
#ifdef ELILO_DEBUG
if (defconf == NULL || kname == NULL) return EFI_INVALID_PARAMETER;
#endif
for (i=0; i<MAX_DEFAULT_CONFIGS; i++) {
defconf[i].fname[0] = CHAR_NULL;
}
if (boot_dev == NULL || boot_dev->fops == NULL) { if (boot_dev == NULL || boot_dev->fops == NULL) {
if (boot_dev == NULL) if (boot_dev == NULL)
@ -360,13 +385,30 @@ fops_setdefaults(CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
Print(L"Using builtin defaults for kernel and config file\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); StrnCpy(kname, FILEOPS_DEFAULT_KERNEL, maxlen-1);
return EFI_UNSUPPORTED;
} }
else {
boot_dev->fops->setdefaults(boot_dev->fops->intf, defconf, kname, maxlen, devpath);
}
i=0; while (i<MAX_DEFAULT_CONFIGS && defconf[i].fname[0] != CHAR_NULL) i += 1;
//#ifdef ELILO_DEBUG
if ((i+3) >= MAX_DEFAULT_CONFIGS) {
Print(L"ERROR: i = %d, MAX_DEFAULT_CONFIGS is not large enough\n", i);
return EFI_INVALID_PARAMETER;
}
//#endif
StrnCpy(defconf[i].fname, FILEOPS_ARCH_DEFAULT_CONFIG, maxlen-1);
StrnCpy(defconf[i+1].fname, FILEOPS_DEFAULT_CONFIG, maxlen-1);
return boot_dev->fops->setdefaults(boot_dev->fops->intf, config, kname, maxlen, devpath); //#ifdef ELILO_DEBUG
VERB_PRT(3,Print(L"Default config filename list:\n"));
for (i=0; i<MAX_DEFAULT_CONFIGS; i++) {
if (defconf[i].fname[0] == CHAR_NULL) { break; }
VERB_PRT(3,Print(L"\t%s\n", defconf[i].fname));
}
//#endif
return EFI_SUCCESS;
} }
EFI_STATUS EFI_STATUS

View file

@ -33,12 +33,15 @@
*/ */
typedef UINTN fops_fd_t; typedef UINTN fops_fd_t;
/* Forward declaration: */
struct config_file;
extern EFI_STATUS fops_open(CHAR16 *name, fops_fd_t *fd); 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_read(fops_fd_t fd,VOID *buf, UINTN *size);
extern EFI_STATUS fops_close(fops_fd_t fd); extern EFI_STATUS fops_close(fops_fd_t fd);
extern EFI_STATUS fops_infosize(fops_fd_t fd, UINT64 *size); 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_seek(fops_fd_t fd, UINT64 newpos);
extern EFI_STATUS fops_setdefaults(CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath); extern EFI_STATUS fops_setdefaults(struct config_file *defconf, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath);
extern EFI_STATUS fops_getdefault_path(CHAR16 *path, UINTN maxlen); extern EFI_STATUS fops_getdefault_path(CHAR16 *path, UINTN maxlen);
extern CHAR16 *fops_bootdev_name(VOID); extern CHAR16 *fops_bootdev_name(VOID);
@ -46,12 +49,13 @@ extern CHAR16 *fops_bootdev_name(VOID);
/* /*
* fileops interface used by underlying filesystems layer * 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_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_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_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_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_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_setdefaults_t)(VOID *intf, struct config_file *defconfs, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath);
typedef EFI_STATUS (*fops_getdefault_path_t)(CHAR16 *path, UINTN maxlen); typedef EFI_STATUS (*fops_getdefault_path_t)(CHAR16 *path, UINTN maxlen);
typedef struct { typedef struct {

View file

@ -99,13 +99,13 @@ set_default_path(CHAR16 *sptr)
#define LOCALFS_DEFAULT_KERNEL L"vmlinux" #define LOCALFS_DEFAULT_KERNEL L"vmlinux"
#define LOCALFS_DEFAULT_CONFIG L"elilo.conf" #define LOCALFS_DEFAULT_CONFIG L"elilo.conf"
static EFI_STATUS static EFI_STATUS
localfs_setdefaults(VOID *this, CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath) localfs_setdefaults(VOID *this, config_file_t *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
{ {
StrnCpy(kname, LOCALFS_DEFAULT_KERNEL, maxlen-1); StrnCpy(kname, LOCALFS_DEFAULT_KERNEL, maxlen-1);
kname[maxlen-1] = CHAR_NULL; kname[maxlen-1] = CHAR_NULL;
StrnCpy(config, LOCALFS_DEFAULT_CONFIG, maxlen-1); StrnCpy(config[0].fname, LOCALFS_DEFAULT_CONFIG, maxlen-1);
config[maxlen-1] = CHAR_NULL; config[0].fname[maxlen-1] = CHAR_NULL;
set_default_path(devpath); set_default_path(devpath);

View file

@ -117,7 +117,7 @@ netfs_set_default_path(netfs_interface_t *netfs, netfs_info_t *info)
} }
static EFI_STATUS static EFI_STATUS
netfs_setdefaults(VOID *intf, CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath) netfs_setdefaults(VOID *intf, config_file_t *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
{ {
netfs_interface_t *netfs = (netfs_interface_t *)intf; netfs_interface_t *netfs = (netfs_interface_t *)intf;
netfs_info_t info; netfs_info_t info;
@ -149,10 +149,10 @@ netfs_setdefaults(VOID *intf, CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR1
set_var(VAR_NETFS_DOMAINAME, info.domainame); set_var(VAR_NETFS_DOMAINAME, info.domainame);
if (info.using_pxe) { if (info.using_pxe) {
status = netfs->netfs_query_layer(netfs, 0, NETFS_CONFIG_LAYER, maxlen, config); status = netfs->netfs_query_layer(netfs, 0, NETFS_CONFIG_LAYER, maxlen, config[0].fname);
if (EFI_ERROR(status)) { if (EFI_ERROR(status)) {
StrnCpy(config, NETFS_DEFAULT_CONFIG, maxlen-1); StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1);
config[maxlen-1] = CHAR_NULL; config[0].fname[maxlen-1] = CHAR_NULL;
} }
status = netfs->netfs_query_layer(netfs, 0, NETFS_KERNEL_LAYER, maxlen, kname); status = netfs->netfs_query_layer(netfs, 0, NETFS_KERNEL_LAYER, maxlen, kname);
@ -162,21 +162,44 @@ netfs_setdefaults(VOID *intf, CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR1
} }
} else { } else {
#ifdef ENABLE_MACHINE_SPECIFIC_NETCONFIG #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'.'; # if defined(CONFIG_ia64)
config[9] = L'c'; # define CONFIG_ARCH_EXTENSION L"-ia64.conf\0"
config[10] = L'o'; # elif defined (CONFIG_ia32)
config[11] = L'n'; # define CONFIG_ARCH_EXTENSION L"-ia64.conf\0"
config[12] = L'f'; # else
config[13] = CHAR_NULL; # error "You need to specfy your default arch config file"
# endif
# define CONFIG_EXTENSION L".conf\0"
/*
* will try machine/subnet specific files first.
* the filenames are constructed based on the IP(v4) address
*/
convert_ip2hex(ipaddr, m, str);
StrnCpy(config[0].fname, str, maxlen-1);
StrnCpy(config[0].fname+8, CONFIG_EXTENSION, 6);
StrnCpy(config[1].fname, str, maxlen-1);
StrnCpy(config[1].fname+6, CONFIG_ARCH_EXTENSION, 11);
StrnCpy(config[2].fname, str, maxlen-1);
StrnCpy(config[2].fname+6, CONFIG_EXTENSION, 6);
StrnCpy(config[3].fname, str, maxlen-1);
StrnCpy(config[3].fname+4, CONFIG_ARCH_EXTENSION, 11);
StrnCpy(config[4].fname, str, maxlen-1);
StrnCpy(config[4].fname+4, CONFIG_EXTENSION, 6);
StrnCpy(config[5].fname, str, maxlen-1);
StrnCpy(config[5].fname+2, CONFIG_ARCH_EXTENSION, 11);
StrnCpy(config[6].fname, str, maxlen-1);
StrnCpy(config[6].fname+2, CONFIG_EXTENSION, 6);
#else #else
StrnCpy(config, NETFS_DEFAULT_CONFIG, maxlen-1); StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1);
config[maxlen-1] = CHAR_NULL; config[0].fname[maxlen-1] = CHAR_NULL;
#endif #endif
StrnCpy(kname, NETFS_DEFAULT_KERNEL, maxlen-1); StrnCpy(kname, NETFS_DEFAULT_KERNEL, maxlen-1);
kname[maxlen-1] = CHAR_NULL; kname[maxlen-1] = CHAR_NULL;

View file

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

View file

@ -28,7 +28,7 @@ include ../Make.rules
TOPDIR=$(CDIR)/.. TOPDIR=$(CDIR)/..
FILES=system.o config.o FILES=system.o config.o bzimage.o plain_loader.o gzip_loader.o gzip.o
TARGET=sysdeps.o TARGET=sysdeps.o

224
ia32/bzimage.c Normal file
View file

@ -0,0 +1,224 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
* Contributed by Mike Johnston <johnston@intel.com>
* Contributed by Chris Ahna <christopher.j.ahna@intel.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
* ELILO is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* ELILO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ELILO; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Please check out the elilo.txt for complete documentation on how
* to use this program.
*/
#include <efi.h>
#include <efilib.h>
#include "elilo.h"
#include "loader.h"
boot_params_t *param_start = NULL;
UINTN param_size = 0;
UINTN kernel_size = 0x200000; /* 2M (largest x86 bzImage kernel image) */
static INTN
bzImage_probe(CHAR16 *kname)
{
EFI_STATUS efi_status;
UINTN size;
fops_fd_t fd;
UINT8 bootsect[512];
DBG_PRT((L"probe_bzImage_boot()\n"));
if (!kname) {
ERR_PRT((L"kname == %xh", kname));
free_kmem();
return -1;
}
/*
* Open kernel image.
*/
DBG_PRT((L"opening %s...\n", kname));
efi_status = fops_open(kname, &fd);
if (EFI_ERROR(efi_status)) {
ERR_PRT((L"Could not open %s.", kname));
free_kmem();
return -1;
}
/*
* Read boot sector.
*/
DBG_PRT((L"\nreading boot sector...\n"));
size = sizeof bootsect;
efi_status = fops_read(fd, bootsect, &size);
if (EFI_ERROR(efi_status) || size != sizeof bootsect) {
ERR_PRT((L"Could not read boot sector from %s.", kname));
fops_close(fd);
free_kmem();
return -1;
}
/*
* Verify boot sector signature.
*/
if (bootsect[0x1FE] != 0x55 || bootsect[0x1FF] != 0xAA) {
ERR_PRT((L"%s is not a bzImage kernel image.\n", kname));
fops_close(fd);
free_kmem();
return -1;
}
/*
* Check for out of range setup data size.
* Will almost always be 7, but we will accept 1 to 64.
*/
DBG_PRT((L"bootsect[1F1h] == %d setup sectors\n", bootsect[0x1F1]));
if (bootsect[0x1F1] < 1 || bootsect[0x1F1] > 64) {
ERR_PRT((L"%s is not a valid bzImage kernel image.",
kname));
fops_close(fd);
free_kmem();
return -1;
}
/*
* Allocate and read setup data.
*/
DBG_PRT((L"reading setup data...\n"));
param_size = (bootsect[0x1F1] + 1) * 512;
param_start = alloc(param_size, EfiLoaderData);
DBG_PRT((L"param_size=%d param_start=%x", param_size, param_start));
if (!param_start) {
ERR_PRT((L"Could not allocate %d bytes of setup data.",
param_size));
fops_close(fd);
free_kmem();
return -1;
}
CopyMem(param_start, bootsect, sizeof bootsect);
size = param_size - 512;
efi_status = fops_read(fd, ((UINT8 *)param_start) + 512, &size);
if (EFI_ERROR(efi_status) || size != param_size - 512) {
ERR_PRT((L"Could not read %d bytes of setup data.",
param_size - 512));
free(param_start);
param_start = NULL;
param_size = 0;
fops_close(fd);
free_kmem();
return -1;
}
/*
* Check for setup data signature.
*/
{
UINT8 *c = ((UINT8 *)param_start)+514;
DBG_PRT((L"param_start(c=%x): %c-%c-%c-%c",
c, (CHAR16)c[0],(CHAR16) c[1], (CHAR16)c[2], (CHAR16)c[3]));
}
if (CompareMem(((UINT8 *)param_start) + 514, "HdrS", 4)) {
ERR_PRT((L"%s does not have a setup signature.",
kname));
free(param_start);
param_start = NULL;
param_size = 0;
fops_close(fd);
free_kmem();
return -1;
}
/*
* Allocate memory for kernel.
*/
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
bzImage_load(CHAR16 *kname, kdesc_t *kd)
{
DBG_PRT((L"load_bzImage_boot()\n"));
if (!kname || !kd) {
ERR_PRT((L"kname=0x%x kd=0x%x", kname, kd));
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;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
loader_ops_t bzimage_loader = {
NULL,
L"bzImage_loader",
&bzImage_probe,
&bzImage_load
};

552
ia32/gzip.c Normal file
View file

@ -0,0 +1,552 @@
/*
* Copyright (C) 2001-2002 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* Copyright (C) 2001 Silicon Graphics, Inc.
* Contributed by Brent Casavant <bcasavan@sgi.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
* ELILO is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* ELILO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ELILO; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Please check out the elilo.txt for complete documentation on how
* to use this program.
*/
#include <efi.h>
#include <efilib.h>
#include "elf.h"
#include "elilo.h"
#include "gzip.h"
#include "private.h"
#define memzero(s, n) Memset((VOID *)(s), 0, (n))
#define memcpy(a,b,n) Memcpy((VOID *)(a),(b),(n))
/* size of output buffer */
#define WSIZE 0x8000 /* Window size must be at least 32k, */
/* and a power of two */
/* size of input buffer */
#define INBUFSIZE 0x8000
/*
* gzip declarations
*/
#define OF(args) args
#define FUNC_STATIC static
typedef unsigned char uch;
typedef unsigned short ush;
typedef unsigned long ulg;
typedef struct segment {
unsigned long addr; /* start address */
unsigned long offset; /* file offset */
unsigned long size; /* file size */
unsigned long bss_sz; /* BSS size */
UINT8 flags; /* indicates whether to load or not */
} segment_t;
#define CHUNK_FL_VALID 0x1
#define CHUNK_FL_LOAD 0x2
#define CHUNK_CAN_LOAD(n) chunks[(n)].flags |= CHUNK_FL_LOAD
#define CHUNK_NO_LOAD(n) chunks[(n)].flags &= ~CHUNK_FL_LOAD
#define CHUNK_IS_LOAD(n) (chunks[(n)].flags & CHUNK_FL_LOAD)
#define CHUNK_VALIDATE(n) chunks[(n)].flags |= CHUNK_FL_VALID
#define CHUNK_INVALIDATE(n) chunks[(n)].flags = 0
#define CHUNK_IS_VALID(n) (chunks[(n)].flags & CHUNK_FL_VALID)
/*
* static parameters to gzip helper functions
* we cannot use paramters because API was not
* designed that way
*/
static segment_t *chunks; /* holds the list of segments */
static segment_t *cur_chunk;
static UINTN nchunks;
static UINTN chunk; /* current segment */
static UINTN input_fd;
static VOID *kernel_entry, *kernel_base, *kernel_end;
static uch *inbuf; /* input buffer (compressed data) */
static uch *window; /* output buffer (uncompressed data) */
static unsigned long file_offset; /* position in the file */
static unsigned insize = 0; /* valid bytes in inbuf */
static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
static unsigned outcnt = 0; /* bytes in output buffer */
/* gzip flag byte */
#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
#define COMMENT 0x10 /* bit 4 set: file comment present */
#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
#define RESERVED 0xC0 /* bit 6,7: reserved */
#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
/* Diagnostic functions */
#ifdef INFLATE_DEBUG
# define Assert(cond,msg) {if(!(cond)) error(msg);}
int stderr;
# define Trace(x) Print(L"line %d:\n", __LINE__);
# define Tracev(x) {if (verbose) Print(L"line %d:\n", __LINE__) ;}
# define Tracevv(x) {if (verbose>1) Print(L"line %d:\n", __LINE__) ;}
# define Tracec(c,x) {if (verbose && (c)) Print(L"line %d:\n", __LINE__) ;}
# define Tracecv(c,x) {if (verbose>1 && (c)) Print(L"line %d:\n", __LINE__) ;}
#else
# define Assert(cond,msg)
# define Trace(x)
# define Tracev(x)
# define Tracevv(x)
# define Tracec(c,x)
# define Tracecv(c,x)
#endif
static int fill_inbuf(void);
static void flush_window(void);
static void error(char *m);
static long bytes_out;
static void error(char *m);
static int error_return;
static void *
gzip_malloc(int size)
{
return (void *)alloc(size, 0);
}
static void
gzip_free(void *where)
{
return free(where);
}
#include "inflate.c"
/*
* Fill the input buffer and return the first byte in it. This is called
* only when the buffer is empty and at least one byte is really needed.
*/
int
fill_inbuf(void)
{
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 INTN
is_valid_header(Elf32_Ehdr *ehdr)
{
UINT16 type, machine;
type = ehdr->e_type;
machine = ehdr->e_machine;
VERB_PRT(3, Print(L"class=%d type=%d data=%d machine=%d\n",
ehdr->e_ident[EI_CLASS],
type,
ehdr->e_ident[EI_DATA],
machine));
return ehdr->e_ident[EI_MAG0] == 0x7f
&& ehdr->e_ident[EI_MAG1] == 'E'
&& ehdr->e_ident[EI_MAG2] == 'L'
&& ehdr->e_ident[EI_MAG3] == 'F'
&& ehdr->e_ident[EI_CLASS] == ELFCLASS32
&& type == ET_EXEC /* must be executable */
&& machine == EM_386 ? 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)
{
Elf32_Ehdr *elf;
Elf32_Phdr *phdrs;
UINTN total_size, pages;
UINTN low_addr, max_addr;
UINTN offs = 0;
UINT16 phnum;
UINTN paddr, memsz;
INTN i;
elf = (Elf32_Ehdr *)buf;
if (is_valid_header(elf) == -1)
return -1;
offs = elf->e_phoff;
phnum = elf->e_phnum;
VERB_PRT(3, {
Print(L"Entry point 0x%lx\n", elf->e_entry);
Print(L"%d program headers\n", phnum);
Print(L"%d segment headers\n", elf->e_shnum);
});
if (offs + phnum * sizeof(*phdrs) > (unsigned) blocksize) {
ERR_PRT((L"%s : ELF program headers not in first block (%ld)\n", LD_NAME, offs));
return -1;
}
kernel_entry = (VOID *)(elf->e_entry & PADDR_MASK);
phdrs = (Elf32_Phdr *) (buf + offs);
low_addr = ~0;
max_addr = 0;
/*
* allocate chunk table
* Convention: a segment that does not need loading will
* have chunk[].addr = 0.
*/
chunks = (void *)alloc(sizeof(struct segment)*phnum, 0);
if (chunks == NULL) {
ERR_PRT((L"%s : failed alloc chunks %r\n", LD_NAME));
return -1;
}
nchunks = phnum;
/*
* find lowest and higest virtual addresses
* don't assume FULLY sorted !
*/
for (i = 0; i < phnum; ++i) {
/*
* record chunk no matter what because no load may happen
* anywhere in archive, not just as the last segment
*/
paddr = (phdrs[i].p_paddr & PADDR_MASK);
memsz = phdrs[i].p_memsz,
chunks[i].addr = paddr;
chunks[i].offset = phdrs[i].p_offset;
chunks[i].size = phdrs[i].p_filesz;
chunks[i].bss_sz = phdrs[i].p_memsz - phdrs[i].p_filesz;
CHUNK_VALIDATE(i);
if (phdrs[i].p_type != PT_LOAD) {
CHUNK_NO_LOAD(i); /* mark no load chunk */
DBG_PRT((L"%s : skipping segment %ld\n", LD_NAME, i));
continue;
}
CHUNK_CAN_LOAD(i); /* mark no load chunk */
VERB_PRT(3,
Print(L"\n%s : segment %ld vaddr [0x%lx-0x%lx] offset %ld filesz %ld "
"memsz=%ld bss_sz=%ld\n",
LD_NAME, 1+i, chunks[i].addr, chunks[i].addr+phdrs[i].p_filesz,
chunks[i].offset, chunks[i].size, memsz, chunks[i].bss_sz));
if (paddr < low_addr)
low_addr = paddr;
if (paddr + memsz > max_addr)
max_addr = paddr + memsz;
}
if (low_addr & (EFI_PAGE_SIZE - 1)) {
ERR_PRT((L"%s : low_addr not page aligned 0x%lx\n", LD_NAME, low_addr));
goto error;
}
analyze_chunks();
DBG_PRT((L"%s : %d program headers entry=0x%lx\nlowest_addr=0x%lx highest_addr=0x%lx\n",
LD_NAME,
phnum, kernel_entry, low_addr, max_addr));
total_size = (UINTN)max_addr - (UINTN)low_addr;
pages = EFI_SIZE_TO_PAGES(total_size);
/*
* Record end of kernel for initrd
*/
kernel_base = (void *)low_addr;
kernel_end = (void *)(low_addr + (pages << EFI_PAGE_SHIFT));
/* allocate memory for the kernel */
if (alloc_kmem((void *)low_addr, pages) == -1) {
ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n",
LD_NAME, pages, low_addr));
ERR_PRT((L"%s : Could not load kernel at 0x%lx\n", LD_NAME, low_addr));
ERR_PRT((L"%s : Bailing\n", LD_NAME));
goto error;
}
return 0;
error:
if (chunks)
free(chunks);
return -1;
}
/*
* Determine which chunk in the Elf file will be coming out of the expand
* code next.
*/
static void
nextchunk(void)
{
int i;
segment_t *cp;
cp = NULL;
for(i=0; i < nchunks; i++) {
if (!CHUNK_IS_VALID(i) || !CHUNK_IS_LOAD(i)) continue;
if (file_offset > chunks[i].offset) continue;
if (cp == NULL || chunks[i].offset < cp->offset) cp = &chunks[i];
}
cur_chunk = cp;
}
/*
* Write the output window window[0..outcnt-1] holding uncompressed
* data and update crc.
*/
void
flush_window(void)
{
static const CHAR8 helicopter[4] = { '|' , '/' , '-' , '\\' };
static UINTN heli_count;
struct segment *cp;
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;
}
static void
error(char *x)
{
ERR_PRT((L"%s : %a", LD_NAME, x));
/* will eventually exit with error from gunzip() */
}
INT32
decompress_kernel(VOID)
{
INT32 ret;
clear_bufs();
makecrc();
Print(L"Uncompressing Linux... ");
ret = gunzip();
if (ret == 0)
Print(L"done\n");
return ret == 0 ? 0 : -1;
}
int
gunzip_kernel(fops_fd_t fd, kdesc_t *kd)
{
int ret = -1;
error_return = ELILO_LOAD_ERROR;
window = (void *)alloc(WSIZE, 0);
if (window == NULL) {
ERR_PRT((L"%s : allocate output window failed\n", LD_NAME));
return -1;
}
inbuf = (void *)alloc(INBUFSIZE, 0);
if (inbuf == NULL) {
ERR_PRT((L"%s : allocate input window failedr\n", LD_NAME));
goto error;
}
input_fd = fd;
insize = 0;
bytes_out = 0;
ret = decompress_kernel();
error:
if (window) free(window);
if (inbuf) free(inbuf);
if (ret == 0) {
kd->kentry = kernel_entry;
kd->kend = kernel_end;
kd->kstart = kernel_base;
error_return = ELILO_LOAD_SUCCESS;
}
return error_return;
}

35
ia32/gzip.h Normal file
View file

@ -0,0 +1,35 @@
/*
* Copyright (C) 2001-2002 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_ia32"
#endif /* __GZIP_H__ */

79
ia32/gzip_loader.c Normal file
View file

@ -0,0 +1,79 @@
/*
* Copyright (C) 2001-2002 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
};

1205
ia32/inflate.c Normal file

File diff suppressed because it is too large Load diff

285
ia32/plain_loader.c Normal file
View file

@ -0,0 +1,285 @@
/*
* Copyright (C) 2001-2002 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* Copyright (C) 2001 Silicon Graphics, Inc.
* Contributed by Brent Casavant <bcasavan@sgi.com>
*
* 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_elf32"
static INTN
is_valid_header(Elf32_Ehdr *ehdr)
{
UINT16 type, machine;
type = ehdr->e_type;
machine = ehdr->e_machine;
DBG_PRT((L"class=%d type=%d data=%d machine=%d\n",
ehdr->e_ident[EI_CLASS],
type,
ehdr->e_ident[EI_DATA],
machine));
return ehdr->e_ident[EI_MAG0] == 0x7f
&& ehdr->e_ident[EI_MAG1] == 'E'
&& ehdr->e_ident[EI_MAG2] == 'L'
&& ehdr->e_ident[EI_MAG3] == 'F'
&& ehdr->e_ident[EI_CLASS] == ELFCLASS32
&& type == ET_EXEC /* must be executable */
&& machine == EM_386 ? 0 : -1;
}
static INTN
plain_probe(CHAR16 *kname)
{
Elf32_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;
}
static INTN
load_elf(fops_fd_t fd, kdesc_t *kd)
{
Elf32_Ehdr ehdr;
Elf32_Phdr *phdrs;
EFI_STATUS status;
INTN ret = ELILO_LOAD_ERROR;
UINTN i, total_size = 0;
UINTN pages, size, bss_sz, osize;
VOID *low_addr = (VOID *)~0;
VOID *max_addr = (VOID *)0;
UINTN paddr, memsz, filesz;
UINT16 phnum;
Print(L"Loading Linux... ");
size = sizeof(ehdr);
status = fops_read(fd, &ehdr, &size);
if (EFI_ERROR(status) || size < sizeof(ehdr))
return ELILO_LOAD_ERROR;
if (is_valid_header(&ehdr) == -1) {
ERR_PRT((L"%s : not a 32-bit ELF image\n", LD_NAME));
return ELILO_LOAD_ERROR;
}
VERB_PRT(3, {
Print(L"ELF Header information: \n");
Print(L"\tEntry point 0x%x\n", (ehdr.e_entry & PADDR_MASK));
Print(L"\t%d program headers\n", ehdr.e_phnum);
Print(L"\t%d segment headers\n", ehdr.e_shnum);
});
phnum = ehdr.e_phnum;
if (fops_seek(fd, ehdr.e_phoff) < 0) {
ERR_PRT((L"%s : seek to %d for phdrs failed", LD_NAME, ehdr.e_phoff));
return ELILO_LOAD_ERROR;
}
size = osize = (phnum * sizeof(Elf32_Phdr));
DBG_PRT((L"%s : allocate %d bytes for %d pheaders each of size:%d phentsize=%d\n",
LD_NAME, size, phnum, sizeof(Elf32_Phdr), ehdr.e_phentsize));
phdrs = (Elf32_Phdr *)alloc(size, 0);
if (phdrs == NULL) {
ERR_PRT((L"%s : allocate for phdrs failed", LD_NAME));
return ELILO_LOAD_ERROR;
}
status = fops_read(fd, phdrs, &size);
if (EFI_ERROR(status) || size != osize) {
ERR_PRT((L"%s : phdr load failed", LD_NAME, status));
goto out;
}
/*
* First pass to figure out total memory footprint
*/
for (i = 0; i < phnum; i++) {
paddr = (phdrs[i].p_paddr & PADDR_MASK);
memsz = phdrs[i].p_memsz;
DBG_PRT((L"Phdr %d paddr [0x%x-0x%x] offset 0x%x"
" filesz 0x%x memsz=0x%x bss_sz=0x%x p_type=0x%x\n",
1+i, paddr, paddr+phdrs[i].p_filesz, phdrs[i].p_offset,
phdrs[i].p_filesz, memsz,
(memsz - phdrs[i].p_filesz), phdrs[i].p_type));
if (phdrs[i].p_type != PT_LOAD)
continue;
if (paddr < (UINTN)low_addr)
low_addr = (VOID *)paddr;
if (paddr + memsz > (UINTN)max_addr)
max_addr = (VOID *)paddr + memsz;
}
if ((UINTN)low_addr & (EFI_PAGE_SIZE - 1)) {
ERR_PRT((L"%s : kernel low address 0x%x not page aligned\n",
LD_NAME, low_addr));
goto out;
}
/* how many bytes are needed to hold the kernel? */
total_size = (UINTN)max_addr - (UINTN)low_addr;
/* round up to get required number of pages */
pages = EFI_SIZE_TO_PAGES(total_size);
/* keep track of location where kernel starts and ends */
kd->kstart = low_addr;
kd->kend = (low_addr + (pages << EFI_PAGE_SHIFT));
kd->kentry = (VOID *)(ehdr.e_entry & PADDR_MASK);
VERB_PRT(3, {
Print(L"Lowest PhysAddr: 0x%x\nTotalMemSize:%d bytes (%d pages)\n",
low_addr, total_size, pages);
Print(L"Kernel entry @ 0x%x\n", kd->kentry);
});
/* now allocate memory for the kernel at the exact requested spot */
if (alloc_kmem(low_addr, pages) == -1) {
ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n",
LD_NAME, pages, low_addr));
ERR_PRT((L"%s : Could not alloc %d pages for the kernel at 0x%lx "
" and relocation is not not been implemented!\n",
LD_NAME, pages, low_addr));
goto load_abort;
}
/* Pure paranoia. Clear the memory first. Just in case... */
Memset(low_addr, 0, (pages << EFI_PAGE_SHIFT));
VERB_PRT(1, Print(L"Press any key to interrupt\n"));
/*
* Walk through the program headers
* and actually load data into physical memory
*/
for (i = 0; i < phnum; i++) {
/* Check for pure loadable segment; ignore if not loadable */
if (phdrs[i].p_type != PT_LOAD)
continue;
VERB_PRT(3, Print(L"poffs: 0x%x (phdrs[%d].p_offset)\n",
phdrs[i].p_offset, i));
filesz = phdrs[i].p_filesz;
low_addr = (VOID *)((UINTN) phdrs[i].p_paddr & PADDR_MASK);
/* Move to the right position */
if (fops_seek(fd, phdrs[i].p_offset) < 0)
goto out_kernel;
/* How many BSS bytes to clear */
bss_sz = phdrs[i].p_memsz - filesz;
VERB_PRT(4, {
Print(L"\nHeader #%d\n", i);
Print(L"Offset in file 0x%x\n", phdrs[i].p_offset);
Print(L"Physical addr 0x%x\n", low_addr);
Print(L"BSS size 0x%x bytes\n", bss_sz);
});
/*
* Read actual segment into memory
*/
ret = fops_read(fd, low_addr, &filesz);
if (ret == ELILO_LOAD_ABORTED) goto load_abort;
if (ret == ELILO_LOAD_ERROR) goto out;
/*
* Clear bss section
*/
if (bss_sz)
Memset((VOID *)low_addr+filesz, 0, bss_sz);
}
free(phdrs);
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);
return ret;
}
loader_ops_t plain_loader={
NULL,
LD_NAME,
plain_probe,
plain_load_kernel
};

View file

@ -33,6 +33,7 @@
#define __ELILO_SYSDEPS_IA32_H__ #define __ELILO_SYSDEPS_IA32_H__
#define ELILO_ARCH "IA-32" /* ASCII string */ #define ELILO_ARCH "IA-32" /* ASCII string */
#define PADDR_MASK 0xfffffff
/* for now use library versions */ /* for now use library versions */
#define Memset(a,v,n) SetMem((a),(n),(v)) #define Memset(a,v,n) SetMem((a),(n),(v))
@ -56,27 +57,6 @@
* A new bit, LDRFLAG_BOOT_PARAM_RELOC, in the loader_flags * A new bit, LDRFLAG_BOOT_PARAM_RELOC, in the loader_flags
* field is also defined in this file. * 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) #pragma pack(1)
typedef union ia32_boot_params { typedef union ia32_boot_params {
@ -275,7 +255,9 @@ typedef union ia32_boot_params {
/* 0x224 */ UINT16 heap_end_ptr; /* LDR */ /* 0x224 */ UINT16 heap_end_ptr; /* LDR */
/* %%TBD */ /* %%TBD */
/* 0x226 */ UINT32 base_mem_size; /* LDR */ /* 0x226 */ UINT16 unused_7; /* LDR */
/* 0x228 */ UINT32 cmdline_addr; /* LDR */
} s; } s;
} boot_params_t; } boot_params_t;
#pragma pack() #pragma pack()
@ -354,7 +336,6 @@ start_kernel(VOID *kentry, boot_params_t *bp)
/* /*
* Disable interrupts. * Disable interrupts.
*/ */
asm volatile ( "cli" : : ); asm volatile ( "cli" : : );
/* /*
@ -362,11 +343,9 @@ start_kernel(VOID *kentry, boot_params_t *bp)
*/ */
if (bp->s.initrd_start) { if (bp->s.initrd_start) {
/* %%TBD */
MEMCPY(15 * 1024 * 1024, bp->s.initrd_start, bp->s.initrd_size); MEMCPY(15 * 1024 * 1024, bp->s.initrd_start, bp->s.initrd_size);
bp->s.initrd_start = 15 * 1024 * 1024; bp->s.initrd_start = 15 * 1024 * 1024;
} }
/* /*
* Copy boot sector, setup data and command line * Copy boot sector, setup data and command line
* to final resting place. We need to copy * to final resting place. We need to copy
@ -375,20 +354,6 @@ start_kernel(VOID *kentry, boot_params_t *bp)
MEMCPY(high_base_mem, bp, 0x4000); 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. * Initialize Linux GDT.
*/ */
@ -429,7 +394,6 @@ start_kernel(VOID *kentry, boot_params_t *bp)
* Jump to kernel entry point. * Jump to kernel entry point.
*/ */
asm volatile ( "jmp *%%ecx" : : ); asm volatile ( "jmp *%%ecx" : : );
} }

View file

@ -26,23 +26,16 @@
*/ */
/* /*
* this file contains all the IA-32 specific code expected by generic loader * This file contains all the IA-32 specific code expected by generic loader
*/ */
#include <efi.h> #include <efi.h>
#include <efilib.h> #include <efilib.h>
#include "elilo.h" #include "elilo.h"
#include "loader.h" #include "loader.h"
#include "rmswitch.h" #include "rmswitch.h"
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ extern loader_ops_t bzimage_loader, plain_loader, gzip_loader;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* extern loader_ops_t plain_loader, gzip_loader; */
efi_ia32_boot_params_t efi_ia32_bp;
/* /*
* Descriptor table base addresses & limits for Linux startup. * Descriptor table base addresses & limits for Linux startup.
@ -77,7 +70,6 @@ UINT16 init_gdt[] = {
UINTN sizeof_init_gdt = sizeof init_gdt; UINTN sizeof_init_gdt = sizeof init_gdt;
/* /*
* Highest available base memory address. * Highest available base memory address.
* *
@ -98,266 +90,33 @@ UINTN high_base_mem = 0x90000;
* *
* This is computed by taking the highest available extended memory * This is computed by taking the highest available extended memory
* address and rounding down to the nearest EFI_PAGE_SIZE (usually * address and rounding down to the nearest EFI_PAGE_SIZE (usually
* 4 kB) boundary. The ia32 Linux kernel can only support up to * 4 kB) boundary.
* 2 GB (AFAIK). * This is only used for backward compatibility.
*/ */
UINTN high_ext_mem = 32 * 1024 * 1024; UINTN high_ext_mem = 32 * 1024 * 1024;
/* /* This starting address will hold true for all of the loader types for now */
* Starting location and size of runtime memory blocks.
*/
boot_params_t *param_start = NULL;
UINTN param_size = 0;
VOID *kernel_start = (VOID *)0x100000; /* 1M */ VOID *kernel_start = (VOID *)0x100000; /* 1M */
UINTN kernel_size = 0x200000; /* 2M (largest x86 kernel image) */
VOID *initrd_start = NULL; VOID *initrd_start = NULL;
UINTN initrd_size = 0; 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 INTN
sysdeps_init(EFI_HANDLE dev) sysdeps_init(EFI_HANDLE dev)
{ {
DBG_PRT((L"sysdeps_init()\n")); DBG_PRT((L"sysdeps_init()\n"));
/* /*
* Register our loader(s)... * Register our loader(s)...
*/ */
loader_register(&loader_bzImage_boot); loader_register(&bzimage_loader);
/* loader_register(&plain_loader); */ loader_register(&plain_loader);
/* loader_register(&gzip_loader); */ loader_register(&gzip_loader);
return 0; return 0;
} }
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* /*
* initrd_get_addr() * initrd_get_addr()
* Compute a starting address for the initial RAMdisk image. * Compute a starting address for the initial RAMdisk image.
@ -381,13 +140,12 @@ sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem)
imem->start_addr = 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)); VERB_PRT(3, Print(L"initrd start_addr=0x%x pgcnt=%d\n",
imem->start_addr, imem->pgcnt));
return 0; return 0;
} }
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
VOID VOID
sysdeps_free_boot_params(boot_params_t *bp) sysdeps_free_boot_params(boot_params_t *bp)
{ {
@ -398,8 +156,6 @@ sysdeps_free_boot_params(boot_params_t *bp)
free_memmap(&md); free_memmap(&md);
} }
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* /*
* IA-32 specific boot parameters initialization routine * IA-32 specific boot parameters initialization routine
*/ */
@ -423,9 +179,11 @@ sysdeps_create_boot_params(
ERR_PRT((L"bp=0x%x cmdline=0x%x initrd=0x%x cookie=0x%x", ERR_PRT((L"bp=0x%x cmdline=0x%x initrd=0x%x cookie=0x%x",
bp, cmdline, initrd, cookie)); bp, cmdline, initrd, cookie));
free(param_start); if (param_start != NULL) {
param_start = NULL; free(param_start);
param_size = 0; param_start = NULL;
param_size = 0;
}
free_kmem(); free_kmem();
return -1; return -1;
} }
@ -436,29 +194,27 @@ sysdeps_create_boot_params(
* the first two sectors (1K). The rest of the storage * the first two sectors (1K). The rest of the storage
* can be used by the command line. * can be used by the command line.
*/ */
if (param_start != NULL) {
CopyMem(bp, param_start, 0x2000); CopyMem(bp, param_start, 0x2000);
free(param_start);
free(param_start); param_start = NULL;
param_start = NULL; param_size = 0;
param_size = 0; }
/* /*
* Save off our header revision information. * Save off our header revision information.
*/ */
hdr_version = (bp->s.hdr_major << 8) | bp->s.hdr_minor; hdr_version = (bp->s.hdr_major << 8) | bp->s.hdr_minor;
/* /*
* Clear out unused memory in boot sector image. * Clear out unused memory in boot sector image.
*/ */
bp->s.unused_1 = 0; bp->s.unused_1 = 0;
bp->s.unused_2 = 0; bp->s.unused_2 = 0;
ZeroMem(bp->s.unused_3, sizeof bp->s.unused_3); ZeroMem(bp->s.unused_3, sizeof bp->s.unused_3);
ZeroMem(bp->s.unused_4, sizeof bp->s.unused_4); ZeroMem(bp->s.unused_4, sizeof bp->s.unused_4);
ZeroMem(bp->s.unused_5, sizeof bp->s.unused_5); ZeroMem(bp->s.unused_5, sizeof bp->s.unused_5);
bp->s.unused_6 = 0; bp->s.unused_6 = 0;
bp->s.unused_7 = 0;
/* /*
* Tell kernel this was loaded by an advanced loader type. * Tell kernel this was loaded by an advanced loader type.
@ -475,6 +231,12 @@ sysdeps_create_boot_params(
bp->s.cmdline_magik = CMDLINE_MAGIK; bp->s.cmdline_magik = CMDLINE_MAGIK;
bp->s.cmdline_offset = (UINT8 *)cmdline - (UINT8 *)bp; bp->s.cmdline_offset = (UINT8 *)cmdline - (UINT8 *)bp;
/*
* Clear out the cmdline_addr field so the kernel can find
* the cmdline.
*/
bp->s.cmdline_addr = 0x0;
/* /*
* Setup hard drive parameters. * Setup hard drive parameters.
* %%TBD - It should be okay to zero fill the hard drive * %%TBD - It should be okay to zero fill the hard drive
@ -484,28 +246,16 @@ sysdeps_create_boot_params(
ZeroMem(bp->s.hd0_info, sizeof bp->s.hd0_info); ZeroMem(bp->s.hd0_info, sizeof bp->s.hd0_info);
ZeroMem(bp->s.hd1_info, sizeof bp->s.hd1_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. * Memory info.
*/ */
bp->s.alt_mem_k = high_ext_mem / 1024; bp->s.alt_mem_k = high_ext_mem / 1024;
if (bp->s.alt_mem_k <= 65535) { if (bp->s.alt_mem_k <= 65535)
bp->s.ext_mem_k = (UINT16)bp->s.alt_mem_k; bp->s.ext_mem_k = (UINT16)bp->s.alt_mem_k;
} else { else
bp->s.ext_mem_k = 65535; bp->s.ext_mem_k = 65535;
}
if (hdr_version < 0x0202)
bp->s.base_mem_size = high_base_mem;
/* /*
* Initial RAMdisk and root device stuff. * Initial RAMdisk and root device stuff.
@ -525,24 +275,17 @@ sysdeps_create_boot_params(
/* /*
* This is the RAMdisk root device for RedHat 2.2.x * This is the RAMdisk root device for RedHat 2.2.x
* kernels (major 0x01, minor 0x00). * 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; bp->s.orig_root_dev = 0x0100;
} else { } else {
bp->s.initrd_start = 0; bp->s.initrd_start = 0;
bp->s.initrd_size = 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. * APM BIOS info.
*/ */
/* %%TBD - How to do Int 15h calls to get this info? */
bp->s.apm_bios_ver = NO_APM_BIOS; bp->s.apm_bios_ver = NO_APM_BIOS;
bp->s.bios_code_seg = 0; bp->s.bios_code_seg = 0;
bp->s.bios_entry_point = 0; bp->s.bios_entry_point = 0;
@ -555,29 +298,22 @@ sysdeps_create_boot_params(
/* /*
* MCA BIOS info (misnomer). * MCA BIOS info (misnomer).
*/ */
/* %%TBD - How to do Int 15h call to get this info? */
bp->s.mca_info_len = 0; bp->s.mca_info_len = 0;
ZeroMem(bp->s.mca_info_buf, sizeof bp->s.mca_info_buf); ZeroMem(bp->s.mca_info_buf, sizeof bp->s.mca_info_buf);
/* /*
* Pointing device presence. * Pointing device presence. The kernel will detect this.
*/ */
/* %%TBD - How to do Int 11h call to get this info? */
bp->s.aux_dev_info = NO_MOUSE; bp->s.aux_dev_info = NO_MOUSE;
/* /*
* EFI loader signature and address of EFI system table. * EFI loader signature
*/ */
CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG, 4); CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG, 4);
bp->s.efi_sys_tbl = 0; /* %%TBD */
/* /*
* Kernel entry point. * Kernel entry point.
*/ */
bp->s.kernel_start = (UINT32)kernel_start; bp->s.kernel_start = (UINT32)kernel_start;
/* /*
@ -587,6 +323,7 @@ sysdeps_create_boot_params(
* arch/i386/boot/bootsect.S * arch/i386/boot/bootsect.S
* arch/i386/boot/setup.S * arch/i386/boot/setup.S
* arch/i386/kernel/setup.c * arch/i386/kernel/setup.c
* include/asm-i386/setup.h (2.5/2.6)
*/ */
#define CHECK_OFFSET(n, o, f) \ #define CHECK_OFFSET(n, o, f) \
@ -610,7 +347,6 @@ sysdeps_create_boot_params(
; \ ; \
} \ } \
} }
{ {
UINTN test = 0; UINTN test = 0;
@ -688,7 +424,7 @@ sysdeps_create_boot_params(
CHECK_OFFSET(initrd_size, 0x21C, L"%xh"); CHECK_OFFSET(initrd_size, 0x21C, L"%xh");
CHECK_OFFSET(bootsect_helper, 0x220, L"%xh"); CHECK_OFFSET(bootsect_helper, 0x220, L"%xh");
CHECK_OFFSET(heap_end_ptr, 0x224, L"%xh"); CHECK_OFFSET(heap_end_ptr, 0x224, L"%xh");
CHECK_OFFSET(base_mem_size, 0x226, L"%xh"); CHECK_OFFSET(cmdline_addr, 0x228, L"%xh");
if (test) { if (test) {
ERR_PRT((L"Boot sector and/or setup parameter alignment error.")); ERR_PRT((L"Boot sector and/or setup parameter alignment error."));
@ -711,7 +447,6 @@ sysdeps_create_boot_params(
if (EFI_ERROR(efi_status)) { if (EFI_ERROR(efi_status)) {
ERR_PRT((L"QueryMode failed. Fake it.")); ERR_PRT((L"QueryMode failed. Fake it."));
mode = 3; mode = 3;
rows = 25; rows = 25;
cols = 80; cols = 80;
@ -730,12 +465,10 @@ sysdeps_create_boot_params(
bp->s.orig_video_cols = (UINT8)cols; bp->s.orig_video_cols = (UINT8)cols;
bp->s.orig_video_rows = (UINT8)rows; 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.orig_ega_bx = 0;
bp->s.is_vga = 0; bp->s.is_vga = 0;
bp->s.orig_video_points = 0; bp->s.orig_video_points = 16;
/* %%TBD - How to do Int 10h calls to get frame buffer info? */
bp->s.lfb_width = 0; bp->s.lfb_width = 0;
bp->s.lfb_height = 0; bp->s.lfb_height = 0;
bp->s.lfb_depth = 0; bp->s.lfb_depth = 0;
@ -763,7 +496,6 @@ sysdeps_create_boot_params(
free_kmem(); free_kmem();
return -1; return -1;
} }
*cookie = mdesc.cookie; *cookie = mdesc.cookie;
bp->s.efi_mem_map = (UINTN)mdesc.md; bp->s.efi_mem_map = (UINTN)mdesc.md;
bp->s.efi_mem_map_size = mdesc.map_size; bp->s.efi_mem_map_size = mdesc.map_size;
@ -771,28 +503,5 @@ sysdeps_create_boot_params(
bp->s.efi_mem_desc_ver = mdesc.desc_version; bp->s.efi_mem_desc_ver = mdesc.desc_version;
bp->s.efi_sys_tbl = (UINTN)systab; 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; return 0;
} }