NetBSD/sys/arch/sparc64/sparc64/ofw_machdep.c

776 lines
16 KiB
C

/* $NetBSD: ofw_machdep.c,v 1.1.1.1 1998/06/20 04:58:52 eeh Exp $ */
/*
* Copyright (C) 1996 Wolfgang Solfrank.
* Copyright (C) 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.
*/
#include <sys/param.h>
#include <sys/buf.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/disk.h>
#include <sys/disklabel.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/stat.h>
#include <sys/systm.h>
#include <machine/openfirm.h>
#if defined(FFS) && defined(CD9660)
#include <ufs/ffs/fs.h>
#endif
/*
* Note that stdarg.h and the ANSI style va_start macro is used for both
* ANSI and traditional C compilers.
*/
#include <machine/stdarg.h>
#include <machine/sparc64.h>
int vsprintf __P((char *, const char *, va_list));
void dk_cleanup __P((void));
#if defined(FFS) && defined(CD9660)
static int dk_match_ffs __P((void));
#endif
static int mmuh = -1, memh = -1;
static int get_mmu_handle __P((void));
static int get_memory_handle __P((void));
static int
get_mmu_handle() {
int chosen;
if ((chosen = OF_finddevice("/chosen")) == -1) {
prom_printf("get_mmu_handle: cannot get /chosen\r\n");
return -1;
}
if (OF_getprop(chosen, "mmu", &mmuh, sizeof(mmuh)) == -1) {
prom_printf("get_mmu_handle: cannot get mmuh\r\n");
return -1;
}
return mmuh;
}
static int
get_memory_handle() {
int chosen;
if ((chosen = OF_finddevice("/chosen")) == -1) {
prom_printf("get_mmu_handle: cannot get /chosen\r\n");
return -1;
}
if (OF_getprop(chosen, "memory", &memh, sizeof(memh)) == -1) {
prom_printf("get_memory_handle: cannot get memh\r\n");
return -1;
}
return memh;
}
/*
* Point prom to our trap table. This stops the prom from mapping us.
*/
int
prom_set_trap_table(tba)
vm_offset_t tba;
{
static struct {
int pad0; char *name;
int64_t nargs;
int64_t nreturns;
int pad1; vm_offset_t tba;
} args = {
0,"SUNW,set-trap-table",
1,
0,
0, NULL
};
args.tba = tba;
return openfirmware(&args);
}
/*
* Have the prom convert from virtual to physical addresses.
*
* Only works while the prom is actively mapping us.
*/
u_int64_t
prom_vtop(vaddr)
vm_offset_t vaddr;
{
static struct {
int pad0; char *name;
int64_t nargs;
int64_t nreturns;
int pad1; char *method;
int pad2; int ihandle;
int pad3; vm_offset_t vaddr;
int64_t status;
int64_t retaddr;
int64_t mode;
u_int64_t paddr_hi;
u_int64_t paddr_lo;
} args = {
0,"call-method",
3,
5,
0,"translate",
0, 0,
0, NULL,
0
};
if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
prom_printf("prom_vtop: cannot get mmuh\r\n");
return 0LL;
}
args.ihandle = mmuh;
args.vaddr = vaddr;
if(openfirmware(&args) != 0)
return 0LL;
#if 0
prom_printf("Called \"translate\", mmuh=%x, vaddr=%x, status=%x %x,\r\n retaddr=%x %x, mode=%x %x, phys_hi=%x %x, phys_lo=%x %x\r\n",
mmuh, vaddr, (int)(args.status>>32), (int)args.status, (int)(args.retaddr>>32), (int)args.retaddr,
(int)(args.mode>>32), (int)args.mode, (int)(args.paddr_hi>>32), (int)args.paddr_hi,
(int)(args.paddr_lo>>32), (int)args.paddr_lo);
#endif
#ifdef INT_IS_64_BITS
return (u_int64_t)((((u_int64_t)args.paddr_hi)<<32)|(u_int64_t)args.paddr_lo);
#else
return args.paddr_lo; /* Kluge till we go 64-bit */
#endif
}
/*
* Grab some address space from the prom
*
* Only works while the prom is actively mapping us.
*/
u_int64_t
prom_claim_virt(vaddr, len)
vm_offset_t vaddr;
int len;
{
static struct {
int pad0; char *name;
int64_t nargs;
int64_t nreturns;
int pad1; char *method;
int pad2; int ihandle;
u_int64_t align;
u_int64_t len;
int pad3; vm_offset_t vaddr;
int64_t status;
int64_t retaddr;
} args = {
0,"call-method",
5,
2,
0,"claim",
0, 0,
0,
0,
0, NULL,
0,
0
};
if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
prom_printf("prom_claim_virt: cannot get mmuh\r\n");
return 0LL;
}
args.ihandle = mmuh;
args.vaddr = vaddr;
args.len = len;
if(openfirmware(&args) != 0)
return 0LL;
return args.retaddr; /* Kluge till we go 64-bit */
}
/*
* Request some address space from the prom
*
* Only works while the prom is actively mapping us.
*/
u_int64_t
prom_alloc_virt(len, align)
int len;
int align;
{
static int retaddr;
static struct {
int pad0; char *name;
int64_t nargs;
int64_t nreturns;
int pad1; char *method;
int pad2; int ihandle;
u_int64_t align;
u_int64_t len;
int64_t status;
int pad4; void* retaddr;
} args = {
0,"call-method",
4,
2,
0,"claim",
0, 0,
0,
0,
0,
0, &retaddr
};
if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
prom_printf("prom_alloc_virt: cannot get mmuh\r\n");
return -1LL;
}
args.ihandle = mmuh;
args.align = align;
args.len = len;
if(openfirmware(&args) != 0)
return -1LL;
return retaddr; /* Kluge till we go 64-bit */
}
/*
* Release some address space to the prom
*
* Only works while the prom is actively mapping us.
*/
int
prom_free_virt(vaddr, len)
vm_offset_t vaddr;
int len;
{
static struct {
int pad0; char *name;
int64_t nargs;
int64_t nreturns;
int pad1; char *method;
int pad2; int ihandle;
u_int64_t len;
int pad3; vm_offset_t vaddr;
} args = {
0,"call-method",
4,
0,
0,"release",
0, 0,
0,
0, NULL
};
if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
prom_printf("prom_claim_virt: cannot get mmuh\r\n");
return -1;
}
args.ihandle = mmuh;
args.vaddr = vaddr;
args.len = len;
return openfirmware(&args);
}
/*
* Unmap some address space
*
* Only works while the prom is actively mapping us.
*/
int
prom_unmap_virt(vaddr, len)
vm_offset_t vaddr;
int len;
{
static struct {
int pad0; char *name;
int64_t nargs;
int64_t nreturns;
int pad1; char *method;
int pad2; int ihandle;
u_int64_t len;
int pad3; vm_offset_t vaddr;
} args = {
0,"call-method",
4,
0,
0,"unmap",
0, 0,
0,
0, NULL
};
if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
prom_printf("prom_claim_virt: cannot get mmuh\r\n");
return -1;
}
args.ihandle = mmuh;
args.vaddr = vaddr;
args.len = len;
return openfirmware(&args);
}
/*
* Have prom map in some memory
*
* Only works while the prom is actively mapping us.
*/
int
prom_map_phys(paddr, size, vaddr, mode)
u_int64_t paddr;
off_t size;
vm_offset_t vaddr;
int mode;
{
int phys_hi, phys_lo;
static struct {
int pad0; char *name;
int64_t nargs;
int64_t nreturns;
int pad1; char *method;
int pad2; int ihandle;
int64_t mode;
u_int64_t size;
int pad3; vm_offset_t vaddr;
int pad4; vm_offset_t paddr_hi;
int pad6; vm_offset_t paddr_lo;
int64_t status;
int64_t retaddr;
} args = {
0,"call-method",
7,
1,
0,"map",
0, 0,
0, 0,
0, NULL,
0, NULL,
0, NULL
};
if (mmuh == -1 && ((mmuh = get_mmu_handle()) == -1)) {
prom_printf("prom_map_phys: cannot get mmuh\r\n");
return 0LL;
}
#ifdef INT_IS_64_BITS
phys_hi = paddr>>32;
#else
phys_hi = 0; /* This is what Solaris does. We gotta fix this for 64-bits */
#endif
phys_lo = paddr;
args.ihandle = mmuh;
args.mode = mode;
args.size = size;
args.vaddr = vaddr;
args.paddr_hi = phys_hi;
args.paddr_lo = phys_lo;
if (openfirmware(&args) == -1)
return -1;
if (args.status)
return -1;
return args.retaddr;
}
/*
* Request some RAM from the prom
*
* Only works while the prom is actively mapping us.
*/
u_int64_t
prom_alloc_phys(len, align)
int len;
int align;
{
static struct {
int pad0; char *name;
int64_t nargs;
int64_t nreturns;
int pad1; char *method;
int pad2; int ihandle;
u_int64_t align;
u_int64_t len;
int64_t status;
u_int64_t phys_hi;
u_int64_t phys_lo;
} args = {
0,"call-method",
4,
3,
0,"claim",
0, 0,
0,
0,
0,
};
if (memh == -1 && ((memh = get_memory_handle()) == -1)) {
prom_printf("prom_alloc_phys: cannot get memh\r\n");
return 0LL;
}
args.ihandle = memh;
args.align = align;
args.len = len;
if(openfirmware(&args) != 0)
return 0LL;
return args.phys_lo; /* Kluge till we go 64-bit */
}
/*
* Request some specific RAM from the prom
*
* Only works while the prom is actively mapping us.
*/
u_int64_t
prom_claim_phys(phys, len)
vm_offset_t phys;
int len;
{
static struct {
int pad0; char *name;
int64_t nargs;
int64_t nreturns;
int pad1; char *method;
int pad2; int ihandle;
u_int64_t align;
u_int64_t len;
int pad4; void* phys_hi;
int pad5; void* phys_lo;
int64_t status;
int64_t res;
u_int64_t rphys_hi;
u_int64_t rphys_lo;
} args = {
0,"call-method",
6,
4,
0,"claim",
0, 0,
0,
0,
0, NULL,
0, NULL,
0
};
if (memh == -1 && ((memh = get_memory_handle()) == -1)) {
prom_printf("prom_alloc_phys: cannot get memh\r\n");
return 0LL;
}
args.ihandle = memh;
args.len = len;
args.phys_lo = phys;
if(openfirmware(&args) != 0)
return 0LL;
return args.rphys_lo; /* Kluge till we go 64-bit */
}
/*
* Free some RAM to prom
*
* Only works while the prom is actively mapping us.
*/
int
prom_free_phys(phys, len)
vm_offset_t phys;
int len;
{
static struct {
int pad0; char *name;
int64_t nargs;
int64_t nreturns;
int pad1; char *method;
int pad2; int ihandle;
u_int64_t len;
int pad4; void* phys_hi;
int pad5; void* phys_lo;
} args = {
0,"call-method",
5,
0,
0,"release",
0, 0,
0,
0, NULL,
0, NULL,
};
if (memh == -1 && ((memh = get_memory_handle()) == -1)) {
prom_printf("prom_free_phys: cannot get memh\r\n");
return -1;
}
args.ihandle = memh;
args.len = len;
args.phys_lo = phys;
return openfirmware(&args);
}
/*
* Get the msgbuf from the prom. Only works once.
*
* Only works while the prom is actively mapping us.
*/
u_int64_t
prom_get_msgbuf(len, align)
int len;
int align;
{
static struct {
int pad0; char *name;
int64_t nargs;
int64_t nreturns;
int pad1; char *method;
int pad2; int ihandle;
u_int64_t align;
u_int64_t len;
int pad3; char *id;
int64_t status;
int pad4; void *phys_hi;
int pad5; void *phys_lo;
} args = {
0,"call-method",
5,
3,
0,"SUNW,retain",
0, 0,
0,
0,
0, "msgbuf",
-1,
0, 0,
0, 0
};
if (memh == -1 && ((memh = get_memory_handle()) == -1)) {
prom_printf("prom_get_msgbuf: cannot get memh\r\n");
return -1LL;
}
args.ihandle = memh;
args.len = len;
args.align = align;
if (OF_test("test-method") == 0) {
if (OF_test_method(memh, "SUNW,retain") != 0) {
if (openfirmware(&args) == 0 && args.status == 0) {
return args.phys_lo;
} else prom_printf("prom_get_msgbuf: SUNW,retain failed\r\n");
} else prom_printf("prom_get_msgbuf: test-method failed\r\n");
} else prom_printf("prom_get_msgbuf: test failed\r\n");
/* Allocate random memory */
args.phys_lo = prom_claim_phys(0x2000, len);
prom_printf("prom_get_msgbuf: allocated new buf at %08x\r\n", args.phys_lo);
if( !args.phys_lo ) {
prom_printf("prom_get_msgbuf: cannot get allocate physmem\r\n");
return -1LL;
}
prom_printf("prom_get_msgbuf: claiming new buf at %08x\r\n", args.phys_lo);
return args.phys_lo; /* Kluge till we go 64-bit */
}
/*
* Low-level prom I/O routines.
*/
static int stdin = NULL;
static int stdout = NULL;
int
OF_stdin()
{
if( stdin == NULL ) {
int chosen;
chosen = OF_finddevice("/chosen");
OF_getprop(chosen, "stdout", &stdin, sizeof(stdin));
}
return stdin;
}
int
OF_stdout()
{
if( stdout == NULL ) {
int chosen;
chosen = OF_finddevice("/chosen");
OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
}
return stdout;
}
/*
* print debug info to prom.
* This is not safe, but then what do you expect?
*/
void
#ifdef __STDC__
prom_printf(const char *fmt, ...)
#else
prom_printf(fmt, va_alist)
char *fmt;
va_dcl
#endif
{
int len;
static char buf[256];
va_list ap;
va_start(ap, fmt);
len = vsprintf(buf, fmt, ap);
va_end(ap);
OF_write(OF_stdout(), buf, len);
}
static char *ksprintn __P((u_long, int, int *));
/*
* Scaled down version of sprintf(3) modified to deal w/va_args.
*/
int
vsprintf(buf, cfmt, ap)
char *buf;
const char *cfmt;
va_list ap;
{
register const char *fmt = cfmt;
register char *p, *bp;
register int ch, base;
u_long ul;
int lflag, tmp, width;
char padc;
for (bp = buf; ; ) {
padc = ' ';
width = 0;
while ((ch = *(u_char *)fmt++) != '%')
if ((*bp++ = ch) == '\0')
return ((bp - buf) - 1);
lflag = 0;
reswitch: switch (ch = *(u_char *)fmt++) {
case '0':
padc = '0';
goto reswitch;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
for (width = 0;; ++fmt) {
width = width * 10 + ch - '0';
ch = *fmt;
if (ch < '0' || ch > '9')
break;
}
goto reswitch;
case 'l':
lflag = 1;
goto reswitch;
/* case 'b': ... break; XXX */
case 'c':
*bp++ = va_arg(ap, int);
break;
/* case 'r': ... break; XXX */
case 's':
p = va_arg(ap, char *);
while ((*bp++ = *p++) != 0)
continue;
--bp;
break;
case 'd':
ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
if ((long)ul < 0) {
*bp++ = '-';
ul = -(long)ul;
}
base = 10;
goto number;
break;
case 'o':
ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
base = 8;
goto number;
break;
case 'u':
ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
base = 10;
goto number;
break;
case 'p':
*bp++ = '0';
*bp++ = 'x';
ul = (u_long)va_arg(ap, void *);
base = 16;
goto number;
case 'x':
ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
base = 16;
number: p = ksprintn(ul, base, &tmp);
if (width && (width -= tmp) > 0)
while (width--)
*bp++ = padc;
while ((ch = *p--) != 0)
*bp++ = ch;
break;
default:
*bp++ = '%';
if (lflag)
*bp++ = 'l';
/* FALLTHROUGH */
case '%':
*bp++ = ch;
}
}
}
/*
* Put a number (base <= 16) in a buffer in reverse order; return an
* optional length and a pointer to the NULL terminated (preceded?)
* buffer.
*/
static char *
ksprintn(ul, base, lenp)
register u_long ul;
register int base, *lenp;
{ /* A long in base 8, plus NULL. */
static char buf[sizeof(long) * NBBY / 3 + 2];
register char *p;
p = buf;
do {
*++p = "0123456789abcdef"[ul % base];
} while (ul /= base);
if (lenp)
*lenp = p - buf;
return (p);
}