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

42
ia64/Makefile Normal file
View file

@ -0,0 +1,42 @@
#
# Copyright (C) 2001-2003 Hewlett-Packard Co.
# Contributed by Stephane Eranian <eranian@hpl.hp.com>
#
# This file is part of the ELILO, the EFI Linux boot loader.
#
# ELILO is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# ELILO is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with ELILO; see the file COPYING. If not, write to the Free
# Software Foundation, 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
#
# Please check out the elilo.txt for complete documentation on how
# to use this program.
#
include ../Make.defaults
include ../Make.rules
TOPDIR=$(CDIR)/..
FILES=system.o config.o fpswa.o plain_loader.o gzip_loader.o \
gzip.o memset.o memcpy.o setjmp.o longjmp.o
TARGET=sysdeps.o
all: $(TARGET)
$(TARGET): $(FILES)
$(LD) -o $@ -r $(FILES)
clean:
$(RM) -f $(TARGET) $(FILES)

154
ia64/config.c Normal file
View file

@ -0,0 +1,154 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
* ELILO is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* ELILO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ELILO; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Please check out the elilo.txt for complete documentation on how
* to use this program.
*/
#include <efi.h>
#include <efilib.h>
#include "elilo.h"
#include "config.h"
#include "private.h"
#include "sysdeps.h"
#include "getopt.h"
typedef struct {
CHAR16 fpswa[FILENAME_MAXLEN];
CHAR16 cmd_fpswa[FILENAME_MAXLEN];
UINTN allow_relocation;
} ia64_global_config_t;
#define ia64_opt_offsetof(option) (&((sys_img_options_t *)(0x0))->option)
static ia64_global_config_t ia64_gconf;
/*
* No IA-64 specific options at this point
* The last entry in each table MUST be use the OPT_NULL type to terminate
* the chain.
*/
config_option_t sysdeps_global_options[]={
{OPT_FILE, OPT_GLOBAL, L"fpswa", NULL, NULL, ia64_gconf.fpswa},
{OPT_BOOL, OPT_GLOBAL, L"relocatable", NULL, NULL, &ia64_gconf.allow_relocation},
};
config_option_t sysdeps_image_options[]={
{OPT_BOOL, OPT_IMAGE_SYS, L"relocatable", NULL, NULL, ia64_opt_offsetof(allow_relocation)},
};
/*
* IA-64 operations that need to be done only once and just before
* entering the main loop of the loader
* Return:
* 0 if sucessful
* -1 otherwise (will abort execution)
*/
INTN
sysdeps_preloop_actions(EFI_HANDLE dev, CHAR16 **argv, INTN argc, INTN index, EFI_HANDLE image)
{
/*
* we have separate string to make sure that the command line take precedence over
* the config file
*/
if (ia64_gconf.cmd_fpswa[0] != CHAR_NULL) {
check_fpswa(image, dev, ia64_gconf.cmd_fpswa);
} else if (ia64_gconf.fpswa[0] != CHAR_NULL)
check_fpswa(image, dev, ia64_gconf.fpswa);
else
check_fpswa(image, dev, NULL);
return 0;
}
/*
* Return:
* 1: if image or global configuration allows relocation
* 0: otherwise
*
* It is written has a function rather than a macro to avoid
* exposing config data structure to the rest of the code in ia64
*/
INTN
ia64_can_relocate(VOID)
{
return ia64_gconf.allow_relocation == TRUE
|| (elilo_opt.sys_img_opts && elilo_opt.sys_img_opts->allow_relocation ==TRUE) ? 1 : 0;
}
#define IA64_CMDLINE_OPTIONS L"rF:"
CHAR16 *
sysdeps_get_cmdline_opts(VOID)
{
return IA64_CMDLINE_OPTIONS;
}
INTN
sysdeps_getopt(INTN c, INTN optind, CHAR16 *optarg)
{
INTN ret = 0; /* let's be optimistic ! */
/*
* XXX: for now these command line options have to be global
*/
switch(c) {
case L'r':
ia64_gconf.allow_relocation = 1;
break;
case L'F':
if (StrLen(Optarg) >= FILENAME_MAXLEN) {
Print(L"FPSWA filename is limited to %d characters\n", FILENAME_MAXLEN);
return -1;
}
StrCpy(ia64_gconf.cmd_fpswa, Optarg);
break;
default:
ret = -1;
}
return ret;
}
VOID
sysdeps_print_cmdline_opts(VOID)
{
Print(L"-r kernel image can be relocated if load address inexistent\n");
Print(L"-F file name of a specific FPSWA EFI driver to load\n");
}
INTN
sysdeps_register_options(VOID)
{
INTN ret;
ret = register_config_options(sysdeps_global_options,
sizeof(sysdeps_global_options)/sizeof(config_option_t),
OPTIONS_GROUP_GLOBAL);
if (ret == -1 ) return ret;
ret = register_config_options(sysdeps_image_options,
sizeof(sysdeps_image_options)/sizeof(config_option_t),
OPTIONS_GROUP_IMAGE);
return ret;
}

167
ia64/fpswa.c Normal file
View file

@ -0,0 +1,167 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
* ELILO is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* ELILO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ELILO; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Please check out the elilo.txt for complete documentation on how
* to use this program.
*/
#include <efi.h>
#include <efilib.h>
#include "elilo.h"
#include "fileops.h"
typedef struct {
UINT32 revision;
UINT32 reserved;
VOID *fpswa;
} fpswa_interface_t;
INTN
query_fpswa(VOID **fpswa)
{
EFI_HANDLE fpswa_image;
UINTN size;
EFI_STATUS status;
EFI_GUID FpswaProtocol = FPSWA_PROTOCOL;
DBG_PRT((L"Querying FpswaProtocol"));
size = sizeof(EFI_HANDLE);
status = BS->LocateHandle(ByProtocol, &FpswaProtocol, NULL, &size, &fpswa_image);
if (EFI_ERROR(status)) {
ERR_PRT((L"boot_params could not locate FPSWA driver", status));
return -1;
}
status = BS->HandleProtocol(fpswa_image, &FpswaProtocol, fpswa);
if (EFI_ERROR(status)) {
ERR_PRT((L"boot_params FpswaProtocol not able find the interface"));
return -1;
}
VERB_PRT(3, Print(L"FpswaProtocol = 0x%lx revision=%x\n", *fpswa,
((fpswa_interface_t *)*fpswa)->revision));
return 0;
}
static INTN
do_check_fpswa(EFI_HANDLE image, EFI_HANDLE dev, CHAR16 *fpswa_file)
{
EFI_STATUS status;
EFI_HANDLE handle;
EFI_DEVICE_PATH *dp;
dp = FileDevicePath(dev, fpswa_file);
if (dp == NULL) {
ERR_PRT((L"Cannot create FilePath for %s", fpswa_file));
return -1;
}
status = BS->LoadImage(0, image, dp, NULL, 0, &handle);
if (EFI_ERROR(status)) {
VERB_PRT(3, Print(L"..not found\n"));
FreePool(dp);
return -1;
}
VERB_PRT(3, Print(L"..starting.."));
status = BS->StartImage(handle, 0, 0);
if (EFI_ERROR(status)) {
VERB_PRT(3, Print(L"failed (%r)\n", status));
/*
* StartImage() automatically unloads if error
* FPSWA init code will automatically abort if newer revision
* is already installed
*/
} else {
VERB_PRT(3, Print(L"..ok\n"));
}
FreePool(dp);
return 0;
}
/*
* If the caller specifies a fpswa filename, then it used instead of the
* defaults.
* Return:
* 0 : indicates that one fpswa driver was loaded, i.e. an update could be done
* -1: no update was found that would have a more recent version of the driver. This is
* not a fatal return value.
*/
INTN
check_fpswa(EFI_HANDLE image, EFI_HANDLE dev, CHAR16 *fpswa_file)
{
/*
* we must use \\ here as this is given to LoadImage() directly
*
* The FPSWA driver MUST be called fpswa.efi and the FPSWA document
* (see developer.intel.com/design/itanium) stipulates that the
* file must be placed in \EFI\Intel Firmware\ (no mention of which
* EFI system partition). So elilo will check on all accessible
* Fat32+ partition for the existence of this directory and file.
*/
static CHAR16 *fpswa_filenames[] ={
L"\\efi\\intel firmware\\fpswa.efi",
#if 0
L"\\fpswa.efi",
L"\\fw\\fpswa.efi",
L"\\efi\\fpswa.efi",
L"\\efi\\tools\\fpswa.efi",
L"\\fpswa.efi",
L"fpswa.efi",
#endif
};
UINTN j, count = sizeof(fpswa_filenames)/sizeof(CHAR16 *);
INTN cookie;
CHAR16 devname[FILENAME_MAXLEN];
if (fpswa_file) {
INTN r;
devname[0] = CHAR_NULL;
r = fops_split_path(fpswa_file, devname);
if (r == -1) {
ERR_PRT((L"FPSWA driver filename too long %s", fpswa_file));
return -1;
}
if (devname[0] != CHAR_NULL) {
if (fops_get_device_handle(devname, &dev) != EFI_SUCCESS) {
ERR_PRT((L"cannot find device %s for FPSWA driver", devname));
return -1;
}
}
return do_check_fpswa(image, dev, fpswa_file);
}
cookie = 0;
while (fops_get_next_device(cookie, L"vfat", FILENAME_MAXLEN, &cookie, devname, &dev) == EFI_SUCCESS) {
for (j = 0; j < count; j++) {
VERB_PRT(3, Print(L"Trying FPSWA driver %s:%s..", devname, fpswa_filenames[j]));
/*
* we need to do all choices to make sure we pickup
* the latest version.
*/
do_check_fpswa(image, dev, fpswa_filenames[j]);
}
}
return -1;
}

