xen-vtx-unstable
annotate xen/arch/x86/vmx_vmcs.c @ 6100:bf98996dded2
Separate out VMCS host state initialization from the rest
This is needed to support virtual cpu migration, because the host state
initialization is done on every migration, but the rest of the initialization
is done once per vcpu.
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Signed-off-by: Arun Sharma <arun.sharma@intel.com>
This is needed to support virtual cpu migration, because the host state
initialization is done on every migration, but the rest of the initialization
is done once per vcpu.
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Signed-off-by: Arun Sharma <arun.sharma@intel.com>
author | kaf24@firebug.cl.cam.ac.uk |
---|---|
date | Thu Aug 11 21:01:36 2005 +0000 (2005-08-11) |
parents | d1034eae9708 |
children | 57b3fdca5dae |
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> |
kaf24@5356 | 25 #include <xen/domain_page.h> |
cl349@5291 | 26 #include <asm/current.h> |
iap10@3290 | 27 #include <asm/cpufeature.h> |
iap10@3290 | 28 #include <asm/processor.h> |
iap10@3290 | 29 #include <asm/msr.h> |
iap10@3290 | 30 #include <asm/vmx.h> |
kaf24@5722 | 31 #include <asm/flushtlb.h> |
iap10@3290 | 32 #include <xen/event.h> |
iap10@3290 | 33 #include <xen/kernel.h> |
iap10@3290 | 34 #include <public/io/ioreq.h> |
kaf24@5722 | 35 #if CONFIG_PAGING_LEVELS >= 4 |
kaf24@5722 | 36 #include <asm/shadow_64.h> |
kaf24@5722 | 37 #endif |
mafetter@3717 | 38 #ifdef CONFIG_VMX |
mafetter@3717 | 39 |
iap10@3290 | 40 struct vmcs_struct *alloc_vmcs(void) |
iap10@3290 | 41 { |
iap10@3290 | 42 struct vmcs_struct *vmcs; |
kaf24@5059 | 43 u32 vmx_msr_low, vmx_msr_high; |
iap10@3290 | 44 |
kaf24@5059 | 45 rdmsr(MSR_IA32_VMX_BASIC_MSR, vmx_msr_low, vmx_msr_high); |
kaf24@5059 | 46 vmcs_size = vmx_msr_high & 0x1fff; |
kaf24@5398 | 47 vmcs = alloc_xenheap_pages(get_order(vmcs_size)); |
kaf24@5398 | 48 memset((char *)vmcs, 0, vmcs_size); /* don't remove this */ |
iap10@3290 | 49 |
kaf24@5059 | 50 vmcs->vmcs_revision_id = vmx_msr_low; |
iap10@3290 | 51 return vmcs; |
iap10@3290 | 52 } |
iap10@3290 | 53 |
iap10@3290 | 54 void free_vmcs(struct vmcs_struct *vmcs) |
iap10@3290 | 55 { |
iap10@3290 | 56 int order; |
iap10@3290 | 57 |
kaf24@5775 | 58 order = get_order(vmcs_size); |
kaf24@5398 | 59 free_xenheap_pages(vmcs, order); |
iap10@3290 | 60 } |
iap10@3290 | 61 |
kaf24@5836 | 62 static inline int construct_vmcs_controls(struct arch_vmx_struct *arch_vmx) |
iap10@3290 | 63 { |
iap10@3290 | 64 int error = 0; |
kaf24@5836 | 65 void *io_bitmap_a; |
kaf24@5836 | 66 void *io_bitmap_b; |
kaf24@5775 | 67 |
iap10@3290 | 68 error |= __vmwrite(PIN_BASED_VM_EXEC_CONTROL, |
iap10@3290 | 69 MONITOR_PIN_BASED_EXEC_CONTROLS); |
iap10@3290 | 70 |
iap10@3290 | 71 error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL, |
iap10@3290 | 72 MONITOR_CPU_BASED_EXEC_CONTROLS); |
kaf24@5775 | 73 |
iap10@3290 | 74 error |= __vmwrite(VM_EXIT_CONTROLS, MONITOR_VM_EXIT_CONTROLS); |
kaf24@5775 | 75 |
iap10@3290 | 76 error |= __vmwrite(VM_ENTRY_CONTROLS, MONITOR_VM_ENTRY_CONTROLS); |
iap10@3290 | 77 |
kaf24@5836 | 78 /* need to use 0x1000 instead of PAGE_SIZE */ |
kaf24@5836 | 79 io_bitmap_a = (void*) alloc_xenheap_pages(get_order(0x1000)); |
kaf24@5836 | 80 io_bitmap_b = (void*) alloc_xenheap_pages(get_order(0x1000)); |
kaf24@5836 | 81 memset(io_bitmap_a, 0xff, 0x1000); |
kaf24@5836 | 82 /* don't bother debug port access */ |
kaf24@5836 | 83 clear_bit(PC_DEBUG_PORT, io_bitmap_a); |
kaf24@5836 | 84 memset(io_bitmap_b, 0xff, 0x1000); |
kaf24@5836 | 85 |
kaf24@5836 | 86 error |= __vmwrite(IO_BITMAP_A, (u64) virt_to_phys(io_bitmap_a)); |
kaf24@5836 | 87 error |= __vmwrite(IO_BITMAP_B, (u64) virt_to_phys(io_bitmap_b)); |
kaf24@5836 | 88 |
kaf24@5836 | 89 arch_vmx->io_bitmap_a = io_bitmap_a; |
kaf24@5836 | 90 arch_vmx->io_bitmap_b = io_bitmap_b; |
kaf24@5836 | 91 |
iap10@3290 | 92 return error; |
iap10@3290 | 93 } |
iap10@3290 | 94 |
iap10@3290 | 95 #define GUEST_SEGMENT_LIMIT 0xffffffff |
iap10@3290 | 96 #define HOST_SEGMENT_LIMIT 0xffffffff |
iap10@3290 | 97 |
iap10@3290 | 98 struct host_execution_env { |
iap10@3290 | 99 /* selectors */ |
iap10@3290 | 100 unsigned short ldtr_selector; |
iap10@3290 | 101 unsigned short tr_selector; |
iap10@3290 | 102 unsigned short ds_selector; |
iap10@3290 | 103 unsigned short cs_selector; |
iap10@3290 | 104 /* limits */ |
iap10@3290 | 105 unsigned short gdtr_limit; |
iap10@3290 | 106 unsigned short ldtr_limit; |
iap10@3290 | 107 unsigned short idtr_limit; |
iap10@3290 | 108 unsigned short tr_limit; |
iap10@3290 | 109 /* base */ |
iap10@3290 | 110 unsigned long gdtr_base; |
iap10@3290 | 111 unsigned long ldtr_base; |
iap10@3290 | 112 unsigned long idtr_base; |
iap10@3290 | 113 unsigned long tr_base; |
iap10@3290 | 114 unsigned long ds_base; |
iap10@3290 | 115 unsigned long cs_base; |
kaf24@5658 | 116 #ifdef __x86_64__ |
kaf24@5658 | 117 unsigned long fs_base; |
kaf24@5658 | 118 unsigned long gs_base; |
kaf24@5658 | 119 #endif |
kaf24@5658 | 120 |
iap10@3290 | 121 /* control registers */ |
iap10@3290 | 122 unsigned long cr3; |
iap10@3290 | 123 unsigned long cr0; |
iap10@3290 | 124 unsigned long cr4; |
iap10@3290 | 125 unsigned long dr7; |
iap10@3290 | 126 }; |
iap10@3290 | 127 |
iap10@3290 | 128 #define round_pgdown(_p) ((_p)&PAGE_MASK) /* coped from domain.c */ |
iap10@3290 | 129 |
kaf24@5289 | 130 int vmx_setup_platform(struct vcpu *d, struct cpu_user_regs *regs) |
iap10@3290 | 131 { |
iap10@3290 | 132 int i; |
iap10@3290 | 133 unsigned int n; |
iap10@3290 | 134 unsigned long *p, mpfn, offset, addr; |
iap10@3290 | 135 struct e820entry *e820p; |
iap10@3290 | 136 unsigned long gpfn = 0; |
iap10@3290 | 137 |
kaf24@5727 | 138 local_flush_tlb_pge(); |
kaf24@4683 | 139 regs->ebx = 0; /* Linux expects ebx to be 0 for boot proc */ |
iap10@3290 | 140 |
kaf24@4683 | 141 n = regs->ecx; |
iap10@3290 | 142 if (n > 32) { |
maf46@3855 | 143 VMX_DBG_LOG(DBG_LEVEL_1, "Too many e820 entries: %d", n); |
iap10@3290 | 144 return -1; |
iap10@3290 | 145 } |
iap10@3290 | 146 |
kaf24@4683 | 147 addr = regs->edi; |
iap10@3290 | 148 offset = (addr & ~PAGE_MASK); |
iap10@3290 | 149 addr = round_pgdown(addr); |
kaf24@5356 | 150 |
iap10@3707 | 151 mpfn = phys_to_machine_mapping(addr >> PAGE_SHIFT); |
kaf24@5356 | 152 p = map_domain_page(mpfn); |
iap10@3290 | 153 |
iap10@3290 | 154 e820p = (struct e820entry *) ((unsigned long) p + offset); |
iap10@3290 | 155 |
maf46@3880 | 156 #ifndef NDEBUG |
maf46@3880 | 157 print_e820_memory_map(e820p, n); |
maf46@3880 | 158 #endif |
maf46@3880 | 159 |
kaf24@5356 | 160 for ( i = 0; i < n; i++ ) |
kaf24@5356 | 161 { |
kaf24@5356 | 162 if ( e820p[i].type == E820_SHARED_PAGE ) |
kaf24@5356 | 163 { |
iap10@3290 | 164 gpfn = (e820p[i].addr >> PAGE_SHIFT); |
iap10@3290 | 165 break; |
iap10@3290 | 166 } |
iap10@3290 | 167 } |
iap10@3290 | 168 |
kaf24@5356 | 169 if ( gpfn == 0 ) |
kaf24@5356 | 170 { |
kaf24@5356 | 171 unmap_domain_page(p); |
iap10@3290 | 172 return -1; |
iap10@3290 | 173 } |
iap10@3290 | 174 |
kaf24@5356 | 175 unmap_domain_page(p); |
iap10@3748 | 176 |
iap10@3748 | 177 /* Initialise shared page */ |
kaf24@5356 | 178 mpfn = phys_to_machine_mapping(gpfn); |
kaf24@5356 | 179 p = map_domain_page(mpfn); |
arun@5608 | 180 d->domain->arch.vmx_platform.shared_page_va = (unsigned long)p; |
arun@5608 | 181 |
arun@5615 | 182 VMX_DBG_LOG(DBG_LEVEL_1, "eport: %x\n", iopacket_port(d->domain)); |
arun@5615 | 183 |
arun@5608 | 184 clear_bit(iopacket_port(d->domain), |
arun@5608 | 185 &d->domain->shared_info->evtchn_mask[0]); |
iap10@3290 | 186 |
iap10@3290 | 187 return 0; |
iap10@3290 | 188 } |
iap10@3290 | 189 |
kaf24@6100 | 190 void vmx_set_host_env(struct vcpu *v) |
iap10@3290 | 191 { |
iap10@3290 | 192 unsigned int tr, cpu, error = 0; |
iap10@3290 | 193 struct host_execution_env host_env; |
iap10@3290 | 194 struct Xgt_desc_struct desc; |
cl349@4856 | 195 |
kaf24@4633 | 196 cpu = smp_processor_id(); |
kaf24@5820 | 197 __asm__ __volatile__ ("sidt (%0) \n" :: "a"(&desc) : "memory"); |
kaf24@5820 | 198 host_env.idtr_limit = desc.size; |
kaf24@5820 | 199 host_env.idtr_base = desc.address; |
kaf24@5820 | 200 error |= __vmwrite(HOST_IDTR_BASE, host_env.idtr_base); |
kaf24@5820 | 201 |
arun@4585 | 202 __asm__ __volatile__ ("sgdt (%0) \n" :: "a"(&desc) : "memory"); |
iap10@3290 | 203 host_env.gdtr_limit = desc.size; |
iap10@3290 | 204 host_env.gdtr_base = desc.address; |
iap10@3290 | 205 error |= __vmwrite(HOST_GDTR_BASE, host_env.gdtr_base); |
iap10@3290 | 206 |
kaf24@6100 | 207 __asm__ __volatile__ ("str (%0) \n" :: "a"(&tr) : "memory"); |
kaf24@6100 | 208 host_env.tr_selector = tr; |
kaf24@6100 | 209 host_env.tr_limit = sizeof(struct tss_struct); |
kaf24@6100 | 210 host_env.tr_base = (unsigned long) &init_tss[cpu]; |
kaf24@6100 | 211 error |= __vmwrite(HOST_TR_SELECTOR, host_env.tr_selector); |
kaf24@6100 | 212 error |= __vmwrite(HOST_TR_BASE, host_env.tr_base); |
kaf24@6100 | 213 |
kaf24@6100 | 214 } |
kaf24@6100 | 215 |
kaf24@6100 | 216 void vmx_do_launch(struct vcpu *v) |
kaf24@6100 | 217 { |
kaf24@6100 | 218 /* Update CR3, GDT, LDT, TR */ |
kaf24@6100 | 219 unsigned int error = 0; |
kaf24@6100 | 220 unsigned long pfn = 0; |
kaf24@6100 | 221 struct pfn_info *page; |
kaf24@6100 | 222 struct cpu_user_regs *regs = guest_cpu_user_regs(); |
kaf24@6100 | 223 |
kaf24@6100 | 224 vmx_stts(); |
kaf24@6100 | 225 |
kaf24@6100 | 226 page = (struct pfn_info *) alloc_domheap_page(NULL); |
kaf24@6100 | 227 pfn = (unsigned long) (page - frame_table); |
kaf24@6100 | 228 |
kaf24@6100 | 229 vmx_setup_platform(v, regs); |
kaf24@6100 | 230 |
kaf24@6100 | 231 vmx_set_host_env(v); |
kaf24@6100 | 232 |
iap10@3290 | 233 error |= __vmwrite(GUEST_LDTR_SELECTOR, 0); |
iap10@3290 | 234 error |= __vmwrite(GUEST_LDTR_BASE, 0); |
iap10@3290 | 235 error |= __vmwrite(GUEST_LDTR_LIMIT, 0); |
iap10@3290 | 236 |
iap10@3290 | 237 error |= __vmwrite(GUEST_TR_BASE, 0); |
iap10@3290 | 238 error |= __vmwrite(GUEST_TR_LIMIT, 0xff); |
iap10@3290 | 239 |
kaf24@5289 | 240 __vmwrite(GUEST_CR3, pagetable_get_paddr(v->arch.guest_table)); |
kaf24@5289 | 241 __vmwrite(HOST_CR3, pagetable_get_paddr(v->arch.monitor_table)); |
kaf24@5414 | 242 __vmwrite(HOST_RSP, (unsigned long)get_stack_bottom()); |
iap10@3290 | 243 |
kaf24@5289 | 244 v->arch.schedule_tail = arch_vmx_do_resume; |
iap10@3290 | 245 } |
iap10@3290 | 246 |
iap10@3290 | 247 /* |
iap10@3290 | 248 * Initially set the same environement as host. |
iap10@3290 | 249 */ |
iap10@3290 | 250 static inline int |
kaf24@4683 | 251 construct_init_vmcs_guest(struct cpu_user_regs *regs, |
kaf24@4683 | 252 struct vcpu_guest_context *ctxt, |
iap10@3290 | 253 struct host_execution_env *host_env) |
iap10@3290 | 254 { |
iap10@3290 | 255 int error = 0; |
iap10@3290 | 256 union vmcs_arbytes arbytes; |
iap10@3290 | 257 unsigned long dr7; |
iap10@3290 | 258 unsigned long eflags, shadow_cr; |
iap10@3290 | 259 |
iap10@3290 | 260 /* MSR */ |
iap10@3290 | 261 error |= __vmwrite(VM_EXIT_MSR_LOAD_ADDR, 0); |
iap10@3290 | 262 error |= __vmwrite(VM_EXIT_MSR_STORE_ADDR, 0); |
iap10@3290 | 263 |
iap10@3290 | 264 error |= __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0); |
iap10@3290 | 265 error |= __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0); |
iap10@3290 | 266 error |= __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0); |
iap10@3290 | 267 /* interrupt */ |
iap10@3290 | 268 error |= __vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0); |
iap10@3290 | 269 /* mask */ |
kaf24@5658 | 270 error |= __vmwrite(CR0_GUEST_HOST_MASK, -1UL); |
kaf24@5658 | 271 error |= __vmwrite(CR4_GUEST_HOST_MASK, -1UL); |
iap10@3290 | 272 |
iap10@3290 | 273 error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0); |
iap10@3290 | 274 error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0); |
iap10@3290 | 275 |
iap10@3290 | 276 /* TSC */ |
iap10@3290 | 277 error |= __vmwrite(TSC_OFFSET, 0); |
iap10@3290 | 278 error |= __vmwrite(CR3_TARGET_COUNT, 0); |
iap10@3290 | 279 |
iap10@3290 | 280 /* Guest Selectors */ |
kaf24@4683 | 281 error |= __vmwrite(GUEST_CS_SELECTOR, regs->cs); |
kaf24@4683 | 282 error |= __vmwrite(GUEST_ES_SELECTOR, regs->es); |
kaf24@4683 | 283 error |= __vmwrite(GUEST_SS_SELECTOR, regs->ss); |
kaf24@4683 | 284 error |= __vmwrite(GUEST_DS_SELECTOR, regs->ds); |
kaf24@4683 | 285 error |= __vmwrite(GUEST_FS_SELECTOR, regs->fs); |
kaf24@4683 | 286 error |= __vmwrite(GUEST_GS_SELECTOR, regs->gs); |
iap10@3290 | 287 |
iap10@3290 | 288 /* Guest segment Limits */ |
iap10@3290 | 289 error |= __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT); |
iap10@3290 | 290 error |= __vmwrite(GUEST_ES_LIMIT, GUEST_SEGMENT_LIMIT); |
iap10@3290 | 291 error |= __vmwrite(GUEST_SS_LIMIT, GUEST_SEGMENT_LIMIT); |
iap10@3290 | 292 error |= __vmwrite(GUEST_DS_LIMIT, GUEST_SEGMENT_LIMIT); |
iap10@3290 | 293 error |= __vmwrite(GUEST_FS_LIMIT, GUEST_SEGMENT_LIMIT); |
iap10@3290 | 294 error |= __vmwrite(GUEST_GS_LIMIT, GUEST_SEGMENT_LIMIT); |
iap10@3290 | 295 |
iap10@3290 | 296 error |= __vmwrite(GUEST_IDTR_LIMIT, host_env->idtr_limit); |
iap10@3290 | 297 |
iap10@3290 | 298 /* AR bytes */ |
iap10@3290 | 299 arbytes.bytes = 0; |
iap10@3290 | 300 arbytes.fields.seg_type = 0x3; /* type = 3 */ |
iap10@3290 | 301 arbytes.fields.s = 1; /* code or data, i.e. not system */ |
iap10@3290 | 302 arbytes.fields.dpl = 0; /* DPL = 3 */ |
iap10@3290 | 303 arbytes.fields.p = 1; /* segment present */ |
iap10@3290 | 304 arbytes.fields.default_ops_size = 1; /* 32-bit */ |
iap10@3290 | 305 arbytes.fields.g = 1; |
iap10@3290 | 306 arbytes.fields.null_bit = 0; /* not null */ |
iap10@3290 | 307 |
iap10@3290 | 308 error |= __vmwrite(GUEST_ES_AR_BYTES, arbytes.bytes); |
iap10@3290 | 309 error |= __vmwrite(GUEST_SS_AR_BYTES, arbytes.bytes); |
iap10@3290 | 310 error |= __vmwrite(GUEST_DS_AR_BYTES, arbytes.bytes); |
iap10@3290 | 311 error |= __vmwrite(GUEST_FS_AR_BYTES, arbytes.bytes); |
iap10@3290 | 312 error |= __vmwrite(GUEST_GS_AR_BYTES, arbytes.bytes); |
iap10@3290 | 313 |
iap10@3290 | 314 arbytes.fields.seg_type = 0xb; /* type = 0xb */ |
iap10@3290 | 315 error |= __vmwrite(GUEST_CS_AR_BYTES, arbytes.bytes); |
iap10@3290 | 316 |
kaf24@4683 | 317 error |= __vmwrite(GUEST_GDTR_BASE, regs->edx); |
kaf24@4683 | 318 regs->edx = 0; |
kaf24@4683 | 319 error |= __vmwrite(GUEST_GDTR_LIMIT, regs->eax); |
kaf24@4683 | 320 regs->eax = 0; |
iap10@3290 | 321 |
iap10@3290 | 322 arbytes.fields.s = 0; /* not code or data segement */ |
iap10@3290 | 323 arbytes.fields.seg_type = 0x2; /* LTD */ |
iap10@3290 | 324 arbytes.fields.default_ops_size = 0; /* 16-bit */ |
iap10@3290 | 325 arbytes.fields.g = 0; |
iap10@3290 | 326 error |= __vmwrite(GUEST_LDTR_AR_BYTES, arbytes.bytes); |
iap10@3290 | 327 |
iap10@3290 | 328 arbytes.fields.seg_type = 0xb; /* 32-bit TSS (busy) */ |
iap10@3290 | 329 error |= __vmwrite(GUEST_TR_AR_BYTES, arbytes.bytes); |
iap10@3290 | 330 |
iap10@3290 | 331 error |= __vmwrite(GUEST_CR0, host_env->cr0); /* same CR0 */ |
iap10@3290 | 332 |
iap10@3290 | 333 /* Initally PG, PE are not set*/ |
iap10@3290 | 334 shadow_cr = host_env->cr0; |
arun@5186 | 335 shadow_cr &= ~X86_CR0_PG; |
iap10@3290 | 336 error |= __vmwrite(CR0_READ_SHADOW, shadow_cr); |
kaf24@3755 | 337 /* CR3 is set in vmx_final_setup_guest */ |
kaf24@5658 | 338 #ifdef __x86_64__ |
kaf24@5727 | 339 error |= __vmwrite(GUEST_CR4, host_env->cr4 & ~X86_CR4_PSE); |
kaf24@5658 | 340 #else |
iap10@3290 | 341 error |= __vmwrite(GUEST_CR4, host_env->cr4); |
kaf24@5658 | 342 #endif |
iap10@3290 | 343 shadow_cr = host_env->cr4; |
kaf24@5658 | 344 |
kaf24@5658 | 345 #ifdef __x86_64__ |
kaf24@5658 | 346 shadow_cr &= ~(X86_CR4_PGE | X86_CR4_VMXE | X86_CR4_PAE); |
kaf24@5658 | 347 #else |
iap10@3290 | 348 shadow_cr &= ~(X86_CR4_PGE | X86_CR4_VMXE); |
kaf24@5658 | 349 #endif |
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 |
kaf24@5414 | 360 error |= __vmwrite(GUEST_RSP, regs->esp); |
kaf24@5414 | 361 error |= __vmwrite(GUEST_RIP, regs->eip); |
iap10@3290 | 362 |
kaf24@4683 | 363 eflags = regs->eflags & ~VMCS_EFLAGS_RESERVED_0; /* clear 0s */ |
iap10@3290 | 364 eflags |= VMCS_EFLAGS_RESERVED_1; /* set 1s */ |
iap10@3290 | 365 |
kaf24@5414 | 366 error |= __vmwrite(GUEST_RFLAGS, 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); |
kaf24@5414 | 371 error |= __vmwrite(VMCS_LINK_POINTER, 0xffffffff); |
kaf24@5414 | 372 error |= __vmwrite(VMCS_LINK_POINTER_HIGH, 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 |
iap10@3290 | 382 /* Host Selectors */ |
iap10@3290 | 383 host_env->ds_selector = __HYPERVISOR_DS; |
iap10@3290 | 384 error |= __vmwrite(HOST_ES_SELECTOR, host_env->ds_selector); |
iap10@3290 | 385 error |= __vmwrite(HOST_SS_SELECTOR, host_env->ds_selector); |
iap10@3290 | 386 error |= __vmwrite(HOST_DS_SELECTOR, host_env->ds_selector); |
kaf24@5658 | 387 #if defined (__i386__) |
iap10@3290 | 388 error |= __vmwrite(HOST_FS_SELECTOR, host_env->ds_selector); |
iap10@3290 | 389 error |= __vmwrite(HOST_GS_SELECTOR, host_env->ds_selector); |
kaf24@5658 | 390 error |= __vmwrite(HOST_FS_BASE, host_env->ds_base); |
kaf24@5658 | 391 error |= __vmwrite(HOST_GS_BASE, host_env->ds_base); |
iap10@3290 | 392 |
kaf24@5658 | 393 #else |
kaf24@5658 | 394 rdmsrl(MSR_FS_BASE, host_env->fs_base); |
kaf24@5658 | 395 rdmsrl(MSR_GS_BASE, host_env->gs_base); |
kaf24@5658 | 396 error |= __vmwrite(HOST_FS_BASE, host_env->fs_base); |
kaf24@5658 | 397 error |= __vmwrite(HOST_GS_BASE, host_env->gs_base); |
kaf24@5658 | 398 |
kaf24@5658 | 399 #endif |
iap10@3290 | 400 host_env->cs_selector = __HYPERVISOR_CS; |
iap10@3290 | 401 error |= __vmwrite(HOST_CS_SELECTOR, host_env->cs_selector); |
iap10@3290 | 402 |
iap10@3290 | 403 host_env->ds_base = 0; |
iap10@3290 | 404 host_env->cs_base = 0; |
iap10@3290 | 405 |
kaf24@5193 | 406 __asm__ __volatile__ ("mov %%cr0,%0" : "=r" (crn) : ); |
iap10@3290 | 407 host_env->cr0 = crn; |
iap10@3290 | 408 error |= __vmwrite(HOST_CR0, crn); /* same CR0 */ |
iap10@3290 | 409 |
iap10@3290 | 410 /* CR3 is set in vmx_final_setup_hostos */ |
kaf24@5193 | 411 __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (crn) : ); |
iap10@3290 | 412 host_env->cr4 = crn; |
iap10@3290 | 413 error |= __vmwrite(HOST_CR4, crn); |
kaf24@5820 | 414 |
kaf24@5414 | 415 error |= __vmwrite(HOST_RIP, (unsigned long) vmx_asm_vmexit_handler); |
kaf24@5658 | 416 #ifdef __x86_64__ |
kaf24@5658 | 417 /* TBD: support cr8 for 64-bit guest */ |
kaf24@5658 | 418 __vmwrite(VIRTUAL_APIC_PAGE_ADDR, 0); |
kaf24@5658 | 419 __vmwrite(TPR_THRESHOLD, 0); |
kaf24@5658 | 420 __vmwrite(SECONDARY_VM_EXEC_CONTROL, 0); |
kaf24@5658 | 421 #endif |
iap10@3290 | 422 |
iap10@3290 | 423 return error; |
iap10@3290 | 424 } |
iap10@3290 | 425 |
iap10@3290 | 426 /* |
iap10@3290 | 427 * Need to extend to support full virtualization. |
iap10@3290 | 428 * The variable use_host_env indicates if the new VMCS needs to use |
iap10@3290 | 429 * the same setups as the host has (xenolinux). |
iap10@3290 | 430 */ |
iap10@3290 | 431 |
iap10@3290 | 432 int construct_vmcs(struct arch_vmx_struct *arch_vmx, |
kaf24@4683 | 433 struct cpu_user_regs *regs, |
kaf24@4683 | 434 struct vcpu_guest_context *ctxt, |
iap10@3290 | 435 int use_host_env) |
iap10@3290 | 436 { |
iap10@3290 | 437 int error; |
iap10@3290 | 438 u64 vmcs_phys_ptr; |
iap10@3290 | 439 |
iap10@3290 | 440 struct host_execution_env host_env; |
iap10@3290 | 441 |
iap10@3290 | 442 if (use_host_env != VMCS_USE_HOST_ENV) |
iap10@3290 | 443 return -EINVAL; |
iap10@3290 | 444 |
iap10@3290 | 445 memset(&host_env, 0, sizeof(struct host_execution_env)); |
iap10@3290 | 446 |
iap10@3290 | 447 vmcs_phys_ptr = (u64) virt_to_phys(arch_vmx->vmcs); |
iap10@3290 | 448 |
iap10@3290 | 449 if ((error = __vmpclear (vmcs_phys_ptr))) { |
iap10@3290 | 450 printk("construct_vmcs: VMCLEAR failed\n"); |
iap10@3290 | 451 return -EINVAL; |
iap10@3290 | 452 } |
iap10@3290 | 453 if ((error = load_vmcs(arch_vmx, vmcs_phys_ptr))) { |
iap10@3290 | 454 printk("construct_vmcs: load_vmcs failed: VMCS = %lx\n", |
iap10@3290 | 455 (unsigned long) vmcs_phys_ptr); |
iap10@3290 | 456 return -EINVAL; |
iap10@3290 | 457 } |
kaf24@5836 | 458 if ((error = construct_vmcs_controls(arch_vmx))) { |
iap10@3290 | 459 printk("construct_vmcs: construct_vmcs_controls failed\n"); |
iap10@3290 | 460 return -EINVAL; |
iap10@3290 | 461 } |
iap10@3290 | 462 /* host selectors */ |
iap10@3290 | 463 if ((error = construct_vmcs_host(&host_env))) { |
iap10@3290 | 464 printk("construct_vmcs: construct_vmcs_host failed\n"); |
iap10@3290 | 465 return -EINVAL; |
iap10@3290 | 466 } |
iap10@3290 | 467 /* guest selectors */ |
kaf24@4683 | 468 if ((error = construct_init_vmcs_guest(regs, ctxt, &host_env))) { |
iap10@3290 | 469 printk("construct_vmcs: construct_vmcs_guest failed\n"); |
iap10@3290 | 470 return -EINVAL; |
iap10@3290 | 471 } |
iap10@3290 | 472 |
iap10@3290 | 473 if ((error |= __vmwrite(EXCEPTION_BITMAP, |
iap10@3290 | 474 MONITOR_DEFAULT_EXCEPTION_BITMAP))) { |
iap10@3290 | 475 printk("construct_vmcs: setting Exception bitmap failed\n"); |
iap10@3290 | 476 return -EINVAL; |
iap10@3290 | 477 } |
iap10@3290 | 478 |
kaf24@5821 | 479 if (regs->eflags & EF_TF) |
kaf24@5821 | 480 __vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB); |
kaf24@5821 | 481 else |
kaf24@5821 | 482 __vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB); |
kaf24@5821 | 483 |
kaf24@5821 | 484 return 0; |
kaf24@5821 | 485 } |
kaf24@5821 | 486 |
kaf24@5821 | 487 /* |
kaf24@5821 | 488 * modify guest eflags and execption bitmap for gdb |
kaf24@5821 | 489 */ |
kaf24@5821 | 490 int modify_vmcs(struct arch_vmx_struct *arch_vmx, |
kaf24@5821 | 491 struct cpu_user_regs *regs) |
kaf24@5821 | 492 { |
kaf24@5821 | 493 int error; |
kaf24@5821 | 494 u64 vmcs_phys_ptr, old, old_phys_ptr; |
kaf24@5821 | 495 vmcs_phys_ptr = (u64) virt_to_phys(arch_vmx->vmcs); |
kaf24@5821 | 496 |
kaf24@5821 | 497 old_phys_ptr = virt_to_phys(&old); |
kaf24@5821 | 498 __vmptrst(old_phys_ptr); |
kaf24@5821 | 499 if ((error = load_vmcs(arch_vmx, vmcs_phys_ptr))) { |
kaf24@5821 | 500 printk("modify_vmcs: load_vmcs failed: VMCS = %lx\n", |
kaf24@5821 | 501 (unsigned long) vmcs_phys_ptr); |
kaf24@5821 | 502 return -EINVAL; |
kaf24@5821 | 503 } |
kaf24@5821 | 504 load_cpu_user_regs(regs); |
kaf24@5821 | 505 |
kaf24@5821 | 506 __vmptrld(old_phys_ptr); |
kaf24@5821 | 507 |
iap10@3290 | 508 return 0; |
iap10@3290 | 509 } |
iap10@3290 | 510 |
iap10@3290 | 511 int load_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr) |
iap10@3290 | 512 { |
iap10@3290 | 513 int error; |
iap10@3290 | 514 |
iap10@3290 | 515 if ((error = __vmptrld(phys_ptr))) { |
iap10@3290 | 516 clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags); |
iap10@3290 | 517 return error; |
iap10@3290 | 518 } |
iap10@3290 | 519 set_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags); |
iap10@3290 | 520 return 0; |
iap10@3290 | 521 } |
iap10@3290 | 522 |
iap10@3290 | 523 int store_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr) |
iap10@3290 | 524 { |
iap10@3290 | 525 /* take the current VMCS */ |
iap10@3290 | 526 __vmptrst(phys_ptr); |
iap10@3290 | 527 clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags); |
iap10@3290 | 528 return 0; |
iap10@3290 | 529 } |
iap10@3290 | 530 |
iap10@3290 | 531 void vm_launch_fail(unsigned long eflags) |
iap10@3290 | 532 { |
kaf24@6099 | 533 unsigned long error; |
kaf24@6099 | 534 __vmread(VM_INSTRUCTION_ERROR, &error); |
kaf24@6099 | 535 printk("<vm_launch_fail> error code %lx\n", error); |
arun@5382 | 536 __vmx_bug(guest_cpu_user_regs()); |
iap10@3290 | 537 } |
iap10@3290 | 538 |
iap10@3290 | 539 void vm_resume_fail(unsigned long eflags) |
iap10@3290 | 540 { |
kaf24@6099 | 541 unsigned long error; |
kaf24@6099 | 542 __vmread(VM_INSTRUCTION_ERROR, &error); |
kaf24@6099 | 543 printk("<vm_resume_fail> error code %lx\n", error); |
arun@5382 | 544 __vmx_bug(guest_cpu_user_regs()); |
iap10@3290 | 545 } |
iap10@3290 | 546 |
mafetter@3717 | 547 #endif /* CONFIG_VMX */ |
kaf24@3914 | 548 |
kaf24@3914 | 549 /* |
kaf24@3914 | 550 * Local variables: |
kaf24@3914 | 551 * mode: C |
kaf24@3914 | 552 * c-set-style: "BSD" |
kaf24@3914 | 553 * c-basic-offset: 4 |
kaf24@3914 | 554 * tab-width: 4 |
kaf24@3914 | 555 * indent-tabs-mode: nil |
kaf24@3988 | 556 * End: |
kaf24@3914 | 557 */ |