Simplify things and put VM info into per-cpu struct
authorRonald G. Minnich <rminnich@google.com>
Sat, 4 Jan 2014 00:37:18 +0000 (16:37 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 17 Jan 2014 22:35:29 +0000 (14:35 -0800)
Rename litevm.h to vm.h, that's what it is on
Akaros.

Signed-off-by: Ronald G. Minnich <rminnich@google.com>
kern/arch/x86/emulate.c
kern/arch/x86/litevm.h [deleted file]
kern/arch/x86/vm.c
kern/arch/x86/vm.h [new file with mode: 0644]
kern/drivers/dev/#vm.c# [new file with mode: 0644]
kern/drivers/dev/vm.c
kern/include/smp.h

index aa99b86..e741947 100644 (file)
@@ -32,7 +32,7 @@
 #include <umem.h>
 #include <devalarm.h>
 #include <arch/types.h>
-#include <arch/litevm.h>
+#include <arch/vm.h>
 #include <arch/emulate.h>
 #include <arch/vmdebug.h>
 
diff --git a/kern/arch/x86/litevm.h b/kern/arch/x86/litevm.h
deleted file mode 100644 (file)
index 7e9b43e..0000000
+++ /dev/null
@@ -1,577 +0,0 @@
-#ifndef __LITEVM_H
-#define __LITEVM_H
-#include <sys/queue.h>
-#include "vmx.h"
-
-#define CR0_PE_MASK (1ULL << 0)
-#define CR0_TS_MASK (1ULL << 3)
-#define CR0_NE_MASK (1ULL << 5)
-#define CR0_WP_MASK (1ULL << 16)
-#define CR0_NW_MASK (1ULL << 29)
-#define CR0_CD_MASK (1ULL << 30)
-#define CR0_PG_MASK (1ULL << 31)
-
-#define CR3_WPT_MASK (1ULL << 3)
-#define CR3_PCD_MASK (1ULL << 4)
-
-#define CR3_RESEVED_BITS 0x07ULL
-#define CR3_L_MODE_RESEVED_BITS (~((1ULL << 40) - 1) | 0x0fe7ULL)
-#define CR3_FLAGS_MASK ((1ULL << 5) - 1)
-
-#define CR4_VME_MASK (1ULL << 0)
-#define CR4_PSE_MASK (1ULL << 4)
-#define CR4_PAE_MASK (1ULL << 5)
-#define CR4_PGE_MASK (1ULL << 7)
-#define CR4_VMXE_MASK (1ULL << 13)
-
-#define LITEVM_GUEST_CR0_MASK \
-       (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK)
-#define LITEVM_VM_CR0_ALWAYS_ON LITEVM_GUEST_CR0_MASK
-
-#define LITEVM_GUEST_CR4_MASK \
-       (CR4_PSE_MASK | CR4_PAE_MASK | CR4_PGE_MASK | CR4_VMXE_MASK | CR4_VME_MASK)
-#define LITEVM_PMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK)
-#define LITEVM_RMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK | CR4_VME_MASK)
-
-#define INVALID_PAGE (~(hpa_t)0)
-#define UNMAPPED_GVA (~(gpa_t)0)
-
-#define LITEVM_MAX_VCPUS 1
-#define LITEVM_MEMORY_SLOTS 4
-#define LITEVM_NUM_MMU_PAGES 256
-
-#define FX_IMAGE_SIZE 512
-#define FX_IMAGE_ALIGN 16
-#define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN)
-
-#define DE_VECTOR 0
-#define DF_VECTOR 8
-#define TS_VECTOR 10
-#define NP_VECTOR 11
-#define SS_VECTOR 12
-#define GP_VECTOR 13
-#define PF_VECTOR 14
-
-#define SELECTOR_TI_MASK (1 << 2)
-#define SELECTOR_RPL_MASK 0x03
-
-#define IOPL_SHIFT 12
-
-/*
- * Address types:
- *
- *  gva - guest virtual address
- *  gpa - guest physical address
- *  gfn - guest frame number
- *  hva - host virtual address
- *  hpa - host physical address
- *  hfn - host frame number
- */
-
-typedef unsigned long  gva_t;
-typedef uint64_t            gpa_t;
-typedef unsigned long  gfn_t;
-
-typedef unsigned long  hva_t;
-typedef uint64_t            hpa_t;
-typedef unsigned long  hfn_t;
-
-struct litevm_mmu_page {
-       LIST_HEAD(link, litevm_mmu_page) link;
-       hpa_t page_hpa;
-       unsigned long slot_bitmap; /* One bit set per slot which has memory
-                                   * in this shadow page.
-                                   */
-       int global;              /* Set if all ptes in this page are global */
-       uint64_t *parent_pte;
-};
-
-struct vmcs {
-       uint32_t revision_id;
-       uint32_t abort;
-       char data[0];
-};
-
-struct vmx_msr_entry {
-       uint32_t index;
-       uint32_t reserved;
-       uint64_t data;
-};
-
-struct litevm_vcpu;
-
-/*
- * x86 supports 3 paging modes (4-level 64-bit, 3-level 64-bit, and 2-level
- * 32-bit).  The litevm_mmu structure abstracts the details of the current mmu
- * mode.
- */
-struct litevm_mmu {
-       void (*new_cr3)(struct litevm_vcpu *vcpu);
-       int (*page_fault)(struct litevm_vcpu *vcpu, gva_t gva, uint32_t err);
-       void (*inval_page)(struct litevm_vcpu *vcpu, gva_t gva);
-       void (*free)(struct litevm_vcpu *vcpu);
-       gpa_t (*gva_to_gpa)(struct litevm_vcpu *vcpu, gva_t gva);
-       hpa_t root_hpa;
-       int root_level;
-       int shadow_root_level;
-};
-
-struct litevm_guest_debug {
-       int enabled;
-       unsigned long bp[4];
-       int singlestep;
-};
-
-enum {
-       VCPU_REGS_RAX = 0,
-       VCPU_REGS_RCX = 1,
-       VCPU_REGS_RDX = 2,
-       VCPU_REGS_RBX = 3,
-       VCPU_REGS_RSP = 4,
-       VCPU_REGS_RBP = 5,
-       VCPU_REGS_RSI = 6,
-       VCPU_REGS_RDI = 7,
-#ifdef __x86_64__
-       VCPU_REGS_R8 = 8,
-       VCPU_REGS_R9 = 9,
-       VCPU_REGS_R10 = 10,
-       VCPU_REGS_R11 = 11,
-       VCPU_REGS_R12 = 12,
-       VCPU_REGS_R13 = 13,
-       VCPU_REGS_R14 = 14,
-       VCPU_REGS_R15 = 15,
-#endif
-       NR_VCPU_REGS
-};
-
-struct litevm_vcpu {
-       struct litevm *litevm;
-       struct vmcs *vmcs;
-       qlock_t mutex; //struct mutex mutex;
-       int   cpu;
-       int   launched;
-       unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */
-#define NR_IRQ_WORDS (256 / BITS_PER_LONG)
-       unsigned long irq_pending[NR_IRQ_WORDS];
-       unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */
-       unsigned long rip;      /* needs vcpu_load_rsp_rip() */
-
-       unsigned long cr2;
-       unsigned long cr3;
-       unsigned long cr8;
-       uint64_t shadow_efer;
-       uint64_t apic_base;
-       int nmsrs;
-       struct vmx_msr_entry *guest_msrs;
-       struct vmx_msr_entry *host_msrs;
-       LIST_HEAD(free_pages, free_pages) free_pages;
-       //struct list_head free_pages;
-       struct litevm_mmu_page page_header_buf[LITEVM_NUM_MMU_PAGES];
-       struct litevm_mmu mmu;
-
-       struct litevm_guest_debug guest_debug;
-
-       char fx_buf[FX_BUF_SIZE];
-       char *host_fx_image;
-       char *guest_fx_image;
-
-       int mmio_needed;
-       int mmio_read_completed;
-       int mmio_is_write;
-       int mmio_size;
-       unsigned char mmio_data[8];
-       gpa_t mmio_phys_addr;
-
-       struct{
-               int active;
-               uint8_t save_iopl;
-               struct {
-                       unsigned long base;
-                       uint32_t limit;
-                       uint32_t ar;
-               } tr;
-       } rmode;
-};
-
-struct litevm_memory_slot {
-       gfn_t base_gfn;
-       unsigned long npages;
-       unsigned long flags;
-       struct page **phys_mem;
-       unsigned long *dirty_bitmap;
-};
-
-struct litevm {
-       spinlock_t lock; /* protects everything except vcpus */
-       int nmemslots;
-       struct litevm_memory_slot memslots[LITEVM_MEMORY_SLOTS];
-       LIST_HEAD(active_mmu_pages, active_mmu_pages) active_mmu_pages;
-       //struct list_head active_mmu_pages;
-       struct litevm_vcpu vcpus[LITEVM_MAX_VCPUS];
-       int memory_config_version;
-       int busy;
-};
-
-struct litevm_stat {
-       uint32_t pf_fixed;
-       uint32_t pf_guest;
-       uint32_t tlb_flush;
-       uint32_t invlpg;
-
-       uint32_t exits;
-       uint32_t io_exits;
-       uint32_t mmio_exits;
-       uint32_t signal_exits;
-       uint32_t irq_exits;
-};
-
-extern struct litevm_stat litevm_stat;
-
-#define litevm_printf(litevm, fmt ...) printk(KERN_DEBUG fmt)
-#define vcpu_printf(vcpu, fmt...) litevm_printf(vcpu->litevm, fmt)
-
-void litevm_mmu_destroy(struct litevm_vcpu *vcpu);
-int litevm_mmu_init(struct litevm_vcpu *vcpu);
-
-int litevm_mmu_reset_context(struct litevm_vcpu *vcpu);
-void litevm_mmu_slot_remove_write_access(struct litevm *litevm, int slot);
-
-hpa_t gpa_to_hpa(struct litevm_vcpu *vcpu, gpa_t gpa);
-#define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
-#define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB)
-static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; }
-hpa_t gva_to_hpa(struct litevm_vcpu *vcpu, gva_t gva);
-
-extern hpa_t bad_page_address;
-
-static inline struct page *gfn_to_page(struct litevm_memory_slot *slot, gfn_t gfn)
-{
-       return slot->phys_mem[gfn - slot->base_gfn];
-}
-
-struct litevm_memory_slot *gfn_to_memslot(struct litevm *litevm, gfn_t gfn);
-void mark_page_dirty(struct litevm *litevm, gfn_t gfn);
-
-void realmode_lgdt(struct litevm_vcpu *vcpu, uint16_t size, unsigned long address);
-void realmode_lidt(struct litevm_vcpu *vcpu, uint16_t size, unsigned long address);
-void realmode_lmsw(struct litevm_vcpu *vcpu, unsigned long msw,
-                  unsigned long *rflags);
-
-unsigned long realmode_get_cr(struct litevm_vcpu *vcpu, int cr);
-void realmode_set_cr(struct litevm_vcpu *vcpu, int cr, unsigned long value,
-                    unsigned long *rflags);
-
-int litevm_read_guest(struct litevm_vcpu *vcpu,
-              gva_t addr,
-              unsigned long size,
-              void *dest);
-
-int litevm_write_guest(struct litevm_vcpu *vcpu,
-               gva_t addr,
-               unsigned long size,
-               void *data);
-
-void vmcs_writel(unsigned long field, unsigned long value);
-unsigned long vmcs_readl(unsigned long field);
-
-static inline uint16_t vmcs_read16(unsigned long field)
-{
-       return vmcs_readl(field);
-}
-
-static inline uint32_t vmcs_read32(unsigned long field)
-{
-       return vmcs_readl(field);
-}
-
-static inline uint64_t vmcs_read64(unsigned long field)
-{
-#ifdef __x86_64__
-       return vmcs_readl(field);
-#else
-       return vmcs_readl(field) | ((uint64_t)vmcs_readl(field+1) << 32);
-#endif
-}
-
-static inline void vmcs_write32(unsigned long field, uint32_t value)
-{
-       vmcs_writel(field, value);
-}
-
-static inline int is_long_mode(void)
-{
-       return vmcs_read32(VM_ENTRY_CONTROLS) & VM_ENTRY_CONTROLS_IA32E_MASK;
-}
-
-static inline unsigned long guest_cr4(void)
-{
-       return (vmcs_readl(CR4_READ_SHADOW) & LITEVM_GUEST_CR4_MASK) |
-               (vmcs_readl(GUEST_CR4) & ~LITEVM_GUEST_CR4_MASK);
-}
-
-static inline int is_pae(void)
-{
-       return guest_cr4() & CR4_PAE_MASK;
-}
-
-static inline int is_pse(void)
-{
-       return guest_cr4() & CR4_PSE_MASK;
-}
-
-static inline unsigned long guest_cr0(void)
-{
-       return (vmcs_readl(CR0_READ_SHADOW) & LITEVM_GUEST_CR0_MASK) |
-               (vmcs_readl(GUEST_CR0) & ~LITEVM_GUEST_CR0_MASK);
-}
-
-static inline unsigned guest_cpl(void)
-{
-       return vmcs_read16(GUEST_CS_SELECTOR) & SELECTOR_RPL_MASK;
-}
-
-static inline int is_paging(void)
-{
-       return guest_cr0() & CR0_PG_MASK;
-}
-
-static inline int is_page_fault(uint32_t intr_info)
-{
-       return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
-                            INTR_INFO_VALID_MASK)) ==
-               (INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK);
-}
-
-static inline int is_external_interrupt(uint32_t intr_info)
-{
-       return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
-               == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
-}
-
-static inline void flush_guest_tlb(struct litevm_vcpu *vcpu)
-{
-       vmcs_writel(GUEST_CR3, vmcs_readl(GUEST_CR3));
-}
-
-static inline int memslot_id(struct litevm *litevm, struct litevm_memory_slot *slot)
-{
-       return slot - litevm->memslots;
-}
-
-/* uh, what? */
-#warning "pfn_to_page is bogus"
-static inline uintptr_t pfn_to_page(unsigned long pfn)
-{
-       return pfn << PAGE_SHIFT;
-}
-static inline struct litevm_mmu_page *page_header(hpa_t shadow_page)
-{
-       struct page *page = (struct page *)pfn_to_page(shadow_page >> PAGE_SHIFT);
-
-       return (struct litevm_mmu_page *)page->pg_private;
-}
-
-#ifdef __x86_64__
-
-/*
- * When emulating 32-bit mode, cr3 is only 32 bits even on x86_64.  Therefore
- * we need to allocate shadow page tables in the first 4GB of memory, which
- * happens to fit the DMA32 zone.
- */
-#define GFP_LITEVM_MMU (GFP_KERNEL | __GFP_DMA32)
-
-#else
-
-#define GFP_LITEVM_MMU GFP_KERNEL
-
-#endif
-
-/* just to get things to build ... include this stuff for now.
- * at some point, this interface gets nuke to and made more plan 
- * 9 like.
- */
-
-/* for LITEVM_CREATE_MEMORY_REGION */
-struct litevm_memory_region {
-       uint32_t slot;
-       uint32_t flags;
-       uint64_t guest_phys_addr;
-       uint64_t memory_size; /* bytes */
-};
-
-/* for litevm_memory_region::flags */
-#define LITEVM_MEM_LOG_DIRTY_PAGES  1UL
-
-
-#define LITEVM_EXIT_TYPE_FAIL_ENTRY 1
-#define LITEVM_EXIT_TYPE_VM_EXIT    2
-
-enum litevm_exit_reason {
-       LITEVM_EXIT_UNKNOWN,
-       LITEVM_EXIT_EXCEPTION,
-       LITEVM_EXIT_IO,
-       LITEVM_EXIT_CPUID,
-       LITEVM_EXIT_DEBUG,
-       LITEVM_EXIT_HLT,
-       LITEVM_EXIT_MMIO,
-};
-
-/* for LITEVM_RUN */
-struct litevm_run {
-       /* in */
-       uint32_t vcpu;
-       uint32_t emulated;  /* skip current instruction */
-       uint32_t mmio_completed; /* mmio request completed */
-
-       /* out */
-       uint32_t exit_type;
-       uint32_t exit_reason;
-       uint32_t instruction_length;
-       union {
-               /* LITEVM_EXIT_UNKNOWN */
-               struct {
-                       uint32_t hardware_exit_reason;
-               } hw;
-               /* LITEVM_EXIT_EXCEPTION */
-               struct {
-                       uint32_t exception;
-                       uint32_t error_code;
-               } ex;
-               /* LITEVM_EXIT_IO */
-               struct {
-#define LITEVM_EXIT_IO_IN  0
-#define LITEVM_EXIT_IO_OUT 1
-                       uint8_t direction;
-                       uint8_t size; /* bytes */
-                       uint8_t string;
-                       uint8_t string_down;
-                       uint8_t rep;
-                       uint8_t pad;
-                       uint16_t port;
-                       uint64_t count;
-                       union {
-                               uint64_t address;
-                               uint32_t value;
-                       };
-               } io;
-               struct {
-               } debug;
-               /* LITEVM_EXIT_MMIO */
-               struct {
-                       uint64_t phys_addr;
-                       uint8_t  data[8];
-                       uint32_t len;
-                       uint8_t  is_write;
-               } mmio;
-       };
-};
-
-/* for LITEVM_GET_REGS and LITEVM_SET_REGS */
-struct litevm_regs {
-       /* in */
-       uint32_t vcpu;
-       uint32_t padding;
-
-       /* out (LITEVM_GET_REGS) / in (LITEVM_SET_REGS) */
-       uint64_t rax, rbx, rcx, rdx;
-       uint64_t rsi, rdi, rsp, rbp;
-       uint64_t r8,  r9,  r10, r11;
-       uint64_t r12, r13, r14, r15;
-       uint64_t rip, rflags;
-};
-
-struct litevm_segment {
-       uint64_t base;
-       uint32_t limit;
-       uint16_t selector;
-       uint8_t  type;
-       uint8_t  present, dpl, db, s, l, g, avl;
-       uint8_t  unusable;
-       uint8_t  padding;
-};
-
-struct litevm_dtable {
-       uint64_t base;
-       uint16_t limit;
-       uint16_t padding[3];
-};
-
-/* for LITEVM_GET_SREGS and LITEVM_SET_SREGS */
-struct litevm_sregs {
-       /* in */
-       uint32_t vcpu;
-       uint32_t padding;
-
-       /* out (LITEVM_GET_SREGS) / in (LITEVM_SET_SREGS) */
-       struct litevm_segment cs, ds, es, fs, gs, ss;
-       struct litevm_segment tr, ldt;
-       struct litevm_dtable gdt, idt;
-       uint64_t cr0, cr2, cr3, cr4, cr8;
-       uint64_t efer;
-       uint64_t apic_base;
-
-       /* out (LITEVM_GET_SREGS) */
-       uint32_t pending_int;
-       uint32_t padding2;
-};
-
-/* for LITEVM_TRANSLATE */
-struct litevm_translation {
-       /* in */
-       uint64_t linear_address;
-       uint32_t vcpu;
-       uint32_t padding;
-
-       /* out */
-       uint64_t physical_address;
-       uint8_t  valid;
-       uint8_t  writeable;
-       uint8_t  usermode;
-};
-
-/* for LITEVM_INTERRUPT */
-struct litevm_interrupt {
-       /* in */
-       uint32_t vcpu;
-       uint32_t irq;
-};
-
-struct litevm_breakpoint {
-       uint32_t enabled;
-       uint32_t padding;
-       uint64_t address;
-};
-
-/* for LITEVM_DEBUG_GUEST */
-struct litevm_debug_guest {
-       /* int */
-       uint32_t vcpu;
-       uint32_t enabled;
-       struct litevm_breakpoint breakpoints[4];
-       uint32_t singlestep;
-};
-
-/* for LITEVM_GET_DIRTY_LOG */
-struct litevm_dirty_log {
-       uint32_t slot;
-       uint32_t padding;
-       union {
-               void *dirty_bitmap; /* one bit per page */
-               uint64_t paddingw;
-       };
-};
-
-enum {
-       LITEVM_RUN = 1,
-       LITEVM_GET_REGS,
-       LITEVM_SET_REGS,
-       LITEVM_GET_SREGS,
-       LITEVM_SET_SREGS,
-       LITEVM_TRANSLATE,
-       LITEVM_INTERRUPT,
-       LITEVM_DEBUG_GUEST,
-       LITEVM_SET_MEMORY_REGION,
-       LITEVM_CREATE_VCPU,
-       LITEVM_GET_DIRTY_LOG,
-};
-#endif
index 053a5f6..4d65620 100644 (file)
@@ -28,7 +28,7 @@
 #include <umem.h>
 #include <devalarm.h>
 #include <arch/types.h>