651
ia64/gzip.c Normal file
View file

@ -0,0 +1,651 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* Copyright (C) 2001 Silicon Graphics, Inc.
* Contributed by Brent Casavant <bcasavan@sgi.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
* ELILO is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* ELILO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ELILO; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Please check out the elilo.txt for complete documentation on how
* to use this program.
*/
#include <efi.h>
#include <efilib.h>
#include "elf.h"
#include "elilo.h"
#include "gzip.h"
#include "private.h"
#include "setjmp.h"
#define memzero(s, n) Memset((VOID *)(s), 0, (n))
#define memcpy(a,b,n) Memcpy((VOID *)(a),(b),(n))
/* size of output buffer */
#define WSIZE 0x8000 /* Window size must be at least 32k, */
/* and a power of two */
/* size of input buffer */
#define INBUFSIZE 0x8000
/*
* gzip declarations
*/
#define OF(args) args
#define FUNC_STATIC static
typedef unsigned char uch;
typedef unsigned short ush;
typedef unsigned long ulg;
typedef struct segment {
unsigned long addr; /* start address */
unsigned long offset; /* file offset */
unsigned long size; /* file size */
unsigned long bss_sz; /* BSS size */
UINT8 flags; /* indicates whether to load or not */
} segment_t;
#define CHUNK_FL_VALID 0x1
#define CHUNK_FL_LOAD 0x2
#define CHUNK_CAN_LOAD(n) chunks[(n)].flags |= CHUNK_FL_LOAD
#define CHUNK_NO_LOAD(n) chunks[(n)].flags &= ~CHUNK_FL_LOAD
#define CHUNK_IS_LOAD(n) (chunks[(n)].flags & CHUNK_FL_LOAD)
#define CHUNK_VALIDATE(n) chunks[(n)].flags |= CHUNK_FL_VALID
#define CHUNK_INVALIDATE(n) chunks[(n)].flags = 0
#define CHUNK_IS_VALID(n) (chunks[(n)].flags & CHUNK_FL_VALID)
/*
* static parameters to gzip helper functions
* we cannot use paramters because API was not
* designed that way
*/
static segment_t *chunks; /* holds the list of segments */
static segment_t *cur_chunk;
static UINTN nchunks;
static UINTN chunk; /* current segment */
static UINTN input_fd;
static VOID *kernel_entry, *kernel_base, *kernel_end;
static uch *inbuf; /* input buffer (compressed data) */
static uch *window; /* output buffer (uncompressed data) */
static unsigned long file_offset; /* position in the file */
static unsigned insize = 0; /* valid bytes in inbuf */
static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
static unsigned outcnt = 0; /* bytes in output buffer */
/* gzip flag byte */
#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
#define COMMENT 0x10 /* bit 4 set: file comment present */
#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
#define RESERVED 0xC0 /* bit 6,7: reserved */
#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
/* Diagnostic functions */
#ifdef INFLATE_DEBUG
# define Assert(cond,msg) {if(!(cond)) error(msg);}
int stderr;
# define Trace(x) Print(L"line %d:\n", __LINE__);
# define Tracev(x) {if (verbose) Print(L"line %d:\n", __LINE__) ;}
# define Tracevv(x) {if (verbose>1) Print(L"line %d:\n", __LINE__) ;}
# define Tracec(c,x) {if (verbose && (c)) Print(L"line %d:\n", __LINE__) ;}
# define Tracecv(c,x) {if (verbose>1 && (c)) Print(L"line %d:\n", __LINE__) ;}
#else
# define Assert(cond,msg)
# define Trace(x)
# define Tracev(x)
# define Tracevv(x)
# define Tracec(c,x)
# define Tracecv(c,x)
#endif
static int fill_inbuf(void);
static void flush_window(void);
static void error(char *m);
static long bytes_out;
static void error(char *m);
static jmp_buf jbuf;
static int error_return;
static UINTN elf_is_big_endian; /* true if ELF file is big endian */
static void *
gzip_malloc(int size)
{
return (void *)alloc(size, 0);
}
static void
gzip_free(void *where)
{
return free(where);
}
#include "inflate.c"
/*
* Fill the input buffer and return the first byte in it. This is called
* only when the buffer is empty and at least one byte is really needed.
*/
int
fill_inbuf(void)
{
INTN expected, nread;
EFI_STATUS status;
expected = nread = INBUFSIZE;
status = fops_read(input_fd, inbuf, &nread);
if (EFI_ERROR(status)) {
error("elilo: Read failed");
}
DBG_PRT((L"%s : read %d bytes of %d bytes\n", LD_NAME, nread, expected));
insize = nread;
inptr = 1;
return inbuf[0];
}
/* ===========================================================================
* Write the output window window[0..outcnt-1] and update crc and bytes_out.
* (Used for the decompressed data only.)
*/
/*
* Run a set of bytes through the crc shift register. If s is a NULL
* pointer, then initialize the crc shift register contents instead.
* Return the current crc in either case.
*
* Input:
* S pointer to bytes to pump through.
* N number of bytes in S[].
*/
unsigned long
updcrc(unsigned char *s, unsigned n)
{
register unsigned long c;
/* crc is defined in inflate.c */
if (!s) {
c = 0xffffffffL;
} else {
c = crc;
while (n--) {
c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
}
}
crc = c;
return c ^ 0xffffffffUL; /* (instead of ~c for 64-bit machines) */
}
/*
* Clear input and output buffers
*/
void
clear_bufs(void)
{
outcnt = 0;
inptr = 0;
chunk = 0;
cur_chunk = NULL;
file_offset = 0;
}
static inline UINT64
bswap64(UINT64 v)
{
if(elf_is_big_endian) v = __ia64_swab64(v);
return v;
}
static inline UINT32
bswap32(UINT32 v)
{
if(elf_is_big_endian) v = __ia64_swab32(v);
return v;
}
static inline UINT16
bswap16(UINT16 v)
{
if(elf_is_big_endian) v = __ia64_swab16(v);
return v;
}
static INTN
is_valid_header(Elf64_Ehdr *ehdr)
{
UINT16 type, machine;
if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
type = __ia64_swab16(ehdr->e_type);
machine = __ia64_swab16(ehdr->e_machine);
} else {
type = ehdr->e_type;
machine = ehdr->e_machine;
}
VERB_PRT(3, Print(L"class=%d type=%d data=%d machine=%d\n",
ehdr->e_ident[EI_CLASS],
type,
ehdr->e_ident[EI_DATA],
machine));
return ehdr->e_ident[EI_MAG0] == 0x7f
&& ehdr->e_ident[EI_MAG1] == 'E'
&& ehdr->e_ident[EI_MAG2] == 'L'
&& ehdr->e_ident[EI_MAG3] == 'F'
&& ehdr->e_ident[EI_CLASS] == ELFCLASS64
&& type == ET_EXEC /* must be executable */
&& machine == EM_IA_64 ? 0 : -1;
}
/*
* will invalidate loadble segments which overlap with others
*/
void
check_overlap(int i)
{
int j;
unsigned long iend = chunks[i].addr + chunks[i].size;
for(j=0; j < nchunks; j++) {
if (j ==i) continue;
if (chunks[i].addr >= chunks[j].addr && iend < (chunks[j].addr + chunks[j].size)) {
DBG_PRT((L"%s : segment %d fully included in segment %d\n", LD_NAME, i, j));
CHUNK_INVALIDATE(i); /* nullyify segment */
break;
}
}
}
void
analyze_chunks(void)
{
INTN i;
for(i=0; i < nchunks; i++) {
if (CHUNK_IS_VALID(i) && !CHUNK_IS_LOAD(i)) check_overlap(i);
}
}
/*
* The decompression code calls this function after decompressing the
* first block of the object file. The first block must contain all
* the relevant header information.
*/
int
first_block (const char *buf, long blocksize)
{
Elf64_Ehdr *elf;
Elf64_Phdr *phdrs;
UINTN total_size, pages;
UINTN low_addr, max_addr;
UINTN load_offset = 0;
UINTN offs = 0;
UINT16 phnum;
UINTN paddr, memsz;
INTN i;
elf = (Elf64_Ehdr *)buf;
if (is_valid_header(elf) == -1) return -1;
/* determine file endianess */
elf_is_big_endian = elf->e_ident[EI_DATA] == ELFDATA2MSB ? 1 : 0;
offs = bswap64(elf->e_phoff);
phnum = bswap16(elf->e_phnum);
VERB_PRT(3, {
Print(L"ELF file is %s\n", elf_is_big_endian ? L"big endian" : L"little endian");
Print(L"Entry point 0x%lx\n", bswap64(elf->e_entry));
Print(L"%d program headers\n", phnum);
Print(L"%d segment headers\n", bswap16(elf->e_shnum));
});
/* XXX: need to check on this */
if (offs + phnum * sizeof(*phdrs) > (unsigned) blocksize) {
ERR_PRT((L"%s : ELF program headers not in first block (%ld)\n", LD_NAME, offs));
return -1;
}
kernel_entry = (void *)bswap64(elf->e_entry);
if (((UINTN)kernel_entry >> 61) != 0) {
ERR_PRT((L"%s: <<ERROR>> entry point is a virtual address 0x%lx : not supported anymore\n", LD_NAME, kernel_entry));
}
phdrs = (Elf64_Phdr *) (buf + offs);
low_addr = ~0;
max_addr = 0;
/*
* allocate chunk table
* Convention: a segment that does not need loading will
* have chunk[].addr = 0.
*/
chunks = (void *)alloc(sizeof(struct segment)*phnum, 0);
if (chunks == NULL) {
ERR_PRT((L"%s : failed alloc chunks %r\n", LD_NAME));
return -1;
}
nchunks = phnum;
/*
* find lowest and higest virtual addresses
* don't assume FULLY sorted !
*/
for (i = 0; i < phnum; ++i) {
/*
* record chunk no matter what because no load may happen
* anywhere in archive, not just as the last segment
*/
paddr = bswap64(phdrs[i].p_paddr);
memsz = bswap64(phdrs[i].p_memsz),
chunks[i].addr = paddr;
chunks[i].offset = bswap64(phdrs[i].p_offset);
chunks[i].size = bswap64(phdrs[i].p_filesz);
chunks[i].bss_sz = bswap64(phdrs[i].p_memsz) - bswap64(phdrs[i].p_filesz);
CHUNK_VALIDATE(i);
if (bswap32(phdrs[i].p_type) != PT_LOAD) {
CHUNK_NO_LOAD(i); /* mark no load chunk */
DBG_PRT((L"%s : skipping segment %ld\n", LD_NAME, i));
continue;
}
CHUNK_CAN_LOAD(i); /* mark no load chunk */
VERB_PRT(3,
Print(L"\n%s : segment %ld vaddr [0x%lx-0x%lx] offset %ld filesz %ld memsz=%ld bss_sz=%ld\n",
LD_NAME,
1+i,
chunks[i].addr,
chunks[i].addr+bswap64(phdrs[i].p_filesz),
chunks[i].offset,
chunks[i].size,
memsz,
chunks[i].bss_sz));
if (paddr < low_addr) low_addr = paddr;
if (paddr + memsz > max_addr) max_addr = paddr + memsz;
}
if (low_addr & (EFI_PAGE_SIZE - 1)) {
ERR_PRT((L"%s : low_addr not page aligned 0x%lx\n", LD_NAME, low_addr));
goto error;
}
analyze_chunks();
DBG_PRT((L"%s : %d program headers entry=0x%lx\nlowest_addr=0x%lx highest_addr=0x%lx\n",
LD_NAME,
phnum, kernel_entry, low_addr, max_addr));
total_size = (UINTN)max_addr - (UINTN)low_addr;
pages = EFI_SIZE_TO_PAGES(total_size);
/*
* Record end of kernel for initrd
*/
kernel_base = (void *)low_addr;
kernel_end = (void *)(low_addr + (pages << EFI_PAGE_SHIFT));
/* allocate memory for the kernel */
if (alloc_kmem((void *)low_addr, pages) == -1) {
VOID *new_addr;
ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
if (ia64_can_relocate() == 0) {
ERR_PRT((L"relocation is disabled, cannot load kernel"));
goto error;
}
/*
* could not allocate at requested spot, try to find a
* suitable location to relocate the kernel
*
* The maximum sized Itanium TLB translation entry is 256 MB.
* If we relocate the kernel by this amount we know for sure
* that alignment constraints will be satisified, regardless
* of the kernel used.
*/
VERB_PRT(1, Print(L"Attempting to relocate kernel.\n"));
if (find_kernel_memory((VOID*) low_addr, (VOID*) max_addr, 256*MB, &new_addr) == -1) {
ERR_PRT((L"%s : find_kernel_memory(0x%lx, 0x%lx, 0x%lx, 0x%lx) failed\n", LD_NAME, low_addr, max_addr, 256*MB, &load_offset));
goto error;
}
/* unsigned arithmetic */
load_offset = (UINTN) (new_addr - ROUNDDOWN((UINTN) low_addr,256*MB));
ERR_PRT((L"low_addr=0x%lx new_addr=0x%lx offset=0x%lx", low_addr, new_addr, load_offset));
/*
* correct various addresses for non-zero load_offset
*/
kernel_base = (void *) ((UINTN) kernel_base + load_offset);
kernel_end = (void *) ((UINTN) kernel_end + load_offset);
kernel_entry = (void*) ((UINTN) kernel_entry + load_offset);
for (i = 0; i < phnum; ++i) {
chunks[i].addr += load_offset;
phdrs[i].p_paddr = (Elf64_Addr) ((UINT64) phdrs[i].p_paddr + load_offset);
}
/*
* try one last time to get memory for the kernel
*/
if (alloc_kmem((void *)low_addr+load_offset, pages) == -1) {
ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr+load_offset));
ERR_PRT((L"Relocation by 0x%lx bytes failed.\n", load_offset));
goto error;
}
}
return 0;
error:
if (chunks) free(chunks);
return -1;
}
/*
* Determine which chunk in the Elf file will be coming out of the expand
* code next.
*/
static void
nextchunk(void)
{
int i;
segment_t *cp;
cp = NULL;
for(i=0; i < nchunks; i++) {
if (!CHUNK_IS_VALID(i) || !CHUNK_IS_LOAD(i)) continue;
if (file_offset > chunks[i].offset) continue;
if (cp == NULL || chunks[i].offset < cp->offset) cp = &chunks[i];
}
cur_chunk = cp;
}
/*
* Write the output window window[0..outcnt-1] holding uncompressed
* data and update crc.
*/
void
flush_window(void)
{
static const CHAR8 helicopter[4] = { '|' , '/' , '-' , '\\' };
static UINTN heli_count;
struct segment *cp;
char *src, *dst;
long cnt;
if (!outcnt) return;
DBG_PRT((L"%s : flush_window outnct=%d file_offset=%ld\n", LD_NAME, outcnt, file_offset));
Print(L"%c\b",helicopter[heli_count++%4]);
updcrc(window, outcnt);
/*
* first time, we extract the headers
*/
if (!bytes_out) {
if (first_block(window, outcnt) < 0) error("invalid exec header");
nextchunk();
}
bytes_out += outcnt;
src = window;
tail:
/* check if user wants to abort */
if (check_abort() == EFI_SUCCESS) goto load_abort;
cp = cur_chunk;
if (cp == NULL || file_offset + outcnt <= cp->offset) {
file_offset += outcnt;
return;
}
// Does this window begin before the current chunk?
if (file_offset < cp->offset) {
unsigned long skip = cp->offset - file_offset;
src += skip;
file_offset += skip;
outcnt -= skip;
}
dst = (char *)cp->addr + (file_offset - cp->offset);
cnt = cp->offset + cp->size - file_offset;
if (cnt > outcnt) cnt = outcnt;
Memcpy(dst, src, cnt);
file_offset += cnt;
outcnt -= cnt;
src += cnt;
/* See if we are at the end of this chunk */
if (file_offset == cp->offset + cp->size) {
if (cp->bss_sz) {
dst = (char *)cp->addr + cp->size;
Memset(dst, 0, cp->bss_sz);
}
nextchunk();
/* handle remaining bytes */
if (outcnt) goto tail;
}
return;
load_abort:
free_kmem();
error_return = ELILO_LOAD_ABORTED;
longjmp(jbuf, 1);
}
static void
error(char *x)
{
ERR_PRT((L"%s : %a", LD_NAME, x));
/* will eventually exit with error from gunzip() */
longjmp(jbuf,1);
}
INT32
decompress_kernel(VOID)
{
INT32 ret;
clear_bufs();
makecrc();
Print(L"Uncompressing Linux... ");
ret = gunzip();
if (ret == 0) Print(L"done\n");
return ret == 0 ? 0 : -1;
}
int
gunzip_kernel(fops_fd_t fd, kdesc_t *kd)
{
int ret = -1;
error_return = ELILO_LOAD_ERROR;
window = (void *)alloc(WSIZE, 0);
if (window == NULL) {
ERR_PRT((L"%s : allocate output window failed\n", LD_NAME));
return -1;
}
inbuf = (void *)alloc(INBUFSIZE, 0);
if (inbuf == NULL) {
ERR_PRT((L"%s : allocate input window failedr\n", LD_NAME));
goto error;
}
input_fd = fd;
insize = 0;
bytes_out = 0;
if (setjmp(jbuf) == 1) goto error;
ret = decompress_kernel();
error:
if (window) free(window);
if (inbuf) free(inbuf);
if (ret == 0) {
kd->kentry = kernel_entry;
kd->kend = kernel_end;
kd->kstart = kernel_base;
error_return = ELILO_LOAD_SUCCESS;
}
return error_return;
}

