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 int vmx_save_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx);
26 static int vmx_restore_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx);
28 int v3_vmxassist_ctx_switch(struct guest_info * info) {
29 uint32_t vmx_magic = 0; // Magic number to check for vmxassist
30 struct vmx_assist_context * old_ctx = NULL;
31 struct vmx_assist_context * new_ctx = NULL;
32 uint32_t old_ctx_gpa = 0;
33 uint32_t new_ctx_gpa = 0;
34 vmx_state_t state = ((struct vmx_data *)info->vmm_data)->state;
36 /* Check validity of VMXASSIST_MAGIC field */
37 if (read_guest_pa_memory(info, VMXASSIST_MAGIC_OFFSET, sizeof(vmx_magic), (uint8_t *)&vmx_magic) != sizeof(vmx_magic)) {
38 PrintError("Could not read guest VMXASSIST magic field\n");
42 if (vmx_magic != VMXASSIST_MAGIC) {
43 PrintError("VMXASSIT_MAGIC field is invalid\n");
48 /* Retrieve the pointer to the Old Context struct */
49 if (read_guest_pa_memory(info, VMXASSIST_OLD_CONTEXT, sizeof(old_ctx_gpa), (uint8_t *)&old_ctx_gpa) != sizeof(old_ctx_gpa)) {
50 PrintError("Could not read Old Context pointer field\n");
54 guest_pa_to_host_va(info, (addr_t)old_ctx_gpa, (addr_t *)&(old_ctx));
57 /* Retrieve the pointer to the New Context struct */
58 if (read_guest_pa_memory(info, VMXASSIST_NEW_CONTEXT, sizeof(new_ctx_gpa), (uint8_t *)&new_ctx_gpa) != sizeof(new_ctx_gpa)) {
59 PrintError("Could not read New Context pointer field\n");
63 guest_pa_to_host_va(info, (addr_t)new_ctx_gpa, (addr_t *)&(new_ctx));
67 if (state == VMXASSIST_DISABLED) {
69 /* Save the old Context */
70 if (vmx_save_world_ctx(info, old_ctx) != 0) {
71 PrintError("Could not save VMXASSIST world context\n");
75 /* restore new context, vmxassist should launch the bios the first time */
76 if (vmx_restore_world_ctx(info, new_ctx) != 0) {
77 PrintError("VMXASSIST could not restore new context\n");
81 } else if (state == VMXASSIST_ENABLED) {
82 /* restore old context */
83 if (vmx_restore_world_ctx(info, old_ctx) != 0) {
84 PrintError("VMXASSIST could not restore old context\n");
93 int vmx_save_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx) {
96 PrintDebug("Writing from RIP: 0x%p\n", (void *)info->rip);
98 error |= vmcs_read(VMCS_GUEST_RIP, &(ctx->eip));
99 error |= vmcs_read(VMCS_GUEST_RSP, &(ctx->esp));
100 error |= vmcs_read(VMCS_GUEST_RFLAGS, &(ctx->eflags));
102 error |= vmcs_read(VMCS_CR0_READ_SHDW, &(ctx->cr0));
103 ctx->cr3 = info->shdw_pg_state.guest_cr3;
104 error |= vmcs_read(VMCS_CR4_READ_SHDW, &(ctx->cr4));
106 error |= vmcs_read(VMCS_GUEST_IDTR_LIMIT, &(ctx->idtr_limit));
107 error |= vmcs_read(VMCS_GUEST_IDTR_BASE, &(ctx->idtr_base));
109 error |= vmcs_read(VMCS_GUEST_GDTR_LIMIT, &(ctx->gdtr_limit));
110 error |= vmcs_read(VMCS_GUEST_GDTR_BASE, &(ctx->gdtr_base));
112 error |= vmcs_read(VMCS_GUEST_CS_SELECTOR, &(ctx->cs_sel));
113 error |= vmcs_read(VMCS_GUEST_CS_LIMIT, &(ctx->cs_limit));
114 error |= vmcs_read(VMCS_GUEST_CS_BASE, &(ctx->cs_base));
115 error |= vmcs_read(VMCS_GUEST_CS_ACCESS, &(ctx->cs_arbytes.bytes));
117 error |= vmcs_read(VMCS_GUEST_DS_SELECTOR, &(ctx->ds_sel));
118 error |= vmcs_read(VMCS_GUEST_DS_LIMIT, &(ctx->ds_limit));
119 error |= vmcs_read(VMCS_GUEST_DS_BASE, &(ctx->ds_base));
120 error |= vmcs_read(VMCS_GUEST_DS_ACCESS, &(ctx->ds_arbytes.bytes));
122 error |= vmcs_read(VMCS_GUEST_ES_SELECTOR, &(ctx->es_sel));
123 error |= vmcs_read(VMCS_GUEST_ES_LIMIT, &(ctx->es_limit));
124 error |= vmcs_read(VMCS_GUEST_ES_BASE, &(ctx->es_base));
125 error |= vmcs_read(VMCS_GUEST_ES_ACCESS, &(ctx->es_arbytes.bytes));
127 error |= vmcs_read(VMCS_GUEST_SS_SELECTOR, &(ctx->ss_sel));
128 error |= vmcs_read(VMCS_GUEST_SS_LIMIT, &(ctx->ss_limit));
129 error |= vmcs_read(VMCS_GUEST_SS_BASE, &(ctx->ss_base));
130 error |= vmcs_read(VMCS_GUEST_SS_ACCESS, &(ctx->ss_arbytes.bytes));
132 error |= vmcs_read(VMCS_GUEST_FS_SELECTOR, &(ctx->fs_sel));
133 error |= vmcs_read(VMCS_GUEST_FS_LIMIT, &(ctx->fs_limit));
134 error |= vmcs_read(VMCS_GUEST_FS_BASE, &(ctx->fs_base));
135 error |= vmcs_read(VMCS_GUEST_FS_ACCESS, &(ctx->fs_arbytes.bytes));
137 error |= vmcs_read(VMCS_GUEST_GS_SELECTOR, &(ctx->gs_sel));
138 error |= vmcs_read(VMCS_GUEST_GS_LIMIT, &(ctx->gs_limit));
139 error |= vmcs_read(VMCS_GUEST_GS_BASE, &(ctx->gs_base));
140 error |= vmcs_read(VMCS_GUEST_GS_ACCESS, &(ctx->gs_arbytes.bytes));
142 error |= vmcs_read(VMCS_GUEST_TR_SELECTOR, &(ctx->tr_sel));
143 error |= vmcs_read(VMCS_GUEST_TR_LIMIT, &(ctx->tr_limit));
144 error |= vmcs_read(VMCS_GUEST_TR_BASE, &(ctx->tr_base));
145 error |= vmcs_read(VMCS_GUEST_TR_ACCESS, &(ctx->tr_arbytes.bytes));
147 error |= vmcs_read(VMCS_GUEST_LDTR_SELECTOR, &(ctx->ldtr_sel));
148 error |= vmcs_read(VMCS_GUEST_LDTR_LIMIT, &(ctx->ldtr_limit));
149 error |= vmcs_read(VMCS_GUEST_LDTR_BASE, &(ctx->ldtr_base));
150 error |= vmcs_read(VMCS_GUEST_LDTR_ACCESS, &(ctx->ldtr_arbytes.bytes));
155 int vmx_restore_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx) {
158 PrintDebug("ctx rip: %p\n", (void *)(addr_t)ctx->eip);
160 error |= vmcs_write(VMCS_GUEST_RIP, ctx->eip);
161 error |= vmcs_write(VMCS_GUEST_RSP, ctx->esp);
162 error |= vmcs_write(VMCS_GUEST_RFLAGS, ctx->eflags);
164 error |= vmcs_write(VMCS_CR0_READ_SHDW, ctx->cr0);
165 info->shdw_pg_state.guest_cr3 = ctx->cr3;
166 error |= vmcs_write(VMCS_CR4_READ_SHDW, ctx->cr4);
168 error |= vmcs_write(VMCS_GUEST_IDTR_LIMIT, ctx->idtr_limit);
169 error |= vmcs_write(VMCS_GUEST_IDTR_BASE, ctx->idtr_base);
171 error |= vmcs_write(VMCS_GUEST_GDTR_LIMIT, ctx->gdtr_limit);
172 error |= vmcs_write(VMCS_GUEST_GDTR_BASE, ctx->gdtr_base);
174 error |= vmcs_write(VMCS_GUEST_CS_SELECTOR, ctx->cs_sel);
175 error |= vmcs_write(VMCS_GUEST_CS_LIMIT, ctx->cs_limit);
176 error |= vmcs_write(VMCS_GUEST_CS_BASE, ctx->cs_base);
177 error |= vmcs_write(VMCS_GUEST_CS_ACCESS, ctx->cs_arbytes.bytes);
179 error |= vmcs_write(VMCS_GUEST_DS_SELECTOR, ctx->ds_sel);
180 error |= vmcs_write(VMCS_GUEST_DS_LIMIT, ctx->ds_limit);
181 error |= vmcs_write(VMCS_GUEST_DS_BASE, ctx->ds_base);
182 error |= vmcs_write(VMCS_GUEST_DS_ACCESS, ctx->ds_arbytes.bytes);
184 error |= vmcs_write(VMCS_GUEST_ES_SELECTOR, ctx->es_sel);
185 error |= vmcs_write(VMCS_GUEST_ES_LIMIT, ctx->es_limit);
186 error |= vmcs_write(VMCS_GUEST_ES_BASE, ctx->es_base);
187 error |= vmcs_write(VMCS_GUEST_ES_ACCESS, ctx->es_arbytes.bytes);
189 error |= vmcs_write(VMCS_GUEST_SS_SELECTOR, ctx->ss_sel);
190 error |= vmcs_write(VMCS_GUEST_SS_LIMIT, ctx->ss_limit);
191 error |= vmcs_write(VMCS_GUEST_SS_BASE, ctx->ss_base);
192 error |= vmcs_write(VMCS_GUEST_SS_ACCESS, ctx->ss_arbytes.bytes);
194 error |= vmcs_write(VMCS_GUEST_FS_SELECTOR, ctx->fs_sel);
195 error |= vmcs_write(VMCS_GUEST_FS_LIMIT, ctx->fs_limit);
196 error |= vmcs_write(VMCS_GUEST_FS_BASE, ctx->fs_base);
197 error |= vmcs_write(VMCS_GUEST_FS_ACCESS, ctx->fs_arbytes.bytes);
199 error |= vmcs_write(VMCS_GUEST_GS_SELECTOR, ctx->gs_sel);
200 error |= vmcs_write(VMCS_GUEST_GS_LIMIT, ctx->gs_limit);
201 error |= vmcs_write(VMCS_GUEST_GS_BASE, ctx->gs_base);
202 error |= vmcs_write(VMCS_GUEST_GS_ACCESS, ctx->gs_arbytes.bytes);
204 error |= vmcs_write(VMCS_GUEST_TR_SELECTOR, ctx->tr_sel);
205 error |= vmcs_write(VMCS_GUEST_TR_LIMIT, ctx->tr_limit);
206 error |= vmcs_write(VMCS_GUEST_TR_BASE, ctx->tr_base);
207 error |= vmcs_write(VMCS_GUEST_TR_ACCESS, ctx->tr_arbytes.bytes);
209 error |= vmcs_write(VMCS_GUEST_LDTR_SELECTOR, ctx->ldtr_sel);
210 error |= vmcs_write(VMCS_GUEST_LDTR_LIMIT, ctx->ldtr_limit);
211 error |= vmcs_write(VMCS_GUEST_LDTR_BASE, ctx->ldtr_base);
212 error |= vmcs_write(VMCS_GUEST_LDTR_ACCESS, ctx->ldtr_arbytes.bytes);