-#include <arch/litevm.h>
+#include <arch/vm.h>
 #include <arch/emulate.h>
 #include <arch/vmdebug.h>
 #include <arch/msr-index.h>
@@ -251,10 +251,6 @@ static void reload_tss(void)
 #endif
 }
 
-#warning "DEFINE PER CPU "
-//static DEFINE_PER_CPU(struct vmcs *, vmxarea);
-//static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
-
 static struct vmcs_descriptor {
        int size;
        int order;
@@ -397,8 +393,7 @@ static struct litevm_vcpu *__vcpu_load(struct litevm_vcpu *vcpu)
 #warning "__pa"
        uint64_t phys_addr = 0; //__pa(vcpu->vmcs);
        int cpu;
-#warning "get_cpu"
-       cpu = 0; //get_cpu();
+       cpu = core_id();
 
        if (vcpu->cpu != cpu) {
 #warning "smp_call_function"
@@ -406,10 +401,10 @@ static struct litevm_vcpu *__vcpu_load(struct litevm_vcpu *vcpu)
                vcpu->launched = 0;
        }
 #warning "per cpu"
-       if (0){//per_cpu(current_vmcs, cpu) != vcpu->vmcs) {
+       if (current->vmcs != vcpu->vmcs) {
                uint8_t error;
 
-               per_cpu(current_vmcs, cpu) = vcpu->vmcs;
+               current->vmcs = vcpu->vmcs;
                asm volatile ("vmptrld %1; setna %0"
                               : "=m"(error) : "m"(phys_addr) : "cc" );
                if (error)
@@ -493,8 +488,8 @@ static void free_litevm_area(void)
 {
        int cpu;
 
-       for_each_online_cpu(cpu)
-               free_vmcs(per_cpu(vmxarea, cpu));
+//     for_each_online_cpu(cpu)
+//             free_vmcs(per_cpu(vmxarea, cpu));
 }
 
 static __init int alloc_litevm_area(void)
diff --git a/kern/arch/x86/vm.h b/kern/arch/x86/vm.h
new file mode 100644 (file)
index 0000000..1b5992f
--- /dev/null
@@ -0,0 +1,578 @@
+#ifndef __LITEVM_H
+#define __LITEVM_H
+#include <page_alloc.h>
+#include <sys/queue.h>
+#include "vmx.h"
+
+#define CR0_PE_MASK (1ULL << 0)
+#define CR0_TS_MASK (1ULL << 3)
+#define CR0_NE_MASK (1ULL << 5)
+#define CR0_WP_MASK (1ULL << 16)
+#define CR0_NW_MASK (1ULL << 29)
+#define CR0_CD_MASK (1ULL << 30)
+#define CR0_PG_MASK (1ULL << 31)
+
+#define CR3_WPT_MASK (1ULL << 3)
+#define CR3_PCD_MASK (1ULL << 4)
+
+#define CR3_RESEVED_BITS 0x07ULL
+#define CR3_L_MODE_RESEVED_BITS (~((1ULL << 40) - 1) | 0x0fe7ULL)
+#define CR3_FLAGS_MASK ((1ULL << 5) - 1)
+
+#define CR4_VME_MASK (1ULL << 0)
+#define CR4_PSE_MASK (1ULL << 4)
+#define CR4_PAE_MASK (1ULL << 5)
+#define CR4_PGE_MASK (1ULL << 7)
+#define CR4_VMXE_MASK (1ULL << 13)
+
+#define LITEVM_GUEST_CR0_MASK \
+       (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK)
+#define LITEVM_VM_CR0_ALWAYS_ON LITEVM_GUEST_CR0_MASK
+
+#define LITEVM_GUEST_CR4_MASK \
+       (CR4_PSE_MASK | CR4_PAE_MASK | CR4_PGE_MASK | CR4_VMXE_MASK | CR4_VME_MASK)
+#define LITEVM_PMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK)
+#define LITEVM_RMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK | CR4_VME_MASK)
+
+#define INVALID_PAGE (~(hpa_t)0)
+#define UNMAPPED_GVA (~(gpa_t)0)
+
+#define LITEVM_MAX_VCPUS 1
+#define LITEVM_MEMORY_SLOTS 4
+#define LITEVM_NUM_MMU_PAGES 256
+
+#define FX_IMAGE_SIZE 512
+#define FX_IMAGE_ALIGN 16
+#define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN)
+
+#define DE_VECTOR 0
+#define DF_VECTOR 8
+#define TS_VECTOR 10
+#define NP_VECTOR 11
+#define SS_VECTOR 12
+#define GP_VECTOR 13
+#define PF_VECTOR 14
+
+#define SELECTOR_TI_MASK (1 << 2)
+#define SELECTOR_RPL_MASK 0x03
+
+#define IOPL_SHIFT 12
+
+/*
+ * Address types:
+ *
+ *  gva - guest virtual address
+ *  gpa - guest physical address
+ *  gfn - guest frame number
+ *  hva - host virtual address
+ *  hpa - host physical address
+ *  hfn - host frame number
+ */
+
+typedef unsigned long  gva_t;
+typedef uint64_t            gpa_t;
+typedef unsigned long  gfn_t;
+
+typedef unsigned long  hva_t;
+typedef uint64_t            hpa_t;
+typedef unsigned long  hfn_t;
+
+struct litevm_mmu_page {
+       LIST_HEAD(link, litevm_mmu_page) link;
+       hpa_t page_hpa;
+       unsigned long slot_bitmap; /* One bit set per slot which has memory
+                                   * in this shadow page.
+                                   */
+       int global;              /* Set if all ptes in this page are global */
+       uint64_t *parent_pte;
+};
+
+struct vmcs {
+       uint32_t revision_id;
+       uint32_t abort;
+       char data[0];
+};
+
+struct vmx_msr_entry {
+       uint32_t index;
+       uint32_t reserved;
+       uint64_t data;
+};
+
+struct litevm_vcpu;
+
+/*
+ * x86 supports 3 paging modes (4-level 64-bit, 3-level 64-bit, and 2-level
+ * 32-bit).  The litevm_mmu structure abstracts the details of the current mmu
+ * mode.
+ */
+struct litevm_mmu {
+       void (*new_cr3)(struct litevm_vcpu *vcpu);
+       int (*page_fault)(struct litevm_vcpu *vcpu, gva_t gva, uint32_t err);
+       void (*inval_page)(struct litevm_vcpu *vcpu, gva_t gva);
+       void (*free)(struct litevm_vcpu *vcpu);
+       gpa_t (*gva_to_gpa)(struct litevm_vcpu *vcpu, gva_t gva);
+       hpa_t root_hpa;
+       int root_level;
+       int shadow_root_level;
+};
+
+struct litevm_guest_debug {
+       int enabled;
+       unsigned long bp[4];
+       int singlestep;
+};
+
+enum {
+       VCPU_REGS_RAX = 0,
+       VCPU_REGS_RCX = 1,
+       VCPU_REGS_RDX = 2,
+       VCPU_REGS_RBX = 3,
+       VCPU_REGS_RSP = 4,
+       VCPU_REGS_RBP = 5,
+       VCPU_REGS_RSI = 6,
+       VCPU_REGS_RDI = 7,
+#ifdef __x86_64__
+       VCPU_REGS_R8 = 8,
+       VCPU_REGS_R9 = 9,
+       VCPU_REGS_R10 = 10,
+       VCPU_REGS_R11 = 11,
+       VCPU_REGS_R12 = 12,
+       VCPU_REGS_R13 = 13,
+       VCPU_REGS_R14 = 14,
+       VCPU_REGS_R15 = 15,
+#endif
+       NR_VCPU_REGS
+};
+
+struct litevm_vcpu {
+       struct litevm *litevm;
+       struct vmcs *vmcs;
+       qlock_t mutex; //struct mutex mutex;
+       int   cpu;
+       int   launched;
+       unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */
+#define NR_IRQ_WORDS (256 / BITS_PER_LONG)
+       unsigned long irq_pending[NR_IRQ_WORDS];
+       unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */
+       unsigned long rip;      /* needs vcpu_load_rsp_rip() */
+
+       unsigned long cr2;
+       unsigned long cr3;
+       unsigned long cr8;
+       uint64_t shadow_efer;
+       uint64_t apic_base;
+       int nmsrs;
+       struct vmx_msr_entry *guest_msrs;
+       struct vmx_msr_entry *host_msrs;
+       LIST_HEAD(free_pages, free_pages) free_pages;
+       //struct list_head free_pages;
+       struct litevm_mmu_page page_header_buf[LITEVM_NUM_MMU_PAGES];
+       struct litevm_mmu mmu;
+
+       struct litevm_guest_debug guest_debug;
+
+       char fx_buf[FX_BUF_SIZE];
+       char *host_fx_image;
+       char *guest_fx_image;
+
+       int mmio_needed;
+       int mmio_read_completed;
+       int mmio_is_write;
+       int mmio_size;
+       unsigned char mmio_data[8];
+       gpa_t mmio_phys_addr;
+
+       struct{
+               int active;
+               uint8_t save_iopl;
+               struct {
+                       unsigned long base;
+                       uint32_t limit;
+                       uint32_t ar;
+               } tr;
+       } rmode;
+};
+
+struct litevm_memory_slot {
+       gfn_t base_gfn;
+       unsigned long npages;
+       unsigned long flags;
+       struct page **phys_mem;
+       unsigned long *dirty_bitmap;
+};
+
+struct litevm {
+       spinlock_t lock; /* protects everything except vcpus */
+       int nmemslots;
+       struct litevm_memory_slot memslots[LITEVM_MEMORY_SLOTS];
+       LIST_HEAD(active_mmu_pages, active_mmu_pages) active_mmu_pages;
+       //struct list_head active_mmu_pages;
+       struct litevm_vcpu vcpus[LITEVM_MAX_VCPUS];
+       int memory_config_version;
+       int busy;
+};
+
+struct litevm_stat {
+       uint32_t pf_fixed;
+       uint32_t pf_guest;
+       uint32_t tlb_flush;
+       uint32_t invlpg;
+
+       uint32_t exits;
+       uint32_t io_exits;
+       uint32_t mmio_exits;
+       uint32_t signal_exits;
+       uint32_t irq_exits;
+};
+
+extern struct litevm_stat litevm_stat;
+
+#define litevm_printf(litevm, fmt ...) printk(KERN_DEBUG fmt)
+#define vcpu_printf(vcpu, fmt...) litevm_printf(vcpu->litevm, fmt)
+
+void litevm_mmu_destroy(struct litevm_vcpu *vcpu);
+int litevm_mmu_init(struct litevm_vcpu *vcpu);
+
+int litevm_mmu_reset_context(struct litevm_vcpu *vcpu);
+void litevm_mmu_slot_remove_write_access(struct litevm *litevm, int slot);
+
+hpa_t gpa_to_hpa(struct litevm_vcpu *vcpu, gpa_t gpa);
+#define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
+#define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB)
+static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; }
+hpa_t gva_to_hpa(struct litevm_vcpu *vcpu, gva_t gva);
+
+extern hpa_t bad_page_address;
+
+static inline struct page *gfn_to_page(struct litevm_memory_slot *slot, gfn_t gfn)
+{
+       return slot->phys_mem[gfn - slot->base_gfn];
+}
+
+struct litevm_memory_slot *gfn_to_memslot(struct litevm *litevm, gfn_t gfn);
+void mark_page_dirty(struct litevm *litevm, gfn_t gfn);
+
+void realmode_lgdt(struct litevm_vcpu *vcpu, uint16_t size, unsigned long address);
+void realmode_lidt(struct litevm_vcpu *vcpu, uint16_t size, unsigned long address);
+void realmode_lmsw(struct litevm_vcpu *vcpu, unsigned long msw,
+                  unsigned long *rflags);
+
+unsigned long realmode_get_cr(struct litevm_vcpu *vcpu, int cr);
+void realmode_set_cr(struct litevm_vcpu *vcpu, int cr, unsigned long value,
+                    unsigned long *rflags);
+
+int litevm_read_guest(struct litevm_vcpu *vcpu,
+              gva_t addr,
+              unsigned long size,
+              void *dest);
+
+int litevm_write_guest(struct litevm_vcpu *vcpu,
+               gva_t addr,
+               unsigned long size,
+               void *data);
+
+void vmcs_writel(unsigned long field, unsigned long value);
+unsigned long vmcs_readl(unsigned long field);
+
+static inline uint16_t vmcs_read16(unsigned long field)
+{
+       return vmcs_readl(field);
+}
+
+static inline uint32_t vmcs_read32(unsigned long field)
+{
+       return vmcs_readl(field);
+}
+
+static inline uint64_t vmcs_read64(unsigned long field)
+{
+#ifdef __x86_64__
+       return vmcs_readl(field);
+#else
+       return vmcs_readl(field) | ((uint64_t)vmcs_readl(field+1) << 32);
+#endif
+}
+
+static inline void vmcs_write32(unsigned long field, uint32_t value)
+{
+       vmcs_writel(field, value);
+}
+
+static inline int is_long_mode(void)
+{
+       return vmcs_read32(VM_ENTRY_CONTROLS) & VM_ENTRY_CONTROLS_IA32E_MASK;
+}
+
+static inline unsigned long guest_cr4(void)
+{
+       return (vmcs_readl(CR4_READ_SHADOW) & LITEVM_GUEST_CR4_MASK) |
+               (vmcs_readl(GUEST_CR4) & ~LITEVM_GUEST_CR4_MASK);
+}
+
+static inline int is_pae(void)
+{
+       return guest_cr4() & CR4_PAE_MASK;
+}
+
+static inline int is_pse(void)
+{
+       return guest_cr4() & CR4_PSE_MASK;
+}
+
+static inline unsigned long guest_cr0(void)
+{
+       return (vmcs_readl(CR0_READ_SHADOW) & LITEVM_GUEST_CR0_MASK) |
+               (vmcs_readl(GUEST_CR0) & ~LITEVM_GUEST_CR0_MASK);
+}
+
+static inline unsigned guest_cpl(void)
+{
+       return vmcs_read16(GUEST_CS_SELECTOR) & SELECTOR_RPL_MASK;
+}
+
+static inline int is_paging(void)
+{
+       return guest_cr0() & CR0_PG_MASK;
+}
+
+static inline int is_page_fault(uint32_t intr_info)
+{
+       return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
+                            INTR_INFO_VALID_MASK)) ==
+               (INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK);
+}
+
+static inline int is_external_interrupt(uint32_t intr_info)
+{
+       return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
+               == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
+}
+
+static inline void flush_guest_tlb(struct litevm_vcpu *vcpu)
+{
+       vmcs_writel(GUEST_CR3, vmcs_readl(GUEST_CR3));
+}
+
+static inline int memslot_id(struct litevm *litevm, struct litevm_memory_slot *slot)
+{
+       return slot - litevm->memslots;
+}
+
+/* uh, what? */
+//#warning "pfn_to_page is bogus"
+static inline uintptr_t pfn_to_page(unsigned long pfn)
+{
+       return pfn << PAGE_SHIFT;
+}
+static inline struct litevm_mmu_page *page_header(hpa_t shadow_page)
+{
+       struct page *page = (struct page *)pfn_to_page(shadow_page >> PAGE_SHIFT);
+
+       return (struct litevm_mmu_page *)page->pg_private;
+}
+
+#ifdef __x86_64__
+
+/*
+ * When emulating 32-bit mode, cr3 is only 32 bits even on x86_64.  Therefore
+ * we need to allocate shadow page tables in the first 4GB of memory, which
+ * happens to fit the DMA32 zone.
+ */
+#define GFP_LITEVM_MMU (GFP_KERNEL | __GFP_DMA32)
+
+#else
+
+#define GFP_LITEVM_MMU GFP_KERNEL
+
+#endif
+
+/* just to get things to build ... include this stuff for now.
+ * at some point, this interface gets nuke to and made more plan 
+ * 9 like.
+ */
+
+/* for LITEVM_CREATE_MEMORY_REGION */
+struct litevm_memory_region {
+       uint32_t slot;
+       uint32_t flags;
+       uint64_t guest_phys_addr;
+       uint64_t memory_size; /* bytes */
+};
+
+/* for litevm_memory_region::flags */
+#define LITEVM_MEM_LOG_DIRTY_PAGES  1UL
+
+
+#define LITEVM_EXIT_TYPE_FAIL_ENTRY 1
+#define LITEVM_EXIT_TYPE_VM_EXIT    2
+
+enum litevm_exit_reason {
+       LITEVM_EXIT_UNKNOWN,
+       LITEVM_EXIT_EXCEPTION,
+       LITEVM_EXIT_IO,
+       LITEVM_EXIT_CPUID,
+       LITEVM_EXIT_DEBUG,
+       LITEVM_EXIT_HLT,
+       LITEVM_EXIT_MMIO,
+};
+
+/* for LITEVM_RUN */
+struct litevm_run {
+       /* in */
+       uint32_t vcpu;
+       uint32_t emulated;  /* skip current instruction */
+       uint32_t mmio_completed; /* mmio request completed */
+
+       /* out */
+       uint32_t exit_type;
+       uint32_t exit_reason;
+       uint32_t instruction_length;
+       union {
+               /* LITEVM_EXIT_UNKNOWN */
+               struct {
+                       uint32_t hardware_exit_reason;
+               } hw;
+               /* LITEVM_EXIT_EXCEPTION */
+               struct {
+                       uint32_t exception;
+                       uint32_t error_code;
+               } ex;
+               /* LITEVM_EXIT_IO */
+               struct {
+#define LITEVM_EXIT_IO_IN  0
+#define LITEVM_EXIT_IO_OUT 1
+                       uint8_t direction;
+                       uint8_t size; /* bytes */
+                       uint8_t string;
+                       uint8_t string_down;
+                       uint8_t rep;
+                       uint8_t pad;
+                       uint16_t port;
+                       uint64_t count;
+                       union {
+                               uint64_t address;
+                               uint32_t value;
+                       };
+               } io;
+               struct {
+               } debug;
+               /* LITEVM_EXIT_MMIO */
+               struct {
+                       uint64_t phys_addr;
+                       uint8_t  data[8];
+                       uint32_t len;
+                       uint8_t  is_write;
+               } mmio;
+       };
+};
+
+/* for LITEVM_GET_REGS and LITEVM_SET_REGS */
+struct litevm_regs {
+       /* in */
+       uint32_t vcpu;
+       uint32_t padding;
+
+       /* out (LITEVM_GET_REGS) / in (LITEVM_SET_REGS) */
+       uint64_t rax, rbx, rcx, rdx;
+       uint64_t rsi, rdi, rsp, rbp;
+       uint64_t r8,  r9,  r10, r11;
+       uint64_t r12, r13, r14, r15;
+       uint64_t rip, rflags;
+};
+
+struct litevm_segment {
+       uint64_t base;
+       uint32_t limit;
+       uint16_t selector;
+       uint8_t  type;
+       uint8_t  present, dpl, db, s, l, g, avl;
+       uint8_t  unusable;
+       uint8_t  padding;
+};
+
+struct litevm_dtable {
+       uint64_t base;
+       uint16_t limit;
+       uint16_t padding[3];
+};
+
+/* for LITEVM_GET_SREGS and LITEVM_SET_SREGS */
+struct litevm_sregs {
+       /* in */
+       uint32_t vcpu;
+       uint32_t padding;
+
+       /* out (LITEVM_GET_SREGS) / in (LITEVM_SET_SREGS) */
+       struct litevm_segment cs, ds, es, fs, gs, ss;
+       struct litevm_segment tr, ldt;
+       struct litevm_dtable gdt, idt;
+       uint64_t cr0, cr2, cr3, cr4, cr8;
+       uint64_t efer;
+       uint64_t apic_base;
+
+       /* out (LITEVM_GET_SREGS) */
+       uint32_t pending_int;
+       uint32_t padding2;
+};
+
+/* for LITEVM_TRANSLATE */
+struct litevm_translation {
+       /* in */
+       uint64_t linear_address;
+       uint32_t vcpu;
+       uint32_t padding;
+
+       /* out */
+       uint64_t physical_address;
+       uint8_t  valid;
+       uint8_t  writeable;
+       uint8_t  usermode;
+};
+
+/* for LITEVM_INTERRUPT */
+struct litevm_interrupt {
+       /* in */
+       uint32_t vcpu;
+       uint32_t irq;
+};
+
+struct litevm_breakpoint {
+       uint32_t enabled;
+       uint32_t padding;
+       uint64_t address;
+};
+
+/* for LITEVM_DEBUG_GUEST */
+struct litevm_debug_guest {
+       /* int */
+       uint32_t vcpu;
+       uint32_t enabled;
+       struct litevm_breakpoint breakpoints[4];
+       uint32_t singlestep;
+};
+
+/* for LITEVM_GET_DIRTY_LOG */
+struct litevm_dirty_log {
+       uint32_t slot;
+       uint32_t padding;
+       union {
+               void *dirty_bitmap; /* one bit per page */
+               uint64_t paddingw;
+       };
+};
+
+enum {
+       LITEVM_RUN = 1,
+       LITEVM_GET_REGS,
+       LITEVM_SET_REGS,
+       LITEVM_GET_SREGS,
+       LITEVM_SET_SREGS,
+       LITEVM_TRANSLATE,
+       LITEVM_INTERRUPT,
+       LITEVM_DEBUG_GUEST,
+       LITEVM_SET_MEMORY_REGION,
+       LITEVM_CREATE_VCPU,
+       LITEVM_GET_DIRTY_LOG,
+};
+#endif
diff --git a/kern/drivers/dev/#vm.c# b/kern/drivers/dev/#vm.c#
new file mode 100644 (file)
index 0000000..97bf7d2
--- /dev/null
@@ -0,0 +1,372 @@
+//#define DEBUG
+/* Copyright 2014 Google Inc.
+ * Copyright (c) 2013 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * devvm/#V: a device for VMs
+ *
+ */
+
+#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 <devalarm.h>
+#incluce <arch/types.h>
+#include <arch/litevm.h>
+
+/* qid path types */
+enum {
+       Qtopdir = 1,
+       Qclone,
+       Qstat,
+       Qvmdir,
+       Qctl,
+       Qimage,
+};
+
+/* This paddr/kaddr is a bit dangerous.  it'll work so long as we don't need all
+ * 64 bits for a physical address (48 is the current norm on x86_64).
+ * We're probably going to move to a model where we put the VM index or something
+ * into the qid, but this works for now.
+ */
+#define ADDR_SHIFT 5
+#define QID2VM(q) ((struct proc_alarm*)KADDR(((q).path >> ADDR_SHIFT)))
+#define TYPE(q) ((q).path & ((1 << ADDR_SHIFT) - 1))
+#define QID(ptr, type) ((PADDR(ptr) << ADDR_SHIFT) | type)
+
+/* vm's have an image.
+ * Note that the image can be read even as it is running. */
+struct vm {
+       struct vm *next;
+       struct kref                                     kref;
+       /* should this be an array of pages? Hmm. */
+       void                                           *image;
+       unsigned long                                   imagesize;
+       int                                             id;
+};
+
+static spinlock_t vmlock;
+/* array, not linked list. We expect few, might as well be cache friendly. */
+static struct vm *vms = NULL;
+static int nvm = 0;
+
+static spinlock_t vmidlock[1];
+static struct kref vmid[1] = { {(void *)1, fake_release} };
+
+static void vm_release(struct kref *kref)
+{
+       struct vm *v = container_of(kref, struct vm, kref);
+       spin_lock(&vmlock);
+       /* cute trick. Save the last element of the array in place of the
+        * one we're deleting. Reduce nvm. Don't realloc; that way, next
+
+        * do and just return.
+        */
+       if (v != &vms[nvm-1]){
+               /* free the image ... oops */
+               /* get rid of the kref. */
+               *v = vms[nvm-1];
+       }
+       nvm--;
+       spin_unlock(&vmlock);
+}
+
+static int newvmid(void)
+{
+       int id;
+       spin_lock(vmidlock);
+       id = kref_refcnt(vmid);
+       kref_get(vmid, 1);
+       spin_unlock(vmidlock);
+       return id;
+}
+
+static int vmgen(struct chan *c, char *entry_name,
+                struct dirtab *unused, int unused_nr_dirtab,
+                int s, struct dir *dp)
+{
+       struct qid q;
+       struct vm *vm_i;
+       printd("GEN s %d\n", s);
+       /* Whether we're in one dir or at the top, .. still takes us to the top. */
+       if (s == DEVDOTDOT) {
+               mkqid(&q, Qtopdir, 0, QTDIR);
+               devdir(c, c->qid, "#V", 0, eve, 0555, dp);
+               return 1;
+       }
+       printd("TYPE %d\n", TYPE(c->qid));
+       switch (TYPE(c->qid)) {
+       case Qtopdir:
+               printd("Qtopdir s %d nvm %d\n", s, nvm);
+               /* Generate elements for the top level dir.  We support clone, stat,
+                * vm dirs at the top level */
+               if (s == 0) {
+                       mkqid(&q, Qclone, 0, QTFILE);
+                       devdir(c, q, "clone", 0, eve, 0666, dp);
+                       return 1;
+               }
+               s--;
+               if (s == 0) {
+                       mkqid(&q, Qstat, 0, QTFILE);
+                       devdir(c, q, "stat", 0, eve, 0666, dp);
+                       return 1;
+               }
+               s--;    /* 1 -> 0th element, 2 -> 1st element, etc */
+               spin_lock(&vmlock);
+               if (s >= nvm){
+                       printd("DONE qtopdir\n");
+                       spin_unlock(&vmlock);
+                       return -1;
+               }
+               vm_i = &vms[s];
+               snprintf(get_cur_genbuf(), GENBUF_SZ, "vm%d", vm_i->id);
+               spin_unlock(&vmlock);
+               mkqid(&q, QID(vm_i, Qvmdir), 0, QTDIR);
+               devdir(c, q, get_cur_genbuf(), 0, eve, 0555, dp);
+               return 1;
+       case Qvmdir:
+               /* Gen the contents of the vm dirs */
+               s += Qctl;      /* first time through, start on Qctl */
+               switch (s) {
+               case Qctl:
+                       mkqid(&q, QID(QID2VM(c->qid), Qctl), 0, QTFILE);
+                       devdir(c, q, "ctl", 0, eve, 0666, dp);
+                       return 1;
+               case Qimage:
+                       mkqid(&q, QID(QID2VM(c->qid), Qimage), 0, QTFILE);
+                       devdir(c, q, "image", 0, eve, 0666, dp);
+                       return 1;
+               }
+               return -1;
+               /* Need to also provide a direct hit for Qclone and all other files (at
+                * all levels of the hierarchy).  Every file is both
+                * generated (via the s increments in their respective directories) and
+                * directly gen-able.  devstat() will call gen with a specific path in
+                * the qid.  In these cases, we make a dir for whatever they are asking
+                * for.  Note the qid stays the same.  I think this is what the old
+                * plan9 comments above devgen were talking about for (ii).
+                *
+                * We don't need to do this for the directories - devstat will look for
+                * the a directory by path and fail.  Then it will manually build the
+                * stat output (check the -1 case in devstat). */
+       case Qclone:
+               devdir(c, c->qid, "clone", 0, eve, 0666, dp);
+               return 1;
+       case Qstat:
+               devdir(c, c->qid, "stat", 0, eve, 0444, dp);
+               return 1;
+       case Qctl:
+               devdir(c, c->qid, "ctl", 0, eve, 0666, dp);
+               return 1;
+       case Qimage:
+               devdir(c, c->qid, "image", 0, eve, 0666, dp);
+               return 1;
+       }
+       return -1;
+}
+
+static void vminit(void)
+{
+       spinlock_init(&vmlock);
+       spinlock_init(vmidlock);
+}
+
+static struct chan *vmattach(char *spec)
+{
+       struct chan *c = devattach('V', spec);
+       mkqid(&c->qid, Qtopdir, 0, QTDIR);
+       return c;
+}
+
+static struct walkqid *vmwalk(struct chan *c, struct chan *nc, char **name,
+                             int nname)
+{
+       return devwalk(c, nc, name, nname, 0, 0, vmgen);
+}
+
+static long vmstat(struct chan *c, uint8_t *db, long n)
+{
+       return devstat(c, db, n, 0, 0, vmgen);
+}
+
+/* It shouldn't matter if p = current is DYING.  We'll eventually fail to insert
+ * the open chan into p's fd table, then decref the chan. */
+static struct chan *vmopen(struct chan *c, int omode)
+{
+       struct vm *v = c->aux;
+       switch (TYPE(c->qid)) {
+       case Qtopdir:
+       case Qvmdir:
+               if (omode & ORCLOSE)
+                       error(Eperm);
+               if (omode != OREAD)
+                       error(Eisdir);
+               break;
+       case Qclone:
+               spin_lock(&vmlock);
+               vms = krealloc(vms, sizeof(vms[0])*(nvm+1),0);
+               v = &vms[nvm];
+               nvm++;
+               spin_unlock(&vmlock);
+               kref_init(&v->kref, vm_release, 1);
+               v->id = newvmid();
+               mkqid(&c->qid, QID(v, Qctl), 0, QTFILE);
+               c->aux = v;
+               printd("New VM id %d\n", v->id);
+               break;
+       case Qstat:
+               break;
+       case Qctl:
+       case Qimage:
+               /* the purpose of opening is to hold a kref on the proc_vm */
+               v = c->aux;
+               /* this isn't a valid pointer yet, since our chan doesn't have a
+                * ref.  since the time that walk gave our chan the qid, the chan
+                * could have been closed, and the vm decref'd and freed.  the
+                * qid is essentially an uncounted reference, and we need to go to
+                * the source to attempt to get a real ref.  Unfortunately, this is
+                * another scan of the list, same as devsrv.  We could speed it up
+                * by storing an "on_list" bool in the vm_is. */
+               //if (!vm_i)
+               //      error("Unable to open vm, concurrent closing");
+               break;
+       }
+       c->mode = openmode(omode);
+       /* Assumes c is unique (can't be closed concurrently */
+       c->flag |= COPEN;
+       c->offset = 0;
+       return c;
+}
+
+static void vmcreate(struct chan *c, char *name, int omode, int perm)
+{
+       error(Eperm);
+}
+
+static void vmremove(struct chan *c)
+{
+       error(Eperm);
+}
+
+static long vmwstat(struct chan *c, uint8_t *dp, long n)
+{
+       error("No vmwstat");
+       return 0;
+}
+
+static void vmclose(struct chan *c)
+{
+       struct vm *v = c->aux;
+       if (!v)
+               return;
+       /* There are more closes than opens.  For instance, sysstat doesn't open,
+        * but it will close the chan it got from namec.  We only want to clean
+        * up/decref chans that were actually open. */
+       if (!(c->flag & COPEN))
+               return;
+       switch (TYPE(c->qid)) {
+               /* for now, leave the VM active even when we close ctl */
+       case Qctl:
+               break;
+       case Qimage:
+               kref_put(&v->kref);
+               break;
+       }
+}
+
+static long vmread(struct chan *c, void *ubuf, long n, int64_t offset)
+{
+       struct vm *v = c->aux;
+       printd("VMREAD\n");
+       switch (TYPE(c->qid)) {
+       case Qtopdir:
+       case Qvmdir:
+               return devdirread(c, ubuf, n, 0, 0, vmgen);
+       case Qstat:
+               return readnum(offset, ubuf, n, nvm, NUMSIZE32);
+       case Qctl:
+               assert(v);
+               return readnum(offset, ubuf, n, v->id, NUMSIZE32);
+       case Qimage:
+               assert(v);
+               return readmem(offset, ubuf, n,
+                              v->image, v->imagesize);
+       default:
+               panic("Bad QID %p in devvm", c->qid.path);
+       }
+       return 0;
+}
+
+static long vmwrite(struct chan *c, void *ubuf, long n, int64_t unused)
+{
+       ERRSTACK(1);
+       char buf[32];
+       struct cmdbuf *cb;
+       struct vm *vm;
+       uint64_t hexval;
+
+       switch (TYPE(c->qid)) {
+       case Qtopdir:
+       case Qvmdir:
+       case Qstat:
+               error(Eperm);
+       case Qctl:
+               vm = c->aux;
+               cb = parsecmd(ubuf, n);
+               if (waserror()) {
+                       kfree(cb);
+                       nexterror();
+               }
+               if (!strcmp(cb->f[0], "start")) {
+                       error("can't run a vm yet");
+               } else if (!strcmp(cb->f[0], "stop")) {
+                       error("can't stop a vm yet");
+               } else {
+                       error("%s: not implemented", cb->f[0]);
+               }
+               kfree(cb);
+               poperror();
+               break;
+       case Qimage:
+               error("can't write an image yet");
+               break;
+       default:
+               panic("Bad QID %p in devvm", c->qid.path);
+       }
+       return n;
+}
+
+struct dev vmdevtab = {
+       'V',
+       "vm",
+
+       devreset,
+       vminit,
+       devshutdown,
+       vmattach,
+       vmwalk,
+       vmstat,
+       vmopen,
+       vmcreate,
+       vmclose,
+       vmread,
+       devbread,
+       vmwrite,
+       devbwrite,
+       vmremove,
+       vmwstat,
+       devpower,
+       devconfig,
+       devchaninfo,
+};
index 39cfc20..984f664 100644 (file)
@@ -23,7 +23,7 @@
 #include <umem.h>
 #include <devalarm.h>
 #include <arch/types.h>
-#include <arch/litevm.h>
+#include <arch/vm.h>
 #include <arch/emulate.h>
 #include <arch/vmdebug.h>
 
index 250cdd9..2736428 100644 (file)
@@ -18,6 +18,9 @@
 #include <syscall.h>
 #include <alarm.h>
 #include <trace.h>
+#ifdef CONFIG_X86_64
+#include <arch/vm.h>
+#endif
 
 #ifdef __SHARC__
 typedef sharC_env_t;
@@ -26,6 +29,9 @@ typedef sharC_env_t;
 struct per_cpu_info {
 #ifdef CONFIG_X86_64
        uintptr_t stacktop;
+       /* virtual machines */
+       struct vmcs vmxarea;
+       struct vmcs *vmcs;
 #endif
        spinlock_t lock;
        /* Process management */