35
ia64/gzip.h Normal file
View file

@ -0,0 +1,35 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
* ELILO is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* ELILO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ELILO; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Please check out the elilo.txt for complete documentation on how
* to use this program.
*/
#ifndef __GZIP_H__
#define __GZIP_H__
int gzip_probe(unsigned char *, unsigned long);
int gunzip_kernel(fops_fd_t, kdesc_t *);
#define LD_NAME L"gzip_ia64"
#endif /* __GZIP_H__ */

79
ia64/gzip_loader.c Normal file
View file

@ -0,0 +1,79 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
* ELILO is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* ELILO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ELILO; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Please check out the elilo.txt for complete documentation on how
* to use this program.
*/
#include <efi.h>
#include <efilib.h>
#include "elilo.h"
#include "loader.h"
#include "gzip.h"
static INTN
gzip_probe_format(CHAR16 *kname)
{
UINT8 buf[4];
EFI_STATUS status;
INTN ret = -1;
UINTN size;
fops_fd_t fd;
status = fops_open(kname, &fd);
if (EFI_ERROR(status)) return -1;
size = sizeof(buf);
status = fops_read(fd, buf, &size);
if (EFI_ERROR(status) || size != sizeof(buf)) goto error;
ret = gzip_probe(buf, sizeof(buf));
error:
fops_close(fd);
return ret;
}
static INTN
gzip_load_kernel(CHAR16 *kname, kdesc_t *kd)
{
EFI_STATUS status;
INT32 ret;
fops_fd_t fd;
status = fops_open(kname, &fd);
if (EFI_ERROR(status)) return ELILO_LOAD_ERROR;
ret = gunzip_kernel(fd, kd);
fops_close(fd);
return ret; /* could be success, error, or abort */
}
loader_ops_t gzip_loader={
NULL,
LD_NAME,
gzip_probe_format,
gzip_load_kernel
};

