1/* 2 * 3 * This file is subject to the terms and conditions of the GNU General Public 4 * License. See the file "COPYING" in the main directory of this archive 5 * for more details. 6 * 7 * (Code copied from or=ther files) 8 * Copyright (C) 1998-2000 Hewlett-Packard Co 9 * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> 10 * 11 * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. 12 */ 13 14 15 16#define __ASSEMBLY__ 1 17#include <linux/config.h> 18#include <asm/processor.h> 19#include <asm/sn/addrs.h> 20#include <asm/sn/sn2/shub_mmr.h> 21 22/* 23 * This file contains additional set up code that is needed to get going on 24 * Medusa. This code should disappear once real hw is available. 25 * 26 * On entry to this routine, the following register values are assumed: 27 * 28 * gr[8] - BSP cpu 29 * pr[9] - kernel entry address 30 * pr[10] - cpu number on the node 31 * 32 * NOTE: 33 * This FPROM may be loaded/executed at an address different from the 34 * address that it was linked at. The FPROM is linked to run on node 0 35 * at address 0x100000. If the code in loaded into another node, it 36 * must be loaded at offset 0x100000 of the node. In addition, the 37 * FPROM does the following things: 38 * - determine the base address of the node it is loaded on 39 * - add the node base to _gp. 40 * - add the node base to all addresses derived from "movl" 41 * instructions. (I couldnt get GPREL addressing to work) 42 * (maybe newer versions of the tools will support this) 43 * - scan the .got section and add the node base to all 44 * pointers in this section. 45 * - add the node base to all physical addresses in the 46 * SAL/PAL/EFI table built by the C code. (This is done 47 * in the C code - not here) 48 * - add the node base to the TLB entries for vmlinux 49 */ 50 51#define KERNEL_BASE 0xe000000000000000 52#define BOOT_PARAM_ADDR 0x40000 53 54 55/* 56 * ar.k0 gets set to IOPB_PA value, on 460gx chipset it should 57 * be 0x00000ffffc000000, but on snia we use the (inverse swizzled) 58 * IOSPEC_BASE value 59 */ 60#ifdef SGI_SN2 61#define IOPB_PA 0xc000000fcc000000 62#endif 63 64#define RR_RID 8 65 66 67 68// ==================================================================================== 69 .text 70 .align 16 71 .global _start 72 .proc _start 73_start: 74 75// Setup psr and rse for system init 76 mov psr.l = r0;; 77 srlz.d;; 78 invala 79 mov ar.rsc = r0;; 80 loadrs 81 ;; 82 83// Isolate node number we are running on. 84 mov r6 = ip;; 85#ifdef SGI_SN2 86 shr r5 = r6,38 // r5 = node number 87 dep r6 = 0,r6,0,36 // r6 = base memory address of node 88 89#endif 90 91 92// Set & relocate gp. 93 movl r1= __gp;; // Add base memory address 94 or r1 = r1,r6 // Relocate to boot node 95 96// Lets figure out who we are & put it in the LID register. 97#ifdef SGI_SN2 98// On SN2, we (currently) pass the cpu number in r10 at boot 99 and r25=3,r10;; 100 movl r16=0x8000008110000400 // Allow IPIs 101 mov r17=-1;; 102 st8 [r16]=r17 103 movl r16=0x8000008110060580;; // SHUB_ID 104 ld8 r27=[r16];; 105 extr.u r27=r27,32,11;; 106 shl r26=r25,28;; // Align local cpu# to lid.eid 107 shl r27=r27,16;; // Align NASID to lid.id 108 or r26=r26,r27;; // build the LID 109#else 110// The BR_PI_SELF_CPU_NUM register gives us a value of 0-3. 111// This identifies the cpu on the node. 112// Merge the cpu number with the NASID to generate the LID. 113 movl r24=0x80000a0001000020;; // BR_PI_SELF_CPU_NUM 114 ld8 r25=[r24] // Fetch PI_SELF 115 movl r27=0x80000a0001600000;; // Fetch REVID to get local NASID 116 ld8 r27=[r27];; 117 extr.u r27=r27,32,8;; 118 shl r26=r25,16;; // Align local cpu# to lid.eid 119 shl r27=r27,24;; // Align NASID to lid.id 120 or r26=r26,r27;; // build the LID 121#endif 122 mov cr.lid=r26 // Now put in in the LID register 123 124 movl r2=FPSR_DEFAULT;; 125 mov ar.fpsr=r2 126 movl sp = bootstacke-16;; 127 or sp = sp,r6 // Relocate to boot node 128 129// Save the NASID that we are loaded on. 130 movl r2=base_nasid;; // Save base_nasid for C code 131 or r2 = r2,r6;; // Relocate to boot node 132 st8 [r2]=r5 // Uncond st8 - same on all cpus 133 134// Save the kernel entry address. It is passed in r9 on one of 135// the cpus. 136 movl r2=bsp_entry_pc 137 cmp.ne p6,p0=r9,r0;; 138 or r2 = r2,r6;; // Relocate to boot node 139(p6) st8 [r2]=r9 // Uncond st8 - same on all cpus 140 141 142// The following can ONLY be done by 1 cpu. Lets set a lock - the 143// cpu that gets it does the initilization. The rest just spin waiting 144// til initilization is complete. 145 movl r22 = initlock;; 146 or r22 = r22,r6 // Relocate to boot node 147 mov r23 = 1;; 148 xchg8 r23 = [r22],r23;; 149 cmp.eq p6,p0 = 0,r23 150(p6) br.cond.spnt.few init 1511: ld4 r23 = [r22];; 152 cmp.eq p6,p0 = 1,r23 153(p6) br.cond.sptk 1b 154 br initx 155 156// Add base address of node memory to each pointer in the .got section. 157init: movl r16 = _GLOBAL_OFFSET_TABLE_;; 158 or r16 = r16,r6;; // Relocate to boot node 1591: ld8 r17 = [r16];; 160 cmp.eq p6,p7=0,r17 161(p6) br.cond.sptk.few.clr 2f;; 162 or r17 = r17,r6;; // Relocate to boot node 163 st8 [r16] = r17,8 164 br 1b 1652: 166 mov r23 = 2;; // All done, release the spinning cpus 167 st4 [r22] = r23 168initx: 169 170// 171// I/O-port space base address: 172// 173 movl r2 = IOPB_PA;; 174 mov ar.k0 = r2 175 176 177// Now call main & pass it the current LID value. 178 alloc r2=ar.pfs,0,0,2,0 179 mov r32=r26 180 mov r33=r8;; 181 br.call.sptk.few rp=fmain 182 183// Initialize Region Registers 184// 185 mov r10 = r0 186 mov r2 = (13<<2) 187 mov r3 = r0;; 1881: cmp4.gtu p6,p7 = 7, r3 189 dep r10 = r3, r10, 61, 3 190 dep r2 = r3, r2, RR_RID, 4;; 191(p7) dep r2 = 0, r2, 0, 1;; 192(p6) dep r2 = -1, r2, 0, 1;; 193 mov rr[r10] = r2 194 add r3 = 1, r3;; 195 srlz.d;; 196 cmp4.gtu p6,p0 = 8, r3 197(p6) br.cond.sptk.few.clr 1b 198 199// 200// Return value indicates if we are the BSP or AP. 201// 1 = BSP, 0 = AP 202 mov cr.tpr=r0;; 203 cmp.eq p6,p0=r8,r0 204(p6) br.cond.spnt slave 205 206// 207// Go to kernel C startup routines 208// Need to do a "rfi" in order set "it" and "ed" bits in the PSR. 209// This is the only way to set them. 210 211 movl r28=BOOT_PARAM_ADDR 212 movl r2=bsp_entry_pc;; 213 or r28 = r28,r6;; // Relocate to boot node 214 or r2 = r2,r6;; // Relocate to boot node 215 ld8 r2=[r2];; 216 or r2=r2,r6;; 217 dep r2=0,r2,61,3;; // convert to phys mode 218 219// 220// Turn on address translation, interrupt collection, psr.ed, protection key. 221// Interrupts (PSR.i) are still off here. 222// 223 224 movl r3 = ( IA64_PSR_BN | \ 225 IA64_PSR_AC | \ 226 IA64_PSR_DB | \ 227 IA64_PSR_DA | \ 228 IA64_PSR_IC \ 229 ) 230 ;; 231 mov cr.ipsr = r3 232 233// 234// Go to kernel C startup routines 235// Need to do a "rfi" in order set "it" and "ed" bits in the PSR. 236// This is the only way to set them. 237 238 mov r8=r28;; 239 bsw.1 ;; 240 mov r28=r8;; 241 bsw.0 ;; 242 mov cr.iip = r2 243 srlz.d;; 244 rfi;; 245 246 .endp _start 247 248 249 250// Slave processors come here to spin til they get an interrupt. Then they launch themselves to 251// the place ap_entry points. No initialization is necessary - the kernel makes no 252// assumptions about state on this entry. 253// Note: should verify that the interrupt we got was really the ap_wakeup 254// interrupt but this should not be an issue on medusa 255slave: 256 mov r8=cr.irr0;; // Check for interrupt pending. 257 cmp.eq p6,p0=r8,r0 258 ;; 259(p6) nop.i 0x8beef // Medusa - put cpu to sleep til interrupt occurs 260(p6) br.cond.sptk slave;; 261 262 mov r8=cr.ivr;; // Got one. Must read ivr to accept it 263 srlz.d;; 264 mov cr.eoi=r0;; // must write eoi to clear 265 movl r8=ap_entry;; // now jump to kernel entry 266 or r8 = r8,r6;; // Relocate to boot node 267 ld8 r9=[r8],8;; 268 ld8 r1=[r8] 269 mov b0=r9;; 270 br b0 271 272// Here is the kernel stack used for the fake PROM 273 .bss 274 .align 16384 275bootstack: 276 .skip 16384 277bootstacke: 278initlock: 279 data4 280 281 282 283////////////////////////////////////////////////////////////////////////////////////////////////////////// 284// This code emulates the PAL. Only essential interfaces are emulated. 285 286 287 .text 288 .global pal_emulator 289 .proc pal_emulator 290pal_emulator: 291 mov r8=-1 292 293 mov r9=256 294 ;; 295 cmp.gtu p6,p7=r9,r28 /* r28 <= 255? */ 296(p6) br.cond.sptk.few static 297 ;; 298 mov r9=512 299 ;; 300 cmp.gtu p6,p7=r9,r28 301(p6) br.cond.sptk.few stacked 302 ;; 303 304static: cmp.eq p6,p7=6,r28 /* PAL_PTCE_INFO */ 305(p7) br.cond.sptk.few 1f 306 movl r8=0 /* status = 0 */ 307 movl r9=0x100000000 /* tc.base */ 308 movl r10=0x0000000200000003 /* count[0], count[1] */ 309 movl r11=0x1000000000002000 /* stride[0], stride[1] */ 310 ;; 311 3121: cmp.eq p6,p7=14,r28 /* PAL_FREQ_RATIOS */ 313(p7) br.cond.sptk.few 1f 314 movl r8=0 /* status = 0 */ 315 movl r9 =0x100000064 /* proc_ratio (1/100) */ 316 movl r10=0x100000100 /* bus_ratio<<32 (1/256) */ 317 movl r11=0x10000000a /* itc_ratio<<32 (1/100) */ 318 ;; 319 3201: cmp.eq p6,p7=8,r28 /* PAL_VM_SUMMARY */ 321(p7) br.cond.sptk.few 1f 322 movl r8=0 323#ifdef SGI_SN2 324 movl r9=0x0203083001151065 325 movl r10=0x183f 326#endif 327 movl r11=0 328 ;; 329 3301: cmp.eq p6,p7=19,r28 /* PAL_RSE_INFO */ 331(p7) br.cond.sptk.few 1f 332 movl r8=0 333 movl r9=0x60 334 movl r10=0x0 335 movl r11=0 336 ;; 337 3381: cmp.eq p6,p7=15,r28 /* PAL_PERF_MON_INFO */ 339(p7) br.cond.sptk.few 1f 340 movl r8=0 341 movl r9=0x08122004 342 movl r10=0x0 343 movl r11=0 344 mov r2=ar.lc 345 mov r3=16;; 346 mov ar.lc=r3 347 mov r3=r29;; 3485: st8 [r3]=r0,8 349 br.cloop.sptk.few 5b;; 350 mov ar.lc=r2 351 mov r3=r29 352 movl r2=0x1fff;; /* PMC regs */ 353 st8 [r3]=r2 354 add r3=32,r3 355 movl r2=0x3ffff;; /* PMD regs */ 356 st8 [r3]=r2 357 add r3=32,r3 358 movl r2=0xf0;; /* cycle regs */ 359 st8 [r3]=r2 360 add r3=32,r3 361 movl r2=0x10;; /* retired regs */ 362 st8 [r3]=r2 363 ;; 364 3651: cmp.eq p6,p7=34,r28 /* PAL_VM_PAGE_SIZE */ 366(p7) br.cond.sptk.few 1f 367 movl r8=0 /* status = 0 */ 368 movl r9=0x015557000 /* insertable page sizes */ 369 movl r10=0x115557000 /* purgeable page sizes */ 370 movl r11=0 371 3721: cmp.eq p6,p7=19,r28 /* PAL_RSE_INFO */ 373(p7) br.cond.sptk.few 1f 374 movl r8=0 /* status = 0 */ 375 movl r9=96 /* num phys stacked */ 376 movl r10=0 /* hints */ 377 movl r11=0 378 ;; 379 3801: cmp.eq p6,p7=1,r28 /* PAL_CACHE_FLUSH */ 381(p7) br.cond.sptk.few 1f 382 mov r9=ar.lc 383 movl r8=524288 /* flush 512k million cache lines (16MB) */ 384 ;; 385 mov ar.lc=r8 386 movl r8=0xe000000000000000 387 ;; 388.loop: fc r8 389 add r8=32,r8 390 br.cloop.sptk.few .loop 391 sync.i 392 ;; 393 srlz.i 394 ;; 395 mov ar.lc=r9 396 mov r8=r0 3971: br.cond.sptk.few rp 398 399stacked: 400 br.ret.sptk.few rp 401 402 .endp pal_emulator 403 404