diff --git a/stand/common/load_elf.c b/stand/common/load_elf.c --- a/stand/common/load_elf.c +++ b/stand/common/load_elf.c @@ -750,13 +750,6 @@ } #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 @@ 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 --- a/stand/defs.mk +++ b/stand/defs.mk @@ -120,10 +120,12 @@ # 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.h b/stand/libofw/openfirm.h --- 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_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/libofw/openfirm.c b/stand/libofw/openfirm.c --- 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 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ #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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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/powerpc/Makefile b/stand/powerpc/Makefile --- a/stand/powerpc/Makefile +++ b/stand/powerpc/Makefile @@ -4,7 +4,11 @@ .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 --- a/stand/powerpc/boot1.chrp/boot1.c +++ b/stand/powerpc/boot1.chrp/boot1.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -82,11 +83,11 @@ */ 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 @@ 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 @@ .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 @@ 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 @@ __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 --- a/stand/powerpc/ofw/Makefile +++ b/stand/powerpc/ofw/Makefile @@ -28,11 +28,15 @@ 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 @@ 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 --- a/stand/powerpc/ofw/cas.c +++ b/stand/powerpc/ofw/cas.c @@ -29,6 +29,8 @@ #include #include +#include + /* #define CAS_DEBUG */ #ifdef CAS_DEBUG #define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) @@ -132,12 +134,12 @@ struct opt_vec5 vec5; } __packed ibm_arch_vec = { /* pvr_list */ { - { PVR_CPU_MASK, PVR_CPU_P8 }, /* POWER8 */ - { PVR_CPU_MASK, PVR_CPU_P8E }, /* POWER8E */ - { PVR_CPU_MASK, PVR_CPU_P8NVL }, /* POWER8NVL */ - { PVR_CPU_MASK, PVR_CPU_P9 }, /* POWER9 */ - { PVR_ISA_MASK, PVR_ISA_207 }, /* All ISA 2.07 */ - { PVR_ISA_MASK, PVR_ISA_300 }, /* All ISA 3.00 */ + { htobe32(PVR_CPU_MASK), htobe32(PVR_CPU_P8) }, + { htobe32(PVR_CPU_MASK), htobe32(PVR_CPU_P8E) }, + { htobe32(PVR_CPU_MASK), htobe32(PVR_CPU_P8NVL) }, + { htobe32(PVR_CPU_MASK), htobe32(PVR_CPU_P9) }, + { htobe32(PVR_ISA_MASK), htobe32(PVR_ISA_207) }, + { htobe32(PVR_ISA_MASK), htobe32(PVR_ISA_300) }, { 0, 0xffffffffu } /* terminator */ }, 4, /* num_opts (4 actually means 5 option vectors) */ diff --git a/stand/powerpc/ofw/ldscript.powerpcle b/stand/powerpc/ofw/ldscript.powerpcle new file mode 100644 --- /dev/null +++ b/stand/powerpc/ofw/ldscript.powerpcle @@ -0,0 +1,142 @@ +/* $FreeBSD$ */ + +OUTPUT_FORMAT("elf32-powerpcle-freebsd", "elf32-powerpcle-freebsd", + "elf32-powerpcle-freebsd") +OUTPUT_ARCH(powerpcle:common) +ENTRY(_start) +SEARCH_DIR(/usr/lib); +PROVIDE (__stack = 0); +PHDRS +{ + text PT_LOAD; +} +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x02c00000 + SIZEOF_HEADERS; + .interp : { *(.interp) } :text + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rela.got : { *(.rela.got) } + .rela.got1 : { *(.rela.got1) } + .rela.got2 : { *(.rela.got2) } + .rela.ctors : { *(.rela.ctors) } + .rela.dtors : { *(.rela.dtors) } + .rela.init : { *(.rela.init) } + .rela.fini : { *(.rela.fini) } + .rela.bss : { *(.rela.bss) } + .rela.plt : { *(.rela.plt) } + .rela.sdata : { *(.rela.sdata) } + .rela.sbss : { *(.rela.sbss) } + .rela.sdata2 : { *(.rela.sdata2) } + .rela.sbss2 : { *(.rela.sbss2) } + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0 + _etext = .; + PROVIDE (etext = .); + .init : { *(.init) } =0 + .fini : { *(.fini) } =0 + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .sdata2 : { *(.sdata2) } + .sbss2 : { *(.sbss2) } + /* Adjust the address for the data segment to the next page up. */ + . = ((. + 0x1000) & ~(0x1000 - 1)); + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .got1 : { *(.got1) } + .dynamic : { *(.dynamic) } + /* Put .ctors and .dtors next to the .got2 section, so that the pointers + get relocated with -mrelocatable. Also put in the .fixup pointers. + The current compiler no longer needs this, but keep it around for 2.7.2 */ + PROVIDE (_GOT2_START_ = .); + .got2 : { *(.got2) } + PROVIDE (__CTOR_LIST__ = .); + .ctors : { *(.ctors) } + PROVIDE (__CTOR_END__ = .); + PROVIDE (__DTOR_LIST__ = .); + .dtors : { *(.dtors) } + PROVIDE (__DTOR_END__ = .); + PROVIDE (_FIXUP_START_ = .); + .fixup : { *(.fixup) } + PROVIDE (_FIXUP_END_ = .); + PROVIDE (_GOT2_END_ = .); + PROVIDE (_GOT_START_ = .); + .got : { *(.got) } + .got.plt : { *(.got.plt) } + PROVIDE (_GOT_END_ = .); + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + .sbss : + { + PROVIDE (__sbss_start = .); + *(.sbss) + *(.scommon) + *(.dynsbss) + PROVIDE (__sbss_end = .); + } + .plt : { *(.plt) } + .bss : + { + PROVIDE (__bss_start = .); + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} + diff --git a/stand/powerpc/ofw/main.c b/stand/powerpc/ofw/main.c --- a/stand/powerpc/ofw/main.c +++ b/stand/powerpc/ofw/main.c @@ -28,11 +28,14 @@ #include __FBSDID("$FreeBSD$"); +#include + #include #include "openfirm.h" #include "libofw.h" #include "bootstrap.h" +#include #include struct arch_switch archsw; /* MI/MD interface boundary */ @@ -77,7 +80,7 @@ memsz = 0; memoryp = OF_instance_to_package(memory); - sz = OF_getprop(memoryp, "reg", ®, sizeof(reg)); + sz = OF_getencprop(memoryp, "reg", ®[0], sizeof(reg)); sz /= sizeof(reg[0]); for (i = 0; i < sz; i += (acells + scells)) { @@ -104,6 +107,26 @@ } #endif +#if BYTE_ORDER == LITTLE_ENDIAN +/* + * In Little-endian, we cannot just branch to the client interface. Since + * the client interface is big endian, we have to rfid to it. + * Likewise, when execution resumes, we are in the wrong endianness so + * we must do a fixup before returning to the caller. + */ +static int (*openfirmware_entry)(void *); +extern int openfirmware_trampoline(void *buf, int (*cb)(void *)); + +/* + * Wrapper to pass the real entry point to our trampoline. + */ +static int +openfirmware_docall(void *buf) +{ + return openfirmware_trampoline(buf, openfirmware_entry); +} +#endif + int main(int (*openfirm)(void *)) { @@ -117,13 +140,21 @@ /* * Initialise the Open Firmware routines by giving them the entry point. */ +#if BYTE_ORDER == LITTLE_ENDIAN + /* + * Use a trampoline entry point for endian fixups. + */ + openfirmware_entry = openfirm; + OF_init(openfirmware_docall); +#else OF_init(openfirm); +#endif root = OF_finddevice("/"); scells = acells = 1; - OF_getprop(root, "#address-cells", &acells, sizeof(acells)); - OF_getprop(root, "#size-cells", &scells, sizeof(scells)); + OF_getencprop(root, "#address-cells", &acells, sizeof(acells)); + OF_getencprop(root, "#size-cells", &scells, sizeof(scells)); /* * Initialise the heap as early as possible. Once this is done, diff --git a/stand/powerpc/ofw/ofwfdt.c b/stand/powerpc/ofw/ofwfdt.c --- a/stand/powerpc/ofw/ofwfdt.c +++ b/stand/powerpc/ofw/ofwfdt.c @@ -112,7 +112,7 @@ node = OF_finddevice("/rtas"); OF_package_to_path(node, path, sizeof(path)); - OF_getprop(node, "rtas-size", &len, sizeof(len)); + OF_getencprop(node, "rtas-size", &len, sizeof(len)); /* Allocate memory */ rtasmem = OF_claim(0, len, 4096); @@ -133,6 +133,7 @@ sizeof(base)); /* Mark RTAS private data area reserved */ + base = fdt32_to_cpu(base); fdt_add_mem_rsv(fdtp, base, len); } else { /* @@ -157,8 +158,7 @@ for (i = 0; chosenprops[i] != NULL; i++) { ihand = fdt_getprop(fdtp, offset, chosenprops[i], &len); if (ihand != NULL && len == sizeof(*ihand)) { - node = OF_instance_to_package( - fdt32_to_cpu(*ihand)); + node = OF_instance_to_package(*ihand); if (OF_hasprop(node, "phandle")) OF_getprop(node, "phandle", &node, sizeof(node)); @@ -168,7 +168,6 @@ else if (OF_hasprop(node, "ibm,phandle")) OF_getprop(node, "ibm,phandle", &node, sizeof(node)); - node = cpu_to_fdt32(node); fdt_setprop(fdtp, offset, chosenprops[i], &node, sizeof(node)); } diff --git a/stand/powerpc/ofw/trampolineLE.S b/stand/powerpc/ofw/trampolineLE.S new file mode 100644 --- /dev/null +++ b/stand/powerpc/ofw/trampolineLE.S @@ -0,0 +1,71 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Brandon Bergren + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include + +/** + * int openfirmware_trampoline(void *buf, int (*cb)(void *)); + */ +ASENTRY_NOPROF(openfirmware_trampoline) + mflr %r0 + stw %r0, 4(%r1) + stwu %r1, -16(%r1) + stw %r30, 8(%r1) + /* Save current MSR for restoration post-call. */ + mfmsr %r30 + mr %r5, %r30 + /* Remove LE bit from MSR. */ + clrrwi %r5, %r5, 1 + mtsrr0 %r4 + mtsrr1 %r5 + LOAD_LR_NIA +1: + mflr %r4 + addi %r4, %r4, (2f - 1b) + mtlr %r4 + /* Switch to BE and transfer control to OF entry */ + rfid +2: + /* Control is returned here, but in BE. */ + .long 0x05009f42 /* LOAD_LR_NIA */ + /* 0: */ + .long 0xa603db7f /* mtsrr1 %r30 */ + .long 0xa602c87f /* mflr %r30 */ + .long 0x1400de3b /* addi %r30, %r30, (1f - 0b) */ + .long 0xa603da7f /* mtsrr0 %r30 */ + .long 0x2400004c /* rfid */ + /* 1: */ +1: + /* Back to normal. Tidy up for return. */ + lwz %r30, 8(%r1) + lwz %r0, 20(%r1) + addi %r1, %r1, 16 + mtlr %r0 + blr +ASEND(openfirmware_trampoline)