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