Prepare v2023.10
[platform/kernel/u-boot.git] / arch / x86 / cpu / sipi_vector.S
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 /*
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
11  * C code
12  */
13
14 #include <asm/msr-index.h>
15 #include <asm/processor.h>
16 #include <asm/processor-flags.h>
17 #include <asm/sipi.h>
18
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)
21
22 /*
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.
26  *
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.
32  */
33 .text
34 .code16
35 .globl ap_start16
36 ap_start16:
37         cli
38         xorl    %eax, %eax
39         movl    %eax, %cr3              /* Invalidate TLB */
40
41         /* setup the data segment */
42         movw    %cs, %ax
43         movw    %ax, %ds
44
45         /* Use an address relative to the data segment for the GDT */
46         movl    $gdtaddr, %ebx
47         subl    $ap_start16, %ebx
48
49         data32 lgdt (%ebx)
50
51         movl    %cr0, %eax
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
55         movl    %eax, %cr0
56
57         movl    $ap_start_jmp, %eax
58         subl    $ap_start16, %eax
59         movw    %ax, %bp
60
61         /* Jump to ap_start within U-Boot */
62 data32 cs       ljmp    *(%bp)
63
64         .align  4
65 .globl sipi_params_16bit
66 sipi_params_16bit:
67         /* 48-bit far pointer */
68 ap_start_jmp:
69         .long   0               /* offset set to ap_start by U-Boot */
70         .word   CODE_SEG        /* segment */
71
72         .word   0               /* padding */
73 gdtaddr:
74         .word   0 /* limit */
75         .long   0 /* table */
76         .word   0 /* unused */
77
78 .globl ap_start16_code_end
79 ap_start16_code_end:
80
81 /*
82  * Set up the special 'fs' segment for global_data. Then jump to ap_continue
83  * to set up the AP.
84  */
85 .globl ap_start
86 ap_start:
87         .code32
88         movw    $DATA_SEG, %ax
89         movw    %ax, %ds
90         movw    %ax, %es
91         movw    %ax, %ss
92         movw    %ax, %gs
93
94         movw    $(X86_GDT_ENTRY_32BIT_FS * X86_GDT_ENTRY_SIZE), %ax
95         movw    %ax, %fs
96
97         /* Load the Interrupt descriptor table */
98         mov     idt_ptr, %ebx
99         lidt    (%ebx)
100
101         /* Obtain cpu number */
102         movl    ap_count, %eax
103 1:
104         movl    %eax, %ecx
105         inc     %ecx
106         lock cmpxchg %ecx, ap_count
107         jnz     1b
108
109         /* Setup stacks for each CPU */
110         movl    stack_size, %eax
111         mul     %ecx
112         movl    stack_top, %edx
113         subl    %eax, %edx
114         mov     %edx, %esp
115         /* Save cpu number */
116         mov     %ecx, %esi
117
118         /* Determine if one should check microcode versions */
119         mov     microcode_ptr, %edi
120         test    %edi, %edi
121         jz      microcode_done /* Bypass if no microde exists */
122
123         /* Get the Microcode version */
124         mov     $1, %eax
125         cpuid
126         mov     $MSR_IA32_UCODE_REV, %ecx
127         rdmsr
128         /* If something already loaded skip loading again */
129         test    %edx, %edx
130         jnz     microcode_done
131
132         /* Determine if parallel microcode loading is allowed */
133         cmpl    $0xffffffff, microcode_lock
134         je      load_microcode
135
136         /* Protect microcode loading */
137 lock_microcode:
138         lock btsl $0, microcode_lock
139         jc      lock_microcode
140
141 load_microcode:
142         /* Load new microcode */
143         mov     $MSR_IA32_UCODE_WRITE, %ecx
144         xor     %edx, %edx
145         mov     %edi, %eax
146         /*
147          * The microcode pointer is passed in pointing to the header. Adjust
148          * pointer to reflect the payload (header size is 48 bytes)
149          */
150         add     $UCODE_HEADER_LEN, %eax
151         pusha
152         wrmsr
153         popa
154
155         /* Unconditionally unlock microcode loading */
156         cmpl    $0xffffffff, microcode_lock
157         je      microcode_done
158
159         xor     %eax, %eax
160         mov     %eax, microcode_lock
161
162 microcode_done:
163         /*
164          * Load MSRs. Each entry in the table consists of:
165          * 0: index,
166          * 4: value[31:0]
167          * 8: value[63:32]
168          * See struct saved_msr in mp_init.c.
169          */
170         mov     msr_table_ptr, %edi
171         mov     msr_count, %ebx
172         test    %ebx, %ebx
173         jz      1f
174 load_msr:
175         mov     (%edi), %ecx
176         mov     4(%edi), %eax
177         mov     8(%edi), %edx
178         wrmsr
179         add     $12, %edi
180         dec     %ebx
181         jnz     load_msr
182
183 1:
184         /* Enable caching */
185         mov     %cr0, %eax
186         andl    $(~(X86_CR0_CD | X86_CR0_NW)), %eax
187         mov     %eax, %cr0
188
189         /* c_handler(cpu_num) */
190         movl    %esi, %eax      /* cpu_num */
191         mov     c_handler, %esi
192         call    *%esi
193
194         /* This matches struct sipi_param */
195         .align  4
196 .globl  sipi_params
197 sipi_params:
198 idt_ptr:
199         .long 0
200 stack_top:
201         .long 0
202 stack_size:
203         .long 0
204 microcode_lock:
205         .long 0
206 microcode_ptr:
207         .long 0
208 msr_table_ptr:
209         .long 0
210 msr_count:
211         .long 0
212 c_handler:
213         .long 0
214 ap_count:
215         .long 0