vmmapi_freebsd.c revision 245652
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 "vmmapi.h"
39
40#define	DESC_UNUSABLE		0x00010000
41
42#define	GUEST_NULL_SEL		0
43#define	GUEST_CODE_SEL		1
44#define	GUEST_DATA_SEL		2
45#define	GUEST_GDTR_LIMIT	(3 * 8 - 1)
46
47void
48vm_setup_freebsd_gdt(uint64_t *gdtr)
49{
50	gdtr[GUEST_NULL_SEL] = 0;
51	gdtr[GUEST_CODE_SEL] = 0x0020980000000000;
52	gdtr[GUEST_DATA_SEL] = 0x0000900000000000;
53}
54
55/*
56 * Setup the 'vcpu' register set such that it will begin execution at
57 * 'rip' in long mode.
58 */
59int
60vm_setup_freebsd_registers(struct vmctx *vmctx, int vcpu,
61			   uint64_t rip, uint64_t cr3, uint64_t gdtbase,
62			   uint64_t rsp)
63{
64	int error;
65	uint64_t cr0, cr4, efer, rflags, desc_base;
66	uint32_t desc_access, desc_limit;
67	uint16_t gsel;
68
69	cr0 = CR0_PE | CR0_PG | CR0_NE;
70	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR0, cr0)) != 0)
71		goto done;
72
73	cr4 = CR4_PAE;
74	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR4, cr4)) != 0)
75		goto done;
76
77	efer = EFER_LME | EFER_LMA;
78	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_EFER, efer)))
79		goto done;
80
81	rflags = 0x2;
82	error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RFLAGS, rflags);
83	if (error)
84		goto done;
85
86	desc_base = 0;
87	desc_limit = 0;
88	desc_access = 0x0000209B;
89	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_CS,
90			    desc_base, desc_limit, desc_access);
91	if (error)
92		goto done;
93
94	desc_access = 0x00000093;
95	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_DS,
96			    desc_base, desc_limit, desc_access);
97	if (error)
98		goto done;
99
100	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_ES,
101			    desc_base, desc_limit, desc_access);
102	if (error)
103		goto done;
104
105	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_FS,
106			    desc_base, desc_limit, desc_access);
107	if (error)
108		goto done;
109
110	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GS,
111			    desc_base, desc_limit, desc_access);
112	if (error)
113		goto done;
114
115	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_SS,
116			    desc_base, desc_limit, desc_access);
117	if (error)
118		goto done;
119
120	/*
121	 * XXX TR is pointing to null selector even though we set the
122	 * TSS segment to be usable with a base address and limit of 0.
123	 */
124	desc_access = 0x0000008b;
125	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_TR, 0, 0, desc_access);
126	if (error)
127		goto done;
128
129	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_LDTR, 0, 0,
130			    DESC_UNUSABLE);
131	if (error)
132		goto done;
133
134	gsel = GSEL(GUEST_CODE_SEL, SEL_KPL);
135	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CS, gsel)) != 0)
136		goto done;
137
138	gsel = GSEL(GUEST_DATA_SEL, SEL_KPL);
139	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_DS, gsel)) != 0)
140		goto done;
141
142	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_ES, gsel)) != 0)
143		goto done;
144
145	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_FS, gsel)) != 0)
146		goto done;
147
148	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_GS, gsel)) != 0)
149		goto done;
150
151	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_SS, gsel)) != 0)
152		goto done;
153
154	/* XXX TR is pointing to the null selector */
155	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_TR, 0)) != 0)
156		goto done;
157
158	/* LDTR is pointing to the null selector */
159	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_LDTR, 0)) != 0)
160		goto done;
161
162	/* entry point */
163	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RIP, rip)) != 0)
164		goto done;
165
166	/* page table base */
167	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR3, cr3)) != 0)
168		goto done;
169
170	desc_base = gdtbase;
171	desc_limit = GUEST_GDTR_LIMIT;
172	error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GDTR,
173			    desc_base, desc_limit, 0);
174	if (error != 0)
175		goto done;
176
177	if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSP, rsp)) != 0)
178		goto done;
179
180	error = 0;
181done:
182	return (error);
183}
184