#! /bin/sh
: This is a shar archive.  Extract with sh, not csh.
echo x - kernel/m68k/enetle.c
cat > kernel/m68k/enetle.c << '27333!Funky!Stuff!'
/*
 * Distributed V Kernel 
 *
 * Kernel Ethernet driver for AMD 7990 LANCE controller chip.
 *
 * David B. Johnson, Dept. of Computer Science, Rice University.
 * Modified at Stanford.
 */

#include "Venviron.h"
#include "Vethernet.h"
#include "Vikc.h"
#include "Vquerykernel.h"
#include "interrupt.h"
#include "dm.h"
#include "ikc.h"
#include "process.h"
#include "sun3mem.h"
#include "enetle.h"

/*
 *  The driver coordinates its uses of the LANCE's Register Address Port
 *  (RAP) so that CSR0 is normally always available without changing the
 *  RAP.  The only use made of the other CSRs is during initialization,
 *  and the RAP is reset to select CSR0 at the end of the initialization.
 *
 *  If any other accesses to the CSR1, CSR2, or CSR3 become necessary,
 *  the RAP should be changed to select that register, the access can
 *  then be made, and the RAP should then be changed back to select CSR0.
 *  Be careful that the driver is not reentered during this sequence
 *  since somebody else could change the RAP out from under you.
 */

typedef Process_id (*PFPID)();

typedef struct { char *ptr; unsigned long bytes; } BufferList;

/* Imports */
extern unsigned char *LastPeripheral;
extern MachineConfigurationReply MachineConfig;
extern SystemCode AllocateMemory();

/* Variables imported from enet.c */
extern DeviceInstance	*EthernetInstance;
extern ProcessId	EnetWriter;	/* Pid of writer; NULL if free */
extern Enet10Address	MulticastDefault;
extern char		UserPacketBuffer[];
extern int		UserPacketLength;
extern SyncQueue	IkpOutq;

/* Exports */
extern SystemCode EnetPowerup();
extern NetworkWrite();
extern SystemCode EnetModify();
extern SystemCode EnetQuery();
extern NetCheck();

int		NetAlarm = 0;		/* Not used in this driver */

/* Used internally */
SystemCode EnetReadPacket();

Enet10Address	EnetHostNumber;		/* physical ethernet address */
int		EnetReceiveMask = ENET_DEFAULT_MASK;
short		EnetCollisions = 0;
short		EnetOverflows = 0;
short		EnetCRCErrors = 0;
short		EnetSyncErrors = 0;
short		EnetTimeOuts = 0;
int		EnetValidPackets = 0;
int		EnetPromiscuous = 0;	/* Are we in promiscuous mode */

/*
 *  Define names to access the LANCE's Register Data Port and
 *  Register Address Port.
 */
#ifdef	notdef
#define	rdp	(*(unsigned short *)(V_AMD_ETHERNET+0))
#define	rap	(*(unsigned short *)(V_AMD_ETHERNET+2))
#else	notdef
#define	rdp	(*(unsigned short *)(0xfe10000+0))
#define	rap	(*(unsigned short *)(0xfe10000+2))
#endif	notdef

#define RECEIVE_BUFFERS		32
#define	RECEIVE_BUFFERS_POWER	5

#define TRANSMIT_BUFFERS	1
#define	TRANSMIT_BUFFERS_POWER	0

#define	LE_INT_LEVEL		INT3

/*
 *  The control block segment for the LANCE chip.  This segment
 *  actually lives in a 128k block allocated by the kernel for
 *  Ethernet buffer/data space.
 */
struct EnetDataSegment
{
    struct InitializationBlock init;
    struct ReceiveMessageDescriptor rmd[RECEIVE_BUFFERS];
    struct TransmitMessageDescriptor tmd;
};
#define cbsp	((struct EnetDataSegment *)ENET_DATA_SEG)

char *tbuf;		/* start address of transmit buffer */
char *rbuf;		/* start address of receive buffers */

int rbufnum;		/* number of current rbuf */

/*
 *  Macro expansion to interrupt-invoked C call to Ethernetinterrupt.
 */
Call_inthandler(EnetInterrupt)

/*
 *  Powerup and initialize the Ethernet Interface Board.
 */
SystemCode
EnetPowerup()
{
    register int i;
    register char *p;
    register int (**intvec)() = (int(**)())(VECTOR_BASE + LE_INT_LEVEL);
    extern int Asm_EnetInterrupt();

    /*
     *  Indicate we have a Sun ethernet interface.
     */
    *LastPeripheral++ = PRF_ENET_LANCE;

    /*
     *  Initialize the kernel packet output queue.
     */
    IkpOutq.tail = (Process *)&(IkpOutq.head);
    IkpOutq.type = IKP_OUT_QUEUE;

    EnetReceiveMask = ENET_SELF + ENET_BROADCAST;

    /*
     *  Allocate receive and transmit buffers.
     */
    i = sizeof(struct EnetDataSegment) +
	(RECEIVE_BUFFERS + TRANSMIT_BUFFERS) * LE_MAX_PACKET;
    if (AllocateMemory(ENET_DATA_SEG, i) != OK)
	Kabort("Couldn't allocate ethernet data buffer space !");
    tbuf = ((char *)ENET_DATA_SEG) + sizeof(struct EnetDataSegment);
    rbuf = tbuf + LE_MAX_PACKET;

    printx("Allocating %d ethernet receive buffers.\n", RECEIVE_BUFFERS);

    /*
     * Get the SMI Ethernet address from the ID PROM.
     */
    p = (char *) &EnetHostNumber;
    for (i = IDP_ENET_ADDRESS;
	i < IDP_ENET_ADDRESS + sizeof(EnetHostNumber); i++)
	*p++ = Fc3ReadBit8(i);

    /*
     *  Initialize the interrupt vector.
     */
    *intvec = Asm_EnetInterrupt;

    EnetReset(ENET_DEFAULT_MASK);

    return (OK);
 }

EnetReset(receiveMask)
int receiveMask;
{
    register struct InitializationBlock *init = &cbsp->init;
    register int i;
    register unsigned long bufp;

    EnetReceiveMask = receiveMask;
    EnetPromiscuous = 0;

    /*
     *  Reset the chip.
     */
    rap = LE_RAP_CSR0;
    rdp = LE_CSR0_STOP;

    rbufnum = 0;

    /*
     *  Initialize the Initialization Block.
     */
    init->mode = 0;	/* no special modes */
    init->padr[0] = (unsigned char)(EnetHostNumber.addrhigh & 0xff);
    init->padr[1] = (unsigned char)(EnetHostNumber.addrhigh >> 8);
    init->padr[2] = (unsigned char)(EnetHostNumber.addrmid & 0xff);
    init->padr[3] = (unsigned char)(EnetHostNumber.addrmid >> 8);
    init->padr[4] = (unsigned char)(EnetHostNumber.addrlow & 0xff);
    init->padr[5] = (unsigned char)(EnetHostNumber.addrlow >> 8);
    for (i = 0; i < sizeof(init->ladrf); i++)
	init->ladrf[i] = 0xff;	/* receive all multicast packets ??? */
    bufp = (unsigned long)(cbsp->rmd);
    init->rdrp.low = (unsigned short)(bufp & 0xffff);
    init->rdrp.high = (unsigned short)(((bufp >> 16) & 0xff) |
	(RECEIVE_BUFFERS_POWER << LE_DRP_LEN_SHIFT));
    bufp = (unsigned long)(&cbsp->tmd);
    init->tdrp.low = (unsigned short)(bufp & 0xffff);
    init->tdrp.high = (unsigned short)(((bufp >> 16) & 0xff) |
	(TRANSMIT_BUFFERS_POWER << LE_DRP_LEN_SHIFT));

    /*
     *  Turn on promiscuous mode if EnetReceiveMask says to.
     */
    if (EnetReceiveMask & ENET_PROMISCUOUS)
    {
    	init->mode |= LE_MODE_PROM;
	EnetPromiscuous = 1;
    }

    /*
     *  Initialize the Buffer Descriptors.  The space pointed to by the
     *  descriptors is located above the control block segment in the
     *  Ethernet buffer/data space.  The buffers are allocated contiguously
     *  with the receive buffers before the single transmit buffer.
     */
    bufp = (unsigned long)rbuf;
    for (i = 0; i < RECEIVE_BUFFERS; i++, bufp += LE_MAX_PACKET)
    {
      	cbsp->rmd[i].ladr = (unsigned short)(bufp & 0xffff);
      	cbsp->rmd[i].flags = LE_RMD_OWN;	/* owned by LANCE */
      	cbsp->rmd[i].hadr = (unsigned char)((bufp >> 16) & 0xff);
      	cbsp->rmd[i].bcnt = -LE_MAX_PACKET;
      	cbsp->rmd[i].mcnt = 0;
    }
    bufp = (unsigned long)tbuf;
    cbsp->tmd.ladr = (unsigned short)(bufp & 0xffff);
    cbsp->tmd.flags = 0;		/* owned by CPU */
    cbsp->tmd.hadr = (unsigned char)((bufp >> 16) & 0xff);
    cbsp->tmd.bcnt = -LE_MAX_PACKET;
    cbsp->tmd.status = 0;

    /*
     *  Load up the address of the Initialization Block.
     */
    rap = LE_RAP_CSR1;
    rdp = (unsigned short)(((unsigned long)(&cbsp->init)) & 0xffff);
    rap = LE_RAP_CSR2;
    rdp = (unsigned short)((((unsigned long)(&cbsp->init)) >> 16) & 0xff);

    /*
     *  Initialize the flag bits in CSR3.
     */
    rap = LE_RAP_CSR3;
    rdp = LE_CSR3_BSWP;		/* do byte swapping to/from the SILO */

    /*
     *  Crank it up and let it go.  We must wait for the initialization
     *  to complete on the chip.
     */
    rap = LE_RAP_CSR0;
    rdp = LE_CSR0_INIT | LE_CSR0_STRT | LE_CSR0_INEA;
    while ((rdp & LE_CSR0_IDON) == 0)
	;
    rdp = LE_CSR0_IDON | LE_CSR0_INEA;	/* turn off Interrupt Done bit */
}

NetworkWrite(bufferptr)
register BufferList *bufferptr;
{
    register struct TransmitMessageDescriptor *tmdp = &cbsp->tmd;
    register unsigned long bytes;
    register char *p;

    if (bufferptr->bytes < sizeof(Enet10Header)) Kabort("Bad network header");

    ((Enet10Header *)(bufferptr->ptr))->SrcHost = EnetHostNumber;

    /*
     *  Copy the packet from the buffer list into our LANCE transmit buffer.
     */
    for (p = tbuf; bufferptr->ptr != NULL; bufferptr++)
        if ((bytes = bufferptr->bytes) != 0)
	{
	    Copy(p, bufferptr->ptr, bytes);
	    p += bytes; 
	}

    /*
     *  Tell the LANCE to ship it out.
     */
    tmdp->bcnt = -(p - tbuf);
    tmdp->status = 0;
    tmdp->flags = LE_TMD_OWN | LE_TMD_STP | LE_TMD_ENP;
    rdp = LE_CSR0_TDMD | LE_CSR0_INEA;	/* tell LANCE to look at descriptor */
}

SystemCode
EnetModify(pd, inst, dirIndex)
register Process *pd;
DeviceInstance *inst;
unsigned short dirIndex;
{
    register QueryEnetReply *reply = (QueryEnetReply *)&(pd->msg);

    if (reply->NumCollisions != -1)
	EnetCollisions = reply->NumCollisions;
    if (reply->NumOverflows != -1)
	EnetOverflows = reply->NumOverflows;
    if (reply->NumCRCErrors != -1)
	EnetCRCErrors = reply->NumCRCErrors;
    if (reply->NumSyncErrors != -1)
	EnetSyncErrors = reply->NumSyncErrors;
    if (reply->NumTimeOuts != -1)
	EnetTimeOuts = reply->NumTimeOuts;
    if (reply->NumValidPackets != -1)
	EnetValidPackets = reply->NumValidPackets;
    if (reply->ReceiveMask != EnetReceiveMask && reply->ReceiveMask != -1)
	EnetReset(reply->ReceiveMask);

   return (OK);
}

SystemCode
EnetQuery(pd, inst, dirIndex)
Process *pd;
DeviceInstance *inst;
unsigned short dirIndex;
{
    register QueryEnetReply *reply = (QueryEnetReply *)&(pd->msg);

    reply->NetworkType = ENET_TYPE_10MBIT;
    reply->NumCollisions = EnetCollisions;
    reply->NumOverflows = EnetOverflows;
    reply->NumCRCErrors = EnetCRCErrors;
    reply->NumSyncErrors = EnetSyncErrors;
    reply->NumTimeOuts = EnetTimeOuts;
    reply->ReceiveMask = EnetReceiveMask;
    reply->NumValidPackets = EnetValidPackets;
    reply->HostAddress.e10 = EnetHostNumber;

    return (OK);
}

/*
 *  Handle an interrupt from the ethernet interface.
 */
EnetInterrupt()
{
    register struct ReceiveMessageDescriptor *rmdp;
    register struct TransmitMessageDescriptor *tmdp;
    register Process *pd;

    if (rdp & LE_CSR0_ERR)
    {
      	if (rdp & LE_CSR0_BABL)
	{
	    printx("LANCE transmitter timeout.\n");
	    rdp = LE_CSR0_BABL | LE_CSR0_INEA;
	    EnetTimeOuts++;
	}
      	if (rdp & LE_CSR0_CERR)
	{
	    /* No hearbeat: ignore */
	    rdp = LE_CSR0_CERR | LE_CSR0_INEA;
	}
      	if (rdp & LE_CSR0_MISS)
	{
	    rdp = LE_CSR0_MISS | LE_CSR0_INEA;
	    EnetOverflows++;
	}
      	if (rdp & LE_CSR0_MERR)
	{
	    Kabort("LANCE memory error");
	}
    }

    if ((rdp & LE_CSR0_RXON) == 0)
    {
    	printx("LANCE receiver not on!\n");
    }

    if ((rdp & LE_CSR0_TXON) == 0)
    {
    	printx("LANCE transmitter not on!\n");
    }

    if (rdp & LE_CSR0_STOP)
    {
    	printx("LANCE chip stopped!\n");
    }

    if (rdp & LE_CSR0_RINT)
    {
      	rdp = LE_CSR0_RINT | LE_CSR0_INEA;

nextPacket:
	rmdp = &cbsp->rmd[rbufnum];
	if (rmdp->flags & LE_RMD_OWN)
	    goto endRINT;	/* next packet not ready yet */
	if (rmdp->flags & LE_RMD_ERR)
	{
	    if (rmdp->flags & LE_RMD_FRAM)
	    {
		/* Framing error */
		EnetSyncErrors++;
	    }
	    if (rmdp->flags & LE_RMD_OFLO)
	    {
	      	/* Overflow */
		EnetOverflows++;
	    }
	    if (rmdp->flags & LE_RMD_CRC)
	    {
		/* CRC error */
		EnetCRCErrors++;
	    }
	    if (rmdp->flags & LE_RMD_BUFF)
	    {
		/* Ran out of buffers */
		EnetOverflows++;
	    }
	}
	else if ((rmdp->flags & (LE_RMD_STP | LE_RMD_ENP)) !=
	    (LE_RMD_STP | LE_RMD_ENP))	/* not a whole packet */
	{
	    register Enet10Header *hdr =
	    	(Enet10Header *)(rbuf + rbufnum * LE_MAX_PACKET);
	    
	    if (rmdp->flags & LE_RMD_STP)
	        printx("LANCE no end of packet from %x.%x.%x\n",
			hdr->SrcHost.addrhigh,
			hdr->SrcHost.addrmid,
			hdr->SrcHost.addrlow);
	    else if (rmdp->flags & LE_RMD_ENP)
	        printx("LANCE no start of packet (length %d)\n",
			rmdp->mcnt);
	    else
	        printx("LANCE no start or end of packet\n");
	}
	else			/* got a valid packet */
	{
	    EnetReadPacket((Enet10Header *)(rbuf + (rbufnum * LE_MAX_PACKET)),
		rmdp->mcnt + sizeof(Enet10Header));
	}
	rmdp->mcnt = 0;
	rmdp->flags = LE_RMD_OWN;	/* give back to chip */
	if (++rbufnum == RECEIVE_BUFFERS) rbufnum = 0;
	goto nextPacket;
      }
endRINT:

    if (rdp & LE_CSR0_TINT)
    {
      	rdp = LE_CSR0_TINT | LE_CSR0_INEA;

	tmdp = &cbsp->tmd;
	if (tmdp->flags & LE_RMD_OWN)
	{
	    printx("Spurious LANCE xmit int\n");
	    return;
	}
	if (tmdp->flags & LE_TMD_ERR)
	{
	    if (tmdp->status & LE_TMD_LCOL)
	    {
		/* Late collision: someone is out of spec */
		EnetCollisions++;
	    }
	    if (tmdp->status & LE_TMD_LCAR)
	    {
	      	printx("LANCE transmit carrier lost.\n");
	    }
	    if (tmdp->status & LE_TMD_UFLO)
	    {
	      	Kabort("LANCE transmit underflow error");
	    }
	    if (tmdp->status & LE_TMD_RTRY)
	    {
		/* Too many collisions -- just go on */
		EnetCollisions += 16;	/* gave up after 16 */
	    }
	}
	else
	{
	    if (tmdp->flags & LE_TMD_ONE)
		EnetCollisions++;
	    else if (tmdp->flags & LE_TMD_MORE)
		EnetCollisions += 2;	/* assume only 2 */
	}
	/* If IkpOutq is non-empty, transmit next interkernel packet. */
	Lockq(&IkpOutq);
	if ((pd = IkpOutq.head) != NULL)
	{
	    if ((IkpOutq.head = pd->link) == NULL)
		IkpOutq.tail = (Process *)&(IkpOutq.head);
	    pd->queuePtr = NULL;
	    Unlockq(&IkpOutq);
	    WriteNextKPacket(pd);
	}
	else
	{
	    Unlockq(&IkpOutq);
	    EnetWriter = 0;		/* No transmission in progress now */
	}
    }
}

