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