1 /* SPDX-License-Identifier: GPL-2.0 */
3 * Copyright (c) 2015 Google, Inc
5 * Taken from coreboot file of the same name
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
14 #include <asm/global_data.h>
15 #include <asm/msr-index.h>
16 #include <asm/processor.h>
17 #include <asm/processor-flags.h>
20 #define CODE_SEG (X86_GDT_ENTRY_32BIT_CS * X86_GDT_ENTRY_SIZE)
21 #define DATA_SEG (X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE)
24 * First we have the 16-bit section. Every AP process starts here.
25 * The simple task is to load U-Boot's Global Descriptor Table (GDT) to allow
26 * U-Boot's 32-bit code to become visible, then jump to ap_start.
28 * Note that this code is copied to RAM below 1MB in mp_init.c, and runs from
29 * there, but the 32-bit code (ap_start and onwards) is part of U-Boot and
30 * is therefore relocated to the top of RAM with other U-Boot code. This
31 * means that for the 16-bit code we must write relocatable code, but for the
32 * rest, we can do what we like.
40 movl %eax, %cr3 /* Invalidate TLB */
42 /* setup the data segment */
46 /* Use an address relative to the data segment for the GDT */
48 subl $ap_start16, %ebx
53 andl $(~(X86_CR0_PG | X86_CR0_AM | X86_CR0_WP | X86_CR0_NE | \
54 X86_CR0_TS | X86_CR0_EM | X86_CR0_MP)), %eax
55 orl $(X86_CR0_NW | X86_CR0_CD | X86_CR0_PE), %eax
58 movl $ap_start_jmp, %eax
59 subl $ap_start16, %eax
62 /* Jump to ap_start within U-Boot */
66 .globl sipi_params_16bit
68 /* 48-bit far pointer */
70 .long 0 /* offset set to ap_start by U-Boot */
71 .word CODE_SEG /* segment */
79 .globl ap_start16_code_end
83 * Set up the special 'fs' segment for global_data. Then jump to ap_continue
95 movw $(X86_GDT_ENTRY_32BIT_FS * X86_GDT_ENTRY_SIZE), %ax
98 /* Load the Interrupt descriptor table */
102 /* Obtain cpu number */
107 lock cmpxchg %ecx, ap_count
110 /* Setup stacks for each CPU */
111 movl stack_size, %eax
116 /* Save cpu number */
119 /* Determine if one should check microcode versions */
120 mov microcode_ptr, %edi
122 jz microcode_done /* Bypass if no microde exists */
124 /* Get the Microcode version */
127 mov $MSR_IA32_UCODE_REV, %ecx
129 /* If something already loaded skip loading again */
133 /* Determine if parallel microcode loading is allowed */
134 cmp $0xffffffff, microcode_lock
137 /* Protect microcode loading */
139 lock bts $0, microcode_lock
143 /* Load new microcode */
144 mov $MSR_IA32_UCODE_WRITE, %ecx
148 * The microcode pointer is passed in pointing to the header. Adjust
149 * pointer to reflect the payload (header size is 48 bytes)
151 add $UCODE_HEADER_LEN, %eax
156 /* Unconditionally unlock microcode loading */
157 cmp $0xffffffff, microcode_lock
161 mov %eax, microcode_lock
165 * Load MSRs. Each entry in the table consists of:
169 * See struct saved_msr in mp_init.c.
171 mov msr_table_ptr, %edi
187 andl $(~(X86_CR0_CD | X86_CR0_NW)), %eax
190 /* c_handler(cpu_num) */
191 movl %esi, %eax /* cpu_num */
195 /* This matches struct sipi_param */