typedef struct Alarms	Alarms;
typedef struct Block	Block;
typedef struct Bpool	Bpool;
typedef struct Chan	Chan;
typedef struct Cmdbuf	Cmdbuf;
typedef struct Cmdtab	Cmdtab;
typedef struct Confmem	Confmem;
typedef struct Dev	Dev;
typedef struct Dirtab	Dirtab;
typedef struct Edf	Edf;
typedef struct Egrp	Egrp;
typedef struct Evalue	Evalue;
typedef struct Fgrp	Fgrp;
typedef struct DevConf	DevConf;
typedef struct Image	Image;
typedef struct Log	Log;
typedef struct Logflag	Logflag;
typedef struct Mntcache Mntcache;
typedef struct Mount	Mount;
typedef struct Mntrah	Mntrah;
typedef struct Mntrpc	Mntrpc;
typedef struct Mntproc	Mntproc;
typedef struct Mnt	Mnt;
typedef struct Mhead	Mhead;
typedef struct Note	Note;
typedef struct Page	Page;
typedef struct Path	Path;
typedef struct Palloc	Palloc;
typedef struct Perf	Perf;
typedef struct PhysUart	PhysUart;
typedef struct Pgrp	Pgrp;
typedef struct Physseg	Physseg;
typedef struct Proc	Proc;
typedef struct Pte	Pte;
typedef struct PMach	PMach;
typedef struct QLock	QLock;
typedef struct Queue	Queue;
typedef struct Ref	Ref;
typedef struct Rendez	Rendez;
typedef struct Rendezq	Rendezq;
typedef struct Rgrp	Rgrp;
typedef struct RWLock	RWLock;
typedef struct Sargs	Sargs;
typedef struct Schedq	Schedq;
typedef struct Segment	Segment;
typedef struct Segio	Segio;
typedef struct Sema	Sema;
typedef struct Timer	Timer;
typedef struct Timers	Timers;
typedef struct Uart	Uart;
typedef struct Waitq	Waitq;
typedef struct Walkqid	Walkqid;
typedef struct Watchpt	Watchpt;
typedef struct Watchdog	Watchdog;
typedef int    Devgen(Chan*, char*, Dirtab*, int, int, Dir*);

#pragma incomplete DevConf
#pragma incomplete Edf
#pragma incomplete Mntcache
#pragma incomplete Mntrpc
#pragma incomplete Queue
#pragma incomplete Timers

#include <fcall.h>

struct Ref
{
	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 */
	uintptr	pc;		/* pc of owner */
	int	locked;		/* flag */
};

struct Rendezq
{
	QLock;
	Rendez;
};

struct RWLock
{
	Lock	use;
	Proc	*head;		/* list of waiting processes */
	Proc	*tail;
	uintptr	wpc;		/* pc of writer */
	int	writer;		/* number of writers */
	int	readers;	/* number of readers */
};

struct Alarms
{
	QLock;
	Proc	*head;
};

struct Sargs
{
	uchar	args[MAXSYSARG*BY2WD];
};

/*
 * Access types in namec & channel flags
 */
enum
{
	Aaccess,			/* as in stat, wstat */
	Abind,				/* for left-hand-side of bind */
	Atodir,				/* as in chdir */
	Aopen,				/* for i/o */
	Amount,				/* to be mounted or mounted upon */
	Acreate,			/* is to be created */
	Aremove,			/* will be removed by caller */
	Aunmount,			/* unmount arg[0] */

	COPEN	= 0x0001,		/* for i/o */
	CMSG	= 0x0002,		/* the message channel for a mount */
/*rsc	CCREATE	= 0x0004,		/* permits creation if c->mnt */
	CCEXEC	= 0x0008,		/* close on exec (per file descriptor) */
	CFREE	= 0x0010,		/* not in use */
	CRCLOSE	= 0x0020,		/* remove on close */
	CCACHE	= 0x0080,		/* client cache */
};

/* flag values */
enum
{
	BINTR	=	(1<<0),
	BFREE	=	(1<<1),
	Bipck	=	(1<<2),		/* ip checksum */
	Budpck	=	(1<<3),		/* udp checksum */
	Btcpck	=	(1<<4),		/* tcp checksum */
	Bpktck	=	(1<<5),		/* packet checksum */
};

