fpromasm.S
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:9k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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