

Jun 19 11:25 1978  buf.h Page 1


/*
 * Each buffer in the pool is usually doubly linked into 2 lists:
 * the device with which it is currently associated (always)
 * and also on a list of blocks available for allocation
 * for other use (usually).
 * The latter list is kept in last-used order, and the two
 * lists are doubly linked to make it easy to remove
 * a buffer from one list when it was found by
 * looking through the other.
 * A buffer is on the available list, and is liable
 * to be reassigned to another disk block, if and only
 * if it is not marked BUSY.  When a buffer is busy, the
 * available-list pointers can be used for other purposes.
 * Most drivers use the forward ptr as a link in their I/O active queue.
 * A buffer header contains all the information required to perform I/O.
 * Most of the routines which manipulate these things are in bio.c.
 */
struct buf
{
	int	b_flags;		/* see defines below */
	struct	buf *b_forw;		/* headed by devtab of b_dev */
	struct	buf *b_back;		/*  "  */
	struct	buf *av_forw;		/* position on free list, */
	struct	buf *av_back;		/*     if not BUSY*/
	int	b_dev;			/* major+minor device name */
	int	b_wcount;		/* transfer count (usu. words) */
	char	*b_addr;		/* low order core address */
	char	*b_xmem;		/* high order core address */
	char	*b_blkno;		/* block # on device */
	char	b_error;		/* returned after I/O */
	char	*b_resid;		/* words not transferred after error */
};

extern struct buf buf[];
extern struct buf bfreelist;
extern char buffers[][514];
/*
 * Each block device has a devtab, which contains private state stuff
 * and 2 list heads: the b_forw/b_back list, which is doubly linked
 * and has all the buffers currently associated with that major
 * device; and the d_actf/d_actl list, which is private to the
 * device but in fact is always used for the head and tail
 * of the I/O queue for the device.
 * Various routines in bio.c look at b_forw/b_back
 * (notice they are the same as in the buf structure)
 * but the rest is private to each device driver.
 */
struct devtab
{
	char	d_active;		/* busy flag */
	char	d_errcnt;		/* error count (for recovery) */
	struct	buf *b_forw;		/* first buffer for this dev */
	struct	buf *b_back;		/* last buffer for this dev */
	struct	buf *d_actf;		/* head of I/O queue */
	struct 	buf *d_actl;		/* tail of I/O queue */
};







Jun 19 11:25 1978  buf.h Page 2



/*
 * These flags are kept in b_flags.
 */
#define	B_WRITE	0	/* non-read pseudo-flag */
#define	B_READ	01	/* read when I/O occurs */
#define	B_DONE	02	/* transaction finished */
#define	B_ERROR	04	/* transaction aborted */
#define	B_BUSY	010	/* not on av_forw/back list */
#define	B_PHYS	020	/* Physical IO potentially using UNIBUS map */
#define	B_MAP	040	/* This block has the UNIBUS map allocated */
#define	B_WANTED 0100	/* issue wakeup when BUSY goes off */
#define	B_AGE	0200	/* delayed write for correct aging */
#define	B_ASYNC	0400	/* don't wait for I/O completion */
#define	B_DELWRI 01000	/* don't write till block leaves available list */
















































Jun 19 11:25 1978  conf.h Page 1


/*
 * Declaration of block device switch. Each entry (row) is
 * the only link between the main unix code and the driver.
 * The initialization of the device switches is in the file conf.c.
 */
struct	bdevsw
{
	int	(*d_open)();
	int	(*d_close)();
	int	(*d_strategy)();
	int	*d_tab;
} bdevsw[];

/*
 * Character device switch.
 */
struct	cdevsw
{
	int	(*d_open)();
	int	(*d_close)();
	int	(*d_read)();
	int	(*d_write)();
	int	(*d_sgtty)();
} cdevsw[];

int	bdevcnt;
int	cdevcnt;




































Jun 19 11:25 1978  file.h Page 1


/*
 * One file structure is allocated for each open/creat/pipe call.
 * Main use is to hold the read/write pointer associated with each
 * open file.
 */
struct	file
{
	char	f_flag;
	char	f_count;	/* reference count */
	struct inode *f_inode;	/* pointer to inode structure */
	char	*f_offset[2];	/* read/write character pointer */
};

extern struct file file[];

/* flags */
#define	FREAD	01
#define	FWRITE	02
#define	FPIPE	04












































Jun 19 11:25 1978  filsys.h Page 1


/*
 * Definition of the unix super block.
 * The root super block is allocated and
 * read in iinit/alloc.c. Subsequently
 * a super block is allocated and read
 * with each mount (smount/sys3.c) and
 * released with unmount (sumount/sys3.c).
 * A disk block is ripped off for storage.
 * See alloc.c for general alloc/free
 * routines for free list and I list.
 */
struct	filsys
{
	char	*s_isize;	/* size in blocks of I list */
	char	*s_fsize;	/* size in blocks of entire volume */
	int	s_nfree;	/* number of in core free blocks (0-100) */
	int	s_free[100];	/* in core free blocks */
	int	s_ninode;	/* number of in core I nodes (0-100) */
	int	s_inode[100];	/* in core free I nodes */
	char	s_flock;	/* lock during free list manipulation */
	char	s_ilock;	/* lock during I list manipulation */
	char	s_fmod;		/* super block modified flag */
	char	s_ronly;	/* mounted read-only flag */
	long	s_time;		/* current date of last update */
	int	pad[40];
	int	s_tfree;	/* Total free, for subsystem examination */
	int	s_tinode;	/* Free inodes, for subsystem examination */
	char	s_fname[6];	/* File system name */
	char	s_fpack[6];	/* File system pack name */
};

































Jun 19 11:25 1978  ino.h Page 1


/*
 * Inode structure as it appears on
 * the disk. Not used by the system,
 * but by things like check, df, dump.
 */
struct	inode
{
	int	i_mode;
	char	i_nlink;
	char	i_uid;
	char	i_gid;
	char	i_size0;
	char	*i_size1;
	int	i_addr[8];
	int	i_atime[2];
	int	i_mtime[2];
};

/* modes */
#define	IALLOC	0100000
#define	IFMT	060000
#define		IFDIR	040000
#define		IFCHR	020000
#define		IFBLK	060000
#define	ILARG	010000
#define	ISUID	04000
#define	ISGID	02000
#define ISVTX	01000
#define	IREAD	0400
#define	IWRITE	0200
#define	IEXEC	0100
































Jun 19 11:25 1978  inode.h Page 1


/*
 * The I node is the focus of all
 * file activity in unix. There is a unique
 * inode allocated for each active file,
 * each current directory, each mounted-on
 * file, text file, and the root. An inode is 'named'
 * by its dev/inumber pair. (iget/iget.c)
 * Data, from mode on, is read in
 * from permanent inode on volume.
 */
struct	inode
{
	char	i_flag;
	char	i_count;	/* reference count */
	int	i_dev;		/* device where inode resides */
	int	i_number;	/* i number, 1-to-1 with device address */
	int	i_mode;
	char	i_nlink;	/* directory entries */
	char	i_uid;		/* owner */
	char	i_gid;		/* group of owner */
	char	i_size0;	/* most significant of size */
	char	*i_size1;	/* least sig */
	int	i_addr[8];	/* device addresses constituting file */
	int	i_lastr;	/* last logical block read (for read-ahead) */
};

extern struct inode inode[];

/* flags */
#define	ILOCK	01		/* inode is locked */
#define	IUPD	02		/* inode has been modified */
#define	IACC	04		/* inode access time to be updated */
#define	IMOUNT	010		/* inode is mounted on */
#define	IWANT	020		/* some process waiting on lock */
#define	ITEXT	040		/* inode is pure text prototype */

/* modes */
#define	IALLOC	0100000		/* file is used */
#define	IFMT	060000		/* type of file */
#define		IFDIR	040000	/* directory */
#define		IFCHR	020000	/* character special */
#define		IFBLK	060000	/* block special, 0 is regular */
#define	ILARG	010000		/* large addressing algorithm */
#define	ISUID	04000		/* set user id on execution */
#define	ISGID	02000		/* set group id on execution */
#define ISVTX	01000		/* save swapped text even after use */
#define	IREAD	0400		/* read, write, execute permissions */
#define	IWRITE	0200
#define	IEXEC	0100














Jun 19 11:26 1978  io.h Page 1


#ifdef DQS11B_0
#define DQS11
#endif
#ifdef DQS11A_0
#define DQS11
#endif
#include "../hd/tty.h"
#include "../hd/peri.h"

#ifdef RP03_0
struct {
	char *nblocks;
	int	cyloff;
} rp_sizes[8] {
	7600,	0,		/* cyl 0 thru 37 */
	36200,	38,		/* cyl 38 thru 218 */
	36200,	219,		/* cyl 219 thru 399 */
	65535,	40,		/* cyl 40 thru 367 */
	36200,	22,		/* cyl 22 thru 202 */
	40600,	203,		/* cyl 203 thru 405 */
	0,	0,
	0,	0,
};
#endif
#ifdef RP05_0
#define RP04_0
#endif
#ifdef RP04_0
struct {
	char *nblocks;
	int	cyloff;
} hp_sizes[8] {
	11286,	0,		/* cyl 0 thru 26 */
	53504,	27,		/* cyl 27 thru 154 */
	53504,	155,		/* cyl 155 thru 282 */
	53504,	283,		/* cyl 283 thru 410 */
	65535,	27,		/* cyl 27 thru 183 */
	65535,	184,		/* cyl 184 thru 340 */
	29260,	341,		/* cyl 341 thru 410 */
	0,	0,
};
#endif
#ifdef RP06_0
struct {
	char *nblocks;
	int	cyloff;
} hp_sizes[8] {
	11286,	0,		/* cyl 0 thru 26 */
	65535,	27,		/* cyl 27 thru 183 */
	53504,	155,		/* cyl 155 thru 282 */
	53504,	283,		/* cyl 282 thru 410 */
	65535,	184,		/* cyl 184 thru 340 */
	65535,	341,		/* cyl 341 thru 497 */
	65535,	498,		/* cyl 498 thru 654 */
	65535,	655,		/* cyl 655 thru 811 */
};







Jun 19 11:26 1978  io.h Page 2


#endif

#ifdef DQS11
struct dqsdat dqsx[] {
#ifdef DQS11B_0
	{ 0,0,0,0,0,026402,070020,064420,0150440,067,055,075,046,03 },
#endif
#ifdef DQS11A_0
	{ 0,0,0,0,2,0102402,0130020,035420,0160440,04,0205,025,0227,0203 },
#endif
#ifdef DQS11B_1
	{ 0,0,0,0,0,026402,070020,064420,0150440,067,055,075,046,03 },
#endif
#ifdef DQS11A_1
	{ 0,0,0,0,2,0102402,0130020,035420,0160440,04,0205,025,0227,0203 },
#endif
#ifdef DQS11B_2
	{ 0,0,0,0,0,026402,070020,064420,0150440,067,055,075,046,03 },
#endif
#ifdef DQS11A_2
	{ 0,0,0,0,2,0102402,0130020,035420,0160440,04,0205,025,0227,0203 },
#endif
#ifdef DQS11B_3
	{ 0,0,0,0,0,026402,070020,064420,0150440,067,055,075,046,03 },
#endif
#ifdef DQS11A_3
	{ 0,0,0,0,2,0102402,0130020,035420,0160440,04,0205,025,0227,0203 },
#endif
};
#endif

































Jun 19 11:26 1978  param.h Page 1


/*
 * fundamental variables
 * don't change too often
 */

#define	NOFILE	15		/* max open files per process */
#define	SSIZE	12		/* initial stack size (*64 bytes) */
#define	SINCR	12		/* increment of stack (*64 bytes) */
#define	NCARGS	4096
#define	HZ	60		/* Ticks/second of the clock */
#define	NSWB	3		/* size of swap pool */
#define	CANBSIZ	256		/* max size of typewriter line */
#define	MAXMEM	(64*32)		/* max core per process - first # is Kw */
#define	USIZE	12		/* size of user block (*64) */
/*
 * priorities
 * probably should not be
 * altered too much
 */

#define	PSWP	-100
#define	PINOD	-90
#define	PRIBIO	-50
#define	PPIPE	1
#define	PWAIT	40
#define	PSLEP	90
#define	PUSER	100

/*
 * signals
 * dont change
 */

#define	NSIG	16
/*
 * No more than 16 signals (1-16) because they are
 * stored in bits in a word.
 */
#define	SIGHUP	1	/* hangup */
#define	SIGINT	2	/* interrupt (rubout) */
#define	SIGQIT	3	/* quit (FS) */
#define	SIGINS	4	/* illegal instruction */
#define	SIGTRC	5	/* trace or breakpoint */
#define	SIGIOT	6	/* iot */
#define	SIGEMT	7	/* emt */
#define	SIGFPT	8	/* floating exception */
#define	SIGKIL	9	/* kill, uncatchable termination */
#define	SIGBUS	10	/* bus error */
#define	SIGSEG	11	/* segmentation violation */
#define	SIGSYS	12	/* bad system call */
#define	SIGPIPE	13	/* end of pipe */
#define	SIGCLK	14	/* alarm clock */
#define	SIGTRM	15	/* Catchable termination */

/*
 * fundamental constants







Jun 19 11:26 1978  param.h Page 2


 * cannot be changed
 */

#define	NULL	0
#define	NODEV	(-1)
#define	ROOTINO	1		/* i number of all roots */
#define	DIRSIZ	14		/* max characters per directory */

/*
 * structure to access an
 * integer in bytes
 */
struct
{
	char	lobyte;
	char	hibyte;
};

/*
 * structure to access an integer
 */
struct
{
	int	integ;
};

/*
 * structure to access a long as integers
 */
struct {
	int	hiword;
	int	loword;
};

/*
 * Certain processor registers
 */
#define PS	0177776
#define KL	0177560
#define SW	0177570

/*
 * Some macros for units conversion
 */
/* Core clicks (64 bytes) to segments */
#define	ctos(x)	((x+127)>>7)

/* Core clicks (64 bytes) to blocks */
#define	ctob(x)	((x+7)>>3)

/* major part of a device */
#define major(x)	(int)((x.hibyte)&0377)

/* minor part of a device */
#define minor(x)	(int)(x&0377)








Jun 19 11:26 1978  peri.h Page 1


struct vp {
	int	vp_state;
	char	*vp_buf;
	char	*vp_count;
	int	vp_offset;
};
extern struct vp vp_vp[];

struct du {
	char	*du_buf;
	char	*du_bufp;
	int	du_nxmit;
	char	du_state;
	char	du_dummy;
	int	du_proc;
	char	*du_bufb;
	char	*du_bufe;
	int	du_nleft;
};
extern struct du du_du[];

#ifdef DQS11
#define NDQ 4
#define NBF 2

struct dqsbuf	{
	int bufl,bufc;
	char *bufb;
	struct dqsbuf *bufn;
	struct buf *bufa;
};

struct dqsdat	{
	int  state;
	char qcase,open;
	char *addr;
	int  dly;
	int  ttd,ack0,wack,ackx;
	char eot,enq,nak,etb,etx;
	char slp,time,try;
	int  cc,resp,uoff;
	struct dqsbuf *x,*q,*u;
	struct dqsbuf bf[NBF];
};

struct dqsdat dqsx[];
#endif
















Jun 19 11:26 1978  proc.h Page 1


/*
 * One structure allocated per active process. It contains all data needed
 * about the process while the process may be swapped out.
 * Other per process data (user.h) is swapped with the process.
 */
struct	proc {
	char	p_stat;
	char	p_flag;
	char	p_pri;		/* priority, negative is high */
	char	p_time;		/* resident time for scheduling */
	char	p_cpu;		/* cpu usage for scheduling */
	char	p_nice;		/* nice for cpu usage */
	int	p_sig;		/* signals pending to this process */
	int	p_uid;		/* user id, used to direct tty signals */
	int	p_pgrp;		/* name of process group leader */
	int	p_pid;		/* unique process id */
	int	p_ppid;		/* process id of parent */
	int	p_addr;		/* address of swappable image */
	int	p_size;		/* size of swappable image (*64 bytes) */
	int	p_wchan;	/* event process is awaiting */
	int	*p_textp;	/* pointer to text structure */
	int	*p_link;	/* linked list of running processes */
	int	p_clktim;	/* time to alarm clock signal */
};
extern struct proc proc[];

/* stat codes */
#define	SSLEEP	1		/* awaiting an event */
#define	SWAIT	2		/* (abandoned state) */
#define	SRUN	3		/* running */
#define	SIDL	4		/* intermediate state in process creation */
#define	SZOMB	5		/* intermediate state in process termination */
#define	SSTOP	6		/* process being traced */

/* flag codes */
#define	SLOAD	01		/* in core */
#define	SSYS	02		/* scheduling process */
#define	SLOCK	04		/* process cannot be swapped */
#define	SSWAP	010		/* process is being swapped out */
#define	STRC	020		/* process is being traced */
#define	SWTED	040		/* another tracing flag */

/*
 * Structure used to access saved times and status
 * of a dead processs, by the parent.
 * Overlays the proc structure.
 */
struct	xproc {
	char	p_stat;
	char	p_flag;
	char	p_pri;		/* priority, negative is high */
	char	p_time;		/* resident time for scheduling */
	char	p_cpu;		/* cpu usage for scheduling */
	char	p_nice;		/* nice for cpu usage */
	int	p_sig;		/* signals pending to this process */
	int	p_uid;		/* user id, used to direct tty signals */







Jun 19 11:26 1978  proc.h Page 2


	int	p_pgrp;		/* name of process group leader */
	int	p_pid;		/* unique process id */
	int	p_ppid;		/* process id of parent */
	int	xp_xstat;	/* Exit status for wait */
	long	xp_utime;	/* user time, this proc */
	long	xp_stime;	/* system time, this proc */
	int	p_clktim;	/* time to alarm clock signal */
};























































Jun 19 11:26 1978  reg.h Page 1


/*
 * Location of the users' stored registers relative to R0.
 * Usage is u.u_ar0[XX].
 */
#define	R0	(0)
#define	R1	(-2)
#define	R2	(-9)
#define	R3	(-8)
#define	R4	(-7)
#define	R5	(-6)
#define	R6	(-3)
#define	R7	(1)
#define	RPS	(2)

#define	TBIT	020		/* PS trace bit */
















































Jun 19 11:26 1978  seg.h Page 1


/*
 * KT-11 addresses and bits.
 */

#define	UISD	0177600		/* first user I-space descriptor register */
#define	UISA	0177640		/* first user I-space address register */
#define	UDSA	0177660		/* first user D-space address register */
#define	RO	02		/* access abilities */
#define	RW	06
#define	ED	010		/* extend direction */
#define	TX	020		/* Software: text segment */

/*
 * structure used to address a sequence of integers.
 */
struct
{
	int	r[];
};
int	*ka6;		/* 11/40 KISA6; 11/45 KDSA6 */

/*
 * address to access 11/70 UNIBUS map
 */
#define	UBMAP	0170200






































Jun 19 11:26 1978  space.h Page 1


#include "../hd/buf.h"
struct	buf	buf[NBUF];	/* buffer headers */
struct	buf	bfreelist;	/* head of the free list of buffers */
char	buffers[NBUF][514];	/* buffer pool */

#include "../hd/file.h"
struct	file	file[NFILE];	/* file table */

#include "../hd/inode.h"
struct	inode	inode[NINODE];	/* inode table */

#include "../hd/proc.h"
struct	proc	proc[NPROC];	/* process table */

#include "../hd/text.h"
struct	text text[NTEXT];	/* text table */

#include "../hd/systm.h"
struct map coremap[CMAPSIZ];
struct map swapmap[SMAPSIZ];
struct callo callout[NCALL];
struct mount mount[NMOUNT];

struct	cblock	cfree[NCLIST];

#include "../hd/var.h"
struct var v {
	NBUF,
	NCALL,
	NINODE,
	&inode[NINODE],
	NFILE,
	&file[NFILE],
	NMOUNT,
	&mount[NMOUNT],
	NPROC,
	&proc[1],
	NTEXT,
	&text[NTEXT],
	NCLIST,
};

char	pwbname[9] "pwbname";




















Jun 19 11:26 1978  systm.h Page 1


/*
 * Random set of variables used by more than one routine.
 */
struct map {
	int	m_size;
	char	*m_addr;
};
struct map coremap[];	/* core allocation map */
struct map swapmap[];	/* swap allocation map */
int	*rootdir;		/* pointer to inode of root directory */
int	*runq;			/* head of linked list of running processes */
int	cputype;		/* type of cpu =40, 45, or 70 */
int	lbolt;			/* time of day in 60th not in time */
long	time;			/* time in sec from 1970 */
long	tout;			/* time of day of next sleep */
/*
 * The callout structure is for a routine arranging to be
 *  called by the clock interrupt (clock.c) with a specified argument,
 * in a specified amount of time.
 * Used, for example, to time tab delays on typewriters.
 */
struct	callo
{
	int	c_time;		/* incremental time */
	int	c_arg;		/* argument to routine */
	int	(*c_func)();	/* routine */
} callout[];
/*
 * Mount structure.
 * One allocated on every mount.
 * Used to find the super block.
 */
struct	mount
{
	int	m_dev;		/* device mounted */
	int	*m_bufp;	/* pointer to superblock */
	int	*m_inodp;	/* pointer to mounted on inode */
} mount[];

int	mpid;			/* generic for unique process id's */
char	runin;			/* scheduling flag */
char	runout;			/* scheduling flag */
char	runrun;			/* scheduling flag */
char	curpri;			/* more scheduling */
int	maxmem;			/* actual max memory per process */
int	*lks;			/* pointer to clock device */
int	rootdev;		/* dev of root see conf.c */
int	swapdev;		/* dev of swap see conf.c */
int	swplo;			/* block number of swap space */
int	nswap;			/* size of swap space */
int	updlock;		/* lock for sync */
int	rablock;		/* block to be read ahead */
char	regloc[];		/* locs. of saved user registers (trap.c) */
char	pwbname[];









Jun 19 11:26 1978  text.h Page 1


/*
 * Text structure.
 * One allocated per pure procedure on swap device.
 * Manipulated by text.c
 */
struct text
{
	int	x_daddr;	/* disk address of segment */
	int	x_caddr;	/* core address, if loaded */
	int	x_size;		/* size (*64) */
	int	*x_iptr;	/* inode of prototype */
	char	x_count;	/* reference count */
	char	x_ccount;	/* number of loaded references */
	char	x_flag;		/* traced, written flags */
};

extern struct text text[];

#define	XWRIT	02		/* Text written into, must swap out */
#define	XLOAD	04		/* Currently being read from file */
#define	XLOCK	010		/* Being swapped in or out */
#define	XWANT	020		/* Wanted for swapping */









































Jun 19 11:26 1978  tty.h Page 1


/*
 * A clist structure is the head of a linked list queue of characters.
 * The characters are stored in 4-word
 * blocks containing a link and 6 characters.
 * The routines getc and putc (m45.s or m40.s)
 * manipulate these structures.
 */
struct clist
{
	int	c_cc;		/* character count */
	int	c_cf;		/* pointer to first block */
	int	c_cl;		/* pointer to last block */
};

/*
 * A tty structure is needed for each UNIX character device that
 * is used for normal terminal IO.
 * The routines in tty.c handle the common code associated with
 * these structures.
 * The definition and device dependent code is in each driver.
 */
struct tty
{
	struct	clist t_rawq;	/* input chars right off device */
	struct	clist t_canq;	/* input chars after erase and kill */
	struct	clist t_outq;	/* output list to device */
	int	t_flags;	/* mode, settable by stty call */
	int	*t_addr;	/* device address (register or startup fcn) */
	char	t_delct;	/* number of delimiters in raw q */
	char	t_col;		/* printing column of device */
	char	t_erase;	/* erase character */
	char	t_kill;		/* kill character */
	char	t_state;	/* internal state, not visible externally */
	char	t_char;		/* character temporary */
	int	t_speeds;	/* output+input line speed */
	int	t_pgrp;		/* process group name */
};

/*
 * The actual structure of a clist block manipulated by
 * getc and putc (mch.s)
 */
struct cblock {
	struct cblock *c_next;
	char info[6];
};

struct ttydma {
	char	c[8];
};

#define	TTIPRI	10
#define	TTOPRI	20

#define	CERASE	'#'		/* default special characters */
#define	CEOT	004







Jun 19 11:26 1978  tty.h Page 2


#define	CKILL	'@'
#define	CQUIT	034		/* FS, cntl shift L */
#define	CINTR	0177		/* DEL */

/* limits */
#define	TTHIWAT	100
#define	TTLOWAT	50
#define	TTYHOG	256

/* modes */
#define	HUPCL	01
#define	XTABS	02
#define	LCASE	04
#define	ECHO	010
#define	CRMOD	020
#define	RAW	040
#define	ODDP	0100
#define	EVENP	0200
#define	NLDELAY	001400
#define	TBDELAY	006000
#define	CRDELAY	030000
#define	VTDELAY	040000

/* Hardware bits */
#define	DONE	0200
#define	IENABLE	0100

/* Internal state bits */
#define	TIMEOUT	01		/* Delay timeout in progress */
#define	WOPEN	02		/* Waiting for open to complete */
#define	ISOPEN	04		/* Device is open */
#define	SSTART	010		/* Has special start routine at addr */
#define	CARR_ON	020		/* Software copy of carrier-present */
#define	BUSY	040		/* Output in progress */
#define	ASLEEP	0100		/* Wakeup when output done */




























Jun 19 11:26 1978  user.h Page 1


/*
 * The user structure.
 * One allocated per process.
 * Contains all per process data that doesn't need to be referenced
 * while the process is swapped.
 * The user block is USIZE*64 bytes long; resides at virtual kernel
 * loc 140000; contains the system stack per user; is cross referenced
 * with the proc structure for the same process.
 */
struct user
{
	int	u_rsav[2];		/* save r5,r6 when exchanging stacks */
	int	u_fsav[25];		/* save fp registers */
					/* rsav and fsav must be first in structure */
	char	u_segflg;		/* IO flag: 0:user D; 1:system; 2:user I */
	char	u_error;		/* return error code */
	char	u_uid;			/* effective user id */
	char	u_gid;			/* effective group id */
	char	u_ruid;			/* real user id */
	char	u_rgid;			/* real group id */
	int	u_procp;		/* pointer to proc structure */
	char	*u_base;		/* base address for IO */
	char	*u_count;		/* bytes remaining for IO */
	char	*u_offset[2];		/* offset in file for IO */
	int	*u_cdir;		/* pointer to inode of current directory */
	char	u_dbuf[DIRSIZ];		/* current pathname component */
	char	*u_dirp;		/* current pointer to inode */
	struct	{			/* current directory entry */
		int	u_ino;
		char	u_name[DIRSIZ];
	} u_dent;
	int	*u_pdir;		/* inode of parent directory of dirp */
	int	u_uisa[16];		/* prototype of segmentation addresses */
	int	u_uisd[16];		/* prototype of segmentation descriptors */
	int	u_ofile[NOFILE];	/* pointers to file structures of open files */
	int	u_arg[5];		/* arguments to current system call */
	int	u_tsize;		/* text size (*64) */
	int	u_dsize;		/* data size (*64) */
	int	u_ssize;		/* stack size (*64) */
	int	u_sep;			/* flag for I and D separation */
	int	u_qsav[2];		/* label variable for quits and interrupts */
	int	u_ssav[2];		/* label variable for swapping */
	int	u_signal[NSIG];		/* disposition of signals */
	long	u_utime;		/* this process user time */
	long	u_stime;		/* this process system time */
	long	u_cutime;		/* sum of childs' utimes */
	long	u_cstime;		/* sum of childs' stimes */
	int	*u_ar0;			/* address of users saved R0 */
	int	u_prof[4];		/* profile arguments */
	char	u_intflg;		/* catch intr from sys */
	int	u_ttyp;			/* controlling tty pointer */
	int	u_ttyd;			/* controlling tty dev */
	struct {			/* header of executable file */
		int	ux_mag;		/* magic number */
		int	ux_tsize;	/* text size */
		int	ux_dsize;	/* data size */







Jun 19 11:26 1978  user.h Page 2


		int	ux_bsize;	/* bss size */
		int	ux_ssize;	/* symbol table size */
		int	ux_entloc;	/* entry location */
	} u_exdata;
	int	u_udata[16];		/* user log data */
					/* kernel stack per user
					 * extends from u + USIZE*64
					 * backward not to reach here
					 */
};
extern u;

/* u_error codes */
#define	EPERM	1
#define	ENOENT	2
#define	ESRCH	3
#define	EINTR	4
#define	EIO	5
#define	ENXIO	6
#define	E2BIG	7
#define	ENOEXEC	8
#define	EBADF	9
#define	ECHILD	10
#define	EAGAIN	11
#define	ENOMEM	12
#define	EACCES	13
#define	EFAULT	14
#define	ENOTBLK	15
#define	EBUSY	16
#define	EEXIST	17
#define	EXDEV	18
#define	ENODEV	19
#define	ENOTDIR	20
#define	EISDIR	21
#define	EINVAL	22
#define	ENFILE	23
#define	EMFILE	24
#define	ENOTTY	25
#define	ETXTBSY	26
#define	EFBIG	27
#define	ENOSPC	28
#define	ESPIPE	29
#define	EROFS	30
#define	EMLINK	31
#define	EPIPE	32


















Jun 19 11:26 1978  var.h Page 1


struct var {
	int	v_buf;
	int	v_call;
	int	v_inode;
	char *	ve_inode;
	int	v_file;
	char *	ve_file;
	int	v_mount;
	char *	ve_mount;
	int	v_proc;
	char *	ve_proc;
	int	v_text;
	char *	ve_text;
	int	v_clist;
};
extern struct var v;















































Jun 19 11:26 1978  alloc.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/filsys.h"
#include "../hd/conf.h"
#include "../hd/buf.h"
#include "../hd/inode.h"
#include "../hd/user.h"
#include "../hd/var.h"

/*
 * iinit is called once (from main) very early in initialization.
 * It reads the root's super block and initializes the current date
 * from the last modified date.
 *
 * panic: iinit -- cannot read the super block, usually because of an IO error.
 */
iinit()
{
	register *cp, *bp;

	(*bdevsw[major(rootdev)].d_open)(minor(rootdev), 1);
	bp = bread(rootdev, 1);
	cp = getblk(NODEV);
	if(u.u_error)
		panic("iinit");
	bcopy(bp->b_addr, cp->b_addr, 256);
	brelse(bp);
	mount[0].m_bufp = cp;
	mount[0].m_dev = rootdev;
	cp = cp->b_addr;
	cp->s_flock = 0;
	cp->s_ilock = 0;
	cp->s_ronly = 0;
	cp->s_ninode = 0;	/* zero free inode cnt to force init by ialloc */
	time = cp->s_time;
}

/*
 * alloc will obtain the next available free disk block from the free list
 * of the specified device.
 * The super block has up to 100 remembered free blocks;
 * the last of these is read to obtain 100 more . . .
 *
 * no space on dev x/y -- when the free list is exhausted.
 */
alloc(dev)
{
	int bno;
	register *bp, *ip, *fp;

	fp = getfs(dev);
	while(fp->s_flock)
		sleep(&fp->s_flock, PINOD);
	do {
		if(fp->s_nfree <= 0)







Jun 19 11:26 1978  alloc.c Page 2


			goto nospace;
		bno = fp->s_free[--fp->s_nfree];
		if(bno == 0)
			goto nospace;
	} while (badblock(fp, bno, dev));
	if(fp->s_nfree <= 0) {
		fp->s_flock++;
		bp = bread(dev, bno);
		ip = bp->b_addr;
		fp->s_nfree = *ip++;
		bcopy(ip, fp->s_free, 100);
		brelse(bp);
		fp->s_flock = 0;
		wakeup(&fp->s_flock);
	}
	bp = getblk(dev, bno);
	clrbuf(bp);
	if(fp->s_tfree) fp->s_tfree--;
	fp->s_fmod = 1;
	return(bp);

nospace:
	fp->s_nfree = 0;
	fp->s_tfree = 0;
	prdev("no space", dev);
	u.u_error = ENOSPC;
	return(NULL);
}

/*
 * place the specified disk block back on the free list of the
 * specified device.
 */
free(dev, bno)
{
	register *fp, *bp, *ip;

	fp = getfs(dev);
	fp->s_fmod = 1;
	while(fp->s_flock)
		sleep(&fp->s_flock, PINOD);
	if (badblock(fp, bno, dev))
		return;
	if(fp->s_nfree <= 0) {
		fp->s_nfree = 1;
		fp->s_free[0] = 0;
	}
	if(fp->s_nfree >= 100) {
		fp->s_flock++;
		bp = getblk(dev, bno);
		ip = bp->b_addr;
		*ip++ = fp->s_nfree;
		bcopy(fp->s_free, ip, 100);
		fp->s_nfree = 0;
		bwrite(bp);
		fp->s_flock = 0;







Jun 19 11:26 1978  alloc.c Page 3


		wakeup(&fp->s_flock);
	}
	fp->s_free[fp->s_nfree++] = bno;
	fp->s_tfree++;
	fp->s_fmod = 1;
}

/*
 * Check that a block number is in the range between the I list
 * and the size of the device.
 * This is used mainly to check that a
 * garbage file system has not been mounted.
 *
 * bad block on dev x/y -- not in range
 */
