git: f83288645cd9 - main - powerpc64le: stand fixes

From: Leandro Lupori <luporl_at_FreeBSD.org>
Date: Wed, 20 Oct 2021 19:01:55 UTC
The branch main has been updated by luporl:

URL: https://cgit.FreeBSD.org/src/commit/?id=f83288645cd9726c24ca67292fbc3abb4eb65a36

commit f83288645cd9726c24ca67292fbc3abb4eb65a36
Author:     Leandro Lupori <luporl@FreeBSD.org>
AuthorDate: 2021-10-20 18:48:33 +0000
Commit:     Leandro Lupori <luporl@FreeBSD.org>
CommitDate: 2021-10-20 18:48:33 +0000

    powerpc64le: stand fixes
    
    Fix boot1 and loader on PowerPC64 little-endian (LE).
    
    Due to endian issues, boot1 couldn't find the UFS boot partition
    and loader wasn't able to load the kernel. Most of the issues
    happened because boot1 and loader were BE binaries trying to access
    LE UFS partitions and because loader expects the kernel ELF image
    to use the same endian as itself.
    
    To fix these issues, boot1 and loader are now built as LE binaries
    on PPC64LE. To support this, the functions that call OpenFirmware
    were enhanced to correctly perform endian conversion on its input
    and output arguments and to change the CPU into BE mode before
    making the calls, as OpenFirmware always runs in BE. Besides that,
    some other small fixes were needed.
    
    Submitted by:           bdragon (initial version)
    Reviewed by:            alfredo, jhibbits
    Sponsored by:           Instituto de Pesquisas Eldorado (eldorado.org.br)
    Differential Revision:  https://reviews.freebsd.org/D32160
---
 stand/common/load_elf.c              |  18 --
 stand/defs.mk                        |   8 +-
 stand/libofw/openfirm.c              | 344 +++++++++++++++--------------------
 stand/libofw/openfirm.h              |   7 +-
 stand/powerpc/Makefile               |   6 +-
 stand/powerpc/boot1.chrp/boot1.c     | 102 ++++++++++-
 stand/powerpc/ofw/Makefile           |  14 +-
 stand/powerpc/ofw/cas.c              |  14 +-
 stand/powerpc/ofw/ldscript.powerpcle | 142 +++++++++++++++
 stand/powerpc/ofw/main.c             |  37 +++-
 stand/powerpc/ofw/ofwfdt.c           |   7 +-
 stand/powerpc/ofw/trampolineLE.S     |  71 ++++++++
 12 files changed, 525 insertions(+), 245 deletions(-)

diff --git a/stand/common/load_elf.c b/stand/common/load_elf.c
index c163b50c9737..a213b34970f0 100644
--- a/stand/common/load_elf.c
+++ b/stand/common/load_elf.c
@@ -750,13 +750,6 @@ __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, uint64_t off)
 		}
 #endif
 		size = shdr[i].sh_size;
-#if defined(__powerpc__)
-  #if __ELF_WORD_SIZE == 64
-		size = htobe64(size);
-  #else
-		size = htobe32(size);
-  #endif
-#endif
 
 		archsw.arch_copyin(&size, lastaddr, sizeof(size));
 		lastaddr += sizeof(size);
@@ -802,17 +795,6 @@ __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, uint64_t off)
 	printf("]");
 #endif
 
-#if defined(__powerpc__)
-  /* On PowerPC we always need to provide BE data to the kernel */
-  #if __ELF_WORD_SIZE == 64
-	ssym = htobe64((uint64_t)ssym);
-	esym = htobe64((uint64_t)esym);
-  #else
-	ssym = htobe32((uint32_t)ssym);
-	esym = htobe32((uint32_t)esym);
-  #endif
-#endif
-
 	file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym);
 	file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym);
 
diff --git a/stand/defs.mk b/stand/defs.mk
index aee4636985ac..765fd046a879 100644
--- a/stand/defs.mk
+++ b/stand/defs.mk
@@ -120,10 +120,12 @@ CFLAGS+= -DLOADER_DISK_SUPPORT
 
 # Machine specific flags for all builds here
 
