Stephane Eranian 2008-01-04 08:34:56 -05:00 committed by Vincent Batts
parent 97b2a7df25
commit 34d8003a54
13 changed files with 587 additions and 135504 deletions

View File

@ -1,3 +1,50 @@
2008-01-03 signed off by Jason Fleischli <jason.fleischli@hp.com>
* Patch contribution from Scott Davilla <davilla@4pi.com>
when x is zero for the first call to add_memory_region, e820_map[-1]
will access memory outside the bounds of e820_map. While this does
not result in any problems as there is a UINT32 unused_8[41] block
above the e820_map[0] location that should have been zeroed by the
bootloader, the code should not access outside the bounds of
structures.
2008-01-03 Jason Fleischli <jason.fleischli@hp.com>
* initrd.c -- Let the allocator decide where to grab the memory from
the efi memory map. Current start_addr=image->start_addr forces the
same efi region everytime, and has a 7mb limit. ramdisk (initrd.img)
files larger than 7MB wouldnt fit into the memory region assumed by
the image->start_addr resulting in an elilo hang. Leaving start_addr
NULL at initialization forces alloc_pages to get a memory region
sufficient for the size of the initrd image.
2007-12-19 Jason Fleischli <jason.fleischli@hp.com>
* bumping version string to 3.8
2007-12-19 Jason Fleischli <jason.fleischli@hp.com>
* MORE PATCHES FROM INTEL FOR IA32 X86_64.
* Fix compile warning for cmdline_addr assignment.
* Fix an issue caused by uninitialized e820_nr_map in fill_e820map.
* On some machines, there are too many EFI memory map entries, so that,
the number of E820 map entries converted from EFI memory map exceeds
the limit (128). This patch fixes this bug by merging consecutive
memory map entries with the same type.
* CL_MAGIC is not supported by 32-bit boot protocol. So, the kernel
command line passing code is changed accordingly.
* EFI-2.0 boot support patches have been accepted into Linux kernel
2.6.24-rc4 and EFI runtime service patches have been accepted by
Linux kernel 2.6.24-rc4-mm1. There are some changes during the
merging, so there are some updates for elilo ia32/x86_64 too.
* The x86_64 boot parameters of Linux kernel is rearranged to line up
with ia32 boot parameters.
* The boot loader signature of IA32 and x86_64 is redefined to
make it possible for Linux kernel to distinguish whether the
underlying firmware is EFI 32 or EFI 64.
* The EFI framebuffer type ID is changed in Linux kernel to
conform to Linux kernel framebuffer type ID grouping rules. So the
EFI framebuffer type ID setting code in ELILO is changed accordingly.
* E820 memory map is added to IA32 to make it possible for
Linux kernel not to depend on EFI memory map on EFI 32.
2007-09-27 Jason Fleischli <jason.fleischli@hp.com>
* updating changelog for last commit that was omitted
* incorporating AGriffis patches to enhance parsing
passes root= option to kernel options and accounts for -- option
designation.
2007-07-19 Jason Fleischli <jason.fleischli@hp.com>
* Integrated x86_64 support patches from Chandramouli Narayanan
<mouli@linux.intel.com> changes summarized in following bullets.

View File