badblock(afp, abn, dev)
{
	register struct filsys *fp;
	register char *bn;

	fp = afp;
	bn = abn;
	if (bn < fp->s_isize+2 || bn >= fp->s_fsize) {
		prdev("bad block", dev);
		return(1);
	}
	return(0);
}

/*
 * Allocate an unused I node on the specified device.
 * Used with file creation.
 * The algorithm keeps up to 100 spare I nodes in the
 * super block. When this runs out, a linear search through the
 * I list is instituted to pick up 100 more.
 */
ialloc(dev)
{
	register *fp, *bp, *ip;
	int i, j, k, ino;

	fp = getfs(dev);
	while(fp->s_ilock)
		sleep(&fp->s_ilock, PINOD);
loop:
	if(fp->s_ninode > 0) {
		ino = fp->s_inode[--fp->s_ninode];
		ip = iget(dev, ino);
		if (ip==NULL)
			return(NULL);
		if(ip->i_mode == 0) {
			for(bp = &ip->i_mode; bp < &ip->i_addr[8];)
				*bp++ = 0;
			if(fp->s_tinode) fp->s_tinode--;
			fp->s_fmod = 1;
			return(ip);







Jun 19 11:26 1978  alloc.c Page 4


		}
		/*
		 * Inode was allocated after all.
		 * Look some more.
		 */
		iput(ip);
		goto loop;
	}
	fp->s_ilock++;
	ino = 0;
	for(i=0; i<fp->s_isize; i++) {
		bp = bread(dev, i+2);
		ip = bp->b_addr;
		for(j=0; j<256; j=+16) {
			ino++;
			if(ip[j] != 0)
				continue;
			for(k=0; k<v.v_inode; k++)
			if(dev==inode[k].i_dev && ino==inode[k].i_number)
				goto cont;
			fp->s_inode[fp->s_ninode++] = ino;
			if(fp->s_ninode >= 100)
				break;
		cont:;
		}
		brelse(bp);
		if(fp->s_ninode >= 100)
			break;
	}
	fp->s_ilock = 0;
	wakeup(&fp->s_ilock);
	if (fp->s_ninode > 0)
		goto loop;
	prdev("Out of inodes", dev);
	u.u_error = ENOSPC;
	fp->s_tinode = 0;
	return(NULL);
}

/*
 * Free the specified I node on the specified device.
 * The algorithm stores up to 100 I nodes in the super
 * block and throws away any more.
 */
ifree(dev, ino)
{
	register *fp;

	fp = getfs(dev);
	fp->s_tinode++;
	if(fp->s_ilock)
		return;
	if(fp->s_ninode >= 100)
		return;
	fp->s_inode[fp->s_ninode++] = ino;
	fp->s_fmod = 1;







Jun 19 11:26 1978  alloc.c Page 5


}

/*
 * getfs maps a device number into a pointer to the incore super block.
 * The algorithm is a linear search through the mount table.
 * A consistency check of the in core free-block and i-node counts.
 *
 * bad count on dev x/y -- the count
 *	check failed. At this point, all
 *	the counts are zeroed which will
 *	almost certainly lead to "no space"
 *	diagnostic
 * panic: no fs -- the device is not mounted.
 *	this "cannot happen"
 */
getfs(dev)
{
	register struct mount *p;
	register char *n1, *n2;

	for (p = &mount[0]; p < v.ve_mount; p++)
	if(p->m_bufp != NULL && p->m_dev == dev) {
		p = p->m_bufp->b_addr;
		n1 = p->s_nfree;
		n2 = p->s_ninode;
		if(n1 > 100 || n2 > 100) {
			prdev("bad count", dev);
			p->s_nfree = 0;
			p->s_ninode = 0;
		}
		return(p);
	}
	panic("no fs");
}

/*
 * update is the internal name of 'sync'. It goes through the disk
 * queues to initiate sandbagged IO; goes through the I nodes to write
 * modified nodes; and it goes through the mount table to initiate modified
 * super blocks.
 */
update()
{
	register struct inode *ip;
	register struct mount *mp;
	register *bp;

	if(updlock)
		return;
	updlock++;
	for (mp = &mount[0]; mp < v.ve_mount; mp++)
		if(mp->m_bufp != NULL) {
			ip = mp->m_bufp->b_addr;
			if(ip->s_fmod==0 || ip->s_ilock!=0 ||
			   ip->s_flock!=0 || ip->s_ronly!=0)
				continue;







Jun 19 11:26 1978  alloc.c Page 6


			bp = getblk(mp->m_dev, 1);
			ip->s_fmod = 0;
			ip->s_time = time;
			bcopy(ip, bp->b_addr, 256);
			bwrite(bp);
		}
	for (ip = &inode[0]; ip < v.ve_inode; ip++)
		if((ip->i_flag&ILOCK)==0 && ip->i_count) {
			ip->i_flag =| ILOCK;
			ip->i_count++;
			iupdat(ip);
			iput(ip);
		}
	updlock = 0;
	bflush(NODEV);
}















































Jun 19 11:27 1978  clock.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/var.h"

int	sstime;
int	rrcput[256];

#define	UMODE	0170000
#define	SCHMAG	8/10

/*
 * clock is called straight from
 * the real time clock interrupt.
 *
 * Functions:
 *	reprime clock
 *	copy *switches to display
 *	implement callouts
 *	maintain user/system times
 *	maintain date
 *	profile
 *	tout wakeup (sys sleep)
 *	lightning bolt wakeup (every 4 sec)
 *	alarm clock signals
 *	jab the scheduler
 */
clock(dev, sp, r1, nps, r0, pc, ps)
{
	register struct callo *p1, *p2;
	register struct proc *pp;
	int a;

	/*
	 * restart clock
	 */

	*lks = 0115;

	/*
	 * display register
	 */

	display();

	/*
	 * callouts
	 * if none, just return
	 * else update first non-zero time
	 */

	if(callout[0].c_func == 0)
		goto out;
	p2 = &callout[0];







Jun 19 11:27 1978  clock.c Page 2


	while(p2->c_time<=0 && p2->c_func!=0)
		p2++;
	p2->c_time--;

	/*
	 * if ps is high, just return
	 */

	if((ps&0340) != 0)
		goto out;

	/*
	 * callout
	 */

	spl5();
	if(callout[0].c_time <= 0) {
		p1 = &callout[0];
		while(p1->c_func != 0 && p1->c_time <= 0) {
			(*p1->c_func)(p1->c_arg);
			p1++;
		}
		p2 = &callout[0];
		while(p2->c_func = p1->c_func) {
			p2->c_time = p1->c_time;
			p2->c_arg = p1->c_arg;
			p1++;
			p2++;
		}
	}

	/*
	 * lightning bolt time-out
	 * and time of day
	 */

out:
	sstime++;
	rrcput[u.u_ruid&0377]++;
	if((ps&UMODE) == UMODE) {
		u.u_utime++;
		if(u.u_prof[3])
			incupc(pc, u.u_prof);
	} else
		u.u_stime++;
	pp = u.u_procp;
	if(++pp->p_cpu == 0)
		pp->p_cpu--;
	if(++lbolt >= HZ) {
		if((ps&0340) != 0)
			return;
		lbolt =- HZ;
		++time;
		spl1();
		if (time == tout)
			wakeup(&tout);







Jun 19 11:27 1978  clock.c Page 3


		runrun++;
		if((time.loword&01) == 0)
			wakeup(&lbolt);
		for(pp = &proc[0]; pp < v.ve_proc; pp++)
		if (pp->p_stat) {
			if(pp->p_time != 127)
				pp->p_time++;
			if(pp->p_clktim)
				if(--pp->p_clktim == 0)
					psignal(pp, SIGCLK);
			pp->p_cpu =>> 1;
			if(pp->p_pri >= PUSER)
				setpri(pp);
		}
		if(runin!=0) {
			runin = 0;
			setrun(&proc[0]);
		}
		if((ps&UMODE) == UMODE) {
			u.u_ar0 = &r0;
			if(issig())
				psig();
			setpri(u.u_procp);
		}
	}
}

/*
 * timeout is called to arrange that fun(arg) is called in tim/HZ seconds.
 * An entry is sorted into the callout structure.
 * The time in each structure entry is the number of HZ's more
 * than the previous entry. In this way, decrementing the
 * first entry has the effect of updating all entries.
 *
 * The panic is there because there is nothing
 * intelligent to be done if an entry won't fit.
 */
timeout(fun, arg, tim)
{
	register struct callo *p1, *p2;
	register t;
	int s;

	t = tim;
	s = PS->integ;
	p1 = &callout[0];
	spl7();
	while(p1->c_func != 0 && p1->c_time <= t) {
		t =- p1->c_time;
		p1++;
	}
	if (p1 >= &callout[v.v_call-1])
		panic("Timeout table overflow");
	p1->c_time =- t;
	p2 = p1;
	while(p2->c_func != 0)







Jun 19 11:27 1978  clock.c Page 4


		p2++;
	while(p2 >= p1) {
		(p2+1)->c_time = p2->c_time;
		(p2+1)->c_func = p2->c_func;
		(p2+1)->c_arg = p2->c_arg;
		p2--;
	}
	p1->c_time = t;
	p1->c_func = fun;
	p1->c_arg = arg;
	PS->integ = s;
}



















































Jun 19 11:27 1978  fio.c Page 1


#
#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/filsys.h"
#include "../hd/file.h"
#include "../hd/conf.h"
#include "../hd/inode.h"
#include "../hd/reg.h"
#include "../hd/systm.h"
#include "../hd/var.h"

/*
 * Convert a user supplied file descriptor into a pointer
 * to a file structure.
 * Only task is to check range of the descriptor.
 */
getf(f)
{
	register *fp, rf;

	rf = f;
	if (0<=rf && rf<NOFILE) {
		fp = u.u_ofile[rf];
		if(fp != NULL)
			return(fp);
	}
	u.u_error = EBADF;
	return(NULL);
}

/*
 * Internal form of close.
 * Decrement reference count on file structure.
 * Also make sure the pipe protocol does not constipate.
 *
 * Decrement reference count on the inode following
 * removal to the referencing file structure.
 * On the last close switch out the the device handler for
 * special files.  Note that the handler is called
 * on every open but only the last close.
 */
closef(fp)
int *fp;
{
	register *ip;
	register struct file *rfp;
	int flag;
	register int (*cfunc)();

	if ((rfp = fp) == NULL)
		return;
	ip = rfp->f_inode;
	if (rfp->f_count > 1) {
		rfp->f_count--;
		return;
	}







Jun 19 11:27 1978  fio.c Page 2


	plock(ip);
	flag = rfp->f_flag&FWRITE;
	rfp->f_count = 0;
	if(rfp->f_flag&FPIPE) {
		ip->i_mode =& ~(IREAD|IWRITE);
		wakeup(ip+1);
		wakeup(ip+2);
	}
	cfunc = 0;
	if ((ip->i_mode&IFMT) == IFCHR)
		cfunc = cdevsw[major(ip->i_addr[0])].d_close;
	else if ((ip->i_mode&IFMT)== IFBLK)
		cfunc = bdevsw[major(ip->i_addr[0])].d_close;
	iput(ip);
	if (cfunc == 0)
		return;
	for (rfp=file; rfp < v.ve_file; rfp++)
		if (rfp->f_count && rfp->f_inode==ip)
			return;
	(*cfunc)(minor(ip->i_addr[0]), flag);
}

/*
 * openi called to allow handler of special files to initialize and
 * validate before actual IO.
 * Called only for open of special files.
 */
openi(ip, rw)
register *ip;
{
	register dev, maj;

	dev = minor(ip->i_addr[0]);
	maj = major(ip->i_addr[0]);
	if ((ip->i_mode&IFMT) == IFCHR)
		if (maj >= cdevcnt)
			u.u_error = ENXIO; else
		{
			if (u.u_ttyp == 0)
				u.u_ttyd = ip->i_addr[0];
			(*cdevsw[maj].d_open)(dev, rw);
		} else
		if (maj >= bdevcnt)
			u.u_error = ENXIO; else
			(*bdevsw[maj].d_open)(dev, rw);
}

/*
 * Check mode permission on inode pointer.
 * Mode is READ, WRITE or EXEC.
 * In the case of WRITE, the read-only status of the file
 * system is checked. Also in WRITE, prototype text
 * segments cannot be written.
 * The mode is shifted to select the owner/group/other fields.
 * The super user is granted all permissions.
 */







Jun 19 11:27 1978  fio.c Page 3


access(aip, mode)
int *aip;
{
	register *ip, m;

	ip = aip;
	m = mode;
	if(m == IWRITE) {
		if(getfs(ip->i_dev)->s_ronly != 0) {
			u.u_error = EROFS;
			return(1);
		}
		if(ip->i_flag & ITEXT) {
			u.u_error = ETXTBSY;
			return(1);
		}
	}
	if(u.u_uid == 0)
		return(0);
	if(u.u_uid != ip->i_uid) {
		m =>> 3;
		if(u.u_gid != ip->i_gid)
			m =>> 3;
	}
	if((ip->i_mode&m) != 0)
		return(0);

bad:
	u.u_error = EACCES;
	return(1);
}

/*
 * Look up a pathname and test if the resultant inode is owned by the
 * current user. If not, try for super-user.
 * If permission is granted, return inode pointer.
 */
owner()
{
	register struct inode *ip;
	extern uchar();

	if ((ip = namei(uchar, 0)) == NULL)
		return(NULL);
	if(u.u_uid == ip->i_uid)
		return(ip);
	if (suser())
		return(ip);
	iput(ip);
	return(NULL);
}

/*
 * Test if the current user is the super user.
 */
suser()







Jun 19 11:27 1978  fio.c Page 4


{

	if(u.u_uid == 0)
		return(1);
	u.u_error = EPERM;
	return(0);
}

/*
 * Allocate a user file descriptor.
 */
ufalloc()
{
	register i;

	for (i=0; i<NOFILE; i++)
		if (u.u_ofile[i] == NULL) {
			u.u_ar0[R0] = i;
			return(i);
		}
	u.u_error = EMFILE;
	return(-1);
}

/*
 * Allocate a user file descriptor and a file structure.
 * Initialize the descriptor to point at the file structure.
 *
 * no file -- if there are no available 	file structures.
 */
falloc()
{
	register struct file *fp;
	register i;

	if ((i = ufalloc()) < 0)
		return(NULL);
	for (fp = &file[0]; fp < v.ve_file; fp++)
		if (fp->f_count==0) {
			u.u_ofile[i] = fp;
			fp->f_count++;
			fp->f_offset[0] = 0;
			fp->f_offset[1] = 0;
			return(fp);
		}
	printf("no file\n");
	u.u_error = ENFILE;
	return(NULL);
}














Jun 19 11:27 1978  iget.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/inode.h"
#include "../hd/filsys.h"
#include "../hd/buf.h"
#include "../hd/var.h"

/*
 * Look up an inode by device,inumber.
 * If it is in core (in the inode structure), honor the locking protocol.
 * If it is not in core, read it in from the specified device.
 * If the inode is mounted on, perform the indicated indirection.
 * In all cases, a pointer to a locked inode structure is returned.
 *
 * printf warning: no inodes -- if the inode structure is full
 * panic: no imt -- if the mounted filesystem is not in the mount table.
 *	"cannot happen"
 */
iget(dev, ino)
{
	register struct inode *p;
	register *ip2;
	int *ip1;
	register struct mount *ip;

loop:
	ip = NULL;
	for(p = &inode[0]; p < v.ve_inode; p++) {
		if(dev==p->i_dev && ino==p->i_number) {
			if((p->i_flag&ILOCK) != 0) {
				p->i_flag =| IWANT;
				sleep(p, PINOD);
				goto loop;
			}
			if((p->i_flag&IMOUNT) != 0) {
				for(ip = &mount[0]; ip < v.ve_mount; ip++)
				if(ip->m_inodp == p) {
					dev = ip->m_dev;
					ino = ROOTINO;
					goto loop;
				}
				panic("no imt");
			}
			p->i_count++;
			p->i_flag =| ILOCK;
			return(p);
		}
		if(ip==NULL && p->i_count==0)
			ip = p;
	}
	if((p=ip) == NULL) {
		printf("Inode table overflow\n");
		u.u_error = ENFILE;
		return(NULL);







Jun 19 11:27 1978  iget.c Page 2


	}
	p->i_dev = dev;
	p->i_number = ino;
	p->i_flag = ILOCK;
	p->i_count++;
	p->i_lastr = -1;
	ip = bread(dev, ldiv(ino+31,16));
	/*
	 * Check I/O errors
	 */
	if (ip->b_flags&B_ERROR) {
		brelse(ip);
		iput(p);
		return(NULL);
	}
	ip1 = ip->b_addr + 32*lrem(ino+31, 16);
	ip2 = &p->i_mode;
	while(ip2 < &p->i_addr[8])
		*ip2++ = *ip1++;
	brelse(ip);
	return(p);
}

/*
 * Decrement reference count of an inode structure.
 * On the last reference, write the inode out and if necessary,
 * truncate and deallocate the file.
 */
iput(p)
struct inode *p;
{
	register *rp;

	rp = p;
	if(rp->i_count == 1) {
		rp->i_flag =| ILOCK;
		if(rp->i_nlink <= 0) {
			itrunc(rp);
			rp->i_mode = 0;
			rp->i_flag =| IUPD;
			ifree(rp->i_dev, rp->i_number);
		}
		iupdat(rp);
		prele(rp);
		rp->i_flag = 0;
		rp->i_number = 0;
	}
	rp->i_count--;
	prele(rp);
}

/*
 * Check accessed and update flags on an inode structure.
 * If either is on, update the inode with the current time.
 */
iupdat(p)







Jun 19 11:27 1978  iget.c Page 3


int *p;
{
	register *ip1, *ip2, *rp;
	int *bp, i;

	rp = p;
	if((rp->i_flag&(IUPD|IACC)) != 0) {
		if(getfs(rp->i_dev)->s_ronly) {
			if(rp->i_flag&IUPD)
				u.u_error = EROFS;
			rp->i_flag =& ~(IUPD|IACC);
			return;
		}
		i = rp->i_number+31;
		bp = bread(rp->i_dev, ldiv(i,16));
		ip1 = bp->b_addr + 32*lrem(i, 16);
		ip2 = &rp->i_mode;
		while(ip2 < &rp->i_addr[8])
			*ip1++ = *ip2++;
		if(rp->i_flag&IACC) {
			*ip1++ = time.hiword;
			*ip1++ = time.loword;
		} else
			ip1 =+ 2;
		if(rp->i_flag&IUPD) {
			*ip1++ = time.hiword;
			*ip1++ = time.loword;
		}
		rp->i_flag =& ~(IUPD|IACC);
		bdwrite(bp);
	}
}

/*
 * Free all the disk blocks associated with the specified inode structure.
 * The blocks of the file are removed in reverse order. This FILO
 * algorithm will tend to maintain
 * a contiguous free list much longer than FIFO.
 */
itrunc(ip)
int *ip;
{
	register *rp, *bp, *cp;
	int *dp, *ep;

	rp = ip;
	if((rp->i_mode&(IFCHR&IFBLK)) != 0)
		return;
	for(ip = &rp->i_addr[7]; ip >= &rp->i_addr[0]; ip--)
	if(*ip) {
		if((rp->i_mode&ILARG) != 0) {
			bp = bread(rp->i_dev, *ip);
			for(cp = bp->b_addr+510; cp >= bp->b_addr; cp--)
			if(*cp) {
				free(rp->i_dev, *cp);
			}







Jun 19 11:27 1978  iget.c Page 4


			brelse(bp);
		}
		free(rp->i_dev, *ip);
		*ip = 0;
	}
	rp->i_mode =& ~ILARG;
	rp->i_size0 = 0;
	rp->i_size1 = 0;
	rp->i_flag =| IUPD;
}

/*
 * Make a new file.
 */
maknode(mode)
{
	register *ip;

	ip = ialloc(u.u_pdir->i_dev);
	if (ip==NULL) {
		iput(u.u_pdir);
		return(NULL);
	}
	ip->i_flag =| IACC|IUPD;
	ip->i_mode = mode|IALLOC;
	ip->i_nlink = 1;
	ip->i_uid = u.u_uid;
	ip->i_gid = u.u_gid;
	wdir(ip);
	return(ip);
}

/*
 * Write a directory entry with parameters left as side effects
 * to a call to namei.
 */
wdir(ip)
int *ip;
{
	register char *cp1, *cp2;

	u.u_dent.u_ino = ip->i_number;
	cp1 = &u.u_dent.u_name[0];
	for(cp2 = &u.u_dbuf[0]; cp2 < &u.u_dbuf[DIRSIZ];)
		*cp1++ = *cp2++;
	u.u_count = DIRSIZ+2;
	u.u_segflg = 1;
	u.u_base = &u.u_dent;
	writei(u.u_pdir);
	iput(u.u_pdir);
}












Jun 19 11:27 1978  main.c Page 1


#
#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/systm.h"
#include "../hd/proc.h"
#include "../hd/text.h"
#include "../hd/inode.h"
#include "../hd/seg.h"

#define	CLOCK1	0177546
#define	CLOCK2	0172540
/*
 * Icode is the octal bootstrap program executed in user mode
 * to bring up the system.
 */
int	icode[]
{
	0104413,	/* sys exec; init; initp */
	0000014,
	0000010,
	0000777,	/* br . */
	0000014,	/* initp: init; 0 */
	0000000,
	0062457,	/* init: </etc/init\0> */
	0061564,
	0064457,
	0064556,
	0000164,
};

/*
 * Initialization code.
 * Called from mch.s as soon as a stack and segmentation
 * have been established.
 * Functions:
 *	clear and free user core
 *	find which clock is configured
 *	hand craft 0th process
 *	call all initialization routines
 *	fork - process 0 to schedule
 *	     - process 1 execute bootstrap
 *
 * panic: no clock -- neither clock responds
 * loop at loc 6 in user mode -- /etc/init
 *	cannot be executed.
 */
main()
{
	register i;

	/*
	 * zero and free all of core
	 */

	printf("\nUnix system %s\n",&pwbname);
	printf("\nRestricted rights:\n");







Jun 19 11:27 1978  main.c Page 2


	printf("Use, duplication or disclosure is subject to restrictions\n");
	printf("stated in your contract with Western Electric Company, Inc.\n");
	i = *ka6 + USIZE;
	UISD->r[0] = 077406;
	for(;;) {
		UISA->r[0] = i;
		if(fuibyte(0) < 0)
			break;
		clearseg(i);
		maxmem++;
		mfree(coremap, 1, i);
		i++;
	}
	printf("\nAvailable user memory = %l * 32 words\n",maxmem);
	maxmem = min(maxmem, MAXMEM);
	mfree(swapmap, nswap, swplo);

	/*
	 * determine clock
	 */

	UISA->r[7] = ka6[1]; /* io segment */
	UISD->r[7] = 077406;
	lks = CLOCK1;
	if(fuiword(lks) == -1) {
		lks = CLOCK2;
		if(fuiword(lks) == -1)
			panic("no clock");
	}

	/*
	 * set up system process
	 */

	proc[0].p_addr = *ka6;
	proc[0].p_size = USIZE;
	proc[0].p_stat = SRUN;
	proc[0].p_flag =| SLOAD|SSYS;
	u.u_procp = &proc[0];

	/*
	 * set up 'known' i-nodes
	 */

	*lks = 0115;
	cinit();
	binit();
	iinit();
	rootdir = iget(rootdev, ROOTINO);
	rootdir->i_flag =& ~ILOCK;
	u.u_cdir = iget(rootdev, ROOTINO);
	u.u_cdir->i_flag =& ~ILOCK;

	/*
	 * make init process
	 * enter scheduling loop







Jun 19 11:27 1978  main.c Page 3


	 * with system process
	 */

	if(newproc()) {
		expand(USIZE+1);
		estabur(0, 1, 0, 0, RO);
		copyout(icode, 0, sizeof icode);
		/*
		 * Return goes to loc. 0 of user init
		 * code just copied out.
		 */
		return;
	}
	sched();
}

/*
 * Load the user hardware segmentation
 * registers from the software prototype.
 * The software registers must have
 * been setup prior by estabur.
 */
sureg()
{
	register *udp, *uap, *rdp;
	int *rap, daddr, taddr, *limudp;

	taddr = daddr = u.u_procp->p_addr;
	if (udp=u.u_procp->p_textp)
		taddr = udp->x_caddr;
	limudp = &u.u_uisd[16];
	if (cputype==40)
		limudp = &u.u_uisd[8];
	rap = UISA;
	rdp = UISD;
	uap = &u.u_uisa[0];
	for (udp = &u.u_uisd[0]; udp < limudp;) {
		*rap++ = *uap++ + (*udp&TX? taddr: daddr);
		*rdp++ = *udp++;
	}
}

/*
 * Set up software prototype segmentation
 * registers to implement the 3 pseudo
 * text,data,stack segment sizes passed
 * as arguments.
 * The argument sep specifies if the
 * text and data+stack segments are to
 * be separated.
 * The last argument determines whether the text
 * segment is read-write or read-only.
 */
estabur(nt, nd, ns, sep, xrw)
{
	register a, *ap, *dp;







Jun 19 11:27 1978  main.c Page 4



	if(checkur(nt, nd, ns, sep))
		return(-1);
	a = 0;
	ap = &u.u_uisa[0];
	dp = &u.u_uisd[0];
	while(nt >= 128) {
		*dp++ = (127<<8) | xrw|TX;
		*ap++ = a;
		a =+ 128;
		nt =- 128;
	}
	if(nt) {
		*dp++ = ((nt-1)<<8) | xrw|TX;
		*ap++ = a;
	}
	if(sep)
	while(ap < &u.u_uisa[8]) {
		*ap++ = 0;
		*dp++ = 0;
	}
	a = USIZE;
	while(nd >= 128) {
		*dp++ = (127<<8) | RW;
		*ap++ = a;
		a =+ 128;
		nd =- 128;
	}
	if(nd) {
		*dp++ = ((nd-1)<<8) | RW;
		*ap++ = a;
		a =+ nd;
	}
	while(ap < &u.u_uisa[8]) {
		*dp++ = 0;
		*ap++ = 0;
	}
	if(sep)
	while(ap < &u.u_uisa[16]) {
		*dp++ = 0;
		*ap++ = 0;
	}
	a =+ ns;
	while(ns >= 128) {
		a =- 128;
		ns =- 128;
		*--dp = (127<<8) | RW;
		*--ap = a;
	}
	if(ns) {
		*--dp = ((128-ns)<<8) | RW | ED;
		*--ap = a-128;
	}
	if(!sep) {
		ap = &u.u_uisa[0];
		dp = &u.u_uisa[8];







Jun 19 11:27 1978  main.c Page 5


		while(ap < &u.u_uisa[8])
			*dp++ = *ap++;
		ap = &u.u_uisd[0];
		dp = &u.u_uisd[8];
		while(ap < &u.u_uisd[8])
			*dp++ = *ap++;
	}
	sureg();
	return(0);

}
checkur(nt, nd, ns, sep)
{
	if(sep) {
		if(cputype == 40)
			goto err;
		if(ctos(nt) > 8 || ctos(nd)+ctos(ns) > 8)
			goto err;
	} else
		if(ctos(nt)+ctos(nd)+ctos(ns) > 8)
			goto err;
	if(nt+nd+ns+USIZE > maxmem)
		goto err;
	return(0);
err:
	u.u_error = ENOMEM;
	return(-1);
}



































Jun 19 11:27 1978  malloc.c Page 1


#include "../hd/param.h"
#include "../hd/systm.h"

/*
 * Allocate 'size' units from the given
 * map. Return the base of the allocated
 * space.
 * In a map, the addresses are increasing and the
 * list is terminated by a 0 size.
 * The core map unit is 64 bytes; the swap map unit
 * is 512 bytes.
 * Algorithm is first-fit.
 */
malloc(mp, size)
struct map *mp;
{
	register int a;
	register struct map *bp;

	for (bp=mp; bp->m_size; bp++) {
		if (bp->m_size >= size) {
			a = bp->m_addr;
			bp->m_addr =+ size;
			if ((bp->m_size =- size) == 0)
				do {
					bp++;
					(bp-1)->m_addr = bp->m_addr;
				} while ((bp-1)->m_size = bp->m_size);
			return(a);
		}
	}
	return(0);
}

/*
 * Free the previously allocated space aa
 * of size units into the specified map.
 * Sort aa into map and combine on
 * one or both ends if possible.
 */
mfree(mp, size, aa)
struct map *mp;
char *aa;
{
	register struct map *bp;
	register int t;
	register char *a;

	a = aa;
	if ((bp = mp)==coremap && runin) {
		runin = 0;
		wakeup(&runin);		/* Wake scheduler when freeing core */
	}
	for (; bp->m_addr<=a && bp->m_size!=0; bp++);
	if (bp>mp && (bp-1)->m_addr+(bp-1)->m_size == a) {
		(bp-1)->m_size =+ size;







Jun 19 11:27 1978  malloc.c Page 2


		if (a+size == bp->m_addr) {
			(bp-1)->m_size =+ bp->m_size;
			while (bp->m_size) {
				bp++;
				(bp-1)->m_addr = bp->m_addr;
				(bp-1)->m_size = bp->m_size;
			}
		}
	} else {
		if (a+size == bp->m_addr && bp->m_size) {
			bp->m_addr =- size;
			bp->m_size =+ size;
		} else if (size) do {
			t = bp->m_addr;
			bp->m_addr = a;
			a = t;
			t = bp->m_size;
			bp->m_size = size;
			bp++;
		} while (size = t);
	}
}









































Jun 19 11:27 1978  nami.c Page 1


#
#include "../hd/param.h"
#include "../hd/inode.h"
#include "../hd/user.h"
#include "../hd/systm.h"
#include "../hd/buf.h"

/*
 * Convert a pathname into a pointer to
 * an inode. Note that the inode is locked.
 *
 * func = function called to get next char of name
 *	&uchar if name is in user space
 *	&schar if name is in system space
 * flag = 0 if name is sought
 *	1 if name is to be created
 *	2 if name is to be deleted
 */
namei(func, flag)
int (*func)();
{
	register struct inode *dp;
	register c;
	register char *cp;
	int eo, *bp;

	/*
	 * If name starts with '/' start from
	 * root; otherwise start from current dir.
	 */

	dp = u.u_cdir;
	if((c=(*func)()) == '/')
		dp = rootdir;
	iget(dp->i_dev, dp->i_number);
	while(c == '/')
		c = (*func)();
	if(c == '\0' && flag != 0) {
		u.u_error = ENOENT;
		goto out;
	}

cloop:
	/*
	 * Here dp contains pointer
	 * to last component matched.
	 */

	if(u.u_error)
		goto out;
	if(c == '\0')
		return(dp);

	/*
	 * If there is another component,
	 * dp must be a directory and







Jun 19 11:27 1978  nami.c Page 2


	 * must have x permission.
	 */

	if((dp->i_mode&IFMT) != IFDIR || dp->i_nlink==0) {
		u.u_error = ENOTDIR;
		goto out;
	}
	if(access(dp, IEXEC))
		goto out;

	/*
	 * Gather up name into
	 * users' dir buffer.
	 */

	cp = &u.u_dbuf[0];
	while(c!='/' && c!='\0' && u.u_error==0) {
		if(cp < &u.u_dbuf[DIRSIZ])
			*cp++ = c;
		c = (*func)();
	}
	while(cp < &u.u_dbuf[DIRSIZ])
		*cp++ = '\0';
	while(c == '/')
		c = (*func)();
	if(u.u_error)
		goto out;

	/*
	 * Set up to search a directory.
	 */

	u.u_offset[1] = 0;
	u.u_offset[0] = 0;
	u.u_segflg = 1;
	eo = 0;
	u.u_count = ldiv(dp->i_size1, DIRSIZ+2);
	bp = NULL;

eloop:

	/*
	 * If at the end of the directory,
	 * the search failed. Report what
	 * is appropriate as per flag.
	 */

	if(u.u_count == 0) {
		if(bp != NULL)
			brelse(bp);
		if(flag==1 && c=='\0') {
			if(access(dp, IWRITE))
				goto out;
			u.u_pdir = dp;
			if(eo)
				u.u_offset[1] = eo-DIRSIZ-2; else







Jun 19 11:27 1978  nami.c Page 3


				bmap(dp,ldiv(u.u_offset[1],512));	/* check space */
			if (u.u_error)
				goto out;
			return(NULL);
		}
		u.u_error = ENOENT;
		goto out;
	}

	/*
	 * If offset is on a block boundary,
	 * read the next directory block.
	 * Release previous if it exists.
	 */

	if((u.u_offset[1]&0777) == 0) {
		if(bp != NULL)
			brelse(bp);
		bp = bread(dp->i_dev,
			bmap(dp, ldiv(u.u_offset[1], 512)));
	}

	/*
	 * Note first empty directory slot
	 * in eo for possible creat.
	 * String compare the directory entry
	 * and the current component.
	 * If they do not match, go back to eloop.
	 */

	bcopy(bp->b_addr+(u.u_offset[1]&0777), &u.u_dent, (DIRSIZ+2)/2);
	u.u_offset[1] =+ DIRSIZ+2;
	if (u.u_offset[1]==0)
		u.u_error = EFBIG;
	u.u_count--;
	if(u.u_dent.u_ino == 0) {
		if(eo == 0)
			eo = u.u_offset[1];
		goto eloop;
	}
	for(cp = &u.u_dbuf[0]; cp < &u.u_dbuf[DIRSIZ]; cp++)
		if(*cp != cp[u.u_dent.u_name - u.u_dbuf])
			goto eloop;

	/*
	 * Here a component matched in a directory.
	 * If there is more pathname, go back to
	 * cloop, otherwise return.
	 */

	if(bp != NULL)
		brelse(bp);
	if(flag==2 && c=='\0') {
		if(access(dp, IWRITE))
			goto out;
		return(dp);







Jun 19 11:27 1978  nami.c Page 4


	}
	bp = dp->i_dev;
	iput(dp);
	dp = iget(bp, u.u_dent.u_ino);
	if(dp == NULL)
		return(NULL);
	goto cloop;

out:
	iput(dp);
	return(NULL);
}

