Send IPI using function in vmx.c through pwrite to #cons/vmtcl at offset 4096 is...
[akaros.git] / kern / arch / x86 / vmm / vmm.c
1 /* Copyright 2015 Google Inc.
2  * 
3  * See LICENSE for details.
4  */
5
6 /* We're not going to falll into the trap of only compiling support
7  * for AMD OR Intel for an image. It all gets compiled in, and which
8  * one you use depends on on cpuinfo, not a compile-time
9  * switch. That's proven to be the best strategy.  Conditionally
10  * compiling in support is the path to hell.
11  */
12 #include <assert.h>
13 #include <pmap.h>
14 #include <smp.h>
15 #include <kmalloc.h>
16
17 #include <ros/vmm.h>
18 #include "intel/vmx.h"
19 #include "vmm.h"
20 #include <trap.h>
21
22 /* TODO: have better cpuid info storage and checks */
23 bool x86_supports_vmx = FALSE;
24
25 static void vmmcp_posted_handler(struct hw_trapframe *hw_tf, void *data);
26
27 /* Figure out what kind of CPU we are on, and if it supports any reasonable
28  * virtualization. For now, if we're not some sort of newer intel, don't
29  * bother. This does all cores. Again, note, we make these decisions at runtime,
30  * to avoid getting into the problems that compile-time decisions can cause. 
31  * At this point, of course, it's still all intel.
32  */
33 void vmm_init(void)
34 {
35         int ret;
36         /* Check first for intel capabilities. This is hence two back-to-back
37          * implementationd-dependent checks. That's ok, it's all msr dependent.
38          */
39         ret = intel_vmm_init();
40         if (! ret) {
41                 printd("intel_vmm_init worked\n");
42
43                 //Register I_VMMCP_POSTED IRQ
44                 register_irq(I_VMMCP_POSTED, vmmcp_posted_handler, NULL, MKBUS(BusLAPIC, 0, 0, 0));
45                 x86_supports_vmx = TRUE;
46                 return;
47         }
48
49         /* TODO: AMD. Will we ever care? It's not clear. */
50         printk("vmm_init failed, ret %d\n", ret);
51         return;
52 }
53
54 static void vmmcp_posted_handler(struct hw_trapframe *hw_tf, void *data)
55 {
56         printk("%s\n", __func__);
57 }
58
59 void vmm_pcpu_init(void)
60 {
61         if (!x86_supports_vmx)
62                 return;
63         if (! intel_vmm_pcpu_init()) {
64                 printd("vmm_pcpu_init worked\n");
65                 return;
66         }
67         /* TODO: AMD. Will we ever care? It's not clear. */
68         printk("vmm_pcpu_init failed\n");
69 }
70
71 int vm_post_interrupt(struct vmctl *v)
72 {
73         int vmx_interrupt_notify(struct vmctl *v);
74         if (current->vmm.amd) {
75                 return -1;
76         } else {
77                 return vmx_interrupt_notify(v);
78         }
79         return -1;
80 }
81
82 int vm_run(struct vmctl *v)
83 {
84         int vmx_launch(struct vmctl *v);
85         if (current->vmm.amd) {
86                 return -1;
87         } else {
88                 return vmx_launch(v);
89         }
90         return -1;
91 }
92
93 /* Initializes a process to run virtual machine contexts, returning the number
94  * initialized, optionally setting errno */
95 int vmm_struct_init(struct proc *p, unsigned int nr_guest_pcores, int flags)
96 {
97         struct vmm *vmm = &p->vmm;
98         unsigned int i;
99         if (flags & ~VMM_ALL_FLAGS) {
100                 set_errstr("%s: flags is 0x%lx, VMM_ALL_FLAGS is 0x%lx\n", __func__,
101                            flags, VMM_ALL_FLAGS);
102                 set_errno(EINVAL);
103                 return 0;
104         }
105         vmm->flags = flags;
106
107         if (!x86_supports_vmx) {
108                 set_errno(ENODEV);
109                 return 0;
110         }
111         qlock(&vmm->qlock);
112         if (vmm->vmmcp) {
113                 set_errno(EINVAL);
114                 qunlock(&vmm->qlock);
115                 return 0;
116         }
117         /* Set this early, so cleanup checks the gpc array */
118         vmm->vmmcp = TRUE;
119         nr_guest_pcores = MIN(nr_guest_pcores, num_cores);
120         vmm->amd = 0;
121         vmm->guest_pcores = kzmalloc(sizeof(void*) * nr_guest_pcores, KMALLOC_WAIT);
122         for (i = 0; i < nr_guest_pcores; i++) {
123                 vmm->guest_pcores[i] = vmx_create_vcpu(p);
124                 /* If we failed, we'll clean it up when the process dies */
125                 if (!vmm->guest_pcores[i]) {
126                         set_errno(ENOMEM);
127                         break;
128                 }
129         }
130         vmm->nr_guest_pcores = i;
131         qunlock(&vmm->qlock);
132         return i;
133 }
134
135 /* Has no concurrency protection - only call this when you know you have the
136  * only ref to vmm.  For instance, from __proc_free, where there is only one ref
137  * to the proc (and thus proc.vmm). */
138 void __vmm_struct_cleanup(struct proc *p)
139 {
140         struct vmm *vmm = &p->vmm;
141         if (!vmm->vmmcp)
142                 return;
143         for (int i = 0; i < vmm->nr_guest_pcores; i++) {
144                 if (vmm->guest_pcores[i])
145                         vmx_destroy_vcpu(vmm->guest_pcores[i]);
146         }
147         kfree(vmm->guest_pcores);
148         ept_flush(p->env_pgdir.eptp);
149         vmm->vmmcp = FALSE;
150 }