SystemCode
EnetReadPacket(enet, len)
register Enet10Header *enet;
register int len;
{
    extern PFPID RemoteTrapTable[];
    Process *pd;
    DeviceInstance *inst;
    register kPacket *kp;
    register IoRequest *req;
    Team *oldteam;
    SystemCode ret;
    register char *p;
    /* SendGroupMembers() may find a remote alias process group member. */
    extern int DeliverToEnetReader;

    DeliverToEnetReader = 0;

    /*
     *  Look at the first few words of the packet to determine
     *  if it is a kernel packet and not addressing an alias process.
     */
    kp = (kPacket *)((unsigned long)enet + sizeof(Enet10Header));
    if (enet->EtherType == KERNEL_PACKET && DifferentIKCByteOrder(kp))
    {
	SwapIKPacket(kp);
	kp->packetType &= ~IKC_LITTLE_ENDIAN;	/* Just to be tidy */
    }
    if (enet->EtherType != KERNEL_PACKET ||
	(kp->dstPid & REMOTE_ALIAS_PROCESS))
    {
nonKernelPacket:
	/* First case: it is not a kernel packet */
	/* and not to a remote alias process */

	if ((inst = EthernetInstance) == NULL)	/* Ethernet device not open */
	    goto finishpacket;
	if (!MAP_TO_RPD(pd, inst->reader))
	{
	    /* No reader process */
	    if (!MAP_TO_RPD(pd, inst->owner))
	    {
		inst->owner = 0; /* Free the instance */
		EthernetInstance = NULL;
		inst = NULL;
		if (EnetReceiveMask != ENET_DEFAULT_MASK)
		    EnetReset(ENET_DEFAULT_MASK);
		/* Ethernet device not open */
		goto finishpacket;
	    }
	    /*
	     *  If in promiscuous mode, dont save packet if it is
	     *  a kernel packet -- too risky.
	     */
	    if (EnetPromiscuous && (enet->EtherType == KERNEL_PACKET &&
		(kp->dstPid & REMOTE_ALIAS_PROCESS)))
		goto finishpacket;

	    /* There is no reader; copy the packet into the user save area */
	    UserPacketLength = len;
	    Copy(UserPacketBuffer, enet, len);
	    goto finishpacket;
	}
	/* First, fill in the bytecount in the reply */
	req = (IoRequest *)&(pd->msg);
    	if (len < req->bytecount)
	    req->bytecount = len;
    	/* Now decide where to put the data */
    	if (req->bytecount <= IO_MSG_BUFFER) 
	    p = req->shortbuffer;
    	else
	    p = req->bufferptr;

	/* Copy data to correct location */
	oldteam = GetAddressableTeam();
	SetAddressableTeam(pd->team);
	Copy(p, enet, req->bytecount);
	SetAddressableTeam(oldteam);
	ret = OK;
	inst->reader = 0;
	req->requestcode = OK;
	Addready(pd);
    }
    else
    {
	/* Second case : a kernel packet */
	/* Don't cache remoteForward pids because multiple forward exist
	 * and determining which field was the source is too confusing.
	 * The protocol shold be fixed.
	 */
	if (kp->packetType != remoteForward)
	    HostCacheEnter(kp->srcPid >> 16, enet->SrcHost);

	/* Ensure in correct packetType range. */
	kp->packetType = kp->packetType & 0xf;
	(*RemoteTrapTable[kp->packetType])(kp);
	ret = NO_REPLY;
	/* If in promiscuous mode, let the enet reader get too. */
	if (EnetPromiscuous || DeliverToEnetReader)
	    goto nonKernelPacket;

    }
finishpacket:
    EnetValidPackets++;
}

SystemCode
AddLogicalHostGroup(lhg)
GroupId lhg;
{
    return (OK);
}

SystemCode
DeleteLogicalHostGroup(lhg)
GroupId lhg;
{
    return (OK);
}

int
NetCheck()
{
    /* not used in this driver */
}
27333!Funky!Stuff!
echo x - kernel/m68k/enetle.h
cat > kernel/m68k/enetle.h << '27333!Funky!Stuff!'
/*
 * V Kernel
 *
 * Ethernet Header for AMD 7990 LANCE Ethernet controller chip.
 *
 * David B. Johnson, Dept. of Computer Science, Rice University.
 * Modified at Stanford.
 */

/*
 *  The LANCE has a Register Address Port (RAP) which is used to select
 *  which of four control/status registers (CSR0, CSR1, CSR2, or CSR3)
 *  is available for reading or writing at the Register Data Port (RDP).
 *  The following values written into the RAP will select the corresponding
 *  CSRs.
 */
#define	LE_RAP_CSR0	0		/* select CSR0 for RDP */
#define	LE_RAP_CSR1	1		/* select CSR1 for RDP */
#define	LE_RAP_CSR2	2		/* select CSR2 for RDP */
#define	LE_RAP_CSR3	3		/* select CSR3 for RDP */

/*
 *  Format of a Descriptor Ring Pointer for the Receive and Transmit
 *  Descriptor Rings.  Each pointer is two words long, where the low word
 *  contains only the low 16 bits of the of the base address of the
 *  Descriptor Ring itself, and the high word contains the high 8 bits of
 *  this address and the length of the ring (the number of entries in the
 *  ring) expressed as a power of two.  This length is shifted up by
 *  LE_DRP_LEN_SHIFT bits within the word.
 */
struct drp {
    unsigned short low;
    unsigned short high;
};
#define	LE_DRP_LEN_SHIFT 13	/* shift count for ring len in high word */

/*
 *  Initialization Block.  This structure is built in memory, and its
 *  address is given to the chip in CSR1 and CSR2 during initialization.
 *  The block will be read by the chip when the INIT bit is then set
 *  in CSR0.
 */
struct InitializationBlock
  {
    unsigned short	mode;		/* chip's operating parameters */
    					/* (see bit definitions below) */
    /*
     *  The bytes within each of the three words of padr must be byte swapped.
     */
    unsigned char	padr[6];	/* physical Ethernet address */

    unsigned char	ladrf[8];	/* logical address filter */
    struct drp		rdrp;		/* receive descriptor ring pointer */
    struct drp		tdrp;		/* transmit descriptor ring poniter */
  };

/*
 *  Mode register bits for the Initialization Block.  For normal operation,
 *  these bits are all 0.
 */
#define LE_MODE_PROM	0x8000		/* promiscuous mode */
#define LE_MODE_INTL	0x0040		/* internal loopback */
#define LE_MODE_DRTY	0x0020		/* disable retry */
#define LE_MODE_COLL	0x0010		/* force collision */
#define LE_MODE_DTCR	0x0008		/* disable transmit CRC */
#define LE_MODE_LOOP	0x0004		/* loopback */
#define LE_MODE_DTX	0x0002		/* disable the transmitter */
#define LE_MODE_DRX	0x0001		/* disable the receiver */

/*
 *  Control and status bits for CSR0.
 *
 *  These behave somewhat strangely, but the net effect is that
 *  bit masks may be written to the register which affect only
 *  those functions for which there is a one bit in the mask.
 *  The exception is the interrupt enable, which must be explicitly
 *  set to the correct value in each mask that is used.
 *
 *  RO  - Read Only, writing has no effect
 *  RC  - Read, Clear.  Writing 1 clears, writing 0 has no effect
 *  RW  - Read, Write.
 *  W1  - Write with 1 only.  Writing 1 sets, writing 0 has no effect.
 *        Reading gives unpredictable data but doesn't hurt anything.
 *  RW1 - Read, Write with 1 only.  Writing 1 sets, writing 0 has no effect.
 */
#define	LE_CSR0_ERR	0x8000		/* error summary (RO) */
#define	LE_CSR0_BABL	0x4000		/* transmitter timeout error (RC) */
#define	LE_CSR0_CERR	0x2000		/* collision error (RC) */
#define	LE_CSR0_MISS	0x1000		/* missed packet (RC) */
#define	LE_CSR0_MERR	0x0800		/* memory error (RC) */
#define	LE_CSR0_RINT	0x0400		/* receiver interrupt (RC) */
#define	LE_CSR0_TINT	0x0200		/* transmitter interrupt (RC) */
#define	LE_CSR0_IDON	0x0100		/* initialization done (RC) */
#define	LE_CSR0_INTR	0x0080		/* interrupt flag (RO) */
#define	LE_CSR0_INEA	0x0040		/* interrupt enable (RW) */
#define	LE_CSR0_RXON	0x0020		/* receiver on (RO) */
#define	LE_CSR0_TXON	0x0010		/* transmitter on (RO) */
#define	LE_CSR0_TDMD	0x0008		/* transmit demand (W1) */
#define	LE_CSR0_STOP	0x0004		/* stop (RW1) */
#define	LE_CSR0_STRT	0x0002		/* start (RW1) */
#define	LE_CSR0_INIT	0x0001		/* initialize (RW1) */

/*
 *  CSR1 is the low 16 bits of the address of the initialization block.
 */

/*
 *  CSR2 is the high 8 bits of the address of the initialization block;
 *          the high 8 bits of the register must be 0.
 */

/*
 *  CSR3 mode bits.
 */
#define	LE_CSR3_BSWP	0x0004		/* byte swap */
#define	LE_CSR3_ACON	0x0002		/* ALE control */
#define	LE_CSR3_BCON	0x0001		/* byte control */

/*
 *  A "ring" of Receive Message Descriptors is pointed to by the rdrp field
 *  of the Initialization Block, where the ring is actually an array of
 *  descriptors viewed by the chip with the first descriptor logically
 *  following the last one in the array.
 */
struct ReceiveMessageDescriptor
  {
    unsigned short	ladr;		/* low order 16 bits of buffer addr */
    unsigned char	flags;		/* flag bits (see below) */
    unsigned char	hadr;		/* high order 8 bits of buffer addr */
    unsigned short	bcnt;		/* buffer byte count */
    					/* (high 4 bits must be 1's) */
    unsigned short	mcnt;		/* message byte count */
					/* (high 4 bits reserved) */
  };

/*
 *  Flag bits for the Receive Message Descriptor.
 */
#define	LE_RMD_OWN	0x80		/* set if buffer owned by LANCE */
#define	LE_RMD_ERR	0x40		/* error summary */
#define	LE_RMD_FRAM	0x20		/* framming error */
#define	LE_RMD_OFLO	0x10		/* overflow error */
#define	LE_RMD_CRC	0x08		/* CRC error */
#define	LE_RMD_BUFF	0x04		/* buffer error */
#define	LE_RMD_STP	0x02		/* start of packet */
#define	LE_RMD_ENP	0x01		/* end of packet */

/*
 *  The Transmit Message Descriptor ring is structured the same as the
 *  Receive Message Descriptor ring, except that it is pointed to by the
 *  tdrp field of the Initialization Block.
 */
struct TransmitMessageDescriptor
  {
    unsigned short	ladr;		/* low order 16 bits of buffer addr */
    unsigned char	flags;		/* flag bits (see below) */
    unsigned char	hadr;		/* high order 8 bits of buffer addr */
    unsigned short	bcnt;		/* buffer byte count */
    					/* (high 4 bits must be 1's) */
    unsigned short	status;		/* transmission status (see below) */
  };

/*
 *  Flag bits for the Transmit Message Descriptor.
 */
#define	LE_TMD_OWN	0x80		/* set if buffer owned by LANCE */
#define	LE_TMD_ERR	0x40		/* error summary */
#define	LE_TMD_MORE	0x10		/* more than one retry needed */
#define	LE_TMD_ONE	0x08		/* exactly one retry needed */
#define	LE_TMD_DEF	0x04		/* defer was necessary */
#define	LE_TMD_STP	0x02		/* start of packet */
#define	LE_TMD_ENP	0x01		/* end of packet */

/*
 *  Status bits for the Transmit Message Descriptor.
 */
#define	LE_TMD_BUFF	0x8000		/* buffer error */
#define	LE_TMD_UFLO	0x4000		/* underflow error */
#define	LE_TMD_LCOL	0x1000		/* late collision */
#define	LE_TMD_LCAR	0x0800		/* loss of carrier */
#define	LE_TMD_RTRY	0x0400		/* failed after 16 retries */
#define	LE_TMD_TDR	0x03ff		/* time domain reflectometry mask */

/*
 *  Maximum length of a LANCE packet in memory.  This is the sum of
 *	   6 bytes	destination Ethernet address
 *	   6 bytes	source Ethernet address
 *	   2 bytes	Ethernet type field
 *	1500 bytes	maximum data field length
 *	   4 bytes	packet CRC
 *
 *  For received packets, the LANCE places all of these fields (including
 *  the CRC) into the buffer in memory.  For transmitting packets, though,
 *  the LANCE suplies the CRC.
 */
#define	LE_MAX_PACKET	1518
27333!Funky!Stuff!
echo x - kernel/m68k/sun3mem.c
cat > kernel/m68k/sun3mem.c << '27333!Funky!Stuff!'
/*
 * V Kernel - Copyright (c) 1982 by David Cheriton, Tim Mann
 *
 * Sun-2 memory mapping routines
 */

#include "process.h"
#include "sun3mem.h"
#include "sunromvec.h"
#include "interrupt.h"
#include "Vexceptions.h"
#include "Vquerykernel.h"
#include <b.out.h>

/* Imports */
extern MachineConfigurationReply MachineConfig;
extern Team *TeamDescriptors;
extern unsigned long MaxTeams;
extern TimeRecord Time;
extern FindConfiguration();

/* Exports */
void Init_memory_mapping();
SystemCode AllocateMemory();
SystemCode SetTeamSize();
char *KSetTeamSize();
void SetAddressableTeam();
void ReclaimMemory();
void InterTeamCopy();
int Probe();
int DiagnoseBusError();
void GetMemoryStats();
void AllocateDvmaSpace();
void MapDvma();

void FreePage();
SystemCode AllocatePage();
void FreePmeg();
SystemCode AllocatePmeg();
int GetMemorySize();
void SaveSegMap();
void RestoreSegMap();

/* Globals */
PageMapEntry FreePageList;	/* list head */
SegMapEntry FreePmegList;

int FreePages = 0;
VirtualAddress FreeKernelSpace;	/* free pages in kernel area */
VirtualAddress FreeDvmaSpace;

Team *AddressableTeam;

struct bhdr KernelBheader = {0},
	    TeamBheader = {0};		/* Force to data segment */