struct Block
{
	Block*	next;
	Block*	list;
	uchar*	rp;			/* first unconsumed byte */
	uchar*	wp;			/* first empty byte */
	uchar*	lim;			/* 1 past the end of the buffer */
	uchar*	base;			/* start of the buffer */
	Bpool*	pool;
	ushort	flag;
	ushort	checksum;		/* IP checksum of complete packet (minus media header) */
};

#define BLEN(s)	((s)->wp - (s)->rp)
#define BALLOC(s) ((s)->lim - (s)->base)

struct Bpool
{
	ulong	size;			/* block size */
	ulong	align;			/* block alignment */

	Lock;
	Block	*head;			/* freelist head */
};

struct Chan
{
	Ref;
	Lock;
	Chan*	next;			/* allocation */
	Chan*	link;
	vlong	offset;			/* in fd */
	vlong	devoffset;		/* in underlying device; see read */
	ushort	type;
	ulong	dev;
	ushort	mode;			/* read/write */
	ushort	flag;
	Qid	qid;
	int	fid;			/* for devmnt */
	ulong	iounit;			/* chunk size for i/o; 0==default */
	Mhead*	umh;			/* mount point that derived Chan; used in unionread */
	Chan*	umc;			/* channel in union; held for union read */
	QLock	umqlock;		/* serialize unionreads */
	int	uri;			/* union read index */
	int	dri;			/* devdirread index */
	uchar*	dirrock;		/* directory entry rock for translations */
	int	nrock;
	int	mrock;
	QLock	rockqlock;
	int	ismtpt;
	Mntcache*mcp;			/* Mount cache pointer */
	Mnt*	mux;			/* Mnt for clients using me for messages */
	union {
		void*	aux;
		ulong	mid;		/* for ns in devproc */
	};
	Chan*	mchan;			/* channel to mounted server */
	Qid	mqid;			/* qid of root of mount point */
	Path*	path;
	char*	srvname;		/* /srv/name when posted */
};

struct Path
{
	Ref;
	char	*s;
	Chan	**mtpt;			/* mtpt history */
	int	len;			/* strlen(s) */
	int	alen;			/* allocated length of s */
	int	mlen;			/* number of path elements */
	int	malen;			/* allocated length of mtpt */
};

struct Dev
{
	int	dc;
	char*	name;

	void	(*reset)(void);
	void	(*init)(void);
	void	(*shutdown)(void);
	Chan*	(*attach)(char*);
	Walkqid*(*walk)(Chan*, Chan*, char**, int);
	int	(*stat)(Chan*, uchar*, int);
	Chan*	(*open)(Chan*, int);
	Chan*	(*create)(Chan*, char*, int, ulong);
	void	(*close)(Chan*);
	long	(*read)(Chan*, void*, long, vlong);
	Block*	(*bread)(Chan*, long, ulong);
	long	(*write)(Chan*, void*, long, vlong);
	long	(*bwrite)(Chan*, Block*, ulong);
	void	(*remove)(Chan*);
	int	(*wstat)(Chan*, uchar*, int);
	void	(*power)(int);	/* power mgt: power(1) => on, power (0) => off */
	int	(*config)(int, char*, DevConf*);	/* returns nil on error */
};

struct Dirtab
{
	char	name[KNAMELEN];
	Qid	qid;
	vlong	length;
	long	perm;
};

struct Walkqid
{
	Chan	*clone;
	int	nqid;
	Qid	qid[1];
};

struct Mount
{
	uvlong	mountid;
	int	mflag;
	Mount*	next;
	Mount*	order;
	Chan*	to;			/* channel replacing channel */
	char	spec[];
};

struct Mhead
{
	Ref;
	RWLock	lock;
	Chan*	from;			/* channel mounted upon */
	Mount*	mount;			/* what's mounted upon it */
	Mhead*	hash;			/* Hash chain */
};

struct Mntrah
{
	Rendez;

	ulong	vers;

	vlong	off;
	vlong	seq;

	uint	i;
	Mntrpc	*r[8];
};

struct Mntproc
{
	Rendez;

	Mnt	*m;
	Mntrpc	*r;
	void	*a;
	void	(*f)(Mntrpc*, void*);
};

