2.9BSD/usr/net/sys/sys/machdep.c
/*
* SCCS id @(#)machdep.c 2.1 (Berkeley) 11/20/83
*/
#include "param.h"
#include <sys/systm.h>
#include <sys/acct.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/inode.h>
#include <sys/proc.h>
#include <sys/seg.h>
#include <sys/map.h>
#include <sys/reg.h>
#include <sys/buf.h>
#include <sys/tty.h>
#ifdef UCB_AUTOBOOT
#include <sys/reboot.h>
#endif
#include <sys/uba.h>
#include <sys/iopage.h>
extern memaddr bpaddr;
#ifndef NOKA5
segm seg5; /* filled in by initialization */
#endif
#ifdef UCB_CLIST
extern memaddr clststrt;
#else
extern struct cblock cfree[];
#endif UCB_CLIST
extern ubadr_t clstaddr;
#ifdef UCB_NET
extern memaddr mbbase;
extern int mbsize;
#endif
#ifdef UCB_AUTOBOOT
int bootflags, checkword; /* saved from r4, r2 by mch.s */
#endif
/*
* Icode is the octal bootstrap
* program executed in user mode
* to bring up the system.
*/
int icode[] =
{
#ifdef UCB_AUTOBOOT
0104413, /* sys exec; init; initp */
0000016,
0000010,
0104401, /* sys exit */
0000016, /* initp: init; bootopts; 0 */
0000030,
0000000,
0062457, /* init: </etc/init\0> */
0061564,
0064457,
0064556,
0000164,
RB_SINGLE, /* bootopts: RB_SINGLE */
0000000
#define ICODE_OPTS 12 /* location of bootopts in icode */
#else
0104413, /* sys exec; init; initp */
0000014,
0000010,
0104401, /* sys exit */
0000014, /* initp: init; 0 */
0000000,
0062457, /* init: </etc/init\0> */
0061564,
0064457,
0064556,
0000164,
#endif UCB_AUTOBOOT
};
int szicode = sizeof (icode);
size_t physmem; /* total amount of physical memory (for savecore) */
/*
* Machine dependent startup code
*/
startup()
{
register memaddr i, freebase;
extern end;
#ifndef NOKA5
saveseg5(seg5); /* must be done before clear() is called */
if (&remap_area > SEG5)
panic("&remap_area > 0120000");
#else
if (&end > SEG5)
panic("_end > 0120000");
#endif
/*
* zero and free all of core
*/
i = freebase = *ka6 + USIZE;
UISD[0] = ((stoc(1) - 1) << 8) | RW;
for (;;) {
UISA[0] = i;
if (fuibyte((caddr_t)0) < 0)
break;
maxmem++;
i++;
/*
* avoid testing locations on the IO page if possible,
* since some people have dz's at 0160000 (0760000).
* Note that more than 248K of memory is not currently
* supported without a Unibus map anyway.
* (3968 is btoc(248K); the macro doesn't do longs.)
*/
if (!ubmap && i >= 3968)
break;
}
clear(freebase, i - freebase);
mfree(coremap, i - freebase, freebase);
physmem = i;
#define B (size_t)(((long)nbuf * (bsize)) / ctob(1))
if ((bpaddr = malloc(coremap, B)) == 0)
panic("buffers");
maxmem -= B;
#undef B
#ifdef UCB_CLIST
#define C (nclist * sizeof(struct cblock))
if ((clststrt = malloc(coremap, btoc(C))) == 0)
panic("clists");
maxmem -= btoc(C);
clstaddr = ((ubadr_t) clststrt) << 6;
#undef C
#else
clstaddr = (ubadr_t) &cfree;
#endif UCB_CLIST
#if defined(PROFILE) && !defined(ENABLE34)
maxmem -= msprof();
#endif defined(PROFILE) && !defined(ENABLE34)
#ifdef UCB_NET
if ((mbbase = malloc(coremap, btoc(mbsize))) == 0)
panic("mbbase");
maxmem -= btoc(mbsize);
#endif
printf("mem = %D\n", ctob((long)maxmem));
if (MAXMEM < maxmem)
maxmem = MAXMEM;
mfree(swapmap, nswap, 1);
swplo--;
UISA[7] = ka6[1]; /* io segment */
UISD[7] = ((stoc(1) - 1) << 8) | RW;
#ifdef UCB_AUTOBOOT
if (checkword == ~bootflags)
icode[ICODE_OPTS] = bootflags;
#endif UCB_AUTOBOOT
}
#if defined(PROFILE) && !defined(ENABLE34)
/*
* Allocate memory for system profiling. Called
* once at boot time. Returns number of clicks
* used by profiling.
*
* The system profiler uses supervisor I space registers 2 and 3
* (virtual addresses 040000 through 0100000) to hold the profile.
*/
static int nproclicks;
memaddr proloc;
msprof()
{
nproclicks = btoc(8192*2);
proloc = malloc(coremap, nproclicks);
if (proloc == 0)
panic("msprof");
*SISA2 = proloc;
*SISA3 = proloc + btoc(8192);
*SISD2 = 077400|RW;
*SISD3 = 077400|RW;
*SISD0 = RW;
*SISD1 = RW;
esprof();
return (nproclicks);
}
/*
* Enable system profiling.
* Zero out the profile buffer and then turn the
* clock (KW11-P) on.
*/
esprof()
{
clear(proloc, nproclicks);
isprof();
printf("profiling on\n");
}
#endif defined(PROFILE) && !defined(ENABLE34)
#ifdef UNIBUS_MAP
/*
* Re-initialize the Unibus map registers to statically map
* the clists and buffers. Free the remaining registers for
* physical I/O.
*/
void
ubinit()
{
long paddr;
register i, ub_nreg;
extern struct map ub_map[];
#ifdef UCB_NET
extern int ub_inited;
#endif
if (!ubmap)
return;
#ifdef UCB_NET
ub_inited++;
#endif
/*
* Clists start at UNIBUS virtual address 0. The size of
* the clist segment can be no larger than UBPAGE bytes.
* Clstaddt was the physical address of clists.
*/
if (nclist * sizeof (struct cblock) > ctob(stoc(1)))
panic("clist area too large");
setubregno(0, clstaddr);
clstaddr = (ubadr_t) 0;
/*
* Buffers start at UNIBUS virtual address BUF_UBADDR.
*/
paddr = ((long) bpaddr) << 6;
ub_nreg = nubreg(nbuf, bsize);
for (i = BUF_UBADDR / UBPAGE; i < ub_nreg + (BUF_UBADDR/UBPAGE); i++) {
setubregno(i, paddr);
paddr += (long) UBPAGE;
}
mfree(ub_map, 31 - ub_nreg - 1, 1 + ub_nreg);
}
#endif UNIBUS_MAP
/*
* set up a physical address
* into users virtual address space.
*/
sysphys()
{
int d;
register i, s;
register struct a {
int segno;
int size;
int phys;
} *uap;
if (!suser())
return;
uap = (struct a *)u.u_ap;
i = uap->segno;
if (i < 0 || i >= 8)
goto bad;
s = uap->size;
if (s < 0 || s > 128)
goto bad;
#ifdef NONSEPARATE
d = u.u_uisd[i];
#else
d = u.u_uisd[i + 8];
#endif NONSEPARATE
if (d != 0 && (d & ABS) == 0)
goto bad;
#ifdef NONSEPARATE
u.u_uisd[i] = 0;
u.u_uisa[i] = 0;
#else
u.u_uisd[i + 8] = 0;
u.u_uisa[i + 8] = 0;
if (!u.u_sep) {
u.u_uisd[i] = 0;
u.u_uisa[i] = 0;
}
#endif NONSEPARATE
if (s) {
#ifdef NONSEPARATE
u.u_uisd[i] = ((s - 1) << 8) | RW | ABS;
u.u_uisa[i] = uap->phys;
#else
u.u_uisd[i + 8] = ((s - 1) << 8) | RW | ABS;
u.u_uisa[i + 8] = uap->phys;
if (!u.u_sep) {
u.u_uisa[i] = u.u_uisa[i + 8];
u.u_uisd[i] = u.u_uisd[i + 8];
}
#endif NONSEPARATE
}
sureg();
return;
bad:
u.u_error = EINVAL;
}
/*
* Determine whether clock is attached. If so, start it.
*/
clkstart()
{
lks = LKS;
if (fioword((caddr_t)lks) == -1) {
lks = KW11P_CSR;
if (fioword((caddr_t)lks) == -1) {
printf("no clock??\n");
lks = 0;
}
}
if (lks)
*lks = 0115;
}
#ifndef ENABLE34
/*
* Fetch a word from an address on the I/O page,
* returning -1 if address does not exist.
*/
fioword(addr)
{
register val, saveUI7, saveUD7;
saveUI7 = UISA[7];
saveUD7 = UISD[7];
UISA[7] = ka6[1]; /* io segment */
UISD[7] = ((stoc(1) - 1) << 8) | RW;
val = fuiword(addr);
UISA[7] = saveUI7;
UISD[7] = saveUD7;
return(val);
}
#endif
/*
* Let a process handle a signal by simulating an interrupt
*/
sendsig(p)
caddr_t p;
{
register unsigned n;
n = u.u_ar0[R6] - 4;
if (n >= -ctob(u.u_ssize) || grow(n)) {
suword((caddr_t)n + 2, u.u_ar0[RPS]);
suword((caddr_t)n, u.u_ar0[R7]);
u.u_ar0[R6] = n;
u.u_ar0[RPS] &= ~PS_T;
u.u_ar0[R7] = (int)p;
} else {
/*
* Process has trashed its stack.
* Blow him away.
*/
u.u_signal[SIGSEGV] = SIG_DFL;
#ifdef MENLO_JCL
u.u_procp->p_cursig = SIGSEGV;
psig();
#else
psignal(u.u_procp, SIGSEGV);
#endif
}
}
#ifdef MENLO_JCL
/*
* Simulate a return from interrupt on return from the syscall.
* after popping n words of the users stack.
*/
dorti(n)
{
register int opc, ops;
u.u_ar0[R6] += n * sizeof(int);
if (((opc = fuword((caddr_t)u.u_ar0[R6])) == -1)
|| ((ops = fuword((caddr_t)(u.u_ar0[R6] + sizeof(int)))) == -1))
psignal(u.u_procp, SIGSEGV);
else {
u.u_ar0[R6] += 2 * sizeof(int);
u.u_ar0[PC] = opc;
ops |= PS_CURMOD | PS_PRVMOD; /* assure user space */
ops &= ~PS_USERCLR; /* priority 0 */
u.u_ar0[RPS] = ops;
}
}
#endif MENLO_JCL
#ifdef UNIBUS_MAP
int ub_wantmr;
#define UMAPSIZ 10
struct mapent _ubmap[UMAPSIZ];
struct map ub_map[1] = {
&_ubmap[0], &_ubmap[UMAPSIZ], "ub_map"
};
#ifdef UCB_METER
struct ubmeter {
long ub_requests; /* total # of calls to mapalloc */
long ub_remaps; /* total # of buffer remappings */
long ub_failures; /* total # of allocation failures */
long ub_pages; /* total # of pages allocated */
} ub_meter;
#endif
/*
* Routine to allocate the UNIBUS map
* and initialize for a UNIBUS device.
* For buffers already mapped by the UNIBUS map,
* perform the physical-to-UNIBUS-virtual address translation.
*/
mapalloc(bp)
register struct buf *bp;
{
long paddr;
ubadr_t ubaddr;
int s, ub_nregs;
register ub_first;
register struct ubmap *ubp;
extern memaddr bpaddr;
if (!ubmap)
return;
#if defined(UNIBUS_MAP) && defined(UCB_METER)
ub_meter.ub_requests++;
#endif
paddr = ((long) ((unsigned) bp->b_xmem)) << 16
| ((long) ((unsigned) bp->b_un.b_addr));
if ((bp->b_flags & B_PHYS) == 0) {
/*
* Transfer in the buffer cache.
* Change the buffer's physical address
* into a UNIBUS address for the driver.
*/
#if defined(UNIBUS_MAP) && defined(UCB_METER)
ub_meter.ub_remaps++;
#endif
ubaddr = paddr - (((ubadr_t) bpaddr) << 6) + BUF_UBADDR;
bp->b_un.b_addr = loint(ubaddr);
bp->b_xmem = hiint(ubaddr);
bp->b_flags |= B_UBAREMAP;
} else {
/*
* Physical I/O.
* Allocate a section of the UNIBUS map.
*/
ub_nregs = (int) btoub(bp->b_bcount);
#if defined(UNIBUS_MAP) && defined(UCB_METER)
ub_meter.ub_pages += ub_nregs;
#endif
s = spl6();
while ((ub_first = malloc(ub_map, ub_nregs)) == NULL) {
ub_wantmr = 1;
#if defined(UNIBUS_MAP) && defined(UCB_METER)
ub_meter.ub_failures++;
#endif
sleep(ub_map, PSWP + 1);
}
splx(s);
ubp = &UBMAP[ub_first];
bp->b_xmem = ub_first >> 3;
bp->b_un.b_addr = (ub_first & 07) << 13;
bp->b_flags |= B_MAP;
while (ub_nregs--) {
ubp->ub_lo = loint(paddr);
ubp->ub_hi = hiint(paddr);
ubp++;
paddr += (ubadr_t) UBPAGE;
}
}
}
mapfree(bp)
register struct buf *bp;
{
register s;
extern memaddr bpaddr;
long paddr;
ubadr_t ubaddr;
if (bp->b_flags & B_MAP) {
/*
* Free the UNIBUS map registers
* allocated to this buffer.
*/
s = spl6();
mfree(ub_map, (int) btoub(bp->b_bcount),
(bp->b_xmem << 3) | ((bp->b_un.b_addr >> 13) & 07));
splx(s);
bp->b_flags &= ~B_MAP;
if (ub_wantmr)
wakeup((caddr_t) ub_map);
ub_wantmr = 0;
} else if (bp->b_flags & B_UBAREMAP) {
/*
* Translate the UNIBUS virtual address of this buffer
* back to a physical memory address.
*/
ubaddr = ((long) ((unsigned) bp->b_xmem)) << 16
| ((long) ((unsigned) bp->b_un.b_addr));
paddr = ubaddr - (long) BUF_UBADDR
+ (((long) bpaddr) << 6);
bp->b_un.b_addr = loint(paddr);
bp->b_xmem = hiint(paddr);
bp->b_flags &= ~B_UBAREMAP;
}
}
#endif UNIBUS_MAP
#ifndef NOKA5
/*
* Save the current kernel mapping and set it to the normal map.
* Called at interrupt time to access proc, text or file structures
* or the user structure.
* Called only if *KDSA5 != seg5.se_addr from the macro savemap.
* If NOKA5 is defined, the macro does the whole job.
*/
Savemap(map)
register mapinfo map;
{
map[0].se_addr = *KDSA5;
map[0].se_desc = *KDSD5;
if (kdsa6) {
map[1].se_addr = *KDSA6;
map[1].se_desc = *KDSD6;
*KDSD6 = KD6;
*KDSA6 = kdsa6;
} else
map[1].se_desc = NOMAP;
restorseg5(seg5);
}
/*
* Restore the mapping information saved above.
* Called only if map[0].se_desc != NOMAP (from macro restormap).
*/
Restormap(map)
register mapinfo map;
{
*KDSA5 = map[0].se_addr;
*KDSD5 = map[0].se_desc;
if (map[1].se_desc != NOMAP) {
*KDSD6 = map[1].se_desc;
*KDSA6 = map[1].se_addr;
}
}
#endif NOKA5
#if !defined(NOKA5) && defined(DIAGNOSTIC)
struct buf *hasmap;
#endif
/*
* Map in an out-of-address space buffer.
* If this is done from interrupt level,
* the previous map must be saved before mapin,
* and restored after mapout; e.g.
* segm save;
* saveseg5(save);
* mapin(bp);
* ...
* mapout(bp);
* restorseg5(save);
*/
#ifdef UCB_NET
segm Bmapsave;
# ifdef NOKA5
ERROR! /* NOKA5 must not be defined with the net for now. */
# endif
#endif
caddr_t
mapin(bp)
register struct buf *bp;
{
register caddr_t paddr;
register caddr_t offset;
#ifdef UCB_NET
saveseg5(Bmapsave);
#endif
#if !defined(NOKA5) && defined(DIAGNOSTIC)
if (hasmap != (struct buf *) 0) {
printf("mapping %o over %o\n", bp, hasmap);
panic("mapin");
}
hasmap = bp;
#endif
offset = bp->b_un.b_addr & 077;
paddr = (bp->b_un.b_addr >> 6) & 01777;
paddr |= bp->b_xmem << 10;
mapseg5(paddr, (BSIZE << 2) | RW);
return(SEG5 + offset);
}
#ifndef NOKA5
void
mapout(bp)
register struct buf *bp;
{
#ifdef DIAGNOSTIC
if (bp != hasmap) {
printf("unmapping %o, not %o\n", bp, hasmap);
panic("mapout");
}
hasmap = (struct buf *) NULL;
#endif
#ifndef UCB_NET
normalseg5();
#else
restorseg5(Bmapsave);
#endif
}
#endif NOKA5
#ifdef UCB_AUTOBOOT
void
boot(dev, howto)
dev_t dev;
int howto;
{
if ((howto & RB_NOSYNC) == 0 && bfreelist.b_forw) {
printf("syncing disks ... ");
update();
delay(5);
printf("done\n\n");
}
(void) _spl7();
if (howto & RB_HALT) {
printf("halting\n");
halt();
/*NOTREACHED*/
} else {
if (howto & RB_DUMP) {
/*
* save the registers in low core.
*/
saveregs();
dumpsys();
}
doboot(dev, howto);
/*NOTREACHED*/
}
}
/*
* wait for time "del", approximately in seconds.
* Used to avoid rescheduling from sleep().
*/
delay(del)
int del;
{
register i, j;
while (del--) {
for (i=10; i>0; --i)
for (j=32000; j>0; --j)
;
}
}
/*
* Dumpsys takes a dump of memory by calling (*dump)(), which must
* correspond to dumpdev. *(dump)() should dump from dumplo blocks
* to the end of memory or to the end of the logical device.
*/
dumpsys()
{
extern int (*dump)();
if (dumpdev != NODEV) {
printf("\ndumping to dev %o, offset %D\n", dumpdev, dumplo);
printf("dump ");
switch ((*dump)(dumpdev)) {
case EFAULT:
printf("device not ready\n");
break;
case EINVAL:
printf("arguments invalid\n");
break;
case EIO:
printf("I/O error\n");
break;
default:
printf("error(?)\n");
break;
case 0:
printf("succeeded\n");
return (1);
}
}
return (0); /* failure */
}
#endif UCB_AUTOBOOT
/*
* lock user into core as much
* as possible. swapping may still
* occur if core grows.
*/
syslock()
{
register struct proc *p;
struct a {
int flag;
};
if (suser()) {
p = u.u_procp;
p->p_flag &= ~SULOCK;
if (((struct a *)u.u_ap)->flag)
p->p_flag |= SULOCK;
}
}