typedef struct Alarms Alarms; typedef struct Block Block; typedef struct Blist Blist; typedef struct Chan Chan; typedef struct Crypt Crypt; typedef struct Dev Dev; typedef struct Dirtab Dirtab; typedef struct Egrp Egrp; typedef struct Evalue Evalue; typedef struct Etherpkt Etherpkt; typedef struct Fgrp Fgrp; typedef struct Image Image; typedef struct IOQ IOQ; typedef struct KIOQ KIOQ; typedef struct List List; typedef struct Mount Mount; typedef struct Mnt Mnt; typedef struct Mhead Mhead; typedef struct Netinf Netinf; typedef struct Netprot Netprot; typedef struct Network Network; typedef struct Note Note; typedef struct Page Page; typedef struct Palloc Palloc; typedef struct Pgrps Pgrps; typedef struct Pgrp Pgrp; typedef struct Proc Proc; typedef struct Pte Pte; typedef struct Qinfo Qinfo; typedef struct QLock QLock; typedef struct Queue Queue; typedef struct Ref Ref; typedef struct Rendez Rendez; typedef struct RWlock RWlock; typedef struct Sargs Sargs; typedef struct Scsi Scsi; typedef struct Scsibuf Scsibuf; typedef struct Scsidata Scsidata; typedef struct Segment Segment; typedef struct Stream Stream; typedef struct Talarm Talarm; typedef struct Waitq Waitq; typedef int Devgen(Chan*, Dirtab*, int, int, Dir*); typedef void Streamput(Queue*, Block*); typedef void Streamopen(Queue*, Stream*); typedef void Streamclose(Queue*); typedef void Streamreset(void); #include "fcall.h" struct Ref { Lock; long ref; }; struct Rendez { Lock; Proc *p; }; struct QLock { Lock use; /* to access Qlock structure */ Proc *head; /* next process waiting for object */ Proc *tail; /* last process waiting for object */ int locked; /* flag */ }; struct RWlock { Lock; /* Lock modify lock */ QLock x; /* Mutual exclusion lock */ QLock k; /* Lock for waiting writers held for readers */ int readers; /* Count of readers in lock */ }; struct Talarm { Lock; Proc *list; }; struct Alarms { QLock; Proc *head; }; #define MAXSYSARG 5 /* for mount(fd, mpt, flag, arg, srv) */ struct Sargs { ulong args[MAXSYSARG]; }; /* Block.flags */ #define S_DELIM 0x80 #define S_CLASS 0x07 /* Block.type */ #define M_DATA 0 #define M_CTL 1 #define M_HANGUP 2 struct Block { Block *next; Block *list; /* chain of block lists */ uchar *rptr; /* first unconsumed byte */ uchar *wptr; /* first empty byte */ uchar *lim; /* 1 past the end of the buffer */ uchar *base; /* start of the buffer */ uchar flags; uchar type; ulong pc; /* pc of caller */ }; struct Blist { Lock; Block *first; /* first data block */ Block *last; /* last data block */ long len; /* length of list in bytes */ int nb; /* number of blocks in list */ }; /* * Access types in namec */ enum { Aaccess, /* as in access, stat */ Atodir, /* as in chdir */ Aopen, /* for i/o */ Amount, /* to be mounted upon */ Acreate, /* file is to be created */ }; /* * Chan.flags */ #define COPEN 1 /* for i/o */ #define CMSG 2 /* is the message channel for a mount */ #define CCREATE 4 /* permits creation if c->mnt */ #define CCEXEC 8 /* close on exec */ #define CFREE 16 /* not in use */ #define CRCLOSE 32 /* remove on close */ struct Chan { Ref; union{ Chan *next; /* allocation */ ulong offset; /* in file */ }; ushort type; ushort dev; ushort mode; /* read/write */ ushort flag; Qid qid; Mount *mnt; /* mount point that derived Chan */ ulong mountid; int fid; /* for devmnt */ Stream *stream; /* for stream channels */ union { void *aux; Qid pgrpid; /* for #p/notepg */ Mnt *mntptr; /* for devmnt */ }; Chan *mchan; /* channel to mounted server */ Qid mqid; /* qid of root of mount point */ }; struct Crypt { char key[DESKEYLEN]; /* des encryption key */ char chal[8]; /* challenge for setting user name */ Crypt *next; }; struct Dev { void (*reset)(void); void (*init)(void); Chan* (*attach)(char*); Chan* (*clone)(Chan*, Chan*); int (*walk)(Chan*, char*); void (*stat)(Chan*, char*); Chan* (*open)(Chan*, int); void (*create)(Chan*, char*, int, ulong); void (*close)(Chan*); long (*read)(Chan*, void*, long, ulong); long (*write)(Chan*, void*, long, ulong); void (*remove)(Chan*); void (*wstat)(Chan*, char*); }; struct Dirtab { char name[NAMELEN]; Qid qid; long length; long perm; }; /* * Ethernet packet buffers. */ struct Etherpkt { uchar d[6]; uchar s[6]; uchar type[2]; uchar data[1500]; uchar crc[4]; }; enum { ETHERMINTU = 60, /* minimum transmit size */ ETHERMAXTU = 1514, /* maximum transmit size */ ETHERHDRSIZE = 14, /* size of an ethernet header */ }; /* SCSI devices. */ enum { ScsiTestunit = 0x00, ScsiExtsens = 0x03, ScsiInquiry = 0x12, ScsiModesense = 0x1a, ScsiGetcap = 0x25, ScsiRead = 0x08, ScsiWrite = 0x0a, /* data direction */ ScsiIn = 1, ScsiOut = 0, }; struct Scsibuf { void* virt; void* phys; Scsibuf* next; }; struct Scsidata { uchar* base; uchar* lim; uchar* ptr; }; struct Scsi { QLock; ulong pid; ushort target; ushort lun; ushort rflag; ushort status; Scsidata cmd; Scsidata data; Scsibuf* b; uchar* save; uchar cmdblk[16]; }; /* character based IO (mouse, keyboard, console screen) */ #define NQ 4096 struct IOQ { Lock; uchar buf[NQ]; uchar *in; uchar *out; int state; Rendez r; union{ void (*puts)(IOQ*, void*, int); /* output */ int (*putc)(IOQ*, int); /* input */ }; union{ int (*gets)(IOQ*, void*, int); /* input */ int (*getc)(IOQ*); /* output */ }; void *ptr; }; struct KIOQ { QLock; IOQ; int repeat; int c; int count; }; struct Mount { ulong mountid; Mount *next; Mhead *head; Chan *to; /* channel replacing underlying channel */ }; struct Mhead { Chan *from; /* channel mounted upon */ Mount *mount; /* what's mounted upon it */ Mhead *hash; /* Hash chain */ }; enum { NUser, /* note provided externally */ NExit, /* deliver note quietly */ NDebug, /* print debug message */ }; struct Note { char msg[ERRLEN]; int flag; /* whether system posted it */ }; enum { PG_NOFLUSH = 0, /* Fields for cache control of pages */ PG_TXTFLUSH = 1, PG_DATFLUSH = 2, PG_MOD = 0x01, /* Simulated modified and referenced bits */ PG_REF = 0x02, }; struct Page { Lock; ulong pa; /* Physical address in memory */ ulong va; /* Virtual address for user */ ulong daddr; /* Disc address on swap */ ushort ref; /* Reference count */ char lock; /* Software lock */ char modref; /* Simulated modify/reference bits */ char cachectl[MAXMACH]; /* Cache flushing control for putmmu */ Image *image; /* Associated text or swap image */ Page *next; /* Lru free list */ Page *prev; Page *hash; /* Image hash chains */ }; struct Swapalloc { Lock; /* Free map lock */ int free; /* Number of currently free swap pages */ uchar *swmap; /* Base of swap map in memory */ uchar *alloc; /* Round robin allocator */ uchar *last; /* Speed swap allocation */ uchar *top; /* Top of swap map */ Rendez r; /* Pager kproc idle sleep */ ulong highwater; /* Threshold beyond which we must page */ ulong headroom; /* Space pager keeps free under highwater */ }swapalloc; struct Image { Ref; Chan *c; /* Channel associated with running image */ Qid qid; /* Qid for page cache coherence checks */ Qid mqid; Chan *mchan; ushort type; /* Device type of owning channel */ Segment *s; /* TEXT segment for image if running */ Image *hash; /* Qid hash chains */ Image *next; /* Free list */ }; struct Pte { Page *pages[PTEPERTAB]; /* Page map for this chunk of pte */ Page **first; /* First used entry */ Page **last; /* Last used entry */ Pte *next; /* Free list */ }; /* Segment types */ enum { SG_TYPE = 07, /* Mask type of segment */ SG_TEXT = 00, SG_DATA = 01, SG_BSS = 02, SG_STACK = 03, SG_SHARED = 04, SG_PHYSICAL = 05, SG_SHDATA = 06, SG_RONLY = 040, /* Segment is read only */ }; #define PG_ONSWAP 1 #define onswap(s) (((ulong)s)&PG_ONSWAP) #define pagedout(s) (((ulong)s)==0 || onswap(s)) #define swapaddr(s) (((ulong)s)&~PG_ONSWAP) #define SEGMAXSIZE (SEGMAPSIZE*PTEMAPMEM) struct Segment { Ref; QLock lk; ushort steal; /* Page stealer lock */ Segment *next; /* free list pointers */ ushort type; /* segment type */ ulong base; /* virtual base */ ulong top; /* virtual top */ ulong size; /* size in pages */ ulong fstart; /* start address in file for demand load */ ulong flen; /* length of segment in file */ int flushme; /* maintain consistent icache for this segment */ Image *image; /* text in file attached to this segment */ Page *(*pgalloc)(ulong addr);/* SG_PHYSICAL page allocator */ void (*pgfree)(Page *); /* SG_PHYSICAL page free */ Pte *map[SEGMAPSIZE]; /* segment pte map */ }; enum { RENDHASH = 32, /* Hash to lookup rendezvous tags */ MNTHASH = 32, /* Hash to walk mount table */ NFD = 100, /* Number of per process file descriptors */ PGHSIZE = 512, /* Page hash for image lookup */ }; #define REND(p,s) ((p)->rendhash[(s)%RENDHASH]) #define MOUNTH(p,s) ((p)->mnthash[(s)->qid.path%MNTHASH]) struct Pgrp { Ref; /* also used as a lock when mounting */ Pgrp *next; /* free list */ ulong pgrpid; Crypt *crypt; /* encryption key and challenge */ QLock debug; /* single access via devproc.c */ RWlock ns; /* Namespace many read/one write lock */ Mhead *mnthash[MNTHASH]; Proc *rendhash[RENDHASH]; /* Rendezvous tag hash */ }; struct Egrp { Ref; QLock; Evalue *entries; ulong path; }; struct Evalue { char *name; char *value; int len; ulong path; Evalue *link; }; struct Fgrp { Ref; Chan *fd[NFD]; int maxfd; /* highest fd in use */ }; struct Palloc { Lock; ulong p0, p1; /* base of pages in bank 0/1 */ ulong np0, np1; /* number of pages in bank 0/1 */ Page *head; /* most recently used */ Page *tail; /* least recently used */ ulong freecount; /* how many pages on free list now */ ulong user; /* how many user pages */ Page *hash[PGHSIZE]; Lock hashlock; Rendez r; /* Sleep for free mem */ QLock pwait; /* Queue of procs waiting for memory */ int wanted; /* Do the wakeup at free */ ulong cmembase; /* Key memory protected from read by devproc */ ulong cmemtop; }; struct Waitq { Waitmsg w; Waitq *next; }; enum { RFNAMEG = (1<<0), RFENVG = (1<<1), RFFDG = (1<<2), RFNOTEG = (1<<3), RFPROC = (1<<4), RFMEM = (1<<5), RFNOWAIT = (1<<6), RFCNAMEG = (1<<10), RFCENVG = (1<<11), RFCFDG = (1<<12) }; /* * process memory segments - NSEG always last ! */ enum { SSEG, TSEG, DSEG, BSEG, ESEG, LSEG, SEG1, SEG2, NSEG }; enum { Dead = 0, /* Process states */ Moribund, Ready, Scheding, Running, Queueing, Wakeme, Broken, Stopped, Rendezvous, Proc_stopme = 1, /* devproc requests */ Proc_exitme, Proc_traceme, TUser = 0, /* Proc.time */ TSys, TReal, TCUser, TCSys, TCReal, }; struct Proc { Label sched; Mach *mach; /* machine running this proc */ char text[NAMELEN]; char user[NAMELEN]; Proc *rnext; /* next process in run queue */ Proc *qnext; /* next process on queue for a QLock */ QLock *qlock; /* address of qlock being queued for DEBUG */ ulong qlockpc; /* pc of last call to qlock */ int state; char *psstate; /* What /proc/#/status reports */ Page *upage; /* page from palloc */ Segment *seg[NSEG]; ulong pid; ulong noteid; /* Equivalent of note group */ Lock exl; /* Lock count and waitq */ Waitq *waitq; /* Exited processes wait children */ int nchild; /* Number of living children */ int nwait; /* Number of uncollected wait records */ Rendez waitr; /* Place to hang out in wait */ Proc *parent; Pgrp *pgrp; /* Process group for notes and namespace */ Egrp *egrp; /* Environment group */ Fgrp *fgrp; /* File descriptor group */ ulong parentpid; ulong time[6]; /* User, Sys, Real; child U, S, R */ short insyscall; int fpstate; QLock debug; /* to access debugging elements of User */ Proc *pdbg; /* the debugging process */ ulong procmode; /* proc device file mode */ int hang; /* hang at next exec for debug */ int procctl; /* Control for /proc debugging */ ulong pc; /* DEBUG only */ Rendez *r; /* rendezvous point slept on */ Rendez sleep; /* place for syssleep/debug */ int notepending; /* note issued but not acted on */ int kp; /* true if a kernel process */ Proc *palarm; /* Next alarm time */ ulong alarm; /* Time of call */ int hasspin; /* I hold a spin lock */ int newtlb; /* Pager has touched my tables so I must flush */ ulong rendtag; /* Tag for rendezvous */ ulong rendval; /* Value for rendezvous */ Proc *rendhash; /* Hash list for tag values */ ulong twhen; Rendez *trend; Proc *tlink; int (*tfn)(void*); /* * machine specific MMU */ PMMU; }; /* * operations available to a queue */ struct Qinfo { Streamput *iput; /* input routine */ Streamput *oput; /* output routine */ Streamopen *open; Streamclose *close; char *name; Streamreset *reset; /* initialization */ char nodelim; /* True if stream does not preserve delimiters */ Qinfo *next; }; /* Queue.flag */ enum { QHUNGUP = 0x1, /* stream has been hung up */ QINUSE = 0x2, /* allocation check */ QHIWAT = 0x4, /* queue has gone past the high water mark */ QDEBUG = 0x8, }; struct Queue { Blist; int flag; Qinfo *info; /* line discipline definition */ Queue *other; /* opposite direction, same line discipline */ Queue *next; /* next queue in the stream */ void (*put)(Queue*, Block*); QLock rlock; /* mutex for processes sleeping at r */ Rendez r; /* standard place to wait for flow control */ Rendez *rp; /* where flow control wakeups go to */ void *ptr; /* private info for the queue */ }; struct Stream { QLock; /* structure lock */ Stream *next; short inuse; /* number of processes in stream */ short opens; /* number of processes with stream open */ ushort hread; /* number of reads after hangup */ ushort type; /* correlation with Chan */ ushort dev; /* ... */ ushort id; /* ... */ QLock rdlock; /* read lock */ Queue *procq; /* write queue at process end */ Queue *devq; /* read queue at device end */ Block *err; /* error message from down stream */ int flushmsg; /* flush up till the next delimiter */ }; /* * useful stream macros */ #define RD(q) ((q)->other < (q) ? (q->other) : q) #define WR(q) ((q)->other > (q) ? (q->other) : q) #define STREAMTYPE(x) ((x)&0x1f) #define STREAMID(x) (((x)&~CHDIR)>>5) #define STREAMQID(i,t) (((i)<<5)|(t)) #define PUTNEXT(q,b) (*(q)->next->put)((q)->next, b) #define BLEN(b) ((b)->wptr - (b)->rptr) #define QFULL(q) ((q)->flag & QHIWAT) #define FLOWCTL(q,b) { if(QFULL(q->next)) flowctl(q,b); else PUTNEXT(q,b);} /* * stream file qid's & high water mark */ enum { Shighqid = STREAMQID(1,0) - 1, Sdataqid = Shighqid, Sctlqid = Sdataqid-1, Slowqid = Sctlqid, Streamhi = (32*1024), /* byte count high water mark */ Streambhi = 128, /* block count high water mark */ }; /* * a multiplexed network */ struct Netprot { int id; Netprot *next; /* linked list of protections */ ulong mode; char owner[NAMELEN]; }; struct Netinf { char *name; void (*fill)(Chan*, char*, int); }; struct Network { Lock; char *name; int nconv; /* max # of conversations */ Qinfo *devp; /* device end line disc */ Qinfo *protop; /* protocol line disc */ int (*listen)(Chan*); int (*clone)(Chan*); int ninfo; Netinf info[5]; Netprot *prot; /* linked list of protections */ }; enum { PRINTSIZE = 256, MAXCRYPT = 127, NUMSIZE = 12, /* size of formatted number */ MB = (1024*1024), }; extern Conf conf; extern char* conffile; extern int cpuserver; extern char* devchar; extern Dev devtab[]; extern char eve[]; extern uchar initcode[]; extern FPsave initfp; extern KIOQ kbdq; extern IOQ lineq; extern IOQ mouseq; extern Ref noteidalloc; extern int nrdy; extern IOQ printq; extern char* statename[]; extern Image swapimage; extern char sysname[NAMELEN]; extern Talarm talarm; extern Palloc palloc; extern int cpuserver; enum { CHDIR = 0x80000000L, CHAPPEND = 0x40000000L, CHEXCL = 0x20000000L, }; /* * auth messages */ enum { FScchal = 1, FSschal, FSok, FSctick, FSstick, FSerr, RXschal = 0, RXstick = 1, AUTHLEN = 8, };