akaros/kern/arch/x86/vmm/intel/vmx.h
<<
>>
Prefs
   1/*
   2 * vmx.h: VMX Architecture related definitions
   3 * Copyright (c) 2004, Intel Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * You should have received a copy of the GNU General Public License along with
  15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  16 * Place - Suite 330, Boston, MA 02111-1307 USA.
  17 *
  18 * A few random additions are:
  19 * Copyright (C) 2006 Qumranet
  20 *    Avi Kivity <avi@qumranet.com>
  21 *    Yaniv Kamay <yaniv@qumranet.com>
  22 *
  23 */
  24
  25#pragma once
  26
  27#include <ros/arch/vmx.h>
  28
  29/* Additional bits for VMMCPs, originally from the Dune version of kvm. */
  30/*
  31 * vmx.h - header file for USM VMX driver.
  32 */
  33
  34/* This is per-guest per-core, and the implementation specific area
  35 * should be assumed to have hidden fields.
  36 */
  37struct vmcs {
  38        uint32_t revision_id;
  39        uint32_t abort_code;
  40        char _impl_specific[PGSIZE - sizeof(uint32_t) * 2];
  41};
  42
  43typedef uint64_t gpa_t;
  44typedef uint64_t gva_t;
  45
  46struct vmx_capability {
  47        uint32_t ept;
  48        uint32_t vpid;
  49};
  50
  51struct vmcs_config {
  52        int size;
  53        uint32_t revision_id;
  54        uint32_t pin_based_exec_ctrl;
  55        uint32_t cpu_based_exec_ctrl;
  56        uint32_t cpu_based_2nd_exec_ctrl;
  57        uint32_t vmexit_ctrl;
  58        uint32_t vmentry_ctrl;
  59};
  60
  61struct guest_pcore {
  62        int cpu;
  63        struct proc *proc;
  64        unsigned long *posted_irq_desc;
  65        struct vmcs *vmcs;
  66        int vmcs_core_id;
  67        bool should_vmresume;
  68        uint64_t xcr0;
  69        uint64_t msr_kern_gs_base;
  70        uint64_t msr_star;
  71        uint64_t msr_lstar;
  72        uint64_t msr_sfmask;
  73};
  74
  75#define NR_AUTOLOAD_MSRS 8
  76
  77/* the horror. */
  78struct desc_struct {
  79        union {
  80                struct {
  81                        unsigned int a;
  82                        unsigned int b;
  83                };
  84                struct {
  85                        uint16_t limit0;
  86                        uint16_t base0;
  87                        unsigned base1: 8, type: 4, s: 1, dpl: 2, p: 1;
  88                        unsigned limit: 4, avl: 1, l: 1, d: 1, g: 1, base2: 8;
  89                };
  90        };
  91} __attribute__((packed));
  92
  93/* LDT or TSS descriptor in the GDT. 16 bytes. */
  94struct ldttss_desc64 {
  95        uint16_t limit0;
  96        uint16_t base0;
  97        unsigned base1 : 8, type : 5, dpl : 2, p : 1;
  98        unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8;
  99        uint32_t base3;
 100        uint32_t zero1;
 101} __attribute__((packed));
 102
 103#define INTEL_MSR_WRITE_OFFSET                  2048
 104
 105#define INTEL_X2APIC_MSR_START                  0x100
 106#define INTEL_X2APIC_MSR_LENGTH                 (0x40/8)
 107
 108#define MSR_IA32_VMX_BASIC_MSR                  0x480
 109#define MSR_IA32_VMX_PINBASED_CTLS_MSR  0x481
 110#define MSR_IA32_VMX_PROCBASED_CTLS_MSR 0x482
 111#define MSR_IA32_VMX_EXIT_CTLS_MSR              0x483
 112#define MSR_IA32_VMX_ENTRY_CTLS_MSR             0x484
 113
 114extern char * const VMX_EXIT_REASON_NAMES[];
 115
 116static inline void native_store_idt(pseudodesc_t *dtr);
 117static inline unsigned long get_desc_base(const struct desc_struct *desc);
 118static inline void native_store_gdt(pseudodesc_t *dtr);
 119static inline bool cpu_has_secondary_exec_ctrls(void);
 120static inline bool cpu_has_vmx_vpid(void);
 121static inline bool cpu_has_vmx_invpcid(void);
 122static inline bool cpu_has_vmx_invvpid_single(void);
 123static inline bool cpu_has_vmx_invvpid_global(void);
 124static inline bool cpu_has_vmx_ept(void);
 125static inline bool cpu_has_vmx_invept(void);
 126static inline bool cpu_has_vmx_invept_individual_addr(void);
 127static inline bool cpu_has_vmx_invept_context(void);
 128static inline bool cpu_has_vmx_invept_global(void);
 129static inline bool cpu_has_vmx_ept_ad_bits(void);
 130static inline bool cpu_has_vmx_ept_execute_only(void);
 131static inline bool cpu_has_vmx_eptp_uncacheable(void);
 132static inline bool cpu_has_vmx_eptp_writeback(void);
 133static inline bool cpu_has_vmx_ept_2m_page(void);
 134static inline bool cpu_has_vmx_ept_1g_page(void);
 135static inline bool cpu_has_vmx_ept_4levels(void);
 136static inline void __invept(int ext, uint64_t eptp, gpa_t gpa);
 137static inline void ept_sync_global(void);
 138static inline void ept_sync_context(uint64_t eptp);
 139static inline void ept_sync_individual_addr(uint64_t eptp, gpa_t gpa);
 140static inline void __vmxon(uint64_t addr);
 141static inline void __vmxoff(void);
 142static inline void __invvpid(int ext, uint16_t vpid, gva_t gva);
 143static inline void vpid_sync_gpc_single(uint16_t vpid);
 144static inline void vpid_sync_gpc_global(void);
 145static inline void vpid_sync_context(uint16_t vpid);
 146
 147/* no way to get around some of this stuff. */
 148/* we will do the bare minimum required. */
 149static inline void native_store_idt(pseudodesc_t *dtr)
 150{
 151        asm volatile("sidt %0":"=m" (*dtr));
 152}
 153
 154static inline unsigned long get_desc_base(const struct desc_struct *desc)
 155{
 156        return (unsigned)(desc->base0 | ((desc->base1) << 16) |
 157                          ((desc->base2) << 24));
 158}
 159
 160#define store_gdt(dtr) native_store_gdt(dtr)
 161static inline void native_store_gdt(pseudodesc_t *dtr)
 162{
 163        asm volatile("sgdt %0":"=m" (*dtr));
 164}
 165
 166/* TODO: somewhat nasty - two structs, only used by the helpers.  Maybe use cpu
 167 * features. */
 168extern struct vmcs_config vmcs_config;
 169extern struct vmx_capability vmx_capability;
 170
 171static inline bool cpu_has_secondary_exec_ctrls(void)
 172{
 173        return vmcs_config.cpu_based_exec_ctrl &
 174                CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
 175}
 176
 177static inline bool cpu_has_vmx_vpid(void)
 178{
 179        return vmcs_config.cpu_based_2nd_exec_ctrl &
 180                SECONDARY_EXEC_ENABLE_VPID;
 181}
 182
 183static inline bool cpu_has_vmx_invpcid(void)
 184{
 185        return vmcs_config.cpu_based_2nd_exec_ctrl &
 186                SECONDARY_EXEC_ENABLE_INVPCID;
 187}
 188
 189static inline bool cpu_has_vmx_invvpid_single(void)
 190{
 191        return vmx_capability.vpid & VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT;
 192}
 193
 194static inline bool cpu_has_vmx_invvpid_global(void)
 195{
 196        return vmx_capability.vpid & VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT;
 197}
 198
 199static inline bool cpu_has_vmx_ept(void)
 200{
 201        return vmcs_config.cpu_based_2nd_exec_ctrl &
 202                SECONDARY_EXEC_ENABLE_EPT;
 203}
 204
 205static inline bool cpu_has_vmx_invept(void)
 206{
 207        return vmx_capability.ept & VMX_EPT_INVEPT_BIT;
 208}
 209
 210/* the SDM (2015-01) doesn't mention this ability (still?) */
 211static inline bool cpu_has_vmx_invept_individual_addr(void)
 212{
 213        return vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT;
 214}
 215
 216static inline bool cpu_has_vmx_invept_context(void)
 217{
 218        return vmx_capability.ept & VMX_EPT_EXTENT_CONTEXT_BIT;
 219}
 220
 221static inline bool cpu_has_vmx_invept_global(void)
 222{
 223        return vmx_capability.ept & VMX_EPT_EXTENT_GLOBAL_BIT;
 224}
 225
 226static inline bool cpu_has_vmx_ept_ad_bits(void)
 227{
 228        return vmx_capability.ept & VMX_EPT_AD_BIT;
 229}
 230
 231static inline bool cpu_has_vmx_ept_execute_only(void)
 232{
 233        return vmx_capability.ept & VMX_EPT_EXECUTE_ONLY_BIT;
 234}
 235
 236static inline bool cpu_has_vmx_eptp_uncacheable(void)
 237{
 238        return vmx_capability.ept & VMX_EPTP_UC_BIT;
 239}
 240
 241static inline bool cpu_has_vmx_eptp_writeback(void)
 242{
 243        return vmx_capability.ept & VMX_EPTP_WB_BIT;
 244}
 245
 246static inline bool cpu_has_vmx_ept_2m_page(void)
 247{
 248        return vmx_capability.ept & VMX_EPT_2MB_PAGE_BIT;
 249}
 250
 251static inline bool cpu_has_vmx_ept_1g_page(void)
 252{
 253        return vmx_capability.ept & VMX_EPT_1GB_PAGE_BIT;
 254}
 255
 256static inline bool cpu_has_vmx_ept_4levels(void)
 257{
 258        return vmx_capability.ept & VMX_EPT_PAGE_WALK_4_BIT;
 259}
 260
 261static inline void __invept(int ext, uint64_t eptp, gpa_t gpa)
 262{
 263        struct {
 264                uint64_t eptp, gpa;
 265        } operand = {eptp, gpa};
 266
 267        asm volatile (ASM_VMX_INVEPT
 268                        /* CF==1 or ZF==1 --> rc = -1 */
 269                        "; ja 1f ; ud2 ; 1:\n"
 270                        : : "a" (&operand), "c" (ext) : "cc", "memory");
 271}
 272
 273/* We assert support for the global flush during ept_init() */
 274static inline void ept_sync_global(void)
 275{
 276        __invept(VMX_EPT_EXTENT_GLOBAL, 0, 0);
 277}
 278
 279static inline void ept_sync_context(uint64_t eptp)
 280{
 281        if (cpu_has_vmx_invept_context())
 282                __invept(VMX_EPT_EXTENT_CONTEXT, eptp, 0);
 283        else
 284                ept_sync_global();
 285}
 286
 287static inline void ept_sync_individual_addr(uint64_t eptp, gpa_t gpa)
 288{
 289        if (cpu_has_vmx_invept_individual_addr())
 290                __invept(VMX_EPT_EXTENT_INDIVIDUAL_ADDR,
 291                                eptp, gpa);
 292        else
 293                ept_sync_context(eptp);
 294}
 295
 296static inline void __vmxon(uint64_t addr)
 297{
 298        asm volatile (ASM_VMX_VMXON_RAX
 299                        : : "a"(&addr), "m"(addr)
 300                        : "memory", "cc");
 301}
 302
 303static inline void __vmxoff(void)
 304{
 305        asm volatile (ASM_VMX_VMXOFF : : : "cc");
 306}
 307
 308static inline void __invvpid(int ext, uint16_t vpid, gva_t gva)
 309{
 310    struct {
 311        uint64_t vpid : 16;
 312        uint64_t rsvd : 48;
 313        uint64_t gva;
 314    } operand = { vpid, 0, gva };
 315
 316    asm volatile (ASM_VMX_INVVPID
 317                  /* CF==1 or ZF==1 --> rc = -1 */
 318                  "; ja 1f ; ud2 ; 1:"
 319                  : : "a"(&operand), "c"(ext) : "cc", "memory");
 320}
 321
 322static inline void vpid_sync_gpc_single(uint16_t vpid)
 323{
 324        if (vpid == 0) {
 325                return;
 326        }
 327
 328        if (cpu_has_vmx_invvpid_single())
 329                __invvpid(VMX_VPID_EXTENT_SINGLE_CONTEXT, vpid, 0);
 330}
 331
 332static inline void vpid_sync_gpc_global(void)
 333{
 334        if (cpu_has_vmx_invvpid_global())
 335                __invvpid(VMX_VPID_EXTENT_ALL_CONTEXT, 0, 0);
 336}
 337
 338static inline void vpid_sync_context(uint16_t vpid)
 339{
 340        if (cpu_has_vmx_invvpid_single())
 341                vpid_sync_gpc_single(vpid);
 342        else
 343                vpid_sync_gpc_global();
 344}
 345
 346static inline unsigned long vmcs_read(unsigned long field)
 347{
 348        unsigned long value;
 349
 350        asm volatile (ASM_VMX_VMREAD_RDX_RAX : "=a"(value) : "d"(field) : "cc");
 351        return value;
 352}
 353
 354/* Returns true if the op succeeded.  It can fail if the field is unsupported */
 355static inline bool vmcs_write(unsigned long field, unsigned long value)
 356{
 357        uint8_t error;
 358
 359        asm volatile (ASM_VMX_VMWRITE_RAX_RDX "; setna %0"
 360                      : "=q"(error) : "a"(value), "d"(field) : "cc");
 361        return error ? FALSE : TRUE;
 362}
 363
 364/*
 365 * VMX Execution Controls (vmxec)
 366 * Some bits can be set, others can not (i.e. they are reserved).
 367 *
 368 * o all bits listed in here must set or clear all the bits in a word
 369 *   that are not reserved (coverage).
 370 * o no bits listed in one of these elements is listed in
 371 *   another element (conflict)
 372 * o you are allowed to specify a bit that matches a reserved value
 373 *   (because it might be settable at some future time).
 374 * o do your best to find symbolic names for the set_to_1 and set_to_0 values.
 375 *   In the one case we could not find a name, it turned out to be an
 376 *   error in kvm constants that went back to the earliest days.
 377 * We're hoping you almost never have to change this. It's painful.
 378 * The assumption going in is that the 5 MSRs that define the vmxec
 379 * values are relatively static. This has been the case for a while.
 380 */
 381struct vmxec {
 382        char *name;
 383        uint32_t msr;
 384        uint32_t truemsr;
 385        uint32_t must_be_1;
 386        uint32_t must_be_0;
 387        uint32_t try_set_1;
 388        uint32_t try_set_0;
 389        uint32_t hw_changeable;
 390        uint32_t policy_changeable;
 391};
 392
 393/* Per-VM VMX info */
 394struct vmx_vmm {
 395        uint32_t                        pin_exec_ctls;
 396        uint32_t                        cpu_exec_ctls;
 397        uint32_t                        cpu2_exec_ctls;
 398};
 399
 400int intel_vmm_init(void);
 401int intel_vmm_pcpu_init(void);
 402void vmx_load_guest_pcore(struct guest_pcore *gpc);
 403void vmx_unload_guest_pcore(struct guest_pcore *gpc);
 404uint64_t gpc_get_eptp(struct guest_pcore *gpc);
 405void vmx_clear_vmcs(void);
 406void vmx_setup_vmx_vmm(struct vmx_vmm *vmx);
 407int vmx_ctl_get_exits(struct vmx_vmm *vmx);
 408int vmx_ctl_set_exits(struct vmx_vmm *vmx, int vmm_exits);
 409