# 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
|