V1/u2.s

/ u2 -- unix

syslink: / name1, name2
	jsr	r0,arg2 / u.namep has 1st arg u.off has 2nd
	jsr	r0,namei / find the i-number associated with the 1st 
                         / path name
	br	error9 / cannot be found
	jsr	r0,iget / get the i-node into core
	mov	(sp)+,u.namep / u.namep points to 2nd name
	mov	r1,-(sp) / put i-number of name1 on the stack (a link
			 / to this file is to be created)
	mov	cdev,-(sp) / put i-nodes device on the stack
	jsr	r0,isdir / is it a directory
	jsr	r0,namei / no, get i-number of name2
		br .+4   / not found so r1-i-number of current directory
			 /              ii = i-number of current directory
	br	error9 / file already exists., error
	cmp	(sp)+,cdev / u.dirp now points to end of current directory
	bne	error9
	mov	(sp),u.dirbuf / i-number of name1 into u.dirbuf
	jsr	r0,mkdir / make directory entry for name2 in current 
                         /directory
	mov	(sp)+,r1 / r1 has i-number of name1
	jsr	r0,iget / get i-node into core
	incb	i.nlks / add 1 to its number of links
	jsr	r0,setimod / set the i-node modified flag
	
sysret9:
	jmp	sysret / see 'sysret' routine
error9:
	jmp	error / see 'error' routine

isdir: / if the i-node whose i-number is in r1 is a directory there is an
       / error unless super user made the call
	tstb	u.uid / super user
	beq	1f / yes, don't care
	mov	ii,-(sp) / put current i-number on stack
	jsr	r0,iget / get i-node into core (i-number in r1)
	bit	$40000,i.flgs / is it a directory
	bne	error9 / yes, error
	mov	(sp)+,r1 / no, put current i-number in r1 (ii)
	jsr	r0,iget / get it back in
1:
	rts	r0

sysunlink: / name - remove link name
	jsr	r0,arg; u.namep / u.namep points to name
	jsr	r0,namei / find the i-number associated with the path name
		br error9 / not found
	mov	r1,-(sp) / put its i-number on the stack
	jsr	r0,isdir / is it a directory
	clr	u.dirbuf / no, clear the location that will get written
	                / into the i-number portion of the entry
	sub	$10.,u.off / move u.off back 1 directory entry
	jsr	r0,wdir / free the directory entry
	mov	(sp)+,r1 / get i-number back
	jsr	r0,iget / get i-node
	jsr	r0,setimod / set modified flag
	decb	i.nlks / decrement the number of links
	bgt	sysret9 / if this was not the last link to file return
	jsr	r0,anyi / if it was, see if anyone has it open.  Then
			/ free contents of file and destroy it.
	br	sysret9

mkdir:
	jsr	r0,copyz; u.dirbuf+2; u.dirbuf+10. / clear this
	mov	u.namep,r2 / r2 points to name of directory entry
	mov	$u.dirbuf+2,r3 / r3 points to u.dirbuf+2
1: / put characters in the directory name in u.dirbuf+2 - u.dirbuf+10
	movb	 (r2)+,r1 / move character in name to r1
	beq	1f / if null, done
	cmp	r1,$'/ / is it a "/"?
	beq	error9 / yes, error
	cmp	r3,$u.dirbuf+10. / have we reached the last slot for
				 / a char?
	beq	1b / yes, go back
	movb	r1,(r3)+ / no, put the char in the u.dirbuf
	br	1b / get next char
1:
	mov	u.dirp,u.off / pointer to empty current directory slot to 
			     /u.off
			     
wdir:
	mov	$u.dirbuf,u.base / u.base points to created file name
	mov	$10.,u.count / u.count = 10
	mov	ii,r1 / r1 has i-number of current directory
	jsr	r0,access; 1 / get i-node and set its file up for writing
	jsr	r0,writei / write into directory
	rts	r0
	
sysexec:
	jsr	r0,arg2 / arg0 in u.namep,arg1 on top of stack
	jsr	r0,namei / namei returns i-number of file named in 
			 / sysexec call in r1
		br error9
	jsr	r0,iget / get i-node for file to be executed
	bit	$20,i.flgs / is file executable
	beq	error9
	jsr	r0,iopen / gets i-node for file with i-number given in 
			 / r1 (opens file)
	bit	$40,i.flgs / test user id on execution bit
	beq	1f
	tstb	u.uid / test user id
	beq	1f / super user
	movb	i.uid,u.uid / put user id of owner of file as process 
			    / user id
1:
	mov	(sp)+,r5 / r5 now contains address of list of pointers to 
			 / arguments to be passed
	mov	$1,u.quit / u.quit determines handling of quits;
			  / u.quit = 1 take quit
	mov	$1,u.intr / u.intr determines handling of interrupts;
			  / u.intr = 1 take interrupt
	mov	$rtssym,30 / emt trap vector set to take system routine
	mov	$fpsym,*10 / reserved instruction trap vector set to take 
			   / system routine
	mov	$sstack,sp / stack space used during swapping
	mov	r5,-(sp) / save arguments pointer on stack
	mov	$ecore,r5 / r5 has end of core
	mov	$core,r4 / r4 has start of users core
	mov	r4,u.base / u.base has start of users core
	mov	(sp),r2 / move arguments list pointer into r2
1:
	tst	(r2)+ / argument char = "nul"
	bne	1b
	tst	-(r2) / decrement r2 by 2; r2 has addr of end of arguent 
		      / pointer list
1: / move arguments to bottom of users core
	mov	-(r2),r3 / (r3) last non zero argument ptr
	cmp	r2,(sp) / is r2 = beginning of argument ptr list
	blo	1f / branch to 1f when all arguments are moved
2:
	tstb	(r3)+
	bne	2b / scan argument for \0 (nul)
2:
	movb	-(r3),-(r5) / move argument char by char starting at 
			    / "ecore"
	cmp	r3,(r2) / moved all characters in this argument
	bhi	2b / branch 2b if not
	mov	r5,(r4)+ / move r5 into top of users core; r5 has 
			 / pointer to nth arg
	br	1b / string
1:
	clrb	-(r5)
	bic	$1,r5 / make r5 even, r5 points to last word of argument 
		      / strings
	mov	$core,r2
1: / move argument pointers into core following argument strings
	cmp	r2,r4
	bhis	1f / branch to 1f when all pointers are moved
	mov	(r2)+,-(r5)
	br	1b