void Init_memory_mapping()
  /*
   * Setup the memory mapping as required.
   *
   * We assume the EPROM monitor has initialized the memory map for
   * context 0 in its standard way.  The kernel and first team are 
   * assumed to have been put at their normal addresses by the 
   * bootloader, and the pages and segments they are loaded into are 
   * assumed to be mapped 1-to-1, that is, the virtual and physical 
   * addresses are the same, and the pmeg and segment numbers are the same.
   *
   * We assign the kernel virtual addresses between 0 and TEAM_START in
   * all contexts.  Only pages that are actually used are mapped to
   * physical memory.
   *
   * Addresses from TEAM_START to TEAM_LIMIT are available to teams.  The 
   * first team is initially given just enough mapped memory in this area
   * to hold its code and data.  All other memory is added to the free
   * list.
   *
   * The area above TEAM_LIMIT is mapped in a complex way by the EPROM
   * monitor (described elsewhere), and we leave it alone (may change
   * protection on somethings later), both to keep the EPROM monitor 
   * happy when we have to call it, and because it is a reasonable 
   * arrangement for our use.
   * 
   */
  {
    int pages;
    char *cptr;
    int ctx, i, framestart, frameend;
    PageMapEntry pme, pme2;
    SegMapEntry sme, xsme, topsme;
    VirtualAddress addr, ttop, ktop;
    Team *td;

    /* Copy the b.out headers into kernel data space */
    TeamBheader = *((struct bhdr *) (TEAM_START - sizeof(struct bhdr)));
    KernelBheader = *((struct bhdr *) (TEAM_START - 2*sizeof(struct bhdr)));

    ttop.u = TEAM_START + TeamBheader.tsize 
		+ TeamBheader.dsize + TeamBheader.bsize + INIT_STACK;
    ktop.u = KERNEL_START + KernelBheader.tsize
		+ KernelBheader.dsize + KernelBheader.bsize;

    /* Zero the bss area in case the loader didn't do it */
    cptr = (char *) TEAM_START + TeamBheader.tsize + TeamBheader.dsize;
    for (i = TeamBheader.bsize; i; i--) *cptr++ = '\0';

    cptr = (char *) KERNEL_START + KernelBheader.tsize + KernelBheader.dsize;
    for (i = KernelBheader.bsize; i; i-- ) *cptr++ = '\0';

    SetContext(0);	/* just to be sure */
    FreeKernelSpace.u = uptopage(ktop.u);
    FreeDvmaSpace.u = V_DVMA_START;
    FindConfiguration();
    pages = GetMemorySize();
    MachineConfig.fastMemory = pages * PAGE_SIZE;
    MachineConfig.slowMemory = 0;
    MachineConfig.memory = MachineConfig.fastMemory;

    printx("Memory size: 0x%x bytes.\r\n", MachineConfig.memory);

    /* Initialize free lists */
    FreePageList.u = NULL_PAGE;
    FreePmegList = NULL_PMEG;

    printx("Bytes: Kernel ( %d ) First team ( %d )\n",
	ktop.u - KERNEL_START, ttop.u - TEAM_START );
    if (ktop.u > TEAM_START) Kabort("Kernel too big");

    /* Set page protection on kernel memory appropriately */
    for (addr.u = 0; addr.u < ktop.u; addr.u += PAGE_SIZE)
      {
	pme.u = GetPageMap(addr.u);
	pme.f.protection = SUPER_ONLY|PAGE_WRITE;
	SetPageMap(addr.u, pme.u);
      }

    /* Set page protection on team memory appropriately */
    for (addr.u = TEAM_START; addr.u < ttop.u; addr.u += PAGE_SIZE)
      {
	pme.u = GetPageMap(addr.u);
	pme.f.protection = PAGE_WRITE;
	SetPageMap(addr.u, pme.u);
      }

    /* map in profile and pd segments here so that they will be valid in
     * all contexts. They will be copied into the other contexts later.
     */
    SetSegMap( PROFILESEG, PROFILE_PMEG );
    SetSegMap( PD_SEG, PD_PMEG );
    SetSegMap( TEAM_SEG, TEAM_PMEG );
    SetSegMap( DVMA_SEG1, DVMA_PMEG1 );
    SetSegMap( DVMA_SEG2, DVMA_PMEG2 );

    /* Unmap segments in context 0 above the top of the first team,
     *   up to TEAM_LIMIT.
     */
    for (addr.u = uptoseg(ttop.u); addr.u < TEAM_LIMIT;
		addr.u += SEG_SIZE)
      {
	SetSegMap(addr.u, NULL_PMEG);
      }

    /* Initialize the segment maps for non-zero contexts.  We copy in the
     *   context 0 mapping for the kernel and the area above TEAM_LIMIT,
     *   and set the rest to NULL_PMEG.
     */
    for (addr.u = 0; addr.u < TEAM_START; addr.u += SEG_SIZE)
      {
	sme = GetSegMap(addr.u);
	for (ctx = 1; ctx < NUM_CONTEXTS; ctx++)
	  {
	    SetContext(ctx);
	    SetSegMap(addr.u, sme);
	  }
	SetContext(0);
      }
    for ( ; addr.u < TEAM_LIMIT; addr.u += SEG_SIZE)
      {
	for (ctx = 1; ctx < NUM_CONTEXTS; ctx++)
	  {
	    SetContext(ctx);
	    SetSegMap(addr.u, NULL_PMEG);
	  }
      }
    SetContext(0);
    for ( ; addr.u < CONTEXT_SIZE; addr.u += SEG_SIZE)
      {
	sme = GetSegMap(addr.u);
	for (ctx = 1; ctx < NUM_CONTEXTS; ctx++)
	  {
	    SetContext(ctx);
	    SetSegMap(addr.u, sme);
	  }
	SetContext(0);
      }

    /* Construct free pmeg list.  We put all the pmegs numbered
     *   above the ones used by the kernel and first team and 
     *   below the ones used above TEAM_LIMIT on the list.  This
     *   technique frees the right ones because the EPROM allocates
     *   pmeg numbers monotonically within this area.
     */
    xsme = GetSegMap(XFERSEG);
    for (sme=ExtractSegNumber(uptoseg(ttop.u));
	sme < NUM_PMEGS-PROM_PMEGS; sme++)
      {
/*
 *  HACK!!!  I don't know why this is necessary or why it works, but
 *  without it, "k1" and sometimes "k2" in the monitor just hang.
 *  The PROM maps PMEGs 0 through 1f into memory, and the last two pages
 *  of 1f get accessed and modified, so it must be using them for
 *  something.  We'll just leave its PMEG alone...   dbj@rice
 */
if (sme == 0x1f) { printx("Skipping FreePmeg on 0x1f\n"); continue; }
	SetSegMap(XFERSEG, sme);
	FreePmeg(XFERSEG);
      }
    SetSegMap(XFERSEG, xsme);

    /* Construct free page list */

    /* First, free unused pages from kernel area */
    for (addr.u = uptopage(ktop.u); addr.u < TEAM_START; addr.u += PAGE_SIZE)
	FreePage(addr.u);

    /* Next, unmap unused pages in team's last pmeg (they are added to
     *   the free list in the next step).
     */
    for (addr.u = uptopage(ttop.u);
	 addr.u < uptoseg(ttop.u); addr.u += PAGE_SIZE)
      {
	SetPageMap(addr.u, NULL_PAGE);
      }

    /* Now free other unused pages, leaving some for prom use */
    /*
     * Make sure that we don't free the page frames belonging to the frame
     * buffer.  For most models of a SUN-3, this check does nothing since
     * the frame buffer is way up at 0xff000000 (physical), but on the
     * SUN-3/50 (at least), the frame buffer is down at 0x100000 (physical),
     * which gets hit by this loop without this check.  -- dbj@rice 7/31/86
     */
    pme2.u = GetPageMap(V_SUN3_FRAMEBUFFER);
    framestart = pme2.f.pagenum;
    frameend = framestart + SUN3_FRAMEBUFFER_SIZE/PAGE_SIZE - 1;
    pme.f.valid = 1;
    pme.f.protection = SUPER_ONLY|PAGE_WRITE;
    pme.f.type = ONBOARD_MEM;
    for ( i = ExtractPageNumber(uptopage(ttop.u)); i < pages-PROM_PAGES; i++ )
      {
	if (framestart <= i && i <= frameend) continue;
	pme.f.pagenum = i;
	SetPageMap(TESTPAGE, pme.u);
	FreePage(TESTPAGE);
      }

    /* Unmap onboard memory pages from DVMA region */
    for (addr.u = V_DVMA_START; addr.u < V_DVMA_LIMIT; addr.u += PAGE_SIZE)
      {
	SetPageMap(addr.u, NULL_PAGE);
      }

    /* Set page protection on high memory */
    for (addr.u = TEAM_LIMIT;
	 addr.u < CONTEXT_SIZE;
	 addr.u += PAGE_SIZE)
      {
	pme.u = GetPageMap(addr.u);
	if (pme.u == NULL_PAGE) continue;
	pme.f.protection |= SUPER_ONLY;
	SetPageMap(addr.u, pme.u);
      }

    /* Unprotect the frame buffer */
    for (addr.u = V_SUN3_FRAMEBUFFER;
         addr.u < V_SUN3_FRAMEBUFFER + SUN3_FRAMEBUFFER_SIZE;
	 addr.u += PAGE_SIZE)
      {
	pme.u = GetPageMap(addr.u);
	if (pme.u == NULL_PAGE) continue;
	pme.f.protection &= ~SUPER_ONLY;
	SetPageMap(addr.u, pme.u);
      }

#ifdef undef
    /*
     * Map in the 16 bit VME space.
     */
    pme.u = 0;
    pme.f.valid = 1;
    pme.f.protection = PAGE_WRITE | SUPER_ONLY | DONT_CACHE;
    pme.f.type = VME_16;
    pme.f.pagenum = ExtractPageNumber(P_VME_16);
    SetPageMap(V_VME_16, pme.u);
#endif
  }

SystemCode SetTeamSize( active )
    Process *active;
  /*
   * Set the memory size for a team, mapping or unmapping pages as needed.
   */
  {
    KernelRequest *req = (KernelRequest *) &(active->msg);
    register Process *pd;

    if( !(pd = MapPid(req->pid)) ) return( NONEXISTENT_PROCESS );

    req->unspecified[0] = (unsigned)KSetTeamSize(pd->team,req->unspecified[0]);
    return( OK );
  }

char *KSetTeamSize(td, size)
    register Team *td;
    char *size;
  /*
   * Called by SetTeamSize to do the actual work.
   */
  {
    register VirtualAddress firstUnusedPage, newFirstUnusedPage;
    register int fail;
    Team *oldteam;

    /* Range check on size */
    if (size < (char *) TEAM_START) size = (char *) TEAM_START;
    if (size >= (char *) TEAM_LIMIT) size = (char *) TEAM_LIMIT;

    /* Temporarily switch contexts */    
    oldteam = GetAddressableTeam();
    SetAddressableTeam(td);

    firstUnusedPage.u = uptopage(td->team_space.size);
    newFirstUnusedPage.u = uptopage(size);

    fail = 0;
    if (firstUnusedPage.u <= newFirstUnusedPage.u)
      {
	/* More memory needed */
	for ( ; firstUnusedPage.u < newFirstUnusedPage.u; 
		firstUnusedPage.u += PAGE_SIZE )
	  {
	    if (fail = AllocatePage(firstUnusedPage.u)) break;
	  }
      }
    else
      {
	/* Less memory needed */
	for (firstUnusedPage.u -= PAGE_SIZE;
	     firstUnusedPage.u >= newFirstUnusedPage.u;
	     firstUnusedPage.u -= PAGE_SIZE)
	  {
	    FreePage(firstUnusedPage.u);
	    /* We are assuming the simple memory model in which
	     *   address spaces do not have holes, so if we free the
	     *   first page in a pmeg here, we can free the pmeg.
	     */
	    if (firstUnusedPage.u == uptoseg(firstUnusedPage.u))
	      {
		FreePmeg(firstUnusedPage.u);
	      }
	  }
      }

    SetAddressableTeam(oldteam);

    if (fail)
      {
	return (td->team_space.size = firstUnusedPage.p);
      }
    else
      {
	return (td->team_space.size = size);
      }

  }



void FreePage(pgaddr)
    VirtualAddress pgaddr;
  /*
   * Add a page to the free list, unmapping it from the current context
   */
  {
    PageMapEntry freepg;

    freepg.u = GetPageMap(pgaddr.u); /* Get map entry pointing to this page */

    /* Point page to old list top */
    *(PageMapEntry *) downtopage(pgaddr.u) = FreePageList;
    FreePageList = freepg;
    FreePages++;

    SetPageMap(pgaddr.u, NULL_PAGE);	 /* Unmap page */
  }


SystemCode AllocatePage(pgaddr)
    VirtualAddress pgaddr;
  /*
   * Map a page into the current context at the given address, if one
   *  can be found.  Return OK for success.
   */
  {
    PageMapEntry newpg;

    /* Find a page, if available */
    if ( (newpg.u = FreePageList.u) == NULL_PAGE )
      {
	return (NO_MEMORY);	/* fail */
      }

    /* Make sure there is a pmeg mapped to this segment */
    if (GetSegMap(pgaddr.u) == NULL_PMEG)
      {
	if (AllocatePmeg(pgaddr.u)) return (NO_MEMORY); /* fail */
      }

    /* Map in the page */
    newpg.f.valid = 1;
    newpg.f.protection = PAGE_WRITE;
    SetPageMap(pgaddr.u, newpg.u);

    /* Remove it from the free list */
    FreePageList = *(PageMapEntry *) downtopage(pgaddr.u);
    FreePages--;

    return (OK);
  }

/* Allocate physical memory. This routine is meant to be called by the kernel
 * to allocate memory for such uses as process decriptor space, ethernet
 * buffer space, and profiling data space. Is does not check to see if the
 * memory has already been allocated.
 */
SystemCode AllocateMemory( start, length )
char *start;
unsigned length;
  {
    register char *ptr, *end;
    
    end = start + length;

    for ( ptr = start; ptr < end; ptr += PAGE_SIZE )
	if ( AllocatePage( ptr ) != OK )
	  {
	    for ( end = start; end < ptr; end += PAGE_SIZE )
		FreePage( end );
	    return( NO_MEMORY );
	  }
    return( OK );    
  }

/* Very rudimentary. All of the memory BETTER BE ALLOCATED. */
FreeMemory( start, length )
char *start;
unsigned length;
  {
    register char *ptr, *end;
    
    end = start + length;
    
    for ( ptr = start; ptr < end; ptr += PAGE_SIZE ) FreePage( ptr );
    return( OK );    
  }

void FreePmeg(addr)
    VirtualAddress addr;
  /*
   * Free the pmeg currently mapped at address addr, clearing out all
   *   the pme's except the first (which is used as a link field).
   */
  {
    VirtualAddress start;

    start.u = downtoseg(addr.u);

    /* Link new pmeg onto start of chain */
    SetPageMap(start.u, FreePmegList);
    FreePmegList = GetSegMap(start.u);

    /* Clear the rest of the pmeg */
    for (addr.u = start.u + PAGE_SIZE; 
	 addr.u < start.u + SEG_SIZE; addr.u += PAGE_SIZE)
      {
	SetPageMap(addr.u, NULL_PAGE);
      }

    /* Unmap the pmeg */
    SetSegMap(start.u, NULL_PMEG);
  }


SystemCode AllocatePmeg(addr)
    VirtualAddress addr;
  /*
   * Map an empty pmeg into the current context at the given address, if one
   *  can be found.  Return OK for success.
   */
  {
    SegMapEntry newpm;

    /* Find a pmeg */
    newpm = FreePmegList;
    if (newpm == NULL_PMEG)
      {
	return (NO_MEMORY);  /* fail */
      }

    /* Map it in */
    SetSegMap(addr.u, newpm);

    /* Remove it from the free list and clear its link field */
    FreePmegList = (SegMapEntry) GetPageMap(downtoseg(addr.u));
    SetPageMap(downtoseg(addr.u), NULL_PAGE);
  }


void ReclaimMemory(td)
    Team *td;
    /* Reclaim the memory allocated to a defunct team */
  {
    KSetTeamSize(td, NULL);
  }


void InterTeamCopy(dest, dteam, src, steam, bytes)
    Team *dteam, *steam;
    char *dest, *src;
    long unsigned bytes;
  /*
   * This routine is used by MoveFrom and MoveTo to copy bytes between
   *   different teams.
   */
  {
    Team *oldteam;
    SegMapEntry oldxfs, xfs;
    int sbytes;

    oldteam = GetAddressableTeam();
    SetAddressableTeam(dteam);
    oldxfs = GetSegMap(XFERSEG);

    while (bytes > 0)
      {
	/* Set up to move all the desired bytes from one source segment */
	sbytes = ((char *) uptoseg(src+1)) - src;
	sbytes = min(sbytes, bytes);

	/* Map segment containing source bytes into xfer segment */
	/* Could speed things up a trifle by assuming neither steam
	 *   nor dteam will be LRU after the first time, and thereafter
	 *   calling SetContextReg instead of SetAddressableTeam */
	SetAddressableTeam(steam);
	xfs = GetSegMap(src);
	SetAddressableTeam(dteam);
	SetSegMap(XFERSEG, xfs);

	/* Move the bytes */
	Copy(dest, XFERSEG + (((unsigned) src)  & (SEG_SIZE-1)), sbytes);
	bytes -= sbytes;
	src += sbytes;
	dest += sbytes;

      }

    SetSegMap(XFERSEG, oldxfs);
    SetAddressableTeam(oldteam);

  }



