smpa.S 6.3 KB

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