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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2008, Andy Gocke <agocke@gmail.com>
11 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Andy Gocke <agocke@gmail.com>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <palacios/vmx_assist.h>
21 #include <palacios/vmx_lowlevel.h>
22 #include <palacios/vm_guest_mem.h>
23 #include <palacios/vmx.h>
25 #ifndef CONFIG_DEBUG_VMX
27 #define PrintDebug(fmt, args...)
30 static void vmx_save_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx);
31 static void vmx_restore_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx);
33 int v3_vmxassist_ctx_switch(struct guest_info * info) {
34 struct vmx_assist_context * old_ctx = NULL;
35 struct vmx_assist_context * new_ctx = NULL;
36 struct vmx_assist_header * hdr = NULL;
37 struct vmx_data * vmx_info = (struct vmx_data *)info->vmm_data;
41 if (v3_gpa_to_hva(info, VMXASSIST_BASE, (addr_t *)&hdr) == -1) {
42 PrintError("Could not translate address for vmxassist header\n");
46 if (hdr->magic != VMXASSIST_MAGIC) {
47 PrintError("VMXASSIST_MAGIC field is invalid\n");
52 if (v3_gpa_to_hva(info, (addr_t)(hdr->old_ctx_gpa), (addr_t *)&(old_ctx)) == -1) {
53 PrintError("Could not translate address for VMXASSIST old context\n");
57 if (v3_gpa_to_hva(info, (addr_t)(hdr->new_ctx_gpa), (addr_t *)&(new_ctx)) == -1) {
58 PrintError("Could not translate address for VMXASSIST new context\n");
62 if (vmx_info->state == VMXASSIST_DISABLED) {
64 /* Save the old Context */
65 vmx_save_world_ctx(info, old_ctx);
67 /* restore new context, vmxassist should launch the bios the first time */
68 vmx_restore_world_ctx(info, new_ctx);
70 vmx_info->state = VMXASSIST_ENABLED;
72 } else if (vmx_info->state == VMXASSIST_ENABLED) {
73 /* restore old context */
74 vmx_restore_world_ctx(info, old_ctx);
76 vmx_info->state = VMXASSIST_DISABLED;
83 static void save_segment(struct v3_segment * seg, struct vmx_assist_segment * vmx_assist_seg) {
84 struct vmcs_segment tmp_seg;
86 memset(&tmp_seg, 0, sizeof(struct vmcs_segment));
88 v3_seg_to_vmxseg(seg, &tmp_seg);
90 vmx_assist_seg->sel = tmp_seg.selector;
91 vmx_assist_seg->limit = tmp_seg.limit;
92 vmx_assist_seg->base = tmp_seg.base;
93 vmx_assist_seg->arbytes.bytes = tmp_seg.access.val;
97 static void load_segment(struct vmx_assist_segment * vmx_assist_seg, struct v3_segment * seg) {
98 struct vmcs_segment tmp_seg;
100 memset(&tmp_seg, 0, sizeof(struct vmcs_segment));
102 tmp_seg.selector = vmx_assist_seg->sel;
103 tmp_seg.limit = vmx_assist_seg->limit;
104 tmp_seg.base = vmx_assist_seg->base;
105 tmp_seg.access.val = vmx_assist_seg->arbytes.bytes;
107 v3_vmxseg_to_seg(&tmp_seg, seg);
110 static void vmx_save_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx) {
111 struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data);
113 PrintDebug("Writing from RIP: 0x%p\n", (void *)(addr_t)info->rip);
115 ctx->eip = info->rip;
116 ctx->esp = info->vm_regs.rsp;
117 ctx->eflags = info->ctrl_regs.rflags;
119 ctx->cr0 = info->shdw_pg_state.guest_cr0;
120 ctx->cr3 = info->shdw_pg_state.guest_cr3;
121 ctx->cr4 = vmx_info->guest_cr4;
124 save_segment(&(info->segments.cs), &(ctx->cs));
125 save_segment(&(info->segments.ds), &(ctx->ds));
126 save_segment(&(info->segments.es), &(ctx->es));
127 save_segment(&(info->segments.ss), &(ctx->ss));
128 save_segment(&(info->segments.fs), &(ctx->fs));
129 save_segment(&(info->segments.gs), &(ctx->gs));
130 save_segment(&(info->segments.tr), &(ctx->tr));
131 save_segment(&(info->segments.ldtr), &(ctx->ldtr));
134 ctx->idtr_limit = info->segments.idtr.limit;
135 ctx->idtr_base = info->segments.idtr.base;
137 ctx->gdtr_limit = info->segments.gdtr.limit;
138 ctx->gdtr_base = info->segments.gdtr.base;
141 static void vmx_restore_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx) {
142 struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data);
144 PrintDebug("ctx rip: %p\n", (void *)(addr_t)ctx->eip);
146 info->rip = ctx->eip;
147 info->vm_regs.rsp = ctx->esp;
148 info->ctrl_regs.rflags = ctx->eflags;
150 info->shdw_pg_state.guest_cr0 = ctx->cr0;
151 info->shdw_pg_state.guest_cr3 = ctx->cr3;
152 vmx_info->guest_cr4 = ctx->cr4;
154 load_segment(&(ctx->cs), &(info->segments.cs));
155 load_segment(&(ctx->ds), &(info->segments.ds));
156 load_segment(&(ctx->es), &(info->segments.es));
157 load_segment(&(ctx->ss), &(info->segments.ss));
158 load_segment(&(ctx->fs), &(info->segments.fs));
159 load_segment(&(ctx->gs), &(info->segments.gs));
160 load_segment(&(ctx->tr), &(info->segments.tr));
161 load_segment(&(ctx->ldtr), &(info->segments.ldtr));
164 info->segments.idtr.limit = ctx->idtr_limit;
165 info->segments.idtr.base = ctx->idtr_base;
167 info->segments.gdtr.limit = ctx->gdtr_limit;
168 info->segments.gdtr.base = ctx->gdtr_base;