/*
 * Return the next character from the
 * kernel string pointed at by dirp.
 */
schar()
{

	return(*u.u_dirp++ & 0377);
}

/*
 * Return the next character from the
 * user string pointed at by dirp.
 */
uchar()
{
	register c;

	c = fubyte(u.u_dirp++);
	if(c == -1)
		u.u_error = EFAULT;
	return(c);
}



























Jun 19 11:27 1978  pipe.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/inode.h"
#include "../hd/file.h"
#include "../hd/reg.h"

/*
 * Max allowable buffering per pipe.
 * This is also the max size of the
 * file created to implement the pipe.
 * If this size is bigger than 4096,
 * pipes will be implemented in LARG
 * files, which is probably not good.
 */
#define	PIPSIZ	4096

/*
 * The sys-pipe entry.
 * Allocate an inode on the root device.
 * Allocate 2 file structures.
 * Put it all together with flags.
 */
pipe()
{
	register *ip, *rf, *wf;
	int r;

	ip = ialloc(rootdev);
	if(ip == NULL)
		return;
	rf = falloc();
	if(rf == NULL) {
		iput(ip);
		return;
	}
	r = u.u_ar0[R0];
	wf = falloc();
	if(wf == NULL) {
		rf->f_count = 0;
		u.u_ofile[r] = NULL;
		iput(ip);
		return;
	}
	u.u_ar0[R1] = u.u_ar0[R0];
	u.u_ar0[R0] = r;
	wf->f_flag = FWRITE|FPIPE;
	wf->f_inode = ip;
	rf->f_flag = FREAD|FPIPE;
	rf->f_inode = ip;
	ip->i_count = 2;
	ip->i_flag = IACC|IUPD;
	ip->i_mode = IALLOC;
}








Jun 19 11:27 1978  pipe.c Page 2


/*
 * Read call directed to a pipe.
 */
readp(fp)
int *fp;
{
	register *rp, *ip;

	rp = fp;
	ip = rp->f_inode;

loop:
	/*
	 * Very conservative locking.
	 */

	plock(ip);
	/*
	 * If nothing in the pipe, wait.
	 */
	if (ip->i_size1==0) {
		/*
		 * If there are not both reader and
		 * writer active, return without
		 * satisfying read.
		 */
		prele(ip);
		if(ip->i_count < 2)
			return;
		ip->i_mode =| IREAD;
		sleep(ip+2, PPIPE);
		goto loop;
	}

	/*
	 * Read and return
	 */

	u.u_offset[0] = 0;
	u.u_offset[1] = rp->f_offset[1];
	readi(ip);
	rp->f_offset[1] = u.u_offset[1];
	/*
	 * If reader has caught up with writer, reset
	 * offset and size to 0.
	 */
	if (rp->f_offset[1] == ip->i_size1) {
		rp->f_offset[1] = 0;
		ip->i_size1 = 0;
		if (ip->i_mode&IWRITE) {
			ip->i_mode =& ~IWRITE;
			wakeup(ip+1);
		}
	}
	prele(ip);
}







Jun 19 11:27 1978  pipe.c Page 3



/*
 * Write call directed to a pipe.
 */
writep(fp)
{
	register *rp, *ip, c;

	rp = fp;
	ip = rp->f_inode;
	c = u.u_count;

loop:

	/*
	 * If all done, return.
	 */

	plock(ip);
	if(c == 0) {
		prele(ip);
		u.u_count = 0;
		return;
	}

	/*
	 * If there are not both read and
	 * write sides of the pipe active,
	 * return error and signal too.
	 */

	if(ip->i_count < 2) {
		prele(ip);
		u.u_error = EPIPE;
		psignal(u.u_procp, SIGPIPE);
		return;
	}

	/*
	 * If the pipe is full,
	 * wait for reads to deplete
	 * and truncate it.
	 */

	if(ip->i_size1 == PIPSIZ) {
		ip->i_mode =| IWRITE;
		prele(ip);
		sleep(ip+1, PPIPE);
		goto loop;
	}

	/*
	 * Write what is possible and
	 * loop back.
	 */








Jun 19 11:27 1978  pipe.c Page 4


	u.u_offset[0] = 0;
	u.u_offset[1] = ip->i_size1;
	u.u_count = min(c, PIPSIZ-u.u_offset[1]);
	c =- u.u_count;
	writei(ip);
	prele(ip);
	if(ip->i_mode&IREAD) {
		ip->i_mode =& ~IREAD;
		wakeup(ip+2);
	}
	goto loop;
}

/*
 * Lock a pipe.
 * If its already locked,
 * set the WANT bit and sleep.
 */
plock(ip)
int *ip;
{
	register *rp;

	rp = ip;
	while(rp->i_flag&ILOCK) {
		rp->i_flag =| IWANT;
		sleep(rp, PPIPE);
	}
	rp->i_flag =| ILOCK;
}

/*
 * Unlock a pipe.
 * If WANT bit is on,
 * wakeup.
 * This routine is also used
 * to unlock inodes in general.
 */
prele(ip)
int *ip;
{
	register *rp;

	rp = ip;
	rp->i_flag =& ~ILOCK;
	if(rp->i_flag&IWANT) {
		rp->i_flag =& ~IWANT;
		wakeup(rp);
	}
}













Jun 19 11:27 1978  prf.c Page 1


#
#include "../hd/param.h"
#include "../hd/seg.h"
#include "../hd/buf.h"
#include "../hd/systm.h"

/*
 * Address and structure of the
 * KL-11 console device registers.
 */
struct
{
	int	rsr;
	int	rbr;
	int	xsr;
	int	xbr;
};

/*
 * In case console is off,
 * panicstr contains argument to last
 * call to panic.
 */

char	*panicstr;

/*
 * Scaled down version of C Library printf.
 * Only %s %l %d (==%l) %o are recognized.
 * Used to print diagnostic information
 * directly on console tty.
 * Since it is not interrupt driven,
 * all system activities are pretty much
 * suspended.
 * Printf should not be used for chit-chat.
 */
printf(fmt,x1)
char fmt[];
{
	register char *s;
	register *adx, c;

	adx = &x1;
loop:
	while((c = *fmt++) != '%') {
		if(c == '\0')
			return;
		putchar(c);
	}
	c = *fmt++;
	if(c == 'd' || c == 'l' || c == 'o')
		printn(*adx, c=='o'? 8: 10);
	if(c == 's') {
		s = *adx;
		while(c = *s++)
			putchar(c);







Jun 19 11:27 1978  prf.c Page 2


	}
	adx++;
	goto loop;
}

/*
 * Print an unsigned integer in base b.
 */
printn(n, b)
{
	register a;

	if(a = ldiv(n, b))
		printn(a, b);
	putchar(lrem(n, b) + '0');
}

/*
 * Print a character on console.
 * Attempts to save and restore device
 * status.
 * If the switches are 0, all
 * printing is inhibited.
 */
putchar(c)
{
	register rc, s;

	rc = c;
	if(SW->integ == 0)
		return;
	while((KL->xsr&0200) == 0)
		;
	if(rc == 0)
		return;
	s = KL->xsr;
	KL->xsr = 0;
	KL->xbr = rc;
	if(rc == '\n') {
		putchar('\r');
		putchar(0177);
		putchar(0177);
	}
	putchar(0);
	KL->xsr = s;
}

/*
 * Panic is called on unresolvable
 * fatal errors.
 * It syncs, prints "panic: mesg" and
 * then loops.
 */
panic(s)
char *s;
{







Jun 19 11:27 1978  prf.c Page 3


	panicstr = s;
	update();
	printf("panic: %s\n", s);
	for(;;)
		idle();
}

/*
 * prdev prints a warning message of the
 * form "mesg on dev x/y".
 * x and y are the major and minor parts of
 * the device argument.
 */
prdev(str, dev)
{

	printf("%s on dev %l/%l\n", str, major(dev), minor(dev));
}

/*
 * deverr prints a diagnostic from
 * a device driver.
 * It prints the device, block number,
 * and an octal word (usually some error
 * status register) passed as argument.
 */
deverror(bp, o1, o2)
int *bp;
{
	register *rbp;

	if(SW->integ&01)
		return;
	rbp = bp;
	prdev("err", rbp->b_dev);
	printf("bn%l er%o %o\n", rbp->b_blkno, o1, o2);
}


























Jun 19 11:27 1978  pwbsys.c Page 1


#
#include "../hd/param.h"
#include "../hd/buf.h"
#include "../hd/filsys.h"
#include "../hd/inode.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/reg.h"
#include "../hd/var.h"

pwbsys()
{
	extern uchar;
	register i;
	register *p;
	register struct buf *bp;

	switch(u.u_arg[0]) {

case 0:		/* uname */
	if (copyout(&pwbname, u.u_ar0[R0], 8))
		u.u_error = EFAULT;
	return;

case 1:		/* udata */
	if (u.u_ar0[R1]) {
		if(suser())
			i = copyin(u.u_ar0[R0],u.u_udata,32); else
			return;
	} else
		i = copyout(u.u_udata,u.u_ar0[R0],32);
	if (i)
		u.u_error = EFAULT;
	return;

case 2:		/* ustat */
	for(i=0; i<v.v_mount; i++) {
		p = &mount[i];
		if(p->m_bufp!=NULL && p->m_dev==u.u_ar0[R1]) {
			p = p->m_bufp->b_addr;
			if(copyout(&p->s_tfree, u.u_ar0[R0], 16))
				u.u_error = EFAULT;
			return;
		}
	}
	u.u_error = EINVAL;
	return;

case 3:		/* utime */
	if (!suser())
		return;
	u.u_dirp = u.u_ar0[R1];
	if ((p = namei(&uchar, 0))==NULL)
		return;
	if (getfs(p->i_dev)->s_ronly) {
		u.u_error = EROFS;







Jun 19 11:27 1978  pwbsys.c Page 2


		return;
	}
	i = p->i_number+31;
	bp = bread(p->i_dev, ldiv(i,16));
	copyin (u.u_ar0[R0], bp->b_addr+32*lrem(i,16)+24, 8);
	p->i_flag =& ~(IACC|IUPD);
	bdwrite(bp);
	iput(p);
	return;

default:
	u.u_error = EFAULT;
	}
}

















































Jun 19 11:27 1978  rdwri.c Page 1


#
#include "../hd/param.h"
#include "../hd/inode.h"
#include "../hd/user.h"
#include "../hd/buf.h"
#include "../hd/conf.h"
#include "../hd/systm.h"

/*
 * Read the file corresponding to
 * the inode pointed at by the argument.
 * The actual read arguments are found
 * in the variables:
 *	u_base		core address for destination
 *	u_offset	byte offset in file
 *	u_count		number of bytes to read
 *	u_segflg	read to kernel/user/user I
 */
readi(aip)
struct inode *aip;
{
	int *bp;
	int lbn, bn, on;
	register dn, n;
	register struct inode *ip;

	ip = aip;
	if(u.u_count == 0)
		return;
	ip->i_flag =| IACC;
	if((ip->i_mode&IFMT) == IFCHR) {
		(*cdevsw[major(ip->i_addr[0])].d_read)(minor(ip->i_addr[0]));
		return;
	}

	do {
		lbn = bn = lshift(u.u_offset, -9);
		on = u.u_offset[1] & 0777;
		n = min(512-on, u.u_count);
		if((ip->i_mode&IFMT) != IFBLK) {
			dn = dpcmp(ip->i_size0&0377, ip->i_size1,
				u.u_offset[0], u.u_offset[1]);
			if(dn <= 0)
				return;
			n = min(n, dn);
			if ((bn = bmap(ip, lbn)) == 0)
				return;
			dn = ip->i_dev;
		} else {
			dn = ip->i_addr[0];
			rablock = bn+1;
		}
		if ((ip->i_lastr+1) == lbn && (on+n) == 512)
			bp = breada(dn, bn, rablock);
		else
			bp = bread(dn, bn);







Jun 19 11:27 1978  rdwri.c Page 2


		if ((on+n) == 512)
			ip->i_lastr = lbn;
		if (bp->b_resid!=0)
			n = 0;
		iomove(bp, on, n, B_READ);
		brelse(bp);
	} while(u.u_error==0 && u.u_count && n);
}

/*
 * Write the file corresponding to
 * the inode pointed at by the argument.
 * The actual write arguments are found
 * in the variables:
 *	u_base		core address for source
 *	u_offset	byte offset in file
 *	u_count		number of bytes to write
 *	u_segflg	write to kernel/user/user I
 */
writei(aip)
struct inode *aip;
{
	int *bp;
	int n, on;
	register dn, bn;
	register struct inode *ip;

	ip = aip;
	ip->i_flag =| IACC|IUPD;
	if((ip->i_mode&IFMT) == IFCHR) {
		(*cdevsw[major(ip->i_addr[0])].d_write)(minor(ip->i_addr[0]));
		return;
	}
	if (u.u_count == 0)
		return;

	do {
		bn = lshift(u.u_offset, -9);
		on = u.u_offset[1] & 0777;
		n = min(512-on, u.u_count);
		if((ip->i_mode&IFMT) != IFBLK) {
			if ((bn = bmap(ip, bn)) == 0)
				return;
			dn = ip->i_dev;
		} else
			dn = ip->i_addr[0];
		if(n == 512) 
			bp = getblk(dn, bn); else
			bp = bread(dn, bn);
		iomove(bp, on, n, B_WRITE);
		if(u.u_error != 0)
			brelse(bp); else
		if ((u.u_offset[1]&0777)==0)
			bawrite(bp); else
			bdwrite(bp);
		if(dpcmp(ip->i_size0&0377, ip->i_size1,







Jun 19 11:27 1978  rdwri.c Page 3


		  u.u_offset[0], u.u_offset[1]) < 0 &&
		  (ip->i_mode&(IFBLK&IFCHR)) == 0) {
			ip->i_size0 = u.u_offset[0];
			ip->i_size1 = u.u_offset[1];
		}
		ip->i_flag =| IUPD;
	} while(u.u_error==0 && u.u_count!=0);
}

/*
 * Return the logical maximum
 * of the 2 arguments.
 */
max(a, b)
char *a, *b;
{

	if(a > b)
		return(a);
	return(b);
}

/*
 * Return the logical minimum
 * of the 2 arguments.
 */
min(a, b)
char *a, *b;
{

	if(a < b)
		return(a);
	return(b);
}

/*
 * Move 'an' bytes at byte location
 * &bp->b_addr[o] to/from (flag) the
 * user/kernel (u.segflg) area starting at u.base.
 * Update all the arguments by the number
 * of bytes moved.
 *
 * There are 2 algorithms,
 * if source address, dest address and count
 * are all even in a user copy,
 * then the machine language copyin/copyout
 * is called.
 * If not, its done byte-by-byte with
 * cpass and passc.
 */
iomove(bp, o, an, flag)
struct buf *bp;
{
	register char *cp;
	register int n, t;








Jun 19 11:27 1978  rdwri.c Page 4


	if ((n = an)==0 || u.u_error)
		return;
	cp = bp->b_addr + o;
	if(u.u_segflg!=1 && ((n | cp | u.u_base)&01)==0) {
		if (flag==B_WRITE)
			if (u.u_segflg==0)
				cp = copyin(u.u_base, cp, n);
			else
				cp = copyiin(u.u_base, cp, n);
		else
			if (u.u_segflg==0)
				cp = copyout(cp, u.u_base, n);
			else
				cp = copyiout(cp, u.u_base, n);
		if (cp) {
			u.u_error = EFAULT;
			return;
		}
		u.u_base =+ n;
		dpadd(u.u_offset, n);
		u.u_count =- n;
		return;
	}
	if (flag==B_WRITE) {
		while(n--) {
			if ((t = cpass()) < 0)
				return;
			*cp++ = t;
		}
	} else
		while (n--)
			if(passc(*cp++) < 0)
				return;
}





























Jun 19 11:27 1978  sig.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/inode.h"
#include "../hd/reg.h"
#include "../hd/text.h"
#include "../hd/seg.h"
#include "../hd/var.h"

/*
 * Priority for tracing
 */
#define	IPCPRI	0

/*
 * Structure to access an array of integers.
 */
struct
{
	int	inta[];
};

/*
 * Tracing variables.
 * Used to pass trace command from
 * parent to child being traced.
 * This data base cannot be
 * shared and is locked
 * per user.
 */
struct
{
	int	ip_lock;
	int	ip_req;
	int	ip_addr;
	int	ip_data;
} ipc;

/*
 * Send the specified signal to
 * all processes with 'pgrp' as
 * process group.
 * Called by tty.c for quits and
 * interrupts.
 */
signal(apgrp, sig)
{
	register struct proc *p;
	register pgrp;

	if ((pgrp = apgrp)==0)
		return;
	for(p = &proc[0]; p < v.ve_proc; p++)
		if(p->p_pgrp == pgrp)







Jun 19 11:27 1978  sig.c Page 2


			psignal(p, sig);
}

/*
 * Send the specified signal to
 * the specified process.
 */
psignal(p, sig)
int *p;
char *sig;
{
	register *rp, a;

	a = sig;
	if(a > NSIG)
		return;
	rp = p;
	if(a)
		rp->p_sig =| 1<<(a-1);
	if(rp->p_pri > PUSER)
		rp->p_pri = PUSER;
	if(rp->p_stat == SSLEEP && rp->p_pri > 0)
		setrun(rp);
}

/*
 * Returns true if the current
 * process has a signal to process.
 * This is asked at least once
 * each time a process enters the
 * system.
 * A signal does not do anything
 * directly to a process; it sets
 * a flag that asks the process to
 * do something to itself.
 */
issig()
{
	register n;
	register struct proc *p;

	p = u.u_procp;
	while(p->p_sig) {
		n = fsig(p);
		if((u.u_signal[n-1]&1) == 0 || (p->p_flag&STRC))
			return(n);
		p->p_sig =& ~(1<<(n-1));
	}
	return(0);
}

/*
 * Enter the tracing STOP state.
 * In this state, the parent is
 * informed and the process is able to
 * receive commands from the parent.







Jun 19 11:27 1978  sig.c Page 3


 */
stop()
{
	register struct proc *pp, *cp;

loop:
	cp = u.u_procp;
	if(cp->p_ppid != 1)
	for (pp = &proc[0]; pp < v.ve_proc; pp++)
		if (pp->p_pid == cp->p_ppid) {
			wakeup(pp);
			cp->p_stat = SSTOP;
			swtch();
			if ((cp->p_flag&STRC)==0 || procxmt())
				return;
			goto loop;
		}
	exit();
}

/*
 * Perform the action specified by
 * the current signal.
 * The usual sequence is:
 *	if(issig())
 *		psig();
 */
psig()
{
	register n, p;
	register *rp;

	rp = u.u_procp;
	if (rp->p_flag&STRC)
		stop();
	n = fsig(rp);
	if (n==0)
		return;
	rp->p_sig =& ~(1<<(n-1));
	if((p=u.u_signal[n-1]) != 0) {
		u.u_error = 0;
		if(n != SIGINS && n != SIGTRC)
			u.u_signal[n-1] = 0;
		n = u.u_ar0[R6] - 4;
		grow(n);
		suword(n+2, u.u_ar0[RPS]);
		suword(n, u.u_ar0[R7]);
		u.u_ar0[R6] = n;
		u.u_ar0[RPS] =& ~TBIT;
		u.u_ar0[R7] = p;
		return;
	}
	switch(n) {

	case SIGQIT:
	case SIGINS:







Jun 19 11:27 1978  sig.c Page 4


	case SIGTRC:
	case SIGIOT:
	case SIGEMT:
	case SIGFPT:
	case SIGBUS:
	case SIGSEG:
	case SIGSYS:
		u.u_arg[0] = n;
		if(core())
			n =+ 0200;
	}
	u.u_arg[0] = (u.u_ar0[R0]<<8) | n;
	exit();
}

/*
 * find the signal in bit-position
 * representation in p_sig.
 */
fsig(p)
struct proc *p;
{
	register n, i;
	register char *cp;

	n = p->p_sig;
	for(i=1; i<=NSIG; i++) {
		if(n & 1)
			return(i);
		n =>> 1;
	}
	return(0);
}

/*
 * Create a core image on the file "core"
 * If you are looking for protection glitches,
 * there are probably a wealth of them here
 * when this occurs to a suid command.
 *
 * It writes USIZE block of the
 * user.h area followed by the entire
 * data+stack segments.
 */
core()
{
	register s, *ip;
	extern schar;

	u.u_error = 0;
	u.u_dirp = "core";
	ip = namei(&schar, 1);
	if(ip == NULL) {
		if(u.u_error)
			return(0);
		ip = maknode(0666);







Jun 19 11:27 1978  sig.c Page 5


		if (ip==NULL)
			return(0);
	}
	if(!access(ip, IWRITE) &&
	   (ip->i_mode&IFMT) == 0 &&
	   u.u_uid == u.u_ruid) {
		itrunc(ip);
		u.u_offset[0] = 0;
		u.u_offset[1] = 0;
		u.u_base = &u;
		u.u_count = USIZE*64;
		u.u_segflg = 1;
		writei(ip);
		s = u.u_procp->p_size - USIZE;
		estabur(0, s, 0, 0, RO);
		u.u_base = 0;
		u.u_count = s*64;
		u.u_segflg = 0;
		writei(ip);
	}
	iput(ip);
	return(u.u_error==0);
}

/*
 * grow the stack to include the SP
 * true return if successful.
 */

grow(sp)
char *sp;
{
	register a, si, i;

	if(sp >= -u.u_ssize*64)
		return(0);
	si = ldiv(-sp, 64) - u.u_ssize + SINCR;
	if(si <= 0)
		return(0);
	if(estabur(u.u_tsize, u.u_dsize, u.u_ssize+si, u.u_sep, RO))
		return(0);
	expand(u.u_procp->p_size+si);
	a = u.u_procp->p_addr + u.u_procp->p_size;
	for(i=u.u_ssize; i; i--) {
		a--;
		copyseg(a-si, a);
	}
	for(i=si; i; i--)
		clearseg(--a);
	u.u_ssize =+ si;
	return(1);
}

/*
 * sys-trace system call.
 */







Jun 19 11:27 1978  sig.c Page 6


ptrace()
{
	register struct proc *p;
	register struct text *xp;

	if (u.u_arg[2] <= 0) {
		u.u_procp->p_flag =| STRC;
		return;
	}
	for (p=proc; p < v.ve_proc; p++) 
		if (p->p_stat==SSTOP
		 && p->p_pid==u.u_arg[0]
		 && p->p_ppid==u.u_procp->p_pid)
			goto found;
	u.u_error = ESRCH;
	return;

    found:
	while (ipc.ip_lock)
		sleep(&ipc, IPCPRI);
	ipc.ip_lock = p->p_pid;
	ipc.ip_data = u.u_ar0[R0];
	ipc.ip_addr = u.u_arg[1] & ~01;
	ipc.ip_req = u.u_arg[2];
	p->p_flag =& ~SWTED;
	setrun(p);
	while (ipc.ip_req > 0)
		sleep(&ipc, IPCPRI);
	u.u_ar0[R0] = ipc.ip_data;
	if (ipc.ip_req < 0)
		u.u_error = EIO;
	ipc.ip_lock = 0;
	wakeup(&ipc);
}

/*
 * Code that the child process
 * executes to implement the command
 * of the parent process in tracing.
 */
procxmt()
{
	register int i;
	register int *p;
	register struct text *xp;

	if (ipc.ip_lock != u.u_procp->p_pid)
		return(0);
	i = ipc.ip_req;
	ipc.ip_req = 0;
	wakeup(&ipc);
	switch (i) {

	/* read user I */
	case 1:
		if (fuibyte(ipc.ip_addr) == -1)







Jun 19 11:27 1978  sig.c Page 7


			goto error;
		ipc.ip_data = fuiword(ipc.ip_addr);
		break;

	/* read user D */
	case 2:
		if (fubyte(ipc.ip_addr) == -1)
			goto error;
		ipc.ip_data = fuword(ipc.ip_addr);
		break;

	/* read u */
	case 3:
		i = ipc.ip_addr;
		if (i<0 || i >= (USIZE<<6))
			goto error;
		ipc.ip_data = u.inta[i>>1];
		break;

	/* write user I */
	/* Must set up to allow writing */
	case 4:
		/*
		 * If text, must assure exclusive use
		 */
		if (xp = u.u_procp->p_textp) {
			if (xp->x_count!=1 || xp->x_iptr->i_mode&ISVTX)
				goto error;
			xp->x_iptr->i_flag =& ~ITEXT;
		}
		estabur(u.u_tsize, u.u_dsize, u.u_ssize, u.u_sep, RW);
		i = suiword(ipc.ip_addr, 0);
		suiword(ipc.ip_addr, ipc.ip_data);
		estabur(u.u_tsize, u.u_dsize, u.u_ssize, u.u_sep, RO);
		if (i<0)
			goto error;
		if (xp)
			xp->x_flag =| XWRIT;
		break;

	/* write user D */
	case 5:
		if (suword(ipc.ip_addr, 0) < 0)
			goto error;
		suword(ipc.ip_addr, ipc.ip_data);
		break;

	/* write u */
	case 6:
		p = &u.inta[ipc.ip_addr>>1];
		if (p >= u.u_fsav && p < &u.u_fsav[25])
			goto ok;
		for (i=0; i<9; i++)
			if (p == &u.u_ar0[regloc[i]])
				goto ok;
		goto error;







Jun 19 11:27 1978  sig.c Page 8


	ok:
		if (p == &u.u_ar0[RPS]) {
			ipc.ip_data =| 0170000;	/* assure user space */
			ipc.ip_data =& ~0340;	/* priority 0 */
		}
		*p = ipc.ip_data;
		break;

	/* set signal and continue */
	case 7:
		u.u_procp->p_sig = 0;
		psignal(u.u_procp, ipc.ip_data);
		return(1);

	/* force exit */
	case 8:
		exit();

	default:
	error:
		ipc.ip_req = -1;
	}
	return(0);
}







































Jun 19 11:27 1978  slp.c Page 1


#
#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/text.h"
#include "../hd/systm.h"
#include "../hd/file.h"
#include "../hd/inode.h"
#include "../hd/buf.h"
#include "../hd/var.h"

/*
 * Give up the processor till a wakeup occurs
 * on chan, at which time the process
 * enters the scheduling queue at priority pri.
 * The most important effect of pri is that when
 * pri<=0 a signal cannot disturb the sleep;
 * if pri>0 signals will be processed.
 * Callers of this routine must be prepared for
 * premature return, and check that the reason for
 * sleeping has gone away.
 */
sleep(chan, pri)
{
	register *rp, s;

	s = PS->integ;
	rp = u.u_procp;
	spl6();
	rp->p_stat = SSLEEP;
	rp->p_wchan = chan;
	rp->p_pri = pri;
	if(pri > 0) {
		if(issig()) {
			rp->p_wchan = 0;
			rp->p_stat = SRUN;
			spl0();
			goto psig;
		}
		spl0();
		swtch();
		if(issig())
			goto psig;
	} else {
		spl0();
		swtch();
	}
	PS->integ = s;
	return;

	/*
	 * If priority was low (>0) and
	 * there has been a signal,
	 * execute non-local goto to
	 * the qsav location.
	 * (see trap1/trap.c)







Jun 19 11:27 1978  slp.c Page 2


	 */
psig:
	aretu(u.u_qsav);
}

/*
 * Wake up all processes sleeping on chan.
 */
wakeup(chan)
{
	register struct proc *p;
	register c, i;

	c = chan;
	p = &proc[0];
	i = v.ve_proc;
	do {
		if(p->p_wchan == c && p->p_stat==SSLEEP)
			setrun(p);
		p++;
	} while(p != i);
}

setrq(p)
struct proc *p;
{
	register struct proc *q;
	register s;

	s = PS->integ;
	spl6();
	for(q=runq; q!=NULL; q=q->p_link)
		if(q == p) {
			printf("proc on q\n");
			goto out;
		}
	p->p_link = runq;
	runq = p;
out:
	PS->integ = s;
}

/*
 * Set the process running;
 * arrange for it to be swapped in if necessary.
 */
setrun(p)
{
	register struct proc *rp;

	rp = p;
	rp->p_wchan = 0;
	rp->p_stat = SRUN;
	setrq(p);
	if((rp->p_flag&SLOAD)==0) {
		rp->p_time = 0;







Jun 19 11:27 1978  slp.c Page 3


		if(runout != 0) {
			runout = 0;
			setrun(&proc[0]);
		}
	} else
		if(rp->p_pri < curpri)
			runrun++;
}

/*
 * Set user priority.
 * The rescheduling flag (runrun)
 * is set if the priority is better
 * than the currently running process.
 */
setpri(up)
{
	register *pp, p;

	pp = up;
	p = pp->p_cpu/4;
	p =+ PUSER + pp->p_nice;
	if(p > 127)
		p = 127;
	pp->p_pri = p;
	return(p);
}

/*
 * The main loop of the scheduling (swapping)
 * process.
 * The basic idea is:
 *  see if anyone wants to be swapped in;
 *  swap out processes until there is room;
 *  swap him in;
 *  repeat.
 * The runout flag is set whenever someone is swapped out.
 * Sched sleeps on it awaiting work.
 *
 * Sched sleeps on runin whenever it cannot find enough
 * core (by swapping out or otherwise) to fit the
 * selected swapped process.  It is awakend when the
 * core situation changes and in any event once per second.
 */
sched()
{
	register struct proc *rp, *p;
	register outage, inage;
	int swapri, a;

	/*
	 * find user to swap in;
	 * of users ready, select one out longest
	 */

loop:







Jun 19 11:27 1978  slp.c Page 4


	spl6();
	outage = -1;
	for(rp = &proc[0]; rp < v.ve_proc; rp++)
	if (rp->p_stat==SRUN && (rp->p_flag&SLOAD)==0 &&
	    rp->p_time > outage) {
		p = rp;
		outage = rp->p_time;
	}
	/*
	 * If there is no one there, wait.
	 */
	if (outage<0) {
		runout++;
		sleep(&runout, PSWP);
		goto loop;
	}
	spl0();

	/*
	 * See if there is core for that process;
	 * if so, swap it in.
	 */

	if (swapin(p))
		goto loop;

	/*
	 * none found.
	 */

	spl6();
	swapri = 0;
	inage = 0;
	for(rp = &proc[0]; rp < v.ve_proc; rp++) {
		if ((rp->p_flag&(SSYS|SLOCK|SLOAD))!=SLOAD)
			continue;
		if (rp->p_textp && rp->p_textp->x_flag&XLOCK)
			continue;
		if(rp->p_stat==SSLEEP || rp->p_stat==SSTOP) {
			a = (rp->p_pri>>1) + rp->p_time;
			if(a>swapri) {
				p = rp;
				swapri = a;
			}
		} else
		if(swapri<=0 && rp->p_stat==SRUN && rp->p_time>inage) {
			p = rp;
			inage = rp->p_time;
		}
	}
	spl0();
	/*
	 * Swap found user out if sleeping,
	 * or if he has spent at least 4 seconds in core and
	 * the swapped-out process has spent at 2 seconds out.
	 * Otherwise wait a bit and try again.







Jun 19 11:27 1978  slp.c Page 5


	 */
	if (swapri>0 || (outage>=2 && inage>=4)) {
		p->p_flag =& ~SLOAD;
		xswap(p, 1, 0);
		goto loop;
	}
	spl6();
	runin++;
	sleep(&runin, PSWP);
	goto loop;

}

/*
 * Swap a process in.
 * Allocate data and possible text separately.
 * It would be better to do largest first.
 */
swapin(pp)
struct proc *pp;
{
	register struct proc *p;
	register struct text *xp;
	register int a;
	int x;

	p = pp;
	if ((a = malloc(coremap, p->p_size)) == NULL)
		return(0);
	if (xp = p->p_textp) {
		xlock(xp);
		if (xp->x_ccount==0) {
			if ((x = malloc(coremap, xp->x_size)) == NULL) {
				xunlock(xp);
				mfree(coremap, p->p_size, a);
				return(0);
			}
			xp->x_caddr = x;
			if ((xp->x_flag&XLOAD)==0)
				swap(xp->x_daddr,x,xp->x_size,B_READ);
		}
		xp->x_ccount++;
		xunlock(xp);
	}
	swap(p->p_addr, a, p->p_size, B_READ);
	mfree(swapmap, ctob(p->p_size), p->p_addr);
	p->p_addr = a;
	p->p_flag =| SLOAD;
	p->p_time = 0;
	return(1);
}

qswtch()
{

	setrq(u.u_procp);







Jun 19 11:27 1978  slp.c Page 6


	swtch();
}

/*
 * This routine is called to reschedule the CPU.
 * if the calling process is not in RUN state,
 * arrangements for it to restart must have
 * been made elsewhere, usually by calling via sleep.
 */
