ast@cs.vu.nl (Andy Tanenbaum) (07/23/88)
: This is a shar archive. Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'amoeba.c'
sed 's/^X//' > 'amoeba.c' << '+ END-OF-FILE ''amoeba.c'
X/*
X** Minix /dev/amoeba driver
X**
X** This file contains two kernel servers: amint_task and amoeba_task.
X** amoeba_task implements transactions for user tasks and amint_task
X** handles asynchronous events such as timeouts, incoming ethernet
X** packets and interrupts.
X**
X** An amoeba_task is permanently assigned to a process until a transaction
X** is complete. If you do a getreq then the kernel task remains
X** allocated until after the putrep or the server dies.
X** There is a limit of one operation at a time except in the case that a
X** getreq is followed by a trans.
X**
X** The value of curtask is only correct if there is non-preemptive
X** scheduling of kernel tasks. It is reset by am_sleep when it returns
X** which keeps it pointing to the correct place.
X**
X** Lines marked HACK are of doubtful portability but produce efficient
X** code.
X*/
X
X#define NDEBUG
X
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/com.h"
X#include "../h/error.h"
X#include "../h/callnr.h"
X#include "../h/signal.h"
X#include "const.h"
X#include "type.h"
X#include "proc.h"
X#include "glo.h" /* need definition of cur_proc */
X
X#include "../h/amoeba.h"
X#undef umap
X#include "../h/amparam.h"
X#include "global.h"
X#define MPX
X#define TRANS
X#include "task.h"
X#include "assert.h"
X#include "internet.h"
X#include "etherformat.h"
X#include "byteorder.h"
X
X/* amoeba task table - can't alloc memory in minix kernel */
XPUBLIC struct task am_task[AM_NTASKS];
X
X#ifndef NONET
X
X#define ETH_HDRS (sizeof (Framehdr))
X#define HSZ (ETH_HDRS + HEADERSIZE) /* watchout for alignment */
X#define FAKESITENO 0xff /* to bluff trans.c */
X#define MAPENTRIES 127
X/* two hacks for speed */
X#define EANULL(a) NullPort((port *) (a)) /* HACK! */
X#define EACMP(a, b) PortCmp((port *) (a), (port *) (b)) /* HACK! */
X
XPRIVATE Etherpacket Packet; /* the latest arrived amoeba ethernet packet */
XPRIVATE phys_bytes Bufaddr;/*physical address of Packet */
X
XPRIVATE phys_bytes Inptr; /* used by pickoff() & getall() to copy data */
XPRIVATE unsigned Insiz; /* total size of received packet */
XPRIVATE phys_bytes Outptr; /* pointer to pos currently building packet */
XPRIVATE unsigned Outsiz; /* size of currently building packet */
XPRIVATE phys_bytes Xmtbuf; /* Pointer to current ethernet write buffer */
XPRIVATE Eth_addr Myaddr; /* ether address of this host */
XPRIVATE Eth_addr Gwaddr; /* ether address of pronet gateway */
X/* broadcast address for ethernet. see next comment. */
XPRIVATE Eth_addr Broadcastaddr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
X/* the 128th map entry is to hold the broadcast address. can you say HACK? */
XPRIVATE Eth_addr Eamap[MAPENTRIES+1];
X
X#endif
X
X
X/*===========================================================================*
X * amoeba_task *
X *===========================================================================*/
XPUBLIC
Xamoeba_task()
X{
X void am_reply();
X message mess;
X int mytask;
X
X mytask = AMOEBA_CLASS - cur_proc;
X curtask = &am_task[mytask]; /* make me the current amoeba task */
X am_init();
X while (TRUE)
X {
X receive(ANY, &mess);
X curtask = &am_task[mytask]; /* make me the current amoeba task */
X switch (mess.AM_OP)
X {
X case AM_TRANS:
X do_trans(&mess);
X break;
X case AM_GETREQ:
X do_getreq(&mess);
X break;
X case AM_PUTREP:
X do_putrep(&mess);
X break;
X default:
X if (mess.m_source >= 0)
X am_reply(TASK_REPLY, mess.m_source, mess.AM_PROC_NR, 1, EINVAL);
X break;
X } /* end switch */
X } /* end while */
X}
X
X
X/*===========================================================================*
X * am_init *
X *===========================================================================*/
XPRIVATE int
Xam_init()
X{
X/* non-pre-emptive scheduling is assumed here for initialisation! */
X static int Initialised;
X
X if (Initialised == 0)
X { /* set up the ethernet driver and init the tables */
X Initialised++;
X uppertask = &am_task[AM_NTASKS];
X ntask = AM_NTASKS;
X#ifndef NONET
X net_init();
X#endif
X transinit();
X portinit();
X }
X trinit();
X curtask->mx_flags = RUNNABLE;
X}
X
X
X/*===========================================================================*
X * amint_task *
X *===========================================================================*/
XPUBLIC
Xamint_task()
X{
X phys_bytes umap();
X message mess;
X struct task * t;
X
X#ifndef NONET
X Bufaddr = umap(proc_addr(AMINT_CLASS), D, (vir_bytes)&Packet, (vir_bytes)HSZ);
X#endif
X set_timer(); /* start the netsweep timer */
X while (TRUE)
X {
X receive(ANY, &mess);
X switch (mess.AM_OP)
X {
X case ETHER_ARRIV: /* an ethernet packet arrived */
X do_arrive(&mess);
X break;
X case AM_TIMEOUT: /* run transaction sweepers every 0.1 secs */
X netsweep();
X portsweep();
X set_timer(); /* reset the timeout */
X break;
X case AM_PUTSIG: /* user typed a del or a quit or a kill */
X sendsig(&am_task[mess.AM_COUNT], 1);
X break;
X case AM_TASK_DIED: /* a user task died while doing an operation */
X t = &am_task[mess.AM_COUNT];
X if (t->mx_active) /* if transaction record is still valid */
X {
X destroy(t); /* then destroy it */
X t->mx_proc_nr = 0;
X t->mx_active = 0;
X t->mx_flags = 0;
X }
X break;
X default:
X break;
X }
X }
X}
X
X
X/*===========================================================================*
X * set_timer *
X *===========================================================================*/
XPRIVATE
Xset_timer()
X{
X message mess;
X int am_runsweep();
X
X mess.m_type = SET_ALARM;
X mess.CLOCK_PROC_NR = AMINT_CLASS;
X mess.DELTA_TICKS = HZ/10; /* every 0.1 seconds ! */
X mess.FUNC_TO_CALL = am_runsweep;
X sendrec(CLOCK, &mess);
X}
X
X
X/*===========================================================================*
X * am_runsweep *
X *===========================================================================*/
XPRIVATE
Xam_runsweep()
X{
X message mess;
X
X mess.AM_OP = AM_TIMEOUT;
X send(AMINT_CLASS, &mess);
X}
X
X
X/*===========================================================================*
X * do_trans *
X *===========================================================================*/
XPRIVATE
Xdo_trans(m_ptr)
Xmessage * m_ptr;
X{
X header * am_starttask();
X void am_endtask();
X unshort trans();
X void am_reply();
X
X unshort ret;
X header * hdr;
X Trpar param; /* parameter block for transaction */
X
X#define req param.tp_par[0]
X#define rep param.tp_par[1]
X
X/* copy in parameter block */
X if (get_param(m_ptr, ¶m) == 0)
X {
X am_reply(TASK_REPLY, m_ptr->m_source, m_ptr->AM_PROC_NR, 1, EFAULT);
X return;
X }
X/* copy header in */
X hdr = am_starttask(m_ptr);
X if (get_header(m_ptr, req.p_hdr, hdr) == 0)
X {
X am_endtask();
X am_reply(TASK_REPLY, m_ptr->m_source, m_ptr->AM_PROC_NR, 1, EFAULT);
X return;
X }
X/* reply to FS to suspend luser task */
X am_reply(TASK_REPLY, m_ptr->m_source, m_ptr->AM_PROC_NR, 0, SUSPEND);
X/* start locate timer */
X (void)am_timeout(param.tp_maxloc);
X/* call trans */
X ret = trans(hdr, req.p_buf, req.p_cnt, hdr, rep.p_buf, rep.p_cnt);
X/* copy header to luser task (trans already copied the data) */
X if ((short)ret >= 0 && put_header(m_ptr->AM_PROC_NR, hdr, rep.p_hdr) == 0)
X {
X am_endtask();
X am_reply(AM_REVIVE, m_ptr->m_source, m_ptr->AM_PROC_NR, 1, EFAULT);
X return;
X }
X am_endtask();
X/* revive luser task */
X am_reply(AM_REVIVE, m_ptr->m_source, m_ptr->AM_PROC_NR, 1, (int)ret);
X}
X
X
X/*===========================================================================*
X * do_getreq *
X *===========================================================================*/
XPRIVATE
Xdo_getreq(m_ptr)
Xmessage * m_ptr;
X{
X unshort getreq();
X header * am_starttask();
X void am_endtask();
X void am_reply();
X
X Trpar param;
X unshort ret;
X header * hdr;
X int free;
X
X/* copy parameter block for getreq */
X if (get_param(m_ptr, ¶m) == 0)
X {
X am_reply(TASK_REPLY, m_ptr->m_source, m_ptr->AM_PROC_NR, 1, EFAULT);
X return;
X }
X/* copy header in */
X hdr = am_starttask(m_ptr);
X if (get_header(m_ptr, param.tp_par[0].p_hdr, hdr) == 0)
X {
X am_endtask();
X am_reply(TASK_REPLY, m_ptr->m_source, m_ptr->AM_PROC_NR, 1, EFAULT);
X return;
X }
X/* reply to FS to suspend luser task */
X am_reply(TASK_REPLY, m_ptr->m_source, m_ptr->AM_PROC_NR, 0, SUSPEND);
X/* call getreq */
X ret = getreq(hdr, param.tp_par[0].p_buf, param.tp_par[0].p_cnt);
X free = 0;
X if ((short)ret < 0) /* getreq failed */
X {
X free = 1;
X am_endtask();
X }
X else /* copy header to luser task (getreq already copied the data) */
X if (put_header(m_ptr->AM_PROC_NR, hdr, param.tp_par[0].p_hdr) == 0)
X {
X free = 1;
X ret = EFAULT;
X am_endtask();
X }
X/* restart luser task but don't free the kernel task! */
X am_reply(AM_REVIVE, m_ptr->m_source, m_ptr->AM_PROC_NR, free, (int)ret);
X}
X
X
X/*===========================================================================*
X * do_putrep *
X *===========================================================================*/
XPRIVATE
Xdo_putrep(m_ptr)
Xmessage * m_ptr;
X{
X unshort putrep();
X void am_reply();
X
X Trpar param;
X header * hdr;
X unshort ret;
X
X/* copy in parameter block */
X if (get_param(m_ptr, ¶m) == 0)
X {
X am_reply(TASK_REPLY, m_ptr->m_source, m_ptr->AM_PROC_NR, 1, EFAULT);
X return;
X }
X/* make sure that there was a getrequest */
X if (!curtask->mx_active || curtask->mx_proc_nr != m_ptr->AM_PROC_NR)
X {
X am_reply(TASK_REPLY, m_ptr->m_source, m_ptr->AM_PROC_NR, 1, (int)FAIL);
X return;
X }
X/* copy in header */
X hdr = &curtask->mx_hdr;
X if (get_header(m_ptr, param.tp_par[0].p_hdr, hdr) == 0)
X {
X am_endtask();
X am_reply(TASK_REPLY, m_ptr->m_source, m_ptr->AM_PROC_NR, 1, EFAULT);
X return;
X }
X/* tell FS to suspend luser task */
X am_reply(TASK_REPLY, m_ptr->m_source, m_ptr->AM_PROC_NR, 0, SUSPEND);
X/* send reply */
X ret = putrep(hdr, param.tp_par[0].p_buf, param.tp_par[0].p_cnt);
X am_endtask();
X/* restart luser task */
X am_reply(AM_REVIVE, m_ptr->m_source, m_ptr->AM_PROC_NR, 1, (int)ret);
X}
X
X
X/*===========================================================================*
X * do_arrive *
X *===========================================================================*/
XPRIVATE
Xdo_arrive(m_ptr)
Xmessage * m_ptr;
X{
X#ifndef NONET
X/*
X** we already know it is an amoeba packet, otherwise we wouldn't get here.
X** copy in the ethernet header, the internet header and the amoeba header
X** and then call packet handle. getall and pickoff do the rest!
X*/
X phys_copy(m_ptr->AM_PADDR, Bufaddr, (long)HSZ);
X
X/* fix amoeba size field - NB. the following is a macro */
X dec_s_le(&Packet.ep_fr.f_ah.ph_size);
X/* if packethandle succeeds it calls netenable itself! */
X if (check(&Packet)) /* then give it to the transaction layer */
X {
X Inptr = m_ptr->AM_PADDR + HSZ; /* pointer to the data after headers */
X Insiz = Packet.ep_fr.f_ah.ph_size;
X Packet.ep_fr.f_ah.ph_size -= ETH_HDRS;
X Packet.ep_fr.f_ah.ph_dstnode = FAKESITENO;
X if (!pkthandle(&Packet.ep_fr.f_ah, Packet.ep_data))
X am_netenable();
X }
X else
X am_netenable();
X#endif
X}
X
X
X/*===========================================================================*
X * am_reply *
X *===========================================================================*/
XPRIVATE void
Xam_reply(code, replyee, proc_nr, free_it, status)
Xint code; /* TASK_REPLY or revive */
Xint replyee; /* destination address for the reply */
Xint proc_nr; /* to whom the reply should go */
Xint free_it; /* if a getreq, then don't free this task */
Xint status; /* reply code */
X{
X/* send reply to process doing a trans, getreq or putrep or anything else */
X message a_mess;
X
X a_mess.m_type = AM_SYSCALL;
X a_mess.AM_OP = code;
X a_mess.AM_FREE_IT = (long)free_it;
X a_mess.AM_PROC_NR = proc_nr;
X a_mess.AM_STATUS = status;
X send(replyee, &a_mess);
X}
X
X
X/*===========================================================================*
X * am_starttask *
X *===========================================================================*/
XPRIVATE header *
Xam_starttask(m_ptr)
Xmessage * m_ptr;
X{
X/* check to see if already doing a transaction for this user */
X if (curtask->mx_active && curtask->mx_proc_nr == m_ptr->AM_PROC_NR)
X {
X assert(curtask->mx_flags & RUNNABLE);
X assert(!(curtask->mx_flags & NESTED));
X curtask->mx_flags |= NESTED;
X }
X else
X {
X curtask->mx_proc_nr = m_ptr->AM_PROC_NR;
X curtask->mx_active = 1;
X curtask->mx_flags = RUNNABLE;
X }
X return &curtask->mx_hdr;
X}
X
X
X/*===========================================================================*
X * am_endtask *
X *===========================================================================*/
XPRIVATE void
Xam_endtask()
X{
X if (curtask->mx_flags & NESTED)
X curtask->mx_flags &= ~NESTED;
X else
X {
X am_cleanup();
X curtask->mx_flags = 0;
X curtask->mx_active = 0;
X }
X}
X
X
X/*===========================================================================*
X * get_param *
X *===========================================================================*/
XPRIVATE
Xget_param(m_ptr, param)
Xmessage * m_ptr;
XTrpar * param;
X{
X phys_bytes umap();
X phys_bytes src; /* physical address of parameter block */
X phys_bytes dst; /* kernel buffer */
X
X/* copy parameter block for trans */
X if (m_ptr->AM_COUNT != (int)sizeof (Trpar) ||
X (src = umap(proc_addr(m_ptr->AM_PROC_NR), D,
X (vir_bytes)m_ptr->AM_ADDRESS, (vir_bytes)sizeof (Trpar))) == 0)
X return 0;
X dst = umap(proc_addr(cur_proc), D, (vir_bytes)param,
X (vir_bytes)sizeof (Trpar));
X phys_copy(src, dst, (long)sizeof (Trpar));
X return 1;
X}
X
X
X/*===========================================================================*
X * get_header *
X *===========================================================================*/
XPRIVATE
Xget_header(m_ptr, h_src, h_dest)
Xmessage * m_ptr;
Xheader * h_src;
Xheader * h_dest;
X{
X/* get amoeba header from user space */
X phys_bytes umap();
X phys_bytes src; /* user's header */
X phys_bytes dst; /* kernel buffer for header */
X
X if ((src = umap(proc_addr(m_ptr->AM_PROC_NR), D, (vir_bytes)h_src,
X (vir_bytes)sizeof (header))) == 0)
X return 0;
X dst = umap(proc_addr(cur_proc), D, (vir_bytes)h_dest,
X (vir_bytes)sizeof (header));
X phys_copy(src, dst, (long)sizeof (header));
X return 1;
X}
X
X
X/*===========================================================================*
X * put_header *
X *===========================================================================*/
XPRIVATE
Xput_header(proc_nr, h_src, h_dest)
Xint proc_nr;
Xheader * h_src;
Xheader * h_dest;
X{
X/* write an amoeba header into user space */
X phys_bytes umap();
X phys_bytes src;
X phys_bytes dst;
X
X if ((dst = umap(proc_addr(proc_nr), D, (vir_bytes)h_dest,
X (vir_bytes)sizeof (header))) == 0)
X return 0;
X src = umap(proc_addr(cur_proc), D, (vir_bytes)h_src,
X (vir_bytes)sizeof (header));
X phys_copy(src, dst, (long)sizeof (header));
X return 1;
X}
X
X
X/*
X** routines which are needed by trans.c
X*/
X
X/*===========================================================================*
X * am_umap *
X *===========================================================================*/
XPUBLIC phys_bytes
Xam_umap(a, b, c)
Xstruct task * a;
Xvir_bytes b;
Xvir_bytes c;
X{
X/* the umap in trans.c needs to be converted to minix umap */
X phys_bytes umap();
X
X return umap(proc_addr(a->mx_proc_nr), D, b, c);
X}
X
X
X/*===========================================================================*
X * am_psig *
X *===========================================================================*/
XPUBLIC
Xam_psig(t, sig)
Xstruct task * t;
Xunshort sig;
X{
X/* should propagate if between a g & p and remember sig! */
X sendsig(t, (char)sig); /* propagate signal to servers */
X cause_sig(t->mx_proc_nr, SIGAMOEBA);
X}
X
X
X/*
X** sleep and wakeup don't fit into the amoeba model too well.
X** the following are hacks and don't give true sleep and wakeup
X** semantics. they also do not take account of interrupts but seem to work.
X*/
X
X/*===========================================================================*
X * am_sleep *
X *===========================================================================*/
Xam_sleep(addr)
Xevent_t addr;
X{
X message mess;
X struct task * c;
X
X c = curtask;
X receive(ANY, &mess);
X if (mess.AM_ADDRESS != addr)
X printf("am_sleep: woken badly %x %x\n", mess.ADDRESS, addr);
X curtask = c;
X return 0;
X}
X
X
X/*===========================================================================*
X * am_wakeup *
X *===========================================================================*/
Xam_wakeup(addr)
Xevent_t addr;
X{
X message mess;
X int tasknr;
X
X mess.AM_ADDRESS = addr;
X tasknr = ((struct task *)addr - am_task); /* HACK */
X if (am_task[tasknr].mx_active) /* don't wake it up if it is dead! */
X send(AMOEBA_CLASS - tasknr, &mess);
X}
X
X
X#ifndef NDEBUG
X
X#define PRINTABLE(c) (((c) >= ' ' && (c) <= '~') ? (c) : '?')
X
X
X/*===========================================================================*
X * prport *
X *===========================================================================*/
XPUBLIC
Xprport(p)
Xport * p;
X{
X int i;
X
X for (i = 0; i < PORTSIZE; i++)
X printf("%c", PRINTABLE(p->_portbytes[i]));
X}
X
X#endif
X
X
X#ifndef NONET
X
X/*===========================================================================*
X * interinit *
X *===========================================================================*/
XPUBLIC address
Xinterinit()
X{
X return 0xFF;
X}
X
X
X/*===========================================================================*
X * check *
X *===========================================================================*/
XPRIVATE
Xcheck(p)
XEtherpacket * p;
X{
X/* make sure that an ethernet packet is a valid amoeba packet */
X if (p->ep_fr.f_ah.ph_srcnode == 0) /* from an ethernet host */
X {
X if ((p->ep_fr.f_ah.ph_srcnode = ealookup(&p->ep_fr.f_srcaddr)) == 0)
X {
X printf("ethernet mapping table overflow\n");
X return 0;
X }
X }
X else /* was the packet from ProNet? */
X#ifdef PRONET
X {
X if (p->ep_fr.f_ah.ph_srcnode & ETHERBITS)
X return 0;
X /* a packet from the pronet gateway */
X if (EANULL(&Gwaddr))
X {
X Gwaddr = p->ep_fr.f_srcaddr;
X pr_addr("Gateway to pronet at", &Gwaddr);
X }
X else
X if (!EACMP(&Gwaddr, &p->ep_fr.f_srcaddr))
X pr_addr("Second gateway claims to be at", &p->ep_fr.f_srcaddr);
X }
X#else
X return 0;
X#endif PRONET
X return 1;
X}
X
X
X/*===========================================================================*
X * pr_addr *
X *===========================================================================*/
XPRIVATE
Xpr_addr(s, p)
Xchar * s;
XEth_addr * p;
X{
X/* print an ethernet address */
X printf("%s %x:%x:%x:%x:%x:%x\n", s,
X p->e[0] & 0xff,
X p->e[1] & 0xff,
X p->e[2] & 0xff,
X p->e[3] & 0xff,
X p->e[4] & 0xff,
X p->e[5] & 0xff);
X}
X
X
X/*===========================================================================*
X * am_puthead *
X *===========================================================================*/
XPUBLIC
Xam_puthead(dst, src, ident, seq, type, size)
Xaddress dst;
Xaddress src;
Xchar ident;
Xchar seq;
Xchar type;
Xunshort size;
X{
X phys_bytes umap();
X phys_bytes eth_getbuf();
X
X unshort totalsize;
X char dstnode;
X Framehdr fh;
X phys_bytes phd;
X
X totalsize = size + sizeof (Framehdr);
X compare(totalsize, <=, 1514);
X fh.f_ah.ph_dstnode = dstnode = lobyte(dst);
X if ((dstnode & ETHERBITS) == 0)
X {
X assert(!EANULL(&Gwaddr));
X fh.f_dstaddr = Gwaddr;
X }
X else /* broadcast is also handled here! */
X fh.f_dstaddr = Eamap[dstnode & 0x7f];
X fh.f_srcaddr = Myaddr;
X fh.f_proto = AMOEBAPROTO;
X enc_s_be(&fh.f_proto);
X
X fh.f_ah.ph_srcnode = 0;
X fh.f_ah.ph_dsttask = hibyte(dst);
X fh.f_ah.ph_srctask = hibyte(src);
X fh.f_ah.ph_ident = ident;
X fh.f_ah.ph_seq = seq;
X fh.f_ah.ph_type = type;
X fh.f_ah.ph_flags = 0;
X fh.f_ah.ph_size = totalsize;
X enc_s_le(&fh.f_ah.ph_size);
X
X if ((Xmtbuf = eth_getbuf()) != 0)
X {
X phd = umap(proc_addr(cur_proc), D, (vir_bytes)&fh, (vir_bytes)sizeof (Framehdr));
X phys_copy(phd, Xmtbuf, (long)sizeof (Framehdr));
X if (size == 0)
X eth_write(Xmtbuf, 60);
X else
X {
X Outsiz = sizeof (Framehdr);
X Outptr = Xmtbuf + sizeof (Framehdr);
X }
X }
X else
X Outptr = 0;
X}
X
X
X/*===========================================================================*
X * am_gall *
X *===========================================================================*/
XPUBLIC
Xam_gall() /* getall in trans.c */
X{
X/*
X** copy in any bytes not already copied into packet! We've already copied
X** the first HSZ bytes!
X** Bufaddr points to the local buffer Packet and Inptr points to the current
X** position in the buffer on the ethernet card.
X*/
X long size;
X
X if ((size = (long)Insiz - HSZ) > 0)
X phys_copy(Inptr, Bufaddr+HSZ, size);
X}
X
X
X/*===========================================================================*
X * am_do_append *
X *===========================================================================*/
XPUBLIC
Xam_doappend(data, size, dosend)
Xphys_bytes data;
Xunshort size;
Xint dosend;
X{
X/* add more data to current ethernet output packet */
X if (Outptr == 0) /* previous puthead failed */
X return;
X phys_copy(data, Outptr, (long)size);
X Outptr += size;
X Outsiz += size;
X if (dosend)
X {
X if (Outsiz < 60)
X Outsiz = 60;
X eth_write(Xmtbuf, (int)Outsiz);
X }
X}
X
X
X/*===========================================================================*
X * am_pickoff *
X *===========================================================================*/
XPUBLIC
Xam_pickoff(data, size)
Xphys_bytes data;
Xunsigned size;
X{
X phys_copy(Inptr, data, (long)size);
X Inptr += size;
X}
X
X
X/*===========================================================================*
X * am_append *
X *===========================================================================*/
XPUBLIC
Xam_append(data, size, dosend)
Xphys_bytes data; /* not really a phys_bytes! really a vir_bytes */
Xunshort size;
Xint dosend;
X{
X phys_bytes paddr;
X phys_bytes umap();
X
X paddr = umap(proc_addr(cur_proc), D, (vir_bytes)data, (vir_bytes)size);
X am_doappend(paddr, size, dosend);
X}
X
X
X/*===========================================================================*
X * am_phys_copy *
X *===========================================================================*/
XPUBLIC
Xam_phys_copy(s, d, size)
Xvir_bytes s;
Xphys_bytes d;
Xphys_bytes size;
X{
X/*
X** the phys_copy in trans.c needs a little help in places since kernel
X** virtual address need to be umapped under minix
X*/
X phys_bytes umap();
X phys_bytes ps;
X
X ps = umap(proc_addr(cur_proc), D, (vir_bytes)s, (vir_bytes)size);
X phys_copy(ps, d, size);
X}
X
X
X/*===========================================================================*
X * ealookup *
X *===========================================================================*/
XPRIVATE
Xealookup(addr)
XEth_addr * addr;
X{
X int index;
X int i;
X Eth_addr * mep;
X
X index = addr->e[5] & 0x7f; /* hash it */
X if (index >= MAPENTRIES)
X index = 0;
X i = index;
X do
X {
X mep = &Eamap[i];
X if (EACMP(addr, mep))
X return i | ETHERBITS;
X if (EANULL(mep))
X {
X *mep = *addr;
X return i | ETHERBITS;
X }
X if (++i >= MAPENTRIES)
X i = 0;
X } while (i != index);
X return 0;
X}
X
X
X/*
X** the following routines provide the interface to the ethernet driver
X*/
X
X
X/*===========================================================================*
X * net_init *
X *===========================================================================*/
XPUBLIC
Xnet_init()
X{
X int pkt_arr(); /* called by ethernet driver when packet arrives */
X int pkt_sent(); /* called by ethernet driver when packet was sent */
X int eth_init(); /* initialise ethernet driver */
X
X Eamap[MAPENTRIES] = Broadcastaddr;
X epl_init();
X etheraddr(&Myaddr);
X pr_addr("Etheraddr:", &Myaddr);
X eth_init(&Myaddr, pkt_arr, pkt_sent);
X}
X
X
X/*
X** some special hack-defines because physical addresses are stored in a long
X** and virtual addresses are not
X*/
X
X#define PROTO_OFFSET ((int) &((Etherpacket *) 0)->ep_fr.f_proto)
X
XPRIVATE message arr_mess;
X
X/*===========================================================================*
X * pkt_arr *
X *===========================================================================*/
XPRIVATE
Xpkt_arr(addr, count)
Xphys_bytes addr;
Xint count;
X{
X/*
X** This routine is called when an ethernet interrupt occurs.
X** It must select appropriate amoeba task to give the packet to.
X** NB: we are only interested in amoeba packets!
X*/
X short getbint();
X short protocol;
X
X protocol = getbint(addr + PROTO_OFFSET);
X#ifdef ALTAMOEBAPROTO
X if (protocol == AMOEBAPROTO || protocol == ALTAMOEBAPROTO)
X#else
X if (protocol == AMOEBAPROTO)
X#endif
X {
X arr_mess.AM_OP = ETHER_ARRIV;
X arr_mess.AM_PADDR = addr;
X arr_mess.AM_COUNT = count;
X interrupt(AMINT_CLASS, &arr_mess);
X }
X else /* not an amoeba packet, so give it back */
X eth_release(addr);
X}
X
X
X/*===========================================================================*
X * pkt_sent *
X *===========================================================================*/
X/*ARGSUSED*/
XPRIVATE
Xpkt_sent (addr)
Xphys_bytes addr;
X{
X/*
X** This is never called. The ethernet driver busy waits! It is here for
X** compatibility with the ethernet driver
X*/
X}
X
X
X/*===========================================================================*
X * am_netenable *
X *===========================================================================*/
XPUBLIC
Xam_netenable() /* release the last received message */
X{
X eth_release((phys_bytes)arr_mess.AM_PADDR);
X}
X
X#endif NONET
+ END-OF-FILE amoeba.c
chmod 'u=rw,g=r,o=r' 'amoeba.c'
set `wc -c 'amoeba.c'`
count=$1
case $count in
27724) :;;
*) echo 'Bad character count in ''amoeba.c' >&2
echo 'Count should be 27724' >&2
esac
echo Extracting 'amstat.h'
sed 's/^X//' > 'amstat.h' << '+ END-OF-FILE ''amstat.h'
Xstruct amstat {
X long ams_clfail;
X long ams_svfail;
X long ams_clcrash;
X long ams_rxcl;
X long ams_rxsv;
X long ams_trans;
X long ams_loctrans;
X long ams_remtrans;
X long ams_getreq;
X long ams_putrep;
X long ams_naks;
X};
+ END-OF-FILE amstat.h
chmod 'u=rw,g=r,o=r' 'amstat.h'
set `wc -c 'amstat.h'`
count=$1
case $count in
215) :;;
*) echo 'Bad character count in ''amstat.h' >&2
echo 'Count should be 215' >&2
esac
echo Extracting 'assert.h'
sed 's/^X//' > 'assert.h' << '+ END-OF-FILE ''assert.h'
X/****************************************************************************
X * *
X * (c) Copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands *
X * *
X * This product is part of the Amoeba distributed operating system. *
X * Permission is hereby granted to use it exclusively for educational *
X * and research purposes. It may also be freely duplicated and given *
X * to others for educational and research purposes only. All other use *
X * requires written permission from the copyright owner. *
X * *
X * Requests for such permissions may be sent to *
X * *
X * *
X * Dr. Andrew S. Tanenbaum *
X * Dept. of Mathematics and Computer Science *
X * Vrije Universiteit *
X * De Boelelaan 1081 *
X * 1081 HV Amsterdam *
X * The Netherlands *
X * *
X/****************************************************************************/
X
X#define NDEBUG
X#ifdef NDEBUG
X#define assert(e) /* NOTHING */
X#define compare(a,t,b) /* NOTHING */
X#else
X#ifdef lint
X#define assert(e) use(e)
X#define compare(a,t,b) use(a, b)
X#else lint
X#define assert(x) if (!(x)) printf("assertion failed in %s at %d\n", __FILE__, __LINE__)
X#define compare(a,t,b) if (!((a) t (b))) \
X printf("comparison failed in %s at %d (%D)\n", \
X __FILE__, __LINE__, a)
X/*
X#define assert(e) do if (!(e)) badassertion(__FILE__,__LINE__); while (0)
X#define compare(a,t,b) do if (!((a) t (b))) \
X badcompare(__FILE__,__LINE__, (long) (a)); \
X while (0)
X*/
X#endif lint
X#endif NDEBUG
+ END-OF-FILE assert.h
chmod 'u=rw,g=r,o=r' 'assert.h'
set `wc -c 'assert.h'`
count=$1
case $count in
1621) :;;
*) echo 'Bad character count in ''assert.h' >&2
echo 'Count should be 1621' >&2
esac
echo Extracting 'byteorder.h'
sed 's/^X//' > 'byteorder.h' << '+ END-OF-FILE ''byteorder.h'
X/*
X * set of macros to do inplace byteorder changes
X * The dec_* routines decode a short (_s) or long (_l) from little endian(_le)
X * or bigendian(_be) to native format.
X * The enc_* are similar for native to net format
X */
X
X
X/* littleendian version for ibm pc */
X
X#define dec_s_le(s) /* nothing */
X#define dec_s_be(s) (*(s))=((((*(s))>>8)&0xFF)|(((*(s))&0xFF)<<8))
X
X#define dec_l_le(l) /* nothing */
X#define dec_l_be(l) (*(l))=((((*(l))>>24)&0xFF)|(((*(l))>>8)&0xFF00)|(((*(l))<<8)&0xFF0000)|(((*(l))<<24)&0xFF000000))
X
X#define enc_s_le(s) /* nothing */
X#define enc_s_be(s) dec_s_be(s)
X
X#define enc_l_le(l) /* nothing */
X#define enc_l_be(l) dec_l_be(l)
+ END-OF-FILE byteorder.h
chmod 'u=rw,g=r,o=r' 'byteorder.h'
set `wc -c 'byteorder.h'`
count=$1
case $count in
654) :;;
*) echo 'Bad character count in ''byteorder.h' >&2
echo 'Count should be 654' >&2
esac
echo Extracting 'conf.c'
sed 's/^X//' > 'conf.c' << '+ END-OF-FILE ''conf.c'
X#include "../h/type.h"
X#include "../h/amoeba.h"
X#include "global.h"
X#include "conf.h"
X
X/*
X** the following hack is imported from task.c under Amoeba to declare
X** a few pointers to the task table
X*/
X#define extern
X
X#include "task.h"
X
X#undef extern
X
X/************************************************************************/
X/* TRANS CONFIGURATION */
X/************************************************************************/
X
X/*
X** various variables used for transactions
X*/
X
Xport NULLPORT; /* used in trans.c, declared here for compatability */
Xlong ticker; /* bogus global used by trans.c for statistics */
X
X#ifndef NONET
X
Xunshort minloccnt = MINLOCCNT;
Xunshort maxloccnt = MAXLOCCNT;
X
Xunshort retranstime = RETRANSTIME;
Xunshort crashtime = CRASHTIME;
Xunshort clientcrash = CLIENTCRASH;
X
Xunshort maxretrans = MAXRETRANS;
Xunshort mincrash = MINCRASH;
Xunshort maxcrash = MAXCRASH;
X
X#endif NONET
+ END-OF-FILE conf.c
chmod 'u=rw,g=r,o=r' 'conf.c'
set `wc -c 'conf.c'`
count=$1
case $count in
902) :;;
*) echo 'Bad character count in ''conf.c' >&2
echo 'Count should be 902' >&2
esac
echo Extracting 'conf.h'
sed 's/^X//' > 'conf.h' << '+ END-OF-FILE ''conf.h'
X/*
X** constants used for configuring amoeba transactions
X*/
X#define MINLOCCNT 5 /* locate message sent every dsec */
X#define MAXLOCCNT 100 /* locate message sent every MAXLOCCNT dsec */
X
X#define RETRANSTIME 5 /* retransmission time in dsec */
X#define CRASHTIME 100 /* crash timer in dsec */
X#define CLIENTCRASH 500 /* client must probe within this time */
X
X#define MAXRETRANS 10 /* max. number of transmissions */
X#define MINCRASH 5 /* enquiry sent MINCRASH times during recv */
X#define MAXCRASH 10 /* enquiry sent MAXCRASH times during serv */
X
X#define NPORTS 16 /* # ports in portcache */
+ END-OF-FILE conf.h
chmod 'u=rw,g=r,o=r' 'conf.h'
set `wc -c 'conf.h'`
count=$1
case $count in
610) :;;
*) echo 'Bad character count in ''conf.h' >&2
echo 'Count should be 610' >&2
esac
echo Extracting 'dp8390.c'
sed 's/^X//' > 'dp8390.c' << '+ END-OF-FILE ''dp8390.c'
X
X#include "../h/const.h"
X
X#ifndef NONET
X
X#include "../h/error.h"
X#include "../h/type.h"
X#include "../h/com.h"
X#include "const.h"
X#include "internet.h"
X#include "etherformat.h"
X#include "dp8390.h"
X#include "dp8390info.h"
X#include "dp8390stat.h"
X#include "assert.h"
X
X/* macros for device I/O */
X#define PIC_enable() port_out(INT_CTL,ENABLE)
X
X#define input(devaddr, dp_register) \
X inbyte((vir_bytes)&((union dp8390reg *) devaddr)->dp_pg0rd.dp_register)
X#define input1(devaddr, dp_register) \
X inbyte((vir_bytes)&((union dp8390reg *) devaddr)->dp_pg1rdwr.dp_register)
X#define output(devaddr, dp_register, value) \
X outbyte((vir_bytes)&((union dp8390reg *) devaddr)->dp_pg0wr.dp_register, value)
X#define output1(devaddr, dp_register, value) \
X outbyte((vir_bytes)&((union dp8390reg *) devaddr)->dp_pg1rdwr.dp_register, value)
X
X#define MAX_WAIT 10000
X
X#ifdef DPSTAT
Xstruct dpstat dpstat;
X#endif
X
Xstatic int (*bufread)(); /* call when packet came in */
Xstatic int (*bufwritten)(); /* call when packet has been written */
X
Xstatic disabled;
Xstatic phys_bytes curopacket; /* packet being transmitted */
Xstatic phys_bytes Curbuff; /* address of next read buffer to release */
X
X
Xstatic
Xchipinit(myaddr)
XEth_addr *myaddr;
X{
X register vir_bytes device;
X
X device = dp8390info.dpi_devaddr;
X output(device, dp_cr, CR_PS_P0|CR_DM_ABORT); /* back to main register set */
X output(device, dp_pstart, dp8390info.dpi_pstart);
X output(device, dp_pstop, dp8390info.dpi_pstop);
X output(device, dp_bnry, dp8390info.dpi_pstart);
X output(device, dp_rcr, RCR_MON);
X output(device, dp_tcr, TCR_NORMAL);
X output(device, dp_dcr, DCR_BYTEWIDE|DCR_8BYTES);
X output(device, dp_rbcr0, 0);
X output(device, dp_rbcr1, 0);
X output(device, dp_isr, 0xFF);
X output(device, dp_cr, CR_PS_P1|CR_DM_ABORT); /* switch to register set 1 */
X output1(device, dp_par0, myaddr->e[0]);
X output1(device, dp_par1, myaddr->e[1]);
X output1(device, dp_par2, myaddr->e[2]);
X output1(device, dp_par3, myaddr->e[3]);
X output1(device, dp_par4, myaddr->e[4]);
X output1(device, dp_par5, myaddr->e[5]);
X output1(device, dp_curr, dp8390info.dpi_pstart+1);
X output1(device, dp_cr, CR_PS_P0|CR_DM_ABORT);
X output(device, dp_rcr, RCR_AB);
X input(device, dp_cntr0);
X input(device, dp_cntr1);
X input(device, dp_cntr2);
X
X#ifdef TRMTINT
X output(device, dp_imr, IMR_TXEE|IMR_PTXE|IMR_PRXE|IMR_CNTE|IMR_OVWE);
X#endif
X output(device, dp_imr, IMR_PRXE|IMR_CNTE|IMR_OVWE);
X output(device, dp_cr, CR_STA|CR_DM_ABORT); /* fire it up */
X}
X
X/*
X * Interrupt handling
X */
X
Xstatic
Xdp_xmit_intr()
X#ifdef TRMTINT
X{
X register tsr;
X
X if (curopacket == 0) {
X printf("Bogus transmit interrupt\n");
X STINC(ds_btint);
X return;
X }
X tsr = input(dp8390info.dpi_devaddr, dp_tsr);
X if (tsr&TSR_PTX)
X STINC(ds_written); /* It went OK! */
X if (tsr&TSR_DFR)
X STINC(ds_deferred);
X if (tsr&TSR_COL)
X STINC(ds_collisions);
X if (tsr&TSR_ABT)
X STINC(ds_xcollisions);
X if (tsr&TSR_CRS) {
X printf("Ethernet carrier sense lost\n");
X STINC(ds_carlost);
X }
X if (tsr&TSR_FU) {
X printf("Ethernet Fifo Underrun\n");
X STINC(ds_fifo);
X }
X if (tsr&TSR_CDH) {
X printf("Ethernet Heartbeat failure\n");
X STINC(ds_heartbeat);
X }
X if (tsr&TSR_OWC) {
X printf("Ethernet late collision\n");
X STINC(ds_lcol);
X }
X (*bufwritten)(curopacket);
X curopacket = 0;
X}
X#else
X{}
X#endif
X
X
Xstatic
Xrecvintr()
X{
X register vir_bytes device;
X register phys_bytes paddr;
X struct rcvdheader pkthead;
X char pageno, curr, next;
X int length;
X
X device = dp8390info.dpi_devaddr;
X pageno=input(device, dp_bnry)+1;
X if (pageno == dp8390info.dpi_pstop)
X pageno = dp8390info.dpi_pstart;
X while (!(disabled)) {
X output(device, dp_cr, CR_PS_P1);/* switch to register set 1 */
X curr = input1(device, dp_curr);
X output1(device, dp_cr, CR_PS_P0);/* back to main register set */
X if (pageno==curr)
X break;
X STINC(ds_read);
X paddr = dp8390info.dpi_membase+(pageno<<8);
X getheader(paddr, &pkthead);
X next = pkthead.rp_next;
X if (pkthead.rp_status&RSR_PRX) {
X if (next < pageno && next > dp8390info.dpi_pstart) {
X /*
X * We copy end of packet to avoid break.
X */
X phys_copy(dp8390info.dpi_membase+
X (dp8390info.dpi_pstart<<8),
X dp8390info.dpi_membase+
X (dp8390info.dpi_pstop<<8),
X (phys_bytes) (next-dp8390info.dpi_pstart)<<8);
X }
X length = (pkthead.rp_rbcl&0xFF)|(pkthead.rp_rbch<<8);
X Curbuff = paddr + sizeof (pkthead);
X disabled = 1;
X (*bufread)(Curbuff, length-4);
X }
X pageno = pkthead.rp_next;
Xif (pageno >= dp8390info.dpi_pstop || pageno < dp8390info.dpi_pstart)
X printf("page no %x\n", pageno);
X assert(pageno >= dp8390info.dpi_pstart);
X assert(pageno < dp8390info.dpi_pstop);
X }
X}
X
Xstatic
Xcntintr()
X{
X register vir_bytes device;
X int n;
X
X printf("dp8390: counter overflow\n"); /*DEBUG*/
X device = dp8390info.dpi_devaddr;
X n = input(device, dp_cntr0);
X STADD(ds_fram, n);
X n = input(device, dp_cntr1);
X STADD(ds_crc, n);
X n =input(device, dp_cntr2);
X STADD(ds_lost, n);
X}
X
Xdp8390_int()
X{
X register isr;
X register vir_bytes device;
X
X PIC_enable();
X device = dp8390info.dpi_devaddr;
X for(isr=input(device, dp_isr); isr&(ISR_OVW|ISR_PRX|ISR_PTX|ISR_CNT);
X isr=input(device, dp_isr)) {
X if (isr&ISR_OVW) {
X printf("OVW, do something\n");
X output(device, dp_isr, ISR_OVW); /* ack */
X }
X if (isr&ISR_PTX) {
X dp_xmit_intr();
X output(device, dp_isr, ISR_PTX); /* ack */
X }
X if (isr&ISR_TXE) {
X dp_xmit_intr();
X output(device, dp_isr, ISR_TXE); /* ack */
X }
X if (isr&ISR_PRX) {
X recvintr();
X output(device, dp_isr, ISR_PRX); /* ack */
X }
X if (isr&ISR_CNT) {
X cntintr();
X output(device, dp_isr, ISR_CNT); /* ack */
X }
X }
X}
X
Xeth_init(etheraddr, br, bw)
XEth_addr *etheraddr;
Xint (*br)(), (*bw)();
X{
X bufread = br;
X bufwritten = bw;
X epl_init(); /* activate on board memory */
X chipinit(etheraddr); /* start ethernet controller chip */
X}
X
X
X
Xeth_write(bufaddr, bufcnt)
Xphys_bytes bufaddr;
X{
X int bpageno;
X register vir_bytes device;
X
X device = dp8390info.dpi_devaddr;
X/* assert(curopacket==0); */
X assert(((bufaddr-dp8390info.dpi_membase)&0xFF)==0);
X assert(bufcnt >= 60); /* magic Ethernet requirement */
X/* assert(bufcnt <= 1514); /* another one */
X bpageno = ((bufaddr-dp8390info.dpi_membase)>>8) & 0xFF;
X curopacket = bufaddr;
X output(device, dp_tpsr, bpageno);
X output(device, dp_tbcr1, bufcnt>>8);
X output(device, dp_tbcr0, bufcnt&0xFF);
X output(device, dp_cr, CR_TXP); /* there it goes */
X}
X
Xeth_release(bufaddr)
Xphys_bytes bufaddr;
X{
X register vir_bytes device;
X register phys_bytes paddr;
X struct rcvdheader pkthead;
X char pageno;
X int old_state;
X
X device = dp8390info.dpi_devaddr;
X paddr = bufaddr-sizeof(pkthead);
X assert(((paddr-dp8390info.dpi_membase)&0xFF)==0);
X getheader(paddr, &pkthead);
X pageno = pkthead.rp_next;
X if (pageno == dp8390info.dpi_pstart)
X pageno = dp8390info.dpi_pstop;
X if (bufaddr != Curbuff)
X panic("eth_release: bad order", NO_NUM);
X output(device, dp_bnry, pageno-1);
X disabled = 0;
X old_state = lock();
X recvintr();
X restore(old_state);
X}
X
Xphys_bytes
Xeth_getbuf()
X{
X int t_cnt;
X register vir_bytes device;
X register tsr;
X
X device = dp8390info.dpi_devaddr;
X
X t_cnt = 0;
X while (input(device,dp_cr)&CR_TXP) {
X if (t_cnt++ > MAX_WAIT)
X printf("transmitter frozen\n");
X return (phys_bytes)0;
X }
X
X#ifndef TRMTINT
X#ifdef DPSTAT
X tsr = input(device, dp_tsr);
X if (tsr&TSR_PTX)
X STINC(ds_written); /* It went OK! */
X if (tsr&TSR_DFR)
X STINC(ds_deferred);
X if (tsr&TSR_COL)
X STINC(ds_collisions);
X if (tsr&TSR_ABT)
X STINC(ds_xcollisions);
X if (tsr&TSR_CRS) {
X printf("Ethernet carrier sense lost\n");
X STINC(ds_carlost);
X }
X if (tsr&TSR_FU) {
X printf("Ethernet Fifo Underrun\n");
X STINC(ds_fifo);
X }
X if (tsr&TSR_CDH) {
X printf("Ethernet Heartbeat failure\n");
X STINC(ds_heartbeat);
X }
X if (tsr&TSR_OWC) {
X printf("Ethernet late collision\n");
X STINC(ds_lcol);
X }
X#endif
X#endif
X return dp8390info.dpi_tbuf; /* return pointer to xmit buffer */
X}
X
X#else NONET
X
XPUBLIC
Xdp8390_int()
X{
X}
X
X#endif NONET
X
X#ifdef i8088
X
XPUBLIC
Xeth_stp()
X{
X/* called from reboot() (klib88.s) to stop the ethernet */
X#ifndef NONET
X output(dp8390info.dpi_devaddr, dp_cr, CR_STP|CR_DM_ABORT);
X
X#endif
X}
X
X#endif i8088
+ END-OF-FILE dp8390.c
chmod 'u=rw,g=r,o=r' 'dp8390.c'
set `wc -c 'dp8390.c'`
count=$1
case $count in
8277) :;;
*) echo 'Bad character count in ''dp8390.c' >&2
echo 'Count should be 8277' >&2
esac
echo Extracting 'dp8390.h'
sed 's/^X//' > 'dp8390.h' << '+ END-OF-FILE ''dp8390.h'
X/*
X * National Semiconductor DP8390 Network Interface Controller
X */
X
Xtypedef
Xunion dp8390reg {
X struct pg0rd { /* Page 0, for reading ------------- */
X char dp_cr; /* Read side of Command Register */
X char dp_clda0; /* Current Local Dma Address 0 */
X char dp_clda1; /* Current Local Dma Address 1 */
X char dp_bnry; /* Boundary Pointer */
X char dp_tsr; /* Transmit Status Register */
X char dp_ncr; /* Number of Collisions Register */
X char dp_fifo; /* Fifo ?? */
X char dp_isr; /* Interrupt Status Register */
X char dp_crda0; /* Current Remote Dma Address 0 */
X char dp_crda1; /* Current Remote Dma Address 1 */
X char dp_dum1; /* unused */
X char dp_dum2; /* unused */
X char dp_rsr; /* Receive Status Register */
X char dp_cntr0; /* Tally Counter 0 */
X char dp_cntr1; /* Tally Counter 1 */
X char dp_cntr2; /* Tally Counter 2 */
X } dp_pg0rd;
X struct pg0wr { /* Page 0, for writing ------------- */
X char dp_cr; /* Write side of Command Register */
X char dp_pstart; /* Page Start Register */
X char dp_pstop; /* Page Stop Register */
X char dp_bnry; /* Boundary Pointer */
X char dp_tpsr; /* Transmit Page Start Register */
X char dp_tbcr0; /* Transmit Byte Count Register 0 */
X char dp_tbcr1; /* Transmit Byte Count Register 1 */
X char dp_isr; /* Interrupt Status Register */
X char dp_rsar0; /* Remote Start Address Register 0 */
X char dp_rsar1; /* Remote Start Address Register 1 */
X char dp_rbcr0; /* Remote Byte Count Register 0 */
X char dp_rbcr1; /* Remote Byte Count Register 1 */
X char dp_rcr; /* Receive Configuration Register */
X char dp_tcr; /* Transmit Configuration Register */
X char dp_dcr; /* Data Configuration Register */
X char dp_imr; /* Interrupt Mask Register */
X } dp_pg0wr;
X struct pg1rdwr { /* Page 1, read/write -------------- */
X char dp_cr; /* Command Register */
X char dp_par0; /* Physical Address Register 0 */
X char dp_par1; /* Physical Address Register 1 */
X char dp_par2; /* Physical Address Register 2 */
X char dp_par3; /* Physical Address Register 3 */
X char dp_par4; /* Physical Address Register 4 */
X char dp_par5; /* Physical Address Register 5 */
X char dp_curr; /* Current Page Register */
X char dp_mar0; /* Multicast Address Register 0 */
X char dp_mar1; /* Multicast Address Register 1 */
X char dp_mar2; /* Multicast Address Register 2 */
X char dp_mar3; /* Multicast Address Register 3 */
X char dp_mar4; /* Multicast Address Register 4 */
X char dp_mar5; /* Multicast Address Register 5 */
X char dp_mar6; /* Multicast Address Register 6 */
X char dp_mar7; /* Multicast Address Register 7 */
X } dp_pg1rdwr;
X} dp8390;
X
X/* Bits in dp_cr */
X
X#define CR_STP 0x01 /* Stop: software reset */
X#define CR_STA 0x02 /* Start: activate NIC */
X#define CR_TXP 0x04 /* Transmit Packet */
X#define CR_DMA 0x38 /* Mask for DMA control */
X# define CR_DM_NOP 0x00 /* DMA: No Operation */
X# define CR_DM_RR 0x08 /* DMA: Remote Read */
X# define CR_DM_RW 0x10 /* DMA: Remote Write */
X# define CR_DM_SP 0x18 /* DMA: Send Packet */
X# define CR_DM_ABORT 0x20 /* DMA: Abort Remote DMA Operation */
X#define CR_PS 0xC0 /* Mask for Page Select */
X# define CR_PS_P0 0x00 /* Register Page 0 */
X# define CR_PS_P1 0x40 /* Register Page 1 */
X# define CR_PS_T0 0x80 /* Test Mode Register Map ?? */
X# define CR_SP_T1 0xC0 /* Test Mode Register Map ?? */
X
X/* Bits in dp_isr */
X
X#define ISR_PRX 0x01 /* Packet Received with no errors */
X#define ISR_PTX 0x02 /* Packet Transmitted with no errors */
X#define ISR_RXE 0x04 /* Receive Error */
X#define ISR_TXE 0x08 /* Transmit Error */
X#define ISR_OVW 0x10 /* Overwrite Warning */
X#define ISR_CNT 0x20 /* Counter Overflow */
X#define ISR_RDC 0x40 /* Remote DMA Complete */
X#define ISR_RST 0x80 /* Reset Status */
X
X/* Bits in dp_imr */
X
X#define IMR_PRXE 0x01 /* Packet Received iEnable */
X#define IMR_PTXE 0x02 /* Packet Transmitted iEnable */
X#define IMR_RXEE 0x04 /* Receive Error iEnable */
X#define IMR_TXEE 0x08 /* Transmit Error iEnable */
X#define IMR_OVWE 0x10 /* Overwrite Warning iEnable */
X#define IMR_CNTE 0x20 /* Counter Overflow iEnable */
X#define IMR_RDCE 0x40 /* DMA Complete iEnable */
X
X/* Bits in dp_dcr */
X
X#define DCR_WTS 0x01 /* Word Transfer Select */
X# define DCR_BYTEWIDE 0x00 /* WTS: byte wide transfers */
X# define DCR_WORDWIDE 0x01 /* WTS: word wide transfers */
X#define DCR_BOS 0x02 /* Byte Order Select */
X# define DCR_LTLENDIAN 0x00 /* BOS: Little Endian */
X# define DCR_BIGENDIAN 0x02 /* BOS: Big Endian */
X#define DCR_LAS 0x04 /* Long Address Select */
X#define DCR_BMS 0x08 /* Burst Mode Select */
X#define DCR_AR 0x10 /* Autoinitialize Remote */
X#define DCR_FTS 0x60 /* Fifo Threshold Select */
X# define DCR_2BYTES 0x00 /* 2 bytes */
X# define DCR_4BYTES 0x40 /* 4 bytes */
X# define DCR_8BYTES 0x20 /* 8 bytes */
X# define DCR_12BYTES 0x60 /* 12 bytes */
X
X/* Bits in dp_tcr */
X
X#define TCR_CRC 0x01 /* Inhibit CRC */
X#define TCR_ELC 0x06 /* Encoded Loopback Control */
X# define TCR_NORMAL 0x00 /* ELC: Normal Operation */
X# define TCR_INTERNAL 0x02 /* ELC: Internal Loopback */
X# define TCR_0EXTERNAL 0x04 /* ELC: External Loopback LPBK=0 */
X# define TCR_1EXTERNAL 0x06 /* ELC: External Loopback LPBK=1 */
X#define TCR_ATD 0x08 /* Auto Transmit */
X#define TCR_OFST 0x10 /* Collision Offset Enable (be nice) */
X
X/* Bits in dp_tsr */
X
X#define TSR_PTX 0x01 /* Packet Transmitted (without error)*/
X#define TSR_DFR 0x02 /* Transmit Deferred */
X#define TSR_COL 0x04 /* Transmit Collided */
X#define TSR_ABT 0x08 /* Transmit Aborted */
X#define TSR_CRS 0x10 /* Carrier Sense Lost */
X#define TSR_FU 0x20 /* Fifo Underrun */
X#define TSR_CDH 0x40 /* CD Heartbeat */
X#define TSR_OWC 0x80 /* Out of Window Collision */
X
X/* Bits in tp_rcr */
X
X#define RCR_SEP 0x01 /* Save Errored Packets */
X#define RCR_AR 0x02 /* Accept Runt Packets */
X#define RCR_AB 0x04 /* Accept Broadcast */
X#define RCR_AM 0x08 /* Accept Multicast */
X#define RCR_PRO 0x10 /* Physical Promiscuous */
X#define RCR_MON 0x20 /* Monitor Mode */
X
X/* Bits in dp_rsr */
X
X#define RSR_PRX 0x01 /* Packet Received Intact */
X#define RSR_CRC 0x02 /* CRC Error */
X#define RSR_FAE 0x04 /* Frame Alignment Error */
X#define RSR_FO 0x08 /* FIFO Overrun */
X#define RSR_MPA 0x10 /* Missed Packet */
X#define RSR_PHY 0x20 /* Multicast Address Match !! */
X#define RSR_DIS 0x40 /* Receiver Disabled */
X
X
Xstruct rcvdheader {
X char rp_status; /* Copy of rsr */
X char rp_next; /* Pointer to next packet */
X char rp_rbcl; /* Receive Byte Count Low */
X char rp_rbch; /* Receive Byte Count High */
X};
+ END-OF-FILE dp8390.h
chmod 'u=rw,g=r,o=r' 'dp8390.h'
set `wc -c 'dp8390.h'`
count=$1
case $count in
8035) :;;
*) echo 'Bad character count in ''dp8390.h' >&2
echo 'Count should be 8035' >&2
esac
echo Extracting 'dp8390info.h'
sed 's/^X//' > 'dp8390info.h' << '+ END-OF-FILE ''dp8390info.h'
X/*
X * parameters for driver for
X * National Semiconductor DP8390 Network Interface Controller
X */
X
Xextern
Xstruct dp8390info {
X vir_bytes dpi_devaddr; /* device address */
X char dpi_pstart; /* start of recv ring */
X char dpi_pstop; /* end of recv ring */
X phys_bytes dpi_membase; /* memory address of page 0 */
X phys_bytes dpi_tbuf; /* memory address of transmit buffer */
X} dp8390info;
X
+ END-OF-FILE dp8390info.h
chmod 'u=rw,g=r,o=r' 'dp8390info.h'
set `wc -c 'dp8390info.h'`
count=$1
case $count in
402) :;;
*) echo 'Bad character count in ''dp8390info.h' >&2
echo 'Count should be 402' >&2
esac
echo Extracting 'dp8390stat.h'
sed 's/^X//' > 'dp8390stat.h' << '+ END-OF-FILE ''dp8390stat.h'
X#ifdef DPSTAT
X/* statistics from dp8390 */
Xstruct dpstat {
X long ds_read; /* packets read */
X long ds_written; /* packets written */
X long ds_fram; /* Input framing errors */
X long ds_crc; /* Input CRC errors */
X long ds_lost; /* Packets lost */
X long ds_btint; /* Bogus transmit interrupts */
X long ds_deferred; /* Deferred packets */
X long ds_collisions; /* Packets collided at least once */
X long ds_xcollisions; /* Aborts due to excessive collisions */
X long ds_carlost; /* Carrier sense lost */
X long ds_fifo; /* Fifo underrun */
X long ds_heartbeat; /* Heart beat failure */
X long ds_lcol; /* Late collisions */
X};
X#define STINC(x) dpstat.x++
X#define STADD(x,y) dpstat.x += y
X#else
X#define STINC(x) /* nothing */
X#define STADD(x,y) /* nothing */
X#endif DPSTAT
+ END-OF-FILE dp8390stat.h
chmod 'u=rw,g=r,o=r' 'dp8390stat.h'
set `wc -c 'dp8390stat.h'`
count=$1
case $count in
821) :;;
*) echo 'Bad character count in ''dp8390stat.h' >&2
echo 'Count should be 821' >&2
esac
echo Extracting 'eplinfo.h'
sed 's/^X//' > 'eplinfo.h' << '+ END-OF-FILE ''eplinfo.h'
X/*
X * parameters for initialisation of
X * Western Digital Ethercard Plus, or WD8003E
X */
X
Xextern
Xstruct eplinfo {
X vir_bytes epi_devaddr; /* device address */
X} eplinfo;
X
+ END-OF-FILE eplinfo.h
chmod 'u=rw,g=r,o=r' 'eplinfo.h'
set `wc -c 'eplinfo.h'`
count=$1
case $count in
181) :;;
*) echo 'Bad character count in ''eplinfo.h' >&2
echo 'Count should be 181' >&2
esac
echo Extracting 'etherformat.h'
sed 's/^X//' > 'etherformat.h' << '+ END-OF-FILE ''etherformat.h'
X/* Format of packets on the Ethernet */
X
X#define AMOEBAPROTO 0x8145 /* Official Ethernet protocol number */
X
X#define ETHERBITS 0x80 /* These addresses on Ethernet */
X
Xtypedef struct
X{
X char e[6];
X} Eth_addr;
X
Xtypedef struct
X{
X Eth_addr f_dstaddr;
X Eth_addr f_srcaddr;
X unshort f_proto;
X struct pktheader f_ah;
X} Framehdr;
X
Xtypedef struct
X{
X Framehdr ep_fr;
X char ep_data[1490];
X} Etherpacket;
+ END-OF-FILE etherformat.h
chmod 'u=rw,g=r,o=r' 'etherformat.h'
set `wc -c 'etherformat.h'`
count=$1
case $count in
404) :;;
*) echo 'Bad character count in ''etherformat.h' >&2
echo 'Count should be 404' >&2
esac
echo Extracting 'etherplus.c'
sed 's/^X//' > 'etherplus.c' << '+ END-OF-FILE ''etherplus.c'
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/com.h"
X#include "const.h"
X#include "dp8390.h"
X#include "internet.h"
X#include "etherformat.h"
X#include "etherplus.h"
X#include "dp8390info.h"
X#include "eplinfo.h"
X#include "assert.h"
X
X/* macros for device I/O */
X
X#define input(devaddr, ep_register) \
X inbyte((vir_bytes)&((struct eplusreg *) devaddr)->ep_register)
X#define output(devaddr, ep_register, value) \
X outbyte((vir_bytes)&((struct eplusreg *) devaddr)->ep_register, value)
X
Xepl_init() {
X register vir_bytes device;
X register sum;
X
X device = eplinfo.epi_devaddr;
X assert((dp8390info.dpi_membase&0x81FFF)==0x80000);
X sum =
X input(device, epl_ea5) +
X input(device, epl_ea4) +
X input(device, epl_ea3) +
X input(device, epl_ea2) +
X input(device, epl_ea1) +
X input(device, epl_ea0) +
X input(device, epl_res2) +
X input(device, epl_chksum);
X if ((sum&0xFF) != 0xFF)
X panic("No ethernet board", NO_NUM);
X output(device, epl_ctlstatus, CTL_RESET);
X output(device, epl_ctlstatus, CTL_MENABLE|((dp8390info.dpi_membase>>13)&CTL_MEMADDR));
X}
X
X
Xetheraddr(eaddr) Eth_addr *eaddr; {
X register vir_bytes device;
X
X device = eplinfo.epi_devaddr;
X eaddr->e[0] = input(device, epl_ea0);
X eaddr->e[1] = input(device, epl_ea1);
X eaddr->e[2] = input(device, epl_ea2);
X eaddr->e[3] = input(device, epl_ea3);
X eaddr->e[4] = input(device, epl_ea4);
X eaddr->e[5] = input(device, epl_ea5);
X}
+ END-OF-FILE etherplus.c
chmod 'u=rw,g=r,o=r' 'etherplus.c'
set `wc -c 'etherplus.c'`
count=$1
case $count in
1390) :;;
*) echo 'Bad character count in ''etherplus.c' >&2
echo 'Count should be 1390' >&2
esac
echo Extracting 'etherplus.h'
sed 's/^X//' > 'etherplus.h' << '+ END-OF-FILE ''etherplus.h'
X/*
X * Western Digital Ethercard Plus, or WD8003E card
X *
X * This information seems to be guarded like the crown jewels
X */
X
Xstruct eplusreg {
X char epl_ctlstatus; /* Control(write) and status(read) */
X char epl_res1[7];
X char epl_ea0; /* Most significant eaddr byte */
X char epl_ea1;
X char epl_ea2;
X char epl_ea3;
X char epl_ea4;
X char epl_ea5; /* Least significant eaddr byte */
X char epl_res2;
X char epl_chksum; /* sum from epl_ea0 upto here is 0xFF */
X dp8390 epl_dp8390; /* NatSemi chip */
X};
X
X/* Bits in epl_ctlstatus */
X
X#define CTL_RESET 0x80 /* Software Reset */
X#define CTL_MENABLE 0x40 /* Memory Enable */
X#define CTL_MEMADDR 0x3F /* Bits SA18-SA13, SA19 implicit 1 */
X
X#define STA_IIJ 0x7 /* Interrupt Indication Jumpers */
+ END-OF-FILE etherplus.h
chmod 'u=rw,g=r,o=r' 'etherplus.h'
set `wc -c 'etherplus.h'`
count=$1
case $count in
826) :;;
*) echo 'Bad character count in ''etherplus.h' >&2
echo 'Count should be 826' >&2
esac
echo Extracting 'exception.h'
sed 's/^X//' > 'exception.h' << '+ END-OF-FILE ''exception.h'
X#define CRASH ((unshort) 0xFF)
+ END-OF-FILE exception.h
chmod 'u=rw,g=r,o=r' 'exception.h'
set `wc -c 'exception.h'`
count=$1
case $count in
32) :;;
*) echo 'Bad character count in ''exception.h' >&2
echo 'Count should be 32' >&2
esac
echo Extracting 'global.h'
sed 's/^X//' > 'global.h' << '+ END-OF-FILE ''global.h'
X/****************************************************************************/
X/* */
X/* (c) Copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands */
X/* */
X/* This product is part of the Amoeba distributed operating system. */
X/* */
X/* Permission to use, sell, duplicate or disclose this software must be */
X/* obtained in writing. Requests for such permissions may be sent to */
X/* */
X/* */
X/* Dr. Andrew S. Tanenbaum */
X/* Dept. of Mathematics and Computer Science */
X/* Vrije Universiteit */
X/* Postbus 7161 */
X/* 1007 MC Amsterdam */
X/* The Netherlands */
X/* */
X/****************************************************************************/
X
X#define KERNEL 0
X#define USER 1
X
Xtypedef unshort address;
Xtypedef int func;
X
X#define bufptr vir_bytes
X
X#define NOWHERE ((address) 0)
X#define SOMEWHERE ((address) -1)
X#define NILVECTOR ((func (*)()) 0)
X
X#ifdef lint
X#define ABSPTR(t, c) (use(c), (t) 0)
X#else
X#define ABSPTR(t, c) ((t) (c))
X#endif
X
X#define bit(b) (1 << (b)) /* simulate type 'bit' */
X
X#define lobyte(x) ((unshort) (x) & 0xFF)
X#define hibyte(x) ((unshort) (x) >> 8)
X#define concat(x, y) ((unshort) (x) << 8 | (unshort) (y) & 0xFF)
X
X#define sizeoftable(t) (sizeof(t) / sizeof((t)[0]))
+ END-OF-FILE global.h
chmod 'u=rw,g=r,o=r' 'global.h'
set `wc -c 'global.h'`
count=$1
case $count in
1354) :;;
*) echo 'Bad character count in ''global.h' >&2
echo 'Count should be 1354' >&2
esac
echo Extracting 'internet.h'
sed 's/^X//' > 'internet.h' << '+ END-OF-FILE ''internet.h'
X/****************************************************************************/
X/* */
X/* (c) Copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands */
X/* */
X/* This product is part of the Amoeba distributed operating system. */
X/* */
X/* Permission to use, sell, duplicate or disclose this software must be */
X/* obtained in writing. Requests for such permissions may be sent to */
X/* */
X/* */
X/* Dr. Andrew S. Tanenbaum */
X/* Dept. of Mathematics and Computer Science */
X/* Vrije Universiteit */
X/* Postbus 7161 */
X/* 1007 MC Amsterdam */
X/* The Netherlands */
X/* */
X/****************************************************************************/
X
X#define PACKETSIZE 1490 /* network packet size - sizeof(framehdr) */
X
X#define BROADCAST ((address) 0xFF)
X
X#define TYPE 0x0F /* message types */
X#define LOCATE 0x01
X#define HERE 0x02
X#define REQUEST 0x03
X#define REPLY 0x04
X#define ACK 0x05
X#define NAK 0x06
X#define ENQUIRY 0x07
X#define ALIVE 0x08
X#define DEAD 0x09
X
X#define LAST 0x10 /* flags */
X#define RETRANS 0x20
X
Xstruct pktheader {
X char ph_dstnode; /* 0: destination node */
X char ph_srcnode; /* 1: source node */
X char ph_dsttask; /* 2: destination task */
X char ph_srctask; /* 3: source task */
X char ph_ident; /* 4: transaction identifier */
X char ph_seq; /* 5: fragment no. */
X unshort ph_size; /* 6: total size of this packet */
X char ph_flags; /* 8: some flags (not used) */
X char ph_type; /* 9: locate, here, data, ack or nak (!= 0) */
X};
X
X#define ph_signal ph_seq
X
X#define NOSEND 0
X#define SEND 1
X
X#define DONTKNOW 0
X#define LOCAL 1
X#define GLOBAL 2
X
X#define siteaddr(x) lobyte(x)
X#define tasknum(x) hibyte(x)
X
X#define pktfrom(ph) ((unshort) (ph->ph_srctask<<8 | ph->ph_srcnode & 0xFF))
X#define pktto(ph) ((unshort) (ph->ph_dsttask<<8 | ph->ph_dstnode & 0xFF))
+ END-OF-FILE internet.h
chmod 'u=rw,g=r,o=r' 'internet.h'
set `wc -c 'internet.h'`
count=$1
case $count in
1958) :;;
*) echo 'Bad character count in ''internet.h' >&2
echo 'Count should be 1958' >&2
esac
echo Extracting 'makefile'
sed 's/^X//' > 'makefile' << '+ END-OF-FILE ''makefile'
X# The kernel dir contains xt_wini.c and at_wini.c. Before running make
X# you must copy one of these to wini.c, depending on which controller you
X# have. If you do not have a hard disk, you MUST choose one of them at random.
X# On a PC, cpp and cem are in /lib and will be removed to make space while
X# linking the kernel. On an AT, they are in /usr/lib are are not removed.
X# This is because they have to be in /lib on a PC; the diskette is too small
X# for them to be in /usr/lib. You can change this by editing commands/cc.c.
X#
X# Normally, MINIX scrolls the screen using the 6845's registers. However,
X# on some EGA cards (those that are not IBM compatible), the 6845 is not
X# properly emulated. On these machines, it is necessary to scroll in
X# software by copying. This is much slower, but it works. The CFLAGS flags are:
X#
X# -Di8088 - required on an 8088/80286/80386 CPU; forbidden on a 68000
X# -F - run cpp and cem sequentially (used when memory is tight)
X# -T. - put temporaries in working directory (when RAM disk is small)
X# -DAM_KERNEL - includes code for Amoeba transactions
X# -DNONET - single machine, no Ethernet available (requires -DAM_KERNEL)
X# -DSTATISTICS - include code to collect Ethernet statistics
X#
X# Machines wishing to use Amoeba transactions should add -DAM_KERNEL to CFLAGS.
X# If there is no ethernet connection then also add -DNONET. The ethernet
X# driver included in this distribution is for the Western Digital Ethercard
X# Plus. If you want ethernet statistics then add -DSTATISTICS to CFLAGS.
X#
X# When making a kernel on a machine with limited RAM disk, it may be
X# necessary to use -T. or even remove /lib/cem and /lib/cpp during asld.
X#
XCFLAGS = -DAM_KERNEL -Di8088 -F -I../../kernel -I.
XA = ../h
XH = ../../h
XK = ../../kernel
XLIB = /usr/lib
X
XOBJ = ../../kernel/mpx88.s main.s tty.s floppy.s wini.s system.s proc.s \
X clock.s memory.s printer.s amoeba.s conf.s dp8390.s util.s \
X etherplus.s portcache.s trans.s table.s ../../kernel/klib88.s dmp.s
X
X
XCOBJS = main.s tty.s floppy.s wini.s system.s proc.s clock.s memory.s \
X amoeba.s conf.s dp8390.s util.s etherplus.s portcache.s trans.s \
X printer.s table.s dmp.s
X
X
Xkernel: makefile $(OBJ) $(LIB)/libc.a
X @echo "Start linking Kernel."
X @asld -o kernel $(OBJ) $(LIB)/libc.a $(LIB)/end.s
X @echo "Kernel done. "
X
Xclean:
X rm -f $(COBJS) kernel
X
Xclock.s: $K/const.h $K/type.h $H/const.h $H/type.h
Xclock.s: $H/callnr.h
Xclock.s: $H/com.h
Xclock.s: $H/error.h
Xclock.s: $H/signal.h
Xclock.s: $K/glo.h
Xclock.s: $K/proc.h
Xclock.s: $K/clock.c
X $(CC) $(CFLAGS) -c $K/clock.c
X
Xdmp.s: $K/const.h $K/type.h $H/const.h $H/type.h
Xdmp.s: $H/callnr.h
Xdmp.s: $H/com.h
Xdmp.s: $H/error.h
Xdmp.s: $K/glo.h
Xdmp.s: $K/proc.h
Xdmp.s: $K/dmp.c
X $(CC) $(CFLAGS) -c $K/dmp.c
X
Xfloppy.s: $K/const.h $K/type.h $H/const.h $H/type.h
Xfloppy.s: $H/callnr.h
Xfloppy.s: $H/com.h
Xfloppy.s: $H/error.h
Xfloppy.s: $K/glo.h
Xfloppy.s: $K/proc.h
Xfloppy.s: $K/floppy.c
X $(CC) $(CFLAGS) -c $K/floppy.c
X
Xmain.s: $K/const.h $K/type.h $H/const.h $H/type.h
Xmain.s: $H/callnr.h
Xmain.s: $H/com.h
Xmain.s: $H/error.h
Xmain.s: $K/glo.h
Xmain.s: $K/proc.h
Xmain.s: $K/main.c
X $(CC) $(CFLAGS) -c $K/main.c
X
Xmemory.s: $K/const.h $K/type.h $H/const.h $H/type.h
Xmemory.s: $H/callnr.h
Xmemory.s: $H/com.h
Xmemory.s: $H/error.h
Xmemory.s: $K/proc.h
Xmemory.s: $K/memory.c
X $(CC) $(CFLAGS) -c $K/memory.c
X
Xprinter.s: $K/const.h $K/type.h $H/const.h $H/type.h
Xprinter.s: $H/callnr.h
Xprinter.s: $H/com.h
Xprinter.s: $H/error.h
Xprinter.s: $K/proc.h
Xprinter.s: $K/glo.h
Xprinter.s: $K/printer.c
X $(CC) $(CFLAGS) -c $K/printer.c
X
Xproc.s: $K/const.h $K/type.h $H/const.h $H/type.h
Xproc.s: $H/callnr.h
Xproc.s: $H/com.h
Xproc.s: $H/error.h
Xproc.s: $K/glo.h
Xproc.s: $K/proc.h
Xproc.s: $K/proc.c
X $(CC) $(CFLAGS) -c $K/proc.c
X
Xsystem.s: $K/const.h $K/type.h $H/const.h $H/type.h
Xsystem.s: $H/callnr.h
Xsystem.s: $H/com.h
Xsystem.s: $H/error.h
Xsystem.s: $H/signal.h
Xsystem.s: $K/glo.h
Xsystem.s: $K/proc.h
Xsystem.s: $K/system.c
X $(CC) $(CFLAGS) -c $K/system.c
X
Xtable.s: $K/const.h $K/type.h $H/const.h $H/type.h $H/com.h
Xtable.s: $K/glo.h
Xtable.s: $K/proc.h
Xtable.s: $K/table.c
X $(CC) $(CFLAGS) -c $K/table.c
X
Xtty.s: $K/const.h $K/type.h $H/const.h $H/type.h
Xtty.s: $H/callnr.h
Xtty.s: $H/com.h
Xtty.s: $H/error.h
Xtty.s: $H/sgtty.h
Xtty.s: $H/signal.h
Xtty.s: $K/glo.h
Xtty.s: $K/proc.h
Xtty.s: $K/tty.c
X $(CC) $(CFLAGS) -c $K/tty.c
X
Xwini.s: $K/const.h $K/type.h $H/const.h $H/type.h
Xwini.s: $H/callnr.h
Xwini.s: $H/com.h
Xwini.s: $H/error.h
Xwini.s: $K/proc.h
Xwini.s: $K/wini.c
X $(CC) $(CFLAGS) -c $K/wini.c
X
Xamoeba.s: $A/amoeba.h
Xamoeba.s: $A/host_os.h
Xamoeba.s: $A/amparam.h
Xamoeba.s: $H/signal.h
Xamoeba.s: $H/type.h
Xamoeba.s: ./assert.h
Xamoeba.s: ./byteorder.h
Xamoeba.s: $K/const.h
Xamoeba.s: ./dp8390info.h
Xamoeba.s: ./etherformat.h
Xamoeba.s: $K/glo.h
Xamoeba.s: ./global.h
Xamoeba.s: ./internet.h
Xamoeba.s: ./mpx.H
Xamoeba.s: ./portcache.H
Xamoeba.s: $K/proc.h
Xamoeba.s: ./task.h
Xamoeba.s: ./trans.H
Xamoeba.s: $K/type.h
Xamoeba.s: amoeba.c
Xconf.s: $A/amoeba.h
Xconf.s: $A/host_os.h
Xconf.s: $H/type.h
Xconf.s: ./conf.h
Xconf.s: ./global.h
Xconf.s: ./mpx.H
Xconf.s: ./portcache.H
Xconf.s: ./task.h
Xconf.s: ./trans.H
Xconf.s: conf.c
Xdp8390.s: $H/com.h
Xdp8390.s: $H/const.h
Xdp8390.s: $H/error.h
Xdp8390.s: $H/type.h
Xdp8390.s: ./assert.h
Xdp8390.s: $K/const.h
Xdp8390.s: ./dp8390.h
Xdp8390.s: ./dp8390info.h
Xdp8390.s: ./dp8390stat.h
Xdp8390.s: ./etherformat.h
Xdp8390.s: ./internet.h
Xdp8390.s: dp8390.c
Xetherplus.s: $H/com.h
Xetherplus.s: $H/const.h
Xetherplus.s: $H/type.h
Xetherplus.s: ./assert.h
Xetherplus.s: $K/const.h
Xetherplus.s: ./dp8390.h
Xetherplus.s: ./dp8390info.h
Xetherplus.s: ./eplinfo.h
Xetherplus.s: ./etherformat.h
Xetherplus.s: ./etherplus.h
Xetherplus.s: ./internet.h
Xetherplus.s: etherplus.c
Xportcache.s: $A/amoeba.h
Xportcache.s: $H/const.h
Xportcache.s: $A/host_os.h
Xportcache.s: $H/type.h
Xportcache.s: ./assert.h
Xportcache.s: ./conf.h
Xportcache.s: $K/const.h
Xportcache.s: ./global.h
Xportcache.s: ./internet.h
Xportcache.s: ./mpx.H
Xportcache.s: ./portcache.H
Xportcache.s: ./task.h
Xportcache.s: ./trans.H
Xportcache.s: portcache.c
Xtrans.s: $A/amoeba.h
Xtrans.s: $H/const.h
Xtrans.s: $A/host_os.h
Xtrans.s: $H/type.h
Xtrans.s: ./amstat.h
Xtrans.s: ./assert.h
Xtrans.s: ./byteorder.h
Xtrans.s: $K/const.h
Xtrans.s: ./exception.h
Xtrans.s: ./global.h
Xtrans.s: ./internet.h
Xtrans.s: ./mpx.H
Xtrans.s: ./portcache.H
Xtrans.s: ./task.h
Xtrans.s: ./trans.H
Xtrans.s: trans.c
Xutil.s: $H/com.h
Xutil.s: $H/const.h
Xutil.s: $H/type.h
Xutil.s: ./assert.h
Xutil.s: $K/const.h
Xutil.s: ./dp8390.h
Xutil.s: ./dp8390info.h
Xutil.s: ./eplinfo.h
Xutil.s: $K/proc.h
Xutil.s: $K/type.h
Xutil.s: util.c
+ END-OF-FILE makefile
chmod 'u=rw,g=r,o=r' 'makefile'
set `wc -c 'makefile'`
count=$1
case $count in
6567) :;;
*) echo 'Bad character count in ''makefile' >&2
echo 'Count should be 6567' >&2
esac
echo Extracting 'mpx.H'
sed 's/^X//' > 'mpx.H' << '+ END-OF-FILE ''mpx.H'
X/****************************************************************************/
X/* */
X/* (c) Copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands */
X/* */
X/* This product is part of the Amoeba distributed operating system. */
X/* */
X/* Permission to use, sell, duplicate or disclose this software must be */
X/* obtained in writing. Requests for such permissions may be sent to */
X/* */
X/* */
X/* Dr. Andrew S. Tanenbaum */
X/* Dept. of Mathematics and Computer Science */
X/* Vrije Universiteit */
X/* Postbus 7161 */
X/* 1007 MC Amsterdam */
X/* The Netherlands */
X/* */
X/****************************************************************************/
X
Xstruct mpx {
X short MX_active; /* is a transaction in progress */
X unshort MX_flags; /* flags - see below */
X int MX_proc_nr; /* task identifier */
X header MX_hdr; /* storage space for header */
X} tk_mpx;
X
X#ifdef MPX
X
X#define mx_flags tk_mpx.MX_flags
X#define mx_active tk_mpx.MX_active
X#define mx_proc_nr tk_mpx.MX_proc_nr
X#define mx_hdr tk_mpx.MX_hdr
X
X
X/* bits in flags: */
X#define RUNNABLE bit(0) /* task is runnable */
X#define NESTED bit(1) /* nested getreq, trans or putrep */
X#define BETWEEN bit(2) /* between getreq and putrep */
X#else
X
X#define tk_mpx tk_dummy /* other modules must not touch it */
X
X#endif
+ END-OF-FILE mpx.H
chmod 'u=rw,g=r,o=r' 'mpx.H'
set `wc -c 'mpx.H'`
count=$1
case $count in
1427) :;;
*) echo 'Bad character count in ''mpx.H' >&2
echo 'Count should be 1427' >&2
esac
echo Extracting 'portcache.H'
sed 's/^X//' > 'portcache.H' << '+ END-OF-FILE ''portcache.H'
X/****************************************************************************/
X/* */
X/* (c) Copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands */
X/* */
X/* This product is part of the Amoeba distributed operating system. */
X/* */
X/* Permission to use, sell, duplicate or disclose this software must be */
X/* obtained in writing. Requests for such permissions may be sent to */
X/* */
X/* */
X/* Dr. Andrew S. Tanenbaum */
X/* Dept. of Mathematics and Computer Science */
X/* Vrije Universiteit */
X/* Postbus 7161 */
X/* 1007 MC Amsterdam */
X/* The Netherlands */
X/* */
X/****************************************************************************/
X
Xstruct portcache {
X address PE_location;
X struct task *PE_link;
X} tk_portcache;
X
X#ifdef PORTCACHE
X
X#define pe_location tk_portcache.PE_location
X#define pe_link tk_portcache.PE_link
X
X#else
X
X#define tk_portcache tk_dummy /* other modules must not touch it */
X
X#endif
X
X#define NOWAIT 0
X#define WAIT 1
X
X#define LOOK 0
X#define DELETE 1
+ END-OF-FILE portcache.H
chmod 'u=rw,g=r,o=r' 'portcache.H'
set `wc -c 'portcache.H'`
count=$1
case $count in
1139) :;;
*) echo 'Bad character count in ''portcache.H' >&2
echo 'Count should be 1139' >&2
esac
echo Extracting 'portcache.c'
sed 's/^X//' > 'portcache.c' << '+ END-OF-FILE ''portcache.c'
X/****************************************************************************/
X/* */
X/* (c) Copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands */
X/* */
X/* This product is part of the Amoeba distributed operating system. */
X/* */
X/* Permission to use, sell, duplicate or disclose this software must be */
X/* obtained in writing. Requests for such permissions may be sent to */
X/* */
X/* */
X/* Dr. Andrew S. Tanenbaum */
X/* Dept. of Mathematics and Computer Science */
X/* Vrije Universiteit */
X/* Postbus 7161 */
X/* 1007 MC Amsterdam */
X/* The Netherlands */
X/* */
X/****************************************************************************/
X
X#define NDEBUG
X#define PORTCACHE
X
X/*
X * This module does the port management. It keeps track of the local servers
X * doing a ``getreq'' on a port, local clients waiting for a server on some
X * port, and interlocal servers addressed by some port. This last category of
X * ports may be forgotten, or may be incorrect.
X *
X * The following routines are defined:
X * portinstall(port, where, wait);
X * portlookup(port, wait, delete);
X * portremove(port, location);
X * portquit(port, task);
X *
X * ``Portinstall'' is called when a port is assumed to be at location
X * ``where.'' If ``wait'' is set, the port is local.
X * ``Portlookup'' is called to find a port in the cache. If ``wait'' is
X * set, the routine will block until the port is found. If ``delete'' is
X * set, the port must be removed when it is found.
X * ``Portremove'' removes a port from the cache which is thought
X * of to be at the specified location.
X * When a port doesn't have to be located anymore for some task, ``portquit''
X * takes care of that.
X */
X
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/amoeba.h"
X#include "const.h"
X#include "global.h"
X#include "task.h"
X#include "internet.h"
X#include "assert.h"
X
Xextern struct task task[];
X
X#ifdef STATISTICS
X#include "portstat.h"
X
Xstruct portstat portstat;
X#define STINC(x) portstat.x++
X#else
X#define STINC(x)
X#endif
X
X#include "conf.h"
X
X#define LOGHASH 5 /* log sizeof hash table of local ports */
X
Xstruct porttab {
X port p_port; /* the port this entry is about */
X unshort p_idle; /* idle timer */
X address p_location; /* where is it? (0 = being located) */
X address p_asker; /* address of someone interested */
X struct porttab *p_nextport; /* port with same hash value */
X struct task *p_tasklist; /* list of tasks */
X};
X
X#define NILPORTTAB ((struct porttab *) 0)
X
X#define NHASH (1 << LOGHASH)
X#define HASHMASK (NHASH - 1)
X
X#define hash(p) (* (unshort *) (p) & HASHMASK)
X
X/* MINIX can't allocate memory in the kernel at run-time
Xextern unshort nport;
XPRIVATE struct porttab *porttab, *lastport, *hashtab[NHASH], *portfree;
X*/
XPRIVATE struct porttab porttab[NPORTS];
XPRIVATE struct porttab *lastport, *hashtab[NHASH], *portfree;
X
X#ifndef NONET
X#ifndef NOCLIENT
X
X#define NLOCATE 8 /* max. number of ports to locate */
XPRIVATE port loctab[NLOCATE];
XPRIVATE unshort loccnt, loctim, locthissweep;
Xextern unshort minloccnt, maxloccnt;
X
X#endif
X#endif
X
X/* Allocate an entry in the hash table at location ``ht.'' */
Xstatic struct porttab *allocate(ht, p)
Xstruct porttab **ht;
Xport *p;
X{
X register struct porttab *pt;
X
X STINC(pts_alloc);
X if ((pt=portfree) == 0) {
X STINC(pts_full);
X portpurge(); /* total cleanup, not likely to happen */
X if ((pt=portfree) == 0)
X return 0;
X }
X portfree = pt->p_nextport;
X pt->p_nextport = *ht;
X *ht = pt;
X pt->p_port = *p;
X return pt;
X}
X
X/* Install a port in the hash table. If ``wait'' is set, the location will
X * be this machine and is certain. If not, the location is somewhere else
X * and uncertain.
X */
Xportinstall(p, where, wait)
Xregister port *p;
Xaddress where;
X{
X register struct porttab **ht, *pt;
X register struct task *t;
X extern address local;
X
X ht = &hashtab[hash(p)];
X for (pt = *ht; pt != NILPORTTAB; pt = pt->p_nextport)
X if (PortCmp(&pt->p_port, p)) {
X if (pt->p_location == SOMEWHERE) {
X compare(pt->p_tasklist, !=, NILTASK);
X do {
X t = pt->p_tasklist;
X t->pe_location = where;
X STINC(pts_wakeup);
X wakeup((event_t) &t->pe_location);
X } while ((pt->p_tasklist = t->pe_link) != NILTASK);
X }
X#ifndef NOCLIENT
X else if (siteaddr(pt->p_location) == local && !wait &&
X pt->p_tasklist != 0)
X return;
X#endif
X break;
X }
X if (pt == NILPORTTAB && (pt = allocate(ht, p)) == NILPORTTAB)
X#ifndef NOCLIENT
X if (wait)
X#endif
X panic("portcache full for servers", 0x8000);
X#ifndef NOCLIENT
X else /* no room left, so forget it */
X return;
X#endif
X pt->p_location = where;
X#ifndef NOCLIENT
X if (wait) { /* task is going to await a client, so leave it immortal */
X#endif
X compare(area(where), ==, LOCAL);
X t = &task[tasknum(where)];
X t->pe_location = where;
X t->pe_link = pt->p_tasklist;
X pt->p_tasklist = t;
X#ifndef NONET
X if (pt->p_asker != NOWHERE) {
X STINC(pts_here);
X hereport(pt->p_asker, p, (unsigned )1);
X pt->p_asker = NOWHERE;
X }
X#endif
X#ifndef NOCLIENT
X }
X#endif
X pt->p_idle = 0;
X}
X
X#ifndef NONET
X#ifndef NOCLIENT
X/* Broadcast a locate message
X */
Xstatic sendloc(){
X register struct porttab *pt;
X register unsigned n = 0;
X
X if (locthissweep) {
X /* During this clocktick we already sent out a broadcast packet.
X * To prevent buggy userprograms from creating a broadcast storm
X * we do not send another one, we just prepare for it to be done
X */
X STINC(pts_nolocate);
X loccnt = maxloccnt;
X return;
X }
X for (pt = porttab; pt < lastport; pt++)
X if (pt->p_location == SOMEWHERE) {
X loctab[n++] = pt->p_port;
X if (n == NLOCATE)
X break;
X }
X if (n) {
X locthissweep = 1;
X whereport(loctab, n); /* send out the broadcast locate */
X } else
X loctim = 0; /* No locates necessary anymore */
X loccnt = 0;
X}
X
X#endif NOCLIENT
X#endif NONET
X
X/* Look whether port p is in the portcache. You can specify whether you
X * want to wait for the information and whether you want to delete it.
X */
Xaddress portlookup(p, wait, del)
Xregister port *p;
X{
X register struct porttab **ht, *pt;
X register struct task *c, *t;
X register address location;
X
X STINC(pts_lookup);
X ht = &hashtab[hash(p)];
X for (pt = *ht; pt != NILPORTTAB; pt = pt->p_nextport)
X if (PortCmp(&pt->p_port, p)) { /* found it */
X location = pt->p_location;
X switch (area(location)) {
X case LOCAL: /* local server */
X if (pt->p_tasklist == 0)
X break;
X if (del) { /* remove it */
X pt->p_tasklist = pt->p_tasklist->pe_link;
X if ((t = pt->p_tasklist) != NILTASK)
X pt->p_location = t->pe_location;
X }
X pt->p_idle = 0;
X STINC(pts_flocal);
X return(location);
X
X case GLOBAL: /* remote server */
X compare(pt->p_tasklist, ==, NILTASK);
X pt->p_idle = 0;
X STINC(pts_fglobal);
X return(location);
X
X case DONTKNOW: /* somebody else wants to know too */
X compare(pt->p_tasklist, !=, NILTASK);
X break;
X
X default:
X assert(0);
X }
X break;
X }
X /* The port wasn't in the port cache */
X#ifndef NOCLIENT
X if (wait) { /* wait for it */
X if (pt == NILPORTTAB && (pt = allocate(ht, p)) == NILPORTTAB)
X panic("portcache full for clients", 0x8000);
X pt->p_location = SOMEWHERE;
X c = curtask;
X c->pe_link = pt->p_tasklist;
X pt->p_tasklist = c;
X#ifndef NONET
X STINC(pts_locate);
X sendloc();
X loctim = minloccnt;
X#endif
X c->pe_location = SOMEWHERE;
X if (sleep((event_t) &c->pe_location))
X assert(pt->p_tasklist != c);
X pt->p_idle = 0;
X return(c->pe_location);
X }
X else
X#endif NOCLIENT
X return(NOWHERE);
X}
X
X/* Port p isn't at location ``location'' anymore */
Xportremove(p, location)
Xport *p;
Xaddress location;
X{
X register struct porttab *pt, **ht;
X register struct task *t;
X
X for (ht = &hashtab[hash(p)]; (pt= *ht) != NILPORTTAB; ht = &pt->p_nextport)
X if (PortCmp(&pt->p_port, p)) {
X if (pt->p_location == location) {
X if ((t = pt->p_tasklist) != NILTASK) {
X compare(area(location), ==, LOCAL);
X compare(t->pe_location, ==, location);
X if ((pt->p_tasklist = t->pe_link) != NILTASK) {
X pt->p_location =
X pt->p_tasklist->pe_location;
X break;
X }
X } else {
X *ht = pt->p_nextport;
X pt->p_location = NOWHERE; /* for dump */
X pt->p_nextport = portfree;
X portfree = pt;
X }
X }
X else if ((t = pt->p_tasklist) != NILTASK)
X while (t->pe_link != NILTASK)
X if (t->pe_link->pe_location == location) {
X t->pe_link = t->pe_link->pe_link;
X break;
X }
X else
X t = t->pe_link;
X return;
X }
X}
X
X#ifndef NOCLIENT
X/* Task ``s'' isn't interested anymore */
Xportquit(p, s)
Xregister port *p;
Xregister struct task *s;
X{
X register struct porttab *pt, **ht;
X register struct task *t;
X
X for (ht = &hashtab[hash(p)]; (pt= *ht) != NILPORTTAB; ht = &pt->p_nextport)
X if (PortCmp(&pt->p_port, p)) {
X if (pt->p_location != SOMEWHERE)
X return;
X if ((t = pt->p_tasklist) == s) {
X if ((pt->p_tasklist = s->pe_link) == NILTASK) {
X *ht = pt->p_nextport;
X pt->p_location = NOWHERE; /* for dump */
X pt->p_nextport = portfree;
X portfree = pt;
X }
X s->pe_location = NOWHERE;
X wakeup((event_t) &s->pe_location);
X }
X else {
X while (t != NILTASK)
X if (t->pe_link == s) {
X t->pe_link = s->pe_link;
X s->pe_location = NOWHERE;
X wakeup((event_t) &s->pe_location);
X break;
X }
X else
X t = t->pe_link;
X }
X return;
X }
X}
X#endif NOCLIENT
X
X#ifndef NONET
X
X#define NHERE 8
XPRIVATE port heretab[NHERE];
X
Xportask(asker, ptab, nports) /* handle locate request */
Xaddress asker;
Xregister port *ptab;
Xunsigned nports;
X{
X register port *p,*q;
X register struct porttab **ht, *pt;
X register unsigned nfound;
X
X STINC(pts_portask);
X nfound = 0; q = heretab;
X for(p=ptab; nports--; p++) {
X ht = &hashtab[hash(p)];
X for (pt = *ht; pt != NILPORTTAB; pt = pt->p_nextport)
X if (PortCmp(&pt->p_port, p)) { /* found it */
X if (area(pt->p_location) == LOCAL) {
X if (pt->p_tasklist == 0) {
X /* just record someone was interested */
X pt->p_asker = asker;
X break;
X }
X if (nfound < NHERE) {
X *q++ = *p;
X nfound++;
X }
X pt->p_idle = 0;
X }
X }
X }
X if (nfound) {
X STINC(pts_portyes);
X hereport(asker, heretab, nfound);
X }
X}
X#endif
X
X#ifndef NDEBUG
Xportdump(){
X register struct porttab *pt;
X register struct task *t;
X
X printf("\n PORT LOCATION IDLE TASKS\n");
X for (pt = porttab; pt < lastport; pt++)
X if (pt->p_location != NOWHERE) {
X prport(&pt->p_port);
X printf(" %4x %4d", pt->p_location, pt->p_idle);
X for (t = pt->p_tasklist; t != NILTASK; t = t->pe_link)
X printf(" {%d, %x}", t - task, t->pe_location);
X printf("\n");
X }
X}
X#endif
X
X/* Initialize tables and free list */
Xportinit(){
X register struct porttab *pt;
X
X/* MINIX can't allocate data in the kernel at run-time
X extern char *aalloc();
X
X porttab = (struct porttab *) aalloc(nport * sizeof(struct porttab), 0);
X lastport = &porttab[nport];
X*/
X lastport = &porttab[NPORTS];
X for (pt = porttab; pt < lastport; pt++) {
X pt->p_nextport = portfree;
X portfree = pt;
X }
X}
X
X/* called when freelist was empty, will throw away all mortal ports */
Xportpurge() {
X register struct porttab *pt,**ht,**htp;
X
X for (htp=hashtab; htp< &hashtab[NHASH]; htp++) {
X ht = htp;
X while ((pt = *ht) != 0) {
X if (pt->p_tasklist == 0){
X *ht = pt->p_nextport;
X pt->p_location = NOWHERE; /* for dump */
X pt->p_nextport = portfree;
X portfree = pt;
X } else
X ht = &pt->p_nextport;
X }
X }
X}
X
X#define MAXSWEEP 3000 /* dseconds maximum idle time for port */
X#define SWEEPRESOLUTION 100 /* accuracy */
X
Xportsweep() {
X register struct porttab *pt,**ht,**htp;
X static unshort cnt;
X
X#ifndef NOCLIENT
X#ifndef NONET
X locthissweep = 0;
X if (loctim && ++loccnt > loctim) { /* send a locate message */
X STINC(pts_relocate);
X sendloc();
X loctim <<= 1;
X if (loctim > maxloccnt)
X loctim = maxloccnt;
X locthissweep = 0;
X }
X#endif NONET
X#endif
X if (++cnt<SWEEPRESOLUTION)
X return;
X for (htp=hashtab; htp< &hashtab[NHASH]; htp++) {
X ht = htp;
X while ((pt = *ht) != 0) {
X if (pt->p_tasklist == 0 && (pt->p_idle += cnt) > MAXSWEEP) {
X *ht = pt->p_nextport;
X pt->p_location = NOWHERE; /* for dump */
X pt->p_nextport = portfree;
X portfree = pt;
X STINC(pts_aged);
X } else
X ht = &pt->p_nextport;
X }
X }
X cnt=0;
X}
+ END-OF-FILE portcache.c
chmod 'u=rw,g=r,o=r' 'portcache.c'
set `wc -c 'portcache.c'`
count=$1
case $count in
12260) :;;
*) echo 'Bad character count in ''portcache.c' >&2
echo 'Count should be 12260' >&2
esac
echo Extracting 'portstat.h'
sed 's/^X//' > 'portstat.h' << '+ END-OF-FILE ''portstat.h'
Xstruct portstat {
X long pts_alloc;
X long pts_aged;
X long pts_full;
X long pts_wakeup;
X long pts_here;
X long pts_lookup;
X long pts_flocal;
X long pts_fglobal;
X long pts_portask;
X long pts_portyes;
X long pts_locate;
X long pts_nolocate;
X long pts_relocate;
X};
+ END-OF-FILE portstat.h
chmod 'u=rw,g=r,o=r' 'portstat.h'
set `wc -c 'portstat.h'`
count=$1
case $count in
255) :;;
*) echo 'Bad character count in ''portstat.h' >&2
echo 'Count should be 255' >&2
esac
echo Extracting 'task.h'
sed 's/^X//' > 'task.h' << '+ END-OF-FILE ''task.h'
X/****************************************************************************/
X/* */
X/* (c) Copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands */
X/* */
X/* This product is part of the Amoeba distributed operating system. */
X/* */
X/* Permission to use, sell, duplicate or disclose this software must be */
X/* obtained in writing. Requests for such permissions may be sent to */
X/* */
X/* */
X/* Dr. Andrew S. Tanenbaum */
X/* Dept. of Mathematics and Computer Science */
X/* Vrije Universiteit */
X/* Postbus 7161 */
X/* 1007 MC Amsterdam */
X/* The Netherlands */
X/* */
X/****************************************************************************/
X
X#ifdef BUFFERED /* HACK */
X#define BUFSIZE 100
X#define NETBUF ((buffer) -1)
X
Xtypedef unshort buffer;
X#endif
X
Xstruct task {
X
X#include "mpx.H" /* mpx module */
X#include "trans.H" /* trans module */
X#include "portcache.H" /* portcache module */
X char *tk_aux; /* auxiliary pointer */
X /* really a hack to make process task more efficient */
X
X};
X
Xextern struct task *curtask, *uppertask;
Xextern unshort ntask;
X
X#define NILTASK ((struct task *) 0)
+ END-OF-FILE task.h
chmod 'u=rw,g=r,o=r' 'task.h'
set `wc -c 'task.h'`
count=$1
case $count in
1259) :;;
*) echo 'Bad character count in ''task.h' >&2
echo 'Count should be 1259' >&2
esac
echo Extracting 'trans.H'
sed 's/^X//' > 'trans.H' << '+ END-OF-FILE ''trans.H'
X/****************************************************************************/
X/* */
X/* (c) Copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands */
X/* */
X/* This product is part of the Amoeba distributed operating system. */
X/* */
X/* Permission to use, sell, duplicate or disclose this software must be */
X/* obtained in writing. Requests for such permissions may be sent to */
X/* */
X/* */
X/* Dr. Andrew S. Tanenbaum */
X/* Dept. of Mathematics and Computer Science */
X/* Vrije Universiteit */
X/* Postbus 7161 */
X/* 1007 MC Amsterdam */
X/* The Netherlands */
X/* */
X/****************************************************************************/
X
Xstruct trans {
X char TS_state; /* see below */
X char TS_flags; /* several flags - see below */
X char TS_clident; /* ident number for client */
X char TS_svident; /* ident number for server */
X char TS_ident; /* transaction identifier */
X char TS_seq; /* fragment sequence number */
X char TS_count; /* max. number timer may expire */
X char TS_signal; /* signal being sent to the server */
X unshort TS_addr; /* network address of this task */
X unshort TS_timer; /* timer, decremented every sweep */
X unshort TS_cltim; /* client crash timer */
X address TS_client; /* if serving: who's the client */
X address TS_server; /* if in trans: who's the server */
X port TS_portcache; /* this port was used the last time */
X header *TS_rhdr; /* saved param in getreq or trans */
X header *TS_xhdr; /* saved param in putrep or trans */
X bufptr TS_rbuf; /* receiver buffer */
X bufptr TS_xbuf; /* transmitter buffer */
X unshort TS_rcnt; /* size of rbuf */
X unshort TS_xcnt; /* size of xbuf */
X unshort TS_offset; /* offset in buffer */
X unshort TS_maxloc; /* max. location time in seconds */
X long TS_totloc; /* total location time in ticks */
X long TS_totsvr; /* total server time in ticks */
X#ifdef BUFFERED
X address TS_sender; /* task that sent the buffer */
X char *TS_savehdr; /* saved header pointer */
X buffer TS_buffer; /* buffer */
X unshort TS_bufcnt; /* buffer size */
X unshort TS_what; /* REQUEST or REPLY */
X#endif
X} tk_trans;
X
X#ifdef TRANS
X
X#define ts_state tk_trans.TS_state
X#define ts_flags tk_trans.TS_flags
X#define ts_clident tk_trans.TS_clident
X#define ts_svident tk_trans.TS_svident
X#define ts_ident tk_trans.TS_ident
X#define ts_seq tk_trans.TS_seq
X#define ts_timer tk_trans.TS_timer
X#define ts_count tk_trans.TS_count
X#define ts_signal tk_trans.TS_signal
X#define ts_addr tk_trans.TS_addr
X#define ts_cltim tk_trans.TS_cltim
X#define ts_client tk_trans.TS_client
X#define ts_server tk_trans.TS_server
X#define ts_portcache tk_trans.TS_portcache
X#define ts_rhdr tk_trans.TS_rhdr
X#define ts_xhdr tk_trans.TS_xhdr
X#define ts_rbuf tk_trans.TS_rbuf
X#define ts_xbuf tk_trans.TS_xbuf
X#define ts_rcnt tk_trans.TS_rcnt
X#define ts_xcnt tk_trans.TS_xcnt
X#define ts_offset tk_trans.TS_offset
X#define ts_maxloc tk_trans.TS_maxloc
X#define ts_totloc tk_trans.TS_totloc
X#define ts_totsvr tk_trans.TS_totsvr
X#define ts_sender tk_trans.TS_sender
X#define ts_savehdr tk_trans.TS_savehdr
X#define ts_buffer tk_trans.TS_buffer
X#define ts_bufcnt tk_trans.TS_bufcnt
X#define ts_what tk_trans.TS_what
X
X/* possible values of ts_state */
X#define IDLE 0
X#define SENDING 1
X#define DONE 2
X#define ACKED 3
X#define NACKED 4
X#define FAILED 5
X#define WAITBUF 6
X#define RECEIVING 7
X#define ABORT 8
X#define MEMFAULT 9
X
X/* possible flags in ts_flags */
X#define LOCATING bit(0) /* blocked in trans locating a port */
X#define PUTREQ bit(1) /* blocked in trans sending a request */
X#define GETREQ bit(2) /* blocked in getreq */
X#define PUTREP bit(3) /* blocked in putrep */
X#define GETREP bit(4) /* blocked in trans getting a reply */
X#define SERVING bit(5) /* running between getreq and putrep */
X
X#else
X
X#define tk_trans tk_dummy /* other modules must not touch it */
X
X#endif
+ END-OF-FILE trans.H
chmod 'u=rw,g=r,o=r' 'trans.H'
set `wc -c 'trans.H'`
count=$1
case $count in
4005) :;;
*) echo 'Bad character count in ''trans.H' >&2
echo 'Count should be 4005' >&2
esac
echo Extracting 'trans.c'
sed 's/^X//' > 'trans.c' << '+ END-OF-FILE ''trans.c'
X/****************************************************************************/
X/* */
X/* (c) Copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands */
X/* */
X/* This product is part of the Amoeba distributed operating system. */
X/* */
X/* Permission to use, sell, duplicate or disclose this software must be */
X/* obtained in writing. Requests for such permissions may be sent to */
X/* */
X/* */
X/* Dr. Andrew S. Tanenbaum */
X/* Dept. of Mathematics and Computer Science */
X/* Vrije Universiteit */
X/* Postbus 7161 */
X/* 1007 MC Amsterdam */
X/* The Netherlands */
X/* */
X/****************************************************************************/
X
X#define NDEBUG
X#define TRANS
X
X/*
X * This module implements the transaction mechanism. The transaction
X * calls are:
X * getreq(header, buffer, count);
X * putrep(header, buffer, count);
X * trans(hdr1, buf1, cnt1, hdr2, buf2, cnt2);
X *
X * ``Getreq'' is called by servers that want to wait for a request.
X * ``Putrep'' is called by servers that what to send a reply to a client.
X * ``Trans'' is called by clients that want to send a request to a server.
X * Requests are addressed by the ``h_port'' field in the header structure.
X * Replies are automatically sent back to the corresponding client. Between
X * a ``getreq'' and a ``putrep'' the server may not call ``getreq''. All
X * the three calls are blocking.
X *
X#ifndef NONET
X * The following network interface routines must be defined externally:
X *
X * puthead(dest, source, ident, seq, type, size);
X * append(data, size, send);
X * pickoff(data, size);
X *
X * ``Puthead'' is called first when a packet has to be sent. Among other
X * things the destination and the size are specified. If this size is zero,
X * the packet must be sent immediately.
X * ``Append'' is called when more data must be appended to a packet. The
X * ``send'' parameter is set when the packet can be sent.
X * ``Pickoff'' is called when a packet has arrived. The specified number
X * of bytes must copied to the specified data buffer.
X *
X * When a packet arrives, the local routine ``handle'' must be called:
X * handle(dest, source, ident, seq, type, size, hdr);
X * ``Hdr'' contains the first HEADERSIZE data bytes. With a call to
X * ``getall'' this buffer is enlarged to contain the full packet.
X#endif NONET
X */
X
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/amoeba.h"
X#include "const.h"
X#undef IDLE
X#include "byteorder.h"
X#include "exception.h"
X#include "global.h"
X#include "task.h"
X#include "internet.h"
X#include "amstat.h"
X#include "assert.h"
X
X#define send amsend
X#define received amreceived
Xextern struct task task[];
X
X#define FIRSTSIZE (PACKETSIZE - HEADERSIZE)
X
X#define MAXCNT 30000 /* maximum buffer size */
X
X#define taskptr(to) (&task[tasknum(to)])
X
Xextern port NULLPORT;
X
X#ifndef NONET
X#ifndef NOCLIENT
Xextern unshort maxcrash;
X#endif NOCLIENT
Xextern unshort retranstime, crashtime, clientcrash;
Xextern unshort maxretrans, mincrash;
X#endif
X
Xaddress local;
Xextern long ticker;
Xextern address portlookup();
Xextern phys_bytes umap();
X
X#ifdef STATISTICS
Xstruct amstat amstat;
X#endif
X#ifdef BUFFERED
X
X/* Some simple routines to test ``BUFFERED transactions''
X */
X
XPRIVATE char bufs[10][BUFSIZE];
XPRIVATE char used[11];
X
X#define NOBUF ((buffer) 0)
X
Xbuffer allocbuf(){
X register buffer b;
X
X for (b = 1; b <= 10; b++)
X if (!used[b]) {
X used[b] = 1;
X return(b);
X }
X#ifndef NDEBUG
X printf("out of buffers\n");
X#endif
X return(NOBUF);
X}
X
Xfreebuf(b)
Xbuffer b;
X{
X assert(used[b]);
X used[b] = 0;
X}
X
Xputbuf(b, addr, size)
Xbuffer b;
Xvir_bytes addr;
Xunshort size;
X{
X register phys_bytes pb;
X
X assert(used[b]);
X if ((pb = umap(curtask, addr, (vir_bytes) size)) == 0)
X return(0);
X phys_copy((phys_bytes) bufs[b - 1], pb, (phys_bytes) size);
X return(1);
X}
X
Xgetbuf(b, addr, size)
Xbuffer b;
Xvir_bytes addr;
Xunshort size;
X{
X register phys_bytes pb;
X
X assert(used[b]);
X if ((pb = umap(curtask, addr, (vir_bytes) size)) == 0)
X return(0);
X phys_copy(pb, (phys_bytes) bufs[b - 1], (phys_bytes) size);
X return(1);
X}
X
X#endif BUFFERED
X
X/* return where the ``location'' can be found:
X * DONTKNOW: the location is unknown;
X * LOCAL: it's on this machine;
X * GLOBAL: it's probably somewhere on the net.
X */
Xarea(location)
Xregister address location;
X{
X if (location == SOMEWHERE)
X return(DONTKNOW);
X if (siteaddr(location) == local)
X return(LOCAL);
X#ifdef NONET
X assert(0);
X /*NOTREACHED*/
X#else
X return(GLOBAL);
X#endif
X}
X
X/* (re)start getreq
X */
Xstatic getreqstart(t)
Xregister struct task *t;
X{
X t->ts_state = WAITBUF;
X t->ts_seq = 0;
X t->ts_offset = 0;
X portinstall(&t->ts_rhdr->h_port, t->ts_addr, WAIT);
X}
X
X#ifndef NONET /*--------------------------------------------------*/
X
Xstatic headerfromnet(hdr)
Xheader *hdr;
X{
X dec_s_be(&hdr->h_command);
X dec_s_be(&hdr->h_size);
X dec_l_be(&hdr->h_offset);
X dec_s_be(&hdr->h_extra);
X}
X
Xstatic headertonet(hdr)
Xheader *hdr;
X{
X enc_s_be(&hdr->h_command);
X enc_s_be(&hdr->h_size);
X enc_l_be(&hdr->h_offset);
X enc_s_be(&hdr->h_extra);
X}
X
X/* A locate message has arrived. This routine handles it by looking the
X * ports up in the cache, and if it finds some there that are local it
X * sends a reply back with those ports.
X */
X
Xstatic locreq(ph, ptab) /* handle locate request */
Xregister struct pktheader *ph;
Xregister char *ptab;
X{
X getall();
X portask(pktfrom(ph), (port *) ptab, ph->ph_size/PORTSIZE);
X netenable();
X}
X
X/* called from portcache.c */
Xhereport(asker, ptab, nports)
Xaddress asker;
Xport *ptab;
Xunsigned nports;
X{
X
X nports *= PORTSIZE;
X puthead(asker, local, 0, 0, HERE, nports);
X append((phys_bytes) ptab, nports, SEND);
X}
X
X#ifndef NOCLIENT
X
X/* called from portcache.c */
Xwhereport(ptab, nports)
Xport *ptab;
Xunsigned nports;
X{
X nports *= PORTSIZE;
X puthead(BROADCAST, local, 0, 0, LOCATE, nports);
X append((phys_bytes) ptab, nports, SEND);
X}
X
X/* start getrep
X */
Xstatic getrepstart(t)
Xregister struct task *t;
X{
X t->ts_flags &= ~PUTREQ;
X t->ts_state = WAITBUF;
X t->ts_seq = 0;
X t->ts_offset = 0;
X t->ts_flags |= GETREP;
X t->ts_timer = crashtime;
X t->ts_count = maxcrash;
X}
X
X/* A reply on a locate message has arrived. Store the ports in the cache.
X */
Xstatic here(ph, ptab) /* handle locate reply */
Xregister struct pktheader *ph;
Xregister char *ptab;
X{
X register port *p;
X register unshort from = pktfrom(ph);
X
X getall();
X p = ABSPTR(port *, ptab + ph->ph_size);
X while ((char *) --p >= ptab)
X portinstall(p, from, NOWAIT);
X netenable();
X}
X
X/* After I've enquired about the health of a server, the processor answered
X * that it's fine. Thank goodness. But keep asking.
X */
Xstatic alive(ph)
Xregister struct pktheader *ph;
X{
X register struct task *t = &task[ph->ph_dsttask & 0xFF];
X
X netenable();
X if (t->ts_server == pktfrom(ph) && t->ts_svident == ph->ph_ident &&
X (t->ts_flags & GETREP)) {
X t->ts_timer = crashtime;
X t->ts_count = maxcrash;
X t->ts_signal = 0;
X }
X}
X
X/* After I've enquired about the health of a server, the processor answered
X * that it's dead. Too bad. Notify client.
X */
Xstatic dead(ph)
Xregister struct pktheader *ph;
X{
X register struct task *t = &task[ph->ph_dsttask & 0xFF];
X
X netenable();
X if (t->ts_server == pktfrom(ph) && t->ts_svident == ph->ph_ident &&
X (t->ts_state == WAITBUF || t->ts_state == RECEIVING ||
X t->ts_state == SENDING) &&
X (t->ts_flags & (PUTREQ | GETREP))) {
X t->ts_timer = 0;
X t->ts_state = FAILED;
X wakeup((event_t) &t->ts_state);
X }
X}
X#endif NOCLIENT
X
X/* Someone enquires how a server doing. Inform him. A signal may be sent
X * along with the enquiry. Handle that.
X */
Xstatic enquiry(ph)
Xregister struct pktheader *ph;
X{
X register unshort from = pktfrom(ph), to = pktto(ph);
X register struct task *t = &task[ph->ph_dsttask & 0xFF];
X
X netenable();
X if (t->ts_client == from && t->ts_clident == ph->ph_ident) {
X if (t->ts_flags & SERVING) {
X t->ts_cltim = clientcrash;
X puthead(from, to, ph->ph_ident, 0, ALIVE, 0);
X if (ph->ph_signal != 0)
X putsig(t, (unshort) (ph->ph_signal & 0xFF));
X
X }
X }
X else
X puthead(from, to, ph->ph_ident, 0, DEAD, 0);
X}
X
X/* Send a fragment of a packet. If it's the first, insert the header.
X */
Xstatic sendfragment(t, what)
Xstruct task *t;
Xunshort what;
X{
X register address to;
X register short size = t->ts_xcnt - t->ts_offset;
X register phys_bytes xbuf;
X
X#ifndef NOCLIENT
X if (t->ts_flags & PUTREQ) {
X to = t->ts_server;
X what |= REQUEST;
X }
X else
X#endif
X {
X to = t->ts_client;
X what |= REPLY;
X }
X if (t->ts_seq == 0) { /* first fragment--append header */
X if (size <= FIRSTSIZE) /* first and last */
X what |= LAST;
X else { /* first but not last */
X size = (size + HEADERSIZE - 1) % PACKETSIZE - HEADERSIZE + 1;
X if (size < 0)
X size = 0;
X }
X puthead(to, t->ts_addr, t->ts_ident, t->ts_seq, (char) what,
X (unshort) size + HEADERSIZE);
X headertonet(t->ts_xhdr);
X append((phys_bytes) t->ts_xhdr, HEADERSIZE, size == 0 ? SEND : NOSEND);
X headerfromnet(t->ts_xhdr);
X }
X else { /* not first */
X if (size <= PACKETSIZE) /* last but not first */
X what |= LAST;
X else /* not first and not last */
X size = PACKETSIZE;
X puthead(to, t->ts_addr, t->ts_ident, t->ts_seq, (char) what,
X (unshort) size);
X }
X/*
X** a change from original trans code because on an ibmpc kernel virtual
X** addresses are different from kernel physical. therefore we must
X** replace call to append with am_doappend().
X*/
X if (size != 0)
X if ((xbuf = umap(t, (vir_bytes) (t->ts_xbuf + t->ts_offset),
X (vir_bytes) size)) == 0)
X return(0);
X else
X am_doappend(xbuf, (unshort) size, SEND);
X return(1);
X}
X
X/* Send a message. Call sendfragment to send the first fragment. When an
X * acknowledgement arrives, the interrupt routine handling it will send
X * the next fragment, if necessary.
X */
Xstatic send(){
X register struct task *c = curtask;
X register unshort what = 0;
X
X c->ts_state = SENDING;
X#ifdef NOCLIENT
X c->ts_ident = c->ts_clident;
X#else
X c->ts_ident = c->ts_flags & PUTREQ ? c->ts_svident : c->ts_clident;
X#endif
X c->ts_seq = 0;
X c->ts_count = maxretrans;
X do {
X if (!sendfragment(c, what)) {
X c->ts_state = MEMFAULT;
X return;
X }
X if (c->ts_state == SENDING) {
X c->ts_timer = retranstime;
X if (sleep((event_t) &c->ts_state)) {
X c->ts_timer = 0;
X c->ts_state = ABORT;
X return;
X }
X }
X if (c->ts_state == ACKED) {
X c->ts_state = SENDING;
X what = 0;
X }
X else /* if (c->ts_state == SENDING) */
X what = RETRANS;
X } while (c->ts_state == SENDING);
X}
X
X/* An acknowledgement for a fragment arrived. If it wasn't the last fragment,
X * send the next. Else if it was a putrep, restart the task. Else it was the
X * putreq part of a transaction, start up the getrep part.
X */
Xstatic gotack(ph)
Xregister struct pktheader *ph;
X{
X register unshort to = pktto(ph), from = pktfrom(ph);
X register struct task *t = &task[ph->ph_dsttask & 0xFF];
X
X netenable();
X if (t->ts_state == SENDING && t->ts_ident == ph->ph_ident &&
X t->ts_seq == ph->ph_seq) {
X if (ph->ph_seq == 0) { /* first fragment */
X register short size = t->ts_xcnt - t->ts_offset;
X
X#ifndef NOCLIENT
X if (t->ts_flags & PUTREQ)
X t->ts_server = from;
X else
X#endif
X if (t->ts_client != from)
X return;
X if (size > 0)
X size = (size + HEADERSIZE - 1) % PACKETSIZE
X - HEADERSIZE + 1;
X if (size > 0)
X t->ts_offset += size;
X }
X else
X t->ts_offset += PACKETSIZE;
X t->ts_timer = 0;
X if (t->ts_offset >= t->ts_xcnt) /* ack for last fragment */
X#ifndef NOCLIENT
X if (t->ts_flags & PUTREQ) { /* in a transaction */
X getrepstart(t);
X if (t->ts_signal != 0)
X puthead(from, to, ph->ph_ident, t->ts_signal,
X ENQUIRY, 0);
X }
X else
X#endif
X { /* putrep done */
X assert(t->ts_flags & PUTREP);
X t->ts_state = DONE;
X wakeup((event_t) &t->ts_state);
X }
X else {
X t->ts_seq++;
X#ifdef BUFFERED
X t->ts_timer = 0;
X t->ts_count = maxretrans;
X t->ts_state = ACKED;
X wakeup((event_t) &t->ts_state);
X#else
X if (sendfragment(t, 0)) {
X t->ts_timer = retranstime;
X t->ts_count = maxretrans;
X }
X else {
X t->ts_timer = 0;
X t->ts_state = MEMFAULT;
X wakeup((event_t) &t->ts_state);
X }
X#endif BUFFERED
X }
X }
X}
X
X#ifndef NOCLIENT
X/* A nak has arrived. Obviously the server was not at the assumed address.
X * Wake up the task, to do a new locate.
X */
Xstatic gotnak(ph)
Xregister struct pktheader *ph;
X{
X register struct task *t = &task[ph->ph_dsttask & 0xFF];
X
X netenable();
X if (t->ts_state == SENDING && t->ts_ident == ph->ph_ident && t->ts_seq == 0
X && (t->ts_flags & PUTREQ) && t->ts_server == (ph->ph_srcnode & 0xFF)) {
X t->ts_timer = 0;
X t->ts_state = NACKED;
X wakeup((event_t) &t->ts_state);
X }
X}
X#endif NOCLIENT
X
X/* A fragment has arrived. Get the data and see if more fragments are expected.
X */
Xstatic received(t, what, size, hdr)
Xstruct task *t;
Xchar what, *hdr;
Xunshort size;
X{
X register unshort cnt = t->ts_rcnt - t->ts_offset, n;
X register phys_bytes rbuf;
X
X if (cnt > size)
X cnt = size;
X if (cnt != 0) {
X rbuf = umap(t, (vir_bytes) (t->ts_rbuf+t->ts_offset), (vir_bytes) cnt);
X if (rbuf == 0) {
X netenable();
X t->ts_timer = 0;
X t->ts_state = MEMFAULT;
X wakeup((event_t) &t->ts_state);
X return;
X }
X t->ts_offset += cnt;
X if (t->ts_seq != 0) { /* copy the ``header'' */
X n = cnt < HEADERSIZE ? cnt : HEADERSIZE;
X/* kernel virtual != kernel physical under minix */
X am_phys_copy((vir_bytes)hdr, rbuf, (phys_bytes) n);
X rbuf += n;
X cnt -= n;
X }
X if (cnt != 0)
X pickoff(rbuf, cnt);
X }
X netenable();
X if (what & LAST) {
X t->ts_timer = 0;
X t->ts_state = DONE;
X#ifndef BUFFERED
X wakeup((event_t) &t->ts_state);
X#endif
X }
X else {
X t->ts_seq++;
X t->ts_timer = crashtime;
X t->ts_count = mincrash;
X t->ts_state = RECEIVING;
X }
X}
X
X#ifdef BUFFERED
X
X/* A network fragment is available. Wake up the waiting task.
X */
Xstatic gotbuffer(t, from, ident, what, size)
Xregister struct task *t;
Xaddress from;
Xchar ident, what;
Xunshort size;
X{
X assert(t->ts_state == WAITBUF || t->ts_state == RECEIVING);
X t->ts_sender = from;
X t->ts_ident = ident;
X t->ts_buffer = NETBUF;
X t->ts_bufcnt = size;
X t->ts_what = what;
X t->ts_timer = 0; /* shouldn't be necessary, but can't hurt */
X wakeup((event_t) &t->ts_state);
X}
X
X#endif BUFFERED
X
X/* See if someone is handling the request for `from.'
X */
Xstatic struct task *find(from, ident)
Xaddress from;
Xchar ident;
X{
X register struct task *t;
X
X for (t = task; t < uppertask; t++)
X if ((t->ts_flags & (GETREQ | SERVING | PUTREP)) &&
X t->ts_client == from && t->ts_clident == ident)
X return(t);
X return(NILTASK);
X}
X
X/* A request packet has arrived. Find out which task this packet should go to.
X * Send an acknowledgement if it can't do any harm.
X */
Xstatic gotrequest(ph, hdr)
Xregister struct pktheader *ph;
Xheader *hdr;
X{
X register struct task *t;
X register unsigned /* unshort */ from = pktfrom(ph), to, size = ph->ph_size;
X
X if (ph->ph_seq == 0) /* only the first fragment is really interesting */
X if ((ph->ph_type & RETRANS) &&
X (t = find(from, ph->ph_ident)) != NILTASK) {
X netenable(); /* ack got lost, send it again */
X puthead(from, t->ts_addr, ph->ph_ident, ph->ph_seq, ACK, 0);
X }
X else {
X register address location;
X
X location = portlookup(&hdr->h_port, NOWAIT, DELETE);
X if (location == NOWHERE || siteaddr(location) != local) {
X netenable();
X puthead(from, pktto(ph), ph->ph_ident, 0, NAK, 0);
X return;
X }
X size -= HEADERSIZE;
X t = taskptr(location);
X t->ts_client = from;
X t->ts_clident = ph->ph_ident;
X *t->ts_rhdr = *hdr;
X headerfromnet(t->ts_rhdr);
X#ifdef BUFFERED
X gotbuffer(t, from, ph->ph_ident, ph->ph_type, size);
X#else
X if ((ph->ph_type & (LAST | RETRANS)) != LAST)
X puthead(from, location, ph->ph_ident, 0, ACK, 0);
X received(t, ph->ph_type, size, (char *) 0);
X#endif BUFFERED
X }
X else { /* seq != 0 */
X to = pktto(ph);
X t = &task[ph->ph_dsttask & 0xFF];
X if (t->ts_state != RECEIVING || ph->ph_seq != t->ts_seq) {
X netenable();
X puthead(from, to, ph->ph_ident, ph->ph_seq, ACK, 0);
X }
X else {
X#ifdef BUFFERED
X t->ts_savehdr = (char *) hdr;
X gotbuffer(t, from, ph->ph_ident, ph->ph_type, size);
X#else
X puthead(from, to, ph->ph_ident, ph->ph_seq, ACK, 0);
X received(t, ph->ph_type, size, (char *) hdr);
X#endif BUFFERED
X }
X }
X}
X
X#ifndef NOCLIENT
X/* A reply packet has arrived. Send an acknowledgement if it can't do any
X * harm.
X */
Xstatic gotreply(ph, hdr)
Xregister struct pktheader *ph;
Xheader *hdr;
X{
X register unshort from = pktfrom(ph), to = pktto(ph), size = ph->ph_size;
X register struct task *t = &task[ph->ph_dsttask & 0xFF];
X
X if (ph->ph_ident != t->ts_svident || ph->ph_seq != t->ts_seq)
X t = NILTASK;
X else if ((t->ts_flags & GETREP) == 0)
X if (t->ts_flags & PUTREQ) { /* ack for request got lost */
X compare(t->ts_ident, ==, ph->ph_ident);
X getrepstart(t); /* start the getrep */
X t->ts_signal = 0;
X }
X else
X t = NILTASK;
X if (t != NILTASK) {
X if (ph->ph_seq == 0) {
X *t->ts_rhdr = *hdr;
X headerfromnet(t->ts_rhdr);
X size -= HEADERSIZE;
X }
X else if (t->ts_state != RECEIVING)
X t = NILTASK;
X }
X if (t == NILTASK) {
X netenable();
X puthead(from, to, ph->ph_ident, ph->ph_seq, ACK, 0);
X }
X else {
X#ifdef BUFFERED
X t->ts_savehdr = (char *) hdr;
X gotbuffer(t, from, ph->ph_ident, ph->ph_type, size);
X#else
X puthead(from, to, ph->ph_ident, ph->ph_seq, ACK, 0);
X received(t, ph->ph_type, size, (char *) hdr);
X#endif BUFFERED
X }
X}
X#endif NOCLIENT
X
X/* A packet has arrived. Call an appropiate routine, after checking some
X * things.
X */
Xpkthandle(ph, hdr)
Xregister struct pktheader *ph;
Xregister char *hdr;
X{
X if (ph->ph_dsttask < ntask && ph->ph_size <= PACKETSIZE)
X switch (ph->ph_type & TYPE) {
X case LOCATE:
X if (ph->ph_size == 0 || ph->ph_ident != 0 || ph->ph_seq != 0)
X break;
X if ((ph->ph_size % PORTSIZE) != 0)
X break;
X locreq(ph, hdr);
X return(1);
X case REQUEST:
X if (ph->ph_seq == 0 && ph->ph_size < HEADERSIZE)
X break;
X gotrequest(ph, ABSPTR(header *, hdr));
X return(1);
X case ACK:
X if (ph->ph_size != 0)
X break;
X gotack(ph);
X return(1);
X case ENQUIRY:
X if (ph->ph_size != 0)
X break;
X enquiry(ph);
X return(1);
X#ifndef NOCLIENT
X case HERE:
X if (ph->ph_size == 0 || ph->ph_ident != 0 || ph->ph_seq != 0)
X break;
X if ((ph->ph_size % PORTSIZE) != 0)
X break;
X here(ph, hdr);
X return(1);
X case REPLY:
X if (ph->ph_seq == 0 && ph->ph_size < HEADERSIZE)
X break;
X gotreply(ph, ABSPTR(header *, hdr));
X return(1);
X case NAK:
X if (ph->ph_size != 0 || ph->ph_seq != 0)
X break;
X gotnak(ph);
X return(1);
X case ALIVE:
X if (ph->ph_size != 0 || ph->ph_seq != 0)
X break;
X alive(ph);
X return(1);
X case DEAD:
X if (ph->ph_size != 0 || ph->ph_seq != 0)
X break;
X dead(ph);
X return(1);
X#endif
X case 0:
X return(0);
X }
X return(0);
X}
X
X#ifdef notdef /* don't need this for minix */
Xhandle(to, from, ident, seq, what, size, hdr) /* compatibility */
Xaddress to, from;
Xchar ident, seq, what;
Xunshort size;
Xchar *hdr;
X{
X struct pktheader ph;
X
X ph.ph_dstnode = siteaddr(to);
X ph.ph_srcnode = siteaddr(from);
X ph.ph_dsttask = tasknum(to);
X ph.ph_srctask = tasknum(from);
X ph.ph_ident = ident;
X ph.ph_seq = seq;
X ph.ph_size = size;
X ph.ph_type = what;
X return pkthandle(&ph, hdr);
X}
X
X#endif
X
X/* A timer has gone off too many times. See what went wrong. Restart the task.
X */
Xstatic failed(t)
Xregister struct task *t;
X{
X assert(t->ts_flags & (GETREQ | PUTREP | GETREP | PUTREQ));
X#ifndef NDEBUG
X if (t->ts_flags & (GETREQ | PUTREP))
X printf("%x: client %x failed (%d)\n", t - task,
X t->ts_client, t->ts_state);
X if (t->ts_flags & (GETREP | PUTREQ))
X printf("%x: server %x failed (%d)\n", t - task,
X t->ts_server, t->ts_state);
X#endif
X#ifdef STATISTICS
X if (t->ts_flags & (GETREQ | PUTREP))
X amstat.ams_clfail++;
X if (t->ts_flags & (GETREP | PUTREQ))
X amstat.ams_svfail++;
X#endif
X switch (t->ts_state) {
X case SENDING: /* Message didn't arrive */
X t->ts_state = FAILED;
X assert(t->ts_flags & (PUTREQ | PUTREP));
X break;
X case WAITBUF: /* server site has crashed */
X assert(t->ts_flags & GETREP);
X case RECEIVING:
X#ifndef NOCLIENT
X if (t->ts_flags & GETREP)
X t->ts_state = FAILED;
X else
X#endif
X {
X getreqstart(t); /* client failed, restart getreq */
X return;
X }
X break;
X default:
X assert(0);
X }
X wakeup((event_t) &t->ts_state);
X}
X
X/* A timer went off. See what is wrong.
X */
Xstatic again(t)
Xregister struct task *t;
X{
X switch (t->ts_state) {
X case SENDING: /* retransmit */
X#ifdef STATISTICS
X if (t->ts_flags & (GETREQ | PUTREP))
X amstat.ams_rxcl++;
X if (t->ts_flags & (GETREP | PUTREQ))
X amstat.ams_rxsv++;
X#endif
X#ifdef BUFFERED
X wakeup((event_t) &t->ts_state);
X#else
X if (!sendfragment(t, RETRANS))
X assert(0);
X t->ts_timer = retranstime;
X#endif
X break;
X case WAITBUF: /* Check if the server is still alive */
X assert(t->ts_flags & GETREP);
X case RECEIVING:
X#ifndef NOCLIENT
X if (t->ts_flags & GETREP) /* See if the other side is still there */
X puthead(t->ts_server, t->ts_addr, t->ts_svident,
X t->ts_signal, ENQUIRY, 0);
X#endif
X t->ts_timer = retranstime;
X break;
X default:
X assert(0);
X }
X}
X
X#endif NONET /*--------------------------------------------------*/
X
X/* First check all the timers. If any went off call the appropiate routine.
X * Then see if there are ports to locate.
X */
Xnetsweep(){
X register struct task *t;
X
X for (t = task; t < uppertask; t++) {
X if (t->ts_timer != 0 && --t->ts_timer == 0) /* timer expired */
X#ifndef NOCLIENT
X if (t->ts_flags & LOCATING)
X portquit(&t->ts_xhdr->h_port, t);
X#endif
X#ifndef NONET
X#ifndef NOCLIENT
X else
X#endif
X {
X compare(t->ts_count, !=, 0);
X if (--t->ts_count == 0) /* serious */
X failed(t);
X else /* try again */
X again(t);
X break;
X }
X if (t->ts_cltim != 0 && --t->ts_cltim == 0) { /* client crashed */
X#ifdef STATISTICS
X amstat.ams_clcrash++;
X#endif
X putsig(t, CRASH);
X }
X#endif NONET
X }
X}
X
X#ifdef BUFFERED
X
X/* Data has arrived. Get it. If there's more, wait for it.
X */
Xstatic recvbuf(){
X register struct task *c = curtask, *t;
X
X c->ts_state = WAITBUF;
X for (;;) {
X#ifndef NONET
X if (c->ts_buffer == NETBUF) { /* something from the net */
X c->ts_buffer = NOBUF;
X puthead(c->ts_sender, c->ts_addr, c->ts_ident, c->ts_seq,
X ACK, 0);
X received(c, (char) c->ts_what, c->ts_bufcnt, c->ts_savehdr);
X if (c->ts_state != RECEIVING)
X return;
X }
X else
X#endif NONET
X if (c->ts_buffer != NOBUF && !putbuf(c->ts_buffer, (vir_bytes)
X (c->ts_rbuf + c->ts_offset), c->ts_bufcnt)) {
X#ifndef NDEBUG
X printf("%x: bad rbuf (received from %x)\n",
X c->ts_addr, t->ts_addr);
X#endif
X c->ts_state = MEMFAULT; /* receiver fails */
X freebuf(c->ts_buffer);
X c->ts_buffer = NOBUF;
X if (c->ts_sender != NOWHERE) {
X t = taskptr(c->ts_sender);
X t->ts_state = FAILED;
X wakeup((event_t) &t->ts_state);
X }
X return;
X }
X else { /* local copy done */
X c->ts_offset += c->ts_bufcnt;
X if (c->ts_bufcnt < BUFSIZE) { /* last buffer */
X if (c->ts_buffer != NOBUF) {
X freebuf(c->ts_buffer);
X c->ts_buffer = NOBUF;
X }
X c->ts_state = DONE;
X return;
X }
X else { /* more buffers expected */
X compare(c->ts_sender, !=, NOWHERE);
X c->ts_state = RECEIVING;
X t = taskptr(c->ts_sender);
X compare(t->ts_state, ==, SENDING);
X assert(t->ts_flags & (PUTREQ | PUTREP));
X wakeup((event_t) &t->ts_state);
X }
X }
X if (sleep((event_t) &c->ts_state)) { /* wait for rest */
X portremove(&c->ts_rhdr->h_port, c->ts_addr);
X if (c->ts_buffer != NOBUF) {
X freebuf(c->ts_buffer);
X c->ts_buffer = NOBUF;
X }
X c->ts_state = ABORT;
X return;
X }
X }
X}
X
X#endif BUFFERED
X
X/* The transaction is local. This routine does the sending.
X */
Xstatic sendbuf(t)
Xregister struct task *t;
X{
X register struct task *c = curtask;
X register unshort cnt = t->ts_rcnt < c->ts_xcnt ? t->ts_rcnt : c->ts_xcnt;
X#ifdef BUFFERED
X register unshort size;
X buffer allocbuf();
X
X c->ts_state = SENDING;
X t->ts_sender = c->ts_addr;
X if (cnt == 0)
X t->ts_buffer = NOBUF;
X else if ((t->ts_buffer = allocbuf()) == NOBUF) {
X c->ts_xcnt = FAIL;
X c->ts_state = FAILED;
X if (!(t->ts_flags & GETREQ)) {
X t->ts_state = FAILED; /* trans fails */
X wakeup((event_t) &t->ts_state);
X }
X return;
X }
X do {
X if ((size = cnt) != 0) {
X if (size > BUFSIZE)
X size = BUFSIZE;
X if (!getbuf(t->ts_buffer, (vir_bytes) (c->ts_xbuf +
X c->ts_offset), size)) {
X#ifndef NDEBUG
X printf("%x: bad xbuf (sending to %x)\n",
X c->ts_addr, t->ts_addr);
X#endif
X freebuf(t->ts_buffer);
X t->ts_buffer = NOBUF;
X c->ts_xcnt = FAIL; /* for putrep */
X c->ts_state = MEMFAULT;
X if (!(t->ts_flags & GETREQ)) {
X t->ts_state = FAILED; /* trans fails */
X wakeup((event_t) &t->ts_state);
X }
X break;
X }
X }
X else if (t->ts_buffer != NOBUF) {
X freebuf(t->ts_buffer);
X t->ts_buffer = NOBUF;
X }
X t->ts_bufcnt = size;
X assert(t->ts_state == WAITBUF || t->ts_state == RECEIVING);
X wakeup((event_t) &t->ts_state);
X if (size != BUFSIZE) { /* last buffer */
X t->ts_sender = NOWHERE;
X c->ts_state = DONE;
X break;
X }
X cnt -= size;
X c->ts_offset += size;
X if (sleep((event_t) &c->ts_state))
X c->ts_state = ABORT;
X } while (c->ts_state == SENDING);
X#else
X compare(t->ts_state, ==, WAITBUF);
X if (cnt != 0) {
X register phys_bytes rbuf, xbuf;
X
X if ((rbuf = umap(t, t->ts_rbuf, (vir_bytes) cnt)) == 0) {
X#ifndef NDEBUG
X printf("bad rbuf (%X,%X)\n", t->ts_rbuf, (vir_bytes) cnt);
X#endif
X c->ts_state = FAILED;
X c->ts_xcnt = FAIL;
X t->ts_state = MEMFAULT;
X wakeup((event_t) &t->ts_state);
X return;
X }
X if ((xbuf = umap(c, c->ts_xbuf, (vir_bytes) cnt)) == 0) {
X#ifndef NDEBUG
X printf("bad xbuf (%X,%X)\n", c->ts_xbuf, (vir_bytes) cnt);
X#endif
X c->ts_state = MEMFAULT;
X c->ts_xcnt = FAIL;
X if (t->ts_flags & GETREQ)
X getreqstart(t); /* client failed, restart getreq */
X else {
X t->ts_state = FAILED;
X wakeup((event_t) &t->ts_state);
X }
X return;
X }
X phys_copy(xbuf, rbuf, (phys_bytes) cnt);
X }
X t->ts_offset = cnt;
X t->ts_state = DONE;
X wakeup((event_t) &t->ts_state);
X c->ts_state = DONE;
X#endif BUFFERED
X}
X
X#ifndef NOCLIENT
X/* The transaction is local. Send the request to the server.
X */
Xstatic recvrequest(){
X register address to;
X register struct task *c = curtask, *t;
X
X if ((to = portlookup(&c->ts_xhdr->h_port, NOWAIT, DELETE)) == NOWHERE)
X return(0);
X#ifndef NONET
X if (siteaddr(to) != local)
X return(0);
X#endif
X t = taskptr(to);
X c->ts_server = to;
X t->ts_client = c->ts_addr;
X t->ts_clident = c->ts_svident;
X *t->ts_rhdr = *c->ts_xhdr;
X sendbuf(t);
X return(c->ts_xcnt != FAIL);
X}
X#endif
X
X/* A task calls this routine when it wants to be blocked awaiting a request.
X * It specifies the header containing the port to wait for, a buffer where
X * the data must go and the size of this buffer. Getreq returns the size of
X * the request when one arrives.
X */
Xunshort getreq(hdr, buf, cnt)
Xheader *hdr;
Xbufptr buf;
Xunshort cnt;
X{
X register struct task *c = curtask;
X
X if (c->ts_flags != 0 || cnt > MAXCNT)
X return(FAIL);
X if (NullPort(&hdr->h_port))
X return(FAIL);
X#ifdef STATISTICS
X amstat.ams_getreq++;
X#endif
X c->ts_rhdr = hdr;
X c->ts_rbuf = buf;
X c->ts_rcnt = cnt;
X c->ts_flags |= GETREQ;
X getreqstart(c);
X if (sleep((event_t) &c->ts_state)) {
X portremove(&hdr->h_port, c->ts_addr);
X c->ts_state = ABORT;
X }
X#ifdef BUFFERED
X if (c->ts_state == WAITBUF)
X recvbuf();
X#endif
X c->ts_flags &= ~GETREQ;
X switch (c->ts_state) {
X case DONE:
X c->ts_flags |= SERVING;
X#ifndef NONET
X if (area(c->ts_client) != LOCAL)
X c->ts_cltim = clientcrash;
X#endif NONET
X cnt = c->ts_offset;
X break;
X case ABORT:
X cnt = ABORTED;
X break;
X case MEMFAULT:
X cnt = BADADDRESS;
X break;
X default:
X assert(0);
X }
X c->ts_state = IDLE;
X return(cnt);
X}
X
X/* A task wants to send a reply to its client. Putrep returns the size of
X * the reply.
X */
Xunshort putrep(hdr, buf, cnt)
Xheader *hdr;
Xbufptr buf;
Xunshort cnt;
X{
X register struct task *c = curtask;
X
X if (c->ts_flags != SERVING)
X return(FAIL);
X c->ts_flags &= ~SERVING;
X if (cnt > MAXCNT)
X return(FAIL);
X#ifdef STATISTICS
X amstat.ams_putrep++;
X#endif
X c->ts_cltim = 0;
X c->ts_xhdr = hdr;
X c->ts_xbuf = buf;
X c->ts_xcnt = cnt;
X c->ts_offset = 0;
X c->ts_flags |= PUTREP;
X#ifndef NONET
X if (siteaddr(c->ts_client) != local)
X send();
X else
X#endif
X { /* local transaction */
X register struct task *t = taskptr(c->ts_client);
X
X if (t->ts_server == c->ts_addr) {
X *t->ts_rhdr = *hdr;
X sendbuf(t);
X }
X }
X c->ts_flags &= ~PUTREP;
X if (c->ts_state == MEMFAULT)
X cnt = BADADDRESS;
X c->ts_state = IDLE;
X return(cnt);
X}
X
X#ifndef NOCLIENT
X/* Somebody wants to contact a server, and wait for a reply. The port this
X * server should listen to is specified in the first header. The reply
X * comes in the second. Trans returns the size of the reply, or FAIL if
X * a transaction fails after the server has been located.
X */
Xunshort trans(hdr1, buf1, cnt1, hdr2, buf2, cnt2)
Xheader *hdr1, *hdr2;
Xbufptr buf1, buf2;
Xunshort cnt1, cnt2;
X{
X register struct task *c = curtask;
X
X if ((c->ts_flags & ~SERVING) || cnt1 > MAXCNT || cnt2 > MAXCNT)
X return(FAIL);
X if (NullPort(&hdr1->h_port))
X return(FAIL);
X#ifdef STATISTICS
X amstat.ams_trans++;
X#endif
X for (;;) {
X c->ts_state = IDLE;
X c->ts_xhdr = hdr1; c->ts_xbuf = buf1; c->ts_xcnt = cnt1;
X c->ts_rhdr = hdr2; c->ts_rbuf = buf2; c->ts_rcnt = cnt2;
X c->ts_signal = 0;
X if (!PortCmp(&c->ts_portcache, &hdr1->h_port)) {
X c->ts_flags |= LOCATING;
X c->ts_timer = c->ts_maxloc;
X c->ts_totloc -= ticker;
X c->ts_server = portlookup(&hdr1->h_port, WAIT, LOOK);
X c->ts_totloc += ticker;
X c->ts_timer = 0;
X c->ts_flags &= ~LOCATING;
X switch (c->ts_server) {
X case NOWHERE: /* server not found */
X c->ts_portcache = NULLPORT;
X return(c->ts_signal == 0 ? NOTFOUND : ABORTED);
X case SOMEWHERE:
X c->ts_portcache = NULLPORT;
X return(FAIL);
X }
X c->ts_portcache = hdr1->h_port;
X }
X#ifdef notdef
X else
X c->ts_server = siteaddr(c->ts_server);
X#endif
X c->ts_svident++;
X c->ts_offset = 0;
X c->ts_flags |= PUTREQ;
X#ifndef NONET
X if (siteaddr(c->ts_server) != local) {
X#ifdef STATISTICS
X amstat.ams_remtrans++;
X#endif
X c->ts_totsvr -= ticker;
X send();
X c->ts_flags &= ~PUTREQ;
X#ifdef BUFFERED
X if (c->ts_state == WAITBUF)
X recvbuf(); /* await the reply */
X#endif
X c->ts_totsvr += ticker;
X if (c->ts_state == NACKED || c->ts_state == FAILED) {
X portremove(&hdr1->h_port, siteaddr(c->ts_server));
X c->ts_portcache = NULLPORT;
X }
X if (c->ts_state != NACKED)
X break;
X#ifdef STATISTICS
X amstat.ams_naks++;
X#endif
X c->ts_portcache = NULLPORT;
X }
X else
X#endif NONET
X if (recvrequest()) { /* local transaction */
X#ifdef STATISTICS
X amstat.ams_loctrans++;
X#endif
X c->ts_flags &= ~PUTREQ;
X c->ts_flags |= GETREP;
X c->ts_totsvr -= ticker;
X c->ts_offset = 0;
X c->ts_state = WAITBUF;
X if (c->ts_signal != 0) {
X putsig(taskptr(c->ts_server),
X (unshort) (c->ts_signal & 0xFF));
X c->ts_signal = 0;
X }
X if (sleep((event_t) &c->ts_state))
X c->ts_state = ABORT;
X#ifdef BUFFERED
X else
X recvbuf();
X#endif
X c->ts_totsvr += ticker;
X break;
X }
X else { /* too bad, try again */
X c->ts_flags &= ~PUTREQ;
X if (c->ts_state == MEMFAULT)
X break;
X }
X c->ts_portcache = NULLPORT;
X if (c->ts_signal != 0) {
X c->ts_state = ABORT;
X break;
X }
X }
X c->ts_signal = 0;
X c->ts_flags &= ~(PUTREQ | GETREP);
X if (c->ts_state == DONE) {
X c->ts_state = IDLE;
X return c->ts_offset;
X }
X#ifndef NDEBUG
X printf("trans failed with %x (state = %d; command = %d; port ",
X c->ts_server, c->ts_state, c->ts_xhdr->h_command);
X prport(&c->ts_xhdr->h_port);
X printf(")\n");
X#endif
X switch (c->ts_state) {
X case FAILED:
X case ABORT:
X cnt2 = FAIL;
X break;
X case MEMFAULT:
X cnt2 = BADADDRESS;
X break;
X default:
X assert(0);
X }
X c->ts_state = IDLE;
X return(cnt2);
X}
X#endif NOCLIENT
X
X/* If doing a transaction, send a signal to the server. For a remote server,
X * the signal is sent along with enquiries. If it's still locating a server,
X * abort that. If it isn't doing a transaction, but blocked in a getreq,
X * abort that.
X */
Xsendsig(t, signal)
Xregister struct task *t;
Xchar signal;
X{
X#ifndef NOCLIENT
X if (t->ts_flags & (LOCATING | PUTREQ | GETREP))
X t->ts_signal = signal;
X if (t->ts_flags & LOCATING)
X portquit(&t->ts_xhdr->h_port, t);
X else if (t->ts_state == WAITBUF)
X if (t->ts_flags & GETREQ) {
X portremove(&t->ts_rhdr->h_port, t->ts_addr);
X t->ts_state = ABORT;
X wakeup((event_t) &t->ts_state);
X }
X else if (signal != 0 && (t->ts_flags & GETREP))
X#ifndef NONET
X if (area(t->ts_server) != LOCAL)
X puthead(t->ts_server, t->ts_addr, t->ts_svident,
X signal, ENQUIRY, 0);
X else
X#endif NONET
X {
X putsig(taskptr(t->ts_server),
X (unshort) (signal & 0xFF));
X t->ts_signal = 0;
X }
X#endif NOCLIENT
X}
X
X#ifndef NOCLIENT
X/* Abort anything task s is doing. If the task is serving somebody, notify
X * it that the server has failed.
X */
Xdestroy(s)
Xregister struct task *s;
X{
X register struct task *t;
X
X sendsig(s, (char) CRASH);
X if (s->ts_flags & SERVING)
X#ifndef NONET
X if (area(s->ts_client) != LOCAL) {
X puthead(s->ts_client, s->ts_addr, s->ts_clident, 0, DEAD, 0);
X s->ts_cltim = 0;
X }
X else
X#endif
X {
X#ifndef NDEBUG
X printf("%x destroyed, %x victim\n", s->ts_addr, s->ts_client);
X#endif
X t = taskptr(s->ts_client);
X if (t->ts_state == WAITBUF) {
X assert(t->ts_flags & GETREP);
X t->ts_timer = 0;
X t->ts_state = FAILED;
X wakeup((event_t) &t->ts_state);
X }
X }
X s->ts_timer = 0;
X if (s->ts_flags & (LOCATING|GETREQ|GETREP|PUTREQ|PUTREP)) {
X s->ts_state = ABORT;
X wakeup((event_t) &s->ts_state);
X }
X else {
X s->ts_state = IDLE;
X s->ts_flags = 0;
X }
X s->ts_server = s->ts_client = 0;
X s->ts_portcache = NULLPORT;
X}
X
X/* Clean up the mess.
X */
Xcleanup(){
X register struct task *c = curtask;
X
X compare(c->ts_state, ==, IDLE);
X destroy(c);
X}
X#endif
X
X
X/* Limit the maximum locate time & service time. 0 is infinite.
X */
Xunshort timeout(maxloc)
Xunshort maxloc;
X{
X unshort oldloc = curtask->ts_maxloc;
X
X curtask->ts_maxloc = maxloc;
X return(oldloc);
X}
X
X#ifndef NDEBUG
Xtransdump(){
X register struct task *t;
X static char *states[] = {
X "IDLE", "SENDING", "DONE", "ACKED", "NACKED", "FAILED",
X "WAITBUF", "RECEIVING", "ABORT", "MEMFAULT"
X };
X static struct ftab {
X unshort flag;
X char *name;
X } ftab[] = {
X { GETREQ, "GETREQ" }, { SERVING, "SERVING" },
X { PUTREP, "PUTREP" }, { LOCATING, "LOCATE" },
X { PUTREQ, "PUTREQ" }, { GETREP, "GETREP" },
X };
X register struct ftab *p;
X
X printf("\nTK STATE CTM TIM CNT CLT SRV CLI SVI SEQ SIG FLAGS\n");
X for (t = task; t < uppertask; t++) {
X if (t->ts_state == IDLE && t->ts_flags == 0) {
X compare(t->ts_cltim, ==, 0);
X compare(t->ts_timer, ==, 0);
X compare(t->ts_signal, ==, 0);
X continue;
X }
X printf("%2d %9s%3d %3d %3d %4x %4x %3d %3d %3d %3d", t - task,
X states[t->ts_state], t->ts_cltim, t->ts_timer, t->ts_count,
X t->ts_client, t->ts_server, t->ts_clident & 0xFF,
X t->ts_svident & 0xFF, t->ts_seq & 0xFF, t->ts_signal & 0xFF);
X for (p = ftab; p < &ftab[sizeoftable(ftab)]; p++)
X if (t->ts_flags & p->flag)
X printf(" %s", p->name);
X if (t->ts_flags & (GETREQ | LOCATING | GETREP)) {
X printf(" '");
X prport(t->ts_flags & GETREQ ? &t->ts_rhdr->h_port
X : &t->ts_xhdr->h_port);
X printf("'");
X }
X printf("\n");
X }
X}
X#endif NDEBUG
X
Xtrinit(){
X curtask->ts_addr = ((curtask - task) << 8 | local);
X}
X
X/* Get the site address.
X */
Xtransinit(){
X#ifdef NONET
X local = 1;
X#else
X extern address interinit();
X
X local = siteaddr(interinit());
X/*
X netenable();
X*/
X#endif NONET
X}
X
X#ifndef NDEBUG
Xamdump()
X{
X#ifdef STATISTICS
X printf("\nAmoeba statistics:\n");
X printf("clfail %7D ", amstat.ams_clfail);
X printf("svfail %7D ", amstat.ams_svfail);
X printf("clcrash %7D ", amstat.ams_clcrash);
X printf("rxcl %7D ", amstat.ams_rxcl);
X printf("rxsv %7D\n",amstat.ams_rxsv);
X printf("trans %7D ", amstat.ams_trans);
X printf("local %7D ", amstat.ams_loctrans);
X printf("remote %7D ", amstat.ams_remtrans);
X printf("getreq %7D ", amstat.ams_getreq);
X printf("putrep %7D\n",amstat.ams_putrep);
X printf("naks %7D\n",amstat.ams_naks);
X#endif
X}
X#endif
+ END-OF-FILE trans.c
chmod 'u=rw,g=r,o=r' 'trans.c'
set `wc -c 'trans.c'`
count=$1
case $count in
35869) :;;
*) echo 'Bad character count in ''trans.c' >&2
echo 'Count should be 35869' >&2
esac
echo Extracting 'util.c'
sed 's/^X//' > 'util.c' << '+ END-OF-FILE ''util.c'
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/com.h"
X#include "const.h"
X#include "type.h"
X#include "proc.h"
X#include "dp8390.h"
X#include "assert.h"
X#include "dp8390info.h"
X#include "eplinfo.h"
X
X#define PIC_enable() port_out(INT_CTL, ENABLE)
X
Xextern char get_byte();
X
Xstruct eplinfo eplinfo = {0x280};
X
Xstruct dp8390info dp8390info = {0x290, 6, 27, 0xC4000, 0xC4000};
X
Xinbyte(port)
X vir_bytes port;
X{
X int value;
X
X port_in(port, &value);
X return value;
X}
X
Xoutbyte(port, value)
X vir_bytes port;
X int value;
X{
X port_out(port, value);
X}
X
Xgetheader(paddr, pkthead)
X phys_bytes paddr;
X struct rcvdheader *pkthead;
X{
X vir_bytes seg;
X
X assert((paddr&0xFFF0000F)==0L);
X seg = paddr>>4;
X pkthead->rp_status = get_byte(seg,0);
X pkthead->rp_next = get_byte(seg,1);
X pkthead->rp_rbcl = get_byte(seg,2);
X pkthead->rp_rbch = get_byte(seg,3);
X}
X
X
Xshort
Xgetbint(paddr)
X phys_bytes paddr;
X{
X vir_bytes seg,offset;
X
X seg = paddr >> 4;
X offset = paddr & 0xF;
X return (((short)get_byte(seg, offset)&0xFF)<<8) + (short)(get_byte(seg, offset+1)&0xFF);
X}
X
X/*
Xgetbyte(paddr)
Xphys_bytes paddr;
X{
X vir_bytes seg;
X vir_bytes offset;
X
X seg = paddr >> 4;
X offset = paddr & 0xf;
X return get_byte(seg, offset);
X}
X
X
Xvp_copy(procnr, seg, vir_addr, phys_addr, count)
X int procnr;
X int seg;
X vir_bytes vir_addr;
X phys_bytes phys_addr;
X vir_bytes count;
X{
X phys_bytes u_phys;
X register struct proc *rp;
X phys_bytes umap();
X
X rp = proc_addr(procnr);
X u_phys = umap(rp, seg, vir_addr, count);
X assert(u_phys!=0L);
X phys_copy(u_phys, phys_addr, (phys_bytes)count);
X}
X
Xpv_copy(phys_addr, procnr, seg, vir_addr, count)
X phys_bytes phys_addr;
X int procnr;
X int seg;
X vir_bytes vir_addr;
X vir_bytes count;
X{
X phys_bytes vir_phys;
X register struct proc *rp;
X phys_bytes umap();
X
X rp = proc_addr(procnr);
X vir_phys = umap(rp, seg, vir_addr, count);
X assert(vir_phys!=0L);
X phys_copy(phys_addr, vir_phys, (phys_bytes)count);
X}
X*/
+ END-OF-FILE util.c
chmod 'u=rw,g=r,o=r' 'util.c'
set `wc -c 'util.c'`
count=$1
case $count in
2063) :;;
*) echo 'Bad character count in ''util.c' >&2
echo 'Count should be 2063' >&2
esac
exit 0