-# Ensure PowerPC64 and PowerPC64LE boot loaders are compiled as 32 bit
-# and in big endian.
-.if ${MACHINE_ARCH:Mpowerpc64*} != ""
+# Ensure PowerPC64 and PowerPC64LE boot loaders are compiled as 32 bit.
+# PowerPC64LE boot loaders are 32-bit little-endian.
+.if ${MACHINE_ARCH} == "powerpc64"
 CFLAGS+=	-m32 -mcpu=powerpc -mbig-endian
+.elif ${MACHINE_ARCH} == "powerpc64le"
+CFLAGS+=	-m32 -mcpu=powerpc -mlittle-endian
 .endif
 
 # For amd64, there's a bit of mixed bag. Some of the tree (i386, lib*32) is
diff --git a/stand/libofw/openfirm.c b/stand/libofw/openfirm.c
index 0b4198d281fd..b2b89581ae70 100644
--- a/stand/libofw/openfirm.c
+++ b/stand/libofw/openfirm.c
@@ -58,6 +58,8 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <sys/endian.h>
+
 #include <machine/stdarg.h>
 
 #include <stand.h>
@@ -71,6 +73,13 @@ ihandle_t mmu;
 ihandle_t memory;
 int	  real_mode = 0;
 
+#define IN(x)		htobe32((cell_t)x)
+#define OUT(x)		be32toh(x)
+#define SETUP(a, b, c, d)		\
+	a.name = IN( (b) );		\
+	a.nargs = IN( (c) );		\
+	a.nreturns = IN( (d) );
+
 /* Initialiser */
 
 void
@@ -117,16 +126,13 @@ OF_test(char *name)
 		cell_t nreturns;
 		cell_t service;
 		cell_t missing;
-	} args = {
-		(cell_t)"test",
-		1,
-		1,
-	};
+	} args = {};
+	SETUP(args, "test", 1, 1);
 
-	args.service = (cell_t)name;
+	args.service = IN(name);
 	if (openfirmware(&args) == -1)
 		return (-1);
-	return (args.missing);
+	return (OUT(args.missing));
 }
 
 /* Return firmware millisecond count. */
@@ -138,14 +144,11 @@ OF_milliseconds()
 		cell_t nargs;
 		cell_t nreturns;
 		cell_t ms;
-	} args = {
-		(cell_t)"milliseconds",
-		0,
-		1,
-	};
+	} args = {};
+	SETUP(args, "milliseconds", 0, 1);
 
 	openfirmware(&args);
-	return (args.ms);
+	return (OUT(args.ms));
 }
 
 /*
@@ -162,11 +165,8 @@ OF_peer(phandle_t node)
 		cell_t nreturns;
 		cell_t node;
 		cell_t next;
-	} args = {
-		(cell_t)"peer",
-		1,
-		1,
-	};
+	} args = {};
+	SETUP(args, "peer", 1, 1);
 
 	args.node = node;
 	if (openfirmware(&args) == -1)
@@ -184,11 +184,8 @@ OF_child(phandle_t node)
 		cell_t nreturns;
 		cell_t node;
 		cell_t child;
-	} args = {
-		(cell_t)"child",
-		1,
-		1,
-	};
+	} args = {};
+	SETUP(args, "child", 1, 1);
 
 	args.node = node;
 	if (openfirmware(&args) == -1)
@@ -206,11 +203,8 @@ OF_parent(phandle_t node)
 		cell_t nreturns;
 		cell_t node;
 		cell_t parent;
-	} args = {
-		(cell_t)"parent",
-		1,
-		1,
-	};
+	} args = {};
+	SETUP(args, "parent", 1, 1);
 
 	args.node = node;
 	if (openfirmware(&args) == -1)
@@ -228,11 +222,8 @@ OF_instance_to_package(ihandle_t instance)
 		cell_t nreturns;
 		cell_t instance;
 		cell_t package;
-	} args = {
-		(cell_t)"instance-to-package",
-		1,
-		1,
-	};
+	} args = {};
+	SETUP(args, "instance-to-package", 1, 1);
 
 	args.instance = instance;
 	if (openfirmware(&args) == -1)
@@ -251,17 +242,14 @@ OF_getproplen(phandle_t package, const char *propname)
 		cell_t package;
 		cell_t propname;
 		cell_t proplen;
-	} args = {
-		(cell_t)"getproplen",
-		2,
-		1,
-	};
+	} args = {};
+	SETUP(args, "getproplen", 2, 1);
 
 	args.package = package;
-	args.propname = (cell_t)propname;
+	args.propname = IN(propname);
 	if (openfirmware(&args) == -1)
 		return (-1);
-	return (args.proplen);
+	return (OUT(args.proplen));
 }
 
 /* Get the value of a property of a package. */