1204
ia64/inflate.c Normal file

File diff suppressed because it is too large Load diff

162
ia64/longjmp.S Normal file
View file

@ -0,0 +1,162 @@
/* Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
Note that __sigsetjmp() did NOT flush the register stack. Instead,
we do it here since __longjmp() is usually much less frequently
invoked than __sigsetjmp(). The only difficulty is that __sigsetjmp()
didn't (and wouldn't be able to) save ar.rnat either. This is a problem
because if we're not careful, we could end up loading random NaT bits.
There are two cases:
(i) ar.bsp < ia64_rse_rnat_addr(jmpbuf.ar_bsp)
ar.rnat contains the desired bits---preserve ar.rnat
across loadrs and write to ar.bspstore
(ii) ar.bsp >= ia64_rse_rnat_addr(jmpbuf.ar_bsp)
The desired ar.rnat is stored in
ia64_rse_rnat_addr(jmpbuf.ar_bsp). Load those
bits into ar.rnat after setting ar.bspstore. */
# define pPos p6 /* is rotate count positive? */
# define pNeg p7 /* is rotate count negative? */
/* __longjmp(__jmp_buf buf, int val) */
.text
.global longjmp
.proc longjmp
longjmp:
alloc r8=ar.pfs,2,1,0,0
mov r27=ar.rsc
add r2=0x98,in0 // r2 <- &jmpbuf.orig_jmp_buf_addr
;;
ld8 r8=[r2],-16 // r8 <- orig_jmp_buf_addr
mov r10=ar.bsp
and r11=~0x3,r27 // clear ar.rsc.mode
;;
flushrs // flush dirty regs to backing store (must be first in insn grp)
ld8 r23=[r2],8 // r23 <- jmpbuf.ar_bsp
sub r8=r8,in0 // r8 <- &orig_jmpbuf - &jmpbuf
;;
ld8 r25=[r2] // r25 <- jmpbuf.ar_unat
extr.u r8=r8,3,6 // r8 <- (&orig_jmpbuf - &jmpbuf)/8 & 0x3f
;;
cmp.lt pNeg,pPos=r8,r0
mov r2=in0
;;
(pPos) mov r16=r8
(pNeg) add r16=64,r8
(pPos) sub r17=64,r8
(pNeg) sub r17=r0,r8
;;
mov ar.rsc=r11 // put RSE in enforced lazy mode
shr.u r8=r25,r16
add r3=8,in0 // r3 <- &jmpbuf.r1
shl r9=r25,r17
;;
or r25=r8,r9
;;
mov r26=ar.rnat
mov ar.unat=r25 // setup ar.unat (NaT bits for r1, r4-r7, and r12)
;;
ld8.fill.nta sp=[r2],16 // r12 (sp)
ld8.fill.nta gp=[r3],16 // r1 (gp)
dep r11=-1,r23,3,6 // r11 <- ia64_rse_rnat_addr(jmpbuf.ar_bsp)
;;
ld8.nta r16=[r2],16 // caller's unat
ld8.nta r17=[r3],16 // fpsr
;;
ld8.fill.nta r4=[r2],16 // r4
ld8.fill.nta r5=[r3],16 // r5 (gp)
cmp.geu p8,p0=r10,r11 // p8 <- (ar.bsp >= jmpbuf.ar_bsp)
;;
ld8.fill.nta r6=[r2],16 // r6
ld8.fill.nta r7=[r3],16 // r7
;;
mov ar.unat=r16 // restore caller's unat
mov ar.fpsr=r17 // restore fpsr
;;
ld8.nta r16=[r2],16 // b0
ld8.nta r17=[r3],16 // b1
;;
(p8) ld8 r26=[r11] // r26 <- *ia64_rse_rnat_addr(jmpbuf.ar_bsp)
mov ar.bspstore=r23 // restore ar.bspstore
;;
ld8.nta r18=[r2],16 // b2
ld8.nta r19=[r3],16 // b3
;;
ld8.nta r20=[r2],16 // b4
ld8.nta r21=[r3],16 // b5
;;
ld8.nta r11=[r2],16 // ar.pfs
ld8.nta r22=[r3],56 // ar.lc
;;
ld8.nta r24=[r2],32 // pr
mov b0=r16
;;
ldf.fill.nta f2=[r2],32
ldf.fill.nta f3=[r3],32
mov b1=r17
;;
ldf.fill.nta f4=[r2],32
ldf.fill.nta f5=[r3],32
mov b2=r18
;;
ldf.fill.nta f16=[r2],32
ldf.fill.nta f17=[r3],32
mov b3=r19
;;
ldf.fill.nta f18=[r2],32
ldf.fill.nta f19=[r3],32
mov b4=r20
;;
ldf.fill.nta f20=[r2],32
ldf.fill.nta f21=[r3],32
mov b5=r21
;;
ldf.fill.nta f22=[r2],32
ldf.fill.nta f23=[r3],32
mov ar.lc=r22
;;
ldf.fill.nta f24=[r2],32
ldf.fill.nta f25=[r3],32
cmp.eq p8,p9=0,in1
;;
ldf.fill.nta f26=[r2],32
ldf.fill.nta f27=[r3],32
mov ar.pfs=r11
;;
ldf.fill.nta f28=[r2],32
ldf.fill.nta f29=[r3],32
;;
ldf.fill.nta f30=[r2]
ldf.fill.nta f31=[r3]
(p8) mov r8=1
mov ar.rnat=r26 // restore ar.rnat
;;
mov ar.rsc=r27 // restore ar.rsc
(p9) mov r8=in1
invala // virt. -> phys. regnum mapping may change
mov pr=r24,-1
br.ret.dptk.few rp
.endp __longjmp

339
ia64/memcpy.S Normal file
View file

