Commit 8f4703aa authored by Aurelien Jarno's avatar Aurelien Jarno Committed by Ralf Baechle

MIPS: Octeon: detect and fix byte swapped initramfs

Octeon machines support running in little endian mode. U-Boot usually
runs in big endian-mode. Therefore the initramfs is loaded in big endian
mode, and the kernel later tries to access it in little endian mode.

This patch fixes that by detecting byte swapped initramfs using either the
CPIO header or the header from standard compression methods, and
byte swaps it if needed. It first checks that the header doesn't match
in the native endianness to avoid false detections. It uses the kernel
decompress library so that we don't have to maintain the list of magics
if some decompression methods are added to the kernel.
Signed-off-by: default avatarAurelien Jarno <aurelien@aurel32.net>
Acked-by: default avatarDavid Daney <david.daney@cavium.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/13219/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent b4720809
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/dma-contiguous.h> #include <linux/dma-contiguous.h>
#include <linux/decompress/generic.h>
#include <asm/addrspace.h> #include <asm/addrspace.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
...@@ -243,6 +244,35 @@ static unsigned long __init init_initrd(void) ...@@ -243,6 +244,35 @@ static unsigned long __init init_initrd(void)
return 0; 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) static void __init finalize_initrd(void)
{ {
unsigned long size = initrd_end - initrd_start; unsigned long size = initrd_end - initrd_start;
...@@ -256,6 +286,8 @@ static void __init finalize_initrd(void) ...@@ -256,6 +286,8 @@ static void __init finalize_initrd(void)
goto disable; goto disable;
} }
maybe_bswap_initrd();
reserve_bootmem(__pa(initrd_start), size, BOOTMEM_DEFAULT); reserve_bootmem(__pa(initrd_start), size, BOOTMEM_DEFAULT);
initrd_below_start_ok = 1; initrd_below_start_ok = 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment