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 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 */
struct Chan
{
QLock rdl; /* read access */
QLock wrl; /* write access */
Lock offl; /* offset access */
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 */
};
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];
};
#define ETHERMINTU 60 /* minimum transmit size */
#define ETHERMAXTU 1514 /* maximum transmit size */
#define ETHERHDRSIZE 14 /* size of an ethernet header */
/*
* 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 */
char *swmap; /* Base of swap map in memory */
char *alloc; /* Round robin allocator */
char *top; /* Top of swap map */
Rendez r; /* Pager kproc idle sleep */
ulong highwater; /* Threshold beyond which we must page */
ulong headroom; /* Space pager attempts to clear below 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, may be null */
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 pagedout(s) (((ulong)s)==0 || (((ulong)s)&PG_ONSWAP))
#define swapaddr(s) (((ulong)s)&~PG_ONSWAP)
#define onswap(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; /* image in file system 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 */
};
#define RENDHASH 32
#define REND(p,s) ((p)->rendhash[(s)%RENDHASH])
#define MNTHASH 32
#define MOUNTH(p,s) ((p)->mnthash[(s)->qid.path%MNTHASH])
struct Pgrp
{
Ref; /* also used as a lock when mounting */
Pgrp *next; /* free list */
int index; /* index in pgrp table */
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;
};
#define NFD 100
struct Fgrp
{
Ref;
Chan *fd[NFD];
int maxfd; /* highest fd in use */
};
#define PGHSIZE 512
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 */
};
struct Pgrps
{
Lock;
Pgrp *arena;
Pgrp *free;
ulong pgrpid;
ulong cryptbase;
ulong crypttop;
};
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; /* BUG: should be unlinked from page list */
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 goo
*/
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
*/
#define QHUNGUP 0x1 /* flag bit meaning the stream has been hung up */
#define QINUSE 0x2
#define QHIWAT 0x4 /* queue has gone past the high water mark */
#define 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 */
};
#define PRINTSIZE 256
#define NUMSIZE 12 /* size of formatted number */
#define MB (1024*1024)
extern Conf conf;
extern char* conffile;
extern int cpuserver;
extern char* devchar;
extern Dev devtab[];
extern char eve[];
extern ulong 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 Pgrps pgrpalloc;
extern int cpuserver;
#define CHDIR 0x80000000L
#define CHAPPEND 0x40000000L
#define CHEXCL 0x20000000L
/*
* auth messages
*/
enum
{
FScchal = 1,
FSschal,
FSok,
FSctick,
FSstick,
FSerr,
RXschal = 0,
RXstick = 1,
AUTHLEN = 8,
};