void AllocateDvmaSpace(size, multibusAddress, virtualAddress)
    unsigned size;
    char **multibusAddress, **virtualAddress;
  {
    /*
     * Allocate 'size' bytes of DVMA space to the caller, rounded up
     *   to a page boundary.  Returns both Multibus and virtual addresses
     *   of the area allocated.  There is no provision for freeing DVMA
     *   space.
     */

    *virtualAddress = (char *) FreeDvmaSpace.u;
    *multibusAddress = (char *) FreeDvmaSpace.u - V_DVMA_START + P_DVMA_START;

    FreeDvmaSpace.u += uptopage(size);

    if (FreeDvmaSpace.u > V_DVMA_LIMIT) 
	Kabort("Out of DVMA space");
  }



void MapDvma( dest, source, length )
  register char      *dest, *source;
  register unsigned  length;

  {
    /* Map starting at 'source' address into Dmva space starting at
     *   'dest' address.
     */

    PageMapEntry  pme;
    register char *p, *q;  

    q = (char *) downtopage( dest );
    for( p = (char *) downtopage( source );
         p < (char *) uptopage( source+length );
         p += PAGE_SIZE )
      {
        pme.u = GetPageMap( p );
        SetPageMap( q, pme.u );
        q += PAGE_SIZE;
      }
  }

	
int GetMemorySize()
  /*
   * Probe to determine size of on-board memory on a Sun-2. 
   * Returns the amount in pages. Assumes that the prom maps 
   */
  {
    PageMapEntry oldPage, pme;
    register int pages, *p;

    /* Save old contents of page map entry we are using */
    oldPage.u = GetPageMap(TESTPAGE);

    /* Test onboard pages until one doesn't work */
    pages = TEAM_START/PAGE_SIZE;  /* Don't test kernel memory */
    pme.f.valid = 1;
    pme.f.protection = PAGE_WRITE|SUPER_ONLY;
    pme.f.type = ONBOARD_MEM;
    while (pages < ExtractPageNumber(P_ONBOARD_RAM_LIMIT))
      {
	pme.f.pagenum = pages;
	SetPageMap(TESTPAGE, pme.u);
	if (Probe(TESTPAGE, PROBE_PRESERVE))
	    pages++;	/* more memory here */
	else
	    break;	/* no more */
      }
	
    SetPageMap(TESTPAGE, oldPage.u);
    return (pages);
  }

int DiagnoseBusError(req)
    ExceptionRequest *req;
  /*
   * Diagnose the cause of a bus error.  Used by exception handler.
   */
  {
    BusErrorRegister cause;

    if (req->accaddr >= CONTEXT_SIZE)
      {
	/* Garbage address -- these processors have 
	 * only 28 bit addressing */
	return (OUT_OF_RANGE);
      }

    cause.u = GetBusErrorReg();

    if (cause.f.invalid) return (PAGE_INVALID);
    if (cause.f.protection) return (PROTECTION);
    if (cause.f.timeout) return (BUS_TIMEOUT);
    if (cause.f.VMEbus) return (VMEBERR);
    if (cause.f.FPAbus) return (FPABERR);
    if (cause.f.FPAenable) return (FPAENERR);
    if (cause.f.watchdog) return (WATCHDOG);

printx("Unknown bus error. Register = %x\n", cause.u);
asm("trap #14");
  }

int Probe(address, how)
    short *address;
    int how;
  /*
   * Look for memory at address.
   * If how == PROBE_INIT,
   *   write before reading to initialize, then look for writeable memory.
   * If how == PROBE_PRESERVE,
   *   look for writeable memory, but preserve contents of location.
   * If how == PROBE_READ,
   *   just try reading and see whether it causes a bus error.
   */
  {
    register short *Zero = (short *) 0;
    register short z, x;
    int BusErrorOnProbe(), (*oldBusErrorVector)();

#define VECTOR (VECTOR_BASE+BUSERROR)
    /* Set bus error vector */
    oldBusErrorVector = *( (int (**)()) VECTOR );
    *( (int (**)()) VECTOR ) = BusErrorOnProbe;

    z = *Zero;  /* Save old contents of address 0 */
		
    if (how == PROBE_INIT) 
	*address = 0x5c5c;	/* Initialize the test location */

    x = ~*address;		/* Read from it */

    if (how == PROBE_READ)
      {
	/* Success if we get here with no bus error */
	*( (int (**)()) VECTOR ) = oldBusErrorVector;
	return (1);
      }
    else
      {
	*address = x;		/* Write back the complement */
	if (*address == x && *Zero == z) 
	  {
	    /* Success */
	    *address = ~x;
	    *( (int (**)()) VECTOR ) = oldBusErrorVector;
	    return (1);
          }
    	else
	  {
	    /* Failure */
	    asm("ProbeFailed:");
	    *( (int (**)()) VECTOR ) = oldBusErrorVector;
	    *Zero = z;
            return (0);
          }
      }

    asm("	.globl BusErrorOnProbe");
    asm("BusErrorOnProbe:");
#ifdef MC68010
    asm("	addl	#58, sp");
#else !MC68010
    asm("	addl	#14, sp");
#endif MC68010
    asm("	jmp	ProbeFailed");

#undef VECTOR
  }

/*
 * Another routine to tell you whether you can read a given location in
 *   memory.  This one, however, is intended specifically for virtual
 *   addresses.  It doesn't actually try to read from the location, just
 *   look at the memory mapping hardware, which had better be set
 *   up properly.
 *
 * May need major fiddling if we introduce virtual memory.
 */

KernelCanRead(address, length)
    register unsigned   address, length;
  {
    register unsigned	testadr;

    /* Test one byte in each page from address to address+length-1 */
    /*   If we can read one byte in the page, we can read anything */
    for (testadr = address; (unsigned)(testadr-address) < length;
			     /* ^ Does this work for all cases? */
	 testadr = (testadr+PAGE_SIZE) & (-PAGE_SIZE) /*gag*/)
      {
	/* On the Sun-3, if the entry is marked valid then it's readable */
	/*   in supervisor mode (i.e. by the kernel).  The "valid" bit   */
	/*   happens to be the most significant bit, so we test for < 0. */
	/*   This stinks, but it's fast and also works - cc68 generated  */
	/*   bogus code when we tried pme.f.valid (did a movw d0,d0 and  */
	/*   then tested bit 15, somehow believing it was bit 31)	 */
	if ( ((long)GetPageMap(testadr)) >= 0 )
	    return 0;
      }
    return 1;
  }

/*
 * Get memory statistics for QueryKernel operation
 */
void GetMemoryStats(reply)
    register MemoryStatisticsReply *reply;
  {
    reply->unusedFastMemory = FreePages * PAGE_SIZE;
    reply->unusedSlowMemory = 0;
  }


/*
 * Routines to set/get the currently addressable team space.
 * The Sun-2 only has 8 sets of segment mapping registers, so if
 *   we have more than 8 teams, we have to do LRU swapping of the
 *   segment maps into and out of registers.
 */

/* GetAddressableTeam() is now a macro */

void SetAddressableTeam(newteam)
    register Team *newteam;
  {
    register Team *td, *oldest;
    
    /* Bring in segment map if not resident */
    if (newteam->team_space.context == MAP_NOT_RESIDENT)
      {
	/* Find the LRU context... */
	oldest = NULL;
	for (td = TeamDescriptors; td < (TeamDescriptors + MaxTeams); td++)
	  {
	    if ( MapPid(td->team_root) == NULL )
		td->team_space.timestamp = 0;		/* a dead team */

	    if ( td->team_space.context != MAP_NOT_RESIDENT &&
		    (oldest == NULL ||
		     td->team_space.timestamp < oldest->team_space.timestamp) )
		oldest = td;
	  }

	/* ...and swap out its segment map */
	newteam->team_space.context = oldest->team_space.context;
	oldest->team_space.context = MAP_NOT_RESIDENT;
        SetContext(newteam->team_space.context);
	SaveSegMap(oldest->team_space.segmap);
	RestoreSegMap(newteam->team_space.segmap);
      }
    else
      {
        SetContext(newteam->team_space.context);
      }

    AddressableTeam->team_space.timestamp = Time.seconds;
				/* %%% should be in clicks, really */
    AddressableTeam = newteam;
  }
  
SystemCode ClearModifiedPages( req, segPtr, segSize )
KernelRequest *req;
register long **segPtr;
unsigned long segSize;
  {
    PageMapEntry pme;
    register VirtualAddress addr, firstUnused;
    register int returnModifiedPages, count;
    int maxCount;
    Process *cpd;
    Team *oldteam;
    
    if ( !Local( req->pid ) ) return( MODE_NOT_SUPPORTED );
    
    if ( !MAP_TO_RPD( cpd, req->pid ) ) return( NONEXISTENT_PROCESS );
    
    if ( returnModifiedPages = ( req->opcode == RETURN_MODIFIED_PAGES ) )
	if( ( count = maxCount = segSize / sizeof( long * ) ) == 0 )
	    return( BAD_BUFFER );

    oldteam = GetAddressableTeam();
    SetAddressableTeam( cpd->team );
    
    firstUnused.u = uptopage( cpd->team->team_space.size );
    for ( addr.u = TEAM_START; addr.u < firstUnused.u; addr.u += PAGE_SIZE )
      {
	pme.u = GetPageMap( addr.u );
	if ( pme.f.modified )
	  {
	    pme.f.modified = 0;
	    SetPageMap( addr.u, pme.u );
	    if ( returnModifiedPages )
	      {
		*segPtr++ = (long *) addr.u;
		if ( --count == 0  ) break;
	      }
	  }
      }
    
    SetAddressableTeam( oldteam );
    
    if ( ( req->unspecified[0] = maxCount - count ) != maxCount )
      {
        *segPtr = NULL;
	return( OK );
      }
    else
	return( RETRY );
  }  


/* Routines to read and write function-code-3 space */

/* All routines assume that both function code registers contain "3"
 *   already.  The EPROM monitor is known to initialize them to that
 *   value, and the kernel never changes them.  */
asm("	.text			");
asm("	.globl Fc3ReadBit8	");
asm("Fc3ReadBit8:		");
asm("   movl sp@(4),a0		");	/* get arg into a0 */
asm("	movsb a0@, d0		");	/* move from outer space */
asm("	rts			");

asm("	.text			");
asm("	.globl Fc3ReadBit16	");
asm("Fc3ReadBit16:		");
asm("   movl sp@(4),a0		");	/* get arg into a0 */
asm("	movsw a0@, d0		");	/* move from outer space */
asm("	rts			");

asm("	.text			");
asm("	.globl Fc3ReadBit32	");
asm("Fc3ReadBit32:		");
asm("   movl sp@(4),a0		");	/* get arg into a0 */
asm("	movsl a0@,d0		");	/* move from outer space */
asm("	rts			");

asm("	.text			");
asm("	.globl Fc3WriteBit8	");
asm("Fc3WriteBit8:		");
asm("	movl sp@(4),a0		");	/* get address into a0 */
asm("	movl sp@(8),d0		");	/* get value into d0 */
asm("	movsb d0,a0@		");	/* move to outer space */
asm("	rts			");

asm("	.text			");
asm("	.globl Fc3WriteBit16	");
asm("Fc3WriteBit16:		");
asm("	movl sp@(4),a0		");	/* get address into a0 */
asm("	movl sp@(8),d0		");	/* get value into d0 */
asm("	movsw d0,a0@		");	/* move to outer space */
asm("	rts			");

asm("	.text			");
asm("	.globl Fc3WriteBit32	");
asm("Fc3WriteBit32:		");
asm("	movl sp@(4),a0		");	/* get address into a0 */
asm("	movl sp@(8),d0		");	/* get value into d0 */
asm("	movsl d0,a0@		");	/* move to outer space */
asm("	rts			");


/* Copy segment tables between mapping registers and memory */

asm("	.text			");
asm("	.globl SaveSegMap	");
asm("SaveSegMap:		");
asm("	movl #/20000000,a0	");	/* base of seg table */
asm("	movl sp@(4),a1		");	/* destination */
asm("	movl #2047,d0		");	/* size of seg table, minus 1 */
asm("loop1:			");
asm("	movsb a0@,d1		");	/* fetch an entry */
asm("	movb d1,a1@+		");	/* save it */
asm("	addl #/20000,a0		");	/* step to next segment */
asm("	dbra d0,loop1		");
asm("	rts			");

asm("	.text			");
asm("	.globl RestoreSegMap	");
asm("RestoreSegMap:		");
asm("	movl #/20000000,a0	");	/* base of seg table */
asm("	movl sp@(4),a1		");	/* destination */
asm("	movl #2047,d0		");	/* size of seg table, minus 1 */
asm("loop2:			");
asm("	movb a1@+,d1		");	/* fetch an entry */
asm("	movsb d1,a0@		");	/* restore it */
asm("	addl #/20000,a0		");	/* step to next segment */
asm("	dbra d0,loop2		");
asm("	rts			");
27333!Funky!Stuff!
echo x - kernel/m68k/sun3mem.h
cat > kernel/m68k/sun3mem.h << '27333!Funky!Stuff!'
/*
 * V Kernel - Copyright (c) 1985 by David Cheriton, Lance Berc
 *
 * Header file describing Sun-3 memory mapping and onboard device
 *   addresses. See the Sun-3 Architecture Manual (if you can get one)
 *   for details.
 */

#ifndef MEMORY
#define MEMORY

/* Where the interrupt vectors live (as set by the boot prom) */
#define VECTOR_BASE 0x0FE60C00

/* The number of pmegs used by the prom (plus a few for internal use) */
#define PROM_PMEGS	19
#define STACK_PMEG	0xef
#define TEAM_PMEG	0xf0
#define PD_PMEG		0xf1
#define PROFILE_PMEG	0xf2
#define DVMA_PMEG1	0xed
#define DVMA_PMEG2	0xee

/* The prom maps the last 8 pages of available memory into high mem. */
#define PROM_PAGES 8

typedef unsigned long	Bit32;
typedef unsigned short	Bit16;
typedef unsigned char	Bit8;
typedef long		sBit32;
typedef short		sBit16;
typedef char		sBit8;

/* Routines to read and write function-code-3 space, exported by sun2mem.c */
extern Bit8 Fc3ReadBit8(/*addr*/);		/* read an 8-bit quantity */
extern Bit16 Fc3ReadBit16(/*addr*/);		/* read a 16-bit quantity */
extern Bit32 Fc3ReadBit32(/*addr*/);		/* read a 32-bit quantity */
extern void Fc3WriteBit8(/*addr, value*/);	/* write an 8-bit quantity */
extern void Fc3WriteBit16(/*addr, value*/);	/* write a 16-bit quantity */
extern void Fc3WriteBit32(/*addr, value*/);	/* write a 32-bit quantity */

/* CPU Layer (Architecure manual, chapter 4) */
/* Addresses and formats for various things in "function code 3" space.
 *  These are accessed using the MOVS instruction with the
 *  value 3 in the function code registers */

#define SPACE(space)(space<<28)

/* - MMU entries for virtual address v in the current address space */
#define PageMapAddr(v)		(SPACE(0x1)|(((Bit32)(v))&0x0fffe000))
#define SegMapAddr(v)		(SPACE(0x2)|(((Bit32)(v))&0x0ffe0000))
#define CONTEXT_REGISTER	SPACE(0x3)

/* MMU hardware characteristics (manual, chapter 4) */

/* Size of a page, a segment, and a context (address space) */
#define PAGE_SIZE	0x2000		/*   8 Kbytes */
#define SEG_SIZE	0x20000		/* 128 Kbytes */
#define CONTEXT_SIZE	0x10000000	/* 256 Mbytes */

#define NUM_CONTEXTS	8		/* Total number of contexts */
#define	NUM_PMEGS	256		/* Number of PMEGs available */

#define SEGS_PER_CTX	(CONTEXT_SIZE/SEG_SIZE)	/*  */
#define PGS_PER_SEG	(SEG_SIZE/PAGE_SIZE)	/*  */

/* - Structure of the context register */
typedef Bit8 ContextRegister;

/* For LRU segment map swapping */
#define MAP_NOT_RESIDENT 0xff	/* an invalid context register value */
#define GetAddressableTeam() AddressableTeam
extern struct _TD *AddressableTeam;

