Stephane Eranian 2011-01-13 08:46:45 -05:00 committed by Vincent Batts
parent e351d8fbea
commit 82f7288853
29 changed files with 659 additions and 235 deletions

View file

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

View file

@ -33,15 +33,23 @@
typedef struct {
UINTN legacy_free_boot;
UINTN text_mode;
} x86_64_global_config_t;
#define x86_64_opt_offsetof(option) (&((sys_img_options_t *)(0x0))->option)
static x86_64_global_config_t x86_64_gconf;
static config_option_t sysdeps_global_options[]={
{OPT_BOOL, OPT_GLOBAL, L"legacy-free", NULL, NULL, &x86_64_gconf.legacy_free_boot}
};
static config_option_t sysdeps_image_options[]={
{OPT_BOOL, OPT_IMAGE_SYS, L"text-mode", NULL, NULL, x86_64_opt_offsetof(text_mode)}
};
/*
* X86_64 operations that need to be done only once and just before
* entering the main loop of the loader
@ -81,6 +89,14 @@ x86_64_use_legacy_free_boot(VOID)
return x86_64_gconf.legacy_free_boot ? 1 : 0;
}
INTN
x86_64_text_mode(VOID)
{
return (elilo_opt.sys_img_opts &&
elilo_opt.sys_img_opts->text_mode == TRUE) ? 1 : 0;
}
INTN
sysdeps_register_options(VOID)
{
@ -89,14 +105,11 @@ sysdeps_register_options(VOID)
ret = register_config_options(sysdeps_global_options,
sizeof(sysdeps_global_options)/sizeof(config_option_t),
OPTIONS_GROUP_GLOBAL);
#if 0
/* no per image options yet */
if (ret == -1 ) return ret;
ret = register_config_options(sysdeps_image_options,
sizeof(sysdeps_image_options)/sizeof(config_option_t),
OPTIONS_GROUP_IMAGE);
#endif
return ret;
}

View file