@ -0,0 +1,339 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
* ELILO is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* ELILO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ELILO; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Please check out the elilo.txt for complete documentation on how
* to use this program.
*
* This file is derived from the Linux/ia64 kernel source code
*/
/*
*
* Optimized version of the standard memcpy() function
*
* Inputs:
* in0: destination address
* in1: source address
* in2: number of bytes to copy
* Output:
* no return value
*
* Copyright (C) 2000 Hewlett-Packard Co
* Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
* Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
*/
/* be pessimistic for now... */
#define CONFIG_ITANIUM_B0_SPECIFIC 1
#if defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)
# define BRP(args...) nop.b 0
#else
# define BRP(args...) brp.loop.imp args
#endif
.text
// FALL THROUGH
.global Memcpy
.proc Memcpy
Memcpy:
# define MEM_LAT 21 /* latency to memory */
# define dst r2
# define src r3
# define retval r8
# define saved_pfs r9
# define saved_lc r10
# define saved_pr r11
# define cnt r16
# define src2 r17
# define t0 r18
# define t1 r19
# define t2 r20
# define t3 r21
# define t4 r22
# define src_end r23
# define N (MEM_LAT + 4)
# define Nrot ((N + 7) & ~7)
/*
* First, check if everything (src, dst, len) is a multiple of eight. If
* so, we handle everything with no taken branches (other than the loop
* itself) and a small icache footprint. Otherwise, we jump off to
* the more general copy routine handling arbitrary
* sizes/alignment etc.
*/
.prologue
.save ar.pfs, saved_pfs
alloc saved_pfs=ar.pfs,3,Nrot,0,Nrot
.save ar.lc, saved_lc
mov saved_lc=ar.lc
or t0=in0,in1
;;
or t0=t0,in2
.save pr, saved_pr
mov saved_pr=pr
.body
cmp.eq p6,p0=in2,r0 // zero length?
mov retval=in0 // return dst
(p6) br.ret.spnt.many rp // zero length, return immediately
;;
mov dst=in0 // copy because of rotation
shr.u cnt=in2,3 // number of 8-byte words to copy
mov pr.rot=1<<16
;;
adds cnt=-1,cnt // br.ctop is repeat/until
cmp.gtu p7,p0=16,in2 // copying less than 16 bytes?
mov ar.ec=N
;;
and t0=0x7,t0
mov ar.lc=cnt
;;
cmp.ne p6,p0=t0,r0
mov src=in1 // copy because of rotation
(p7) br.cond.spnt.few memcpy_short
(p6) br.cond.spnt.few memcpy_long
;;
nop.m 0
;;
nop.m 0
nop.i 0
;;
nop.m 0
;;
.rotr val[N]
.rotp p[N]
.align 32
1: { .mib
(p[0]) ld8 val[0]=[src],8
nop.i 0
BRP(1b, 2f)
}
2: { .mfb
(p[N-1])st8 [dst]=val[N-1],8
nop.f 0
br.ctop.dptk.few 1b
}
;;
mov ar.lc=saved_lc
mov pr=saved_pr,-1
mov ar.pfs=saved_pfs
br.ret.sptk.many rp
/*
* Small (<16 bytes) unaligned copying is done via a simple byte-at-the-time
* copy loop. This performs relatively poorly on Itanium, but it doesn't
* get used very often (gcc inlines small copies) and due to atomicity
* issues, we want to avoid read-modify-write of entire words.
*/
.align 32
memcpy_short:
adds cnt=-1,in2 // br.ctop is repeat/until
mov ar.ec=MEM_LAT
BRP(1f, 2f)
;;
mov ar.lc=cnt
;;
nop.m 0
;;
nop.m 0
nop.i 0
;;
nop.m 0
;;
nop.m 0
;;
/*
* It is faster to put a stop bit in the loop here because it makes
* the pipeline shorter (and latency is what matters on short copies).
*/
.align 32
1: { .mib
(p[0]) ld1 val[0]=[src],1
nop.i 0
BRP(1b, 2f)
} ;;
2: { .mfb
(p[MEM_LAT-1])st1 [dst]=val[MEM_LAT-1],1
nop.f 0
br.ctop.dptk.few 1b
} ;;
mov ar.lc=saved_lc
mov pr=saved_pr,-1
mov ar.pfs=saved_pfs
br.ret.sptk.many rp
/*
* Large (>= 16 bytes) copying is done in a fancy way. Latency isn't
* an overriding concern here, but throughput is. We first do
* sub-word copying until the destination is aligned, then we check
* if the source is also aligned. If so, we do a simple load/store-loop
* until there are less than 8 bytes left over and then we do the tail,
* by storing the last few bytes using sub-word copying. If the source
* is not aligned, we branch off to the non-congruent loop.
*
* stage: op:
* 0 ld
* :
* MEM_LAT+3 shrp
* MEM_LAT+4 st
*
* On Itanium, the pipeline itself runs without stalls. However, br.ctop
* seems to introduce an unavoidable bubble in the pipeline so the overall
* latency is 2 cycles/iteration. This gives us a _copy_ throughput
* of 4 byte/cycle. Still not bad.
*/
# undef N
# undef Nrot
# define N (MEM_LAT + 5) /* number of stages */
# define Nrot ((N+1 + 2 + 7) & ~7) /* number of rotating regs */
#define LOG_LOOP_SIZE 6
memcpy_long:
alloc t3=ar.pfs,3,Nrot,0,Nrot // resize register frame
and t0=-8,src // t0 = src & ~7
and t2=7,src // t2 = src & 7
;;
ld8 t0=[t0] // t0 = 1st source word
adds src2=7,src // src2 = (src + 7)
sub t4=r0,dst // t4 = -dst
;;
and src2=-8,src2 // src2 = (src + 7) & ~7
shl t2=t2,3 // t2 = 8*(src & 7)
shl t4=t4,3 // t4 = 8*(dst & 7)
;;
ld8 t1=[src2] // t1 = 1st source word if src is 8-byte aligned, 2nd otherwise
sub t3=64,t2 // t3 = 64-8*(src & 7)
shr.u t0=t0,t2
;;
add src_end=src,in2
shl t1=t1,t3
mov pr=t4,0x38 // (p5,p4,p3)=(dst & 7)
;;
or t0=t0,t1
mov cnt=r0
adds src_end=-1,src_end
;;
(p3) st1 [dst]=t0,1
(p3) shr.u t0=t0,8
(p3) adds cnt=1,cnt
;;
(p4) st2 [dst]=t0,2
(p4) shr.u t0=t0,16
(p4) adds cnt=2,cnt
;;
(p5) st4 [dst]=t0,4
(p5) adds cnt=4,cnt
and src_end=-8,src_end // src_end = last word of source buffer
;;
// At this point, dst is aligned to 8 bytes and there at least 16-7=9 bytes left to copy:
1:{ add src=cnt,src // make src point to remainder of source buffer
sub cnt=in2,cnt // cnt = number of bytes left to copy
mov t4=ip
} ;;
and src2=-8,src // align source pointer
adds t4=memcpy_loops-1b,t4
mov ar.ec=N
and t0=7,src // t0 = src & 7
shr.u t2=cnt,3 // t2 = number of 8-byte words left to copy
shl cnt=cnt,3 // move bits 0-2 to 3-5
;;
.rotr val[N+1], w[2]
.rotp p[N]
cmp.ne p6,p0=t0,r0 // is src aligned, too?
shl t0=t0,LOG_LOOP_SIZE // t0 = 8*(src & 7)
adds t2=-1,t2 // br.ctop is repeat/until
;;
add t4=t0,t4
mov pr=cnt,0x38 // set (p5,p4,p3) to # of bytes last-word bytes to copy
mov ar.lc=t2
;;
nop.m 0
;;
nop.m 0
nop.i 0
;;
nop.m 0
;;
(p6) ld8 val[1]=[src2],8 // prime the pump...
mov b6=t4
br.sptk.few b6
;;
memcpy_tail:
// At this point, (p5,p4,p3) are set to the number of bytes left to copy (which is
// less than 8) and t0 contains the last few bytes of the src buffer:
(p5) st4 [dst]=t0,4
(p5) shr.u t0=t0,32
mov ar.lc=saved_lc
;;
(p4) st2 [dst]=t0,2
(p4) shr.u t0=t0,16
mov ar.pfs=saved_pfs
;;
(p3) st1 [dst]=t0
mov pr=saved_pr,-1
br.ret.sptk.many rp
///////////////////////////////////////////////////////
.align 64
#define COPY(shift,index) \
1: { .mib \
(p[0]) ld8 val[0]=[src2],8; \
(p[MEM_LAT+3]) shrp w[0]=val[MEM_LAT+3],val[MEM_LAT+4-index],shift; \
BRP(1b, 2f) \
}; \
2: { .mfb \
(p[MEM_LAT+4]) st8 [dst]=w[1],8; \
nop.f 0; \
br.ctop.dptk.few 1b; \
}; \
;; \
ld8 val[N-1]=[src_end]; /* load last word (may be same as val[N]) */ \
;; \
shrp t0=val[N-1],val[N-index],shift; \
br memcpy_tail
memcpy_loops:
COPY(0, 1) /* no point special casing this---it doesn't go any faster without shrp */
COPY(8, 0)
COPY(16, 0)
COPY(24, 0)
COPY(32, 0)
COPY(40, 0)
COPY(48, 0)
COPY(56, 0)
.endp Memcpy

133
ia64/memset.S Normal file
View file

