Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Avoid physical/virtual contiguity assumptions using new guest memory access functions
[palacios.git] / palacios / src / palacios / vmx_assist.c
1 /*
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Andy Gocke <agocke@gmail.com>
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Andy Gocke <agocke@gmail.com>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmx_assist.h>
21 #include <palacios/vmx_lowlevel.h>
22 #include <palacios/vm_guest_mem.h>
23 #include <palacios/vmx.h>
24 #include <palacios/vmm_ctrl_regs.h>
25
26 #ifndef V3_CONFIG_DEBUG_VMX
27 #undef PrintDebug
28 #define PrintDebug(fmt, args...)
29 #endif
30
31
32
33
34 #define VMXASSIST_MAGIC        0x17101966
35
36
37 struct vmx_assist_header {
38     uint64_t rsvd; // 8 bytes of nothing
39     uint32_t magic;
40     uint32_t new_ctx_gpa;
41     uint32_t old_ctx_gpa;
42 } __attribute__((packed));
43
44
45 union vmcs_arbytes {
46     struct arbyte_fields {
47         unsigned int seg_type : 4,
48             s         : 1,
49             dpl       : 2,
50             p         : 1,
51             reserved0 : 4,
52             avl       : 1,
53             reserved1 : 1,
54             default_ops_size: 1,
55             g         : 1,
56             null_bit  : 1,
57             reserved2 : 15;
58     } __attribute__((packed)) fields;
59     unsigned int bytes;
60 } __attribute__((packed));
61
62 struct vmx_assist_segment {
63     uint32_t sel;
64     uint32_t limit;
65     uint32_t base;
66     union vmcs_arbytes arbytes;
67 } __attribute__((packed));
68
69
70 /*
71  * World switch state
72  */
73 struct vmx_assist_context {
74     uint32_t  eip;        /* execution pointer */
75     uint32_t  esp;        /* stack pointer */
76     uint32_t  eflags;     /* flags register */
77     uint32_t  cr0;
78     uint32_t  cr3;        /* page table directory */
79     uint32_t  cr4;
80
81     uint32_t  idtr_limit; /* idt */
82     uint32_t  idtr_base;
83
84     uint32_t  gdtr_limit; /* gdt */
85     uint32_t  gdtr_base;
86
87     struct vmx_assist_segment cs;
88     struct vmx_assist_segment ds;
89     struct vmx_assist_segment es;
90     struct vmx_assist_segment ss;
91     struct vmx_assist_segment fs;
92     struct vmx_assist_segment gs;
93     struct vmx_assist_segment tr;
94     struct vmx_assist_segment ldtr;
95
96
97     unsigned char rm_irqbase[2];
98 } __attribute__((packed));
99
100
101
102 static void vmx_save_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx);
103 static void vmx_restore_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx);
104
105 int v3_vmxassist_ctx_switch(struct guest_info * info) {
106     struct vmx_assist_context * old_ctx = NULL;
107     struct vmx_assist_context * new_ctx = NULL;
108     struct vmx_assist_header * hdr = NULL;
109     struct vmx_data * vmx_info = (struct vmx_data *)info->vmm_data;
110  
111
112
113     if (v3_gpa_to_hva(info, VMXASSIST_START, (addr_t *)&hdr) == -1) {
114         PrintError(info->vm_info, info, "Could not translate address for vmxassist header\n");
115         return -1;
116     }
117
118     if (hdr->magic != VMXASSIST_MAGIC) {
119         PrintError(info->vm_info, info, "VMXASSIST_MAGIC field is invalid\n");
120         return -1;
121     }
122
123
124     if (v3_gpa_to_hva(info, (addr_t)(hdr->old_ctx_gpa), (addr_t *)&(old_ctx)) == -1) {
125         PrintError(info->vm_info, info, "Could not translate address for VMXASSIST old context\n");
126         return -1;
127     }
128
129     if (v3_gpa_to_hva(info, (addr_t)(hdr->new_ctx_gpa), (addr_t *)&(new_ctx)) == -1) {
130         PrintError(info->vm_info, info, "Could not translate address for VMXASSIST new context\n");
131         return -1;
132     }
133
134     if (vmx_info->assist_state == VMXASSIST_OFF) {
135         
136         /* Save the old Context */
137         vmx_save_world_ctx(info, old_ctx);
138
139         /* restore new context, vmxassist should launch the bios the first time */
140         vmx_restore_world_ctx(info, new_ctx);
141
142         vmx_info->assist_state = VMXASSIST_ON;
143
144     } else if (vmx_info->assist_state == VMXASSIST_ON) {
145         /* restore old context */
146         vmx_restore_world_ctx(info, old_ctx);
147
148         vmx_info->assist_state = VMXASSIST_OFF;
149     }
150
151     return 0;
152 }
153
154
155 static void save_segment(struct v3_segment * seg, struct vmx_assist_segment * vmx_assist_seg) {
156     struct vmcs_segment tmp_seg;
157
158     memset(&tmp_seg, 0, sizeof(struct vmcs_segment));
159
160     v3_seg_to_vmxseg(seg, &tmp_seg);
161
162     vmx_assist_seg->sel = tmp_seg.selector;
163     vmx_assist_seg->limit = tmp_seg.limit;
164     vmx_assist_seg->base = tmp_seg.base;
165     vmx_assist_seg->arbytes.bytes = tmp_seg.access.val;
166 }
167
168
169 static void load_segment(struct vmx_assist_segment * vmx_assist_seg, struct v3_segment * seg)  {
170     struct vmcs_segment tmp_seg;
171
172     memset(&tmp_seg, 0, sizeof(struct vmcs_segment));
173
174     tmp_seg.selector = vmx_assist_seg->sel;
175     tmp_seg.limit = vmx_assist_seg->limit;
176     tmp_seg.base = vmx_assist_seg->base;
177     tmp_seg.access.val = vmx_assist_seg->arbytes.bytes;
178
179     v3_vmxseg_to_seg(&tmp_seg, seg);
180 }
181
182 static void vmx_save_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx) {
183     struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data);
184
185     PrintDebug(info->vm_info, info, "Writing from RIP: 0x%p\n", (void *)(addr_t)info->rip);
186     
187     ctx->eip = info->rip;
188     ctx->esp = info->vm_regs.rsp;
189     ctx->eflags = info->ctrl_regs.rflags;
190
191     ctx->cr0 = info->shdw_pg_state.guest_cr0;
192     ctx->cr3 = info->shdw_pg_state.guest_cr3;
193     ctx->cr4 = vmx_info->guest_cr4;
194
195     
196     save_segment(&(info->segments.cs), &(ctx->cs));
197     save_segment(&(info->segments.ds), &(ctx->ds));
198     save_segment(&(info->segments.es), &(ctx->es));
199     save_segment(&(info->segments.ss), &(ctx->ss));
200     save_segment(&(info->segments.fs), &(ctx->fs));
201     save_segment(&(info->segments.gs), &(ctx->gs));
202     save_segment(&(info->segments.tr), &(ctx->tr));
203     save_segment(&(info->segments.ldtr), &(ctx->ldtr));
204
205     // Odd segments 
206     ctx->idtr_limit = info->segments.idtr.limit;
207     ctx->idtr_base = info->segments.idtr.base;
208
209     ctx->gdtr_limit = info->segments.gdtr.limit;
210     ctx->gdtr_base = info->segments.gdtr.base;
211 }
212
213 static void vmx_restore_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx) {
214     struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data);
215
216     PrintDebug(info->vm_info, info, "ctx rip: %p\n", (void *)(addr_t)ctx->eip);
217     
218     info->rip = ctx->eip;
219     info->vm_regs.rsp = ctx->esp;
220     info->ctrl_regs.rflags = ctx->eflags;
221
222     info->shdw_pg_state.guest_cr0 = ctx->cr0;
223     info->shdw_pg_state.guest_cr3 = ctx->cr3;
224     vmx_info->guest_cr4 = ctx->cr4;
225
226     load_segment(&(ctx->cs), &(info->segments.cs));
227     load_segment(&(ctx->ds), &(info->segments.ds));
228     load_segment(&(ctx->es), &(info->segments.es));
229     load_segment(&(ctx->ss), &(info->segments.ss));
230     load_segment(&(ctx->fs), &(info->segments.fs));
231     load_segment(&(ctx->gs), &(info->segments.gs));
232     load_segment(&(ctx->tr), &(info->segments.tr));
233     load_segment(&(ctx->ldtr), &(info->segments.ldtr));
234
235     // odd segments
236     info->segments.idtr.limit = ctx->idtr_limit;
237     info->segments.idtr.base = ctx->idtr_base;
238
239     info->segments.gdtr.limit = ctx->gdtr_limit;
240     info->segments.gdtr.base = ctx->gdtr_base;
241
242 }
243
244
245 int v3_vmxassist_init(struct guest_info * core, struct vmx_data * vmx_state) {
246
247     core->rip = 0xd0000;
248     core->vm_regs.rsp = 0x80000;
249     ((struct rflags *)&(core->ctrl_regs.rflags))->rsvd1 = 1;
250
251 #define GUEST_CR0_MASK 0x80010031
252 #define GUEST_CR4_MASK 0x00002010
253     core->ctrl_regs.cr0 |= GUEST_CR0_MASK;
254     core->ctrl_regs.cr4 |= GUEST_CR4_MASK;
255
256     ((struct cr0_32 *)&(core->shdw_pg_state.guest_cr0))->pe = 1;
257     ((struct cr0_32 *)&(core->shdw_pg_state.guest_cr0))->wp = 1;
258     ((struct cr0_32 *)&(core->shdw_pg_state.guest_cr0))->ne = 1;
259    
260
261     // Setup segment registers
262     {
263         struct v3_segment * seg_reg = (struct v3_segment *)&(core->segments);
264
265         int i;
266
267         for (i = 0; i < 10; i++) {
268             seg_reg[i].selector = 3 << 3;
269             seg_reg[i].limit = 0xffff;
270             seg_reg[i].base = 0x0;
271         }
272
273         core->segments.cs.selector = 2 << 3;
274
275         /* Set only the segment registers */
276         for (i = 0; i < 6; i++) {
277             seg_reg[i].limit = 0xfffff;
278             seg_reg[i].granularity = 1;
279             seg_reg[i].type = 3;
280             seg_reg[i].system = 1;
281             seg_reg[i].dpl = 0;
282             seg_reg[i].present = 1;
283             seg_reg[i].db = 1;
284         }
285
286         core->segments.cs.type = 0xb;
287
288         core->segments.ldtr.selector = 0x20;
289         core->segments.ldtr.type = 2;
290         core->segments.ldtr.system = 0;
291         core->segments.ldtr.present = 1;
292         core->segments.ldtr.granularity = 0;
293
294     
295         /************* Map in GDT and vmxassist *************/
296
297         uint64_t  gdt[] __attribute__ ((aligned(32))) = {
298             0x0000000000000000ULL,              /* 0x00: reserved */
299             0x0000830000000000ULL,              /* 0x08: 32-bit TSS */
300             //0x0000890000000000ULL,            /* 0x08: 32-bit TSS */
301             0x00CF9b000000FFFFULL,              /* 0x10: CS 32-bit */
302             0x00CF93000000FFFFULL,              /* 0x18: DS 32-bit */
303             0x000082000000FFFFULL,              /* 0x20: LDTR 32-bit */
304         };
305
306
307         if (v3_write_gpa_memory(core, VMXASSIST_GDT, sizeof(uint64_t)*5, (void*)gdt)!=sizeof(uint64_t)*5) { 
308             PrintError(core->vm_info, core, "Could not write VMXASSIST GDT\n");
309             return -1;
310         }
311         
312         core->segments.gdtr.base = VMXASSIST_GDT;
313
314
315         uint64_t vmxassist_tss = VMXASSIST_TSS;
316         gdt[0x08 / sizeof(gdt[0])] |=
317             ((vmxassist_tss & 0xFF000000) << (56 - 24)) |
318             ((vmxassist_tss & 0x00FF0000) << (32 - 16)) |
319             ((vmxassist_tss & 0x0000FFFF) << (16)) |
320             (8392 - 1);
321
322         core->segments.tr.selector = 0x08;
323         core->segments.tr.base = vmxassist_tss;
324
325         //core->segments.tr.type = 0x9; 
326         core->segments.tr.type = 0x3;
327         core->segments.tr.system = 0;
328         core->segments.tr.present = 1;
329         core->segments.tr.granularity = 0;
330     }
331  
332     if (core->shdw_pg_mode == NESTED_PAGING) {
333         // setup 1to1 page table internally.
334         int i = 0;
335         pde32_4MB_t * pde = NULL;
336
337         V3_Print(core->vm_info, core, "Setting up internal VMXASSIST page tables\n");
338
339         if (v3_gpa_to_hva(core, VMXASSIST_1to1_PT, (addr_t *)(&pde)) == -1) {
340             PrintError(core->vm_info, core, "Could not find VMXASSIST 1to1 PT destination\n");
341             return -1;
342         }
343
344         memset(pde, 0, PAGE_SIZE);
345
346         for (i = 0; i < 1024; i++) {
347             pde[i].present = 1;
348             pde[i].writable = 1;
349             pde[i].user_page = 1;
350             pde[i].large_page = 1;
351             pde[i].page_base_addr = PAGE_BASE_ADDR_4MB(i * PAGE_SIZE_4MB);
352
353             //      PrintError(core->vm_info, core, "PDE %d: %x\n", i, *(uint32_t *)&(pde[i]));
354         }
355
356         core->ctrl_regs.cr3 = VMXASSIST_1to1_PT;
357
358     }
359
360     // setup VMXASSIST
361     { 
362
363         extern uint8_t v3_vmxassist_start[];
364         extern uint8_t v3_vmxassist_end[];
365
366         if (v3_write_gpa_memory(core, VMXASSIST_START, v3_vmxassist_end-v3_vmxassist_start,v3_vmxassist_start)!=v3_vmxassist_end-v3_vmxassist_start) { 
367             PrintError(core->vm_info, core, "Could not write VMXASSIST\n");
368             return -1;
369         }
370
371
372         vmx_state->assist_state = VMXASSIST_OFF;
373     }
374
375
376     return 0;
377 }