swtch()
{
	register n;
	register struct proc *p, *q;
	static struct proc *pp, *pq;

	/*
	 * Remember stack of caller
	 * and switch to schedulers stack.
	 */
	savu(u.u_rsav);
	retu(proc[0].p_addr);

loop:
	spl6();
	runrun = 0;
	pp = NULL;
	q = NULL;
	n = 128;
	/*
	 * Search for highest-priority runnable process
	 */
	for(p=runq; p!=NULL; p=p->p_link) {
		if((p->p_stat==SRUN) && (p->p_flag&SLOAD)) {
			if(p->p_pri <= n) {
				pp = p;
				pq = q;
				n = p->p_pri;
			}
		}
		q = p;
	}
	/*
	 * If no process is runnable, idle.
	 */
	p = pp;
	if(p == NULL) {
		idle();
		spl0();
		goto loop;
	}
	q = pq;
	if(q == NULL)
		runq = p->p_link; else
		q->p_link = p->p_link;
	curpri = n;
	spl0();







Jun 19 11:27 1978  slp.c Page 7


	/*
	 * Switch to stack of the new process and set up
	 * his segmentation registers.
	 */
	retu(p->p_addr);
	sureg();
	/*
	 * If the new process paused because it was
	 * swapped out, set the stack level to the last call
	 * to savu(u_ssav).  This means that the return
	 * which is executed immediately after the call to aretu
	 * actually returns from the last routine which did
	 * the savu.
	 */
	if(p->p_flag&SSWAP) {
		p->p_flag =& ~SSWAP;
		aretu(u.u_ssav);
	}
	/*
	 * The value returned here has many subtle implications.
	 * See the newproc comments.
	 */
	return(1);
}

/*
 * Create a new process-- the internal version of
 * sys fork.
 * It returns 1 in the new process.
 * How this happens is rather hard to understand.
 * The essential fact is that the new process is created
 * in such a way that appears to have started executing
 * in the same call to newproc as the parent;
 * but in fact the code that runs is that of swtch.
 * The subtle implication of the returned value of swtch
 * (see above) is that this is the value that newproc's
 * caller in the new process sees.
 */
newproc()
{
	int a1, a2;
	struct proc *p, *up;
	register struct proc *rpp;
	register *rip, n;
	struct proc *pend;

	p = NULL;
	/*
	 * First, just locate a slot for a process
	 * and copy the useful info from this process into it.
	 * The panic "cannot happen" because fork has already
	 * checked for the existence of a slot.
	 */
retry:
	mpid++;
	if(mpid < 0) {







Jun 19 11:27 1978  slp.c Page 8


		mpid = 0;
		goto retry;
	}
	for(rpp = &proc[0]; rpp < &proc[v.v_proc]; rpp++) {
		if(rpp->p_stat == NULL) {
			if(p == NULL)
				p = rpp;
		} else
			pend = rpp;
		if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
			goto retry;
	}
	if ((rpp = p)==NULL)
		panic("no procs");
	if (rpp > pend)
		pend = rpp;
	pend++;
	v.ve_proc = pend;

	/*
	 * make proc entry for new proc
	 */

	rip = u.u_procp;
	up = rip;
	rpp->p_stat = SRUN;
	rpp->p_clktim = 0;
	rpp->p_flag = SLOAD;
	rpp->p_uid = rip->p_uid;
	rpp->p_pgrp = rip->p_pgrp;
	rpp->p_nice = rip->p_nice;
	rpp->p_textp = rip->p_textp;
	rpp->p_pid = mpid;
	rpp->p_ppid = rip->p_pid;
	rpp->p_time = 0;
	rpp->p_cpu = 0;

	/*
	 * make duplicate entries
	 * where needed
	 */

	for(rip = &u.u_ofile[0]; rip < &u.u_ofile[NOFILE];)
		if((rpp = *rip++) != NULL)
			rpp->f_count++;
	if((rpp=up->p_textp) != NULL) {
		rpp->x_count++;
		rpp->x_ccount++;
	}
	u.u_cdir->i_count++;
	/*
	 * Partially simulate the environment
	 * of the new process so that when it is actually
	 * created (by copying) it will look right.
	 */
	savu(u.u_rsav);







Jun 19 11:27 1978  slp.c Page 9


	rpp = p;
	u.u_procp = rpp;
	rip = up;
	n = rip->p_size;
	a1 = rip->p_addr;
	rpp->p_size = n;
	a2 = malloc(coremap, n);
	/*
	 * If there is not enough core for the
	 * new process, swap out the current process to generate the
	 * copy.
	 */
	if(a2 == NULL) {
		rip->p_stat = SIDL;
		rpp->p_addr = a1;
		savu(u.u_ssav);
		xswap(rpp, 0, 0);
		rpp->p_flag =| SSWAP;
		rip->p_stat = SRUN;
	} else {
	/*
	 * There is core, so just copy.
	 */
		rpp->p_addr = a2;
		while(n--)
			copyseg(a1++, a2++);
	}
	u.u_procp = rip;
	setrq(rpp);
	return(0);
}

/*
 * Change the size of the data+stack regions of the process.
 * If the size is shrinking, it's easy-- just release the extra core.
 * If it's growing, and there is core, just allocate it
 * and copy the image, taking care to reset registers to account
 * for the fact that the system's stack has moved.
 * If there is no core, arrange for the process to be swapped
 * out after adjusting the size requirement-- when it comes
 * in, enough core will be allocated.
 * Because of the ssave and SSWAP flags, control will
 * resume after the swap in swtch, which executes the return
 * from this stack level.
 *
 * After the expansion, the caller will take care of copying
 * the user's stack towards or away from the data area.
 */
expand(newsize)
{
	int i, n;
	register *p, a1, a2;

	p = u.u_procp;
	n = p->p_size;
	p->p_size = newsize;







Jun 19 11:27 1978  slp.c Page 10


	a1 = p->p_addr;
	if(n >= newsize) {
		mfree(coremap, n-newsize, a1+newsize);
		return;
	}
	savu(u.u_rsav);
	a2 = malloc(coremap, newsize);
	if(a2 == NULL) {
		savu(u.u_ssav);
		xswap(p, 1, n);
		p->p_flag =| SSWAP;
		qswtch();
		/* no return */
	}
	p->p_addr = a2;
	for(i=0; i<n; i++)
		copyseg(a1+i, a2++);
	mfree(coremap, n, a1);
	retu(p->p_addr);
	sureg();
}










































Jun 19 11:27 1978  subr.c Page 1


#
#include "../hd/param.h"
#include "../hd/inode.h"
#include "../hd/user.h"
#include "../hd/buf.h"
#include "../hd/systm.h"

/*
 * Bmap defines the structure of file system storage
 * by returning the physical block number on a device given the
 * inode and the logical block number in a file.
 * When convenient, it also leaves the physical
 * block number of the next block of the file in rablock
 * for use in read-ahead.
 */
bmap(ip, bn)
struct inode *ip;
int bn;
{
	register *bp, *bap, nb;
	int *nbp, d, i;

	d = ip->i_dev;
	if(bn & ~03777) {
		u.u_error = EFBIG;
		return(0);
	}

	if((ip->i_mode&ILARG) == 0) {

		/*
		 * small file algorithm
		 */

		if((bn & ~7) != 0) {

			/*
			 * convert small to large
			 */

			if ((bp = alloc(d)) == NULL)
				return(NULL);
			bap = bp->b_addr;
			for(i=0; i<8; i++) {
				*bap++ = ip->i_addr[i];
				ip->i_addr[i] = 0;
			}
			ip->i_addr[0] = bp->b_blkno;
			bdwrite(bp);
			ip->i_mode =| ILARG;
			ip->i_flag =| IUPD;
			goto large;
		}
		nb = ip->i_addr[bn];
		if(nb == 0 && (bp = alloc(d)) != NULL) {
			bdwrite(bp);







Jun 19 11:27 1978  subr.c Page 2


			nb = bp->b_blkno;
			ip->i_addr[bn] = nb;
			ip->i_flag =| IUPD;
		}
		rablock = 0;
		if (bn<7)
			rablock = ip->i_addr[bn+1];
		return(nb);
	}

	/*
	 * large file algorithm
	 */

    large:
	i = bn>>8;
	if((nb=ip->i_addr[i]) == 0) {
		if ((bp = alloc(d)) == NULL)
			return(NULL);
		ip->i_addr[i] = bp->b_blkno;
		ip->i_flag =| IUPD;
	} else
		bp = bread(d, nb);
	bap = bp->b_addr;

	/*
	 * normal indirect fetch
	 */

	i = bn & 0377;
	if((nb=bap[i]) == 0 && (nbp = alloc(d)) != NULL) {
		nb = nbp->b_blkno;
		bap[i] = nb;
		bdwrite(nbp);
		bdwrite(bp);
	} else
		brelse(bp);
	rablock = 0;
	if(i < 255)
		rablock = bap[i+1];
	return(nb);
}

/*
 * Pass back  c  to the user at his location u_base;
 * update u_base, u_count, and u_offset.  Return -1
 * on the last character of the user's read.
 * u_base is in the user address space unless u_segflg is set.
 */
passc(c)
char c;
{
	register id;

	if((id = u.u_segflg) == 1)
		*u.u_base = c;







Jun 19 11:27 1978  subr.c Page 3


	else
		if(id?suibyte(u.u_base, c):subyte(u.u_base, c) < 0) {
			u.u_error = EFAULT;
			return(-1);
		}
	u.u_count--;
	if(++u.u_offset[1] == 0)
		u.u_offset[0]++;
	u.u_base++;
	return(u.u_count == 0? -1: 0);
}

/*
 * Pick up and return the next character from the user's
 * write call at location u_base;
 * update u_base, u_count, and u_offset.  Return -1
 * when u_count is exhausted.  u_base is in the user's
 * address space unless u_segflg is set.
 */
cpass()
{
	register c, id;

	if(u.u_count == 0)
		return(-1);
	if((id = u.u_segflg) == 1)
		c = *u.u_base;
	else
		if((c = id==0?fubyte(u.u_base):fuibyte(u.u_base)) < 0) {
			u.u_error = EFAULT;
			return(-1);
		}
	u.u_count--;
	if(++u.u_offset[1] == 0)
		u.u_offset[0]++;
	u.u_base++;
	return(c&0377);
}

/*
 * Routine which sets a user error; placed in
 * illegal entries in the bdevsw and cdevsw tables.
 */
nodev()
{

	u.u_error = ENODEV;
}

/*
 * Null routine; placed in insignificant entries
 * in the bdevsw and cdevsw tables.
 */
nulldev()
{
}







Jun 19 11:27 1978  subr.c Page 4



/*
 * copy count words from from to to.
 */
bcopy(from, to, count)
int *from, *to;
{
	register *a, *b, c;

	a = from;
	b = to;
	c = count;
	do
		*b++ = *a++;
	while(--c);
}















































Jun 19 11:27 1978  sys1.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/buf.h"
#include "../hd/reg.h"
#include "../hd/inode.h"
#include "../hd/seg.h"
#include "../hd/var.h"

exec()
{
	register nc;
	register char *cp;
	register struct buf *bp;
	int na, bno, ucp, ap, c, ip;

	if((ip = gethead()) == NULL)
		return;
	bp = na = nc = 0;
	/* collect arglist */
	if ((bno = malloc(swapmap,(NCARGS+511)/512)) == 0)
		panic("Out of swap");
	if (u.u_arg[1]) while(ap = fuword(u.u_arg[1])) {
		na++;
		if(ap == -1)
			u.u_error = EFAULT;
		u.u_arg[1] =+ 2;
		do {
			if (nc >= NCARGS-1)
				u.u_error = E2BIG;
			if ((c = fubyte(ap++)) < 0)
				u.u_error = EFAULT;
			if (u.u_error)
				goto bad;
			if ((nc&0777) == 0) {
				if (bp)
					bawrite(bp);
				bp = getblk(swapdev, bno+(nc>>9));
				cp = bp->b_addr;
			}
			nc++;
			*cp++ = c;
		} while (c>0);
	}
	if (bp)
		bawrite(bp);
	bp = 0;
	if((nc&1) != 0)
		nc++;
	ip = getxfile(ip, nc+2*na);
	if (u.u_error)
		goto bad;
	/* copy back arglist */
	ucp = -nc;







Jun 19 11:27 1978  sys1.c Page 2


	ap = ucp - na*2 - 4;
	u.u_ar0[R6] = ap;
	suword(ap, na);
	nc = 0;
	while(na--) {
		suword(ap=+2, ucp);
		do {
			if ((nc&0777) == 0) {
				if (bp)
					brelse(bp);
				bp = bread(swapdev, bno+(nc>>9));
				cp = bp->b_addr;
			}
			subyte(ucp++, (c = *cp++));
			nc++;
		} while(c&0377);
	}
	suword(ap+2, -1);
	setregs();
bad:
	if (bp)
		brelse(bp);
	if(ip)
		iput(ip);
	mfree(swapmap, (NCARGS+511)/512, bno);
}

/*
 * Read in and set up memory for executed file.
 */
getxfile(ip,nargc)
register struct inode *ip;
{
	register i, as, ds;

	u.u_prof[3] = 0;
	xfree();
	as = nargc>>6;
	u.u_ssize = SSIZE+as;
	u.u_dsize = ((u.u_exdata.ux_dsize+u.u_exdata.ux_bsize+63)>>6) & 01777;
	u.u_tsize = ((u.u_exdata.ux_tsize+63)>>6) & 01777;
	i = USIZE+u.u_dsize+u.u_ssize;
	expand(i);
	i =- as;
	ds = USIZE+((u.u_exdata.ux_dsize>>6)&01777);
	while(--i >= ds)
		clearseg(u.u_procp->p_addr+i);
	xalloc(ip);
	/* read in data segment */
	estabur(0, u.u_dsize, 0, 0, RO);
	u.u_base = 0;
	u.u_offset[1] = 020+u.u_exdata.ux_tsize;
	u.u_count = u.u_exdata.ux_dsize;
	readi(ip);
	if (u.u_count!=0)
		u.u_error = EFAULT;







Jun 19 11:27 1978  sys1.c Page 3


	/*
	 * set SUID/SGID protections, if no tracing
	 */
	if ((u.u_procp->p_flag&STRC)==0) {
		if(ip->i_mode&ISUID)
			if(u.u_uid != 0) {
				u.u_uid = ip->i_uid;
				u.u_procp->p_uid = ip->i_uid;
			}
		if(ip->i_mode&ISGID)
			u.u_gid = ip->i_gid;
	}
	u.u_sep = (u.u_exdata.ux_mag == 0411)?1:0;
	estabur(u.u_tsize, u.u_dsize, u.u_ssize,u.u_sep,RO);
	iput(ip);
	if (u.u_error)
		psignal(u.u_procp, SIGKIL);
	return(0);
}