@@ -277,19 +265,31 @@ OF_getprop(phandle_t package, const char *propname, void *buf, int buflen)
 		cell_t buf;
 		cell_t buflen;
 		cell_t size;
-	} args = {
-		(cell_t)"getprop",
-		4,
-		1,
-	};
+	} args = {};
+	SETUP(args, "getprop", 4, 1);
 
 	args.package = package;
-	args.propname = (cell_t)propname;
-	args.buf = (cell_t)buf;
-	args.buflen = buflen;
+	args.propname = IN(propname);
+	args.buf = IN(buf);
+	args.buflen = IN(buflen);
 	if (openfirmware(&args) == -1)
 		return (-1);
-	return (args.size);
+	return (OUT(args.size));
+}
+
+/* Decode a binary property from a package. */
+int
+OF_getencprop(phandle_t package, const char *propname, cell_t *buf, int buflen)
+{
+	int retval, i;
+	retval = OF_getprop(package, propname, buf, buflen);
+	if (retval == -1)
+		return (retval);
+
+	for (i = 0; i < buflen/4; i++)
+		buf[i] = be32toh((uint32_t)buf[i]);
+
+	return (retval);
 }
 
 /* Get the next property of a package. */
@@ -304,18 +304,15 @@ OF_nextprop(phandle_t package, const char *previous, char *buf)
 		cell_t previous;
 		cell_t buf;
 		cell_t flag;
-	} args = {
-		(cell_t)"nextprop",
-		3,
-		1,
-	};
+	} args = {};
+	SETUP(args, "nextprop", 3, 1);
 
 	args.package = package;
-	args.previous = (cell_t)previous;
-	args.buf = (cell_t)buf;
+	args.previous = IN(previous);
+	args.buf = IN(buf);
 	if (openfirmware(&args) == -1)
 		return (-1);
-	return (args.flag);
+	return (OUT(args.flag));
 }
 
 /* Set the value of a property of a package. */
@@ -332,19 +329,16 @@ OF_setprop(phandle_t package, const char *propname, void *buf, int len)
 		cell_t buf;
 		cell_t len;
 		cell_t size;
-	} args = {
-		(cell_t)"setprop",
-		4,
-		1,
-	};
+	} args = {};
+	SETUP(args, "setprop", 4, 1);
 
 	args.package = package;
-	args.propname = (cell_t)propname;
-	args.buf = (cell_t)buf;
-	args.len = len;
+	args.propname = IN(propname);
+	args.buf = IN(buf);
+	args.len = IN(len);
 	if (openfirmware(&args) == -1)
 		return (-1);
-	return (args.size);
+	return (OUT(args.size));
 }
 
 /* Convert a device specifier to a fully qualified pathname. */
@@ -359,18 +353,15 @@ OF_canon(const char *device, char *buf, int len)
 		cell_t buf;
 		cell_t len;
 		cell_t size;
-	} args = {
-		(cell_t)"canon",
-		3,
-		1,
-	};
-
-	args.device = (cell_t)device;
-	args.buf = (cell_t)buf;
-	args.len = len;
+	} args = {};
+	SETUP(args, "canon", 3, 1);
+
+	args.device = IN(device);
+	args.buf = IN(buf);
+	args.len = IN(len);
 	if (openfirmware(&args) == -1)
 		return (-1);
-	return (args.size);
+	return (OUT(args.size));
 }
 
 /* Return a package handle for the specified device. */
@@ -383,13 +374,10 @@ OF_finddevice(const char *device)
 		cell_t nreturns;
 		cell_t device;
 		cell_t package;
-	} args = {
-		(cell_t)"finddevice",
-		1,
-		1,
-	};
+	} args = {};
+	SETUP(args, "finddevice", 1, 1);
 
