1 /*
2 * smp.c: Secondary processor bringup and initialisation.
3 *
4 * Copyright (c) 2008, Citrix Systems, Inc.
5 *
6 * Authors:
7 * Keir Fraser <keir@xen.org>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms and conditions of the GNU General Public License,
11 * version 2, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program; If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "util.h"
23 #include "config.h"
24 #include "apic_regs.h"
25
26 #define AP_BOOT_EIP 0x1000
27 extern char ap_boot_start[], ap_boot_end[];
28
29 static int ap_callin, ap_cpuid;
30
31 asm (
32 " .text \n"
33 " .code16 \n"
34 "ap_boot_start: .code16 \n"
35 " mov %cs,%ax \n"
36 " mov %ax,%ds \n"
37 " lgdt gdt_desr-ap_boot_start\n"
38 " xor %ax, %ax \n"
39 " inc %ax \n"
40 " lmsw %ax \n"
41 " ljmpl $0x08,$1f \n"
42 "gdt_desr: \n"
43 " .word gdt_end - gdt - 1 \n"
44 " .long gdt \n"
45 "ap_boot_end: .code32 \n"
46 "1: mov $0x10,%eax \n"
47 " mov %eax,%ds \n"
48 " mov %eax,%es \n"
49 " mov %eax,%ss \n"
50 " movl $stack_top,%esp \n"
51 " movl %esp,%ebp \n"
52 " call ap_start \n"
53 "1: hlt \n"
54 " jmp 1b \n"
55 " \n"
56 " .align 8 \n"
57 "gdt: \n"
58 " .quad 0x0000000000000000 \n"
59 " .quad 0x00cf9a000000ffff \n" /* 0x08: Flat code segment */
60 " .quad 0x00cf92000000ffff \n" /* 0x10: Flat data segment */
61 "gdt_end: \n"
62 " \n"
63 " .bss \n"
64 " .align 8 \n"
65 "stack: \n"
66 " .skip 0x4000 \n"
67 "stack_top: \n"
68 " .text \n"
69 );
70
71 void ap_start(void); /* non-static avoids unused-function compiler warning */
ap_start(void)72 /*static*/ void ap_start(void)
73 {
74 printf(" - CPU%d ... ", ap_cpuid);
75 cacheattr_init();
76 printf("done.\n");
77 wmb();
78 ap_callin = 1;
79 }
80
lapic_wait_ready(void)81 static void lapic_wait_ready(void)
82 {
83 while ( lapic_read(APIC_ICR) & APIC_ICR_BUSY )
84 cpu_relax();
85 }
86
boot_cpu(unsigned int cpu)87 static void boot_cpu(unsigned int cpu)
88 {
89 unsigned int icr2 = SET_APIC_DEST_FIELD(LAPIC_ID(cpu));
90
91 /* Initialise shared variables. */
92 ap_cpuid = cpu;
93 ap_callin = 0;
94 wmb();
95
96 /* Wake up the secondary processor: INIT-SIPI-SIPI... */
97 lapic_wait_ready();
98 lapic_write(APIC_ICR2, icr2);
99 lapic_write(APIC_ICR, APIC_DM_INIT);
100 lapic_wait_ready();
101 lapic_write(APIC_ICR2, icr2);
102 lapic_write(APIC_ICR, APIC_DM_STARTUP | (AP_BOOT_EIP >> 12));
103 lapic_wait_ready();
104 lapic_write(APIC_ICR2, icr2);
105 lapic_write(APIC_ICR, APIC_DM_STARTUP | (AP_BOOT_EIP >> 12));
106 lapic_wait_ready();
107
108 /*
109 * Wait for the secondary processor to complete initialisation.
110 * Do not touch shared resources meanwhile.
111 */
112 while ( !ap_callin )
113 cpu_relax();
114
115 /* Take the secondary processor offline. */
116 lapic_write(APIC_ICR2, icr2);
117 lapic_write(APIC_ICR, APIC_DM_INIT);
118 lapic_wait_ready();
119 }
120
smp_initialise(void)121 void smp_initialise(void)
122 {
123 unsigned int i, nr_cpus = hvm_info->nr_vcpus;
124
125 memcpy((void *)AP_BOOT_EIP, ap_boot_start, ap_boot_end - ap_boot_start);
126
127 printf("Multiprocessor initialisation:\n");
128 ap_start();
129 for ( i = 1; i < nr_cpus; i++ )
130 boot_cpu(i);
131 }
132
133 /*
134 * Local variables:
135 * mode: C
136 * c-file-style: "BSD"
137 * c-basic-offset: 4
138 * tab-width: 4
139 * indent-tabs-mode: nil
140 * End:
141 */
142