[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [SVM] Move VMCB construction to VCPU creation time.
# HG changeset patch # User kaf24@xxxxxxxxxxxxxxxxxxxxx # Node ID 81c451bd398e950f9df8819ab7fab4b847815c82 # Parent f8ffeb540ec168ac3461e3572ba2244cf53d23db [SVM] Move VMCB construction to VCPU creation time. Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> --- xen/arch/x86/hvm/svm/svm.c | 53 ++------- xen/arch/x86/hvm/svm/vmcb.c | 217 +++++++++++++++---------------------- xen/include/asm-x86/hvm/svm/vmcb.h | 20 +-- 3 files changed, 113 insertions(+), 177 deletions(-) diff -r f8ffeb540ec1 -r 81c451bd398e xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Mon Nov 06 18:57:33 2006 +0000 +++ b/xen/arch/x86/hvm/svm/svm.c Mon Nov 06 20:23:08 2006 +0000 @@ -213,10 +213,7 @@ static void stop_svm(void) free_vmcb(root_vmcb[cpu]); root_vmcb[cpu] = NULL; root_vmcb_pa[cpu] = 0; - - printk("AMD SVM Extension is disabled.\n"); -} - +} static void svm_store_cpu_guest_regs( struct vcpu *v, struct cpu_user_regs *regs, unsigned long *crs) @@ -690,35 +687,13 @@ int svm_long_mode_enabled(struct vcpu *v return SVM_LONG_GUEST(v); } - - static void arch_svm_do_launch(struct vcpu *v) { - cpu_user_regs_t *regs = ¤t->arch.guest_context.user_regs; - int error; - -#if 0 - if (svm_dbg_on) - printk("Do launch\n"); -#endif - error = construct_vmcb(&v->arch.hvm_svm, regs); - if ( error < 0 ) - { - if (v->vcpu_id == 0) { - printk("Failed to construct a new VMCB for BSP.\n"); - } else { - printk("Failed to construct a new VMCB for AP %d\n", v->vcpu_id); - } - domain_crash_synchronous(); - } - svm_do_launch(v); -#if 0 - if (svm_dbg_on) - svm_dump_host_regs(__func__); -#endif - if (v->vcpu_id != 0) - { + + if ( v->vcpu_id != 0 ) + { + cpu_user_regs_t *regs = ¤t->arch.guest_context.user_regs; u16 cs_sel = regs->cs; /* * This is the launch of an AP; set state so that we begin executing @@ -770,24 +745,26 @@ static void svm_ctxt_switch_to(struct vc static int svm_vcpu_initialise(struct vcpu *v) { + int rc; + v->arch.schedule_tail = arch_svm_do_launch; v->arch.ctxt_switch_from = svm_ctxt_switch_from; v->arch.ctxt_switch_to = svm_ctxt_switch_to; - if ( (v->arch.hvm_svm.vmcb = alloc_vmcb()) == NULL ) - { - printk("Failed to create a new VMCB\n"); - return -ENOMEM; - } - - v->arch.hvm_svm.vmcb_pa = virt_to_maddr(v->arch.hvm_svm.vmcb); + if ( (rc = svm_create_vmcb(v)) != 0 ) + { + dprintk(XENLOG_WARNING, + "Failed to create VMCB for vcpu %d: err=%d.\n", + v->vcpu_id, rc); + return rc; + } return 0; } static void svm_vcpu_destroy(struct vcpu *v) { - destroy_vmcb(&v->arch.hvm_svm); + svm_destroy_vmcb(v); } int start_svm(void) diff -r f8ffeb540ec1 -r 81c451bd398e xen/arch/x86/hvm/svm/vmcb.c --- a/xen/arch/x86/hvm/svm/vmcb.c Mon Nov 06 18:57:33 2006 +0000 +++ b/xen/arch/x86/hvm/svm/vmcb.c Mon Nov 06 20:23:08 2006 +0000 @@ -86,13 +86,14 @@ void free_host_save_area(struct host_sav free_xenheap_page(hsa); } -/* Set up intercepts to exit the guest into the hypervisor when we want it. */ -static int construct_vmcb_controls(struct arch_svm_struct *arch_svm) -{ +static int construct_vmcb(struct vcpu *v) +{ + struct arch_svm_struct *arch_svm = &v->arch.hvm_svm; struct vmcb_struct *vmcb = arch_svm->vmcb; - u32 *iopm, *msrpm; - - /* mask off all general 1 intercepts except those listed here */ + segment_attributes_t attrib; + unsigned long dr7; + + /* SVM intercepts. */ vmcb->general1_intercepts = GENERAL1_INTERCEPT_INTR | GENERAL1_INTERCEPT_NMI | GENERAL1_INTERCEPT_SMI | GENERAL1_INTERCEPT_INIT | @@ -100,74 +101,43 @@ static int construct_vmcb_controls(struc GENERAL1_INTERCEPT_HLT | GENERAL1_INTERCEPT_INVLPG | GENERAL1_INTERCEPT_INVLPGA | GENERAL1_INTERCEPT_IOIO_PROT | GENERAL1_INTERCEPT_MSR_PROT | GENERAL1_INTERCEPT_SHUTDOWN_EVT; - - /* turn on the general 2 intercepts */ vmcb->general2_intercepts = GENERAL2_INTERCEPT_VMRUN | GENERAL2_INTERCEPT_VMMCALL | GENERAL2_INTERCEPT_VMLOAD | GENERAL2_INTERCEPT_VMSAVE | GENERAL2_INTERCEPT_STGI | GENERAL2_INTERCEPT_CLGI | GENERAL2_INTERCEPT_SKINIT | GENERAL2_INTERCEPT_RDTSCP; - /* read or write all debug registers 0 - 15 */ + /* Intercept all debug-register writes. */ vmcb->dr_intercepts = DR_INTERCEPT_ALL_WRITES; - /* RD/WR all control registers 0 - 15, but not read CR2 */ + /* Intercept all control-register accesses, except to CR2. */ vmcb->cr_intercepts = ~(CR_INTERCEPT_CR2_READ | CR_INTERCEPT_CR2_WRITE); - /* The following is for I/O and MSR permision map */ - iopm = alloc_xenheap_pages(get_order_from_bytes(IOPM_SIZE)); - if ( iopm != NULL ) - { - memset(iopm, 0xff, IOPM_SIZE); - clear_bit(PC_DEBUG_PORT, iopm); - } - msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE)); - if ( msrpm != NULL ) - memset(msrpm, 0xff, MSRPM_SIZE); - - arch_svm->iopm = iopm; - arch_svm->msrpm = msrpm; - - if ( !iopm || !msrpm ) - return 1; - - vmcb->iopm_base_pa = (u64) virt_to_maddr(iopm); - vmcb->msrpm_base_pa = (u64) virt_to_maddr(msrpm); - - return 0; -} - - -/* - * Initially set the same environement as host. - */ -static int construct_init_vmcb_guest(struct arch_svm_struct *arch_svm, - struct cpu_user_regs *regs ) -{ - int error = 0; - unsigned long crn; - segment_attributes_t attrib; - unsigned long dr7; - unsigned long shadow_cr; - struct vmcb_struct *vmcb = arch_svm->vmcb; - - /* Allows IRQs to be shares */ + /* I/O and MSR permission bitmaps. */ + arch_svm->iopm = alloc_xenheap_pages(get_order_from_bytes(IOPM_SIZE)); + arch_svm->msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE)); + if ( (arch_svm->iopm == NULL) || (arch_svm->msrpm == NULL) ) + { + free_xenheap_pages(arch_svm->iopm, get_order_from_bytes(IOPM_SIZE)); + free_xenheap_pages(arch_svm->msrpm, get_order_from_bytes(MSRPM_SIZE)); + return -ENOMEM; + } + memset(arch_svm->iopm, 0xff, IOPM_SIZE); + clear_bit(PC_DEBUG_PORT, arch_svm->iopm); + memset(arch_svm->msrpm, 0xff, MSRPM_SIZE); + vmcb->iopm_base_pa = (u64)virt_to_maddr(arch_svm->iopm); + vmcb->msrpm_base_pa = (u64)virt_to_maddr(arch_svm->msrpm); + + /* Virtualise EFLAGS.IF and LAPIC TPR (CR8). */ vmcb->vintr.fields.intr_masking = 1; - /* Set up event injection entry in VMCB. Just clear it. */ + /* Initialise event injection to no-op. */ vmcb->eventinj.bytes = 0; - /* TSC */ + /* TSC. */ vmcb->tsc_offset = 0; - vmcb->cs.sel = regs->cs; - vmcb->es.sel = regs->es; - vmcb->ss.sel = regs->ss; - vmcb->ds.sel = regs->ds; - vmcb->fs.sel = regs->fs; - vmcb->gs.sel = regs->gs; - - /* Guest segment Limits. 64K for real mode*/ + /* Guest segment limits. */ vmcb->cs.limit = GUEST_SEGMENT_LIMIT; vmcb->es.limit = GUEST_SEGMENT_LIMIT; vmcb->ss.limit = GUEST_SEGMENT_LIMIT; @@ -175,7 +145,7 @@ static int construct_init_vmcb_guest(str vmcb->fs.limit = GUEST_SEGMENT_LIMIT; vmcb->gs.limit = GUEST_SEGMENT_LIMIT; - /* Base address for segments */ + /* Guest segment bases. */ vmcb->cs.base = 0; vmcb->es.base = 0; vmcb->ss.base = 0; @@ -183,74 +153,88 @@ static int construct_init_vmcb_guest(str vmcb->fs.base = 0; vmcb->gs.base = 0; - /* Guest Interrupt descriptor table */ - vmcb->idtr.base = 0; - vmcb->idtr.limit = 0; - - /* Set up segment attributes */ + /* Guest segment AR bytes. */ attrib.bytes = 0; attrib.fields.type = 0x3; /* type = 3 */ - attrib.fields.s = 1; /* code or data, i.e. not system */ - attrib.fields.dpl = 0; /* DPL = 0 */ - attrib.fields.p = 1; /* segment present */ - attrib.fields.db = 1; /* 32-bit */ - attrib.fields.g = 1; /* 4K pages in limit */ - - /* Data selectors */ + attrib.fields.s = 1; /* code or data, i.e. not system */ + attrib.fields.dpl = 0; /* DPL = 0 */ + attrib.fields.p = 1; /* segment present */ + attrib.fields.db = 1; /* 32-bit */ + attrib.fields.g = 1; /* 4K pages in limit */ vmcb->es.attributes = attrib; vmcb->ss.attributes = attrib; vmcb->ds.attributes = attrib; vmcb->fs.attributes = attrib; vmcb->gs.attributes = attrib; - - /* Code selector */ - attrib.fields.type = 0xb; /* type=0xb -> executable/readable, accessed */ + attrib.fields.type = 0xb; /* type=0xb -> executable/readable, accessed */ vmcb->cs.attributes = attrib; - /* Guest Global descriptor table */ + /* Guest IDT. */ + vmcb->idtr.base = 0; + vmcb->idtr.limit = 0; + + /* Guest GDT. */ vmcb->gdtr.base = 0; vmcb->gdtr.limit = 0; - /* Guest Local Descriptor Table */ - attrib.fields.s = 0; /* not code or data segement */ + /* Guest LDT. */ + attrib.fields.s = 0; /* not code or data segement */ attrib.fields.type = 0x2; /* LDT */ - attrib.fields.db = 0; /* 16-bit */ - attrib.fields.g = 0; + attrib.fields.db = 0; /* 16-bit */ + attrib.fields.g = 0; vmcb->ldtr.attributes = attrib; + /* Guest TSS. */ attrib.fields.type = 0xb; /* 32-bit TSS (busy) */ vmcb->tr.attributes = attrib; vmcb->tr.base = 0; vmcb->tr.limit = 0xff; - __asm__ __volatile__ ("mov %%cr0,%0" : "=r" (crn) :); - vmcb->cr0 = crn; - - /* Initally PG, PE are not set*/ - shadow_cr = vmcb->cr0; - shadow_cr &= ~X86_CR0_PG; - arch_svm->cpu_shadow_cr0 = shadow_cr; - - /* CR3 is set in svm_final_setup_guest */ - - __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (crn) :); - crn &= ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE); - arch_svm->cpu_shadow_cr4 = crn; - vmcb->cr4 = crn | SVM_CR4_HOST_MASK; - - vmcb->rsp = 0; - vmcb->rip = regs->eip; - - vmcb->rflags = regs->eflags | 2UL; /* inc. reserved bit */ - + /* Guest CR0. */ + vmcb->cr0 = read_cr0(); + arch_svm->cpu_shadow_cr0 = vmcb->cr0 & ~(X86_CR0_PG | X86_CR0_TS); + + /* Guest CR4. */ + arch_svm->cpu_shadow_cr4 = + read_cr4() & ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE); + vmcb->cr4 = arch_svm->cpu_shadow_cr4 | SVM_CR4_HOST_MASK; + + /* Guest DR7. */ __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7)); vmcb->dr7 = dr7; - return error; -} - -void destroy_vmcb(struct arch_svm_struct *arch_svm) -{ + arch_svm->vmcb->exception_intercepts = MONITOR_DEFAULT_EXCEPTION_BITMAP; + + return 0; +} + +int svm_create_vmcb(struct vcpu *v) +{ + struct arch_svm_struct *arch_svm = &v->arch.hvm_svm; + int rc; + + if ( (arch_svm->vmcb = alloc_vmcb()) == NULL ) + { + printk("Failed to create a new VMCB\n"); + return -ENOMEM; + } + + if ( (rc = construct_vmcb(v)) != 0 ) + { + free_vmcb(arch_svm->vmcb); + arch_svm->vmcb = NULL; + return rc; + } + + arch_svm->vmcb_pa = virt_to_maddr(arch_svm->vmcb); + + return 0; +} + +void svm_destroy_vmcb(struct vcpu *v) +{ + struct arch_svm_struct *arch_svm = &v->arch.hvm_svm; + if ( arch_svm->vmcb != NULL ) { asidpool_retire(arch_svm->vmcb, arch_svm->asid_core); @@ -273,31 +257,6 @@ void destroy_vmcb(struct arch_svm_struct arch_svm->vmcb = NULL; } - -int construct_vmcb(struct arch_svm_struct *arch_svm, - struct cpu_user_regs *regs) -{ - if ( construct_vmcb_controls(arch_svm) != 0 ) - { - printk("construct_vmcb: construct_vmcb_controls failed\n"); - return -EINVAL; - } - - if ( construct_init_vmcb_guest(arch_svm, regs) != 0 ) - { - printk("construct_vmcb: construct_vmcb_guest failed\n"); - return -EINVAL; - } - - arch_svm->vmcb->exception_intercepts = MONITOR_DEFAULT_EXCEPTION_BITMAP; - if ( regs->eflags & EF_TF ) - arch_svm->vmcb->exception_intercepts |= EXCEPTION_BITMAP_DB; - else - arch_svm->vmcb->exception_intercepts &= ~EXCEPTION_BITMAP_DB; - - return 0; -} - void svm_do_launch(struct vcpu *v) { diff -r f8ffeb540ec1 -r 81c451bd398e xen/include/asm-x86/hvm/svm/vmcb.h --- a/xen/include/asm-x86/hvm/svm/vmcb.h Mon Nov 06 18:57:33 2006 +0000 +++ b/xen/include/asm-x86/hvm/svm/vmcb.h Mon Nov 06 20:23:08 2006 +0000 @@ -23,7 +23,7 @@ #include <asm/config.h> #include <asm/hvm/hvm.h> -extern int start_svm(void); +int start_svm(void); /* general 1 intercepts */ enum GenericIntercept1bits @@ -496,15 +496,15 @@ struct arch_svm_struct { unsigned long cpu_state; }; -extern struct vmcb_struct *alloc_vmcb(void); -extern struct host_save_area *alloc_host_save_area(void); -extern void free_vmcb(struct vmcb_struct *vmcb); -extern void free_host_save_area(struct host_save_area *hsa); - -extern int construct_vmcb(struct arch_svm_struct *, struct cpu_user_regs *); -extern void destroy_vmcb(struct arch_svm_struct *); - -extern void setup_vmcb_dump(void); +struct vmcb_struct *alloc_vmcb(void); +struct host_save_area *alloc_host_save_area(void); +void free_vmcb(struct vmcb_struct *vmcb); +void free_host_save_area(struct host_save_area *hsa); + +int svm_create_vmcb(struct vcpu *v); +void svm_destroy_vmcb(struct vcpu *v); + +void setup_vmcb_dump(void); #define VMCB_USE_HOST_ENV 1 #define VMCB_USE_SEPARATE_ENV 0 _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |