head_64.S 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. * Copyright 2011 Tilera Corporation. All Rights Reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation, version 2.
  7. *
  8. * This program is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  11. * NON INFRINGEMENT. See the GNU General Public License for
  12. * more details.
  13. *
  14. * TILE startup code.
  15. */
  16. #include <linux/linkage.h>
  17. #include <linux/init.h>
  18. #include <asm/page.h>
  19. #include <asm/pgtable.h>
  20. #include <asm/thread_info.h>
  21. #include <asm/processor.h>
  22. #include <asm/asm-offsets.h>
  23. #include <hv/hypervisor.h>
  24. #include <arch/chip.h>
  25. #include <arch/spr_def.h>
  26. /*
  27. * This module contains the entry code for kernel images. It performs the
  28. * minimal setup needed to call the generic C routines.
  29. */
  30. __HEAD
  31. ENTRY(_start)
  32. /* Notify the hypervisor of what version of the API we want */
  33. {
  34. #if KERNEL_PL == 1 && _HV_VERSION == 13
  35. /* Support older hypervisors by asking for API version 12. */
  36. movei r0, _HV_VERSION_OLD_HV_INIT
  37. #else
  38. movei r0, _HV_VERSION
  39. #endif
  40. movei r1, TILE_CHIP
  41. }
  42. {
  43. movei r2, TILE_CHIP_REV
  44. movei r3, KERNEL_PL
  45. }
  46. jal hv_init
  47. /* Get a reasonable default ASID in r0 */
  48. {
  49. move r0, zero
  50. jal hv_inquire_asid
  51. }
  52. /*
  53. * Install the default page table. The relocation required to
  54. * statically define the table is a bit too complex, so we have
  55. * to plug in the pointer from the L0 to the L1 table by hand.
  56. * We only do this on the first cpu to boot, though, since the
  57. * other CPUs should see a properly-constructed page table.
  58. */
  59. {
  60. v4int_l r2, zero, r0 /* ASID for hv_install_context */
  61. moveli r4, hw1_last(swapper_pgprot - PAGE_OFFSET)
  62. }
  63. {
  64. shl16insli r4, r4, hw0(swapper_pgprot - PAGE_OFFSET)
  65. }
  66. {
  67. ld r1, r4 /* access_pte for hv_install_context */
  68. }
  69. {
  70. moveli r0, hw1_last(.Lsv_data_pmd - PAGE_OFFSET)
  71. moveli r6, hw1_last(temp_data_pmd - PAGE_OFFSET)
  72. }
  73. {
  74. /* After initializing swapper_pgprot, HV_PTE_GLOBAL is set. */
  75. bfextu r7, r1, HV_PTE_INDEX_GLOBAL, HV_PTE_INDEX_GLOBAL
  76. inv r4
  77. }
  78. bnez r7, .Lno_write
  79. {
  80. shl16insli r0, r0, hw0(.Lsv_data_pmd - PAGE_OFFSET)
  81. shl16insli r6, r6, hw0(temp_data_pmd - PAGE_OFFSET)
  82. }
  83. {
  84. /* Cut off the low bits of the PT address. */
  85. shrui r6, r6, HV_LOG2_PAGE_TABLE_ALIGN
  86. /* Start with our access pte. */
  87. move r5, r1
  88. }
  89. {
  90. /* Stuff the address into the page table pointer slot of the PTE. */
  91. bfins r5, r6, HV_PTE_INDEX_PTFN, \
  92. HV_PTE_INDEX_PTFN + HV_PTE_PTFN_BITS - 1
  93. }
  94. {
  95. /* Store the L0 data PTE. */
  96. st r0, r5
  97. addli r6, r6, (temp_code_pmd - temp_data_pmd) >> \
  98. HV_LOG2_PAGE_TABLE_ALIGN
  99. }
  100. {
  101. addli r0, r0, .Lsv_code_pmd - .Lsv_data_pmd
  102. bfins r5, r6, HV_PTE_INDEX_PTFN, \
  103. HV_PTE_INDEX_PTFN + HV_PTE_PTFN_BITS - 1
  104. }
  105. /* Store the L0 code PTE. */
  106. st r0, r5
  107. .Lno_write:
  108. moveli lr, hw2_last(1f)
  109. {
  110. shl16insli lr, lr, hw1(1f)
  111. moveli r0, hw1_last(swapper_pg_dir - PAGE_OFFSET)
  112. }
  113. {
  114. shl16insli lr, lr, hw0(1f)
  115. shl16insli r0, r0, hw0(swapper_pg_dir - PAGE_OFFSET)
  116. }
  117. {
  118. moveli r3, CTX_PAGE_FLAG
  119. j hv_install_context
  120. }
  121. 1:
  122. /* Install the interrupt base. */
  123. moveli r0, hw2_last(MEM_SV_START)
  124. shl16insli r0, r0, hw1(MEM_SV_START)
  125. shl16insli r0, r0, hw0(MEM_SV_START)
  126. mtspr SPR_INTERRUPT_VECTOR_BASE_K, r0
  127. /*
  128. * Get our processor number and save it away in SAVE_K_0.
  129. * Extract stuff from the topology structure: r4 = y, r6 = x,
  130. * r5 = width. FIXME: consider whether we want to just make these
  131. * 64-bit values (and if so fix smp_topology write below, too).
  132. */
  133. jal hv_inquire_topology
  134. {
  135. v4int_l r5, zero, r1 /* r5 = width */
  136. shrui r4, r0, 32 /* r4 = y */
  137. }
  138. {
  139. v4int_l r6, zero, r0 /* r6 = x */
  140. mul_lu_lu r4, r4, r5
  141. }
  142. {
  143. add r4, r4, r6 /* r4 == cpu == y*width + x */
  144. }
  145. #ifdef CONFIG_SMP
  146. /*
  147. * Load up our per-cpu offset. When the first (master) tile
  148. * boots, this value is still zero, so we will load boot_pc
  149. * with start_kernel, and boot_sp with init_stack + THREAD_SIZE.
  150. * The master tile initializes the per-cpu offset array, so that
  151. * when subsequent (secondary) tiles boot, they will instead load
  152. * from their per-cpu versions of boot_sp and boot_pc.
  153. */
  154. moveli r5, hw2_last(__per_cpu_offset)
  155. shl16insli r5, r5, hw1(__per_cpu_offset)
  156. shl16insli r5, r5, hw0(__per_cpu_offset)
  157. shl3add r5, r4, r5
  158. ld r5, r5
  159. bnez r5, 1f
  160. /*
  161. * Save the width and height to the smp_topology variable
  162. * for later use.
  163. */
  164. moveli r0, hw2_last(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
  165. shl16insli r0, r0, hw1(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
  166. shl16insli r0, r0, hw0(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
  167. st r0, r1
  168. 1:
  169. #else
  170. move r5, zero
  171. #endif
  172. /* Load and go with the correct pc and sp. */
  173. {
  174. moveli r1, hw2_last(boot_sp)
  175. moveli r0, hw2_last(boot_pc)
  176. }
  177. {
  178. shl16insli r1, r1, hw1(boot_sp)
  179. shl16insli r0, r0, hw1(boot_pc)
  180. }
  181. {
  182. shl16insli r1, r1, hw0(boot_sp)
  183. shl16insli r0, r0, hw0(boot_pc)
  184. }
  185. {
  186. add r1, r1, r5
  187. add r0, r0, r5
  188. }
  189. ld r0, r0
  190. ld sp, r1
  191. or r4, sp, r4
  192. mtspr SPR_SYSTEM_SAVE_K_0, r4 /* save ksp0 + cpu */
  193. addi sp, sp, -STACK_TOP_DELTA
  194. {
  195. move lr, zero /* stop backtraces in the called function */
  196. jr r0
  197. }
  198. ENDPROC(_start)
  199. __PAGE_ALIGNED_BSS
  200. .align PAGE_SIZE
  201. ENTRY(empty_zero_page)
  202. .fill PAGE_SIZE,1,0
  203. END(empty_zero_page)
  204. .macro PTE cpa, bits1
  205. .quad HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED |\
  206. HV_PTE_GLOBAL | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE) |\
  207. (\bits1) | (HV_CPA_TO_PTFN(\cpa) << HV_PTE_INDEX_PTFN)
  208. .endm
  209. __PAGE_ALIGNED_DATA
  210. .align PAGE_SIZE
  211. ENTRY(swapper_pg_dir)
  212. .org swapper_pg_dir + PGD_INDEX(PAGE_OFFSET) * HV_PTE_SIZE
  213. .Lsv_data_pmd:
  214. .quad 0 /* PTE temp_data_pmd - PAGE_OFFSET, 0 */
  215. .org swapper_pg_dir + PGD_INDEX(MEM_SV_START) * HV_PTE_SIZE
  216. .Lsv_code_pmd:
  217. .quad 0 /* PTE temp_code_pmd - PAGE_OFFSET, 0 */
  218. .org swapper_pg_dir + SIZEOF_PGD
  219. END(swapper_pg_dir)
  220. .align HV_PAGE_TABLE_ALIGN
  221. ENTRY(temp_data_pmd)
  222. /*
  223. * We fill the PAGE_OFFSET pmd with huge pages with
  224. * VA = PA + PAGE_OFFSET. We remap things with more precise access
  225. * permissions later.
  226. */
  227. .set addr, 0
  228. .rept PTRS_PER_PMD
  229. PTE addr, HV_PTE_READABLE | HV_PTE_WRITABLE
  230. .set addr, addr + HPAGE_SIZE
  231. .endr
  232. .org temp_data_pmd + SIZEOF_PMD
  233. END(temp_data_pmd)
  234. .align HV_PAGE_TABLE_ALIGN
  235. ENTRY(temp_code_pmd)
  236. /*
  237. * We fill the MEM_SV_START pmd with huge pages with
  238. * VA = PA + PAGE_OFFSET. We remap things with more precise access
  239. * permissions later.
  240. */
  241. .set addr, 0
  242. .rept PTRS_PER_PMD
  243. PTE addr, HV_PTE_READABLE | HV_PTE_EXECUTABLE
  244. .set addr, addr + HPAGE_SIZE
  245. .endr
  246. .org temp_code_pmd + SIZEOF_PMD
  247. END(temp_code_pmd)
  248. /*
  249. * Isolate swapper_pgprot to its own cache line, since each cpu
  250. * starting up will read it using VA-is-PA and local homing.
  251. * This would otherwise likely conflict with other data on the cache
  252. * line, once we have set its permanent home in the page tables.
  253. */
  254. __INITDATA
  255. .align CHIP_L2_LINE_SIZE()
  256. ENTRY(swapper_pgprot)
  257. .quad HV_PTE_PRESENT | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE)
  258. .align CHIP_L2_LINE_SIZE()
  259. END(swapper_pgprot)