e63b676ff6d7022df219f9dd9e873037962a5679
[dragonfly.git] / sys / platform / pc64 / vmm / svm.c
1 #include <sys/systm.h>
2 #include <sys/malloc.h>
3 #include <sys/thread.h>
4 #include <sys/vmm.h>
5
6 #include <vm/pmap.h>
7
8 #include <machine/cputypes.h>
9 #include <machine/md_var.h>
10 #include <machine/specialreg.h>
11
12 #include "vmm.h"
13 #include "svm.h"
14
15 static int svm_available = 0;
16 static int svm_enabled = 0;
17
18 //static int svm_rvi_available = 0;
19 //static int svm_vmcb_caching_available = 0;
20
21 static vm_offset_t vm_hsave_va[MAXCPU];
22
23 /*
24  * svm_init() - Identify AMD SVM support.
25  *
26  *      Called in early boot. Detects AMD SVM support and extended features.
27  */
28 static int svm_init(void) {
29         uint64_t vm_cr;
30
31         /* SVM is identified by CPUID */
32         if ((amd_feature2 & AMDID2_SVM) == 0)
33                 return (ENODEV);
34
35         /* Processor may support SVM, but it may be disabled. */
36         vm_cr = rdmsr(MSR_AMD_VM_CR);
37         if (vm_cr & MSR_AMD_VM_CR_SVMDIS)
38                 return (ENODEV);
39
40         svm_available = 1;
41
42         return (0);
43 }
44
45 /*
46  * svm_enable() - Called to enable SVM extensions on every processor.
47  */
48 static int svm_enable(void) {
49         uint64_t efer;
50         int origcpu;
51         int i;
52         vm_paddr_t vm_hsave_pa;
53
54         if (!svm_available)
55                 return (ENODEV);
56
57         KKASSERT(svm_enabled == 0);
58
59         /* Set EFER.SVME and allocate a VM Host Save Area on every cpu */
60         origcpu = mycpuid;
61         for (i = 0; i < ncpus; i++) {
62                 lwkt_migratecpu(i);
63
64                 efer = rdmsr(MSR_EFER);
65                 efer |= EFER_SVME;
66                 wrmsr(MSR_EFER, efer);
67
68                 vm_hsave_va[i] = (vm_offset_t) contigmalloc(4096, M_TEMP,
69                                                             M_WAITOK | M_ZERO,
70                                                             0, 0xffffffff,
71                                                             4096, 0);
72                 vm_hsave_pa = vtophys(vm_hsave_va[i]);
73                 wrmsr(MSR_AMD_VM_HSAVE_PA, vm_hsave_pa);
74         }
75         lwkt_migratecpu(origcpu);
76
77         svm_enabled = 1;
78
79         return (0);
80 }
81
82 /*
83  * svm_disable() - Called to disable SVM extensions on every processor.
84  */
85 static int svm_disable(void) {
86         uint64_t efer;
87         int origcpu;
88         int i;
89
90         /* XXX Wait till no vmms are running? */
91
92         KKASSERT(svm_enabled == 1);
93
94         origcpu = mycpuid;
95         for (i = 0; i < ncpus; i++) {
96                 lwkt_migratecpu(i);
97
98                 wrmsr(MSR_AMD_VM_HSAVE_PA, 0);
99
100                 contigfree((void *) vm_hsave_va[i], 4096, M_TEMP);
101                 vm_hsave_va[i] = 0;
102
103                 efer = rdmsr(MSR_EFER);
104                 efer &= ~EFER_SVME;
105                 wrmsr(MSR_EFER, efer);
106         }
107         lwkt_migratecpu(origcpu);
108
109         svm_enabled = 0;
110
111         return (0);
112 }
113
114 /*
115  * svm_vminit() - Prepare current thread for VMRUN.
116  *
117  *      Allocates a VMCB for the current thread and flags the thread to return
118  *      to usermode via svm_vmrun().
119  */
120 static int svm_vminit(struct guest_options *options) {
121         return (ENODEV);
122 }
123
124 /*
125  * svm_vmdestroy() -
126  */
127 static int svm_vmdestroy(void) {
128         return (ENODEV);
129 }
130
131 /*
132  * svm_vmrun() - Execute VMRUN on a prepared VMCB for a thread.
133  *
134  *      Called while a thread is returning to userspace, after being flagged as
135  *      a VMM thread. svm_vmrun() continues in a loop around VMRUN/#VMEXIT
136  *      handling until we are no longer a VMM thread.
137  */
138 static int svm_vmrun(void) {
139         return (ENODEV);
140 }
141
142 static struct vmm_ctl ctl_svm = {
143         .name = "SVM",
144         .init = svm_init,
145         .enable = svm_enable,
146         .disable = svm_disable,
147         .vminit = svm_vminit,
148         .vmdestroy = svm_vmdestroy,
149         .vmrun = svm_vmrun,
150 };
151
152 struct vmm_ctl *
153 get_ctl_amd(void)
154 {
155         return &ctl_svm;
156 }