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 static void vmx_save_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx);
26 static void vmx_restore_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx);
28 int v3_vmxassist_ctx_switch(struct guest_info * info) {
29 struct vmx_assist_context * old_ctx = NULL;
30 struct vmx_assist_context * new_ctx = NULL;
31 struct vmx_assist_header * hdr = NULL;
32 struct vmx_data * vmx_info = (struct vmx_data *)info->vmm_data;
36 if (guest_pa_to_host_va(info, VMXASSIST_BASE, (addr_t *)&hdr) == -1) {
37 PrintError("Could not translate address for vmxassist header\n");
41 if (hdr->magic != VMXASSIST_MAGIC) {
42 PrintError("VMXASSIST_MAGIC field is invalid\n");
47 if (guest_pa_to_host_va(info, (addr_t)(hdr->old_ctx_gpa), (addr_t *)&(old_ctx)) == -1) {
48 PrintError("Could not translate address for VMXASSIST old context\n");
52 if (guest_pa_to_host_va(info, (addr_t)(hdr->new_ctx_gpa), (addr_t *)&(new_ctx)) == -1) {
53 PrintError("Could not translate address for VMXASSIST new context\n");
57 if (vmx_info->state == VMXASSIST_DISABLED) {
59 /* Save the old Context */
60 vmx_save_world_ctx(info, old_ctx);
62 /* restore new context, vmxassist should launch the bios the first time */
63 vmx_restore_world_ctx(info, new_ctx);
65 vmx_info->state = VMXASSIST_ENABLED;
67 } else if (vmx_info->state == VMXASSIST_ENABLED) {
68 /* restore old context */
69 vmx_restore_world_ctx(info, old_ctx);
71 vmx_info->state = VMXASSIST_DISABLED;
78 static void save_segment(struct v3_segment * seg, struct vmx_assist_segment * vmx_assist_seg) {
79 struct vmcs_segment tmp_seg;
81 memset(&tmp_seg, 0, sizeof(struct vmcs_segment));
83 v3_seg_to_vmxseg(seg, &tmp_seg);
85 vmx_assist_seg->sel = tmp_seg.selector;
86 vmx_assist_seg->limit = tmp_seg.limit;
87 vmx_assist_seg->base = tmp_seg.base;
88 vmx_assist_seg->arbytes.bytes = tmp_seg.access.val;
92 static void load_segment(struct vmx_assist_segment * vmx_assist_seg, struct v3_segment * seg) {
93 struct vmcs_segment tmp_seg;
95 memset(&tmp_seg, 0, sizeof(struct vmcs_segment));
97 tmp_seg.selector = vmx_assist_seg->sel;
98 tmp_seg.limit = vmx_assist_seg->limit;
99 tmp_seg.base = vmx_assist_seg->base;
100 tmp_seg.access.val = vmx_assist_seg->arbytes.bytes;
102 v3_vmxseg_to_seg(&tmp_seg, seg);
105 static void vmx_save_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx) {
106 struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data);
108 PrintDebug("Writing from RIP: 0x%p\n", (void *)info->rip);
110 ctx->eip = info->rip;
111 ctx->esp = info->vm_regs.rsp;
112 ctx->eflags = info->ctrl_regs.rflags;
114 ctx->cr0 = info->shdw_pg_state.guest_cr0;
115 ctx->cr3 = info->shdw_pg_state.guest_cr3;
116 ctx->cr4 = vmx_info->guest_cr4;
119 save_segment(&(info->segments.cs), &(ctx->cs));
120 save_segment(&(info->segments.ds), &(ctx->ds));
121 save_segment(&(info->segments.es), &(ctx->es));
122 save_segment(&(info->segments.ss), &(ctx->ss));
123 save_segment(&(info->segments.fs), &(ctx->fs));
124 save_segment(&(info->segments.gs), &(ctx->gs));
125 save_segment(&(info->segments.tr), &(ctx->tr));
126 save_segment(&(info->segments.ldtr), &(ctx->ldtr));
129 ctx->idtr_limit = info->segments.idtr.limit;
130 ctx->idtr_base = info->segments.idtr.base;
132 ctx->gdtr_limit = info->segments.gdtr.limit;
133 ctx->gdtr_base = info->segments.gdtr.base;
136 static void vmx_restore_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx) {
137 struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data);
139 PrintDebug("ctx rip: %p\n", (void *)(addr_t)ctx->eip);
141 info->rip = ctx->eip;
142 info->vm_regs.rsp = ctx->esp;
143 info->ctrl_regs.rflags = ctx->eflags;
145 info->shdw_pg_state.guest_cr0 = ctx->cr0;
146 info->shdw_pg_state.guest_cr3 = ctx->cr3;
147 vmx_info->guest_cr4 = ctx->cr4;
149 load_segment(&(ctx->cs), &(info->segments.cs));
150 load_segment(&(ctx->ds), &(info->segments.ds));
151 load_segment(&(ctx->es), &(info->segments.es));
152 load_segment(&(ctx->ss), &(info->segments.ss));
153 load_segment(&(ctx->fs), &(info->segments.fs));
154 load_segment(&(ctx->gs), &(info->segments.gs));
155 load_segment(&(ctx->tr), &(info->segments.tr));
156 load_segment(&(ctx->ldtr), &(info->segments.ldtr));
159 info->segments.idtr.limit = ctx->idtr_limit;
160 info->segments.idtr.base = ctx->idtr_base;
162 info->segments.gdtr.limit = ctx->gdtr_limit;
163 info->segments.gdtr.base = ctx->gdtr_base;