]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/spinup_ap.c
Add an option "-a" to present the local apic in the XAPIC mode instead of the
[FreeBSD/FreeBSD.git] / usr.sbin / bhyve / spinup_ap.c
1 /*-
2  * Copyright (c) 2012 NetApp, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/types.h>
34
35 #include <machine/vmm.h>
36 #include <vmmapi.h>
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <assert.h>
41
42 #include "fbsdrun.h"
43 #include "spinup_ap.h"
44
45 /*
46  * Trampoline for hypervisor direct 64-bit jump.
47  *
48  *   0  - signature for guest->host verification
49  *   8  - kernel virtual address of trampoline
50  *  16  - instruction virtual address
51  *  24  - stack pointer virtual address
52  *  32  - CR3, physical address of kernel page table
53  *  40  - 24-byte area for null/code/data GDT entries
54  */
55 #define MP_V64T_SIG     0xcafebabecafebabeULL
56 struct mp_v64tramp {
57         uint64_t        mt_sig;
58         uint64_t        mt_virt;
59         uint64_t        mt_eip;
60         uint64_t        mt_rsp;
61         uint64_t        mt_cr3;
62         uint64_t        mt_gdtr[3];
63 };
64
65 static void
66 spinup_ap_realmode(struct vmctx *ctx, int newcpu, uint64_t *rip)
67 {
68         int vector, error;
69         uint16_t cs;
70         uint64_t desc_base;
71         uint32_t desc_limit, desc_access;
72
73         vector = *rip >> PAGE_SHIFT;
74         *rip = 0;
75
76         /*
77          * Update the %cs and %rip of the guest so that it starts
78          * executing real mode code at at 'vector << 12'.
79          */
80         error = vm_set_register(ctx, newcpu, VM_REG_GUEST_RIP, *rip);
81         assert(error == 0);
82
83         error = vm_get_desc(ctx, newcpu, VM_REG_GUEST_CS, &desc_base,
84                             &desc_limit, &desc_access);
85         assert(error == 0);
86
87         desc_base = vector << PAGE_SHIFT;
88         error = vm_set_desc(ctx, newcpu, VM_REG_GUEST_CS,
89                             desc_base, desc_limit, desc_access);
90         assert(error == 0);
91
92         cs = (vector << PAGE_SHIFT) >> 4;
93         error = vm_set_register(ctx, newcpu, VM_REG_GUEST_CS, cs);
94         assert(error == 0);
95 }
96
97 static void
98 spinup_ap_direct64(struct vmctx *ctx, int newcpu, uint64_t *rip)
99 {
100         struct mp_v64tramp *mvt;
101         char *errstr;
102         int error;
103         uint64_t gdtbase;
104
105         mvt = paddr_guest2host(*rip);
106
107         assert(mvt->mt_sig == MP_V64T_SIG);
108
109         /*
110          * Set up the 3-entry GDT using memory supplied in the
111          * guest's trampoline structure.
112          */
113         vm_setup_freebsd_gdt(mvt->mt_gdtr);
114
115 #define  CHECK_ERROR(msg) \
116         if (error != 0) { \
117                 errstr = msg; \
118                 goto err_exit; \
119         }
120
121         /* entry point */
122         *rip = mvt->mt_eip;
123
124         /* Get the guest virtual address of the GDT */
125         gdtbase = mvt->mt_virt + __offsetof(struct mp_v64tramp, mt_gdtr);
126
127         error = vm_setup_freebsd_registers(ctx, newcpu, mvt->mt_eip,
128                                            mvt->mt_cr3, gdtbase, mvt->mt_rsp);
129         CHECK_ERROR("vm_setup_freebsd_registers");
130
131         return;
132 err_exit:
133         printf("spinup_ap_direct64: machine state error: %s", errstr);
134         exit(1);
135 }
136
137 int
138 spinup_ap(struct vmctx *ctx, int vcpu, int newcpu, uint64_t rip)
139 {
140         int error;
141
142         assert(newcpu != 0);
143         assert(newcpu < guest_ncpus);
144
145         error = vcpu_reset(ctx, newcpu);
146         assert(error == 0);
147
148         /* Set up capabilities */
149         if (fbsdrun_vmexit_on_hlt()) {
150                 error = vm_set_capability(ctx, newcpu, VM_CAP_HALT_EXIT, 1);
151                 assert(error == 0);
152         }
153
154         if (fbsdrun_vmexit_on_pause()) {
155                 error = vm_set_capability(ctx, newcpu, VM_CAP_PAUSE_EXIT, 1);
156                 assert(error == 0);
157         }
158
159         if (fbsdrun_disable_x2apic())
160                 error = vm_set_x2apic_state(ctx, newcpu, X2APIC_DISABLED);
161         else
162                 error = vm_set_x2apic_state(ctx, newcpu, X2APIC_ENABLED);
163         assert(error == 0);
164
165         /*
166          * There are 2 startup modes possible here:
167          *  - if the CPU supports 'unrestricted guest' mode, the spinup can
168          *    set up the processor state in power-on 16-bit mode, with the CS:IP
169          *    init'd to the specified low-mem 4K page.
170          *  - if the guest has requested a 64-bit trampoline in the low-mem 4K
171          *    page by placing in the specified signature, set up the register
172          *    state using register state in the signature. Note that this
173          *    requires accessing guest physical memory to read the signature
174          *    while 'unrestricted mode' does not.
175          */
176         error = vm_set_capability(ctx, newcpu, VM_CAP_UNRESTRICTED_GUEST, 1);
177         if (error) {
178                 spinup_ap_direct64(ctx, newcpu, &rip);
179         } else {
180                 spinup_ap_realmode(ctx, newcpu, &rip);
181         }
182
183         fbsdrun_addcpu(ctx, newcpu, rip);
184
185         return (newcpu);
186 }