blob: 985b9da08029486b6bfd5dc8e7ab88de11ec79e0 [file] [log] [blame]
Aaron Durbine0785c02013-10-21 12:15:29 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Aaron Durbine0785c02013-10-21 12:15:29 -050015 */
16
17/* The SIPI vector is responsible for initializing the APs in the sytem. It
18 * loads microcode, sets up MSRs, and enables caching before calling into
19 * C code. */
20
21/* These segment selectors need to match the gdt entries in c_start.S. */
22#define CODE_SEG 0x10
23#define DATA_SEG 0x18
24
25#define IA32_UPDT_TRIG 0x79
26#define IA32_BIOS_SIGN_ID 0x8b
27
28.section ".module_parameters", "aw", @progbits
29ap_start_params:
30gdtaddr:
31.word 0 /* limit */
32.long 0 /* table */
33.word 0 /* unused */
34idt_ptr:
35.long 0
36stack_top:
37.long 0
38stack_size:
39.long 0
40microcode_lock:
41.long 0
42microcode_ptr:
43.long 0
44msr_table_ptr:
45.long 0
46msr_count:
47.long 0
48c_handler:
49.long 0
50ap_count:
51.long 0
52
53.text
54.code16
Aaron Durbindde76292015-09-05 12:59:26 -050055.global _start
56_start:
Aaron Durbine0785c02013-10-21 12:15:29 -050057 cli
58 xorl %eax, %eax
59 movl %eax, %cr3 /* Invalidate TLB*/
60
61 /* On hyper threaded cpus, invalidating the cache here is
62 * very very bad. Don't.
63 */
64
65 /* setup the data segment */
66 movw %cs, %ax
67 movw %ax, %ds
68
69 /* The gdtaddr needs to be releative to the data segment in order
70 * to properly dereference it. The .text section comes first in an
Aaron Durbindde76292015-09-05 12:59:26 -050071 * rmodule so _start can be used as a proxy for the load address. */
Aaron Durbine0785c02013-10-21 12:15:29 -050072 movl $(gdtaddr), %ebx
Aaron Durbindde76292015-09-05 12:59:26 -050073 sub $(_start), %ebx
Aaron Durbine0785c02013-10-21 12:15:29 -050074
75 data32 lgdt (%ebx)
76
77 movl %cr0, %eax
78 andl $0x7FFAFFD1, %eax /* PG,AM,WP,NE,TS,EM,MP = 0 */
79 orl $0x60000001, %eax /* CD, NW, PE = 1 */
80 movl %eax, %cr0
81
82 ljmpl $CODE_SEG, $1f
831:
84 .code32
85 movw $DATA_SEG, %ax
86 movw %ax, %ds
87 movw %ax, %es
88 movw %ax, %ss
89 movw %ax, %fs
90 movw %ax, %gs
91
92 /* Load the Interrupt descriptor table */
93 mov idt_ptr, %ebx
94 lidt (%ebx)
95
96 /* Obtain cpu number. */
97 movl ap_count, %eax
981:
99 movl %eax, %ecx
100 inc %ecx
101 lock cmpxchg %ecx, ap_count
102 jnz 1b
103
104 /* Setup stacks for each CPU. */
105 movl stack_size, %eax
106 mul %ecx
107 movl stack_top, %edx
108 subl %eax, %edx
109 mov %edx, %esp
110 /* Save cpu number. */
111 mov %ecx, %esi
112
113 /* Determine if one should check microcode versions. */
114 mov microcode_ptr, %edi
115 test %edi, %edi
116 jz microcode_done /* Bypass if no microde exists. */
117
118 /* Get the Microcode version. */
119 mov $1, %eax
120 cpuid
121 mov $IA32_BIOS_SIGN_ID, %ecx
122 rdmsr
123 /* If something already loaded skip loading again. */
124 test %edx, %edx
125 jnz microcode_done
126
127 /* Determine if parallel microcode loading is allowed. */
128 cmp $0xffffffff, microcode_lock
129 je load_microcode
130
131 /* Protect microcode loading. */
132lock_microcode:
133 lock bts $0, microcode_lock
134 jc lock_microcode
135
136load_microcode:
137 /* Load new microcode. */
138 mov $IA32_UPDT_TRIG, %ecx
139 xor %edx, %edx
140 mov %edi, %eax
141 /* The microcode pointer is passed in pointing to the header. Adjust
142 * pointer to reflect the payload (header size is 48 bytes). */
143 add $48, %eax
144 pusha
145 wrmsr
146 popa
147
148 /* Unconditionally unlock microcode loading. */
149 cmp $0xffffffff, microcode_lock
150 je microcode_done
151
152 xor %eax, %eax
153 mov %eax, microcode_lock
154
155microcode_done:
156 /*
157 * Load MSRs. Each entry in the table consists of:
158 * 0: index,
159 * 4: value[31:0]
160 * 8: value[63:32]
161 */
162 mov msr_table_ptr, %edi
163 mov msr_count, %ebx
164 test %ebx, %ebx
165 jz 1f
166load_msr:
167 mov (%edi), %ecx
168 mov 4(%edi), %eax
169 mov 8(%edi), %edx
170 wrmsr
171 add $12, %edi
172 dec %ebx
173 jnz load_msr
174
1751:
176 /* Enable caching. */
177 mov %cr0, %eax
178 and $0x9fffffff, %eax /* CD, NW = 0 */
179 mov %eax, %cr0
180
181 /* c_handler(cpu_num) */
182 push %esi /* cpu_num */
183 mov c_handler, %eax
184 call *%eax
185halt_jump:
186 hlt
187 jmp halt_jump