subr.S revision 1.1 1 /* $NetBSD: subr.S,v 1.1 2002/02/23 23:48:04 matt Exp $ */
2
3 /*
4 * Copyright (c) 1994 Ludd, University of Lule}, Sweden.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed at Ludd, University of Lule}.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <machine/asm.h>
34
35 #include "assym.h"
36 #include "opt_ddb.h"
37 #include "opt_multiprocessor.h"
38 #include "opt_lockdebug.h"
39 #include "opt_compat_netbsd.h"
40 #include "opt_compat_ibcs2.h"
41 #ifdef COMPAT_IBCS2
42 #include <compat/ibcs2/ibcs2_syscall.h>
43 #endif
44 #include "opt_compat_ultrix.h"
45 #ifdef COMPAT_ULTRIX
46 #include <compat/ultrix/ultrix_syscall.h>
47 #endif
48
49 #define JSBENTRY(x) .globl x ; .align 2 ; x :
50
51 .text
52
53 #ifdef KERNEL_LOADABLE_BY_MOP
54 /*
55 * This is a little tricky. The kernel is not loaded at the correct
56 * address, so the kernel must first be relocated, then copied, then
57 * jump back to the correct address.
58 */
59 /* Copy routine */
60 cps:
61 2: movb (r0)+,(r1)+
62 cmpl r0,r7
63 bneq 2b
64
65 3: clrb (r1)+
66 incl r0
67 cmpl r0,r6
68 bneq 3b
69 clrl -(sp)
70 movl sp,ap
71 movl $_cca,r7
72 movl r8,(r7)
73 movpsl -(sp)
74 pushl r2
75 rei
76 cpe:
77
78 /* Copy the copy routine */
79 1: movab cps,r0
80 movab cpe,r1
81 movl $0x300000,sp
82 movl sp,r3
83 4: movb (r0)+,(r3)+
84 cmpl r0,r1
85 bneq 4b
86 movl r7,r8
87 /* Ok, copy routine copied, set registers and rei */
88 movab _edata,r7
89 movab _end,r6
90 movl $0x80000000,r1
91 movl $0x80000200,r0
92 subl3 $0x200,r6,r9
93 movab 2f,r2
94 subl2 $0x200,r2
95 movpsl -(sp)
96 pushab 4(sp)
97 rei
98
99 /*
100 * First entry routine from boot. This should be in a file called locore.
101 */
102 JSBENTRY(start)
103 brb 1b # Netbooted starts here
104 #else
105 ASENTRY(start, 0)
106 #endif
107 2: bisl3 $0x80000000,r9,_C_LABEL(esym) # End of loaded code
108 pushl $0x1f0000 # Push a nice PSL
109 pushl $to # Address to jump to
110 rei # change to kernel stack
111 to: movw $0xfff,_C_LABEL(panic) # Save all regs in panic
112 cmpb (ap),$3 # symbols info present?
113 blssu 3f # nope, skip
114 bisl3 $0x80000000,8(ap),_C_LABEL(symtab_start)
115 # save start of symtab
116 movl 12(ap),_C_LABEL(symtab_nsyms) # save end of symtab
117 3: addl3 _C_LABEL(esym),$0x3ff,r0 # Round symbol table end
118 bicl3 $0x3ff,r0,_C_LABEL(proc0paddr) # save proc0 uarea pointer
119 bicl3 $0x80000000,_C_LABEL(proc0paddr),r0 # get phys proc0 uarea addr
120 mtpr r0,$PR_PCBB # Save in IPR PCBB
121 addl3 $USPACE,_C_LABEL(proc0paddr),r0 # Get kernel stack top
122 mtpr r0,$PR_KSP # put in IPR KSP
123 movl r0,_C_LABEL(Sysmap) # SPT start addr after KSP
124 movl _C_LABEL(proc0paddr),r0 # get PCB virtual address
125 movab IFTRAP(r0),4(r0) # Save trap address in ESP
126 mtpr 4(r0),$PR_ESP # Put it in ESP also
127
128 # Set some registers in known state
129 movl _C_LABEL(proc0paddr),r0
130 clrl P0LR(r0)
131 clrl P1LR(r0)
132 mtpr $0,$PR_P0LR
133 mtpr $0,$PR_P1LR
134 movl $0x80000000,r1
135 movl r1,P0BR(r0)
136 movl r1,P1BR(r0)
137 mtpr r1,$PR_P0BR
138 mtpr r1,$PR_P1BR
139 clrl IFTRAP(r0)
140 mtpr $0,$PR_SCBB
141
142 # Copy the RPB to its new position
143 #if defined(COMPAT_14)
144 tstl (ap) # Any arguments?
145 bneq 1f # Yes, called from new boot
146 movl r11,_C_LABEL(boothowto) # Howto boot (single etc...)
147 # movl r10,_C_LABEL(bootdev) # uninteresting, will complain
148 movl r8,_C_LABEL(avail_end) # Usable memory (from VMB)
149 clrl -(sp) # Have no RPB
150 brb 2f
151 #endif
152
153 1: pushl 4(ap) # Address of old rpb
154 2: calls $1,_C_LABEL(_start) # Jump away.
155 /* NOTREACHED */
156
157
158 /*
159 * Signal handler code.
160 */
161
162 .align 2
163 .globl _C_LABEL(sigcode),_C_LABEL(esigcode)
164 _C_LABEL(sigcode):
165 pushr $0x3f
166 subl2 $0xc,sp
167 movl 0x24(sp),r0
168 calls $3,(r0)
169 popr $0x3f
170 chmk $SYS___sigreturn14
171 chmk $SYS_exit
172 halt
173 _C_LABEL(esigcode):
174
175 #ifdef COMPAT_IBCS2
176 .align 2
177 .globl _C_LABEL(ibcs2_sigcode),_C_LABEL(ibcs2_esigcode)
178 _C_LABEL(ibcs2_sigcode):
179 pushr $0x3f
180 subl2 $0xc,sp
181 movl 0x24(sp),r0
182 calls $3,(r0)
183 popr $0x3f
184 chmk $SYS___sigreturn14
185 chmk $SYS_exit
186 halt
187 _C_LABEL(ibcs2_esigcode):
188 #endif /* COMPAT_IBCS2 */
189
190 #ifdef COMPAT_ULTRIX
191 .align 2
192 .globl _C_LABEL(ultrix_sigcode),_C_LABEL(ultrix_esigcode)
193 _C_LABEL(ultrix_sigcode):
194 pushr $0x3f
195 subl2 $0xc,sp
196 movl 0x24(sp),r0
197 calls $3,(r0)
198 popr $0x3f
199 chmk $ULTRIX_SYS_sigreturn
200 chmk $SYS_exit
201 halt
202 _C_LABEL(ultrix_esigcode):
203 #endif
204
205 .align 2
206 .globl _C_LABEL(idsptch), _C_LABEL(eidsptch)
207 _C_LABEL(idsptch): pushr $0x3f
208 .word 0x9f16 # jsb to absolute address
209 .long _C_LABEL(cmn_idsptch) # the absolute address
210 .long 0 # the callback interrupt routine
211 .long 0 # its argument
212 .long 0 # ptr to correspond evcnt struct
213 _C_LABEL(eidsptch):
214
215 _C_LABEL(cmn_idsptch):
216 movl (sp)+,r0 # get pointer to idspvec
217 movl 8(r0),r1 # get evcnt pointer
218 beql 1f # no ptr, skip increment
219 incl EV_COUNT(r1) # increment low longword
220 adwc $0,EV_COUNT+4(r1) # add any carry to hi longword
221 1: pushl 4(r0) # push argument
222 calls $1,*(r0) # call interrupt routine
223 popr $0x3f # pop registers
224 rei # return from interrut
225
226 ENTRY(badaddr,0) # Called with addr,b/w/l
227 mfpr $PR_IPL,r0 # splhigh()
228 mtpr $IPL_HIGH,$PR_IPL
229 movl 4(ap),r2 # First argument, the address
230 movl 8(ap),r1 # Sec arg, b,w,l
231 pushl r0 # Save old IPL
232 clrl r3
233 movab 4f,_C_LABEL(memtest) # Set the return address
234
235 caseb r1,$1,$4 # What is the size
236 1: .word 1f-1b
237 .word 2f-1b
238 .word 3f-1b # This is unused
239 .word 3f-1b
240
241 1: movb (r2),r1 # Test a byte
242 brb 5f
243
244 2: movw (r2),r1 # Test a word
245 brb 5f
246
247 3: movl (r2),r1 # Test a long
248 brb 5f
249
250 4: incl r3 # Got machine chk => addr bad
251 5: mtpr (sp)+,$PR_IPL
252 movl r3,r0
253 ret
254
255 #ifdef DDB
256 /*
257 * DDB is the only routine that uses setjmp/longjmp.
258 */
259 .globl _C_LABEL(setjmp), _C_LABEL(longjmp)
260 _C_LABEL(setjmp):.word 0
261 movl 4(ap), r0
262 movl 8(fp), (r0)
263 movl 12(fp), 4(r0)
264 movl 16(fp), 8(r0)
265 moval 28(fp),12(r0)
266 clrl r0
267 ret
268
269 _C_LABEL(longjmp):.word 0
270 movl 4(ap), r1
271 movl 8(ap), r0
272 movl (r1), ap
273 movl 4(r1), fp
274 movl 12(r1), sp
275 jmp *8(r1)
276 #endif
277
278 #
279 # setrunqueue/remrunqueue fast variants.
280 #
281
282 JSBENTRY(Setrq)
283 #ifdef DIAGNOSTIC
284 tstl 4(r0) # Check that process actually are off the queue
285 beql 1f
286 pushab setrq
287 calls $1,_C_LABEL(panic)
288 setrq: .asciz "setrunqueue"
289 #endif
290 1: extzv $2,$6,P_PRIORITY(r0),r1 # get priority
291 movaq _C_LABEL(sched_qs)[r1],r2 # get address of queue
292 insque (r0),*PH_RLINK(r2) # put proc last in queue
293 bbss r1,_C_LABEL(sched_whichqs),1f # set queue bit.
294 1: rsb
295
296 JSBENTRY(Remrq)
297 extzv $2,$6,P_PRIORITY(r0),r1
298 #ifdef DIAGNOSTIC
299 bbs r1,_C_LABEL(sched_whichqs),1f
300 pushab remrq
301 calls $1,_C_LABEL(panic)
302 remrq: .asciz "remrunqueue"
303 #endif
304 1: remque (r0),r2
305 bneq 2f # Not last process on queue
306 bbsc r1,_C_LABEL(sched_whichqs),2f
307 2: clrl P_BACK(r0) # saftey belt
308 rsb
309
310 #
311 # Idle loop. Here we could do something fun, maybe, like calculating
312 # pi or something.
313 #
314 idle:
315 #if defined(LOCKDEBUG)
316 calls $0,_C_LABEL(sched_unlock_idle)
317 #elif defined(MULTIPROCESSOR)
318 clrl _C_LABEL(sched_lock) # release sched lock
319 #endif
320 mtpr $1,$PR_IPL # IPL cannot be 0 because we are
321 # running on the interrupt stack
322 # and may get interrupts
323
324 1: tstl _C_LABEL(sched_whichqs) # Anything ready to run?
325 beql 1b # no, run the idle loop again.
326 /* Now try the test the long way */
327 mtpr $IPL_HIGH,$PR_IPL # block all types of interrupts
328 #if defined(LOCKDEBUG)
329 calls $0,_C_LABEL(sched_lock_idle)
330 #elif defined(MULTIPROCESSOR)
331 3: bbssi $0,_C_LABEL(sched_lock),3b # acquire sched lock
332 #endif
333 brb lp # check sched_whichqs again
334
335 #
336 # cpu_switch, cpu_exit and the idle loop implemented in assembler
337 # for efficiency. r6 contains pointer to last process. This is
338 # called at IPL_HIGH.
339 #
340
341 JSBENTRY(Swtch)
342 mfpr $PR_SSP,r1 # Get ptr to this cpu_info struct
343 clrl CI_CURPROC(r1) # Stop process accounting
344 svpctx # Save context if another CPU
345 # get control first (must be on
346 # the interrupt stack when idling)
347
348
349 lp: ffs $0,$32,_C_LABEL(sched_whichqs),r3 # Search for bit set
350 beql idle # no bit set, go to idle loop
351
352 movaq _C_LABEL(sched_qs)[r3],r1 # get address of queue head
353 remque *(r1),r2 # remove proc pointed to by queue head
354 # proc ptr is now in r2
355 #ifdef DIAGNOSTIC
356 bvc 1f # check if something on queue
357 pushab noque
358 calls $1,_C_LABEL(panic)
359 #endif
360
361 1: bneq 2f # more processes on queue?
362 bbsc r3,_C_LABEL(sched_whichqs),2f # no, clear bit in whichqs
363 2: clrl P_BACK(r2) # clear proc backpointer
364 mfpr $PR_SSP,r1 # Get ptr to this cpu_info struct
365 /* p->p_cpu initialized in fork1() for single-processor */
366 #if defined(MULTIPROCESSOR)
367 movl r1,P_CPU(r2) # p->p_cpu = curcpu();
368 #endif
369 movb $SONPROC,P_STAT(r2) # p->p_stat = SONPROC;
370 movl r2,CI_CURPROC(r1) # set new process running
371 clrl CI_WANT_RESCHED(r1) # we are now changing process
372 movl P_ADDR(r2),r0 # Get pointer to new pcb.
373 addl3 r0,$IFTRAP,r1 # Save for copy* functions.
374 mtpr r1,$PR_ESP # Use ESP as CPU-specific pointer
375 movl r1,ESP(r0) # Must save in PCB also.
376 mfpr $PR_SSP,r1 # New process must inherit cpu_info
377 movl r1,SSP(r0) # Put it in new PCB
378
379 #
380 # Nice routine to get physical from virtual adresses.
381 #
382 extzv $9,$21,r0,r1 # extract offset
383 ashl $9,*_C_LABEL(Sysmap)[r1],r3
384
385 mtpr r3,$PR_PCBB
386 ldpctx
387 #if defined(LOCKDEBUG)
388 calls $0,_C_LABEL(sched_unlock_idle)
389 #elif defined(MULTIPROCESSOR)
390 clrl _C_LABEL(sched_lock) # clear sched lock
391 #endif
392 rei
393
394 #if defined(MULTIPROCESSOR)
395 .align 2
396 .globl _C_LABEL(tramp) # used to kick off multiprocessor systems.
397 _C_LABEL(tramp):
398 ldpctx
399 rei
400 #endif
401
402 #
403 # the last routine called by a process.
404 #
405
406 ENTRY(cpu_exit,0)
407 movl 4(ap),r6 # Process pointer in r6
408 mtpr $IPL_CLOCK,$PR_IPL # Block almost everything
409 mfpr $PR_SSP,r7 # get cpu_info ptr
410 movl CI_EXIT(r7),r8 # scratch page address
411 movab 512(r8),sp # change stack
412 bicl2 $0xc0000000,r8 # get physical address
413 mtpr r8,$PR_PCBB # new PCB
414 mtpr r7,$PR_SSP # In case...
415 pushl r6
416 calls $1,_C_LABEL(exit2) # release last resources.
417 mtpr $IPL_HIGH,$PR_IPL # block all types of interrupts
418 #if defined(LOCKDEBUG)
419 calls $0,_C_LABEL(sched_lock_idle)
420 #elif defined(MULTIPROCESSOR)
421 1: bbssi $0,_C_LABEL(sched_lock),1b # acquire sched lock
422 #endif
423 clrl r6
424 brw Swtch
425
426 #
427 # copy/fetch/store routines.
428 #
429
430 ENTRY(copyout, 0)
431 movl 8(ap),r2
432 blss 3f # kernel space
433 movl 4(ap),r1
434 brb 2f
435
436 ENTRY(copyin, 0)
437 movl 4(ap),r1
438 blss 3f # kernel space
439 movl 8(ap),r2
440 2: mfpr $PR_ESP,r3
441 movab 1f,(r3)
442 movc3 12(ap),(r1),(r2)
443 1: mfpr $PR_ESP,r3
444 clrl (r3)
445 ret
446
447 3: mnegl $1,r0
448 ret
449
450 ENTRY(kcopy,0)
451 mfpr $PR_ESP,r3
452 movl (r3),-(sp)
453 movab 1f,(r3)
454 movl 4(ap),r1
455 movl 8(ap),r2
456 movc3 12(ap),(r1), (r2)
457 clrl r1
458 1: mfpr $PR_ESP,r3
459 movl (sp)+,(r3)
460 movl r1,r0
461 ret
462
463 /*
464 * copy{in,out}str() copies data from/to user space to/from kernel space.
465 * Security checks:
466 * 1) user space address must be < KERNBASE
467 * 2) the VM system will do the checks while copying
468 */
469 ENTRY(copyinstr, 0)
470 tstl 4(ap) # kernel address?
471 bgeq 8f # no, continue
472 6: movl $EFAULT,r0
473 movl 16(ap),r2
474 beql 7f
475 clrl (r2)
476 7: ret
477
478 ENTRY(copyoutstr, 0)
479 tstl 8(ap) # kernel address?
480 bgeq 8f # no, continue
481 brb 6b # yes, return EFAULT
482
483 ENTRY(copystr,0)
484 8: movl 4(ap),r5 # from
485 movl 8(ap),r4 # to
486 movl 12(ap),r3 # len
487 movl 16(ap),r2 # copied
488 clrl r0
489 mfpr $PR_ESP,r1
490 movab 3f,(r1)
491
492 tstl r3 # any chars to copy?
493 bneq 1f # yes, jump for more
494 0: tstl r2 # save copied len?
495 beql 2f # no
496 subl3 4(ap),r5,(r2) # save copied len
497 2: ret
498
499 1: movb (r5)+,(r4)+ # copy one char
500 beql 0b # jmp if last char
501 sobgtr r3,1b # copy one more
502 movl $ENAMETOOLONG,r0 # inform about too long string
503 brb 0b # out of chars
504
505 3: mfpr $PR_ESP,r1
506 clrl (r1)
507 brb 0b
508
509 ENTRY(subyte,0)
510 movl 4(ap),r0
511 blss 3f # illegal space
512 mfpr $PR_ESP,r1
513 movab 1f,(r1)
514 movb 8(ap),(r0)
515 clrl r1
516 1: mfpr $PR_ESP,r2
517 clrl (r2)
518 movl r1,r0
519 ret
520
521 ENTRY(suword,0)
522 movl 4(ap),r0
523 blss 3f # illegal space
524 mfpr $PR_ESP,r1
525 movab 1f,(r1)
526 movl 8(ap),(r0)
527 clrl r1
528 1: mfpr $PR_ESP,r2
529 clrl (r2)
530 movl r1,r0
531 ret
532
533 ENTRY(suswintr,0)
534 movl 4(ap),r0
535 blss 3f # illegal space
536 mfpr $PR_ESP,r1
537 movab 1f,(r1)
538 movw 8(ap),(r0)
539 clrl r1
540 1: mfpr $PR_ESP,r2
541 clrl (r2)
542 movl r1,r0
543 ret
544
545 3: mnegl $1,r0
546 ret
547
548 .align 2
549 ALTENTRY(fusword)
550 ENTRY(fuswintr,0)
551 movl 4(ap),r0
552 blss 3b
553 mfpr $PR_ESP,r1
554 movab 1f,(r1)
555 movzwl (r0),r1
556 1: mfpr $PR_ESP,r2
557 clrl (r2)
558 movl r1,r0
559 ret
560
561 #if defined(MULTIPROCESSOR)
562
563 JSBENTRY(Slock)
564 1: bbssi $0,(r1),1b
565 rsb
566
567 JSBENTRY(Slocktry)
568 clrl r0
569 bbssi $0,(r1),1f
570 incl r0
571 1: rsb
572
573 JSBENTRY(Sunlock)
574 bbcci $0,(r1),1f
575 1: rsb
576
577 #endif
578
579 #
580 # data department
581 #
582 .data
583
584 .globl _C_LABEL(memtest)
585 _C_LABEL(memtest): # memory test in progress
586 .long 0
587
588 #ifdef __ELF__
589 .section .rodata
590 #endif
591 noque: .asciz "swtch"
592