diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/kernel/setup.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 19c03a9..ef408a0 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -26,6 +26,7 @@ #include <linux/sizes.h> #include <linux/device.h> #include <linux/dma-contiguous.h> +#include <linux/decompress/generic.h> #include <asm/addrspace.h> #include <asm/bootinfo.h> @@ -243,6 +244,35 @@ disable: return 0; } +/* In some conditions (e.g. big endian bootloader with a little endian + kernel), the initrd might appear byte swapped. Try to detect this and + byte swap it if needed. */ +static void __init maybe_bswap_initrd(void) +{ +#if defined(CONFIG_CPU_CAVIUM_OCTEON) + u64 buf; + + /* Check for CPIO signature */ + if (!memcmp((void *)initrd_start, "070701", 6)) + return; + + /* Check for compressed initrd */ + if (decompress_method((unsigned char *)initrd_start, 8, NULL)) + return; + + /* Try again with a byte swapped header */ + buf = swab64p((u64 *)initrd_start); + if (!memcmp(&buf, "070701", 6) || + decompress_method((unsigned char *)(&buf), 8, NULL)) { + unsigned long i; + + pr_info("Byteswapped initrd detected\n"); + for (i = initrd_start; i < ALIGN(initrd_end, 8); i += 8) + swab64s((u64 *)i); + } +#endif +} + static void __init finalize_initrd(void) { unsigned long size = initrd_end - initrd_start; @@ -256,6 +286,8 @@ static void __init finalize_initrd(void) goto disable; } + maybe_bswap_initrd(); + reserve_bootmem(__pa(initrd_start), size, BOOTMEM_DEFAULT); initrd_below_start_ok = 1; |