summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2011-06-02 14:12:37 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2011-06-02 14:12:37 +0000
commit612f3ac60f3ae3700867097de2bfb3d62d5d838f (patch)
treeeb50272d7ef30241f58793552750755dc61cd2f7 /sys
parentc51270cda9202701419eec54ff0cf10e70c30263 (diff)
downloadFreeBSD-src-612f3ac60f3ae3700867097de2bfb3d62d5d838f.zip
FreeBSD-src-612f3ac60f3ae3700867097de2bfb3d62d5d838f.tar.gz
MFpseries:
Renovate and improve the AIM Open Firmware support: - Add RTAS (Run-Time Abstraction Services) support, found on all IBM systems and some Apple ones - Improve support for 32-bit real mode Open Firmware systems - Pull some more OF bits over from the AIM directory - Fix memory detection on IBM LPARs and systems with more than one /memory node (by andreast@)
Diffstat (limited to 'sys')
-rw-r--r--sys/powerpc/aim/locore32.S13
-rw-r--r--sys/powerpc/aim/locore64.S132
-rw-r--r--sys/powerpc/include/rtas.h61
-rw-r--r--sys/powerpc/ofw/ofw_machdep.c185
-rw-r--r--sys/powerpc/ofw/ofw_real.c7
-rw-r--r--sys/powerpc/ofw/ofwcall32.S154
-rw-r--r--sys/powerpc/ofw/ofwcall64.S290
-rw-r--r--sys/powerpc/ofw/ofwmagic.S (renamed from sys/powerpc/aim/ofwmagic.S)0
-rw-r--r--sys/powerpc/ofw/rtas.c243
9 files changed, 898 insertions, 187 deletions
diff --git a/sys/powerpc/aim/locore32.S b/sys/powerpc/aim/locore32.S
index 64bf81e..35ea99b 100644
--- a/sys/powerpc/aim/locore32.S
+++ b/sys/powerpc/aim/locore32.S
@@ -87,9 +87,6 @@ GLOBAL(tmpstk)
GLOBAL(esym)
.long 0 /* end of symbol table */
-GLOBAL(ofmsr)
- .long 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */
-
#define INTRCNT_COUNT 256 /* max(HROWPIC_IRQMAX,OPENPIC_IRQMAX) */
GLOBAL(intrnames)
.space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
@@ -99,16 +96,6 @@ GLOBAL(intrcnt)
.space INTRCNT_COUNT * 4 * 2
GLOBAL(eintrcnt)
-/*
- * File-scope for locore.S
- */
-idle_u:
- .long 0 /* fake uarea during idle after exit */
-openfirmware_entry:
- .long 0 /* Open Firmware entry point */
-srsave:
- .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
.text
.globl btext
btext:
diff --git a/sys/powerpc/aim/locore64.S b/sys/powerpc/aim/locore64.S
index acdc8a1..e71594e 100644
--- a/sys/powerpc/aim/locore64.S
+++ b/sys/powerpc/aim/locore64.S
@@ -76,7 +76,6 @@
.set kernbase, KERNBASE
#define TMPSTKSZ 8192 /* 8K temporary stack */
-#define OFWSTKSZ 4096 /* 4K Open Firmware stack */
/*
* Globals
@@ -85,14 +84,9 @@
.align 4
GLOBAL(tmpstk)
.space TMPSTKSZ
-GLOBAL(ofwstk)
- .space OFWSTKSZ
GLOBAL(esym)
.llong 0 /* end of symbol table */
-GLOBAL(ofmsr)
- .llong 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */
-
#define INTRCNT_COUNT 256 /* max(HROWPIC_IRQMAX,OPENPIC_IRQMAX) */
GLOBAL(intrnames)
.space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
@@ -102,16 +96,6 @@ GLOBAL(intrcnt)
.space INTRCNT_COUNT * 4 * 2
GLOBAL(eintrcnt)
-/*
- * File-scope for locore.S
- */
-idle_u:
- .llong 0 /* fake uarea during idle after exit */
-openfirmware_entry:
- .llong 0 /* Open Firmware entry point */
-srsave:
- .llong 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
.text
.globl btext
btext:
@@ -208,122 +192,6 @@ tocbase:
.llong .TOC.@tocbase
/*
- * Open Firmware Real-mode Entry Point. This is a huge pain.
- */
-
-ASENTRY(ofw_32bit_mode_entry)
- mflr %r0
- std %r0,16(%r1)
- stdu %r1,-208(%r1)
-
- /*
- * We need to save the following, because OF's register save/
- * restore code assumes that the contents of registers are
- * at most 32 bits wide: lr, cr, r2, r13-r31, the old MSR. These
- * get placed in that order in the stack.
- */
-
- mfcr %r4
- std %r4,48(%r1)
- std %r13,56(%r1)
- std %r14,64(%r1)
- std %r15,72(%r1)
- std %r16,80(%r1)
- std %r17,88(%r1)
- std %r18,96(%r1)
- std %r19,104(%r1)
- std %r20,112(%r1)
- std %r21,120(%r1)
- std %r22,128(%r1)
- std %r23,136(%r1)
- std %r24,144(%r1)
- std %r25,152(%r1)
- std %r26,160(%r1)
- std %r27,168(%r1)
- std %r28,176(%r1)
- std %r29,184(%r1)
- std %r30,192(%r1)
- std %r31,200(%r1)
-
- /* Record the old MSR */
- mfmsr %r6
-
- /* read client interface handler */
- lis %r4,openfirmware_entry@ha
- ld %r4,openfirmware_entry@l(%r4)
-
- /*
- * Set the MSR to the OF value. This has the side effect of disabling
- * exceptions, which is important for the next few steps.
- */
-
- lis %r5,ofmsr@ha
- ld %r5,ofmsr@l(%r5)
- mtmsrd %r5
- isync
-
- /*
- * Set up OF stack. This needs to be accessible in real mode and
- * use the 32-bit ABI stack frame format. The pointer to the current
- * kernel stack is placed at the very top of the stack along with
- * the old MSR so we can get them back later.
- */
- mr %r5,%r1
- lis %r1,(ofwstk+OFWSTKSZ-32)@ha
- addi %r1,%r1,(ofwstk+OFWSTKSZ-32)@l
- std %r5,8(%r1) /* Save real stack pointer */
- std %r2,16(%r1) /* Save old TOC */
- std %r6,24(%r1) /* Save old MSR */
- li %r5,0
- stw %r5,4(%r1)
- stw %r5,0(%r1)
-
- /* Finally, branch to OF */
- mtctr %r4
- bctrl
-
- /* Reload stack pointer and MSR from the OFW stack */
- ld %r6,24(%r1)
- ld %r2,16(%r1)
- ld %r1,8(%r1)
-
- /* Now set the real MSR */
- mtmsrd %r6
- isync
-
- /* Sign-extend the return value from OF */
- extsw %r3,%r3
-
- /* Restore all the non-volatile registers */
- ld %r5,48(%r1)
- mtcr %r5
- ld %r13,56(%r1)
- ld %r14,64(%r1)
- ld %r15,72(%r1)
- ld %r16,80(%r1)
- ld %r17,88(%r1)
- ld %r18,96(%r1)
- ld %r19,104(%r1)
- ld %r20,112(%r1)
- ld %r21,120(%r1)
- ld %r22,128(%r1)
- ld %r23,136(%r1)
- ld %r24,144(%r1)
- ld %r25,152(%r1)
- ld %r26,160(%r1)
- ld %r27,168(%r1)
- ld %r28,176(%r1)
- ld %r29,184(%r1)
- ld %r30,192(%r1)
- ld %r31,200(%r1)
-
- /* Restore the stack and link register */
- ld %r1,0(%r1)
- ld %r0,16(%r1)
- mtlr %r0
- blr
-
-/*
* int setfault()
*
* Similar to setjmp to setup for handling faults on accesses to user memory.
diff --git a/sys/powerpc/include/rtas.h b/sys/powerpc/include/rtas.h
new file mode 100644
index 0000000..5b18632
--- /dev/null
+++ b/sys/powerpc/include/rtas.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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 THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_RTAS_H_
+#define _MACHINE_RTAS_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <dev/ofw/openfirm.h>
+
+/*
+ * RTAS functions are defined by 32-bit integer tokens. These vary from
+ * system to system, and can be looked up from their standardized names
+ * using rtas_token_lookup(). If RTAS is not available, rtas_token_lookup()
+ * and rtas_call_method() return -1; this can be checked in advance using
+ * rtas_exists(). Otherwise, rtas_call_method() returns one of the RTAS
+ * status codes from the bottom of this file.
+ */
+
+int rtas_exists(void);
+int rtas_call_method(cell_t token, int nargs, int nreturns, ...);
+cell_t rtas_token_lookup(const char *method);
+
+/* RTAS Status Codes: see CHRP or PAPR specification */
+#define RTAS_OK 0
+#define RTAS_HW_ERROR -1
+#define RTAS_BUSY -2
+#define RTAS_PARAM_ERROR -3
+#define RTAS_STATE_CHANGE -7
+#define RTAS_VENDOR_BEGIN 9000
+#define RTAS_EXTENDED_DELAY 9900
+#define RTAS_ISOLATION_ERROR -9000
+#define RTAS_VENDOR_ERROR_BEGIN -9004
+
+#endif /* _MACHINE_RTAS_H_ */
+
diff --git a/sys/powerpc/ofw/ofw_machdep.c b/sys/powerpc/ofw/ofw_machdep.c
index 9af4051..f602430 100644
--- a/sys/powerpc/ofw/ofw_machdep.c
+++ b/sys/powerpc/ofw/ofw_machdep.c
@@ -60,17 +60,15 @@ __FBSDID("$FreeBSD$");
#include <machine/platform.h>
#include <machine/ofw_machdep.h>
-#define OFMEM_REGIONS 32
-static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
-static struct mem_region OFfree[OFMEM_REGIONS + 3];
-static int nOFmem;
+static struct mem_region OFmem[PHYS_AVAIL_SZ], OFavail[PHYS_AVAIL_SZ];
+static struct mem_region OFfree[PHYS_AVAIL_SZ];
extern register_t ofmsr[5];
-static int (*ofwcall)(void *);
+extern void *openfirmware_entry;
static void *fdt;
int ofw_real_mode;
-int ofw_32bit_mode_entry(void *);
+int ofwcall(void *);
static void ofw_quiesce(void);
static int openfirmware(void *args);
@@ -134,11 +132,32 @@ memr_merge(struct mem_region *from, struct mem_region *to)
to->mr_size = end - to->mr_start;
}
+/*
+ * Quick sort callout for comparing memory regions.
+ */
+static int mr_cmp(const void *a, const void *b);
+
+static int
+mr_cmp(const void *a, const void *b)
+{
+ const struct mem_region *regiona;
+ const struct mem_region *regionb;
+
+ regiona = a;
+ regionb = b;
+ if (regiona->mr_start < regionb->mr_start)
+ return (-1);
+ else if (regiona->mr_start > regionb->mr_start)
+ return (1);
+ else
+ return (0);
+}
+
static int
parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
{
cell_t address_cells, size_cells;
- cell_t OFmem[4*(OFMEM_REGIONS + 1)];
+ cell_t OFmem[4 * PHYS_AVAIL_SZ];
int sz, i, j;
int apple_hack_mode;
phandle_t phandle;
@@ -175,7 +194,7 @@ parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
* Get memory.
*/
if ((node == -1) || (sz = OF_getprop(node, prop,
- OFmem, sizeof(OFmem[0]) * 4 * OFMEM_REGIONS)) <= 0)
+ OFmem, sizeof(OFmem[0]) * 4 * PHYS_AVAIL_SZ)) <= 0)
panic("Physical memory map not found");
i = 0;
@@ -225,7 +244,7 @@ parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
#ifdef __powerpc64__
if (apple_hack_mode) {
/* Add in regions above 4 GB to the available list */
- struct mem_region himem[OFMEM_REGIONS];
+ struct mem_region himem[PHYS_AVAIL_SZ];
int hisz;
hisz = parse_ofw_memory(node, "reg", himem);
@@ -243,6 +262,81 @@ parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
return (sz);
}
+static int
+parse_drconf_memory(int *msz, int *asz, struct mem_region *ofmem,
+ struct mem_region *ofavail)
+{
+ phandle_t phandle;
+ vm_offset_t base;
+ int i, idx, len, lasz, lmsz, res;
+ uint32_t lmb_size[2];
+ unsigned long *dmem, flags;
+
+ lmsz = *msz;
+ lasz = *asz;
+
+ phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory");
+ if (phandle == -1)
+ /* No drconf node, return. */
+ return (0);
+
+ res = OF_getprop(phandle, "ibm,lmb-size", lmb_size, sizeof(lmb_size));
+ if (res == -1)
+ return (0);
+
+ /* Parse the /ibm,dynamic-memory.
+ The first position gives the # of entries. The next two words
+ reflect the address of the memory block. The next four words are
+ the DRC index, reserved, list index and flags.
+ (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory)
+
+ #el Addr DRC-idx res list-idx flags
+ -------------------------------------------------
+ | 4 | 8 | 4 | 4 | 4 | 4 |....
+ -------------------------------------------------
+ */
+
+ len = OF_getproplen(phandle, "ibm,dynamic-memory");
+ if (len > 0) {
+
+ /* We have to use a variable length array on the stack
+ since we have very limited stack space.
+ */
+ cell_t arr[len/sizeof(cell_t)];
+
+ res = OF_getprop(phandle, "ibm,dynamic-memory", &arr,
+ sizeof(arr));
+ if (res == -1)
+ return (0);
+
+ /* Number of elements */
+ idx = arr[0];
+
+ /* First address. */
+ dmem = (void*)&arr[1];
+
+ for (i = 0; i < idx; i++) {
+ base = *dmem;
+ dmem += 2;
+ flags = *dmem;
+ /* Use region only if available and not reserved. */
+ if ((flags & 0x8) && !(flags & 0x80)) {
+ ofmem[lmsz].mr_start = base;
+ ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1];
+ ofavail[lasz].mr_start = base;
+ ofavail[lasz].mr_size = (vm_size_t)lmb_size[1];
+ lmsz++;
+ lasz++;
+ }
+ dmem++;
+ }
+ }
+
+ *msz = lmsz;
+ *asz = lasz;
+
+ return (1);
+}
/*
* This is called during powerpc_init, before the system is really initialized.
* It shall provide the total and the available regions of RAM.
@@ -255,31 +349,62 @@ ofw_mem_regions(struct mem_region **memp, int *memsz,
struct mem_region **availp, int *availsz)
{
phandle_t phandle;
+ vm_offset_t maxphysaddr;
int asz, msz, fsz;
- int i, j;
+ int i, j, res;
int still_merging;
+ char name[31];
asz = msz = 0;
/*
- * Get memory.
+ * Get memory from all the /memory nodes.
*/
- phandle = OF_finddevice("/memory");
- if (phandle == -1)
- phandle = OF_finddevice("/memory@0");
+ for (phandle = OF_child(OF_peer(0)); phandle != 0;
+ phandle = OF_peer(phandle)) {
+ if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0)
+ continue;
+ if (strncmp(name, "memory", sizeof(name)) != 0)
+ continue;
+
+ res = parse_ofw_memory(phandle, "reg", &OFmem[msz]);
+ msz += res/sizeof(struct mem_region);
+ if (OF_getproplen(phandle, "available") >= 0)
+ res = parse_ofw_memory(phandle, "available",
+ &OFavail[asz]);
+ else
+ res = parse_ofw_memory(phandle, "reg", &OFavail[asz]);
+ asz += res/sizeof(struct mem_region);
+ }
+
+ /* Check for memory in ibm,dynamic-reconfiguration-memory */
+ parse_drconf_memory(&msz, &asz, OFmem, OFavail);
- msz = parse_ofw_memory(phandle, "reg", OFmem);
- nOFmem = msz / sizeof(struct mem_region);
- asz = parse_ofw_memory(phandle, "available", OFavail);
+ qsort(OFmem, msz, sizeof(*OFmem), mr_cmp);
+ qsort(OFavail, asz, sizeof(*OFavail), mr_cmp);
*memp = OFmem;
- *memsz = nOFmem;
-
+ *memsz = msz;
+
+ /*
+ * On some firmwares (SLOF), some memory may be marked available that
+ * doesn't actually exist. This manifests as an extension of the last
+ * available segment past the end of physical memory, so truncate that
+ * one.
+ */
+ maxphysaddr = 0;
+ for (i = 0; i < msz; i++)
+ if (OFmem[i].mr_start + OFmem[i].mr_size > maxphysaddr)
+ maxphysaddr = OFmem[i].mr_start + OFmem[i].mr_size;
+
+ if (OFavail[asz - 1].mr_start + OFavail[asz - 1].mr_size > maxphysaddr)
+ OFavail[asz - 1].mr_size = maxphysaddr -
+ OFavail[asz - 1].mr_start;
+
/*
* OFavail may have overlapping regions - collapse these
* and copy out remaining regions to OFfree
*/
- asz /= sizeof(struct mem_region);
do {
still_merging = FALSE;
for (i = 0; i < asz; i++) {
@@ -318,19 +443,6 @@ OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
else
ofw_real_mode = 1;
- ofwcall = NULL;
-
- #ifdef __powerpc64__
- /*
- * For PPC64, we need to use some hand-written
- * asm trampolines to get to OF.
- */
- if (openfirm != NULL)
- ofwcall = ofw_32bit_mode_entry;
- #else
- ofwcall = openfirm;
- #endif
-
fdt = fdt_ptr;
#ifdef FDT_DTB_STATIC
@@ -345,7 +457,7 @@ OF_bootstrap()
{
boolean_t status = FALSE;
- if (ofwcall != NULL) {
+ if (openfirmware_entry != NULL) {
if (ofw_real_mode) {
status = OF_install(OFW_STD_REAL, 0);
} else {
@@ -481,12 +593,7 @@ openfirmware(void *args)
int result;
#ifdef SMP
struct ofw_rv_args rv_args;
- #endif
-
- if (pmap_bootstrapped && ofw_real_mode)
- args = (void *)pmap_kextract((vm_offset_t)args);
- #ifdef SMP
rv_args.args = args;
rv_args.in_progress = 1;
smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch,
diff --git a/sys/powerpc/ofw/ofw_real.c b/sys/powerpc/ofw/ofw_real.c
index 617f9be..1fc2ed1 100644
--- a/sys/powerpc/ofw/ofw_real.c
+++ b/sys/powerpc/ofw/ofw_real.c
@@ -205,13 +205,14 @@ ofw_real_bounce_alloc(void *junk)
/*
* Allocate a page of contiguous, wired physical memory that can
- * fit into a 32-bit address space.
+ * fit into a 32-bit address space and accessed from real mode.
*/
mtx_lock(&of_bounce_mtx);
- of_bounce_virt = contigmalloc(PAGE_SIZE, M_OFWREAL, 0,
- 0, BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE, PAGE_SIZE);
+ of_bounce_virt = contigmalloc(PAGE_SIZE, M_OFWREAL, 0, 0,
+ ulmin(platform_real_maxaddr(), BUS_SPACE_MAXADDR_32BIT), PAGE_SIZE,
+ PAGE_SIZE);
of_bounce_phys = vtophys(of_bounce_virt);
of_bounce_size = PAGE_SIZE;
diff --git a/sys/powerpc/ofw/ofwcall32.S b/sys/powerpc/ofw/ofwcall32.S
new file mode 100644
index 0000000..06cc105
--- /dev/null
+++ b/sys/powerpc/ofw/ofwcall32.S
@@ -0,0 +1,154 @@
+/*-
+ * Copyright (C) 2009-2011 Nathan Whitehorn
+ * 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 THE AUTHOR ``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 <sys/syscall.h>
+
+#include <machine/trap.h>
+#include <machine/param.h>
+#include <machine/spr.h>
+#include <machine/asm.h>
+
+#define OFWSTKSZ 4096 /* 4K Open Firmware stack */
+
+/*
+ * Globals
+ */
+ .data
+GLOBAL(ofmsr)
+ .long 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */
+GLOBAL(rtasmsr)
+ .long 0
+GLOBAL(openfirmware_entry)
+ .long 0 /* Open Firmware entry point */
+GLOBAL(rtas_entry)
+ .long 0 /* RTAS entry point */
+
+ .align 4
+ofwstk:
+ .space OFWSTKSZ
+rtas_regsave:
+ .space 4
+
+/*
+ * Open Firmware Entry Point. May need to enter real mode.
+ *
+ * C prototype: int ofwcall(void *callbuffer);
+ */
+
+ASENTRY(ofwcall)
+ mflr %r0
+ stw %r0,4(%r1)
+
+ /* Record the old MSR */
+ mfmsr %r6
+
+ /* read client interface handler */
+ lis %r4,openfirmware_entry@ha
+ lwz %r4,openfirmware_entry@l(%r4)
+
+ /*
+ * Set the MSR to the OF value. This has the side effect of disabling
+ * exceptions, which prevents preemption later.
+ */
+
+ lis %r5,ofmsr@ha
+ lwz %r5,ofmsr@l(%r5)
+ mtmsr %r5
+ isync
+
+ /*
+ * Set up OF stack. This needs to be potentially accessible in real mode
+ * The pointer to the current kernel stack is placed at the very
+ * top of the stack along with the old MSR so we can get them back
+ * later.
+ */
+ mr %r5,%r1
+ lis %r1,(ofwstk+OFWSTKSZ-16)@ha
+ addi %r1,%r1,(ofwstk+OFWSTKSZ-16)@l
+ stw %r5,8(%r1) /* Save real stack pointer */
+ stw %r6,12(%r1) /* Save old MSR */
+ li %r5,0
+ stw %r5,4(%r1)
+ stw %r5,0(%r1)
+
+ /* Finally, branch to OF */
+ mtctr %r4
+ bctrl
+
+ /* Reload stack pointer and MSR from the OFW stack */
+ lwz %r6,12(%r1)
+ lwz %r1,8(%r1)
+
+ /* Now set the real MSR */
+ mtmsr %r6
+ isync
+
+ /* Return */
+ lwz %r0,4(%r1)
+ mtlr %r0
+ blr
+
+/*
+ * RTAS Entry Point. Similar to the OF one, but simpler (no separate stack)
+ *
+ * C prototype: int rtascall(void *callbuffer, void *rtas_privdat);
+ */
+
+ASENTRY(rtascall)
+ mflr %r0
+ stw %r0,4(%r1)
+
+ /* Record the old MSR to real-mode-accessible area */
+ mfmsr %r0
+ lis %r5,rtas_regsave@ha
+ stw %r0,rtas_regsave@l(%r5)
+
+ /* read client interface handler */
+ lis %r5,rtas_entry@ha
+ lwz %r5,rtas_entry@l(%r5)
+
+ /* Set the MSR to the RTAS value */
+ lis %r6,rtasmsr@ha
+ lwz %r6,rtasmsr@l(%r6)
+ mtmsr %r6
+ isync
+
+ /* Branch to RTAS */
+ mtctr %r5
+ bctrl
+
+ /* Now set the MSR back */
+ lis %r6,rtas_regsave@ha
+ lwz %r6,rtas_regsave@l(%r6)
+ mtmsr %r6
+ isync
+
+ /* And return */
+ lwz %r0,4(%r1)
+ mtlr %r0
+ blr
+
diff --git a/sys/powerpc/ofw/ofwcall64.S b/sys/powerpc/ofw/ofwcall64.S
new file mode 100644
index 0000000..1fb78e8
--- /dev/null
+++ b/sys/powerpc/ofw/ofwcall64.S
@@ -0,0 +1,290 @@
+/*-
+ * Copyright (C) 2009-2011 Nathan Whitehorn
+ * 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 THE AUTHOR ``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 <sys/syscall.h>
+
+#include <machine/trap.h>
+#include <machine/param.h>
+#include <machine/spr.h>
+#include <machine/asm.h>
+
+#define OFWSTKSZ 4096 /* 4K Open Firmware stack */
+
+/*
+ * Globals
+ */
+ .data
+ .align 4
+ofwstk:
+ .space OFWSTKSZ
+rtas_regsave:
+ .space 24 /* 3 * sizeof(register_t) */
+GLOBAL(ofmsr)
+ .llong 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */
+GLOBAL(rtasmsr)
+ .llong 0
+GLOBAL(openfirmware_entry)
+ .llong 0 /* Open Firmware entry point */
+GLOBAL(rtas_entry)
+ .llong 0 /* RTAS entry point */
+
+/*
+ * Open Firmware Real-mode Entry Point. This is a huge pain.
+ */
+
+ASENTRY(ofwcall)
+ mflr %r0
+ std %r0,16(%r1)
+ stdu %r1,-208(%r1)
+
+ /*
+ * We need to save the following, because OF's register save/
+ * restore code assumes that the contents of registers are
+ * at most 32 bits wide: lr, cr, r2, r13-r31, the old MSR. These
+ * get placed in that order in the stack.
+ */
+
+ mfcr %r4
+ std %r4,48(%r1)
+ std %r13,56(%r1)
+ std %r14,64(%r1)
+ std %r15,72(%r1)
+ std %r16,80(%r1)
+ std %r17,88(%r1)
+ std %r18,96(%r1)
+ std %r19,104(%r1)
+ std %r20,112(%r1)
+ std %r21,120(%r1)
+ std %r22,128(%r1)
+ std %r23,136(%r1)
+ std %r24,144(%r1)
+ std %r25,152(%r1)
+ std %r26,160(%r1)
+ std %r27,168(%r1)
+ std %r28,176(%r1)
+ std %r29,184(%r1)
+ std %r30,192(%r1)
+ std %r31,200(%r1)
+
+ /* Record the old MSR */
+ mfmsr %r6
+
+ /* read client interface handler */
+ lis %r4,openfirmware_entry@ha
+ ld %r4,openfirmware_entry@l(%r4)
+
+ /*
+ * Set the MSR to the OF value. This has the side effect of disabling
+ * exceptions, which is important for the next few steps.
+ */
+
+ lis %r5,ofmsr@ha
+ ld %r5,ofmsr@l(%r5)
+ mtmsrd %r5
+ isync
+
+ /*
+ * Set up OF stack. This needs to be accessible in real mode and
+ * use the 32-bit ABI stack frame format. The pointer to the current
+ * kernel stack is placed at the very top of the stack along with
+ * the old MSR so we can get them back later.
+ */
+ mr %r5,%r1
+ lis %r1,(ofwstk+OFWSTKSZ-32)@ha
+ addi %r1,%r1,(ofwstk+OFWSTKSZ-32)@l
+ std %r5,8(%r1) /* Save real stack pointer */
+ std %r2,16(%r1) /* Save old TOC */
+ std %r6,24(%r1) /* Save old MSR */
+ li %r5,0
+ stw %r5,4(%r1)
+ stw %r5,0(%r1)
+
+ /* Finally, branch to OF */
+ mtctr %r4
+ bctrl
+
+ /* Reload stack pointer and MSR from the OFW stack */
+ ld %r6,24(%r1)
+ ld %r2,16(%r1)
+ ld %r1,8(%r1)
+
+ /* Now set the real MSR */
+ mtmsrd %r6
+ isync
+
+ /* Sign-extend the return value from OF */
+ extsw %r3,%r3
+
+ /* Restore all the non-volatile registers */
+ ld %r5,48(%r1)
+ mtcr %r5
+ ld %r13,56(%r1)
+ ld %r14,64(%r1)
+ ld %r15,72(%r1)
+ ld %r16,80(%r1)
+ ld %r17,88(%r1)
+ ld %r18,96(%r1)
+ ld %r19,104(%r1)
+ ld %r20,112(%r1)
+ ld %r21,120(%r1)
+ ld %r22,128(%r1)
+ ld %r23,136(%r1)
+ ld %r24,144(%r1)
+ ld %r25,152(%r1)
+ ld %r26,160(%r1)
+ ld %r27,168(%r1)
+ ld %r28,176(%r1)
+ ld %r29,184(%r1)
+ ld %r30,192(%r1)
+ ld %r31,200(%r1)
+
+ /* Restore the stack and link register */
+ ld %r1,0(%r1)
+ ld %r0,16(%r1)
+ mtlr %r0
+ blr
+
+/*
+ * RTAS 32-bit Entry Point. Similar to the OF one, but simpler (no separate
+ * stack)
+ *
+ * C prototype: int rtascall(void *callbuffer, void *rtas_privdat);
+ */
+
+ASENTRY(rtascall)
+ mflr %r0
+ std %r0,16(%r1)
+ stdu %r1,-208(%r1)
+
+ /*
+ * We need to save the following, because RTAS's register save/
+ * restore code assumes that the contents of registers are
+ * at most 32 bits wide: lr, cr, r2, r13-r31, the old MSR. These
+ * get placed in that order in the stack.
+ */
+
+ mfcr %r5
+ std %r5,48(%r1)
+ std %r13,56(%r1)
+ std %r14,64(%r1)
+ std %r15,72(%r1)
+ std %r16,80(%r1)
+ std %r17,88(%r1)
+ std %r18,96(%r1)
+ std %r19,104(%r1)
+ std %r20,112(%r1)
+ std %r21,120(%r1)
+ std %r22,128(%r1)
+ std %r23,136(%r1)
+ std %r24,144(%r1)
+ std %r25,152(%r1)
+ std %r26,160(%r1)
+ std %r27,168(%r1)
+ std %r28,176(%r1)
+ std %r29,184(%r1)
+ std %r30,192(%r1)
+ std %r31,200(%r1)
+
+ /* Record the old MSR */
+ mfmsr %r6
+
+ /* read client interface handler */
+ lis %r5,rtas_entry@ha
+ ld %r5,rtas_entry@l(%r5)
+
+ /*
+ * Set the MSR to the RTAS value. This has the side effect of disabling
+ * exceptions, which is important for the next few steps.
+ */
+
+ lis %r7,rtasmsr@ha
+ ld %r7,rtasmsr@l(%r7)
+ mtmsrd %r7
+ isync
+
+ /*
+ * Set up RTAS register save area, so that we can get back all of
+ * our 64-bit pointers. Save our stack pointer, the TOC, and the MSR.
+ * Put this in r1, since RTAS is obliged to save it. Kernel globals
+ * are below 4 GB, so this is safe.
+ */
+ mr %r7,%r1
+ lis %r1,rtas_regsave@ha
+ addi %r1,%r1,rtas_regsave@l
+ std %r7,0(%r1) /* Save 64-bit stack pointer */
+ std %r2,8(%r1) /* Save TOC */
+ std %r6,16(%r1) /* Save MSR */
+
+ /* Finally, branch to RTAS */
+ mtctr %r5
+ bctrl
+
+ /*
+ * Reload stack pointer and MSR from the reg save area in r1. We are
+ * running in 32-bit mode at this point, so it doesn't matter if r1
+ * has become sign-extended.
+ */
+ ld %r6,16(%r1)
+ ld %r2,8(%r1)
+ ld %r1,0(%r1)
+
+ /* Now set the real MSR */
+ mtmsrd %r6
+ isync
+
+ /* Sign-extend the return value from RTAS */
+ extsw %r3,%r3
+
+ /* Restore all the non-volatile registers */
+ ld %r5,48(%r1)
+ mtcr %r5
+ ld %r13,56(%r1)
+ ld %r14,64(%r1)
+ ld %r15,72(%r1)
+ ld %r16,80(%r1)
+ ld %r17,88(%r1)
+ ld %r18,96(%r1)
+ ld %r19,104(%r1)
+ ld %r20,112(%r1)
+ ld %r21,120(%r1)
+ ld %r22,128(%r1)
+ ld %r23,136(%r1)
+ ld %r24,144(%r1)
+ ld %r25,152(%r1)
+ ld %r26,160(%r1)
+ ld %r27,168(%r1)
+ ld %r28,176(%r1)
+ ld %r29,184(%r1)
+ ld %r30,192(%r1)
+ ld %r31,200(%r1)
+
+ /* Restore the stack and link register */
+ ld %r1,0(%r1)
+ ld %r0,16(%r1)
+ mtlr %r0
+ blr
+
diff --git a/sys/powerpc/aim/ofwmagic.S b/sys/powerpc/ofw/ofwmagic.S
index f44f1e5..f44f1e5 100644
--- a/sys/powerpc/aim/ofwmagic.S
+++ b/sys/powerpc/ofw/ofwmagic.S
diff --git a/sys/powerpc/ofw/rtas.c b/sys/powerpc/ofw/rtas.c
new file mode 100644
index 0000000..59692c9
--- /dev/null
+++ b/sys/powerpc/ofw/rtas.c
@@ -0,0 +1,243 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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 THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+#include <machine/md_var.h>
+#include <machine/pmap.h>
+#include <machine/rtas.h>
+#include <machine/stdarg.h>
+
+#include <dev/ofw/openfirm.h>
+
+MALLOC_DEFINE(M_RTAS, "rtas", "Run Time Abstraction Service");
+
+static vm_offset_t rtas_bounce_phys;
+static caddr_t rtas_bounce_virt;
+static off_t rtas_bounce_offset;
+static size_t rtas_bounce_size;
+static uintptr_t rtas_private_data;
+static struct mtx rtas_mtx;
+static phandle_t rtas;
+
+/* From ofwcall.S */
+int rtascall(vm_offset_t callbuffer, uintptr_t rtas_privdat);
+extern uintptr_t rtas_entry;
+extern register_t rtasmsr;
+
+/*
+ * After the VM is up, allocate RTAS memory and instantiate it
+ */
+
+static void rtas_setup(void *);
+
+SYSINIT(rtas_setup, SI_SUB_KMEM, SI_ORDER_ANY, rtas_setup, NULL);
+
+static void
+rtas_setup(void *junk)
+{
+ ihandle_t rtasi;
+ cell_t rtas_size = 0, rtas_ptr;
+ char path[31];
+ int result;
+
+ rtas = OF_finddevice("/rtas");
+ if (rtas == -1) {
+ rtas = 0;
+ return;
+ }
+ OF_package_to_path(rtas, path, sizeof(path));
+ rtasi = OF_open(path);
+ if (rtasi == 0) {
+ rtas = 0;
+ printf("Error initializing RTAS: could not open node\n");
+ return;
+ }
+
+ mtx_init(&rtas_mtx, "RTAS", MTX_DEF, 0);
+
+ /* RTAS must be called with everything turned off in MSR */
+ rtasmsr = mfmsr();
+ rtasmsr &= ~(PSL_IR | PSL_DR | PSL_EE | PSL_SE);
+ #ifdef __powerpc64__
+ rtasmsr &= ~PSL_SF;
+ #endif
+
+ /*
+ * Allocate rtas_size + one page of contiguous, wired physical memory
+ * that can fit into a 32-bit address space and accessed from real mode.
+ * This is used both to bounce arguments and for RTAS private data.
+ *
+ * It must be 4KB-aligned and not cross a 256 MB boundary.
+ */
+
+ OF_getprop(rtas, "rtas-size", &rtas_size, sizeof(rtas_size));
+ rtas_size = round_page(rtas_size);
+ rtas_bounce_virt = contigmalloc(rtas_size + PAGE_SIZE, M_RTAS, 0, 0,
+ ulmin(platform_real_maxaddr(), BUS_SPACE_MAXADDR_32BIT),
+ 4096, 256*1024*1024);
+
+ rtas_private_data = vtophys(rtas_bounce_virt);
+ rtas_bounce_virt += rtas_size; /* Actual bounce area */
+ rtas_bounce_phys = vtophys(rtas_bounce_virt);
+ rtas_bounce_size = PAGE_SIZE;
+
+ /*
+ * Instantiate RTAS. We always use the 32-bit version.
+ */
+
+ result = OF_call_method("instantiate-rtas", rtasi, 1, 1,
+ (cell_t)rtas_private_data, &rtas_ptr);
+ OF_close(rtasi);
+
+ if (result != 0) {
+ rtas = 0;
+ rtas_ptr = 0;
+ printf("Error initializing RTAS (%d)\n", result);
+ return;
+ }
+
+ rtas_entry = (uintptr_t)(rtas_ptr);
+}
+
+static cell_t
+rtas_real_map(const void *buf, size_t len)
+{
+ cell_t phys;
+
+ mtx_assert(&rtas_mtx, MA_OWNED);
+
+ /*
+ * Make sure the bounce page offset satisfies any reasonable
+ * alignment constraint.
+ */
+ rtas_bounce_offset += sizeof(register_t) -
+ (rtas_bounce_offset % sizeof(register_t));
+
+ if (rtas_bounce_offset + len > rtas_bounce_size) {
+ panic("Oversize RTAS call!");
+ return 0;
+ }
+
+ if (buf != NULL)
+ memcpy(rtas_bounce_virt + rtas_bounce_offset, buf, len);
+ else
+ return (0);
+
+ phys = rtas_bounce_phys + rtas_bounce_offset;
+ rtas_bounce_offset += len;
+
+ return (phys);
+}
+
+static void
+rtas_real_unmap(cell_t physaddr, void *buf, size_t len)
+{
+ mtx_assert(&rtas_mtx, MA_OWNED);
+
+ if (physaddr == 0)
+ return;
+
+ memcpy(buf, rtas_bounce_virt + (physaddr - rtas_bounce_phys), len);
+}
+
+/* Check if we have RTAS */
+int
+rtas_exists(void)
+{
+ return (rtas != 0);
+}
+
+/* Call an RTAS method by token */
+int
+rtas_call_method(cell_t token, int nargs, int nreturns, ...)
+{
+ vm_offset_t argsptr;
+ va_list ap;
+ struct {
+ cell_t token;
+ cell_t nargs;
+ cell_t nreturns;
+ cell_t args_n_results[12];
+ } args;
+ int n, result;
+
+ if (!rtas_exists() || nargs + nreturns > 12)
+ return (-1);
+
+ args.token = token;
+ va_start(ap, nreturns);
+
+ mtx_lock(&rtas_mtx);
+ rtas_bounce_offset = 0;
+
+ args.nargs = nargs;
+ args.nreturns = nreturns;
+
+ for (n = 0; n < nargs; n++)
+ args.args_n_results[n] = va_arg(ap, cell_t);
+
+ argsptr = rtas_real_map(&args, sizeof(args));
+ result = rtascall(argsptr, rtas_private_data);
+ rtas_real_unmap(argsptr, &args, sizeof(args));
+ mtx_unlock(&rtas_mtx);
+
+ if (result < 0)
+ return (result);
+
+ for (n = nargs; n < nargs + nreturns; n++)
+ *va_arg(ap, cell_t *) = args.args_n_results[n];
+ return (result);
+}
+
+/* Look up an RTAS token */
+cell_t
+rtas_token_lookup(const char *method)
+{
+ cell_t token;
+
+ if (!rtas_exists())
+ return (-1);
+
+ if (OF_getprop(rtas, method, &token, sizeof(token)) == -1)
+ return (-1);
+
+ return (token);
+}
+
+
OpenPOWER on IntegriCloud