struct Mnt
{
	Lock;
	/* references are counted using c->ref; channels on this mount point incref(c->mchan) == Mnt.c */
	Chan	*c;		/* Channel to file service */
	Proc	*rip;		/* Reader in progress */
	Mntrpc	*queue;		/* Queue of pending requests on this channel */
	Mntproc	defered[8];	/* Worker processes for defered RPCs (read ahead) */
	ulong	id;		/* Multiplexer id for channel check */
	Mnt	*list;		/* Free list */
	int	flags;		/* cache */
	int	msize;		/* data + IOHDRSZ */
	char	*version;	/* 9P version */
	Queue	*q;		/* input queue */
};

enum
{
	NUser,				/* note provided externally */
	NExit,				/* deliver note quietly */
	NDebug,				/* print debug message */
};

struct Note
{
	char	msg[ERRMAX];
	int	flag;			/* whether system posted it */
	Ref;
};

enum
{
	PG_MOD		= 0x01,		/* software modified bit */
	PG_REF		= 0x02,		/* software referenced bit */
	PG_PRIV		= 0x04,		/* private page */
};

struct Page
{
	Ref;
	Page	*next;			/* Free list or Hash chains */
	uintptr	pa;			/* Physical address in memory */
	uintptr	va;			/* Virtual address for user */
	uintptr	daddr;			/* Disc address on swap */
	Image	*image;			/* Associated text or swap image */
	ushort	refage;			/* Swap reference age */
	char	modref;			/* Simulated modify/reference bits */
	char	color;			/* Cache coloring */

#ifndef inittxtflush
	/* Flush icache bitmap for putmmu() */
	ulong	txtflush[(MAXMACH+31)/32];

#define inittxtflush(p)	memset((p)->txtflush, 0, sizeof((p)->txtflush))
#define settxtflush(p, c) if(c) memset((p)->txtflush, ~0, sizeof((p)->txtflush))
#define needtxtflush(p)	((p)->txtflush[m->machno>>5] & (1 << (m->machno&0x1F)))
#define donetxtflush(p)	((p)->txtflush[m->machno>>5] &= ~(1 << (m->machno&0x1F)))
#endif
};

struct Swapalloc
{
	Lock;				/* Free map lock */
	int	free;			/* 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;		/* Pager start threshold */
	ulong	headroom;		/* Space pager frees under highwater */
	ulong	xref;			/* Ref count for all map refs >= 255 */
}swapalloc;

struct Pte
{
	Page	*pages[PTEPERTAB];	/* Page map for this chunk of pte */
	Page	**first;		/* First used entry */
	Page	**last;			/* Last used entry */
};

/* 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_FIXED	= 06,
	SG_STICKY	= 07,

	SG_RONLY	= 0040,		/* Segment is read only */
	SG_CEXEC	= 0100,		/* Detach at exec */
	SG_FAULT	= 0200,		/* Fault on access */
	SG_CACHED	= 0400,		/* Normal cached memory */
	SG_DEVICE	= 01000,	/* Memory mapped device */
	SG_NOEXEC	= 02000,	/* No execute */
};

#define PG_ONSWAP	1
#define onswap(s)	(((uintptr)s)&PG_ONSWAP)
#define pagedout(s)	(((uintptr)s)==0 || onswap(s))
#define swapaddr(s)	(((uintptr)s)&~PG_ONSWAP)

#define SEGMAXSIZE	(1ULL*SEGMAPSIZE*PTEMAPMEM)

struct Physseg
{
	int	attr;			/* Segment attributes */
	char	*name;			/* Attach name */
	uintptr	pa;			/* Physical address */
	uintptr	size;			/* Maximum segment size in bytes */
};

struct Sema
{
	Rendez;
	long	*addr;
	int	waiting;
	Sema	*next;
	Sema	*prev;
};

struct Segment
{
	Ref;
	QLock;
	int	type;		/* segment type */
	ulong	size;		/* size in pages */

	uintptr	base;		/* virtual base */
	uintptr	top;		/* virtual top */
	uintptr	fstart;		/* start address in file for demand load */
	uintptr	flen;		/* length of segment in file */

	int	flushme;	/* maintain icache for this segment */
	Image	*image;		/* text in file attached to this segment */
	Physseg *pseg;
	ulong	*profile;	/* Tick profile area */
	Pte	**map;
	int	mapsize;
	Pte	*ssegmap[SSEGMAPSIZE];

	ulong	used;		/* pages used (swapped or not) */
	ulong	swapped;	/* pages swapped */

	Sema	sema;
};

struct Segio
{
	QLock;
	Rendez	cmdwait;
	Rendez	replywait;

	Proc	*p;		/* segmentio kproc */
	Segment	*s;

	char	*data;
	char	*addr;
	int	dlen;
	int	cmd;
	char	*err;
};

enum
{
	RENDLOG	=	5,
	RENDHASH =	1<<RENDLOG,	/* Hash to lookup rendezvous tags */
	MNTLOG	=	5,
	MNTHASH =	1<<MNTLOG,	/* Hash to walk mount table */
	NFD =		100,		/* per process file descriptors */
	ENVLOG =	5,
	ENVHASH =	1<<ENVLOG,	/* Egrp hash for variable lookup */
};
#define REND(p,s)	((p)->rendhash[(s)&((1<<RENDLOG)-1)])
#define MOUNTH(p,qid)	((p)->mnthash[(qid).path&((1<<MNTLOG)-1)])
#define PGHASH(i,daddr)	((i)->pghash[((daddr)>>PGSHIFT)&((i)->pghsize-1)])

struct Image
{
	Ref;
	Lock;

	long	pgref;			/* number of cached pages (pgref <= ref) */

	ulong	nattach;		/* usage frequency */

	Image	**link;			/* idle list */
	Image	*next;			/* idle list */

	Image	*hash;			/* Qid hash chains */

	Segment *s;			/* TEXT segment for image if running */

	Chan	*c;			/* channel to text file, nil when not used */
	Qid 	qid;			/* Qid for page cache coherence */
	ulong	dev;			/* Device id of owning channel */
	ushort	type;			/* Device type of owning channel */
	char	notext;			/* no file associated */

	ulong	pghsize;
	Page	*pghash[];		/* page cache */
};

struct Pgrp
{
	Ref;
	RWLock	ns;			/* Namespace n read/one write lock */
	u64int	notallowed[4];		/* Room for 256 devices */
	Mhead	*mnthash[MNTHASH];
};

struct Rgrp
{
	Ref;
	Lock;
	Proc	*rendhash[RENDHASH];	/* Rendezvous tag hash */
};

struct Evalue
{
	char	*value;
	int	len;
	ulong	vers;
	uvlong	path;			/* qid.path: Egrp.path << 32 | index (of Egrp.ent[]) */
	Evalue	*hash;
	char	name[];
};

struct Egrp
{
	Ref;
	RWLock;
	Evalue	**ent;
	int	nent;			/* numer of slots in ent[] */
	int	low;			/* lowest free index in ent[] */
	int	alloc;			/* bytes allocated for env */
	ulong	path;			/* generator for qid path */
	ulong	vers;			/* of Egrp */
	Evalue	*hash[ENVHASH];		/* hashtable for name lookup */
};

struct Fgrp
{
	Ref;
	Lock;
	Chan	**fd;
	uchar	*flag;			/* per file-descriptor flags (CCEXEC) */
	int	nfd;			/* number allocated */
	int	maxfd;			/* highest fd in use */
	int	exceed;			/* debugging */
};

enum
{
	DELTAFD	= 20		/* incremental increase in Fgrp.fd's */
};

struct Palloc
{
	Lock;
	Page	*head;			/* freelist head */
	ulong	freecount;		/* how many pages on free list now */
	Page	*pages;			/* array of all pages */
	ulong	user;			/* how many user pages */
	Rendezq		pwait[2];	/* Queues of procs waiting for memory */
};

struct Waitq
{
	Waitmsg	w;
	Waitq	*next;
};

/*
 * fasttick timer interrupts
 */
enum {
	/* Mode */
	Trelative,	/* timer programmed in ns from now */
	Tperiodic,	/* periodic timer, period in ns */
};

struct Timer
{
	/* Public interface */
	int	tmode;		/* See above */
	vlong	tns;		/* meaning defined by mode */
	void	(*tf)(Ureg*, Timer*);
	void	*ta;
	/* Internal */
	Lock;
	Mach	*tactive;	/* The cpu that tf is active on */
	Timers	*tt;		/* Timers queue this timer runs on */
	Tval	tticks;		/* tns converted to ticks */
	Tval	twhen;		/* ns represented in fastticks */
	Timer	*tnext;
};

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),
	RFREND		= (1<<13),
	RFNOMNT		= (1<<14),
};

/*
 *  process memory segments - NSEG always last !
 */
enum
{
	SSEG, TSEG, DSEG, BSEG, ESEG, LSEG, SEG1, SEG2, SEG3, SEG4, NSEG
};

enum
{
	Dead = 0,		/* Process states */
	Moribund,
	New,
	Ready,
	Scheding,
	Running,
	Queueing,
	QueueingR,
	QueueingW,
	Wakeme,
	Broken,
	Stopped,
	Rendezvous,
	Waitrelease,

	Proc_stopme = 1, 	/* devproc requests */
	Proc_exitme,
	Proc_traceme,
	Proc_exitbig,
	Proc_tracesyscall,

	TUser = 0, 		/* Proc.time */
	TSys,
	TReal,
	TCUser,
	TCSys,
	TCReal,

	NERR = 32,
	NNOTE = 5,

	Npriq		= 20,		/* number of scheduler priority levels */
	Nrq		= Npriq+2,	/* number of priority levels including real time */
	PriRelease	= Npriq,	/* released edf processes */
	PriEdf		= Npriq+1,	/* active edf processes */
	PriNormal	= 10,		/* base priority for normal processes */
	PriExtra	= Npriq-1,	/* edf processes at high best-effort pri */
	PriKproc	= 13,		/* base priority for kernel processes */
	PriRoot		= 13,		/* base priority for root processes */
};

struct Schedq
{
	Lock;
	Proc*	head;
	Proc*	tail;
	int	n;
};

struct Proc
{
	Label	sched;		/* known to l.s */

	Mach	*mach;		/* machine running this proc */
	char	*text;
	char	*user;

	char	*args;
	int	nargs;		/* number of bytes of args */
	int	setargs;	/* process changed its args */

	Proc	*rnext;		/* next process in run queue */
	Proc	*qnext;		/* next process on queue for a QLock */

	char	*psstate;	/* What /proc/#/status reports */
	int	state;

	ulong	pid;
	ulong	noteid;		/* Equivalent of note group */
	ulong	parentpid;
	ulong	index;

	Proc	*parent;	/* Process to send wait record on exit */
	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 */
	QLock	qwaitr;
	Rendez	waitr;		/* Place to hang out in wait */

	QLock	seglock;	/* locked whenever seg[] changes */
	Segment	*seg[NSEG];

	Pgrp	*pgrp;		/* Process group for namespace */
	Egrp 	*egrp;		/* Environment group */
	Fgrp	*fgrp;		/* File descriptor group */
	Rgrp	*rgrp;		/* Rendez group */

	Fgrp	*closingfgrp;	/* used during teardown */

	int	insyscall;
	ulong	time[6];	/* User, Sys, Real; child U, S, R */

	uvlong	kentry;		/* Kernel entry time stamp (for profiling) */
	/*
	 * pcycles: cycles spent in this process (updated on procswitch)
	 * when this is the current proc and we're in the kernel
	 * (procrestores outnumber procsaves by one)
	 * the number of cycles spent in the proc is pcycles + cycles()
	 * when this is not the current process or we're in user mode
	 * (procrestores and procsaves balance), it is pcycles.
	 */
	vlong	pcycles;

	QLock	debug;		/* to access debugging elements of User */
	Proc	*pdbg;		/* the debugging process */
	ulong	procmode;	/* proc device default file mode */
	int	privatemem;	/* proc does not let anyone read mem */
	int	noswap;		/* process is not swappable */
	int	hang;		/* hang at next exec for debug */
	int	procctl;	/* Control for /proc debugging */

	Lock	rlock;		/* sync sleep/wakeup with procinterrupt */
	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	newtlb;		/* Pager has changed my pte's, I must flush */

	uintptr	rendtag;	/* Tag for rendezvous */
	uintptr	rendval;	/* Value for rendezvous */
	Proc	*rendhash;	/* Hash list for tag values */

	Timer;			/* For tsleep and real-time */
	Rendez	*trend;
	int	(*tfn)(void*);
	void	(*kpfun)(void*);
	void	*kparg;

	Sargs	s;		/* syscall arguments */
	int	scallnr;	/* sys call number */
	int	nerrlab;
	Label	errlab[NERR];
	char	*syserrstr;	/* last error from a system call, errbuf0 or 1 */
	char	*errstr;	/* reason we're unwinding the error stack, errbuf1 or 0 */
	char	errbuf0[ERRMAX];
	char	errbuf1[ERRMAX];
	char	genbuf[128];	/* buffer used e.g. for last name element from namec */
	Chan	*slash;
	Chan	*dot;

	Note	*lastnote;
	Note	*note[NNOTE];
	short	nnote;
	short	notified;	/* sysnoted is due */
	int	(*notify)(void*, char*);

	Lock	*lastlock;	/* debugging */
	Lock	*lastilock;	/* debugging */

	int	nlocks;		/* number of locks held by proc */

	ulong	delaysched;
	ulong	priority;	/* priority level */
	ulong	basepri;	/* base priority level */
	uchar	fixedpri;	/* priority level doesn't change */
	uchar	wired;
	int	affinity;	/* machno this process last ran on */
	ulong	cpu;		/* cpu average */
	ulong	lastupdate;

	Edf	*edf;		/* if non-null, real-time proc, edf contains scheduling params */
	int	trace;		/* process being traced? */

	uintptr	qpc;		/* pc calling last blocking qlock */
	QLock	*eql;		/* interruptable eqlock */

	void	*noteureg;	/* User registers for notes */
	void	*dbgreg;	/* User registers for devproc */

	PFPU;			/* machine specific fpu state */
	PMMU;			/* machine specific mmu state */

	char	*syscalltrace;	/* syscall trace */
	
	Watchpt	*watchpt;	/* watchpoints */
	int	nwatchpt;
};

enum
{
	PRINTSIZE =	256,
	NUMSIZE	=	12,		/* size of formatted number */
	MB =		(1024*1024),
	/* READSTR was 1000, which is way too small for usb's ctl file */
	READSTR =	8000,		/* temporary buffer size for device reads */
};

extern	Conf	conf;
extern	char*	conffile;
extern	int	cpuserver;
extern	Dev*	devtab[];
extern	char*	eve;
extern	char	hostdomain[];
extern	uchar	initcode[];
extern	Queue*	kprintoq;
extern	int	nsyscall;
extern	Palloc	palloc;
extern	int	panicking;
extern	Queue*	serialoq;
extern	char*	statename[];
extern	Image*	swapimage;
extern	Image*	fscache;
extern	char*	sysname;
extern	uint	qiomaxatomic;
extern	char*	sysctab[];

enum
{
	LRESPROF	= 3,
};

/*
 *  action log
 */
struct Log {
	Lock;
	int	opens;
	char*	buf;
	char	*end;
	char	*rptr;
	int	len;
	int	nlog;
	int	minread;

	int	logmask;	/* mask of things to debug */

	QLock	readq;
	Rendez	readr;
};

struct Logflag {
	char*	name;
	int	mask;
};

enum
{
	NCMDFIELD = 128
};

struct Cmdbuf
{
	char	*buf;
	char	**f;
	int	nf;
};

struct Cmdtab
{
	int	index;	/* used by client to switch on result */
	char	*cmd;	/* command name */
	int	narg;	/* expected #args; 0 ==> variadic */
};

/*
 *  routines to access UART hardware
 */
struct PhysUart
{
	char*	name;
	Uart*	(*pnp)(void);
	void	(*enable)(Uart*, int);
	void	(*disable)(Uart*);
	void	(*kick)(Uart*);
	void	(*dobreak)(Uart*, int);
	int	(*baud)(Uart*, int);
	int	(*bits)(Uart*, int);
	int	(*stop)(Uart*, int);
	int	(*parity)(Uart*, int);
	void	(*modemctl)(Uart*, int);
	void	(*rts)(Uart*, int);
	void	(*dtr)(Uart*, int);
	char*	(*status)(Uart*, char*, char*);
	void	(*fifo)(Uart*, int);
	void	(*power)(Uart*, int);
	int	(*getc)(Uart*);	/* polling versions, for iprint, rdb */
	void	(*putc)(Uart*, int);
};

enum {
	Stagesize=	2048
};