/* - Segment map entry */
typedef Bit8 SegMapEntry;

/* - Page map entry */
typedef union
  {
    /* Fields */
    struct
      {
        Bit32 valid:1;		/* 1 = Valid page */
	Bit32 protection:3;	/* write, system, dont_cache */
	Bit32 type:2;		/* Page type; see below */
	Bit32 accessed:1;	/* Page has been accessed */
	Bit32 modified:1;	/* Page has been modified */
	Bit32 reserved:5;
	Bit32 pagenum:19;	/* Page number (physical address) */
      }
    f;
    Bit32 u;	/* Whole thing as an unsigned integer */
  }
PageMapEntry;
	
/* Protection bits */
#define PAGE_WRITE	0x4
#define SUPER_ONLY	0x2
#define	DONT_CACHE	0x1

/* Page types */
#define ONBOARD_MEM	0	/* "Onboard" (P2 bus) */
#define ONBOARD_IO	1	/* Onboard devices */
#define VME_16		2	/* VMEbus 16 bit data space */
#define VME_32		3	/* VMEbus 32 bit data space */

/* - Structure of a virtual address */
typedef union
  {
    /* Fields */
    struct
      {
	Bit32	unused:4;
	Bit32	segment:11;	/* Segment number */
	Bit32	page:4;		/* Page number within segment */
	Bit32	byte:13;	/* Byte number */
      }
    f;
    char *p;		/* Whole thing as a character pointer */
    Bit32 u;		/* Whole thing as an unsigned 32-bit quantity */
  }
VirtualAddress;

/* Extract the page number (for the pagenum field of a page table entry)
 *   from a physical address */
#define ExtractPageNumber(p) ((p)>>13)	/* effectively same as p%PAGE_SIZE */
/* Extract the segment number from an address */
#define ExtractSegNumber(p) ((p)>>17)	/* effectively same as p%SEG_SIZE */

/* Page map entry used to indicate an unmapped page.  Note that the 
 * valid bit is not set!
 */
#define NULL_PAGE 0

/* Segment map entry used to indicate an unused segment.  This pmeg
 *   is filled with NULL_PAGE page entries.
 */
#define NULL_PMEG (NUM_PMEGS-1)

/* Round an address up to the nearest page boundary */
#define uptopage(addr)\
  ( ((((Bit32) (addr)) - 1) & (~(PAGE_SIZE-1))) + PAGE_SIZE )
/* Round an address up to the nearest segment boundary */
#define uptoseg(addr)\
  ( ((((Bit32) (addr)) - 1) & (~(SEG_SIZE-1))) + SEG_SIZE )
/* Round an address down to the nearest page boundary */
#define downtopage(addr)\
  ( ((Bit32) (addr)) & ~(PAGE_SIZE-1) )
/* Round an address down to the nearest segment boundary */
#define downtoseg(addr)\
  ( ((Bit32) (addr)) & ~(SEG_SIZE-1) )

/* Read and write MMU registers */
#define SetPageMap(addr, value)\
  Fc3WriteBit32(PageMapAddr(addr), (Bit32)(value))
#define SetSegMap(addr, value)\
  Fc3WriteBit8(SegMapAddr(addr), (Bit8)(value))
#define GetPageMap(addr)\
  Fc3ReadBit32(PageMapAddr(addr))
#define GetSegMap(addr)\
  Fc3ReadBit8(SegMapAddr(addr))
#define SetContext(cxt)\
  Fc3WriteBit8(CONTEXT_REGISTER, (Bit8)(cxt))
#define GetContext(cxt)\
  (cxt) = Fc3ReadBit8(CONTEXT_REGISTER)
#define GetBusErrorReg()\
  Fc3ReadBit8(BUS_ERROR_REGISTER)

/* - Identification PROM (read only)*/
#define IDP SPACE(0x0)
#define IDP_FORMAT		0	/* format byte */
#define IDP_MACHINE_TYPE	1	/* machine type byte */
#define IDP_ENET_ADDRESS	2	/* start of Enet address (6 bytes) */
#define IDP_DATE		8	/* start of manuf. date (4 bytes) */
#define IDP_SERIAL_NUMBER	12	/* start of serial number (3 bytes) */
#define IDP_CHECKSUM		15	/* checksum (1 byte) */
#define IDP_RESERVED		16	/* reserved field (16 bytes) */

/* System Enable register (8 bits, read/write) */
#define SYSTEM_ENABLE_REGISTER	SPACE(0x4)
typedef union
  {
    struct
      {
	Bit8 enableBoot:1;	/* 0 = boot ; 1 = normal */
	Bit8 enableFPP:1;	/* enable floating point coprocessor */
	Bit8 enableDVMA:1;	/* enable VME DVMA */
	Bit8 enableCache:1;	/* enable external cache */
	Bit8 enableVideo:1;	/* enable video output to monitor */
	Bit8 enableCopy:1;	/* enable copy update mode to monitor */
	Bit8 enableFPA:1;	/* enable floating point accelerator */
	Bit8 diag:1;		/* State of diagnostic switch */
      } f;
    Bit8 u;
  }
SystemEnableRegister;

#define DVMA_ENABLE_REGISTER	SPACE(0x5)
typedef union
  {
    struct
      {
	Bit8 enable7:1;		/* Enable DVMA to context 7 */
	Bit8 enable6:1;
	Bit8 enable5:1;
	Bit8 enable4:1;
	Bit8 enable3:1;
	Bit8 enable2:1;
	Bit8 enable1:1;
	Bit8 enable0:1;		/* Enable DVMA to context 0 */
      }
    f;
    Bit8 u;
  }
DVMAEnableRegister;

/* - Bus error register (16 bits, read only) */
#define BUS_ERROR_REGISTER	SPACE(0x6)
typedef union
  {
    struct
      {
	Bit8 invalid:1;		/* Access to an invalid address */
	Bit8 protection:1;	/* Protection violation */
	Bit8 timeout:1;		/* Bus timeout (on and off board) */
	Bit8 VMEbus:1;		/* VMEbus access error */
	Bit8 FPAbus:1;		/* FPA error (FPA doesn't interrupt) */
	Bit8 FPAenable:1;	/* Access to FPA when en.fpa = 0 */
	Bit8 unused:1;
        Bit8 watchdog:1;	/* Watchdog or User reset (optional) */
      }
    f;
    Bit8 u;			/* Whole thing as an unsigned quantity */
  }
BusErrorRegister;

/* - Diagnostic LED register (1 byte, write only) */
#define DIAGNOSTIC_REGISTER	SPACE(0x7)

/*
 * Physical addresses for things in onboard memory space
 *   These are addressed through page map entries of type ONBOARD_MEM.
 */
#define P_ONBOARD_RAM		0
#define P_ONBOARD_RAM_LIMIT	0x800000	/* No more than 8 Mbytes (?)*/
#define P_BW_FRAMEBUFFER	0xFF000000	/* "new" frame buffer */

/* Addresses for things in onboard mappable device space
 *   These are addressed through page map entries of type ONBOARD_IO.
 */
#define P_KBD_MOUSE_UART	0x00000000
#define P_SERIAL_PORT		0x00020000
#define P_EEPROM		0x00040000
#define P_REAL_TIME_CLOCK	0x00060000
#define P_MEMORY_ERROR_REGS	0x00080000
#define P_INTERRUPT_REG		0x000A0000
#define P_INTEL_ETHERNET	0x000C0000
#define P_COLOR_MAP		0x000E0000
#define P_EPROM			0x00100000
#define P_AMD_ETHERNET		0x00120000
#define P_SCSI			0x00140000
#define P_IOX			0x001A0000
#define P_ENCRYPTION_CHIP	0x001C0000

#define P_VME_16		0xFFFFE000	/* added by rgb@rice 6/26/86 */

/* Conventional virtual addresses.
 */
#define KERNEL_START	0x2000		/* Kernel is loaded at this address */
#define KERNEL_LIMIT	0x20000		/* end of kernel */
#define TEAM_START 	KERNEL_LIMIT	/* Start of team space */
#define TEAM_LIMIT	0x0FE00000	/* Team size limit */
#define STACK		0x0FF40000
#define XFERSEG		0x0FF60000	/* Used by kernel for moving things */
#define TEAM_SEG	0x0FF80000	/* 128k for team descriptors */
#define PD_SEG		0x0FFA0000	/* 128k for process descriptors */
#define PROFILESEG	0x0FFC0000	/* 128k for profile data */
#define ENET_DATA_SEG   0x0FFE0000	/* 128k for buffer/data space */
#define TESTPAGE	ENET_DATA_SEG

#define V_SUN3_FRAMEBUFFER	0x0FE20000
#define SUN3_FRAMEBUFFER_SIZE	0x020000
#define V_KBD_MOUSE_UART	0x0FE00000
#define V_SERIAL_PORT		0x0FE02000
#define V_EEPROM		0x0FE04000
#define V_REAL_TIME_CLOCK	0x0FE06000
#define V_MEMORY_ERROR_REGS	0x0FE08000
#define V_INTERRUPT_REG		0x0FE0A000
#define V_INTEL_ETHERNET	0x0FE0C000
#define V_COLOR_MAP		0x0FE0E000
#define V_AMD_ETHERNET		0x0FE12000
#define V_SCSI			0x0FE14000
#define V_IOX			0x0FE1A000
#define V_ENCRYPTION_CHIP	0x0FE1C000
#define V_VME_16		0x0FE68000	/* added by rgb@rice 6/26/86 */
#define V_EPROM			0x0FEF0000

/*
 * The virtual starting address of the DVMA segment is where the SUN3
 * hardware reference manual manual says VME addresses are mapped during DVMA
 * operations (at or around page 44).  The physical DVMA starting address
 * happens to be zero because of the way VME addresses are mapped to
 * virtual addresses.
 */
#define P_DVMA_START	0
#define DVMA_SEG1	0x0FF00000
#define DVMA_SEG2	0x0FF20000
#define V_DVMA_START	0x0FF00000	/* Virtual address of DVMA space */
#define V_DVMA_LIMIT	0x0FF40000

/* end conventional addresses */

/* data structures for memory error registers */
typedef union
  {
    struct
      {
	Bit32 DVMAcycle:1;	/* Error occurred during a dvma cycle */
	Bit32 context:3;	/* Context register value at error time */
	Bit32 address:28;	/* Virtual address of error reference */
      }
    f;
    Bit32 u;
  }
MemoryErrorAddressRegister;

typedef union
  {
    struct
      {
	Bit8 pending:1;		/* Parity interrupt pending */
	Bit8 enable:1;		/* Enable parity check interrupts */
	Bit8 test:1;		/* Invert parity bit to test circuitry */
	Bit8 check:1;		/* Enable parity checking */
	Bit8 bytes:4;		/* Bytes within word that failed check */ 
      }
    f;
    Bit8 u;
  }
ParityMemoryErrorControlRegister;

typedef union
  {
    struct
      {
	Bit8 pending:1;		/* Parity interrupt pending */
	Bit8 enable:1;		/* Enable parity check interrupts */
	Bit8 bushold:1;		/* Hold memory bus mastership */
	Bit8 recording:1;
	Bit8 wbtimeout:1;	/* Writeback failure */
	Bit8 wberror:1;		/* Writeback error */
	Bit8 uncorrectable:1;
	Bit8 correctable:1;	/* See manual */
      }
    f;
    Bit8 u;
  }
ECCMemoryErrorControlRegister;

typedef struct
  {
    unsigned char control;
    unsigned char unused[3];
    unsigned long address; 
  }
MemoryErrorRegister;

/* Interrupt enable register control strcuture */
typedef struct
  {
    Bit8 enableInt7:1;		/* NMI - caught by chip */
    Bit8 enableInt6:1;		/* Serial chips (including mouse/keyboard) */
    Bit8 enableInt5:1;		/* 100Hz timer */
    Bit8 enableInt4:1;		/* Video */
    Bit8 enableInt3:1;		/* Ethernet */
    Bit8 enableInt2:1;
    Bit8 enableInt1:1;
    Bit8 enableInt:1;		/* Master interrupt enable */
  }
InterruptRegister;


/* Modes for Probe() function -- see memory.c */
#define PROBE_READ 1
#define PROBE_INIT 2
#define PROBE_PRESERVE 3

#endif
27333!Funky!Stuff!
echo x - kernel/sun3+le/buildfile
cat > kernel/sun3+le/buildfile << '27333!Funky!Stuff!'
#
# Buildfile for V kernel
# sun3+le version
# Dave Johnson 6-28-86
#

CONFIG= sun3+le

MI= ../mi
HOST= ../m68k
HOST2= m68k
VINCL= ../../libc/include
INCLPATH= -I. -I$(HOST) -I$(MI) -I$(VINCL)/$(HOST2) -I$(VINCL)/mi
C68FLAGS = -O -$(Xx)V -DMC68000 -DMC68010 -DMC68020 -DENET10MEG -DSUN2 -DSUN3 $(INCLPATH)
LD68FLAGS = -T 2000

MIOBJECTS= $(COMMONMI)

MDOBJECTS= $(COMMONMD) sun3mem.b smimouse.b enetle.b z8530scc.b intersil7170.b

MDLIBS= ../../libc/rawio/m68k/sun3rawio.b

#include ../m68k/buildtemplate

#include dependencies
27333!Funky!Stuff!
echo x - kernel/sun3+le/config.h
cat > kernel/sun3+le/config.h << '27333!Funky!Stuff!'
/*
 * V Kernel - Copyright (c) 1982 by David Cheriton
 * (Transliterated from Zed and Verex Kernel)
 *
 * Configuration Parameters for the Kernel: sun2+ec
 */

#ifndef CONFIG
#define CONFIG

#include "Vio.h"
#include "Vdirectory.h"

#define PID_HASH_MASK 0x3f	/* Size of pid hash table - 1 */
#define MAX_TEAMS 16		/* Maximum number of teams */
#define MAX_LOGICAL_ID	40	/* Maximum logical id for GetPid and SetPid */
#define ROOT_PRIORITY 4		/* Priority of first created process */
#define INIT_STACK 0x2000	/* Size of initial stack for root team */

#define HOST_CACHE_SIZE 64	/* Number of logical host to net address
				 *  mappings kept in our cache */
#define HOST_CACHE_SHIFT 26	/* 32 - log_sub_2(HOST_CACHE_SIZE) */

/*
 * Kernel device configuration declarations.
 */

#define MAX_DEVICES	16		/* Size of device instance table.
					 *  Must be a power of 2 */
#define DEV_DIR_SIZE	11		/* Size of device directory */

typedef struct
  {
    DeviceDescriptor	d;
    SystemCode		(*CreateFunc)();
    SystemCode		(*NModifyFunc)();
    SystemCode		(*NQueryFunc)();
  } 
KernelDeviceDescriptor;

#endif
27333!Funky!Stuff!
echo x - kernel/sun3+le/dependencies
cat > kernel/sun3+le/dependencies << '27333!Funky!Stuff!'
27333!Funky!Stuff!
echo x - libc/include/mi/Vquerykernel.h
cat > libc/include/mi/Vquerykernel.h << '27333!Funky!Stuff!'
/*
 * Distributed V Kernel
 * Copyright (c) 1983 by Stanford University, all rights reserved.
 *
 * QueryKernel operation manifests and types.
 */

#ifndef QKERNEL
#define QKERNEL

/* Request message format */

typedef struct
  {
#ifndef LITTLE_ENDIAN
    unsigned short requestcode;		/* must be QUERY_KERNEL */
    unsigned short groupSelect;
#else LITTLE_ENDIAN
    unsigned short groupSelect;
    unsigned short requestcode;
#endif LITTLE_ENDIAN
    ProcessId pid;
    unsigned filler[6];
  } 
QueryKernelRequest;


/* Group selection codes */
#define MACHINE_CONFIG		1
#define PERIPHERAL_CONFIG	2
#define MEMORY_STATS		3
#define KERNEL_CONFIG		4
#define KERNEL_STATS		5
#define LOGICAL_HOST_QUERY	6  /* Check if given logical host is local. */

/* Machine configuration group */

typedef struct
  {
#ifndef LITTLE_ENDIAN
    unsigned short replycode;
    unsigned short filler;
    unsigned char processor;	/* Processor type code */
    unsigned char machine;	/* Machine type code */
    unsigned short confreg;	/* Config register contents, if applicable */
    unsigned memory;		/* Bytes of physical memory (total) */
    unsigned fastMemory;	/* For SUN, bytes of onboard memory */
    unsigned slowMemory;	/* For SUN, bytes of multibus mem */
    unsigned reserved[3];
#else LITTLE_ENDIAN
    unsigned short filler;
    unsigned short replycode;
    unsigned short confreg;	/* Config register contents, if applicable */
    unsigned char machine;	/* Machine type code */
    unsigned char processor;	/* Processor type code */
    unsigned memory;		/* Bytes of physical memory (total) */
    unsigned fastMemory;	/* For SUN, bytes of onboard memory */
    unsigned slowMemory;	/* For SUN, bytes of multibus mem */
    unsigned reserved[3];
#endif LITTLE_ENDIAN
  }
