xref: /csrg-svn/sys/vax/mdec/tmscpboot.c (revision 33387)
1 #
2 #	@(#)tmscpboot.c	7.1 (Berkeley) 01/22/88
3 #
4 # TK50 tape boot block for distribution tapes
5 # works on Q-bus tk50 drive on uVaxen
6 #
7 # Rick Lindsley
8 # richl@tektronix.tek.com
9 #
10 # reads a program from a tp directory on a tape and executes it
11 # program must be stripped of the header and is loaded ``bits as is''
12 # you can return to this loader via ``ret'' as you are called ``calls $0,ent''
13 #
14 	.set	RELOC,0x70000
15 /*  tp directory definitions */
16 	.set	FILSIZ,38	# tp direc offset for file size
17 	.set	BNUM,44		# tp dir offset for start block no.
18 	.set	ENTSIZ,64	# size of 1 TP dir entry, bytes
19 	.set	PTHSIZ,32	# size of TP path name, bytes
20 	.set	BLKSIZ,512	# tape block size, bytes
21 	.set	NUMDIR,24	# no. of dir blocks on tape
22 	.set	ENTBLK,8	# no. of dir entries per tape block
23 /* processor registers and bits */
24 	.set	RXCS,32
25 	.set	RXDB,33
26 	.set	TXCS,34
27 	.set	TXDB,35
28 	.set	RXCS_DONE,0x80
29 	.set	TXCS_RDY,0x80
30 	.set	TXCS_pr,7	/* bit position of TXCS ready bit */
31 	.set	RXCS_pd,7	/* bit position of RXCS done bit */
32 /* UBA registers */
33 	.set	MAPSTART,0x20088000	# for a uVax, anyway
34 	.set	UBAMEM,0x1ffc2000	# again, for a uVax
35 	.set	MRV,0x80000000		# map register valid bit
36 /* TMSCP UBA registers */
37 	.set	TMSCP_CSR, 0774500	# CSR of tk50
38 	.set	TMSCPip,0		# initialization and polling
39 	.set	TMSCPsa,2		# status and address
40 /* handy values for tmscp communication area */
41 	.set	TMSCP_OWN,0x80000000
42 	.set	TMSCP_ERR,0x8000
43 	.set	TMSCP_STEP4,0x4000
44 	.set	TMSCP_STEP3,0x2000
45 	.set	TMSCP_STEP2,0x1000
46 	.set	TMSCP_STEP1,0x800
47 	.set	TMSCP_IE,0x80
48 	.set	TMSCP_GO,1
49 /* handy offsets into tmscp communication area (from tmscpca) */
50 	.set	cmdint,4
51 	.set	rspint,6
52 	.set	rspdsc,8
53 	.set	cmddsc,12
54 /* handy offsets into mscp packets (from %rCMD or %rRSP) */
55 	.set	msglen,0
56 	.set	vcid,3
57 	.set	unit,8
58 	.set	op,12
59 	.set	status,14
60 	.set	modifier,14
61 	.set	bytecnt,16
62 	.set	cntflgs,18
63 	.set	buffer,20
64 	.set	tmkcnt,20
65 	.set	lbn,32
66 	.set	dscptr,40
67 /* TMSCP commands and modifiers */
68 	.set	M_OP_STCON,4
69 	.set	M_OP_ONLIN,9
70 	.set	M_OP_READ,33
71 	.set	M_OP_REPOS,37
72 	.set	M_MD_REWND,2
73 	.set	M_MD_IMMED,0x80
74 	.set	M_MD_CLSEX,0x200
75 	.set	M_ST_MASK,0x1f
76 	.set	M_ST_TAPEM,14
77 /* miscellaneous */
78 	.set	IUR, 0x37
79 	.set	SID, 0x3e
80 	.set	VAX_630,8
81 /* local stack variables */
82 	.set	tmscpca,-240-PTHSIZ-26	# struct tmscpca (see tmscpreg.h)
83 	.set	rsp,-240-PTHSIZ-10	# tmscp response area
84 	.set	cmd,-120-PTHSIZ-10	# tmscp command area
85 	.set	name,-PTHSIZ-10		# operator-typed file name
86 	.set	dirread,-10		# is the tape directory incore already?
87 	.set	mtapa,-8		# cur tape addr (last blk we read)
88 	.set	tapa,-4			# desired tape addr (inclusive)
89 /* register usage */
90 	.set	rCMD,r7
91 	.set	rRSP,r8
92 	.set	rUBADDR,r9
93 	.set	rMAPREGS,r10
94 	.set	rCSR,r11
95 /* ===== */
96 
97 /* initialization */
98 init:
99 	#
100 	# if on a uVax, we were loaded by VMB from tape. We also have
101 	# only one unibus, at 0x1fffc2000 (see above). Elstwise, this
102 	# boot program will almost certainly need help.
103 	#
104 	mfpr	$SID,r0
105 	cmpzv	$24,$8,r0,$VAX_630
106 	beql	1f
107 	halt
108 	#
109 	# We must have been loaded by VMB, and thus we are at a non-zero
110 	# location.  sp will contain the base address of the area at which
111 	# we were loaded. So we add sp to $end to get the true end-of-program
112 	# address.
113 	#
114 1:	movl	sp,r6		# r6 - beginning of program
115 	movl	$RELOC,fp	# core loc to which to move this program
116 	addl3	$-512,fp,sp	# set stack pointer; leave room for locals
117 	addl3	$-512,fp,r0	# zero our destination mem .. we start here
118 	addl3	$end,fp,r1	# and end here
119 clr:	clrl	(r0)+
120 	cmpl	r0,r1
121 	jlss	clr
122 
123 	movc3	$end,(r6),(fp)	# copy to relocated position
124 	addl3	$reginit,$RELOC,r0
125 	jmp	(r0)		# and go there
126 reginit:
127 	/* initialize our registers. Should need to do this only once */
128 	addl3	$UBAMEM, $TMSCP_CSR, %rCSR	# set up CSR register
129 	movl	$MAPSTART, %rMAPREGS	# locate map registers
130 
131 	moval	tmscpca(fp), %rUBADDR	# set unibus address for comm area
132 	extzv	$0,$9,%rUBADDR,%rUBADDR	# format: (MR# << 9) | (&comm & 0x1ff)
133 	ashl	$-9,$RELOC-512,r0	# setting up map register for our stack
134 	bisl3	$MRV,r0,(%rMAPREGS)	# mark our stack valid (MR #0)
135 
136 	moval	cmd(fp),%rCMD		# location of cmd mscp packet
137 	moval	rsp(fp),%rRSP		# location of rsp mscp packet
138 	bsbw	inittmscp		# init the unit
139 	bsbw	onlin			# set tape online
140 	bsbw	rew			# rewind tape
141 
142 start:
143 #	movzbl	$11,r0			# newline
144 #	bsbw	putc
145 #	movzbl	$13,r0			# return
146 #	bsbw	putc
147 	movzbl	$'=,r0			# prompt
148 	bsbw	putc
149 	bsbw	getname
150 
151 	# desired TP filename is in name(fp).  Now read in entire tp directory
152 	# contents into low core, starting at loc 0. Because tk50's are slow,
153 	# and because we are going to go over 512 bytes anyway, and because
154 	# it requires so little effort, we'll keep track of whether the data
155 	# at location 0 is the tape directory.
156 
157 	tstw	dirread(fp)	# if directory needs to be read in, do so
158 	bneq	1f
159 	bsbw	readdir
160 1:
161 	#
162 	# all of directory is now in locore, @ 0.
163 	# search for filename; return to start if it isn't there.
164 	#
165 	clrl	r0			# start at location 0
166 nxtdir:	moval	name(fp),r2
167 	movl	r0,r1
168 1:	cmpb	(r1),(r2)
169 	bneq	2f
170 	tstb	(r1)
171 	beql	found
172 	incl	r1
173 	incl	r2
174 	brb	1b
175 2:	acbl	$NUMDIR*BLKSIZ-1,$ENTSIZ,r0,nxtdir
176 	brw	start			# entry not in directory; start over
177 
178 	# entry IS here; read it in from tape
179 
180 found:	movzwl	BNUM(r0),tapa(fp)	# start block no., 2 bytes
181 	addl2	$2-1,tapa(fp)		# skip over this program (2 blocks)
182 					# minus 1 because we will read THROUGH
183 					# this block; so we want to stop just
184 					# before it
185 	movzwl	FILSIZ(r0),r4		# low 2 bytes file size
186 	insv	FILSIZ-1(r0),$16,$8,r4  # file size, high byte
187 	cmpl	r4,$RELOC-512		# check if file fits below stack
188 	bgeq	start 			# file too large
189 
190 	# Now advance to proper place on tape. tapa has our
191 	# desired address
192 
193 	clrw	dirread(fp)	# we are about to obliterate our incore copy
194 				# of the directory
195 2:	clrl	r3	# rrec expects r3 to point to a buffer. 0 will do ...
196 	bsbw	rrec
197 	cmpl	mtapa(fp),tapa(fp)
198 	blss	2b
199 
200 	# tape now positioned correctly. Read in program. Number of bytes
201 	# to read is in r4. We must round up to an even BLKSIZ boundary.
202 	# Clear the area we are putting it at; unix expects zeroes in its
203 	# data and bss section.
204 
205 	addl2	$BLKSIZ-1,r4		# round up
206 	bicl2	$BLKSIZ-1,r4		# mask out
207 	movl	r4,r5			# use r5; need to save r4 for later
208 1:	clrl	(r5)
209 	sobgtr	r5,1b
210 
211 	# now read in file.
212 
213 	clrl	r3			# read into page 0 (incremented by rrec)
214 	ashl	$-9,r4,r5		# r5 now holds # blks to read
215 	addl2	r5,tapa(fp)		# compute desired tape blk #
216 1:	bsbw	rrec
217 	cmpl	mtapa(fp),tapa(fp)	# got it yet?
218 	blss	1b
219 
220 	# begin execution. Call as a function.
221 	clrl	r5
222 	calls	$0,(r5)
223 
224 	# now, since the called function has reset the tape drive for
225 	# us (!) we must reinit it again ourselves.
226 
227 	ashl	$-9,$RELOC-512,r0	# set up map register for our stack
228 	bisl3	$MRV,r0,(%rMAPREGS)	# mark our stack valid (MR #0)
229 	bsbw	inittmscp		# re-init drive
230 	bsbw	onlin			# re-online it
231 	brw	start
232 
233 	# getname will set name(fp) and leave len(name(fp)) in r6
234 getname:moval	name(fp),r1		# mov to register for ease of access
235 nxtc:	bsbw	getc
236 	cmpb	r0,$012			# end of line?
237 	beql	nullc
238 	movb	r0,(r1)+
239 	brb	nxtc
240 nullc:	moval	name(fp),r0
241 	subl3	r0,r1,r6		# length of path name
242 	jeql	start			# just hit return; nothing useful here
243 	clrb	(r1)+			# add null at end
244 	incl	r6			# add null to length
245 	rsb
246 
247 getc:	mfpr	$RXCS,r0
248 	bbc	$RXCS_pd,r0,getc	/* receiver ready ? */
249 	mfpr	$RXDB,r0
250 	extzv	$0,$7,r0,r0
251 	cmpb	r0,$015
252 	bneq	putc
253 	bsbw	putc
254 	movb	$0,r0
255 	bsbw	putc
256 	movb	$012,r0
257 
258 putc:	mfpr	$TXCS,r2
259 	bbc	$TXCS_pr,r2,putc	/* transmitter ready ? */
260 	extzv	$0,$7,r0,r0
261 	mtpr	r0,$TXDB
262 	rsb
263 
264 inittmscp:
265 	movw	$0,TMSCPip(%rCSR)		# start step 1
266 1:	bitw	$TMSCP_STEP1,TMSCPsa(%rCSR)
267 	beql	1b
268 #	movzbl	$'1,r0
269 #	bsbw	putc
270 init2:	movw	$TMSCP_ERR,TMSCPsa(%rCSR)	# start step 2
271 2:	bitw	$TMSCP_STEP2,TMSCPsa(%rCSR)
272 	beql	2b
273 #	movzbl	$'2,r0
274 #	bsbw	putc
275 init3:	addl3	$8,%rUBADDR,r0			# start step 3
276 	cvtlw	r0,TMSCPsa(%rCSR)
277 3:	bitw	$TMSCP_STEP3,TMSCPsa(%rCSR)
278 	beql	3b
279 #	movzbl	$'3,r0
280 #	bsbw	putc
281 init4:	addl3	$8,%rUBADDR,r0			# start step 4
282 	ashl	$-16,r0,r0
283 	cvtlw	r0,TMSCPsa(%rCSR)
284 4:	bitw	$TMSCP_STEP4,TMSCPsa(%rCSR)
285 	beql	4b
286 #	movzbl	$'4,r0
287 #	bsbw	putc
288 setchar:
289 	movw	$TMSCP_GO,TMSCPsa(%rCSR)
290 	moval	140(%rUBADDR),tmscpca+cmddsc(fp)
291 	moval	tmscpca+cmddsc(fp),dscptr(%rCMD)
292 	movb	$1,vcid(%rCMD)
293 	moval	20(%rUBADDR),tmscpca+rspdsc(fp)
294 	moval	tmscpca+rspdsc(fp),dscptr(%rRSP)
295 	clrw	cntflgs(%rCMD)
296 
297 	movb	$M_OP_STCON,op(%rCMD)
298 	clrw	modifier(%rCMD)
299 	clrl	buffer(%rCMD)
300 	clrl	bytecnt(%rCMD)
301 	bsbw	tmscpcmd
302 #	movzbl	$'S,r0
303 #	bsbw	putc
304 
305 	rsb
306 
307 tmscpcmd:
308 	movw	$116,msglen(%rCMD)		# 116 -- size of an mscp packet
309 	bisl2	$TMSCP_OWN,tmscpca+cmddsc(fp)
310 	movw	$116,msglen(%rRSP)
311 	bisl2	$TMSCP_OWN,tmscpca+rspdsc(fp)
312 	movw	TMSCPip(%rCSR),r0		# start polling
313 wait:	cvtwl	TMSCPsa(%rCSR),r0
314 	bitl	$TMSCP_ERR,r0
315 	beql	1f
316 	movw	modifier(%rRSP),r1	# so we can read status easily
317 	halt				# some error or other
318 1:	tstl	tmscpca+4(fp)
319 	beql	2f
320 	clrw	tmscpca+4(fp)
321 2:	bitl	$TMSCP_OWN,tmscpca+rspdsc(fp)
322 	bneq	wait
323 
324 	# cmd done
325 
326 	clrw	tmscpca+rspint(fp)
327 	extzv	$0,$5,status(%rRSP),r0
328 	tstl	r0
329 	beql	ok			# no errors
330 	cmpl	$M_ST_TAPEM, r0
331 	beql	ok			# not an error, just a tape mark
332 	halt				# some unknown error
333 ok:	rsb
334 
335 rew:	movb	$M_OP_REPOS,op(%rCMD)
336 	movw	$M_MD_REWND|M_MD_IMMED,modifier(%rCMD)
337 	clrl	buffer(%rCMD)
338 	clrl	bytecnt(%rCMD)
339 	bsbw	tmscpcmd
340 #	movzbl	$'r,r0			# to indicate r)ewind
341 #	bsbw	putc
342 	movl	$-1,mtapa(fp)		# no blocks read yet
343 	rsb
344 
345 onlin:	movb	$M_OP_ONLIN,op(%rCMD)
346 	clrw	modifier(%rCMD)
347 	clrl	buffer(%rCMD)
348 	clrl	bytecnt(%rCMD)
349 	bsbw	tmscpcmd
350 #	movzbl	$'O,r0			# to indicate O)nline
351 #	bsbw	putc
352 	rsb
353 
354 	# Read the tp directory. Number of blocks to read is in tapa(fp),
355 	# and will be read into memory starting at location 0.
356 readdir:bsbw	rew			# beginning of tape
357 	addl3	$2,$NUMDIR,tapa(fp)	# blocks to read (skip this 1k program)
358 	clrl	r3			# using mem starting at 0 as free space
359 	bsbw	rrec; bsbw rrec		# read and discard first two blocks --
360 					# those are this program
361 	bsbw	rrec			# read and discard first tp block
362 	clrl	r3			# reset starting place
363 	incw	dirread(fp)		# show that directory is incore
364 1:	bsbw	rrec
365 	cmpl	mtapa(fp),tapa(fp)	# done yet?
366 	blss	1b
367 	rsb
368 
369 	# read 1 block from mag tape into page indicated by r3, which will
370 	# automatically be incremented here. mtapa is also advanced.
371 
372 rrec:	bisl3	$MRV,r3,4(%rMAPREGS)	# using map register #1
373 	movl	$BLKSIZ,bytecnt(%rCMD)	# how much to read
374 	ashl	$9,$1,buffer(%rCMD)	# indicating mr #1. We just happen to
375 					# be on a page boundary, so filling in
376 					# the low 9 bits is not necessary.
377 	movb	$M_OP_READ,op(%rCMD)
378 	clrw	modifier(%rCMD)
379 	bsbw	tmscpcmd
380 #	movzbl	$'R,r0			# to indicate R)ead a record
381 #	bsbw	putc
382 	incl	mtapa(fp)
383 	incl	r3
384 	rsb
385 end:
386