gethead()
{
	register struct inode *ip;
	register sep, ts;
	long	ls;
	int	ds;
	extern int uchar();

	if ((ip = namei(uchar, 0)) == NULL)
		return(NULL);
	if (access(ip, IEXEC) ||
	   (ip->i_mode & IFMT) != 0 ||
	   (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) {
		u.u_error = EACCES;
		goto bad;
	}
	/*
	 * read in first few bytes of file for segment sizes
	 * ux_mag = 407/410/411
	 *  407 is plain executable
	 *  410 is RO text
	 *  411 is separated ID
	 */
	u.u_base = &u.u_exdata;
	u.u_count = sizeof(u.u_exdata);
	u.u_offset[0] = u.u_offset[1] = 0;
	u.u_segflg = 1;
	readi(ip);
	u.u_segflg = 0;
	if(u.u_error)
		goto bad;
	if (u.u_count!=0) {
		u.u_error = ENOEXEC;
		goto bad;
	}







Jun 19 11:27 1978  sys1.c Page 4


	sep = 0;
	ls = 63;
	dpadd(&ls, u.u_exdata.ux_dsize);
	dpadd(&ls, u.u_exdata.ux_bsize);
	if(u.u_exdata.ux_mag == 0407) {
		dpadd(&ls, u.u_exdata.ux_tsize);
		u.u_exdata.ux_dsize =+ u.u_exdata.ux_tsize;
		u.u_exdata.ux_tsize = 0;
	} else if (u.u_exdata.ux_mag == 0411)
		sep++;
	else if (u.u_exdata.ux_mag != 0410) {
		u.u_error = ENOEXEC;
		goto bad;
	}
	if(u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && ip->i_count!=1) {
		u.u_error = ETXTBSY;
		goto bad;
	}
	ts = (u.u_exdata.ux_tsize>>6) & 01777;
	if (u.u_exdata.ux_tsize&077)
		ts++;
	ds = ls>>6;
	if(checkur(ts,ds,SSIZE,sep)==0)
		return(ip);
bad:
	iput(ip);
	return(NULL);
}

setregs()
{
	register int *rp;
	register char *cp;

	for(rp = &u.u_signal[0]; rp < &u.u_signal[NSIG]; rp++)
		if((*rp & 1) == 0)
			*rp = 0;
	for(cp = &regloc[0]; cp < &regloc[6];)
		u.u_ar0[*cp++] = 0;
	u.u_ar0[R7] = u.u_exdata.ux_entloc & ~01;
	for(rp = &u.u_fsav[0]; rp < &u.u_fsav[25];)
		*rp++ = 0;

}

/*
 * exit system call:
 * pass back caller's r0
 */
rexit()
{

	u.u_arg[0] = u.u_ar0[R0] << 8;
	exit();
}








Jun 19 11:27 1978  sys1.c Page 5


/*
 * Release resources.
 * Save u. area for parent to look at.
 * Enter zombie state.
 * Wake up parent and init processes,
 * and dispose of children.
 */
exit()
{
	register int *a;
	register struct proc *p, *q;

	p = u.u_procp;
	p->p_flag =& ~STRC;
	p->p_clktim = 0;
	for(a = &u.u_signal[0]; a < &u.u_signal[NSIG];)
		*a++ = 1;
	for(a = &u.u_ofile[0]; a < &u.u_ofile[NOFILE]; a++)
		if (*a) {
			closef(*a);
			*a = NULL;
		}
	plock(u.u_cdir);
	iput(u.u_cdir);
	xfree();
	mfree(coremap, p->p_size, p->p_addr);
	p->p_stat = SZOMB;
	p->xp_xstat = u.u_arg[0];
	p->xp_utime = u.u_cutime + u.u_utime;
	p->xp_stime = u.u_cstime + u.u_stime;
	for(q = &proc[0]; q < v.ve_proc; q++)
		if(q->p_ppid == p->p_pid) {
			wakeup(&proc[1]);
			q->p_ppid = 1;
			if (q->p_stat==SSTOP)
				setrun(q);
		}
	for(q = &proc[0]; q < v.ve_proc; q++)
		if(p->p_ppid == q->p_pid) {
			wakeup(q);
			swtch();
			/* no return */
		}
	printf("Init proc dead");
	swtch();
}

/*
 * Wait system call.
 * Search for a terminated (zombie) child,
 * finally lay it to rest, and collect its status.
 * Look also for stopped (traced) children,
 * and pass back status from them.
 */
wait()
{







Jun 19 11:27 1978  sys1.c Page 6


	register f;
	register struct proc *p;

	f = 0;

loop:
	for(p = &proc[0]; p < v.ve_proc; p++)
	if(p->p_ppid == u.u_procp->p_pid) {
		f++;
		if(p->p_stat == SZOMB) {
			u.u_ar0[R0] = p->p_pid;
			u.u_ar0[R1] = p->xp_xstat;
			u.u_cutime =+ p->xp_utime;
			u.u_cstime =+ p->xp_stime;
			p->p_stat = NULL;
			p->p_pid = 0;
			p->p_ppid = 0;
			p->p_sig = 0;
			p->p_pgrp = 0;
			p->p_flag = 0;
			p->p_wchan = 0;
			return;
		}
		if(p->p_stat == SSTOP) {
			if((p->p_flag&SWTED) == 0) {
				p->p_flag =| SWTED;
				u.u_ar0[R0] = p->p_pid;
				u.u_ar0[R1] = (fsig(p)<<8) | 0177;
				return;
			}
			continue;
		}
	}
	if(f) {
		sleep(u.u_procp, PWAIT);
		goto loop;
	}
	u.u_error = ECHILD;
}

/*
 * fork system call.
 */
fork()
{
	register struct proc *p1, *p2;
	register a;

	/*
	 * Make sure there's enough swap space for max
	 * core image, thus reducing chances of running out
	 */
	if ((a = malloc(swapmap, ctob(MAXMEM))) == 0) {
		u.u_error = ENOMEM;
		goto out;
	}







Jun 19 11:27 1978  sys1.c Page 7


	mfree(swapmap, ctob(MAXMEM), a);
	p1 = u.u_procp;
	for(p2 = &proc[0]; p2 < &proc[v.v_proc]; p2++)
		if(p2->p_stat == NULL)
			goto found;
	u.u_error = EAGAIN;
	goto out;

found:
	if(newproc()) {
		u.u_ar0[R0] = p1->p_pid;
		u.u_cstime = 0;
		u.u_stime = 0;
		u.u_cutime = 0;
		u.u_utime = 0;
		return;
	}
	u.u_ar0[R0] = p2->p_pid;

out:
	u.u_ar0[R7] =+ 2;
}

/*
 * break system call.
 *  -- bad planning: "break" is a dirty word in C.
 */
sbreak()
{
	register a, n, d;
	int i;

	/*
	 * set n to new data size
	 * set d to new-old
	 * set n to new total size
	 */

	n = (((u.u_arg[0]+63)>>6) & 01777);
	if(!u.u_sep)
		n =- ctos(u.u_tsize) * 128;
	if(n < 0)
		n = 0;
	d = n - u.u_dsize;
	n =+ USIZE+u.u_ssize;
	if(estabur(u.u_tsize, u.u_dsize+d, u.u_ssize, u.u_sep, RO))
		return;
	u.u_dsize =+ d;
	if(d > 0)
		goto bigger;
	a = u.u_procp->p_addr + n - u.u_ssize;
	i = n;
	n = u.u_ssize;
	while(n--) {
		copyseg(a-d, a);
		a++;







Jun 19 11:27 1978  sys1.c Page 8


	}
	expand(i);
	return;

bigger:
	expand(n);
	a = u.u_procp->p_addr + n;
	n = u.u_ssize;
	while(n--) {
		a--;
		copyseg(a-d, a);
	}
	while(d--)
		clearseg(--a);
}
















































Jun 19 11:27 1978  sys2.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/reg.h"
#include "../hd/file.h"
#include "../hd/inode.h"

/*
 * read system call
 */
read()
{
	rdwr(FREAD);
}

/*
 * write system call
 */
write()
{
	rdwr(FWRITE);
}

/*
 * common code for read and write calls:
 * check permissions, set base, count, and offset,
 * and switch out to readi, writei, or pipe code.
 */
rdwr(mode)
{
	register *fp, *ip, m;

	m = mode;
	fp = getf(u.u_ar0[R0]);
	if(fp == NULL)
		return;
	if((fp->f_flag&m) == 0) {
		u.u_error = EBADF;
		return;
	}
	u.u_base = u.u_arg[0];
	u.u_count = u.u_arg[1];
	u.u_segflg = 0;
	if(fp->f_flag&FPIPE) {
		if(m==FREAD)
			readp(fp); else
			writep(fp);
	} else {
		ip = fp->f_inode;
		u.u_offset[1] = fp->f_offset[1];
		u.u_offset[0] = fp->f_offset[0];
		if((ip->i_mode&(IFCHR&IFBLK)) == 0)
			plock(ip);
		if(m==FREAD)
			readi(ip); else







Jun 19 11:27 1978  sys2.c Page 2


			writei(ip);
		if((ip->i_mode&(IFCHR&IFBLK)) == 0)
			prele(ip);
		dpadd(fp->f_offset, u.u_arg[1]-u.u_count);
	}
	u.u_ar0[R0] = u.u_arg[1]-u.u_count;
}

/*
 * open system call
 */
open()
{
	register *ip;
	extern uchar;

	ip = namei(&uchar, 0);
	if(ip == NULL)
		return;
	u.u_arg[1]++;
	open1(ip, u.u_arg[1], 0);
}

/*
 * creat system call
 */
creat()
{
	register *ip;
	extern uchar;

	ip = namei(&uchar, 1);
	if(ip == NULL) {
		if(u.u_error)
			return;
		ip = maknode(u.u_arg[1]&07777&(~ISVTX));
		if (ip==NULL)
			return;
		open1(ip, FWRITE, 2);
	} else
		open1(ip, FWRITE, 1);
}

/*
 * common code for open and creat.
 * Check permissions, allocate an open file structure,
 * and call the device open routine if any.
 */
open1(ip, mode, trf)
int *ip;
{
	register struct file *fp;
	register *rip, m;
	int i;

	rip = ip;







Jun 19 11:27 1978  sys2.c Page 3


	m = mode;
	if(trf != 2) {
		if(m&FREAD)
			access(rip, IREAD);
		if(m&FWRITE) {
			access(rip, IWRITE);
			if((rip->i_mode&IFMT) == IFDIR)
				u.u_error = EISDIR;
		}
	}
	if(u.u_error)
		goto out;
	if(trf == 1)
		itrunc(rip);
	prele(rip);
	if ((fp = falloc()) == NULL)
		goto out;
	fp->f_flag = m&(FREAD|FWRITE);
	fp->f_inode = rip;
	i = u.u_ar0[R0];
	if (rip->i_mode&(IFCHR&IFBLK))
		openi(rip, m&FWRITE);
	if(u.u_error == 0)
		return;
	u.u_ofile[i] = NULL;
	fp->f_count--;

out:
	iput(rip);
}

/*
 * close system call
 */
close()
{
	register *fp;

	fp = getf(u.u_ar0[R0]);
	if(fp == NULL)
		return;
	u.u_ofile[u.u_ar0[R0]] = NULL;
	closef(fp);
}

/*
 * seek system call
 */
seek()
{
	int n[2];
	register *fp, t;

	fp = getf(u.u_ar0[R0]);
	if(fp == NULL)
		return;







Jun 19 11:27 1978  sys2.c Page 4


	if(fp->f_flag&FPIPE) {
		u.u_error = ESPIPE;
		return;
	}
	t = u.u_arg[1];
	if(t > 2) {
		n[1] = u.u_arg[0]<<9;
		n[0] = u.u_arg[0]>>7;
		if(t == 3)
			n[0] =& 0777;
	} else {
		n[1] = u.u_arg[0];
		n[0] = 0;
		if(t!=0 && n[1]<0)
			n[0] = -1;
	}
	switch(t) {

	case 1:
	case 4:
		n[0] =+ fp->f_offset[0];
		dpadd(n, fp->f_offset[1]);
		break;

	default:
		n[0] =+ fp->f_inode->i_size0&0377;
		dpadd(n, fp->f_inode->i_size1);

	case 0:
	case 3:
		;
	}
	if (n[0] & ~0777)
		u.u_error = EFBIG;
	else {
		fp->f_offset[1] = n[1];
		fp->f_offset[0] = n[0];
	}
}

/*
 * Tell -- discover offset of file R/W pointer
 */
tell()
{
	register struct file *fp;

	if (fp = getf(u.u_ar0[R0])) {
		u.u_ar0[R0] = fp->f_offset[0];
		u.u_ar0[R1] = fp->f_offset[1];
	}
}

/*
 * link system call
 */







Jun 19 11:27 1978  sys2.c Page 5


link()
{
	register *ip, *xp;
	extern uchar;

	ip = namei(&uchar, 0);
	if(ip == NULL)
		return;
	if(ip->i_nlink >= 127) {
		u.u_error = EMLINK;
		goto out;
	}
	if((ip->i_mode&IFMT)==IFDIR && !suser())
		goto out;
	/*
	 * Unlock to avoid possibly hanging the namei.
	 * Sadly, this means races. (Suppose someone
	 * deletes the file in the meantime?)
	 * Nor can it be locked again later
	 * because then there will be deadly
	 * embraces.
	 */
	prele(ip);
	u.u_dirp = u.u_arg[1];
	xp = namei(&uchar, 1);
	if(xp != NULL) {
		u.u_error = EEXIST;
		iput(xp);
	}
	if(u.u_error)
		goto out;
	if(u.u_pdir->i_dev != ip->i_dev) {
		iput(u.u_pdir);
		u.u_error = EXDEV;
		goto out;
	}
	wdir(ip);
	ip->i_nlink++;
	ip->i_flag =| IUPD;

out:
	iput(ip);
}

/*
 * mknod system call
 */
mknod()
{
	register *ip;
	extern uchar;

	if(suser()) {
		ip = namei(&uchar, 1);
		if(ip != NULL) {
			u.u_error = EEXIST;







Jun 19 11:27 1978  sys2.c Page 6


			goto out;
		}
	}
	if(u.u_error)
		return;
	ip = maknode(u.u_arg[1]);
	if (ip==NULL)
		return;
	ip->i_addr[0] = u.u_arg[2];

out:
	iput(ip);
}

/*
 * sleep system call
 * not to be confused with the sleep internal routine.
 */
sslep()
{
	long d;

	spl7();
	d = time + u.u_ar0[R0];
	while (time < d) {
		if (tout<=time || d<tout)
			tout = d;
		sleep(&tout, PSLEP);
	}
	spl0();
}

/*
 * access system call
 */
saccess()
{
	extern uchar;
	register svuid, svgid;
	register *ip;

	svuid = u.u_uid;
	svgid = u.u_gid;
	u.u_uid = u.u_ruid;
	u.u_gid = u.u_rgid;
	ip = namei(&uchar, 0);
	if (ip != NULL) {
		if (u.u_arg[1]&(IREAD>>6))
			access(ip, IREAD);
		if (u.u_arg[1]&(IWRITE>>6))
			access(ip, IWRITE);
		if (u.u_arg[1]&(IEXEC>>6))
			access(ip, IEXEC);
		iput(ip);
	}
	u.u_uid = svuid;







Jun 19 11:27 1978  sys2.c Page 7


	u.u_gid = svgid;
}





























































Jun 19 11:27 1978  sys3.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/reg.h"
#include "../hd/buf.h"
#include "../hd/filsys.h"
#include "../hd/user.h"
#include "../hd/inode.h"
#include "../hd/file.h"
#include "../hd/conf.h"
#include "../hd/var.h"

/*
 * the fstat system call.
 */
fstat()
{
	register *fp, *base;

	fp = getf(u.u_ar0[R0]);
	if(fp == NULL)
		return;
	base	= u.u_arg[0];
	stat1(fp->f_inode, base);
	if (fp->f_flag&FPIPE)		/* correct if pipe */
		suword(&base[5],fp->f_inode->i_size1-fp->f_offset[1]);
}

/*
 * the stat system call.
 */
stat()
{
	register ip;
	extern uchar;

	ip = namei(&uchar, 0);
	if(ip == NULL)
		return;
	stat1(ip, u.u_arg[1]);
	iput(ip);
}

/*
 * The basic routine for fstat and stat:
 * get the inode and pass appropriate parts back.
 */
stat1(ip, ub)
int *ip;
{
	register i, *bp, *cp;

	iupdat(ip);
	bp = bread(ip->i_dev, ldiv(ip->i_number+31, 16));
	cp = bp->b_addr + 32*lrem(ip->i_number+31, 16) + 24;
	ip = &(ip->i_dev);







Jun 19 11:27 1978  sys3.c Page 2


	for(i=0; i<14; i++) {
		if (suword(ub, *ip) != *ip++)
			u.u_error = EFAULT;
		ub =+ 2;
	}
	for(i=0; i<4; i++) {
		if (suword(ub, *cp) != *cp++)
			u.u_error = EFAULT;
		ub =+ 2;
	}
	brelse(bp);
}

/*
 * the dup system call.
 */
dup()
{
	register i, *fp;

	fp = getf(u.u_ar0[R0]);
	if(fp == NULL)
		return;
	if ((i = ufalloc()) < 0)
		return;
	u.u_ofile[i] = fp;
	fp->f_count++;
}

/*
 * the mount system call.
 */
smount()
{
	int d;
	register *ip;
	register struct mount *mp, *smp;
	extern uchar;

	if(!suser())
		return;
	d = getmdev();
	if(u.u_error)
		return;
	u.u_dirp = u.u_arg[1];
	ip = namei(&uchar, 0);
	if(ip == NULL)
		return;
	if(ip->i_count!=1 || (ip->i_mode&(IFBLK&IFCHR))!=0)
		goto out;
	smp = NULL;
	for(mp = &mount[0]; mp < v.ve_mount; mp++) {
		if(mp->m_bufp != NULL) {
			if(d == mp->m_dev)
				goto out;
		} else







Jun 19 11:27 1978  sys3.c Page 3


		if(smp == NULL)
			smp = mp;
	}
	if(smp == NULL)
		goto out;
	(*bdevsw[major(d)].d_open)(minor(d), !u.u_arg[2]);
	if(u.u_error)
		goto out;
	mp = bread(d, 1);
	if(u.u_error) {
		brelse(mp);
		goto out1;
	}
	smp->m_inodp = ip;
	smp->m_dev = d;
	smp->m_bufp = getblk(NODEV);
	bcopy(mp->b_addr, smp->m_bufp->b_addr, 256);
	smp = smp->m_bufp->b_addr;
	smp->s_ilock = 0;
	smp->s_flock = 0;
	smp->s_ninode = 0;
	smp->s_ronly = u.u_arg[2] & 1;
	brelse(mp);
	ip->i_flag =| IMOUNT;
	prele(ip);
	return;

out:
	u.u_error = EBUSY;
out1:
	iput(ip);
}

/*
 * the umount system call.
 */
sumount()
{
	int d;
	register struct inode *ip;
	register struct mount *mp;

	if(!suser())
		return;
	update();
	d = getmdev();
	if(u.u_error)
		return;
	for(mp = &mount[0]; mp < v.ve_mount; mp++)
		if(mp->m_bufp!=NULL && d==mp->m_dev)
			goto found;
	u.u_error = EINVAL;
	return;

found:
	for(ip = &inode[0]; ip < v.ve_inode; ip++)







Jun 19 11:27 1978  sys3.c Page 4


		if(ip->i_number!=0 && d==ip->i_dev) {
			u.u_error = EBUSY;
			return;
		}
	(*bdevsw[major(d)].d_close)(minor(d), 0);
	ip = mp->m_inodp;
	ip->i_flag =& ~IMOUNT;
	plock(ip);
	iput(ip);
	ip = mp->m_bufp;
	mp->m_bufp = NULL;
	brelse(ip);
}

/*
 * Common code for mount and umount.
 * Check that the user's argument is a reasonable
 * thing on which to mount, and return the device number if so.
 */
getmdev()
{
	register d, *ip;
	extern uchar;

	ip = namei(&uchar, 0);
	if(ip == NULL)
		return(NODEV);
	if((ip->i_mode&IFMT) != IFBLK)
		u.u_error = ENOTBLK;
	d = ip->i_addr[0];
	if(major(ip->i_addr[0]) >= bdevcnt)
		u.u_error = ENXIO;
	iput(ip);
	return(d);
}




























Jun 19 11:27 1978  sys4.c Page 1


#
/*
 * Everything in this file is a routine implementing a system call.
 */

#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/reg.h"
#include "../hd/inode.h"
#include "../hd/systm.h"
#include "../hd/proc.h"
#include "../hd/var.h"

getswit()
{

	u.u_ar0[R0] = SW->integ;
}

gtime()
{
	u.u_ar0[R0] = time.hiword;
	u.u_ar0[R1] = time.loword;
}

stime()
{
	if(suser()) {
		time.hiword = u.u_ar0[R0];
		time.loword = u.u_ar0[R1];
		wakeup(&tout);
	}
}

setuid()
{
	register uid;

	uid = u.u_ar0[R0].lobyte;
	if(u.u_ruid == uid.lobyte || suser()) {
		u.u_uid = uid;
		u.u_procp->p_uid = uid;
		u.u_ruid = uid;
	}
}

getuid()
{

	u.u_ar0[R0].lobyte = u.u_ruid;
	u.u_ar0[R0].hibyte = u.u_uid;
}

setgid()
{
	register gid;







Jun 19 11:27 1978  sys4.c Page 2



	gid = u.u_ar0[R0].lobyte;
	if(u.u_rgid == gid.lobyte || suser()) {
		u.u_gid = gid;
		u.u_rgid = gid;
	}
}

getgid()
{

	u.u_ar0[R0].lobyte = u.u_rgid;
	u.u_ar0[R0].hibyte = u.u_gid;
}

getpid()
{
	u.u_ar0[R0] = u.u_procp->p_pid;
	u.u_ar0[R1] = u.u_procp->p_pgrp;
}

setpgrp()
{
	u.u_procp->p_pgrp = u.u_procp->p_pid;
}

sync()
{

	update();
}

nice()
{
	register n;

	n = u.u_ar0[R0];
	if(n > 20)
		n = 20;
	if(n < 0 && !suser())
		n = 0;
	u.u_procp->p_nice = n;
}

/*
 * Unlink system call.
 * Hard to avoid races here, especially
 * in unlinking directories.
 */
unlink()
{
	register *ip, *pp;
	extern uchar;

	pp = namei(&uchar, 2);
	if(pp == NULL)







Jun 19 11:27 1978  sys4.c Page 3


		return;
	/*
	 * Check for unlink(".")
	 * to avoid hanging on the iget
	 */
	if (pp->i_number != u.u_dent.u_ino)
		ip = iget(pp->i_dev, u.u_dent.u_ino);
	else {
		ip = pp;
		ip->i_count++;
	}
	if(ip == NULL)
		goto out1;
	if((ip->i_mode&IFMT)==IFDIR && !suser())
		goto out;
	/*
	 * Don't unlink a mounted file.
	 */
	if (ip->i_dev != pp->i_dev) {
		u.u_error = EBUSY;
		goto out;
	}
	if (ip->i_flag&ITEXT && ip->i_nlink==1) {
		u.u_error = ETXTBSY;
		goto out;
	}
	u.u_offset[1] =- DIRSIZ+2;
	u.u_base = &u.u_dent;
	u.u_count = DIRSIZ+2;
	u.u_dent.u_ino = 0;
	writei(pp);
	ip->i_nlink--;
	ip->i_flag =| IUPD;

out:
	iput(ip);
out1:
	iput(pp);
}

chdir()
{
	register *ip;
	extern uchar;

	ip = namei(&uchar, 0);
	if(ip == NULL)
		return;
	if((ip->i_mode&IFMT) != IFDIR) {
		u.u_error = ENOTDIR;
	bad:
		iput(ip);
		return;
	}
	if(access(ip, IEXEC))
		goto bad;







Jun 19 11:27 1978  sys4.c Page 4


	prele(ip);
	plock(u.u_cdir);
	iput(u.u_cdir);
	u.u_cdir = ip;
}

chmod()
{
	register *ip, a;

	if ((ip = owner()) == NULL)
		return;
	ip->i_mode =& ~07777;
	a = u.u_arg[1];
	if (u.u_uid) {
		a =& ~ISVTX;
		if (u.u_gid != ip->i_gid)
			a =& ~ISGID;
	}
	ip->i_mode =| a&07777;
	ip->i_flag =| IUPD;
	iput(ip);
}

chown()
{
	register *ip;

	if ((ip = owner()) == NULL)
		return;
	ip->i_uid = u.u_arg[1].lobyte;
	ip->i_gid = u.u_arg[1].hibyte;
	if(u.u_uid != 0)
		ip->i_mode =& ~(ISUID|ISGID);
	ip->i_flag =| IUPD;
	iput(ip);
}

ssig()
{
	register a;

	a = u.u_arg[0];
	if(a<=0 || a>NSIG || a==SIGKIL) {
		u.u_error = EINVAL;
		return;
	}
	u.u_ar0[R0] = u.u_signal[a-1];
	u.u_signal[a-1] = u.u_arg[1];
	u.u_procp->p_sig =& ~(1<<(a-1));
}

kill()
{
	register struct proc *p;
	register a, f;







Jun 19 11:27 1978  sys4.c Page 5



	f = 0;
	a = u.u_ar0[R0];
	if (a>0)
		p = &proc[0]; else
		p = &proc[2];
	for(; p < v.ve_proc; p++) {
		if(a > 0 && p->p_pid != a)
			continue;
		if(a == 0 && p->p_pgrp != u.u_procp->p_pgrp)
			continue;
		if(u.u_uid != 0 && u.u_uid != p->p_uid)
			if (a>0) {
				u.u_error = EPERM;
				return;
			} else
				continue;
		f++;
		psignal(p, u.u_arg[0]);
	}
	if(f == 0)
		u.u_error = ESRCH;
}

times()
{
	register *p;

	for(p = &u.u_utime; p  < &u.u_utime+4;) {
		suword(u.u_arg[0], *p++);
		u.u_arg[0] =+ 2;
	}
}

profil()
{

	u.u_prof[0] = u.u_arg[0] & ~1;	/* base of sample buf */
	u.u_prof[1] = u.u_arg[1];	/* size of same */
	u.u_prof[2] = u.u_arg[2];	/* pc offset */
	u.u_prof[3] = (u.u_arg[3]>>1) & 077777; /* pc scale */
}

/*
 * alarm clock signal
 */
alarm()
{
	register c, *p;

	p = u.u_procp;
	c = p->p_clktim;
	p->p_clktim = u.u_ar0[R0];
	u.u_ar0[R0] = c;
}








Jun 19 11:27 1978  sys4.c Page 6


/*
 * indefinite wait.
 * no one should wakeup(&u)
 */
pause()
{

	for(;;)
		sleep(&u, PSLEP);
}





















































Jun 19 11:27 1978  sysent.c Page 1


#
/*
 * This table is the switch used to transfer
 * to the appropriate routine for processing a system call.
 * Each row contains the number of arguments expected
 * and a pointer to the routine.
 */
extern	nullsys(),rexit(),fork(),read(),write(),open(),close(),wait(),creat(),link();
extern	unlink(),exec(),chdir(),gtime(),mknod(),chmod(),chown(),sbreak(),stat(),seek();
extern	getpid(),smount(),sumount(),setuid(),getuid(),stime(),ptrace(),alarm(),fstat(),pause();
extern	stty(),gtty(),saccess(),nice(),sslep(),sync(),kill(),getswit(),setpgrp();
extern	tell(),dup(),pipe(),times(),profil(),setgid(),getgid(),ssig(),pwbsys(),nosys();
int	sysent[]
{
	0, &nullsys,			/*  0 = indir */
	0, &rexit,			/*  1 = exit */
	0, &fork,			/*  2 = fork */
	2, &read,			/*  3 = read */
	2, &write,			/*  4 = write */
	2, &open,			/*  5 = open */
	0, &close,			/*  6 = close */
	0, &wait,			/*  7 = wait */
	2, &creat,			/*  8 = creat */
	2, &link,			/*  9 = link */
	1, &unlink,			/* 10 = unlink */
	2, &exec,			/* 11 = exec */
	1, &chdir,			/* 12 = chdir */
	0, &gtime,			/* 13 = time */
	3, &mknod,			/* 14 = mknod */
	2, &chmod,			/* 15 = chmod */
	2, &chown,			/* 16 = chown */
	1, &sbreak,			/* 17 = break */
	2, &stat,			/* 18 = stat */
	2, &seek,			/* 19 = seek */
	0, &getpid,			/* 20 = getpid */
	3, &smount,			/* 21 = mount */
	1, &sumount,			/* 22 = umount */
	0, &setuid,			/* 23 = setuid */
	0, &getuid,			/* 24 = getuid */
	0, &stime,			/* 25 = stime */
	3, &ptrace,			/* 26 = ptrace */
	0, &alarm,			/* 27 = alarm */
	1, &fstat,			/* 28 = fstat */
	0, &pause,			/* 29 = pause */
	0, &nosys,			/* 30 = smdate */
	1, &stty,			/* 31 = stty */
	1, &gtty,			/* 32 = gtty */
	2, &saccess,			/* 33 = access */
	0, &nice,			/* 34 = nice */
	0, &sslep,			/* 35 = sleep */
	0, &sync,			/* 36 = sync */
	1, &kill,			/* 37 = kill */
	0, &getswit,			/* 38 = switch */
	0, &setpgrp,			/* 39 = setpgrp */
	0, &tell,			/* 40 = tell */
	0, &dup,			/* 41 = dup */







Jun 19 11:27 1978  sysent.c Page 2


	0, &pipe,			/* 42 = pipe */
	1, &times,			/* 43 = times */
	4, &profil,			/* 44 = prof */
	0, &nosys,			/* 45 = tiu */
	0, &setgid,			/* 46 = setgid */
	0, &getgid,			/* 47 = getgid */
	2, &ssig,			/* 48 = sig */
	0, &nosys,			/* 49 = reserved for USG */
	0, &nosys,			/* 50 = reserved for USG */
	0, &nosys,			/* 51 = x */
	0, &nosys,			/* 52 = x */
	0, &nosys,			/* 53 = x */
	0, &nosys,			/* 54 = x */
	0, &nosys,			/* 55 = x */
	0, &nosys,			/* 56 = x */
	1, &pwbsys,			/* 57 = pwbsys */
	0, &nosys,			/* 58 = x */
	0, &nosys,			/* 59 = x */
	0, &nosys,			/* 60 = x */
	0, &nosys,			/* 61 = x */
	0, &nosys,			/* 62 = x */
	0, &nosys			/* 63 = x */
};

/*
 * Dummy entry for illegal system calls
 */

int badent[] {
	0, &nosys
};
































Jun 19 11:27 1978  text.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/text.h"
#include "../hd/inode.h"
#include "../hd/buf.h"
#include "../hd/seg.h"
#include "../hd/var.h"

/*
 * Swap out process p.
 * The ff flag causes its core to be freed--
 * it may be off when called to create an image for a
 * child process in newproc.
 * Os is the old size of the data area of the process,
 * and is supplied during core expansion swaps.
 *
 * panic: out of swap space
 */
xswap(rp, ff, os)
register *rp;
{
	register a;

	if(os == 0)
		os = rp->p_size;
	a = malloc(swapmap, ctob(rp->p_size));
	if(a == NULL)
		panic("out of swap space");
	rp->p_flag =| SLOCK;
	xccdec(rp->p_textp);
	swap(a, rp->p_addr, os, B_WRITE);
	if(ff)
		mfree(coremap, os, rp->p_addr);
	rp->p_addr = a;
	rp->p_flag =& ~(SLOAD|SLOCK);
	rp->p_time = 0;
	if(runout) {
		runout = 0;
		wakeup(&runout);
	}
}

/*
 * relinquish use of the shared text segment
 * of a process.
 */
xfree()
{
	register struct text *xp;
	register struct inode *ip;

	if((xp=u.u_procp->p_textp) == NULL)
		return;







Jun 19 11:27 1978  text.c Page 2


	xlock(xp);
	u.u_procp->p_textp = NULL;
	xp->x_flag =& ~XLOCK;
	ip = xp->x_iptr;
	if(--xp->x_count==0 && (ip->i_mode&ISVTX)==0) {
		xp->x_iptr = NULL;
		mfree(swapmap, ctob(xp->x_size), xp->x_daddr);
		mfree(coremap, xp->x_size, xp->x_caddr);
		ip->i_flag =& ~ITEXT;
		if (ip->i_flag&ILOCK)
			ip->i_count--;
		else
			iput(ip);
	} else
		xccdec(xp);
}

/*
 * Attach to a shared text segment.
 * If there is no shared text, just return.
 * If there is, hook up to it:
 * if it is not currently being used, it has to be read
 * in from the inode (ip); the written bit is set to force it
 * to be written out as appropriate.
 * If it is being used, but is not currently in core,
 * a swap has to be done to get it back.
 */
xalloc(ip)
int *ip;
{
	register struct text *xp;
	register *rp, ts;

	if(u.u_exdata.ux_tsize == 0)
		return;
	rp = NULL;
	for (xp = &text[0]; xp < v.ve_text; xp++) {
		if(xp->x_iptr == NULL) {
			if(rp == NULL)
				rp = xp;
			continue;
		}
		if(xp->x_iptr == ip) {
			xlock(xp);
			xp->x_count++;
			u.u_procp->p_textp = xp;
			if (xp->x_ccount == 0)
				xexpand(xp);
			else
				xp->x_ccount++;
			xunlock(xp);
			return;
		}
	}
	if((xp=rp) == NULL) {
		printf("out of text");







Jun 19 11:27 1978  text.c Page 3


		psignal(u.u_procp, SIGKIL);
		return;
	}
	xp->x_flag = XLOAD|XLOCK;
	xp->x_count = 1;
	xp->x_ccount = 0;
	xp->x_iptr = rp = ip;
	rp->i_flag =| ITEXT;
	rp->i_count++;
	ts = ((u.u_exdata.ux_tsize+63)>>6) & 01777;
	xp->x_size = ts;
	if((xp->x_daddr = malloc(swapmap, ctob(ts))) == NULL)
		panic("out of swap space");
	u.u_procp->p_textp = xp;
	xexpand(xp);
	estabur(ts, 0, 0, 0, RW);
	u.u_count = u.u_exdata.ux_tsize;
	u.u_offset[0] = 0;
	u.u_offset[1] = 020;
	u.u_base = 0;
	u.u_segflg = 2;
	u.u_procp->p_flag =| SLOCK;
	readi(rp);
	u.u_procp->p_flag =& ~SLOCK;
	u.u_segflg = 0;
	xp->x_flag = XWRIT;
}

/*
 * Assure core for text segment
 * Text must be locked to keep someone else from
 * freeing it in the meantime.
 * x_ccount must be 0.
 */
xexpand(xp)
register struct text *xp;
{
	if ((xp->x_caddr = malloc(coremap, xp->x_size)) != NULL) {
		if ((xp->x_flag&XLOAD)==0)
			swap(xp->x_daddr, xp->x_caddr, xp->x_size, B_READ);
		xp->x_ccount++;
		xunlock(xp);
		return;
	}
	savu(u.u_rsav);
	savu(u.u_ssav);
	xswap(u.u_procp, 1, 0);
	xunlock(xp);
	u.u_procp->p_flag =| SSWAP;
	qswtch();
	/* no return */
}

/*
 * Lock and unlock a text segment from swapping
 */







Jun 19 11:27 1978  text.c Page 4


xlock(xp)
register struct text *xp;
{
	while(xp->x_flag&XLOCK) {
		xp->x_flag =| XWANT;
		sleep(xp, PSWP);
	}
	xp->x_flag =| XLOCK;
}

xunlock(xp)
register struct text *xp;
{
	if (xp->x_flag&XWANT)
		wakeup(xp);
	xp->x_flag =& ~(XLOCK|XWANT);
}

/*
 * Decrement the in-core usage count of a shared text segment.
 * When it drops to zero, free the core space.
 */
xccdec(xp)
register struct text *xp;
{
	if (xp==NULL || xp->x_ccount==0)
		return;
	xlock(xp);
	if (--xp->x_ccount==0) {
		if (xp->x_flag&XWRIT) {
			xp->x_flag =& ~XWRIT;
			swap(xp->x_daddr,xp->x_caddr,xp->x_size,B_WRITE);
		}
		mfree(coremap, xp->x_size, xp->x_caddr);
	}
	xunlock(xp);
}


























Jun 19 11:27 1978  trap.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/reg.h"
#include "../hd/seg.h"

#define	EBIT	1		/* user error bit in PS: C-bit */
#define	UMODE	0170000		/* user-mode bits in PS word */
#define	SETD	0170011		/* SETD instruction */
#define	SYS	0104400		/* sys (trap) instruction */
#define	USER	020		/* user-mode flag added to dev */
#define	MEMORY	0177740		/* 11/70 "memory" subsystem */
#define	NSYSENT	64		/* number of syscall entries */

/*
 * structure of the system entry table (sysent.c)
 */
struct sysent	{
	int	count;		/* argument count */
	int	(*call)();	/* name of handler */
} sysent[];

/*
 * Dummy entry for illegal system calls
 */

struct sysent badent[];

/*
 * Offsets of the user's registers relative to
 * the saved r0. See reg.h
 */
char	regloc[9]
{
	R0, R1, R2, R3, R4, R5, R6, R7, RPS
};

/*
 * Called from l40.s or l45.s when a processor trap occurs.
 * The arguments are the words saved on the system stack
 * by the hardware and software during the trap processing.
 * Their order is dictated by the hardware and the details
 * of C's calling sequence. They are peculiar in that
 * this call is not 'by value' and changed user registers
 * get copied back on return.
 * dev is the kind of trap that occurred.
 */
trap(dev, sp, r1, nps, r0, pc, ps)
{
	register i, a;
	register struct sysent *callp;

	savfp();
	if ((ps&UMODE) == UMODE)







Jun 19 11:27 1978  trap.c Page 2


		dev =| USER;
	u.u_ar0 = &r0;
	switch(dev) {

	/*
	 * Trap not expected.
	 * Usually a kernel mode bus error.
	 * The numbers printed are used to
	 * find the hardware PS/PC as follows.
	 * (all numbers in octal 18 bits)
	 *	address_of_saved_ps =
	 *		(ka6*0100) + aps - 0140000;
	 *	address_of_saved_pc =
	 *		address_of_saved_ps - 2;
	 */
	default:
		printf("ka6 = %o\n", *ka6);
		printf("aps = %o\n", &ps);
		printf("trap type %d\n", dev);
		panic("trap");

	case 0+USER: /* bus error */
		i = SIGBUS;
		break;

	/*
	 * If illegal instructions are not
	 * being caught and the offending instruction
	 * is a SETD, the trap is ignored.
	 * This is because C produces a SETD at
	 * the beginning of every program which
	 * will trap on CPUs without 11/45 FPU.
	 */
	case 1+USER: /* illegal instruction */
		if(fuiword(pc-2) == SETD && u.u_signal[SIGINS-1] == 0)
			goto out;
		i = SIGINS;
		break;

	case 2+USER: /* bpt or trace */
		i = SIGTRC;
		break;

	case 3+USER: /* iot */
		i = SIGIOT;
		break;

	case 5+USER: /* emt */
		i = SIGEMT;
		break;

	case 6+USER: /* sys call */
		u.u_error = 0;
		ps =& ~EBIT;
		if ((i=fuiword(pc-2)&0377) < NSYSENT)
			callp = &sysent[i]; else







Jun 19 11:27 1978  trap.c Page 3


			callp = &badent;
		if (callp == sysent) { /* indirect */
			a = fuiword(pc);
			pc =+ 2;
			i = fuword(a);
			if ((i & ~0377) != SYS || (i =& 0377) >= NSYSENT)
				callp = &badent; else
				callp = &sysent[i];
			for(i=0; i<callp->count; i++)
				u.u_arg[i] = fuword(a =+ 2);
		} else {
			for(i=0; i<callp->count; i++) {
				u.u_arg[i] = fuiword(pc);
				pc =+ 2;
			}
		}
		u.u_dirp = u.u_arg[0];
		trap1(callp->call);
		if(u.u_intflg)
			u.u_error = EINTR;
		if(u.u_error) {
			ps =| EBIT;
			r0 = u.u_error;
		}
		goto out;

	/*
	 * Since the floating exception is an
	 * imprecise trap, a user generated
	 * trap may actually come from kernel
	 * mode. In this case, a signal is sent
	 * to the current process to be picked
	 * up later.
	 */
	case 8: /* floating exception */
		psignal(u.u_procp, SIGFPT);
		return;

	case 8+USER:
		i = SIGFPT;
		break;

	/*
	 * If the user SP is below the stack segment,
	 * grow the stack automatically.
	 * This relies on the ability of the hardware
	 * to restart a half executed instruction.
	 * On the 11/40 this is not the case and
	 * the routine backup/l40.s may fail.
	 * The classic example is on the instruction
	 *	cmp	-(sp),-(sp)
	 */
	case 9+USER: /* segmentation exception */
		a = sp;
		if(backup(u.u_ar0) == 0)
		if(grow(a))







Jun 19 11:27 1978  trap.c Page 4


			goto out;
		i = SIGSEG;
		break;

	case 10:
	case 10+USER:
		if (cputype == 70) {
			printf("parity error\n");
			for(i=0; i<4; i++)
				printf("%o ", MEMORY->r[i]);
			printf("\n");
			MEMORY->r[2] = -1;
			if (dev&USER) {
				i = SIGBUS;
				break;
			}
		}
		panic("parity");

	}
	psignal(u.u_procp, i);

out:
	if(issig())
		psig();
	curpri = setpri(u.u_procp);
}

/*
 * Call the system-entry routine f (out of the
 * sysent table). This is a subroutine for trap, and
 * not in-line, because if a signal occurs
 * during processing, an (abnormal) return is simulated from
 * the last caller to savu(qsav); if this took place
 * inside of trap, it wouldn't have a chance to clean up.
 *
 * If this occurs, the return takes place without
 * clearing u_intflg; if it's still set, trap
 * marks an error which means that a system
 * call (like read on a typewriter) got interrupted
 * by a signal.
 */
trap1(f)
int (*f)();
{

	u.u_intflg = 1;
	savu(u.u_qsav);
	(*f)();
	u.u_intflg = 0;
}

/*
 * nonexistent system call-- signal bad system call.
 */
nosys()







Jun 19 11:27 1978  trap.c Page 5


{
	psignal(u.u_procp, SIGSYS);
}

/*
 * Ignored system call
 */
nullsys()
{
}

/*
 * Catch stray interrupts by using trace feature
 * trap through 0 looks like 42
 */
stray(dev, sp, r1, addr)
{
	printf("stray interrupt at %o\n",addr==042?0:addr-2);
}












































Jun 19 11:26 1978  bio.c Page 1


#
#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/buf.h"
#include "../hd/conf.h"
#include "../hd/systm.h"
#include "../hd/var.h"

/*
 * Declarations of the tables for the magtape devices;
 * see bdwrite.
 */
int	tmtab, httab;

/*
 * The following several routines allocate and free
 * buffers with various side effects.  In general the
 * arguments to an allocate routine are a device and
 * a block number, and the value is a pointer to
 * to the buffer header; the buffer is marked "busy"
 * so that no on else can touch it.  If the block was
 * already in core, no I/O need be done; if it is
 * already busy, the process waits until it becomes free.
 * The following routines allocate a buffer:
 *	getblk
 *	bread
 *	breada
 * Eventually the buffer must be released, possibly with the
 * side effect of writing it out, by using one of
 *	bwrite
 *	bdwrite
 *	bawrite
 *	brelse
 */

/*
 * Read in (if necessary) the block and return a buffer pointer.
 */
bread(dev, blkno)
{
	register struct buf *rbp;

	rbp = getblk(dev, blkno);
	if (rbp->b_flags&B_DONE)
		return(rbp);
	rbp->b_flags =| B_READ;
	(*bdevsw[major(dev)].d_strategy)(rbp);
	iowait(rbp);
	return(rbp);
}

/*
 * Read in the block, like bread, but also start I/O on the
 * read-ahead block (which is not allocated to the caller)
 */
breada(adev, blkno, rablkno)







Jun 19 11:26 1978  bio.c Page 2


{
	register struct buf *rbp, *rabp;
	register int dev;

	dev = adev;
	rbp = 0;
	if (!incore(dev, blkno)) {
		rbp = getblk(dev, blkno);
		if ((rbp->b_flags&B_DONE) == 0) {
			rbp->b_flags =| B_READ;
			(*bdevsw[major(adev)].d_strategy)(rbp);
		}
	}
	if (rablkno && bfreelist.b_wcount>1 && !incore(dev, rablkno)) {
		rabp = getblk(dev, rablkno);
		if (rabp->b_flags & B_DONE)
			brelse(rabp);
		else {
			rabp->b_flags =| B_READ|B_ASYNC;
			(*bdevsw[major(adev)].d_strategy)(rabp);
		}
	}
	if (rbp==0)
		return(bread(dev, blkno));
	iowait(rbp);
	return(rbp);
}

/*
 * Write the buffer, waiting for completion.
 * Then release the buffer.
 */
bwrite(bp)
struct buf *bp;
{
	register struct buf *rbp;
	register flag;

	rbp = bp;
	flag = rbp->b_flags;
	rbp->b_flags =& ~(B_READ | B_DONE | B_ERROR | B_DELWRI | B_AGE);
	(*bdevsw[major(rbp->b_dev)].d_strategy)(rbp);
	if ((flag&B_ASYNC) == 0) {
		iowait(rbp);
		brelse(rbp);
	} else if ((flag&B_DELWRI)==0)
		geterror(rbp); else
		rbp->b_flags =| B_AGE;
}

/*
 * Release the buffer, marking it so that if it is grabbed
 * for another purpose it will be written out before being
 * given up (e.g. when writing a partial block where it is
 * assumed that another write for the same block will soon follow).
 * This can't be done for magtape, since writes must be done







Jun 19 11:26 1978  bio.c Page 3


 * in the same order as requested.
 */
bdwrite(bp)
struct buf *bp;
{
	register struct buf *rbp;
	register struct devtab *dp;

	rbp = bp;
	dp = bdevsw[major(rbp->b_dev)].d_tab;
	if (dp == &tmtab || dp == &httab)
		bawrite(rbp);
	else {
		rbp->b_flags =| B_DELWRI | B_DONE;
		brelse(rbp);
	}
}

/*
 * Release the buffer, start I/O on it, but don't wait for completion.
 */
bawrite(bp)
struct buf *bp;
{
	register struct buf *rbp;

	rbp = bp;
	if(bfreelist.b_wcount>4)
		rbp->b_flags =| B_ASYNC;
	bwrite(rbp);
}

/*
 * release the buffer, with no I/O implied.
 */
brelse(bp)
struct buf *bp;
{
	register struct buf *rbp, **backp;
	register int sps;

	rbp = bp;
	if (rbp->b_flags&B_WANTED)
		wakeup(rbp);
	if (bfreelist.b_flags&B_WANTED) {
		bfreelist.b_flags =& ~B_WANTED;
		wakeup(&bfreelist);
	}
	if (rbp->b_flags&B_ERROR) {
		rbp->b_dev =| 0200;
		rbp->b_flags =& ~(B_ERROR|B_DELWRI);
	}
	sps = PS->integ;
	spl6();
	if(rbp->b_flags & B_AGE) {
		backp = &bfreelist.av_forw;







Jun 19 11:26 1978  bio.c Page 4


		(*backp)->av_back = rbp;
		rbp->av_forw = *backp;
		*backp = rbp;
		rbp->av_back = &bfreelist;
	} else {
		backp = &bfreelist.av_back;
		(*backp)->av_forw = rbp;
		rbp->av_back = *backp;
		*backp = rbp;
		rbp->av_forw = &bfreelist;
	}
	rbp->b_flags =& ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE);
	bfreelist.b_wcount++;
	PS->integ = sps;
}

/*
 * See if the block is associated with some buffer
 * (mainly to avoid getting hung up on a wait in breada)
 */
incore(adev, blkno)
{
	register int dev;
	register struct buf *bp;
	register struct devtab *dp;

	dev = adev;
	dp = bdevsw[major(adev)].d_tab;
	for (bp=dp->b_forw; bp != dp; bp = bp->b_forw)
		if (bp->b_blkno==blkno && bp->b_dev==dev)
			return(bp);
	return(0);
}

/*
 * Assign a buffer for the given block.  If the appropriate
 * block is already associated, return it; otherwise search
 * for the oldest non-busy buffer and reassign it.
 * When a 512-byte area is wanted for some random reason
 * (e.g. during exec, for the user arglist) getblk can be called
 * with device NODEV to avoid unwanted associativity.
 */
getblk(dev, blkno)
{
	register struct buf *bp;
	register struct devtab *dp;

    loop:
	if (dev < 0)
		dp = &bfreelist;
	else {
		if (major(dev) >= bdevcnt)
			panic("blkdev");
		dp = bdevsw[major(dev)].d_tab;
		if(dp == NULL)
			panic("devtab");







Jun 19 11:26 1978  bio.c Page 5


		for (bp=dp->b_forw; bp != dp; bp = bp->b_forw) {
			if (bp->b_blkno!=blkno || bp->b_dev!=dev)
				continue;
			spl6();
			if (bp->b_flags&B_BUSY) {
				bp->b_flags =| B_WANTED;
				sleep(bp, PRIBIO+1);
				spl0();
				goto loop;
			}
			spl0();
			notavail(bp);
			return(bp);
		}
	}
	spl6();
	if (bfreelist.av_forw == &bfreelist) {
		bfreelist.b_flags =| B_WANTED;
		sleep(&bfreelist, PRIBIO+1);
		spl0();
		goto loop;
	}
	spl0();
	notavail(bp = bfreelist.av_forw);
	if (bp->b_flags & B_DELWRI) {
		bp->b_flags =| B_ASYNC;
		bwrite(bp);
		goto loop;
	}
	bp->b_flags = B_BUSY;
	bp->b_back->b_forw = bp->b_forw;
	bp->b_forw->b_back = bp->b_back;
	bp->b_forw = dp->b_forw;
	bp->b_back = dp;
	dp->b_forw->b_back = bp;
	dp->b_forw = bp;
	bp->b_dev = dev;
	bp->b_blkno = blkno;
	return(bp);
}

/*
 * Wait for I/O completion on the buffer; return errors
 * to the user.
 */
iowait(bp)
struct buf *bp;
{
	register struct buf *rbp;

	rbp = bp;
	spl6();
	while ((rbp->b_flags&B_DONE)==0)
		sleep(rbp, PRIBIO);
	spl0();
	geterror(rbp);







Jun 19 11:26 1978  bio.c Page 6


}

/*
 * Unlink a buffer from the available list and mark it busy.
 * (internal interface)
 */
notavail(bp)
struct buf *bp;
{
	register struct buf *rbp;
	register int sps;

	rbp = bp;
	sps = PS->integ;
	spl6();
	rbp->av_back->av_forw = rbp->av_forw;
	rbp->av_forw->av_back = rbp->av_back;
	rbp->b_flags =| B_BUSY;
	bfreelist.b_wcount--;
	PS->integ = sps;
}

/*
 * Mark I/O complete on a buffer, release it if I/O is asynchronous,
 * and wake up anyone waiting for it.
 */
iodone(bp)
struct buf *bp;
{
	register struct buf *rbp;

	rbp = bp;
	rbp->b_flags =| B_DONE;
	if (rbp->b_flags&B_ASYNC)
		brelse(rbp);
	else {
		rbp->b_flags =& ~B_WANTED;
		wakeup(rbp);
	}
}

/*
 * Zero the core associated with a buffer.
 */
clrbuf(bp)
int *bp;
{
	register *p;
	register c;

	p = bp->b_addr;
	c = 256;
	do
		*p++ = 0;
	while (--c);
}







Jun 19 11:26 1978  bio.c Page 7



/*
 * Initialize the buffer I/O system by freeing
 * all buffers and setting all device buffer lists to empty.
 */
