Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | /* * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * (Code copied from or=ther files) * Copyright (C) 1998-2000 Hewlett-Packard Co * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> * * Copyright (C) 2000 Silicon Graphics, Inc. * Copyright (C) 2000 by Jack Steiner (steiner@sgi.com) */ #define __ASSEMBLY__ 1 #include "asm/processor.h" /* * This file contains additional set up code that is needed to get going on * Medusa. This code should disappear once real hw is available. * * On entry to this routine, the following register values are assumed: * * gr[8] - BSP cpu * pr[9] - kernel entry address * * NOTE: * This FPROM may be loaded/executed at an address different from the * address that it was linked at. The FPROM is linked to run on node 0 * at address 0x100000. If the code in loaded into another node, it * must be loaded at offset 0x100000 of the node. In addition, the * FPROM does the following things: * - determine the base address of the node it is loaded on * - add the node base to _gp. * - add the node base to all addresses derived from "movl" * instructions. (I couldnt get GPREL addressing to work) * (maybe newer versions of the tools will support this) * - scan the .got section and add the node base to all * pointers in this section. * - add the node base to all physical addresses in the * SAL/PAL/EFI table built by the C code. (This is done * in the C code - not here) * - add the node base to the TLB entries for vmlinux */ #define KERNEL_BASE 0xe000000000000000 #define PAGESIZE_256M 28 /* * ar.k0 gets set to IOPB_PA value, on 460gx chipset it should * be 0x00000ffffc000000, but on snia we use the (inverse swizzled) * IOSPEC_BASE value */ #define IOPB_PA 0x00000a0000000000 /* inv swizzle IOSPEC_BASE */ #define RR_RID 8 // ==================================================================================== .text .align 16 .global _start .proc _start _start: // Setup psr and rse for system init mov psr.l = r0;; srlz.d;; invala mov ar.rsc = r0;; loadrs ;; // Set CALIAS size to zero. We dont use it. movl r24=0x80000a0001000028;; // BR_PI_CALIAS_SIZE st8 [r24]=r0 // Isolate node number we are running on. mov r6 = ip;; shr r5 = r6,33;; // r5 = node number shl r6 = r5,33 // r6 = base memory address of node // Set & relocate gp. movl r1= __gp;; // Add base memory address add r1 = r1,r6 // Relocate to boot node // Lets figure out who we are & put it in the LID register. // The BR_PI_SELF_CPU_NUM register gives us a value of 0-3. // This identifies the cpu on the node. // Merge the cpu number with the NASID to generate the LID. movl r24=0x80000a0001000020;; // BR_PI_SELF_CPU_NUM ld8 r25=[r24] // Fetch PI_SELF movl r27=0x80000a0001600000;; // Fetch REVID to get local NASID ld8 r27=[r27];; extr.u r27=r27,32,8 shl r26=r25,16;; // Align local cpu# to lid.eid shl r27=r27,24;; // Align NASID to lid.id or r26=r26,r27;; // build the LID mov cr.lid=r26 // Now put in in the LID register movl r2=FPSR_DEFAULT;; mov ar.fpsr=r2 movl sp = bootstacke-16;; add sp = sp,r6 // Relocate to boot node // Save the NASID that we are loaded on. movl r2=base_nasid;; // Save base_nasid for C code add r2 = r2,r6;; // Relocate to boot node st8 [r2]=r5 // Uncond st8 - same on all cpus // Save the kernel entry address. It is passed in r9 on one of // the cpus. movl r2=bsp_entry_pc cmp.ne p6,p0=r9,r0;; add r2 = r2,r6;; // Relocate to boot node (p6) st8 [r2]=r9 // Uncond st8 - same on all cpus // The following can ONLY be done by 1 cpu. Lets set a lock - the // cpu that gets it does the initilization. The rest just spin waiting // til initilization is complete. movl r22 = initlock;; add r22 = r22,r6 // Relocate to boot node mov r23 = 1;; xchg8 r23 = [r22],r23;; cmp.eq p6,p0 = 0,r23 (p6) br.cond.spnt.few init 1: ld4 r23 = [r22];; cmp.eq p6,p0 = 1,r23 (p6) br.cond.sptk 1b br initx // Add base address of node memory to each pointer in the .got section. init: movl r16 = _GLOBAL_OFFSET_TABLE_;; add r16 = r16,r6;; // Relocate to boot node 1: ld8 r17 = [r16];; cmp.eq p6,p7=0,r17 (p6) br.cond.sptk.few.clr 2f;; add r17 = r17,r6;; // Relocate to boot node st8 [r16] = r17,8 br 1b 2: mov r23 = 2;; // All done, release the spinning cpus st4 [r22] = r23 initx: // // I/O-port space base address: // movl r2 = IOPB_PA;; mov ar.k0 = r2 // Now call main & pass it the current LID value. alloc r0=ar.pfs,0,0,2,0 mov r32=r26 mov r33=r8;; br.call.sptk.few rp=fmain // Initialize Region Registers // mov r10 = r0 mov r2 = (13<<2) mov r3 = r0;; 1: cmp4.gtu p6,p7 = 7, r3 dep r10 = r3, r10, 61, 3 dep r2 = r3, r2, RR_RID, 4;; (p7) dep r2 = 0, r2, 0, 1;; (p6) dep r2 = -1, r2, 0, 1;; mov rr[r10] = r2 add r3 = 1, r3;; srlz.d;; cmp4.gtu p6,p0 = 8, r3 (p6) br.cond.sptk.few.clr 1b // // Return value indicates if we are the BSP or AP. // 1 = BSP, 0 = AP mov cr.tpr=r0;; cmp.eq p6,p0=r8,r0 (p6) br.cond.spnt slave // // Initialize the protection key registers with only pkr[0] = valid. // // Should be initialized in accordance with the OS. // mov r2 = 1 mov r3 = r0;; mov pkr[r3] = r2;; srlz.d;; mov r2 = r0 1: add r3 = r3, r0, 1;; // increment PKR cmp.gtu p6, p0 = 16, r3;; (p6) mov pkr[r3] = r2 (p6) br.cond.sptk.few.clr 1b mov ar.rnat = r0 // clear RNAT register // // Setup system address translation for kernel // // Note: The setup of Kernel Virtual address space can be done by the // C code of the boot loader. // // #define LINUX_PAGE_OFFSET 0xe000000000000000 #define ITIR(key, ps) ((key<<8) | (ps<<2)) #define ITRGR(ed,ar,ma) ((ed<<52) | (ar<<9) | (ma<<2) | 0x61) #define AR_RX 1 // RX permission #define AR_RW 4 // RW permission #define MA_WB 0 // WRITEBACK memory attribute #define TLB_PAGESIZE 28 // Use 256MB pages for now. mov r16=r5 // // text section // movl r2 = LINUX_PAGE_OFFSET;; // Set up IFA with VPN of linux mov cr.ifa = r2 movl r3 = ITIR(0,TLB_PAGESIZE);; // Set ITIR to default pagesize mov cr.itir = r3 shl r4 = r16,33;; // physical addr of start of node movl r5 = ITRGR(1,AR_RX,MA_WB);; // TLB attributes or r10=r4,r5;; itr.i itr[r0] = r10;; // Dropin ITR entry srlz.i;; // // data section // movl r2 = LINUX_PAGE_OFFSET;; // Set up IFA with VPN of linux mov cr.ifa = r2 movl r3 = ITIR(0,TLB_PAGESIZE);; // Set ITIR to default pagesize mov cr.itir = r3 shl r4 = r16,33;; // physical addr of start of node movl r5 = ITRGR(1,AR_RW,MA_WB);; // TLB attributes or r10=r4,r5;; itr.d dtr[r0] = r10;; // Dropin DTR entry srlz.d;; // // Turn on address translation, interrupt collection, psr.ed, protection key. // Interrupts (PSR.i) are still off here. // movl r3 = ( IA64_PSR_BN | \ IA64_PSR_AC | \ IA64_PSR_IT | \ IA64_PSR_DB | \ IA64_PSR_DA | \ IA64_PSR_RT | \ IA64_PSR_DT | \ IA64_PSR_IC \ ) ;; mov cr.ipsr = r3 // // Go to kernel C startup routines // Need to do a "rfi" in order set "it" and "ed" bits in the PSR. // This is the only way to set them. movl r2=bsp_entry_pc;; add r2 = r2,r6;; // Relocate to boot node ld8 r2=[r2];; mov cr.iip = r2 srlz.d;; rfi;; .endp _start // Slave processors come here to spin til they get an interrupt. Then they launch themselves to // the place ap_entry points. No initialization is necessary - the kernel makes no // assumptions about state on this entry. // Note: should verify that the interrupt we got was really the ap_wakeup // interrupt but this should not be an issue on medusa slave: nop.i 0x8beef // Medusa - put cpu to sleep til interrupt occurs mov r8=cr.irr0;; // Check for interrupt pending. cmp.eq p6,p0=r8,r0 (p6) br.cond.sptk slave;; mov r8=cr.ivr;; // Got one. Must read ivr to accept it srlz.d;; mov cr.eoi=r0;; // must write eoi to clear movl r8=ap_entry;; // now jump to kernel entry add r8 = r8,r6;; // Relocate to boot node ld8 r9=[r8],8;; ld8 r1=[r8] mov b0=r9;; br b0 // Here is the kernel stack used for the fake PROM .bss .align 16384 bootstack: .skip 16384 bootstacke: initlock: data4 |