On 23/10/2019 12:36, Oliver O'Halloran wrote: > When booting under OF the zImage expects the initrd address and size to be > passed to it using registers r3 and r4. SLOF (guest firmware used by QEMU) > currently doesn't do this so the zImage is not aware of the initrd > location. This can result in initrd corruption either though the zImage > extracting the vmlinux over the initrd, or by the vmlinux overwriting the > initrd when relocating itself. > > QEMU does put the linux,initrd-start and linux,initrd-end properties into > the devicetree to vmlinux to find the initrd. We can work around the SLOF > bug by also looking those properties in the zImage. This does not boot zImage for me anyway: Trying to unpack rootfs image as initramfs... rootfs image is not initramfs (invalid magic at start of compressed archive); looks like an initrd > > Cc: stable@xxxxxxxxxxxxxxx > Cc: Alexey Kardashevskiy <aik@xxxxxxxxx> > Signed-off-by: Oliver O'Halloran <oohall@xxxxxxxxx> > --- > First noticed here: https://unix.stackexchange.com/questions/547023/linux-kernel-on-ppc64le-vmlinux-equivalent-in-arch-powerpc-boot > --- > arch/powerpc/boot/devtree.c | 21 +++++++++++++++++++++ > arch/powerpc/boot/main.c | 7 +++++++ > arch/powerpc/boot/of.h | 16 ---------------- > arch/powerpc/boot/ops.h | 1 + > arch/powerpc/boot/swab.h | 17 +++++++++++++++++ > 5 files changed, 46 insertions(+), 16 deletions(-) > > diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c > index 5d91036..ac5c26b 100644 > --- a/arch/powerpc/boot/devtree.c > +++ b/arch/powerpc/boot/devtree.c > @@ -13,6 +13,7 @@ > #include "string.h" > #include "stdio.h" > #include "ops.h" > +#include "swab.h" > > void dt_fixup_memory(u64 start, u64 size) > { > @@ -318,6 +319,26 @@ int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size) > return dt_xlate(node, res, reglen, addr, size); > } > > +int dt_read_addr(void *node, const char *prop, unsigned long *out_addr) > +{ > + int reglen; > + > + *out_addr = 0; > + > + reglen = getprop(node, prop, prop_buf, sizeof(prop_buf)) / 4; > + if (reglen == 2) { > + u64 v0 = be32_to_cpu(prop_buf[0]); > + u64 v1 = be32_to_cpu(prop_buf[1]); > + *out_addr = (v0 << 32) | v1; > + } else if (reglen == 1) { > + *out_addr = be32_to_cpu(prop_buf[0]); > + } else { > + return 0; > + } > + > + return 1; > +} > + > int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr) > { > > diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c > index a9d2091..518af24 100644 > --- a/arch/powerpc/boot/main.c > +++ b/arch/powerpc/boot/main.c > @@ -112,6 +112,13 @@ static struct addr_range prep_initrd(struct addr_range vmlinux, void *chosen, > } else if (initrd_size > 0) { > printf("Using loader supplied ramdisk at 0x%lx-0x%lx\n\r", > initrd_addr, initrd_addr + initrd_size); > + } else if (chosen) { > + unsigned long initrd_end; > + > + dt_read_addr(chosen, "linux,initrd-start", &initrd_addr); > + dt_read_addr(chosen, "linux,initrd-end", &initrd_end); > + > + initrd_size = initrd_end - initrd_addr; > } > > /* If there's no initrd at all, we're done */ > diff --git a/arch/powerpc/boot/of.h b/arch/powerpc/boot/of.h > index 31b2f5d..dc24770 100644 > --- a/arch/powerpc/boot/of.h > +++ b/arch/powerpc/boot/of.h > @@ -26,22 +26,6 @@ typedef u16 __be16; > typedef u32 __be32; > typedef u64 __be64; > > -#ifdef __LITTLE_ENDIAN__ > -#define cpu_to_be16(x) swab16(x) > -#define be16_to_cpu(x) swab16(x) > -#define cpu_to_be32(x) swab32(x) > -#define be32_to_cpu(x) swab32(x) > -#define cpu_to_be64(x) swab64(x) > -#define be64_to_cpu(x) swab64(x) > -#else > -#define cpu_to_be16(x) (x) > -#define be16_to_cpu(x) (x) > -#define cpu_to_be32(x) (x) > -#define be32_to_cpu(x) (x) > -#define cpu_to_be64(x) (x) > -#define be64_to_cpu(x) (x) > -#endif > - > #define PROM_ERROR (-1u) > > #endif /* _PPC_BOOT_OF_H_ */ > diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h > index e060676..5100dd7 100644 > --- a/arch/powerpc/boot/ops.h > +++ b/arch/powerpc/boot/ops.h > @@ -95,6 +95,7 @@ void *simple_alloc_init(char *base, unsigned long heap_size, > extern void flush_cache(void *, unsigned long); > int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size); > int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr); > +int dt_read_addr(void *node, const char *prop, unsigned long *out); > int dt_is_compatible(void *node, const char *compat); > void dt_get_reg_format(void *node, u32 *naddr, u32 *nsize); > int dt_get_virtual_reg(void *node, void **addr, int nres); > diff --git a/arch/powerpc/boot/swab.h b/arch/powerpc/boot/swab.h > index 11d2069..82db2c1 100644 > --- a/arch/powerpc/boot/swab.h > +++ b/arch/powerpc/boot/swab.h > @@ -27,4 +27,21 @@ static inline u64 swab64(u64 x) > (u64)((x & (u64)0x00ff000000000000ULL) >> 40) | > (u64)((x & (u64)0xff00000000000000ULL) >> 56); > } > + > +#ifdef __LITTLE_ENDIAN__ > +#define cpu_to_be16(x) swab16(x) > +#define be16_to_cpu(x) swab16(x) > +#define cpu_to_be32(x) swab32(x) > +#define be32_to_cpu(x) swab32(x) > +#define cpu_to_be64(x) swab64(x) > +#define be64_to_cpu(x) swab64(x) > +#else > +#define cpu_to_be16(x) (x) > +#define be16_to_cpu(x) (x) > +#define cpu_to_be32(x) (x) > +#define be32_to_cpu(x) (x) > +#define cpu_to_be64(x) (x) > +#define be64_to_cpu(x) (x) > +#endif > + > #endif /* _PPC_BOOT_SWAB_H_ */ > -- Alexey