-	args.device = (cell_t)device;
+	args.device = IN(device);
 	if (openfirmware(&args) == -1)
 		return (-1);
 	return (args.package);
@@ -407,18 +395,15 @@ OF_instance_to_path(ihandle_t instance, char *buf, int len)
 		cell_t buf;
 		cell_t len;
 		cell_t size;
-	} args = {
-		(cell_t)"instance-to-path",
-		3,
-		1,
-	};
+	} args = {};
+	SETUP(args, "instance-to-path", 3, 1);
 
 	args.instance = instance;
-	args.buf = (cell_t)buf;
-	args.len = len;
+	args.buf = IN(buf);
+	args.len = IN(len);
 	if (openfirmware(&args) == -1)
 		return (-1);
-	return (args.size);
+	return (OUT(args.size));
 }
 
 /* Return the fully qualified pathname corresponding to a package. */
@@ -433,18 +418,15 @@ OF_package_to_path(phandle_t package, char *buf, int len)
 		cell_t buf;
 		cell_t len;
 		cell_t size;
-	} args = {
-		(cell_t)"package-to-path",
-		3,
-		1,
-	};
+	} args = {};
+	SETUP(args, "package-to-path", 3, 1);
 
 	args.package = package;
-	args.buf = (cell_t)buf;
-	args.len = len;
+	args.buf = IN(buf);
+	args.len = IN(len);
 	if (openfirmware(&args) == -1)
 		return (-1);
-	return (args.size);
+	return (OUT(args.size));
 }
 
 /*  Call the method in the scope of a given instance. */
@@ -459,30 +441,26 @@ OF_call_method(char *method, ihandle_t instance, int nargs, int nreturns, ...)
 		cell_t method;
 		cell_t instance;
 		cell_t args_n_results[12];
-	} args = {
-		(cell_t)"call-method",
-		2,
-		1,
-	};
+	} args = {};
+	SETUP(args, "call-method", nargs + 2, nreturns + 1);
 	cell_t *cp;
 	int n;
 
 	if (nargs > 6)
 		return (-1);
-	args.nargs = nargs + 2;
-	args.nreturns = nreturns + 1;
-	args.method = (cell_t)method;
+	args.method = IN(method);
 	args.instance = instance;
 	va_start(ap, nreturns);
 	for (cp = (cell_t *)(args.args_n_results + (n = nargs)); --n >= 0;)
-		*--cp = va_arg(ap, cell_t);
+		*--cp = IN(va_arg(ap, cell_t));
 	if (openfirmware(&args) == -1)
 		return (-1);
 	if (args.args_n_results[nargs])
-		return (args.args_n_results[nargs]);
-	for (cp = (cell_t *)(args.args_n_results + nargs + (n = args.nreturns));
-	    --n > 0;)
-		*va_arg(ap, cell_t *) = *--cp;
+		return (OUT(args.args_n_results[nargs]));
+	/* XXX what if ihandles or phandles are returned */
+	for (cp = (cell_t *)(args.args_n_results + nargs +
+	    (n = be32toh(args.nreturns))); --n > 0;)
+		*va_arg(ap, cell_t *) = OUT(*--cp);
 	va_end(ap);
 	return (0);
 }
@@ -501,13 +479,10 @@ OF_open(char *device)
 		cell_t nreturns;
 		cell_t device;
 		cell_t instance;
-	} args = {
-		(cell_t)"open",
-		1,
-		1,
-	};
+	} args = {};
+	SETUP(args, "open", 1, 1);
 
-	args.device = (cell_t)device;
+	args.device = IN(device);
 	if (openfirmware(&args) == -1 || args.instance == 0) {
 		return (-1);
 	}
@@ -523,10 +498,8 @@ OF_close(ihandle_t instance)
 		cell_t nargs;
 		cell_t nreturns;
 		cell_t instance;
-	} args = {
-		(cell_t)"close",
-		1,
-	};
+	} args = {};
+	SETUP(args, "close", 1, 0);
 
 	args.instance = instance;
 	openfirmware(&args);
@@ -544,19 +517,16 @@ OF_read(ihandle_t instance, void *addr, int len)
 		cell_t addr;
 		cell_t len;
 		cell_t actual;