MachineConfigurationReply;

/* - Processor types */
#define PROC_FAMILY		0xF0	/* mask to see family */
#define PROC_LITTLE_ENDIAN	0x10	/* odd families are little-endian */
#define PROC_FAM_68000		0x00	/* MC68000 family */
#define PROC_MC68000		0x01
#define PROC_MC68008		0x02
#define PROC_MC68010		0x03
#define PROC_MC68012		0x04
#define PROC_MC68020		0x05
#define PROC_MC68030		0x06
#define PROC_FAM_VAX11		0x10	/* VAX family */
#define PROC_VAX11_725		0x12
#define PROC_VAX11_730		0x14
#define PROC_VAX11_750		0x16
#define PROC_VAX11_780		0x18
#define PROC_VAX11_782		0x1A
#define PROC_UVAX2		0x1C
#define PROC_UVAX1		0x1E

#define NUM_PROC_FAMILIES	2
#define PROC_FAMILY_SHIFT	4

/* - General machine types
 *     Not quite the same thing as processor type.
 *     We distinguish Vax models by processor type,
 *     while various 68000-family-based machines may
 *     use the same processor chip, but have different MMU's, etc.
 */	
#define MACH_STANFORD_SUN	1
#define MACH_CADLINC_SUN	2
#define MACH_SMI_SUN1		3
#define MACH_SMI_SUN15		4	/* Sun 1.5 */
#define MACH_SMI_SUN2		5
#define MACH_IRIS		6
#define MACH_FORWARD_SUN	7	/* Forward Tech Gateway Series */
#define MACH_SMI_SUN3		8
#define MACH_VAX		10


/*  Peripheral group */
/*  - Warning: peripheral codes are not guaranteed to be packed densely
 *    into the array in the reply message -- there can be gaps, filled
 *    in by PRF_NONE codes.  (This is because of byte-ordering problems).
 *    So it is NOT correct to stop at the first PRF_NONE when searching the
 *    array for a particular code.
 */
#define MAX_PERIPHERALS 28  /* just enough to fill up the message */
typedef struct
  {
#ifndef LITTLE_ENDIAN
    unsigned short replycode;
    unsigned short filler;
#else LITTLE_ENDIAN
    unsigned short filler;
    unsigned short replycode;
#endif LITTLE_ENDIAN
    unsigned char peripheral[MAX_PERIPHERALS];
  }
PeripheralConfigurationReply;

/* - Filler for unused array positions*/
#define PRF_NONE		0

/* - Console keyboards */
#define PRF_CONSOLE_CADLINC	1
#define PRF_CONSOLE_SMI100	2
#define PRF_CONSOLE_TERMINAL	3
#define PRF_CONSOLE_SMI120	4
#define PRF_CONSOLE_SMI3	4		/* Sun-3 keyboard */
/* - Mice */
#define PRF_MOUSE_CADLINC	10
#define PRF_MOUSE_SMI100	11
#define PRF_MOUSE_IRIS		12
#define PRF_MOUSE_SMI120	13
#define	PRF_MOUSE_QVSS		14
/* - Ethernet boards */
#define PRF_ENET_3MBIT		20		/* 3 meg ethernet */
#define PRF_ENET_3COM		21		/* 10 meg ethernet */
#define PRF_ENET_EXCELAN	22
#define PRF_ENET_INTERLAN	23
#define PRF_ENET_DEUNA		24
#define PRF_ENET_SMI10		25
#define PRF_ENET_MEIS		26
#define PRF_ENET_DEQNA		27
#define PRF_ENET_SUN50		28
#define PRF_ENET_CMC		29
#define PRF_ENET_SUNIE		28		/* SMI intel82586 chip */
#define	PRF_ENET_LANCE		80		/* SMI AMD 7990 - dbj@rice */

/* - Frame buffer stuff */
#define PRF_FRAMEBUFFER_SMI100	30
#define PRF_FRAMEBUFFER_SMI120	31
#define PRF_FRAMEBUFFER_QVSS	32
#define PRF_FRAMEBUFFER_SUN3	33
/* - Odds and ends */
#define PRF_GPIB_ZIATECH	40
#define PRF_CONFREG		41		/* Has a config register */
/* - Disk controllers */
#define PRF_DISK_INTERPHASE	50		/* Interphase controller */
#define PRF_DISK_XYLOGICS	51		/* Xylogics controller */
#define PRF_DISK_RQDX		52		/* DEC RQDX controller */
/* - Serial ports */
#define PRF_SERIAL_SUNONBOARD	70
#define PRF_SERIAL_SUN8UART	71
#define PRF_SERIAL_SUN16UART	72
#define PRF_SERIAL_VAXDZ11	73
#define PRF_SERIAL_QVSS		74
/* - For historical compatibility */
#define PRF_CADLINC_KEYBOARD	PRF_CONSOLE_CADLINC
#define PRF_SMI100_KEYBOARD	PRF_CONSOLE_SMI100
#define PRF_ASCII_TERMINAL	PRF_CONSOLE_TERMINAL
#define PRF_SMI120_KEYBOARD	PRF_CONSOLE_SMI120
#define PRF_FRAMEBUFFER_SUN1	PRF_FRAMEBUFFER_SMI100
#define PRF_FRAMEBUFFER_SUN2	PRF_FRAMEBUFFER_SMI120
#define PRF_CADLINC_MOUSE	PRF_MOUSE_CADLINC
#define PRF_SMI100_MOUSE	PRF_MOUSE_SMI100
#define PRF_IRIS_MOUSE		PRF_MOUSE_IRIS
#define PRF_SMI120_MOUSE	PRF_MOUSE_SMI120


/* Memory statistics group */

typedef struct
  {
#ifndef LITTLE_ENDIAN
    unsigned short replycode;
    unsigned short filler;
#else LITTLE_ENDIAN
    unsigned short filler;
    unsigned short replycode;
#endif LITTLE_ENDIAN
    unsigned unusedFastMemory;		/* How much unused real memory */
    unsigned unusedSlowMemory;
    unsigned reserved[5];
  }    
MemoryStatisticsReply;


/* Kernel configuration group */

typedef struct
  {
#ifndef LITTLE_ENDIAN
    unsigned short replycode;
    unsigned short ikcType;		/* See below */
    unsigned short maxProcesses;	/* Max number of processes */
    unsigned short maxTeams;		/* Max number of teams */
    unsigned short maxLogicalId;	/* Max logical pid */    
    unsigned short rootPriority;	/* Priority of root process */
    unsigned short initStack;		/* Root process initial stack size */
    unsigned short vmConfig;		/* See below */
    unsigned short versionNumber;	/* Printed as "#xxx" while booting */
    unsigned short reserved[7];
#else LITTLE_ENDIAN
    unsigned short ikcType;		/* See below */
    unsigned short replycode;
    unsigned short maxTeams;		/* Max number of teams */
    unsigned short maxProcesses;	/* Max number of processes */
    unsigned short rootPriority;	/* Priority of root process */
    unsigned short maxLogicalId;	/* Max logical pid */    
    unsigned short vmConfig;		/* See below */
    unsigned short initStack;		/* Root process initial stack size */
    unsigned short versionNumber;	/* Printed as "#xxx" while booting */
    unsigned short reserved[7];
#endif LITTLE_ENDIAN
  }
KernelConfigurationReply;

/* - IKC type */
#define IKC_NONE	0	/* No ikc -- local kernel only */
#define IKC_3MBIT	3	/* ikc on 3 Mbit ethernet */
#define IKC_10MBIT	10	/* ikc on 10 Mbit ethernet */

/* - Virtual Memory configuration */
#define	VM_NONE		0	/* No virtual memory */
#define VM_PRESENT	1	/* Yes, virtual memory available */



/* Kernel statistics group */

typedef struct
  {
#ifndef LITTLE_ENDIAN
    unsigned short replycode;
    unsigned short freePds;	/* How many free process descriptors */
    unsigned short freeTds;	/* How many free team descriptors */
    unsigned short alienCount;	/* How many aliens exist */
#else LITTLE_ENDIAN
    unsigned short freePds;	/* How many free process descriptors */
    unsigned short replycode;
    unsigned short alienCount;	/* How many aliens exist */
    unsigned short freeTds;	/* How many free team descriptors */
#endif LITTLE_ENDIAN
    ProcessId delayQueueHead;	/* Process at head of delay queue */
    int numRetrans;		/* Number of retransmissions - dbj@rice */
    unsigned reserved[4];
  }
KernelStatisticsReply;

#endif QKERNEL
27333!Funky!Stuff!
echo x - standalone/Vload/m68k/enetle.c
cat > standalone/Vload/m68k/enetle.c << '24392!Funky!Stuff!'
#define	DEBUG

/*
 * Distributed V Kernel 
 *
 * Vload Ethernet driver for AMD 7990 LANCE Ethernet controller chip.
 *
 * David B. Johnson, Dept. of Computer Science, Rice University.
 */

#include "Venviron.h"
#include "Vikc.h"
#include "process.h"
#include "Vethernet.h"
#include "enetle.h"
#include "sun3mem.h"

/*
 *  The driver coordinates its uses of the LANCE's Register Address Port
 *  (RAP) so that CSR0 is normally always available without changing the
 *  RAP.  The only use made of the other CSRs is during initialization,
 *  and the RAP is reset to select CSR0 at the end of the initialization.
 *
 *  If any other accesses to the CSR1, CSR2, or CSR3 become necessary,
 *  the RAP should be changed to select that register, the access can
 *  then be made, and the RAP should then be changed back to select CSR0.
 *  Be careful that the driver is not reentered during this sequence
 *  since somebody else could change the RAP out from under you.
 */

#ifdef SUN3
#define MAXLOOPCOUNT 0x800000
#else
#define MAXLOOPCOUNT 0x100000
#endif

#ifdef DEBUG
#define debug(c) K_putchar(c)
#else
#define debug(c)
#endif DEBUG

#define CopyMsg(to, from) CopyBytes(to, from, sizeof(MsgStruct))

/* Exports */
extern SystemCode EnetPowerup();
extern SystemCode AwaitKernelPacket();
extern int WriteKernelPacket();
int KernelPacketType = V_KERNEL_PACKET;
char HexEnetAddress[sizeof(NetAddress)*2 + 1];

NetAddress	EnetHostNumber;		/* physical ethernet address */
short		EnetCollisions = 0;	/* Number of collision errors */
EnetBlock	*EnetPacket;
kPacketWithSegment
		*kPacketSave;		/* Save area for kernel packets */

NetAddress	ServerHostAddress;	/* A one-address "cache" */
int		ServerLogicalHost = -1;

NetAddress	BroadcastAddress = { 0xFFFF, 0xFFFF, 0xFFFF };

/*
 *  Define names to access the LANCE's Register Data Port and
 *  Register Address Port.
 */
#ifdef	notdef
#define	rdp	(*(unsigned short *)(V_AMD_ETHERNET+0))
#define	rap	(*(unsigned short *)(V_AMD_ETHERNET+2))
#else	notdef
#define	rdp	(*(unsigned short *)(0xfe10000+0))
#define	rap	(*(unsigned short *)(0xfe10000+2))
#endif	notdef

#define RECEIVE_BUFFERS		32
#define	RECEIVE_BUFFERS_POWER	5

#define TRANSMIT_BUFFERS	1
#define	TRANSMIT_BUFFERS_POWER	0

/*
 *  The control block segment for the LANCE chip.  This segment
 *  actually lives in a 128k block allocated by the kernel for
 *  Ethernet buffer/data space.
 */
struct ControlBlockSegment
  {
    struct InitializationBlock init;
    struct ReceiveMessageDescriptor rmd[RECEIVE_BUFFERS];
    struct TransmitMessageDescriptor tmd;
  };
#define cbsp	((struct ControlBlockSegment *) ENET_DATA_SEG)
#define	rbuf	((char *)(ENET_DATA_SEG + \
			sizeof(struct ControlBlockSegment)))
#define	tbuf	((char *)(ENET_DATA_SEG + \
			sizeof(struct ControlBlockSegment) + \
			(RECEIVE_BUFFERS * LE_MAX_PACKET)))

int rbufnum = 0;		/* number of current rbuf */

/*
 *  Powerup and initialize the Ethernet Interface Board.
 */
SystemCode EnetPowerup()
  {
    register struct InitializationBlock *init = &cbsp->init;
    register int i;
    register unsigned long bufp;
    register char *p, *q;
    PageMapEntry pme;
    extern Process *Active;

    /*
     *  Set up the page protections so that we can access the necessary pages
     *  of the Ethernet buffer/data space.
     */
#ifdef	notdef
    for (bufp = ENET_DATA_SEG; bufp < (unsigned long)(tbuf + LE_MAX_PACKET);
	bufp += PAGE_SIZE)
      {
	pme.u = GetPageMap(bufp);
printf("GetPageMap bufp = %x, pme.u = %x\n", bufp, pme.u);
	pme.f.protection = SUPER_ONLY|PAGE_WRITE;
printf("SetPageMap bufp = %x, pme.u = %x\n", bufp, pme.u);
	SetPageMap(bufp, pme.u);
      }
#else	notdef
    for (i = 0; i < 8; i++)
	SetPageMap(ENET_DATA_SEG + (i * PAGE_SIZE), 0xC30001F8 + i);
#endif	notdef

    /*
     *  Reset the chip.
     */
    rap = LE_RAP_CSR0;
    rdp = LE_CSR0_STOP;

    /*
     * Get the SMI Ethernet address from the ID PROM.
     */
    p = (char *) &EnetHostNumber;
    for (i = IDP_ENET_ADDRESS;
	i < IDP_ENET_ADDRESS + sizeof(EnetHostNumber); i++)
	*p++ = Fc3ReadBit8(i);

    /*
     *  Convert the Ethernet address to hex for use elsewhere.
     */
    p = (char *) &EnetHostNumber;
    q = HexEnetAddress;
    for (i=0; i<sizeof(EnetHostNumber); i++)
      {
	*q++ = MakeHexDigit((*p)>>4);
        *q++ = MakeHexDigit(*p++);
      }
    *q = '\0';

    /*
     *  Make a fake pid for the loader process.
     */
    Active->pid = ((K_ticks() << 16) + 0xbead) &
	~(LITTLE_ENDIAN_HOST | GROUP_ID_BIT);

    /*
     *  Initialize the Initialization Block.
     */
    init->mode = 0;	/* no special modes */
    init->padr[0] = (unsigned char)(EnetHostNumber.addrhigh & 0xff);
    init->padr[1] = (unsigned char)(EnetHostNumber.addrhigh >> 8);
    init->padr[2] = (unsigned char)(EnetHostNumber.addrmid & 0xff);
    init->padr[3] = (unsigned char)(EnetHostNumber.addrmid >> 8);
    init->padr[4] = (unsigned char)(EnetHostNumber.addrlow & 0xff);
    init->padr[5] = (unsigned char)(EnetHostNumber.addrlow >> 8);
    for (i = 0; i < sizeof(init->ladrf); i++)
	init->ladrf[i] = 0;	/* no need for multicast now */
    bufp = (unsigned long)(cbsp->rmd);
    init->rdrp.low = (unsigned short)(bufp & 0xffff);
    init->rdrp.high = (unsigned short)(((bufp >> 16) & 0xff) |
	(RECEIVE_BUFFERS_POWER << LE_DRP_LEN_SHIFT));
    bufp = (unsigned long)(&cbsp->tmd);
    init->tdrp.low = (unsigned short)(bufp & 0xffff);
    init->tdrp.high = (unsigned short)(((bufp >> 16) & 0xff) |
	(TRANSMIT_BUFFERS_POWER << LE_DRP_LEN_SHIFT));

    /*
     *  Initialize the Buffer Descriptors.  The space pointed to by the
     *  descriptors is located above the control block segment in the
     *  Ethernet buffer/data space.  The buffers are allocated contiguously
     *  with the receive buffers before the single transmit buffer.
     */
    bufp = (unsigned long)rbuf;
    for (i = 0; i < RECEIVE_BUFFERS; i++, bufp += LE_MAX_PACKET)
      {
      	cbsp->rmd[i].ladr = (unsigned short)(bufp & 0xffff);
      	cbsp->rmd[i].flags = LE_RMD_OWN;	/* owned by LANCE */
      	cbsp->rmd[i].hadr = (unsigned char)((bufp >> 16) & 0xff);
      	cbsp->rmd[i].bcnt = -LE_MAX_PACKET;
      	cbsp->rmd[i].mcnt = 0;
      }
    bufp = (unsigned long)tbuf;
    cbsp->tmd.ladr = (unsigned short)(bufp & 0xffff);
    cbsp->tmd.flags = 0;		/* owned by CPU */
    cbsp->tmd.hadr = (unsigned char)((bufp >> 16) & 0xff);
    cbsp->tmd.bcnt = -LE_MAX_PACKET;
    cbsp->tmd.status = 0;

    /*
     *  Load up the address of the Initialization Block.
     */
    rap = LE_RAP_CSR1;
    rdp = (unsigned short)(((unsigned long)(&cbsp->init)) & 0xffff);
    rap = LE_RAP_CSR2;
    rdp = (unsigned short)((((unsigned long)(&cbsp->init)) >> 16) & 0xff);

    /*
     *  Initialize the flag bits in CSR3.
     */
    rap = LE_RAP_CSR3;
    rdp = LE_CSR3_BSWP;		/* do byte swapping */

    /*
     *  Crank it up and let it go.  We must wait for the initialization
     *  to complete on the chip.
     */
    rap = LE_RAP_CSR0;
    rdp = LE_CSR0_INIT | LE_CSR0_STRT;
    while ((rdp & LE_CSR0_IDON) == 0)
	;
    rdp = LE_CSR0_IDON;		/* turn off IDON */

    return( OK );
 }

