#! /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 /* 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>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!