summaryrefslogtreecommitdiffstats
path: root/sys/boot/ofw/libofw/openfirm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/boot/ofw/libofw/openfirm.c')
-rw-r--r--sys/boot/ofw/libofw/openfirm.c943
1 files changed, 943 insertions, 0 deletions
diff --git a/sys/boot/ofw/libofw/openfirm.c b/sys/boot/ofw/libofw/openfirm.c
new file mode 100644
index 0000000..4181067
--- /dev/null
+++ b/sys/boot/ofw/libofw/openfirm.c
@@ -0,0 +1,943 @@
+/* $NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996 Wolfgang Solfrank.
+ * Copyright (C) 1995, 1996 TooLs GmbH.
+ * All rights reserved.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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.
+ */
+/*
+ * Copyright (C) 2000 Benno Rice.
+ * All rights reserved.
+ *
+ * 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 Benno Rice ``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 TOOLS GMBH 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/stdarg.h>
+
+#include <stand.h>
+
+#include "openfirm.h"
+
+int (*openfirmware)(void *);
+
+static ihandle_t stdin;
+static ihandle_t stdout;
+
+ihandle_t mmu;
+ihandle_t memory;
+
+/* Initialiaser */
+
+void
+OF_init(int (*openfirm)(void *))
+{
+ phandle_t chosen;
+
+ openfirmware = openfirm;
+
+ chosen = OF_finddevice("/chosen");
+ OF_getprop(chosen, "memory", &memory, sizeof(memory));
+ if (memory == 0)
+ panic("failed to get memory ihandle");
+ OF_getprop(chosen, "mmu", &mmu, sizeof(mmu));
+ if (mmu == 0)
+ panic("failed to get mmu ihandle");
+}
+
+/*
+ * Generic functions
+ */
+
+/* Test to see if a service exists. */
+int
+OF_test(char *name)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t service;
+ cell_t missing;
+ } args = {
+ (cell_t)"test",
+ 1,
+ 1,
+ 0,
+ 0
+ };
+
+ args.service = (cell_t)name;
+ if (openfirmware(&args) == -1)
+ return -1;
+ return (int)args.missing;
+}
+
+/* Return firmware millisecond count. */
+int
+OF_milliseconds()
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t ms;
+ } args = {
+ (cell_t)"milliseconds",
+ 0,
+ 1,
+ 0
+ };
+
+ openfirmware(&args);
+ return (int)args.ms;
+}
+
+/*
+ * Device tree functions
+ */
+
+/* Return the next sibling of this node or 0. */
+phandle_t
+OF_peer(phandle_t node)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t node;
+ cell_t next;
+ } args = {
+ (cell_t)"peer",
+ 1,
+ 1,
+ 0,
+ 0
+ };
+
+ args.node = (u_int)node;
+ if (openfirmware(&args) == -1)
+ return -1;
+ return (phandle_t)args.next;
+}
+
+/* Return the first child of this node or 0. */
+phandle_t
+OF_child(phandle_t node)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t node;
+ cell_t child;
+ } args = {
+ (cell_t)"child",
+ 1,
+ 1,
+ 0,
+ 0
+ };
+
+ args.node = (u_int)node;
+ if (openfirmware(&args) == -1)
+ return -1;
+ return (phandle_t)args.child;
+}
+
+/* Return the parent of this node or 0. */
+phandle_t
+OF_parent(phandle_t node)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t node;
+ cell_t parent;
+ } args = {
+ (cell_t)"parent",
+ 1,
+ 1,
+ 0,
+ 0
+ };
+
+ args.node = (u_int)node;
+ if (openfirmware(&args) == -1)
+ return -1;
+ return (phandle_t)args.parent;
+}
+
+/* Return the package handle that corresponds to an instance handle. */
+phandle_t
+OF_instance_to_package(ihandle_t instance)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t instance;
+ cell_t package;
+ } args = {
+ (cell_t)"instance-to-package",
+ 1,
+ 1,
+ 0,
+ 0
+ };
+
+ args.instance = (u_int)instance;
+ if (openfirmware(&args) == -1)
+ return -1;
+ return (phandle_t)args.package;
+}
+
+/* Get the length of a property of a package. */
+int
+OF_getproplen(phandle_t package, char *propname)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t package;
+ cell_t propname;
+ cell_t proplen;
+ } args = {
+ (cell_t)"getproplen",
+ 2,
+ 1,
+ 0,
+ 0,
+ 0
+ };
+
+ args.package = (u_int)package;
+ args.propname = (cell_t)propname;
+ if (openfirmware(&args) == -1)
+ return -1;
+ return (int)args.proplen;
+}
+
+/* Get the value of a property of a package. */
+int
+OF_getprop(phandle_t package, char *propname, void *buf, int buflen)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t package;
+ cell_t propname;
+ cell_t buf;
+ cell_t buflen;
+ cell_t size;
+ } args = {
+ (cell_t)"getprop",
+ 4,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ args.package = (u_int)package;
+ args.propname = (cell_t)propname;
+ args.buf = (cell_t)buf;
+ args.buflen = (u_int)buflen;
+ if (openfirmware(&args) == -1)
+ return -1;
+ return (int)args.size;
+}
+
+/* Get the next property of a package. */
+int
+OF_nextprop(phandle_t package, char *previous, char *buf)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t package;
+ cell_t previous;
+ cell_t buf;
+ cell_t flag;
+ } args = {
+ (cell_t)"nextprop",
+ 3,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ args.package = (u_int)package;
+ args.previous = (cell_t)previous;
+ args.buf = (cell_t)buf;
+ if (openfirmware(&args) == -1)
+ return -1;
+ return (int)args.flag;
+}
+
+/* Set the value of a property of a package. */
+/* XXX Has a bug on FirePower */
+int
+OF_setprop(phandle_t package, char *propname, void *buf, int len)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t package;
+ cell_t propname;
+ cell_t buf;
+ cell_t len;
+ cell_t size;
+ } args = {
+ (cell_t)"setprop",
+ 4,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ args.package = (u_int)package;
+ args.propname = (cell_t)propname;
+ args.buf = (cell_t)buf;
+ args.len = (u_int)len;
+ if (openfirmware(&args) == -1)
+ return -1;
+ return (int)args.size;
+}
+
+/* Convert a device specifier to a fully qualified pathname. */
+int
+OF_canon(const char *device, char *buf, int len)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t device;
+ cell_t buf;
+ cell_t len;
+ cell_t size;
+ } args = {
+ (cell_t)"canon",
+ 3,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ args.device = (cell_t)device;
+ args.buf = (cell_t)buf;
+ args.len = (cell_t)len;
+ if (openfirmware(&args) == -1)
+ return -1;
+ return (int)args.size;
+}
+
+/* Return a package handle for the specified device. */
+phandle_t
+OF_finddevice(const char *device)
+{
+ int i;
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t device;
+ cell_t package;
+ } args = {
+ (cell_t)"finddevice",
+ 1,
+ 1,
+ 0,
+ 0
+ };
+
+ args.device = (cell_t)device;
+ if (openfirmware(&args) == -1)
+ return -1;
+
+ return (phandle_t)args.package;
+}
+
+/* Return the fully qualified pathname corresponding to an instance. */
+int
+OF_instance_to_path(ihandle_t instance, char *buf, int len)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t instance;
+ cell_t buf;
+ cell_t len;
+ cell_t size;
+ } args = {
+ (cell_t)"instance-to-path",
+ 3,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ args.instance = (u_int)instance;
+ args.buf = (cell_t)buf;
+ args.len = (u_int)len;
+ if (openfirmware(&args) == -1)
+ return -1;
+ return (int)args.size;
+}
+
+/* Return the fully qualified pathname corresponding to a package. */
+int
+OF_package_to_path(phandle_t package, char *buf, int len)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t package;
+ cell_t buf;
+ cell_t len;
+ cell_t size;
+ } args = {
+ (cell_t)"package-to-path",
+ 3,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ args.package = (u_int)package;
+ args.buf = (cell_t)buf;
+ args.len = (u_int)len;
+ if (openfirmware(&args) == -1)
+ return -1;
+ return (int)args.size;
+}
+
+/* Call the method in the scope of a given instance. */
+int
+OF_call_method(char *method, ihandle_t instance, int nargs, int nreturns, ...)
+{
+ va_list ap;
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t method;
+ cell_t instance;
+ cell_t args_n_results[12];
+ } args = {
+ (cell_t)"call-method",
+ 2,
+ 1,
+ 0,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ };
+ int *ip, n;
+
+ if (nargs > 6)
+ return -1;
+ args.nargs = nargs + 2;
+ args.nreturns = nreturns + 1;
+ args.method = (cell_t)method;
+ args.instance = (u_int)instance;
+ va_start(ap, nreturns);
+ for (ip = (int *)(args.args_n_results + (n = nargs)); --n >= 0;)
+ *--ip = va_arg(ap, int);
+
+ if (openfirmware(&args) == -1)
+ return -1;
+ if (args.args_n_results[nargs])
+ return (int)args.args_n_results[nargs];
+ for (ip = (int *)(args.args_n_results + nargs + (n = args.nreturns));
+ --n > 0;)
+ *va_arg(ap, int *) = *--ip;
+ va_end(ap);
+ return 0;
+}
+
+/*
+ * Device I/O functions.
+ */
+
+/* Open an instance for a device. */
+ihandle_t
+OF_open(char *device)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t device;
+ cell_t instance;
+ } args = {
+ (cell_t)"open",
+ 1,
+ 1,
+ 0,
+ 0
+ };
+
+ args.device = (cell_t)device;
+ if (openfirmware(&args) == -1 || args.instance == 0) {
+ return -1;
+ }
+ return (ihandle_t)args.instance;
+}
+
+/* Close an instance. */
+void
+OF_close(ihandle_t instance)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t instance;
+ } args = {
+ (cell_t)"close",
+ 1,
+ 0,
+ 0
+ };
+
+ args.instance = (u_int)instance;
+ openfirmware(&args);
+}
+
+/* Read from an instance. */
+int
+OF_read(ihandle_t instance, void *addr, int len)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t instance;
+ cell_t addr;
+ cell_t len;
+ cell_t actual;
+ } args = {
+ (cell_t)"read",
+ 3,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ args.instance = (u_int)instance;
+ args.addr = (cell_t)addr;
+ args.len = (u_int)len;
+
+#if defined(OPENFIRM_DEBUG)
+ printf("OF_read: called with instance=%08x, addr=%p, len=%d\n",
+ args.instance, args.addr, args.len);
+#endif
+
+ if (openfirmware(&args) == -1)
+ return -1;
+
+#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);
+#endif
+
+ return (int)args.actual;
+}
+
+/* Write to an instance. */
+int
+OF_write(ihandle_t instance, void *addr, int len)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t instance;
+ cell_t addr;
+ cell_t len;
+ cell_t actual;
+ } args = {
+ (cell_t)"write",
+ 3,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ args.instance = (u_int)instance;
+ args.addr = (cell_t)addr;
+ args.len = (u_int)len;
+ if (openfirmware(&args) == -1)
+ return -1;
+ return (int)args.actual;
+}
+
+/* Seek to a position. */
+int
+OF_seek(ihandle_t instance, u_int64_t pos)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t instance;
+ cell_t poshi;
+ cell_t poslo;
+ cell_t status;
+ } args = {
+ (cell_t)"seek",
+ 3,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ args.instance = (u_int)instance;
+ args.poshi = pos >> 32;
+ args.poslo = pos;
+ if (openfirmware(&args) == -1)
+ return -1;
+ return (int)args.status;
+}
+
+/*
+ * Memory functions.
+ */
+
+/* Claim an area of memory. */
+void *
+OF_claim(void *virt, u_int size, u_int align)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t virt;
+ cell_t size;
+ cell_t align;
+ cell_t baseaddr;
+ } args = {
+ (cell_t)"claim",
+ 3,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ args.virt = (cell_t)virt;
+ args.size = size;
+ args.align = align;
+ if (openfirmware(&args) == -1)
+ return (void *)-1;
+ return (void *)args.baseaddr;
+}
+
+/* Allocate an area of physical memory */
+vm_offset_t
+OF_claim_virt(vm_offset_t virt, size_t size, int align)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nret;
+ cell_t method;
+ cell_t ihandle;
+ cell_t align;
+ cell_t size;
+ cell_t virt;
+ cell_t status;
+ cell_t ret;
+ } args = {
+ (cell_t)"call-method",
+ 5,
+ 2,
+ (cell_t)"claim",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0, /* ret */
+ 0,
+ };
+
+ args.ihandle = mmu;
+ args.align = align;
+ args.size = size;
+ args.virt = virt;
+
+ if (openfirmware(&args) == -1)
+ return (vm_offset_t)-1;
+
+ return (vm_offset_t)args.ret;
+}
+
+/* Allocate an area of physical memory */
+void *
+OF_alloc_phys(size_t size, int align)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nret;
+ cell_t method;
+ cell_t ihandle;
+ cell_t align;
+ cell_t size;
+ cell_t status;
+ cell_t phys_hi;
+ cell_t phys_low;
+ } args = {
+ (cell_t)"call-method",
+ 4,
+ 3,
+ (cell_t)"claim",
+ 0,
+ 0,
+ 0,
+ 0, /* ret */
+ 0,
+ 0,
+ };
+
+ args.ihandle = memory;
+ args.size = size;
+ args.align = align;
+
+ if (openfirmware(&args) == -1)
+ return (void *)-1;
+
+ return (void *)(args.phys_hi << 32 | args.phys_low);
+}
+
+/* Release an area of memory. */
+void
+OF_release(void *virt, u_int size)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t virt;
+ cell_t size;
+ } args = {
+ (cell_t)"release",
+ 2,
+ 0,
+ 0,
+ 0
+ };
+
+ args.virt = (cell_t)virt;
+ args.size = size;
+ openfirmware(&args);
+}
+
+/* Release an area of physical memory. */
+void
+OF_release_phys(vm_offset_t phys, u_int size)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nret;
+ cell_t method;
+ cell_t ihandle;
+ cell_t size;
+ cell_t phys_hi;
+ cell_t phys_lo;
+ } args = {
+ (cell_t)"call-method",
+ 5,
+ 0,
+ (cell_t)"release",
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ args.ihandle = memory;
+ args.phys_hi = (u_int32_t)(phys >> 32);
+ args.phys_lo = (u_int32_t)phys;
+ args.size = size;
+ openfirmware(&args);
+}
+
+/*
+ * Control transfer functions.
+ */
+
+/* Reset the system and call "boot <bootspec>". */
+void
+OF_boot(char *bootspec)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t bootspec;
+ } args = {
+ (cell_t)"boot",
+ 1,
+ 0,
+ 0
+ };
+
+ args.bootspec = (cell_t)bootspec;
+ openfirmware(&args);
+ for (;;); /* just in case */
+}
+
+/* Suspend and drop back to the OpenFirmware interface. */
+void
+OF_enter()
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ } args = {
+ (cell_t)"enter",
+ 0,
+ 0
+ };
+
+ openfirmware(&args);
+}
+
+/* Shut down and drop back to the OpenFirmware interface. */
+void
+OF_exit()
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ } args = {
+ (cell_t)"exit",
+ 0,
+ 0
+ };
+
+ openfirmware(&args);
+ for (;;); /* just in case */
+}
+
+/* Free <size> bytes starting at <virt>, then call <entry> with <arg>. */
+#ifdef __notyet__
+void
+OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
+{
+ static struct {
+ cell_t name;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t virt;
+ cell_t size;
+ cell_t entry;
+ cell_t arg;
+ cell_t len;
+ } args = {
+ (cell_t)"chain",
+ 5,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ args.virt = (cell_t)virt;
+ args.size = size;
+ args.entry = (cell_t)entry;
+ args.arg = (cell_t)arg;
+ args.len = len;
+ openfirmware(&args);
+}
+#else
+void
+OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len)
+{
+ /*
+ * This is a REALLY dirty hack till the firmware gets this going
+ */
+ if (size > 0)
+ OF_release(virt, size);
+
+ entry(0, 0, openfirmware, arg, len);
+}
+#endif
OpenPOWER on IntegriCloud