2 * Copyright (c) 2015 Google, Inc
4 * SPDX-License-Identifier: GPL-2.0
6 * Taken from coreboot file of the same name
10 * The SIPI vector is responsible for initializing the APs in the sytem. It
11 * loads microcode, sets up MSRs, and enables caching before calling into
15 #include <asm/global_data.h>
16 #include <asm/msr-index.h>
17 #include <asm/processor.h>
18 #include <asm/processor-flags.h>
21 #define CODE_SEG (X86_GDT_ENTRY_32BIT_CS * X86_GDT_ENTRY_SIZE)
22 #define DATA_SEG (X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE)
25 * First we have the 16-bit section. Every AP process starts here.
26 * The simple task is to load U-Boot's Global Descriptor Table (GDT) to allow
27 * U-Boot's 32-bit code to become visible, then jump to ap_start.
29 * Note that this code is copied to RAM below 1MB in mp_init.c, and runs from
30 * there, but the 32-bit code (ap_start and onwards) is part of U-Boot and
31 * is therefore relocated to the top of RAM with other U-Boot code. This
32 * means that for the 16-bit code we must write relocatable code, but for the
33 * rest, we can do what we like.
41 movl %eax, %cr3 /* Invalidate TLB */
43 /* setup the data segment */
47 /* Use an address relative to the data segment for the GDT */
49 subl $ap_start16, %ebx
54 andl $(~(X86_CR0_PG | X86_CR0_AM | X86_CR0_WP | X86_CR0_NE | \
55 X86_CR0_TS | X86_CR0_EM | X86_CR0_MP)), %eax
56 orl $(X86_CR0_NW | X86_CR0_CD | X86_CR0_PE), %eax
59 movl $ap_start_jmp, %eax
60 subl $ap_start16, %eax
63 /* Jump to ap_start within U-Boot */
67 .globl sipi_params_16bit
69 /* 48-bit far pointer */
71 .long 0 /* offset set to ap_start by U-Boot */
72 .word CODE_SEG /* segment */
80 .globl ap_start16_code_end
84 * Set up the special 'fs' segment for global_data. Then jump to ap_continue
96 movw $(X86_GDT_ENTRY_32BIT_FS * X86_GDT_ENTRY_SIZE), %ax
99 /* Load the Interrupt descriptor table */
103 /* Obtain cpu number */
108 lock cmpxchg %ecx, ap_count
111 /* Setup stacks for each CPU */
112 movl stack_size, %eax
117 /* Save cpu number */
120 /* Determine if one should check microcode versions */
121 mov microcode_ptr, %edi
123 jz microcode_done /* Bypass if no microde exists */
125 /* Get the Microcode version */
128 mov $MSR_IA32_UCODE_REV, %ecx
130 /* If something already loaded skip loading again */
134 /* Determine if parallel microcode loading is allowed */
135 cmp $0xffffffff, microcode_lock
138 /* Protect microcode loading */
140 lock bts $0, microcode_lock
144 /* Load new microcode */
145 mov $MSR_IA32_UCODE_WRITE, %ecx
149 * The microcode pointer is passed in pointing to the header. Adjust
150 * pointer to reflect the payload (header size is 48 bytes)
152 add $UCODE_HEADER_LEN, %eax
157 /* Unconditionally unlock microcode loading */
158 cmp $0xffffffff, microcode_lock
162 mov %eax, microcode_lock
166 * Load MSRs. Each entry in the table consists of:
170 * See struct saved_msr in mp_init.c.
172 mov msr_table_ptr, %edi
188 andl $(~(X86_CR0_CD | X86_CR0_NW)), %eax
191 /* c_handler(cpu_num) */
192 movl %esi, %eax /* cpu_num */