From nobody Fri Nov 05 14:31:24 2021 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 42E3E180417B; Fri, 5 Nov 2021 14:31:25 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Hm2xn10ZCz3spJ; Fri, 5 Nov 2021 14:31:25 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 029D019363; Fri, 5 Nov 2021 14:31:25 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 1A5EVOb2002746; Fri, 5 Nov 2021 14:31:24 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 1A5EVOpD002745; Fri, 5 Nov 2021 14:31:24 GMT (envelope-from git) Date: Fri, 5 Nov 2021 14:31:24 GMT Message-Id: <202111051431.1A5EVOpD002745@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Leandro Lupori Subject: git: 8a62b07bce7b - stable/13 - powerpc64le: stand fixes List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: luporl X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: 8a62b07bce7ba43caa7a345be30ab3a8afc220b0 Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by luporl: URL: https://cgit.FreeBSD.org/src/commit/?id=8a62b07bce7ba43caa7a345be30ab3a8afc220b0 commit 8a62b07bce7ba43caa7a345be30ab3a8afc220b0 Author: Leandro Lupori AuthorDate: 2021-10-20 18:48:33 +0000 Commit: Leandro Lupori CommitDate: 2021-11-05 14:29:40 +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 (cherry picked from commit f83288645cd9726c24ca67292fbc3abb4eb65a36) --- 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 2b0201b940b5..bbebf270c7ef 100644 --- a/stand/defs.mk +++ b/stand/defs.mk @@ -114,10 +114,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 __FBSDID("$FreeBSD$"); +#include + #include #include @@ -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 #include -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 -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 #include +#include #include #include #include @@ -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 a35a7c7c56bf..6d75bb882d2b 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 *** 374 LINES SKIPPED ***