| //#define DEBUG |
| /** |
| * vmx.c - The Intel VT-x driver for Dune |
| * |
| * This file is derived from Linux KVM VT-x support. |
| * Copyright (C) 2006 Qumranet, Inc. |
| * Copyright 2010 Red Hat, Inc. and/or its affiliates. |
| * |
| * Original Authors: |
| * Avi Kivity <avi@qumranet.com> |
| * Yaniv Kamay <yaniv@qumranet.com> |
| * |
| * This modified version is simpler because it avoids the following |
| * features that are not requirements for Dune: |
| * * Real-mode emulation |
| * * Nested VT-x support |
| * * I/O hardware emulation |
| * * Any of the more esoteric X86 features and registers |
| * * KVM-specific functionality |
| * |
| * In essence we provide only the minimum functionality needed to run |
| * a process in vmx non-root mode rather than the full hardware emulation |
| * needed to support an entire OS. |
| * |
| * This driver is a research prototype and as such has the following |
| * limitations: |
| * |
| * FIXME: Backward compatibility is currently a non-goal, and only recent |
| * full-featured (EPT, PCID, VPID, etc.) Intel hardware is supported by this |
| * driver. |
| * |
| * FIXME: Eventually we should handle concurrent user's of VT-x more |
| * gracefully instead of requiring exclusive access. This would allow |
| * Dune to interoperate with KVM and other HV solutions. |
| * |
| * FIXME: We need to support hotplugged physical CPUs. |
| * |
| * Authors: |
| * Adam Belay <abelay@stanford.edu> |
| */ |
| |
| /* Basic flow. |
| * Yep, it's confusing. This is in part because the vmcs is used twice, for two different things. |
| * You're left with the feeling that they got part way through and realized they had to have one for |
| * |
| * 1) your CPU is going to be capable of running VMs, and you need state for |
| * that. |
| * |
| * 2) you're about to start a guest, and you need state for that. |
| * |
| * So there is get cpu set up to be able to run VMs stuff, and now |
| * let's start a guest stuff. In Akaros, CPUs will always be set up |
| * to run a VM if that is possible. Processes can flip themselves into |
| * a VM and that will require another VMCS. |
| * |
| * So: at kernel startup time, the SMP boot stuff calls |
| * k/a/x86/vmm/vmm.c:vmm_init, which calls arch-dependent bits, which |
| * in the case of this file is intel_vmm_init. That does some code |
| * that sets up stuff for ALL sockets, based on the capabilities of |
| * the socket it runs on. If any cpu supports vmx, it assumes they all |
| * do. That's a realistic assumption. So the call_function_all is kind |
| * of stupid, really; it could just see what's on the current cpu and |
| * assume it's on all. HOWEVER: there are systems in the wild that |
| * can run VMs on some but not all CPUs, due to BIOS mistakes, so we |
| * might as well allow for the chance that we'll only all VMMCPs on a |
| * subset (not implemented yet however). So: probe all CPUs, get a |
| * count of how many support VMX and, for now, assume they all do |
| * anyway. |
| * |
| * Next, call setup_vmcs_config to configure the GLOBAL vmcs_config struct, |
| * which contains all the naughty bits settings for all the cpus that can run a |
| * VM. |
| * Realistically, all VMX-capable cpus in a system will have identical |
| * configurations. |
| * So: 0 or more cpus can run VMX; all cpus which can run VMX will have the same |
| * configuration. |
| * |
| * configure the msr_bitmap. This is the bitmap of MSRs which the |
| * guest can manipulate. Currently, we only allow GS and FS base. |
| * |
| * Reserve bit 0 in the vpid bitmap as guests can not use that |
| * |
| * Set up the what we call the vmxarea. The vmxarea is per-cpu, not |
| * per-guest. Once set up, it is left alone. The ONLY think we set in |
| * there is the revision area. The VMX is page-sized per cpu and |
| * page-aligned. Note that it can be smaller, but why bother? We know |
| * the max size and alignment, and it's convenient. |
| * |
| * Now that it is set up, enable vmx on all cpus. This involves |
| * testing VMXE in cr4, to see if we've been here before (TODO: delete |
| * this test), then testing MSR_IA32_FEATURE_CONTROL to see if we can |
| * do a VM, the setting the VMXE in cr4, calling vmxon (does a vmxon |
| * instruction), and syncing vpid's and ept's. Now the CPU is ready |
| * to host guests. |
| * |
| * Setting up a guest. |
| * We divide this into two things: vmm_proc_init and vm_run. |
| * Currently, on Intel, vmm_proc_init does nothing. |
| * |
| * vm_run is really complicated. It is called with a coreid, and |
| * vmctl struct. On intel, it calls vmx_launch. vmx_launch is set |
| * up for a few test cases. If rip is 1, it sets the guest rip to |
| * a function which will deref 0 and should exit with failure 2. If rip is 0, |
| * it calls an infinite loop in the guest. |
| * |
| * The sequence of operations: |
| * create a vcpu |
| * while (1) { |
| * get a vcpu |
| * disable irqs (required or you can't enter the VM) |
| * vmx_run_vcpu() |
| * enable irqs |
| * manage the vm exit |
| * } |
| * |
| * get a vcpu |
| * See if the current cpu has a vcpu. If so, and is the same as the vcpu we |
| * want, vmcs_load(vcpu->vmcs) -- i.e. issue a VMPTRLD. |
| * |
| * If it's not the same, see if the vcpu thinks it is on the core. If it is not, |
| * call __vmx_get_cpu_helper on the other cpu, to free it up. Else vmcs_clear |
| * the one attached to this cpu. Then vmcs_load the vmcs for vcpu on this this |
| * cpu, call __vmx_setup_cpu, mark this vcpu as being attached to this cpu, |
| * done. |
| * |
| * vmx_run_vcpu this one gets messy, mainly because it's a giant wad |
| * of inline assembly with embedded CPP crap. I suspect we'll want to |
| * un-inline it someday, but maybe not. It's called with a vcpu |
| * struct from which it loads guest state, and to which it stores |
| * non-virtualized host state. It issues a vmlaunch or vmresume |
| * instruction depending, and on return, it evaluates if things the |
| * launch/resume had an error in that operation. Note this is NOT the |
| * same as an error while in the virtual machine; this is an error in |
| * startup due to misconfiguration. Depending on what is returned it's |
| * either a failed vm startup or an exit for lots of many reasons. |
| * |
| */ |
| |
| /* basically: only rename those globals that might conflict |
| * with existing names. Leave all else the same. |
| * this code is more modern than the other code, yet still |
| * well encapsulated, it seems. |
| */ |
| #include <kmalloc.h> |
| #include <string.h> |
| #include <stdio.h> |
| #include <assert.h> |
| #include <error.h> |
| #include <pmap.h> |
| #include <sys/queue.h> |
| #include <smp.h> |
| #include <kref.h> |
| #include <atomic.h> |
| #include <alarm.h> |
| #include <event.h> |
| #include <umem.h> |
| #include <bitops.h> |
| #include <arch/types.h> |
| #include <syscall.h> |
| #include <arch/io.h> |
| #include <percpu.h> |
| |
| #include <ros/vmm.h> |
| #include "vmx.h" |
| #include "../vmm.h" |
| |
| #include <trap.h> |
| |
| #include <smp.h> |
| #include <ros/procinfo.h> |
| |
| #define currentcpu (&per_cpu_info[core_id()]) |
| |
| static unsigned long *msr_bitmap; |
| #define VMX_IO_BITMAP_SZ (1 << 16) /* 64 KB */ |
| static unsigned long *io_bitmap; |
| |
| int x86_ept_pte_fix_ups = 0; |
| |
| struct vmx_capability vmx_capability; |
| struct vmcs_config vmcs_config; |
| |
| char * const VMX_EXIT_REASON_NAMES[] = { |
| VMX_EXIT_REASONS |
| }; |
| |
| static char *cr_access_type[] = { |
| "move to cr", |
| "move from cr", |
| "clts", |
| "lmsw" |
| }; |
| |
| static char *cr_gpr[] = { |
| "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", |
| "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" |
| }; |
| |
| static int guest_cr_num[16] = { |
| GUEST_CR0, |
| -1, |
| -1, |
| GUEST_CR3, |
| GUEST_CR4, |
| -1, |
| -1, |
| -1, |
| -1, /* 8? */ |
| -1, -1, -1, -1, -1, -1, -1 |
| }; |
| |
| static __always_inline unsigned long vmcs_readl(unsigned long field); |
| |
| /* See section 24-3 of The Good Book */ |
| void show_cr_access(uint64_t val) |
| { |
| int crnr = val & 0xf; |
| int type = (val >> 4) & 3; |
| int reg = (val >> 11) & 0xf; |
| |
| print_lock(); |
| printk("%s: %d: ", cr_access_type[type], crnr); |
| if (type < 2) { |
| printk("%s", cr_gpr[reg]); |
| if (guest_cr_num[crnr] > -1) { |
| printk(": 0x%x", vmcs_readl(guest_cr_num[crnr])); |
| } |
| } |
| printk("\n"); |
| print_unlock(); |
| } |
| |
| void ept_flush(uint64_t eptp) |
| { |
| ept_sync_context(eptp); |
| } |
| |
| static void vmcs_clear(struct vmcs *vmcs) |
| { |
| uint64_t phys_addr = PADDR(vmcs); |
| uint8_t error; |
| |
| asm volatile (ASM_VMX_VMCLEAR_RAX "; setna %0" |
| : "=qm"(error) |
| : "a"(&phys_addr), "m"(phys_addr) |
| :"cc", "memory"); |
| if (error) |
| printk("vmclear fail: %p/%llx\n", vmcs, phys_addr); |
| } |
| |
| static void vmcs_load(struct vmcs *vmcs) |
| { |
| uint64_t phys_addr = PADDR(vmcs); |
| uint8_t error; |
| |
| asm volatile (ASM_VMX_VMPTRLD_RAX "; setna %0" |
| : "=qm"(error) |
| : "a"(&phys_addr), "m"(phys_addr) |
| : "cc", "memory"); |
| if (error) |
| printk("vmptrld %p/%llx failed\n", vmcs, phys_addr); |
| } |
| |
| /* Returns the paddr pointer of the current CPU's VMCS region, or -1 if none. */ |
| static physaddr_t vmcs_get_current(void) |
| { |
| physaddr_t vmcs_paddr; |
| |
| /* RAX contains the addr of the location to store the VMCS pointer. The |
| * compiler doesn't know the ASM will deref that pointer, hence the =m |
| */ |
| asm volatile (ASM_VMX_VMPTRST_RAX:"=m"(vmcs_paddr):"a"(&vmcs_paddr)); |
| return vmcs_paddr; |
| } |
| |
| static __always_inline unsigned long vmcs_readl(unsigned long field) |
| { |
| return vmcs_read(field); |
| } |
| |
| static __always_inline uint16_t vmcs_read16(unsigned long field) |
| { |
| return vmcs_readl(field); |
| } |
| |
| static __always_inline uint32_t vmcs_read32(unsigned long field) |
| { |
| return vmcs_readl(field); |
| } |
| |
| static __always_inline uint64_t vmcs_read64(unsigned long field) |
| { |
| return vmcs_readl(field); |
| } |
| |
| void vmwrite_error(unsigned long field, unsigned long value) |
| { |
| printk("vmwrite error: reg %lx value %lx (err %d)\n", |
| field, value, vmcs_read32(VM_INSTRUCTION_ERROR)); |
| } |
| |
| void vmcs_writel(unsigned long field, unsigned long value) |
| { |
| if (!vmcs_write(field, value)) |
| vmwrite_error(field, value); |
| } |
| |
| static void vmcs_write16(unsigned long field, uint16_t value) |
| { |
| vmcs_writel(field, value); |
| } |
| |
| static void vmcs_write32(unsigned long field, uint32_t value) |
| { |
| vmcs_writel(field, value); |
| } |
| |
| static void vmcs_write64(unsigned long field, uint64_t value) |
| { |
| vmcs_writel(field, value); |
| } |
| |
| void vapic_status_dump_kernel(void *vapic); |
| |
| static bool vmx_control_can_be_changed(struct vmxec *v, uint32_t ctl) |
| { |
| return v->hw_changeable & v->policy_changeable & ctl; |
| } |
| |
| /* |
| * A note on Things You Can't Make Up. |
| * or |
| * "George, you can type this shit, but you can't say it" -- Harrison Ford |
| * |
| * There are 5 VMCS 32-bit words that control guest permissions. If |
| * you set these correctly, you've got a guest that will behave. If |
| * you get even one bit wrong, you've got a guest that will chew your |
| * leg off. Some bits must be 1, some must be 0, and some can be set |
| * either way. To add to the fun, the docs are sort of a docudrama or, |
| * as the quote goes, "interesting if true." |
| * |
| * To determine what bit can be set in what VMCS 32-bit control word, |
| * there are 5 corresponding 64-bit MSRs. And, to make it even more |
| * fun, the standard set of MSRs have errors in them, i.e. report |
| * incorrect values, for legacy reasons, and so you are supposed to |
| * "look around" to another set, which have correct bits in |
| * them. There are four such 'correct' registers, and they have _TRUE_ |
| * in the names as you can see below. We test for the value of VMCS |
| * control bits in the _TRUE_ registers if possible. The fifth |
| * register, CPU Secondary Exec Controls, which came later, needs no |
| * _TRUE_ variant. |
| * |
| * For each MSR, the high 32 bits tell you what bits can be "1" by a |
| * "1" in that position; the low 32 bits tell you what bit can be "0" |
| * by a "0" in that position. So, for each of 32 bits in a given VMCS |
| * control word, there is a pair of bits in an MSR that tells you what |
| * values it can take. The two bits, of which there are *four* |
| * combinations, describe the *three* possible operations on a |
| * bit. The two bits, taken together, form an untruth table: There are |
| * three possibilities: The VMCS bit can be set to 0 or 1, or it can |
| * only be 0, or only 1. The fourth combination is not supposed to |
| * happen. |
| * |
| * So: there is the 1 bit from the upper 32 bits of the msr. |
| * If this bit is set, then the bit can be 1. If clear, it can not be 1. |
| * |
| * Then there is the 0 bit, from low 32 bits. If clear, the VMCS bit |
| * can be 0. If 1, the VMCS bit can not be 0. |
| * |
| * SO, let's call the 1 bit R1, and the 0 bit R0, we have: |
| * R1 R0 |
| * 0 0 -> must be 0 |
| * 1 0 -> can be 1, can be 0 |
| * 0 1 -> can not be 1, can not be 0. --> JACKPOT! Not seen yet. |
| * 1 1 -> must be one. |
| * |
| * It's also pretty hard to know what you can and can't set, and |
| * that's led to inadvertent opening of permissions at times. Because |
| * of this complexity we've decided on the following: the driver must |
| * define EVERY bit, UNIQUELY, for each of the 5 registers, that it wants |
| * set. Further, for any bit that's settable, the driver must specify |
| * a setting; for any bit that's reserved, the driver settings must |
| * match that bit. If there are reserved bits we don't specify, that's |
| * ok; we'll take them as is. |
| * |
| * We use a set-means-set, and set-means-clear model, i.e. we use a |
| * 32-bit word to contain the bits we want to be 1, indicated by one; |
| * and another 32-bit word in which a bit we want to be 0 is indicated |
| * by a 1. This allows us to easily create masks of all bits we're |
| * going to set, for example. |
| * |
| * We have two 32-bit numbers for each 32-bit VMCS field: bits we want |
| * set and bits we want clear. If you read the MSR for that field, |
| * compute the reserved 0 and 1 settings, and | them together, they |
| * need to result in 0xffffffff. You can see that we can create other |
| * tests for conflicts (i.e. overlap). |
| * |
| * At this point, I've tested check_vmx_controls in every way |
| * possible, because I kept screwing the bitfields up. You'll get a nice |
| * error it won't work at all, which is what we want: a |
| * failure-prone setup, where even errors that might result in correct |
| * values are caught -- "right answer, wrong method, zero credit." If there's |
| * weirdness in the bits, we don't want to run. |
| * The try_set stuff adds particular ugliness but we have to have it. |
| */ |
| static bool check_vmxec_controls(struct vmxec *v, bool have_true_msr, |
| uint32_t *result) |
| { |
| bool err = false; |
| uint32_t vmx_msr_low, vmx_msr_high; |
| uint64_t msr_val; |
| uint32_t reserved_0, reserved_1, changeable_bits, try0, try1; |
| |
| if (have_true_msr) |
| msr_val = read_msr(v->truemsr); |
| else |
| msr_val = read_msr(v->msr); |
| vmx_msr_high = high32(msr_val); |
| vmx_msr_low = low32(msr_val); |
| |
| if (vmx_msr_low & ~vmx_msr_high) |
| warn("JACKPOT: Conflicting VMX ec ctls for %s, high 0x%08x low 0x%08x", |
| v->name, vmx_msr_high, vmx_msr_low); |
| |
| reserved_0 = (~vmx_msr_low) & (~vmx_msr_high); |
| reserved_1 = vmx_msr_low & vmx_msr_high; |
| changeable_bits = ~(reserved_0 | reserved_1); |
| v->hw_changeable = changeable_bits; |
| |
| /* |
| * this is very much as follows: |
| * accept the things I cannot change, |
| * change the things I can, |
| * know the difference. |
| */ |
| |
| /* Conflict. Don't try to both set and reset bits. */ |
| if ((v->must_be_1 & (v->must_be_0 | v->try_set_1 | v->try_set_0)) || |
| (v->must_be_0 & (v->try_set_1 | v->try_set_0)) || |
| (v->try_set_1 & v->try_set_0)) { |
| printk("%s: must 0 (0x%x) and must be 1 (0x%x) and try_set_0 (0x%x) and try_set_1 (0x%x) overlap\n", |
| v->name, v->must_be_0, v->must_be_1, v->try_set_0, |
| v->try_set_1); |
| err = true; |
| } |
| |
| /* coverage */ |
| if (((v->must_be_0 | v->must_be_1 | v->try_set_0 | v->try_set_1) |
| & changeable_bits) != changeable_bits) { |
| printk("%s: Need to cover 0x%x and have 0x%x,0x%x\n", |
| v->name, changeable_bits, v->must_be_0, v->must_be_1, |
| v->try_set_0, v->try_set_1); |
| err = true; |
| } |
| |
| if ((v->must_be_0 | v->must_be_1 | v->try_set_0 | v->try_set_1 |
| | reserved_0 | reserved_1) != 0xffffffff) { |
| printk("%s: incomplete coverage: have 0x%x, want 0x%x\n", |
| v->name, v->must_be_0 | v->must_be_1 | v->try_set_0 | |
| v->try_set_1 | reserved_0 | reserved_1, 0xffffffff); |
| err = true; |
| } |
| |
| /* Don't try to change bits that can't be changed. */ |
| if ((v->must_be_0 & (reserved_0 | changeable_bits)) != v->must_be_0) { |
| printk("%s: set to 0 (0x%x) can't be done\n", v->name, |
| v->must_be_0); |
| err = true; |
| } |
| |
| if ((v->must_be_1 & (reserved_1 | changeable_bits)) != v->must_be_1) { |
| printk("%s: set to 1 (0x%x) can't be done\n", v->name, |
| v->must_be_1); |
| err = true; |
| } |
| // Note we don't REQUIRE that try_set_0 or try_set_0 be possible. We |
| // just want to try it. |
| |
| // Clear bits in try_set that can't be set. |
| try1 = v->try_set_1 & (reserved_1 | changeable_bits); |
| |
| /* If there's been any error at all, spill our guts and return. */ |
| if (err) { |
| printk("%s: vmx_msr_high 0x%x, vmx_msr_low 0x%x, ", |
| v->name, vmx_msr_high, vmx_msr_low); |
| printk("must_be_0 0x%x, try_set_0 0x%x,reserved_0 0x%x", |
| v->must_be_0, v->try_set_0, reserved_0); |
| printk("must_be_1 0x%x, try_set_1 0x%x,reserved_1 0x%x", |
| v->must_be_1, v->try_set_1, reserved_1); |
| printk(" reserved_0 0x%x", reserved_0); |
| printk(" changeable_bits 0x%x\n", changeable_bits); |
| return false; |
| } |
| |
| *result = v->must_be_1 | try1 | reserved_1; |
| |
| printk("%s: check_vmxec_controls succeeds with result 0x%x\n", |
| v->name, *result); |
| return true; |
| } |
| |
| /* |
| * We're trying to make this as readable as possible. Realistically, it will |
| * rarely if ever change, if the past is any guide. |
| */ |
| static struct vmxec pbec = { |
| .name = "Pin Based Execution Controls", |
| .msr = MSR_IA32_VMX_PINBASED_CTLS, |
| .truemsr = MSR_IA32_VMX_TRUE_PINBASED_CTLS, |
| |
| .must_be_1 = (PIN_BASED_EXT_INTR_MASK | |
| PIN_BASED_NMI_EXITING | |
| PIN_BASED_VIRTUAL_NMIS | |
| PIN_BASED_POSTED_INTR), |
| |
| .must_be_0 = (PIN_BASED_VMX_PREEMPTION_TIMER), |
| }; |
| |
| static struct vmxec cbec = { |
| .name = "CPU Based Execution Controls", |
| .msr = MSR_IA32_VMX_PROCBASED_CTLS, |
| .truemsr = MSR_IA32_VMX_TRUE_PROCBASED_CTLS, |
| |
| .must_be_1 = ( |
| CPU_BASED_MWAIT_EXITING | |
| CPU_BASED_HLT_EXITING | |
| CPU_BASED_TPR_SHADOW | |
| CPU_BASED_RDPMC_EXITING | |
| CPU_BASED_CR8_LOAD_EXITING | |
| CPU_BASED_CR8_STORE_EXITING | |
| CPU_BASED_USE_MSR_BITMAPS | |
| CPU_BASED_USE_IO_BITMAPS | |
| CPU_BASED_ACTIVATE_SECONDARY_CONTROLS), |
| |
| .must_be_0 = ( |
| CPU_BASED_VIRTUAL_INTR_PENDING | |
| CPU_BASED_INVLPG_EXITING | |
| CPU_BASED_USE_TSC_OFFSETING | |
| CPU_BASED_RDTSC_EXITING | |
| CPU_BASED_CR3_LOAD_EXITING | |
| CPU_BASED_CR3_STORE_EXITING | |
| CPU_BASED_MOV_DR_EXITING | |
| CPU_BASED_VIRTUAL_NMI_PENDING | |
| CPU_BASED_MONITOR_TRAP | |
| CPU_BASED_PAUSE_EXITING | |
| CPU_BASED_UNCOND_IO_EXITING), |
| |
| .try_set_0 = (CPU_BASED_MONITOR_EXITING), |
| .policy_changeable = ( |
| CPU_BASED_HLT_EXITING | |
| CPU_BASED_PAUSE_EXITING | |
| CPU_BASED_MWAIT_EXITING | |
| 0), |
| }; |
| |
| static struct vmxec cb2ec = { |
| .name = "CPU Based 2nd Execution Controls", |
| .msr = MSR_IA32_VMX_PROCBASED_CTLS2, |
| .truemsr = MSR_IA32_VMX_PROCBASED_CTLS2, |
| |
| .must_be_1 = (SECONDARY_EXEC_ENABLE_EPT | |
| SECONDARY_EXEC_APIC_REGISTER_VIRT | |
| SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | |
| SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | |
| SECONDARY_EXEC_ENABLE_INVPCID | |
| SECONDARY_EXEC_WBINVD_EXITING), |
| |
| .must_be_0 = ( |
| SECONDARY_EXEC_DESCRIPTOR_EXITING | |
| SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | |
| SECONDARY_EXEC_ENABLE_VPID | |
| SECONDARY_EXEC_UNRESTRICTED_GUEST | |
| SECONDARY_EXEC_PAUSE_LOOP_EXITING | |
| SECONDARY_EXEC_RDRAND_EXITING | |
| SECONDARY_EXEC_ENABLE_VMFUNC | |
| SECONDARY_EXEC_SHADOW_VMCS | |
| SECONDARY_EXEC_RDSEED_EXITING | |
| SECONDARY_EPT_VE | |
| SECONDARY_ENABLE_XSAV_RESTORE), |
| |
| .try_set_1 = SECONDARY_EXEC_RDTSCP, |
| |
| .try_set_0 = SECONDARY_EXEC_TSC_SCALING | SECONDARY_EXEC_ENABLE_PML |
| |
| }; |
| |
| static struct vmxec vmentry = { |
| .name = "VMENTRY controls", |
| .msr = MSR_IA32_VMX_ENTRY_CTLS, |
| .truemsr = MSR_IA32_VMX_TRUE_ENTRY_CTLS, |
| /* exact order from vmx.h; only the first two are enabled. */ |
| |
| .must_be_1 = (VM_ENTRY_LOAD_DEBUG_CONTROLS | /* can't set to 0 */ |
| VM_ENTRY_LOAD_IA32_EFER | |
| VM_ENTRY_IA32E_MODE), |
| |
| .must_be_0 = (VM_ENTRY_SMM | |
| VM_ENTRY_DEACT_DUAL_MONITOR | |
| VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | |
| VM_ENTRY_LOAD_IA32_PAT), |
| }; |
| |
| static struct vmxec vmexit = { |
| .name = "VMEXIT controls", |
| .msr = MSR_IA32_VMX_EXIT_CTLS, |
| .truemsr = MSR_IA32_VMX_TRUE_EXIT_CTLS, |
| |
| .must_be_1 = (VM_EXIT_SAVE_DEBUG_CONTROLS | /* can't set to 0 */ |
| VM_EXIT_ACK_INTR_ON_EXIT | |
| VM_EXIT_SAVE_IA32_EFER | |
| VM_EXIT_LOAD_IA32_EFER | |
| VM_EXIT_HOST_ADDR_SPACE_SIZE), /* 64 bit */ |
| |
| .must_be_0 = (VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | |
| VM_EXIT_SAVE_IA32_PAT | |
| VM_EXIT_LOAD_IA32_PAT | |
| VM_EXIT_SAVE_VMX_PREEMPTION_TIMER), |
| }; |
| |
| static void setup_vmcs_config(void *p) |
| { |
| int *ret = p; |
| struct vmcs_config *vmcs_conf = &vmcs_config; |
| uint32_t vmx_msr_high; |
| uint64_t vmx_msr; |
| bool have_true_msrs = false; |
| bool ok; |
| |
| *ret = -EIO; |
| |
| vmx_msr = read_msr(MSR_IA32_VMX_BASIC); |
| vmx_msr_high = vmx_msr >> 32; |
| |
| /* |
| * If bit 55 (VMX_BASIC_HAVE_TRUE_MSRS) is set, then we |
| * can go for the true MSRs. Else, we ask you to get a better CPU. |
| */ |
| if (vmx_msr & VMX_BASIC_TRUE_CTLS) { |
| have_true_msrs = true; |
| printd("Running with TRUE MSRs\n"); |
| } else { |
| printk("Running with non-TRUE MSRs, this is old hardware\n"); |
| } |
| |
| /* |
| * Don't worry that one or more of these might fail and leave |
| * the VMCS in some kind of incomplete state. If one of these |
| * fails, the caller is going to discard the VMCS. |
| * It is written this way to ensure we get results of all tests and |
| * avoid BMAFR behavior. |
| */ |
| ok = check_vmxec_controls(&pbec, have_true_msrs, |
| &vmcs_conf->pin_based_exec_ctrl); |
| ok = check_vmxec_controls(&cbec, have_true_msrs, |
| &vmcs_conf->cpu_based_exec_ctrl) && ok; |
| /* Only check cb2ec if we're still ok, o/w we may GPF */ |
| ok = ok && check_vmxec_controls(&cb2ec, have_true_msrs, |
| &vmcs_conf->cpu_based_2nd_exec_ctrl); |
| ok = check_vmxec_controls(&vmentry, have_true_msrs, |
| &vmcs_conf->vmentry_ctrl) && ok; |
| ok = check_vmxec_controls(&vmexit, have_true_msrs, |
| &vmcs_conf->vmexit_ctrl) && ok; |
| if (!ok) { |
| printk("vmxexec controls is no good.\n"); |
| return; |
| } |
| assert(cpu_has_secondary_exec_ctrls()); |
| |
| /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ |
| if ((vmx_msr_high & 0x1fff) > PGSIZE) { |
| printk("vmx_msr_high & 0x1fff) is 0x%x, > PAGE_SIZE 0x%x\n", |
| vmx_msr_high & 0x1fff, PGSIZE); |
| return; |
| } |
| |
| /* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */ |
| if (vmx_msr & VMX_BASIC_64) { |
| printk("VMX doesn't support 64 bit width!\n"); |
| return; |
| } |
| |
| if (((vmx_msr & VMX_BASIC_MEM_TYPE_MASK) >> VMX_BASIC_MEM_TYPE_SHIFT) |
| != VMX_BASIC_MEM_TYPE_WB) { |
| printk("VMX doesn't support WB memory for VMCS accesses!\n"); |
| return; |
| } |
| |
| vmcs_conf->size = vmx_msr_high & 0x1fff; |
| vmcs_conf->revision_id = (uint32_t) vmx_msr; |
| |
| /* Read in the caps for runtime checks. This MSR is only available if |
| * secondary controls and ept or vpid is on, which we check earlier */ |
| vmx_msr = read_msr(MSR_IA32_VMX_EPT_VPID_CAP); |
| vmx_capability.vpid = high32(vmx_msr); |
| vmx_capability.ept = low32(vmx_msr); |
| |
| *ret = 0; |
| } |
| |
| static struct vmcs *__vmx_alloc_vmcs(int node) |
| { |
| struct vmcs *vmcs; |
| |
| vmcs = kpages_alloc(vmcs_config.size, MEM_WAIT); |
| if (!vmcs) |
| error(ENOMEM, "__vmx_alloc_vmcs: Could not get %d contig bytes", |
| vmcs_config.size); |
| memset(vmcs, 0, vmcs_config.size); |
| vmcs->revision_id = vmcs_config.revision_id; /* vmcs revision id */ |
| printd("%d: set rev id %d\n", core_id(), vmcs->revision_id); |
| return vmcs; |
| } |
| |
| /** |
| * vmx_alloc_vmcs - allocates a VMCS region |
| * |
| * NOTE: Assumes the new region will be used by the current CPU. |
| * |
| * Returns a valid VMCS region. |
| */ |
| static struct vmcs *vmx_alloc_vmcs(void) |
| { |
| return __vmx_alloc_vmcs(numa_id()); |
| } |
| |
| /** |
| * vmx_free_vmcs - frees a VMCS region |
| */ |
| static void vmx_free_vmcs(struct vmcs *vmcs) |
| { |
| kpages_free(vmcs, vmcs_config.size); |
| } |
| |
| /* |
| * Set up the vmcs's constant host-state fields, i.e., host-state fields that |
| * will not change in the lifetime of the guest. |
| * Note that host-state that does change is set elsewhere. E.g., host-state |
| * that is set differently for each CPU is set in __vmx_setup_pcpu(), not here. |
| */ |
| static void vmx_setup_constant_host_state(void) |
| { |
| pseudodesc_t dt; |
| |
| vmcs_writel(HOST_CR0, rcr0() & ~X86_CR0_TS); /* 22.2.3 */ |
| vmcs_writel(HOST_CR4, rcr4()); /* 22.2.3, 22.2.5 */ |
| vmcs_writel(HOST_CR3, rcr3()); /* 22.2.3 */ |
| |
| vmcs_write16(HOST_CS_SELECTOR, GD_KT); /* 22.2.4 */ |
| vmcs_write16(HOST_DS_SELECTOR, GD_KD); /* 22.2.4 */ |
| vmcs_write16(HOST_ES_SELECTOR, GD_KD); /* 22.2.4 */ |
| vmcs_write16(HOST_SS_SELECTOR, GD_KD); /* 22.2.4 */ |
| vmcs_write16(HOST_TR_SELECTOR, GD_TSS); /* 22.2.4 */ |
| |
| native_store_idt(&dt); |
| vmcs_writel(HOST_IDTR_BASE, dt.pd_base); /* 22.2.4 */ |
| |
| extern void vmexit_handler(void); |
| vmcs_writel(HOST_RIP, (unsigned long)vmexit_handler); |
| |
| vmcs_write32(HOST_IA32_SYSENTER_CS, read_msr(MSR_IA32_SYSENTER_CS)); |
| vmcs_writel(HOST_IA32_SYSENTER_EIP, read_msr(MSR_IA32_SYSENTER_EIP)); |
| |
| vmcs_write32(HOST_IA32_EFER, read_msr(MSR_EFER)); |
| |
| if (vmcs_config.vmexit_ctrl & VM_EXIT_LOAD_IA32_PAT) |
| vmcs_write64(HOST_IA32_PAT, read_msr(MSR_IA32_CR_PAT)); |
| |
| vmcs_write16(HOST_FS_SELECTOR, 0); /* 22.2.4 */ |
| vmcs_write16(HOST_GS_SELECTOR, 0); /* 22.2.4 */ |
| vmcs_write(HOST_FS_BASE, 0); |
| } |
| |
| /* Set up the per-core VMCS fields. This is the host state that varies from |
| * core to core, which the hardware will switch for us on VM enters/exits. */ |
| static void __vmx_setup_pcpu(struct guest_pcore *gpc) |
| { |
| struct per_cpu_info *pcpui = &per_cpu_info[core_id()]; |
| struct vmx_vmm *vmx = &gpc->proc->vmm.vmx; |
| |
| vmcs_write(HOST_TR_BASE, (uintptr_t)pcpui->tss); |
| vmcs_writel(HOST_GDTR_BASE, (uintptr_t)pcpui->gdt); |
| vmcs_write(HOST_GS_BASE, (uintptr_t)pcpui); |
| /* TODO: we might need to also set HOST_IA32_PERF_GLOBAL_CTRL. Need to |
| * think about how perf will work with VMs */ |
| /* Userspace can request changes to the ctls. They take effect when we |
| * reload the GPC, which occurs after a transition from userspace to VM. |
| */ |
| vmcs_write(PIN_BASED_VM_EXEC_CONTROL, vmx->pin_exec_ctls); |
| vmcs_write(CPU_BASED_VM_EXEC_CONTROL, vmx->cpu_exec_ctls); |
| vmcs_write(SECONDARY_VM_EXEC_CONTROL, vmx->cpu2_exec_ctls); |
| } |
| |
| uint64_t construct_eptp(physaddr_t root_hpa) |
| { |
| uint64_t eptp; |
| |
| /* set WB memory and 4 levels of walk. we checked these in ept_init */ |
| eptp = VMX_EPT_MEM_TYPE_WB | (VMX_EPT_GAW_4_LVL << |
| VMX_EPT_GAW_EPTP_SHIFT); |
| if (cpu_has_vmx_ept_ad_bits()) |
| eptp |= VMX_EPT_AD_ENABLE_BIT; |
| eptp |= (root_hpa & PAGE_MASK); |
| |
| return eptp; |
| } |
| |
| /* Helper: some fields of the VMCS need a physical page address, e.g. the VAPIC |
| * page. We have the user address. This converts the user to phys addr and |
| * sets that up in the VMCS. Throws on error. */ |
| static void vmcs_set_pgaddr(struct proc *p, void *u_addr, |
| unsigned long field, char *what) |
| { |
| uintptr_t kva; |
| physaddr_t paddr; |
| |
| /* Enforce page alignment */ |
| kva = uva2kva(p, ROUNDDOWN(u_addr, PGSIZE), PGSIZE, PROT_WRITE); |
| if (!kva) |
| error(EINVAL, "Unmapped pgaddr %p for VMCS page %s", |
| u_addr, what); |
| |
| paddr = PADDR(kva); |
| /* TODO: need to pin the page. A munmap would actually be okay |
| * (though probably we should kill the process), but we need to |
| * keep the page from being reused. A refcnt would do the trick, |
| * which we decref when we destroy the guest core/vcpu. Note that |
| * this is an assert, not an error, because it represents an error |
| * in the kernel itself. */ |
| assert(!PGOFF(paddr)); |
| vmcs_writel(field, paddr); |
| /* Pages are inserted twice. Once, with the full paddr. The next field |
| * is the upper 32 bits of the paddr. */ |
| vmcs_writel(field + 1, paddr >> 32); |
| } |
| |
| /** |
| * vmx_setup_initial_guest_state - configures the initial state of guest |
| * registers and the VMCS. Throws on error. |
| */ |
| static void vmx_setup_initial_guest_state(struct proc *p, |
| struct vmm_gpcore_init *gpci) |
| { |
| unsigned long cr4 = X86_CR4_PAE | X86_CR4_VMXE | X86_CR4_OSXMMEXCPT | |
| X86_CR4_PGE | X86_CR4_OSFXSR; |
| uint32_t protected_mode = X86_CR0_PG | X86_CR0_PE; |
| |
| /* |
| * Allow guest to use xsave and read/write fs/gs base. |
| * We require these features to be present on the cpu. |
| */ |
| assert(cpu_has_feat(CPU_FEAT_X86_XSAVE)); |
| assert(cpu_has_feat(CPU_FEAT_X86_FSGSBASE)); |
| cr4 |= X86_CR4_RDWRGSFS; |
| cr4 |= X86_CR4_OSXSAVE; |
| /* configure control and data registers */ |
| vmcs_writel(GUEST_CR0, protected_mode | X86_CR0_WP | |
| X86_CR0_MP | X86_CR0_ET | X86_CR0_NE); |
| vmcs_writel(CR0_READ_SHADOW, protected_mode | X86_CR0_WP | |
| X86_CR0_MP | X86_CR0_ET | X86_CR0_NE); |
| vmcs_writel(GUEST_CR3, rcr3()); |
| vmcs_writel(GUEST_CR4, cr4); |
| /* The only bits that matter in this shadow are those that are |
| * set in CR4_GUEST_HOST_MASK. TODO: do we need to separate |
| * the setting of this value from that of |
| * CR4_GUEST_HOST_MASK? */ |
| vmcs_writel(CR4_READ_SHADOW, 0); |
| vmcs_writel(GUEST_IA32_EFER, EFER_LME | EFER_LMA | |
| EFER_SCE | EFER_NX /*| EFER_FFXSR */ ); |
| vmcs_writel(GUEST_GDTR_BASE, 0); |
| vmcs_writel(GUEST_GDTR_LIMIT, 0); |
| vmcs_writel(GUEST_IDTR_BASE, 0); |
| vmcs_writel(GUEST_IDTR_LIMIT, 0); |
| vmcs_writel(GUEST_RIP, 0xdeadbeef); |
| vmcs_writel(GUEST_RSP, 0xdeadbeef); |
| vmcs_writel(GUEST_RFLAGS, FL_RSVD_1); |
| vmcs_writel(GUEST_DR7, 0); |
| |
| /* guest segment bases */ |
| vmcs_writel(GUEST_CS_BASE, 0); |
| vmcs_writel(GUEST_DS_BASE, 0); |
| vmcs_writel(GUEST_ES_BASE, 0); |
| enforce_user_canon(&gpci->fsbase); |
| vmcs_writel(GUEST_FS_BASE, gpci->fsbase); |
| enforce_user_canon(&gpci->gsbase); |
| vmcs_writel(GUEST_GS_BASE, gpci->gsbase); |
| vmcs_writel(GUEST_SS_BASE, 0); |
| |
| /* guest segment access rights */ |
| vmcs_writel(GUEST_CS_AR_BYTES, 0xA09B); |
| vmcs_writel(GUEST_DS_AR_BYTES, 0xA093); |
| vmcs_writel(GUEST_ES_AR_BYTES, 0xA093); |
| vmcs_writel(GUEST_FS_AR_BYTES, 0xA093); |
| vmcs_writel(GUEST_GS_AR_BYTES, 0xA093); |
| vmcs_writel(GUEST_SS_AR_BYTES, 0xA093); |
| |
| /* guest segment limits */ |
| vmcs_write32(GUEST_CS_LIMIT, 0xFFFFFFFF); |
| vmcs_write32(GUEST_DS_LIMIT, 0xFFFFFFFF); |
| vmcs_write32(GUEST_ES_LIMIT, 0xFFFFFFFF); |
| vmcs_write32(GUEST_FS_LIMIT, 0xFFFFFFFF); |
| vmcs_write32(GUEST_GS_LIMIT, 0xFFFFFFFF); |
| vmcs_write32(GUEST_SS_LIMIT, 0xFFFFFFFF); |
| |
| /* configure segment selectors */ |
| vmcs_write16(GUEST_CS_SELECTOR, 0); |
| vmcs_write16(GUEST_DS_SELECTOR, 0); |
| vmcs_write16(GUEST_ES_SELECTOR, 0); |
| vmcs_write16(GUEST_FS_SELECTOR, 0); |
| vmcs_write16(GUEST_GS_SELECTOR, 0); |
| vmcs_write16(GUEST_SS_SELECTOR, 0); |
| vmcs_write16(GUEST_TR_SELECTOR, 0); |
| |
| /* guest LDTR */ |
| vmcs_write16(GUEST_LDTR_SELECTOR, 0); |
| vmcs_writel(GUEST_LDTR_AR_BYTES, 0x0082); |
| vmcs_writel(GUEST_LDTR_BASE, 0); |
| vmcs_writel(GUEST_LDTR_LIMIT, 0); |
| |
| /* guest TSS */ |
| vmcs_writel(GUEST_TR_BASE, 0); |
| vmcs_writel(GUEST_TR_AR_BYTES, 0x0080 | AR_TYPE_BUSY_64_TSS); |
| vmcs_writel(GUEST_TR_LIMIT, 0xff); |
| |
| /* initialize sysenter */ |
| vmcs_write32(GUEST_SYSENTER_CS, 0); |
| vmcs_writel(GUEST_SYSENTER_ESP, 0); |
| vmcs_writel(GUEST_SYSENTER_EIP, 0); |
| |
| /* other random initialization */ |
| vmcs_write32(GUEST_ACTIVITY_STATE, GUEST_ACTIVITY_ACTIVE); |
| vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0); |
| vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0); |
| vmcs_write64(GUEST_IA32_DEBUGCTL, 0); |
| vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */ |
| |
| /* Initialize posted interrupt notification vector */ |
| vmcs_write16(POSTED_NOTIFICATION_VEC, I_POKE_GUEST); |
| |
| /* Clear the EOI exit bitmap */ |
| vmcs_writel(EOI_EXIT_BITMAP0, 0); |
| vmcs_writel(EOI_EXIT_BITMAP0_HIGH, 0); |
| vmcs_writel(EOI_EXIT_BITMAP1, 0); |
| vmcs_writel(EOI_EXIT_BITMAP1_HIGH, 0); |
| vmcs_writel(EOI_EXIT_BITMAP2, 0); |
| vmcs_writel(EOI_EXIT_BITMAP2_HIGH, 0); |
| vmcs_writel(EOI_EXIT_BITMAP3, 0); |
| vmcs_writel(EOI_EXIT_BITMAP3_HIGH, 0); |
| |
| /* Initialize parts based on the users info. */ |
| vmcs_set_pgaddr(p, gpci->posted_irq_desc, POSTED_INTR_DESC_ADDR, |
| "posted_irq_desc"); |
| vmcs_set_pgaddr(p, gpci->vapic_addr, VIRTUAL_APIC_PAGE_ADDR, |
| "vapic_addr"); |
| vmcs_set_pgaddr(p, gpci->apic_addr, APIC_ACCESS_ADDR, "apic_addr"); |
| } |
| |
| static void __vmx_disable_intercept_for_msr(unsigned long *msr_bitmap, |
| uint32_t msr) |
| { |
| int f = sizeof(unsigned long); |
| |
| /* |
| * See Intel PRM Vol. 3, 20.6.9 (MSR-Bitmap Address). Early manuals |
| * have the write-low and read-high bitmap offsets the wrong way round. |
| * We can control MSRs 0x00000000-0x00001fff and 0xc0000000-0xc0001fff. |
| */ |
| if (msr <= 0x1fff) { |
| __clear_bit(msr, msr_bitmap + 0x000 / f); /* read-low */ |
| __clear_bit(msr, msr_bitmap + 0x800 / f); /* write-low */ |
| } else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) { |
| msr &= 0x1fff; |
| __clear_bit(msr, msr_bitmap + 0x400 / f); /* read-high */ |
| __clear_bit(msr, msr_bitmap + 0xc00 / f); /* write-high */ |
| } |
| } |
| |
| /* note the io_bitmap is big enough for the 64K port space. */ |
| static void __vmx_disable_intercept_for_io(unsigned long *io_bitmap, |
| uint16_t port) |
| { |
| __clear_bit(port, io_bitmap); |
| } |
| |
| static void dumpmsrs(void) |
| { |
| int i; |
| int set[] = { |
| MSR_LSTAR, |
| MSR_FS_BASE, |
| MSR_GS_BASE, |
| MSR_KERNEL_GS_BASE, |
| MSR_SFMASK, |
| MSR_IA32_PEBS_ENABLE |
| }; |
| |
| for (i = 0; i < ARRAY_SIZE(set); i++) { |
| printk("%p: %p\n", set[i], read_msr(set[i])); |
| } |
| printk("core id %d\n", core_id()); |
| } |
| |
| /* Notes on autoloading. We can't autoload FS_BASE or GS_BASE, according to the |
| * manual, but that's because they are automatically saved and restored when all |
| * of the other architectural registers are saved and restored, such as cs, ds, |
| * es, and other fun things. (See 24.4.1). We need to make sure we don't |
| * accidentally intercept them too, since they are magically autoloaded. |
| * |
| * We'll need to be careful of any MSR we neither autoload nor intercept |
| * whenever we vmenter/vmexit, and we intercept by default. |
| * |
| * Other MSRs, such as MSR_IA32_PEBS_ENABLE only work on certain architectures |
| * only work on certain architectures. */ |
| static void setup_msr(struct guest_pcore *gpc) |
| { |
| /* Since PADDR(msr_bitmap) is non-zero, and the bitmap is all 0xff, we |
| * now intercept all MSRs */ |
| vmcs_write64(MSR_BITMAP, PADDR(msr_bitmap)); |
| |
| vmcs_write64(IO_BITMAP_A, PADDR(io_bitmap)); |
| vmcs_write64(IO_BITMAP_B, PADDR((uintptr_t)io_bitmap + |
| (VMX_IO_BITMAP_SZ / 2))); |
| |
| vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0); |
| vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0); |
| vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0); |
| } |
| |
| void vmx_setup_vmx_vmm(struct vmx_vmm *vmx) |
| { |
| vmx->pin_exec_ctls = vmcs_config.pin_based_exec_ctrl; |
| vmx->cpu_exec_ctls = vmcs_config.cpu_based_exec_ctrl; |
| vmx->cpu2_exec_ctls = vmcs_config.cpu_based_2nd_exec_ctrl; |
| } |
| |
| /** |
| * vmx_setup_vmcs - configures the vmcs with starting parameters |
| */ |
| static void vmx_setup_vmcs(struct guest_pcore *gpc) |
| { |
| vmcs_write16(VIRTUAL_PROCESSOR_ID, 0); |
| vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */ |
| |
| vmcs_write64(EPT_POINTER, gpc_get_eptp(gpc)); |
| |
| vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0); |
| vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0); |
| vmcs_write32(CR3_TARGET_COUNT, 0); /* 22.2.1 */ |
| |
| setup_msr(gpc); |
| |
| vmcs_config.vmentry_ctrl |= VM_ENTRY_IA32E_MODE; |
| |
| vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl); |
| vmcs_write32(VM_ENTRY_CONTROLS, vmcs_config.vmentry_ctrl); |
| |
| vmcs_writel(CR0_GUEST_HOST_MASK, 0); // ~0ul); |
| |
| /* Mask some bits in CR4 as host-owned by setting them in this |
| * VMCS entry. For example, for now, we mark the CR4_VMXE bit |
| * as host owned. Right now, when Linux boots, it wants to |
| * set CR4_VMXE to 0 at first, which is fine -- we do not want |
| * to think about nested virtualization yet. But if we don't |
| * mark this bit as host owned we get a VMEXIT. Marking |
| * CR4_VMXE as host owned means that the writes will succeed |
| * with no vmexit if the value written matches the |
| * corresponding bit in the shadow register. */ |
| vmcs_writel(CR4_GUEST_HOST_MASK, CR4_VMXE); |
| |
| //kvm_write_tsc(&vmx->gpc, 0); |
| vmcs_writel(TSC_OFFSET, 0); |
| |
| vmx_setup_constant_host_state(); |
| } |
| |
| /** |
| * create_guest_pcore - allocates and initializes a guest physical core |
| * |
| * Returns: A new VCPU structure |
| */ |
| struct guest_pcore *create_guest_pcore(struct proc *p, |
| struct vmm_gpcore_init *gpci) |
| { |
| ERRSTACK(2); |
| int8_t state = 0; |
| struct guest_pcore *gpc = kmalloc(sizeof(struct guest_pcore), MEM_WAIT); |
| |
| if (!gpc) |
| error(ENOMEM, "create_guest_pcore could not allocate gpc"); |
| |
| if (waserror()) { |
| kfree(gpc); |
| nexterror(); |
| } |
| |
| memset(gpc, 0, sizeof(*gpc)); |
| |
| /* Warning: p here is uncounted (weak) reference */ |
| gpc->proc = p; |
| gpc->vmcs = vmx_alloc_vmcs(); |
| if (waserror()) { |
| vmx_free_vmcs(gpc->vmcs); |
| nexterror(); |
| } |
| printd("%d: gpc->vmcs is %p\n", core_id(), gpc->vmcs); |
| gpc->cpu = -1; |
| gpc->vmcs_core_id = -1; |
| gpc->should_vmresume = FALSE; |
| |
| disable_irqsave(&state); |
| vmx_load_guest_pcore(gpc); |
| vmx_setup_vmcs(gpc); |
| vmx_setup_initial_guest_state(p, gpci); |
| vmx_unload_guest_pcore(gpc); |
| enable_irqsave(&state); |
| |
| gpc->xcr0 = __proc_global_info.x86_default_xcr0; |
| |
| gpc->posted_irq_desc = gpci->posted_irq_desc; |
| poperror(); |
| poperror(); |
| return gpc; |
| } |
| |
| /** |
| * destroy_guest_pcore - destroys and frees an existing guest physical core |
| * @gpc: the GPC to destroy |
| */ |
| void destroy_guest_pcore(struct guest_pcore *gpc) |
| { |
| vmx_free_vmcs(gpc->vmcs); |
| kfree(gpc); |
| } |
| |
| static void vmx_step_instruction(void) |
| { |
| vmcs_writel(GUEST_RIP, vmcs_readl(GUEST_RIP) + |
| vmcs_read32(VM_EXIT_INSTRUCTION_LEN)); |
| } |
| |
| /** |
| * __vmx_enable - low-level enable of VMX mode on the current CPU |
| * @vmxon_buf: an opaque buffer for use as the VMXON region |
| */ |
| static int __vmx_enable(struct vmcs *vmxon_buf) |
| { |
| uint64_t phys_addr = PADDR(vmxon_buf); |
| uint64_t old, test_bits; |
| |
| if (rcr4() & X86_CR4_VMXE) { |
| panic("Should never have this happen"); |
| return -EBUSY; |
| } |
| |
| old = read_msr(MSR_IA32_FEATURE_CONTROL); |
| |
| test_bits = FEATURE_CONTROL_LOCKED; |
| test_bits |= FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX; |
| |
| if (0) // tboot_enabled()) |
| test_bits |= FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX; |
| |
| if ((old & test_bits) != test_bits) { |
| /* If it's locked, then trying to set it will cause a GPF. |
| * No Dune for you! |
| */ |
| if (old & FEATURE_CONTROL_LOCKED) { |
| printk("Dune: MSR_IA32_FEATURE_CONTROL is locked!\n"); |
| return -1; |
| } |
| |
| /* enable and lock */ |
| write_msr(MSR_IA32_FEATURE_CONTROL, old | test_bits); |
| } |
| lcr4(rcr4() | X86_CR4_VMXE); |
| |
| __vmxon(phys_addr); |
| vpid_sync_gpc_global(); /* good idea, even if we aren't using vpids */ |
| ept_sync_global(); |
| |
| return 0; |
| } |
| |
| /** |
| * vmx_disable - disables VMX mode on the current CPU |
| */ |
| static void vmx_disable(void *unused) |
| { |
| if (currentcpu->vmx_enabled) { |
| __vmxoff(); |
| lcr4(rcr4() & ~X86_CR4_VMXE); |
| currentcpu->vmx_enabled = 0; |
| } |
| } |
| |
| /* Probe the cpus to see which ones can do vmx. |
| * Return -errno if it fails, and 1 if it succeeds. |
| */ |
| static bool probe_cpu_vmx(void) |
| { |
| /* The best way to test this code is: |
| * wrmsr -p <cpu> 0x3a 1 |
| * This will lock vmx off; then modprobe dune. |
| * Frequently, however, systems have all 0x3a registers set to 5, |
| * meaning testing is impossible, as vmx can not be disabled. |
| * We have to simulate it being unavailable in most cases. |
| * The 'test' variable provides an easy way to simulate |
| * unavailability of vmx on some, none, or all cpus. |
| */ |
| if (!cpu_has_vmx()) { |
| printk("Machine does not support VT-x\n"); |
| return FALSE; |
| } else { |
| printk("Machine supports VT-x\n"); |
| return TRUE; |
| } |
| } |
| |
| static int ept_init(void) |
| { |
| if (!cpu_has_vmx_ept()) { |
| printk("VMX doesn't support EPT!\n"); |
| return -1; |
| } |
| if (!cpu_has_vmx_eptp_writeback()) { |
| printk("VMX EPT doesn't support WB memory!\n"); |
| return -1; |
| } |
| if (!cpu_has_vmx_ept_4levels()) { |
| printk("VMX EPT doesn't support 4 level walks!\n"); |
| return -1; |
| } |
| switch (arch_max_jumbo_page_shift()) { |
| case PML3_SHIFT: |
| if (!cpu_has_vmx_ept_1g_page()) { |
| printk("VMX EPT doesn't support 1 GB pages!\n"); |
| return -1; |
| } |
| break; |
| case PML2_SHIFT: |
| if (!cpu_has_vmx_ept_2m_page()) { |
| printk("VMX EPT doesn't support 2 MB pages!\n"); |
| return -1; |
| } |
| break; |
| default: |
| printk("Unexpected jumbo page size %d\n", |
| arch_max_jumbo_page_shift()); |
| return -1; |
| } |
| if (!cpu_has_vmx_ept_ad_bits()) { |
| printk("VMX EPT doesn't support accessed/dirty!\n"); |
| x86_ept_pte_fix_ups |= EPTE_A | EPTE_D; |
| } |
| if (!cpu_has_vmx_invept() || !cpu_has_vmx_invept_global()) { |
| printk("VMX EPT can't invalidate PTEs/TLBs!\n"); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * vmx_init sets up physical core data areas that are required to run a vm at |
| * all. These data areas are not connected to a specific user process in any |
| * way. Instead, they are in some sense externalizing what would other wise be a |
| * very large ball of state that would be inside the CPU. |
| */ |
| int intel_vmm_init(void) |
| { |
| int r, cpu, ret; |
| |
| if (!probe_cpu_vmx()) { |
| return -EOPNOTSUPP; |
| } |
| |
| setup_vmcs_config(&ret); |
| |
| if (ret) { |
| printk("setup_vmcs_config failed: %d\n", ret); |
| return ret; |
| } |
| |
| msr_bitmap = (unsigned long *)kpage_zalloc_addr(); |
| if (!msr_bitmap) { |
| printk("Could not allocate msr_bitmap\n"); |
| return -ENOMEM; |
| } |
| io_bitmap = (unsigned long *)kpages_alloc(VMX_IO_BITMAP_SZ, MEM_WAIT); |
| if (!io_bitmap) { |
| printk("Could not allocate msr_bitmap\n"); |
| kfree(msr_bitmap); |
| return -ENOMEM; |
| } |
| /* FIXME: do we need APIC virtualization (flexpriority?) */ |
| |
| memset(msr_bitmap, 0xff, PAGE_SIZE); |
| |
| /* The following MSRs are virtualized to the vapic page so there is no |
| * write or read from the actual MSR. */ |
| memset((void *)msr_bitmap + INTEL_X2APIC_MSR_START, 0, |
| INTEL_X2APIC_MSR_LENGTH); |
| __vmx_disable_intercept_for_msr(msr_bitmap, MSR_LAPIC_EOI); |
| __vmx_disable_intercept_for_msr(msr_bitmap, MSR_LAPIC_TPR); |
| __vmx_disable_intercept_for_msr(msr_bitmap, MSR_LAPIC_SELF_IPI); |
| |
| memset(io_bitmap, 0xff, VMX_IO_BITMAP_SZ); |
| |
| /* These are the only MSRs that are not intercepted. The hardware takes |
| * care of FS_BASE, GS_BASE, and EFER. We do the rest manually when |
| * loading and unloading guest pcores. */ |
| __vmx_disable_intercept_for_msr(msr_bitmap, MSR_FS_BASE); |
| __vmx_disable_intercept_for_msr(msr_bitmap, MSR_GS_BASE); |
| __vmx_disable_intercept_for_msr(msr_bitmap, MSR_EFER); |
| __vmx_disable_intercept_for_msr(msr_bitmap, MSR_KERNEL_GS_BASE); |
| __vmx_disable_intercept_for_msr(msr_bitmap, MSR_LSTAR); |
| __vmx_disable_intercept_for_msr(msr_bitmap, MSR_STAR); |
| __vmx_disable_intercept_for_msr(msr_bitmap, MSR_SFMASK); |
| |
| /* TODO: this might be dangerous, since they can do more than just read |
| * the CMOS */ |
| __vmx_disable_intercept_for_io(io_bitmap, CMOS_RAM_IDX); |
| __vmx_disable_intercept_for_io(io_bitmap, CMOS_RAM_DATA); |
| |
| if ((ret = ept_init())) { |
| printk("EPT init failed, %d\n", ret); |
| return ret; |
| } |
| printk("VMX setup succeeded\n"); |
| /* If this isn't true (we have VMX but not mwait), then we'll have to |
| * look closely at CPU_BASED_MWAIT_EXITING. */ |
| assert(cpu_has_feat(CPU_FEAT_X86_MWAIT)); |
| return 0; |
| } |
| |
| int intel_vmm_pcpu_init(void) |
| { |
| struct vmcs *vmxon_buf; |
| int ret; |
| |
| vmxon_buf = __vmx_alloc_vmcs(core_id()); |
| if (!vmxon_buf) { |
| printk("setup_vmxarea failed on node %d\n", core_id()); |
| return -1; |
| } |
| |
| ret = __vmx_enable(vmxon_buf); |
| if (ret) |
| goto failed; |
| currentcpu->vmx_enabled = 1; |
| return 0; |
| failed: |
| printk("Failed to enable VMX on core %d, err = %d\n", core_id(), ret); |
| return ret; |
| } |
| |
| |
| void vapic_status_dump_kernel(void *vapic) |
| { |
| uint32_t *p = (uint32_t *)vapic; |
| int i; |
| printk("-- BEGIN KERNEL APIC STATUS DUMP --\n"); |
| for (i = 0x100/sizeof(*p); i < 0x180/sizeof(*p); i+=4) { |
| printk("VISR : 0x%x: 0x%08x\n", i, p[i]); |
| } |
| for (i = 0x200/sizeof(*p); i < 0x280/sizeof(*p); i+=4) { |
| printk("VIRR : 0x%x: 0x%08x\n", i, p[i]); |
| } |
| i = 0x0B0/sizeof(*p); |
| printk("EOI FIELD : 0x%x, 0x%08x\n", i, p[i]); |
| |
| printk("-- END KERNEL APIC STATUS DUMP --\n"); |
| } |
| |
| static DEFINE_PERCPU(struct guest_pcore *, gpc_to_clear_to); |
| |
| /* Note this is set up to allow spurious pokes. Someone could arbitrarily send |
| * us this KMSG at any time. We only actually clear when we've previously |
| * unloaded the GPC. gpc_to_clear_to is only set once we're just 'caching' it. |
| * */ |
| void vmx_clear_vmcs(void) |
| { |
| struct guest_pcore *gpc; |
| int8_t irq_state = 0; |
| |
| disable_irqsave(&irq_state); |
| gpc = PERCPU_VAR(gpc_to_clear_to); |
| if (gpc) { |
| vmcs_clear(gpc->vmcs); |
| ept_sync_context(gpc_get_eptp(gpc)); |
| gpc->should_vmresume = FALSE; |
| wmb(); /* write -1 after clearing */ |
| gpc->vmcs_core_id = -1; |
| PERCPU_VAR(gpc_to_clear_to) = NULL; |
| } |
| enable_irqsave(&irq_state); |
| } |
| |
| static void __clear_vmcs(uint32_t srcid, long a0, long a1, long a2) |
| { |
| vmx_clear_vmcs(); |
| } |
| |
| /* We are safe from races on GPC, other than vmcs and vmcs_core_id. For |
| * instance, only one core can be loading or unloading a particular GPC at a |
| * time. Other cores write to our GPC's vmcs_core_id and vmcs (doing a |
| * vmcs_clear). Once they write vmcs_core_id != -1, it's ours. */ |
| void vmx_load_guest_pcore(struct guest_pcore *gpc) |
| { |
| int remote_core; |
| |
| assert(!irq_is_enabled()); |
| if (gpc->vmcs_core_id == core_id()) { |
| PERCPU_VAR(gpc_to_clear_to) = NULL; |
| return; |
| } |
| /* Clear ours *before* waiting on someone else; avoids deadlock |
| * (circular wait). */ |
| __clear_vmcs(0, 0, 0, 0); |
| remote_core = ACCESS_ONCE(gpc->vmcs_core_id); |
| if (remote_core != -1) { |
| /* This is a bit nasty. It requires the remote core to receive |
| * interrupts, which means we're now waiting indefinitely for |
| * them to enable IRQs. They can wait on another core, and so |
| * on. We cleared our vmcs first, so that we won't deadlock on |
| * *this*. |
| * |
| * However, this means we can't wait on another core with IRQs |
| * disabled for any *other* reason. For instance, if some other |
| * subsystem decides to have one core wait with IRQs disabled on |
| * another, the core that has our VMCS could be waiting on us to |
| * do something that we'll never do. */ |
| send_kernel_message(remote_core, __clear_vmcs, 0, 0, 0, |
| KMSG_IMMEDIATE); |
| while (gpc->vmcs_core_id != -1) |
| cpu_relax(); |
| } |
| vmcs_load(gpc->vmcs); |
| __vmx_setup_pcpu(gpc); |
| gpc->vmcs_core_id = core_id(); |
| } |
| |
| void vmx_unload_guest_pcore(struct guest_pcore *gpc) |
| { |
| /* We don't have to worry about races yet. No one will try to load gpc |
| * until we've returned and unlocked, and no one will clear an old VMCS |
| * to this GPC, since it was cleared before we finished loading (above). |
| */ |
| assert(!irq_is_enabled()); |
| gpc->vmcs_core_id = core_id(); |
| PERCPU_VAR(gpc_to_clear_to) = gpc; |
| } |
| |
| uint64_t gpc_get_eptp(struct guest_pcore *gpc) |
| { |
| return gpc->proc->env_pgdir.eptp; |
| } |
| |
| int vmx_ctl_get_exits(struct vmx_vmm *vmx) |
| { |
| int ret = 0; |
| |
| if (vmx->cpu_exec_ctls & CPU_BASED_HLT_EXITING) |
| ret |= VMM_CTL_EXIT_HALT; |
| if (vmx->cpu_exec_ctls & CPU_BASED_PAUSE_EXITING) |
| ret |= VMM_CTL_EXIT_PAUSE; |
| if (vmx->cpu_exec_ctls & CPU_BASED_MWAIT_EXITING) |
| ret |= VMM_CTL_EXIT_MWAIT; |
| return ret; |
| } |
| |
| int vmx_ctl_set_exits(struct vmx_vmm *vmx, int vmm_exits) |
| { |
| int toggle_want; |
| int vmx_toggle_do = 0; |
| |
| toggle_want = (vmx_ctl_get_exits(vmx) ^ vmm_exits) & VMM_CTL_ALL_EXITS; |
| if (toggle_want & VMM_CTL_EXIT_HALT) { |
| if (!vmx_control_can_be_changed(&cbec, CPU_BASED_HLT_EXITING)) |
| error(ENOSYS, "VMX can't toggle EXIT_HALT"); |
| vmx_toggle_do |= CPU_BASED_HLT_EXITING; |
| } |
| if (toggle_want & VMM_CTL_EXIT_PAUSE) { |
| if (!vmx_control_can_be_changed(&cbec, CPU_BASED_PAUSE_EXITING)) |
| error(ENOSYS, "VMX can't toggle EXIT_PAUSE"); |
| vmx_toggle_do |= CPU_BASED_PAUSE_EXITING; |
| } |
| if (toggle_want & VMM_CTL_EXIT_MWAIT) { |
| if (!vmx_control_can_be_changed(&cbec, CPU_BASED_MWAIT_EXITING)) |
| error(ENOSYS, "VMX can't toggle EXIT_MWAIT"); |
| vmx_toggle_do |= CPU_BASED_MWAIT_EXITING; |
| } |
| /* This is being read concurrently by load_guest_pcore. */ |
| WRITE_ONCE(vmx->cpu_exec_ctls, vmx->cpu_exec_ctls ^ vmx_toggle_do); |
| return 0; |
| } |