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/msr-index.h>
15 #include <asm/processor.h>
16 #include <asm/processor-flags.h>
19 #define CODE_SEG (X86_GDT_ENTRY_32BIT_CS * X86_GDT_ENTRY_SIZE)
20 #define DATA_SEG (X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE)
23 * First we have the 16-bit section. Every AP process starts here.
24 * The simple task is to load U-Boot's Global Descriptor Table (GDT) to allow
25 * U-Boot's 32-bit code to become visible, then jump to ap_start.
27 * Note that this code is copied to RAM below 1MB in mp_init.c, and runs from
28 * there, but the 32-bit code (ap_start and onwards) is part of U-Boot and
29 * is therefore relocated to the top of RAM with other U-Boot code. This
30 * means that for the 16-bit code we must write relocatable code, but for the
31 * rest, we can do what we like.
39 movl %eax, %cr3 /* Invalidate TLB */
41 /* setup the data segment */
45 /* Use an address relative to the data segment for the GDT */
47 subl $ap_start16, %ebx
52 andl $(~(X86_CR0_PG | X86_CR0_AM | X86_CR0_WP | X86_CR0_NE | \
53 X86_CR0_TS | X86_CR0_EM | X86_CR0_MP)), %eax
54 orl $(X86_CR0_NW | X86_CR0_CD | X86_CR0_PE), %eax
57 movl $ap_start_jmp, %eax
58 subl $ap_start16, %eax
61 /* Jump to ap_start within U-Boot */
65 .globl sipi_params_16bit
67 /* 48-bit far pointer */
69 .long 0 /* offset set to ap_start by U-Boot */
70 .word CODE_SEG /* segment */
78 .globl ap_start16_code_end
82 * Set up the special 'fs' segment for global_data. Then jump to ap_continue
94 movw $(X86_GDT_ENTRY_32BIT_FS * X86_GDT_ENTRY_SIZE), %ax
97 /* Load the Interrupt descriptor table */
101 /* Obtain cpu number */
106 lock cmpxchg %ecx, ap_count
109 /* Setup stacks for each CPU */
110 movl stack_size, %eax
115 /* Save cpu number */
118 /* Determine if one should check microcode versions */
119 mov microcode_ptr, %edi
121 jz microcode_done /* Bypass if no microde exists */
123 /* Get the Microcode version */
126 mov $MSR_IA32_UCODE_REV, %ecx
128 /* If something already loaded skip loading again */
132 /* Determine if parallel microcode loading is allowed */
133 cmpl $0xffffffff, microcode_lock
136 /* Protect microcode loading */
138 lock btsl $0, microcode_lock
142 /* Load new microcode */
143 mov $MSR_IA32_UCODE_WRITE, %ecx
147 * The microcode pointer is passed in pointing to the header. Adjust
148 * pointer to reflect the payload (header size is 48 bytes)
150 add $UCODE_HEADER_LEN, %eax
155 /* Unconditionally unlock microcode loading */
156 cmpl $0xffffffff, microcode_lock
160 mov %eax, microcode_lock
164 * Load MSRs. Each entry in the table consists of:
168 * See struct saved_msr in mp_init.c.
170 mov msr_table_ptr, %edi
186 andl $(~(X86_CR0_CD | X86_CR0_NW)), %eax
189 /* c_handler(cpu_num) */
190 movl %esi, %eax /* cpu_num */
194 /* This matches struct sipi_param */