hammer2 - Merge Mihai Carabas's VKERNEL/VMM GSOC project into the main tree
[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
54 static int
55 sysctl_vmm_enable(SYSCTL_HANDLER_ARGS)
56 {
57         int error, new_val;
58
59         new_val = vmm_enabled;
60
61         error = sysctl_handle_int(oidp, &new_val, 0, req);
62         if (error != 0 || req->newptr == NULL)
63                 return (error);
64
65         if (new_val != 0 && new_val != 1)
66                 return (EINVAL);
67
68         if (vmm_enabled != new_val) {
69                 if (new_val == 1) {
70                         if (ctl->enable()) {
71                                 kprintf("VMM: vmm enable() failed\n");
72                                 return (EINVAL);
73                         }
74                 } else if (new_val == 0) {
75                         if (ctl->disable()) {
76                                 kprintf("VMM: vmm disable() failed\n");
77                                 return (EINVAL);
78                         }
79                 }
80         } else {
81                 return (EINVAL);
82         }
83
84         vmm_enabled = new_val;
85
86         return (0);
87 }
88
89 static void
90 vmm_shutdown(void)
91 {
92         if(vmm_enabled)
93                 ctl->disable();
94 }
95
96 static void
97 vmm_init(void)
98 {
99         sysctl_ctx_init(&vmm_sysctl_ctx);
100         vmm_sysctl_tree = SYSCTL_ADD_NODE(&vmm_sysctl_ctx,
101             SYSCTL_STATIC_CHILDREN(_hw),
102             OID_AUTO, "vmm",
103             CTLFLAG_RD, 0, "VMM options");
104
105         if (cpu_vendor_id == CPU_VENDOR_INTEL) {
106                 ctl = get_ctl_intel();
107         } else if (cpu_vendor_id == CPU_VENDOR_AMD) {
108                 ctl = get_ctl_amd();
109         }
110
111         if (ctl->init()) {
112                 SYSCTL_ADD_STRING(&vmm_sysctl_ctx,
113                     SYSCTL_CHILDREN(vmm_sysctl_tree),
114                     OID_AUTO, "enable", CTLFLAG_RD,
115                     "NOT SUPPORTED", 0,
116                     "enable not supported");
117         } else {
118                 SYSCTL_ADD_STRING(&vmm_sysctl_ctx,
119                     SYSCTL_CHILDREN(vmm_sysctl_tree),
120                     OID_AUTO, "type", CTLFLAG_RD,
121                     ctl->name, 0,
122                     "Type of the VMM");
123                 SYSCTL_ADD_PROC(&vmm_sysctl_ctx,
124                     SYSCTL_CHILDREN(vmm_sysctl_tree),
125                     OID_AUTO, "enable", CTLTYPE_INT | CTLFLAG_WR,
126                     NULL, sizeof vmm_enabled, sysctl_vmm_enable, "I",
127                     "Control the state of the VMM");
128
129                 if (ctl->enable()) {
130                         kprintf("VMM: vmm enable() failed\n");
131                 } else {
132                         vmm_enabled = 1;
133                 }
134
135                 EVENTHANDLER_REGISTER(shutdown_pre_sync, vmm_shutdown, NULL, SHUTDOWN_PRI_DEFAULT-1);
136         }
137 }
138 SYSINIT(vmm_init, SI_BOOT2_CPU_TOPOLOGY, SI_ORDER_ANY, vmm_init, NULL);
139
140
141 int
142 vmm_vminit(struct guest_options *options)
143 {
144         if (!vmm_enabled) {
145                 return ENODEV;
146         }
147
148         return ctl->vminit(options);
149 }
150
151 int
152 vmm_vmdestroy(void)
153 {
154         if (!vmm_enabled) {
155                 return ENODEV;
156         }
157
158         return ctl->vmdestroy();
159 }
160
161 int
162 vmm_vmrun(void)
163 {
164         if (!vmm_enabled) {
165                 return ENODEV;
166         }
167         return ctl->vmrun();
168 }
169
170 int
171 vmm_vm_set_tls_area(void)
172 {
173         if (!vmm_enabled) {
174                 return ENODEV;
175         }
176         return ctl->vm_set_tls_area();
177 }
178
179 void
180 vmm_vm_set_guest_cr3(register_t guest_cr3)
181 {
182         ctl->vm_set_guest_cr3(guest_cr3);
183 }
184
185 void
186 vmm_lwp_return(struct lwp *lp, struct trapframe *frame)
187 {
188         ctl->vm_lwp_return(lp, frame);
189 }
190
191 int
192 vmm_vm_get_gpa(struct proc *p, register_t *gpa, register_t uaddr)
193 {
194         return ctl->vm_get_gpa(p, gpa, uaddr);
195 }