/*
 *  Wait until a valid kernel packet is received.  Return
 *  TIMEOUT if we time out before getting one.
 */
SystemCode
AwaitKernelPacket()
  {
    register int	loopcount;
    register struct ReceiveMessageDescriptor *rmdp = &cbsp->rmd[rbufnum];

    if ((rmdp->flags & LE_RMD_OWN) == 0)	/* still owned by CPU */
      {
	rmdp->flags = LE_RMD_OWN;	/* give back to LANCE */
	if (++rbufnum == RECEIVE_BUFFERS) rbufnum = 0;
	rmdp = &cbsp->rmd[rbufnum];
      }

    /*
     *  Wait for a valid kernel packet to arrive, but don't wait too long.
     */
    for (loopcount = MAXLOOPCOUNT; --loopcount != 0; )
      {
	if (rdp & LE_CSR0_MISS)
	    rdp = LE_CSR0_MISS;
	if (rmdp->flags & LE_RMD_OWN)
	    continue;		/* still owned by LANCE */
	if (rdp & LE_CSR0_RINT)
	    rdp = LE_CSR0_RINT;	/* turn off RINT bit just to be tidy */

if ((rmdp->flags & (LE_RMD_STP|LE_RMD_ENP)) != (LE_RMD_STP|LE_RMD_ENP) ||
(rmdp->flags & LE_RMD_ERR)) K_putchar('r'), hexprint(rmdp->flags);

	/*
	 *  We have a valid packet.  Check to see if it is a V kernel
	 *  packet, and if so, return OK.  Otherwise, just go around the
	 *  loop again waiting for another packet.
	 */
	EnetPacket = (EnetBlock *)(rbuf + rbufnum * LE_MAX_PACKET);
	if (EnetPacket->EtherType == KernelPacketType)
	  {
	    kPacketSave = (kPacketWithSegment *)EnetPacket->data;
	    ServerHostAddress = EnetPacket->SrcHost;
	    if (DifferentIKCByteOrder(kPacketSave))
	      {
		SwapIKPacket(kPacketSave);
	      }
	    kPacketSave->packetType &= ~IKC_LITTLE_ENDIAN;
	    ServerLogicalHost = (kPacketSave->srcPid)>>16;
	    return (OK);
	  }
	rmdp->flags = LE_RMD_OWN;
	if (++rbufnum == RECEIVE_BUFFERS) rbufnum = 0;
	rmdp = &cbsp->rmd[rbufnum];
      }

    return (TIMEOUT);
  }

/*
 *  Write a kernel packet to the Ethernet.
 */
int
WriteKernelPacket(type, srcPid, dstPid, forwarder, length,
    localaddress, remoteaddress, sequenceNo, msg, data)
short type;
ProcessId srcPid, dstPid, forwarder;
unsigned int length;
Unspec *localaddress;
Unspec *remoteaddress;
unsigned short sequenceNo;
MsgStruct *msg;
unsigned char *data;
  {
    register EnetBlock *enetpacket = (EnetBlock *)tbuf;
    register kPacketWithSegment *packet =
		(kPacketWithSegment *)(enetpacket->data);
    register struct TransmitMessageDescriptor *tmdp;

    /*
     *  Fill in the Ethernet packet header.
     */
    if ((dstPid >> 16) == ServerLogicalHost)
        enetpacket->DestHost = ServerHostAddress;
    else
        enetpacket->DestHost = BroadcastAddress;
    enetpacket->SrcHost = EnetHostNumber;
    enetpacket->EtherType = KernelPacketType;

    /*
     *  Fill in the packet with the fields that were passed to us.
     */
    packet->packetType = type & ~IKC_LITTLE_ENDIAN;
    packet->sequenceNo = sequenceNo;
    packet->srcPid = srcPid;
    packet->dstPid = dstPid;
    packet->forwarder = forwarder;
    packet->userNumber = 0;		/* user number */
    packet->length = length;
    packet->localaddress = localaddress;
    packet->remoteaddress = remoteaddress;
    if (msg != NULL)
	CopyMsg(&packet->msg, msg);
    if (data != NULL)
	CopyBytes(packet->data, data, length);

    /*
     *  Tell the LANCE to ship it out.
     */
    tmdp = &cbsp->tmd;
    tmdp->bcnt = -(ENET10_HEADER_SIZE + sizeof(kPacket));
    if (data != NULL) tmdp->bcnt -= length;
    tmdp->status = 0;
    tmdp->flags = LE_TMD_OWN|LE_TMD_STP|LE_TMD_ENP;
    rdp = LE_CSR0_TDMD;			/* tell LANCE to look at descriptor */

    /*
     *  Wait for the transmission to complete.
     */
    while ((rdp & LE_CSR0_TINT) == 0)
	;
    rdp = LE_CSR0_TINT;		/* turn off TINT bit */

if ((tmdp->flags & (LE_TMD_STP|LE_TMD_ENP)) != (LE_TMD_STP|LE_TMD_ENP) ||
(tmdp->flags & LE_TMD_ERR)) K_putchar('t'), hexprint(tmdp->flags),
K_putchar('/'), hexprint(tmdp->status);

    return (OK);
  }

int
ReadDataPacket(bytes, dst)
unsigned bytes; 
unsigned char *dst;
  {
    CopyBytes(dst, kPacketSave->data, bytes);
    return (OK);
  }

int
DiscardDataPacket(bytes)
unsigned bytes;
  {
    return( OK );
  }

hexprint(n)
  register unsigned n;
  {
    register unsigned i, digit;

    n <<= 16;
    for (i = 0; i < 4; i++)
      {
	digit = (n >> 28);
	if (digit > 9) digit += 'a'-10;
	else digit += '0';
	K_putchar(digit);
	n <<= 4;
      }
  }
24392!Funky!Stuff!
echo x - standalone/Vload/m68k/enetle.h
cat > standalone/Vload/m68k/enetle.h << '24392!Funky!Stuff!'
/*
 * V Kernel
 *
 * Ethernet Header for AMD 7990 LANCE Ethernet controller chip.
 *
 * David B. Johnson, Dept. of Computer Science, Rice University.
 */

/*
 *  The LANCE has a Register Address Port (RAP) which is used to select
 *  which of four control/status registers (CSR0, CSR1, CSR2, or CSR3)
 *  is available for reading or writing at the Register Data Port (RDP).
 *  The following values written into the RAP will select the corresponding
 *  CSRs.
 */
#define	LE_RAP_CSR0	0		/* select CSR0 for RDP */
#define	LE_RAP_CSR1	1		/* select CSR1 for RDP */
#define	LE_RAP_CSR2	2		/* select CSR2 for RDP */
#define	LE_RAP_CSR3	3		/* select CSR3 for RDP */

/*
 *  Format of a Descriptor Ring Pointer for the Receive and Transmit
 *  Descriptor Rings.  Each pointer is two words long, where the low word
 *  contains only the low 16 bits of the of the base address of the
 *  Descriptor Ring itself, and the high word contains the high 8 bits of
 *  this address and the length of the ring (the number of entries in the
 *  ring) expressed as a power of two.  This length is shifted up by
 *  LE_DRP_LEN_SHIFT bits within the word.
 */
struct drp {
    unsigned short low;
    unsigned short high;
};
#define	LE_DRP_LEN_SHIFT 13	/* shift count for ring len in high word */

/*
 *  Initialization Block.  This structure is built in memory, and its
 *  address is given to the chip in CSR1 and CSR2 during initialization.
 *  The block will be read by the chip when the INIT bit is then set
 *  in CSR0.
 */
struct InitializationBlock
  {
    unsigned short	mode;		/* chip's operating parameters */
    					/* (see bit definitions below) */
    /*
     *  The bytes within each of the three words of padr must be byte swapped.
     */
    unsigned char	padr[6];	/* physical Ethernet address */

    unsigned char	ladrf[8];	/* logical address filter */
    struct drp		rdrp;		/* receive descriptor ring pointer */
    struct drp		tdrp;		/* transmit descriptor ring poniter */
  };

/*
 *  Mode register bits for the Initialization Block.  For normal operation,
 *  these bits are all 0.
 */
#define LE_MODE_PROM	0x8000		/* promiscuous mode */
#define LE_MODE_INTL	0x0040		/* internal loopback */
#define LE_MODE_DRTY	0x0020		/* disable retry */
#define LE_MODE_COLL	0x0010		/* force collision */
#define LE_MODE_DTCR	0x0008		/* disable transmit CRC */
#define LE_MODE_LOOP	0x0004		/* loopback */
#define LE_MODE_DTX	0x0002		/* disable the transmitter */
#define LE_MODE_DRX	0x0001		/* disable the receiver */

/*
 *  Control and status bits for CSR0.
 *
 *  These behave somewhat strangely, but the net effect is that
 *  bit masks may be written to the register which affect only
 *  those functions for which there is a one bit in the mask.
 *  The exception is the interrupt enable, which must be explicitly
 *  set to the correct value in each mask that is used.
 *
 *  RO  - Read Only, writing has no effect
 *  RC  - Read, Clear.  Writing 1 clears, writing 0 has no effect
 *  RW  - Read, Write.
 *  W1  - Write with 1 only.  Writing 1 sets, writing 0 has no effect.
 *        Reading gives unpredictable data but doesn't hurt anything.
 *  RW1 - Read, Write with 1 only.  Writing 1 sets, writing 0 has no effect.
 */
#define	LE_CSR0_ERR	0x8000		/* error summary (RO) */
#define	LE_CSR0_BABL	0x4000		/* transmitter timeout error (RC) */
#define	LE_CSR0_CERR	0x2000		/* collision error (RC) */
#define	LE_CSR0_MISS	0x1000		/* missed packet (RC) */
#define	LE_CSR0_MERR	0x0800		/* memory error (RC) */
#define	LE_CSR0_RINT	0x0400		/* receiver interrupt (RC) */
#define	LE_CSR0_TINT	0x0200		/* transmitter interrupt (RC) */
#define	LE_CSR0_IDON	0x0100		/* initialization done (RC) */
#define	LE_CSR0_INTR	0x0080		/* interrupt flag (RO) */
#define	LE_CSR0_INEA	0x0040		/* interrupt enable (RW) */
#define	LE_CSR0_RXON	0x0020		/* receiver on (RO) */
#define	LE_CSR0_TXON	0x0010		/* transmitter on (RO) */
#define	LE_CSR0_TDMD	0x0008		/* transmit demand (W1) */
#define	LE_CSR0_STOP	0x0004		/* stop (RW1) */
#define	LE_CSR0_STRT	0x0002		/* start (RW1) */
#define	LE_CSR0_INIT	0x0001		/* initialize (RW1) */

/*
 *  CSR1 is the low 16 bits of the address of the initialization block.
 */

/*
 *  CSR2 is the high 8 bits of the address of the initialization block;
 *          the high 8 bits of the register must be 0.
 */

/*
 *  CSR3 mode bits.
 */
#define	LE_CSR3_BSWP	0x0004		/* byte swap */
#define	LE_CSR3_ACON	0x0002		/* ALE control */
#define	LE_CSR3_BCON	0x0001		/* byte control */

/*
 *  A "ring" of Receive Message Descriptors is pointed to by the rdrp field
 *  of the Initialization Block, where the ring is actually an array of
 *  descriptors viewed by the chip with the first descriptor logically
 *  following the last one in the array.
 */
struct ReceiveMessageDescriptor
  {
    unsigned short	ladr;		/* low order 16 bits of buffer addr */
    unsigned char	flags;		/* flag bits (see below) */
    unsigned char	hadr;		/* high order 8 bits of buffer addr */
    unsigned short	bcnt;		/* buffer byte count */
    					/* (high 4 bits must be 1's) */
    unsigned short	mcnt;		/* message byte count */
					/* (high 4 bits reserved) */
  };

/*
 *  Flag bits for the Receive Message Descriptor.
 */
#define	LE_RMD_OWN	0x80		/* set if buffer owned by LANCE */
#define	LE_RMD_ERR	0x40		/* error summary */
#define	LE_RMD_FRAM	0x20		/* framming error */
#define	LE_RMD_OFLO	0x10		/* overflow error */
#define	LE_RMD_CRC	0x08		/* CRC error */
#define	LE_RMD_BUFF	0x04		/* buffer error */
#define	LE_RMD_STP	0x02		/* start of packet */
#define	LE_RMD_ENP	0x01		/* end of packet */

/*
 *  The Transmit Message Descriptor ring is structured the same as the
 *  Receive Message Descriptor ring, except that it is pointed to by the
 *  tdrp field of the Initialization Block.
 */
struct TransmitMessageDescriptor
  {
    unsigned short	ladr;		/* low order 16 bits of buffer addr */
    unsigned char	flags;		/* flag bits (see below) */
    unsigned char	hadr;		/* high order 8 bits of buffer addr */
    unsigned short	bcnt;		/* buffer byte count */
    					/* (high 4 bits must be 1's) */
    unsigned short	status;		/* transmission status (see below) */
  };

/*
 *  Flag bits for the Transmit Message Descriptor.
 */
#define	LE_TMD_OWN	0x80		/* set if buffer owned by LANCE */
#define	LE_TMD_ERR	0x40		/* error summary */
#define	LE_TMD_MORE	0x10		/* more than one retry needed */
#define	LE_TMD_ONE	0x08		/* exactly one retry needed */
#define	LE_TMD_DEF	0x04		/* defer was necessary */
#define	LE_TMD_STP	0x02		/* start of packet */
#define	LE_TMD_ENP	0x01		/* end of packet */

/*
 *  Status bits for the Transmit Message Descriptor.
 */
#define	LE_TMD_BUFF	0x8000		/* buffer error */
#define	LE_TMD_UFLO	0x4000		/* underflow error */
#define	LE_TMD_LCOL	0x1000		/* late collision */
#define	LE_TMD_LCAR	0x0800		/* loss of carrier */
#define	LE_TMD_RTRY	0x0400		/* failed after 16 retries */
#define	LE_TMD_TDR	0x03ff		/* time domain reflectometry mask */

/*
 *  Maximum length of a LANCE packet in memory.  This is the sum of
 *	   6 bytes	destination Ethernet address
 *	   6 bytes	source Ethernet address
 *	   2 bytes	Ethernet type field
 *	1500 bytes	maximum data field length
 *	   4 bytes	packet CRC
 *
 *  For received packets, the LANCE places all of these fields (including
 *  the CRC) into the buffer in memory.  For transmitting packets, though,
 *  the LANCE suplies the CRC.
 */
