xen-vtx-unstable

annotate xen/arch/x86/vmx_vmcs.c @ 3290:b9ab4345fd1b

bitkeeper revision 1.1159.1.483 (41c0c417XYObowWqbfqU0cdLx30C9w)

Initial Intel VMX changes to support unmodified Linux guests on Intel's VT p
latform.
author iap10@labyrinth.cl.cam.ac.uk
date Wed Dec 15 23:09:11 2004 +0000 (2004-12-15)
parents
children a7f99d7a4027
rev   line source
iap10@3290 1 /*
iap10@3290 2 * vmx_vmcs.c: VMCS management
iap10@3290 3 * Copyright (c) 2004, Intel Corporation.
iap10@3290 4 *
iap10@3290 5 * This program is free software; you can redistribute it and/or modify it
iap10@3290 6 * under the terms and conditions of the GNU General Public License,
iap10@3290 7 * version 2, as published by the Free Software Foundation.
iap10@3290 8 *
iap10@3290 9 * This program is distributed in the hope it will be useful, but WITHOUT
iap10@3290 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
iap10@3290 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
iap10@3290 12 * more details.
iap10@3290 13 *
iap10@3290 14 * You should have received a copy of the GNU General Public License along with
iap10@3290 15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
iap10@3290 16 * Place - Suite 330, Boston, MA 02111-1307 USA.
iap10@3290 17 *
iap10@3290 18 */
iap10@3290 19
iap10@3290 20 #include <xen/config.h>
iap10@3290 21 #include <xen/init.h>
iap10@3290 22 #include <xen/mm.h>
iap10@3290 23 #include <xen/lib.h>
iap10@3290 24 #include <xen/errno.h>
iap10@3290 25
iap10@3290 26 #include <asm/cpufeature.h>
iap10@3290 27 #include <asm/processor.h>
iap10@3290 28 #include <asm/msr.h>
iap10@3290 29 #include <asm/vmx.h>
iap10@3290 30 #include <xen/event.h>
iap10@3290 31 #include <xen/kernel.h>
iap10@3290 32 #include <public/io/ioreq.h>
iap10@3290 33 #include <asm/domain_page.h>
iap10@3290 34
iap10@3290 35 struct vmcs_struct *alloc_vmcs(void)
iap10@3290 36 {
iap10@3290 37 struct vmcs_struct *vmcs;
iap10@3290 38 unsigned int cpu_sig = cpuid_eax(0x00000001);
iap10@3290 39
iap10@3290 40 vmcs = (struct vmcs_struct *) alloc_xenheap_pages(get_order(vmcs_size));
iap10@3290 41 memset((char *) vmcs, 0, vmcs_size); /* don't remove this */
iap10@3290 42
iap10@3290 43 vmcs->vmcs_revision_id = (cpu_sig > 0xf41)? 3 : 1;
iap10@3290 44 return vmcs;
iap10@3290 45 }
iap10@3290 46
iap10@3290 47 void free_vmcs(struct vmcs_struct *vmcs)
iap10@3290 48 {
iap10@3290 49 int order;
iap10@3290 50
iap10@3290 51 order = (vmcs_size >> PAGE_SHIFT) - 1;
iap10@3290 52 free_xenheap_pages((unsigned long) vmcs, order);
iap10@3290 53 }
iap10@3290 54
iap10@3290 55 static inline int construct_vmcs_controls(void)
iap10@3290 56 {
iap10@3290 57 int error = 0;
iap10@3290 58
iap10@3290 59 error |= __vmwrite(PIN_BASED_VM_EXEC_CONTROL,
iap10@3290 60 MONITOR_PIN_BASED_EXEC_CONTROLS);
iap10@3290 61
iap10@3290 62 error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
iap10@3290 63 MONITOR_CPU_BASED_EXEC_CONTROLS);
iap10@3290 64
iap10@3290 65 error |= __vmwrite(VM_EXIT_CONTROLS, MONITOR_VM_EXIT_CONTROLS);
iap10@3290 66 error |= __vmwrite(VM_ENTRY_CONTROLS, MONITOR_VM_ENTRY_CONTROLS);
iap10@3290 67
iap10@3290 68 return error;
iap10@3290 69 }
iap10@3290 70
iap10@3290 71 #define GUEST_SEGMENT_LIMIT 0xffffffff
iap10@3290 72 #define HOST_SEGMENT_LIMIT 0xffffffff
iap10@3290 73
iap10@3290 74 struct host_execution_env {
iap10@3290 75 /* selectors */
iap10@3290 76 unsigned short ldtr_selector;
iap10@3290 77 unsigned short tr_selector;
iap10@3290 78 unsigned short ds_selector;
iap10@3290 79 unsigned short cs_selector;
iap10@3290 80 /* limits */
iap10@3290 81 unsigned short gdtr_limit;
iap10@3290 82 unsigned short ldtr_limit;
iap10@3290 83 unsigned short idtr_limit;
iap10@3290 84 unsigned short tr_limit;
iap10@3290 85 /* base */
iap10@3290 86 unsigned long gdtr_base;
iap10@3290 87 unsigned long ldtr_base;
iap10@3290 88 unsigned long idtr_base;
iap10@3290 89 unsigned long tr_base;
iap10@3290 90 unsigned long ds_base;
iap10@3290 91 unsigned long cs_base;
iap10@3290 92 /* control registers */
iap10@3290 93 unsigned long cr3;
iap10@3290 94 unsigned long cr0;
iap10@3290 95 unsigned long cr4;
iap10@3290 96 unsigned long dr7;
iap10@3290 97 };
iap10@3290 98
iap10@3290 99 #define round_pgdown(_p) ((_p)&PAGE_MASK) /* coped from domain.c */
iap10@3290 100
iap10@3290 101 int vmx_setup_platform(struct exec_domain *d, execution_context_t *context)
iap10@3290 102 {
iap10@3290 103 int i;
iap10@3290 104 unsigned int n;
iap10@3290 105 unsigned long *p, mpfn, offset, addr;
iap10@3290 106 struct e820entry *e820p;
iap10@3290 107 unsigned long gpfn = 0;
iap10@3290 108
iap10@3290 109 context->ebx = 0; /* Linux expects ebx to be 0 for boot proc */
iap10@3290 110
iap10@3290 111 n = context->ecx;
iap10@3290 112 if (n > 32) {
iap10@3290 113 VMX_DBG_LOG(DBG_LEVEL_1, "Too many e820 entries: %d\n", n);
iap10@3290 114 return -1;
iap10@3290 115 }
iap10@3290 116
iap10@3290 117 addr = context->edi;
iap10@3290 118 offset = (addr & ~PAGE_MASK);
iap10@3290 119 addr = round_pgdown(addr);
iap10@3290 120 mpfn = phys_to_machine_mapping[addr >> PAGE_SHIFT];
iap10@3290 121 p = map_domain_mem(mpfn << PAGE_SHIFT);
iap10@3290 122
iap10@3290 123 e820p = (struct e820entry *) ((unsigned long) p + offset);
iap10@3290 124
iap10@3290 125 for (i = 0; i < n; i++) {
iap10@3290 126 if (e820p[i].type == E820_SHARED_PAGE) {
iap10@3290 127 gpfn = (e820p[i].addr >> PAGE_SHIFT);
iap10@3290 128 break;
iap10@3290 129 }
iap10@3290 130 }
iap10@3290 131
iap10@3290 132 if (gpfn == 0) {
iap10@3290 133 VMX_DBG_LOG(DBG_LEVEL_1, "No shared Page ?\n");
iap10@3290 134 return -1;
iap10@3290 135 }
iap10@3290 136 unmap_domain_mem(p);
iap10@3290 137
iap10@3290 138 mpfn = phys_to_machine_mapping[gpfn];
iap10@3290 139 p = map_domain_mem(mpfn << PAGE_SHIFT);
iap10@3290 140 d->thread.arch_vmx.vmx_platform.shared_page_va = (unsigned long) p;
iap10@3290 141
iap10@3290 142 return 0;
iap10@3290 143 }
iap10@3290 144
iap10@3290 145
iap10@3290 146 /*
iap10@3290 147 * Add <guest pfn, machine pfn> mapping to per-domain mapping. Full
iap10@3290 148 * virtualization does not need per-domain mapping.
iap10@3290 149 */
iap10@3290 150 static int add_mapping_perdomain(struct exec_domain *d, unsigned long gpfn,
iap10@3290 151 unsigned long mpfn)
iap10@3290 152 {
iap10@3290 153 struct pfn_info *page;
iap10@3290 154 unsigned long pfn = 0;
iap10@3290 155
iap10@3290 156 /*
iap10@3290 157 * We support up to 4GB memory for a guest at this point
iap10@3290 158 */
iap10@3290 159 if (gpfn > ENTRIES_PER_L2_PAGETABLE * ENTRIES_PER_L1_PAGETABLE)
iap10@3290 160 return -1;
iap10@3290 161
iap10@3290 162 if (!(l1_pgentry_val(d->domain->mm_perdomain_pt[
iap10@3290 163 gpfn >> (L2_PAGETABLE_SHIFT - L1_PAGETABLE_SHIFT)]) & _PAGE_PRESENT))
iap10@3290 164 {
iap10@3290 165 page = (struct pfn_info *) alloc_domheap_page(NULL);
iap10@3290 166 if (!page) {
iap10@3290 167 return -1;
iap10@3290 168 }
iap10@3290 169
iap10@3290 170 pfn = (unsigned long) (page - frame_table);
iap10@3290 171 d->domain->mm_perdomain_pt[gpfn >> (L2_PAGETABLE_SHIFT - L1_PAGETABLE_SHIFT)] =
iap10@3290 172 mk_l1_pgentry((pfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
iap10@3290 173 }
iap10@3290 174 phys_to_machine_mapping[gpfn] = mpfn;
iap10@3290 175
iap10@3290 176 return 0;
iap10@3290 177 }
iap10@3290 178
iap10@3290 179 void vmx_do_launch(struct exec_domain *ed)
iap10@3290 180 {
iap10@3290 181 /* Update CR3, GDT, LDT, TR */
iap10@3290 182 unsigned int tr, cpu, error = 0;
iap10@3290 183 struct host_execution_env host_env;
iap10@3290 184 struct Xgt_desc_struct desc;
iap10@3290 185 struct list_head *list_ent;
iap10@3290 186 l2_pgentry_t *mpl2e, *guest_pl2e_cache;
iap10@3290 187 unsigned long i, pfn = 0;
iap10@3290 188 struct pfn_info *page;
iap10@3290 189 execution_context_t *ec = get_execution_context();
iap10@3290 190 struct domain *d = ed->domain;
iap10@3290 191
iap10@3290 192 cpu = smp_processor_id();
iap10@3290 193 ed->mm.min_pfn = ed->mm.max_pfn = 0;
iap10@3290 194
iap10@3290 195 spin_lock(&d->page_alloc_lock);
iap10@3290 196 list_ent = d->page_list.next;
iap10@3290 197
iap10@3290 198 mpl2e = (l2_pgentry_t *) map_domain_mem(pagetable_val(ed->mm.monitor_table));
iap10@3290 199 ASSERT(mpl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT]);
iap10@3290 200
iap10@3290 201 for (i = 0; list_ent != &d->page_list; i++ ) {
iap10@3290 202 pfn = list_entry(list_ent, struct pfn_info, list) - frame_table;
iap10@3290 203 ed->mm.min_pfn = min(ed->mm.min_pfn, pfn);
iap10@3290 204 ed->mm.max_pfn = max(ed->mm.max_pfn, pfn);
iap10@3290 205 list_ent = frame_table[pfn].list.next;
iap10@3290 206 add_mapping_perdomain(ed, i, pfn);
iap10@3290 207 }
iap10@3290 208
iap10@3290 209 spin_unlock(&d->page_alloc_lock);
iap10@3290 210
iap10@3290 211 page = (struct pfn_info *) alloc_domheap_page(NULL);
iap10@3290 212 pfn = (unsigned long) (page - frame_table);
iap10@3290 213
iap10@3290 214 /*
iap10@3290 215 * make linear_pt_table work for guest ptes
iap10@3290 216 */
iap10@3290 217 mpl2e[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
iap10@3290 218 mk_l2_pgentry((pfn << PAGE_SHIFT)| __PAGE_HYPERVISOR);
iap10@3290 219
iap10@3290 220 guest_pl2e_cache = map_domain_mem(pfn << PAGE_SHIFT);
iap10@3290 221 memset(guest_pl2e_cache, 0, PAGE_SIZE); /* clean it up */
iap10@3290 222 ed->mm.guest_pl2e_cache = guest_pl2e_cache;
iap10@3290 223
iap10@3290 224 unmap_domain_mem(mpl2e);
iap10@3290 225
iap10@3290 226 vmx_setup_platform(ed, ec);
iap10@3290 227
iap10@3290 228 __asm__ __volatile__ ("sgdt (%%eax) \n" :: "a"(&desc) : "memory");
iap10@3290 229 host_env.gdtr_limit = desc.size;
iap10@3290 230 host_env.gdtr_base = desc.address;
iap10@3290 231
iap10@3290 232 error |= __vmwrite(HOST_GDTR_BASE, host_env.gdtr_base);
iap10@3290 233
iap10@3290 234 error |= __vmwrite(GUEST_LDTR_SELECTOR, 0);
iap10@3290 235 error |= __vmwrite(GUEST_LDTR_BASE, 0);
iap10@3290 236 error |= __vmwrite(GUEST_LDTR_LIMIT, 0);
iap10@3290 237
iap10@3290 238 __asm__ __volatile__ ("str (%%eax) \n" :: "a"(&tr) : "memory");
iap10@3290 239 host_env.tr_selector = tr;
iap10@3290 240 host_env.tr_limit = sizeof(struct tss_struct);
iap10@3290 241 host_env.tr_base = (unsigned long) &init_tss[cpu];
iap10@3290 242
iap10@3290 243 error |= __vmwrite(HOST_TR_SELECTOR, host_env.tr_selector);
iap10@3290 244 error |= __vmwrite(HOST_TR_BASE, host_env.tr_base);
iap10@3290 245 error |= __vmwrite(GUEST_TR_BASE, 0);
iap10@3290 246 error |= __vmwrite(GUEST_TR_LIMIT, 0xff);
iap10@3290 247
iap10@3290 248 ed->mm.shadow_table = ed->mm.pagetable;
iap10@3290 249 __vmwrite(GUEST_CR3, pagetable_val(ed->mm.pagetable));
iap10@3290 250 __vmwrite(HOST_CR3, pagetable_val(ed->mm.monitor_table));
iap10@3290 251 __vmwrite(HOST_ESP, (unsigned long) get_stack_top());
iap10@3290 252
iap10@3290 253 ed->thread.schedule_tail = arch_vmx_do_resume;
iap10@3290 254 }
iap10@3290 255
iap10@3290 256 /*
iap10@3290 257 * Initially set the same environement as host.
iap10@3290 258 */
iap10@3290 259 static inline int
iap10@3290 260 construct_init_vmcs_guest(execution_context_t *context,
iap10@3290 261 full_execution_context_t *full_context,
iap10@3290 262 struct host_execution_env *host_env)
iap10@3290 263 {
iap10@3290 264 int error = 0;
iap10@3290 265 union vmcs_arbytes arbytes;
iap10@3290 266 unsigned long dr7;
iap10@3290 267 unsigned long eflags, shadow_cr;
iap10@3290 268
iap10@3290 269 /* MSR */
iap10@3290 270 error |= __vmwrite(VM_EXIT_MSR_LOAD_ADDR, 0);
iap10@3290 271 error |= __vmwrite(VM_EXIT_MSR_STORE_ADDR, 0);
iap10@3290 272
iap10@3290 273 error |= __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0);
iap10@3290 274 error |= __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0);
iap10@3290 275 error |= __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0);
iap10@3290 276 /* interrupt */
iap10@3290 277 error |= __vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0);
iap10@3290 278 /* mask */
iap10@3290 279 error |= __vmwrite(CR0_GUEST_HOST_MASK, 0xffffffff);
iap10@3290 280 error |= __vmwrite(CR4_GUEST_HOST_MASK, 0xffffffff);
iap10@3290 281
iap10@3290 282 error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0);
iap10@3290 283 error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0);
iap10@3290 284
iap10@3290 285 /* TSC */
iap10@3290 286 error |= __vmwrite(TSC_OFFSET, 0);
iap10@3290 287 error |= __vmwrite(CR3_TARGET_COUNT, 0);
iap10@3290 288
iap10@3290 289 /* Guest Selectors */
iap10@3290 290 error |= __vmwrite(GUEST_CS_SELECTOR, context->cs);
iap10@3290 291 error |= __vmwrite(GUEST_ES_SELECTOR, context->es);
iap10@3290 292 error |= __vmwrite(GUEST_SS_SELECTOR, context->ss);
iap10@3290 293 error |= __vmwrite(GUEST_DS_SELECTOR, context->ds);
iap10@3290 294 error |= __vmwrite(GUEST_FS_SELECTOR, context->fs);
iap10@3290 295 error |= __vmwrite(GUEST_GS_SELECTOR, context->gs);
iap10@3290 296
iap10@3290 297 /* Guest segment Limits */
iap10@3290 298 error |= __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT);
iap10@3290 299 error |= __vmwrite(GUEST_ES_LIMIT, GUEST_SEGMENT_LIMIT);
iap10@3290 300 error |= __vmwrite(GUEST_SS_LIMIT, GUEST_SEGMENT_LIMIT);
iap10@3290 301 error |= __vmwrite(GUEST_DS_LIMIT, GUEST_SEGMENT_LIMIT);
iap10@3290 302 error |= __vmwrite(GUEST_FS_LIMIT, GUEST_SEGMENT_LIMIT);
iap10@3290 303 error |= __vmwrite(GUEST_GS_LIMIT, GUEST_SEGMENT_LIMIT);
iap10@3290 304
iap10@3290 305 error |= __vmwrite(GUEST_IDTR_LIMIT, host_env->idtr_limit);
iap10@3290 306
iap10@3290 307 /* AR bytes */
iap10@3290 308 arbytes.bytes = 0;
iap10@3290 309 arbytes.fields.seg_type = 0x3; /* type = 3 */
iap10@3290 310 arbytes.fields.s = 1; /* code or data, i.e. not system */
iap10@3290 311 arbytes.fields.dpl = 0; /* DPL = 3 */
iap10@3290 312 arbytes.fields.p = 1; /* segment present */
iap10@3290 313 arbytes.fields.default_ops_size = 1; /* 32-bit */
iap10@3290 314 arbytes.fields.g = 1;
iap10@3290 315 arbytes.fields.null_bit = 0; /* not null */
iap10@3290 316
iap10@3290 317 error |= __vmwrite(GUEST_ES_AR_BYTES, arbytes.bytes);
iap10@3290 318 error |= __vmwrite(GUEST_SS_AR_BYTES, arbytes.bytes);
iap10@3290 319 error |= __vmwrite(GUEST_DS_AR_BYTES, arbytes.bytes);
iap10@3290 320 error |= __vmwrite(GUEST_FS_AR_BYTES, arbytes.bytes);
iap10@3290 321 error |= __vmwrite(GUEST_GS_AR_BYTES, arbytes.bytes);
iap10@3290 322
iap10@3290 323 arbytes.fields.seg_type = 0xb; /* type = 0xb */
iap10@3290 324 error |= __vmwrite(GUEST_CS_AR_BYTES, arbytes.bytes);
iap10@3290 325
iap10@3290 326 error |= __vmwrite(GUEST_GDTR_BASE, context->edx);
iap10@3290 327 context->edx = 0;
iap10@3290 328 error |= __vmwrite(GUEST_GDTR_LIMIT, context->eax);
iap10@3290 329 context->eax = 0;
iap10@3290 330
iap10@3290 331 arbytes.fields.s = 0; /* not code or data segement */
iap10@3290 332 arbytes.fields.seg_type = 0x2; /* LTD */
iap10@3290 333 arbytes.fields.default_ops_size = 0; /* 16-bit */
iap10@3290 334 arbytes.fields.g = 0;
iap10@3290 335 error |= __vmwrite(GUEST_LDTR_AR_BYTES, arbytes.bytes);
iap10@3290 336
iap10@3290 337 arbytes.fields.seg_type = 0xb; /* 32-bit TSS (busy) */
iap10@3290 338 error |= __vmwrite(GUEST_TR_AR_BYTES, arbytes.bytes);
iap10@3290 339
iap10@3290 340 error |= __vmwrite(GUEST_CR0, host_env->cr0); /* same CR0 */
iap10@3290 341
iap10@3290 342 /* Initally PG, PE are not set*/
iap10@3290 343 shadow_cr = host_env->cr0;
iap10@3290 344 shadow_cr &= ~(X86_CR0_PE | X86_CR0_PG);
iap10@3290 345 error |= __vmwrite(CR0_READ_SHADOW, shadow_cr);
iap10@3290 346 /* CR3 is set in vmx_final_setup_guestos */
iap10@3290 347 error |= __vmwrite(GUEST_CR4, host_env->cr4);
iap10@3290 348 shadow_cr = host_env->cr4;
iap10@3290 349 shadow_cr &= ~(X86_CR4_PGE | X86_CR4_VMXE);
iap10@3290 350 error |= __vmwrite(CR4_READ_SHADOW, shadow_cr);
iap10@3290 351
iap10@3290 352 error |= __vmwrite(GUEST_ES_BASE, host_env->ds_base);
iap10@3290 353 error |= __vmwrite(GUEST_CS_BASE, host_env->cs_base);
iap10@3290 354 error |= __vmwrite(GUEST_SS_BASE, host_env->ds_base);
iap10@3290 355 error |= __vmwrite(GUEST_DS_BASE, host_env->ds_base);
iap10@3290 356 error |= __vmwrite(GUEST_FS_BASE, host_env->ds_base);
iap10@3290 357 error |= __vmwrite(GUEST_GS_BASE, host_env->ds_base);
iap10@3290 358 error |= __vmwrite(GUEST_IDTR_BASE, host_env->idtr_base);
iap10@3290 359
iap10@3290 360 error |= __vmwrite(GUEST_ESP, context->esp);
iap10@3290 361 error |= __vmwrite(GUEST_EIP, context->eip);
iap10@3290 362
iap10@3290 363 eflags = context->eflags & ~VMCS_EFLAGS_RESERVED_0; /* clear 0s */
iap10@3290 364 eflags |= VMCS_EFLAGS_RESERVED_1; /* set 1s */
iap10@3290 365
iap10@3290 366 error |= __vmwrite(GUEST_EFLAGS, eflags);
iap10@3290 367
iap10@3290 368 error |= __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
iap10@3290 369 __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7));
iap10@3290 370 error |= __vmwrite(GUEST_DR7, dr7);
iap10@3290 371 error |= __vmwrite(GUEST_VMCS0, 0xffffffff);
iap10@3290 372 error |= __vmwrite(GUEST_VMCS1, 0xffffffff);
iap10@3290 373
iap10@3290 374 return error;
iap10@3290 375 }
iap10@3290 376
iap10@3290 377 static inline int construct_vmcs_host(struct host_execution_env *host_env)
iap10@3290 378 {
iap10@3290 379 int error = 0;
iap10@3290 380 unsigned long crn;
iap10@3290 381 struct Xgt_desc_struct desc;
iap10@3290 382
iap10@3290 383 /* Host Selectors */
iap10@3290 384 host_env->ds_selector = __HYPERVISOR_DS;
iap10@3290 385 error |= __vmwrite(HOST_ES_SELECTOR, host_env->ds_selector);
iap10@3290 386 error |= __vmwrite(HOST_SS_SELECTOR, host_env->ds_selector);
iap10@3290 387 error |= __vmwrite(HOST_DS_SELECTOR, host_env->ds_selector);
iap10@3290 388 error |= __vmwrite(HOST_FS_SELECTOR, host_env->ds_selector);
iap10@3290 389 error |= __vmwrite(HOST_GS_SELECTOR, host_env->ds_selector);
iap10@3290 390
iap10@3290 391 host_env->cs_selector = __HYPERVISOR_CS;
iap10@3290 392 error |= __vmwrite(HOST_CS_SELECTOR, host_env->cs_selector);
iap10@3290 393
iap10@3290 394 host_env->ds_base = 0;
iap10@3290 395 host_env->cs_base = 0;
iap10@3290 396 error |= __vmwrite(HOST_FS_BASE, host_env->ds_base);
iap10@3290 397 error |= __vmwrite(HOST_GS_BASE, host_env->ds_base);
iap10@3290 398
iap10@3290 399 /* Debug */
iap10@3290 400 __asm__ __volatile__ ("sidt (%%eax) \n" :: "a"(&desc) : "memory");
iap10@3290 401 host_env->idtr_limit = desc.size;
iap10@3290 402 host_env->idtr_base = desc.address;
iap10@3290 403 error |= __vmwrite(HOST_IDTR_BASE, host_env->idtr_base);
iap10@3290 404
iap10@3290 405 __asm__ __volatile__ ("movl %%cr0,%0" : "=r" (crn) : );
iap10@3290 406 host_env->cr0 = crn;
iap10@3290 407 error |= __vmwrite(HOST_CR0, crn); /* same CR0 */
iap10@3290 408
iap10@3290 409 /* CR3 is set in vmx_final_setup_hostos */
iap10@3290 410 __asm__ __volatile__ ("movl %%cr4,%0" : "=r" (crn) : );
iap10@3290 411 host_env->cr4 = crn;
iap10@3290 412 error |= __vmwrite(HOST_CR4, crn);
iap10@3290 413 error |= __vmwrite(HOST_EIP, (unsigned long) vmx_asm_vmexit_handler);
iap10@3290 414
iap10@3290 415 return error;
iap10@3290 416 }
iap10@3290 417
iap10@3290 418 /*
iap10@3290 419 * Need to extend to support full virtualization.
iap10@3290 420 * The variable use_host_env indicates if the new VMCS needs to use
iap10@3290 421 * the same setups as the host has (xenolinux).
iap10@3290 422 */
iap10@3290 423
iap10@3290 424 int construct_vmcs(struct arch_vmx_struct *arch_vmx,
iap10@3290 425 execution_context_t *context,
iap10@3290 426 full_execution_context_t *full_context,
iap10@3290 427 int use_host_env)
iap10@3290 428 {
iap10@3290 429 int error;
iap10@3290 430 u64 vmcs_phys_ptr;
iap10@3290 431
iap10@3290 432 struct host_execution_env host_env;
iap10@3290 433
iap10@3290 434 if (use_host_env != VMCS_USE_HOST_ENV)
iap10@3290 435 return -EINVAL;
iap10@3290 436
iap10@3290 437 memset(&host_env, 0, sizeof(struct host_execution_env));
iap10@3290 438
iap10@3290 439 vmcs_phys_ptr = (u64) virt_to_phys(arch_vmx->vmcs);
iap10@3290 440
iap10@3290 441 if ((error = __vmpclear (vmcs_phys_ptr))) {
iap10@3290 442 printk("construct_vmcs: VMCLEAR failed\n");
iap10@3290 443 return -EINVAL;
iap10@3290 444 }
iap10@3290 445 if ((error = load_vmcs(arch_vmx, vmcs_phys_ptr))) {
iap10@3290 446 printk("construct_vmcs: load_vmcs failed: VMCS = %lx\n",
iap10@3290 447 (unsigned long) vmcs_phys_ptr);
iap10@3290 448 return -EINVAL;
iap10@3290 449 }
iap10@3290 450 if ((error = construct_vmcs_controls())) {
iap10@3290 451 printk("construct_vmcs: construct_vmcs_controls failed\n");
iap10@3290 452 return -EINVAL;
iap10@3290 453 }
iap10@3290 454 /* host selectors */
iap10@3290 455 if ((error = construct_vmcs_host(&host_env))) {
iap10@3290 456 printk("construct_vmcs: construct_vmcs_host failed\n");
iap10@3290 457 return -EINVAL;
iap10@3290 458 }
iap10@3290 459 /* guest selectors */
iap10@3290 460 if ((error = construct_init_vmcs_guest(context, full_context, &host_env))) {
iap10@3290 461 printk("construct_vmcs: construct_vmcs_guest failed\n");
iap10@3290 462 return -EINVAL;
iap10@3290 463 }
iap10@3290 464
iap10@3290 465 if ((error |= __vmwrite(EXCEPTION_BITMAP,
iap10@3290 466 MONITOR_DEFAULT_EXCEPTION_BITMAP))) {
iap10@3290 467 printk("construct_vmcs: setting Exception bitmap failed\n");
iap10@3290 468 return -EINVAL;
iap10@3290 469 }
iap10@3290 470
iap10@3290 471 return 0;
iap10@3290 472 }
iap10@3290 473
iap10@3290 474 int load_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
iap10@3290 475 {
iap10@3290 476 int error;
iap10@3290 477
iap10@3290 478 if ((error = __vmptrld(phys_ptr))) {
iap10@3290 479 clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
iap10@3290 480 return error;
iap10@3290 481 }
iap10@3290 482 set_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
iap10@3290 483 return 0;
iap10@3290 484 }
iap10@3290 485
iap10@3290 486 int store_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
iap10@3290 487 {
iap10@3290 488 /* take the current VMCS */
iap10@3290 489 __vmptrst(phys_ptr);
iap10@3290 490 clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
iap10@3290 491 return 0;
iap10@3290 492 }
iap10@3290 493
iap10@3290 494 void vm_launch_fail(unsigned long eflags)
iap10@3290 495 {
iap10@3290 496 BUG();
iap10@3290 497 }
iap10@3290 498
iap10@3290 499 void vm_resume_fail(unsigned long eflags)
iap10@3290 500 {
iap10@3290 501 BUG();
iap10@3290 502 }
iap10@3290 503