binit()
{
	register struct buf *bp;
	register struct devtab *dp;
	register int i;
	struct bdevsw *bdp;

	bfreelist.b_forw = bfreelist.b_back =
	    bfreelist.av_forw = bfreelist.av_back = &bfreelist;
	for (i=0; i<v.v_buf; i++) {
		bp = &buf[i];
		bp->b_dev = -1;
		bp->b_addr = buffers[i];
		bp->b_back = &bfreelist;
		bp->b_forw = bfreelist.b_forw;
		bfreelist.b_forw->b_back = bp;
		bfreelist.b_forw = bp;
		bp->b_flags = B_BUSY;
		bp->b_wcount = -256;
		brelse(bp);
	}
	for (i=0, bdp = bdevsw; i<bdevcnt; i++, bdp++) {
		dp = bdp->d_tab;
		if(dp) {
			dp->b_forw = dp;
			dp->b_back = dp;
		}
	}
}

/*
 * make sure all write-behind blocks on dev (or NODEV for all)
 * are flushed out.
 */
bflush(dev)
{
	register struct buf *bp;

loop:
	spl6();
	for (bp = bfreelist.av_forw; bp != &bfreelist; bp = bp->av_forw) {
		if (bp->b_flags&B_DELWRI && (dev == NODEV||dev==bp->b_dev)) {
			bp->b_flags =| B_ASYNC;
			notavail(bp);
			bwrite(bp);
			goto loop;
		}
	}
	spl0();
}








Jun 19 11:26 1978  bio.c Page 8


/*
 * Pick up the device's error number and pass it to the user;
 * if there is an error but the number is 0 set a generalized code.
 */
geterror(abp)
struct buf *abp;
{
	register struct buf *bp;

	bp = abp;
	if (bp->b_flags&B_ERROR)
		if ((u.u_error = bp->b_error)==0)
			u.u_error = EIO;
}

















































Jun 19 11:26 1978  cat.c Page 1


#
/*
 * DR11C driver used for C/A/T
 */

#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/tty.h"

extern cat_addr[], cat_cnt;

#define	CTPRI	9
#define	CTMAX	4
#define	CTHIWAT	80
#define	CTLOWAT	20

struct {
	struct	clist	cat_outq;
	int	cat_lock;
} cat[CTMAX];

struct {
	int	drcsr, drobuf, dribuf;
};

catopen(dev)
register dev;
{
	if (dev >= cat_cnt || dev >= CTMAX || cat[dev].cat_lock) {
		u.u_error = ENXIO;
		return;
	}
	cat[dev].cat_lock++;
	cat_addr[dev]->drcsr =| IENABLE;
}

catclose(dev)
{
	cat[dev].cat_lock = 0;
	catrint(dev);
}

catwrite(dev)
{
	register c, *cp;
	extern lbolt;

	cp = &cat[dev];
	while ((c=cpass()) >= 0) {
		spl5();
		while (cp->cat_outq.c_cc > CTHIWAT)
			sleep(cp, CTPRI);
		while (putc(c, &cp->cat_outq) < 0)
			sleep(&lbolt, CTPRI);
		catrint(dev);
		spl0();







Jun 19 11:26 1978  cat.c Page 2


	}
}

catrint(dev)
{
	register c, *cp, *dp;

	dp = cat_addr[dev];
	if (dp->drcsr&DONE) {
		cp = &cat[dev];
		if ((c = getc(&cp->cat_outq)) >= 0) {
			dp->drobuf = c;
			if (cp->cat_outq.c_cc==0 || cp->cat_outq.c_cc==CTLOWAT)
				wakeup(cp);
		} else if (cp->cat_lock==0)
			dp->drcsr = 0;
	}
}
catxint() {}












































Jun 19 11:26 1978  dh.c Page 1


#
/*
 *	DH11 & DM11-BB driver for multiple units
 */

#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/tty.h"

extern	dh_addr[], dh_cnt;
struct tty dh_tty[];
struct ttydma dh_ttydma[];
int	dhsar[8];

#define	BITS6	01
#define	BITS7	02
#define	BITS8	03
#define	TWOSB	04
#define	PENABLE	020
#define	OPAR	040
#define	HDUPLX	040000

#define	IENABLE	030100
#define	PERROR	010000
#define	FRERROR	020000
#define	XINT	0100000
#define	SSPEED	7	/* standard speed: 300 baud */

struct {
	int dhcsr, dhnxch, dhlpr, dhcar;
	int dhbcr, dhbar, dhbreak, dhsilo;
};

int	dm_addr[];

#define	DONE	0200
#define	SCENABL	040
#define	BSY	020
#define	TURNON	07	/* RTS, DTR, line enable */
#define	TURNOFF	1	/* line enable only */
#define	CARRIER	0140

struct {
	int	dmcsr, dmlstat;
};

dhopen(dev, flag)
{
	register struct tty *tp;
	extern dhstart();

	if (dev >= dh_cnt) {
		u.u_error = ENXIO;
		return;
	}
	tp = &dh_tty[dev];







Jun 19 11:26 1978  dh.c Page 2


	if ((tp->t_state&(ISOPEN|WOPEN)) == 0) {
		tp->t_addr = dhstart;
		tp->t_state = SSTART;
		tp->t_erase = CERASE;
		tp->t_kill = CKILL;
		tp->t_speeds = SSPEED | (SSPEED<<8);
		tp->t_flags = ODDP|EVENP|ECHO|HUPCL;
		dhparam(dev);
	}
	spl4();
	if (dmctl(dev, TURNON)&CARRIER)
		tp->t_state =| CARR_ON;
	while ((tp->t_state&CARR_ON)==0) {
		tp->t_state =| WOPEN;
		sleep(&tp->t_rawq, TTIPRI);
	}
	ttyopen(tp);
	spl0();
}

dhclose(dev)
{
	register struct tty *tp;

	tp = &dh_tty[dev];
	wflushtty(tp);
	if (tp->t_flags&HUPCL)
		dmctl(dev, TURNOFF);
	tp->t_state =& (CARR_ON|SSTART);
}

dhread(dev)
{
	ttread(&dh_tty[dev]);
}

dhwrite(dev)
{
	ttwrite(&dh_tty[dev]);
}

