Module Name:    src
Committed By:   thorpej
Date:           Sun Feb 28 20:27:40 UTC 2021

Modified Files:
        src/sys/arch/macppc/include: loadfile_machdep.h
        src/sys/arch/macppc/stand/ofwboot: Locore.c Makefile boot.c ofdev.c
            openfirm.h version
Added Files:
        src/sys/arch/macppc/stand/ofwboot: loadfile_machdep.c

Log Message:
- When starting the boot program, cache a bunch of OFW frequently used
  ihandles / phandles, rather than fetching them all the time.
- Change the signature of OF_call_method() to take an array of cells for
  the inputs and outputs, rather than using variadic arguments.  This
  makes it much easier to use OF_call_method() when the format of the
  arguments passed to a given method are determined at run-time
  (due to e.g. #address-cells).
- Properly inform OpenFirmware where the kernel is loaded by using
  "claim" on /chosen/memory and, if running in virtual-mode, using
  "claim" on /chosen/mmu to reserve the VA, and "map" on /chosen/mmu
  to enter the translation.  (The kernel is still always mapped VA==PA.)


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/macppc/include/loadfile_machdep.h
cvs rdiff -u -r1.34 -r1.35 src/sys/arch/macppc/stand/ofwboot/Locore.c
cvs rdiff -u -r1.59 -r1.60 src/sys/arch/macppc/stand/ofwboot/Makefile
cvs rdiff -u -r1.30 -r1.31 src/sys/arch/macppc/stand/ofwboot/boot.c
cvs rdiff -u -r0 -r1.1 src/sys/arch/macppc/stand/ofwboot/loadfile_machdep.c
cvs rdiff -u -r1.27 -r1.28 src/sys/arch/macppc/stand/ofwboot/ofdev.c
cvs rdiff -u -r1.8 -r1.9 src/sys/arch/macppc/stand/ofwboot/openfirm.h
cvs rdiff -u -r1.14 -r1.15 src/sys/arch/macppc/stand/ofwboot/version

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/macppc/include/loadfile_machdep.h
diff -u src/sys/arch/macppc/include/loadfile_machdep.h:1.6 src/sys/arch/macppc/include/loadfile_machdep.h:1.7
--- src/sys/arch/macppc/include/loadfile_machdep.h:1.6	Wed Aug  6 21:57:50 2014
+++ src/sys/arch/macppc/include/loadfile_machdep.h	Sun Feb 28 20:27:40 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: loadfile_machdep.h,v 1.6 2014/08/06 21:57:50 joerg Exp $	*/
+/*	$NetBSD: loadfile_machdep.h,v 1.7 2021/02/28 20:27:40 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -36,9 +36,21 @@
 
 #define LOADADDR(a)		(((u_long)(a)) + offset)
 #define ALIGNENTRY(a)		((u_long)(a))
+
+#ifdef _STANDALONE
+ssize_t	macppc_read(int, void *, size_t);
+void *	macppc_memcpy(void *, const void *, size_t);
+void *	macppc_memset(void *, int, size_t);
+
+#define READ(f, b, c)		macppc_read((f), (void *)LOADADDR(b), (c))
+#define BCOPY(s, d, c)		macppc_memcpy((void *)LOADADDR(d), (void *)(s), (c))
+#define BZERO(d, c)		macppc_memset((void *)LOADADDR(d), 0, (c))
+#else
 #define READ(f, b, c)		read((f), (void *)LOADADDR(b), (c))
 #define BCOPY(s, d, c)		memcpy((void *)LOADADDR(d), (void *)(s), (c))
 #define BZERO(d, c)		memset((void *)LOADADDR(d), 0, (c))
+#endif /* _STANDALONE */
+
 #define	WARN(a)			do { \
 					(void)printf a; \
 					if (errno) \

Index: src/sys/arch/macppc/stand/ofwboot/Locore.c
diff -u src/sys/arch/macppc/stand/ofwboot/Locore.c:1.34 src/sys/arch/macppc/stand/ofwboot/Locore.c:1.35
--- src/sys/arch/macppc/stand/ofwboot/Locore.c:1.34	Wed Apr 15 13:33:13 2020
+++ src/sys/arch/macppc/stand/ofwboot/Locore.c	Sun Feb 28 20:27:40 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: Locore.c,v 1.34 2020/04/15 13:33:13 rin Exp $	*/
+/*	$NetBSD: Locore.c,v 1.35 2021/02/28 20:27:40 thorpej Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -201,6 +201,34 @@ openfirmware(void *arg)
 }
 #endif
 
+int	ofw_real_mode;
+int	ofw_address_cells;
+int	ofw_size_cells;
+
+int	ofw_root;		/* / */
+int	ofw_options;		/* /options */
+int	ofw_openprom;		/* /openprom */
+int	ofw_chosen;		/* /chosen (package) */
+int	ofw_stdin;		/* /chosen/stdin */
+int	ofw_stdout;		/* /chosen/stdout */
+int	ofw_memory_ihandle;	/* /chosen/memory */
+int	ofw_mmu_ihandle;	/* /chosen/mmu */
+
+bool
+ofw_option_truefalse(const char *prop, int proplen)
+{
+	/* These are all supposed to be strings. */
+	switch (prop[0]) {  
+	case 'y':
+	case 'Y':
+	case 't':
+	case 'T':
+	case '1':
+		return true; 
+	}
+	return false;
+}
+
 static void
 startup(void *vpd, int res, int (*openfirm)(void *), char *arg, int argl)
 {
@@ -623,9 +651,9 @@ OF_chain(void *virt, u_int size, boot_en
 #endif
 
 int
-OF_call_method(const char *method, int ihandle, int nargs, int nreturns, ...)
+OF_call_method(const char *method, int ihandle, int nargs, int nreturns,
+    int *cells)
 {
-	va_list ap;
 	static struct {
 		const char *name;
 		int nargs;
@@ -642,47 +670,47 @@ OF_call_method(const char *method, int i
 
 	if (nargs > 6)
 		return -1;
+
 	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;)
-		*--ip = va_arg(ap, int);
+		*--ip = *cells++;
 
 	if (openfirmware(&args) == -1) {
-		va_end(ap);
 		return -1;
 	}
+
 	if (args.args_n_results[nargs]) {
-		va_end(ap);
 		return args.args_n_results[nargs];
 	}
+
 	for (ip = args.args_n_results + nargs + (n = args.nreturns); --n > 0;)
-		*va_arg(ap, int *) = *--ip;
-	va_end(ap);
+		*cells++ = *--ip;
+
 	return 0;
 }
 
-static int stdin;
-static int stdout;
-
 static void
 setup(void)
 {
-	int chosen;
+	char prop[32];
+	int proplen;
+	const char *reason = NULL;
 
-	if ((chosen = OF_finddevice("/chosen")) == -1)
+	if ((ofw_chosen = OF_finddevice("/chosen")) == -1)
 		OF_exit();
-	if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) !=
-	    sizeof(stdin) ||
-	    OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) !=
-	    sizeof(stdout))
+	if (OF_getprop(ofw_chosen, "stdin", &ofw_stdin, sizeof(ofw_stdin)) !=
+	    sizeof(ofw_stdin) ||
+	    OF_getprop(ofw_chosen, "stdout", &ofw_stdout, sizeof(ofw_stdout)) !=
+	    sizeof(ofw_stdout))
 		OF_exit();
 
-	if (stdout == 0) {
+	if (ofw_stdout == 0) {
 		/* screen should be console, but it is not open */
-		stdout = OF_open("screen");
+		ofw_stdout = OF_open("screen");
 	}
 
 #ifdef HEAP_VARIABLE
@@ -699,6 +727,72 @@ setup(void)
 
 	setheap(heapspace, heapspace + HEAP_SIZE);
 #endif	/* HEAP_VARIABLE */
+
+	ofw_root = OF_finddevice("/");
+	ofw_options = OF_finddevice("/options");
+	ofw_openprom = OF_finddevice("/openprom");
+	ofw_chosen = OF_finddevice("/chosen");
+
+	if (ofw_root == -1) {
+		reason = "No root node";
+		goto bad_environment;
+	}
+	if (ofw_chosen == -1) {
+		reason = "No chosen node";
+		goto bad_environment;
+	}
+
+	if (ofw_options != -1) {
+		proplen = OF_getprop(ofw_options, "real-mode?", prop,
+		    sizeof(prop));
+		if (proplen > 0) {
+			ofw_real_mode = ofw_option_truefalse(prop, proplen);
+		}
+	}
+
+	/*
+	 * Get #address-cells and #size-cells.
+	 */
+	ofw_address_cells = 1;
+	ofw_size_cells = 1;
+	OF_getprop(ofw_root, "#address-cells", &ofw_address_cells,
+		   sizeof(ofw_address_cells));
+	OF_getprop(ofw_root, "#size-cells", &ofw_size_cells,
+		   sizeof(ofw_size_cells));
+
+	/* See loadfile_machdep.c */
+	if (ofw_size_cells != 1) {
+		printf("#size-cells = %d not yet supported\n", ofw_size_cells);
+		reason = "unsupported #size-cells";
+		goto bad_environment;
+	}
+
+	/*
+	 * Get the ihandle on /chosen/memory and /chosen/mmu.
+	 */
+	ofw_memory_ihandle = -1;
+	ofw_mmu_ihandle = -1;
+	OF_getprop(ofw_chosen, "memory", &ofw_memory_ihandle,
+		   sizeof(ofw_memory_ihandle));
+	OF_getprop(ofw_chosen, "mmu", &ofw_mmu_ihandle,
+		   sizeof(ofw_mmu_ihandle));
+	if (ofw_memory_ihandle == -1) {
+		reason = "no /chosen/memory";
+		goto bad_environment;
+	}
+	if (ofw_mmu_ihandle == -1) {
+		reason = "no /chosen/mmu";
+		goto bad_environment;
+	}
+
+	return;
+
+ bad_environment:
+	if (reason == NULL) {
+		reason = "unknown reason";
+	}
+	printf("Invalid Openfirmware environment: %s\n", reason);
+	OF_exit();
 }
 
 void
@@ -708,7 +802,7 @@ putchar(int c)
 
 	if (c == '\n')
 		putchar('\r');
-	OF_write(stdout, &ch, 1);
+	OF_write(ofw_stdout, &ch, 1);
 }
 
 int
@@ -717,7 +811,7 @@ getchar(void)
 	unsigned char ch = '\0';
 	int l;
 
-	while ((l = OF_read(stdin, &ch, 1)) != 1)
+	while ((l = OF_read(ofw_stdin, &ch, 1)) != 1)
 		if (l != -2 && l != 0)
 			return -1;
 	return ch;

Index: src/sys/arch/macppc/stand/ofwboot/Makefile
diff -u src/sys/arch/macppc/stand/ofwboot/Makefile:1.59 src/sys/arch/macppc/stand/ofwboot/Makefile:1.60
--- src/sys/arch/macppc/stand/ofwboot/Makefile:1.59	Wed Jun  6 22:56:25 2018
+++ src/sys/arch/macppc/stand/ofwboot/Makefile	Sun Feb 28 20:27:40 2021
@@ -1,10 +1,11 @@
-#	$NetBSD: Makefile,v 1.59 2018/06/06 22:56:25 uwe Exp $
+#	$NetBSD: Makefile,v 1.60 2021/02/28 20:27:40 thorpej Exp $
 
 S=	${.CURDIR}/../../../..
 
 PROG=		ofwboot
 FILES=		${PROG}.elf ${PROG}.xcf
-SRCS=		Locore.c boot.c ofdev.c hfs.c net.c netif_of.c
+SRCS=		Locore.c boot.c ofdev.c hfs.c net.c netif_of.c \
+		loadfile_machdep.c
 XCOFFXTRA=	Xcoffxtra.c
 XCOFFXTRAOBJ=	Xcoffxtra.o
 CFLAGS+=	-ffreestanding

Index: src/sys/arch/macppc/stand/ofwboot/boot.c
diff -u src/sys/arch/macppc/stand/ofwboot/boot.c:1.30 src/sys/arch/macppc/stand/ofwboot/boot.c:1.31
--- src/sys/arch/macppc/stand/ofwboot/boot.c:1.30	Thu Apr 23 00:12:28 2020
+++ src/sys/arch/macppc/stand/ofwboot/boot.c	Sun Feb 28 20:27:40 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: boot.c,v 1.30 2020/04/23 00:12:28 joerg Exp $	*/
+/*	$NetBSD: boot.c,v 1.31 2021/02/28 20:27:40 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -211,8 +211,8 @@ void
 main(void)
 {
 	extern char bootprog_name[], bootprog_rev[];
-	int chosen, options, openprom;
 	char bootline[512];		/* Should check size? */
+	char prop[32];
 	char *cp;
 	u_long marks[MARK_MAX];
 	u_int32_t entry;
@@ -224,25 +224,24 @@ main(void)
 	/*
 	 * Figure out what version of Open Firmware...
 	 */
-	if ((openprom = OF_finddevice("/openprom")) != -1) {
-		char model[32];
-
-		memset(model, 0, sizeof model);
-		OF_getprop(openprom, "model", model, sizeof model);
-		for (cp = model; *cp; cp++)
+	if (ofw_openprom != -1) {
+		memset(prop, 0, sizeof prop);
+		OF_getprop(ofw_openprom, "model", prop, sizeof prop);
+		for (cp = prop; *cp; cp++)
 			if (*cp >= '0' && *cp <= '9') {
 				ofw_version = *cp - '0';
 				break;
 			}
-		DPRINTF(">> Open Firmware version %d.x\n", ofw_version);
+		printf(">> Open Firmware version %d.x\n", ofw_version);
 	}
+	printf(">> Open Firmware running in %s-mode.\n",
+	    ofw_real_mode ? "real" : "virtual");
 
 	/*
 	 * Get the boot arguments from Openfirmware
 	 */
-	if ((chosen = OF_finddevice("/chosen")) == -1 ||
-	    OF_getprop(chosen, "bootpath", bootdev, sizeof bootdev) < 0 ||
-	    OF_getprop(chosen, "bootargs", bootline, sizeof bootline) < 0) {
+	if (OF_getprop(ofw_chosen, "bootpath", bootdev, sizeof bootdev) < 0 ||
+	    OF_getprop(ofw_chosen, "bootargs", bootline, sizeof bootline) < 0) {
 		printf("Invalid Openfirmware environment\n");
 		OF_exit();
 	}
@@ -253,8 +252,8 @@ main(void)
 	 */
 	if (bootdev[0] == 0) {
 		printf("Cannot use bootpath\n");
-		if ((options = OF_finddevice("/options")) == -1 ||
-		    OF_getprop(options, "boot-device", bootdev,
+		if (ofw_options == -1 ||
+		    OF_getprop(ofw_options, "boot-device", bootdev,
 			       sizeof bootdev) < 0) {
 			printf("Invalid Openfirmware environment\n");
 			OF_exit();
@@ -299,7 +298,8 @@ main(void)
 loaded:
 
 #ifdef	__notyet__
-	OF_setprop(chosen, "bootpath", opened_name, strlen(opened_name) + 1);
+	OF_setprop(ofw_chosen, "bootpath", opened_name,
+		   strlen(opened_name) + 1);
 	cp = bootline;
 #else
 	strcpy(bootline, opened_name);
@@ -324,7 +324,7 @@ loaded:
 	else
 		*++cp = 0;
 #ifdef	__notyet__
-	OF_setprop(chosen, "bootargs", bootline, strlen(bootline) + 1);
+	OF_setprop(ofw_chosen, "bootargs", bootline, strlen(bootline) + 1);
 #endif
 
 	entry = marks[MARK_ENTRY];
@@ -345,7 +345,7 @@ changedisk_hook(struct open_file *of)
 	struct of_dev *op = of->f_devdata;
 	int c;
 
-	OF_call_method("eject", op->handle, 0, 0);
+	OF_call_method("eject", op->handle, 0, 0, NULL);
 
 	c = getchar();
 	if (c == 'q') {
@@ -353,7 +353,7 @@ changedisk_hook(struct open_file *of)
 		OF_exit();
 	}
 
-	OF_call_method("close", op->handle, 0, 0);
-	OF_call_method("open", op->handle, 0, 0);
+	OF_call_method("close", op->handle, 0, 0, NULL);
+	OF_call_method("open", op->handle, 0, 0, NULL);
 }
 #endif

Index: src/sys/arch/macppc/stand/ofwboot/ofdev.c
diff -u src/sys/arch/macppc/stand/ofwboot/ofdev.c:1.27 src/sys/arch/macppc/stand/ofwboot/ofdev.c:1.28
--- src/sys/arch/macppc/stand/ofwboot/ofdev.c:1.27	Fri Nov 16 14:58:54 2018
+++ src/sys/arch/macppc/stand/ofwboot/ofdev.c	Sun Feb 28 20:27:40 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: ofdev.c,v 1.27 2018/11/16 14:58:54 tsutsui Exp $	*/
+/*	$NetBSD: ofdev.c,v 1.28 2021/02/28 20:27:40 thorpej Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -100,11 +100,15 @@ devopen_dummy(struct open_file *of, ...)
 static int
 devclose(struct open_file *of)
 {
+	uint32_t cells[2];
 	struct of_dev *op = of->f_devdata;
 
+	cells[0] = (uint32_t)op->dmabuf;
+	cells[1] = MAXPHYS;
+
 	if (op->type == OFDEV_NET)
 		net_close(op);
-	OF_call_method("dma-free", op->handle, 2, 0, op->dmabuf, MAXPHYS);
+	OF_call_method("dma-free", op->handle, 2, 0, (int *)cells);
 	OF_close(op->handle);
 	op->handle = -1;
 	return 0;
@@ -385,6 +389,7 @@ devopen(struct open_file *of, const char
 	int handle, part;
 	size_t nread;
 	int error = 0;
+	uint32_t cells[2];
 
 	if (ofdev.handle != -1)
 		panic("devopen");
@@ -432,7 +437,9 @@ devopen(struct open_file *of, const char
 	memset(&ofdev, 0, sizeof ofdev);
 	ofdev.handle = handle;
 	ofdev.dmabuf = NULL;
-	OF_call_method("dma-alloc", handle, 1, 1, MAXPHYS, &ofdev.dmabuf);
+	cells[0] = MAXPHYS;
+	OF_call_method("dma-alloc", handle, 1, 1, (int *)cells);
+	ofdev.dmabuf = (void *)cells[1];
 	if (!strcmp(buf, "block")) {
 		ofdev.type = OFDEV_DISK;
 		ofdev.bsize = DEV_BSIZE;

Index: src/sys/arch/macppc/stand/ofwboot/openfirm.h
diff -u src/sys/arch/macppc/stand/ofwboot/openfirm.h:1.8 src/sys/arch/macppc/stand/ofwboot/openfirm.h:1.9
--- src/sys/arch/macppc/stand/ofwboot/openfirm.h:1.8	Wed Jun  6 23:50:29 2018
+++ src/sys/arch/macppc/stand/ofwboot/openfirm.h	Sun Feb 28 20:27:40 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: openfirm.h,v 1.8 2018/06/06 23:50:29 uwe Exp $	*/
+/*	$NetBSD: openfirm.h,v 1.9 2021/02/28 20:27:40 thorpej Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -39,6 +39,20 @@
 
 #include "boot.h"
 
+extern int	ofw_real_mode;
+extern int	ofw_address_cells;
+extern int	ofw_size_cells;
+extern int	ofw_root;
+extern int	ofw_chosen;
+extern int	ofw_options;
+extern int	ofw_openprom;
+extern int	ofw_stdin;
+extern int	ofw_stdout;
+extern int	ofw_memory_ihandle;
+extern int	ofw_mmu_ihandle;
+
+bool	ofw_option_truefalse(const char *, int);
+
 void OF_enter(void);
 __dead void OF_exit(void);
 int OF_finddevice(const char *);
@@ -56,4 +70,4 @@ void *OF_claim(void *, u_int, u_int);
 void OF_release(void *, u_int);
 int OF_milliseconds(void);
 void OF_chain(void *, u_int, boot_entry_t, void *, u_int);
-int OF_call_method(const char *, int, int, int, ...);
+int OF_call_method(const char *, int, int, int, int *);

Index: src/sys/arch/macppc/stand/ofwboot/version
diff -u src/sys/arch/macppc/stand/ofwboot/version:1.14 src/sys/arch/macppc/stand/ofwboot/version:1.15
--- src/sys/arch/macppc/stand/ofwboot/version:1.14	Fri Nov 16 14:58:54 2018
+++ src/sys/arch/macppc/stand/ofwboot/version	Sun Feb 28 20:27:40 2021
@@ -1,4 +1,4 @@
-$NetBSD: version,v 1.14 2018/11/16 14:58:54 tsutsui Exp $
+$NetBSD: version,v 1.15 2021/02/28 20:27:40 thorpej Exp $
 
 1.1:		Initial revision from NetBSD/powerpc.
 1.2:		Use MI loadfile().
@@ -15,3 +15,4 @@ $NetBSD: version,v 1.14 2018/11/16 14:58
 1.12:		Read Apple Partition Map to find the root partition, when
 		no OF path was specified.
 1.13:		Fix boot failure of installation floppies
+1.14:		Properly inform OFW of the kernel's location using claim + map.

Added files:

Index: src/sys/arch/macppc/stand/ofwboot/loadfile_machdep.c
diff -u /dev/null src/sys/arch/macppc/stand/ofwboot/loadfile_machdep.c:1.1
--- /dev/null	Sun Feb 28 20:27:40 2021
+++ src/sys/arch/macppc/stand/ofwboot/loadfile_machdep.c	Sun Feb 28 20:27:40 2021
@@ -0,0 +1,452 @@
+/*	$NetBSD: loadfile_machdep.c,v 1.1 2021/02/28 20:27:40 thorpej Exp $	*/
+
+/*-
+ * Copyright (c) 2021 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#include "boot.h"
+
+#include <sys/param.h>
+#include <sys/boot_flag.h>
+#include <sys/disklabel.h>
+
+#include <lib/libsa/stand.h> 
+#include <lib/libsa/loadfile.h>
+#include <lib/libkern/libkern.h>
+ 
+#include "openfirm.h" 
+
+#ifdef KMAPPING_DEBUG
+#define	DPRINTF		printf
+#else
+#define	DPRINTF		while (0) printf
+#endif
+
+static int
+ofw_claimphys(paddr_t pa, vsize_t size)
+{
+	/* (2) phys, (2) size, (1) align -> 2 (phys) */
+	uint32_t cells[2+2+1+2];
+	uint32_t *p = cells;
+	paddr_t result;
+
+	if (ofw_address_cells == 2) {
+		/* order of cells is phys.lo ... phys.hi */
+		*p++ = (uint32_t)pa;
+		*p++ = ((uint64_t)pa) >> 32;
+	} else {
+		*p++ = (uint32_t)pa;
+	}
+
+#if 0	/* No known Mac systems with 2, and spec is ambiguous about order. */
+	if (ofw_size_cells == 2) {
+		*p++ = ((uint64_t)size) >> 32;
+		*p++ = (uint32_t)size;
+	} else
+#endif
+		*p++ = (uint32_t)size;
+
+	*p++ = 0;	/* align */
+
+	if (OF_call_method("claim", ofw_memory_ihandle,
+			   ofw_address_cells + ofw_size_cells + 1,
+			   ofw_address_cells, (int *)cells) == -1) {
+		return -1;
+	}
+
+	if (ofw_address_cells == 2) {
+		/* order of cells is base.lo ... base.hi */
+		uint64_t v;
+		v = *p++;
+		v |= (uint64_t)(*p++) << 32;
+		result = (paddr_t)v;
+	} else {
+		result = *p++;
+	}
+
+	if (result != pa) {
+		printf("!!! CLAIM PHYS 0x%lx RETURNED 0x%lx\n",
+		    pa, result);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+ofw_releasephys(paddr_t pa, vsize_t size)
+{
+	/* (2) phys, (2) size, -> nil */
+	uint32_t cells[2+2];
+	uint32_t *p = cells;
+
+	if (ofw_address_cells == 2) {
+		/* order of cells is phys.lo ... phys.hi */
+		*p++ = (uint32_t)pa;
+		*p++ = ((uint64_t)pa) >> 32;
+	} else {
+		*p++ = (uint32_t)pa;
+	}
+
+#if 0	/* No known Mac systems with 2, and spec is ambiguous about order. */
+	if (ofw_size_cells == 2) {
+		*p++ = ((uint64_t)size) >> 32;
+		*p++ = (uint32_t)size;
+	} else
+#endif
+		*p++ = (uint32_t)size;
+
+	if (OF_call_method("release", ofw_memory_ihandle,
+			   ofw_address_cells + ofw_size_cells,
+			   0, (int *)cells) == -1) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+ofw_claimvirt(vaddr_t va, vsize_t size)
+{
+	/* (1) virt, (1) size, (1) align -> (1) virt */
+	uint32_t cells[1+1+1+1];
+	uint32_t *p = cells;
+	vaddr_t result;
+
+	*p++ = va;
+	*p++ = size;
+	*p++ = 0;		/* align */
+
+	if (OF_call_method("claim", ofw_mmu_ihandle,
+			   3, 1, (int *)cells) == -1) {
+		return -1;
+	}
+
+	result = *p++;
+
+	if (result != va) {
+		printf("!!! CLAIM VIRT 0x%lx RETURNED 0x%lx\n",
+		    va, result);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+ofw_releasevirt(vaddr_t va, vsize_t size)
+{
+	/* (1) virt, (1) size -> nil */
+	uint32_t cells[1+1];
+	uint32_t *p = cells;
+
+	*p++ = va;
+	*p++ = size;
+
+	if (OF_call_method("release", ofw_mmu_ihandle,
+			   2, 0, (int *)cells) == -1) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+ofw_map(vaddr_t va, paddr_t pa, vsize_t size)
+{
+	/* (2) phys, (1) virt, (1) size, (1) mode -> nil */
+	uint32_t cells[2+1+1+1];
+	uint32_t *p = cells;
+
+	if (ofw_address_cells == 2) {
+		/* order of cells is phys.lo ... phys.hi */
+		*p++ = (uint32_t)pa;
+		*p++ = ((uint64_t)pa) >> 32;
+	} else {
+		*p++ = (uint32_t)pa;
+	}
+
+	*p++ = va;
+	*p++ = size;
+	*p++ = 0x00000010 /* PTE_SO | PTE_M */;	/* XXX magic numbers */
+
+	if (OF_call_method("map", ofw_mmu_ihandle,
+			   ofw_address_cells + 3, 0, (int *)cells) == -1) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+ofw_create_mapping(vaddr_t va, paddr_t pa, vsize_t size)
+{
+	if (ofw_claimphys(pa, size) == -1) {
+		printf("!!! FAILED TO CLAIM PHYS 0x%lx size 0x%lx\n",
+		    pa, size);
+		return -1;
+	}
+
+	/*
+	 * If we're running in real-mode, the claimphys is enough.
+	 */
+	if (ofw_real_mode) {
+		return 0;
+	}
+
+	if (ofw_claimvirt(va, size) == -1) {
+		printf("!!! FAILED TO CLAIM VIRT 0x%lx size 0x%lx\n",
+		    va, size);
+		ofw_releasephys(pa, size);
+		return -1;
+	}
+	if (ofw_map(va, pa, size) == -1) {
+		printf("!!! FAILED TO MAP PHYS 0x%lx @ 0x%lx size 0x%lx\n",
+		    pa, va, size);
+		ofw_releasevirt(va, size);
+		ofw_releasephys(pa, size);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * This structure describes a physically contiguous mapping
+ * for the loaded kernel.  We assume VA==PA, which would be
+ * equivalent to running in real-mode.
+ */
+#define	MAX_KMAPPINGS	64
+struct kmapping {
+	vaddr_t		vstart;
+	vaddr_t		vend;
+} kmappings[MAX_KMAPPINGS];
+
+#define	TRUNC_PAGE(x)	((x) & ~((unsigned long)NBPG - 1))
+#define	ROUND_PAGE(x)	TRUNC_PAGE((x) + (NBPG - 1))
+
+/*
+ * Enter a mapping for the loaded kernel.  If the start is within an
+ * already mapped region, or if it starts immediately following a
+ * previous region, we extend it.
+ */
+static int
+kmapping_enter(vaddr_t va, vsize_t size)
+{
+	struct kmapping *km, *km_prev, *km_next, *km_last;
+	vaddr_t va_end;
+	int i;
+
+	km_last = &kmappings[MAX_KMAPPINGS - 1];
+
+	/* Round the region to a page. */
+	va_end = ROUND_PAGE(va + size);
+
+	/* Truncate the region to the nearest page boundary. */
+	va = TRUNC_PAGE(va);
+
+	/* Get the rounded size. */
+	size = va_end - va;
+
+	DPRINTF("kmapping_enter: va=0x%lx size=0x%lx\n",
+	    va, size);
+
+	/* Check to see if there's an overlapping entry in the table. */
+	for (i = 0, km_prev = NULL; i < MAX_KMAPPINGS; i++, km_prev = km) {
+		km = &kmappings[i];
+		km_next = (km == km_last) ? NULL : (km + 1);
+
+		if (km->vstart == km->vend) {
+			/*
+			 * Found an empty slot.  We are guaranteed there
+			 * is not slot after this to merge with.
+			 */
+			DPRINTF("!!! entering into empty slot (%d)\n", i);
+			goto enter_new;
+		}
+
+		if (va >= km->vstart) {
+			if (va_end <= km->vend) {
+				/* This region is already fully mapped. */
+				DPRINTF("!!! matches existing region "
+				       "va=0x%lx-0x%lx\n",
+				       km->vstart, km->vend);
+				return 0;
+			}
+			if (va > km->vend) {
+				/* Requested region falls after this one. */
+				continue;
+			}
+
+			/*
+			 * We will extend this region.  Adjust the
+			 * start and size.
+			 */
+			va = km->vend;
+			size = va_end - va;
+
+			/*
+			 * If there is a slot after this one and it's
+			 * not empty, see if these two can be merged.
+			 */
+			if (km_next != NULL &&
+			    km_next->vstart != km_next->vend &&
+			    va_end >= km_next->vstart) {
+				if (va_end > km_next->vend) {
+					/* Crazy! */
+					printf("!!! GOBBLED UP KM_NEXT!\n");
+					return 1;
+				}
+				va_end = km_next->vstart;
+				size = va_end - va;
+
+				DPRINTF("!!! merging va=0x%lx-0x%lx and "
+				       "va=0x%lx-0x%lx\n",
+				       km->vstart, km->vend,
+				       km_next->vstart, km_next->vend);
+				goto merge_two;
+			}
+
+			DPRINTF("!!! extending existing region "
+			       "va=0x%lx-0x%lx to "
+			       "va=0x%lx-0x%lx\n",
+			       km->vstart, km->vend,
+			       km->vstart, va_end);
+			goto extend_existing;
+		}
+
+		/*
+		 * We know that the new region starts before the current
+		 * one.  Check to see of the end overlaps.
+		 */
+		if (va_end >= km->vstart) {
+			va_end = km->vstart;
+			size = va_end - va;
+
+			/*
+			 * No need to check for a merge here; we would
+			 * have caught it above.
+			 */
+			goto prepend_existing;
+		}
+
+		/*
+		 * Need to the new region in front of the current one.
+		 * Make sure there's room.
+		 */
+		if (km_next == NULL || km_last->vstart != km_last->vend) {
+			printf("!!! NO ROOM TO INSERT MAPPING\n");
+			return 1;
+		}
+
+		if (km_prev == NULL) {
+			DPRINTF("!!! entering before 0x%lx-0x%lx\n",
+			    km->vstart, km->vend);
+		} else {
+			DPRINTF("!!! entering between 0x%lx-0x%lx and "
+			       "0x%lx-0x%lx\n",
+			       km_prev->vstart, km_prev->vend,
+			       km->vstart, km->vend);
+		}
+
+		if (ofw_create_mapping(va, va, size) == -1) {
+			return 1;
+		}
+		size = (uintptr_t)(&kmappings[MAX_KMAPPINGS]) -
+		    (uintptr_t)(km_next + 1);
+		memmove(km_next, km, size);
+		km->vstart = va;
+		km->vend = va_end;
+		return 0;
+	}
+
+ extend_existing:
+	if (ofw_create_mapping(va, va, size) == -1) {
+		return 1;
+	}
+	km->vend = va_end;
+	return 0;
+
+ prepend_existing:
+	if (ofw_create_mapping(va, va, size) == -1) {
+		return 1;
+	}
+	km->vstart = va;
+	return 0;
+
+ enter_new:
+	if (ofw_create_mapping(va, va, size) == -1) {
+		return 1;
+	}
+	km->vstart = va;
+	km->vend = va_end;
+	return 0;
+
+ merge_two:
+	if (ofw_create_mapping(va, va, size) == -1) {
+		return 1;
+	}
+	km->vend = km_next->vend;
+	size =
+	    (uintptr_t)(&kmappings[MAX_KMAPPINGS]) - (uintptr_t)(km_next + 1);
+	if (size != 0) {
+		memmove(km_next, km_next + 1, size);
+	}
+	km_last->vstart = km_last->vend = 0;
+	return 0;
+}
+
+/*
+ * loadfile() hooks.
+ */
+ssize_t
+macppc_read(int f, void *addr, size_t size)
+{
+	if (kmapping_enter((vaddr_t)addr, size)) {
+		return -1;
+	}
+	return read(f, addr, size);
+}
+
+void *
+macppc_memcpy(void *dst, const void *src, size_t size)
+{
+	if (kmapping_enter((vaddr_t)dst, size)) {
+		panic("macppc_memcpy: kmapping_enter failed");
+	}
+	return memcpy(dst, src, size);
+}
+
+void *
+macppc_memset(void *dst, int c, size_t size)
+{
+	if (kmapping_enter((vaddr_t)dst, size)) {
+		panic("macppc_memset: kmapping_enter failed");
+	}
+	return memset(dst, c, size);
+}

Reply via email to