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 #include "hypercall.h"
26 
27 #include <xen/asm/x86-defns.h>
28 #include <xen/hvm/hvm_vcpu.h>
29 
30 #include <xen/vcpu.h>
31 
32 static int ap_callin;
33 
cpu_setup(unsigned int cpu)34 static void __attribute__((regparm(1))) cpu_setup(unsigned int cpu)
35 {
36     printf(" - CPU%d ... ", cpu);
37     cacheattr_init();
38     printf("done.\n");
39 
40     if ( !cpu ) /* Used on the BSP too */
41         return;
42 
43     wmb();
44     ap_callin = 1;
45 
46     /* After this point, the BSP will shut us down. */
47 
48     for ( ;; )
49         asm volatile ( "hlt" );
50 }
51 
boot_cpu(unsigned int cpu)52 static void boot_cpu(unsigned int cpu)
53 {
54     static uint8_t ap_stack[PAGE_SIZE] __attribute__ ((aligned (16)));
55     static struct vcpu_hvm_context ap;
56 
57     /* Initialise shared variables. */
58     ap_callin = 0;
59     wmb();
60 
61     /* Wake up the secondary processor */
62     ap = (struct vcpu_hvm_context) {
63         .mode = VCPU_HVM_MODE_32B,
64         .cpu_regs.x86_32 = {
65             .eip = (unsigned long)cpu_setup,
66             .esp = (unsigned long)ap_stack + ARRAY_SIZE(ap_stack),
67 
68             .eax = cpu,
69 
70             /* Protected Mode, no paging. */
71             .cr0 = X86_CR0_PE,
72 
73             /* 32bit Flat Mode */
74             .cs_limit = -1U,
75             .ds_limit = -1U,
76             .ss_limit = -1U,
77             .es_limit = -1U,
78             .tr_limit = 0x67,
79             .cs_ar = 0xc9b,
80             .ds_ar = 0xc93,
81             .es_ar = 0xc93,
82             .ss_ar = 0xc93,
83             .tr_ar = 0x8b,
84         },
85     };
86 
87     if ( hypercall_vcpu_op(VCPUOP_initialise, cpu, &ap) )
88         BUG();
89     if ( hypercall_vcpu_op(VCPUOP_up, cpu, NULL) )
90         BUG();
91 
92     /*
93      * Wait for the secondary processor to complete initialisation.
94      * Do not touch shared resources meanwhile.
95      */
96     while ( !ap_callin )
97         cpu_relax();
98 
99     /* Take the secondary processor offline. */
100     if ( hypercall_vcpu_op(VCPUOP_down, cpu, NULL) )
101         BUG();
102 }
103 
smp_initialise(void)104 void smp_initialise(void)
105 {
106     unsigned int i, nr_cpus = hvm_info->nr_vcpus;
107 
108     printf("Multiprocessor initialisation:\n");
109     cpu_setup(0);
110     for ( i = 1; i < nr_cpus; i++ )
111         boot_cpu(i);
112 }
113 
114 /*
115  * Local variables:
116  * mode: C
117  * c-file-style: "BSD"
118  * c-basic-offset: 4
119  * tab-width: 4
120  * indent-tabs-mode: nil
121  * End:
122  */
123