locore.S revision 205234
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: head/sys/ia64/ia64/locore.S 205234 2010-03-17 00:37:15Z marcel $ 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 40kstack: .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 */ 49ENTRY_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 */ 1331: br.cond.sptk.few 1b 134END(__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 */ 148ENTRY(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 173enter_userland: 174{ .mib 175 nop 0 176 nop 0 177 br.sptk epc_syscall_return 178 ;; 179} 180END(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 193ENTRY_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 ;; 2391: 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 2522: 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 */ 2899: 290{ .mib 291 nop 0 292 nop 0 293 br.sptk 9b 294 ;; 295} 296END(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 306EXPORT(intrnames) 307 .ascii "clock" 308 .fill INTRNAME_LEN - 5 - 1, 1, ' ' 309 .byte 0 310intr_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 320EXPORT(eintrnames) 321 .align 8 322EXPORT(intrcnt) 323 .fill INTRCNT_COUNT, 8, 0 324EXPORT(eintrcnt) 325 326 .text 327 // in0: image base 328STATIC_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 ;; 3401: 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 3712: 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 4113: 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 4174: 418 add r16=in0,r17 // BD + A 419 ;; 420 st8 [r15]=r16 // word64 (LSB) 421 br.cond.sptk.few 3b 422 4235: 424 add r16=r16,r17 // S + A 425 ;; 426 st8 [r15]=r16 // word64 (LSB) 427 br.cond.sptk.few 3b 428 4296: 430 movl r17=@gprel(fptr_storage) 431 ;; 432 add r17=r17,gp // start of fptrs 433 ;; 4347: 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 4458: // 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 4569: 457 mov ar.pfs=loc0 458 mov rp=loc1 459 ;; 460 br.ret.sptk.few rp 461 462END(_reloc) 463 464 .data 465 .align 16 466 .global fptr_storage 467fptr_storage: 468 .space 4096*16 // XXX 469fptr_storage_end: 470