diff options
author | Paul Mundt <lethal@linux-sh.org> | 2010-05-06 15:09:45 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-05-06 15:09:45 +0900 |
commit | 9b7a37853a8cd69829eb1d9715a6c09aae01eeec (patch) | |
tree | 0ae5f3290d5a3804fc87b7af5af5943104d9531e /arch | |
parent | 1483feac74fdfd84a7ed7586c66482842e3b6e86 (diff) |
sh: Make initrd detection more robust.
Various boot loaders go to various extents to thwart the initrd detection
logic (mostly on account of not being able to be bothered with adhering
to the established boot ABI), so we make the detection logic a bit more
robust. This makes it possible to work around the SDK7786's firmware's
attempts to thwart compressed image booting. Victory is mine.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sh/kernel/setup.c | 78 |
1 files changed, 58 insertions, 20 deletions
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 14735d5ede5..9c7f7811af7 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -188,6 +188,63 @@ static inline void __init reserve_crashkernel(void) {} #endif +static void __init check_for_initrd(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD + unsigned long start, end; + + /* + * Check for the rare cases where boot loaders adhere to the boot + * ABI. + */ + if (!LOADER_TYPE || !INITRD_START || !INITRD_SIZE) + goto disable; + + start = INITRD_START + __MEMORY_START; + end = start + INITRD_SIZE; + + if (unlikely(end <= start)) + goto disable; + if (unlikely(start & ~PAGE_MASK)) { + pr_err("initrd must be page aligned\n"); + goto disable; + } + + if (unlikely(start < PAGE_OFFSET)) { + pr_err("initrd start < PAGE_OFFSET\n"); + goto disable; + } + + if (unlikely(end > lmb_end_of_DRAM())) { + pr_err("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + end, (unsigned long)lmb_end_of_DRAM()); + goto disable; + } + + /* + * If we got this far inspite of the boot loader's best efforts + * to the contrary, assume we actually have a valid initrd and + * fix up the root dev. + */ + ROOT_DEV = Root_RAM0; + + /* + * Address sanitization + */ + initrd_start = (unsigned long)__va(__pa(start)); + initrd_end = initrd_start + INITRD_SIZE; + + reserve_bootmem(__pa(initrd_start), INITRD_SIZE, BOOTMEM_DEFAULT); + + return; + +disable: + pr_info("initrd disabled\n"); + initrd_start = initrd_end = 0; +#endif +} + void __cpuinit calibrate_delay(void) { struct clk *clk = clk_get(NULL, "cpu_clk"); @@ -277,26 +334,7 @@ void __init setup_bootmem_allocator(unsigned long free_pfn) sparse_memory_present_with_active_regions(0); -#ifdef CONFIG_BLK_DEV_INITRD - ROOT_DEV = Root_RAM0; - - if (LOADER_TYPE && INITRD_START) { - unsigned long initrd_start_phys = INITRD_START + __MEMORY_START; - - if (initrd_start_phys + INITRD_SIZE <= PFN_PHYS(max_low_pfn)) { - reserve_bootmem(initrd_start_phys, INITRD_SIZE, - BOOTMEM_DEFAULT); - initrd_start = (unsigned long)__va(initrd_start_phys); - initrd_end = initrd_start + INITRD_SIZE; - } else { - printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - initrd_start_phys + INITRD_SIZE, - (unsigned long)PFN_PHYS(max_low_pfn)); - initrd_start = 0; - } - } -#endif + check_for_initrd(); reserve_crashkernel(); } |