Module Name: src
Committed By: thorpej
Date: Sat Feb 13 01:48:33 UTC 2021
Modified Files:
src/sys/arch/powerpc/oea: ofw_subr.S
src/sys/arch/powerpc/powerpc: openfirm.c
Log Message:
- Don't change to the OFW stack in C code; instead, switch to the OFW
stack in the openfirmware() wrapper itself. Inspired by a similar
change in OpenBSD designed to appease clang.
- The OF_*() entry firmware interfaces use several global resources;
protect those global resources with a __cpu_simple_lock_t.
- Make ofbcopy() static -- it's no longer referenced outside openfirm.c
To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/sys/arch/powerpc/oea/ofw_subr.S
cvs rdiff -u -r1.32 -r1.33 src/sys/arch/powerpc/powerpc/openfirm.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/powerpc/oea/ofw_subr.S
diff -u src/sys/arch/powerpc/oea/ofw_subr.S:1.12 src/sys/arch/powerpc/oea/ofw_subr.S:1.13
--- src/sys/arch/powerpc/oea/ofw_subr.S:1.12 Mon Jul 6 10:31:23 2020
+++ src/sys/arch/powerpc/oea/ofw_subr.S Sat Feb 13 01:48:33 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: ofw_subr.S,v 1.12 2020/07/06 10:31:23 rin Exp $ */
+/* $NetBSD: ofw_subr.S,v 1.13 2021/02/13 01:48:33 thorpej Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -103,9 +103,18 @@ ENTRY_NOPROFILE(ofwinit)
*/
.text
ENTRY(openfirmware)
- mflr %r0 /* save return address */
- stw %r0,4(%r1)
- stwu %r1,-32(%r1) /* setup stack frame */
+ mflr %r0
+ stw %r0,4(%r1) /* save return address */
+
+ /*
+ * Switch to OpenFirmware stack.
+ *
+ * -48 == -16 to stack old SP and align, -32 for save area
+ */
+ lis %r7,firmstk+NBPG-48@ha
+ addi %r7,%r7,firmstk+NBPG-48@l
+ stw %r1,32(%r7) /* stash away prev stack pointer */
+ mr %r1,%r7
lis %r4,openfirmware_entry@ha /* get firmware entry point */
lwz %r4,openfirmware_entry@l(%r4)
@@ -202,77 +211,7 @@ ENTRY(openfirmware)
lwz %r5,28(%r1)
mtsprg3 %r5
- lwz %r1,0(%r1) /* and return */
- lwz %r0,4(%r1)
- mtlr %r0
- blr
-
-/*
- * Switch to/from OpenFirmware real mode stack
- *
- * Note: has to be called as the very first thing in OpenFirmware interface
- * routines.
- * E.g.:
- * int
- * OF_xxx(arg1, arg2)
- * type arg1, arg2;
- * {
- * static struct {
- * char *name;
- * int nargs;
- * int nreturns;
- * char *method;
- * int arg1;
- * int arg2;
- * int ret;
- * } args = {
- * "xxx",
- * 2,
- * 1,
- * };
- *
- * ofw_stack();
- * args.arg1 = arg1;
- * args.arg2 = arg2;
- * if (openfirmware(&args) < 0)
- * return -1;
- * return args.ret;
- * }
- */
-
-ENTRY(ofw_stack)
- mfmsr %r8 /* turn off interrupts */
- andi. %r0,%r8,~(PSL_EE|PSL_RI)@l
- mtmsr %r0
- stw %r8,4(%r1) /* abuse return address slot */
-
- lwz %r5,0(%r1) /* get length of stack frame */
- subf %r5,%r1,%r5
-
- lis %r7,firmstk+NBPG-8@ha
- addi %r7,%r7,firmstk+NBPG-8@l
- lis %r6,ofw_back@ha
- addi %r6,%r6,ofw_back@l
- subf %r4,%r5,%r7 /* make room for stack frame on
- new stack */
- stw %r6,-4(%r7) /* setup return pointer */
- stwu %r1,-8(%r7)
-
- stw %r7,-8(%r4)
-
- addi %r3,%r1,8
- addi %r1,%r4,-8
- subi %r5,%r5,8
-
- b _C_LABEL(ofbcopy) /* and copy it */
-
-ofw_back:
- lwz %r1,0(%r1) /* get callers original stack pointer */
-
- lwz %r0,4(%r1) /* get saved msr from abused slot */
- mtmsr %r0
-
- lwz %r1,0(%r1) /* return */
- lwz %r0,4(%r1)
+ lwz %r1,32(%r1) /* restore previous stack pointer */
+ lwz %r0,4(%r1) /* return address */
mtlr %r0
blr
Index: src/sys/arch/powerpc/powerpc/openfirm.c
diff -u src/sys/arch/powerpc/powerpc/openfirm.c:1.32 src/sys/arch/powerpc/powerpc/openfirm.c:1.33
--- src/sys/arch/powerpc/powerpc/openfirm.c:1.32 Fri Feb 5 00:06:11 2021
+++ src/sys/arch/powerpc/powerpc/openfirm.c Sat Feb 13 01:48:33 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: openfirm.c,v 1.32 2021/02/05 00:06:11 thorpej Exp $ */
+/* $NetBSD: openfirm.c,v 1.33 2021/02/13 01:48:33 thorpej Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: openfirm.c,v 1.32 2021/02/05 00:06:11 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: openfirm.c,v 1.33 2021/02/13 01:48:33 thorpej Exp $");
#ifdef _KERNEL_OPT
#include "opt_multiprocessor.h"
@@ -50,11 +50,37 @@ __KERNEL_RCSID(0, "$NetBSD: openfirm.c,v
char *OF_buf;
-void ofw_stack(void);
-void ofbcopy(const void *, void *, size_t);
+static void ofbcopy(const void *, void *, size_t);
+
#ifdef MULTIPROCESSOR
void OF_start_cpu(int, u_int, int);
-#endif
+
+
+static __cpu_simple_lock_t ofw_mutex = __SIMPLELOCK_UNLOCKED;
+#endif /* MULTIPROCESSOR */
+
+static inline register_t
+ofw_lock(void)
+{
+ const register_t s = mfmsr();
+
+ mtmsr(s & ~(PSL_EE|PSL_RI)); /* disable interrupts */
+
+#ifdef MULTIPROCESSOR
+ __cpu_simple_lock(&ofw_mutex);
+#endif /* MULTIPROCESSOR */
+
+ return s;
+}
+
+static inline void
+ofw_unlock(register_t s)
+{
+#ifdef MULTIPROCESSOR
+ __cpu_simple_unlock(&ofw_mutex);
+#endif /* MULTIPROCESSOR */
+ mtmsr(s);
+}
int
OF_peer(int phandle)
@@ -71,11 +97,17 @@ OF_peer(int phandle)
1,
};
- ofw_stack();
+ const register_t s = ofw_lock();
+ int rv;
+
args.phandle = phandle;
if (openfirmware(&args) == -1)
- return 0;
- return args.sibling;
+ rv = 0;
+ else
+ rv = args.sibling;
+
+ ofw_unlock(s);
+ return rv;
}
int
@@ -93,11 +125,17 @@ OF_child(int phandle)
1,
};
- ofw_stack();
+ const register_t s = ofw_lock();
+ int rv;
+
args.phandle = phandle;
if (openfirmware(&args) == -1)
- return 0;
- return args.child;
+ rv = 0;
+ else
+ rv = args.child;
+
+ ofw_unlock(s);
+ return rv;
}
int
@@ -115,11 +153,17 @@ OF_parent(int phandle)
1,
};
- ofw_stack();
+ const register_t s = ofw_lock();
+ int rv;
+
args.phandle = phandle;
if (openfirmware(&args) == -1)
- return 0;
- return args.parent;
+ rv = 0;
+ else
+ rv = args.parent;
+
+ ofw_unlock(s);
+ return rv;
}
int
@@ -137,11 +181,17 @@ OF_instance_to_package(int ihandle)
1,
};
- ofw_stack();
+ const register_t s = ofw_lock();
+ int rv;
+
args.ihandle = ihandle;
if (openfirmware(&args) == -1)
- return -1;
- return args.phandle;
+ rv = -1;
+ else
+ rv = args.phandle;
+
+ ofw_unlock(s);
+ return rv;
}
int
@@ -160,13 +210,19 @@ OF_getproplen(int handle, const char *pr
1,
};
- ofw_stack();
+ const register_t s = ofw_lock();
+ int rv;
+
strncpy(OF_buf, prop, 32);
args.phandle = handle;
args.prop = OF_buf;
if (openfirmware(&args) == -1)
- return -1;
- return args.proplen;
+ rv = -1;
+ else
+ rv = args.proplen;
+
+ ofw_unlock(s);
+ return rv;
}
int
@@ -187,21 +243,29 @@ OF_getprop(int handle, const char *prop,
1,
};
- ofw_stack();
if (buflen > PAGE_SIZE)
return -1;
+
+ const register_t s = ofw_lock();
+ int rv;
+
strncpy(OF_buf, prop, 32);
args.phandle = handle;
args.prop = OF_buf;
args.buf = &OF_buf[33];
args.buflen = buflen;
if (openfirmware(&args) == -1)
- return -1;
- if (args.size > buflen)
- args.size = buflen;
- if (args.size > 0)
- ofbcopy(&OF_buf[33], buf, args.size);
- return args.size;
+ rv = -1;
+ else {
+ if (args.size > buflen)
+ args.size = buflen;
+ if (args.size > 0)
+ ofbcopy(&OF_buf[33], buf, args.size);
+ rv = args.size;
+ }
+
+ ofw_unlock(s);
+ return rv;
}
int
@@ -221,19 +285,25 @@ OF_setprop(int handle, const char *prop,
4,
1
};
- ofw_stack();
- if (buflen > NBPG)
+ if (buflen > PAGE_SIZE)
return -1;
+ const register_t s = ofw_lock();
+ int rv;
+
ofbcopy(buf, OF_buf, buflen);
args.phandle = handle;
args.prop = prop;
args.buf = OF_buf;
args.buflen = buflen;
if (openfirmware(&args) == -1)
- return -1;
- return args.size;
+ rv = -1;
+ else
+ rv = args.size;
+
+ ofw_unlock(s);
+ return rv;
}
int
@@ -253,15 +323,22 @@ OF_nextprop(int handle, const char *prop
1,
};
- ofw_stack();
+ const register_t s = ofw_lock();
+ int rv;
+
strncpy(OF_buf, prop, 32);
args.phandle = handle;
args.prop = OF_buf;
args.buf = &OF_buf[33];
if (openfirmware(&args) == -1)
- return -1;
- strncpy(nextprop, &OF_buf[33], 32);
- return args.flag;
+ rv = -1;
+ else {
+ strncpy(nextprop, &OF_buf[33], 32);
+ rv = args.flag;
+ }
+
+ ofw_unlock(s);
+ return rv;
}
int
@@ -279,12 +356,18 @@ OF_finddevice(const char *name)
1,
};
- ofw_stack();
+ const register_t s = ofw_lock();
+ int rv;
+
strncpy(OF_buf, name, NBPG);
args.device = OF_buf;
if (openfirmware(&args) == -1)
- return -1;
- return args.phandle;
+ rv = -1;
+ else
+ rv = args.phandle;
+
+ ofw_unlock(s);
+ return rv;
}
int
@@ -306,16 +389,25 @@ OF_instance_to_path(int ihandle, char *b
if (buflen > PAGE_SIZE)
return -1;
+
+ const register_t s = ofw_lock();
+ int rv;
+
args.ihandle = ihandle;
args.buf = OF_buf;
args.buflen = buflen;
if (openfirmware(&args) < 0)
- return -1;
- if (args.length > buflen)
- args.length = buflen;
- if (args.length > 0)
- ofbcopy(OF_buf, buf, args.length);
- return args.length;
+ rv = -1;
+ else {
+ if (args.length > buflen)
+ args.length = buflen;
+ if (args.length > 0)
+ ofbcopy(OF_buf, buf, args.length);
+ rv = args.length;
+ }
+
+ ofw_unlock(s);
+ return rv;
}
int
@@ -335,25 +427,32 @@ OF_package_to_path(int phandle, char *bu
1,
};
- ofw_stack();
if (buflen > PAGE_SIZE)
return -1;
+
+ const register_t s = ofw_lock();
+ int rv;
+
args.phandle = phandle;
args.buf = OF_buf;
args.buflen = buflen;
if (openfirmware(&args) < 0)
- return -1;
- if (args.length > buflen)
- args.length = buflen;
- if (args.length > 0)
- ofbcopy(OF_buf, buf, args.length);
- return args.length;
+ rv = -1;
+ else {
+ if (args.length > buflen)
+ args.length = buflen;
+ if (args.length > 0)
+ ofbcopy(OF_buf, buf, args.length);
+ rv = args.length;
+ }
+
+ ofw_unlock(s);
+ return rv;
}
int
OF_call_method(const char *method, int ihandle, int nargs, int nreturns, ...)
{
- va_list ap;
static struct {
const char *name;
int nargs;
@@ -366,36 +465,48 @@ OF_call_method(const char *method, int i
2,
1,
};
- int *ip, n;
if (nargs > 6)
return -1;
+
+ va_list ap;
+ int *ip, n;
+ int rv;
+
+ const register_t s = ofw_lock();
+
args.nargs = nargs + 2;
args.nreturns = nreturns + 1;
args.method = method;
args.ihandle = ihandle;
+
va_start(ap, nreturns);
- for (ip = args.args_n_results + (n = nargs); --n >= 0;)
+
+ for (ip = args.args_n_results + (n = nargs); --n >= 0;) {
*--ip = va_arg(ap, int);
- ofw_stack();
- if (openfirmware(&args) == -1) {
- va_end(ap);
- return -1;
}
- if (args.args_n_results[nargs]) {
- va_end(ap);
- return args.args_n_results[nargs];
+
+ if (openfirmware(&args) == -1) {
+ rv = -1;
+ } else if (args.args_n_results[nargs]) {
+ rv = args.args_n_results[nargs];
+ } else {
+ for (ip = args.args_n_results + nargs + (n = args.nreturns);
+ --n > 0;) {
+ *va_arg(ap, int *) = *--ip;
+ }
+ rv = 0;
}
- for (ip = args.args_n_results + nargs + (n = args.nreturns); --n > 0;)
- *va_arg(ap, int *) = *--ip;
+
va_end(ap);
- return 0;
+
+ ofw_unlock(s);
+ return rv;
}
int
OF_call_method_1(const char *method, int ihandle, int nargs, ...)
{
- va_list ap;
static struct {
const char *name;
int nargs;
@@ -408,23 +519,35 @@ OF_call_method_1(const char *method, int
2,
2,
};
- int *ip, n;
if (nargs > 6)
return -1;
+
+ va_list ap;
+ int *ip, n;
+ int rv;
+
+ const register_t s = ofw_lock();
+
args.nargs = nargs + 2;
args.method = method;
args.ihandle = ihandle;
+
va_start(ap, nargs);
- for (ip = args.args_n_results + (n = nargs); --n >= 0;)
+ for (ip = args.args_n_results + (n = nargs); --n >= 0;) {
*--ip = va_arg(ap, int);
+ }
va_end(ap);
- ofw_stack();
+
if (openfirmware(&args) == -1)
- return -1;
- if (args.args_n_results[nargs])
- return -1;
- return args.args_n_results[nargs + 1];
+ rv = -1;
+ else if (args.args_n_results[nargs])
+ rv = -1;
+ else
+ rv = args.args_n_results[nargs + 1];
+
+ ofw_unlock(s);
+ return rv;
}
int
@@ -443,14 +566,21 @@ OF_open(const char *dname)
};
int l;
- ofw_stack();
if ((l = strlen(dname)) >= PAGE_SIZE)
return -1;
+
+ const register_t s = ofw_lock();
+ int rv;
+
ofbcopy(dname, OF_buf, l + 1);
args.dname = OF_buf;
if (openfirmware(&args) == -1)
- return -1;
- return args.handle;
+ rv = -1;
+ else
+ rv = args.handle;
+
+ ofw_unlock(s);
+ return rv;
}
void
@@ -467,9 +597,12 @@ OF_close(int handle)
0,
};
- ofw_stack();
+ const register_t s = ofw_lock();
+
args.handle = handle;
openfirmware(&args);
+
+ ofw_unlock(s);
}
/*
@@ -494,25 +627,31 @@ OF_read(int handle, void *addr, int len)
int l, act = 0;
char *p = addr;
- ofw_stack();
+ const register_t s = ofw_lock();
+
args.ihandle = handle;
args.addr = OF_buf;
for (; len > 0; len -= l, p += l) {
l = uimin(PAGE_SIZE, len);
args.len = l;
- if (openfirmware(&args) == -1)
- return -1;
+ if (openfirmware(&args) == -1) {
+ act = -1;
+ goto out;
+ }
if (args.actual > 0) {
ofbcopy(OF_buf, p, args.actual);
act += args.actual;
}
if (args.actual < l) {
- if (act)
- return act;
- else
- return args.actual;
+ if (act == 0) {
+ act = args.actual;
+ }
+ goto out;
}
}
+
+ out:
+ ofw_unlock(s);
return act;
}
@@ -535,7 +674,8 @@ OF_write(int handle, const void *addr, i
int l, act = 0;
const char *p = addr;
- ofw_stack();
+ const register_t s = ofw_lock();
+
args.ihandle = handle;
args.addr = OF_buf;
for (; len > 0; len -= l, p += l) {
@@ -543,11 +683,16 @@ OF_write(int handle, const void *addr, i
ofbcopy(p, OF_buf, l);
args.len = l;
args.actual = l; /* work around a PIBS bug */
- if (openfirmware(&args) == -1)
- return -1;
+ if (openfirmware(&args) == -1) {
+ act = -1;
+ goto out;
+ }
l = args.actual;
act += l;
}
+
+ out:
+ ofw_unlock(s);
return act;
}
@@ -568,13 +713,19 @@ OF_seek(int handle, u_quad_t pos)
1,
};
- ofw_stack();
+ const register_t s = ofw_lock();
+ int rv;
+
args.handle = handle;
args.poshi = (int)(pos >> 32);
args.poslo = (int)pos;
if (openfirmware(&args) == -1)
- return -1;
- return args.status;
+ rv = -1;
+ else
+ rv = args.status;
+
+ ofw_unlock(s);
+ return rv;
}
#ifdef MULTIPROCESSOR
@@ -593,12 +744,20 @@ OF_start_cpu(int phandle, u_int pc, int
3,
0,
};
- ofw_stack();
+
+ const register_t s = ofw_lock();
+ bool failed = false;
+
args.phandle = phandle;
args.pc = pc;
args.arg = arg;
if (openfirmware(&args) == -1)
+ failed = true;
+
+ ofw_unlock(s);
+ if (failed) {
panic("WTF?");
+ }
}
#endif
@@ -619,10 +778,14 @@ OF_boot(const char *bstr)
if ((l = strlen(bstr)) >= PAGE_SIZE)
panic("OF_boot");
- ofw_stack();
+
+ const register_t s = ofw_lock();
+
ofbcopy(bstr, OF_buf, l + 1);
args.bootspec = OF_buf;
openfirmware(&args);
+
+ ofw_unlock(s);
panic("OF_boot didn't");
}
@@ -639,8 +802,11 @@ OF_enter(void)
0,
};
- ofw_stack();
+ const register_t s = ofw_lock();
+
openfirmware(&args);
+
+ ofw_unlock(s);
}
void
@@ -656,8 +822,11 @@ OF_exit(void)
0,
};
- ofw_stack();
+ const register_t s = ofw_lock();
+
openfirmware(&args);
+
+ ofw_unlock(s);
while (1); /* just in case */
}
@@ -676,18 +845,22 @@ void
1,
};
- ofw_stack();
+ const register_t s = ofw_lock();
+ void (*rv)(void *);
+
args.newfunc = newfunc;
if (openfirmware(&args) == -1)
- return 0;
- return args.oldfunc;
+ rv = NULL;
+ else
+ rv = args.oldfunc;
+
+ ofw_unlock(s);
+ return rv;
}
int
OF_interpret(const char *cmd, int nargs, int nreturns, ...)
{
- va_list ap;
- int i, len, status;
static struct {
const char *name;
uint32_t nargs;
@@ -699,11 +872,17 @@ OF_interpret(const char *cmd, int nargs,
2,
};
- ofw_stack();
+ va_list ap;
+ int i, len;
+ int rv;
+
if (nreturns > 8)
return -1;
if ((len = strlen(cmd)) >= PAGE_SIZE)
return -1;
+
+ const register_t s = ofw_lock();
+
ofbcopy(cmd, OF_buf, len + 1);
i = 0;
args.slots[i] = (uintptr_t)OF_buf;
@@ -717,16 +896,20 @@ OF_interpret(const char *cmd, int nargs,
}
if (openfirmware(&args) == -1)
- return -1;
- status = args.slots[i];
- i++;
-
- while (i < args.nargs + args.nreturns) {
- *va_arg(ap, uint32_t *) = args.slots[i];
+ rv = -1;
+ else {
+ rv = args.slots[i];
i++;
+
+ while (i < args.nargs + args.nreturns) {
+ *va_arg(ap, uint32_t *) = args.slots[i];
+ i++;
+ }
}
va_end(ap);
- return status;
+
+ ofw_unlock(s);
+ return rv;
}
void
@@ -742,14 +925,17 @@ OF_quiesce(void)
0,
};
- ofw_stack();
+ const register_t s = ofw_lock();
+
openfirmware(&args);
+
+ ofw_unlock(s);
}
/*
* This version of bcopy doesn't work for overlapping regions!
*/
-void
+static void
ofbcopy(const void *src, void *dst, size_t len)
{
const char *sp = src;
@@ -758,9 +944,6 @@ ofbcopy(const void *src, void *dst, size
if (src == dst)
return;
- /*
- * Do some optimization? XXX
- */
while (len-- > 0)
*dp++ = *sp++;
}