@ -0,0 +1,133 @@
/*
* Copyright (C) 1999-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
* ELILO is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* ELILO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ELILO; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Please check out the elilo.txt for complete documentation on how
* to use this program.
*
* This code is derived from the Linux/ia64 source code.
*/
/*
*
* Optimized version of the standard memset() function
*
* Return: none
*
* Inputs:
* in0: address of buffer
* in1: byte value to use for storing
* in2: length of the buffer
*
*/
// arguments
//
#define buf r32
#define val r33
#define len r34
//
// local registers
//
#define saved_pfs r14
#define cnt r18
#define buf2 r19
#define saved_lc r20
#define tmp r21
.text
.global Memset
.proc Memset
Memset:
.prologue
.save ar.pfs, saved_pfs
alloc saved_pfs=ar.pfs,3,0,0,0 // cnt is sink here
cmp.eq p8,p0=r0,len // check for zero length
.save ar.lc, saved_lc
mov saved_lc=ar.lc // preserve ar.lc (slow)
;;
.body
adds tmp=-1,len // br.ctop is repeat/until
tbit.nz p6,p0=buf,0 // odd alignment
(p8) br.ret.spnt.few rp
cmp.lt p7,p0=16,len // if len > 16 then long memset
mux1 val=val,@brcst // prepare value
(p7) br.cond.dptk.few long_memset
;;
mov ar.lc=tmp // initialize lc for small count
;; // avoid RAW and WAW on ar.lc
1: // worst case 15 cyles, avg 8 cycles
st1 [buf]=val,1
br.cloop.dptk.few 1b
;; // avoid RAW on ar.lc
mov ar.lc=saved_lc
mov ar.pfs=saved_pfs
br.ret.sptk.few rp // end of short memset
// at this point we know we have more than 16 bytes to copy
// so we focus on alignment
long_memset:
(p6) st1 [buf]=val,1 // 1-byte aligned
(p6) adds len=-1,len;; // sync because buf is modified
tbit.nz p6,p0=buf,1
;;
(p6) st2 [buf]=val,2 // 2-byte aligned
(p6) adds len=-2,len;;
tbit.nz p6,p0=buf,2
;;
(p6) st4 [buf]=val,4 // 4-byte aligned
(p6) adds len=-4,len;;
tbit.nz p6,p0=buf,3
;;
(p6) st8 [buf]=val,8 // 8-byte aligned
(p6) adds len=-8,len;;
shr.u cnt=len,4 // number of 128-bit (2x64bit) words
;;
cmp.eq p6,p0=r0,cnt
adds tmp=-1,cnt
(p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left
;;
adds buf2=8,buf // setup second base pointer
mov ar.lc=tmp
;;
2: // 16bytes/iteration
st8 [buf]=val,16
st8 [buf2]=val,16
br.cloop.dptk.few 2b
;;
.dotail: // tail correction based on len only
tbit.nz p6,p0=len,3
;;
(p6) st8 [buf]=val,8 // at least 8 bytes
tbit.nz p6,p0=len,2
;;
(p6) st4 [buf]=val,4 // at least 4 bytes
tbit.nz p6,p0=len,1
;;
(p6) st2 [buf]=val,2 // at least 2 bytes
tbit.nz p6,p0=len,0
mov ar.lc=saved_lc
;;
(p6) st1 [buf]=val // only 1 byte left
br.ret.dptk.few rp
.endp Memset

453
ia64/plain_loader.c Normal file
View file

@ -0,0 +1,453 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* Copyright (C) 2001 Silicon Graphics, Inc.
* Contributed by Brent Casavant <bcasavan@sgi.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
* ELILO is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* ELILO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ELILO; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Please check out the elilo.txt for complete documentation on how
* to use this program.
*/
#include <efi.h>
#include <efilib.h>
#include "elilo.h"
#include "loader.h"
#include "elf.h"
#include "private.h"
#define LD_NAME L"plain_elf64"
#define PLAIN_MIN_BLOCK_SIZE sizeof(Elf64_Ehdr) /* see load_elf() for details */
#define SKIPBUFSIZE 2048 /* minimal default size of the skip buffer */
static CHAR8 *skip_buffer; /* used to skip over unneeded data */
static UINTN skip_bufsize;
static UINTN elf_is_big_endian; /* true if ELF file is big endian */
static inline UINT64
bswap64(UINT64 v)
{
if(elf_is_big_endian) v = __ia64_swab64(v);
return v;
}
static inline UINT32
bswap32(UINT32 v)
{
if(elf_is_big_endian) v = __ia64_swab32(v);
return v;
}
static inline UINT16
bswap16(UINT16 v)
{
if(elf_is_big_endian) v = __ia64_swab16(v);
return v;
}
static INTN
is_valid_header(Elf64_Ehdr *ehdr)
{
UINT16 type, machine;
if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
type = __ia64_swab16(ehdr->e_type);
machine = __ia64_swab16(ehdr->e_machine);
} else {
type = ehdr->e_type;
machine = ehdr->e_machine;
}
DBG_PRT((L"class=%d type=%d data=%d machine=%d\n",
ehdr->e_ident[EI_CLASS],
type,
ehdr->e_ident[EI_DATA],
machine));
return ehdr->e_ident[EI_MAG0] == 0x7f
&& ehdr->e_ident[EI_MAG1] == 'E'
&& ehdr->e_ident[EI_MAG2] == 'L'
&& ehdr->e_ident[EI_MAG3] == 'F'
&& ehdr->e_ident[EI_CLASS] == ELFCLASS64
&& type == ET_EXEC /* must be executable */
&& machine == EM_IA_64 ? 0 : -1;
}
static INTN
plain_probe(CHAR16 *kname)
{
Elf64_Ehdr ehdr;
EFI_STATUS status;
INTN ret = -1;
fops_fd_t fd;
UINTN size = sizeof(ehdr);
status = fops_open(kname, &fd);
if (EFI_ERROR(status)) return -1;
status = fops_read(fd, &ehdr, &size);
if (EFI_ERROR(status) || size != sizeof(ehdr)) goto error;
ret = is_valid_header(&ehdr);
error:
fops_close(fd);
return ret;
}
/*
* move skip bytes forward in the file
* this is required because we cannot assume fileops has
* seek() capabilities.
*/
static INTN
skip_bytes(fops_fd_t fd, UINTN curpos, UINTN newpos)
{
EFI_STATUS status;
UINTN n, skip;
skip = newpos - curpos;
/* check if seek capability exists */
status = fops_seek(fd, newpos);
if (status == EFI_SUCCESS) return 0;
if (status != EFI_UNSUPPORTED) goto error;
/* unsupported case */
if (skip_buffer == NULL) {
skip_bufsize = MAX(skip, SKIPBUFSIZE);
skip_buffer= (CHAR8 *)alloc(skip_bufsize, EfiLoaderData);
if (skip_buffer == NULL) return -1;
}
while (skip) {
n = skip > skip_bufsize? skip_bufsize : skip;
status = fops_read(fd, skip_buffer, &n);
if (EFI_ERROR(status)) goto error;
skip -=n;
}
return 0;
error:
ERR_PRT((L"%s : cannot skip %d bytes\n", LD_NAME, n));
return -1;
}
static INTN
load_elf(fops_fd_t fd, kdesc_t *kd)
{
Elf64_Ehdr ehdr;
Elf64_Phdr *phdrs;
EFI_STATUS status;
INTN ret = ELILO_LOAD_ERROR;
UINTN i, total_size = 0;
UINTN pages, size, bss_sz, osize;
UINTN offs = 0;
VOID *low_addr = (VOID *)~0;
VOID *max_addr = (VOID *)0;
UINTN load_offset = 0;
UINTN paddr, memsz, filesz, poffs;
UINT16 phnum;
Print(L"Loading Linux... ");
size = sizeof(ehdr);
status = fops_read(fd, &ehdr, &size);
if (EFI_ERROR(status) ||size < sizeof(ehdr)) return ELILO_LOAD_ERROR;
offs += size;
/*
* do some sanity checking on the file
*/
if (is_valid_header(&ehdr) == -1) {
ERR_PRT((L"%s : not an elf 64-bit file\n", LD_NAME));
return ELILO_LOAD_ERROR;
}
/* determine file endianess */
elf_is_big_endian = ehdr.e_ident[EI_DATA] == ELFDATA2MSB ? 1 : 0;
VERB_PRT(3, {
Print(L"ELF file is %s\n", elf_is_big_endian ? L"big endian" : L"little endian");
Print(L"Entry point 0x%lx\n", bswap64(ehdr.e_entry));
Print(L"%d program headers\n", bswap16(ehdr.e_phnum));
Print(L"%d segment headers\n", bswap16(ehdr.e_shnum));
});
phnum = bswap16(ehdr.e_phnum);
if (skip_bytes(fd, offs, bswap64(ehdr.e_phoff)) != 0) {
ERR_PRT((L"%s : skip tp %ld for phdrs failed", LD_NAME, offs));
return ELILO_LOAD_ERROR;
}
offs = bswap64(ehdr.e_phoff);
size = osize = phnum*sizeof(Elf64_Phdr);
DBG_PRT((L"%s : phdrs allocate %d bytes sizeof=%d entsize=%d\n", LD_NAME, size,sizeof(Elf64_Phdr), bswap16(ehdr.e_phentsize)));
phdrs = (Elf64_Phdr *)alloc(size, 0);
if (phdrs == NULL) {
ERR_PRT((L"%s : allocate phdrs failed", LD_NAME));
return ELILO_LOAD_ERROR;
}
status = fops_read(fd, phdrs, &size);
if (EFI_ERROR(status) || size != osize) {
ERR_PRT((L"%s : load phdrs failed", LD_NAME, status));
goto out;
}
offs += size;
/*
* First pass to figure out:
* - lowest physical address
* - total memory footprint
*/
for (i = 0; i < phnum; i++) {
paddr = bswap64(phdrs[i].p_paddr);
memsz = bswap64(phdrs[i].p_memsz);
DBG_PRT((L"Phdr %d paddr [0x%lx-0x%lx] offset %ld"
" filesz %ld memsz=%ld bss_sz=%ld p_type=%d\n",
1+i,
paddr,
paddr+bswap64(phdrs[i].p_filesz),
bswap64(phdrs[i].p_offset),
bswap64(phdrs[i].p_filesz),
memsz,
memsz - bswap64(phdrs[i].p_filesz), bswap32(phdrs[i].p_type)));
if (bswap32(phdrs[i].p_type) != PT_LOAD) continue;
if (paddr < (UINTN)low_addr) low_addr = (VOID *)paddr;
if (paddr + memsz > (UINTN)max_addr)
max_addr = (VOID *)paddr + memsz;
}
if ((UINTN)low_addr & (EFI_PAGE_SIZE - 1)) {
ERR_PRT((L"%s : kernel low address 0x%lx not page aligned\n", LD_NAME, low_addr));
goto out;
}
/* how many bytes are needed to hold the kernel */
total_size = (UINTN)max_addr - (UINTN)low_addr;
/* round up to get required number of pages */
pages = EFI_SIZE_TO_PAGES(total_size);
/* keep track of location where kernel ends for
* the initrd ramdisk (it will be put right after the kernel)
*/
kd->kstart = low_addr;
kd->kend = low_addr+ (pages << EFI_PAGE_SHIFT);
/*
* that's the kernel entry point (virtual address)
*/
kd->kentry = (VOID *)bswap64(ehdr.e_entry);
if (((UINTN)kd->kentry >> 61) != 0) {
ERR_PRT((L"%s: <<ERROR>> entry point is a virtual address 0x%lx : not supported anymore\n", LD_NAME, kd->kentry));
}
VERB_PRT(3, {
Print(L"Lowest PhysAddr: 0x%lx\nTotalMemSize:%d bytes (%d pages)\n",
low_addr, total_size, pages);
Print(L"Kernel entry @ 0x%lx\n", kd->kentry);
});
/*
* now allocate memory for the kernel at the exact requested spot
*/
if (alloc_kmem(low_addr, pages) == -1) {
VOID *new_addr;
ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
if (ia64_can_relocate() == 0) {
ERR_PRT((L"relocation is disabled, cannot load kernel"));
goto out;
}
/*
* could not allocate at requested spot, try to find a
* suitable location to relocate the kernel
*
* The maximum sized Itanium TLB translation entry is 256 MB.
* If we relocate the kernel by this amount we know for sure
* that alignment constraints will be satisified, regardless
* of the kernel used.
*/
Print(L"Attempting to relocate kernel.\n");
if (find_kernel_memory(low_addr, max_addr, 256*MB, &new_addr) == -1) {
ERR_PRT((L"%s : find_kernel_memory(0x%lx, 0x%lx, 0x%lx, 0x%lx) failed\n", LD_NAME, low_addr, max_addr, 256*MB, &load_offset));
goto out;
}
/* unsigned arithmetic */
load_offset = (UINTN) (new_addr - ROUNDDOWN((UINTN) low_addr,256*MB));
VERB_PRT(3, Print(L"low_addr=0x%lx new_addr=0x%lx offset=0x%lx", low_addr, new_addr, load_offset));
/*
* correct various addesses for non-zero load_offset
*/
low_addr = (VOID*) ((UINTN) low_addr + load_offset);
max_addr = (VOID*) ((UINTN) max_addr + load_offset);
kd->kstart = (VOID *) ((UINTN) kd->kstart + load_offset);
kd->kend = (VOID *) ((UINTN) kd->kend + load_offset);
kd->kentry = (VOID *) ((UINTN) kd->kentry + load_offset);
/*
* try one last time to get memory for the kernel
*/
if (alloc_kmem(low_addr, pages) == -1) {
ERR_PRT((L"%s : AllocatePages(%d, 0x%lx) for kernel failed\n", LD_NAME, pages, low_addr));
ERR_PRT((L"Relocation by 0x%lx bytes failed.\n", load_offset));
goto out;
}
}
VERB_PRT(1, Print(L"Press any key to interrupt\n"));
/* Second pass:
* Walk through the program headers
* and actually load data into physical memory
*/
for (i = 0; i < phnum; i++) {
/*
* Check for pure loadable segment; ignore if not loadable
*/
if (bswap32(phdrs[i].p_type) != PT_LOAD) continue;
poffs = bswap64(phdrs[i].p_offset);
size = poffs - offs;
VERB_PRT(3, Print(L"\noff=%ld poffs=%ld size=%ld\n", offs, poffs, size));
filesz = bswap64(phdrs[i].p_filesz);
/*
* correct p_paddr for non-zero load offset
*/
phdrs[i].p_paddr = (Elf64_Addr) ((UINTN) bswap64(phdrs[i].p_paddr) + load_offset);
/*
* Move to the right position
*/
if (size && skip_bytes(fd, offs, poffs) != 0) goto out_kernel;
/*
* Keep track of current position in file
*/
offs += size;
/*
* How many BSS bytes to clear
*/
bss_sz = bswap64(phdrs[i].p_memsz) - filesz;
VERB_PRT(4, {
Print(L"\nHeader #%d\n", i);
Print(L"offset %ld\n", poffs);
Print(L"Phys addr 0x%lx\n", phdrs[i].p_paddr); /* already endian adjusted */
Print(L"BSS size %ld bytes\n", bss_sz);
Print(L"skip=%ld offs=%ld\n", size, offs);
});
/*
* Read actual segment into memory
*/
ret = read_file(fd, filesz, (CHAR8 *)phdrs[i].p_paddr);
if (ret == ELILO_LOAD_ABORTED) goto load_abort;
if (ret == ELILO_LOAD_ERROR) goto out;
/*
* update file position
*/
offs += filesz;
/*
* Clear bss section
*/
if (bss_sz) Memset((VOID *) phdrs[i].p_paddr+filesz, 0, bss_sz);
}
free(phdrs);
Print(L"..done\n");
return ELILO_LOAD_SUCCESS;
load_abort:
Print(L"..Aborted\n");
ret = ELILO_LOAD_ABORTED;
out_kernel:
/* free kernel memory */
free_kmem();
out:
free(phdrs);
return ret;
}
static INTN
plain_load_kernel(CHAR16 *kname, kdesc_t *kd)
{
INTN ret;
fops_fd_t fd;
EFI_STATUS status;
/*
* Moving the open here simplifies the load_elf() error handling
*/
status = fops_open(kname, &fd);
if (EFI_ERROR(status)) return ELILO_LOAD_ERROR;
Print(L"Loading %s...", kname);
ret = load_elf(fd, kd);
fops_close(fd);
/*
* if the skip buffer was ever used, free it
*/
if (skip_buffer) {
free(skip_buffer);
/* in case we come back */
skip_buffer = NULL;
}
return ret;
}
loader_ops_t plain_loader={
NULL,
LD_NAME,
plain_probe,
plain_load_kernel
};

