powerpc: select endianness
This patch allows to build tests for ppc64 little endian target
(ppc64le) on big and little endian hosts.
We add a new parameter to configure to select the endianness of the
tests (--endian=little or --endian=big).
I have built and tested big and little endian tests on a little
endian host, a big endian host, with kvm_hv and kvm_pr, and on
x86_64 with ppc64 as a TCG target.
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1456824930-15078-3-git-send-email-lvivier@redhat.com>
Reviewed-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/configure b/configure
index a685cca..958321d 100755
--- a/configure
+++ b/configure
@@ -10,6 +10,7 @@
arch=`uname -m | sed -e 's/i.86/i386/;s/arm.*/arm/;s/ppc64.*/ppc64/'`
host=$arch
cross_prefix=
+endian=""
usage() {
cat <<-EOF
@@ -23,6 +24,7 @@
--ld=LD ld linker to use ($ld)
--prefix=PREFIX where to install things ($prefix)
--kerneldir=DIR kernel build directory for kvm.h ($kerneldir)
+ --endian=ENDIAN endianness to compile for (little or big, ppc64 only)
EOF
exit 1
}
@@ -50,6 +52,9 @@
--cross-prefix)
cross_prefix="$arg"
;;
+ --endian)
+ endian="$arg"
+ ;;
--cc)
cc="$arg"
;;
@@ -84,6 +89,10 @@
elif [ "$arch" = "ppc64" ]; then
testdir=powerpc
firmware="$testdir/boot_rom.bin"
+ if [ "$endian" != "little" ] && [ "$endian" != "big" ]; then
+ echo "You must provide endianness (big or little)!"
+ usage
+ fi
else
testdir=$arch
fi
@@ -139,4 +148,5 @@
API=$api
TEST_DIR=$testdir
FIRMWARE=$firmware
+ENDIAN=$endian
EOF
diff --git a/lib/powerpc/asm/ppc_asm.h b/lib/powerpc/asm/ppc_asm.h
index f63bb72..f18100e 100644
--- a/lib/powerpc/asm/ppc_asm.h
+++ b/lib/powerpc/asm/ppc_asm.h
@@ -11,4 +11,23 @@
#define LOAD_REG_ADDR(reg,name) \
ld reg,name@got(r2)
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+
+#define FIXUP_ENDIAN
+
+#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+
+#define FIXUP_ENDIAN \
+ .long 0x05000048; /* bl . + 4 */ \
+ .long 0xa602487d; /* mflr r10 */ \
+ .long 0x20004a39; /* addi r10,r10,32 */ \
+ .long 0xa600607d; /* mfmsr r11 */ \
+ .long 0x01006b69; /* xori r11,r11,1 */ \
+ .long 0xa6035a7d; /* mtsrr0 r10 */ \
+ .long 0xa6037b7d; /* mtsrr1 r11 */ \
+ .long 0x2400004c; /* rfid */ \
+ .long 0x00000048; /* b . */ \
+
+#endif /* __BYTE_ORDER__ */
+
#endif /* _ASMPOWERPC_PPC_ASM_H */
diff --git a/lib/powerpc/asm/rtas.h b/lib/powerpc/asm/rtas.h
index 522225b..9012a1e 100644
--- a/lib/powerpc/asm/rtas.h
+++ b/lib/powerpc/asm/rtas.h
@@ -5,6 +5,9 @@
*
* This work is licensed under the terms of the GNU LGPL, version 2.
*/
+
+#ifndef __ASSEMBLY__
+
#include <libcflat.h>
#define RTAS_UNKNOWN_SERVICE (-1)
@@ -22,5 +25,8 @@
extern int rtas_call(int token, int nargs, int nret, int *outputs, ...);
extern void rtas_power_off(void);
+#endif /* __ASSEMBLY__ */
+
+#define RTAS_MSR_MASK 0xfffffffffffffffe
#endif /* _ASMPOWERPC_RTAS_H_ */
diff --git a/lib/ppc64/asm/io.h b/lib/ppc64/asm/io.h
index c0801d4..4f2c31b 100644
--- a/lib/ppc64/asm/io.h
+++ b/lib/ppc64/asm/io.h
@@ -1,5 +1,13 @@
#ifndef _ASMPPC64_IO_H_
#define _ASMPPC64_IO_H_
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define __cpu_is_be() (0)
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define __cpu_is_be() (1)
+#else
+#error Undefined byte order
+#endif
+
#include <asm-generic/io.h>
#endif
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index cc27ac8..b526668 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -11,7 +11,6 @@
##################################################################
-CFLAGS += $(arch_CFLAGS)
CFLAGS += -std=gnu99
CFLAGS += -ffreestanding
CFLAGS += -Wextra
@@ -32,6 +31,7 @@
cflatobjs += lib/powerpc/rtas.o
FLATLIBS = $(libcflat) $(LIBFDT_archive)
+%.elf: CFLAGS += $(arch_CFLAGS)
%.elf: LDFLAGS = $(arch_LDFLAGS) -nostdlib -pie
%.elf: %.o $(FLATLIBS) powerpc/flat.lds
$(LD) $(LDFLAGS) -o $@ \
@@ -48,6 +48,7 @@
dd if=/dev/zero of=$@ bs=256 count=1
$(OBJCOPY) -O binary $^ >(cat - >>$@)
+$(TEST_DIR)/boot_rom.elf: CFLAGS = -mbig-endian
$(TEST_DIR)/boot_rom.elf: $(TEST_DIR)/boot_rom.o
$(LD) -EB -nostdlib -Ttext=0x100 --entry=start --build-id=none -o $@ $<
diff --git a/powerpc/Makefile.ppc64 b/powerpc/Makefile.ppc64
index 2df44d4..3da3a83 100644
--- a/powerpc/Makefile.ppc64
+++ b/powerpc/Makefile.ppc64
@@ -5,8 +5,13 @@
#
bits = 64
-arch_CFLAGS = -mbig-endian
-arch_LDFLAGS = -EB
+ifeq ($(ENDIAN),little)
+ arch_CFLAGS = -mlittle-endian
+ arch_LDFLAGS = -EL
+else
+ arch_CFLAGS = -mbig-endian
+ arch_LDFLAGS = -EB
+endif
cstart.o = $(TEST_DIR)/cstart64.o
reloc.o = $(TEST_DIR)/reloc64.o
diff --git a/powerpc/cstart64.S b/powerpc/cstart64.S
index 6072597..c87e3d6 100644
--- a/powerpc/cstart64.S
+++ b/powerpc/cstart64.S
@@ -8,6 +8,7 @@
#define __ASSEMBLY__
#include <asm/hcall.h>
#include <asm/ppc_asm.h>
+#include <asm/rtas.h>
.section .init
@@ -16,6 +17,7 @@
*/
.globl start
start:
+ FIXUP_ENDIAN
/*
* We were loaded at QEMU's kernel load address, but we're not
* allowed to link there due to how QEMU deals with linker VMAs,
@@ -84,12 +86,22 @@
enter_rtas:
mflr r0
std r0, 16(r1)
+
+ LOAD_REG_ADDR(r10, rtas_return_loc)
+ mtlr r10
LOAD_REG_ADDR(r11, rtas_entry)
ld r10, 0(r11)
-//FIXME: change this bctrl to an rtas-prep, rfid, rtas-return sequence
- mtctr r10
- nop
- bctrl
+
+ mfmsr r11
+ LOAD_REG_IMMEDIATE(r9, RTAS_MSR_MASK)
+ and r11, r11, r9
+ mtsrr0 r10
+ mtsrr1 r11
+ rfid
+ b .
+
+rtas_return_loc:
+ FIXUP_ENDIAN
ld r0, 16(r1)
mtlr r0
blr