]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - lib/libvmmapi/vmmapi_freebsd.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / lib / libvmmapi / vmmapi_freebsd.c
1 /*-
2  * Copyright (c) 2011 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/types.h>
33
34 #include <machine/specialreg.h>
35 #include <machine/segments.h>
36 #include <machine/vmm.h>
37
38 #include <errno.h>
39 #include <string.h>
40
41 #include "vmmapi.h"
42
43 #define I386_TSS_SIZE           104
44
45 #define DESC_PRESENT            0x00000080
46 #define DESC_LONGMODE           0x00002000
47 #define DESC_DEF32              0x00004000
48 #define DESC_GRAN               0x00008000
49 #define DESC_UNUSABLE           0x00010000
50
51 #define GUEST_NULL_SEL          0
52 #define GUEST_CODE_SEL          1
53 #define GUEST_DATA_SEL          2
54 #define GUEST_TSS_SEL           3
55 #define GUEST_GDTR_LIMIT64      (3 * 8 - 1)
56
57 static struct segment_descriptor i386_gdt[] = {
58         {},                                             /* NULL */
59         { .sd_lolimit = 0xffff, .sd_type = SDT_MEMER,   /* CODE */
60           .sd_p = 1, .sd_hilimit = 0xf, .sd_def32 = 1, .sd_gran = 1 }, 
61         { .sd_lolimit = 0xffff, .sd_type = SDT_MEMRW,   /* DATA */
62           .sd_p = 1, .sd_hilimit = 0xf, .sd_def32 = 1, .sd_gran = 1 },
63         { .sd_lolimit = I386_TSS_SIZE - 1,              /* TSS */
64           .sd_type = SDT_SYS386TSS, .sd_p = 1 }
65 };
66
67 /*
68  * Setup the 'vcpu' register set such that it will begin execution at
69  * 'eip' in flat mode.
70  */
71 int
72 vm_setup_freebsd_registers_i386(struct vmctx *vmctx, int vcpu, uint32_t eip,
73                                 uint32_t gdtbase, uint32_t esp)
74 {
75         uint64_t cr0, rflags, desc_base;
76         uint32_t desc_access, desc_limit, tssbase;
77         uint16_t gsel;
78         struct segment_descriptor *gdt;
79         int error, tmp;
80
81         /* A 32-bit guest requires unrestricted mode. */        
82         error = vm_get_capability(vmctx, vcpu, VM_CAP_UNRESTRICTED_GUEST, &tmp);
83         if (error)
84                 goto done;
85         error = vm_set_capability(vmctx, vcpu, VM_CAP_UNRESTRICTED_GUEST, 1);
86         if (error)
87                 goto done;
88
89         cr0 = CR0_PE | CR0_NE;
90         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR0, cr0)) != 0)
91                 goto done;
92
93         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR4, 0)) != 0)
94                 goto done;
95
96         /*
97          * Forcing EFER to 0 causes bhyve to clear the "IA-32e guest
98          * mode" entry control.
99          */
100         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_EFER, 0)))
101                 goto done;
102
103         gdt = vm_map_gpa(vmctx, gdtbase, 0x1000);
104         if (gdt == NULL)
105                 return (EFAULT);
106         memcpy(gdt, i386_gdt, sizeof(i386_gdt));
107         desc_base = gdtbase;
108         desc_limit = sizeof(i386_gdt) - 1;
109         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GDTR,
110                             desc_base, desc_limit, 0);
111         if (error != 0)
112                 goto done;
113
114         /* Place the TSS one page above the GDT. */
115         tssbase = gdtbase + 0x1000;
116         gdt[3].sd_lobase = tssbase;     
117
118         rflags = 0x2;
119         error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RFLAGS, rflags);
120         if (error)
121                 goto done;
122
123         desc_base = 0;
124         desc_limit = 0xffffffff;
125         desc_access = DESC_GRAN | DESC_DEF32 | DESC_PRESENT | SDT_MEMERA;
126         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_CS,
127                             desc_base, desc_limit, desc_access);
128
129         desc_access = DESC_GRAN | DESC_DEF32 | DESC_PRESENT | SDT_MEMRWA;
130         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_DS,
131                             desc_base, desc_limit, desc_access);
132         if (error)
133                 goto done;
134
135         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_ES,
136                             desc_base, desc_limit, desc_access);
137         if (error)
138                 goto done;
139
140         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_FS,
141                             desc_base, desc_limit, desc_access);
142         if (error)
143                 goto done;
144
145         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GS,
146                             desc_base, desc_limit, desc_access);
147         if (error)
148                 goto done;
149
150         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_SS,
151                             desc_base, desc_limit, desc_access);
152         if (error)
153                 goto done;
154
155         desc_base = tssbase;
156         desc_limit = I386_TSS_SIZE - 1;
157         desc_access = DESC_PRESENT | SDT_SYS386BSY;
158         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_TR,
159                             desc_base, desc_limit, desc_access);
160         if (error)
161                 goto done;
162
163         
164         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_LDTR, 0, 0,
165                             DESC_UNUSABLE);
166         if (error)
167                 goto done;
168
169         gsel = GSEL(GUEST_CODE_SEL, SEL_KPL);
170         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CS, gsel)) != 0)
171                 goto done;
172         
173         gsel = GSEL(GUEST_DATA_SEL, SEL_KPL);
174         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_DS, gsel)) != 0)
175                 goto done;
176         
177         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_ES, gsel)) != 0)
178                 goto done;
179
180         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_FS, gsel)) != 0)
181                 goto done;
182         
183         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_GS, gsel)) != 0)
184                 goto done;
185         
186         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_SS, gsel)) != 0)
187                 goto done;
188
189         gsel = GSEL(GUEST_TSS_SEL, SEL_KPL);
190         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_TR, gsel)) != 0)
191                 goto done;
192
193         /* LDTR is pointing to the null selector */
194         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_LDTR, 0)) != 0)
195                 goto done;
196
197         /* entry point */
198         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RIP, eip)) != 0)
199                 goto done;
200
201         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSP, esp)) != 0)
202                 goto done;
203
204         error = 0;
205 done:
206         return (error);
207 }
208
209 void     
210 vm_setup_freebsd_gdt(uint64_t *gdtr)
211 {       
212         gdtr[GUEST_NULL_SEL] = 0;
213         gdtr[GUEST_CODE_SEL] = 0x0020980000000000;
214         gdtr[GUEST_DATA_SEL] = 0x0000900000000000;
215 }
216
217 /*
218  * Setup the 'vcpu' register set such that it will begin execution at
219  * 'rip' in long mode.
220  */
221 int
222 vm_setup_freebsd_registers(struct vmctx *vmctx, int vcpu,
223                            uint64_t rip, uint64_t cr3, uint64_t gdtbase,
224                            uint64_t rsp)
225 {
226         int error;
227         uint64_t cr0, cr4, efer, rflags, desc_base;
228         uint32_t desc_access, desc_limit;
229         uint16_t gsel;
230
231         cr0 = CR0_PE | CR0_PG | CR0_NE;
232         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR0, cr0)) != 0)
233                 goto done;
234
235         cr4 = CR4_PAE;
236         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR4, cr4)) != 0)
237                 goto done;
238
239         efer = EFER_LME | EFER_LMA;
240         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_EFER, efer)))
241                 goto done;
242
243         rflags = 0x2;
244         error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RFLAGS, rflags);
245         if (error)
246                 goto done;
247
248         desc_base = 0;
249         desc_limit = 0;
250         desc_access = 0x0000209B;
251         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_CS,
252                             desc_base, desc_limit, desc_access);
253         if (error)
254                 goto done;
255
256         desc_access = 0x00000093;
257         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_DS,
258                             desc_base, desc_limit, desc_access);
259         if (error)
260                 goto done;
261
262         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_ES,
263                             desc_base, desc_limit, desc_access);
264         if (error)
265                 goto done;
266
267         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_FS,
268                             desc_base, desc_limit, desc_access);
269         if (error)
270                 goto done;
271
272         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GS,
273                             desc_base, desc_limit, desc_access);
274         if (error)
275                 goto done;
276
277         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_SS,
278                             desc_base, desc_limit, desc_access);
279         if (error)
280                 goto done;
281
282         /*
283          * XXX TR is pointing to null selector even though we set the
284          * TSS segment to be usable with a base address and limit of 0.
285          */
286         desc_access = 0x0000008b;
287         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_TR, 0, 0, desc_access);
288         if (error)
289                 goto done;
290
291         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_LDTR, 0, 0,
292                             DESC_UNUSABLE);
293         if (error)
294                 goto done;
295
296         gsel = GSEL(GUEST_CODE_SEL, SEL_KPL);
297         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CS, gsel)) != 0)
298                 goto done;
299         
300         gsel = GSEL(GUEST_DATA_SEL, SEL_KPL);
301         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_DS, gsel)) != 0)
302                 goto done;
303         
304         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_ES, gsel)) != 0)
305                 goto done;
306
307         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_FS, gsel)) != 0)
308                 goto done;
309         
310         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_GS, gsel)) != 0)
311                 goto done;
312         
313         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_SS, gsel)) != 0)
314                 goto done;
315
316         /* XXX TR is pointing to the null selector */
317         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_TR, 0)) != 0)
318                 goto done;
319
320         /* LDTR is pointing to the null selector */
321         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_LDTR, 0)) != 0)
322                 goto done;
323
324         /* entry point */
325         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RIP, rip)) != 0)
326                 goto done;
327
328         /* page table base */
329         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR3, cr3)) != 0)
330                 goto done;
331
332         desc_base = gdtbase;
333         desc_limit = GUEST_GDTR_LIMIT64;
334         error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GDTR,
335                             desc_base, desc_limit, 0);
336         if (error != 0)
337                 goto done;
338
339         if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSP, rsp)) != 0)
340                 goto done;
341
342         error = 0;
343 done:
344         return (error);
345 }