1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <cpu/x86/cr.h>
4 #include <cpu/amd/mtrr.h>
5 #include <cpu/x86/msr.h>
6 #include <arch/ram_segs.h>
10 /* The SIPI vector is responsible for initializing the APs in the system. It
11 * loads microcode, sets up MSRs, and enables caching before calling into
14 .section ".module_parameters", "aw", @progbits
22 per_cpu_segment_descriptors:
24 per_cpu_segment_selector:
43 #define CR0_CLEAR_FLAGS_CACHE_ENABLE (CR0_CD | CR0_NW)
44 #define CR0_SET_FLAGS (CR0_CLEAR_FLAGS_CACHE_ENABLE | CR0_PE)
45 #define CR0_CLEAR_FLAGS \
46 (CR0_PG | CR0_AM | CR0_WP | CR0_NE | CR0_TS | CR0_EM | CR0_MP)
54 movl %eax, %cr3 /* Invalidate TLB*/
56 /* On hyper threaded cpus, invalidating the cache here is
57 * very very bad. Don't.
60 /* setup the data segment */
64 /* The gdtaddr needs to be relative to the data segment in order
65 * to properly dereference it. The .text section comes first in an
66 * rmodule so _start can be used as a proxy for the load address. */
73 andl $~CR0_CLEAR_FLAGS, %eax
74 orl $CR0_SET_FLAGS, %eax
77 ljmpl $RAM_CODE_SEG, $1f
80 movw $RAM_DATA_SEG, %ax
84 xor %ax, %ax /* zero out the gs and fs segment index */
86 movw %ax, %gs /* Will be used for cpu_info */
88 /* Load the Interrupt descriptor table */
93 /* Obtain CPU number. */
96 lock cmpxchg %ecx, ap_count
99 /* Setup stacks for each CPU. */
100 movl stack_size, %eax
106 /* Save CPU number for calling the AP entry */
110 * The following code only needs to run on Intel platforms and thus the caller
111 * doesn't provide a microcode_ptr if not on Intel.
112 * On Intel platforms which update microcode using FIT the version check will
113 * also skip the microcode update.
116 /* Determine if one should check microcode versions. */
117 mov microcode_ptr, %edi
119 jz microcode_done /* Bypass if no microde exists. */
121 /* Get the Microcode version. */
124 movl $IA32_BIOS_SIGN_ID, %ecx
128 mov $IA32_BIOS_SIGN_ID, %ecx
130 /* If something already loaded skip loading again. */
135 * Intel SDM and various BWGs specify to use a semaphore to update microcode
136 * on one thread per core on Hyper-Threading enabled CPUs. Due to this complex
137 * code would be necessary to determine the core #ID, initializing and picking
138 * the right semaphore out of CONFIG_MAX_CPUS / 2.
139 * Instead of the per core approachm, as recommended, use one global spinlock.
140 * Assuming that only pre-FIT platforms with Hyper-Threading enabled and at
141 * most 8 threads will ever run into this condition, the boot delay is negligible.
144 /* Determine if parallel microcode loading is allowed. */
145 cmpl $0xffffffff, microcode_lock
148 /* Protect microcode loading. */
150 lock btsl $0, microcode_lock
154 /* Load new microcode. */
155 mov $IA32_BIOS_UPDT_TRIG, %ecx
158 /* The microcode pointer is passed in pointing to the header. Adjust
159 * pointer to reflect the payload (header size is 48 bytes). */
165 /* Unconditionally unlock microcode loading. */
166 cmpl $0xffffffff, microcode_lock
170 mov %eax, microcode_lock
174 * Load MSRs. Each entry in the table consists of:
179 mov msr_table_ptr, %edi
184 #if CONFIG(X86_AMD_FIXED_MTRRS)
185 /* Allow modification of RdDram and WrDram bits */
186 mov $SYSCFG_MSR, %ecx
188 or $SYSCFG_MSR_MtrrFixDramModEn, %eax
201 #if CONFIG(X86_AMD_FIXED_MTRRS)
202 mov $SYSCFG_MSR, %ecx
204 and $~SYSCFG_MSR_MtrrFixDramModEn, %eax
209 /* Enable caching. */
211 and $~(CR0_CLEAR_FLAGS_CACHE_ENABLE), %eax
215 /* Enable sse instructions. */
217 orl $(CR4_OSFXSR | CR4_OSXMMEXCPT), %eax
221 pop %edi /* Retrieve cpu index */
222 andl $0xfffffff0, %esp /* ensure stack alignment */
225 /* entry64.inc preserves ebx, esi, edi, ebp */
226 #include <cpu/x86/64bit/entry64.inc>
227 movabs c_handler, %eax