35
ia64/private.h Normal file
View file

@ -0,0 +1,35 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
* ELILO is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* ELILO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ELILO; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Please check out the elilo.txt for complete documentation on how
* to use this program.
*/
#ifndef __ELILO_PRIVATE_IA64_H__
#define __ELILO_PRIVATE_IA64_H__
extern INTN check_fpswa(EFI_HANDLE, EFI_HANDLE, CHAR16 *);
extern INTN query_fpswa(VOID **);
extern INTN ia64_can_relocate();
#endif /* __ELILO_PRIVATE_IA64_H__ */

170
ia64/setjmp.S Normal file
View file

@ -0,0 +1,170 @@
/* Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
The layout of the jmp_buf is as follows. This is subject to change
and user-code should never depend on the particular layout of
jmp_buf!
offset: description:
------- ------------
0x000 stack pointer (r12) ; unchangeable (see _JMPBUF_UNWINDS)
0x008 r1 (gp)
0x010 caller's unat
0x018 fpsr
0x020 r4
0x028 r5
0x030 r6
0x038 r7
0x040 rp (b0)
0x048 b1
0x050 b2
0x058 b3
0x060 b4
0x068 b5
0x070 ar.pfs
0x078 ar.lc
0x080 pr
0x088 ar.bsp ; unchangeable (see __longjmp.S)
0x090 ar.unat
0x098 &__jmp_buf ; address of the jmpbuf (needed to locate NaT bits in unat)
0x0a0 f2
0x0b0 f3
0x0c0 f4
0x0d0 f5
0x0e0 f16
0x0f0 f17
0x100 f18
0x110 f19
0x120 f20
0x130 f21
0x130 f22
0x140 f23
0x150 f24
0x160 f25
0x170 f26
0x180 f27
0x190 f28
0x1a0 f29
0x1b0 f30
0x1c0 f31 */
/* The following two entry points are the traditional entry points: */
.text
.global setjmp
.proc setjmp
setjmp:
alloc r8=ar.pfs,2,0,0,0
mov in1=1
br.cond.sptk.many __sigsetjmp
.endp setjmp
/* __sigsetjmp(__jmp_buf buf, int savemask) */
__sigsetjmp:
//.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
alloc loc1=ar.pfs,2,2,2,0
mov r16=ar.unat
;;
mov r17=ar.fpsr
mov r2=in0
add r3=8,in0
;;
st8.spill.nta [r2]=sp,16 // r12 (sp)
st8.spill.nta [r3]=gp,16 // r1 (gp)
;;
st8.nta [r2]=r16,16 // save caller's unat
st8.nta [r3]=r17,16 // save fpsr
add r8=0xa0,in0
;;
st8.spill.nta [r2]=r4,16 // r4
st8.spill.nta [r3]=r5,16 // r5
add r9=0xb0,in0
;;
stf.spill.nta [r8]=f2,32
stf.spill.nta [r9]=f3,32
mov loc0=rp
.body
;;
stf.spill.nta [r8]=f4,32
stf.spill.nta [r9]=f5,32
mov r17=b1
;;
stf.spill.nta [r8]=f16,32
stf.spill.nta [r9]=f17,32
mov r18=b2
;;
stf.spill.nta [r8]=f18,32
stf.spill.nta [r9]=f19,32
mov r19=b3
;;
stf.spill.nta [r8]=f20,32
stf.spill.nta [r9]=f21,32
mov r20=b4
;;
stf.spill.nta [r8]=f22,32
stf.spill.nta [r9]=f23,32
mov r21=b5
;;
stf.spill.nta [r8]=f24,32
stf.spill.nta [r9]=f25,32
mov r22=ar.lc
;;
stf.spill.nta [r8]=f26,32
stf.spill.nta [r9]=f27,32
mov r24=pr
;;
stf.spill.nta [r8]=f28,32
stf.spill.nta [r9]=f29,32
;;
stf.spill.nta [r8]=f30
stf.spill.nta [r9]=f31
st8.spill.nta [r2]=r6,16 // r6
st8.spill.nta [r3]=r7,16 // r7
;;
mov r23=ar.bsp
mov r25=ar.unat
mov out0=in0
st8.nta [r2]=loc0,16 // b0
st8.nta [r3]=r17,16 // b1
mov out1=in1
;;
st8.nta [r2]=r18,16 // b2
st8.nta [r3]=r19,16 // b3
;;
st8.nta [r2]=r20,16 // b4
st8.nta [r3]=r21,16 // b5
;;
st8.nta [r2]=loc1,16 // ar.pfs
st8.nta [r3]=r22,16 // ar.lc
;;
st8.nta [r2]=r24,16 // pr
st8.nta [r3]=r23,16 // ar.bsp
;;
st8.nta [r2]=r25 // ar.unat
st8.nta [r3]=in0 // &__jmp_buf
mov r8=0
mov rp=loc0
mov ar.pfs=loc1
br.ret.sptk.many rp
.endp __sigsetjmp

