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