coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
lapic_cpu_init.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <cpu/x86/cr.h>
4 #include <cpu/x86/gdt.h>
5 #include <cpu/x86/lapic.h>
7 #include <acpi/acpi.h>
8 #include <delay.h>
9 #include <lib.h>
10 #include <string.h>
11 #include <symbols.h>
12 #include <console/console.h>
13 #include <device/device.h>
14 #include <device/path.h>
15 #include <smp/atomic.h>
16 #include <smp/spinlock.h>
17 #include <cpu/cpu.h>
18 #include <cpu/intel/speedstep.h>
19 #include <smp/node.h>
20 #include <stdlib.h>
21 #include <thread.h>
22 
23 /* This is a lot more paranoid now, since Linux can NOT handle
24  * being told there is a CPU when none exists. So any errors
25  * will return 0, meaning no CPU.
26  *
27  * We actually handling that case by noting which cpus startup
28  * and not telling anyone about the ones that don't.
29  */
30 
31 /* Start-UP IPI vector must be 4kB aligned and below 1MB. */
32 #define AP_SIPI_VECTOR 0x1000
33 
34 static char *lowmem_backup;
35 static char *lowmem_backup_ptr;
36 static int lowmem_backup_size;
37 
38 static inline void setup_secondary_gdt(void)
39 {
40  u16 *gdt_limit;
41 #if ENV_X86_64
42  u64 *gdt_base;
43 #else
44  u32 *gdt_base;
45 #endif
46 
47  gdt_limit = (void *)&_secondary_gdt_addr;
48  gdt_base = (void *)&gdt_limit[1];
49 
50  *gdt_limit = (uintptr_t)&gdt_end - (uintptr_t)&gdt - 1;
51  *gdt_base = (uintptr_t)&gdt;
52 }
53 
55 {
56  unsigned long code_size;
57 
58  /* Fill in secondary_start's local gdt. */
60 
61  code_size = (unsigned long)_secondary_start_end
62  - (unsigned long)_secondary_start;
63 
64  if (acpi_is_wakeup_s3()) {
65  /* need to save it for RAM resume */
66  lowmem_backup_size = code_size;
67  lowmem_backup = malloc(code_size);
69 
70  if (lowmem_backup == NULL)
71  die("Out of backup memory\n");
72 
74  }
75 
76  /* copy the _secondary_start to the RAM below 1M*/
77  memcpy((unsigned char *)AP_SIPI_VECTOR,
78  (unsigned char *)_secondary_start, code_size);
79 
80  printk(BIOS_DEBUG, "start_eip=0x%08lx, code_size=0x%08lx\n",
81  (unsigned long int)AP_SIPI_VECTOR, code_size);
82 }
83 
84 static void recover_lowest_1M(void)
85 {
86  if (acpi_is_wakeup_s3())
88 }
89 
90 static uint32_t wait_for_ipi_completion(const int timeout_ms)
91 {
92  int loops = timeout_ms * 10;
93  uint32_t send_status;
94 
95  /* wait for the ipi send to finish */
96  printk(BIOS_SPEW, "Waiting for send to finish...\n");
97  do {
98  printk(BIOS_SPEW, "+");
99  udelay(100);
100  send_status = lapic_busy();
101  } while (send_status && (--loops > 0));
102 
103  return send_status;
104 }
105 
106 static int lapic_start_cpu(unsigned long apicid)
107 {
108  const int timeout_100ms = 100;
109  uint32_t send_status, accept_status;
110  int j, maxlvt;
111 
112  /*
113  * Starting actual IPI sequence...
114  */
115 
116  printk(BIOS_SPEW, "Asserting INIT.\n");
117 
118  /*
119  * Turn INIT on target chip
120  */
122 
123  send_status = wait_for_ipi_completion(timeout_100ms);
124  if (send_status) {
125  printk(BIOS_ERR, "CPU %ld: First APIC write timed out. "
126  "Disabling\n", apicid);
127  // too bad.
128  printk(BIOS_ERR, "ESR is 0x%x\n", lapic_read(LAPIC_ESR));
129  if (lapic_read(LAPIC_ESR)) {
130  printk(BIOS_ERR, "Try to reset ESR\n");
132  printk(BIOS_ERR, "ESR is 0x%x\n",
134  }
135  return 0;
136  }
137  mdelay(10);
138 
139  printk(BIOS_SPEW, "Deasserting INIT.\n");
140 
142 
143  send_status = wait_for_ipi_completion(timeout_100ms);
144  if (send_status) {
145  printk(BIOS_ERR, "CPU %ld: Second APIC write timed out. "
146  "Disabling\n", apicid);
147  // too bad.
148  return 0;
149  }
150 
151  /*
152  * Run STARTUP IPI loop.
153  */
154  printk(BIOS_SPEW, "#startup loops: %d.\n", CONFIG_NUM_IPI_STARTS);
155 
156  maxlvt = 4;
157 
158  for (j = 1; j <= CONFIG_NUM_IPI_STARTS; j++) {
159  printk(BIOS_SPEW, "Sending STARTUP #%d to %lu.\n", j, apicid);
163  printk(BIOS_SPEW, "After apic_write.\n");
164 
165  /*
166  * STARTUP IPI
167  */
168 
170 
171  /*
172  * Give the other CPU some time to accept the IPI.
173  */
174  udelay(300);
175 
176  printk(BIOS_SPEW, "Startup point 1.\n");
177 
178  send_status = wait_for_ipi_completion(timeout_100ms);
179 
180  /*
181  * Give the other CPU some time to accept the IPI.
182  */
183  udelay(200);
184  /*
185  * Due to the Pentium erratum 3AP.
186  */
187  if (maxlvt > 3) {
190  }
191  accept_status = (lapic_read(LAPIC_ESR) & 0xEF);
192  if (send_status || accept_status)
193  break;
194  }
195  printk(BIOS_SPEW, "After Startup.\n");
196  if (send_status)
197  printk(BIOS_WARNING, "APIC never delivered???\n");
198  if (accept_status)
199  printk(BIOS_WARNING, "APIC delivery error (%x).\n",
200  accept_status);
201  if (send_status || accept_status)
202  return 0;
203  return 1;
204 }
205 
206 /* Number of cpus that are currently running in coreboot */
208 
209 /* start_cpu_lock covers last_cpu_index and secondary_stack.
210  * Only starting one CPU at a time let's me remove the logic
211  * for select the stack from assembly language.
212  *
213  * In addition communicating by variables to the CPU I
214  * am starting allows me to verify it has started before
215  * start_cpu returns.
216  */
217 
218 DECLARE_SPIN_LOCK(start_cpu_lock);
219 static unsigned int last_cpu_index = 0;
220 static void *stacks[CONFIG_MAX_CPUS];
221 volatile unsigned long secondary_stack;
222 volatile unsigned int secondary_cpu_index;
223 
224 static int start_cpu(struct device *cpu)
225 {
226  struct cpu_info *info;
228  uintptr_t stack_base;
229  unsigned long apicid;
230  unsigned int index;
231  unsigned long count;
232  int result;
233 
234  spin_lock(&start_cpu_lock);
235 
236  /* Get the CPU's apicid */
237  apicid = cpu->path.apic.apic_id;
238 
239  /* Get an index for the new processor */
240  index = ++last_cpu_index;
241 
242  /* Find boundaries of the new processor's stack */
243  stack_top = ALIGN_DOWN((uintptr_t)_estack, CONFIG_STACK_SIZE);
244  stack_top -= (CONFIG_STACK_SIZE*index);
245  stack_base = stack_top - CONFIG_STACK_SIZE;
246  stack_top -= sizeof(struct cpu_info);
247  printk(BIOS_SPEW, "CPU%d: stack_base %p, stack_top %p\n", index,
248  (void *)stack_base, (void *)stack_top);
249  stacks[index] = (void *)stack_base;
250 
251  /* Record the index and which CPU structure we are using */
252  info = (struct cpu_info *)stack_top;
253  info->index = index;
254  info->cpu = cpu;
255  cpu_add_map_entry(info->index);
256 
257  /* Advertise the new stack and index to start_cpu */
260 
261  /* Until the CPU starts up report the CPU is not enabled */
262  cpu->enabled = 0;
263  cpu->initialized = 0;
264 
265  /* Start the CPU */
266  result = lapic_start_cpu(apicid);
267 
268  if (result) {
269  result = 0;
270  /* Wait 1s or until the new CPU calls in */
271  for (count = 0; count < 100000; count++) {
272  if (secondary_stack == 0) {
273  result = 1;
274  break;
275  }
276  udelay(10);
277  }
278  }
279  secondary_stack = 0;
280  spin_unlock(&start_cpu_lock);
281  return result;
282 }
283 
284 /* C entry point of secondary cpus */
286 {
288 
289  spin_lock(&start_cpu_lock);
290 
291 #ifdef __SSE3__
292  /*
293  * Seems that CR4 was cleared when AP start via lapic_start_cpu()
294  * Turn on CR4.OSFXSR and CR4.OSXMMEXCPT when SSE options enabled
295  */
296  CRx_TYPE cr4_val;
297  cr4_val = read_cr4();
298  cr4_val |= (CR4_OSFXSR | CR4_OSXMMEXCPT);
299  write_cr4(cr4_val);
300 #endif
301 
302  /* Ensure the local APIC is enabled */
303  enable_lapic();
305 
307 
308  spin_unlock(&start_cpu_lock);
309 
311 
312  stop_this_cpu();
313 }
314 
315 static void start_other_cpus(struct bus *cpu_bus, struct device *bsp_cpu)
316 {
317  struct device *cpu;
318  /* Loop through the cpus once getting them started */
319 
320  for (cpu = cpu_bus->children; cpu; cpu = cpu->sibling) {
321  if (cpu->path.type != DEVICE_PATH_APIC)
322  continue;
323 
324  if (!cpu->enabled)
325  continue;
326 
327  if (cpu->initialized)
328  continue;
329 
330  if (!start_cpu(cpu))
331  /* Record the error in cpu? */
332  printk(BIOS_ERR, "CPU 0x%02x would not start!\n",
333  cpu->path.apic.apic_id);
334 
335  udelay(10);
336  }
337 
338 }
339 
340 static void wait_other_cpus_stop(struct bus *cpu_bus)
341 {
342  struct device *cpu;
343  int old_active_count, active_count;
344  long loopcount = 0;
345  int i;
346 
347  /* Now loop until the other cpus have finished initializing */
348  old_active_count = 1;
349  active_count = atomic_read(&active_cpus);
350  while (active_count > 1) {
351  if (active_count != old_active_count) {
352  printk(BIOS_INFO, "Waiting for %d CPUS to stop\n",
353  active_count - 1);
354  old_active_count = active_count;
355  }
356  udelay(10);
357  active_count = atomic_read(&active_cpus);
358  loopcount++;
359  }
360  for (cpu = cpu_bus->children; cpu; cpu = cpu->sibling) {
361  if (cpu->path.type != DEVICE_PATH_APIC)
362  continue;
364  continue;
365  if (!cpu->initialized)
366  printk(BIOS_ERR, "CPU 0x%02x did not initialize!\n",
367  cpu->path.apic.apic_id);
368  }
369  printk(BIOS_DEBUG, "All AP CPUs stopped (%ld loops)\n", loopcount);
370  checkstack(_estack, 0);
371  for (i = 1; i < CONFIG_MAX_CPUS && i <= last_cpu_index; i++)
372  checkstack((void *)stacks[i] + CONFIG_STACK_SIZE, i);
373 }
374 
375 void initialize_cpus(struct bus *cpu_bus)
376 {
377  struct device_path cpu_path;
378  struct cpu_info *info;
379 
380  /* Find the info struct for this CPU */
381  info = cpu_info();
382 
383  /* Ensure the local APIC is enabled */
384  if (is_smp_boot()) {
385  enable_lapic();
387  } else {
388  disable_lapic();
389  }
390 
391  /* Get the device path of the boot CPU */
392  cpu_path.type = DEVICE_PATH_APIC;
393  cpu_path.apic.apic_id = lapicid();
394 
395  /* Find the device structure for the boot CPU */
396  info->cpu = alloc_find_dev(cpu_bus, &cpu_path);
397  cpu_add_map_entry(info->index);
398 
399  // why here? In case some day we can start core1 in amd_sibling_init
400  if (is_smp_boot())
402 
403  if (CONFIG(SMM_LEGACY_ASEG))
404  smm_init();
405 
406  /* Initialize the bootstrap processor */
407  cpu_initialize(0);
408 
409  if (is_smp_boot())
410  start_other_cpus(cpu_bus, info->cpu);
411 
412  /* Now wait the rest of the cpus stop*/
413  if (is_smp_boot())
414  wait_other_cpus_stop(cpu_bus);
415 
416  if (CONFIG(SMM_LEGACY_ASEG))
418 
419  if (is_smp_boot())
421 }
static int acpi_is_wakeup_s3(void)
Definition: acpi.h:9
#define asmlinkage
Definition: cpu.h:8
#define atomic_read(v)
Definition: atomic.h:14
void cpu_initialize(unsigned int index)
Definition: cpu.c:231
void cpu_add_map_entry(unsigned int index)
Definition: cpu.c:217
static struct cpu_info * cpu_info(void)
Definition: cpu.h:252
#define ATOMIC_INIT(i)
Definition: atomic.h:13
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
#define ALIGN_DOWN(x, a)
Definition: helpers.h:18
#define printk(level,...)
Definition: stdlib.h:16
void __noreturn die(const char *fmt,...)
Definition: die.c:17
#define SPEEDSTEP_APIC_MAGIC
Definition: chip.h:4
#define CR4_OSXMMEXCPT
Definition: cr.h:124
static __always_inline void write_cr4(CRx_TYPE data)
Definition: cr.h:88
static __always_inline CRx_TYPE read_cr4(void)
Definition: cr.h:76
#define CRx_TYPE
Definition: cr.h:17
#define CR4_OSFXSR
Definition: cr.h:123
void mdelay(unsigned int msecs)
Definition: delay.c:2
struct device * alloc_find_dev(struct bus *parent, struct device_path *path)
See if a device structure already exists and if not allocate it.
Definition: device.c:138
static struct smmstore_params_info info
Definition: ramstage.c:12
@ CONFIG
Definition: dsi_common.h:201
char gdt[]
char _secondary_gdt_addr[]
char _secondary_start[]
char gdt_end[]
char _secondary_start_end[]
#define atomic_dec(v)
atomic_dec - decrement atomic variable
Definition: atomic.h:50
#define atomic_inc(v)
atomic_inc - increment atomic variable
Definition: atomic.h:41
#define spin_lock(lock)
Definition: spinlock.h:11
#define spin_unlock(lock)
Definition: spinlock.h:12
void * malloc(size_t size)
Definition: malloc.c:53
void setup_lapic_interrupts(void)
Definition: lapic.c:68
void enable_lapic(void)
Definition: lapic.c:12
void disable_lapic(void)
Definition: lapic.c:55
static __always_inline unsigned int lapicid(void)
Definition: lapic.h:136
static __always_inline int lapic_busy(void)
Definition: lapic.h:118
static __always_inline void lapic_write(unsigned int reg, uint32_t v)
Definition: lapic.h:83
static __always_inline uint32_t lapic_read(unsigned int reg)
Definition: lapic.h:75
static __always_inline void lapic_send_ipi(uint32_t icrlow, uint32_t apicid)
Definition: lapic.h:110
static void copy_secondary_start_to_lowest_1M(void)
void initialize_cpus(struct bus *cpu_bus)
static void * stacks[CONFIG_MAX_CPUS]
static uint32_t wait_for_ipi_completion(const int timeout_ms)
asmlinkage void secondary_cpu_init(unsigned int index)
DECLARE_SPIN_LOCK(start_cpu_lock)
static char * lowmem_backup_ptr
volatile unsigned int secondary_cpu_index
static int lapic_start_cpu(unsigned long apicid)
static void start_other_cpus(struct bus *cpu_bus, struct device *bsp_cpu)
static unsigned int last_cpu_index
static char * lowmem_backup
#define AP_SIPI_VECTOR
static int lowmem_backup_size
static void wait_other_cpus_stop(struct bus *cpu_bus)
static void recover_lowest_1M(void)
volatile unsigned long secondary_stack
static atomic_t active_cpus
static void setup_secondary_gdt(void)
static int start_cpu(struct device *cpu)
void stop_this_cpu(void)
Normally this function is defined in lapic.h as an always inline function that just keeps the CPU in ...
#define LAPIC_DM_INIT
Definition: lapic_def.h:48
#define LAPIC_DM_STARTUP
Definition: lapic_def.h:49
#define LAPIC_ESR
Definition: lapic_def.h:23
#define LAPIC_INT_ASSERT
Definition: lapic_def.h:40
#define LAPIC_INT_LEVELTRIG
Definition: lapic_def.h:39
#define LAPIC_SPIV
Definition: lapic_def.h:21
int checkstack(void *top_of_stack, int core)
Definition: stack.c:30
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
#define BIOS_SPEW
BIOS_SPEW - Excessively verbose output.
Definition: loglevel.h:142
#define BIOS_WARNING
BIOS_WARNING - Bad configuration.
Definition: loglevel.h:86
result
Definition: mrc_cache.c:35
static int is_smp_boot(void)
Definition: node.h:10
@ DEVICE_PATH_APIC
Definition: path.h:12
void smm_init(void)
Definition: smm_init.c:12
void smm_init_completion(void)
Definition: smm_init.c:59
static uintptr_t stack_top
#define NULL
Definition: stddef.h:19
uint64_t u64
Definition: stdint.h:54
unsigned int uint32_t
Definition: stdint.h:14
uint32_t u32
Definition: stdint.h:51
unsigned long uintptr_t
Definition: stdint.h:21
uint16_t u16
Definition: stdint.h:48
unsigned int apic_id
Definition: path.h:72
Definition: atomic.h:8
Definition: device.h:76
DEVTREE_CONST struct device * children
Definition: device.h:79
Definition: cpu.h:230
struct device * cpu
Definition: cpu.h:231
size_t index
Definition: cpu.h:232
Definition: path.h:87
struct apic_path apic
Definition: path.h:119
enum device_path_type type
Definition: path.h:114
Definition: device.h:107
DEVTREE_CONST struct device * sibling
Definition: device.h:111
unsigned int initialized
Definition: device.h:123
struct device_path path
Definition: device.h:115
unsigned int enabled
Definition: device.h:122
void udelay(uint32_t us)
Definition: udelay.c:15
#define count