direct-io.hg

changeset 12255:81c451bd398e

[SVM] Move VMCB construction to VCPU creation time.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@localhost.localdomain
date Mon Nov 06 20:23:08 2006 +0000 (2006-11-06)
parents f8ffeb540ec1
children ad8f0e049d63
files xen/arch/x86/hvm/svm/svm.c xen/arch/x86/hvm/svm/vmcb.c xen/include/asm-x86/hvm/svm/vmcb.h
line diff
     1.1 --- a/xen/arch/x86/hvm/svm/svm.c	Mon Nov 06 18:57:33 2006 +0000
     1.2 +++ b/xen/arch/x86/hvm/svm/svm.c	Mon Nov 06 20:23:08 2006 +0000
     1.3 @@ -213,11 +213,8 @@ static void stop_svm(void)
     1.4      free_vmcb(root_vmcb[cpu]);
     1.5      root_vmcb[cpu] = NULL;
     1.6      root_vmcb_pa[cpu] = 0;
     1.7 -
     1.8 -    printk("AMD SVM Extension is disabled.\n");
     1.9  }
    1.10  
    1.11 -
    1.12  static void svm_store_cpu_guest_regs(
    1.13      struct vcpu *v, struct cpu_user_regs *regs, unsigned long *crs)
    1.14  {
    1.15 @@ -690,35 +687,13 @@ int svm_long_mode_enabled(struct vcpu *v
    1.16      return SVM_LONG_GUEST(v);
    1.17  }
    1.18  
    1.19 -
    1.20 -
    1.21  static void arch_svm_do_launch(struct vcpu *v) 
    1.22  {
    1.23 -    cpu_user_regs_t *regs = &current->arch.guest_context.user_regs;
    1.24 -    int error;
    1.25 -
    1.26 -#if 0
    1.27 -    if (svm_dbg_on)
    1.28 -        printk("Do launch\n");
    1.29 -#endif
    1.30 -    error = construct_vmcb(&v->arch.hvm_svm, regs);
    1.31 -    if ( error < 0 )
    1.32 +    svm_do_launch(v);
    1.33 +
    1.34 +    if ( v->vcpu_id != 0 )
    1.35      {
    1.36 -        if (v->vcpu_id == 0) {
    1.37 -            printk("Failed to construct a new VMCB for BSP.\n");
    1.38 -        } else {
    1.39 -            printk("Failed to construct a new VMCB for AP %d\n", v->vcpu_id);
    1.40 -        }
    1.41 -        domain_crash_synchronous();
    1.42 -    }
    1.43 -
    1.44 -    svm_do_launch(v);
    1.45 -#if 0
    1.46 -    if (svm_dbg_on)
    1.47 -        svm_dump_host_regs(__func__);
    1.48 -#endif
    1.49 -    if (v->vcpu_id != 0) 
    1.50 -    {
    1.51 +        cpu_user_regs_t *regs = &current->arch.guest_context.user_regs;
    1.52          u16 cs_sel = regs->cs;
    1.53          /*
    1.54           * This is the launch of an AP; set state so that we begin executing
    1.55 @@ -770,24 +745,26 @@ static void svm_ctxt_switch_to(struct vc
    1.56  
    1.57  static int svm_vcpu_initialise(struct vcpu *v)
    1.58  {
    1.59 +    int rc;
    1.60 +
    1.61      v->arch.schedule_tail    = arch_svm_do_launch;
    1.62      v->arch.ctxt_switch_from = svm_ctxt_switch_from;
    1.63      v->arch.ctxt_switch_to   = svm_ctxt_switch_to;
    1.64  
    1.65 -    if ( (v->arch.hvm_svm.vmcb = alloc_vmcb()) == NULL )
    1.66 +    if ( (rc = svm_create_vmcb(v)) != 0 )
    1.67      {
    1.68 -        printk("Failed to create a new VMCB\n");
    1.69 -        return -ENOMEM;
    1.70 +        dprintk(XENLOG_WARNING,
    1.71 +                "Failed to create VMCB for vcpu %d: err=%d.\n",
    1.72 +                v->vcpu_id, rc);
    1.73 +        return rc;
    1.74      }
    1.75  
    1.76 -    v->arch.hvm_svm.vmcb_pa = virt_to_maddr(v->arch.hvm_svm.vmcb);
    1.77 -
    1.78      return 0;
    1.79  }
    1.80  
    1.81  static void svm_vcpu_destroy(struct vcpu *v)
    1.82  {
    1.83 -    destroy_vmcb(&v->arch.hvm_svm);
    1.84 +    svm_destroy_vmcb(v);
    1.85  }
    1.86  
    1.87  int start_svm(void)
     2.1 --- a/xen/arch/x86/hvm/svm/vmcb.c	Mon Nov 06 18:57:33 2006 +0000
     2.2 +++ b/xen/arch/x86/hvm/svm/vmcb.c	Mon Nov 06 20:23:08 2006 +0000
     2.3 @@ -86,13 +86,14 @@ void free_host_save_area(struct host_sav
     2.4      free_xenheap_page(hsa);
     2.5  }
     2.6  
     2.7 -/* Set up intercepts to exit the guest into the hypervisor when we want it. */
     2.8 -static int construct_vmcb_controls(struct arch_svm_struct *arch_svm)
     2.9 +static int construct_vmcb(struct vcpu *v)
    2.10  {
    2.11 +    struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
    2.12      struct vmcb_struct *vmcb = arch_svm->vmcb;
    2.13 -    u32 *iopm, *msrpm;
    2.14 +    segment_attributes_t attrib;
    2.15 +    unsigned long dr7;
    2.16  
    2.17 -    /* mask off all general 1 intercepts except those listed here */
    2.18 +    /* SVM intercepts. */
    2.19      vmcb->general1_intercepts = 
    2.20          GENERAL1_INTERCEPT_INTR         | GENERAL1_INTERCEPT_NMI         |
    2.21          GENERAL1_INTERCEPT_SMI          | GENERAL1_INTERCEPT_INIT        |
    2.22 @@ -100,74 +101,43 @@ static int construct_vmcb_controls(struc
    2.23          GENERAL1_INTERCEPT_HLT          | GENERAL1_INTERCEPT_INVLPG      | 
    2.24          GENERAL1_INTERCEPT_INVLPGA      | GENERAL1_INTERCEPT_IOIO_PROT   |
    2.25          GENERAL1_INTERCEPT_MSR_PROT     | GENERAL1_INTERCEPT_SHUTDOWN_EVT;
    2.26 -
    2.27 -    /* turn on the general 2 intercepts */
    2.28      vmcb->general2_intercepts = 
    2.29          GENERAL2_INTERCEPT_VMRUN  | GENERAL2_INTERCEPT_VMMCALL | 
    2.30          GENERAL2_INTERCEPT_VMLOAD | GENERAL2_INTERCEPT_VMSAVE  |
    2.31          GENERAL2_INTERCEPT_STGI   | GENERAL2_INTERCEPT_CLGI    |
    2.32          GENERAL2_INTERCEPT_SKINIT | GENERAL2_INTERCEPT_RDTSCP;
    2.33  
    2.34 -    /* read or write all debug registers 0 - 15 */
    2.35 +    /* Intercept all debug-register writes. */
    2.36      vmcb->dr_intercepts = DR_INTERCEPT_ALL_WRITES;
    2.37  
    2.38 -    /* RD/WR all control registers 0 - 15, but not read CR2 */
    2.39 +    /* Intercept all control-register accesses, except to CR2. */
    2.40      vmcb->cr_intercepts = ~(CR_INTERCEPT_CR2_READ | CR_INTERCEPT_CR2_WRITE);
    2.41  
    2.42 -    /* The following is for I/O and MSR permision map */
    2.43 -    iopm = alloc_xenheap_pages(get_order_from_bytes(IOPM_SIZE));
    2.44 -    if ( iopm != NULL )
    2.45 +    /* I/O and MSR permission bitmaps. */
    2.46 +    arch_svm->iopm  = alloc_xenheap_pages(get_order_from_bytes(IOPM_SIZE));
    2.47 +    arch_svm->msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE));
    2.48 +    if ( (arch_svm->iopm == NULL) || (arch_svm->msrpm == NULL) )
    2.49      {
    2.50 -        memset(iopm, 0xff, IOPM_SIZE);
    2.51 -        clear_bit(PC_DEBUG_PORT, iopm);
    2.52 +        free_xenheap_pages(arch_svm->iopm,  get_order_from_bytes(IOPM_SIZE));
    2.53 +        free_xenheap_pages(arch_svm->msrpm, get_order_from_bytes(MSRPM_SIZE));
    2.54 +        return -ENOMEM;
    2.55      }
    2.56 -    msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE));
    2.57 -    if ( msrpm != NULL )
    2.58 -        memset(msrpm, 0xff, MSRPM_SIZE);
    2.59 -
    2.60 -    arch_svm->iopm = iopm;
    2.61 -    arch_svm->msrpm = msrpm;
    2.62 -
    2.63 -    if ( !iopm || !msrpm )
    2.64 -        return 1;
    2.65 +    memset(arch_svm->iopm, 0xff, IOPM_SIZE);
    2.66 +    clear_bit(PC_DEBUG_PORT, arch_svm->iopm);
    2.67 +    memset(arch_svm->msrpm, 0xff, MSRPM_SIZE);
    2.68 +    vmcb->iopm_base_pa = (u64)virt_to_maddr(arch_svm->iopm);
    2.69 +    vmcb->msrpm_base_pa = (u64)virt_to_maddr(arch_svm->msrpm);
    2.70  
    2.71 -    vmcb->iopm_base_pa = (u64) virt_to_maddr(iopm);
    2.72 -    vmcb->msrpm_base_pa = (u64) virt_to_maddr(msrpm);
    2.73 -
    2.74 -    return 0;
    2.75 -}
    2.76 -
    2.77 -
    2.78 -/*
    2.79 - * Initially set the same environement as host.
    2.80 - */
    2.81 -static int construct_init_vmcb_guest(struct arch_svm_struct *arch_svm, 
    2.82 -                                     struct cpu_user_regs *regs )
    2.83 -{
    2.84 -    int error = 0;
    2.85 -    unsigned long crn;
    2.86 -    segment_attributes_t attrib;
    2.87 -    unsigned long dr7;
    2.88 -    unsigned long shadow_cr;
    2.89 -    struct vmcb_struct *vmcb = arch_svm->vmcb;
    2.90 -
    2.91 -    /* Allows IRQs to be shares */
    2.92 +    /* Virtualise EFLAGS.IF and LAPIC TPR (CR8). */
    2.93      vmcb->vintr.fields.intr_masking = 1;
    2.94    
    2.95 -    /* Set up event injection entry in VMCB. Just clear it. */
    2.96 +    /* Initialise event injection to no-op. */
    2.97      vmcb->eventinj.bytes = 0;
    2.98  
    2.99 -    /* TSC */
   2.100 +    /* TSC. */
   2.101      vmcb->tsc_offset = 0;
   2.102      
   2.103 -    vmcb->cs.sel = regs->cs;
   2.104 -    vmcb->es.sel = regs->es;
   2.105 -    vmcb->ss.sel = regs->ss;
   2.106 -    vmcb->ds.sel = regs->ds;
   2.107 -    vmcb->fs.sel = regs->fs;
   2.108 -    vmcb->gs.sel = regs->gs;
   2.109 -
   2.110 -    /* Guest segment Limits. 64K for real mode*/
   2.111 +    /* Guest segment limits. */
   2.112      vmcb->cs.limit = GUEST_SEGMENT_LIMIT;
   2.113      vmcb->es.limit = GUEST_SEGMENT_LIMIT;
   2.114      vmcb->ss.limit = GUEST_SEGMENT_LIMIT;
   2.115 @@ -175,7 +145,7 @@ static int construct_init_vmcb_guest(str
   2.116      vmcb->fs.limit = GUEST_SEGMENT_LIMIT;
   2.117      vmcb->gs.limit = GUEST_SEGMENT_LIMIT;
   2.118  
   2.119 -    /* Base address for segments */
   2.120 +    /* Guest segment bases. */
   2.121      vmcb->cs.base = 0;
   2.122      vmcb->es.base = 0;
   2.123      vmcb->ss.base = 0;
   2.124 @@ -183,74 +153,88 @@ static int construct_init_vmcb_guest(str
   2.125      vmcb->fs.base = 0;
   2.126      vmcb->gs.base = 0;
   2.127  
   2.128 -    /* Guest Interrupt descriptor table */
   2.129 -    vmcb->idtr.base = 0;
   2.130 -    vmcb->idtr.limit = 0;
   2.131 -
   2.132 -    /* Set up segment attributes */
   2.133 +    /* Guest segment AR bytes. */
   2.134      attrib.bytes = 0;
   2.135      attrib.fields.type = 0x3; /* type = 3 */
   2.136 -    attrib.fields.s = 1; /* code or data, i.e. not system */
   2.137 -    attrib.fields.dpl = 0; /* DPL = 0 */
   2.138 -    attrib.fields.p = 1; /* segment present */
   2.139 -    attrib.fields.db = 1; /* 32-bit */
   2.140 -    attrib.fields.g = 1; /* 4K pages in limit */
   2.141 -
   2.142 -    /* Data selectors */
   2.143 +    attrib.fields.s = 1;      /* code or data, i.e. not system */
   2.144 +    attrib.fields.dpl = 0;    /* DPL = 0 */
   2.145 +    attrib.fields.p = 1;      /* segment present */
   2.146 +    attrib.fields.db = 1;     /* 32-bit */
   2.147 +    attrib.fields.g = 1;      /* 4K pages in limit */
   2.148      vmcb->es.attributes = attrib;
   2.149      vmcb->ss.attributes = attrib;
   2.150      vmcb->ds.attributes = attrib;
   2.151      vmcb->fs.attributes = attrib;
   2.152      vmcb->gs.attributes = attrib;
   2.153 -
   2.154 -    /* Code selector */
   2.155 -    attrib.fields.type = 0xb;   /* type=0xb -> executable/readable, accessed */
   2.156 +    attrib.fields.type = 0xb; /* type=0xb -> executable/readable, accessed */
   2.157      vmcb->cs.attributes = attrib;
   2.158  
   2.159 -    /* Guest Global descriptor table */
   2.160 +    /* Guest IDT. */
   2.161 +    vmcb->idtr.base = 0;
   2.162 +    vmcb->idtr.limit = 0;
   2.163 +
   2.164 +    /* Guest GDT. */
   2.165      vmcb->gdtr.base = 0;
   2.166      vmcb->gdtr.limit = 0;
   2.167  
   2.168 -    /* Guest Local Descriptor Table */
   2.169 -    attrib.fields.s = 0; /* not code or data segement */
   2.170 +    /* Guest LDT. */
   2.171 +    attrib.fields.s = 0;      /* not code or data segement */
   2.172      attrib.fields.type = 0x2; /* LDT */
   2.173 -    attrib.fields.db = 0; /* 16-bit */
   2.174 -    attrib.fields.g = 0;   
   2.175 +    attrib.fields.db = 0;     /* 16-bit */
   2.176 +    attrib.fields.g = 0;
   2.177      vmcb->ldtr.attributes = attrib;
   2.178  
   2.179 +    /* Guest TSS. */
   2.180      attrib.fields.type = 0xb; /* 32-bit TSS (busy) */
   2.181      vmcb->tr.attributes = attrib;
   2.182      vmcb->tr.base = 0;
   2.183      vmcb->tr.limit = 0xff;
   2.184  
   2.185 -    __asm__ __volatile__ ("mov %%cr0,%0" : "=r" (crn) :);
   2.186 -    vmcb->cr0 = crn;
   2.187 -
   2.188 -    /* Initally PG, PE are not set*/
   2.189 -    shadow_cr = vmcb->cr0;
   2.190 -    shadow_cr &= ~X86_CR0_PG;
   2.191 -    arch_svm->cpu_shadow_cr0 = shadow_cr;
   2.192 -
   2.193 -    /* CR3 is set in svm_final_setup_guest */
   2.194 +    /* Guest CR0. */
   2.195 +    vmcb->cr0 = read_cr0();
   2.196 +    arch_svm->cpu_shadow_cr0 = vmcb->cr0 & ~(X86_CR0_PG | X86_CR0_TS);
   2.197  
   2.198 -    __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (crn) :);
   2.199 -    crn &= ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE);
   2.200 -    arch_svm->cpu_shadow_cr4 = crn;
   2.201 -    vmcb->cr4 = crn | SVM_CR4_HOST_MASK;
   2.202 +    /* Guest CR4. */
   2.203 +    arch_svm->cpu_shadow_cr4 =
   2.204 +        read_cr4() & ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE);
   2.205 +    vmcb->cr4 = arch_svm->cpu_shadow_cr4 | SVM_CR4_HOST_MASK;
   2.206  
   2.207 -    vmcb->rsp = 0;
   2.208 -    vmcb->rip = regs->eip;
   2.209 -
   2.210 -    vmcb->rflags = regs->eflags | 2UL; /* inc. reserved bit */
   2.211 -
   2.212 +    /* Guest DR7. */
   2.213      __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7));
   2.214      vmcb->dr7 = dr7;
   2.215  
   2.216 -    return error;
   2.217 +    arch_svm->vmcb->exception_intercepts = MONITOR_DEFAULT_EXCEPTION_BITMAP;
   2.218 +
   2.219 +    return 0;
   2.220  }
   2.221  
   2.222 -void destroy_vmcb(struct arch_svm_struct *arch_svm)
   2.223 +int svm_create_vmcb(struct vcpu *v)
   2.224  {
   2.225 +    struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
   2.226 +    int rc;
   2.227 +
   2.228 +    if ( (arch_svm->vmcb = alloc_vmcb()) == NULL )
   2.229 +    {
   2.230 +        printk("Failed to create a new VMCB\n");
   2.231 +        return -ENOMEM;
   2.232 +    }
   2.233 +
   2.234 +    if ( (rc = construct_vmcb(v)) != 0 )
   2.235 +    {
   2.236 +        free_vmcb(arch_svm->vmcb);
   2.237 +        arch_svm->vmcb = NULL;
   2.238 +        return rc;
   2.239 +    }
   2.240 +
   2.241 +    arch_svm->vmcb_pa = virt_to_maddr(arch_svm->vmcb);
   2.242 +
   2.243 +    return 0;
   2.244 +}
   2.245 +
   2.246 +void svm_destroy_vmcb(struct vcpu *v)
   2.247 +{
   2.248 +    struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
   2.249 +
   2.250      if ( arch_svm->vmcb != NULL )
   2.251      {
   2.252          asidpool_retire(arch_svm->vmcb, arch_svm->asid_core);
   2.253 @@ -274,31 +258,6 @@ void destroy_vmcb(struct arch_svm_struct
   2.254      arch_svm->vmcb = NULL;
   2.255  }
   2.256  
   2.257 -int construct_vmcb(struct arch_svm_struct *arch_svm, 
   2.258 -                   struct cpu_user_regs *regs)
   2.259 -{
   2.260 -    if ( construct_vmcb_controls(arch_svm) != 0 )
   2.261 -    {
   2.262 -        printk("construct_vmcb: construct_vmcb_controls failed\n");
   2.263 -        return -EINVAL;
   2.264 -    }
   2.265 -
   2.266 -    if ( construct_init_vmcb_guest(arch_svm, regs) != 0 )
   2.267 -    {
   2.268 -        printk("construct_vmcb: construct_vmcb_guest failed\n");
   2.269 -        return -EINVAL;
   2.270 -    }
   2.271 -
   2.272 -    arch_svm->vmcb->exception_intercepts = MONITOR_DEFAULT_EXCEPTION_BITMAP;
   2.273 -    if ( regs->eflags & EF_TF )
   2.274 -        arch_svm->vmcb->exception_intercepts |= EXCEPTION_BITMAP_DB;
   2.275 -    else
   2.276 -        arch_svm->vmcb->exception_intercepts &= ~EXCEPTION_BITMAP_DB;
   2.277 -
   2.278 -    return 0;
   2.279 -}
   2.280 -
   2.281 -
   2.282  void svm_do_launch(struct vcpu *v)
   2.283  {
   2.284      struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
     3.1 --- a/xen/include/asm-x86/hvm/svm/vmcb.h	Mon Nov 06 18:57:33 2006 +0000
     3.2 +++ b/xen/include/asm-x86/hvm/svm/vmcb.h	Mon Nov 06 20:23:08 2006 +0000
     3.3 @@ -23,7 +23,7 @@
     3.4  #include <asm/config.h>
     3.5  #include <asm/hvm/hvm.h>
     3.6  
     3.7 -extern int start_svm(void);
     3.8 +int start_svm(void);
     3.9  
    3.10  /* general 1 intercepts */
    3.11  enum GenericIntercept1bits
    3.12 @@ -496,15 +496,15 @@ struct arch_svm_struct {
    3.13      unsigned long       cpu_state;
    3.14  };
    3.15  
    3.16 -extern struct vmcb_struct *alloc_vmcb(void);
    3.17 -extern struct host_save_area *alloc_host_save_area(void);
    3.18 -extern void free_vmcb(struct vmcb_struct *vmcb);
    3.19 -extern void free_host_save_area(struct host_save_area *hsa);
    3.20 +struct vmcb_struct *alloc_vmcb(void);
    3.21 +struct host_save_area *alloc_host_save_area(void);
    3.22 +void free_vmcb(struct vmcb_struct *vmcb);
    3.23 +void free_host_save_area(struct host_save_area *hsa);
    3.24  
    3.25 -extern int  construct_vmcb(struct arch_svm_struct *, struct cpu_user_regs *);
    3.26 -extern void destroy_vmcb(struct arch_svm_struct *);
    3.27 +int  svm_create_vmcb(struct vcpu *v);
    3.28 +void svm_destroy_vmcb(struct vcpu *v);
    3.29  
    3.30 -extern void setup_vmcb_dump(void);
    3.31 +void setup_vmcb_dump(void);
    3.32  
    3.33  #define VMCB_USE_HOST_ENV       1
    3.34  #define VMCB_USE_SEPARATE_ENV   0