smpa.S 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*++
  2. Copyright (c) 2015 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. smpa.S
  9. Abstract:
  10. This module implements assembly routines necessary for booting the
  11. application processors on the BCM2836.
  12. Author:
  13. Chris Stevens 19-Apr-2015
  14. Environment:
  15. Firmware
  16. --*/
  17. //
  18. // ------------------------------------------------------------------ Includes
  19. //
  20. #include <minoca/kernel/arm.inc>
  21. //
  22. // --------------------------------------------------------------- Definitions
  23. //
  24. //
  25. // ---------------------------------------------------------------------- Code
  26. //
  27. ASSEMBLY_FILE_HEADER
  28. .arch_extension virt
  29. //
  30. // .globl allows these labels to be visible to the linker.
  31. //
  32. .globl EfipBcm2836ProcessorStartup
  33. .globl EfipBcm2836ParkingLoop
  34. .globl EfipBcm2836ParkingLoopEnd
  35. //
  36. // VOID
  37. // EfipBcm2836SendEvent (
  38. // VOID
  39. // )
  40. //
  41. /*++
  42. Routine Description:
  43. This routine executes a SEV instruction, which is a hint instruction that
  44. causes an event to be signalled to all processors.
  45. Arguments:
  46. None.
  47. Return Value:
  48. None.
  49. --*/
  50. FUNCTION EfipBcm2836SendEvent
  51. DSB @ Data Synchronization Barrier.
  52. sev @ Send Event.
  53. bx %lr @ Return.
  54. END_FUNCTION EfipBcm2836SendEvent
  55. //
  56. // UINT32
  57. // EfipBcm2836GetMultiprocessorIdRegister (
  58. // VOID
  59. // )
  60. //
  61. /*++
  62. Routine Description:
  63. This routine gets the Multiprocessor ID register (MPIDR).
  64. Arguments:
  65. None.
  66. Return Value:
  67. Returns the value of the MPIDR.
  68. --*/
  69. FUNCTION EfipBcm2836GetMultiprocessorIdRegister
  70. mrc p15, 0, %r0, %c0, %c0, 5 @ Get the MPIDR
  71. bx %lr @
  72. END_FUNCTION EfipBcm2836GetMultiprocessorIdRegister
  73. //
  74. // VOID
  75. // EfipBcm2836SwitchToSvcMode (
  76. // VOID
  77. // )
  78. //
  79. /*++
  80. Routine Description:
  81. This routine disabled interrupts and switches to SVC mode. It handles the
  82. case where the core is in HYP mode, which requires an execution state
  83. transition in order to enter SVC mode.
  84. Arguments:
  85. None.
  86. Return Value:
  87. None.
  88. --*/
  89. FUNCTION EfipBcm2836SwitchToSvcMode
  90. //
  91. // Disable interrupts.
  92. //
  93. cpsid i
  94. //
  95. // Test to see if the core is in HYP mode. Transitioning from HYP mode to
  96. // SVC mode requires an ERET to switch execution states.
  97. //
  98. mrs %r0, CPSR
  99. and %r1, %r0, #ARM_MODE_MASK
  100. cmp %r1, #ARM_MODE_HYP
  101. bne EfipBcm2836SwitchToSvcModeEnd
  102. //
  103. // While in HYP mode, zero out the Generic Timer's virtual offset. Assume
  104. // that if the core is not in HYP mode that some other source appropriately
  105. // set the virtual offset.
  106. //
  107. mov %r2, #0
  108. mov %r3, #0
  109. mcrr p15, 4, %r2, %r3, %c14
  110. //
  111. // Trasition to SVC mode with the ERET.
  112. //
  113. msr ELR_hyp, %lr
  114. and %r0, %r0, #~(ARM_MODE_MASK)
  115. orr %r0, %r0, #ARM_MODE_SVC
  116. msr SPSR_hyp, %r0
  117. eret
  118. EfipBcm2836SwitchToSvcModeEnd:
  119. //
  120. // The core was not in HYP mode. Switch to SVC mode the easy way.
  121. //
  122. mov %r0, #(PSR_FLAG_IRQ | ARM_MODE_SVC)
  123. msr CPSR_c, %r0
  124. bx %lr
  125. END_FUNCTION EfipBcm2836SwitchToSvcMode
  126. //
  127. // VOID
  128. // EfipBcm2836ProcessorStartup (
  129. // VOID
  130. // )
  131. //
  132. /*++
  133. Routine Description:
  134. This routine implements the startup routine for the alternate CPUs on the
  135. Raspberry Pi 2. Since this is the very first set of instructions executed
  136. on this core there is nothing set up, including a stack.
  137. Arguments:
  138. None.
  139. Return Value:
  140. None. This function does not return, as there is nothing to return to.
  141. --*/
  142. .arm
  143. .align 4
  144. EfipBcm2836ProcessorStartup:
  145. //
  146. // Disable interrupts and switch to SVC mode.
  147. //
  148. bl EfipBcm2836SwitchToSvcMode
  149. //
  150. // Park the core again, waiting until the firmware can allocate a page for
  151. // the final parking location.
  152. //
  153. mov %r3, #0
  154. ldr %r1, =EfiBcm2836ProcessorId @ Get the processor ID address.
  155. ldr %r0, [%r1] @ Get the value.
  156. str %r3, [%r1] @ Zero the value.
  157. EfipBcm2836ProcessorStartupLoop:
  158. DSB @ Data synchronization barrier.
  159. ldr %r2, [%r1] @ Load the processor ID.
  160. cmp %r0, %r2
  161. beq EfipBcm2836ProcessorStartupEnd @ Move to the jump if it's real.
  162. wfe @ Wait for an event.
  163. b EfipBcm2836ProcessorStartupLoop @ Try again.
  164. EfipBcm2836ProcessorStartupEnd:
  165. ldr %r1, =EfiBcm2836JumpAddress @ Get the jump address.
  166. ldr %r2, [%r1] @ Get the value.
  167. str %r3, [%r1] @ Store zero into jump address.
  168. bic %r1, %r2, #0xF00 @ Set the parking location.
  169. bic %r1, %r1, #0x0FF
  170. DSB @ One final breath, then...
  171. bx %r2 @ Jump head first into the abyss.
  172. .ltorg
  173. //
  174. // VOID
  175. // EfipBcm2836ParkingLoop (
  176. // UINT32 ProcessorId,
  177. // VOID *ParkingLocation
  178. // )
  179. //
  180. /*++
  181. Routine Description:
  182. This routine implements the MP parking protocol loop.
  183. Arguments:
  184. ProcessorId - Supplies the ID of this processor.
  185. ParkingLocation - Supplies the parking protocol mailbox base.
  186. Return Value:
  187. None. This function does not return, it launches the core.
  188. --*/
  189. EfipBcm2836ParkingLoop:
  190. DSB @ Data synchronization barrier.
  191. ldr %r2, [%r1] @ Read the processor ID.
  192. cmp %r0, %r2 @ Compare to this processor ID.
  193. beq EfipBcm2836ParkingLoopJump @ Move to the jump if it's real.
  194. wfi @ Wait for an interrupt.
  195. b EfipBcm2836ParkingLoop @ Try again.
  196. EfipBcm2836ParkingLoopJump:
  197. ldr %r2, [%r1, #8] @ Get the jump address.
  198. mov %r3, #0 @ Clear R3.
  199. str %r3, [%r1, #8] @ Store zero into jump address.
  200. DSB @ One final breath, then...
  201. bx %r2 @ Jump head first into the abyss.
  202. //
  203. // Dump any literals being saved up.
  204. //
  205. .ltorg
  206. EfipBcm2836ParkingLoopEnd:
  207. //
  208. // --------------------------------------------------------- Internal Functions
  209. //