File elilo-x86-64-initrd.diff of Package elilo

---
 elilo.h          |    5 ++++
 ia32/system.c    |    6 +++++
 ia64/system.c    |    6 +++++
 initrd.c         |   12 +++++++++-
 x86_64/sysdeps.h |   20 ++++++------------
 x86_64/system.c  |   61 ++++++++++++++++++++++++++++++++++++++++++++++++-------
 6 files changed, 88 insertions(+), 22 deletions(-)

--- a/elilo.h
+++ b/elilo.h
@@ -54,6 +54,10 @@
 #define ROUNDUP(x,a)	(((x) + (a) - 1) & ~((a) - 1))
 #define ROUNDDOWN(x,a)  ((x) & ~((a) - 1))
 
+#ifndef UINT32_MAX
+#define UINT32_MAX	((UINT32)-1)
+#endif
+
 /*
  * Elilo Boot modes
  */
@@ -212,6 +216,7 @@ extern CHAR16 *sysdeps_get_cmdline_opts(
 extern INTN sysdeps_getopt(INTN, INTN, CHAR16 *);
 extern VOID sysdeps_print_cmdline_opts(VOID);
 extern INTN sysdeps_register_options(VOID);
+extern VOID *sysdeps_checkfix_initrd(VOID *, memdesc_t *);
 
 #define	CHAR_SLASH	L'/'
 #define CHAR_BACKSLASH	L'\\'
--- a/ia32/system.c
+++ b/ia32/system.c
@@ -149,6 +149,12 @@ sysdeps_initrd_get_addr(kdesc_t *kd, mem
 	return 0;
 }
 
+VOID *
+sysdeps_checkfix_initrd(VOID *start_addr, memdesc_t *imem)
+{
+	return start_addr;
+}
+
 VOID
 sysdeps_free_boot_params(boot_params_t *bp)
 {
--- a/ia64/system.c
+++ b/ia64/system.c
@@ -140,6 +140,12 @@ sysdeps_initrd_get_addr(kdesc_t *kd, mem
 	return 0;
 }
 
+VOID *
+sysdeps_checkfix_initrd(VOID *start_addr, memdesc_t *imem)
+{
+	return start_addr;
+}
+
 /* Flush data cache [addr; addr + len], and sync with icache.  */
 void
 flush_dcache (CHAR8 *addr, UINT64 len)
--- a/initrd.c
+++ b/initrd.c
@@ -41,7 +41,11 @@ INTN
 load_file(CHAR16 *filename, memdesc_t *image)
 {
 	EFI_STATUS status;
-	VOID *start_addr = NULL;
+	/*
+	 * Actually using the value from sysdeps_initrd_get_addr()
+	 * instead of NULL is no change for ia64!
+	 */
+	VOID *start_addr = image->start_addr;
 	UINTN pgcnt;
 	UINT64 size = 0;
 	fops_fd_t fd;
@@ -71,7 +75,11 @@ load_file(CHAR16 *filename, memdesc_t *i
 	/* 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, 0 );
+	start_addr = alloc_pages(pgcnt, EfiLoaderData,
+		start_addr ? AllocateAddress : AllocateAnyPages, start_addr);
+
+	start_addr = sysdeps_checkfix_initrd(start_addr, image);
+
 	if (start_addr == NULL) {
 		ERR_PRT((L"Failed to allocate %d pages for %s image", pgcnt,
 		         filename));
--- a/x86_64/sysdeps.h
+++ b/x86_64/sysdeps.h
@@ -284,7 +284,8 @@ typedef union x86_64_boot_params {
 /* 0x227 */	UINT8 ext_loader_type;		/* LDR */
 
 /* 0x228 */	UINT32 cmdline_addr; 		/* LDR */
-/* 0x22C */	UINT32 pad_8[41];
+/* 0x22C */	UINT32 initrd_addr_max; 	/* BLD */
+/* 0x230 */	UINT32 pad_8[40];
 /* 0x2D0 */	UINT8  e820_map[2560];
 	} s;
 } boot_params_t;
@@ -374,7 +375,6 @@ start_kernel(VOID *kentry, boot_params_t
 		UINT16	kernel_cs;
 	} jumpvector;
 	VOID 	*jump_start;
-	uint64_t temp;
 
 	/*
 	 * Disable interrupts.
@@ -382,22 +382,16 @@ start_kernel(VOID *kentry, boot_params_t
 	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
--- a/x86_64/system.c
+++ b/x86_64/system.c
@@ -131,10 +131,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 +144,12 @@ sysdeps_initrd_get_addr(kdesc_t *kd, mem
 		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 +157,48 @@ sysdeps_initrd_get_addr(kdesc_t *kd, mem
 	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)
 {
@@ -550,6 +592,11 @@ sysdeps_create_boot_params(
 	/* 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);
openSUSE Build Service is sponsored by