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
This commit is contained in:
Leandro Lupori 2021-10-20 15:48:33 -03:00
parent 2ff7c2cc4f
commit f83288645c
12 changed files with 522 additions and 242 deletions

View File

@ -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);

View File

@ -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

View File

@ -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 = {};
SETUP(args, "canon", 3, 1);
args.device = (cell_t)device;
args.buf = (cell_t)buf;
args.len = len;
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 = {};
SETUP(args, "claim", 3, 1);
args.virt = (cell_t)virt;
args.size = size;
args.align = align;
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 = {};
SETUP(args, "chain", 5, 0);
args.virt = (cell_t)virt;
args.size = size;
args.entry = (cell_t)entry;
args.arg = (cell_t)arg;
args.len = len;
args.virt = IN(virt);
args.size = IN(size);
args.entry = IN(entry);
args.arg = IN(arg);
args.len = IN(len);
openfirmware(&args);
}
#else

View File

@ -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);

View File

@ -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

View File

@ -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));
@ -538,7 +628,7 @@ load(const char *fname)
}
ofw_close(bootdev);
(*(void (*)(void *, int, ofwfp_t, char *, int))eh.e_entry)(NULL, 0,
ofw,NULL,0);
realofw, NULL, 0);
}
static int

View File

@ -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

View File

@ -29,6 +29,8 @@ __FBSDID("$FreeBSD$");
#include <openfirm.h>
#include <stand.h>
#include <sys/endian.h>
/* #define CAS_DEBUG */
#ifdef CAS_DEBUG
#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
@ -132,12 +134,12 @@ static struct ibm_arch_vec {
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) */

View File

@ -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 . */
}

View File

@ -28,11 +28,14 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/endian.h>
#include <stand.h>
#include "openfirm.h"
#include "libofw.h"
#include "bootstrap.h"
#include <machine/asm.h>
#include <machine/psl.h>
struct arch_switch archsw; /* MI/MD interface boundary */
@ -77,7 +80,7 @@ memsize(void)
memsz = 0;
memoryp = OF_instance_to_package(memory);
sz = OF_getprop(memoryp, "reg", &reg, sizeof(reg));
sz = OF_getencprop(memoryp, "reg", &reg[0], sizeof(reg));
sz /= sizeof(reg[0]);
for (i = 0; i < sz; i += (acells + scells)) {
@ -104,6 +107,26 @@ ppc64_autoload(void)
}
#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 @@ main(int (*openfirm)(void *))
/*
* 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,

View File

@ -112,7 +112,7 @@ ofwfdt_fixups(void *fdtp)
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 @@ ofwfdt_fixups(void *fdtp)
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 @@ ofwfdt_fixups(void *fdtp)
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 @@ ofwfdt_fixups(void *fdtp)
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));
}

View File

@ -0,0 +1,71 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2020 Brandon Bergren <bdragon@FreeBSD.org>
*
* 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 <machine/asm.h>
/**
* 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)