subr.S revision 1.33 1 /* $NetBSD: subr.S,v 1.33 2010/12/20 00:25:45 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 #define SCBENTRY(name) \
51 .text ; \
52 .align 2 ; \
53 .globl __CONCAT(X,name) ; \
54 __CONCAT(X,name):
55
56 .text
57
58 #ifdef KERNEL_LOADABLE_BY_MOP
59 /*
60 * This is a little tricky. The kernel is not loaded at the correct
61 * address, so the kernel must first be relocated, then copied, then
62 * jump back to the correct address.
63 */
64 /* Copy routine */
65 cps:
66 2: movb (%r0)+,(%r1)+
67 cmpl %r0,%r7
68 bneq 2b
69
70 3: clrb (%r1)+
71 incl %r0
72 cmpl %r0,%r6
73 bneq 3b
74 clrl -(%sp)
75 movl %sp,%ap
76 movl $_cca,%r7
77 movl %r8,(%r7)
78 movpsl -(%sp)
79 pushl %r2
80 rei
81 cpe:
82
83 /* Copy the copy routine */
84 1: movab cps,%r0
85 movab cpe,%r1
86 movl $0x300000,%sp
87 movl %sp,%r3
88 4: movb (%r0)+,(%r3)+
89 cmpl %r0,%r1
90 bneq 4b
91 movl %r7,%r8
92 /* Ok, copy routine copied, set registers and rei */
93 movab _edata,%r7
94 movab _end,%r6
95 movl $0x80000000,%r1
96 movl $0x80000200,%r0
97 subl3 $0x200,%r6,%r9
98 movab 2f,%r2
99 subl2 $0x200,%r2
100 movpsl -(%sp)
101 pushab 4(%sp)
102 rei
103
104 /*
105 * First entry routine from boot. This should be in a file called locore.
106 */
107 JSBENTRY(start)
108 brb 1b # Netbooted starts here
109 #else
110 ASENTRY(start, 0)
111 #endif
112 2: bisl3 $0x80000000,%r9,_C_LABEL(esym) # End of loaded code
113 pushl $0x1f0000 # Push a nice PSL
114 pushl $to # Address to jump to
115 rei # change to kernel stack
116 to: movw $0xfff,_C_LABEL(panic) # Save all regs in panic
117 cmpb (%ap),$3 # symbols info present?
118 blssu 3f # nope, skip
119 bisl3 $0x80000000,8(%ap),_C_LABEL(symtab_start)
120 # save start of symtab
121 movl 12(%ap),_C_LABEL(symtab_nsyms) # save number of symtab
122 bisl3 $0x80000000,%r9,_C_LABEL(symtab_end)
123 # save end of symtab
124 3: addl3 _C_LABEL(esym),$0x3ff,%r0 # Round symbol table end
125 bicl3 $0x3ff,%r0,%r1 #
126 movl %r1,_C_LABEL(lwp0)+L_PCB # lwp0 pcb, XXXuvm_lwp_getuarea
127 bicl3 $0x80000000,%r1,%r0 # get phys lwp0 uarea addr
128 mtpr %r0,$PR_PCBB # Save in IPR PCBB
129 addl3 $USPACE,%r1,%r0 # Get kernel stack top
130 mtpr %r0,$PR_KSP # put in IPR KSP
131 movl %r0,_C_LABEL(Sysmap) # SPT start addr after KSP
132 movl _C_LABEL(lwp0)+L_PCB,%r0 # get PCB virtual address
133 mfpr $PR_PCBB,PCB_PADDR(%r0) # save PCB physical address
134 movab PCB_ONFAULT(%r0),ESP(%r0) # Save trap address in ESP
135 mtpr 4(%r0),$PR_ESP # Put it in ESP also
136
137 # Set some registers in known state
138 movl %r1,%r0 # get lwp0 pcb
139 clrl P0LR(%r0)
140 clrl P1LR(%r0)
141 mtpr $0,$PR_P0LR
142 mtpr $0,$PR_P1LR
143 movl $0x80000000,%r1
144 movl %r1,P0BR(%r0)
145 movl %r1,P1BR(%r0)
146 mtpr %r1,$PR_P0BR
147 mtpr %r1,$PR_P1BR
148 clrl PCB_ONFAULT(%r0)
149 mtpr $0,$PR_SCBB
150
151 # Copy the RPB to its new position
152 #if defined(COMPAT_14)
153 tstl (%ap) # Any arguments?
154 bneq 1f # Yes, called from new boot
155 movl %r11,_C_LABEL(boothowto) # Howto boot (single etc...)
156 # movl %r10,_C_LABEL(bootdev) # uninteresting, will complain
157 movl %r8,_C_LABEL(avail_end) # Usable memory (from VMB)
158 clrl -(%sp) # Have no RPB
159 brb 2f
160 #endif
161
162 1: pushl 4(%ap) # Address of old rpb
163 2: calls $1,_C_LABEL(_start) # Jump away.
164 /* NOTREACHED */
165
166
167 /*
168 * Signal handler code.
169 */
170
171 .align 2
172 .globl _C_LABEL(sigcode),_C_LABEL(esigcode)
173 _C_LABEL(sigcode):
174 pushr $0x3f
175 subl2 $0xc,%sp
176 movl 0x24(%sp),%r0
177 calls $3,(%r0)
178 popr $0x3f
179 chmk $SYS_compat_16___sigreturn14
180 chmk $SYS_exit
181 halt
182 _C_LABEL(esigcode):
183
184 #ifdef COMPAT_IBCS2
185 .align 2
186 .globl _C_LABEL(ibcs2_sigcode),_C_LABEL(ibcs2_esigcode)
187 _C_LABEL(ibcs2_sigcode):
188 pushr $0x3f
189 subl2 $0xc,%sp
190 movl 0x24(%sp),%r0
191 calls $3,(%r0)
192 popr $0x3f
193 chmk $SYS_compat_16___sigreturn14
194 chmk $SYS_exit
195 halt
196 _C_LABEL(ibcs2_esigcode):
197 #endif /* COMPAT_IBCS2 */
198
199 #ifdef COMPAT_ULTRIX
200 .align 2
201 .globl _C_LABEL(ultrix_sigcode),_C_LABEL(ultrix_esigcode)
202 _C_LABEL(ultrix_sigcode):
203 pushr $0x3f
204 subl2 $0xc,%sp
205 movl 0x24(%sp),%r0
206 calls $3,(%r0)
207 popr $0x3f
208 chmk $ULTRIX_SYS_sigreturn
209 chmk $SYS_exit
210 halt
211 _C_LABEL(ultrix_esigcode):
212 #endif
213
214 .align 2
215 .globl _C_LABEL(idsptch), _C_LABEL(eidsptch)
216 _C_LABEL(idsptch):
217 pushr $0x3f
218 .word 0x9f16 # jsb to absolute address
219 .long _C_LABEL(cmn_idsptch) # the absolute address
220 .long 0 # the callback interrupt routine
221 .long 0 # its argument
222 .long 0 # ptr to correspond evcnt struct
223 _C_LABEL(eidsptch):
224
225 _C_LABEL(cmn_idsptch):
226 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
227 calls $0,_C_LABEL(krnlock)
228 #endif
229 movl (%sp)+,%r0 # get pointer to idspvec
230 mtpr $IPL_VM,$PR_IPL # Make sure we are at IPL_VM
231 movl 8(%r0),%r1 # get evcnt pointer
232 beql 1f # no ptr, skip increment
233 incl EV_COUNT(%r1) # increment low longword
234 adwc $0,EV_COUNT+4(%r1) # add any carry to hi longword
235 1: mfpr $PR_SSP, %r2 # get curlwp
236 movl L_CPU(%r2), %r2 # get curcpu
237 incl CI_NINTR(%r2) # increment ci_data.cpu_nintr
238 adwc $0,(CI_NINTR+4)(%r2)
239 #if 0
240 pushl %r0
241 movq (%r0),-(%sp)
242 pushab 2f
243 calls $3,_C_LABEL(printf)
244 movl (%sp)+,%r0
245 #endif
246 pushl 4(%r0) # push argument
247 calls $1,*(%r0) # call interrupt routine
248 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
249 calls $0,_C_LABEL(krnunlock)
250 #endif
251 popr $0x3f # pop registers
252 rei # return from interrut
253 #if 0
254 2: .asciz "intr %p(%p)\n"
255 #endif
256
257 ENTRY(badaddr,0) # Called with addr,b/w/l
258 mfpr $PR_IPL,%r0 # splhigh()
259 mtpr $IPL_HIGH,$PR_IPL
260 movl 4(%ap),%r2 # First argument, the address
261 movl 8(%ap),%r1 # Sec arg, b,w,l
262 pushl %r0 # Save old IPL
263 clrl %r3
264 movab 4f,_C_LABEL(memtest) # Set the return address
265
266 caseb %r1,$1,$4 # What is the size
267 1: .word 1f-1b
268 .word 2f-1b
269 .word 3f-1b # This is unused
270 .word 3f-1b
271
272 1: movb (%r2),%r1 # Test a byte
273 brb 5f
274
275 2: movw (%r2),%r1 # Test a word
276 brb 5f
277
278 3: movl (%r2),%r1 # Test a long
279 brb 5f
280
281 4: incl %r3 # Got machine chk => addr bad
282 5: mtpr (%sp)+,$PR_IPL
283 movl %r3,%r0
284 ret
285
286 #ifdef DDB
287 /*
288 * DDB is the only routine that uses setjmp/longjmp.
289 */
290 .globl _C_LABEL(setjmp), _C_LABEL(longjmp)
291 _C_LABEL(setjmp):.word 0
292 movl 4(%ap), %r0
293 movl 8(%fp), (%r0)
294 movl 12(%fp), 4(%r0)
295 movl 16(%fp), 8(%r0)
296 moval 28(%fp),12(%r0)
297 clrl %r0
298 ret
299
300 _C_LABEL(longjmp):.word 0
301 movl 4(%ap), %r1
302 movl 8(%ap), %r0
303 movl (%r1), %ap
304 movl 4(%r1), %fp
305 movl 12(%r1), %sp
306 jmp *8(%r1)
307 #endif
308
309 #if defined(MULTIPROCESSOR)
310 .align 2
311 .globl _C_LABEL(vax_mp_tramp) # used to kick off multiprocessor systems.
312 _C_LABEL(vax_mp_tramp):
313 ldpctx
314 rei
315 #endif
316
317 .globl softint_cleanup,softint_exit,softint_process
318 .type softint_cleanup@function
319 .type softint_exit@function
320 .type softint_process@function
321 softint_cleanup:
322 movl L_CPU(%r0),%r1 /* get cpu_info */
323 incl CI_MTX_COUNT(%r1) /* increment mutex count */
324 clrl L_CTXSWTCH(%r0) /* clear l_ctxswtch of old lwp */
325 movl L_PCB(%r0),%r1 /* get PCB of softint LWP */
326 softint_exit:
327 popr $0x3 /* restore r0 and r1 */
328 rei /* return from interrupt */
329
330 softint_process:
331 /*
332 * R6 contains pinned LWP
333 * R7 contains ipl to dispatch with
334 */
335 movq %r6,-(%sp) /* push old lwp and ipl onto stack */
336 calls $2,_C_LABEL(softint_dispatch) /* dispatch it */
337
338 /* We can use any register because ldpctx will overwrite them */
339 movl L_PCB(%r6),%r3 /* get pcb */
340 movab softint_exit,PCB_PC(%r3)/* do a quick exit */
341 #ifdef MULTIPROCESSOR
342 movl L_CPU(%r6),%r8
343 movl %r6,CI_CURLWP(%r8)
344 #endif
345
346 mtpr PCB_PADDR(%r3),$PR_PCBB /* restore PA of interrupted pcb */
347 ldpctx /* implictily updates curlwp */
348 rei
349
350
351 softint_common:
352 mfpr $PR_IPL,%r1
353 mtpr $IPL_HIGH,$PR_IPL /* we need to be at IPL_HIGH */
354 movpsl -(%sp) /* add cleanup hook */
355 pushab softint_cleanup
356 svpctx
357
358 /* We can use any register because ldpctx will overwrite them */
359 mfpr $PR_SSP,%r6 /* Get curlwp */
360 movl L_CPU(%r6),%r8 /* get cpu_info */
361 movl CI_SOFTLWPS(%r8)[%r0],%r2 /* get softlwp to switch to */
362 movl L_PCB(%r2),%r3 /* Get pointer to its pcb. */
363 movl %r6,PCB_R6(%r3) /* move old lwp into new pcb */
364 movl %r1,PCB_R7(%r3) /* move IPL into new pcb */
365 #ifdef MULTIPROCESSOR
366 movl %r2,CI_CURLWP(%r8) /* update ci_curlwp */
367 #endif
368
369 /*
370 * Now reset the PCB since we no idea what state it was last in
371 */
372 movab (USPACE-TRAPFRAMELEN-CALLSFRAMELEN)(%r3),%r0
373 /* calculate where KSP should be */
374 movl %r0,KSP(%r3) /* save it as SP */
375 movl %r0,PCB_FP(%r3) /* and as the FP too */
376 movab CA_ARGNO(%r0),PCB_AP(%r3) /* update the AP as well */
377 movab softint_process,PCB_PC(%r3) /* and where we will start */
378 movl $PSL_HIGHIPL,PCB_PSL(%r3) /* Needs to be running at IPL_HIGH */
379
380 mtpr PCB_PADDR(%r3),$PR_PCBB /* set PA of new pcb */
381 ldpctx /* load it */
382 rei /* get off interrupt stack */
383
384 SCBENTRY(softclock)
385 pushr $0x3 /* save r0 and r1 */
386 movl $SOFTINT_CLOCK,%r0
387 brb softint_common
388
389 SCBENTRY(softbio)
390 pushr $0x3 /* save r0 and r1 */
391 movl $SOFTINT_BIO,%r0
392 brb softint_common
393
394 SCBENTRY(softnet)
395 pushr $0x3 /* save r0 and r1 */
396 movl $SOFTINT_NET,%r0
397 brb softint_common
398
399 SCBENTRY(softserial)
400 pushr $0x3 /* save r0 and r1 */
401 movl $SOFTINT_SERIAL,%r0
402 brb softint_common
403
404 /*
405 * Helper routine for cpu_lwp_fork. It get invoked by Swtchto.
406 * It let's the kernel know the lwp is alive and then calls func(arg)
407 * and possibly returns to sret.
408 */
409 ENTRY(cpu_lwp_bootstrap, 0)
410 movq %r2,-(%sp) /* save func & arg */
411 movq %r0,-(%sp) /* push oldl/newl */
412 calls $2,_C_LABEL(lwp_startup) /* startup the lwp */
413 movl (%sp)+,%r0 /* grab func */
414 calls $1,(%r0) /* call it with arg */
415 ret
416
417 /*
418 * r1 = newlwp
419 * r0 = oldlwp
420 */
421 JSBENTRY(Swtchto)
422 /* this pops the pc and psw from the stack and puts them in the pcb. */
423 svpctx # Now on interrupt stack
424
425 /* We can know use any register because ldpctx will overwrite them */
426 /* New LWP already in %r1 */
427 movl L_PCB(%r1),%r3 # Get pointer to new pcb.
428 movl %r0,PCB_R0(%r3) # move r0 into new pcb (return value)
429 #ifdef MULTIPROCESSOR
430 movl L_CPU(%r0), %r8 /* get cpu_info of old lwp */
431 movl %r8, L_CPU(%r1) /* update cpu_info of new lwp */
432 movl %r1,CI_CURLWP(%r8) /* update ci_curlwp */
433 #endif
434
435 mtpr PCB_PADDR(%r3),$PR_PCBB # set PA of new pcb
436 mtpr $IPL_HIGH,$PR_IPL /* we need to be at IPL_HIGH */
437 ldpctx # load it
438 /* r0 already has previous lwp */
439 /* r1 already has this lwp */
440 /* r2/r3 and r4/r5 restored */
441 rei /* get off interrupt stack */
442
443 #
444 # copy/fetch/store routines.
445 #
446
447 ENTRY(copyout, 0)
448 movl 8(%ap),%r3
449 blss 3f # kernel space
450 movl 4(%ap),%r1
451 brb 2f
452
453 ENTRY(copyin, 0)
454 movl 4(%ap),%r1
455 blss 3f # kernel space
456 movl 8(%ap),%r3
457 2: mfpr $PR_ESP,%r2
458 movab 1f,(%r2) # set pcb_onfault
459 4: tstw 14(%ap) # check if >= 64K
460 bneq 5f
461 movc3 12(%ap),(%r1),(%r3)
462 clrl %r0
463 1: mfpr $PR_ESP,%r2
464 clrl (%r2) # clear pcb_onfault
465 ret
466 5: movc3 $0xfffc,(%r1),(%r3)
467 subl2 $0xfffc,12(%ap)
468 brb 4b
469
470 3: movl $EFAULT,%r0
471 ret
472
473 ENTRY(kcopy,0)
474 mfpr $PR_ESP,%r3
475 movl (%r3),-(%sp) # save current pcb_onfault
476 movab 1f,(%r3) # set pcb_onfault
477 movl 4(%ap),%r1
478 movl 8(%ap),%r2
479 movc3 12(%ap),(%r1), (%r2)
480 clrl %r0
481 1: mfpr $PR_ESP,%r3
482 movl (%sp)+,(%r3) # restore pcb_onfault
483 ret
484
485 /*
486 * copy{in,out}str() copies data from/to user space to/from kernel space.
487 * Security checks:
488 * 1) user space address must be < KERNBASE
489 * 2) the VM system will do the checks while copying
490 */
491 ENTRY(copyinstr, 0)
492 tstl 4(%ap) # kernel address?
493 bgeq 8f # no, continue
494 6: movl $EFAULT,%r0
495 movl 16(%ap),%r2
496 beql 7f
497 clrl (%r2)
498 7: ret
499
500 ENTRY(copyoutstr, 0)
501 tstl 8(%ap) # kernel address?
502 bgeq 8f # no, continue
503 brb 6b # yes, return EFAULT
504
505 ENTRY(copystr,0)
506 8: movl 4(%ap),%r5 # from
507 movl 8(%ap),%r4 # to
508 movl 12(%ap),%r3 # len
509 movl 16(%ap),%r2 # copied
510 clrl %r0
511 mfpr $PR_ESP,%r1
512 movab 2f,(%r1) # set pcb_onfault
513
514 tstl %r3 # any chars to copy?
515 bneq 1f # yes, jump for more
516 0: tstl %r2 # save copied len?
517 beql 2f # no
518 subl3 4(%ap),%r5,(%r2) # save copied len
519 2: mfpr $PR_ESP,%r1
520 clrl (%r1) # clear pcb_onfault
521 ret
522
523 1: movb (%r5)+,(%r4)+ # copy one char
524 beql 0b # jmp if last char
525 sobgtr %r3,1b # copy one more
526 movl $ENAMETOOLONG,%r0 # inform about too long string
527 brb 0b # out of chars
528
529 ENTRY(subyte,0)
530 movl 4(%ap),%r0
531 blss 3f # illegal space
532 mfpr $PR_ESP,%r1
533 movab 1f,(%r1) # set pcb_onfault
534 movb 8(%ap),(%r0)
535 clrl %r0
536 1: mfpr $PR_ESP,%r1
537 clrl (%r1) # clear pcb_onfault
538 ret
539
540 ENTRY(suword,0)
541 movl 4(%ap),%r0
542 blss 3f # illegal space
543 mfpr $PR_ESP,%r1
544 movab 3f,(%r1) # set pcb_onfault
545 movl 8(%ap),(%r0)
546 clrl %r0
547 1: mfpr $PR_ESP,%r1
548 clrl (%r1) # clear pcb_onfault
549 ret
550
551 ENTRY(suswintr,0)
552 movl 4(%ap),%r0
553 blss 3f # illegal space
554 mfpr $PR_ESP,%r1
555 movab 3f,(%r1) # set pcb_onfault
556 movw 8(%ap),(%r0)
557 clrl %r0
558 1: mfpr $PR_ESP,%r1
559 clrl (%r1) # clear pcb_onfault
560 ret
561
562 3: mnegl $1,%r0
563 brb 1b
564
565 .align 2
566 ALTENTRY(fusword)
567 ENTRY(fuswintr,0)
568 movl 4(%ap),%r2
569 blss 3b
570 mfpr $PR_ESP,%r1
571 movab 3b,(%r1) # set pcb_onfault
572 movzwl (%r2),%r0
573 1: mfpr $PR_ESP,%r1
574 clrl (%r1) # clear pcb_onfault
575 ret
576
577 JSBENTRY(Slock)
578 1: bbssi $0,(%r1),1b
579 rsb
580
581 JSBENTRY(Slocktry)
582 clrl %r0
583 bbssi $0,(%r1),1f
584 incl %r0
585 1: rsb
586
587 JSBENTRY(Sunlock)
588 bbcci $0,(%r1),1f
589 1: rsb
590
591 #
592 # data department
593 #
594 .data
595
596 .globl _C_LABEL(memtest)
597 _C_LABEL(memtest): # memory test in progress
598 .long 0
599