ast@cs.vu.nl (Andy Tanenbaum) (07/18/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
ddl@husc6.harvard.edu (Dan Lanciani) (07/20/88)
In article <910@ast.cs.vu.nl|, ast@cs.vu.nl (Andy Tanenbaum) writes: | 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 */ It seems unreasonable to disallow all use and disclosure of material published to a public network such as USENET. A literal interpretation would appear to imply that letting someone read over my shoulder is violating the copyright. Any interpretation would indicate that I can't *run* the software. Dan Lanciani ddl@harvard.*
ast@cs.vu.nl (Andy Tanenbaum) (07/21/88)
In article <4989@husc6.harvard.edu> ddl@husc6.harvard.edu (Dan Lanciani) writes: > It seems unreasonable to disallow all use and disclosure of material >published to a public network such as USENET. I agree. The files for the MINIX networking were taken literally from the Amoeba distribution, of which stuff I posted is only a small subset. I didn't even look at the copyright notice (which is appropriate for Amoeba, which is licensed software) I hereby grant permission for anyone to use the contents of the amoeba directory that I posted for educational and research use. It may also be duplicated and redistributed to others for educational and research use, but the copyright notice must remain intact. For all commercial use a licensing agreement is required. Andy Tanenbaum (ast@cs.vu.nl)
oswald@cpe.UUCP (07/22/88)
I only received the first 100000 bytes of V1.3 posting #39 - amoeba/kernal/*. Would some kind soul post or mail me the end of the file. This is a tail of what I received. 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 && Thanks, Roy Oswald Tandy Computer Product Engineering convex!ctvax!trsvax!cpe!oswald decvax!microsoft!trsvax!cpe!oswald