-	} args = {
-		(cell_t)"read",
-		3,
-		1,
-	};
+	} args = {};
+	SETUP(args, "read", 3, 1);
 
 	args.instance = instance;
-	args.addr = (cell_t)addr;
-	args.len = len;
+	args.addr = IN(addr);
+	args.len = IN(len);
 
 #if defined(OPENFIRM_DEBUG)
 	printf("OF_read: called with instance=%08x, addr=%p, len=%d\n",
-	    args.instance, args.addr, args.len);
+	    instance, addr, len);
 #endif
 
 	if (openfirmware(&args) == -1)
@@ -564,10 +534,10 @@ OF_read(ihandle_t instance, void *addr, int len)
 
 #if defined(OPENFIRM_DEBUG)
 	printf("OF_read: returning instance=%d, addr=%p, len=%d, actual=%d\n",
-	    args.instance, args.addr, args.len, args.actual);
+	    args.instance, OUT(args.addr), OUT(args.len), OUT(args.actual));
 #endif
 
-	return (args.actual);
+	return (OUT(args.actual));
 }
 
 /* Write to an instance. */
@@ -582,18 +552,15 @@ OF_write(ihandle_t instance, void *addr, int len)
 		cell_t addr;
 		cell_t len;
 		cell_t actual;
-	} args = {
-		(cell_t)"write",
-		3,
-		1,
-	};
+	} args = {};
+	SETUP(args, "write", 3, 1);
 
 	args.instance = instance;
-	args.addr = (cell_t)addr;
-	args.len = len;
+	args.addr = IN(addr);
+	args.len = IN(len);
 	if (openfirmware(&args) == -1)
 		return (-1);
-	return (args.actual);
+	return (OUT(args.actual));
 }
 
 /* Seek to a position. */
@@ -608,18 +575,15 @@ OF_seek(ihandle_t instance, uint64_t pos)
 		cell_t poshi;
 		cell_t poslo;
 		cell_t status;
-	} args = {
-		(cell_t)"seek",
-		3,
-		1,
-	};
+	} args = {};
+	SETUP(args, "seek", 3, 1);
 
 	args.instance = instance;
-	args.poshi = pos >> 32;
-	args.poslo = pos;
+	args.poshi = IN(((uint64_t)pos >> 32));
+	args.poslo = IN(pos);
 	if (openfirmware(&args) == -1)
 		return (-1);
-	return (args.status);
+	return (OUT(args.status));
 }
 
 /* Blocks. */
@@ -633,16 +597,13 @@ OF_blocks(ihandle_t instance)
 		cell_t instance;
 		cell_t result;
 		cell_t blocks;
-	} args = {
-		(cell_t)"#blocks",
-		2,
-		1,
-	};
+	} args = {};
+	SETUP(args, "#blocks", 2, 1);
 
 	args.instance = instance;
 	if (openfirmware(&args) == -1)
 		return ((unsigned int)-1);
-	return (args.blocks);
+	return (OUT(args.blocks));
 }
 
 /* Block size. */
@@ -656,16 +617,13 @@ OF_block_size(ihandle_t instance)
 		cell_t instance;
 		cell_t result;
 		cell_t size;
-	} args = {
-		(cell_t)"block-size",
-		2,
-		1,
-	};
+	} args = {};
+	SETUP(args, "block-size", 2, 1);
 
 	args.instance = instance;
 	if (openfirmware(&args) == -1)
 		return (512);
-	return (args.size);
+	return (OUT(args.size));
 }
 
 /* 
@@ -684,18 +642,15 @@ OF_claim(void *virt, u_int size, u_int align)
 		cell_t size;
 		cell_t align;
 		cell_t baseaddr;
-	} args = {
-		(cell_t)"claim",
-		3,
-		1,
-	};
-
-	args.virt = (cell_t)virt;
-	args.size = size;
-	args.align = align;
+	} args = {};
+	SETUP(args, "claim", 3, 1);
+
+	args.virt = IN(virt);
+	args.size = IN(size);
+	args.align = IN(align);
 	if (openfirmware(&args) == -1)
 		return ((void *)-1);
-	return ((void *)args.baseaddr);
+	return ((void *)OUT(args.baseaddr));
 }
 
 /* Release an area of memory. */
