sipi_vector.S 4.4 KB

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