]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/ia64/ia64/locore.S
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / ia64 / ia64 / locore.S
1 /*-
2  * Copyright (c) 1998 Doug Rabson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/syscall.h>
30 #include <machine/asm.h>
31 #include <machine/ia64_cpu.h>
32 #include <machine/intrcnt.h>
33 #include <machine/pte.h>
34 #include <machine/intrcnt.h>
35 #include <assym.s>
36
37         .section .data.proc0,"aw"
38         .global kstack
39         .align  PAGE_SIZE
40 kstack: .space KSTACK_PAGES * PAGE_SIZE
41
42         .text
43
44 /*
45  * Not really a leaf but we can't return.
46  * The EFI loader passes the physical address of the bootinfo block in
47  * register r8.
48  */
49 ENTRY_NOPROFILE(__start, 1)
50         .prologue
51         .save   rp,r0
52         .body
53 {       .mlx
54         mov     ar.rsc=0
55         movl    r16=ia64_vector_table   // set up IVT early
56         ;;
57 }
58 {       .mlx
59         mov     cr.iva=r16
60         movl    r16=kstack
61         ;;
62 }
63 {       .mmi
64         srlz.i
65         ;;
66         ssm     IA64_PSR_DFH
67         mov     r17=KSTACK_PAGES*PAGE_SIZE-SIZEOF_PCB-SIZEOF_TRAPFRAME-16
68         ;;
69 }
70 {       .mlx
71         add     sp=r16,r17              // proc0's stack
72         movl    gp=__gp                 // find kernel globals
73         ;;
74 }
75 {       .mlx
76         mov     ar.bspstore=r16         // switch backing store
77         movl    r16=pa_bootinfo
78         ;;
79 }
80 {       .mmi
81         st8     [r16]=r8                // save the PA of the bootinfo block
82         loadrs                          // invalidate regs
83         mov     r17=IA64_DCR_DEFAULT
84         ;;
85 }
86 {       .mmi
87         mov     cr.dcr=r17
88         mov     ar.rsc=3                // turn rse back on
89         nop     0
90         ;;
91 }
92 {       .mmi
93         srlz.d
94         alloc   r16=ar.pfs,0,0,1,0
95         mov     out0=r0                 // we are linked at the right address 
96         ;;                              // we just need to process fptrs
97 }
98 {       .mib
99         nop     0
100         nop     0
101         br.call.sptk.many rp=_reloc
102         ;;
103 }
104 {       .mib
105         nop     0
106         nop     0
107         br.call.sptk.many rp=ia64_init
108         ;;
109 }
110         // We have the new bspstore in r8 and the new sp in r9.
111         // Switch onto the new stack and call mi_startup().
112 {       .mmi
113         mov     ar.rsc = 0
114         ;;
115         mov     ar.bspstore = r8
116         mov     sp = r9
117         ;;
118 }
119 {       .mmi
120         loadrs
121         ;;
122         mov     ar.rsc = 3
123         nop     0
124         ;;
125 }
126 {       .mib
127         nop     0
128         nop     0
129         br.call.sptk.many rp=mi_startup
130         ;;
131 }
132         /* NOTREACHED */
133 1:      br.cond.sptk.few 1b
134 END(__start)
135
136 /*
137  * fork_trampoline()
138  *
139  * Arrange for a function to be invoked neatly, after a cpu_switch().
140  *
141  * Invokes fork_exit() passing in three arguments: a callout function, an
142  * argument to the callout, and a trapframe pointer.  For child processes
143  * returning from fork(2), the argument is a pointer to the child process.
144  *
145  * The callout function and its argument is in the trapframe in scratch
146  * registers r2 and r3.
147  */
148 ENTRY(fork_trampoline, 0)
149         .prologue
150         .save   rp,r0
151         .body
152 {       .mmi
153         alloc           r14=ar.pfs,0,0,3,0
154         add             r15=32+SIZEOF_SPECIAL+8,sp
155         add             r16=32+SIZEOF_SPECIAL+16,sp
156         ;;
157 }
158 {       .mmi
159         ld8             out0=[r15]
160         ld8             out1=[r16]
161         nop             0
162 }
163 {       .mib
164         add             out2=16,sp
165         nop             0
166         br.call.sptk    rp=fork_exit
167         ;;
168 }
169         // If we get back here, it means we're a user space process that's
170         // the immediate result of fork(2).
171         .global         enter_userland
172         .type           enter_userland, @function
173 enter_userland:
174 {       .mib
175         nop             0
176         nop             0
177         br.sptk         epc_syscall_return
178         ;;
179 }
180 END(fork_trampoline)
181
182 #ifdef SMP
183 /*
184  * AP wake-up entry point. The handoff state is similar as for the BSP,
185  * as described on page 3-9 of the IPF SAL Specification. The difference
186  * lies in the contents of register b0. For APs this register holds the
187  * return address into the SAL rendezvous routine.
188  *
189  * Note that we're responsible for clearing the IRR bit by reading cr.ivr
190  * and issuing the EOI to the local SAPIC.
191  */
192         .align  32
193 ENTRY_NOPROFILE(os_boot_rendez,0)
194         mov     r16=cr.ivr      // clear IRR bit
195         ;;
196         srlz.d
197         mov     cr.eoi=r0       // ACK the wake-up
198         ;;
199         srlz.d
200         rsm     IA64_PSR_IC|IA64_PSR_I
201         ;;
202         mov     r16 = (5<<8)|(PAGE_SHIFT<<2)|1
203         movl    r17 = 5<<61
204         ;;
205         mov     rr[r17] = r16
206         ;;
207         srlz.d
208         mov     r16 = (6<<8)|(IA64_ID_PAGE_SHIFT<<2)
209         movl    r17 = 6<<61
210         ;;
211         mov     rr[r17] = r16
212         ;;
213         srlz.d
214         mov     r16 = (7<<8)|(IA64_ID_PAGE_SHIFT<<2)
215         movl    r17 = 7<<61
216         ;;
217         mov     rr[r17] = r16
218         ;;
219         srlz.d
220         mov     r18 = 28<<2
221         movl    r16 = PTE_PRESENT+PTE_MA_WB+PTE_ACCESSED+PTE_DIRTY+ \
222                         PTE_PL_KERN+PTE_AR_RWX+PTE_ED
223         ;;
224         mov     cr.ifa = r17
225         mov     cr.itir = r18
226         ptr.d   r17, r18
227         ptr.i   r17, r18
228         ;;
229         srlz.i
230         ;;
231         itr.d   dtr[r0] = r16
232         mov     r18 = IA64_DCR_DEFAULT
233         ;;
234         itr.i   itr[r0] = r16
235         mov     cr.dcr = r18
236         ;;
237         srlz.i
238         ;;
239 1:      mov     r16 = ip
240         add     r17 = 2f-1b, r17
241         movl    r18 = (IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_DFH|IA64_PSR_DT|IA64_PSR_IC|IA64_PSR_IT|IA64_PSR_RT)
242         ;;
243         add     r17 = r17, r16
244         mov     cr.ipsr = r18
245         mov     cr.ifs = r0
246         ;;
247         mov     cr.iip = r17
248         ;;
249         rfi
250
251         .align  32
252 2:
253 {       .mlx
254         mov     ar.rsc = 0
255         movl    r16 = ia64_vector_table                 // set up IVT early
256         ;;
257 }
258 {       .mlx
259         mov     cr.iva = r16
260         movl    r16 = ap_stack
261         ;;
262 }
263 {       .mmi
264         srlz.i
265         ;;
266         ld8     r16 = [r16]
267         mov     r18 = KSTACK_PAGES*PAGE_SIZE-SIZEOF_PCB-SIZEOF_TRAPFRAME-16
268         ;;
269 }
270 {       .mlx
271         mov     ar.bspstore = r16
272         movl    gp = __gp
273         ;;
274 }
275 {       .mmi
276         loadrs
277         ;;
278         alloc   r17 = ar.pfs, 0, 0, 0, 0
279         add     sp = r18, r16
280         ;;
281 }
282 {       .mib
283         mov     ar.rsc = 3
284         nop     0
285         br.call.sptk.few rp = ia64_ap_startup
286         ;;
287 }
288         /* NOT REACHED */
289 9:
290 {       .mib
291         nop     0
292         nop     0
293         br.sptk 9b
294         ;;
295 }
296 END(os_boot_rendez)
297
298 #endif /* !SMP */
299
300 /*
301  * Create a default interrupt name table. The first entry (vector 0) is
302  * hardwaired to the clock interrupt.
303  */
304         .data
305         .align 8
306 EXPORT(intrnames)
307         .ascii "clock"
308         .fill INTRNAME_LEN - 5 - 1, 1, ' '
309         .byte 0
310 intr_n = 1
311 .rept INTRCNT_COUNT - 1
312         .ascii "#"
313         .byte intr_n / 100 + '0'
314         .byte (intr_n % 100) / 10 + '0'
315         .byte intr_n % 10 + '0'
316         .fill INTRNAME_LEN - 1 - 3 - 1, 1, ' '
317         .byte 0
318         intr_n = intr_n + 1
319 .endr
320 EXPORT(eintrnames)
321         .align 8
322 EXPORT(intrcnt)
323         .fill INTRCNT_COUNT, 8, 0
324 EXPORT(eintrcnt)
325
326         .text
327         // in0: image base
328 STATIC_ENTRY(_reloc, 1)
329         alloc   loc0=ar.pfs,1,2,0,0
330         mov     loc1=rp
331         ;; 
332         movl    r15=@gprel(_DYNAMIC)    // find _DYNAMIC etc.
333         movl    r2=@gprel(fptr_storage)
334         movl    r3=@gprel(fptr_storage_end)
335         ;;
336         add     r15=r15,gp              // relocate _DYNAMIC etc.
337         add     r2=r2,gp
338         add     r3=r3,gp
339         ;;
340 1:      ld8     r16=[r15],8             // read r15->d_tag
341         ;;
342         ld8     r17=[r15],8             // and r15->d_val
343         ;;
344         cmp.eq  p6,p0=DT_NULL,r16       // done?
345 (p6)    br.cond.dpnt.few 2f
346         ;; 
347         cmp.eq  p6,p0=DT_RELA,r16
348         ;; 
349 (p6)    add     r18=r17,in0             // found rela section
350         ;; 
351         cmp.eq  p6,p0=DT_RELASZ,r16
352         ;; 
353 (p6)    mov     r19=r17                 // found rela size
354         ;; 
355         cmp.eq  p6,p0=DT_SYMTAB,r16
356         ;; 
357 (p6)    add     r20=r17,in0             // found symbol table
358         ;; 
359 (p6)    setf.sig f8=r20
360         ;; 
361         cmp.eq  p6,p0=DT_SYMENT,r16
362         ;; 
363 (p6)    setf.sig f9=r17                 // found symbol entry size
364         ;; 
365         cmp.eq  p6,p0=DT_RELAENT,r16
366         ;; 
367 (p6)    mov     r22=r17                 // found rela entry size
368         ;;
369         br.sptk.few 1b
370         
371 2:      
372         ld8     r15=[r18],8             // read r_offset
373         ;; 
374         ld8     r16=[r18],8             // read r_info
375         add     r15=r15,in0             // relocate r_offset
376         ;;
377         ld8     r17=[r18],8             // read r_addend
378         sub     r19=r19,r22             // update relasz
379
380         extr.u  r23=r16,0,32            // ELF64_R_TYPE(r16)
381         ;;
382         cmp.eq  p6,p0=R_IA_64_NONE,r23
383 (p6)    br.cond.dpnt.few 3f
384         ;;
385         cmp.eq  p6,p0=R_IA_64_REL64LSB,r23
386 (p6)    br.cond.dptk.few 4f
387         ;;
388
389         extr.u  r16=r16,32,32           // ELF64_R_SYM(r16)
390         ;; 
391         setf.sig f10=r16                // so we can multiply
392         ;;
393         xma.lu  f10=f10,f9,f8           // f10=symtab + r_sym*syment
394         ;;
395         getf.sig r16=f10
396         ;;
397         add     r16=8,r16               // address of st_value
398         ;;
399         ld8     r16=[r16]               // read symbol value
400         ;;
401         add     r16=r16,in0             // relocate symbol value
402         ;;
403
404         cmp.eq  p6,p0=R_IA_64_DIR64LSB,r23
405 (p6)    br.cond.dptk.few 5f
406         ;;
407         cmp.eq  p6,p0=R_IA_64_FPTR64LSB,r23
408 (p6)    br.cond.dptk.few 6f
409         ;;
410
411 3:
412         cmp.ltu p6,p0=0,r19             // more?
413 (p6)    br.cond.dptk.few 2b             // loop
414         mov     r8=0                    // success return value
415         br.cond.sptk.few 9f             // done
416
417 4:
418         add     r16=in0,r17             // BD + A
419         ;;
420         st8     [r15]=r16               // word64 (LSB)
421         br.cond.sptk.few 3b
422
423 5:
424         add     r16=r16,r17             // S + A
425         ;;
426         st8     [r15]=r16               // word64 (LSB)
427         br.cond.sptk.few 3b
428
429 6:
430         movl    r17=@gprel(fptr_storage)
431         ;;
432         add     r17=r17,gp              // start of fptrs
433         ;;
434 7:      cmp.geu p6,p0=r17,r2            // end of fptrs?
435 (p6)    br.cond.dpnt.few 8f             // can't find existing fptr
436         ld8     r20=[r17]               // read function from fptr
437         ;;
438         cmp.eq  p6,p0=r16,r20           // same function?
439         ;;
440 (p6)    st8     [r15]=r17               // reuse fptr
441 (p6)    br.cond.sptk.few 3b             // done
442         add     r17=16,r17              // next fptr
443         br.cond.sptk.few 7b
444
445 8:                                      // allocate new fptr
446         mov     r8=1                    // failure return value
447         cmp.geu p6,p0=r2,r3             // space left?
448 (p6)    br.cond.dpnt.few 9f             // bail out
449
450         st8     [r15]=r2                // install fptr
451         st8     [r2]=r16,8              // write fptr address
452         ;;
453         st8     [r2]=gp,8               // write fptr gp
454         br.cond.sptk.few 3b
455
456 9:
457         mov     ar.pfs=loc0
458         mov     rp=loc1
459         ;;
460         br.ret.sptk.few rp
461
462 END(_reloc)
463
464         .data
465         .align  16
466         .global fptr_storage
467 fptr_storage:
468         .space  4096*16                 // XXX
469 fptr_storage_end: