! "W N, R=    @ #D  D ҃TP  B ы e@W 0 ,"& 7   0ߋp@E A Ze      |@7x@ eE "  ɋ -lɋ e-RNHɋ ^?sys/buf.h l Lsys/conf.h зNsys/file.h з!Wsys/filsys.h з"-sys/ino.h з$sys/inode.hl &csys/param.hc T*5sys/proc.hl )/"sys/reg.h з2sys/seg.hl J3#sys/systm.h ѷ5lsys/text.h| ѷ9Lsys/tty.h  ѷ:sys/user.h l r?$ sys/runm Esys/lib1 Gsys/lib2rY m`ken/alloc.ck 1fCken/clock.c2 l j%nken/fio.czk :+ken/iget.c/l 4!ken/main.c%=Hken/malloc.cqk GFken/nami.ch l JBken/pipe.c k QQ6ken/prf.cl AX5ken/rdwri.ck Z] aken/sig.c/l eqken/slp.c$m hrYsken/subr.cu k iken/sys1.cl ߌAken/sys2.c"l ߚfKken/sys3.c k {Xken/sys4.c=l Zken/sysent.cSk ken/text.c k '+ken/trap.cl getd.c vjg@misc/getd.doc o wsys/dmr/dj11.c R 0hsys/dmr/tty.c )R 0usbrk.s gn &y{/* * 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 */ } buf[NBUF]; /* * 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 */ }; /* * This is the head of the queue of available * buffers-- all unused except for the 2 list heads. */ struct buf bfreelist; /* * 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_RELOC 0200 /* no longer used */ #define B_ASYNC 0400 /* don't wait for I/O completion */ #define B_DELWRI 01000 /* don't write till block leaves available list */ ccurs */ #define B_DONE 02 /* transaction finished */ #d/* * Used to dissect integer device code * into major (driver designation) and * minor (driver parameter) parts. */ struct { char d_minor; char d_major; }; /* * 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[]; /* * Nblkdev is the number of entries * (rows) in the block switch. It is * set in binit/bio.c by making * a pass over the switch. * Used in bounds checking on major * device numbers. */ int nblkdev; /* * Character device switch. */ struct cdevsw { int (*d_open)(); int (*d_close)(); int (*d_read)(); int (*d_write)(); int (*d_sgtty)(); } cdevsw[]; /* * Number of character switch entries. * Set by cinit/tty.c */ int nchrdev; int (*d_close)(); int (*d_strategy)(); int *d_tab; } bdevsw[]; /* * Nblkdev is the number of entries * /* * 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 */ int f_inode; /* pointer to inode structure */ char *f_offset[2]; /* read/write character pointer */ } file[NFILE]; /* flags */ #define FREAD 01 #define FWRITE 02 #define FPIPE 04 (*d_close)(); int (*d_strategy)(); int *d_tab; } bdevsw[]; /* * Nblkdev is the number of entries * /* * 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 { int s_isize; /* size in blocks of I list */ int 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 */ int s_time[2]; /* current date of last update */ int pad[50]; }; ze; /* size in blocks of entire volume */ int s_nfree; /* number of in cor/* * 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 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 020/* * 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) */ } inode[NINODE]; /* 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 le 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 */ #/* * tunable variables */ #define NBUF 30 /* size of buffer cache */ #define NINODE 150 /* number of in core inodes */ #define NFILE 150 /* number of in core file structures */ #define NMOUNT 5 /* number of mountable file systems */ #define NEXEC 3 /* number of simultaneous exec's */ #define MAXMEM (64*32) /* max core per process - first # is Kw */ #define SSIZE 20 /* initial stack size (*64 bytes) */ #define SINCR 20 /* increment of stack (*64 bytes) */ #define NOFILE 15 /* max open files per process */ #define CANBSIZ 256 /* max size of typewriter line */ #define CMAPSIZ 100 /* size of core allocation area */ #define SMAPSIZ 100 /* size of swap allocation area */ #define NCALL 20 /* max simultaneous time callouts */ #define NPROC 50 /* max number of processes */ #define NTEXT 40 /* max number of pure texts */ #define NCLIST 500 /* max total clist size */ #define HZ 60 /* Ticks/second of the clock */ /* * 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 20 #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 */ #define SIGBUS 10 /* bus error */ #define SIGSEG 11 /* segmentation violation */ #define SIGSYS 12 /* sys */ #define SIGPIPE 13 /* end of pipe */ /* * fundamental constants * cannot be changed */ #define USIZE 16 /* size of user block (*64) */ #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; }; /* * Certain processor registers */ #define PS 0177776 #define KL 0177560 #define SW 0177570 * end of pipe */ /* * fundamental constants * cannot be changed */ #define USIZE 16 /* size of user block (*64) */ #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; /* * 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_sig; /* signal number sent to this process */ char p_uid; /* user id, used to direct tty signals */ char p_time; /* resident time for scheduling */ char p_cpu; /* cpu usage for scheduling */ char p_nice; /* nice for scheduling */ int p_ttyp; /* controlling tty */ 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 */ } proc[NPROC]; /* stat codes */ #define SSLEEP 1 /* sleeping on high priority */ #define SWAIT 2 /* sleeping on low priority */ #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 */ ng on low priority */ #define SRUN 3 /* running */ #de/* * 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 */ 4 /* 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 */ ng on low priority */ #define SRUN 3 /* running */ #de/* * 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 WO 04 #define RW 06 #define ED 010 /* extend direction */ /* * 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 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 WO 04 #define RW 06 #define ED 010 /* extend direction */ /* * 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 */ #/* * Random set of variables * used by more than one * routine. */ char canonb[CANBSIZ]; /* buffer for erase and kill (#@) */ int coremap[CMAPSIZ]; /* space for core allocation */ int swapmap[SMAPSIZ]; /* space for swap allocation */ int *rootdir; /* pointer to inode of root directory */ int cputype; /* type of cpu =40, 45, or 70 */ int execnt; /* number of processes in exec */ int lbolt; /* time of day in 60th not in time */ int time[2]; /* time in sec from 1970 */ int tout[2]; /* 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 teletypes. */ struct callo { int c_time; /* incremental time */ int c_arg; /* argument to routine */ int (*c_func)(); /* routine */ } callout[NCALL]; /* * 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[NMOUNT]; 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 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/* * 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 */ } text[NTEXT]; lks; /* pointer to clock device */ int rootdev; /* dev of root see conf.c */ int swapdev; /* dev of swap see conf.c */ int swplo/* * 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. (kl.c dc.c dh.c) */ 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_dev; /* device name */ }; char partab[]; /* ASCII table: parity, character class */ #define TTIPRI 10 #define TTOPRI 20 #define CERASE '#' /* default special characters */ #define CEOT 004 #define CKILL '@' #define CQUIT 034 /* FS, cntl shift L */ #define CINTR 0177 /* DEL */ /* limits */ #define TTHIWAT 50 #define TTLOWAT 30 #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 */ fine 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 op/* * 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; /* flag for IO; user or kernel space */ 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 */ int u_utime; /* this process user time */ int u_stime; /* this process system time */ int u_cutime[2]; /* sum of childs' utimes */ int u_cstime[2]; /* 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 */ /* kernel stack per user * extends from u + USIZE*64 * backward not to reach here */ } u; /* u_error codes */ #define EFAULT 106 #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 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 ENT 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 ENOTBLK 15 #define EBUSY 16 #defchdir ken cc -c -O *.c ar r ../lib1 rm *.o chdir ../dmr cc -c -O *.c ar r ../lib2 rm *.o chdir ../conf as m40.s mv a.out m40.o : as m45.s : mv a.out m45.o : cc sysfix.c : mv a.out sysfix cc mkconf.c mv a.out mkconf mkconf rk tm tc done cc -c c.c as l.s ld -x a.out m40.o c.o ../lib1 ../lib2 : as data.s l.s : ld -x -r -d a.out m45.o c.o ../lib1 ../lib2 : nm -ug : sysfix a.out x : mv x a.out cmp a.out /rkunix cp a.out /rkunix mkconf rp tm tc done cc -c c.c as l.s ld -x a.out m40.o c.o ../lib1 ../lib2 : as data.s l.s : ld -x -r -d a.out m45.o c.o ../lib1 ../lib2 : nm -ug : sysfix a.out x : mv x a.out cmp a.out /rpunix cp a.out /rpunix mkconf hp tm tc done cc -c c.c as l.s ld -x a.out m40.o c.o ../lib1 ../lib2 : as data.s l.s : ld -x -r -d a.out m45.o c.o ../lib1 ../lib2 : nm -ug : sysfix a.out x : mv x a.out cmp a.out /hpunix cp a.out /hpunix rm mkconf c.c l.s a.out *.o : rm sysfix x a.out cmp a.out /rkunix cp a.out /rkunix mkconf rp tm tc done cc -c c.c as l.s ld -x a.out m40.o c.o ../lib1 ../lib2 : ammain.o w 7 e   % %F %> Wt p 0 eWpWtN    L z R 7HD@ %2f  %`  % M  7 7   & & e&  % ^wZw V%(@%`#` %( %#5 ww %(_N %_N &f  e%_N &f ` &f T ee%_@@m@me-\_ j% e  @teU %z  % e  @teUDm%z   %  Dm% #  @tU"e# jz%z%  mw,w (@etw  /etc/initmem = %l RESTRICTED RIGHTS Use, duplication or disclosure is subject to restrictions stated in Contract with Western Electric Company, Inc. no clock9yXx(Y8Yi8))H))H )9II9 9I9 Y YI9Y I9I_u "_canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _proc L_text _inode _ka6 _icode#_main"~mainipcsv L2_fuibyte L3B_clearse _mfree L4nL5LL6nL7hL8_printf L9 L10L11LL12z_min _fuiword L13 L14 L15_panic _cinit _binit _iinit _iget _newproc L16_expand _estabur"_copyout L1_sched cret _sureg"~sureguprpaL18L19L20L21L22L23L24L25L17~estaburapnddpntnsasep L27bL28_nseg"L29L30L31L32L33L34L35L36L37L386L396L40BL41TL42HL43TL44XL45rL46L47L48L49L50L51L26~nsegnL52alloc.ol |8w t %   & % 744477w|w x N e  I  `5?Nf %  !Nf de % 2e Nf  w2 N  w N &e Nf& % ; 4 %d#Nf d&e %4  4e  apww DCe - N w w N &e *  a5Nf  e e w<  5 5 KNef 5 @ ` %5 @tp-@tp- %d ap%de% %d 5#4e N  _w PN %d  apww  L-%d%d N 4 4  e%ڂ% ww Q  *#  4nj& % e%΂̵ &  e % 7  w iinitno spacebad blockOut of inodesbad countno fsY)))hx )yyYhx YxYYxh YYYiixyyxH X ih _canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _bdevsw _nblkdev _cdevsw _nchrdev _buf h_bfreeli _inode _u "_iinit"~iinitcpbpcsv _bread _getblk L2BL3_panic _bcopy _brelse cret _alloc"~allocbpipfpdevbno_getfs"L5L20001_sleep L9L10D_badbloc"L11"_wakeup _clrbuf L4@L12_prdev _free"`~free`fpbpipdevbnoL14L20003vL13L16L17_bwrite ~badblocfpbnabnafpdevL100006L19LL20L18H_ialloc"P~iallocPfpbpipijkdevinoL22tL20005dL24L20011|_iget L26L20018L21L20009L28L20007_iput L30zL20017L20015L35ZL20013L384L34hL31L40 _ifree"~ifreefpdevinoL41~getfsn1n2pdevL20020L45.L10002L47*L48L42@L49%_update"D~updateDipmpbpL50L20022VL53L20024L57_iupdat _prele _bflush iget.ol w &  5-(5-$̵̵2!e%   w~ e % ɂtt̕fe f 5  ,fe tl5eSee  w D  24 & &   4  w|w xBʵL Ee5f  5f tA@lee ʵeʵTeTN ww D5 pe5[ U5HN& e5 1e@-%& 5e5  N& @p- & ,ȃ N& = e@-E4 4 ww 6  w@U4  pw @7ZHԔ%VX  ,wLno imtInode table overflow 8xhyyX_canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _u "_inode _bdevsw _nblkdev _cdevsw _nchrdev _buf h_bfreeli _iget"~igetipip1ip2pdevinocsv L2$L20001_sleep L20013L20005*L6L8bL20003JL13_panic L20011jL1~L20007nL16_printf L20008|cret L5_ldiv _bread L17_brelse _iput",_lrem L18L20010~iput,rppL21vL22^_itrunc"2_ifree _iupdat"_prele ~iupdattmrpbpip1ip2ipL23._getfs L25L20015L27L28L29&_bwrite ~itrunc2iprpbpcpdpepL30&L31L20021RL33L35L36L20019zL38L40L41L20017L43_free _maknode"*~maknode*modeip_ialloc L46DL45@_wdir"p~wdirpipcp1cp2L20023_writei prf.ol ~.xw Ce 1 @ %%B %d%l%o %o  v %s eww Nf N& v Nf e0 wLw HD x 5t t tv%     tww w N~ w @@&f eww D  ( Nf& ewpanic: %s %s on dev %l/%l errbn%l er%o %o yyyyyy_ka6 _buf h_bfreeli _bdevsw _nblkdev _cdevsw _nchrdev _panicst _printf"~printfxaxbxccsadxfmtx1x2x3 x4 x5x6x7x8x9csv L3L20001 L1r_putchar"L10000@L5XL10001LL10002P_printn"vL6lL7hL20003bcret ~printnvban_ldiv L10_lrem ~putcharrccsL11L12L14_panic"~panics_update L16~L17"_idle _prdev"(~prdev(devstrL20_deverro"L~deverroLbprbpo1o2L22L23rdwri.ol JLw B 0_4E% Wp  _4B 55E5N  E%`# &E eH  N 59@ 7* @- f& %N& 5rff eN  ww BE% Wp  _t _tB E5N  5E%`  X%& & 5 fff e/N 5*N N   &E e 5    ww u-@wt@w ju-@wZ@w PC@Dmr*Q]p5# &\ P& %j7w`6B (     h(Xxh(xx_inode _u "_buf h_bfreeli _bdevsw _nblkdev _cdevsw _nchrdev _canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _readi"~readibpbnondnipnaiplbncsv L14L5>_lshift _min"L6_dpcmp _bmap L7L8_breada L20000_bread _iomove"_brelse cret _writei"8~writei8bpdnonbnipnaipL11lL10tL14vL15L16L17_getblk L20002L19L20.L21&_bawrite _bdwrite L23d_max"x~maxxabL25L24~minabL27L26~iomovebpanflag cpnotL29L30_copyin L20004_copyout L32L28_dpadd L374L34 _cpass _passc slp.ool b w 0 %  t̕t 7 ~   w t̕t Pw ~C2  e~w\w XD4 ̕H@< 7. ~w"w DEted`% ww  ̥  5e%L% D m J TE%̥.̥+e%L%E%̥̥ 5e%L%D  & %_4@ && e ,m D&& e et& %4_4b w8w 4  * 77 2e%Lʥ  R HB 8  ww 5 7 ~̋ 5-f e%LDm ̕"  4%@ 4 D7C 5˕t  & & %˕ wt N f w Z5tu- NmfN %? N  N& % 5  Nm u-f % wswap errorno procsi )i)i)  )i))i HHX8)i))9)i8   HH )i HHHH9)_u "_proc L_text _canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _file _inode _buf h_bfreeli _sleep"~sleepchanrpspricsv L2\_issig L3P_spl6 _spl0 L4D_wakeup"~_swtch"L5x_aretu L1Xcret ~wakeup~chancipL9L10_setrun"~setrunrppL12L11_setpri"~setpriuppppL15L16_sched"~schedp1rpanL184L19"L20003.L20001@L22^L24|L25_malloc L27<L20005L30L31 L20007L34 L10001_xswap L36pL37l_swap L38_mfree L39b_panic ~swtchL41vrpipvnL42_savu _retu L43L46L47 L44(L50:_idle _sureg L51d_newproc"l~newproclupnpriprppa1a2L53~L20009zL20011L58L59L60mL20013L61L64L65|L66rL67_copyseg _expand"~expandnewsizeinpa1a2L70L69^L71L72:L20015&subr.ol w @55S@5/5LN C5 @ @m@ @m0  %@0 @U@t55@ @mBN 0 w2@ @mN  @ @m7 %@ @m7@ @m0f %4@tEe5 `N 5 @ `AH  f 5D@E5 `N 5@ `N   7 %@ `7w     w@ j w ğ  Ewb jw Duw:w 6w2w .DCB~wY(y((((YYYYYYYyYYYYYYYYyYYhYYyyy_bdevsw _nblkdev _cdevsw _nchrdev _inode _u "_buf h_bfreeli _canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _bmap"~bmapipbnbpnbdibapnbpcsv L2"L20005L9L4_alloc L20004J_bdwrite L12L13:L14(L1cret L10L11$L15H_bread L16L17L18_brelse L19L20L21_passc"~passccL24NL25.L27<L10000jL20006FL23J_subyte _cpass"n~cpassncL29L20009xL28L20008~L31L33_fubyte _nodev"~nodev_nulldev"~nulldev_bcopy"~bcopycounttofromabcL39text.ol =D l<w D 5et l  < f& e ~  f %4p7j w^w Z$0  <54 et& %  ww _8  e % t-0a 4 tle?tEet  e  & & e7 N v e& e3C      % ww D  & %wout of swap spaceswap errorout of textout of swap spaceI(h)I()I(h)I)_canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _u "_proc L_text _inode _xswap"~xswapffosrpapcsv L2_malloc L38L4l_panic _xccdec"<_swap L5fL6~L7~_mfree L1_wakeup cret _xfree"~xfreeipxpL9_iput _xalloc"~xallociprpxptsL138L14L20001L16L15>L21L22JL23L24L25_expand _estabur _readi L264_savu _swtch ~xccdec<rpxpL27htrap.ol GD VPw @E%U@e 7@  x&J NeT N^ l   ~  v wjNe %  >7mENe Ete%)N e E?%?Ete "e  1  N  1e "b d_~U5 _~ _r __rCL  _~ _rw . 7ww d'ww w:::::::n::ka6 = %o aps = %o trap type %o trapIY )8Yhhhh(HIxYIYIY_canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc#_u "_proc L_ka6 _sysent _trap"L10002&L29L5:L10nL11L13L14L15L16L30L31~trappcsppsaidevcallpnps r1r0 csv _savfp L2L6J_printf L7TL8^L9l_panic L3r_psignal L12~_issig L33_psig _setpri L1cret _fuiword L10000L17B_fuword L18L19(L22bL23^L20001F_trap1"L26|L27_backup L32_grow ~trap1f_savu _nosys"~nosys_nullsys"~nullsyssig.ol *Pw t-N& * e%Lww %D t̥d̕d̥ ww Ĝ   Ĝ  wr 5w ` ˕ P  x% , e%L ww J2 57/%% 0 e j&e & 0E x7D  etQ7* ^wZw V78  mI C 55`1FB- 7 @7 >2. e & && e7 t77   ww d t@-@@ & @e 60`(" e  w>v` h`@l &   `w R̥ - 0- e%L:  7 FE7x

e U E_D _ _2Jdcore)i)i)i)9i)9i)hxi)i()i)i  8 H X X 9_canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _u "_proc L_inode _ipc _signal"~signaltppsigcsv L20001L4_psignal"*cret ~psignal*rppsigL6^L7HL8R_setrun _issig"b~issigbnpL20004L12_stop"L10L20003~stopcpppL16L20006_wakeup _swtch L15_procxmt"L17L20008_exit _psig"L10001L35L25~psigrpnpL23nL24_grow"j_suword L22_core"~coreipsL388_schar _namei L39L20012^_maknode _access L42R_itrunc _writei _estabur _iput L10002dL37`~growjsispaiL20020_ldiv L46L43_expand L47L20017_copyseg L50 L20019_clearse _ptrace"~ptracepL54.L53L200222L57LL59^L60t_sleep L61L20024L63L10007(L68L702L71JL72dL73L74L80L81~procxmtipL65L20025L64L69 _fuibyte _fuiword L20028,_fubyte _fuword _suiword L20029L10005L75L76L20027L79sysent.ol 4 (8HXhx(8HXhx(8HXhx_sysent#_nullsys _rexit _fork _read _write _open _close _wait _creat _link _unlink _exec _chdir _gtime _mknod _chmod _chown _sbreak _stat _seek _getpid _smount _sumount _setuid _getuid _stime _ptrace _nosys _fstat _stty _gtty _nice _sslep _sync _kill _getswit _dup _pipe _times _profil _setgid _getgid _ssig clock.ol wP ,w M 2 e  5#   &  e  3ee3@E%  f  h F%<@_5f<, * " -- 5 ʋE%  r2d e%Lۂ7 @E%@e 7 v  n wbw ^ B J e e   !tt_wyXiiiyyyyyh(Ii(yyy_canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _u "_proc L_clock"~clockpcppsppsdevnps r1r0 p1p2csv _display L2xL3$L20001L4(_spl5 L6TL20003BL7ZL8pL20005`L10L12_incupc L13L1L15_spl1 L16_wakeup L17L20007L20RL22"L23@L24D_setpri L26n_issig L28_psig cret _timeout"~timeoutargstfuntimp1p2_spl7 L30L20009L31L32L20011L34L20013fio.ool  "w C % w  w D̵Ee e  E& x ww DE7 yfWp % wf _\_Vw E ww   %jwiY888HX8ii_inode _u "_canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _buf h_bfreeli _namei"~nameiflagdpcpeobpfuncccsv L2_iget L32L20001,L7\L20010BL6PL20014J_iput L20015VL1L20003_access L10L20005L13L12L20007L15L20009_ldiv L17L18@L19_brelse L21:L23~L24V_bmap _bread _bcopy L25L20012L30L31 cret _schar"0~schar0_uchar"D~ucharDc_fubyte L35bpipe.ool w  # ( ʕ2˕3̕w3@ 0  w D% 4 3 5Ee   Ue  , 7 f7b X ww D8   7 $     w% U e 7   7  5Ee w LD& ̵w(w $D̵ w))8YY)(Xx)(XHX()X)(_canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _u "_inode _file _pipe"~pipeiprfwfrcsv _ialloc L1X_falloc L20001jL20003\cret _iput _readp"r~readprfpiprpL5L20005L7_wakeup _prele"L4_sleep _plock"_readi _writep"~writepfpiprpcL10L11<L98L20007_psignal L13j_min _writei ~plockiprpL16L20009~preleiprpL18sys1.ool  ,w    _X %  5@ _65`_6@5 5 $ %_6eBN %_6 %_6  55 `\7 \7 VD 7:7_65 %Om7 e?tE5me?tE5Nff e _67   De$ % 4˵ _6% % q_6na % & f& e7 He7B8 www e@@ A @e5pNf @ ef & ҋ@ fe x5 ` X 5 E5 e%  m %0  %6 N % ww t7\ ww %   e% J  *  % B& %̕,   ,  ʥ e%L e%Lڂ w  , n ʥL f  % 2 2 22 2l@   l    1ʥ   WtUp0 e%L ( _r wxw tˋ e%L  R ? ^7 V7 T7 H7 F7 D7 :  >61`ww  e?tE  t  e`` e ` `zr&  N wx `: &     out of swapXYY(xhxxx(8YXXYii(((X9hxXX9(8iYiX iX h_canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _u "_proc L_buf h_bfreeli _inode _exec"~execapnancbpdsipcptscsepcsv _uchar _namei L2*L1XL20001_sleep _getblk _access L46L5L20015tL7_fubyte L9_fuword L10_readi L11L16_estabur _xfree _expand _xalloc L17L20003L12L20005_clearse _suword L19L20007~L23_subyte L24L25L20009L30L20011L20013,_iput _brelse L36T_wakeup cret _rexit"\~rexit\_exit"t~exittapqL20017L20019L43_closef _malloc L45L46_panic _bcopy _bwrite _mfree L47L20023L50ZL200212L54L_setrun _swtch _wait"l~waitlbpfpL58rL20025vL61^L63"_bread _dpadd L57L65RL66~_fork"~forkp1p2L20027L71L72_newproc L73L67_sbreak"~sbreakadinL75_nseg L76L74L77L78tL20029f_copyseg L80L20031L82sys2.ool . <w  ww  ww C >̰ 87̵ %  77%  6&e "?fwLw H     & $%w"w  ?E  & $%ww CB%5 5 E%@'   rE tE @ 0  w0w ,> 2 0  w w  D̵#=%t 5t5%E ~5    x.5mfe ttwl E5` w N  Ag6E%@  +d - #N0-    ww    R H wpw l d`\jfe F@ff e  (w$" e Nf e wwZ nn  x(8 x x (H x x8 x xHH8H  xH yy8yy yyH_canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _u "_file _inode _read"~readcsv _rdwr" cret _write"~write~rdwr fpmodem_getf L3L4@L5lL6d_readp L8_writep L9_readi L10_writei _dpadd _open"~openip_uchar _namei L11_open1"$_creat"~creatipL13L12 _maknode L20003~open1$ipmodefpimtrfripL16rL17L_access L20L21_itrunc _prele _falloc _openi L15_iput _close"~closefpL22_closef _seek"L10001.L29L32nL33~seekfpntL23L24L25FL27`L20007x_link"~linkipxpL36DL37L38>L10002_suser L39L400_wdir _mknod"H~mknodHipL42nL44L41_sslep"~sslepd_spl7 L20008_dpcmp L20010_spl0 L10003L48 _sleep sys3.ool #$ w  & L ww    & L  ww f @&e @& @&e tle@e5 Nef e % f e % ww     ww 5"   5     "  w| e%  0& f@t %{f e 2J 2& %22E2  w 5; " e%* 5-e % & f@t % 3  w:w 6  E%`I-5 wYhYYxxYhIYXhxYY_canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _buf h_bfreeli _u "_inode _file _bdevsw _nblkdev _cdevsw _nchrdev _fstat"~fstatfpcsv _getf L1_stat1"Lcret _stat""~stat"ip_uchar _namei L2H_iput ~stat1Lipubbpcpi_iupdat _ldiv _bread _lrem L20001_suword L20003_brelse _dup"~dupfpiL10$_ufalloc _smount"(~smount(ipmpdsmp_getmdev"L11L12tL20005hL16L15L20zL10000L10001L19_getblk _bcopy _prele _sumount"4~sumount4ipmpd_update L21L20007PL24\L25nL20009rL28~getmdevipdL30 L31L32sys4.ool . Zw x ww ww 7 ww ğ7 707ww wpw lğ~7 ^ 77wNw JZVuw6w 2j? >w$w ww &%   00ww  3 $ Z E%@ X7    wlw h  E%@{ @& n 7f ww  E8EE4P ww     ww p%%  ? J!0wfw b 5 n    ,%d7\ & e%L܂ 3ww   e%ww E7 E7wunlink -- iget  I h I   I    I 8Hh xI  8H X  h I        x  _u "_inode _canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _proc L_getswit"~getswitcsv cret _gtime"~gtime_stime"&~stime&_suser L3J_wakeup _setuid"N~setuidNuidL10000dL5t_getuid"x~getuidx_setgid"~setgidgidL10001L8_getgid"~getgid_getpid"~getpid_sync"~sync_update _nice"~nicenL14L15_unlink"~unlinkippp_uchar _namei L16_prele _iget L17JL18Z_panic L10002`L19_writei _iput _chdir"~chdiripL20L21L22_access _chmod"~chmodip_owner L23L24_chown""~chown"ipL25L_ssig"P~ssigPaL10003fL27nL26_kill"~killafpqL20001L32L10004L10005L10006_psignal L29_times"~timespL20003_suword _profil",~profil,ir"~chdiripL20L21L22_access _chmod"~chmodip_owner L23L24_chown""~chown"ipL25L_ssig"P~ssigPaL10003fL27nL26_kill"~killafpqmbio.ol 4 w Nf " 5wU &@t   w B N  N " 5 U &@t  #N  N " 5  U @t  N w w DE & t  5  5 ww D t%% rU ww DU wxw tD5@ 5@^E@V 5  6EH0 ww D@t s-3! w  w @-4  %<U@ @t;  t-t-  f5U@& P LwD :< L5U 0003t tw D & 5  ww D 00Uww D5  pU5 E@ wPw L@ ~w8w 4 727,7&7  WpDe Wpet07  %  @ e ww DCL @ tEWt@PUA5UUwVw RDC%FD L EtUA5U8U0w w %F5 U@ 5U BU  e%   e%0ww E 5@ 7 rwnw j bU@& 5@ U  j'ww D57wblkdevdevtab88888HX))(((8I(())(HY8YY)HY())))(()))8Ii h Hi i Yi h i 8H9999988HY)(Y     H  H Y   _u "_buf h_bfreeli _bdevsw _nblkdev _cdevsw _nchrdev _canonb _coremap _swapmap _rootdir _cputype _execnt _lbolt _time _tout _callout x_mount _mpid _runin _runout _runrun _curpri _maxmem _lks _rootdev _swapdev _swplo _nswap _updlock _rablock _regloc _proc L_ka6 _buffers _swbuf _tmtab _httab _bread"~breaddevrbpblknocsv _getblk""L2 L20000cret _iowait"_breada"B~breadaBadevrabpdevrbpblknorablkno_incore"L4L6L7_brelse"L9L3_bwrite"~bwritebpflagrbpL11,L108_geterro"_bdwrite"<~bdwrite<bpdprbpL10000\L15d_bawrite"rL14n~bawriterbprbp~brelsebpbackprbpspsL19_wakeup L20L21_spl6 ~incoreadevbpdpdevblknoL23L20002L25L22~getblk"bpdpdevblknoL30bL294_panic L20004:L32>L39L20007X_sleep _spl0 L33~L34;L35L37L38_notavai"LL20008L40~iowaitbprbpL428L20010,~notavaiLbprbpsps_iodone"|~iodone|bprbpL46_mapfree"pL47L45_clrbuf"~clrbufbpcpL52_binit"~binitbpdpibdpL20012L57RL200148L60J_devstar"`~devstar`bpdpdevblkdevlochbcom comrbpL62L63_rhstart"~rhstartbpabae dpdevblkdevloccomrbpL65L66L67_maplock _mapallo"~mapallobpabpiaL68lL69L20016L20018>L74`L20020T~mapfreepbpL78_swap"~swapcountfpcoreaddrrdflg blknoL80L20022L82L20024L840_bflush"B~bflushBbpdevL86hL20026HL10001XL89xL87|L20028r_physio"~physiostratbpbasenbrw abptsdevL92 L93L10002L94*L20030L10003VL10004Z_lshift L96L20032L98L91~geterrobpabpL990tty.ol (< w Ce & e& e& ww x 7ne 7be 7V ww | E%  fWp %w6& @5 '\ %  %(( 5\( %  %5eD-w BCE% 5 5 %%%  <4%5%A%Ze  5 % %   5 $  ww CDE%5 _% 5  $ _5ҋ !\ $ %a%ze% 5 $ e & Ze5 E B xʋ=ʊ;tE5%ʋt&e % tE5% U@%  e &U wx5@tE5%% w L84&_timeout _ttread"B~ttreadBatptpL86|L88b_passc _ttwrite"~ttwriteatptpcL91L90L20015L93L20013_cpass _ttystty"~ttysttyatpavtpvL96L95dc.o.ol p4@xw %FDueCteUA#@II5  &  0tw\w XDue45E w0w ,@te ww @te ww Due % e ww Due5E&  (55 E 5@ 5 w$w DueN& E 4EE TwAIQYAIQY IxhIy xy xy xXy xy xxy xhy_bdevsw _nblkdev _cdevsw _nchrdev _u "_partab _proc L_dc11 _dcrstab#4_dctstab#T_dcopen"~dcopenflagaddrdevrtpcsv L2L1L3dL5~L20001r_sleep cret _dcclose"~dcclosetpdevL9_wflusht _dcread"~dcreaddev_ttread _dcwrite"~dcwritedev_ttwrite _dcxint"~dcxinttpdev_ttstart L10000(L122_wakeup _dcrint"6~dcrint6tpcdevcsrL15L16L17z_signal _flushtt L14L10001L18L19L10003L10002_ttyinpu _dcsgtty"~dcsgttyavtprdev_ttystty L210L22L23dn.o.ol :xw C e̕Eww @ ww D e ̵ŀw̵  ̵ l%-  e4w 0 w$III8_bdevsw _nblkdev _cdevsw _nchrdev _u "_dnopen"~dnopenflagdprdevdevcsv L2 L1*cret _dnclose".~dnclose.dev_dnwrite"B~dnwriteBdpcdevL8`L20001R_sleep L10jL11|L5x_cpass L12_lbolt _dnint"~dnintdev_wakeup dp.o.ol Clw -.%7  77<<&  %ߕBaww   77 z 7 rwnw jf XY L  8  !` %&&  eww  ># F 7% &  e Rww 5 5  w ~ fw ` a ZğR NE@ EQ27.7.w$w # <&  %ww ėE5Ue-? ww E5  5 *ww E  y7tj7f wXyIyIIyyyyyy(9yyyyxy9yxy x( IIyX9IyyyIIIyIyX9yI 9yx( yyyyhyyy9yyy(9yyyyy9y9yyyyyx9_bdevsw _nblkdev _cdevsw _nchrdev _u "_buf h_bfreeli _dp11 _dpopen"~dpopenflagdevcsv L2L1dL3R_getblk _dptimeo"_timeout cret _dpclose"h~dpclosehL4_brelse _dpread"~dpreadbpeppL7L20001_spl6 L9_spl0 L6_sleep _dpwait"N_min _iomove _dpwrite"~dpwritebpL10JL11,_dpstart"~dpwaitNL13RL10000`L15~L12zL20003lL16~dpstartcL18_partab L17~dptimeoL20L21_dpturna"v_dprint" ~dprint cL22BL24(_dpxint"F~dpxintFdpstatL27`L26r~dpturnavL31_wakeup kl.ooY x|`w %8Cte sDuepeeH3 #@UCU@wxw tDue 4wZw V@te w@w <@te w&w "Due % e ww BteU53& ww DueN& wIxIYxYxYx(YxxYx(YxY_bdevsw _nblkdev _cdevsw _nchrdev _u "_partab _proc L_kl11 _klopen"~klopenflagaddrtpdevcsv L2L1L34L4JL5VL6zcret _klclose"~klclosetpdev_wflusht _klread"~klreaddev_ttread _klwrite"~klwritedev_ttwrite _klxint"~klxinttpdev_ttstart L10000L10_wakeup _klrint" ~klrint addrtpcdevL132_ttyinpu _klsgtty"@~klsgtty@tpvdev_ttystty mem.ol vdFw AB  E tE mE@` __ ~ wjw f7 7aB w>B nE "Q tE mE@` __  )YHY hy y 9 )YXY_u "_bdevsw _nblkdev _cdevsw _nchrdev _ka6 _mmread"~mmreadbnoncaddevcsv L1L4_lshift _spl7 L5j_fuibyte _spl0 _passc cret _mmwrite"~mmwritebnoncaddevL8_dpadd L6_cpass L10*_suibyte pc.ol $w  !%Ah U@l vww    h7  Fww ~%v5hUAh    >w:w 6 t *w"w 5l nww %5h!%5hj %UAh ww ~%2 ww 5l%dz( f P * HwDw @d tw0YIYY)XY)YXXH))X)YYYYXhYXx)YXx)IYXXh))_bdevsw _nblkdev _cdevsw _nchrdev _u "_pc11 _pcopen"~pcopenflagdevcsv L2<L3L1FL4_lbolt _sleep _pcleade"cret _pcclose"J~pccloseJflagdevL8r_spl4 L9X_getc _spl0 L7v_pcread"z~pcreadzcL16L20001L18L19_passc _pcwrite"~pcwritecL21L20003_pcoutpu"t_cpass _pcstart"~pcstartcL23_pcrint"~pcrintL26L25TL280L29L_putc _wakeup _pcpint"X~pcpintXL31p~pcoutputcL34L33L35~pcleadeiL39rf.ol t*w D5 t -U 4  707  ww 8 t&6& ewjw fb$b7X 080& %09 3 U7)7( zww f eww  f ew9yyyyyyyyyy8yyyy_buf h_bfreeli _bdevsw _nblkdev _cdevsw _nchrdev _u "_rftab _rrfbuf _rfstrat"~rfstratbpabpcsv L2_mapallo L30_iodone L1^_spl5 L4DL5LL6Z_rfstart"b_spl0 cret ~rfstartbbpL7_devstar _rfintr"~rfintrbpL8L9_deverro L20000_rfread"~rfreaddev_physio _rfwrite" ~rfwrite devrk.ol 4w D5 e5AWp-U 4  707 t ww D e5 5N 5N  r f r tUAWt @Pww  & ~ & & eww (7 & %5 U77 zww f ewtw p f ewV (Xyyyyyy x yy yyy(yyyyX  _buf h_bfreeli _bdevsw _nblkdev _cdevsw _nchrdev _u "_rktab _rrkbuf _rkstrat"~rkstratbpqcqldabpcsv L2_mapallo L3*L4D_iodone L1r_spl5 L5XL6`L7n_rkstart"_spl0 cret _rkaddr"v~rkaddrvbpbdmpL9L10_lrem _ldiv ~rkstartbpL11 _devstar _rkintr"~rkintrbpL12hL13T_deverro L14<L20000d_rkread"l~rkreadldev_physio _rkwrite"~rkwritedevtc.ol w N @E0ww D5 %B EU 4  707  w|w x 7v˕U ^' EE @ ˕/( tUC5U ww 565 & %5 E7E U77! ,!5EU˕Cwz  xߕ  - -؂"" Et5 @PUA e-HHxyyyyyyxyyyyyHyyyyyyyxy_bdevsw _nblkdev _cdevsw _nchrdev _buf h_bfreeli _u "_tctab _tcper _tcclose"~tcclosedevcsv _bflush cret _tcstrat"~tcstratbpabpL30_mapallo L10000FL4R_iodone L2_spl6 L5fL6nL7|_tcstart"_spl0 ~tcstartbpcomtccmpL9L20001L11L8L12L13_tcintr"L10004L29L30L19H~tcintrbptccmptcdtpL15~L16$_deverro L17:L18ZL27L28L23lL21`L22vL14zL10001L10002tm.ol  hw D#  0  ww D4 & ^ & ^ ww  5R@t@]U`Rwhw dD e - - U  !55 4   707   ww U7 W 5 @5RtEWt@PU@`--U   UU TRV TV57 PRw w J R(5Z5P   7*%5@PU7 77 T 0 w~w zN f el 7wLw HN  f e7 fw"w DB    wiII(yI yyyyyYIyyyyyIyyyyyyyyyyIXiIXiIhI_buf h_bfreeli _bdevsw _nblkdev _cdevsw _nchrdev _u "_tmtab _rtmbuf _t_openf _t_blkno _t_nxrec _tmopen"~tmopenflagdminordevcsv L2L1,cret _tmclose"0~tmclose0flagdminordevL5N_tcomman"^~tcomman^unitcomL7rL10000d_lbolt _sleep _tmstrat"~tmstratbpabppL10L11L20002L20004_clrbuf _iodone L9 L13_spl5 L14L15L16_tmstart"_spl0 ~tmstartbpunitcomblknoL18(L10001L17L20L21L20006L23L22L10002L10003L10004_tmintr"~tmintrbpunitL25~L26DL27L29&L31:L34zL33p_tmread"~tmreaddev_tmphys"_physio _tmwrite"~tmwritedev~tmphysunitadev_lshift partab.ol { _partab#rp.ob.ol 2 $w D5  Ete2@ "U L4      rWtPt r4` vx7r3-, 3-,34  *w&w "$ t&& eww :7 && %5 ߕ  5~ 5~ U77 Nwpw lN  f ewDw @N   f eww B >e `@Et0!2 w##hN<_iodone L1_lrem _ldiv _spl5 L6L5L7L10001L8L9_rpstart"_spl0 cret ~rpstartbpL10 _devstar _rpintr"~rpintrbpctrL11L12r_deverro L13PL14FL16XL17bL20000_rpread"~rpreaddev_rpphys"L19_physio _rpwrite"~rpwritedevL21~rpphyscdev_lshift L24,L23(lp.o.ol o4w 5 L UU@L ^ww  ^7 ww  ^ ww D5%a%z e7 y 7p y ( )'!^ ^ B-8eE7,w5  7  %<5  % 7 7 5  - 7 %P  -  w x N5LwZw V %2L F w8w 4%d.  f w`{|}~~ 6"~BYIYYYYYYYYYYYYYYYYYYYYYYYYYYYYXYYXXYXX_bdevsw _nblkdev _cdevsw _nchrdev _u "_lp11 _lpopen"~lpopenflagdevcsv L10000L2L1._lpcanon"^cret _lpclose"2~lpclose2flagdev_lpwrite"F~lpwriteFcL5RL20001L_cpass L10002L10003 L16L13L17L15L18L8~L10007L10008$L296L21L23L27"L31~L32B~lpcanon^cc1c2L9L10009L10004L14L7L10005L25_lpoutpu"L33VL35lL20003`_lpstart"~lpstartcL38L20005_getc L37_lpint"~lpintcL10010L40_wakeup ~lpoutpucL43_sleep _putc _spl4 _spl0 dhdm.ol /w Due@@B5@B`@  &  ww Due5 @@B`@w|w x5@0@Eue\te! 5@B &  B `@w X)X)XiX)_partab _bdevsw _nblkdev _cdevsw _nchrdev _dh11 _ndh11 _dmopen"~dmopentpdevcsv L2,_spl5 L3DL200018_sleep _spl0 cret _dmclose"T~dmcloseTtpdevL5_dmint"~dminttpL7L9_wakeup L10L11_signal _flushtt dh.ool ) "tw %6Due8tU@0 #@ hN  0w|w xDueN  wTw P@te w:w 6@te w w ' #uEue%55 5   ww DueN&  hww D U@0U +t Wt@PU@5 5@UUU2U ww @ A @@E0 @@  8 e ww  B!aNte5 % e %/2% @@e !U@0@`tQ7Q" = 2Ee %_w IxhIy xy xy xXy xxy xxy Yy xy y_bdevsw _nblkdev _cdevsw _nchrdev _u "_partab _proc L_dh11 _dh_clis _ndh11#"_dhsar _dhopen"~dhopenflagtpdevcsv L2L1_dhstart"8L3^_dhparam"h_dmopen cret _dhclose"~dhclosetpdev_dmclose _wflusht _dhread"~dhreaddev_ttread _dhwrite"~dhwritedev_ttwrite _dhrint"~dhrinttpcL94L10000_wakeup L20002L12*L13&_ttyinpu _dhsgtty">~dhsgtty>avtprdev_ttystty L15d~dhparamhtpatplpr_spl5 L17L16L18L19L20L21L24_spl0 _dhxint"~dhxinttpttybitbarL260L20004L29*~dhstart8cptpcnchatpspsL31L20013L33nL34_getc L35L36L37_ttrstrt _timeout dhfdm.ol 4"w Dueww wX_partab _bdevsw _nblkdev _cdevsw _nchrdev _dh11 _dmopen"~dmopentpdevcsv cret _dmclose"~dmclosedevsys.ool w  f&Wp %ww b &Wp  ww @ &Wp  ww  f&Wp %wpw lwV((((II_bdevsw _nblkdev _cdevsw _nchrdev _u "_partab _proc L_syopen"~syopenflagtpdevcsv _syttyp"L1"cret _syread"&~syread&tpdevL3D_sywrite"H~sywriteHtpdevL5f_sysgtty"j~sysgttyjflagtpdevL7~syttyptpL10hp.ool MP $w   ww D EteP@ "U L4    rWtPt r4` XZ7T3-, 3-,3  ww  t&& eww 775@" & %5p   5 ~ } w U7m7l NwRw NN  f* ew&w "N   f* eww B  e `@Et0!P w%,Qfd,Ihii_buf h_bfreeli _bdevsw _nblkdev _cdevsw _nchrdev _u "_hp_size#P_hptab _hpbuf _hp_open _hpopen"~hpopencsv L1&cret _hpstrat"*~hpstrat*bpabpp1p2L10000PL4\_iodone L3_lrem _ldiv _spl5 L7L6L8L10001L9L10_hpstart"_spl0 ~hpstartbpL11._rhstart _hpintr"2~hpintr2bpctrL12L13_deverro L14zL15pL20000_hpread"~hpreaddev_hpphys"L18_physio _hpwrite"~hpwritedevL20~hpphyscdev_lshift L23JL22Fht.ool _ w DE% 0   f ww DE4 f f f wvw rD Z5 tE( 5*%@EUEU: *E%@U ww D E e - - U  !55 4  707zn  dw`w \^a tE(%@EUEU:E 5 U7 -- &Y  G &[ < &&& eww O E5@ *5* % @ 5*H C = 7. U"7 77 & 0 ww N xf$ e 7ww N x f$ e7 ww DB    wZiii8Hy8H8HiHXyyyyyiyyXyyiyyyyyyyyyyXiiiiih(i_buf h_bfreeli _bdevsw _nblkdev _cdevsw _nchrdev _u "_httab _rhtbuf _h_openf _h_blkno _h_nxrec _htopen"~htopenflagunitdevcsv L10000L2 L1B_hcomman"cret _htclose"F~htcloseFflagunitdevL5x~hcommanunitdevcomL7L10001_lbolt _sleep L9L20002L11L20003L13L20005_htstrat"$~htstrat$bpabppL16`L17ZL20007RL20009L_clrbuf _iodone L15L19n_spl5 L20L21L22_htstart"_spl0 ~htstartbpunitblknoL24L23lL25L20010L10002L27L28LL29,L31:_rhstart _htintr"p~htintrpbpunitL33L34L35L37L40L39 _htread"~htreaddev_htphys"x_physio _htwrite"N~htwriteNdev~htphysxunitadev_lshift hs.ool T4(w D  U 4  707  ww   E(8 &&& ew`w \X$X7N5@  (& % / ) U77 jw w f eww  f ew9yyyyyyyyyyXyyyy_buf h_bfreeli _bdevsw _nblkdev _cdevsw _nchrdev _u "_hstab _rhsbuf _hsstrat"~hsstratbpabpmblkscsv L2L3*_iodone L1X_spl5 L4>L5FL6T_hsstart"\_spl0 cret ~hsstart\bpaddrL7L8x_rhstart _hsintr"~hsintrbpL9L10_deverro L20000_hsread"~hsreaddev_physio _hswrite"~hswritedevdr.ooY nXTw %wDue  AWt@4`w Due  e  < w|w xDue + d &e %2   e   % N @  ww Due  &e e   ww Due5+ %#e &&e tU1U@ % e E@wNw JDuee et& e w )hh)hY)hYx)h)h)_u "_bdevsw _nblkdev _cdevsw _nchrdev _partab _dr11 _dropen"~dropenflagjunkaddpdevcsv L2L3 L1cret _drclose"F~drcloseFpdevL6fL20001X_lbolt _sleep L8l_getc _drwrite"~drwritecpdevwL11L20007_spl5 L13L20003L15L20005_putc L17_drxint"@_spl0 _cpass _drread"~drreadcpdevwL22 L20009_passc ~drxint@cpdevwL24L25L10000_wakeup _drrint"~drrintcpdevwc _drwrite"~drwritecpdevwL11L20007_spl5 L13L20003L1# /* */ #include "../param.h" #include "../systm.h" #include "../filsys.h" #include "../conf.h" #include "../buf.h" #include "../inode.h" #include "../user.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[rootdev.d_major].d_open)(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; time[0] = cp->s_time[0]; time[1] = cp->s_time[1]; } /* * 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) 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); fp->s_fmod = 1; return(bp); nospace: fp->s_nfree = 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; wakeup(&fp->s_flock); } fp->s_free[fp->s_nfree++] = bno; 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; fp->s_fmod = 1; return(ip); } /* * Inode was allocated after all. * Look some more. */ iput(ip); goto loop; } fp->s_ilock++; ino = 0; for(i=0; is_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; ks_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; 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); if(fp->s_ilock) return; if(fp->s_ninode >= 100) return; fp->s_inode[fp->s_ninode++] = ino; fp->s_fmod = 1; } /* * 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 < &mount[NMOUNT]; 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 < &mount[NMOUNT]; 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; bp = getblk(mp->m_dev, 1); ip->s_fmod = 0; ip->s_time[0] = time[0]; ip->s_time[1] = time[1]; bcopy(ip, bp->b_addr, 256); bwrite(bp); } for(ip = &inode[0]; ip < &inode[NINODE]; ip++) if((ip->i_flag&ILOCK) == 0) { ip->i_flag =| ILOCK; iupdat(ip, time); prele(ip); } updlock = 0; bflush(NODEV); } [0]; mp < &mount[NMOUNT]; mp++) if(mp->m_bufp != NULL) { # #include "../param.h" #include "../systm.h" #include "../user.h" #include "../proc.h" #define UMODE 0170000 #define SCHMAG 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; /* * 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]; 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: 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; if(++time[1] == 0) ++time[0]; spl1(); if(time[1]==tout[1] && time[0]==tout[0]) wakeup(tout); if((time[1]&03) == 0) { runrun++; wakeup(&lbolt); } for(pp = &proc[0]; pp < &proc[NPROC]; pp++) if (pp->p_stat) { if(pp->p_time != 127) pp->p_time++; if((pp->p_cpu & 0377) > SCHMAG) pp->p_cpu =- SCHMAG; else pp->p_cpu = 0; if(pp->p_pri > PUSER) setpri(pp); } if(runin!=0) { runin = 0; wakeup(&runin); } 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. */ 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++; } p1->c_time =- t; p2 = p1; while(p2->c_func != 0) 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; } ry has the effect of * updating all entries. */ 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# /* */ #include "../param.h" #include "../user.h" #include "../filsys.h" #include "../file.h" #include "../conf.h" #include "../inode.h" #include "../reg.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(rf<0 || rf>=NOFILE) goto bad; fp = u.u_ofile[rf]; if(fp != NULL) return(fp); bad: u.u_error = EBADF; return(NULL); } /* * Internal form of close. * Decrement reference count on * file structure and call closei * on last closef. * Also make sure the pipe protocol * does not constipate. */ closef(fp) int *fp; { register *rfp, *ip; rfp = fp; if(rfp->f_flag&FPIPE) { ip = rfp->f_inode; ip->i_mode =& ~(IREAD|IWRITE); wakeup(ip+1); wakeup(ip+2); } if(rfp->f_count <= 1) closei(rfp->f_inode, rfp->f_flag&FWRITE); rfp->f_count--; } /* * Decrement reference count on an * inode due to the removal of a * referencing file structure. * On the last closei, switchout * to the close entry point of special * device handler. * Note that the handler gets called * on every open and only on the last * close. */ closei(ip, rw) int *ip; { register *rip; register dev, maj; rip = ip; dev = rip->i_addr[0]; maj = rip->i_addr[0].d_major; if(rip->i_count <= 1) switch(rip->i_mode&IFMT) { case IFCHR: (*cdevsw[maj].d_close)(dev, rw); break; case IFBLK: (*bdevsw[maj].d_close)(dev, rw); } iput(rip); } /* * openi called to allow handler * of special files to initialize and * validate before actual IO. * Called on all sorts of opens * and also on mount. */ openi(ip, rw) int *ip; { register *rip; register dev, maj; rip = ip; dev = rip->i_addr[0]; maj = rip->i_addr[0].d_major; switch(rip->i_mode&IFMT) { case IFCHR: if(maj >= nchrdev) goto bad; (*cdevsw[maj].d_open)(dev, rw); break; case IFBLK: if(maj >= nblkdev) goto bad; (*bdevsw[maj].d_open)(dev, rw); } return; bad: u.u_error = ENXIO; } /* * 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 except for EXEC where * at least one of the EXEC bits must * be on. */ 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) { if(m == IEXEC && (ip->i_mode & (IEXEC | (IEXEC>>3) | (IEXEC>>6))) == 0) goto bad; 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() { if(u.u_uid == 0) return(1); u.u_error = EPERM; return(0); } /* * Allocate a user file descriptor. */ ufalloc() { register i; for (i=0; if_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); } 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 < &file[NFILE]; fp++) if (fp->f_count==0) { u.u_ofile[i] = fp; fp->f_count++; fp# #include "../param.h" #include "../systm.h" #include "../user.h" #include "../inode.h" #include "../filsys.h" #include "../conf.h" #include "../buf.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 file * system 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 < &inode[NINODE]; 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 < &mount[NMOUNT]; 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); } 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; ifree(rp->i_dev, rp->i_number); } iupdat(rp, time); 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 corresponding dates * set to the argument tm. */ iupdat(p, tm) int *p; int *tm; { register *ip1, *ip2, *rp; int *bp, i; rp = p; if((rp->i_flag&(IUPD|IACC)) != 0) { if(getfs(rp->i_dev)->s_ronly) 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[0]; *ip1++ = time[1]; } else ip1 =+ 2; if(rp->i_flag&IUPD) { *ip1++ = *tm++; *ip1++ = *tm; } bwrite(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+512; cp >= bp->b_addr; cp--) if(*cp) { if(ip == &rp->i_addr[7]) { dp = bread(rp->i_dev, *cp); for(ep = dp->b_addr+512; ep >= dp->b_addr; ep--) if(*ep) free(rp->i_dev, *ep); brelse(dp); } free(rp->i_dev, *cp); } 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) 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); } _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 * # #include "../param.h" #include "../user.h" #include "../systm.h" #include "../proc.h" #include "../text.h" #include "../inode.h" #include "../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: */ 0061564, 0064457, 0064556, 0000164, }; /* * Initialization code. * Called from m40.s or m45.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() { extern schar; register i, *p; /* * zero and free all of core */ updlock = 0; 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++; } if(cputype == 70) for(i=0; i<62; i=+2) { UBMAP->r[i] = i<<12; UBMAP->r[i+1] = 0; } printf("mem = %l\n", maxmem*5/16); 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 * with system process */ if(newproc()) { expand(USIZE+1); estabur(0, 1, 0, 0); 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 *up, *rp, a; a = u.u_procp->p_addr; up = &u.u_uisa[16]; rp = &UISA->r[16]; if(cputype == 40) { up =- 8; rp =- 8; } while(rp > &UISA->r[0]) *--rp = *--up + a; if((up=u.u_procp->p_textp) != NULL) a =- up->x_caddr; up = &u.u_uisd[16]; rp = &UISD->r[16]; if(cputype == 40) { up =- 8; rp =- 8; } while(rp > &UISD->r[0]) { *--rp = *--up; if((*rp & WO) == 0) rp[(UISA-UISD)/2] =- a; } } /* * 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. */ estabur(nt, nd, ns, sep) { register a, *ap, *dp; if(sep) { if(cputype == 40) goto err; if(nseg(nt) > 8 || nseg(nd)+nseg(ns) > 8) goto err; } else if(nseg(nt)+nseg(nd)+nseg(ns) > 8) goto err; if(nt+nd+ns+USIZE > maxmem) goto err; a = 0; ap = &u.u_uisa[0]; dp = &u.u_uisd[0]; while(nt >= 128) { *dp++ = (127<<8) | RO; *ap++ = a; a =+ 128; nt =- 128; } if(nt) { *dp++ = ((nt-1)<<8) | RO; *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]; 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); err: u.u_error = ENOMEM; return(-1); } /* * Return the arg/128 rounded up. */ nseg(n) { return((n+127)>>7); } = 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]; # /* */ /* * Structure of the coremap and swapmap * arrays. Consists of non-zero count * and base address of that many * contiguous units. * (The coremap unit is 64 bytes, * the swapmap unit is 512 bytes) * The addresses are increasing and * the list is terminated with the * first zero count. */ struct map { char *m_size; char *m_addr; }; /* * Allocate size units from the given * map. Return the base of the allocated * space. * 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; { register struct map *bp; register int t; register int a; a = aa; for (bp = mp; 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; 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); } } e!=0; bp++); if (bp>mp && (bp-1)->m_addr+(bp-1)->m_size == a) { (bp-1)->m_size =+ size; 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# #include "../param.h" #include "../inode.h" #include "../user.h" #include "../systm.h" #include "../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 * must have x permission. */ if((dp->i_mode&IFMT) != IFDIR) { 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 dp->i_flag =| IUPD; 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; 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); } 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); } && c=='\0') { if(access(dp, IWRITE)) goto out; return(dp); } bp = dp->i_dev; iput(dp); dp = iget(bp, u.u_dent.u_ino); if(dp == NULL) retur# /* */ #include "../param.h" #include "../systm.h" #include "../user.h" #include "../inode.h" #include "../file.h" #include "../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; } /* * 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 the head (read) has caught up with * the tail (write), reset both to 0. */ if(rp->f_offset[1] == ip->i_size1) { if(rp->f_offset[1] != 0) { rp->f_offset[1] = 0; ip->i_size1 = 0; if(ip->i_mode&IWRITE) { ip->i_mode =& ~IWRITE; wakeup(ip+1); } } /* * 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]; prele(ip); } /* * 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. */ 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); } } akeup(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 gene# /* */ #include "../param.h" #include "../seg.h" #include "../buf.h" #include "../conf.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,x2,x3,x4,x5,x6,x7,x8,x9,xa,xb,xc) 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); } 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; { 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, dev.d_major, dev.d_minor); } /* * 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; rbp = bp; prdev("err", rbp->b_dev); printf("bn%l er%o %o\n", rbp->b_blkno, o1, o2); } ge 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, dev.d_major, dev.d_minor); } /* * deverr prints a diagnostic from * a device driver. * It pri# /* */ #include "../param.h" #include "../inode.h" #include "../user.h" #include "../buf.h" #include "../conf.h" #include "../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 */ 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[ip->i_addr[0].d_major].d_read)(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) bp = breada(dn, bn, rablock); else bp = bread(dn, bn); ip->i_lastr = lbn; iomove(bp, on, n, B_READ); brelse(bp); } while(u.u_error==0 && u.u_count!=0); } /* * 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 */ 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[ip->i_addr[0].d_major].d_write)(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, 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; n = an; cp = bp->b_addr + o; if(u.u_segflg==0 && ((n | cp | u.u_base)&01)==0) { if (flag==B_WRITE) cp = copyin(u.u_base, cp, n); else cp = copyout(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; } struct buf *bp; { register char *cp; register int n, t; n = an; cp = bp->b_addr + o; if(u.u_segflg==0 && ((n | cp | u.u_base)&01)==0) { if (flag==B_WRITE) cp = copyin(u.u_base, cp, n); else cp = copyout(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==# /* */ #include "../param.h" #include "../systm.h" #include "../user.h" #include "../proc.h" #include "../inode.h" #include "../reg.h" /* * Priority for tracing */ #define IPCPRI (-1) /* * 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 'tp' as its * controlling teletype. * Called by tty.c for quits and * interrupts. */ signal(tp, sig) { register struct proc *p; for(p = &proc[0]; p < &proc[NPROC]; p++) if(p->p_ttyp == tp) psignal(p, sig); } /* * Send the specified signal to * the specified process. */ psignal(p, sig) int *p; { register *rp; if(sig >= NSIG) return; rp = p; if(rp->p_sig != SIGKIL) rp->p_sig = sig; if(rp->p_stat > PUSER) rp->p_stat = PUSER; if(rp->p_stat == SWAIT) 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; if(n = p->p_sig) { if (p->p_flag&STRC) { stop(); if ((n = p->p_sig) == 0) return(0); } if((u.u_signal[n]&1) == 0) return(n); } 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. */ stop() { register struct proc *pp, *cp; loop: cp = u.u_procp; if(cp->p_ppid != 1) for (pp = &proc[0]; pp < &proc[NPROC]; 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; n = rp->p_sig; rp->p_sig = 0; if((p=u.u_signal[n]) != 0) { u.u_error = 0; if(n != SIGINS && n != SIGTRC) u.u_signal[n] = 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: 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(); } /* * 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); 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); 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)) 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. */ ptrace() { register struct proc *p; if (u.u_arg[2] <= 0) { u.u_procp->p_flag =| STRC; return; } for (p=proc; p < &proc[NPROC]; 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; 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) 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 (for now, always an error) */ case 4: if (suiword(ipc.ip_addr, 0) < 0) goto error; suiword(ipc.ip_addr, ipc.ip_data); 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; 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 = ipc.ip_data; return(1); /* force exit */ case 8: exit(); default: error: ipc.ip_req = -1; } return(0); } e 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; 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 = ipc.ip_data; return(1); /* force exit */ case 8: exit(); defaul# /* */ #include "../param.h" #include "../user.h" #include "../proc.h" #include "../text.h" #include "../systm.h" #include "../file.h" #include "../inode.h" #include "../buf.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; if(pri >= 0) { if(issig()) goto psig; spl6(); rp->p_wchan = chan; rp->p_stat = SWAIT; rp->p_pri = pri; spl0(); if(runin != 0) { runin = 0; wakeup(&runin); } swtch(); if(issig()) goto psig; } else { spl6(); rp->p_wchan = chan; rp->p_stat = SSLEEP; rp->p_pri = pri; 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) */ 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 = NPROC; do { if(p->p_wchan == c) { setrun(p); } p++; } while(--i); } /* * 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; if(rp->p_pri < curpri) runrun++; if(runout != 0 && (rp->p_flag&SLOAD) == 0) { runout = 0; wakeup(&runout); } } /* * Set user priority. * The rescheduling flag (runrun) * is set if the priority is higher * than the currently running process. */ setpri(up) { register *pp, p; pp = up; p = (pp->p_cpu & 0377)/16; p =+ PUSER + pp->p_nice; if(p > 127) p = 127; if(p > curpri) runrun++; pp->p_pri = 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. * Although it is not remarkably evident, the basic * synchronization here is on the runin flag, which is * slept on and is set once per second by the clock routine. * Core shuffling therefore takes place once per second. * * panic: swap error -- IO error while swapping. * this is the one panic that should be * handled in a less drastic way. Its * very hard. */ sched() { struct proc *p1; register struct proc *rp; register a, n; /* * find user to swap in * of users ready, select one out longest */ goto loop; sloop: runin++; sleep(&runin, PSWP); loop: spl6(); n = -1; for(rp = &proc[0]; rp < &proc[NPROC]; rp++) if(rp->p_stat==SRUN && (rp->p_flag&SLOAD)==0 && rp->p_time > n) { p1 = rp; n = rp->p_time; } if(n == -1) { runout++; sleep(&runout, PSWP); goto loop; } /* * see if there is core for that process */ spl0(); rp = p1; a = rp->p_size; if((rp=rp->p_textp) != NULL) if(rp->x_ccount == 0) a =+ rp->x_size; if((a=malloc(coremap, a)) != NULL) goto found2; /* * none found, * look around for easy core */ spl6(); for(rp = &proc[0]; rp < &proc[NPROC]; rp++) if((rp->p_flag&(SSYS|SLOCK|SLOAD))==SLOAD && (rp->p_stat == SWAIT || rp->p_stat==SSTOP)) goto found1; /* * no easy core, * if this process is deserving, * look around for * oldest process in core */ if(n < 3) goto sloop; n = -1; for(rp = &proc[0]; rp < &proc[NPROC]; rp++) if((rp->p_flag&(SSYS|SLOCK|SLOAD))==SLOAD && (rp->p_stat==SRUN || rp->p_stat==SSLEEP) && rp->p_time > n) { p1 = rp; n = rp->p_time; } if(n < 2) goto sloop; rp = p1; /* * swap user out */ found1: spl0(); rp->p_flag =& ~SLOAD; xswap(rp, 1, 0); goto loop; /* * swap user in */ found2: if((rp=p1->p_textp) != NULL) { if(rp->x_ccount == 0) { if(swap(rp->x_daddr, a, rp->x_size, B_READ)) goto swaper; rp->x_caddr = a; a =+ rp->x_size; } rp->x_ccount++; } rp = p1; if(swap(rp->p_addr, a, rp->p_size, B_READ)) goto swaper; mfree(swapmap, (rp->p_size+7)/8, rp->p_addr); rp->p_addr = a; rp->p_flag =| SLOAD; rp->p_time = 0; goto loop; swaper: panic("swap error"); } /* * 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() { static struct proc *p; register i, n; register struct proc *rp; if(p == NULL) p = &proc[0]; /* * Remember stack of caller */ savu(u.u_rsav); /* * Switch to scheduler's stack */ retu(proc[0].p_addr); loop: runrun = 0; rp = p; p = NULL; n = 128; /* * Search for highest-priority runnable process */ i = NPROC; do { rp++; if(rp >= &proc[NPROC]) rp = &proc[0]; if(rp->p_stat==SRUN && (rp->p_flag&SLOAD)!=0) { if(rp->p_pri < n) { p = rp; n = rp->p_pri; } } } while(--i); /* * If no process is runnable, idle. */ if(p == NULL) { p = rp; idle(); goto loop; } rp = p; curpri = n; /* * Switch to stack of the new process and set up * his segmentation registers. */ retu(rp->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. * * You are not expected to understand this. */ if(rp->p_flag&SSWAP) { rp->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; 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) { mpid = 0; goto retry; } for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) { if(rpp->p_stat == NULL && p==NULL) p = rpp; if (rpp->p_pid==mpid) goto retry; } if ((rpp = p)==NULL) panic("no procs"); /* * make proc entry for new proc */ rip = u.u_procp; up = rip; rpp->p_stat = SRUN; rpp->p_flag = SLOAD; rpp->p_uid = rip->p_uid; rpp->p_ttyp = rip->p_ttyp; 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; /* * 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); 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; 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; 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; swtch(); /* no return */ } p->p_addr = a2; for(i=0; ip_addr); sureg(); } ack 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; 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; swtch(# /* */ #include "../param.h" #include "../conf.h" #include "../inode.h" #include "../user.h" #include "../buf.h" #include "../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 & ~077777) { 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; goto large; } nb = ip->i_addr[bn]; if(nb == 0 && (bp = alloc(d)) != NULL) { bdwrite(bp); 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(bn & 0174000) i = 7; if((nb=ip->i_addr[i]) == 0) { ip->i_flag =| IUPD; if ((bp = alloc(d)) == NULL) return(NULL); ip->i_addr[i] = bp->b_blkno; } else bp = bread(d, nb); bap = bp->b_addr; /* * "huge" fetch of double indirect block */ if(i == 7) { i = ((bn>>8) & 0377) - 7; if((nb=bap[i]) == 0) { if((nbp = alloc(d)) == NULL) { brelse(bp); return(NULL); } bap[i] = nbp->b_blkno; bdwrite(bp); } else { brelse(bp); nbp = bread(d, nb); } bp = nbp; 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; { if(u.u_segflg) *u.u_base = c; else if(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; if(u.u_count == 0) return(-1); if(u.u_segflg) c = *u.u_base; else if((c=fubyte(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() { } /* * 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); } 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 i# /* */ #include "../param.h" #include "../systm.h" #include "../user.h" #include "../proc.h" #include "../buf.h" #include "../reg.h" #include "../inode.h" /* * exec system call. * Because of the fact that an I/O buffer is used * to store the caller's arguments during exec, * and more buffers are needed to read in the text file, * deadly embraces waiting for free buffers are possible. * Therefore the number of processes simultaneously * running in exec has to be limited to NEXEC. */ #define EXPRI -1 exec() { int ap, na, nc, *bp; int ts, ds, sep; register c, *ip; register char *cp; extern uchar; /* * pick up file names * and check various modes * for execute permission */ ip = namei(&uchar, 0); if(ip == NULL) return; while(execnt >= NEXEC) sleep(&execnt, EXPRI); execnt++; bp = getblk(NODEV); if(access(ip, IEXEC) || (ip->i_mode&IFMT)!=0) goto bad; /* * pack up arguments into * allocated disk buffer */ cp = bp->b_addr; na = 0; nc = 0; while(ap = fuword(u.u_arg[1])) { na++; if(ap == -1) goto bad; u.u_arg[1] =+ 2; for(;;) { c = fubyte(ap++); if(c == -1) goto bad; *cp++ = c; nc++; if(nc > 510) { u.u_error = E2BIG; goto bad; } if(c == 0) break; } } if((nc&1) != 0) { *cp++ = 0; nc++; } /* * read in first 8 bytes * of file for segment * sizes: * w0 = 407/410/411 (410 implies RO text) (411 implies sep ID) * w1 = text size * w2 = data size * w3 = bss size */ u.u_base = &u.u_arg[0]; u.u_count = 8; u.u_offset[1] = 0; u.u_offset[0] = 0; u.u_segflg = 1; readi(ip); u.u_segflg = 0; if(u.u_error) goto bad; sep = 0; if(u.u_arg[0] == 0407) { u.u_arg[2] =+ u.u_arg[1]; u.u_arg[1] = 0; } else if(u.u_arg[0] == 0411) sep++; else if(u.u_arg[0] != 0410) { u.u_error = ENOEXEC; goto bad; } if(u.u_arg[1]!=0 && (ip->i_flag&ITEXT)==0 && ip->i_count!=1) { u.u_error = ETXTBSY; goto bad; } /* * find text and data sizes * try them out for possible * exceed of max sizes */ ts = ((u.u_arg[1]+63)>>6) & 01777; ds = ((u.u_arg[2]+u.u_arg[3]+63)>>6) & 01777; if(estabur(ts, ds, SSIZE, sep)) goto bad; /* * allocate and clear core * at this point, committed * to the new image */ u.u_prof[3] = 0; xfree(); expand(USIZE); xalloc(ip); c = USIZE+ds+SSIZE; expand(c); while(--c >= USIZE) clearseg(u.u_procp->p_addr+c); /* * read in data segment */ estabur(0, ds, 0, 0); u.u_base = 0; u.u_offset[1] = 020+u.u_arg[1]; u.u_count = u.u_arg[2]; readi(ip); /* * initialize stack segment */ u.u_tsize = ts; u.u_dsize = ds; u.u_ssize = SSIZE; u.u_sep = sep; estabur(u.u_tsize, u.u_dsize, u.u_ssize, u.u_sep); cp = bp->b_addr; ap = -nc - na*2 - 4; u.u_ar0[R6] = ap; suword(ap, na); c = -nc; while(na--) { suword(ap=+2, c); do subyte(c++, *cp); while(*cp++); } suword(ap+2, -1); /* * 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; } /* * clear sigs, regs and return */ c = ip; for(ip = &u.u_signal[0]; ip < &u.u_signal[NSIG]; ip++) if((*ip & 1) == 0) *ip = 0; for(cp = ®loc[0]; cp < ®loc[6];) u.u_ar0[*cp++] = 0; u.u_ar0[R7] = 0; for(ip = &u.u_fsav[0]; ip < &u.u_fsav[25];) *ip++ = 0; ip = c; bad: iput(ip); brelse(bp); if(execnt >= NEXEC) wakeup(&execnt); execnt--; } /* * exit system call: * pass back caller's r0 */ rexit() { u.u_arg[0] = u.u_ar0[R0] << 8; exit(); } /* * 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 *q, a; register struct proc *p; u.u_procp->p_flag =& ~STRC; for(q = &u.u_signal[0]; q < &u.u_signal[NSIG];) *q++ = 1; for(q = &u.u_ofile[0]; q < &u.u_ofile[NOFILE]; q++) if(a = *q) { *q = NULL; closef(a); } iput(u.u_cdir); xfree(); a = malloc(swapmap, 1); if(a == NULL) panic("out of swap"); p = getblk(swapdev, a); bcopy(&u, p->b_addr, 256); bwrite(p); q = u.u_procp; mfree(coremap, q->p_size, q->p_addr); q->p_addr = a; q->p_stat = SZOMB; loop: for(p = &proc[0]; p < &proc[NPROC]; p++) if(q->p_ppid == p->p_pid) { wakeup(&proc[1]); wakeup(p); for(p = &proc[0]; p < &proc[NPROC]; p++) if(q->p_pid == p->p_ppid) { p->p_ppid = 1; if (p->p_stat == SSTOP) setrun(p); } swtch(); /* no return */ } q->p_ppid = 1; goto loop; } /* * 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() { register f, *bp; register struct proc *p; f = 0; loop: for(p = &proc[0]; p < &proc[NPROC]; p++) if(p->p_ppid == u.u_procp->p_pid) { f++; if(p->p_stat == SZOMB) { u.u_ar0[R0] = p->p_pid; bp = bread(swapdev, f=p->p_addr); mfree(swapmap, 1, f); p->p_stat = NULL; p->p_pid = 0; p->p_ppid = 0; p->p_sig = 0; p->p_ttyp = 0; p->p_flag = 0; p = bp->b_addr; u.u_cstime[0] =+ p->u_cstime[0]; dpadd(u.u_cstime, p->u_cstime[1]); dpadd(u.u_cstime, p->u_stime); u.u_cutime[0] =+ p->u_cutime[0]; dpadd(u.u_cutime, p->u_cutime[1]); dpadd(u.u_cutime, p->u_utime); u.u_ar0[R1] = p->u_arg[0]; brelse(bp); 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] = (p->p_sig<<8) | 0177; return; } p->p_flag =& ~(STRC|SWTED); setrun(p); } } if(f) { sleep(u.u_procp, PWAIT); goto loop; } u.u_error = ECHILD; } /* * fork system call. */ fork() { register struct proc *p1, *p2; p1 = u.u_procp; for(p2 = &proc[0]; p2 < &proc[NPROC]; 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] = 0; u.u_cstime[1] = 0; u.u_stime = 0; u.u_cutime[0] = 0; u.u_cutime[1] = 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 =- nseg(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)) 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++; } 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); } .u_arg[0]+63)>>6) & 01777); if(!u.u_sep) n =- nseg(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)) return; u.u_dsize =+ d; if(d > 0) goto bigge# #include "../param.h" #include "../systm.h" #include "../user.h" #include "../reg.h" #include "../file.h" #include "../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, 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 { u.u_offset[1] = fp->f_offset[1]; u.u_offset[0] = fp->f_offset[0]; if(m==FREAD) readi(fp->f_inode); else writei(fp->f_inode); 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; 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) 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]; 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; 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: ; } fp->f_offset[1] = n[1]; fp->f_offset[0] = n[0]; } /* * link system call */ 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 */ ip->i_flag =& ~ILOCK; 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; 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() { char *d[2]; spl7(); d[0] = time[0]; d[1] = time[1]; dpadd(d, u.u_ar0[R0]); while(dpcmp(d[0], d[1], time[0], time[1]) > 0) { if(dpcmp(tout[0], tout[1], time[0], time[1]) <= 0 || dpcmp(tout[0], tout[1], d[0], d[1]) > 0) { tout[0] = d[0]; tout[1] = d[1]; } sleep(tout, PSLEP); } spl0(); } urn; 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() { char *d[2]; spl7(); d[0] = time[0]; d[1] = time[1]; dpadd(d, u.u_ar0[R0]); while(dpcmp(d[0], d[1], time[0], time[1]) > 0) { if(dpcmp(tout[0], tout[1], time[0], time[1]) <= 0 || dpcmp(tout[0], tout[1], d[0], d[1]) > 0) { tout[0] = d[0]; tout[1] = d[1]; } # /* */ #include "../param.h" #include "../systm.h" #include "../reg.h" #include "../buf.h" #include "../filsys.h" #include "../user.h" #include "../inode.h" #include "../file.h" #include "../conf.h" /* * the fstat system call. */ fstat() { register *fp; fp = getf(u.u_ar0[R0]); if(fp == NULL) return; stat1(fp->f_inode, u.u_arg[0]); } /* * 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, time); 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); for(i=0; i<14; i++) { suword(ub, *ip++); ub =+ 2; } for(i=0; i<4; i++) { suword(ub, *cp++); 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; 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 < &mount[NMOUNT]; mp++) { if(mp->m_bufp != NULL) { if(d == mp->m_dev) goto out; } else if(smp == NULL) smp = mp; } if(smp == NULL) goto out; (*bdevsw[d.d_major].d_open)(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_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; update(); d = getmdev(); if(u.u_error) return; for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) if(mp->m_bufp!=NULL && d==mp->m_dev) goto found; u.u_error = EINVAL; return; found: for(ip = &inode[0]; ip < &inode[NINODE]; ip++) if(ip->i_number!=0 && d==ip->i_dev) { u.u_error = EBUSY; return; } (*bdevsw[d.d_major].d_close)(d, 0); ip = mp->m_inodp; ip->i_flag =& ~IMOUNT; 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; if((ip->i_mode&IFMT) != IFBLK) u.u_error = ENOTBLK; d = ip->i_addr[0]; if(ip->i_addr[0].d_major >= nblkdev) u.u_error = ENXIO; iput(ip); return(d); } >m_inodp; ip->i_flag =&# /* */ /* * Everything in this file is a routine implementing a system call. */ #include "../param.h" #include "../user.h" #include "../reg.h" #include "../inode.h" #include "../systm.h" #include "../proc.h" getswit() { u.u_ar0[R0] = SW->integ; } gtime() { u.u_ar0[R0] = time[0]; u.u_ar0[R1] = time[1]; } stime() { if(suser()) { time[0] = u.u_ar0[R0]; time[1] = 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; 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; } 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. * panic: unlink -- "cannot happen" */ unlink() { register *ip, *pp; extern uchar; pp = namei(&uchar, 2); if(pp == NULL) return; prele(pp); ip = iget(pp->i_dev, u.u_dent.u_ino); if(ip == NULL) panic("unlink -- iget"); if((ip->i_mode&IFMT)==IFDIR && !suser()) 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(pp); iput(ip); } 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; iput(u.u_cdir); u.u_cdir = ip; prele(ip); } chmod() { register *ip; if ((ip = owner()) == NULL) return; ip->i_mode =& ~07777; if (u.u_uid) u.u_arg[1] =& ~ISVTX; ip->i_mode =| u.u_arg[1]&07777; ip->i_flag =| IUPD; iput(ip); } chown() { register *ip; if (!suser() || (ip = owner()) == NULL) return; ip->i_uid = u.u_arg[1].lobyte; ip->i_gid = u.u_arg[1].hibyte; ip->i_flag =| IUPD; iput(ip); } /* * Change modified date of file: * time to r0-r1; sys smdate; file * This call has been withdrawn because it messes up * incremental dumps (pseudo-old files aren't dumped). * It works though and you can uncomment it if you like. smdate() { register struct inode *ip; register int *tp; int tbuf[2]; if ((ip = owner()) == NULL) return; ip->i_flag =| IUPD; tp = &tbuf[2]; *--tp = u.u_ar0[R1]; *--tp = u.u_ar0[R0]; iupdat(ip, tp); 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]; u.u_signal[a] = u.u_arg[1]; if(u.u_procp->p_sig == a) u.u_procp->p_sig = 0; } kill() { register struct proc *p, *q; register a; int f; f = 0; a = u.u_ar0[R0]; q = u.u_procp; for(p = &proc[0]; p < &proc[NPROC]; p++) { if(p == q) continue; if(a != 0 && p->p_pid != a) continue; if(a == 0 && (p->p_ttyp != q->p_ttyp || p <= &proc[1])) continue; if(u.u_uid != 0 && u.u_uid != p->p_uid) 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+6;) { 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 */ } yp != q->p_ttyp || p <= &proc[1])) continue; if(u.u_uid != 0 && u.u_uid != p->p_uid) 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+6;) { 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 # /* */ /* * 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. */ 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, >ime, /* 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, &nosys, /* 27 = x */ 1, &fstat, /* 28 = fstat */ 0, &nosys, /* 29 = x */ 1, &nullsys, /* 30 = smdate; inoperative */ 1, &stty, /* 31 = stty */ 1, >ty, /* 32 = gtty */ 0, &nosys, /* 33 = x */ 0, &nice, /* 34 = nice */ 0, &sslep, /* 35 = sleep */ 0, &sync, /* 36 = sync */ 1, &kill, /* 37 = kill */ 0, &getswit, /* 38 = switch */ 0, &nosys, /* 39 = x */ 0, &nosys, /* 40 = x */ 0, &dup, /* 41 = dup */ 0, &pipe, /* 42 = pipe */ 1, ×, /* 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 = x */ 0, &nosys, /* 50 = x */ 0, &nosys, /* 51 = x */ 0, &nosys, /* 52 = x */ 0, &nosys, /* 53 = x */ 0, &nosys, /* 54 = x */ 0, &nosys, /* 55 = x */ 0, &nosys, /* 56 = x */ 0, &nosys, /* 57 = x */ 0, &nosys, /* 58 = x */ 0, &nosys, /* 59 = x */ 0, &nosys, /* 60 = x */ 0, &nosys, /* 61 = x */ 0, &nosys, /* 62 = x */ 0, &nosys /* 63 = x */ }; 5 = tiu */ 0, &setgid, /* 46 = setgid */ 0, &getgid, /* 47 = getgid */ 2, &ssig, /* 48 = sig */ 0, &nosys, /* 49 = x */ 0, &nosys, /* 50 = x */ 0, &nosys, /* 51 = x */ 0, &nosys, /* 52 = x */ 0, &nosys, /* 53 = x */ 0, &nosys, /* 54 = x */ 0, &nosys, /* 55 = x */ 0, &nosys, /* 56 = x */ 0, &nosys, /* 57 = x */ 0, &nosys, /* 58 = x */ 0, &nosys, /* 59 = x */ 0, &nosys, /* 60 = x */ # /* */ #include "../param.h" #include "../systm.h" #include "../user.h" #include "../proc.h" #include "../text.h" #include "../inode.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 * panic: swap error -- IO error */ xswap(p, ff, os) int *p; { register *rp, a; rp = p; if(os == 0) os = rp->p_size; a = malloc(swapmap, (rp->p_size+7)/8); if(a == NULL) panic("out of swap space"); xccdec(rp->p_textp); rp->p_flag =| SLOCK; if(swap(a, rp->p_addr, os, 0)) panic("swap error"); 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 *xp, *ip; if((xp=u.u_procp->p_textp) != NULL) { u.u_procp->p_textp = NULL; xccdec(xp); if(--xp->x_count == 0) { ip = xp->x_iptr; if((ip->i_mode&ISVTX) == 0) { xp->x_iptr = NULL; mfree(swapmap, (xp->x_size+7)/8, xp->x_daddr); ip->i_flag =& ~ITEXT; iput(ip); } } } } /* * 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) and established in the swap space. * If it is being used, but is not currently in core, * a swap has to be done to get it back. * The full coroutine glory has to be invoked-- * see slp.c-- because if the calling process * is misplaced in core the text image might not fit. * Quite possibly the code after "out:" could check to * see if the text does fit and simply swap it in. * * panic: out of swap space */ xalloc(ip) int *ip; { register struct text *xp; register *rp, ts; if(u.u_arg[1] == 0) return; rp = NULL; for(xp = &text[0]; xp < &text[NTEXT]; xp++) if(xp->x_iptr == NULL) { if(rp == NULL) rp = xp; } else if(xp->x_iptr == ip) { xp->x_count++; u.u_procp->p_textp = xp; goto out; } if((xp=rp) == NULL) panic("out of text"); xp->x_count = 1; xp->x_ccount = 0; xp->x_iptr = ip; ts = ((u.u_arg[1]+63)>>6) & 01777; xp->x_size = ts; if((xp->x_daddr = malloc(swapmap, (ts+7)/8)) == NULL) panic("out of swap space"); expand(USIZE+ts); estabur(0, ts, 0, 0); u.u_count = u.u_arg[1]; u.u_offset[1] = 020; u.u_base = 0; readi(ip); rp = u.u_procp; rp->p_flag =| SLOCK; swap(xp->x_daddr, rp->p_addr+USIZE, ts, 0); rp->p_flag =& ~SLOCK; rp->p_textp = xp; rp = ip; rp->i_flag =| ITEXT; rp->i_count++; expand(USIZE); out: if(xp->x_ccount == 0) { savu(u.u_rsav); savu(u.u_ssav); xswap(u.u_procp, 1, 0); u.u_procp->p_flag =| SSWAP; swtch(); /* no return */ } xp->x_ccount++; } /* * Decrement the in-core usage count of a shared text segment. * When it drops to zero, free the core space. */ xccdec(xp) int *xp; { register *rp; if((rp=xp)!=NULL && rp->x_ccount!=0) if(--rp->x_ccount == 0) mfree(coremap, rp->x_size, rp->x_caddr); } p = xp; rp = ip; rp->i_flag =| ITEXT; rp->i_count++; expand(USIZE); out: if(xp->x_ccount == 0) { savu(u.u_rsav); savu(u.u_ssav); xswap(u.u_procp, 1, 0); u.u_procp->p_flag =| SSWAP; swtch(); /* no return */ } xp->x_ccount++; } /* * Decrement the in-core usage count of a shared text segment. * When it drops to zero, free the core space. */ xccdec(xp) int *# #include "../param.h" #include "../systm.h" #include "../user.h" #include "../proc.h" #include "../reg.h" #include "../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 */ /* * structure of the system entry table (sysent.c) */ struct sysent { int count; /* argument count */ int (*call)(); /* name of handler */ } sysent[64]; /* * 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) 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 %o\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] == 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; callp = &sysent[fuiword(pc-2)&077]; if (callp == sysent) { /* indirect */ a = fuiword(pc); pc =+ 2; i = fuword(a); if ((i & ~077) != SYS) i = 077; /* illegal */ callp = &sysent[i&077]; for(i=0; icount; i++) u.u_arg[i] = fuword(a =+ 2); } else { for(i=0; icount; 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 < 100) { if(u.u_error) { ps =| EBIT; r0 = u.u_error; } goto out; } i = SIGSYS; break; /* * 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)) goto out; i = SIGSEG; break; } psignal(u.u_procp, i); out: if(issig()) psig(); 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-- set fatal error code. */ nosys() { u.u_error = 100; } /* * Ignored system call */ nullsys() { } if this took place * inside of trap, it wouldn't have a cha:>.h & 6  w %f ^ @5q1-'-@:7 y {@u @ ^   @p f  7 ^ ~ @m&   ^ fe@- @m v& @m& 6 tU7, < e- , -*-$- 5 ^   BwV% Ȇ  ^ $e% ˆ  ^ w D@ApN& l Ne& l  ԥ.Ne& l ww  u @  Wp(C` %  wt%Wp(C @w F%a%z@e%9 @ew&%0 w  % ^ fH %  ^ " %   ^ ww B %8 u`e%0w~w l 7 .  ^  %    xVʕ ʕ  % ze    x^ʕ ʕ   %ww ~w,De"   % w7 7 ׯ-  (w7  .we*B J ӕ- R r f e0 @ > ҋ D~8RV hӕ0 $f v Le0 9e4. &  7we&  m  ~    ~ w7   0   Wp `e0eӕ?f ,P x r @f V  7D Z :2-,$fww`wf@wwfwpf@wwlwN f@ww~rw*f@@& HADCBF7bF0123dt~rB>>:arg count /dev/rrkx/dev/tapx/dev/rrkxbad option: %c open failed bad name can not find uic can not find file linked files only bad block number seek failed read failed corrupted file d*o$xfftecslr crt0.ostartgetd.o~mainargcfpfilejpargvunitmfd1~dosname cpns~pack1ljnprsval~r50c~getbbn~atoovcpsnum~rdfileendbplenprintf.o^formp looprrjust ndigit gnumwidth ndfnd swtab*decimaloctal*hex$floatfscientcharacstringlogicalremoteprbufprstrffltpr.oputchr.oflJopen.oread.oseek.owrite.oexit.ocsv.ocerror.o,savr5$ _exit"_main"_duic$x_fd$z_mfdp$|_ufd$~_ufdp$_textb$csv"_printf"^_open"_dosname" _atoo"v_getb"_rdfile"cret"_pack1"l_r50"_seek"_read"_write"pfloat"pscien"_putchar"_flush">_fout$ cerror",_errno$ calremoteprbufprstrffltpr.oputchr.oflJopen.oread.oseek.owrite.oexit.ocsv.ocerror.o,savr5$ _exit"_main"_duic$x_fd$z_mfdp$|_ufd$~_ufdp$_textb$# /* * getdos file [n m] */ /* * d.c.anderson nov,1975 */ /* global variables */ int duic; /* dos uic code */ int fd; /* file descriptor */ int binary; /* set if no cr,lf to be done */ struct mfdent { /* mfd entry structure */ int uic; int firstb; int ufdsize; int ignore; } *mfdp; struct ufdent { /* ufd entry structure */ int name[2]; int ext; int date; int ebp; int head; int length; int tail; int prot; } ufd, *ufdp; struct block { /* dos disk block structure */ int link; char text[510]; } textb; main(argc,argv) int argc; char *argv[]; { char *file, unit, *fp; register int mfd1, jp; if( argc<2){ printf("arg count\n"); exit(1); } fp= argv[1]; file="/dev/tap0"; jp=1; mfd1=64; unit='0'; if( *fp == '-' ) { while( *(++fp) ){ switch( *fp ){ case 't': file="/dev/tap0"; mfd1=64; continue; case 'd': file="/dev/rrk1"; mfd1=1;continue; case '0': case '1': case '2': case '3': unit = *fp;continue; case 'b': binary++; continue; default: { printf("bad option: %c\n",*fp); exit(1);} } } jp=2; } file[8]= unit; if( (fd=open(file,0))<0) { printf("open failed\n"); exit(1);} if( dosname(argv[jp],ufd.name )){ printf("bad name\n"); exit(1);} duic=0401; if( argc ==(jp+3)) duic=atoo(argv[jp+1])<<8 | atoo(argv[jp+2]); getb(mfd1); getb(textb.link); /* -- search for the uic */ mfdp=textb.text; while( (mfdp++)->uic != duic ) { if( mfdp > textb.text+510){ if( textb.link ==0) { printf("can not find uic\n"); exit();} getb(textb.link); mfdp=textb.text;} } /* -- found the uic */ getb( (--mfdp)->firstb ); ufdp= textb.text; while( ufdp->name[0] != ufd.name[0] || ufdp->name[1]!= ufd.name[1] || ufdp->ext != ufd.ext ){ if( (++ufdp)>textb.text+510){ if( textb.link==0){ printf("can not find file\n");exit();} getb(textb.link); ufdp=textb.text;} } /* found the file */ if( ufdp->date & 0100000){ printf("linked files only\n"); exit(1);} rdfile(); exit(); } /* * dosname - convert ascii to r50 name */ dosname(s,n) char *s; int n[]; { register char *cp; cp=s; n[1]=n[2]=0; if( r50(*cp)==0) return(1); cp=pack1(cp,&n[0]); cp=pack1(cp,&n[1]); if( *cp++ != '.') return(0); pack1(cp,&n[2]); return(0); } /* * pack1 -- return a radix 50 packed name */ pack1(s,n) char *s; int n[]; { register int j,val,r; char *p; p=s; j=val=0; while( j<3 && (r=r50(*p)) ){ val = val*40 + r; j++; p++; } for(; j<3; j++) val=* 40; n[0]=val; return(p); } /* * */ r50(c) int c; { if( c>='a' && c<='z') return( c-'a'+1); if( c>='0' && c<='9') return( c-'0'+30); return(0); } /* * */ getb(bn) int bn; { if( bn<0 || bn>4872){ printf("bad block number\n"); exit(1);} if( seek(fd,bn,3) < 0) { printf("seek failed\n"); exit(1);} if( read(fd,&textb,512) < 0 ) { printf("read failed\n"); exit(1);} } /* * ascii to octal conversion from cp */ atoo(s) char *s; { register int num,c; register char *p; p=s; num=0; while( (c= *p++) >= '0' && c<'8'){ num = num*8 + (c-'0'); } return(num); } /* * read a file , xfer to file 1 */ rdfile() { register int endb; register int len; register char *p; endb= ufdp->ebp; len= ufdp->length; textb.link = ufdp->head; while( textb.link ){ if( len-- <= 0) { printf("corrupted file\n"); exit(1);} getb(textb.link); if( binary == 0) for(p=textb.text; plength; textb.link = ufdp->head; while( textb.link ){ if( len-- <= 0) { printf("corrupted file\n"); exit(1);} getb(textb.link); if( binary == 0) for(p=textb.text; p= NDJ11) { u.u_error = ENXIO; return; } tp = &DJ11[dev.d_minor]; if(u.u_procp->p_ttyp == 0) u.u_procp->p_ttyp = tp; tp->t_addr = djstart; /* a special start routine */ tp->t_dev = dev; if((tp->t_state&ISOPEN) == 0) { tp->t_state = SSTART | ISOPEN | CARR_ON; tp->t_flags = XTABS | LCASE | ECHO | CRMOD; tp->t_erase = CERASE; tp->t_kill = CKILL; } DJADDR->djcsr = DJTIE | DJTSE | DJRE | DJRIE; } djclose(dev) { register struct tty *tp; tp = &DJ11[dev.d_minor]; wflushtty(tp); tp->t_state = 0; } djread(dev) { ttread(&DJ11[dev.d_minor]); } djwrite(dev) { ttwrite(&DJ11[dev.d_minor]); } djstart(atp) struct tty *atp; { /* enable xmitter for this line */ DJADDR->djtcr =| 1<<(atp-DJ11); } djxint(dev) { register int c; register struct tty *tp; while (DJADDR->djcsr&DJTR) /*loop till xmitter happy */ { c = DJADDR->djtbuf; tp = &DJ11[c>>8]; if((c = getc(&tp->t_outq)) >= 0) DJADDR->djtbuf = c + (partab[c]&0200); else DJADDR->djtcr =& ~(1<<(tp-DJ11)); /*turn it off*/ if(tp->t_outq.c_cc == 0 || tp->t_outq.c_cc == TTLOWAT) wakeup(&tp->t_outq); } } djrint(dev) { register int c, *addr; register struct tty *tp; while (DJADDR->djrbuf) /*loop till fifo empty*/ { c = DJADDR->djrbuf; if(c&ERRFLAG) return; tp = &DJ11[(c>>8)&017]; /*line number*/ c =& 0177; ttyinput(c,tp); } } djsgtty(dev,v) int *v; { register struct tty *tp; tp = &DJ11[dev.d_minor]; ttystty(tp,v); } c + (partab[c]&0200); else DJADDR->djtcr =& ~(1<<(tp-DJ11)); /*turn it off*/ if(tp->t_outq.c_cc == 0 || tp->t_outq.c_cc == TTLOWAT) wakeup(&tp->t_outq); } } djrint(dev) { register int c, *addr; register struct tty *tp; while (DJADDR->djrbuf) /*loop till fifo empt# /* * dr11-c word driver */ #include "../param.h" #include "../user.h" #include "../conf.h" #include "../tty.h" #define DRADDR 0167770 #define PDR 9 /* number of dr11's */ #define NDR11 2 #define DRHIWAT 50 #define DRLOWAT 14 /* control bits */ #define INPRDY 0100000 #define OUTRDY 0000200 #define OUTINT 0000100 #define INPINT 0000040 struct { /*dr11 registers */ int csr; int xbuf; int rbuf; }; struct dr { /* dr control structure */ int lock; /* 1=opened */ int addr; struct clist inpq; /* input character queue */ struct clist outq; /* output character queue */ }; struct dr dr11[NDR11]; dropen(dev,flag) { register struct dr *p; register int *add,junk; if ( dev.d_minor >= NDR11 ) { u.u_error = ENXIO; return; } p= &dr11[dev.d_minor]; if( p-> lock ==0){ p-> lock++; p->addr=add= DRADDR - (dev.d_minor*8); junk=add->rbuf; /* clear any hanging input */ add->csr= (INPINT | OUTINT); } else u.u_error = ENXIO; } drclose(dev) { extern lbolt; register struct dr *p; p= &dr11[dev.d_minor]; while( p->outq.c_cc) sleep( &lbolt,PDR); while( getc(&p->inpq) >= 0); p->lock=0; (p->addr)->csr=0; } drwrite(dev) { register struct dr *p; register c,w; extern lbolt; p= &dr11[dev.d_minor]; w=0; while( (c=cpass()) >= 0){ spl5(); while( p->outq.c_cc > DRHIWAT) sleep(&p->outq,PDR); while( putc(c,&p->outq) < 0) sleep( &lbolt,PDR); if( ++w == 2){ w=0; drxint(dev); } spl0(); } } drread(dev) { register struct dr *p; register c,w; p= &dr11[dev.d_minor]; spl5(); do{ while( (c=getc(&p->inpq))<0) sleep(&p->inpq,PDR); } while ( passc(c) >= 0); spl0(); } drxint(dev) { register struct dr *p; register int c,w; p= &dr11[dev.d_minor]; if( ((p->addr)->csr & OUTRDY) ==0) return; if( (w= (p->outq.c_cc)) >= 2){ (p->addr)->xbuf = (getc(&p->outq)<<8) | getc(&p->outq); (p->addr)->csr =| OUTINT; if( (w=-2)==0 || w==DRLOWAT) wakeup(&p->outq); } else (p->addr)->csr =& ~OUTINT; } drrint(dev) { register struct dr *p; register int c,w; p= &dr11[dev.d_minor]; w= (p->addr)->rbuf; putc(w,&p->inpq); putc(w>>8, &p->inpq); wakeup(&p->inpq); } spl0(); } drxint(dev) { register struct dr *p; register int c,w; p= &dr11[dev.d_minor]; if( ((p->addr)->csr & OUTRDY) ==0) return; if( (w= (p->outq.c_cc)) >= 2){ (p->addr)->xbuf = (getc(&p->outq)<<8) | getc(&p->outq); (p->addr)->csr =| OUTINT; if( (w=-2)==0 || w==DRLOWAT) wakeup(&p->outq); } else (p->addr)->csr =& ~OUTINT; } drrint(dev) { register struct dr *p; register int c,w; p= &dr11[dev.d_min# /* */ /* * general TTY subroutines * modified for 8 bit i/o by d.anderson, may 27,1976 */ #include "../param.h" #include "../systm.h" #include "../user.h" #include "../tty.h" #include "../proc.h" #include "../inode.h" #include "../file.h" #include "../reg.h" #include "../conf.h" /* * 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,004,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 actual structure of a clist block manipulated by * getc and putc (mch.s) */ struct cblock { struct cblock *c_next; char info[6]; }; /* The character lists-- space for 6*NCLIST characters */ struct cblock cfree[NCLIST]; /* 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 ttrcsr; int ttrbuf; int tttcsr; int tttbuf; }; /* * 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); 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[]. * c 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[ip->i_addr[0].d_major].d_sgtty)(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; register struct cdevsw *cdp; ccp = cfree; for (cp=(ccp+07)&~07; cp <= &cfree[NCLIST-1]; cp++) { cp->c_next = cfreelist; cfreelist = cp; } ccp = 0; for(cdp = cdevsw; cdp->d_open; cdp++) ccp++; nchrdev = ccp; } /* * 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; tp = atp; spl5(); while (tp->t_delct==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) { tp->t_delct--; putc(c,&tp->t_canq); return(1); } if (c==0377) { 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 if (maptab[c] && (maptab[c]==c || (tp->t_flags&LCASE))) { if (bp[-2] != '\\') c = maptab[c]; bp--; } *bp++ = c; if (bp>=canonb+CANBSIZ) break; } bp1 = bp; bp = &canonb[2]; c = &tp->t_canq; while (bpt_flags; if( t_flags & RAW ) goto skip; if ((c =& 0177) == '\r' && t_flags&CRMOD) c = '\n'; if ((t_flags&RAW)==0 && (c==CQUIT || c==CINTR)) { signal(tp, c==CINTR? SIGINT:SIGQIT); flushtty(tp); return; } if(t_flags&LCASE && c>='A' && c<='Z') c =+ 'a'-'A'; skip: if (tp->t_rawq.c_cc>=TTYHOG) { flushtty(tp); return; } putc(c, &tp->t_rawq); if (t_flags&RAW || c=='\n' || c==004) { wakeup(&tp->t_rawq); if ( t_flags&RAW ||(putc(0377, &tp->t_rawq)==0)) tp->t_delct++; } if( t_flags&RAW) return; 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; rtp = tp; if( rtp->t_flags&RAW) { putc(ac,&rtp->t_outq); return; } c = ac&0177; /* * Ignore EOT in normal mode to avoid hanging up * certain terminals. */ if (c==004 && (rtp->t_flags&RAW)==0) return; /* * 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 to if desired. */ if (c=='\n' && rtp->t_flags&CRMOD) ttyoutput('\r', rtp); if (putc(c, &rtp->t_outq)) return; /* * Calculate delays. * The numbers here represent clock ticks * and are not necessarily optimal for all terminals. * The delays are indicated by characters above 0200, * thus (unfortunately) restricting the transmission * path to 7 bits. */ 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; /* newline */ case 3: ctype = (rtp->t_flags >> 8) & 03; if(ctype == 1) { /* tty 37 */ if (*colp) c = max((*colp>>4) + 3, 6); } else if(ctype == 2) { /* vt05 */ c = 6; } *colp = 0; 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) { /* ti 700 */ c = 10; } *colp = 0; } if(c) putc(c|0200, &rtp->t_outq); } /* * 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; register struct tty *tp; struct { int (*func)(); }; tp = atp; addr = tp->t_addr; if (tp->t_state&SSTART) { (*addr.func)(tp); return; } if ((addr->tttcsr&DONE)==0 || tp->t_state&TIMEOUT) return; if ((c=getc(&tp->t_outq)) >= 0) { if( tp->t_flags&RAW) { addr->tttbuf = c; return; } if (c<=0177) addr->tttbuf = c | (partab[c]&0200); else { timeout(ttrstrt, tp, c&0177); tp->t_state =| TIMEOUT; } } } /* * 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; { 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); } /old = sbrk(increment); / modified by dca, 12-aug-76 to check overflow condition. / /sbrk gets increment more core, and returns a pointer / to the beginning of the new core area / .globl _sbrk,_end, cerror _sbrk: mov r5,-(sp) mov sp,r5 mov nd,0f add 4(r5),0f bcs 2f / *** sys 0; 9f bec 1f 2: / *** jmp cerror 1: mov nd,r0 add 4(r5),nd mov (sp)+,r5 rts pc .globl _brk / brk(value) / as described in man2. / returns 0 for ok, -1 for error. _brk: mov r5,-(sp) mov sp,r5 mov 4(r5),0f sys 0; 9f bec 1f jmp cerror 1: mov 4(r5),nd clr r0 mov (sp)+,r5 rts pc .data 9: sys break; 0:.. nd: _end nt more core, and returns a pointer / to the beginning of the new core area / .globl _sbrk,_end, cerror _sbrk: mov r5,-(sp) mov sp,r5 mov nd,0f add 4(r5),0f bcs 2f / *** sys 0; 9f bec 1f 2: / *** jmp cerror 1: mov nd,r0 add 4(r5),nd mov (sp)+,r5 rts pc .globl _brk / brk(value) / as described in man2. / returns 0 for ok, -1 for error. _brk: mov r5,-(sp) mov sp,r5 mov 4(r5),0f sys 0; 9f 4 i4i2 .+2 sys signal; 2; 1 ror r0 bcs 1f sys signal; 2; restor 1: mov (sp),r0 mov r0,ifdw sys gtty; oldw mov (sp)+,r0 sys stty; raw mov (sp),r0 mov r0,ifdr sys gtty; oldr mov (sp)+,r0 sys stty; raw jmp retrn / / restore- internal routine to restore old tty modes / restore: mov ifdr,r0 sys stty; oldr mov ifdw,r0 sys stty; oldw rts pc restor: jsr pc,restore sys exit .globl calout. calout.: temp .+2 jsr pc,restore jmp retrn .data oldr: .=.+6 oldw: .=.+6 raw: 0; 0; 40 ifdr: 0 ifdw: 0 temp: 0;0 sys signal; 2; 1 ror r0 bcs 1f sys signal; 2; restor 1: mov (sp),r0 mov r0,ifdw sys gtty; oldw mov (sp)+,r0 sys stty; raw mov (sp),r0 mov r0,ifdr sys gtty; oldr mov (sp)+,r0 sys stty; raw jmp retrn / / restore- internal routine to restore old tty modes / restore: mov ifdr,r0 sys stty; oldr mov ifdw,r0 sys stty; oldw rts pc restor: jsr pc,restore sys exit .globl calout. calout.: temp .+2 jsr pc,restore jmp retrn .data oldr: .=.+6 oldw: .=.+6 raw: 0; 0; 40 ifdr: 0 ifdw/ tty control package .globl retrn / / stat(name,buf) / integer stat / integer*2 buf(18) / integer*1 name(??) / .globl stat. stat.: temp lvalp; 2 lvalp; 4 .+2 mov (sp)+,1f /buf mov (sp)+,0f sys stat; 0:.. ; 1:.. br ret / / stty(ifd,iarg) / integer ifd,stty / integer*2 iarg(3) / .globl stty. stty.: temp rval4p; 2 i4i2 lvalp; 4 .+2 mov (sp)+,0f mov (sp)+,r0 sys stty; 0:.. br ret / / gtty(ifd,iarg) / integer ifd,gtty / integer*2 iarg(3) / .globl gtty. gtty.: temp rval4p; 2 i4i2 lvalp; 4 .+2 mov (sp)+,0f mov (sp)+,r0 sys gtty; 0:.. ret: bec 1f mov $-1,r0 1: mov r0,temp+2 sxt temp jmp retrn .data temp: 0; 0 emp lvalp; 2 lvalp; 4 .+2 mov (sp)+,1f /buf mov (sp)+,0f sys stat; 0:.. ; 1:.. br ret / / stty(ifd,iarg) / integer ifd,stty / integer*2 iarg(3) / .globl stty. stty.: temp rval4p; 2 i4i2 lvalp; 4 .+2 mov (sp)+,0f mov (sp)+,r0 sys stty; 0:.. br ret / / gtty(ifd,iarg) / integer ifd,gtty / integer*2 iarg(3) / .globl gtty. gtty.: temp rval4p; 2 i4i2 lvalpmaxis.o8 \ @x    ~4T~4T0,,jtt h  =5C}@pC8H B>@u>?= ?(\>(x10 ) ?>(\(f3.0) (f6.4) (f6.3) (f6.2) (f6.1) (f6.0) (f6.0) ̾>̀L>L>̀??LL̀?&ff??&@ffܿ(?zTz0@ףܿ(?zTz0@ף(Hh((Hh(hHh(8(h(h((h(H((H(H((h(H(H(H(HhH8x(H((h(((hH(h8(((HxHxHH8HXHHHHHHHHHHHHH(H8(HHHHHXhHHH8HHHhHHH8HHH8hH8HhX8H(88888HHH8HH8HhH8XhH(H8hH(H8HH(HHH(H8(888X8HhX8H(888XHHHH(888XHHHH(888XXHH(HH(H((HH(h(H(hHH8HHHhHH8HHH8(888XX8xHHHHHHH(H8HHHH(H8(8888X8xHHH8HHHHH8HH8(888HH(X8axis."axis_stsp ftrval4 c0rval4p angle_ rmp4 call cos. gmv4 c_c1sin. s_c2lrot_i4r4 rad4 t_ns_iabs. k_c3min0. c4max0. c5iad4 l_c6mod. c7c8c9m_size_ c10r4i4 n_c11zmin_abs. zdel_amax1. alog10. axp_ixp_jxp_c12rge4 lif2 goto .10c13isb4 c14ile4 c15igt4 lor2 c16ine4 c17rlt4 lan2 c18c19rpi4 d_x_arval d2~xx_4d3yy_Trsb4 xa_y_ya_rdv4 za_lval i_izero_gas4 t0do14 o0stst c20gal8 format_number. .100xb_yb_gar4 ww_,c21plot. c22t1o1jc23c24.200@c25c26c27c28c29amin0. d4zz_tc30lvalp string_symbol. ieq4 retrn c31c32c33c34c35c36c37c38c39c40c41c42c43d0rd1xbaseline.o8 5 ~@fZj`jXn  jzrfZZZf```~r~jf$VfZZZ``` jRj~~ jR~vvz jf~~r~>(\?(\((Xhh(h((hxh(h(xhhHXhHXhhH(hhHXhHXh(xxh(xHHXline."line_rval4p n_k_imp4 gmv4 n1_rval4 c0fiad4 im_id_arvalp d0Zx_c1ji4r4 req4 d1`y_c2jlor2 lif2 retrn c3nipen_j_ m_c4jige4 goto .10ing4 c5rc6frsb4 rdv4 x1_c7fy1_stsp ft~lval stst c8rcall plot. c9jjcnt_i_c10fgas4 t0do24 o0Vc11fxp_yp_c12jieq4 .20ine4 .30Rc13jc14jc15vc16vc17zlvalp ocsym_ c18jc19fsymbol. c20rbasenumber.o8 +Y tff4fd fdffjjdX jdde(Hhx(HHH(xHH(hH(Hhx(HHHH(8HXhxxHHH(H((number."number_lval i_frval4 c0gas4 goto t0c1do14 o04.1gal1 iwk_c2ing4 i4i1 gas1 c3lvalp format_ encod rnum_rio4 endio c4t1Xc5o1c6isb4 gmv4 n_jgar1 i1i4 c7ine4 lif2 .3.2retrn stsp ftx_stst y_height_angle_ call symbol. d0d1basesymbol.o8 ^6 D| $&        |      |       r                            t x | JL | r L   @      H f  =AAAA $ !# " $""$ $8 $$    $"$  # "   8"8$"" 8$8 ! $8! !8#8 8        " 8  888"8$ "#%8 8'8 " #%!##'!&8&$ &% #!#!#' #!&'& &% #!&$ &!88"&$8!$&%8  !% #& &%#!!&&!' '#!&%$ '!''8 '  ''!&&%!&8 &% !# &'!'&' ''8 '' 8 $ ' ' &                ")08@GN\iosy{}!%)49?AFHSXant~ *06<DGLP[box(H(H((HHHhxHHHhH(H(HHH(x(xH((xHH(H8HHH(H(H(H(HHHHHHhXH(H(HHhHHxHhHHxHhHh8HHHxHhHHxHhHh8H8HHHHHHHH(HHHHhHhHHH8(HxHH((xH((HHh(HHHHHsymbol."symbol_rval4p height_gmv4 h_| nchar_ nc_ rval4 c0ine4 lif2 goto .20&.10$retrn theta_ c1rmp4 th_ stsp ft call sin. si_ cos. co_ x1_x_ y1_y_ c2ige4 .50.30c3rdv4 fact_ c4rsb4 c5rad4 c6c7ing4 .60.40c8ic_ .70c9i4r4 c10xa_ ya_ c11xt_ c12yt_ c13idel_ c14j_ c15ile4 .100.80rc16isb4 float. stlen_ xn_ yn_ lval xnow_ stst ynow_ g_ where. abs. max1. del1_ del2_ rlt4 .90c17xk_ yk_ rng4 ii_ c18gas4 t0do14 o0tarvalp d0xbcd_i1i4 c19iad4 itsub_ gar4 kct_|ict_ c20ieq4 .200Lkoc_| loc_ i_ c21t1fo1Lc22gar1 ifont_iy_ c23idv4 i4l2 c24ian4 l2r4 xx_ c25req4 .110@c26yy_ plot. c27.115Hc28c29.210pd1~d2d3basewhere.o8 i6 >@::D(8X((8(8X((8(8where."where_@rval4 _com502 xcur_i4r4 c0:fact_rmp4 rdv4 gmv4p x_ycur_c1:y_factr_retrn base>xorg_yorg_ istate_factor.o8 5 (HXxxfactor."factor_rval4p factr_gmv4 _com502 fact_retrn basexcur_ycur_xorg_yorg_ istate_plot.oo8 X $ t*,~6tt:0">B:VBjFFHHH6LP(6tvttvttvxTzvvttvttvxTzvvtX\t`vttvtHdH<pt`vttvtHttHt`vttvthtlvttvttpvt(021h type cr to continue )D80(8(hx(x(x(Xx(Xx((8((8((8H((8H(8(8(8(8X(((x(((x(HXhHXhHX(XhHXhHX(Xh((((xHXhHX8((8((xHXhHX8(((xHXhHX8(HH(8HXhHX8HXhplot."plot_~rval4 _com502 istate_c06ine4 lif2 stsp fttcall plots. rval4p ip_c1:ieq4 goto .4"c2>.8c3:ing4 .5c4B.7x_c5Frmp4 fact_r4i4 gmv4 ix_y_c6Fiy_xcur_isb4 idx_ycur_idy_ipc_iif4 .1.2c7Hc8Hc9Hline_c106c11Lc12Pc136lval stst xdl. c14Tishift. c15T_bufcon bytcnt_c16Xiad4 c17\ilt4 retrn c18`iack_rdl. c19Hc20dc21H.91pc22`c23Hcalout. c24Hile4 .903c25`c26h.901iowf endio paus c27lc28pbase|xorg_yorg_ plots.o8 6 d`h`<bHd`l`<bLd`plLpLd|PLLLL T`pbld`LP'X`\b`L(024h can not open /dev/tty1 )(013h calin failed)/dev/tty1 @08XxXx8XxXx((HXhXXh8XxXxXXX8Xx8XXplots."plots_h.1stsp ft`lval c0<stst c1Hcall open. gmv4 ifdw_lc2<c3Lifdr_prval4 c4Ligt4 c5Llan2 lif2 goto .2|c6P.100iowf endio paus c7L_com502 xcur_c8Lycur_c9Lxorg_c10Lyorg_ c11Tfact_calin. c12Li4r4 rne4 c13P.101'c14Xistate_c15\xdl. c16L_bufcon bytcnt_retrn basefscale.o8 ,6 T :|p|p|Jpp:| F |p|p}½@X@ B@SA@AA((Xhhh8H(hhhHhh8H(hh(hh8H(hHXh8h(HhHHhHh8h(HHXHhhHXh(8h8hH88(XXh8scale."scale_rval4p n_k_imp4 gmv4 m_rval4 c0|arvalp d0px_xmax_c1|xmin_lval i_c2|gas4 goto t0:do24 o0stsp ftcall amax1. .5ramin1. c3x0_c4dx_c5rsb4 rmp4 s_rdv4 w_c6req4 lif2 c7c8|t1c9do14 o1c10gar4 t_alog10. rad4 b_c11rlt4 c12c13ifix. rpi4 c_rgt4 .21c14aint. d_c15c16|iad4 alvalp c17c18|retrn d1vbasedlio.o8 q6 `7  e7 wV0 07V 7D wv2,  wR    retrn xdl."tempifdwret4rdl."ifdrcalin."Frval4p i4i2 restoroldwrawoldrrestorecalout."ishift.o8 y6  < v7ww8H8 retrn ishift."temp rval4p i4i2   "e7v pwV0 07D 72 wv  8H 8H8H retrn xdl."temprval4p i4i2 ifdrret4rdl."lvalp calin."Frestoreifdwoldwrawoldr"e7v pwV0 07D 72 wv  8H 8H8H retrn xdl."temprval4p i4i2 ifdrret4rdl."lvalp calin."Frestoreifdwoldwraw: assemble calcomp library fc -c *.f as - dlio.s; mv a.out dlio.o ar r cal.a number.o symbol.o where.o ar r cal.a axis.o factor.o line.o plot.o ar r cal.a plots.o scale.o dlio.o rm *.o  8H8H retrn xdl."temprval4p i4i2 ifdrret4rdl."lvalp calin."Frestoreifdwoldwraw/ tty control package .globl retrn / / stat(name,buf) / integer stat / integer*2 buf(18) / integer*1 name(??) / .globl stat. stat.: temp lvalp; 2 lvalp; 4 .+2 mov (sp)+,1f /buf mov (sp)+,0f sys stat; 0:.. ; 1:.. br ret / / stty(ifd,iarg) / integer ifd,stty / integer*2 iarg(3) / .globl stty. stty.: temp rval4p; 2 i4i2 lvalp; 4 .+2 mov (sp)+,0f mov (sp)+,r0 sys stty; 0:.. br ret / / gtty(ifd,iarg) / integer ifd,gtty / integer*2 iarg(3) / .globl gtty. gtty.: temp rval4p; 2 i4i2 lvalp; 4 .+2 mov (sp)+,0f mov (sp)+,r0 sys gtty; 0:.. ret: bec 1f mov $-1,r0 1: mov r0,temp+2 sxt temp jmp retrn .data temp: 0; 0 emp lvalp; 2 lvalp; 4 .+2 mov (sp)+,1f /buf mov (sp)+,0f sys stat; 0:.. ; 1:.. br ret / / stty(ifd,iarg) / integer ifd,stty / integer*2 iarg(3) / .globl stty. stty.: temp rval4p; 2 i4i2 lvalp; 4 .+2 mov (sp)+,0f mov (sp)+,r0 sys stty; 0:.. br ret / / gtty(ifd,iarg) / integer ifd,gtty / integer*2 iarg(3) / .globl gtty. gtty.: temp rval4p; 2 i4i2 lvalp