@ -107,12 +107,12 @@ typedef union x86_64_boot_params {
/* 0x06 */ UINT8 orig_video_mode; /* LDR */
/* 0x07 */ UINT8 orig_video_cols; /* LDR */
/* 0x08 */ UINT16 unused_1; /* unused */
/* 0x08 */ UINT16 pad_1; /* unused */
/* %%TBD */
/* 0x0A */ UINT16 orig_ega_bx; /* LDR */
/* 0x0C */ UINT16 unused_2; /* unused */
/* 0x0C */ UINT16 pad_2; /* unused */
/* Screen height before passing control to kernel. */
/* 0x0E */ UINT8 orig_video_rows; /* LDR */
@ -174,7 +174,7 @@ typedef union x86_64_boot_params {
/* 0x4E */ UINT32 bios_code_len; /* LDR */
/* 0x52 */ UINT16 bios_data_len; /* LDR */
/* 0x54 */ UINT8 unused_3[0x2C]; /* unused */
/* 0x54 */ UINT8 pad_3[0x2C]; /* unused */
/* %%TBD */
/* 0x80 */ UINT8 hd0_info[0x10]; /* LDR */
@ -184,7 +184,7 @@ typedef union x86_64_boot_params {
/* 0xA0 */ UINT16 mca_info_len; /* LDR */
/* 0xA2 */ UINT8 mca_info_buf[0x10]; /* LDR */
/* 0xB2 */ UINT8 unused_4[0x10E]; /* unused */
/* 0xB2 */ UINT8 pad_4[0x10E]; /* unused */
/* EFI boot loader signature. */
/* 0x1C0 */ UINT8 efi_loader_sig[4]; /* LDR */
@ -209,9 +209,9 @@ typedef union x86_64_boot_params {
/* Available contiguous extended memory in KB. */
/* 0x1E0 */ UINT32 alt_mem_k; /* LDR */
/* 0x1E4 */ UINT32 unused_51; /* unused */
/* 0x1E4 */ UINT32 pad_51; /* unused */
/* 0x1E8 */ UINT8 e820_nrmap;
/* 0x1E9 */ UINT32 unused_52[2]; /* unused */
/* 0x1E9 */ UINT32 pad_52[2]; /* unused */
/* Size of setup code in sectors (1 sector == 512 bytes). */
/* 0x1F1 */ UINT8 setup_sectors; /* BLD */
@ -220,15 +220,10 @@ typedef union x86_64_boot_params {
/* 0x1F2 */ UINT16 mount_root_rdonly; /* BLD */
/* %%TBD */
/* 0x1F4 */ UINT16 sys_size; /* BLD */
/* 0x1F4 */ UINT32 sys_size; /* BLD */
/* %%TBD */
/* 0x1F6 */ UINT16 swap_dev; /* BLD */
/* %%TBD */
/* 0x1F8 */ UINT16 ramdisk_flags; /* BLD */
#define RAMDISK_PROMPT 0x8000
#define RAMDISK_LOAD 0x4000
/* 0x1F8 */ UINT16 ram_size_DNU; /* BLD */
/* %%TBD */
/* 0x1FA */ UINT16 video_mode_flag; /* BLD */
@ -236,12 +231,8 @@ typedef union x86_64_boot_params {
/* %%TBD */
/* 0x1FC */ UINT16 orig_root_dev; /* BLD */
/* 0x1FE */ UINT8 unused_6; /* unused */
/* %%TBD */
/* 0x1FF */ UINT8 aux_dev_info; /* LDR */
#define NO_MOUSE 0x00
#define FOUND_MOUSE 0xAA
/* 0x1FE */ UINT16 boot_flag; /* ? */
/* Jump past setup data (not used in EFI). */
/* 0x200 */ UINT16 jump; /* BLD */
@ -283,16 +274,21 @@ typedef union x86_64_boot_params {
/* 0x21C */ UINT32 initrd_size; /* LDR */
/* %%TBD */
/* 0x220 */ UINT32 bootsect_helper; /* BLD */
/* 0x220 */ UINT32 bootsect_helper_DNU; /* BLD */
/* %%TBD */
/* 0x224 */ UINT16 heap_end_ptr; /* LDR */
/* %%TBD */
/* 0x226 */ UINT16 unused_7; /* LDR */
/* 0x226 */ UINT8 ext_loader_ver; /* LDR */
/* 0x227 */ UINT8 ext_loader_type; /* LDR */
/* 0x228 */ UINT32 cmdline_addr; /* LDR */
/* 0x22C */ UINT32 unused_8[41];
/* 0x22C */ UINT32 initrd_addr_max; /* BLD */
/* 0x230 */ UINT32 kernel_alignment; /* BLD */
/* 0x234 */ UINT8 relocatable_kernel; /* BLD */
/* 0x235 */ UINT8 pad_8[3];
/* 0x238 */ UINT32 pad_9[38];
/* 0x2D0 */ UINT8 e820_map[2560];
} s;
} boot_params_t;
@ -368,6 +364,7 @@ extern UINT8 rmswitch_image[];
extern UINTN rmswitch_size;
extern INTN x86_64_use_legacy_free_boot();
extern INTN x86_64_text_mode();
/*
* How to jump to kernel code
@ -382,7 +379,6 @@ start_kernel(VOID *kentry, boot_params_t *bp)
UINT16 kernel_cs;
} jumpvector;
VOID *jump_start;
uint64_t temp;
/*
* Disable interrupts.
@ -390,22 +386,16 @@ start_kernel(VOID *kentry, boot_params_t *bp)
asm volatile ( "cli" : : );
/*
* Relocate kernel (if needed), and initrd (if present).
* Copy kernel first, in case kernel was loaded overlapping where we're
* planning to copy the initrd. This assumes that the initrd didn't
* get loaded overlapping where we're planning to copy the kernel, but
* that's pretty unlikely since we couldn't alloc that space for the
* kernel (or the kernel would already be there).
* Relocate kernel (if needed).
* This assumes that the initrd didn't get loaded overlapping where
* we're planning to copy the kernel, but that's pretty unlikely
* since we couldn't alloc that space for the kernel (or the kernel
* would already be there).
*/
if (kernel_start != kernel_load_address) {
MEMCPY(kernel_start, kernel_load_address, kernel_size);
}
if (bp->s.initrd_start) {
temp = bp->s.initrd_start;
MEMCPY(INITRD_START, temp , bp->s.initrd_size);
bp->s.initrd_start = INITRD_START;
}
/*
* Copy boot sector, setup data and command line
* to final resting place. We need to copy
@ -468,7 +458,8 @@ start_kernel(VOID *kentry, boot_params_t *bp)
}
typedef struct sys_img_options {
UINT8 nothing_yet;
UINT8 dummy; /* forces non-zero offset for first field */
UINT8 text_mode; /* do not try to initialize Graphics Output Protocol */
} sys_img_options_t;
#endif /* __ELILO_SYSDEPS_X86_64_H__ */

View file

@ -38,11 +38,19 @@
*/
#include <efi.h>
#include <efilib.h>
#include <string.h>
#include "elilo.h"
#include "loader.h"
#include "rmswitch.h"
#define DEBUG_CREATE_BOOT_PARAMS 0
#if DEBUG_CREATE_BOOT_PARAMS
#define DPR(a) do { if (elilo_opt.debug) { Print a; } } while ( 0 )
#else
#define DPR(a)
#endif
extern loader_ops_t bzimage_loader, plain_loader, gzip_loader;
/*
@ -105,14 +113,16 @@ UINTN high_base_mem = 0x90000;
UINTN high_ext_mem = 32 * 1024 * 1024;
/* This starting address will hold true for all of the loader types for now */
VOID *kernel_start = (void *)DEFAULT_KERNEL_START;
VOID *kernel_start = (VOID *)DEFAULT_KERNEL_START;
/* The kernel may load elsewhere if EFI firmware reserves kernel_start */
VOID *kernel_load_address = DEFAULT_KERNEL_START;
VOID *kernel_load_address = (VOID *)DEFAULT_KERNEL_START;
VOID *initrd_start = NULL;
UINTN initrd_size = 0;
INTN e820_map_overflow = 0;
INTN
sysdeps_init(EFI_HANDLE dev)
{
@ -131,10 +141,8 @@ sysdeps_init(EFI_HANDLE dev)
/*
* initrd_get_addr()
* Compute a starting address for the initial RAMdisk image.
* For now, this image is placed immediately after the end of
* the kernel memory. Inside the start_kernel() code, the
* RAMdisk image will be relocated to the top of available
* extended memory.
* For now we suggest 'initrd_addr_max' with room for 32MB,
* as image->pgcnt is not initialized yet.
*/
INTN
sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem)
@ -146,10 +154,12 @@ sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem)
return -1;
}
VERB_PRT(3, Print(L"kstart="PTR_FMT" kentry="PTR_FMT" kend="PTR_FMT"\n",
kd->kstart, kd->kentry, kd->kend));
VERB_PRT(3, Print(L"initrd_addr_max="PTR_FMT" reserve=%d\n",
param_start->s.initrd_addr_max, 32*MB));
imem->start_addr = kd->kend;
imem->start_addr = (VOID *)
(((UINT64)param_start->s.initrd_addr_max - 32*MB + 1)
& ~EFI_PAGE_MASK);
VERB_PRT(3, Print(L"initrd start_addr="PTR_FMT" pgcnt=%d\n",
imem->start_addr, imem->pgcnt));
@ -157,6 +167,48 @@ sysdeps_initrd_get_addr(kdesc_t *kd, memdesc_t *imem)
return 0;
}
/*
* checkfix_initrd()
* Check and possibly fix allocation of initrd memory.
*/
VOID *
sysdeps_checkfix_initrd(VOID *start_addr, memdesc_t *imem)
{
UINTN pgcnt = EFI_SIZE_TO_PAGES(imem->size);
UINT64 initrd_addr_max = (UINT64)param_start->s.initrd_addr_max;
UINT64 ki_max = initrd_addr_max - imem->size + 1;
VOID *ki_max_addr;
VERB_PRT( 3, Print(L"loadfile: start_addr="PTR_FMT
" ki_max_addr="PTR_FMT"\n", start_addr, (VOID *)ki_max));
if (ki_max > UINT32_MAX) {
ERR_PRT((L"Force kernel specified initrd_addr_max="PTR_FMT
" below 4GB\n", (VOID *)initrd_addr_max));
ki_max = UINT32_MAX - imem->size + 1;
}
ki_max_addr = (VOID *)ki_max;
if ((UINT64)start_addr > ki_max) {
VERB_PRT(1, Print(L"initrd start_addr="PTR_FMT" above "
"limit="PTR_FMT"\n", start_addr, ki_max_addr));
free(start_addr);
start_addr = NULL;
}
/* so either the initial allocation failed or it's been to high! */
if (start_addr == NULL) {
start_addr = alloc_pages(pgcnt, EfiLoaderData,
AllocateMaxAddress, ki_max_addr);
}
if ((UINT64)start_addr > ki_max) {
ERR_PRT((L"Failed to allocate %d pages below %dMB",
pgcnt, (param_start->s.initrd_addr_max+1)>>20));
free(start_addr);
start_addr = NULL;
}
return start_addr;
}
VOID
sysdeps_free_boot_params(boot_params_t *bp)
{
@ -199,6 +251,10 @@ static INTN get_video_info(boot_params_t * bp) {
UINTN size1;
UINT8 i;
if (x86_64_text_mode() == 1) {
Print((L"Skip GOP init, force text-mode.\n"));
return -1;
}
efi_status = uefi_call_wrapper(
BS->LocateHandle,
5,
@ -209,7 +265,19 @@ static INTN get_video_info(boot_params_t * bp) {
(VOID **)Gop_handle);
if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) {
ERR_PRT((L"LocateHandle GopProtocol failed."));
Print(L"LocateHandle GopProtocol failed.\n");
Print(L"--Either no graphics head is installed,\n" \
"--efi console is set to serial, or,\n" \
"--the EFI firmware version of this machine is\n" \
"--older than UEFI 2.0. and does not support GOP");
Print(L"you can SAFELY IGNORE this error. elilo will\n" \
"default to text-mode.\n Alternatively you can " \
"now force text mode by setting config variable\n" \
"text_mode=1 for x86 in elilo.conf or via cmdline.\n\n");
Print(L"However if this is the last text output you see\n" \
"ensure that your kernel console command line\n " \
"variable matches up with the actual efi boot menu\n" \
"console output settings.\n\n");
return -1;
}
Gop_handle = alloc(size, 0);
@ -326,10 +394,56 @@ static INTN get_video_info(boot_params_t * bp) {
return 0;
}
CHAR16 *
StrStr(IN const CHAR16 *h, IN const CHAR16 *n)
{
const CHAR16 *t = h;
CHAR16 *res;
int len = 0, i;
len = StrLen((CHAR16 *)n);
while(*t != CHAR_NULL) {
res = StrChr( t, n[0]);
if (!res) return res;
for( i = 1; i < len && res[i] != CHAR_NULL && res[i] == n[i]; i++);
if ( i == len ) return res;
t = res + 1;
if (t > h + CMDLINE_MAXLEN) return (CHAR16 *)0;
}
return (CHAR16 *)0;
}
CHAR8 *
StrStr8(IN const CHAR8 *h, IN const CHAR8 *n)
{
const CHAR8 *t = h;
CHAR8 *res;
int len = 0, i;
len = strlena((CHAR8 *)n);
while(*t != 0) {
res = strchra( t, n[0]);
if (!res) return res;
for( i = 1; i < len && res[i] != 0 && res[i] == n[i]; i++);
if ( i == len ) return res;
t = res + 1;
if (t > (h + CMDLINE_MAXLEN)) return (CHAR8 *)0;
}
return (CHAR8 *)0;
}
/* Convert EFI memory map to E820 map for the operating system
* This code is based on a Linux kernel patch submitted by Edgar Hucek
*/
#if DEBUG_CREATE_BOOT_PARAMS
static int e820_max = 6;
#else
static int e820_max = E820_MAX;
#endif
/* Add a memory region to the e820 map */
static void add_memory_region (struct e820entry *e820_map,
int *e820_nr_map,
@ -338,21 +452,56 @@ static void add_memory_region (struct e820entry *e820_map,
unsigned int type)
{
int x = *e820_nr_map;
static unsigned long long estart = 0ULL;
static unsigned long esize = 0L;
static unsigned int etype = -1;
static int merge = 0;
if (x == E820_MAX) {
Print(L"Too many entries in the memory map!\n");
if (x == 0)
DPR((L"AMR: %3s %4s %16s/%12s/%s\n",
L"idx", L" ", L"start", L"size", L"type"));
/* merge adjacent regions of same type */
if ((x > 0) && e820_map[x-1].addr + e820_map[x-1].size == start
&& e820_map[x-1].type == type) {
e820_map[x-1].size += size;
estart = e820_map[x-1].addr;
esize = e820_map[x-1].size;
etype = e820_map[x-1].type;
merge++;
return;
}
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 {
/* fill up to E820_MAX */
if ( x < e820_max ) {
e820_map[x].addr = start;
e820_map[x].size = size;
e820_map[x].type = type;
(*e820_nr_map)++;
if (merge) DPR((L"AMR: %3d ==> %016llx/%012lx/%d (%d)\n",
x-1, estart, esize, etype, merge));
merge=0;
DPR((L"AMR: %3d add %016llx/%012lx/%d\n",
x, start, size, type));
return;
}
/* different type means another region didn't fit */
/* or same type, but there's a hole */
if (etype != type || (estart + esize) != start) {
if (merge) DPR((L"AMR: %3d ===> %016llx/%012lx/%d (%d)\n",
e820_map_overflow, estart, esize, etype, merge));
merge = 0;
estart = start;
esize = size;
etype = type;
e820_map_overflow++;
DPR((L"AMR: %3d OVER %016llx/%012lx/%d\n",
e820_map_overflow, start, size, type));
return;
}
/* same type and no hole, merge it */
estart += esize;
esize += size;
merge++;
}
void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc)
@ -431,6 +580,7 @@ void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc)
break;
default:
/* We should not hit this case */
DBG_PRT((L"hit default!?"));
add_memory_region(e820_map, &e820_nr_map,
md->PhysicalStart,
md->NumberOfPages << EFI_PAGE_SHIFT,
@ -444,6 +594,8 @@ void fill_e820map(boot_params_t *bp, mmap_desc_t *mdesc)
/*
* x86_64 specific boot parameters initialization routine
*
* Note: debug and verbose messages have already been turned off!
*/
INTN
sysdeps_create_boot_params(
@ -459,6 +611,12 @@ sysdeps_create_boot_params(
UINT8 row, col;
UINT8 mode;
UINT16 hdr_version;
UINT8 e820_map_overflow_warned = 0;
#if DEBUG_CREATE_BOOT_PARAMS
elilo_opt.debug=1;
elilo_opt.verbose=5;
#endif
DBG_PRT((L"fill_boot_params()\n"));
@ -493,17 +651,9 @@ sysdeps_create_boot_params(
hdr_version = (bp->s.hdr_major << 8) | bp->s.hdr_minor;
/*
* Clear out unused memory in boot sector image.
* Do NOT clear out unknown memory in boot sector image.
* This breaks boot protocol >= 2.10 (2.6.31).
*/
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);
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.
@ -553,19 +703,19 @@ sysdeps_create_boot_params(
DBG_PRT((L"initrd->start_addr="PTR_FMT" initrd->pgcnt=%d\n",
initrd->start_addr, initrd->pgcnt));
/* These RAMdisk flags are not needed, just zero them. */
bp->s.ramdisk_flags = 0;
/* These RAMdisk flags are not needed, just zero them. NOT!*/
/* 'ramdisk_flags' (@0x1F8) is called 'ram_size' in the meantime, */
/* see Documentation/x86/boot.txt. */
if (initrd->start_addr && initrd->pgcnt) {
if ( (UINT64)initrd->start_addr > UINT32_MAX ) {
ERR_PRT((L"Start of initrd out of reach (>4GB)."));
free_kmem();
return -1;
}
/* %%TBD - This will probably have to be changed. */
bp->s.initrd_start = (UINT32)(UINT64)initrd->start_addr;
bp->s.initrd_size = (UINT32)(initrd->size);
/*
* This is the RAMdisk root device for RedHat 2.2.x
* kernels (major 0x01, minor 0x00).
*/
bp->s.orig_root_dev = 0x0100;
} else {
bp->s.initrd_start = 0;
bp->s.initrd_size = 0;
@ -589,11 +739,6 @@ sysdeps_create_boot_params(
bp->s.mca_info_len = 0;
ZeroMem(bp->s.mca_info_buf, sizeof bp->s.mca_info_buf);
/*
* Pointing device presence. The kernel will detect this.
*/
bp->s.aux_dev_info = NO_MOUSE;
/*
* EFI loader signature
*/
@ -602,6 +747,11 @@ sysdeps_create_boot_params(
/*
* Kernel entry point.
*/
if ( (UINT64)kernel_start != (UINT32)(UINT64)kernel_start ) {
ERR_PRT((L"Start of kernel (will be) out of reach (>4GB)."));
free_kmem();
return -1;
}
bp->s.kernel_start = (UINT32)(UINT64)kernel_start;
/*
@ -692,11 +842,9 @@ sysdeps_create_boot_params(
CHECK_OFFSET(setup_sectors, 0x1F1, L"%xh");
CHECK_OFFSET(mount_root_rdonly, 0x1F2, L"%xh");
CHECK_OFFSET(sys_size, 0x1F4, L"%xh");
CHECK_OFFSET(swap_dev, 0x1F6, L"%xh");
CHECK_OFFSET(ramdisk_flags, 0x1F8, L"%xh");
CHECK_OFFSET(video_mode_flag, 0x1FA, L"%xh");
CHECK_OFFSET(orig_root_dev, 0x1FC, L"%xh");
CHECK_OFFSET(aux_dev_info, 0x1FF, L"%xh");
CHECK_OFFSET(boot_flag, 0x1FE, L"%xh");
CHECK_OFFSET(jump, 0x200, L"%xh");
CHECK_OFFSET(setup_sig, 0x202, L"'%-4.4a'");
CHECK_OFFSET(hdr_minor, 0x206, L"%xh");
@ -710,9 +858,9 @@ sysdeps_create_boot_params(
CHECK_OFFSET(kernel_start, 0x214, L"%xh");
CHECK_OFFSET(initrd_start, 0x218, L"%xh");
CHECK_OFFSET(initrd_size, 0x21C, L"%xh");
CHECK_OFFSET(bootsect_helper, 0x220, L"%xh");
CHECK_OFFSET(heap_end_ptr, 0x224, L"%xh");
CHECK_OFFSET(cmdline_addr, 0x228, L"%xh");
CHECK_OFFSET(e820_map, 0x2D0, L"%xh");
if (test) {
ERR_PRT((L"Boot sector and/or setup parameter alignment error."));
@ -802,6 +950,31 @@ do_memmap:
* and update the bootparam accordingly
*/
fill_e820map(bp, &mdesc);
#if DEBUG_CREATE_BOOT_PARAMS
if ( e820_map_overflow == 0 )
e820_map_overflow = -1; /* force second get_memmap()! */
#endif
if (e820_map_overflow && !e820_map_overflow_warned) {
CHAR8 *aem = (CHAR8 *)"add_efi_memmap";
e820_map_overflow_warned++;
#if DEBUG_CREATE_BOOT_PARAMS
elilo_opt.debug=0;
elilo_opt.verbose=0;
#endif
if (e820_map_overflow == -1 || StrStr8(cmdline, aem)) {
/* Print(L"...mapping again, silently!\n"); */
goto do_memmap;
}
Print(L"\nCAUTION: EFI memory map has %d more entr%a"
" than E820 map supports.\n"
"To access all memory, '%a' may be necessary.\n\n",
e820_map_overflow, (e820_map_overflow==1)?"y":"ies",
aem);
goto do_memmap;
}
return 0;
}