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@)
This commit is contained in:
parent
f0cdc18176
commit
1787909001
@ -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:
|
||||
|
@ -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:
|
||||
@ -207,122 +191,6 @@ ASENTRY(__start)
|
||||
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()
|
||||
*
|
||||
|
61
sys/powerpc/include/rtas.h
Normal file
61
sys/powerpc/include/rtas.h
Normal file
@ -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_ */
|
||||
|
@ -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;
|
||||
|
||||
msz = parse_ofw_memory(phandle, "reg", OFmem);
|
||||
nOFmem = msz / sizeof(struct mem_region);
|
||||
asz = parse_ofw_memory(phandle, "available", OFavail);
|
||||
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);
|
||||
|
||||
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,
|
||||
|
@ -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;
|
||||
|
154
sys/powerpc/ofw/ofwcall32.S
Normal file
154
sys/powerpc/ofw/ofwcall32.S
Normal file
@ -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
|
||||
|
290
sys/powerpc/ofw/ofwcall64.S
Normal file
290
sys/powerpc/ofw/ofwcall64.S
Normal file
@ -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
|
||||
|
243
sys/powerpc/ofw/rtas.c
Normal file
243
sys/powerpc/ofw/rtas.c
Normal file
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user