@@ -708,13 +663,11 @@ OF_release(void *virt, u_int size)
 		cell_t nreturns;
 		cell_t virt;
 		cell_t size;
-	} args = {
-		(cell_t)"release",
-		2,
-	};
+	} args = {};
+	SETUP(args, "release", 2, 0);
 
-	args.virt = (cell_t)virt;
-	args.size = size;
+	args.virt = IN(virt);
+	args.size = IN(size);
 	openfirmware(&args);
 }
 
@@ -731,12 +684,10 @@ OF_boot(char *bootspec)
 		cell_t nargs;
 		cell_t nreturns;
 		cell_t bootspec;
-	} args = {
-		(cell_t)"boot",
-		1,
-	};
+	} args = {};
+	SETUP(args, "boot", 1, 0);
 
-	args.bootspec = (cell_t)bootspec;
+	args.bootspec = IN(bootspec);
 	openfirmware(&args);
 	for (;;)			/* just in case */
 		;
@@ -750,9 +701,8 @@ OF_enter()
 		cell_t name;
 		cell_t nargs;
 		cell_t nreturns;
-	} args = {
-		(cell_t)"enter",
-	};
+	} args = {};
+	SETUP(args, "enter", 0, 0);
 
 	openfirmware(&args);
 	/* We may come back. */
@@ -766,9 +716,8 @@ OF_exit()
 		cell_t name;
 		cell_t nargs;
 		cell_t nreturns;
-	} args = {
-		(cell_t)"exit",
-	};
+	} args = {};
+	SETUP(args, "exit", 0, 0);
 
 	openfirmware(&args);
 	for (;;)			/* just in case */
@@ -782,9 +731,8 @@ OF_quiesce()
 		cell_t name;
 		cell_t nargs;
 		cell_t nreturns;
-	} args = {
-		(cell_t)"quiesce",
-	};
+	} args = {};
+	SETUP(args, "quiesce", 0, 0);
 
 	openfirmware(&args);
 }
@@ -803,16 +751,14 @@ OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
 		cell_t entry;
 		cell_t arg;
 		cell_t len;
-	} args = {
-		(cell_t)"chain",
-		5,
-	};
-
-	args.virt = (cell_t)virt;
-	args.size = size;
-	args.entry = (cell_t)entry;
-	args.arg = (cell_t)arg;
-	args.len = len;
+	} args = {};
+	SETUP(args, "chain", 5, 0);
+
+	args.virt = IN(virt);
+	args.size = IN(size);
+	args.entry = IN(entry);
+	args.arg = IN(arg);
+	args.len = IN(len);
 	openfirmware(&args);
 }
 #else
diff --git a/stand/libofw/openfirm.h b/stand/libofw/openfirm.h
index b83cf4b0b27f..0981dbf093eb 100644
--- a/stand/libofw/openfirm.h
+++ b/stand/libofw/openfirm.h
@@ -65,9 +65,9 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 
-typedef	unsigned int		ihandle_t;
-typedef unsigned int		phandle_t;
-typedef unsigned long int	cell_t;
+typedef uint32_t		ihandle_t;
+typedef uint32_t		phandle_t;
+typedef uint32_t		cell_t;
 
 extern int		(*openfirmware)(void *);
 extern phandle_t	chosen;
@@ -91,6 +91,7 @@ phandle_t	OF_parent(phandle_t);
 phandle_t	OF_instance_to_package(ihandle_t);
 int		OF_getproplen(phandle_t, const char *);
 int		OF_getprop(phandle_t, const char *, void *, int);
+int		OF_getencprop(phandle_t, const char *, cell_t *, int);
 int		OF_nextprop(phandle_t, const char *, char *);
 int		OF_setprop(phandle_t, const char *, void *, int);
 int		OF_canon(const char *, char *, int);
diff --git a/stand/powerpc/Makefile b/stand/powerpc/Makefile
index 888fe0e97028..a16d3933ff7e 100644
--- a/stand/powerpc/Makefile
+++ b/stand/powerpc/Makefile
@@ -4,7 +4,11 @@ NO_OBJ=t
 
 .include <bsd.init.mk>
 
