subr.S revision 1.16 1 /* $NetBSD: subr.S,v 1.16 2007/03/12 02:22:43 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 number of symtab
117 bisl3 $0x80000000,%r9,_C_LABEL(symtab_end)
118 # save end of symtab
119 3: addl3 _C_LABEL(esym),$0x3ff,%r0 # Round symbol table end
120 bicl3 $0x3ff,%r0,_C_LABEL(proc0paddr) # save proc0 uarea pointer
121 bicl3 $0x80000000,_C_LABEL(proc0paddr),%r0 # get phys proc0 uarea addr
122 mtpr %r0,$PR_PCBB # Save in IPR PCBB
123 addl3 $USPACE,_C_LABEL(proc0paddr),%r0 # Get kernel stack top
124 mtpr %r0,$PR_KSP # put in IPR KSP
125 movl %r0,_C_LABEL(Sysmap) # SPT start addr after KSP
126 movl _C_LABEL(proc0paddr),%r0 # get PCB virtual address
127 movab IFTRAP(%r0),4(%r0) # Save trap address in ESP
128 mtpr 4(%r0),$PR_ESP # Put it in ESP also
129
130 # Set some registers in known state
131 movl _C_LABEL(proc0paddr),%r0
132 clrl P0LR(%r0)
133 clrl P1LR(%r0)
134 mtpr $0,$PR_P0LR
135 mtpr $0,$PR_P1LR
136 movl $0x80000000,%r1
137 movl %r1,P0BR(%r0)
138 movl %r1,P1BR(%r0)
139 mtpr %r1,$PR_P0BR
140 mtpr %r1,$PR_P1BR
141 clrl IFTRAP(%r0)
142 mtpr $0,$PR_SCBB
143
144 # Copy the RPB to its new position
145 #if defined(COMPAT_14)
146 tstl (%ap) # Any arguments?
147 bneq 1f # Yes, called from new boot
148 movl %r11,_C_LABEL(boothowto) # Howto boot (single etc...)
149 # movl %r10,_C_LABEL(bootdev) # uninteresting, will complain
150 movl %r8,_C_LABEL(avail_end) # Usable memory (from VMB)
151 clrl -(%sp) # Have no RPB
152 brb 2f
153 #endif
154
155 1: pushl 4(%ap) # Address of old rpb
156 2: calls $1,_C_LABEL(_start) # Jump away.
157 /* NOTREACHED */
158
159
160 /*
161 * Signal handler code.
162 */
163
164 .align 2
165 .globl _C_LABEL(sigcode),_C_LABEL(esigcode)
166 _C_LABEL(sigcode):
167 pushr $0x3f
168 subl2 $0xc,%sp
169 movl 0x24(%sp),%r0
170 calls $3,(%r0)
171 popr $0x3f
172 chmk $SYS_compat_16___sigreturn14
173 chmk $SYS_exit
174 halt
175 _C_LABEL(esigcode):
176
177 #ifdef COMPAT_IBCS2
178 .align 2
179 .globl _C_LABEL(ibcs2_sigcode),_C_LABEL(ibcs2_esigcode)
180 _C_LABEL(ibcs2_sigcode):
181 pushr $0x3f
182 subl2 $0xc,%sp
183 movl 0x24(%sp),%r0
184 calls $3,(%r0)
185 popr $0x3f
186 chmk $SYS_compat_16___sigreturn14
187 chmk $SYS_exit
188 halt
189 _C_LABEL(ibcs2_esigcode):
190 #endif /* COMPAT_IBCS2 */
191
192 #ifdef COMPAT_ULTRIX
193 .align 2
194 .globl _C_LABEL(ultrix_sigcode),_C_LABEL(ultrix_esigcode)
195 _C_LABEL(ultrix_sigcode):
196 pushr $0x3f
197 subl2 $0xc,%sp
198 movl 0x24(%sp),%r0
199 calls $3,(%r0)
200 popr $0x3f
201 chmk $ULTRIX_SYS_sigreturn
202 chmk $SYS_exit
203 halt
204 _C_LABEL(ultrix_esigcode):
205 #endif
206
207 .align 2
208 .globl _C_LABEL(idsptch), _C_LABEL(eidsptch)
209 _C_LABEL(idsptch):
210 pushr $0x3f
211 .word 0x9f16 # jsb to absolute address
212 .long _C_LABEL(cmn_idsptch) # the absolute address
213 .long 0 # the callback interrupt routine
214 .long 0 # its argument
215 .long 0 # ptr to correspond evcnt struct
216 _C_LABEL(eidsptch):
217
218 _C_LABEL(cmn_idsptch):
219 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
220 calls $0,_C_LABEL(krnlock)
221 #endif
222 movl (%sp)+,%r0 # get pointer to idspvec
223 movl 8(%r0),%r1 # get evcnt pointer
224 beql 1f # no ptr, skip increment
225 incl EV_COUNT(%r1) # increment low longword
226 adwc $0,EV_COUNT+4(%r1) # add any carry to hi longword
227 1: incl _C_LABEL(uvmexp)+UVME_INTRS # increment uvmexp.intrs
228 #if 0
229 pushl %r0
230 movq (%r0),-(%sp)
231 pushab 2f
232 calls $3,_C_LABEL(printf)
233 movl (%sp)+,%r0
234 #endif
235 pushl 4(%r0) # push argument
236 calls $1,*(%r0) # call interrupt routine
237 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
238 calls $0,_C_LABEL(krnunlock)
239 #endif
240 popr $0x3f # pop registers
241 rei # return from interrut
242 #if 0
243 2: .asciz "intr %p(%p)\n"
244 #endif
245
246 ENTRY(badaddr,0) # Called with addr,b/w/l
247 mfpr $PR_IPL,%r0 # splhigh()
248 mtpr $IPL_HIGH,$PR_IPL
249 movl 4(%ap),%r2 # First argument, the address
250 movl 8(%ap),%r1 # Sec arg, b,w,l
251 pushl %r0 # Save old IPL
252 clrl %r3
253 movab 4f,_C_LABEL(memtest) # Set the return address
254
255 caseb %r1,$1,$4 # What is the size
256 1: .word 1f-1b
257 .word 2f-1b
258 .word 3f-1b # This is unused
259 .word 3f-1b
260
261 1: movb (%r2),%r1 # Test a byte
262 brb 5f
263
264 2: movw (%r2),%r1 # Test a word
265 brb 5f
266
267 3: movl (%r2),%r1 # Test a long
268 brb 5f
269
270 4: incl %r3 # Got machine chk => addr bad
271 5: mtpr (%sp)+,$PR_IPL
272 movl %r3,%r0
273 ret
274
275 #ifdef DDB
276 /*
277 * DDB is the only routine that uses setjmp/longjmp.
278 */
279 .globl _C_LABEL(setjmp), _C_LABEL(longjmp)
280 _C_LABEL(setjmp):.word 0
281 movl 4(%ap), %r0
282 movl 8(%fp), (%r0)
283 movl 12(%fp), 4(%r0)
284 movl 16(%fp), 8(%r0)
285 moval 28(%fp),12(%r0)
286 clrl %r0
287 ret
288
289 _C_LABEL(longjmp):.word 0
290 movl 4(%ap), %r1
291 movl 8(%ap), %r0
292 movl (%r1), %ap
293 movl 4(%r1), %fp
294 movl 12(%r1), %sp
295 jmp *8(%r1)
296 #endif
297
298 #
299 # setrunqueue/remrunqueue fast variants.
300 #
301
302 JSBENTRY(Setrq)
303 #ifdef DIAGNOSTIC
304 tstl 4(%r0) # Check that process actually are off the queue
305 beql 1f
306 pushab setrq
307 calls $1,_C_LABEL(panic)
308 setrq: .asciz "setrunqueue"
309 #endif
310 1: extzv $2,$6,L_PRIORITY(%r0),%r1 # get priority
311 movaq _C_LABEL(sched_qs)[%r1],%r2 # get address of queue
312 insque (%r0),*PH_RLINK(%r2) # put proc last in queue
313 bbss %r1,_C_LABEL(sched_whichqs),1f # set queue bit.
314 1: rsb
315
316 JSBENTRY(Remrq)
317 extzv $2,$6,L_PRIORITY(%r0),%r1
318 #ifdef DIAGNOSTIC
319 bbs %r1,_C_LABEL(sched_whichqs),1f
320 pushab remrq
321 calls $1,_C_LABEL(panic)
322 remrq: .asciz "remrunqueue"
323 #endif
324 1: remque (%r0),%r2
325 bneq 2f # Not last process on queue
326 bbsc %r1,_C_LABEL(sched_whichqs),2f
327 2: clrl L_BACK(%r0) # saftey belt
328 rsb
329
330 #
331 # Idle loop. Here we could do something fun, maybe, like calculating
332 # pi or something.
333 #
334 idle:
335 calls $0,_C_LABEL(sched_unlock_idle)
336 mtpr $1,$PR_IPL # IPL cannot be 0 because we are
337 # running on the interrupt stack
338 # and may get interrupts
339
340 1: tstl _C_LABEL(sched_whichqs) # Anything ready to run?
341 beql 1b # no, run the idle loop again.
342 /* Now try the test the long way */
343 mtpr $IPL_HIGH,$PR_IPL # block all types of interrupts
344 3: calls $0,_C_LABEL(sched_lock_idle)
345 brb lp # check sched_whichqs again
346
347 #
348 # cpu_switch, cpu_preempt, cpu_exit and the idle loop implemented in
349 # assembler for efficiency. This is called at IPL_HIGH.
350 #
351
352 JSBENTRY(Swtch)
353 mfpr $PR_SSP,%r1 # Get ptr to this cpu_info struct
354 clrl CI_CURLWP(%r1) # Stop process accounting
355 svpctx # Save context if another CPU
356 # get control first (must be on
357 # the interrupt stack when idling)
358
359
360 lp: ffs $0,$32,_C_LABEL(sched_whichqs),%r3 # Search for bit set
361 beql idle # no bit set, go to idle loop
362
363 movaq _C_LABEL(sched_qs)[%r3],%r1 # get address of queue head
364 remque *(%r1),%r2 # remove lwp pointed to by queue head
365 # lwp ptr is now in %r2
366 #ifdef DIAGNOSTIC
367 bvc 1f # check if something on queue
368 pushab noque
369 calls $1,_C_LABEL(panic)
370 #endif
371
372 1: bneq 2f # more processes on queue?
373 bbsc %r3,_C_LABEL(sched_whichqs),2f # no, clear bit in whichqs
374 2: clrl L_BACK(%r2) # clear proc backpointer
375 mfpr $PR_SSP,%r1 # Get ptr to this cpu_info struct
376 /* p->p_cpu initialized in fork1() for single-processor */
377 #if defined(MULTIPROCESSOR)
378 movl %r1,L_CPU(%r2) # l->l_cpu = curcpu();
379 #endif
380 movb $LSONPROC,L_STAT(%r2) # l->l_stat = LSONPROC;
381 movl %r2,CI_CURLWP(%r1) # set new process running
382 clrl CI_WANT_RESCHED(%r1) # we are now changing process
383 movl L_ADDR(%r2),%r0 # Get pointer to new pcb.
384 addl3 %r0,$IFTRAP,%r1 # Save for copy* functions.
385 mtpr %r1,$PR_ESP # Use ESP as CPU-specific pointer
386 movl %r1,ESP(%r0) # Must save in PCB also.
387 mfpr $PR_SSP,%r1 # New process must inherit cpu_info
388 movl %r1,SSP(%r0) # Put it in new PCB
389
390 #
391 # Nice routine to get physical from virtual addresses.
392 #
393 extzv $9,$21,%r0,%r1 # extract offset
394 ashl $9,*_C_LABEL(Sysmap)[%r1],%r3
395
396 clrl PCB_R0(%r0) # Assume switch to same lwp
397 mfpr $PR_PCBB,%r1 # Get old PCB address
398 cmpl %r1,%r3 # The same lwp?
399 beql 1f # Branch if it is
400 movl $1,PCB_R0(%r0) # Otherwise, return 1.
401
402 1: mtpr %r3,$PR_PCBB
403 ldpctx
404 pushl %r0
405 calls $0,_C_LABEL(sched_unlock_idle)
406 movl (%sp)+,%r0
407 rei
408
409 #if defined(MULTIPROCESSOR)
410 .align 2
411 .globl _C_LABEL(vax_mp_tramp) # used to kick off multiprocessor systems.
412 _C_LABEL(vax_mp_tramp):
413 ldpctx
414 rei
415 #endif
416
417 JSBENTRY(Swtchto)
418 mfpr $PR_SSP,%r1 # Get ptr to this cpu_info struct
419 clrl CI_CURLWP(%r1) # Stop process accounting
420 svpctx # Now on interrupt stack
421
422 # New LWP already in %r2
423 mfpr $PR_SSP,%r1 # Get ptr to this cpu_info struct
424 #if defined(MULTIPROCESSOR)
425 movl %r1,L_CPU(%r2) # l->l_cpu = curcpu();
426 #endif
427 movb $LSONPROC,L_STAT(%r2) # l->l_stat = LSONPROC;
428 movl %r2,CI_CURLWP(%r1) # set new process running
429 movl L_ADDR(%r2),%r0 # Get pointer to new pcb.
430 addl3 %r0,$IFTRAP,%r3 # Save for copy* functions.
431 mtpr %r3,$PR_ESP # Use ESP as CPU-specific pointer
432 movl %r3,ESP(%r0) # Must save in PCB also.
433 movl %r1,SSP(%r0) # Put it in new PCB
434
435 extzv $9,$21,%r0,%r1 # extract offset
436 ashl $9,*_C_LABEL(Sysmap)[%r1],%r3
437
438 mtpr %r3,$PR_PCBB
439 ldpctx
440 pushl %r0
441 calls $0,_C_LABEL(sched_unlock_idle)
442 movl (%sp)+,%r0
443 rei
444
445 #
446 # the last routine called by a process.
447 #
448
449 ENTRY(cpu_exit,0)
450 movl 4(%ap),%r6 # Process pointer in %r6
451
452 mtpr $IPL_CLOCK,$PR_IPL # Block almost everything
453 mfpr $PR_SSP,%r7 # get cpu_info ptr
454 movl CI_EXIT(%r7),%r8 # scratch page address
455 movab 512(%r8),%sp # change stack
456 bicl2 $0xc0000000,%r8 # get physical address
457 mtpr %r8,$PR_PCBB # new PCB
458 mtpr %r7,$PR_SSP # In case...
459 pushl %r6
460 calls $1,_C_LABEL(lwp_exit2) # release last resources.
461 mtpr $IPL_HIGH,$PR_IPL # block all types of interrupts
462 calls $0,_C_LABEL(sched_lock_idle)
463 clrl %r6
464 brw Swtch
465
466 #
467 # copy/fetch/store routines.
468 #
469
470 ENTRY(copyout, 0)
471 movl 8(%ap),%r2
472 blss 3f # kernel space
473 movl 4(%ap),%r1
474 brb 2f
475
476 ENTRY(copyin, 0)
477 movl 4(%ap),%r1
478 blss 3f # kernel space
479 movl 8(%ap),%r2
480 2: mfpr $PR_ESP,%r3
481 movab 1f,(%r3)
482 movc3 12(%ap),(%r1),(%r2)
483 1: mfpr $PR_ESP,%r3
484 clrl (%r3)
485 ret
486
487 3: mnegl $1,%r0
488 ret
489
490 ENTRY(kcopy,0)
491 mfpr $PR_ESP,%r3
492 movl (%r3),-(%sp)
493 movab 1f,(%r3)
494 movl 4(%ap),%r1
495 movl 8(%ap),%r2
496 movc3 12(%ap),(%r1), (%r2)
497 clrl %r1
498 1: mfpr $PR_ESP,%r3
499 movl (%sp)+,(%r3)
500 movl %r1,%r0
501 ret
502
503 /*
504 * copy{in,out}str() copies data from/to user space to/from kernel space.
505 * Security checks:
506 * 1) user space address must be < KERNBASE
507 * 2) the VM system will do the checks while copying
508 */
509 ENTRY(copyinstr, 0)
510 tstl 4(%ap) # kernel address?
511 bgeq 8f # no, continue
512 6: movl $EFAULT,%r0
513 movl 16(%ap),%r2
514 beql 7f
515 clrl (%r2)
516 7: ret
517
518 ENTRY(copyoutstr, 0)
519 tstl 8(%ap) # kernel address?
520 bgeq 8f # no, continue
521 brb 6b # yes, return EFAULT
522
523 ENTRY(copystr,0)
524 8: movl 4(%ap),%r5 # from
525 movl 8(%ap),%r4 # to
526 movl 12(%ap),%r3 # len
527 movl 16(%ap),%r2 # copied
528 clrl %r0
529 mfpr $PR_ESP,%r1
530 movab 3f,(%r1)
531
532 tstl %r3 # any chars to copy?
533 bneq 1f # yes, jump for more
534 0: tstl %r2 # save copied len?
535 beql 2f # no
536 subl3 4(%ap),%r5,(%r2) # save copied len
537 2: ret
538
539 1: movb (%r5)+,(%r4)+ # copy one char
540 beql 0b # jmp if last char
541 sobgtr %r3,1b # copy one more
542 movl $ENAMETOOLONG,%r0 # inform about too long string
543 brb 0b # out of chars
544
545 3: mfpr $PR_ESP,%r1
546 clrl (%r1)
547 brb 0b
548
549 ENTRY(subyte,0)
550 movl 4(%ap),%r0
551 blss 3f # illegal space
552 mfpr $PR_ESP,%r1
553 movab 1f,(%r1)
554 movb 8(%ap),(%r0)
555 clrl %r1
556 1: mfpr $PR_ESP,%r2
557 clrl (%r2)
558 movl %r1,%r0
559 ret
560
561 ENTRY(suword,0)
562 movl 4(%ap),%r0
563 blss 3f # illegal space
564 mfpr $PR_ESP,%r1
565 movab 1f,(%r1)
566 movl 8(%ap),(%r0)
567 clrl %r1
568 1: mfpr $PR_ESP,%r2
569 clrl (%r2)
570 movl %r1,%r0
571 ret
572
573 ENTRY(suswintr,0)
574 movl 4(%ap),%r0
575 blss 3f # illegal space
576 mfpr $PR_ESP,%r1
577 movab 1f,(%r1)
578 movw 8(%ap),(%r0)
579 clrl %r1
580 1: mfpr $PR_ESP,%r2
581 clrl (%r2)
582 movl %r1,%r0
583 ret
584
585 3: mnegl $1,%r0
586 ret
587
588 .align 2
589 ALTENTRY(fusword)
590 ENTRY(fuswintr,0)
591 movl 4(%ap),%r0
592 blss 3b
593 mfpr $PR_ESP,%r1
594 movab 1f,(%r1)
595 movzwl (%r0),%r1
596 1: mfpr $PR_ESP,%r2
597 clrl (%r2)
598 movl %r1,%r0
599 ret
600
601 #if defined(MULTIPROCESSOR) || defined(DEBUG) || defined(DIAGNOSTIC) || defined(LOCKDEBUG)
602
603 JSBENTRY(Slock)
604 1: bbssi $0,(%r1),1b
605 rsb
606
607 JSBENTRY(Slocktry)
608 clrl %r0
609 bbssi $0,(%r1),1f
610 incl %r0
611 1: rsb
612
613 JSBENTRY(Sunlock)
614 bbcci $0,(%r1),1f
615 1: rsb
616
617 #endif
618
619 #
620 # data department
621 #
622 .data
623
624 .globl _C_LABEL(memtest)
625 _C_LABEL(memtest): # memory test in progress
626 .long 0
627
628 #ifdef __ELF__
629 .section .rodata
630 #endif
631 noque: .asciz "swtch"
632