#define	LE_MAX_PACKET	1518
24392!Funky!Stuff!
echo x - standalone/Vload/m68k/buildfile
cat > standalone/Vload/m68k/buildfile << '24392!Funky!Stuff!'
#
# Buildfile for V I/O protocol boot
#
# NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
#
# Do you know what you're doing ? Are you sure that you know what you're
# doing ? This set of programs operates under a very special set of
# constraints and normal rules of programming do not always apply.
# Though kludgey in appearence Vload is at the very heart of the V-system
# and THERE IS ONLY ONE VLOAD. V and xV boot using a single version of
# this program. Installing a broken Vload makes it impossible for anybody
# to boot anything including netwatch. This makes for a very difficult 
# debugging chore.
#
# If you're not sure that you know what you're doing don't be ashamed
# to ask somebody who does.
# 
# NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
#
# Warning: Vload must run in a very limited amount of memory. After you
#  make any changes, note the output of the "size68 -h" that the buildfile
#  runs on Vload*.r. For Vload10, if the sum of the first two hex
#  numbers (code + initialized data) is more than 0x1C00 it will NOT work.
#  Vload50 can go up to 0x1E00.  These restrictions are imposed by the Sun
#  Network Disk (ND) boot protocol; versions of Vload that will not be booted
#  by ND are allowed to be larger.  Sun-1's on the 3Mb experimental network,
#  Sun-3's (except ones with pre-release ROMs), and the machine we use for
#  netwatching (3Mb and Excelan interfaces) all use EFTP or TFTP and hence
#  can support larger Vloads.
# There is also a limit on the total size, which is imposed by the load
#  origin specified with the -T option in the final ld68 step. The load
#  origin plus the total size must not go beyond the end of mapped memory.
#  The load origin also must not be so low that it runs into the team or
#  kernel being loaded.  Thus, the Sun-1 versions of Vload (called
#  "Vload" and "xlnVload") cannot have total size larger than 
#  0x20000 - 0x1d000 = 0x3000.  The total size is the last number printed
#  out by the "size68 -h" command.
#
# Further warning: Vload*.b must be the first module name passed to ld68,
#   so that the symbol "entry" labels the first instruction in the program.
#
# Tim Mann, March 22, 1984
#
# Nasty comments added by Lance Berc because he had to work on Vload
# for a month once after various people had randomized it to the point
# where no versions would compile or link. 8/85 - 12/85

# Support for the CMC ENP-30 board has been removed from the buildfile - lance

#include ../../../buildprefix

#
# Only the xV copy of Vload should be built and installed; the sources in V
#   are just a (possibly out of date) copy
#
#ifndef X
default:
	@echo '--- The copy of Vload in xV should be used for all changes ---'
*:
	@echo '--- The copy of Vload in xV should be used for all changes ---'
#else X

VPATH= . ../mi
.SUFFIXES:
.SUFFIXES: .b .c

V=../../..
MI=../mi
INCL= -I. -I$(MI) -I$(V)/libc/include/m68k -I$(V)/libc/include/mi

C68FLAGS= -O -vV $(INCL)

.c.b:
	cc68 $(C68FLAGS) -c $*.c

#ifdef X
LINK= ld68 -vx
#else
LINK= ld68 -vV
#endif

# Sun-1 board w/sun 3meg ethernet interface
ALL3= Vload V VV xVload xV xVV 1.Boot

# Sun-2 / 3com
ALL10= Vload10.d Vload10.boot

# Sun-1 / Excelan
ALL10XLN= xlnVload xlnV xlnVV xlnxVload xlnxV xlnxVV

# Sun-2/50 (Intel 82586)
ALL50= Vload50.d Vload50.boot

# Sun-3 (Intel 82586)
ALL3IE= Vload3+ie.d Vload3+ie.boot

# Sun-3 (AMD 7990 LANCE)
ALL3LE= Vload3+le.d Vload3+le.boot

ALL= $(ALL3) $(ALL10) $(ALL10XLN) $(ALL50) $(ALL3IE) $(ALL3LE)

C68FLAGS3=    $(C68FLAGS)           -DENET3MEG  -DLOTS_OF_ROOM
C68FLAGS10XLN=$(C68FLAGS)           -DENET10MEG -DLOTS_OF_ROOM -DEXCELAN
C68FLAGS3IE=  $(C68FLAGS) -DMC68010 -DENET10MEG -DLOTS_OF_ROOM -DSUN3
C68FLAGS3LE=  $(C68FLAGS) -DMC68010 -DENET10MEG -DLOTS_OF_ROOM -DSUN3 -DSUN3_50
C68FLAGS10=   $(C68FLAGS) -DMC68010 -DENET10MEG -DNDBOOT       -DTHREECOM
C68FLAGS50=   $(C68FLAGS) -DMC68010 -DENET10MEG -DNDBOOT       -DSUN50

SUN1LIBS= -lVsaconsole -lsun1rawio
SUN2LIBS= -lVsaconsole -lsun2rawio
SUN3LIBS= -lVsaconsole -lsun3rawio

OBJECTS= open.b close.b read.b qwconfig.b load.b ikc.b misc.b

OBJECTS3=     Vload3.b    enet3.b          getvalue.b    $(OBJECTS)
OBJECTS10XLN= Vload10x.b  enet10x.b        getvalue.b    $(OBJECTS)
OBJECTS3IE=   Vload3+ie.b enetie.b   fc3.b getvalue.b    $(OBJECTS)
OBJECTS3LE=   Vload3+le.b enetle.b   fc3.b getvalue.b    $(OBJECTS)
OBJECTS10=    Vload10.b   enet3com.b fc3.b getvalue.nd.b $(OBJECTS)
OBJECTS50=    Vload50.b   enet50.b   fc3.b getvalue.nd.b $(OBJECTS)

all: $(ALL)

# special stripped version of get value - used with ndboot versions.
getvalue.nd.b: $(MI)/getvalue.c
	cc68 $(C68FLAGS) -DNDBOOT -c $(MI)/getvalue.c -o getvalue.nd.b

# 3Mbit version
# Update the downloadable image (byte-reversed),
#   changing the entry point to 1000
#  .68 is the default extension for rev68

Vload3.b: $(MI)/Vload.c
	cc68 $(C68FLAGS3) -c $(MI)/Vload.c -o Vload3.b
enet3.b: enet3.c 
	cc68 $(C68FLAGS3) -c enet3.c

Vload: Vload.68 addr1000
	sh -c "dd bs=28 count=1 < Vload.68 > FOO.68"
	cat addr1000 >> FOO.68
	sh -c "dd bs=32 skip=1 < Vload.68 >> FOO.68"
	rev68 FOO Vload
	rm -f FOO.68
	size68 -h Vload

# Update the unreversed version
Vload.68: $(OBJECTS3) 
	$(LINK) -e entry -o Vload.68 -s -T 1d000 $(OBJECTS3) $(SUN1LIBS)

Vload.sym: $(OBJECTS3) 
	$(LINK) -e entry -o foo -X -T 1d000 $(OBJECTS3) $(SUN1LIBS)
	nm68 -n -h foo | grep -v " a " > Vload.sym
	rm foo

V: Vload
	cp Vload V
VV: Vload
	cp Vload VV

xVload: Vload
	cp Vload xVload
xV: xVload
	cp xVload xV
xVV: xVload
	cp xVload xVV

1.Boot: Vload
	cp Vload 1.Boot

# 10Mbit version (MC68020 with Intel 82586 chip as found in Sun-3/75)
#  .r is byte-reversed, with Sun-style b.out header.
#  .d has the b.out header stripped.
#  .boot has the SMI-Unix style a.out header, with entry point 4000.
# fc3.b is made with the Sun-2/50 stuff.

enetie.b: enetie.c i82586.h
	cc68 $(C68FLAGS3IE) -c enetie.c
Vload3+ie.b: $(MI)/Vload.c
	cc68 $(C68FLAGS3IE) -DXV -c $(MI)/Vload.c -o Vload3+ie.b

Vload3+ie.68: $(OBJECTS3IE) 
	$(LINK) -e entry -o Vload3+ie.68 -s -T b8000 $(OBJECTS3IE) $(SUN3LIBS)

Vload3+ie.r: Vload3+ie.68
	rev68 Vload3+ie Vload3+ie.r
	size68 -h Vload3+ie.r

Vload3+ie.d: Vload3+ie.r
	sh -c "dd bs=32 skip=1 < Vload3+ie.r > Vload3+ie.d"

Vload3+ie.boot: Vload3+ie.r addr4000
	sh -c "dd bs=4 count=5 < Vload3+ie.r > Vload3+ie.boot"
	cat addr4000 >> Vload3+ie.boot
	sh -c "dd bs=4 skip=5 count=2 < Vload3+ie.r >> Vload3+ie.boot"
	sh -c "dd bs=32 skip=1 < Vload3+ie.r >> Vload3+ie.boot"

Vload3+ie.sym: Vload3+ie.d
	$(LINK) -e entry -o foo -X -T b8000 $(OBJECTS3IE) $(SUN3LIBS)
	nm68 -n -h foo | grep -v " a " > Vload3+ie.sym
	rm foo

# 10Mbit version (MC68020 with AMD 7990 LANCE chip as found in Sun-3/50)
#  .r is byte-reversed, with Sun-style b.out header.
#  .d has the b.out header stripped.
#  .boot has the SMI-Unix style a.out header, with entry point 4000.
# fc3.b is made with the Sun-2/50 stuff.

enetle.b: enetle.c enetle.h
	cc68 $(C68FLAGS3LE) -c enetle.c
Vload3+le.b: $(MI)/Vload.c
	cc68 $(C68FLAGS3LE) -DXV -c $(MI)/Vload.c -o Vload3+le.b

Vload3+le.68: $(OBJECTS3LE) 
	$(LINK) -e entry -o Vload3+le.68 -s -T b8000 $(OBJECTS3LE) $(SUN3LIBS)

Vload3+le.r: Vload3+le.68
	rev68 Vload3+le Vload3+le.r
	size68 -h Vload3+le.r

Vload3+le.d: Vload3+le.r
	sh -c "dd bs=32 skip=1 < Vload3+le.r > Vload3+le.d"

Vload3+le.boot: Vload3+le.r addr4000
	sh -c "dd bs=4 count=5 < Vload3+le.r > Vload3+le.boot"
	cat addr4000 >> Vload3+le.boot
	sh -c "dd bs=4 skip=5 count=2 < Vload3+le.r >> Vload3+le.boot"
	sh -c "dd bs=32 skip=1 < Vload3+le.r >> Vload3+le.boot"

Vload3+le.sym: Vload3+le.d
	$(LINK) -e entry -o foo -X -T b8000 $(OBJECTS3LE) $(SUN3LIBS)
	nm68 -n -h foo | grep -v " a " > Vload3+le.sym
	rm foo

# 10Mbit version (MC68010 with Intel 82586 chip as found in Sun-2/50)
#  .r is byte-reversed, with Sun-style b.out header.
#  .d has the b.out header stripped.
#  .boot has the SMI-Unix style a.out header, with entry point 4000.

enet50.b: enet50.c enet50.h
	cc68 $(C68FLAGS50) -c enet50.c
fc3.b: fc3.c
	cc68 $(C68FLAGS50) -c fc3.c
Vload50.b: $(MI)/Vload.c
	cc68 $(C68FLAGS50) -DXV -c $(MI)/Vload.c -o Vload50.b

Vload50.68: $(OBJECTS50) 
	$(LINK) -e entry -o Vload50.68 -s -T b8000 $(OBJECTS50) $(SUN2LIBS)
	rm -f Vload50.sym

Vload50.r: Vload50.68
	rev68 Vload50 Vload50.r
	size68 -h Vload50.r

Vload50.d: Vload50.r
	sh -c "dd bs=32 skip=1 < Vload50.r > Vload50.d"

Vload50.boot: Vload50.r addr4000
	sh -c "dd bs=4 count=5 < Vload50.r > Vload50.boot"
	cat addr4000 >> Vload50.boot
	sh -c "dd bs=4 skip=5 count=2 < Vload50.r >> Vload50.boot"
	sh -c "dd bs=32 skip=1 < Vload50.r >> Vload50.boot"

Vload50.sym: $(OBJECTS50) 
	$(LINK) -e entry -o foo -X -T b8000 $(OBJECTS50) $(SUN2LIBS)
	nm68 -n -h foo | grep -v " a " > Vload50.sym
	rm foo

# 10Mbit version (MC68010 with 3Com board)
# Update the downloadable images
#  .r is byte-reversed, with Sun-style b.out header.
#  .d has the b.out header stripped.
#  .boot has the SMI-Unix style a.out header, with entry point 4000.
# fc3.b is made with the Sun-2/50 stuff.
#  
Vload10.b: $(MI)/Vload.c
	cc68 $(C68FLAGS10) -DXV -c $(MI)/Vload.c -o Vload10.b

enet3com.b: enet3com.c
	cc68 $(C68FLAGS10) -I../../../libc/drivers/m68k -c enet3com.c
# CROCK!  We (temporarily, I hope) pull enet3com.h out of this hat.  Ideally,
#         we should abolish Vload's enet3com.c and use the version from
#         libc/drivers, unless there's a vital difference in space consumption

Vload10.68: $(OBJECTS10) 
	$(LINK) -e entry -o Vload10.68 -s -T b8000 $(OBJECTS10) $(SUN2LIBS)
	rm -f Vload10.sym

Vload10.r: Vload10.68
	rev68 Vload10 Vload10.r
	size68 -h Vload10.r

Vload10.d: Vload10.r
	sh -c "dd bs=32 skip=1 < Vload10.r > Vload10.d"

Vload10.boot: Vload10.r addr4000
	sh -c "dd bs=4 count=5 < Vload10.r > Vload10.boot"
	cat addr4000 >> Vload10.boot
	sh -c "dd bs=4 skip=5 count=2 < Vload10.r >> Vload10.boot"
	sh -c "dd bs=32 skip=1 < Vload10.r >> Vload10.boot"

Vload10.sym: $(OBJECTS10) 
	$(LINK) -e entry -o foo -X -T b8000 $(OBJECTS10) $(SUN2LIBS)
	nm68 -n -h foo | grep -v " a " > Vload10.sym
	rm foo

# 10Mbit version (MC68000 with Excelan board)
# Update the downloadable image (byte-reversed),
#   changing the entry point to 1000
#  .68 is the default extension for rev68

Vload10x.b: $(MI)/Vload.c
	cc68 $(C68FLAGS10XLN) -c $(MI)/Vload.c -o Vload10x.b
enet10x.b: enet10x.c
	cc68 $(C68FLAGS10XLN) -c enet10x.c

Vload10x.68: $(OBJECTS10XLN) 
	$(LINK) -e entry -o Vload10x.68 -s -T 1d000 $(OBJECTS10XLN) $(SUN1LIBS)
	rm -f Vload10x.sym

xlnVload: Vload10x.68 addr1000
	sh -c "dd bs=28 count=1 < Vload10x.68 > FOO.68"
	cat addr1000 >> FOO.68
	sh -c "dd bs=32 skip=1 < Vload10x.68 >> FOO.68"
	rev68 FOO xlnVload
	rm -f FOO.68
	size68 -h xlnVload

Vload10x.sym: $(OBJECTS10XLN) 
	$(LINK) -e entry -o foo -X -T 1d000 $(OBJECTS10XLN) $(SUN1LIBS)
	nm68 -n -h foo | grep -v " a " > Vload10x.sym
	rm foo

xlnV: xlnVload
	cp xlnVload xlnV
xlnVV: xlnVload
	cp xlnVload xlnVV

xlnxVload: xlnVload
	cp xlnVload xlnxVload
xlnxV: xlnxVload
	cp xlnxVload xlnxV
xlnxVV: xlnxVload
	cp xlnxVload xlnxVV

# Standard buildfile entries
relink:
	rm -f *.68 $(ALL) *.sym

clean:
	rm -f *.b *.d *.o *.r *.s *.ls *.BAK *.CKP *.68 *.boot *.sym .emacs*

install: all
	netinstall -x -p -m 0654 "$(ALL3) $(ALL10XLN)" /usr/sun/bootfile
	netinstall -x -p -m 0654 "Vload3+ie.d Vload3+le.d" /usr/sun/bootfile
	netinstall -x -p "Vload10.d Vload50.d" $(PRODUCTION_VSYS)/boot
	netinstall -x -p "Vload10.boot Vload50.boot Vload3+ie.boot Vload3+le.boot" $(PRODUCTION_VSYS)/boot
# The first two lines (installing to /usr/sun/bootfile) are for Sun-1 and
# Sun-3 machines: these boot using EFTP or TFTP (?), and the unix servers we
# run (nothing to do with the V system) look in /usr/sun/bootfile.
# The third line is for machines that boot using the Sun ND protocol; our
# ndserver expects to fetch these from /usr/V/boot.
# The fourth line installs the Sun boot-format files, even though they don't
# belong in that directory.  The place they do belong varies, but this makes
# sure that everybody gets a copy.

#endif X
24392!Funky!Stuff!