dhrint(dev)
{
	register struct tty *tp;
	register int c, *dhaddr;

	dhaddr = dh_addr[dev];
	while ((c = dhaddr->dhnxch) < 0) {	/* char. present */
		tp = &dh_tty[((c>>8)&017)|(dev<<4)];
		if (tp >= &dh_tty[dh_cnt])
			continue;
		if((tp->t_state&ISOPEN)==0) {
			wakeup(&tp->t_rawq);
			continue;
		}
		if (c&FRERROR)		/* break */







Jun 19 11:26 1978  dh.c Page 3


			if (tp->t_flags&RAW)
				c = 0;		/* null (for getty) */
			else
				c = 0177;	/* DEL (intr) */
		if (c&PERROR)
			if ((tp->t_flags&(EVENP|ODDP))==EVENP
			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
				continue;
		ttyinput(c, tp);
	}
}

dhsgtty(dev, av)
int *av;
{
	register struct tty *tp;

	tp = &dh_tty[dev];
	if (ttystty(tp, av))
		return;
	dhparam(dev);
}

/*
 * Set parameters from open or stty into the DH hardware
 * registers.
 */
dhparam(dev)
{
	register struct tty *tp;
	register int lpr, *dhaddr;

	tp = &dh_tty[dev];
	dhaddr = dh_addr[dev>>4];
	spl5();
	dhaddr->dhcsr =& ~017;
	dhaddr->dhcsr =| (dev&017) | IENABLE;
	if (tp->t_speeds.lobyte==0) {	/* Hang up line */
		dhaddr->dhbcr = 0;
		spl0();
		dmctl(dev, TURNOFF);
		return;
	}
	lpr = (tp->t_speeds.hibyte<<10) | (tp->t_speeds.lobyte<<6);
	if (tp->t_speeds.lobyte == 4)		/* 134.5 baud */
		lpr =| BITS6|PENABLE|HDUPLX;
	else if (tp->t_flags&RAW)
		lpr =| BITS8;
	else
		lpr =| BITS7|PENABLE;
	if ((tp->t_flags&EVENP)==0)
		lpr =| OPAR;
	if (tp->t_speeds.lobyte == 3)	/* 110 baud */
		lpr =| TWOSB;
	dhaddr->dhlpr = lpr;
	spl0();







Jun 19 11:26 1978  dh.c Page 4


}

/*
 * DH11 transmitter interrupt.
 * Restart each line which used to be active but has
 * terminated transmission since the last interrupt.
 */
dhxint(dev)
{
	register struct tty *tp;
	register ttybit, bar;
	int *dhaddr;

	dhaddr = dh_addr[dev];
	bar = dhsar[dev] & ~dhaddr->dhbar;
	dhaddr->dhcsr =& ~XINT;
	ttybit = 1;
	for (tp = &dh_tty[dev<<4]; bar; tp++) {
		if(bar&ttybit) {
			dhsar[dev] =& ~ttybit;
			bar =& ~ttybit;
			tp->t_state =& ~BUSY;
			dhstart(tp);
		}
		ttybit =<< 1;
	}
}

/*
 * Start (restart) transmission on the given DH11 line.
 */
dhstart(atp)
struct tty *atp;
{
	extern ttrstrt();
	register c, nch;
	register struct tty *tp;
	int sps, dev;
	char *cp;
	int line, *dhaddr;

	sps = PS->integ;
	spl5();
	tp = atp;
	dev = tp-dh_tty;
	/*
	 * If it's currently active, or delaying,
	 * no need to do anything.
	 */
	if (tp->t_state&(TIMEOUT|BUSY))
		goto out;
	/*
	 * t_char is a delay indicator which may have been
	 * left over from the last start.
	 * Arrange for the delay.
	 */







Jun 19 11:26 1978  dh.c Page 5


	if (c = tp->t_char) {
		tp->t_char = 0;
		timeout(ttrstrt, tp, (c&0177)+6);
		tp->t_state =| TIMEOUT;
		goto out;
	}
	cp = &dh_ttydma[dev];
	nch = 0;
	/*
	 * Copy TTYDMA characters, or up to a delay indicator,
	 * to the DMA area.
	 */
	while (nch > -(sizeof (struct ttydma)) && (c = getc(&tp->t_outq))>=0) {
		if (c >= 0200 && (tp->t_flags&RAW)==0) {
			tp->t_char = c;
			break;
		}
		*cp++ = c;
		nch--;
	}
	/*
	 * If the writer was sleeping on output overflow,
	 * wake him when low tide is reached.
	 */
	if (tp->t_outq.c_cc<=TTLOWAT && tp->t_state&ASLEEP) {
		tp->t_state =& ~ASLEEP;
		wakeup(&tp->t_outq);
	}
	/*
	 * If any characters were set up, start transmission;
	 * otherwise, check for possible delay.
	 */
	if (nch) {
		dhaddr = dh_addr[dev>>4];
		line = dev & 017;
		dhaddr->dhcsr.lobyte = line | IENABLE;
		dhaddr->dhcar = cp+nch;
		dhaddr->dhbcr = nch;
		c = 1<<line;
		dhaddr->dhbar =| c;
		dhsar[dev>>4] =| c;
		tp->t_state =| BUSY;
	} else if (c = tp->t_char) {
		tp->t_char = 0;
		timeout(ttrstrt, tp, (c&0177)+6);
		tp->t_state =| TIMEOUT;
	}
    out:
	PS->integ = sps;
}

/*
 * Dump control bits into the DM registers.
 */
dmctl(dev, bits)
register dev;







Jun 19 11:26 1978  dh.c Page 6


{
	register *dmaddr;

	dmaddr = dm_addr[dev>>4];
	dmaddr->dmcsr =& ~SCENABL;
	while(dmaddr->dmcsr&BSY);
	dmaddr->dmcsr = dev&017;
	dmaddr->dmlstat = bits;
	dev = dmaddr->dmlstat;
	dmaddr->dmcsr =| IENABLE|SCENABL;
	return(dev);
}

/*
 * DM11 interrupt.
 * Mainly, deal with carrier transitions.
 */
dmintr(dev)
{
	register struct tty *tp;
	register *dmaddr;

	dmaddr = dm_addr[dev];
	if (dmaddr->dmcsr&DONE) {
		tp = &dh_tty[(dmaddr->dmcsr&017)|(dev<<4)];
		if (tp < &dh_tty[dh_cnt]) {
			wakeup(&tp->t_rawq);
			if ((dmaddr->dmlstat&CARRIER)==0) {
				if ((tp->t_state&WOPEN)==0) {
					signal(tp->t_pgrp, SIGHUP);
					dmaddr->dmlstat = 0;
					flushtty(tp);
				}
				tp->t_state =& ~CARR_ON;
			} else
				tp->t_state =| CARR_ON;
		}
		dmaddr->dmcsr =& ~DONE;
	}
}























Jun 19 11:26 1978  dn.c Page 1


#
/*
 * DN-11 ACU interface
 */

#include "../hd/param.h"
#include "../hd/user.h"

struct {
	int	dn_reg[4];
};

extern	dn_addr[], dn_cnt;

#define	PWI	0100000
#define	ACR	040000
#define	DLO	010000
#define	DONE	0200
#define	IENABLE	0100
#define	DSS	040
#define	PND	020
#define	MENABLE	04
#define	DPR	02
#define	CRQ	01

#define	DNPRI	5

dnopen(dev)
register dev;
{
	register *dp;

	if (dev >= dn_cnt ||
	   (dp = dn_addr[dev>>2])->dn_reg[dev&03]&(PWI|DLO))
		u.u_error = ENXIO;
	else {
		*dp =| MENABLE;
		dp->dn_reg[dev&03] = IENABLE|MENABLE|CRQ;
	}
}

dnclose(dev)
{
	dn_addr[dev>>2]->dn_reg[dev&03] = MENABLE;
}

dnwrite(dev)
register dev;
{
	register c, *dp;
	extern lbolt;

	dp = &(dn_addr[dev>>2]->dn_reg[dev&03]);
	while ((*dp & (PWI|ACR|DSS)) == 0) {
		spl5();
		if ((*dp&DONE) == 0) {







Jun 19 11:26 1978  dn.c Page 2


			sleep(dn_addr[dev>>2], DNPRI);
		} else if (u.u_count == 0) {
			*dp = IENABLE|MENABLE|CRQ;
		} else if ((c=cpass()) == '-') {
			sleep(&lbolt, DNPRI);
			sleep(&lbolt, DNPRI);
		} else if (*dp&PND) {
			*dp = (c<<8)|IENABLE|MENABLE|DPR|CRQ;
		}
		spl0();
	}
	if (*dp&(PWI|ACR))
		u.u_error = EIO;
	*dp = MENABLE|CRQ;
}

dnintr(dev)
{
	wakeup(dn_addr[dev]);
}











































Jun 19 11:26 1978  dqs.c Page 1


#
/*
 * DQS11[AB] handler - IBM Bisync
 */

#define	DQS11
#include "../hd/param.h"
#include "../hd/buf.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/peri.h"

int dqstr[61];
extern dqs_addr[], dqs_cnt;

#define PRI 5

struct { int csr, bcr, bar, dbr; };

#define CSR dqs->addr->csr
#define BCR dqs->addr->bcr
#define BAR dqs->addr->bar
#define DBR dqs->addr->dbr

#define GO  01
#define RX  02
#define IE  0100
#define RDY 0200
#define DTR	0400
#define ERR 0177000

#define DLY dqs->dly

#define EOT dqs->eot
#define ENQ dqs->enq
#define NAK dqs->nak
#define ETB dqs->etb
#define ETX dqs->etx

#define TTD  dqs->ttd
#define ACK0 dqs->ack0
#define WACK dqs->wack
#define ACKX dqs->ackx

#define R0 1
#define R1 2
#define R2 3
#define R3 4
#define R4 5
#define R5 6
#define W0 7
#define W1 8
#define W2 9
#define W3 10

#define RT0 11







Jun 19 11:26 1978  dqs.c Page 2


#define RT1 12
#define RT2 13
#define RT3 14
#define RT4 15
#define RT5 16
#define WT0 17
#define WT1 18
#define WT2 19
#define WT3 20

#define TOUT 10

dqsopen(dev)
register dev;
{
	register struct dqsdat *dqs;
	int dqstout();
	if (dev>=NDQ || dev>=dqs_cnt || (dqs = &dqsx[dev])->open) {
		u.u_error = ENXIO;
		return;
	}
	dqs->addr = dqs_addr[dev];
	dqs->open=1; 
	dqs->time=0;
	timeout(dqstout,dqs,20);
}

dqsclose(dev)
{
	register struct dqsdat *dqs;
	dqs = &dqsx[dev];
	CSR = DTR;
	dqs->qcase=0;
	dqs->open=2;
	dqsfin();
	CSR = 0;
}

dqsread(dev)
{
	register struct dqsdat *dqs;
	register struct dqsbuf *b;
	register int c;
	dqs = &dqsx[dev];
	spl5();
	while (dqs->state<0) sleep(dqs,PRI);
	spl0();
	if (dqs->state==0) {
		dqs->q=0;
		dqs->resp=ACK0; 
		dqs->try=3;
		dqs->state++; 
		dqs->qcase=R0;
		dqsrecv(); 
		dqs->time=20;
		dqs->u=0;







Jun 19 11:26 1978  dqs.c Page 3


	}
	if (dqs->u==0) {
		dqs->uoff=0;
		spl5();
		while ((c=dqs->state)>0) {
			if ((dqs->u=dqsget(1))!=0) break;
			if (c==2 && dqs->x==0) {
				dqsbeg(); 
				spl5();
				if (dqs->qcase==R4) dqs->time=1;
				continue;
			}
			if (c>=3) {
				spl0(); 
				dqsfin(); 
				return;
			}
			dqsleep();
		}
		spl0();
		if (dqs->state<=0) return;
	}
	b=dqs->u;
	c=min(b->bufc,u.u_count);
	if (c&1 && c<u.u_count) {
		c++; 
		u.u_count++;
	}
	iomove(b->bufa,dqs->uoff,c,B_READ);
	dqs->uoff=+c;
	if ((b->bufc=- c)>0) return;
	b->bufl=0; 
	dqs->u=0;
	spl5();
	if (dqs->qcase==R4) dqs->time=1;
	spl0();
}

dqswrite(dev)
{
	register struct dqsdat *dqs;
	register struct dqsbuf *b;
	register int c;
	dqs = &dqsx[dev];
	spl5();
	while (dqs->state>0) sleep(dqs,PRI);
	if (u.u_count==0) {
		while ((c=dqs->state)<0 && c>(-5)) {
			if (c==(-2)) {
				dqs->state--;
				if (dqs->qcase==W2) dqs->time=1;
			}
			dqsleep();
		}
		goto N;
	}







Jun 19 11:26 1978  dqs.c Page 4


	spl0();
	if (dqs->state==0) {
		dqs->q=0;
		dqs->resp=ACK0; 
		dqs->try=3;
		dqs->state--; 
		dqs->qcase=W0;
		dqspoke(ENQ);
	}
	spl5();
	while ((c=dqs->state)<0 && c>(-5)) {
		if ((b=dqsget(0))!=0) break;
		if (c==(-2) && dqs->x==0) {
			dqsbeg(); 
			spl5(); 
			continue;
		}
		dqsleep();
	}
N: 
	spl0();
	if ((c=dqs->state)<=(-5)) {
		if (c==(-5)) u.u_error=EIO;
		dqsfin(); 
		return;
	}
	if (dqs->state>=0) return;
	b->bufc=c=min(512,u.u_count);
	if (c&1) {
		c++; 
		u.u_count++;
	}
	iomove(b->bufa,0,c,B_WRITE);
	b->bufl=1;
	spl5();
	if (dqs->qcase==W2) dqs->time=1;
	spl0();
}

dqsgo(reg)
struct dqsreg *reg;
{
	reg->csr=IE|GO;
}

dqsintr(dev)
{
	int erf;
	register struct dqsdat *dqs;
	register struct dqsbuf *b;
	register int tmp;
	struct {
		int *ip;
	};
	struct {
		char *bp;







Jun 19 11:26 1978  dqs.c Page 5


	};
	dqs = &dqsx[dev];
	tmp = &dqstr[dqstr[0]+1];
	*tmp.bp++=dev;
	*tmp.bp++=time.loword;
	*tmp.bp++=dqs->state;
	*tmp.bp++=dqs->qcase;
	*tmp.ip++=CSR;
	*tmp.ip++=BCR;
	*tmp.ip++=BAR;
	*tmp.ip++=DBR;
	tmp=tmp.ip-(dqstr+1);
	if (tmp>54) tmp=0;
	dqstr[0]=tmp;
	erf=CSR&ERR;
	CSR=0; 
	dqs->time=0;
	switch (dqs->qcase) {
	case R0:
		tmp=dqs->cc;
		if (erf) tmp=0;
		if (tmp.lobyte==EOT) goto reot;
		if (tmp.lobyte==ENQ) {
			if (dqs->state==1) {
				dqs->state++; 
				dqswake(); 
				dqs->try=7;
			}
			goto rack;
		}
		dqs->qcase=R1; 
		goto rnak;
	case R1: 
	case RT1:
		dqs->qcase=R0; 
		dqsrecv(); 
		break;
	case R2: 
	case RT2:
		dqs->qcase=R3;
		tmp=dqs->addr;
		tmp->bcr=(-512);
		tmp->bar=dqs->q->bufb;
		tmp->csr=IE|RX|GO;
		dqs->time=40; 
		break;
	case R3:
		dqs->qcase=R2;
		if (erf) goto rnak;
		b=dqs->q;
		tmp=(*(b->bufb));
		if (tmp.lobyte==EOT) goto reot;
		if (tmp.lobyte==ENQ) goto rack;
		b->bufc=(BAR-(b->bufb));
		b->bufc--; 
		tmp=DBR;







Jun 19 11:26 1978  dqs.c Page 6


		if (tmp.lobyte==ENQ) goto rnak;
		if (tmp.lobyte!=ETB && tmp.lobyte!=ETX) {
			b->bufc++; 
			tmp=>>8;
			if (tmp.lobyte!=ETB && tmp.lobyte!=ETX) goto rnak;
		}
		b->bufl=1; 
		dqs->q=0;
		dqswake();
		dqs->resp=ACKX-dqs->resp;
		dqs->try=7;
rack: 
		if (--dqs->try<0) goto rabt;
	case R4: 
	case RT4:
		if (dqs->q==0 && (dqs->q=dqsget(0))==0) {
			if (dqs->qcase==RT4) {
				dqs->try++; 
				dqs->qcase=R1; 
				dqspoke(WACK); 
				break;
			}
			dqs->qcase=R4; 
			dqs->time=7; 
			break;
		}
		dqs->qcase=R2; 
		dqspoke(dqs->resp); 
		break;
rnak: 
		if (--dqs->try<=0) goto rabt;
		dqspoke(NAK); 
		break;
	case RT0: 
	case RT3:
rabt: 
		if (dqs->state==1) goto reot;
		dqs->qcase=R5; 
		dqspoke(EOT); 
		break;
	case R5: 
	case RT5:
reot: 
		dqs->state=3; 
		dqswake(); 
		dqs->qcase=0; 
		break;
	case W0: 
	case WT0:
		dqs->qcase=W1; 
		dqsrecv(); 
		break;
	case WT1:
		erf++;
	case W1:
		tmp=dqs->cc;







Jun 19 11:26 1978  dqs.c Page 7


		if (erf) tmp=0;
		if (tmp!=dqs->resp) goto wnot;
		if (dqs->state==(-1)) dqs->state--;
		if (b=dqs->q) {
			b->bufl=0; 
			dqs->q=0;
		}
		dqswake();
		dqs->resp=ACKX-dqs->resp;
		dqs->try=7;
	case W2: 
	case WT2:
wsnd: 
		if (dqs->q==0 && (dqs->q=dqsget(1))==0) {
			if (dqs->state==(-3)) goto weot;
			if (dqs->qcase==WT2) {
				dqs->try++; 
				dqs->qcase=W0; 
				dqspoke(TTD); 
				break;
			}
			dqs->qcase=W2; 
			dqs->time=7; 
			break;
		}
		b=dqs->q;
		dqs->qcase=W0;
		tmp=dqs->addr;
		tmp->bcr=(-b->bufc);
		tmp->bar=b->bufb;
		dqs->time=7+DLY;
		if (DLY==0) tmp->csr=IE|GO;
		else timeout(dqsgo,tmp,DLY);
		break;
wnot: 
		if (--dqs->try<=0) goto wabt;
		if (tmp.lobyte==ENQ || tmp.lobyte==EOT) goto wabt;
		if (tmp.lobyte==NAK) {
			if (dqs->state==(-1)) goto wabt; 
			goto wsnd;
		}
		dqs->qcase=W0; 
		dqspoke(ENQ); 
		break;
wabt: 
		if (dqs->state!=(-1)) dqs->state=(-4);
		else if (tmp.lobyte==ENQ) goto wend;
weot: 
		dqs->qcase=W3; 
		dqspoke(EOT); 
		break;
	case W3: 
	case WT3:
wend: 
		dqs->state=(dqs->state>(-4)? -6:-5);
		dqswake(); 







Jun 19 11:26 1978  dqs.c Page 8


		dqs->qcase=0; 
		break;
	}
}

dqstout(ptr)
struct dqsdat *ptr;
{
	register struct dqsdat *dqs;
	dqs=ptr;
	if (dqs->open!=1) {
		dqs->open=0; 
		return;
	}
	if (dqs->time>0 && --dqs->time==0) {
		CSR=0; 
		dqs->qcase=+TOUT; 
		dqsintr(dqs-dqsx);
	}
	timeout(dqstout,dqs,20);
}


/* dqs passed in register beyond this point */

dqsrecv()
{
	register struct dqsdat *dqs;
	register int *reg;
	reg=dqs->addr;
	reg->bcr=(-2);
	reg->bar=(&dqs->cc);
	reg->csr=IE|RX|GO;
	dqs->time=11;
}

dqspoke(code)
{
	register struct dqsdat *dqs;
	register int *reg,tmp;
	reg=dqs->addr;
	tmp=code; 
	dqs->cc=tmp;
	reg->bcr=(tmp==tmp.lobyte? -1:-2);
	reg->bar=(&dqs->cc);
	dqs->time=2+DLY;
	if (DLY==0) reg->csr=IE|GO;
	else timeout(dqsgo,reg,DLY);
}

dqsleep()
{
	register struct dqsdat *dqs;
	dqs->slp=1; 
	sleep(dqs->addr,PRI);
}







Jun 19 11:26 1978  dqs.c Page 9



dqswake()
{
	register struct dqsdat *dqs;
	if (dqs->slp) wakeup(dqs->addr);
	dqs->slp=0;
}

dqsbeg()
{
	register struct dqsdat *dqs;
	register struct dqsbuf *b;
	register int i;
	dqs->x=dqs;
	b=(&dqs->bf[NBF-1]);
	for (i=0;i<NBF;i++) {
		b=b->bufn=(&dqs->bf[i]); 
		b->bufl=0;
		b->bufb=(b->bufa=getblk(NODEV))->b_addr;
	}
	dqs->x=b;
}

dqsget(flag)
{
	register struct dqsdat *dqs;
	register struct dqsbuf *b;
	if ((b=dqs->x)<=dqs) return (0);
	if (flag!=0) {
		if (b->bufl!=1) return (0);
		dqs->x=b->bufn; 
		goto P;
	}
	while (b->bufl!=0) {
		b=b->bufn; 
		if (b==dqs->x) return (0);
	}
P: 
	b->bufl=2; 
	return (b);
}

dqsfin()
{
	register struct dqsdat *dqs;
	register struct dqsbuf *b;
	if ((b=dqs->x)==dqs) return;
	if (b!=0) {
		do {
			brelse(b->bufa); 
			b=b->bufn;
		} 
		while (b!=dqs->x);
	}
	dqs->x=0;
	dqs->state=0;







Jun 19 11:26 1978  dqs.c Page 10


	wakeup(dqs);
}





























































Jun 19 11:26 1978  du.c Page 1


#
/*
 * DU-11 Synchronous interface driver
 */

#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/buf.h"
#include "../hd/peri.h"

/* device registers */
struct {
	int	rxcsr, rxdbuf;
	int	txcsr, txdbuf;
};

extern	du_addr[], du_cnt;

#define	DONE	0200
#define	IE	0100
#define	SIE	040
#define CTS	020000
#define	CARRIER	010000
#define	RCVACT	04000
#define	DSR	01000
#define STRIP	0400
#define SCH	020
#define RTS	04
#define	DTR	02
#define MR	0400
#define SEND	020
#define	HALF	010

#define	READ	0
#define	WRITE	1
#define PWRIT	2

#define	DUPRI	5

duopen(dev)
{
	register struct du *dp;
	register *lp;

	if (dev >= du_cnt ||
	   ((dp = &du_du[dev])->du_proc!=0 && dp->du_proc!=u.u_procp)) {
		u.u_error = ENXIO;
		return;
	}
	dp->du_proc = u.u_procp;
	lp = du_addr[dev];
	lp->txcsr = MR;
	lp->rxdbuf = 035026;
	if (dp->du_buf==0) {
		dp->du_buf = getblk(NODEV);
		dp->du_bufb = dp->du_buf->b_addr;







Jun 19 11:26 1978  du.c Page 2


		dp->du_bufe = dp->du_bufb+512;
		dp->du_state = WRITE;
		duturn(dev);
	}
}

duclose(dev)
{
	register struct du *dp;
	register *lp;

	dp = &du_du[dev];
	lp = du_addr[dev];
	lp->rxcsr = 0;
	lp->txcsr = 0;
	dp->du_proc = 0;
	if (dp->du_buf != 0) {
		brelse(dp->du_buf);
		dp->du_buf = 0;
	}
}

duread(dev)
{
	register char *bp;
	register struct du *dp;
	register n;
	int	flag;

	dp = &du_du[dev];
	bp = dp->du_bufb;
	flag = 0;
	for(;;) {
		if(duwait(dev))
			return;
		spl5();
		if (n = dp->du_nleft) {
			dp->du_nleft = 0;
			spl0();
			flag++;
			while (n--) {
				if (passc(*bp++)<0)
					break;
				if (bp == dp->du_bufe)
					bp = dp->du_bufb;
			}
		} else {
			if ( flag) {
				spl0();
				break;
			}
			sleep(dp, DUPRI);
			spl0();
		}
	}
	dp->du_bufp = dp->du_bufb;







Jun 19 11:26 1978  du.c Page 3


}

duwrite(dev)
{
	register struct du *dp;
	register char *bp,*ep;
	int	n, *lp;

	dp = &du_du[dev];
	lp = du_addr[dev];
	if (u.u_count==0 ||duwait(dev))
		return;
	dp->du_bufp = ep = bp = dp->du_bufb;
	dp->du_state = PWRIT;
	lp->rxcsr =& ~SCH;
	lp->rxcsr = SIE|RTS|DTR;
	n = 0;
	while (u.u_count!=0) {
		*bp++ = cpass();
		n++;
		if (bp==dp->du_bufe)
			bp = dp->du_bufb;
		if (bp==ep) {
			duset(dev, n);
			if (u.u_count!=0) {
				spl5();
				sleep(dp,DUPRI);
				spl0();
			} else
				return;
			ep = dp->du_bufp;
			n = 0;
		}
	}
	duset(dev, n);
}

duwait(dev)
{
	register struct du *dp;
	register *lp;

	dp = &du_du[dev];
	lp = du_addr[dev];
	for(;;) {
		if ((lp->rxcsr&DSR)==0 || dp->du_buf==0) {
			u.u_error = EIO;
			return(1);
		}
		spl5();
		if (dp->du_state==READ &&
			((lp->rxcsr&RCVACT)==0 || dp->du_nleft)) {
			spl0();
			return(0);
		}
		sleep(dp, DUPRI);







Jun 19 11:26 1978  du.c Page 4


		spl0();
	}
}

dustart(dev)
{
	register struct du *dp;
	register *lp

	dp = &du_du[dev];
	lp = du_addr[dev];
	if (dp->du_nleft > 0) {
		if (--dp->du_nleft==200)
			wakeup(dp);
		lp->txdbuf = *dp->du_bufp++;
		if (dp->du_bufp==dp->du_bufe)
			dp->du_bufp = dp->du_bufb;
	} else {
		duturn(dev);
	}
}

duset(dev, an)
{
	register struct du *dp;
	register *lp;

	dp = &du_du[dev];
	lp = du_addr[dev];
	spl5();
	while((lp->rxcsr&CTS)==0)
		sleep(dp,DUPRI);
	dp->du_nleft =+ an;
	if (dp->du_state != WRITE) {
		dp->du_state = WRITE;
		lp->txcsr = IE|SIE|SEND|HALF;
		dustart(dev);
	}
	spl0();
}

durint(dev)
{
	register struct du *dp;
	register c, s;
	int	dustat, *lp;

	dp = &du_du[dev];
	lp = du_addr[dev];
	dustat = lp->rxcsr;
	if(dustat<0) {
		if((dustat&CARRIER)==0 && dp->du_state==READ)
			duturn(dev); else
			wakeup(dp);
	} else
	if(dustat&DONE) {







Jun 19 11:26 1978  du.c Page 5


		lp->rxcsr = IE|SIE|SCH|DTR;
		c = s = lp->rxdbuf;
		c =& 0177;
		if(s<0)
			c =| 0200;
		if (++dp->du_nleft==384)
			wakeup(dp);
		if (dp->du_bufp == dp->du_bufe)
			dp->du_bufp = dp->du_bufb;
		*dp->du_bufp++ = c;
		if (c == 0377) duturn(dev);
	}
}

duxint(dev)
{
	register struct du *dp;
	register *lp;
	register int dustat;

	dp = &du_du[dev];
	lp = du_addr[dev];
	dustat = lp->txcsr;
	if(dustat<0)
		duturn(dev); else
	if(dustat&DONE)
		dustart(dev);
}

duturn(dev)
{
	register struct du *dp;
	register *lp;

	dp = &du_du[dev];
	lp = du_addr[dev];
	if (dp->du_state!=READ) {
		dp->du_state = READ;
		dp->du_bufp = dp->du_bufb;
		dp->du_nleft = 0;
	}
	lp->txcsr = HALF;
	lp->rxcsr =& ~SCH;
	lp->rxcsr = STRIP|IE|SIE|SCH|DTR;
	wakeup(dp);
}

















Jun 19 11:26 1978  hp.c Page 1


#
/*
 * RJP04, RWP04 driver
 */

#include "../hd/param.h"
#include "../hd/buf.h"
#include "../hd/user.h"

struct {
	int	hpcs1, hpwc, hpba, hpda;	
	int	hpcs2, hpds, hper1, hpas;	
	int	hpla, hpdb, hpmr, hpdt;	
	int	hpsn, hpof, hpdc, hpcc;	
	int	hper2, hper3, hpec1, hpec2;	
	int	hpbae, hpcs3;	
};

int	hp_addr, hp_cnt;

struct {
	unsigned nblocks;
	int	cyloff;
} hp_sizes[8];

struct	devtab	hptab;
struct	devtab	hputab[8];
struct	buf	hpbuf;
char	hpstatus[8];
int	hpsioc[8], hpsios[8];

#define	GO	01
#define	UNLOAD	02
#define RECAL	06
#define DCLR	010
#define	RELEASE	012
#define	PRESET	020
#define	SEARCH	030

#define	ERR	040000	/* hpds - Error */
#define PIP	020000
#define	MOL	010000	/* hpds - Medium online */
#define	DRY	0200	/* hpds - drive ready */
#define VV	0100	/* hpds - volume valid */
#define SC	0100000	/* hpcs1 - Special condition */
#define	TRE	040000	/* hpcs1 - transfer error */
#define DVA	04000	/* hpcs1 - drive available */
#define	IE	0100	/* hpcs1 - interrupt enable */
#define	WLE	04000	/* hper1 - Write lock error */
#define FMT22	010000	/* hpof - 16 bit /word format */
#define	ECI	04000	/* hpof - ecc inhibit */
/*
 * Use av_back to save track+sector,
 * b_resid for cylinder.
 */








Jun 19 11:26 1978  hp.c Page 2


#define	trksec	av_back
#define	cylin	b_resid

hpopen(dev)
{
	if (((dev>>3)&037)>hp_cnt)
		u.u_error = ENXIO;
}

hpclose(dev)
{
}

hpstrategy(abp)
struct buf *abp;
{
	register struct buf *bp;
	register char *p1, *p2;
	struct devtab *dp;
	int	unit;

	bp = abp;
	p1 = &hp_sizes[minor(bp->b_dev)&07];
	unit = minor(bp->b_dev)>>3;
	if (hpstatus[unit] || bp->b_blkno >= p1->nblocks) {
		if (bp->b_blkno == p1->nblocks && bp->b_flags&B_READ)
			bp->b_resid = 512;
		else {
			bp->b_flags =| B_ERROR;
			bp->b_error = ENXIO;
		}
		iodone(bp);
		return;
	}
	bp->av_forw = 0;
	bp->cylin = p1->cyloff;
	p1 = bp->b_blkno;
	p2 = lrem(p1, 22);
	p1 = ldiv(p1, 22);
	bp->trksec = (p1%19)<<8 | p2;
	bp->cylin =+ p1/19;
	spl5();
	dp = &hputab[unit];
	hpsioc[unit]++;
	if ((p1 = dp->d_actf)==0)
		dp->d_actf = bp;
	else {
		for (; p2 = p1->av_forw; p1 = p2) {
			if (p1->cylin <= bp->cylin
			 && bp->cylin <  p2->cylin
			 || p1->cylin >= bp->cylin
			 && bp->cylin >  p2->cylin) 
				break;
		}
		bp->av_forw = p2;
		p1->av_forw = bp;







Jun 19 11:26 1978  hp.c Page 3


	}
	if (dp->d_active==0) {
		hpustart(unit);
		if (hptab.d_active==0)
			hpstart();
	}
	spl0();
}

hpustart(unit)
{
	register struct buf *bp;
	register struct devtab *dp;
	register *rp;
	int	search;

	dp = &hputab[unit];
	rp = hp_addr;
	rp->hpcs2 = unit;
	rp->hpcs1.lobyte = IE;
	rp->hpas = 1<<unit;
	if ((rp->hpcs1&DVA)==0) {
	/* either NED or dual-port not avail */
		goto abort;
	}
	if (rp->hpds&ERR) {
		printf("RP04 drive %d errors: %o %o %o\n",
			unit, rp->hper1, rp->hper2, rp->hper3);
		rp->hpcs1.lobyte = IE|DCLR|GO;
		if (rp->hpds&ERR || ++dp->d_errcnt > 16)
			goto abort;
	}
	if ((rp->hpds&MOL)==0)
		goto abort;
	hpstatus[unit] = 0;
	if ((bp = dp->d_actf)==0)
		return;
	if ((rp->hpds&VV) == 0) {
		rp->hpcs1.lobyte = IE|PRESET|GO;
		rp->hpof = FMT22|ECI;
	}
	dp->d_active++;
	rp->hpdc = bp->cylin;
	search = bp->trksec.lobyte-(rp->hpla>>6)-1;
	if (search<0) search =+ 22;
	if ((bp->cylin!=rp->hpcc || search>6) &&
	    dp->d_active<3) {
		search = bp->trksec;
		search.lobyte =- 4;
		if (search.lobyte<0) search.lobyte =+ 22;
		hpsios[unit]++;
		rp->hpda = search;
		rp->hpcs1.lobyte = IE|SEARCH|GO;
	} else {
		dp->b_forw = 0;
		if (hptab.d_actf == 0)







Jun 19 11:26 1978  hp.c Page 4


			hptab.d_actf = dp; else
			hptab.d_actl->b_forw = dp;
		hptab.d_actl = dp;
	}
	return;
    abort:
	rp->hpas = 1<<unit;
	if (hpstatus[unit])
		return;
	hpstatus[unit] = 1;
	while(bp = dp->d_actf) {
		bp->b_flags =| B_ERROR;
		dp->d_actf = bp->av_forw;
		iodone(bp);
	}
	dp->d_active = 0;
	dp->d_errcnt = 0;
	printf("RP04 drive %d offline\n",unit);
}

hpstart()
{
	register struct buf *bp;
	register struct devtab *dp;
	register *rp;

    loop:
	if ((dp = hptab.d_actf) == 0)
		return;
	if ((bp = dp->d_actf) == 0) {
		hptab.d_actf = dp->b_forw;
		goto loop;
	}
	rp = hp_addr;
	rp->hpcs2 = minor(bp->b_dev) >> 3;
	hptab.d_active++;
	rp->hpdc = bp->cylin;
	rhstart(bp, &rp->hpda, bp->trksec, &rp->hpbae);
}

hpintr()
{
	register struct buf *bp;
	register unit;
	register *rp;
	struct devtab *dp;
	int as;

	rp = hp_addr;
	as = rp->hpas&0377;
	if (hptab.d_active) {	/* data transfer underway */
		dp = hptab.d_actf;
		bp = dp->d_actf;
		unit = minor(bp->b_dev)>>3;
		rp->hpcs2.lobyte = unit;
		if (rp->hpcs1 & TRE) {		/* error bit */







Jun 19 11:26 1978  hp.c Page 5


			while ((rp->hpds&DRY)==0);
			if (++hptab.d_errcnt>16 || rp->hper1&WLE)
				bp->b_flags =| B_ERROR; else
				hptab.d_active = 0;
			if (hptab.d_errcnt > 3)
				deverror(bp, rp->hper1, rp->hpcs2);
			rp->hpcs1 = TRE|IE|DCLR|GO;
			if ((hptab.d_errcnt&07)==04) {	/* 4,12 */
				rp->hpcs1 = IE|RECAL|GO;
				while ((rp->hpds&PIP));
			}
		}
		if (hptab.d_active) {
			hptab.d_active = 0;
			hptab.d_errcnt = 0;
			hptab.d_actf = dp->b_forw;
			dp->d_active = 0;
			dp->d_errcnt = 0;
			dp->d_actf = bp->av_forw;
			bp->b_resid = (-rp->hpwc)<<1;
			iodone(bp);
			rp->hpcs1 = IE|RELEASE|GO;
			if (dp->d_actf)
				hpustart(unit);
		}
		as =& ~(1<<unit);
	} else {
		if (as==0)
			rp->hpcs1 = IE;
		rp->hpcs1.hibyte = TRE>>8;
	}
	for (unit=0; as; unit++)
		if (as&(1<<unit)) {
			as =& ~(1<<unit);
			hpustart(unit);
		}
	hpstart();
}

hpread(dev)
{
	if (physck(hp_sizes[dev&07].nblocks, B_READ))
		physio(hpstrategy, &hpbuf, dev, B_READ);
}

hpwrite(dev)
{
	if (physck(hp_sizes[dev&07].nblocks, B_WRITE))
		physio(hpstrategy, &hpbuf, dev, B_WRITE);
}













Jun 19 11:26 1978  hs.c Page 1


#
/*
 * RS03/04 disk driver
 */

#include "../hd/param.h"
#include "../hd/buf.h"
#include "../hd/user.h"

struct {
	int	hscs1, hswc, hdba, hsda;
	int	hscs2, hsds, hser, hsas;
	int	hsla, hsdb, hsmr, hsdt;
	int	hsbae, hscs3;
};

struct	devtab	hstab;
struct	buf	rhsbuf;

int	hs_addr, hs_cnt;

#define ERR	040000	/* hscs1 - composite error */

#define GO	01
#define RCLR	010
#define	DRY	0200	/* hsds - Drive Ready */

hsopen(dev)
{
}

hsclose(dev)
{
}

hsstrategy(abp)
struct buf *abp;
{
	register struct buf *bp;
	register mblks;

	bp = abp;
	if(bp->b_dev&010)
		mblks = 2048; /* RS04 */
	else	mblks = 1024; /* RS03 */
	if(bp->b_blkno >= mblks) {
		if (bp->b_blkno == mblks && bp->b_flags&B_READ)
			bp->b_resid = 512;
		else {
			bp->b_flags =| B_ERROR;
			bp->b_error = ENXIO;
		}
		iodone(bp);
		return;
	}
	bp->av_forw = 0;







Jun 19 11:26 1978  hs.c Page 2


	spl5();
	if (hstab.d_actf==0)
		hstab.d_actf = bp; else
		hstab.d_actl->av_forw = bp;
	hstab.d_actl = bp;
	if (hstab.d_active==0)
		hsstart();
	spl0();
}

hsstart()
{
	register struct buf *bp;
	register *rp;
	register addr;

	if ((bp = hstab.d_actf) == 0)
		return;
	hstab.d_active++;
	rp = hs_addr;
	addr = bp->b_blkno<<1;
	if ((bp->b_dev&010) == 0)
		addr =<< 1;
	rp->hscs2 = bp->b_dev & 07;
	rhstart(bp, &rp->hsda, addr, &rp->hsbae);
}

hsintr()
{
	register struct buf *bp;
	register *rp;

	if (hstab.d_active == 0)
		return;
	bp = hstab.d_actf;
	rp = hs_addr;
	hstab.d_active = 0;
	if(rp->hscs1 & ERR){	/* error bit */
		deverror(bp, rp->hscs2, 0);
		rp->hscs1 = RCLR|GO;
		if (++hstab.d_errcnt <= 10) {
			hsstart();
			return;
		}
		bp->b_flags =| B_ERROR;
	}
	hstab.d_errcnt = 0;
	hstab.d_actf = bp->av_forw;
	bp->b_resid = (-rp->hswc)<<1;
	iodone(bp);
	hsstart();
}

hsread(dev)
{
	if (physck((dev&010) ? 2048 : 1024, B_READ))







Jun 19 11:26 1978  hs.c Page 3


		physio(hsstrategy, &rhsbuf, dev, B_READ);
}

hswrite(dev)
{
	if (physck((dev&010) ? 2048 : 1024, B_WRITE))
		physio(hsstrategy, &rhsbuf, dev, B_WRITE);
}























































Jun 19 11:26 1978  ht.c Page 1


#
/*
 * TJU16, TWU16 driver
 * Handles one TM02 controller, up to 4 TU16 slave transports
 * minor device classes:
 * bits 0,1: slave select
 * bit 2 off: rewind on close; on: position after first TM
 * bit 3 off: 800 bpi; on: 1600 bpi
 */

#include "../hd/param.h"
#include "../hd/buf.h"
#include "../hd/user.h"

#define NUNIT 4

struct {
	int	htcs1, htwc, htba, htfc;
	int	htcs2, htds, hter, htas;
	int	htck, htdb, htmr, htdt;
	int	htsn, httc, htbae, htcs3;
};

struct	devtab	httab;
struct	buf	rhtbuf, chtbuf;

char	h_openf[NUNIT];
int	h_den[NUNIT];
char	*h_blkno[NUNIT], *h_nxrec[NUNIT];

int	ht_addr;

#define	GO	01
#define	NOP	0
#define	WEOF	026
#define	SFORW	030
#define	SREV	032
#define	ERASE	024
#define	REW	06
#define	DCLR	010
#define P800	01300		/* 800 + pdp11 mode */
#define	P1600	02300		/* 1600 + pdp11 mode */
#define	IENABLE	0100
#define	RDY	0200
#define	TM	04
#define	DRY	0200
#define EOT	02000
#define CS	02000
#define COR	0100000
#define PES	040
#define WRL	04000
#define MOL	010000
#define ERR	040000
#define FCE	01000
#define	TRE	040000
#define HARD	064023	/* UNS|OPI|NEF|FMT|RMR|ILR|ILF */







Jun 19 11:26 1978  ht.c Page 2



#define	SIO	1
#define	SSFOR	2
#define SSREV	3
#define SRETRY	4
#define SCOM	5
#define SOK	6

htopen(dev, flag)
{
	register unit, ds;

	unit = dev&03;
	if (unit >= NUNIT || h_openf[unit]) {
		u.u_error = ENXIO;
		return;
	}
	h_den[unit] = (dev&010 ? P1600 : P800)|unit;
	h_blkno[unit] = 0;
	h_nxrec[unit] = -1;
	ds = hcommand(unit, NOP);
	if ((ds&MOL)==0 || (flag && (ds&WRL)))
		u.u_error = ENXIO;
	if (u.u_error==0)
		h_openf[unit]++;
}

htclose(dev, flag)
{
	register unit;
	register struct buf *bp;
	register struct devtab *dp;

	unit = dev&03;
	if (flag) {
		hcommand(unit, WEOF);
		hcommand(unit, WEOF);
	}
	if (dev&04) {
		if (flag)
			hcommand(unit, SREV); else
			{
				hcommand(unit, NOP);
				if (h_blkno[unit] < h_nxrec[unit])
					hcommand(unit, SFORW);
			}
	} else
		hcommand(unit, REW);
	dp = &httab;
	for (bp=dp->b_forw; bp!=dp; bp=bp->b_forw)
		if ((bp->b_dev&03)==unit)
			bp->b_dev =| 0100;
	h_openf[unit] = 0;
}

hcommand(unit, com)







Jun 19 11:26 1978  ht.c Page 3


{
	register struct buf *bp;
	register *rp;

	bp = &chtbuf;
	rp = ht_addr;
	spl5();
	while(bp->b_flags&B_BUSY) {
		bp->b_flags =| B_WANTED;
		sleep(bp, PRIBIO);
	}
	spl0();
	bp->b_dev = unit;
	bp->b_resid = com;
	bp->b_blkno = 0;
	bp->b_flags = B_BUSY|B_READ;
	htstrategy(bp);
	iowait(bp);
	if(bp->b_flags&B_WANTED)
		wakeup(bp);
	bp->b_flags = 0;
	return(bp->b_resid);
}

htstrategy(bp)
register struct buf *bp;
{
	register char **p;

	if (bp != &chtbuf) {
		p = &h_nxrec[bp->b_dev&03];
		if (bp->b_blkno > *p) {
			bp->b_flags =| B_ERROR;
			bp->b_error = ENXIO;
			iodone(bp);
			return;
		}
		if (bp->b_blkno == *p && bp->b_flags&B_READ) {
			bp->b_resid = 512;
			clrbuf(bp);
			iodone(bp);
			return;
		}
		if ((bp->b_flags&B_READ)==0)
			*p = bp->b_blkno + 1;
	}
	bp->av_forw = 0;
	spl5();
	if (httab.d_actf==0)
		httab.d_actf = bp;
	else
		httab.d_actl->av_forw = bp;
	httab.d_actl = bp;
	if (httab.d_active==0)
		htstart();
	spl0();







Jun 19 11:26 1978  ht.c Page 4


}

htstart()
{
	register struct buf *bp;
	register int unit;
	register *rp;
	char *blkno;

	rp = ht_addr;
    loop:
	if ((bp = httab.d_actf) == 0)
		return;
	unit = bp->b_dev&03;
	rp->htcs2 = 0;
	if((rp->httc&03777)!=h_den[unit])
		rp->httc = h_den[unit];
	blkno = h_blkno[unit];
	if (bp == &chtbuf) {
		if (bp->b_resid==NOP) {
			bp->b_resid = rp->htds;
			goto next;
		}
		httab.d_active = SCOM;
		rp->htfc = 0;
		rp->htcs1 = bp->b_resid|IENABLE|GO;
		return;
	}
	if (h_openf[unit] < 0 || bp->b_blkno > h_nxrec[unit])
		goto abort;
	if (blkno == bp->b_blkno) {
		httab.d_active = SIO;
		rhstart(bp, &rp->htfc, bp->b_wcount<<1, &rp->htbae);
	} else {
		if (blkno < bp->b_blkno) {
			httab.d_active = SSFOR;
			rp->htfc = blkno - bp->b_blkno;
			rp->htcs1 = SFORW|IENABLE|GO;
		} else {
			httab.d_active = SSREV;
			rp->htfc = bp->b_blkno - blkno;
			rp->htcs1 = SREV|IENABLE|GO;
		}
	}
	return;
    abort:
	bp->b_flags =| B_ERROR;
    next:
	httab.d_actf = bp->av_forw;
	iodone(bp);
	goto loop;
}

htintr()
{
	register struct buf *bp;







Jun 19 11:26 1978  ht.c Page 5


	register int unit;
	register *rp;
	int	err, state;

	if ((bp = httab.d_actf)==0)
		return;
	rp = ht_addr;
	unit = bp->b_dev&03;
	state = httab.d_active;
	httab.d_active = 0;
	if (rp->htcs1&TRE) {
		err = rp->hter;
		if (rp->htcs2.hibyte>0 || err&HARD)
			state = 0;
		if (bp == &rhtbuf)
			err =& ~FCE;
		if ((bp->b_flags&B_READ) && (rp->htds&PES))
			err =& ~(CS|COR);
		if (rp->htds&EOT || (rp->htds&MOL)==0)
			h_openf[unit] = -1;
		else if (rp->htds&TM) {
			rp->htwc = bp->b_wcount;
			h_nxrec[unit] = bp->b_blkno;
			state = SOK;
		}
		else if (state && err == 0)
			state = SOK;
		if (httab.d_errcnt > 4)
			deverror(bp, rp->hter, rp->htcs2);
		rp->htcs1 = TRE|DCLR|GO;
		if (state==SIO && ++httab.d_errcnt < 10) {
			httab.d_active = SRETRY;
			h_blkno[unit]++;
			rp->htfc = -1;
			rp->htcs1 = SREV|IENABLE|GO;
			return;
		}
		if (state!=SOK) {
			bp->b_flags =| B_ERROR;
			state = SIO;
		}
	} else if (rp->htcs1 < 0) {	/* SC */
		if (rp->htds&ERR)
			rp->htcs1 = DCLR|GO;
	}
	switch(state) {
	case SIO:
	case SOK:
		h_blkno[unit]++;
	case SCOM:
		httab.d_errcnt = 0;
		httab.d_actf = bp->av_forw;
		iodone(bp);
		bp->b_resid = (-rp->htwc)<<1;
		break;
	case SRETRY:







Jun 19 11:26 1978  ht.c Page 6


		if((bp->b_flags&B_READ)==0) {
			httab.d_active = SSFOR;
			rp->htcs1 = ERASE|IENABLE|GO;
			return;
		}
	case SSFOR:
	case SSREV:
		if (rp->htds&TM) {
			h_nxrec[unit] = bp->b_blkno+(state==SSREV?
				-rp->htfc:rp->htfc-1);
			h_blkno[unit] = bp->b_blkno+(state==SSREV?
				-rp->htfc:rp->htfc);
		} else
			h_blkno[unit] = bp->b_blkno;
		break;
	default:
		return;
	}
	htstart();
}

htread(dev)
{
	htphys(dev);
	physio(htstrategy, &rhtbuf, dev, B_READ);
}

htwrite(dev)
{
	htphys(dev);
	physio(htstrategy, &rhtbuf, dev, B_WRITE);
}

htphys(dev)
{
	register unit, a;

	unit = dev&03;
	a = lshift(u.u_offset, -9);
	h_blkno[unit] = a;
	h_nxrec[unit] = ++a;
}





















Jun 19 11:26 1978  kl.c Page 1


#
/*
 *   KL/DL-11 driver
 */
#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/tty.h"

extern	kl_addr[], kl_cnt;
struct tty kl_tty[];
#define DSRDY	02
#define	RDRENB	01

struct klregs {
	int klrcsr, klrbuf;
	int kltcsr, kltbuf;
};

klopen(dev, flag)
{
	register char *addr;
	register struct tty *tp;

	if(dev >= kl_cnt) {
		u.u_error = ENXIO;
		return;
	}
	tp = &kl_tty[dev];
	addr = kl_addr[dev];
	tp->t_addr = addr;
	if ((tp->t_state&ISOPEN) == 0) {
		tp->t_state = ISOPEN|CARR_ON;
		tp->t_flags = XTABS|ECHO|CRMOD;
		tp->t_erase = CERASE;
		tp->t_kill = CKILL;
	}
	addr->klrcsr =| IENABLE|DSRDY|RDRENB;
	addr->kltcsr =| IENABLE;
	ttyopen(tp);
}

klclose(dev)
{
	register struct tty *tp;

	tp = &kl_tty[dev];
	wflushtty(tp);
	tp->t_state = 0;
}

klread(dev)
{
	ttread(&kl_tty[dev]);
}

klwrite(dev)







Jun 19 11:26 1978  kl.c Page 2


{
	ttwrite(&kl_tty[dev]);
}

klxint(dev)
{
	register struct tty *tp;

	tp = &kl_tty[dev];
	ttstart(tp);
	if (tp->t_outq.c_cc == 0 || tp->t_outq.c_cc == TTLOWAT)
		wakeup(&tp->t_outq);
}

klrint(dev)
{
	register int c, *addr;
	register struct tty *tp;

	tp = &kl_tty[dev];
	addr = tp->t_addr;
	c = addr->klrbuf;
	addr->klrcsr =| RDRENB;
	if ((c&0177)==0)
		addr->kltbuf = c;	/* hardware botch */
	ttyinput(c, tp);
}

klsgtty(dev, v)
int *v;
{
	register struct tty *tp;

	tp = &kl_tty[dev];
	ttystty(tp, v);
}



























Jun 19 11:26 1978  lp.c Page 1


#
/*
 *  Line printer driver
 */

#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/tty.h"

extern lp_addr[], lp_cnt;

#define	LPPRI	10
#define	LPLOWAT	50
#define	LPHIWAT	100
#define	LPMAX	2

struct	{ int lpcsr, lpbuf; };

struct  {
	struct	clist l_outq;
	char	flag, ind;
	int	ccc, mcc, mlc;
	int	line, col;
} lp_dt[LPMAX];

#define	OPEN	010
#define	CAP	020
#define	NOCR	040
#define	ASLEEP	0100

#define	FORM	014

lpopen(dev, flag)
{
	register unit, *lp;

	unit = dev&07;
	if (unit >= lp_cnt || unit >= LPMAX ||
	 (lp = &lp_dt[unit])->flag || lp_addr[unit]->lpcsr <0 ) {
		u.u_error = EIO;
		return;
	}
	lp->flag = (dev&077)|OPEN;
	lp->ind = 8;
	lp->col = 132;
	lp->line = 60;
	lp_addr[unit]->lpcsr =| IENABLE;
	lpoutput(unit, FORM);
}

lpclose(dev)
{
	register unit;

	unit = dev&07;
	lpoutput(unit, FORM);







Jun 19 11:26 1978  lp.c Page 2


	lp_dt[unit].flag = 0;
}

lpwrite(dev)
{
	register c, *lp;

	while ((c=cpass())>=0)
		lpoutput(dev&07, c);
}

lpoutput(dev, c)
register dev, c;
{
	register *lp;

	lp = &lp_dt[dev];
	if(lp->flag&CAP) {
		if(c>='a' && c<='z')
			c =+ 'A'-'a'; else
		switch(c) {
		case '{':
			c = '(';
			goto esc;
		case '}':
			c = ')';
			goto esc;
		case '`':
			c = '\'';
			goto esc;
		case '|':
			c = '!';
			goto esc;
		case '~':
			c = '^';
		esc:
			lpoutput(c);
			lp->ccc--;
			c = '-';
		}
	}
	switch(c) {
	case '\t':
		lp->ccc = (lp->ccc+8) & ~7;
		return;
	case '\n':
		lp->mlc++;
		if(lp->mlc >= lp->line )
			c = FORM;
	case FORM:
		lp->mcc = 0;
		if (lp->mlc) {
			lpputc(dev, c);
			if(c == FORM)
				lp->mlc = 0;
		}







Jun 19 11:26 1978  lp.c Page 3


	case '\r':
		lp->ccc = 0;
		if(lp->ind)
			lp->ccc = lp->ind;
		return;
	case 010:
		if(lp->ccc > 0)
			lp->ccc--;
		return;
	case ' ':
		lp->ccc++;
		return;
	default:
		if(lp->ccc < lp->mcc) {
			if (lp->flag&NOCR) {
				lp->ccc++;
				return;
			}
			lpputc(dev, '\r');
			lp->mcc = 0;
		}
		if(lp->ccc < lp->col) {
			while(lp->ccc > lp->mcc) {
				lpputc(dev, ' ');
				lp->mcc++;
			}
			lpputc(dev, c);
			lp->mcc++;
		}
		lp->ccc++;
	}
}

lpputc(dev, c)
register dev, c;
{
	register *lp;

	lp = &lp_dt[dev];
	spl4();
	while (lp->l_outq.c_cc > LPHIWAT) {
		lp->flag =| ASLEEP;
		sleep(lp, LPPRI);
	}
	putc(c, &lp->l_outq);
	lpintr(dev);
	spl0();
}

lpintr(dev)
register dev;
{
	register *lp, c;

	lp = &lp_dt[dev];
	while (lp_addr[dev]->lpcsr&DONE && (c = getc(&lp->l_outq)) >= 0)







Jun 19 11:26 1978  lp.c Page 4


		lp_addr[dev]->lpbuf = c;
	if (lp->l_outq.c_cc <= LPLOWAT && lp->flag&ASLEEP) {
		lp->flag =& ~ASLEEP;
		wakeup(lp);
	}
}

lpsgtty(dev, v)
register *v;
{
	register *lp;

	lp = &lp_dt[dev&07];
	if (v) {
		v->lobyte = lp->flag;
		v->hibyte = lp->ind;
		v[1] = lp->line;
		v[2] = lp->col;
	} else {
		lp->flag = (u.u_arg[0].lobyte&077)|OPEN;
		lp->ind = u.u_arg[0].hibyte;
		lp->line = u.u_arg[1];
		lp->col = u.u_arg[2];
	}
}






































Jun 19 11:26 1978  mem.c Page 1


#
/*
 *	Memory special file
 *	minor device 0 is physical memory
 *	minor device 1 is kernel memory
 *	minor device 2 is EOF/NULL
 */

#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/seg.h"

mmread(dev)
{
	register c, bn, on;
	int a, d;

	if(dev == 2)
		return;
	do {
		bn = lshift(u.u_offset, -6);
		on = u.u_offset[1] & 077;
		a = UISA->r[0];
		d = UISD->r[0];
		spl7();
		UISA->r[0] = bn;
		UISD->r[0] = 077406;
		if(dev == 1)
			UISA->r[0] = (ka6-6)->r[(bn>>7)&07] + (bn & 0177);
		if ((c = fuibyte(on)) < 0)
			u.u_error = ENXIO;
		UISA->r[0] = a;
		UISD->r[0] = d;
		spl0();
	} while(u.u_error==0 && passc(c)>=0);
}

mmwrite(dev)
{
	register c, bn, on;
	int a, d;

	if(dev == 2) {
		c = u.u_count;
		u.u_count = 0;
		u.u_base =+ c;
		dpadd(u.u_offset, c);
		return;
	}
	for(;;) {
		bn = lshift(u.u_offset, -6);
		on = u.u_offset[1] & 077;
		if ((c=cpass())<0 || u.u_error!=0)
			break;
		a = UISA->r[0];
		d = UISD->r[0];







Jun 19 11:26 1978  mem.c Page 2


		spl7();
		UISA->r[0] = bn;
		UISD->r[0] = 077406;
		if(dev == 1)
			UISA->r[0] = (ka6-6)->r[(bn>>7)&07] + (bn & 0177);
		if (suibyte(on, c) < 0)
			u.u_error = ENXIO;
		UISA->r[0] = a;
		UISD->r[0] = d;
		spl0();
	}
}



















































Jun 19 11:26 1978  partab.c Page 1


char partab[] {
	0001,0201,0201,0001,0201,0001,0001,0201,
	0202,0004,0003,0205,0005,0206,0201,0001,
	0201,0001,0001,0201,0001,0201,0201,0001,
	0001,0201,0201,0001,0201,0001,0001,0201,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0000,0200,0200,0000,0200,0000,0000,0201
};













































Jun 19 11:26 1978  pio.c Page 1


#
#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/buf.h"
#include "../hd/systm.h"
#include "../hd/proc.h"
#include "../hd/conf.h"
#include "../hd/seg.h"

struct	buf	swbuf[NSWB];

/*
 * Device start routine for disks
 * and other devices that have the register
 * layout of the older DEC controllers (RF, RK, RP, TM)
 */
#define	IENABLE	0100
#define	WCOM	02
#define	RCOM	04
#define	GO	01
devstart(bp, devloc, devblk, hbcom)
struct buf *bp;
int *devloc;
{
	register int *dp;
	register struct buf *rbp;
	register int com;

	dp = devloc;
	rbp = bp;
	*dp = devblk;			/* block address */
	*--dp = rbp->b_addr;		/* buffer address */
	*--dp = rbp->b_wcount;		/* word count */
	com = (hbcom<<8) | IENABLE | GO |
		((rbp->b_xmem & 03) << 4);
	if (rbp->b_flags&B_READ)	/* command + x-mem */
		com =| RCOM;
	else
		com =| WCOM;
	*--dp = com;
}

/*
 * startup routine for RH controllers.
 */
#define	RHWCOM	060
#define	RHRCOM	070

rhstart(bp, devloc, devblk, abae)
struct buf *bp;
int *devloc, *abae;
{
	register int *dp;
	register struct buf *rbp;
	register int com;








Jun 19 11:26 1978  pio.c Page 2


	dp = devloc;
	rbp = bp;
	if(cputype == 70)
		*abae = rbp->b_xmem;
	*dp = devblk;			/* block address */
	*--dp = rbp->b_addr;		/* buffer address */
	*--dp = rbp->b_wcount;		/* word count */
	com = IENABLE | GO |
		((rbp->b_xmem & 03) << 8);
	if (rbp->b_flags&B_READ)	/* command + x-mem */
		com =| RHRCOM; else
		com =| RHWCOM;
	*--dp = com;
}

/*
 * swap I/O
 */
swap(blkno, coreaddr, count, rdflg)
{
	static struct buf *sbp;
	register struct buf *bp;

	if (sbp==NULL)
		sbp = &swbuf[0];
	bp = sbp++;
	if (sbp > &swbuf[NSWB-1])
		sbp = &swbuf[0];
	spl6();
	while (bp->b_flags&B_BUSY) {
		bp->b_flags =| B_WANTED;
		sleep(bp, PSWP+1);
	}
	bp->b_flags = B_BUSY | B_PHYS | rdflg;
	bp->b_dev = swapdev;
	bp->b_wcount = - (count<<5);	/* 32 w/block */
	bp->b_blkno = blkno;
	bp->b_addr = coreaddr<<6;	/* 64 b/block */
	bp->b_xmem = (coreaddr>>10) & 077;
	(*bdevsw[major(swapdev)].d_strategy)(bp);
	spl6();
	while((bp->b_flags&B_DONE)==0)
		sleep(bp, PSWP);
	if (bp->b_flags&B_WANTED)
		wakeup(bp);
	spl0();
	bp->b_flags =& ~(B_BUSY|B_WANTED);
	if (bp->b_flags & B_ERROR)
		panic("IO err in swap");
}

/*
 * Raw I/O. The arguments are
 *	The strategy routine for the device
 *	A buffer, which will always be a special buffer
 *	  header owned exclusively by the device for this purpose







Jun 19 11:26 1978  pio.c Page 3


 *	The device number
 *	Read/write flag
 * Essentially all the work is computing physical addresses and
 * validating them.
 */
physio(strat, abp, dev, rw)
struct buf *abp;
int (*strat)();
{
	register struct buf *bp;
	register char *base;
	register int nb;
	int ts;

	bp = abp;
	base = u.u_base;
	/*
	 * Check odd base, odd count, and address wraparound
	 */
	if (base&01 || u.u_count&01 || base>=base+u.u_count)
		goto bad;
	ts = (u.u_tsize+127) & ~0177;
	if (u.u_sep)
		ts = 0;
	nb = (base>>6) & 01777;
	/*
	 * Check overlap with text. (ts and nb now
	 * in 64-byte clicks)
	 */
	if (nb < ts)
		goto bad;
	/*
	 * Check that transfer is either entirely in the
	 * data or in the stack: that is, either
	 * the end is in the data or the start is in the stack
	 * (remember wraparound was already checked).
	 */
	if ((((base+u.u_count)>>6)&01777) >= ts+u.u_dsize
	    && nb < 1024-u.u_ssize)
		goto bad;
	spl6();
	while (bp->b_flags&B_BUSY) {
		bp->b_flags =| B_WANTED;
		sleep(bp, PRIBIO+1);
	}
	bp->b_flags = B_BUSY | B_PHYS | rw;
	bp->b_dev = dev;
	/*
	 * Compute physical address by simulating
	 * the segmentation hardware.
	 */
	bp->b_addr = base&077;
	base = (u.u_sep? UDSA: UISA)->r[nb>>7] + (nb&0177);
	bp->b_addr =+ base<<6;
	bp->b_xmem = (base>>10) & 077;
	bp->b_blkno = lshift(u.u_offset, -9);







Jun 19 11:26 1978  pio.c Page 4


	bp->b_wcount = -((u.u_count>>1) & 077777);
	bp->b_error = 0;
	u.u_procp->p_flag =| SLOCK;
	(*strat)(bp);
	spl6();
	while ((bp->b_flags&B_DONE) == 0)
		sleep(bp, PRIBIO);
	u.u_procp->p_flag =& ~SLOCK;
	if (bp->b_flags&B_WANTED)
		wakeup(bp);
	if(runin) {
		runin = 0;
		wakeup(&runin);
	}
	spl0();
	bp->b_flags =& ~(B_BUSY|B_WANTED);
	u.u_count = bp->b_resid;
	geterror(bp);
	return;
    bad:
	u.u_error = EFAULT;
}

physck(nblocks, rw)
register unsigned nblocks;
{
	register unsigned base, limit;

	base = lshift(u.u_offset, -9);
	if (base >= nblocks) {
		if (base > nblocks || rw == B_WRITE)
			u.u_error = ENXIO;
		return(0);
	}
	limit = base + ldiv(u.u_count+511, 512);
	if (limit > nblocks) {
		base = (limit-nblocks)<<9;
		u.u_count =- base;
		u.u_arg[1] =- base;
	}
	return(1);
}





















Jun 19 11:26 1978  rp.c Page 1


#
/*
 * RP11/RP03 disk driver
 */

#include "../hd/param.h"
#include "../hd/buf.h"
#include "../hd/user.h"

struct {
	int	rpds, rper, rpcs, rpwc;
	int	rpba, rpca, rpda;
};

int	rp_addr, rp_cnt;

struct {
	char	*nblocks;
	int	cyloff;
} rp_sizes[8];

struct	devtab	rptab;
struct	buf	rrpbuf;

#define	GO	01
#define	RESET	0
#define	HSEEK	014

#define	IENABLE	0100
#define	READY	0200

#define	SUFU	01000
#define	SUSU	02000
#define	SUSI	04000
#define	HNF	010000

/*
 * Use av_back to save track+sector,
 * b_resid for cylinder.
 */

#define	trksec	av_back
#define	cylin	b_resid


rpopen(dev)
{
	if (dev >= (rp_cnt<<3))
		u.u_error = ENXIO;
}

rpclose(dev)
{
}

rpstrategy(abp)







Jun 19 11:26 1978  rp.c Page 2


struct buf *abp;
{
	register struct buf *bp;
	register char *p1, *p2;

	bp = abp;
	p1 = &rp_sizes[minor(bp->b_dev)&07];
	if (bp->b_blkno >= p1->nblocks) {
		if (bp->b_blkno == p1->nblocks && bp->b_flags&B_READ)
			bp->b_resid = 512;
		else {
			bp->b_flags =| B_ERROR;
			bp->b_error = ENXIO;
		}
		iodone(bp);
		return;
	}
	bp->av_forw = 0;
	bp->cylin = p1->cyloff;
	p1 = bp->b_blkno;
	p2 = lrem(p1, 10);
	p1 = ldiv(p1, 10);
	bp->trksec = (p1%20)<<8 | p2;
	bp->cylin =+ p1/20;
	spl5();
	if ((p1 = rptab.d_actf)==0) {
		rptab.d_actf = bp;
		rptab.d_actl = bp;
	} else {
		for (p1 = rptab.d_actl; p2 = p1->av_forw; p1 = p2) {
			if (p1->cylin <= bp->cylin
			 && bp->cylin <  p2->cylin
			 || p1->cylin >= bp->cylin
			 && bp->cylin >  p2->cylin) 
				break;
		}
		bp->av_forw = p2;
		p1->av_forw = bp;
	}
	if (rptab.d_active==0)
		rpstart();
	spl0();
}

rpstart()
{
	register struct buf *bp;
	register *rp;

	if ((bp = rptab.d_actf) == 0)
		return;
	rptab.d_active++;
	rp = rp_addr;
	rp->rpda = bp->trksec;
	devstart(bp, &rp->rpca, bp->cylin, minor(bp->b_dev)>>3);
}







Jun 19 11:26 1978  rp.c Page 3



rpintr()
{
	register struct buf *bp;
	register ctr, *rp;

	if (rptab.d_active == 0)
		return;
	bp = rptab.d_actf;
	rp = rp_addr;
	rptab.d_active = 0;
	if (rp->rpcs < 0) {		/* error bit */
		deverror(bp, rp->rper, rp->rpds);
		if(rp->rpds & (SUFU|SUSI|HNF)) {
			rp->rpcs.lobyte = HSEEK|GO;
			ctr = 0;
			while ((rp->rpds&SUSU) && --ctr);
		}
		rp->rpcs = RESET|GO;
		ctr = 0;
		while ((rp->rpcs&READY) == 0 && --ctr);
		if (++rptab.d_errcnt <= 10) {
			rpstart();
			return;
		}
		bp->b_flags =| B_ERROR;
	}
	rptab.d_errcnt = 0;
	rptab.d_actf = bp->av_forw;
	bp->b_resid = (-rp->rpwc)<<1;
	iodone(bp);
	if(bp=rptab.d_actf) while(bp->av_forw) bp = bp->av_forw;
	rptab.d_actl = bp;
	rpstart();
}

rpread(dev)
{
	if (physck(rp_sizes[dev&07].nblocks, B_READ))
		physio(rpstrategy, &rrpbuf, dev, B_READ);
}

rpwrite(dev)
{
	if (physck(rp_sizes[dev&07].nblocks, B_WRITE))
		physio(rpstrategy, &rrpbuf, dev, B_WRITE);
}
















Jun 19 11:26 1978  sys.c Page 1


#
/*
 *	indirect driver for controlling tty.
 */
#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/conf.h"
#include "../hd/tty.h"

syopen(dev, flag)
{

	if(u.u_ttyp == NULL) {
		u.u_error = ENXIO;
		return;
	}
	(*cdevsw[major(u.u_ttyd)].d_open)(minor(u.u_ttyd), flag);
}

syread(dev)
{

	(*cdevsw[major(u.u_ttyd)].d_read)(minor(u.u_ttyd));
}

sywrite(dev)
{

	(*cdevsw[major(u.u_ttyd)].d_write)(minor(u.u_ttyd));
}

sysgtty(dev, flag)
{

	(*cdevsw[major(u.u_ttyd)].d_sgtty)(minor(u.u_ttyd), flag);
}



























Jun 19 11:26 1978  tm.c Page 1


#
/*
 * TM tape driver
 * minor device classes:
 * bits 0,1: slave select
 * bit 2 off: rewind on close; on: position after first TM
 */

#include "../hd/param.h"
#include "../hd/buf.h"
#include "../hd/user.h"

struct {
	int tmer, tmcs, tmbc, tmba;
	int tmdb, tmrd;
};

struct	devtab	tmtab;
struct	buf	rtmbuf;
char	t_openf[4], *t_blkno[4], *t_nxrec[4];

int	tm_addr;

#define	RCOM	03
#define	WCOM	05
#define	WEOF	07
#define	SFORW	011
#define	SREV	013
#define	WIRG	015
#define	REW	017
#define	DENS	060000		/* 9-channel */
#define	IENABLE	0100
#define GSD	010000
#define	HARD	0102200	/* ILC, EOT, NXM */
#define	EOF	0040000
#define	RLE	01000

#define	SIO	1
#define	SSFOR	2
#define	SSREV	3
#define SCOM	4

tmopen(dev, flag)
{
	register unit;

	unit = dev&03;
	if (t_openf[unit])
		u.u_error = ENXIO;
	else {
		t_openf[unit]++;
		t_blkno[unit] = 0;
		t_nxrec[unit] = 65535;
	}
}








Jun 19 11:26 1978  tm.c Page 2


tmclose(dev, flag)
{
	register unit;
	register struct buf *bp;
	register struct devtab *dp;

	unit = dev&03;
	if (flag) {
		tcommand(unit, WEOF);
		tcommand(unit, WEOF);
	}
	if (dev&04) {
		if (flag)
			tcommand(unit, SREV); else
			if (t_blkno[unit] < t_nxrec[unit])
				tcommand(unit, SFORW);
	} else
		tcommand(unit, REW);
	dp = &tmtab;
	for (bp=dp->b_forw; bp!=dp; bp=bp->b_forw)
		if ((bp->b_dev&03)==unit)
			bp->b_dev =| 0100;
	t_openf[unit] = 0;
}

tcommand(unit, com)
{
	register *rp;

	rp = tm_addr;
	spl5();
	while(tmtab.d_active)
		sleep(&tmtab, -1);
	tmtab.d_active = SCOM;
	rp->tmbc = 0;
	rp->tmcs = IENABLE|DENS|com | (unit<<8);
	spl0();
}

tmstrategy(abp)
struct buf *abp;
{
	register struct buf *bp;
	register char **p;

	bp = abp;
	p = &t_nxrec[bp->b_dev&03];
	if (bp->b_blkno > *p) {
		bp->b_flags =| B_ERROR;
		bp->b_error = ENXIO;
		iodone(bp);
		return;
	}
	if (bp->b_blkno == *p && bp->b_flags&B_READ) {
		bp->b_resid = 512;
		clrbuf(bp);







Jun 19 11:26 1978  tm.c Page 3


		iodone(bp);
		return;
	}
	if ((bp->b_flags&B_READ)==0)
		*p = bp->b_blkno + 1;
	bp->av_forw = 0;
	spl5();
	if (tmtab.d_actf==0)
		tmtab.d_actf = bp;
	else
		tmtab.d_actl->av_forw = bp;
	tmtab.d_actl = bp;
	if (tmtab.d_active==0)
		tmstart();
	spl0();
}

tmstart()
{
	register struct buf *bp;
	register com, *rp;
	int unit;
	char *blkno;

    loop:
	if ((bp = tmtab.d_actf) == 0) {
		tmtab.d_active = 0;
		wakeup(&tmtab);
		return;
	}
	unit = bp->b_dev&03;
	blkno = t_blkno[unit];
	if (t_openf[unit] < 0 || bp->b_blkno > t_nxrec[unit]) {
		bp->b_flags =| B_ERROR;
		tmtab.d_actf = bp->av_forw;
		iodone(bp);
		goto loop;
	}
	com = (unit<<8) | ((bp->b_xmem & 03) << 4) | IENABLE|DENS;
	rp = tm_addr;
	if (blkno != bp->b_blkno) {
		if (bp->b_blkno > blkno) {
			com =| SFORW;
			tmtab.d_active = SSFOR;
			rp->tmbc = blkno - bp->b_blkno;
		} else {
			com =| SREV;
			tmtab.d_active = SSREV;
			rp->tmbc = bp->b_blkno - blkno;
		}
		rp->tmcs = com;
		return;
	}
	tmtab.d_active = SIO;
	rp->tmbc = bp->b_wcount << 1;
	rp->tmba = bp->b_addr;		/* core address */







Jun 19 11:26 1978  tm.c Page 4


	rp->tmcs = com | ((bp->b_flags&B_READ)? RCOM:
	    ((tmtab.d_errcnt)? WIRG: WCOM));
}

tmintr()
{
	register struct buf *bp;
	register unit, *rp;
	int	state;

	if ((state = tmtab.d_active)==0)
		return;
	rp = tm_addr;
	if (state != SCOM) {
	bp = tmtab.d_actf;
	unit = bp->b_dev&03;
	if (rp->tmcs < 0) {		/* error bit */
		while(rp->tmrd & GSD) ; /* wait for gap shutdown */
		if ((rp->tmer&(HARD|EOF))==0 && state==SIO) {
			if (bp != &rtmbuf || (rp->tmer&RLE)==0)
			if (++tmtab.d_errcnt < 10) {
				t_blkno[unit]++;
				tmstart();
				return;
			} else
				bp->b_flags =| B_ERROR;
		} else
		if (rp->tmer&EOF) {
			if (state==SIO) {
				rp->tmbc = bp->b_wcount<<1;
				t_nxrec[unit] = bp->b_blkno;
			} else {
				t_nxrec[unit] = bp->b_blkno+(state==SSREV?
					-rp->tmbc:rp->tmbc-1);
				t_blkno[unit] = bp->b_blkno+(state==SSREV?
					-rp->tmbc:rp->tmbc);
				tmstart();
				return;
			}
		} else {
			bp->b_flags =| B_ERROR;
			if (bp != &rtmbuf)
				t_openf[unit] = -1;
		}
	}
	if (state == SIO) {
		tmtab.d_errcnt = 0;
		t_blkno[unit]++;
		tmtab.d_actf = bp->av_forw;
		bp->b_resid = -rp->tmbc;
		iodone(bp);
	} else
		t_blkno[unit] = bp->b_blkno;
	}
	tmstart();
}







Jun 19 11:26 1978  tm.c Page 5



tmread(dev)
{
	tmphys(dev);
	physio(tmstrategy, &rtmbuf, dev, B_READ);
}

tmwrite(dev)
{
	tmphys(dev);
	physio(tmstrategy, &rtmbuf, dev, B_WRITE);
}

tmphys(dev)
{
	register unit, a;

	unit = dev&03;
	a = lshift(u.u_offset, -9);
	t_blkno[unit] = a;
	t_nxrec[unit] = ++a;
}









































Jun 19 11:26 1978  tty.c Page 1


#
/*
 * general TTY subroutines
 */
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/tty.h"
#include "../hd/proc.h"
#include "../hd/conf.h"
#include "../hd/inode.h"
#include "../hd/file.h"
#include "../hd/reg.h"
#include "../hd/var.h"

char	partab[];
char	canonb[CANBSIZ];
/*
 * Input mapping table-- if an entry is non-zero, when the
 * corresponding character is typed preceded by "\" the escape
 * sequence is replaced by the table value.  Mostly used for
 * upper-case only terminals.
 */
char	maptab[]
{
	000,000,000,000,CEOT,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,'|',000,000,000,000,000,'`',
	'{','}',000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,000,000,
	000,000,000,000,000,000,'~',000,
	000,'A','B','C','D','E','F','G',
	'H','I','J','K','L','M','N','O',
	'P','Q','R','S','T','U','V','W',
	'X','Y','Z',000,000,000,000,000,
};

/* The character lists-- space for 6*NCLIST characters */
struct cblock cfree[];
/* List head for unused character blocks. */
struct cblock *cfreelist;

/*
 * structure of device registers for KL, DL, and DC
 * interfaces-- more particularly, those for which the
 * SSTART bit is off and can be treated by general routines
 * (that is, not DH).
 */
struct {
	int	rcsr, rbuf, xcsr, xbuf;







Jun 19 11:26 1978  tty.c Page 2


};

/*
 * routine called on first teletype open.
 * establishes a process group for distribution
 * of quits and interrupts from the tty.
 */
ttyopen(tp)
register struct tty *tp;
{
	register struct proc *pp;

	pp = u.u_procp;
	if(pp->p_pgrp == 0) {
		pp->p_pgrp = pp->p_pid;
		u.u_ttyp = tp;
	/* u.u_ttyd set up by openi in fio.c */
		if(tp->t_pgrp) {
			signal(tp->t_pgrp, SIGHUP);
			flushtty(tp);
		}
		tp->t_pgrp = pp->p_pid;
	}
	tp->t_state =& ~WOPEN;
	tp->t_state =| ISOPEN;
}

/*
 * The routine implementing the gtty system call.
 * Just call lower level routine and pass back values.
 */
gtty()
{
	int v[3];
	register *up, *vp;

	vp = v;
	sgtty(vp);
	if (u.u_error)
		return;
	up = u.u_arg[0];
	suword(up, *vp++);
	suword(++up, *vp++);
	suword(++up, *vp++);
}

/*
 * The routine implementing the stty system call.
 * Read in values and call lower level.
 */
stty()
{
	register int *up;

	up = u.u_arg[0];
	u.u_arg[0] = fuword(up);







Jun 19 11:26 1978  tty.c Page 3


	u.u_arg[1] = fuword(++up);
	u.u_arg[2] = fuword(++up);
	sgtty(0);
}

/*
 * Stuff common to stty and gtty.
 * Check legality and switch out to individual device routine.
 * v is 0 for stty; the parameters are taken from u.u_arg[].
 * v is non-zero for gtty and is the place in which the device
 * routines place their information.
 */
sgtty(v)
int *v;
{
	register struct file *fp;
	register struct inode *ip;

	if ((fp = getf(u.u_ar0[R0])) == NULL)
		return;
	ip = fp->f_inode;
	if ((ip->i_mode&IFMT) != IFCHR) {
		u.u_error = ENOTTY;
		return;
	}
	(*cdevsw[major(ip->i_addr[0])].d_sgtty)(minor(ip->i_addr[0]), v);
}

/*
 * Wait for output to drain, then flush input waiting.
 */
wflushtty(atp)
struct tty *atp;
{
	register struct tty *tp;

	tp = atp;
	spl5();
	while (tp->t_outq.c_cc) {
		tp->t_state =| ASLEEP;
		sleep(&tp->t_outq, TTOPRI);
	}
	flushtty(tp);
	spl0();
}

/*
 * Initialize clist by freeing all character blocks, then count
 * number of character devices. (Once-only routine)
 */
cinit()
{
	register int ccp;
	register struct cblock *cp;

	ccp = cfree;







Jun 19 11:26 1978  tty.c Page 4


	for (cp=(ccp+07)&~07; cp <= &cfree[v.v_clist-1]; cp++) {
		cp->c_next = cfreelist;
		cfreelist = cp;
	}
}

/*
 * flush all TTY queues
 */
flushtty(atp)
struct tty *atp;
{
	register struct tty *tp;
	register int sps;

	tp = atp;
	while (getc(&tp->t_canq) >= 0);
	while (getc(&tp->t_outq) >= 0);
	wakeup(&tp->t_rawq);
	wakeup(&tp->t_outq);
	sps = PS->integ;
	spl5();
	while (getc(&tp->t_rawq) >= 0);
	tp->t_delct = 0;
	PS->integ = sps;
}

/*
 * transfer raw input list to canonical list,
 * doing erase-kill processing and handling escapes.
 * It waits until a full line has been typed in cooked mode,
 * or until any character has been typed in raw mode.
 */
canon(atp)
struct tty *atp;
{
	register char *bp;
	char *bp1;
	register struct tty *tp;
	register int c;
	int mc;

	tp = atp;
	spl5();
	while ((tp->t_flags&RAW)==0 && tp->t_delct==0
	    || (tp->t_flags&RAW)!=0 && tp->t_rawq.c_cc==0) {
		if ((tp->t_state&CARR_ON)==0)
			return(0);
		sleep(&tp->t_rawq, TTIPRI);
	}
	spl0();
loop:
	bp = &canonb[2];
	while ((c=getc(&tp->t_rawq)) >= 0) {
		if ((tp->t_flags&RAW)==0) {
			if (c==0377) {







Jun 19 11:26 1978  tty.c Page 5


				tp->t_delct--;
				break;
			}
			if (bp[-1]!='\\') {
				if (c==tp->t_erase) {
					if (bp > &canonb[2])
						bp--;
					continue;
				}
				if (c==tp->t_kill)
					goto loop;
				if (c==CEOT)
					continue;
			} else {
				mc = maptab[c];
				if (c==tp->t_erase || c==tp->t_kill)
					mc = c;
				if (mc && (mc==c || (tp->t_flags&LCASE))) {
					if (bp[-2] != '\\')
						c = mc;
					bp--;
				}
			}
		}
		*bp++ = c;
		if (bp>=canonb+CANBSIZ)
			break;
	}
	bp1 = bp;
	bp = &canonb[2];
	c = &tp->t_canq;
	while (bp<bp1)
		putc(*bp++, c);
	return(1);
}

/*
 * Place a character on raw TTY input queue, putting in delimiters
 * and waking up top half as needed.
 * Also echo if required.
 * The arguments are the character and the appropriate
 * tty structure.
 */
ttyinput(ac, atp)
struct tty *atp;
{
	register int t_flags, c;
	register struct tty *tp;

	tp = atp;
	c = ac&0377;
	t_flags = tp->t_flags;
	if ((t_flags&RAW)==0) {
		c =& 0177;
		if (c==CQUIT || c==CINTR) {
			signal(tp->t_pgrp, c==CINTR? SIGINT:SIGQIT);







Jun 19 11:26 1978  tty.c Page 6


			flushtty(tp);
			return;
		}
		if (c=='\r' && t_flags&CRMOD)
			c = '\n';
	}
	if (tp->t_rawq.c_cc>TTYHOG) {
		flushtty(tp);
		return;
	}
	if (t_flags&LCASE && c>='A' && c<='Z')
		c =+ 'a'-'A';
	if (putc(c, &tp->t_rawq)!=0)
		return;		/* don't echo on overflow */
	if (t_flags&RAW || (c=='\n' || c==CEOT)) {
		wakeup(&tp->t_rawq);
		if ((t_flags&RAW)==0 && putc(0377, &tp->t_rawq)==0)
			tp->t_delct++;
	}
	if (t_flags&ECHO) {
		ttyoutput(c, tp);
		ttstart(tp);
	}
}

/*
 * put character on TTY output queue, adding delays,
 * expanding tabs, and handling the CR/NL bit.
 * It is called both from the top half for output, and from
 * interrupt level for echoing.
 * The arguments are the character and the tty structure.
 */
ttyoutput(ac, tp)
struct tty *tp;
{
	register int c;
	register struct tty *rtp;
	register char *colp;
	int ctype;
	int cs;

	rtp = tp;
	c = ac;
	/*
	 * Ignore EOT in normal mode to avoid hanging up
	 * certain terminals.
	 * In raw mode dump the char unchanged.
	 */
	if ((rtp->t_flags&RAW)==0) {
		c =& 0177;
		if (c==CEOT)
			return;
	} else {
		putc(c, &rtp->t_outq);
		return;
	}







Jun 19 11:26 1978  tty.c Page 7


	/*
	 * Turn tabs to spaces as required
	 */
	if (c=='\t' && rtp->t_flags&XTABS) {
		do
			ttyoutput(' ', rtp);
		while (rtp->t_col&07);
		return;
	}
	/*
	 * for upper-case-only terminals,
	 * generate escapes.
	 */
	if (rtp->t_flags&LCASE) {
		colp = "({)}!|^~'`";
		while(*colp++)
			if(c == *colp++) {
				ttyoutput('\\', rtp);
				c = colp[-2];
				break;
			}
		if ('a'<=c && c<='z')
			c =+ 'A' - 'a';
	}
	/*
	 * turn <nl> to <cr><lf> if desired.
	 */
	if (c=='\n' && rtp->t_flags&CRMOD)
		ttyoutput('\r', rtp);
	cs = c;
	/*
	 * Calculate delays.
	 * The numbers here represent clock ticks
	 * and are not necessarily optimal for all terminals.
	 * The delays are indicated by characters above 0200.
	 * In raw mode there are no delays and the
	 * transmission path is 8 bits wide.
	 */
	colp = &rtp->t_col;
	ctype = partab[c];
	c = 0;
	switch (ctype&077) {

	/* ordinary */
	case 0:
		(*colp)++;

	/* non-printing */
	case 1:
		break;

	/* backspace */
	case 2:
		if (*colp)
			(*colp)--;
		break;







Jun 19 11:26 1978  tty.c Page 8



	/* newline */
	case 3:
		ctype = (rtp->t_flags >> 8) & 03;
		if(ctype == 1) { /* tty 37 */
			if (*colp)
				c = max((*colp>>4) + 3, 6);
			*colp = 0;
		} else
		if(ctype == 2) {
			c = 2;
		} else
		if(ctype == 3) {
			c = 9;
		}
		break;

	/* tab */
	case 4:
		ctype = (rtp->t_flags >> 10) & 03;
		if(ctype == 1) { /* tty 37 */
			c = 1 - (*colp | ~07);
			if(c < 5)
				c = 0;
		}
		*colp =| 07;
		(*colp)++;
		break;

	/* vertical motion */
	case 5:
		if(rtp->t_flags & VTDELAY) /* tty 37 */
			c = 0177;
		break;

	/* carriage return */
	case 6:
		ctype = (rtp->t_flags >> 12) & 03;
		if(ctype == 1) { /* tn 300 */
			c = 5;
		} else
		if(ctype == 2) {
			if(*colp==0)
				return;
			c = 5;
		} else
		if(ctype == 3) {
			if(*colp==0)
				return;
			c = 9;
		}
		*colp = 0;
	}
	putc(cs, &rtp->t_outq);
	if(c)
		putc(c|0200, &rtp->t_outq);







Jun 19 11:26 1978  tty.c Page 9


}

/*
 * Restart typewriter output following a delay
 * timeout.
 * The name of the routine is passed to the timeout
 * subroutine and it is called during a clock interrupt.
 */
ttrstrt(atp)
{
	register struct tty *tp;

	tp = atp;
	tp->t_state =& ~TIMEOUT;
	ttstart(tp);
}

/*
 * Start output on the typewriter. It is used from the top half
 * after some characters have been put on the output queue,
 * from the interrupt routine to transmit the next
 * character, and after a timeout has finished.
 * If the SSTART bit is off for the tty the work is done here,
 * using the protocol of the single-line interfaces (KL, DL, DC);
 * otherwise the address word of the tty structure is
 * taken to be the name of the device-dependent startup routine.
 */
ttstart(atp)
struct tty *atp;
{
	register int *addr, c;
	int sps;
	register struct tty *tp;
	struct { int (*func)(); };

	tp = atp;
	addr = tp->t_addr;
	if (tp->t_state&SSTART) {
		(*addr.func)(tp);
		return;
	}
	sps = PS->integ;
	spl5();
	if ((addr->xcsr&DONE)==0 || tp->t_state&TIMEOUT)
		return;
	if ((c=getc(&tp->t_outq)) >= 0) {
		if (tp->t_flags&RAW)
			addr->xbuf = c;
		else if (c<=0177)
			addr->xbuf = c | (partab[c]&0200);
		else {
			timeout(ttrstrt, tp, c&0177);
			tp->t_state =| TIMEOUT;
		}
	}
	PS->integ = sps;







Jun 19 11:26 1978  tty.c Page 10


}

/*
 * Called from device's read routine after it has
 * calculated the tty-structure given as argument.
 * The pc is backed up for the duration of this call.
 * In case of a caught interrupt, an RTI will re-execute.
 */
ttread(atp)
struct tty *atp;
{
	register struct tty *tp;

	tp = atp;
	if ((tp->t_state&CARR_ON)==0)
		return;
	if (tp->t_canq.c_cc || canon(tp))
		while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0);
}