1:
	sub	$core,r4 / gives number of arguments *2
	asr	r4 / divide r4 by 2 to calculate the number of args stored
	mov	r4,-(r5) / save number of arguments ahead of the argument 
			 / pointers
	clr	-(r5) / popped into ps when rti in sysrele is executed
	mov	$core,-(r5) / popped into pc when rti in sysrele 
			    / is executed
	mov	r5,0f / load second copyz argument
	tst	-(r5) / decrement r5
	mov	r5,u.r0 /
	sub	$16.,r5 / skip 8 words
	mov	r5,u.sp / assign user stack pointer value, effectively
		        / zeroes all regs when sysrele is executed
	jsr	r0,copyz; core; 0:0 / zero user's core
	clr	u.break
	mov	r5,sp / point sp to user's stack
	mov	$14,u.count
	mov	$u.off,u.fofp
	clr	u.off / set offset in file to be read to zero
	jsr	r0,readi / read in first six words of user's file, starting 
			 / at $core
	mov	sp,r5 / put users stack address in r5
	sub	$core+40.,r5 / subtract $core +40, from r5 (leaves
			     / number of words less 26 available for
			     / program in user core
	mov	r5,u.count /
	cmp	core,$405 / br .+14 is first instruction if file is
			  / standard a.out format
	bne	1f / branch, if not standard format
	mov	core+2,r5 / put 2nd word of users program in r5; number of
			  / bytes in program text
	sub	$14,r5 / subtract 12
	cmp	r5,u.count /
	bgt	1f / branch if r5 greater than u.count
	mov	r5,u.count
	jsr	r0,readi / read in rest of user's program text
	add	core+10,u.nread / add size of user data area to u.nread
	br	2f
1:
	jsr	r0,readi / read in rest of file
2:
	mov	u.nread,u.break / set users program break to end of 
				/ user code
	add	$core+14,u.break / plus data area
	jsr	r0,iclose / does nothing
	br	sysret3 / return to core image at $core
	
sysfstat: / set status of open file
	jsr	r0,arg; u.off / put buffer address in u.off
	mov	u.off,-(sp) / put buffer address on the stack
	mov	*u.r0,r1 / put file descriptor in r1
	jsr	r0,getf / get the files i-number
	tst	r1 / is it 0?
	beq	error3 / yes, error
	bgt	1f / if i-number is negative (open for writing)
	neg	r1 / make it positive, then branch
	br	1f / to 1f
	
sysstat: / ; name of file; buffer - get files status
	jsr	r0,arg2 / get the 2 arguments
	jsr	r0,namei / get the i-number for the file
		br error3 / no such file, error
1:
	jsr	r0,iget / get the i-node into core
	mov	(sp)+,r3 / move u.off to r3 (points to buffer)
	mov	r1,(r3)+ / put i-number in 1st word of buffer
	mov	$inode,r2 / r2 points to i-node
1:
	mov	(r2)+,(r3)+ / move rest of i-node to buffer
	cmp	r2,$inode+32 / done?
	bne	1b / no, go back
	br	sysret3 / return through sysret
	
error3:
	jmp	error / see 'error' routine
sysret3:
	jmp	sysret / see 'sysret' routine

getf: / get the device number and the i-number of an open file
	cmp	r1,$10. / user limited to 10 open files
	bhis	error3 / u.fp is table of users open files, index in 
		       / fsp table
	movb	u.fp(r1),r1 / r1 contains number of entry in fsp table
	beq	1f / if its zero return
	asl	r1
	asl	r1 / multiply by 8 to get index into fsp table entry
	asl	r1
	add	$fsp-4,r1 / r1 is pointing at the 3rd word in the fsp entry
	mov	r1,u.fofp / save address of 3rd word in fsp entry in u.fofp
	mov	-(r1),cdev / remove the device number  cdev
	mov	-(r1),r1 / and the i-number  r1
1:
	rts	r0

namei:
	mov	u.cdir,r1 / put the i-number of current directory in r1
	mov	u.cdev,cdev / device number for users directory into cdev
	cmpb	*u.namep,$'/ / is first char in file name a /
	bne	1f
	inc	u.namep / go to next char
	mov	rootdir,r1 / put i-number of rootdirectory in r1
	clr	cdev / clear device number
1:
	tstb	*u.namep / is the character in file name a nul
	beq	nig / yes, end of file name reached; branch to "nig"
1:
	jsr	r0,access; 2 / get i-node with i-number r1
	bit	$40000,i.flgs / directory i-node?
	beq	error3 / no, got an error
	mov	i.size,u.dirp / put size of directory in u.dirp
	clr	u.off / u.off is file offset used by user
	mov	$u.off,u.fofp / u.fofp is a pointer to the offset portion 
			      / of fsp entry
2:
	mov	$u.dirbuf,u.base / u.dirbuf holds a file name copied from 
				 / a directory
	mov	$10.,u.count / u.count is byte count for reads and writes
	jsr	r0,readi / read 10. bytes of file with i-number (r1);
			 / i.e. read a directory entry
	tst	u.nread
	ble	nib / gives error return
	tst	u.dirbuf /
	bne	3f / branch when active directory entry (i-node word in 
		   / entry non zero)
	mov	u.off,u.dirp
	sub	$10.,u.dirp
	br	2b
3:
	mov	u.namep,r2 / u.namep points into a file name string
	mov	$u.dirbuf+2,r3 / points to file name of directory entry
3:
	movb	(r2)+,r4 / move a character from u.namep string into r4
	beq	3f / if char is nul, then the last char in string has been 
		   / moved
	cmp	r4,$'/ / is char a </>
	beq	3f
	cmp	r3,$u.dirbuf+10. / have I checked all 8 bytes of file name
	beq	3b
	cmpb	(r3)+,r4 / compare char in u.namep string to file name 
			 / char read from
	beq	3b / directory; branch if chars match
	br	2b / file names do not match go to next directory entry
3:
	cmp	r3,$u.dirbuf+10. / if equal all 8 bytes were matched
	beq	3f
	tstb	(r3)+ /
	bne	2b
3:
	mov	r2,u.namep / u.namep points to char following a / or nul
	mov	u.dirbuf,r1 / move i-node number in directory entry to r1
	tst	r4 / if r4 = 0 the end of file name reached, if r4 = </>
		   / then go to next directory
	bne	1b

nig:
	tst	(r0)+ / gives non-error return
nib:
	rts	r0

syschdir: / makes the directory specified in the argument the current 
	  / directory
	jsr	r0,arg; u.namep / u.namep points to path name
	jsr	r0,namei / find its i-number
		br error3
	jsr	r0,access; 2 / get i-node into core
	bit	$40000,i.flgs / is it a directory?
	beq	error3 / no error
	mov	r1,u.cdir / move i-number to users current directory
	mov	cdev,u.cdev / move its device to users current device
	br	sysret3
	
isown:
	jsr	r0,arg2 / u.namep points to file name
	jsr	r0,namei / get its i-number
		br error3
	jsr	r0,iget / get i-node into core
	tstb	u.uid / super user?
	beq	1f / yes, branch
	cmpb	i.uid,u.uid / no, is this the owner of the file
	beq	1f / yes
	jmp	error3 / no, error
1:
	jsr	r0,setimod / indicates i-node has been modified
	mov	(sp)+,r2 / mode is put in r2 (u.off put on stack with 
			 / 2nd arg)
	rts	r0

syschmod: / name; mode
	jsr	r0,isown / get the i-node and check user status
	bit	$40000,i.flgs / directory?
	beq	2f / no
	bic	$60,r2 / su & ex / yes, clear set user id and 
				 / executable modes
2:
	movb	r2,i.flgs / move remaining mode to i.flgs
	br	1f

syschown: / name; owner
	jsr	r0,isown / get the i-node and check user status
	tstb	u.uid / super user
	beq	2f / yes, 2f
	bit	$40,i.flgs / no, set userid on execution?
	bne	3f / yes error, could create Trojan Horses
2:
	movb	r2,i.uid / no, put the new owners id in the i-node
1:
	jmp	sysret4
3:
	jmp	error

arg:
	mov	u.sp,r1
	mov	*18.(r1),*(r0)+ / put argument of system call into 
				/ argument of arg2
	add	$2,18.(r1) / point pc on stack to next system argument
	rts	r0
	
arg2:
	jsr	r0,arg; u.namep / u.namep contains value of first arg in 
				/ sys call
	jsr	r0,arg; u.off / u.off contains value of second arg in 
			      / sys call
	mov	r0,r1 / r0 points to calling routine
	mov	(sp),r0 / put operation code back in r0
	mov	u.off,(sp) / put pointer to second argument on stack
	jmp	(r1) / return to calling routine

systime: / get time of year
	mov	s.time,4(sp)
	mov	s.time+2,2(sp) / put the present time on the stack
	br	sysret4

sysstime: / set time
	tstb	u.uid / is user the super user
	bne	error4 / no, error
	mov	4(sp),s.time
	mov	2(sp),s.time+2 / set the system time
	br	sysret4
	
sysbreak: / set the program break
	mov	u.break,r1 / move users break point to r1
	cmp	r1,$core / is it the same or lower than core?
	blos	1f / yes, 1f
	cmp	r1,sp / is it the same or higher than the stack?
	bhis	1f / yes, 1f
	bit	$1,r1 / is it an odd address
	beq	2f / no, its even
	clrb	(r1)+ / yes, make it even
2: / clear area between the break point and the stack
	cmp	r1,sp / is it higher or same than the stack
	bhis	1f / yes, quit
	clr	(r1)+ / clear word
	br	2b / go back
1:
	jsr	r0,arg; u.break / put the "address" in u.break (set new 
				/ break point)
	br	sysret4 / br sysret
	
maknod: / r1 contains the mode
	bis	$100000,r1 / allocate flag set
	mov	r1,-(sp) / put mode on stack
	mov	ii,r1 / move current i-number to r1
	jsr	r0,access; 1 / get its i-node into core
	mov	r1,-(sp) / put i-number on stack
	mov	$40.,r1 / r1 = 40
1: / scan for a free i-node (next 4 instructions)
	inc	r1 / r1 = r1 + 1
	jsr	r0,imap / get byte address and bit position in inode map in 
			/ r2 & m
	bitb	mq,(r2) / is the i-node active
	bne	1b / yes, try the next one
	bisb	mq,(r2) / no, make it active (put a 1 in the bit map)
	jsr	r0,iget / get i-node into core
	tst	i.flgs / is i-node already allocated
	blt	1b / yes, look for another one
	mov	r1,u.dirbuf / no, put i-number in u.dirbuf
	mov	(sp)+,r1 / get current i-number back
	jsr	r0,iget / get i-node in core
	jsr	r0,mkdir / make a directory entry in current directory
	mov	u.dirbuf,r1 / r1 = new inode number
	jsr	r0,iget / get it into core
	jsr	r0,copyz; inode; inode+32. / 0 it out
	mov	(sp)+,i.flgs / fill flags
	movb	u.uid,i.uid / user id
	movb	$1,i.nlks / 1 link
	mov	s.time,i.ctim / time created
	mov	s.time+2,i.ctim+2 / time modified
	jsr	r0,setimod / set modified flag
	rts	r0 / return
	
sysseek: / moves read write pointer in an fsp entry
	jsr	r0,seektell / get proper value in u.count
	add	u.base,u.count / add u.base to it
	mov	u.count,*u.fofp / put result into r/w pointer
	br	sysret4
	
systell: / get the r/w pointer
	jsr	r0,seektell
	br	error4
	
error4:
	jmp	error / see 'error' routine
sysret4:
	jmp	sysret / see 'sysret' routine
	
seektell:
	jsr	r0,arg; u.base / puts offset in u.base
	jsr	r0,arg; u.count / put ptr name in u.count
	mov	*u.r0,r1 / file descriptor in r1 (index in u.fp list)
	jsr	r0,getf / u.fofp points to 3rd word in fsp entry
	mov	r1,-(sp) / r1 has i-number of file, put it on the stack
	beq	error4 / if i-number is 0, not active so error
	bgt	.+4 / if its positive jump
	neg	r1 / if not make it positive
	jsr	r0,iget / get its i-node into core
	cmp	u.count,$1 / is ptr name =1
	blt	2f / no its zero
	beq	1f / yes its 1
	mov	i.size,u.count /  put number of bytes in file in u.count
	br	2f
1: / ptr name =1
	mov	*u.fofp,u.count / put offset in u.count
2: / ptrname =0
	mov	(sp)+,r1 / i-number on stack  r1
	rts	r0
	
sysintr: / set interrupt handling
	jsr	r0,arg; u.intr / put the argument in u.intr
	br	1f / go into quit routine
sysquit:
	jsr	r0,arg; u.quit / put argument in u.quit
1:
	mov	u.ttyp,r1 / move pointer to control tty buffer to r1
	beq	sysret4 / return to user
	clrb	6(r1) / clear the interrupt character in the tty buffer
	br	sysret4 / return to user
	
syssetuid: / set process id
	movb	*u.r0,r1 / move process id (number) to r1
	cmpb	r1,u.ruid / is it equal to the real user id number
	beq	1f / yes
	tstb	u.uid / no, is current user the super user?
	bne	error4 / no, error
1:
	movb	r1,u.uid / put process id in u.uid
	movb	 r1,u.ruid / put process id in u.ruid
	br	sysret4 / system return
	
sysgetuid:
	movb	u.ruid,*u.r0 / move the real user id to (u.r0)
	br	sysret4 / systerm return, sysret
	
fclose:
	mov	r1,-(sp) / put r1 on the stack (it contains the index 
			 / to u.fp list)
	jsr	r0,getf / r1 contains i-number, cdev has device =, u.fofp 
			/ points to 3rd word of fsp entry
	tst	r1 / is inumber 0?
	beq	1f / yes, i-node not active so return
	tst	(r0)+ / no, jump over error return
	mov	r1,r2 / move i-number to r2
	mov	(sp),r1 / restore value of r1 from the stack which is 
			/ index to u.fp
	clrb	u.fp(r1) / clear that entry in the u.fp list
	mov	u.fofp,r1 / r1 points to 3rd word in fsp entry
	decb	2(r1) / decrement the number of processes that have opened 
		      / the file
	bge	1f / if all processes haven't closed the file, return
	mov	r2,-(sp) / put r2 on the stack (i-number)
	clr	-4(r1) / clear 1st word of fsp entry
	tstb	3(r1) / has this file been deleted
	beq	2f / no, branch
	mov	r2,r1 / yes, put i-number back into r1
	jsr	r0,anyi / free all blocks related to i-number
			/ check if file appears in fsp again
2:
	mov	(sp)+,r1 / put i-number back into r1
	jsr	r0,iclose / check to see if its a special file
1:
	mov	(sp)+,r1 / put index to u.fp back into r1
	rts	r0
	
anyi: / r1 contains an i-number
	mov	$fsp,r2 / move start of fsp table to r2
1:
	cmp	r1,(r2) / do i-numbers match?
	beq	1f / yes, 1f
	neg	r1 / no complement r1
	cmp	r1,(r2) / do they match now?
	beq	1f / yes, transfer
		   / i-numbers do not match
	add	$8,r2 / no, bump to next entry in fsp table
	cmp	r2,$fsp+[nfiles*8] / are we at last entry in the table
	blt	1b / no, check next entries i-number
	tst	r1 / yes, no match
	bge	.+4
	neg	r1 / make i-number positive
	jsr	r0,imap / get address of allocation bit in the i-map in r2
	bicb	mq,(r2) / clear bit for i-node in the imap
	jsr	r0,itrunc / free all blocks related to i-node
	clr	i.flgs / clear all flags in the i-node
	rts	r0 / return
1: / i-numbers match
	incb	7(r2) / increment upper byte of the 4th word
	rts	r0 / in that fsp entry (deleted flag of fsp entry)