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