SHA256
1
0
forked from pool/elilo
elilo/elilo-x86-64-initrd.diff

229 lines
6.9 KiB
Diff
Raw Normal View History

---
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);