forked from pool/elilo
163b743a22
Accepted submit request 56257 from user coolo OBS-URL: https://build.opensuse.org/request/show/56257 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/elilo?expand=0&rev=18
258 lines
7.7 KiB
Diff
258 lines
7.7 KiB
Diff
---
|
|
alloc.c | 10 +++
|
|
ia32/bzimage.c | 2
|
|
x86_64/bzimage.c | 160 +++++++++++++++++++++++++++++++++++++++++++++----------
|
|
x86_64/sysdeps.h | 5 +
|
|
x86_64/system.c | 9 ++-
|
|
5 files changed, 152 insertions(+), 34 deletions(-)
|
|
|
|
--- a/alloc.c
|
|
+++ b/alloc.c
|
|
@@ -217,7 +217,15 @@ INTN
|
|
alloc_kmem_anywhere(VOID **start_addr, UINTN pgcnt)
|
|
{
|
|
void * tmp;
|
|
- if ((tmp = alloc_pages(pgcnt, EfiLoaderData, AllocateAnyPages, *start_addr)) == 0) return -1;
|
|
+ /*
|
|
+ * During "AllocateAnyPages" *start_addr will be ignored.
|
|
+ * Therefore we can safely subvert it to reuse this function with
|
|
+ * an alloc_kmem_anyhwere_below() semantic...
|
|
+ */
|
|
+ tmp = alloc_pages(pgcnt, EfiLoaderData,
|
|
+ (*start_addr) ? AllocateMaxAddress : AllocateAnyPages,
|
|
+ *start_addr);
|
|
+ if (tmp == NULL) return -1;
|
|
|
|
kmem_addr = tmp;
|
|
kmem_pgcnt = pgcnt;
|
|
--- a/ia32/bzimage.c
|
|
+++ b/ia32/bzimage.c
|
|
@@ -169,7 +169,7 @@ bzImage_probe(CHAR16 *kname)
|
|
kernel_start));
|
|
}
|
|
|
|
- kernel_load_address = kernel_start;
|
|
+ kernel_load_address = NULL; /* allocate anywhere! */
|
|
|
|
if (alloc_kmem(kernel_start, EFI_SIZE_TO_PAGES(kernel_size)) != 0) {
|
|
/*
|
|
--- a/x86_64/bzimage.c
|
|
+++ b/x86_64/bzimage.c
|
|
@@ -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,37 +281,16 @@ 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 = 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;
|
|
- }
|
|
+ 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;
|
|
}
|
|
|
|
- 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.
|
|
*/
|
|
--- a/x86_64/sysdeps.h
|
|
+++ b/x86_64/sysdeps.h
|
|
@@ -285,7 +285,10 @@ typedef union x86_64_boot_params {
|
|
|
|
/* 0x228 */ UINT32 cmdline_addr; /* LDR */
|
|
/* 0x22C */ UINT32 initrd_addr_max; /* BLD */
|
|
-/* 0x230 */ UINT32 pad_8[40];
|
|
+/* 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;
|
|
--- a/x86_64/system.c
|
|
+++ b/x86_64/system.c
|
|
@@ -105,10 +105,10 @@ 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;
|
|
@@ -631,6 +631,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;
|
|
|
|
/*
|