-SUBDIR.yes=		boot1.chrp ofw uboot
+SUBDIR.yes=		boot1.chrp ofw
+
+.if "${MACHINE_ARCH}" != "powerpc64le"
+SUBDIR.${MK_FDT}+=	uboot
+.endif
 
 .if "${MACHINE_ARCH}" == "powerpc64"
 SUBDIR.${MK_FDT}+=	kboot
diff --git a/stand/powerpc/boot1.chrp/boot1.c b/stand/powerpc/boot1.chrp/boot1.c
index 4d152efe1a70..ed7c55d11d6f 100644
--- a/stand/powerpc/boot1.chrp/boot1.c
+++ b/stand/powerpc/boot1.chrp/boot1.c
@@ -20,6 +20,7 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/dirent.h>
+#include <sys/endian.h>
 #include <machine/elf.h>
 #include <machine/stdarg.h>
 #include <machine/md_var.h>
@@ -82,11 +83,11 @@ static char *__ultoa(char *buf, u_long val, int base);
  */
 typedef uint32_t	ofwcell_t;
 typedef uint32_t	u_ofwh_t;
-typedef int (*ofwfp_t)(void *);
+typedef int (*ofwfp_t)(ofwcell_t *);
 ofwfp_t ofw;			/* the prom Open Firmware entry */
 ofwh_t chosenh;
 
-void ofw_init(void *, int, int (*)(void *), char *, int);
+void ofw_init(void *, int, ofwfp_t, char *, int);
 static ofwh_t ofw_finddevice(const char *);
 static ofwh_t ofw_open(const char *);
 static int ofw_close(ofwh_t);
@@ -101,6 +102,16 @@ static void ofw_exit(void) __dead2;
 ofwh_t bootdevh;
 ofwh_t stdinh, stdouth;
 
+/*
+ * Note about the entry point:
+ *
+ * For some odd reason, the first page of the load appears to have trouble
+ * when entering in LE. The first five instructions decode weirdly.
+ * I suspect it is some cache weirdness between the ELF headers and .text.
+ *
+ * Ensure we have a gap between the start of .text and the entry as a
+ * workaround.
+ */
 __asm("                         \n\
         .data                   \n\
 	.align 4		\n\
@@ -108,6 +119,8 @@ stack:                          \n\
         .space  16384           \n\
                                 \n\
         .text                   \n\
+        /* SLOF cache hack */   \n\
+        .space 4096             \n\
         .globl  _start          \n\
 _start:                         \n\
         lis     %r1,stack@ha    \n\
@@ -117,18 +130,95 @@ _start:                         \n\
         b       ofw_init        \n\
 ");
 
+ofwfp_t realofw;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+/*
+ * Minimal endianness-swap trampoline for LE.
+ */
+__attribute__((naked)) int
+ofwtramp(void *buf, ofwfp_t cb)
+{
+__asm("									\n\
+	mflr	%r0							\n\
+	stw	%r0, 4(%r1)						\n\
+	stwu	%r1, -16(%r1)						\n\
+	stw	%r30, 8(%r1)						\n\
+	/* Save current MSR for restoration post-call. */		\n\
+	mfmsr	%r30							\n\
+	mr	%r5, %r30						\n\
+	/* Remove LE bit from MSR. */					\n\
+	clrrwi	%r5, %r5, 1						\n\
+	mtsrr0	%r4							\n\
+	mtsrr1	%r5							\n\
+	bcl	20, 31, .+4	/* LOAD_LR_NIA */			\n\
+1:									\n\
+	mflr	%r4							\n\
+	addi	%r4, %r4, (2f - 1b)					\n\
+	mtlr	%r4							\n\
+	/* Switch to BE and transfer control to OF entry */		\n\
+	rfid								\n\
+2:									\n\
+	/* Control is returned here, but in BE. */			\n\
+	.long	0x05009f42	/* LOAD_LR_NIA			      */\n\
+				/* 0:			 	      */\n\
+	.long	0xa603db7f	/* mtsrr1 	%r30		      */\n\
+	.long	0xa602c87f	/* mflr		%r30		      */\n\
+	.long	0x1400de3b	/* addi		%r30, %r30, (1f - 0b) */\n\
+	.long	0xa603da7f	/* mtsrr0	%r30		      */\n\
+	.long	0x2400004c	/* rfid				      */\n\
+				/* 1:				      */\n\
+1:									\n\
+	/* Back to normal. Tidy up for return. */			\n\
+	lwz	%r30, 8(%r1)						\n\
+	lwz	%r0, 20(%r1)						\n\
+	addi	%r1, %r1, 16						\n\
+	mtlr	%r0							\n\
+	blr								\n\
+");
+}
+
+/*
+ * Little-endian OFW entrypoint replacement.
+ *
+ * We are doing all the byteswapping in one place here to save space.
+ * This means instance handles will be byteswapped as well.
+ */
+int
+call_ofw(ofwcell_t* buf)
+{
+	int ret, i, ncells;
+
+	ncells = 3 + buf[1] + buf[2];
+	for (i = 0; i < ncells; i++)
+		buf[i] = htobe32(buf[i]);
+
+	ret = (ofwtramp(buf, realofw));
+	for (i = 0; i < ncells; i++)
+		buf[i] = be32toh(buf[i]);
+	return (ret);
+}
+#endif
+
 void
