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++;
 }

Reply via email to