head_64.S 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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. /* Extract two 32-bit bit values that were read into one register. */
  27. #ifdef __BIG_ENDIAN__
  28. #define GET_FIRST_INT(rd, rs) shrsi rd, rs, 32
  29. #define GET_SECOND_INT(rd, rs) addxi rd, rs, 0
  30. #else
  31. #define GET_FIRST_INT(rd, rs) addxi rd, rs, 0
  32. #define GET_SECOND_INT(rd, rs) shrsi rd, rs, 32
  33. #endif
  34. /*
  35. * This module contains the entry code for kernel images. It performs the
  36. * minimal setup needed to call the generic C routines.
  37. */
  38. __HEAD
  39. ENTRY(_start)
  40. /* Notify the hypervisor of what version of the API we want */
  41. {
  42. #if KERNEL_PL == 1 && _HV_VERSION == 13
  43. /* Support older hypervisors by asking for API version 12. */
  44. movei r0, _HV_VERSION_OLD_HV_INIT
  45. #else
  46. movei r0, _HV_VERSION
  47. #endif
  48. movei r1, TILE_CHIP
  49. }
  50. {
  51. movei r2, TILE_CHIP_REV
  52. movei r3, KERNEL_PL
  53. }
  54. jal _hv_init
  55. /* Get a reasonable default ASID in r0 */
  56. {
  57. move r0, zero
  58. jal _hv_inquire_asid
  59. }
  60. /*
  61. * Install the default page table. The relocation required to
  62. * statically define the table is a bit too complex, so we have
  63. * to plug in the pointer from the L0 to the L1 table by hand.
  64. * We only do this on the first cpu to boot, though, since the
  65. * other CPUs should see a properly-constructed page table.
  66. */
  67. {
  68. GET_FIRST_INT(r2, r0) /* ASID for hv_install_context */
  69. moveli r4, hw1_last(swapper_pgprot - PAGE_OFFSET)
  70. }
  71. {
  72. shl16insli r4, r4, hw0(swapper_pgprot - PAGE_OFFSET)
  73. }
  74. {
  75. ld r1, r4 /* access_pte for hv_install_context */
  76. }
  77. {
  78. moveli r0, hw1_last(.Lsv_data_pmd - PAGE_OFFSET)
  79. moveli r6, hw1_last(temp_data_pmd - PAGE_OFFSET)
  80. }
  81. {
  82. /* After initializing swapper_pgprot, HV_PTE_GLOBAL is set. */
  83. bfextu r7, r1, HV_PTE_INDEX_GLOBAL, HV_PTE_INDEX_GLOBAL
  84. finv r4
  85. }
  86. bnez r7, .Lno_write
  87. {
  88. shl16insli r0, r0, hw0(.Lsv_data_pmd - PAGE_OFFSET)
  89. shl16insli r6, r6, hw0(temp_data_pmd - PAGE_OFFSET)
  90. }
  91. {
  92. /* Cut off the low bits of the PT address. */
  93. shrui r6, r6, HV_LOG2_PAGE_TABLE_ALIGN
  94. /* Start with our access pte. */
  95. move r5, r1
  96. }
  97. {
  98. /* Stuff the address into the page table pointer slot of the PTE. */
  99. bfins r5, r6, HV_PTE_INDEX_PTFN, \
  100. HV_PTE_INDEX_PTFN + HV_PTE_PTFN_BITS - 1
  101. }
  102. {
  103. /* Store the L0 data PTE. */
  104. st r0, r5
  105. addli r6, r6, (temp_code_pmd - temp_data_pmd) >> \
  106. HV_LOG2_PAGE_TABLE_ALIGN
  107. }
  108. {
  109. addli r0, r0, .Lsv_code_pmd - .Lsv_data_pmd
  110. bfins r5, r6, HV_PTE_INDEX_PTFN, \
  111. HV_PTE_INDEX_PTFN + HV_PTE_PTFN_BITS - 1
  112. }
  113. /* Store the L0 code PTE. */
  114. st r0, r5
  115. .Lno_write:
  116. moveli lr, hw2_last(1f)
  117. {
  118. shl16insli lr, lr, hw1(1f)
  119. moveli r0, hw1_last(swapper_pg_dir - PAGE_OFFSET)
  120. }
  121. {
  122. shl16insli lr, lr, hw0(1f)
  123. shl16insli r0, r0, hw0(swapper_pg_dir - PAGE_OFFSET)
  124. }
  125. {
  126. moveli r3, CTX_PAGE_FLAG
  127. j _hv_install_context
  128. }
  129. 1:
  130. /* Install the interrupt base. */
  131. moveli r0, hw2_last(intrpt_start)
  132. shl16insli r0, r0, hw1(intrpt_start)
  133. shl16insli r0, r0, hw0(intrpt_start)
  134. mtspr SPR_INTERRUPT_VECTOR_BASE_K, r0
  135. /* Get our processor number and save it away in SAVE_K_0. */
  136. jal _hv_inquire_topology
  137. {
  138. GET_FIRST_INT(r5, r1) /* r5 = width */
  139. GET_SECOND_INT(r4, r0) /* r4 = y */
  140. }
  141. {
  142. GET_FIRST_INT(r6, r0) /* r6 = x */
  143. mul_lu_lu r4, r4, r5
  144. }
  145. {
  146. add r4, r4, r6 /* r4 == cpu == y*width + x */
  147. }
  148. #ifdef CONFIG_SMP
  149. /*
  150. * Load up our per-cpu offset. When the first (master) tile
  151. * boots, this value is still zero, so we will load boot_pc
  152. * with start_kernel, and boot_sp with at the top of init_stack.
  153. * The master tile initializes the per-cpu offset array, so that
  154. * when subsequent (secondary) tiles boot, they will instead load
  155. * from their per-cpu versions of boot_sp and boot_pc.
  156. */
  157. moveli r5, hw2_last(__per_cpu_offset)
  158. shl16insli r5, r5, hw1(__per_cpu_offset)
  159. shl16insli r5, r5, hw0(__per_cpu_offset)
  160. shl3add r5, r4, r5
  161. ld r5, r5
  162. bnez r5, 1f
  163. /*
  164. * Save the width and height to the smp_topology variable
  165. * for later use.
  166. */
  167. moveli r0, hw2_last(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
  168. shl16insli r0, r0, hw1(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
  169. shl16insli r0, r0, hw0(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
  170. st r0, r1
  171. 1:
  172. #else
  173. move r5, zero
  174. #endif
  175. /* Load and go with the correct pc and sp. */
  176. {
  177. moveli r1, hw2_last(boot_sp)
  178. moveli r0, hw2_last(boot_pc)
  179. }
  180. {
  181. shl16insli r1, r1, hw1(boot_sp)
  182. shl16insli r0, r0, hw1(boot_pc)
  183. }
  184. {
  185. shl16insli r1, r1, hw0(boot_sp)
  186. shl16insli r0, r0, hw0(boot_pc)
  187. }
  188. {
  189. add r1, r1, r5
  190. add r0, r0, r5
  191. }
  192. ld r0, r0
  193. ld sp, r1
  194. shli r4, r4, CPU_SHIFT
  195. bfins r4, sp, 0, CPU_SHIFT-1
  196. mtspr SPR_SYSTEM_SAVE_K_0, r4 /* save ksp0 + cpu */
  197. {
  198. move lr, zero /* stop backtraces in the called function */
  199. jr r0
  200. }
  201. ENDPROC(_start)
  202. __PAGE_ALIGNED_BSS
  203. .align PAGE_SIZE
  204. ENTRY(empty_zero_page)
  205. .fill PAGE_SIZE,1,0
  206. END(empty_zero_page)
  207. .macro PTE cpa, bits1
  208. .quad HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED |\
  209. HV_PTE_GLOBAL | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE) |\
  210. (\bits1) | (HV_CPA_TO_PTFN(\cpa) << HV_PTE_INDEX_PTFN)
  211. .endm
  212. __PAGE_ALIGNED_DATA
  213. .align PAGE_SIZE
  214. ENTRY(swapper_pg_dir)
  215. .org swapper_pg_dir + PGD_INDEX(PAGE_OFFSET) * HV_PTE_SIZE
  216. .Lsv_data_pmd:
  217. .quad 0 /* PTE temp_data_pmd - PAGE_OFFSET, 0 */
  218. .org swapper_pg_dir + PGD_INDEX(MEM_SV_START) * HV_PTE_SIZE
  219. .Lsv_code_pmd:
  220. .quad 0 /* PTE temp_code_pmd - PAGE_OFFSET, 0 */
  221. .org swapper_pg_dir + SIZEOF_PGD
  222. END(swapper_pg_dir)
  223. .align HV_PAGE_TABLE_ALIGN
  224. ENTRY(temp_data_pmd)
  225. /*
  226. * We fill the PAGE_OFFSET pmd with huge pages with
  227. * VA = PA + PAGE_OFFSET. We remap things with more precise access
  228. * permissions later.
  229. */
  230. .set addr, 0
  231. .rept PTRS_PER_PMD
  232. PTE addr, HV_PTE_READABLE | HV_PTE_WRITABLE
  233. .set addr, addr + HPAGE_SIZE
  234. .endr
  235. .org temp_data_pmd + SIZEOF_PMD
  236. END(temp_data_pmd)
  237. .align HV_PAGE_TABLE_ALIGN
  238. ENTRY(temp_code_pmd)
  239. /*
  240. * We fill the MEM_SV_START pmd with huge pages with
  241. * VA = PA + PAGE_OFFSET. We remap things with more precise access
  242. * permissions later.
  243. */
  244. .set addr, 0
  245. .rept PTRS_PER_PMD
  246. PTE addr, HV_PTE_READABLE | HV_PTE_EXECUTABLE
  247. .set addr, addr + HPAGE_SIZE
  248. .endr
  249. .org temp_code_pmd + SIZEOF_PMD
  250. END(temp_code_pmd)
  251. /*
  252. * Isolate swapper_pgprot to its own cache line, since each cpu
  253. * starting up will read it using VA-is-PA and local homing.
  254. * This would otherwise likely conflict with other data on the cache
  255. * line, once we have set its permanent home in the page tables.
  256. */
  257. __INITDATA
  258. .align CHIP_L2_LINE_SIZE()
  259. ENTRY(swapper_pgprot)
  260. .quad HV_PTE_PRESENT | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE)
  261. .align CHIP_L2_LINE_SIZE()
  262. END(swapper_pgprot)