@ -304,7 +304,7 @@ find_option(config_option_group_t *grp, CHAR16 *str)
* - TOK_ERR: in case of (parsing) error
*/
static token_t
get_token(CHAR16 *str, UINTN maxlen)
get_token_core(CHAR16 *str, UINTN maxlen, BOOLEAN rhs)
{
INTN ch, escaped;
CHAR16 *here;
@ -320,7 +320,7 @@ get_token(CHAR16 *str, UINTN maxlen)
while ((ch = next()), ch != '\n') if (ch == CHAR_EOF) return TOK_EOF;
line_num++;
}
if (ch == '=') return TOK_EQUAL;
if (ch == '=' && !rhs) return TOK_EQUAL;
if (ch == '"') {
here = str;
@ -373,7 +373,7 @@ get_token(CHAR16 *str, UINTN maxlen)
}
else {
if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '#' ||
ch == '=' || ch == CHAR_EOF) {
ch == CHAR_EOF || (ch == '=' && !rhs)) {
again(ch);
*here = 0;
return TOK_STR;
@ -386,6 +386,18 @@ get_token(CHAR16 *str, UINTN maxlen)
return TOK_ERR;
}
static token_t
get_token(CHAR16 *str, UINTN maxlen)
{
return get_token_core(str, maxlen, FALSE);
}
static token_t
get_token_rhs(CHAR16 *str, UINTN maxlen)
{
return get_token_core(str, maxlen, TRUE);
}
static INTN
image_check(boot_image_t *img)
{
@ -679,7 +691,7 @@ do_string_core(config_option_t *p, CHAR16 *str, UINTN maxlen, CHAR16 *msg)
/*
* now get the value
*/
tok = get_token(str, maxlen);
tok = get_token_rhs(str, maxlen);
if (tok != TOK_STR) {
config_error(L"Option %s expects %s", p->name, msg);
return -1;
@ -935,6 +947,37 @@ find_description(CHAR16 *label)
return NULL;
}
static void
add_root_to_options(CHAR16 *options, CHAR16 *root, CHAR16 *vmcode)
{
CHAR16 *o, ko[CMDLINE_MAXLEN];
if (vmcode[0]) {
for (o = options; *o; o++) {
if (*o == '-' && *(o+1) == '-')
break;
}
if (! *o) {
/* no separator found, add one */
StrCpy(o, L" -- ");
o++;
}
/* advance past separator and whitespace */
o += 2;
while (*o == ' ') o++;
} else {
o = options;
}
/* insert root param at this point */
StrCpy(ko, o);
StrCpy(o, L"root=");
StrCat(o, root);
StrCat(o, L" ");
StrCat(o, ko);
}
INTN
find_label(CHAR16 *label, CHAR16 *kname, CHAR16 *options, CHAR16 *initrd, CHAR16 *vmcode)
{
@ -957,15 +1000,12 @@ find_label(CHAR16 *label, CHAR16 *kname, CHAR16 *options, CHAR16 *initrd, CHAR16
/*
* when the label does not exist, we still propagate the global options
*/
if (global_config.root[0]) {
StrCpy(options, L" root=");
StrCat(options, global_config.root);
}
if (global_config.options[0]) {
StrCat(options, L" ");
StrCat(options, global_config.options);
}
if (global_config.root[0])
add_root_to_options(options, global_config.root, global_config.vmcode);
if (global_config.readonly) StrCat(options, L" ro");
if (global_config.initrd[0]) StrCpy(initrd, global_config.initrd);
@ -978,21 +1018,33 @@ find_label(CHAR16 *label, CHAR16 *kname, CHAR16 *options, CHAR16 *initrd, CHAR16
found:
StrCpy(kname, img->kname);
/* per image initrd has precedence over global initrd */
if (img->initrd[0])
StrCpy(initrd, img->initrd);
else
StrCpy(initrd, global_config.initrd);
/* per image vmcode has precedence over global vmcode */
if (img->vmcode[0])
StrCpy(vmcode, img->vmcode);
else
StrCpy(vmcode, global_config.vmcode);
/*
* literal option overrides any other image-based or global option
*
* In any case, the image option has priority over the global option
*/
if (img->literal == 0) {
if (img->root[0] || global_config.root[0]) {
StrCat(options, L"root=");
StrCat(options, img->root[0] ? img->root : global_config.root);
}
/* XXX: check max length */
if (img->options[0] || global_config.options[0]) {
StrCat(options, L" ");
StrCat(options, img->options[0] ? img->options: global_config.options);
}
if (img->root[0] || global_config.root[0]) {
add_root_to_options(options, img->root[0]
? img->root : global_config.root, vmcode);
}
if (img->readonly || global_config.readonly) {
StrCat(options, L" ro");
}
@ -1001,17 +1053,6 @@ found:
StrCpy(options, img->options);
}
/* per image initrd has precedence over global initrd */
if (img->initrd[0])
StrCpy(initrd, img->initrd);
else if (global_config.initrd[0])
StrCpy(initrd, global_config.initrd);
if (img->vmcode[0])
StrCpy(vmcode, img->vmcode);
else if (global_config.vmcode[0])
StrCpy(vmcode, global_config.vmcode);
/*
* point to architecture dependent options for this image
*/

135421
cscope.out

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -46,7 +46,7 @@
#include "loader.h"
#include "config.h" /* for config_init() */
#define ELILO_VERSION L"3.7"
#define ELILO_VERSION L"3.8"
#define ELILO_SHARED_CMDLINE_OPTS L"pPMC:aDhd:i:vVc:E"
elilo_config_t elilo_opt;

View File

@ -59,6 +59,26 @@
*/
#pragma pack(1)
/* Definitions for converting EFI memory map to E820 map for Linux
* These definitions are from include/linux/asm-x86/e820.h
* The structure ia32_boot_params below is updated to accommodate E820 map
* EFI memory map is converted to E820 map in this structure and passed
* to Linux. This way the OS does not need to do the conversion.
*/
#define E820_RAM 1
#define E820_RESERVED 2
#define E820_ACPI 3
#define E820_NVS 4
#define E820_MAX 128
struct e820entry {
UINT64 addr; /* start of memory segment */
UINT64 size; /* size of memory segment */
UINT32 type; /* type of memory segment */
} __attribute__((packed));
typedef union ia32_boot_params {
UINT8 raw[0x2000];
struct {
@ -155,7 +175,7 @@ typedef union ia32_boot_params {
/* EFI boot loader signature. */
/* 0x1C0 */ UINT8 efi_loader_sig[4]; /* LDR */
#define EFI_LOADER_SIG "EFIL"
#define EFI_LOADER_SIG_IA32 "EL32"
/* Address of the EFI system table. */
/* 0x1C4 */ UINT32 efi_sys_tbl; /* LDR */
@ -177,7 +197,9 @@ typedef union ia32_boot_params {
/* Available contiguous extended memory in KB. */
/* 0x1E0 */ UINT32 alt_mem_k; /* LDR */
/* 0x1E4 */ UINT8 unused_5[0x0D]; /* unused */
/* 0x1E4 */ UINT32 unused_51; /* unused */
/* 0x1E8 */ UINT8 e820_nrmap;
/* 0x1E9 */ UINT32 unused_52[2]; /* unused */
/* Size of setup code in sectors (1 sector == 512 bytes). */
/* 0x1F1 */ UINT8 setup_sectors; /* BLD */
@ -258,6 +280,8 @@ typedef union ia32_boot_params {
/* 0x226 */ UINT16 unused_7; /* LDR */
/* 0x228 */ UINT32 cmdline_addr; /* LDR */
/* 0x22C */ UINT32 unused_8[41];
/* 0x2D0 */ UINT8 e820_map[2560];
} s;
} boot_params_t;
#pragma pack()
@ -354,6 +378,9 @@ start_kernel(VOID *kentry, boot_params_t *bp)
MEMCPY(high_base_mem, bp, 0x4000);
bp = (boot_params_t *)high_base_mem;
bp->s.cmdline_addr = high_base_mem + bp->s.cmdline_offset;
/*
* Initialize Linux GDT.
*/

View File

@ -156,6 +156,257 @@ sysdeps_free_boot_params(boot_params_t *bp)
free_memmap(&md);
}
/*
* Get video information.
*/
static INTN get_video_info(boot_params_t * bp) {
EFI_GUID GopProtocol = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop_interface;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Gop_info;
EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Gop_mode;
EFI_HANDLE *Gop_handle;
EFI_STATUS efi_status;
UINTN size, size1;
UINT8 i;
efi_status = uefi_call_wrapper(
BS->LocateHandle,
5,
ByProtocol,
&GopProtocol,
NULL,
&size,
(VOID **)Gop_handle);
if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) {
ERR_PRT((L"LocateHandle GopProtocol failed."));
return -1;
}
Gop_handle = alloc(size, 0);
efi_status = uefi_call_wrapper(
BS->LocateHandle,
5,
ByProtocol,
&GopProtocol,
NULL,
&size,
(VOID **)Gop_handle);
if (EFI_ERROR(efi_status)) {
ERR_PRT((L"LocateHandle GopProtocol failed."));
free(Gop_handle);
return -1;
}
for (i=0; i < size/sizeof(EFI_HANDLE); i++) {
Gop_handle += i;
efi_status = uefi_call_wrapper(
BS->HandleProtocol,
3,
*Gop_handle,
&GopProtocol,
&Gop_interface);
if (EFI_ERROR(efi_status)) {
continue;
}
Gop_mode = Gop_interface->Mode;
efi_status = uefi_call_wrapper(
Gop_interface->QueryMode,
4,
Gop_interface,
Gop_mode->Mode,
&size1,
&Gop_info);
if (!EFI_ERROR(efi_status))
break;
if (EFI_ERROR(efi_status)) {
continue;
}
}
if (EFI_ERROR(efi_status) || i > (size/sizeof(EFI_HANDLE))) {
ERR_PRT((L"HandleProtocol GopProtocol failed."));
free(Gop_handle);
return -1;
}
bp->s.is_vga = 0x70;
bp->s.orig_cursor_col = 0;
bp->s.orig_cursor_row = 0;
bp->s.orig_video_page = 0;
bp->s.orig_video_mode = 0;
bp->s.orig_video_cols = 0;
bp->s.orig_video_rows = 0;
bp->s.orig_ega_bx = 0;
bp->s.orig_video_points = 0;
bp->s.lfb_width = Gop_info->HorizontalResolution;
bp->s.lfb_height = Gop_info->VerticalResolution;
bp->s.lfb_base = Gop_mode->FrameBufferBase;
bp->s.lfb_size = Gop_mode->FrameBufferSize;
bp->s.lfb_pages = 1;
bp->s.vesa_seg = 0;
bp->s.vesa_off = 0;
if (Gop_info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
bp->s.lfb_depth = 32;
bp->s.lfb_red_size = 8;
bp->s.lfb_red_pos = 0;
bp->s.lfb_green_size = 8;
bp->s.lfb_green_pos = 8;
bp->s.lfb_blue_size = 8;
bp->s.lfb_blue_pos = 16;
bp->s.lfb_rsvd_size = 8;
bp->s.lfb_rsvd_pos = 24;
bp->s.lfb_line_len = Gop_info->PixelsPerScanLine * 4;
} else if (Gop_info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
bp->s.lfb_depth = 32;
bp->s.lfb_red_size = 8;
bp->s.lfb_red_pos = 16;
bp->s.lfb_green_size = 8;
bp->s.lfb_green_pos = 8;
bp->s.lfb_blue_size = 8;
bp->s.lfb_blue_pos = 0;
bp->s.lfb_rsvd_size = 8;
bp->s.lfb_rsvd_pos = 24;
bp->s.lfb_line_len = Gop_info->PixelsPerScanLine * 4;
} else if (Gop_info->PixelFormat == PixelBitMask) {
find_bits(Gop_info->PixelInformation.RedMask,
&bp->s.lfb_red_pos, &bp->s.lfb_red_size);
find_bits(Gop_info->PixelInformation.GreenMask,
&bp->s.lfb_green_pos, &bp->s.lfb_green_size);
find_bits(Gop_info->PixelInformation.BlueMask,
&bp->s.lfb_blue_pos, &bp->s.lfb_blue_size);
find_bits(Gop_info->PixelInformation.ReservedMask,
&bp->s.lfb_rsvd_pos, &bp->s.lfb_rsvd_size);
bp->s.lfb_depth = bp->s.lfb_red_size + bp->s.lfb_green_size +
bp->s.lfb_blue_size + bp->s.lfb_rsvd_size;
bp->s.lfb_line_len = (Gop_info->PixelsPerScanLine * bp->s.lfb_depth) / 8;
} else {
bp->s.lfb_depth = 4;
bp->s.lfb_red_size = 0;
bp->s.lfb_red_pos = 0;
bp->s.lfb_green_size = 0;
bp->s.lfb_green_pos = 0;
bp->s.lfb_blue_size = 0;
bp->s.lfb_blue_pos = 0;
bp->s.lfb_rsvd_size = 0;
bp->s.lfb_rsvd_pos = 0;
bp->s.lfb_line_len = bp->s.lfb_width / 2;
}
return 0;
}
/* Convert EFI memory map to E820 map for the operating system
* This code is based on a Linux kernel patch submitted by Edgar Hucek
*/
/* Add a memory region to the e820 map */
static void add_memory_region (struct e820entry *e820_map,
int *e820_nr_map,
UINT64 start,
UINT64 size,
UINT32 type)
{
int x = *e820_nr_map;
if (x == E820_MAX) {
Print(L"Too many entries in the memory map!\n");
return;
}
if ((x > 0) && e820_map[x-1].addr + e820_map[x-1].size == start
&& e820_map[x-1].type == type)
e820_map[x-1].size += size;
else {
e820_map[x].addr = start;
e820_map[x].size = size;
e820_map[x].type = type;
(*e820_nr_map)++;
}
}
void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc)
{
int nr_map, e820_nr_map = 0, i;
UINT64 start, end, size;
EFI_MEMORY_DESCRIPTOR *md, *p;
struct e820entry *e820_map;
nr_map = mdesc->map_size/mdesc->desc_size;
e820_map = (struct e820entry *)bp->s.e820_map;
for (i = 0, p = mdesc->md; i < nr_map; i++)
{
md = p;
switch (md->Type) {
case EfiACPIReclaimMemory:
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_ACPI);
break;
case EfiRuntimeServicesCode:
case EfiRuntimeServicesData:
case EfiReservedMemoryType:
case EfiMemoryMappedIO:
case EfiMemoryMappedIOPortSpace:
case EfiUnusableMemory:
case EfiPalCode:
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_RESERVED);
break;
case EfiLoaderCode:
case EfiLoaderData:
case EfiBootServicesCode:
case EfiBootServicesData:
case EfiConventionalMemory:
start = md->PhysicalStart;
size = md->NumberOfPages << EFI_PAGE_SHIFT;
end = start + size;
/* Fix up for BIOS that claims RAM in 640K-1MB region */
if (start < 0x100000ULL && end > 0xA0000ULL) {
if (start < 0xA0000ULL) {
/* start < 640K
* set memory map from start to 640K
*/
add_memory_region(e820_map,
&e820_nr_map,
start,
0xA0000ULL-start,
E820_RAM);
}
if (end <= 0x100000ULL)
continue;
/* end > 1MB
* set memory map avoiding 640K to 1MB hole
*/
start = 0x100000ULL;
size = end - start;
}
add_memory_region(e820_map, &e820_nr_map,
start, size, E820_RAM);
break;
case EfiACPIMemoryNVS:
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_NVS);
break;
default:
/* We should not hit this case */
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_RESERVED);
break;
}
p = NextMemoryDescriptor(p, mdesc->desc_size);
}
bp->s.e820_nrmap = e820_nr_map;
}
/*
* IA-32 specific boot parameters initialization routine
*/
@ -213,9 +464,11 @@ sysdeps_create_boot_params(
bp->s.unused_2 = 0;
ZeroMem(bp->s.unused_3, sizeof bp->s.unused_3);
ZeroMem(bp->s.unused_4, sizeof bp->s.unused_4);
ZeroMem(bp->s.unused_5, sizeof bp->s.unused_5);
ZeroMem(&bp->s.unused_51, sizeof bp->s.unused_51);
ZeroMem(bp->s.unused_52, sizeof bp->s.unused_52);
bp->s.unused_6 = 0;
bp->s.unused_7 = 0;
ZeroMem(bp->s.unused_8, sizeof bp->s.unused_8);
/*
* Tell kernel this was loaded by an advanced loader type.
@ -310,7 +563,7 @@ sysdeps_create_boot_params(
/*
* EFI loader signature
*/
CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG, 4);
CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG_IA32, 4);
/*
* Kernel entry point.
@ -402,6 +655,7 @@ sysdeps_create_boot_params(
CHECK_OFFSET(loader_start, 0x1D8, L"%xh");
CHECK_OFFSET(loader_size, 0x1DC, L"%xh");
CHECK_OFFSET(alt_mem_k, 0x1E0, L"%xh");
CHECK_OFFSET(e820_nrmap, 0x1E8, L"%xh");
CHECK_OFFSET(setup_sectors, 0x1F1, L"%xh");
CHECK_OFFSET(mount_root_rdonly, 0x1F2, L"%xh");
CHECK_OFFSET(sys_size, 0x1F4, L"%xh");
@ -426,6 +680,7 @@ sysdeps_create_boot_params(
CHECK_OFFSET(bootsect_helper, 0x220, L"%xh");
CHECK_OFFSET(heap_end_ptr, 0x224, L"%xh");
CHECK_OFFSET(cmdline_addr, 0x228, L"%xh");
CHECK_OFFSET(e820_map, 0x2D0, L"'%-2560.2560a'");
if (test) {
ERR_PRT((L"Boot sector and/or setup parameter alignment error."));
@ -440,6 +695,8 @@ sysdeps_create_boot_params(
* in the fill routine gets accounted for.
*/
if (!get_video_info(bp)) goto do_memmap;
efi_status = ST->ConOut->QueryMode(
ST->ConOut,
ST->ConOut->Mode->Mode,
@ -488,6 +745,7 @@ sysdeps_create_boot_params(
bp->s.vesa_seg = 0;
bp->s.vesa_off = 0;
do_memmap:
/*
* Get memory map description and cookie for ExitBootServices()
*/
@ -503,6 +761,10 @@ sysdeps_create_boot_params(
bp->s.efi_mem_desc_size = mdesc.desc_size;
bp->s.efi_mem_desc_ver = mdesc.desc_version;
bp->s.efi_sys_tbl = (UINTN)systab;
/* Now that we have EFI memory map, convert it to E820 map
* and update the bootparam accordingly
*/
fill_e820map(bp, &mdesc);
return 0;
}

View File

@ -41,7 +41,7 @@ INTN
load_file(CHAR16 *filename, memdesc_t *image)
{
EFI_STATUS status;
VOID *start_addr = image->start_addr;
VOID *start_addr = NULL;
UINTN pgcnt;
UINT64 size = 0;
fops_fd_t fd;
@ -71,7 +71,7 @@ load_file(CHAR16 *filename, memdesc_t *image)
/* round up to get required number of pages (4KB) */
image->pgcnt = pgcnt = EFI_SIZE_TO_PAGES(image->size);
start_addr = alloc_pages(pgcnt, EfiLoaderData, start_addr ? AllocateAddress : AllocateAnyPages, start_addr);
start_addr = alloc_pages(pgcnt, EfiLoaderData, start_addr ? AllocateAddress : AllocateAnyPages, 0 );
if (start_addr == NULL) {
ERR_PRT((L"Failed to allocate %d pages for %s image", pgcnt,
filename));

94
release.notes Normal file
View File

@ -0,0 +1,94 @@
SUBMIT BUG REPORTS HERE --> http://sourceforge.net/tracker/?group_id=91879&atid=598709
IMPORTANT NOTE FOR BUILDS ON ALL ARCHS:
-------------------------
You will need the following toolchain to build elilo with the 3.7 source tarball
(for all archs due to the new uefi call wrappers).
1. gnu-efi-3.0d or > .... http://sourceforge.net/project/showfiles.php?group_id=163609&package_id=185019&release_id=508306
2. gcc-4.1.1 or >
3. binutils-2.17.50.0.14 or > with Intel64 EFI support
*BuildNote: efi libraries are installed to /usr/local/lib
by the default gnu-efi source package. elilo expects them to
be in standard linux system location /usr/lib. efi includes
may be located in /usr/local/include/efi. elilo expects
them to be in standard linux system location /usr/include/efi.
likewise objcopy may be installed to /usr/local/bin by binutils,
elilo source expects it to be in /usr/bin. On distributions
using standard linux system conventions such
as Debian and Ubuntu this is corrected in the binutils and gnu-efi packages.
Implementation:
--------------
Calls to EFI services in x86_64 require a wrapper to pass the arguments
in the appropriate manner. This is implemented with efi wrapper.
For IA32 and IA64, the wrapper is a macro that merely calls the
EFI services directly. The elilo source has been modified to use the
efi wrapper implemented in the gnu-efi-3.0d library.
elilo for x86_64 and its dependent libraries are built and the final
ELF image is converted into PE-COFF image using the objcopy supported
by binutils-2.17.50.0.14 or above with Intel64 EFI support.
On UEFI 2.0 firmware, only Graphics Output Protocol (GOP) is supported.
The x86_64 elilo first queries video information from GOP failing which
it queries for text mode support. The video information is passed to
Linux kernel via boot parameter. The GOP support requires
Linux kernel EFI framebuffer driver (kernel configuration option).
Booting on EFI/x86_64 platforms
-----------------------------
To use elilo on x86_64, you can put it on a floppy and
on a FAT32 partition (msdos partition). You can also
netboot if your network adapter has support for UNDI/PXE.
Elilo/x86_64 requires efi64 enabled linux kernel (> 2.6.21).
You need to compile the kernel with CONFIG_EFI option.
x86_64 platforms with UEFI 2.0 firmware deprecate UGA protocol
and therefore only the Graphics Output Protocol (GOP) is supported. For
such platforms, the kernel must be configured with EFI_FB option. This
will enable early boot messages on the console. The elilo for x86_64
attempts to query the firmware for GOP and if it fails it defaults to
text mode.
The x86_64 implementation converts the EFI memory map into E820 map and
passes it in the bootparameter supplied to the kernel. For details on
bootparameter, see x86_64/sysdeps.h.
CHANGES BETWEEN 3.6 & 3.8
-------------------------
- options parsing changed to append root= after append="-- options" to
accomodate xen ia64 support. without this change the option is
passed to the hypervisor instead of the kernel resulting in the
standard kernel panic.
INTEL PATCHES
- E820 memory map is added to IA32 to make it possible for
Linux kernel not to depend on EFI memory map on EFI 32.
- The EFI framebuffer type ID is changed in Linux kernel to
conform to Linux kernel framebuffer type ID grouping rules. So the
EFI framebuffer type ID setting code in ELILO is changed accordingly.
- The boot loader signature of IA32 and x86_64 is redefined to
make it possible for Linux kernel to distinguish whether the
underlying firmware is EFI 32 or EFI 64.
- updates for EFI-2.0 boot support going into linux kernel 2.6.24-rc4
- CL_MAGIC is not supported by 32-bit boot protocol. So, the kernel
command line passing code is changed accordingly.
- bugfix, on some machines efi memmap entries exceed the 128 maximum
for e820 map entries, so consecutive memmap entries with the same
type are merged to bring the count below 128.
- bugfix, uninitialized e820 _nr_map in fill_e820map.
- fixed compile warning for cmdline_addr assignment.
ADDITIONAL CHANGES
- version string updated to 3.8
- fixed x86_64 hang created by initrd images larger than 7mb due
to the code always using the same efi region which on some machines
is only 7mb. code changed to properly have the efi allocator decide
which regions to use based on the total pagecount required by the
size of the initrd to be loaded.
- bugfix, for ia32 and x86_64 code, e820_map[x-1] accesses memory
out of bounds when x=0.

View File

@ -180,28 +180,27 @@ typedef union x86_64_boot_params {
/* 0xA0 */ UINT16 mca_info_len; /* LDR */
/* 0xA2 */ UINT8 mca_info_buf[0x10]; /* LDR */
/* 0xB2 */ UINT8 unused_4[0x106]; /* unused */
/* Address of the EFI system table. */
/* 0x1B8 */ UINT64 efi_sys_tbl; /* LDR */
/* 0xB2 */ UINT8 unused_4[0x10E]; /* unused */
/* EFI boot loader signature. */
/* 0x1C0 */ UINT8 efi_loader_sig[4]; /* LDR */
#define EFI_LOADER_SIG "EFIL"
#define EFI_LOADER_SIG_X64 "EL64"
/* Address of the EFI system table. */
/* 0x1C4 */ UINT32 efi_sys_tbl; /* LDR */
/* EFI memory descriptor size. */
/* 0x1C4 */ UINT32 efi_mem_desc_size; /* LDR */
/* 0x1C8 */ UINT32 efi_mem_desc_size; /* LDR */
/* EFI memory descriptor version. */
/* 0x1C8 */ UINT32 efi_mem_desc_ver; /* LDR */
/* 0x1CC */ UINT32 efi_mem_desc_ver; /* LDR */
/* Address & size of EFI memory map. */
/* 0x1CC */ UINT32 efi_mem_map_size; /* LDR */
/* 0x1D0 */ UINT64 efi_mem_map; /* LDR */
/* 0x1D0 */ UINT32 efi_mem_map; /* LDR */
/* 0x1D4 */ UINT32 efi_mem_map_size; /* LDR */
/* Address & size of loader. */
/* 0x1D8 */ UINT32 loader_start; /* LDR */
/* 0x1DC */ UINT32 loader_size; /* LDR */
/* 0x1D8 */ UINT32 efi_sys_tbl_hi; /* LDR */
/* 0x1DC */ UINT32 efi_mem_map_hi; /* LDR */
/* Available contiguous extended memory in KB. */
/* 0x1E0 */ UINT32 alt_mem_k; /* LDR */
@ -395,6 +394,9 @@ start_kernel(VOID *kentry, boot_params_t *bp)
MEMCPY(high_base_mem, bp, 0x4000);
bp = (boot_params_t *)high_base_mem;
bp->s.cmdline_addr = high_base_mem + bp->s.cmdline_offset;
/*
* Initialize Linux GDT.
*/

View File

@ -255,7 +255,7 @@ static INTN get_video_info(boot_params_t * bp) {
return -1;
}
bp->s.is_vga = 0x24;
bp->s.is_vga = 0x70;
bp->s.orig_cursor_col = 0;
bp->s.orig_cursor_row = 0;
bp->s.orig_video_page = 0;
@ -326,30 +326,56 @@ static INTN get_video_info(boot_params_t * bp) {
* This code is based on a Linux kernel patch submitted by Edgar Hucek
*/
/* Add a memory region to the e820 map */
static void add_memory_region (struct e820entry *e820_map,
int *e820_nr_map,
unsigned long long start,
unsigned long size,
unsigned int type)
{
int x = *e820_nr_map;
if (x == E820_MAX) {
Print(L"Too many entries in the memory map!\n");
return;
}
if ((x > 0) && e820_map[x-1].addr + e820_map[x-1].size == start
&& e820_map[x-1].type == type)
e820_map[x-1].size += size;
else {
e820_map[x].addr = start;
e820_map[x].size = size;
e820_map[x].type = type;
(*e820_nr_map)++;
}
}
void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc)
{
int nr_map, i;
int nr_map, e820_nr_map = 0, i;
UINT64 start, end, size;
EFI_MEMORY_DESCRIPTOR *md, *p;
struct e820entry *e820_map;
nr_map = mdesc->map_size/mdesc->desc_size;
e820_map = (struct e820entry *)bp->s.e820_map;
bp->s.e820_nrmap = nr_map;
for (i = 0, p = mdesc->md; i < nr_map; i++)
{
md = p;
switch (md->Type) {
case EfiACPIReclaimMemory:
e820_map->addr = md->PhysicalStart;
e820_map->size = md->NumberOfPages << EFI_PAGE_SHIFT;
e820_map->type = E820_ACPI;
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_ACPI);
break;
case EfiRuntimeServicesCode:
e820_map->addr = md->PhysicalStart;
e820_map->size = md->NumberOfPages << EFI_PAGE_SHIFT;
e820_map->type = E820_EXEC_CODE;
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_EXEC_CODE);
break;
case EfiRuntimeServicesData:
case EfiReservedMemoryType:
@ -357,9 +383,10 @@ void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc)
case EfiMemoryMappedIOPortSpace:
case EfiUnusableMemory:
case EfiPalCode:
e820_map->addr = md->PhysicalStart;
e820_map->size = md->NumberOfPages << EFI_PAGE_SHIFT;
e820_map->type = E820_RESERVED;
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_RESERVED);
break;
case EfiLoaderCode:
case EfiLoaderData:
@ -375,10 +402,11 @@ void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc)
/* start < 640K
* set memory map from start to 640K
*/
e820_map->addr = start;
e820_map->size = 0xA0000ULL-start;
e820_map->type = E820_RAM;
e820_map++;
add_memory_region(e820_map,
&e820_nr_map,
start,
0xA0000ULL-start,
E820_RAM);
}
if (end <= 0x100000ULL)
continue;
@ -388,27 +416,28 @@ void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc)
start = 0x100000ULL;
size = end - start;
}
e820_map->addr = start;
e820_map->size = size;
e820_map->type = E820_RAM;
add_memory_region(e820_map, &e820_nr_map,
start, size, E820_RAM);
break;
case EfiACPIMemoryNVS:
e820_map->addr = md->PhysicalStart;
e820_map->size = md->NumberOfPages << EFI_PAGE_SHIFT;
e820_map->type = E820_NVS;
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_NVS);
break;
default:
/* We should not hit this case */
e820_map->addr = md->PhysicalStart;
size = md->NumberOfPages << EFI_PAGE_SHIFT;
e820_map->type = E820_RESERVED;
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
E820_RESERVED);
break;
}
e820_map++;
p = NextMemoryDescriptor(p, mdesc->desc_size);
}
bp->s.e820_nrmap = e820_nr_map;
}
/*
* x86_64 specific boot parameters initialization routine
*/
@ -464,10 +493,10 @@ sysdeps_create_boot_params(
*/
bp->s.unused_1 = 0;
bp->s.unused_2 = 0;
ZeroMem(bp->s.unused_3, sizeof bp->s.unused_3);
ZeroMem(bp->s.unused_4, sizeof bp->s.unused_4);
ZeroMem(bp->s.unused_51, sizeof bp->s.unused_51);
ZeroMem(bp->s.unused_52, sizeof bp->s.unused_52);
ZeroMem(&bp->s.unused_3, sizeof bp->s.unused_3);
ZeroMem(&bp->s.unused_4, sizeof bp->s.unused_4);
ZeroMem(&bp->s.unused_51, sizeof bp->s.unused_51);
ZeroMem(&bp->s.unused_52, sizeof bp->s.unused_52);
bp->s.unused_6 = 0;
bp->s.unused_7 = 0;
ZeroMem(bp->s.unused_8, sizeof bp->s.unused_8);
@ -564,7 +593,7 @@ sysdeps_create_boot_params(
/*
* EFI loader signature
*/
CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG, 4);
CopyMem(bp->s.efi_loader_sig, EFI_LOADER_SIG_X64, 4);
/*
* Kernel entry point.
@ -647,14 +676,14 @@ sysdeps_create_boot_params(
CHECK_OFFSET(hd1_info, 0x90, L"");
CHECK_OFFSET(mca_info_len, 0xA0, L"%xh");
CHECK_OFFSET(mca_info_buf, 0xA2, L"");
CHECK_OFFSET(efi_sys_tbl, 0x1B8, L"%xh");
CHECK_OFFSET(efi_loader_sig, 0x1C0, L"'%-4.4a'");
CHECK_OFFSET(efi_mem_desc_size, 0x1C4, L"%xh");
CHECK_OFFSET(efi_mem_desc_ver, 0x1C8, L"%xh");
CHECK_OFFSET(efi_mem_map_size, 0x1CC, L"%xh");
CHECK_OFFSET(efi_sys_tbl, 0x1C4, L"%xh");
CHECK_OFFSET(efi_mem_desc_size, 0x1C8, L"%xh");
CHECK_OFFSET(efi_mem_desc_ver, 0x1CC, L"%xh");
CHECK_OFFSET(efi_mem_map, 0x1D0, L"%xh");
CHECK_OFFSET(loader_start, 0x1D8, L"%xh");
CHECK_OFFSET(loader_size, 0x1DC, L"%xh");
CHECK_OFFSET(efi_mem_map_size, 0x1D4, L"%xh");
CHECK_OFFSET(efi_sys_tbl_hi, 0x1D8, L"%xh");
CHECK_OFFSET(efi_mem_map_hi, 0x1DC, L"%xh");
CHECK_OFFSET(alt_mem_k, 0x1E0, L"%xh");
CHECK_OFFSET(setup_sectors, 0x1F1, L"%xh");
CHECK_OFFSET(mount_root_rdonly, 0x1F2, L"%xh");
@ -758,11 +787,13 @@ do_memmap:
return -1;
}
*cookie = mdesc.cookie;
bp->s.efi_mem_map = (UINTN)mdesc.md;
bp->s.efi_mem_map = (UINT32)(unsigned long)mdesc.md;
bp->s.efi_mem_map_size = mdesc.map_size;
bp->s.efi_mem_desc_size = mdesc.desc_size;
bp->s.efi_mem_desc_ver = mdesc.desc_version;
bp->s.efi_sys_tbl = (UINTN)systab;
bp->s.efi_sys_tbl = (UINT32)(unsigned long)systab;
bp->s.efi_mem_map_hi = (unsigned long)mdesc.md >> 32;
bp->s.efi_sys_tbl_hi = (unsigned long)systab >> 32;
/* Now that we have EFI memory map, convert it to E820 map
* and update the bootparam accordingly
*/