28
ia64/setjmp.h Normal file
View file

@ -0,0 +1,28 @@
/* Define the machine-dependent type `jmp_buf'. Linux/IA-64 version.
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* User code must not depend on the internal representation of jmp_buf. */
#define _JBLEN 70
/* the __jmp_buf element type should be __float80 per ABI... */
typedef long jmp_buf[_JBLEN] __attribute__ ((aligned (16))); /* guarantees 128-bit alignment! */
extern int setjmp (jmp_buf __env);
extern void longjmp (jmp_buf __env, int __val);

107
ia64/sysdeps.h Normal file
View file

@ -0,0 +1,107 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
* ELILO is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* ELILO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ELILO; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Please check out the elilo.txt for complete documentation on how
* to use this program.
*/
/*
* This file is used to define all the IA64-specific data structures, functions,
* and constants used by the generic ELILO.
*
* For things specific to this platform use private.h instead
*/
#ifndef __ELILO_SYSDEPS_IA64_H__
#define __ELILO_SYSDEPS_IA64_H__
#define ELILO_ARCH "IA-64" /* ASCII string ! */
/* in respective assembly files */
extern VOID Memset(VOID *, INTN, UINTN);
extern VOID Memcpy(VOID *, VOID *, UINTN);
extern VOID sysdep_register_options(VOID);
/*
* This version must match the one in the kernel
*/
typedef struct ia64_boot_params {
/*
* The following three pointers MUST point to memory that is marked
* as EfiRuntimeServicesData so that the kernel doesn't think the
* underlying memory is free.
*/
UINTN command_line; /* physical address of command line arguments */
UINTN efi_systab; /* physical address of EFI system table */
UINTN efi_memmap; /* physical address of EFI memory map */
UINTN efi_memmap_size; /* size of EFI memory map */
UINTN efi_memdesc_size; /* size of an EFI memory map descriptor */
UINT32 efi_memdesc_version; /* descriptor version */
struct {
UINT16 num_cols; /* number of columns on console output device */
UINT16 num_rows; /* number of rows on console output device */
UINT16 orig_x; /* cursor's x position */
UINT16 orig_y; /* cursor's y position */
} console_info;
UINTN fpswa; /* physical address of fpswa interface */
UINTN initrd_start; /* virtual address where the initial ramdisk begins */
UINTN initrd_size; /* how big is the initial ramdisk */
UINTN loader_addr; /* start address of boot loader */
UINTN loader_size; /* size of loader code & data */
} boot_params_t;
typedef struct sys_img_options {
UINT8 dummy; /* forces non-zero offset for first field */
UINT8 allow_relocation; /* allow kernel relocation on allocation error */
} sys_img_options_t;
/*
* How to jump to kernel code
*/
static inline void
start_kernel(VOID *kentry, VOID *bp)
{
asm volatile ("mov r28=%1; br.sptk.few %0" :: "b"(kentry),"r"(bp));
}
static inline const UINT64
__ia64_swab64 (UINT64 x)
{
UINT64 result;
asm volatile ("mux1 %0=%1,@rev" : "=r" (result) : "r" (x));
return result;
}
static inline const UINT32
__ia64_swab32 (UINT32 x)
{
return __ia64_swab64(x) >> 32;
}
static inline const UINT16
__ia64_swab16(UINT16 x)
{
return __ia64_swab64(x) >> 48;
}
#endif /* __ELILO_SYSDEPS_IA64_H__ */

137
ia64/system.c Normal file
View file

@ -0,0 +1,137 @@
/*
* Copyright (C) 2001-2003 Hewlett-Packard Co.
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
*
* This file is part of the ELILO, the EFI Linux boot loader.
*
* ELILO is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* ELILO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ELILO; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Please check out the elilo.txt for complete documentation on how
* to use this program.
*/
/*
* this file contains all the IA-64 specific code expected by generic loader
*/
#include <efi.h>
#include <efilib.h>
#include "elilo.h"
#include "loader.h"
#include "private.h"
extern loader_ops_t plain_loader, gzip_loader;
/*
* IA-64 specific boot paramters initialization routine
*/
INTN
sysdeps_create_boot_params(boot_params_t *bp, CHAR8 *cmdline, memdesc_t *initrd, UINTN *cookie)
{
UINTN cols, rows;
SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
EFI_STATUS status;
mmap_desc_t mdesc;
/*
* retrieve address of FPSWA interface
* if not found, argument is not touched
* will be 0 because of Memset()
*/
query_fpswa((VOID **)&bp->fpswa);
if (get_memmap(&mdesc) == -1) return -1;
DBG_PRT((L"Got memory map @ 0x%lx (%d bytes)", mdesc.md, mdesc.map_size));
bp->efi_systab = (UINTN)systab;
bp->efi_memmap = (UINTN)mdesc.md;
bp->efi_memmap_size = mdesc.map_size;
bp->efi_memdesc_size = mdesc.desc_size;
bp->efi_memdesc_version = mdesc.desc_version;
bp->command_line = (UINTN)cmdline;
bp->initrd_start = (UINTN) initrd->start_addr;
bp->initrd_size = initrd->pgcnt << EFI_PAGE_SHIFT;
/* fetch console parameters: */
conout = systab->ConOut;
status = conout->QueryMode(conout, conout->Mode->Mode, &cols, &rows);
if (EFI_ERROR(status)) {
ERR_PRT((L"boot_params QueryMode failed %r", status));
goto error;
}
DBG_PRT((L"Got console info: cols=%d rows=%d x=%d y=%d",
cols, rows, conout->Mode->CursorColumn, conout->Mode->CursorRow));
bp->console_info.num_cols = cols;
bp->console_info.num_rows = rows;
bp->console_info.orig_x = conout->Mode->CursorColumn;
bp->console_info.orig_y = conout->Mode->CursorRow;
*cookie = mdesc.cookie;
return 0;
error:
/* free descriptors' memory */
free_memmap(&mdesc);
return -1;
}
VOID
sysdeps_free_boot_params(boot_params_t *bp)
{
mmap_desc_t md;
Memset(&md, 0, sizeof(md));
md.md = (VOID *)bp->efi_memmap;
free_memmap(&md);
}
INTN
sysdeps_init(EFI_HANDLE dev)
{
loader_register(&plain_loader);
loader_register(&gzip_loader);
return 0;
}
INTN
sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem)
{
/*
* We currently place the initrd at the next page aligned boundary
* after the kernel.
*
* Current kernel implementation requires this (see arch/ia64/kernel/setup.c).
*
* IMPORTANT: EFI & kernel page sizes may differ. We have no way
* of guessing what size the kernel uses. It is the responsibility
* of the kernel to adjust.
*
*/
#if 0
imem->start_addr = (VOID *)ROUNDUP((UINTN)kd->kend, EFI_PAGE_SIZE);
#else
imem->start_addr = 0; /* let the allocator decide */
#endif
return 0;
}