2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2011 NetApp, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 #include <sys/types.h>
32 #include <machine/specialreg.h>
33 #include <machine/segments.h>
34 #include <machine/vmm.h>
42 #define I386_TSS_SIZE 104
44 #define DESC_PRESENT 0x00000080
45 #define DESC_LONGMODE 0x00002000
46 #define DESC_DEF32 0x00004000
47 #define DESC_GRAN 0x00008000
48 #define DESC_UNUSABLE 0x00010000
50 #define GUEST_NULL_SEL 0
51 #define GUEST_CODE_SEL 1
52 #define GUEST_DATA_SEL 2
53 #define GUEST_TSS_SEL 3
54 #define GUEST_GDTR_LIMIT64 (3 * 8 - 1)
56 static struct segment_descriptor i386_gdt[] = {
58 { .sd_lolimit = 0xffff, .sd_type = SDT_MEMER, /* CODE */
59 .sd_p = 1, .sd_hilimit = 0xf, .sd_def32 = 1, .sd_gran = 1 },
60 { .sd_lolimit = 0xffff, .sd_type = SDT_MEMRW, /* DATA */
61 .sd_p = 1, .sd_hilimit = 0xf, .sd_def32 = 1, .sd_gran = 1 },
62 { .sd_lolimit = I386_TSS_SIZE - 1, /* TSS */
63 .sd_type = SDT_SYS386TSS, .sd_p = 1 }
67 * Setup the 'vcpu' register set such that it will begin execution at
71 vm_setup_freebsd_registers_i386(struct vcpu *vcpu, uint32_t eip,
72 uint32_t gdtbase, uint32_t esp)
74 uint64_t cr0, rflags, desc_base;
75 uint32_t desc_access, desc_limit, tssbase;
77 struct segment_descriptor *gdt;
80 /* A 32-bit guest requires unrestricted mode. */
81 error = vm_get_capability(vcpu, VM_CAP_UNRESTRICTED_GUEST, &tmp);
84 error = vm_set_capability(vcpu, VM_CAP_UNRESTRICTED_GUEST, 1);
88 cr0 = CR0_PE | CR0_NE;
89 if ((error = vm_set_register(vcpu, VM_REG_GUEST_CR0, cr0)) != 0)
92 if ((error = vm_set_register(vcpu, VM_REG_GUEST_CR4, 0)) != 0)
96 * Forcing EFER to 0 causes bhyve to clear the "IA-32e guest
97 * mode" entry control.
99 if ((error = vm_set_register(vcpu, VM_REG_GUEST_EFER, 0)))
102 gdt = vm_map_gpa(vcpu->ctx, gdtbase, 0x1000);
105 memcpy(gdt, i386_gdt, sizeof(i386_gdt));
107 desc_limit = sizeof(i386_gdt) - 1;
108 error = vm_set_desc(vcpu, VM_REG_GUEST_GDTR,
109 desc_base, desc_limit, 0);
113 /* Place the TSS one page above the GDT. */
114 tssbase = gdtbase + 0x1000;
115 gdt[3].sd_lobase = tssbase;
118 error = vm_set_register(vcpu, VM_REG_GUEST_RFLAGS, rflags);
123 desc_limit = 0xffffffff;
124 desc_access = DESC_GRAN | DESC_DEF32 | DESC_PRESENT | SDT_MEMERA;
125 error = vm_set_desc(vcpu, VM_REG_GUEST_CS,
126 desc_base, desc_limit, desc_access);
128 desc_access = DESC_GRAN | DESC_DEF32 | DESC_PRESENT | SDT_MEMRWA;
129 error = vm_set_desc(vcpu, VM_REG_GUEST_DS,
130 desc_base, desc_limit, desc_access);
134 error = vm_set_desc(vcpu, VM_REG_GUEST_ES,
135 desc_base, desc_limit, desc_access);
139 error = vm_set_desc(vcpu, VM_REG_GUEST_FS,
140 desc_base, desc_limit, desc_access);
144 error = vm_set_desc(vcpu, VM_REG_GUEST_GS,
145 desc_base, desc_limit, desc_access);
149 error = vm_set_desc(vcpu, VM_REG_GUEST_SS,
150 desc_base, desc_limit, desc_access);
155 desc_limit = I386_TSS_SIZE - 1;
156 desc_access = DESC_PRESENT | SDT_SYS386BSY;
157 error = vm_set_desc(vcpu, VM_REG_GUEST_TR,
158 desc_base, desc_limit, desc_access);
163 error = vm_set_desc(vcpu, VM_REG_GUEST_LDTR, 0, 0,
168 gsel = GSEL(GUEST_CODE_SEL, SEL_KPL);
169 if ((error = vm_set_register(vcpu, VM_REG_GUEST_CS, gsel)) != 0)
172 gsel = GSEL(GUEST_DATA_SEL, SEL_KPL);
173 if ((error = vm_set_register(vcpu, VM_REG_GUEST_DS, gsel)) != 0)
176 if ((error = vm_set_register(vcpu, VM_REG_GUEST_ES, gsel)) != 0)
179 if ((error = vm_set_register(vcpu, VM_REG_GUEST_FS, gsel)) != 0)
182 if ((error = vm_set_register(vcpu, VM_REG_GUEST_GS, gsel)) != 0)
185 if ((error = vm_set_register(vcpu, VM_REG_GUEST_SS, gsel)) != 0)
188 gsel = GSEL(GUEST_TSS_SEL, SEL_KPL);
189 if ((error = vm_set_register(vcpu, VM_REG_GUEST_TR, gsel)) != 0)
192 /* LDTR is pointing to the null selector */
193 if ((error = vm_set_register(vcpu, VM_REG_GUEST_LDTR, 0)) != 0)
197 if ((error = vm_set_register(vcpu, VM_REG_GUEST_RIP, eip)) != 0)
200 if ((error = vm_set_register(vcpu, VM_REG_GUEST_RSP, esp)) != 0)
209 vm_setup_freebsd_gdt(uint64_t *gdtr)
211 gdtr[GUEST_NULL_SEL] = 0;
212 gdtr[GUEST_CODE_SEL] = 0x0020980000000000;
213 gdtr[GUEST_DATA_SEL] = 0x0000900000000000;
217 * Setup the 'vcpu' register set such that it will begin execution at
218 * 'rip' in long mode.
221 vm_setup_freebsd_registers(struct vcpu *vcpu,
222 uint64_t rip, uint64_t cr3, uint64_t gdtbase,
226 uint64_t cr0, cr4, efer, rflags, desc_base;
227 uint32_t desc_access, desc_limit;
230 cr0 = CR0_PE | CR0_PG | CR0_NE;
231 if ((error = vm_set_register(vcpu, VM_REG_GUEST_CR0, cr0)) != 0)
235 if ((error = vm_set_register(vcpu, VM_REG_GUEST_CR4, cr4)) != 0)
238 efer = EFER_LME | EFER_LMA;
239 if ((error = vm_set_register(vcpu, VM_REG_GUEST_EFER, efer)))
243 error = vm_set_register(vcpu, VM_REG_GUEST_RFLAGS, rflags);
249 desc_access = 0x0000209B;
250 error = vm_set_desc(vcpu, VM_REG_GUEST_CS,
251 desc_base, desc_limit, desc_access);
255 desc_access = 0x00000093;
256 error = vm_set_desc(vcpu, VM_REG_GUEST_DS,
257 desc_base, desc_limit, desc_access);
261 error = vm_set_desc(vcpu, VM_REG_GUEST_ES,
262 desc_base, desc_limit, desc_access);
266 error = vm_set_desc(vcpu, VM_REG_GUEST_FS,
267 desc_base, desc_limit, desc_access);
271 error = vm_set_desc(vcpu, VM_REG_GUEST_GS,
272 desc_base, desc_limit, desc_access);
276 error = vm_set_desc(vcpu, VM_REG_GUEST_SS,
277 desc_base, desc_limit, desc_access);
282 * XXX TR is pointing to null selector even though we set the
283 * TSS segment to be usable with a base address and limit of 0.
285 desc_access = 0x0000008b;
286 error = vm_set_desc(vcpu, VM_REG_GUEST_TR, 0, 0, desc_access);
290 error = vm_set_desc(vcpu, VM_REG_GUEST_LDTR, 0, 0,
295 gsel = GSEL(GUEST_CODE_SEL, SEL_KPL);
296 if ((error = vm_set_register(vcpu, VM_REG_GUEST_CS, gsel)) != 0)
299 gsel = GSEL(GUEST_DATA_SEL, SEL_KPL);
300 if ((error = vm_set_register(vcpu, VM_REG_GUEST_DS, gsel)) != 0)
303 if ((error = vm_set_register(vcpu, VM_REG_GUEST_ES, gsel)) != 0)
306 if ((error = vm_set_register(vcpu, VM_REG_GUEST_FS, gsel)) != 0)
309 if ((error = vm_set_register(vcpu, VM_REG_GUEST_GS, gsel)) != 0)
312 if ((error = vm_set_register(vcpu, VM_REG_GUEST_SS, gsel)) != 0)
315 /* XXX TR is pointing to the null selector */
316 if ((error = vm_set_register(vcpu, VM_REG_GUEST_TR, 0)) != 0)
319 /* LDTR is pointing to the null selector */
320 if ((error = vm_set_register(vcpu, VM_REG_GUEST_LDTR, 0)) != 0)
324 if ((error = vm_set_register(vcpu, VM_REG_GUEST_RIP, rip)) != 0)
327 /* page table base */
328 if ((error = vm_set_register(vcpu, VM_REG_GUEST_CR3, cr3)) != 0)
332 desc_limit = GUEST_GDTR_LIMIT64;
333 error = vm_set_desc(vcpu, VM_REG_GUEST_GDTR,
334 desc_base, desc_limit, 0);
338 if ((error = vm_set_register(vcpu, VM_REG_GUEST_RSP, rsp)) != 0)