kernel - Refactor VMX code
[dragonfly.git] / sys / platform / pc64 / vmm / vmm.c
1 /*
2  * Copyright (c) 2003-2013 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Mihai Carabas <mihai.carabas@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #include <sys/systm.h>
36 #include <sys/sysctl.h>
37 #include <sys/eventhandler.h>
38 #include <sys/proc.h>
39 #include <sys/vkernel.h>
40
41 #include <machine/vmm.h>
42 #include <machine/cputypes.h>
43 #include <machine/md_var.h>
44
45 #include "vmm.h"
46
47 static struct vmm_ctl *ctl = NULL;
48
49 struct sysctl_ctx_list vmm_sysctl_ctx;
50 struct sysctl_oid *vmm_sysctl_tree;
51
52 int vmm_enabled;
53 int vmm_debug;
54
55 static int
56 sysctl_vmm_enable(SYSCTL_HANDLER_ARGS)
57 {
58         int error, new_val;
59
60         new_val = vmm_enabled;
61
62         error = sysctl_handle_int(oidp, &new_val, 0, req);
63         if (error != 0 || req->newptr == NULL)
64                 return (error);
65
66         if (new_val != 0 && new_val != 1)
67                 return (EINVAL);
68
69         if (vmm_enabled != new_val) {
70                 if (new_val == 1) {
71                         if (ctl->enable()) {
72                                 kprintf("VMM: vmm enable() failed\n");
73                                 return (EINVAL);
74                         }
75                 } else if (new_val == 0) {
76                         if (ctl->disable()) {
77                                 kprintf("VMM: vmm disable() failed\n");
78                                 return (EINVAL);
79                         }
80                 }
81         } else {
82                 return (EINVAL);
83         }
84
85         vmm_enabled = new_val;
86
87         return (0);
88 }
89
90 static void
91 vmm_shutdown(void)
92 {
93         if(vmm_enabled)
94                 ctl->disable();
95 }
96
97 static void
98 vmm_init(void)
99 {
100         sysctl_ctx_init(&vmm_sysctl_ctx);
101         vmm_sysctl_tree = SYSCTL_ADD_NODE(&vmm_sysctl_ctx,
102             SYSCTL_STATIC_CHILDREN(_hw),
103             OID_AUTO, "vmm",
104             CTLFLAG_RD, 0, "VMM options");
105
106         if (cpu_vendor_id == CPU_VENDOR_INTEL) {
107                 ctl = get_ctl_intel();
108         } else if (cpu_vendor_id == CPU_VENDOR_AMD) {
109                 ctl = get_ctl_amd();
110         }
111
112         if (ctl->init()) {
113                 SYSCTL_ADD_INT(&vmm_sysctl_ctx,
114                     SYSCTL_CHILDREN(vmm_sysctl_tree),
115                     OID_AUTO, "enable", CTLFLAG_RD,
116                     &vmm_enabled, 0,
117                     "enable not supported");
118         } else {
119                 SYSCTL_ADD_STRING(&vmm_sysctl_ctx,
120                     SYSCTL_CHILDREN(vmm_sysctl_tree),
121                     OID_AUTO, "type", CTLFLAG_RD,
122                     ctl->name, 0,
123                     "Type of the VMM");
124                 SYSCTL_ADD_PROC(&vmm_sysctl_ctx,
125                     SYSCTL_CHILDREN(vmm_sysctl_tree),
126                     OID_AUTO, "enable", CTLTYPE_INT | CTLFLAG_WR,
127                     NULL, sizeof vmm_enabled, sysctl_vmm_enable, "I",
128                     "Control the state of the VMM");
129                 SYSCTL_ADD_INT(&vmm_sysctl_ctx,
130                     SYSCTL_CHILDREN(vmm_sysctl_tree),
131                     OID_AUTO, "debug", CTLTYPE_INT | CTLFLAG_RW,
132                     &vmm_debug, 0,
133                     "vmm debugging");
134
135                 if (ctl->enable()) {
136                         kprintf("VMM: vmm enable() failed\n");
137                 } else {
138                         vmm_enabled = 1;
139                 }
140
141                 EVENTHANDLER_REGISTER(shutdown_pre_sync, vmm_shutdown, NULL, SHUTDOWN_PRI_DEFAULT-1);
142         }
143 }
144 SYSINIT(vmm_init, SI_BOOT2_CPU_TOPOLOGY, SI_ORDER_ANY, vmm_init, NULL);
145
146
147 int
148 vmm_vminit(struct vmm_guest_options *options)
149 {
150         if (!vmm_enabled) {
151                 return ENODEV;
152         }
153
154         return ctl->vminit(options);
155 }
156
157 int
158 vmm_vmdestroy(void)
159 {
160         if (!vmm_enabled) {
161                 return ENODEV;
162         }
163         return ctl->vmdestroy();
164 }
165
166 int
167 vmm_vmrun(void)
168 {
169         if (!vmm_enabled) {
170                 return ENODEV;
171         }
172         return ctl->vmrun();
173 }
174
175 int
176 vmm_vm_set_tls_area(void)
177 {
178         if (!vmm_enabled) {
179                 return ENODEV;
180         }
181         return ctl->vm_set_tls_area();
182 }
183
184 void
185 vmm_vm_set_guest_cr3(register_t guest_cr3)
186 {
187         ctl->vm_set_guest_cr3(guest_cr3);
188 }
189
190 void
191 vmm_lwp_return(struct lwp *lp, struct trapframe *frame)
192 {
193         ctl->vm_lwp_return(lp, frame);
194 }
195
196 int
197 vmm_vm_get_gpa(struct proc *p, register_t *gpa, register_t uaddr)
198 {
199         return ctl->vm_get_gpa(p, gpa, uaddr);
200 }