/*
 *  software UART
 */
struct Uart
{
	void*	regs;			/* hardware stuff */
	void*	saveregs;		/* place to put registers on power down */
	char*	name;			/* internal name */
	ulong	freq;			/* clock frequency */
	int	bits;			/* bits per character */
	int	stop;			/* stop bits */
	int	parity;			/* even, odd or no parity */
	int	baud;			/* baud rate */
	PhysUart*phys;
	int	console;		/* used as a serial console */
	int	special;		/* internal kernel device */
	Uart*	next;			/* list of allocated uarts */

	QLock;
	int	type;			/* ?? */
	int	dev;
	int	opens;

	int	enabled;
	Uart	*elist;			/* next enabled interface */

	int	perr;			/* parity errors */
	int	ferr;			/* framing errors */
	int	oerr;			/* rcvr overruns */
	int	berr;			/* no input buffers */
	int	serr;			/* input queue overflow */

	/* buffers */
	int	(*putc)(Queue*, int);
	Queue	*iq;
	Queue	*oq;

	Lock	rlock;
	uchar	istage[Stagesize];
	uchar	*iw;
	uchar	*ir;
	uchar	*ie;

	Lock	tlock;			/* transmit */
	uchar	ostage[Stagesize];
	uchar	*op;
	uchar	*oe;
	int	drain;

	int	modem;			/* hardware flow control on */
	int	xonoff;			/* software flow control on */
	int	blocked;
	int	cts, dsr, dcd;	/* keep track of modem status */ 
	int	ctsbackoff;
	int	hup_dsr, hup_dcd;	/* send hangup upstream? */
	int	dohup;

	Rendez	r;
};

extern	Uart*	consuart;

/*
 *  performance timers, all units in perfticks
 */
struct Perf
{
	ulong	intrts;		/* time of last interrupt */
	ulong	inintr;		/* time since last clock tick in interrupt handlers */
	ulong	avg_inintr;	/* avg time per clock tick in interrupt handlers */
	ulong	inidle;		/* time since last clock tick in idle loop */
	ulong	avg_inidle;	/* avg time per clock tick in idle loop */
	ulong	last;		/* value of perfticks() at last clock tick */
	ulong	period;		/* perfticks() per clock tick */
};

struct Watchdog
{
	void	(*enable)(void);	/* watchdog enable */
	void	(*disable)(void);	/* watchdog disable */
	void	(*restart)(void);	/* watchdog restart */
	void	(*stat)(char*, char*);	/* watchdog statistics */
};

struct Watchpt
{
	enum {
		WATCHRD = 1,
		WATCHWR = 2,
		WATCHEX = 4,
	} type;
	uintptr addr, len;
};

struct PMach
{
	Proc*	readied;		/* for runproc */
	Label	sched;			/* scheduler wakeup */
	ulong	ticks;			/* of the clock since boot time */
	ulong	schedticks;		/* next forced context switch */

	int	pfault;
	int	cs;
	int	syscall;
	int	load;
	int	intr;
	int	ilockdepth;

	int	flushmmu;		/* make current proc flush it's mmu state */

	int	tlbfault;
	int	tlbpurge;

	Perf	perf;			/* performance counters */

	uvlong	cyclefreq;		/* Frequency of user readable cycle counter */
};

/* queue state bits,  Qmsg, Qcoalesce, and Qkick can be set in qopen */
enum
{
	/* Queue.state */
	Qstarve		= (1<<0),	/* consumer starved */
	Qmsg		= (1<<1),	/* message stream */
	Qclosed		= (1<<2),	/* queue has been closed/hungup */
	Qflow		= (1<<3),	/* producer flow controlled */
	Qcoalesce	= (1<<4),	/* coallesce packets on read */
	Qkick		= (1<<5),	/* always call the kick routine after qwrite */
};

#define DEVDOTDOT -1

#pragma	varargck	type	"I"	uchar*
#pragma	varargck	type	"V"	uchar*
#pragma	varargck	type	"E"	uchar*
#pragma	varargck	type	"M"	uchar*

/*
 * Log console output so it can be retrieved via /dev/kmesg.
 * This is good for catching boot-time messages after the fact.
 */
struct {
	Lock lk;
	uint n;
	char buf[16384];
} kmesg;
