You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
627 lines
11 KiB
627 lines
11 KiB
/* $Id: kern_misc.c,v 1.1.1.1 2006/09/14 01:59:08 root Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 2000 Opsycon AB (www.opsycon.se)
|
|
* Copyright (c) 2000 Rtmx, Inc (www.rtmx.com)
|
|
*
|
|
* 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 for Rtmx, Inc by
|
|
* Opsycon Open System Consulting AB, Sweden.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* 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 THE AUTHOR 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.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Miscelaneous code requiered by the kernel code.
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/syslog.h>
|
|
#include <sys/queue.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/socketvar.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/sysctl.h>
|
|
#include <sys/buf.h>
|
|
|
|
#include <net/if.h>
|
|
#include <net/if_types.h>
|
|
#include <net/netisr.h>
|
|
|
|
#include <machine/stdarg.h>
|
|
#include <machine/intr.h>
|
|
|
|
#include <pmon.h>
|
|
#include <linux/io.h>
|
|
#undef MYPRINT
|
|
|
|
#define PORT3fd (mips_io_port_base+0x3fd)
|
|
#define PORT3f8 (mips_io_port_base+0x3f8)
|
|
|
|
int hz = 100;
|
|
int securelevel = -1;
|
|
int cmask = 0777;
|
|
vm_size_t page_mask = (NBPG-1);
|
|
struct timeval boottime;
|
|
static u_char *kmem;
|
|
vm_offset_t kmem_offs;
|
|
|
|
static void ifpoll __P((void));
|
|
#ifdef MYPRINT
|
|
void printstr(char *);
|
|
void printnum(unsigned long long);
|
|
#endif
|
|
int
|
|
copyin (src, dest, cnt)
|
|
const void *src;
|
|
void *dest;
|
|
size_t cnt;
|
|
{
|
|
memcpy (dest, src, cnt);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
copyout(src, dest, size)
|
|
const void *src;
|
|
void *dest;
|
|
size_t size;
|
|
{
|
|
memcpy(dest, src, size);
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
uiomove(cp, n, uio)
|
|
caddr_t cp;
|
|
int n;
|
|
struct uio *uio;
|
|
{
|
|
struct iovec *iov;
|
|
u_int cnt;
|
|
|
|
while (n > 0 && uio->uio_resid) {
|
|
iov = uio->uio_iov;
|
|
cnt = iov->iov_len;
|
|
if (cnt == 0) {
|
|
uio->uio_iov++;
|
|
uio->uio_iovcnt--;
|
|
continue;
|
|
}
|
|
if (cnt > n) {
|
|
cnt = n;
|
|
}
|
|
if (uio->uio_rw == UIO_READ) {
|
|
memcpy (iov->iov_base, cp, cnt);
|
|
}
|
|
else {
|
|
memcpy (cp, iov->iov_base, cnt);
|
|
}
|
|
iov->iov_base += cnt;
|
|
iov->iov_len -= cnt;
|
|
uio->uio_resid -= cnt;
|
|
uio->uio_offset += cnt;
|
|
cp += cnt;
|
|
n -= cnt;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
panic(msg)
|
|
const char *msg;
|
|
{
|
|
printf("PMON PANIC '%s'\n", msg);
|
|
md_do_stacktrace(NULL, -1, -1, 0);
|
|
tgt_reboot();
|
|
while(1);
|
|
}
|
|
|
|
extern int sysloglevel;
|
|
|
|
static const char *const priname[] = {
|
|
"\nEMERG",
|
|
"\nALERT",
|
|
"\nCRIT",
|
|
"\nERROR",
|
|
"\nWARNING",
|
|
"\nNOTICE",
|
|
"INFO",
|
|
"DEBUG",
|
|
};
|
|
|
|
|
|
void
|
|
log (int kind, const char *fmt, ...)
|
|
{
|
|
va_list arg;
|
|
int pri = kind & LOG_PRIMASK;
|
|
|
|
if (pri > sysloglevel)
|
|
return;
|
|
|
|
printf ("%s: ", priname[pri]);
|
|
va_start(arg, fmt);
|
|
vprintf (fmt, arg);
|
|
va_end(arg);
|
|
}
|
|
|
|
void
|
|
tablefull (name)
|
|
const char *name;
|
|
{
|
|
log (LOG_ERR, "%s table is full\n", name);
|
|
}
|
|
|
|
int
|
|
min (a, b)
|
|
{
|
|
return a < b ? a : b;
|
|
}
|
|
|
|
int
|
|
imin (a, b)
|
|
{
|
|
return a < b ? a : b;
|
|
}
|
|
|
|
int
|
|
max (a, b)
|
|
{
|
|
return a > b ? a : b;
|
|
}
|
|
|
|
|
|
int
|
|
imax (a, b)
|
|
{
|
|
return a > b ? a : b;
|
|
}
|
|
|
|
u_int32_t
|
|
arc4random()
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* General routine to allocate a hash table.
|
|
*/
|
|
void *
|
|
hashinit(elements, type, flags, hashmask)
|
|
int elements, type, flags;
|
|
u_long *hashmask;
|
|
{
|
|
long hashsize;
|
|
LIST_HEAD(generic, generic) *hashtbl;
|
|
int i;
|
|
|
|
if (elements <= 0)
|
|
panic("hashinit: bad cnt");
|
|
for (hashsize = 1; hashsize <= elements; hashsize <<= 1)
|
|
continue;
|
|
hashsize >>= 1;
|
|
hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, flags);
|
|
for (i = 0; i < hashsize; i++)
|
|
LIST_INIT(&hashtbl[i]);
|
|
*hashmask = hashsize - 1;
|
|
return (hashtbl);
|
|
}
|
|
|
|
/*
|
|
* Validate parameters and get old / set new parameters
|
|
* for a structure oriented sysctl function.
|
|
*/
|
|
int
|
|
sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
|
|
void *oldp;
|
|
size_t *oldlenp;
|
|
void *newp;
|
|
size_t newlen;
|
|
void *sp;
|
|
int len;
|
|
{
|
|
int error = 0;
|
|
|
|
if (oldp && *oldlenp < len)
|
|
return (ENOMEM);
|
|
if (newp && newlen > len)
|
|
return (EINVAL);
|
|
if (oldp) {
|
|
*oldlenp = len;
|
|
error = copyout(sp, oldp, len);
|
|
}
|
|
if (error == 0 && newp)
|
|
error = copyin(newp, sp, len);
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* Validate parameters and get old / set new parameters
|
|
* for an integer-valued sysctl function.
|
|
*/
|
|
int
|
|
sysctl_int(oldp, oldlenp, newp, newlen, valp)
|
|
void *oldp;
|
|
size_t *oldlenp;
|
|
void *newp;
|
|
size_t newlen;
|
|
int *valp;
|
|
{
|
|
int error = 0;
|
|
|
|
if (oldp && *oldlenp < sizeof(int))
|
|
return (ENOMEM);
|
|
if (newp && newlen != sizeof(int))
|
|
return (EINVAL);
|
|
*oldlenp = sizeof(int);
|
|
if (oldp)
|
|
error = copyout(valp, oldp, sizeof(int));
|
|
if (error == 0 && newp)
|
|
error = copyin(newp, valp, sizeof(int));
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* As above, but read-only.
|
|
*/
|
|
int
|
|
sysctl_rdint(oldp, oldlenp, newp, val)
|
|
void *oldp;
|
|
size_t *oldlenp;
|
|
void *newp;
|
|
int val;
|
|
{
|
|
int error = 0;
|
|
|
|
if (oldp && *oldlenp < sizeof(int))
|
|
return (ENOMEM);
|
|
if (newp)
|
|
return (EPERM);
|
|
*oldlenp = sizeof(int);
|
|
if (oldp)
|
|
error = copyout((caddr_t)&val, oldp, sizeof(int));
|
|
return (error);
|
|
}
|
|
|
|
void vminit __P((void));
|
|
void
|
|
vminit ()
|
|
{
|
|
extern unsigned long long memorysize;
|
|
|
|
if (!kmem) {
|
|
/* grab a chunk at the top of memory */
|
|
if (memorysize < VM_KMEM_SIZE * 2) {
|
|
panic ("not enough memory for network");
|
|
}
|
|
memorysize = (memorysize - VM_KMEM_SIZE) & ~PGOFSET;
|
|
#ifdef __mips__
|
|
if ((u_int32_t)&kmem < (u_int32_t)UNCACHED_MEMORY_ADDR) {
|
|
/* if linked for data in kseg0, keep kmem there too */
|
|
kmem = (u_char *) PHYS_TO_CACHED (memorysize);
|
|
}
|
|
else {
|
|
kmem = (u_char *) PHYS_TO_UNCACHED (memorysize);
|
|
}
|
|
#else
|
|
kmem = (u_char *)memorysize;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
vm_offset_t
|
|
kmem_malloc (map, size, canwait)
|
|
vm_map_t map;
|
|
vm_size_t size;
|
|
{
|
|
vm_offset_t p;
|
|
|
|
if(!kmem) { /* In case we call this before vminit() */
|
|
vminit();
|
|
}
|
|
|
|
size = (size + PGOFSET) & ~PGOFSET;
|
|
//reserved 16MB for upper pmon code (@0x8f00 0000 ~ 0x8fff ffff)
|
|
if (kmem_offs + size > VM_KMEM_SIZE - 0x01000000) {
|
|
log (LOG_DEBUG, "kmem_malloc: request for %d bytes fails\n", size);
|
|
return 0;
|
|
}
|
|
p = (vm_offset_t) &kmem[kmem_offs];
|
|
kmem_offs += size;
|
|
return p;
|
|
}
|
|
|
|
|
|
vm_offset_t
|
|
kmem_alloc (map, size)
|
|
vm_map_t map;
|
|
vm_size_t size;
|
|
{
|
|
return kmem_malloc (map, size, 0);
|
|
}
|
|
|
|
|
|
vm_map_t
|
|
kmem_suballoc (map, base, lim, size, canwait)
|
|
vm_map_t map;
|
|
vm_offset_t *base, *lim;
|
|
vm_size_t size;
|
|
{
|
|
if (size > VM_KMEM_SIZE)
|
|
panic ("kmem_suballoc");
|
|
*base = (vm_offset_t) kmem;
|
|
*lim = (vm_offset_t) kmem + VM_KMEM_SIZE;
|
|
return map;
|
|
}
|
|
|
|
void
|
|
kmem_free (map, addr, size)
|
|
vm_map_t map;
|
|
vm_offset_t addr;
|
|
vm_size_t size;
|
|
{
|
|
panic ("kmem_free");
|
|
}
|
|
|
|
|
|
/*XXX*/
|
|
/*
|
|
* Shutdown hooks are currently nops. Later we should add something
|
|
* that shutdown activites like ethernet etc (eg does the hook calls)
|
|
* so interfearence with loaded and run programs will not occur.
|
|
*/
|
|
void *
|
|
shutdownhook_establish(callee, sc)
|
|
void (*callee) __P((void *));
|
|
void *sc;
|
|
{
|
|
return((void *)1); /* Return non-zero for now */
|
|
}
|
|
|
|
|
|
static void
|
|
ifpoll()
|
|
{
|
|
struct ifnet *ifp;
|
|
static int here = 0;
|
|
|
|
if(here) { /* Don't recurse */
|
|
splhigh();
|
|
printf("ifpoll recursed!\n");
|
|
md_do_stacktrace(0, -1, 0, 0);
|
|
while(1);
|
|
}
|
|
|
|
here = 1;
|
|
for(ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
|
|
if (ifp->if_ioctl) {
|
|
(*ifp->if_ioctl)(ifp, SIOCPOLL, 0);
|
|
}
|
|
}
|
|
here = 0;
|
|
}
|
|
|
|
/*
|
|
* XXX The entire SPL code is wrong in the sense that the 'levels'
|
|
* XXX are not levels but events that should be masked. Note that
|
|
* XXX some 'levels' masks more than one event anyhow. This should
|
|
* XXX really be rewritten in the future and especially if we start
|
|
* XXX using real interrupts.
|
|
*/
|
|
|
|
volatile int spl; /* Current SPL mask */
|
|
|
|
int
|
|
splhigh()
|
|
{
|
|
int old = spl;
|
|
|
|
spl = 7;
|
|
return(old);
|
|
}
|
|
|
|
int
|
|
splclock()
|
|
{
|
|
int old = spl;
|
|
|
|
spl = 7;
|
|
return(old);
|
|
}
|
|
|
|
int
|
|
spltty()
|
|
{
|
|
int old = spl;
|
|
|
|
if(old < 5) {
|
|
spl = 5;
|
|
}
|
|
return(old);
|
|
}
|
|
|
|
int
|
|
splbio()
|
|
{
|
|
int old = spl;
|
|
|
|
if(old < 4) {
|
|
spl = 4;
|
|
}
|
|
return(old);
|
|
}
|
|
|
|
int
|
|
splimp()
|
|
{
|
|
int old = spl;
|
|
|
|
if(old < 7) {
|
|
spl = 7;
|
|
}
|
|
return(old);
|
|
}
|
|
|
|
int
|
|
splnet()
|
|
{
|
|
int old = spl;
|
|
|
|
if(old < 3) {
|
|
spl = 3;
|
|
}
|
|
return(old);
|
|
}
|
|
|
|
int
|
|
splsoftclock()
|
|
{
|
|
int old = spl;
|
|
|
|
if(old < 1) {
|
|
spl = 1;
|
|
}
|
|
return(old);
|
|
}
|
|
|
|
int
|
|
splsoftnet()
|
|
{
|
|
int old = spl;
|
|
|
|
if(old < 1) {
|
|
spl = 1;
|
|
}
|
|
return(old);
|
|
}
|
|
|
|
int
|
|
spl0()
|
|
{
|
|
int s = spl;
|
|
|
|
splx(0);
|
|
return(s);
|
|
}
|
|
#ifdef MYPRINT
|
|
void printstr(char *s)
|
|
{
|
|
unsigned long port = PORT3f8;
|
|
while (*s) {
|
|
while (((*(volatile unsigned char*)PORT3fd) & 0x20)==0);
|
|
*(unsigned char*)port = *s;
|
|
s++;
|
|
}
|
|
}
|
|
void printnum(unsigned long long n)
|
|
{
|
|
int i,j;
|
|
unsigned char a[40];
|
|
unsigned long port = PORT3f8;
|
|
i = 0;
|
|
do {
|
|
a[i] = n % 16;
|
|
n = n / 16;
|
|
i++;
|
|
}while(n);
|
|
|
|
for (j=i-1;j>=0;j--) {
|
|
if (a[j]>=10) {
|
|
while (((*(volatile unsigned char*)PORT3fd) & 0x20)==0);
|
|
*(unsigned char*)port = 'a' + a[j] - 10;
|
|
}else{
|
|
while (((*(volatile unsigned char*)PORT3fd) & 0x20)==0);
|
|
*(unsigned char*)port = '0' + a[j];
|
|
}
|
|
}
|
|
printstr("\r\n");
|
|
}
|
|
#endif
|
|
|
|
void
|
|
splx(newspl)
|
|
{
|
|
extern void softnet __P((void));
|
|
/* If new means lowering then check pending jobs */
|
|
#ifdef MYPRINT
|
|
printstr("in splx");
|
|
printnum(newspl);
|
|
#endif
|
|
if (newspl < spl) {
|
|
if (newspl < 7) {
|
|
spl = 7;
|
|
tgt_clkpoll ();
|
|
#ifdef MYPRINT
|
|
printstr("clkpoll");
|
|
#endif
|
|
}
|
|
if (newspl < 3) { /* NET + IMP */
|
|
spl = 3;
|
|
ifpoll ();
|
|
#ifdef MYPRINT
|
|
printstr("ifpoll");
|
|
#endif
|
|
}
|
|
if (newspl < 1 && netisr != 0) {
|
|
spl = 1;
|
|
softnet ();
|
|
#ifdef MYPRINT
|
|
printstr("softnet");
|
|
#endif
|
|
}
|
|
}
|
|
spl = newspl;
|
|
if (spl == 0) {
|
|
tgt_poll();
|
|
#ifdef MYPRINT
|
|
printstr("tgtpoll");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void
|
|
setsoftnet ()
|
|
{
|
|
/* nothing to do, checked by spl0() */
|
|
}
|
|
|
|
void
|
|
setsoftclock ()
|
|
{
|
|
/* simulated soft clock */
|
|
schednetisr(NETISR_SCLK);
|
|
}
|
|
|
|
void
|
|
minphys(bp)
|
|
struct buf *bp;
|
|
{
|
|
if (bp->b_bcount > MAXPHYS)
|
|
bp->b_bcount = MAXPHYS;
|
|
}
|
|
|