]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/vmm/amd/vmcb.c
IFC @r271887
[FreeBSD/FreeBSD.git] / sys / amd64 / vmm / amd / vmcb.c
1 /*-
2  * Copyright (c) 2013 Anish Gupta (akgupt3@gmail.com)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/cpuset.h>
33
34 #include <machine/segments.h>
35 #include <machine/specialreg.h>
36 #include <machine/vmm.h>
37
38 #include "vmcb.h"
39 #include "svm.h"
40
41 /*
42  * The VMCB aka Virtual Machine Control Block is a 4KB aligned page
43  * in memory that describes the virtual machine.
44  *
45  * The VMCB contains:
46  * - instructions or events in the guest to intercept
47  * - control bits that modify execution environment of the guest
48  * - guest processor state (e.g. general purpose registers)
49  */
50
51 /*
52  * Read from segment selector, control and general purpose register of VMCB.
53  */
54 int
55 vmcb_read(struct vmcb *vmcb, int ident, uint64_t *retval)
56 {
57         struct vmcb_state *state;
58         struct vmcb_segment *seg;
59         int err;
60
61         state = &vmcb->state;
62         err = 0;
63
64         switch (ident) {
65         case VM_REG_GUEST_CR0:
66                 *retval = state->cr0;
67                 break;
68
69         case VM_REG_GUEST_CR2:
70                 *retval = state->cr2;
71                 break;
72
73         case VM_REG_GUEST_CR3:
74                 *retval = state->cr3;
75                 break;
76
77         case VM_REG_GUEST_CR4:
78                 *retval = state->cr4;
79                 break;
80
81         case VM_REG_GUEST_DR7:
82                 *retval = state->dr7;
83                 break;
84
85         case VM_REG_GUEST_EFER:
86                 *retval = state->efer;
87                 break;
88
89         case VM_REG_GUEST_RAX:
90                 *retval = state->rax;
91                 break;
92
93         case VM_REG_GUEST_RFLAGS:
94                 *retval = state->rflags;
95                 break;
96
97         case VM_REG_GUEST_RIP:
98                 *retval = state->rip;
99                 break;
100
101         case VM_REG_GUEST_RSP:
102                 *retval = state->rsp;
103                 break;
104
105         case VM_REG_GUEST_CS:
106         case VM_REG_GUEST_DS:
107         case VM_REG_GUEST_ES:
108         case VM_REG_GUEST_FS:
109         case VM_REG_GUEST_GS:
110         case VM_REG_GUEST_SS:
111         case VM_REG_GUEST_GDTR:
112         case VM_REG_GUEST_IDTR:
113         case VM_REG_GUEST_LDTR:
114         case VM_REG_GUEST_TR:
115                 seg = vmcb_seg(vmcb, ident);
116                 if (seg == NULL) {
117                         ERR("Invalid seg type %d\n", ident);
118                         err = EINVAL;
119                         break;
120                 }
121
122                 *retval = seg->selector;
123                 break;
124
125         default:
126                 err =  EINVAL;
127                 break;
128         }
129
130         return (err);
131 }
132
133 /*
134  * Write to segment selector, control and general purpose register of VMCB.
135  */
136 int
137 vmcb_write(struct vmcb *vmcb, int ident, uint64_t val)
138 {
139         struct vmcb_state *state;
140         struct vmcb_segment *seg;
141         int err;
142
143         state = &vmcb->state;
144         err = 0;
145
146         switch (ident) {
147         case VM_REG_GUEST_CR0:
148                 state->cr0 = val;
149                 break;
150
151         case VM_REG_GUEST_CR2:
152                 state->cr2 = val;
153                 break;
154
155         case VM_REG_GUEST_CR3:
156                 state->cr3 = val;
157                 break;
158
159         case VM_REG_GUEST_CR4:
160                 state->cr4 = val;
161                 break;
162
163         case VM_REG_GUEST_DR7:
164                 state->dr7 = val;
165                 break;
166
167         case VM_REG_GUEST_EFER:
168                 /* EFER_SVM must always be set when the guest is executing */
169                 state->efer = val | EFER_SVM;
170                 break;
171
172         case VM_REG_GUEST_RAX:
173                 state->rax = val;
174                 break;
175
176         case VM_REG_GUEST_RFLAGS:
177                 state->rflags = val;
178                 break;
179
180         case VM_REG_GUEST_RIP:
181                 state->rip = val;
182                 break;
183
184         case VM_REG_GUEST_RSP:
185                 state->rsp = val;
186                 break;
187
188         case VM_REG_GUEST_CS:
189         case VM_REG_GUEST_DS:
190         case VM_REG_GUEST_ES:
191         case VM_REG_GUEST_FS:
192         case VM_REG_GUEST_GS:
193         case VM_REG_GUEST_SS:
194         case VM_REG_GUEST_GDTR:
195         case VM_REG_GUEST_IDTR:
196         case VM_REG_GUEST_LDTR:
197         case VM_REG_GUEST_TR:
198                 seg = vmcb_seg(vmcb, ident);
199                 if (seg == NULL) {
200                         ERR("Invalid segment type %d\n", ident);
201                         err = EINVAL;
202                         break;
203                 }
204
205                 seg->selector = val;
206                 break;
207
208         default:
209                 err = EINVAL;
210         }
211
212         return (err);
213 }
214
215 /*
216  * Return VMCB segment area.
217  */
218 struct vmcb_segment *
219 vmcb_seg(struct vmcb *vmcb, int type)
220 {
221         struct vmcb_state *state;
222         struct vmcb_segment *seg;
223
224         state = &vmcb->state;
225
226         switch (type) {
227         case VM_REG_GUEST_CS:
228                 seg = &state->cs;
229                 break;
230
231         case VM_REG_GUEST_DS:
232                 seg = &state->ds;
233                 break;
234
235         case VM_REG_GUEST_ES:
236                 seg = &state->es;
237                 break;
238
239         case VM_REG_GUEST_FS:
240                 seg = &state->fs;
241                 break;
242
243         case VM_REG_GUEST_GS:
244                 seg = &state->gs;
245                 break;
246
247         case VM_REG_GUEST_SS:
248                 seg = &state->ss;
249                 break;
250
251         case VM_REG_GUEST_GDTR:
252                 seg = &state->gdt;
253                 break;
254
255         case VM_REG_GUEST_IDTR:
256                 seg = &state->idt;
257                 break;
258
259         case VM_REG_GUEST_LDTR:
260                 seg = &state->ldt;
261                 break;
262
263         case VM_REG_GUEST_TR:
264                 seg = &state->tr;
265                 break;
266
267         default:
268                 seg = NULL;
269                 break;
270         }
271
272         return (seg);
273 }