Merge remote-tracking branch 'origin/vendor/LDNS'
[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 && panicstr == NULL)
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                 /*
136                  * Normally enable VMM if it is supported.  But for now
137                  * lets not, because the vkernel is not stable with it
138                  * enabled.
139                  */
140                 if (1) {
141                         kprintf("VMM: available, disabled by default\n");
142                 } else if (ctl->enable()) {
143                         kprintf("VMM: vmm enable() failed\n");
144                 } else {
145                         vmm_enabled = 1;
146                 }
147
148                 EVENTHANDLER_REGISTER(shutdown_pre_sync, vmm_shutdown, NULL, SHUTDOWN_PRI_DEFAULT-1);
149         }
150 }
151 SYSINIT(vmm_init, SI_BOOT2_VMM, SI_ORDER_ANY, vmm_init, NULL);
152
153
154 int
155 vmm_vminit(struct vmm_guest_options *options)
156 {
157         if (!vmm_enabled) {
158                 return ENODEV;
159         }
160
161         return ctl->vminit(options);
162 }
163
164 int
165 vmm_vmdestroy(void)
166 {
167         if (!vmm_enabled) {
168                 return ENODEV;
169         }
170         return ctl->vmdestroy();
171 }
172
173 int
174 vmm_vmrun(void)
175 {
176         if (!vmm_enabled) {
177                 return ENODEV;
178         }
179         return ctl->vmrun();
180 }
181
182 int
183 vmm_vm_set_tls_area(void)
184 {
185         if (!vmm_enabled) {
186                 return ENODEV;
187         }
188         return ctl->vm_set_tls_area();
189 }
190
191 void
192 vmm_vm_set_guest_cr3(register_t guest_cr3)
193 {
194         ctl->vm_set_guest_cr3(guest_cr3);
195 }
196
197 void
198 vmm_lwp_return(struct lwp *lp, struct trapframe *frame)
199 {
200         ctl->vm_lwp_return(lp, frame);
201 }
202
203 int
204 vmm_vm_get_gpa(struct proc *p, register_t *gpa, register_t uaddr)
205 {
206         return ctl->vm_get_gpa(p, gpa, uaddr);
207 }