-ofw_init(void *vpd, int res, int (*openfirm)(void *), char *arg, int argl)
+ofw_init(void *vpd, int res, ofwfp_t openfirm, char *arg, int argl)
 {
 	char *av[16];
 	char *p;
 	int ac;
 
-	ofw = openfirm;
+#if BYTE_ORDER == LITTLE_ENDIAN
+	realofw = openfirm;
+	ofw = call_ofw;
+#else
+	realofw = ofw = openfirm;
+#endif
 
 	chosenh = ofw_finddevice("/chosen");
 	ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
+	stdinh = be32toh(stdinh);
 	ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
+	stdouth = be32toh(stdouth);
 	ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs));
 	ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
 
@@ -537,8 +627,8 @@ load(const char *fname)
 		__syncicache(p, ph.p_memsz);
 	}
 	ofw_close(bootdev);
-	(*(void (*)(void *, int, ofwfp_t, char *, int))eh.e_entry)(NULL, 0, 
-	    ofw,NULL,0);
+	(*(void (*)(void *, int, ofwfp_t, char *, int))eh.e_entry)(NULL, 0,
+	    realofw, NULL, 0);
 }
 
 static int
diff --git a/stand/powerpc/ofw/Makefile b/stand/powerpc/ofw/Makefile
index 7c2e97ebb382..03844301f094 100644
--- a/stand/powerpc/ofw/Makefile
+++ b/stand/powerpc/ofw/Makefile
@@ -28,11 +28,15 @@ CFLAGS.gfx_fb.c += -I${SRCTOP}/sys/teken
 SRCS+=		ofwfdt.c
 .endif
 
-.if ${MACHINE_ARCH} == "powerpc64"
+.if ${MACHINE_ARCH:Mpowerpc64*} != ""
 SRCS+=		cas.c
 CFLAGS+=	-DCAS
 .endif
 
+.if ${MACHINE_ARCH} == "powerpc64le"
+SRCS+=		trampolineLE.S
+.endif
+
 HELP_FILES=	${FDTSRC}/help.fdt
 
 # Always add MI sources
@@ -44,7 +48,13 @@ HELP_FILES=	${FDTSRC}/help.fdt
 RELOC?=		0x1C00000
 CFLAGS+=	-DRELOC=${RELOC} -g
 
-LDFLAGS=	-nostdlib -static -T ${.CURDIR}/ldscript.powerpc
+LDFLAGS=	-nostdlib -static
+
+.if ${MACHINE_ARCH} == "powerpc64le"
+LDFLAGS+=	-T ${.CURDIR}/ldscript.powerpcle
+.else
+LDFLAGS+=	-T ${.CURDIR}/ldscript.powerpc
+.endif
 
 # Open Firmware standalone support library
 LIBOFW=		${BOOTOBJ}/libofw/libofw.a
diff --git a/stand/powerpc/ofw/cas.c b/stand/powerpc/ofw/cas.c
index 6292e04794a8..0a12f31d1a1a 100644
--- a/stand/powerpc/ofw/cas.c
*** 372 LINES SKIPPED ***