sipi_vector.S 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. * Copyright (c) 2015 Google, Inc
  3. *
  4. * SPDX-License-Identifier: GPL-2.0
  5. *
  6. * Taken from coreboot file of the same name
  7. */
  8. /*
  9. * The SIPI vector is responsible for initializing the APs in the sytem. It
  10. * loads microcode, sets up MSRs, and enables caching before calling into
  11. * C code
  12. */
  13. #include <asm/global_data.h>
  14. #include <asm/msr-index.h>
  15. #include <asm/processor.h>
  16. #include <asm/processor-flags.h>
  17. #include <asm/sipi.h>
  18. #define CODE_SEG (X86_GDT_ENTRY_32BIT_CS * X86_GDT_ENTRY_SIZE)
  19. #define DATA_SEG (X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE)
  20. /*
  21. * First we have the 16-bit section. Every AP process starts here.
  22. * The simple task is to load U-Boot's Global Descriptor Table (GDT) to allow
  23. * U-Boot's 32-bit code to become visible, then jump to ap_start.
  24. *
  25. * Note that this code is copied to RAM below 1MB in mp_init.c, and runs from
  26. * there, but the 32-bit code (ap_start and onwards) is part of U-Boot and
  27. * is therefore relocated to the top of RAM with other U-Boot code. This
  28. * means that for the 16-bit code we must write relocatable code, but for the
  29. * rest, we can do what we like.
  30. */
  31. .text
  32. .code16
  33. .globl ap_start16
  34. ap_start16:
  35. cli
  36. xorl %eax, %eax
  37. movl %eax, %cr3 /* Invalidate TLB */
  38. /* setup the data segment */
  39. movw %cs, %ax
  40. movw %ax, %ds
  41. /* Use an address relative to the data segment for the GDT */
  42. movl $gdtaddr, %ebx
  43. subl $ap_start16, %ebx
  44. data32 lgdt (%ebx)
  45. movl %cr0, %eax
  46. andl $(~(X86_CR0_PG | X86_CR0_AM | X86_CR0_WP | X86_CR0_NE | \
  47. X86_CR0_TS | X86_CR0_EM | X86_CR0_MP)), %eax
  48. orl $(X86_CR0_NW | X86_CR0_CD | X86_CR0_PE), %eax
  49. movl %eax, %cr0
  50. movl $ap_start_jmp, %eax
  51. subl $ap_start16, %eax
  52. movw %ax, %bp
  53. /* Jump to ap_start within U-Boot */
  54. data32 cs ljmp *(%bp)
  55. .align 4
  56. .globl sipi_params_16bit
  57. sipi_params_16bit:
  58. /* 48-bit far pointer */
  59. ap_start_jmp:
  60. .long 0 /* offset set to ap_start by U-Boot */
  61. .word CODE_SEG /* segment */
  62. .word 0 /* padding */
  63. gdtaddr:
  64. .word 0 /* limit */
  65. .long 0 /* table */
  66. .word 0 /* unused */
  67. .globl ap_start16_code_end
  68. ap_start16_code_end:
  69. /*
  70. * Set up the special 'fs' segment for global_data. Then jump to ap_continue
  71. * to set up the AP.
  72. */
  73. .globl ap_start
  74. ap_start:
  75. .code32
  76. movw $DATA_SEG, %ax
  77. movw %ax, %ds
  78. movw %ax, %es
  79. movw %ax, %ss
  80. movw %ax, %gs
  81. movw $(X86_GDT_ENTRY_32BIT_FS * X86_GDT_ENTRY_SIZE), %ax
  82. movw %ax, %fs
  83. /* Load the Interrupt descriptor table */
  84. mov idt_ptr, %ebx
  85. lidt (%ebx)
  86. /* Obtain cpu number */
  87. movl ap_count, %eax
  88. 1:
  89. movl %eax, %ecx
  90. inc %ecx
  91. lock cmpxchg %ecx, ap_count
  92. jnz 1b
  93. /* Setup stacks for each CPU */
  94. movl stack_size, %eax
  95. mul %ecx
  96. movl stack_top, %edx
  97. subl %eax, %edx
  98. mov %edx, %esp
  99. /* Save cpu number */
  100. mov %ecx, %esi
  101. /* Determine if one should check microcode versions */
  102. mov microcode_ptr, %edi
  103. test %edi, %edi
  104. jz microcode_done /* Bypass if no microde exists */
  105. /* Get the Microcode version */
  106. mov $1, %eax
  107. cpuid
  108. mov $MSR_IA32_UCODE_REV, %ecx
  109. rdmsr
  110. /* If something already loaded skip loading again */
  111. test %edx, %edx
  112. jnz microcode_done
  113. /* Determine if parallel microcode loading is allowed */
  114. cmp $0xffffffff, microcode_lock
  115. je load_microcode
  116. /* Protect microcode loading */
  117. lock_microcode:
  118. lock bts $0, microcode_lock
  119. jc lock_microcode
  120. load_microcode:
  121. /* Load new microcode */
  122. mov $MSR_IA32_UCODE_WRITE, %ecx
  123. xor %edx, %edx
  124. mov %edi, %eax
  125. /*
  126. * The microcode pointer is passed in pointing to the header. Adjust
  127. * pointer to reflect the payload (header size is 48 bytes)
  128. */
  129. add $UCODE_HEADER_LEN, %eax
  130. pusha
  131. wrmsr
  132. popa
  133. /* Unconditionally unlock microcode loading */
  134. cmp $0xffffffff, microcode_lock
  135. je microcode_done
  136. xor %eax, %eax
  137. mov %eax, microcode_lock
  138. microcode_done:
  139. /*
  140. * Load MSRs. Each entry in the table consists of:
  141. * 0: index,
  142. * 4: value[31:0]
  143. * 8: value[63:32]
  144. * See struct saved_msr in mp_init.c.
  145. */
  146. mov msr_table_ptr, %edi
  147. mov msr_count, %ebx
  148. test %ebx, %ebx
  149. jz 1f
  150. load_msr:
  151. mov (%edi), %ecx
  152. mov 4(%edi), %eax
  153. mov 8(%edi), %edx
  154. wrmsr
  155. add $12, %edi
  156. dec %ebx
  157. jnz load_msr
  158. 1:
  159. /* Enable caching */
  160. mov %cr0, %eax
  161. andl $(~(X86_CR0_CD | X86_CR0_NW)), %eax
  162. mov %eax, %cr0
  163. /* c_handler(cpu_num) */
  164. movl %esi, %eax /* cpu_num */
  165. mov c_handler, %esi
  166. call *%esi
  167. /* This matches struct sipi_param */
  168. .align 4
  169. .globl sipi_params
  170. sipi_params:
  171. idt_ptr:
  172. .long 0
  173. stack_top:
  174. .long 0
  175. stack_size:
  176. .long 0
  177. microcode_lock:
  178. .long 0
  179. microcode_ptr:
  180. .long 0
  181. msr_table_ptr:
  182. .long 0
  183. msr_count:
  184. .long 0
  185. c_handler:
  186. .long 0
  187. ap_count:
  188. .long 0