/*
 * Called from the device's write routine after it has
 * calculated the tty-structure given as argument.
 */
ttwrite(atp)
struct tty *atp;
{
	register struct tty *tp;
	register int c;

	tp = atp;
	if ((tp->t_state&CARR_ON)==0)
		return;
	while ((c=cpass())>=0) {
		spl5();
		while (tp->t_outq.c_cc > TTHIWAT) {
			ttstart(tp);
			tp->t_state =| ASLEEP;
			sleep(&tp->t_outq, TTOPRI);
		}
		spl0();
		ttyoutput(c, tp);
	}
	ttstart(tp);
}

/*
 * Common code for gtty and stty functions on typewriters.
 * If v is non-zero then gtty is being done and information is
 * passed back therein;
 * if it is zero stty is being done and the input information is in the
 * u_arg array.
 */
ttystty(atp, av)
int *atp, *av;
{







Jun 19 11:26 1978  tty.c Page 11


	register  *tp, *v;

	tp = atp;
	if(v = av) {
		*v++ = tp->t_speeds;
		v->lobyte = tp->t_erase;
		v->hibyte = tp->t_kill;
		v[1] = tp->t_flags;
		return(1);
	}
	wflushtty(tp);
	v = u.u_arg;
	tp->t_speeds = *v++;
	tp->t_erase = v->lobyte;
	tp->t_kill = v->hibyte;
	tp->t_flags = v[1];
	return(0);
}













































Jun 19 11:26 1978  vp.c Page 1


/*
 *  Versatec matrix printer/plotter dma interface driver
 */

#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/buf.h"
#include "../hd/peri.h"

#define	VPPRI	10

struct {
	int	plbcr, pbae, prbcr, pbaddr;
	int	plcsr, plbuf, prcsr, prbuf;
};

extern vp_addr[], vp_cnt;

/* status bits */
#define	ERROR	0100000
#define	READY	0200
#define	IENABLE	0100
#define	FFCOM	020
#define	RESET	02
#define	SPP	01

/*states */
#define	PRINT	0100
#define	PLOT	0200
#define	PPLOT	0400

vpopen(dev)
register dev;
{
	register *vp, *vpaddr;

	if (dev>=vp_cnt || (vp = &vp_vp[dev])->vp_buf) {
		u.u_error = ENXIO;
		return;
	}
	vpaddr = &(vp_addr[dev]->plcsr);
	*vpaddr = IENABLE|RESET;
	vp->vp_state = PRINT;
	if (vpready(dev)<0) {
		*vpaddr = 0;
		u.u_error = EIO;
		return;
	}
	*vpaddr = IENABLE|FFCOM;
	vp->vp_buf = getblk(NODEV);
	vp->vp_offset = vp->vp_count = 0;
}

vpclose(dev)
{
	register *vp, *vpaddr;







Jun 19 11:26 1978  vp.c Page 2



	vp = &vp_vp[dev];
	vpaddr = &(vp_addr[dev]->plcsr);
	vpready(dev);
	*vpaddr = 0;
	brelse(vp->vp_buf);
	vp->vp_buf = 0;
}

vpwrite(dev)
register dev;
{
	register *vp, *vpaddr;

	vp = &vp_vp[dev];
	vpaddr = vp_addr[dev];
	if (vp->vp_count) {
		u.u_error = EIO;
		return;
	}
	while (u.u_count && u.u_error==0) {
		vp->vp_count = min(256,u.u_count);
		iomove(vp->vp_buf, vp->vp_offset, vp->vp_count, B_WRITE);
		if (vpready(dev)<0) {
			u.u_error = EIO;
			vpaddr->plcsr = IENABLE|RESET;
			break;
		}
		vpaddr->pbaddr = vp->vp_buf->b_addr + vp->vp_offset;
		if (vp->vp_state&PLOT)
			vpaddr->plbcr = vp->vp_count; else
			vpaddr->prbcr = vp->vp_count;
		vp->vp_offset = 256 - vp->vp_offset;
		if (vp->vp_state&PPLOT)
			vp->vp_state = PLOT;
	}
	vp->vp_count = 0;
}

vpready(dev)
{
	register *vp, *vpaddr;

	vp = &vp_vp[dev];
	vpaddr = (vp->vp_state&PLOT)?&(vp_addr[dev]->plcsr):
		&(vp_addr[dev]->prcsr);
	spl4();
	while ((*vpaddr&(READY|ERROR))==0)
		sleep(vp, VPPRI);
	spl0();
	return(*vpaddr);
}

vpsgtty(dev, av)
int *av;
{







Jun 19 11:26 1978  vp.c Page 3


	register *vp, *vpaddr;
	register bit;

	vp = &vp_vp[dev];
	vpaddr = &(vp_addr[dev]->plcsr);
	if (av) {
		*av = vp->vp_state;
		return;
	}
	vpready(dev);
	vp->vp_state = u.u_arg[0];
	if (vp->vp_state&PPLOT)
		*vpaddr = IENABLE|SPP; else
		*vpaddr = IENABLE;
	for (bit=2; bit<IENABLE; bit=<<1)
		if (vp->vp_state&bit) {
			vpready(dev);
			*vpaddr =| bit;
			vp->vp_state =& ~bit;
		}
}

vpintr(dev)
{
	wakeup(&vp_vp[dev]);
}



































