mirror of
https://github.com/xen-project/xen.git
synced 2026-10-30 03:00:05 +01:00
Move construct_vmcs to arch_vmx_do_launch.
Currently, since VMX guest is brought up by xen0, construct_vmcs is executed in xen0 hypervisor context, this is not reasonable. This=20 patch moves construct_vmcs to arch_vmx_do_launch. Signed-off-by: Xin Li <xin.b.li@intel.com> Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com> Signed-off-by: Nakajima Jun <nakajima.jun@intel.com>
This commit is contained in:
1 parent
f16cb294c5
commit
88e2b02038
5 files changed
+116
-154
No files matched your search
+5
-67
@@ -323,47 +323,16 @@ void vcpu_migrate_cpu(struct vcpu *v, int newcpu)
|
||||
#ifdef CONFIG_VMX
|
||||
static int vmx_switch_on;
|
||||
|
||||
static int vmx_final_setup_guest(
|
||||
struct vcpu *v, struct vcpu_guest_context *ctxt)
|
||||
static void vmx_final_setup_guest(struct vcpu *v)
|
||||
{
|
||||
int error;
|
||||
struct cpu_user_regs *regs;
|
||||
struct vmcs_struct *vmcs;
|
||||
|
||||
regs = &ctxt->user_regs;
|
||||
|
||||
/*
|
||||
* Create a new VMCS
|
||||
*/
|
||||
if (!(vmcs = alloc_vmcs())) {
|
||||
printk("Failed to create a new VMCS\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(&v->arch.arch_vmx, 0, sizeof (struct arch_vmx_struct));
|
||||
|
||||
v->arch.arch_vmx.vmcs = vmcs;
|
||||
error = construct_vmcs(
|
||||
&v->arch.arch_vmx, regs, ctxt, VMCS_USE_HOST_ENV);
|
||||
if ( error < 0 )
|
||||
{
|
||||
printk("Failed to construct a new VMCS\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
v->arch.schedule_tail = arch_vmx_do_launch;
|
||||
|
||||
#if defined (__i386__)
|
||||
v->domain->arch.vmx_platform.real_mode_data =
|
||||
(unsigned long *) regs->esi;
|
||||
#endif
|
||||
|
||||
if (v == v->domain->vcpu[0]) {
|
||||
/*
|
||||
/*
|
||||
* Required to do this once per domain
|
||||
* XXX todo: add a seperate function to do these.
|
||||
*/
|
||||
memset(&v->domain->shared_info->evtchn_mask[0], 0xff,
|
||||
memset(&v->domain->shared_info->evtchn_mask[0], 0xff,
|
||||
sizeof(v->domain->shared_info->evtchn_mask));
|
||||
|
||||
/* Put the domain in shadow mode even though we're going to be using
|
||||
@@ -375,23 +344,6 @@ static int vmx_final_setup_guest(
|
||||
|
||||
if (!vmx_switch_on)
|
||||
vmx_switch_on = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
free_vmcs(vmcs);
|
||||
if(v->arch.arch_vmx.io_bitmap_a != 0) {
|
||||
free_xenheap_pages(
|
||||
v->arch.arch_vmx.io_bitmap_a, get_order_from_bytes(0x1000));
|
||||
v->arch.arch_vmx.io_bitmap_a = 0;
|
||||
}
|
||||
if(v->arch.arch_vmx.io_bitmap_b != 0) {
|
||||
free_xenheap_pages(
|
||||
v->arch.arch_vmx.io_bitmap_b, get_order_from_bytes(0x1000));
|
||||
v->arch.arch_vmx.io_bitmap_b = 0;
|
||||
}
|
||||
v->arch.arch_vmx.vmcs = 0;
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -480,8 +432,7 @@ int arch_set_info_guest(
|
||||
if ( !pagetable_get_paddr(d->arch.phys_table) )
|
||||
d->arch.phys_table = v->arch.guest_table;
|
||||
|
||||
if ( (rc = vmx_final_setup_guest(v, c)) != 0 )
|
||||
return rc;
|
||||
vmx_final_setup_guest(v);
|
||||
}
|
||||
|
||||
update_pagetables(v);
|
||||
@@ -968,20 +919,7 @@ static void vmx_relinquish_resources(struct vcpu *v)
|
||||
if ( !VMX_DOMAIN(v) )
|
||||
return;
|
||||
|
||||
BUG_ON(v->arch.arch_vmx.vmcs == NULL);
|
||||
free_vmcs(v->arch.arch_vmx.vmcs);
|
||||
if(v->arch.arch_vmx.io_bitmap_a != 0) {
|
||||
free_xenheap_pages(
|
||||
v->arch.arch_vmx.io_bitmap_a, get_order_from_bytes(0x1000));
|
||||
v->arch.arch_vmx.io_bitmap_a = 0;
|
||||
}
|
||||
if(v->arch.arch_vmx.io_bitmap_b != 0) {
|
||||
free_xenheap_pages(
|
||||
v->arch.arch_vmx.io_bitmap_b, get_order_from_bytes(0x1000));
|
||||
v->arch.arch_vmx.io_bitmap_b = 0;
|
||||
}
|
||||
v->arch.arch_vmx.vmcs = 0;
|
||||
|
||||
destroy_vmcs(&v->arch.arch_vmx);
|
||||
free_monitor_pagetable(v);
|
||||
rem_ac_timer(&v->domain->arch.vmx_platform.vmx_pit.pit_timer);
|
||||
}
|
||||
|
||||
@@ -47,8 +47,6 @@
|
||||
int hvm_enabled;
|
||||
|
||||
#ifdef CONFIG_VMX
|
||||
|
||||
int vmcs_size;
|
||||
unsigned int opt_vmx_debug_level = 0;
|
||||
integer_param("vmx_debug", opt_vmx_debug_level);
|
||||
|
||||
|
||||
+106
-74
@@ -37,6 +37,8 @@
|
||||
#endif
|
||||
#ifdef CONFIG_VMX
|
||||
|
||||
int vmcs_size;
|
||||
|
||||
struct vmcs_struct *alloc_vmcs(void)
|
||||
{
|
||||
struct vmcs_struct *vmcs;
|
||||
@@ -51,7 +53,7 @@ struct vmcs_struct *alloc_vmcs(void)
|
||||
return vmcs;
|
||||
}
|
||||
|
||||
void free_vmcs(struct vmcs_struct *vmcs)
|
||||
static void free_vmcs(struct vmcs_struct *vmcs)
|
||||
{
|
||||
int order;
|
||||
|
||||
@@ -59,6 +61,28 @@ void free_vmcs(struct vmcs_struct *vmcs)
|
||||
free_xenheap_pages(vmcs, order);
|
||||
}
|
||||
|
||||
static int load_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
|
||||
{
|
||||
int error;
|
||||
|
||||
if ((error = __vmptrld(phys_ptr))) {
|
||||
clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
|
||||
return error;
|
||||
}
|
||||
set_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int store_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
|
||||
{
|
||||
/* take the current VMCS */
|
||||
__vmptrst(phys_ptr);
|
||||
clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int construct_vmcs_controls(struct arch_vmx_struct *arch_vmx)
|
||||
{
|
||||
int error = 0;
|
||||
@@ -118,7 +142,7 @@ struct host_execution_env {
|
||||
#endif
|
||||
};
|
||||
|
||||
static void vmx_setup_platform(struct vcpu *v, struct cpu_user_regs *regs)
|
||||
static void vmx_setup_platform(struct vcpu *v)
|
||||
{
|
||||
int i;
|
||||
unsigned char e820_map_nr;
|
||||
@@ -161,9 +185,6 @@ static void vmx_setup_platform(struct vcpu *v, struct cpu_user_regs *regs)
|
||||
}
|
||||
unmap_domain_page(p);
|
||||
|
||||
if (v->vcpu_id)
|
||||
return;
|
||||
|
||||
/* Initialise shared page */
|
||||
mpfn = get_mfn_from_pfn(gpfn);
|
||||
if (mpfn == INVALID_MFN) {
|
||||
@@ -184,7 +205,7 @@ static void vmx_setup_platform(struct vcpu *v, struct cpu_user_regs *regs)
|
||||
&v->domain->shared_info->evtchn_mask[0]);
|
||||
}
|
||||
|
||||
void vmx_set_host_env(struct vcpu *v)
|
||||
static void vmx_set_host_env(struct vcpu *v)
|
||||
{
|
||||
unsigned int tr, cpu, error = 0;
|
||||
struct host_execution_env host_env;
|
||||
@@ -209,14 +230,13 @@ void vmx_set_host_env(struct vcpu *v)
|
||||
error |= __vmwrite(HOST_TR_BASE, host_env.tr_base);
|
||||
}
|
||||
|
||||
void vmx_do_launch(struct vcpu *v)
|
||||
static void vmx_do_launch(struct vcpu *v)
|
||||
{
|
||||
/* Update CR3, GDT, LDT, TR */
|
||||
unsigned int error = 0;
|
||||
unsigned long pfn = 0;
|
||||
unsigned long cr0, cr4;
|
||||
struct pfn_info *page;
|
||||
struct cpu_user_regs *regs = guest_cpu_user_regs();
|
||||
|
||||
__asm__ __volatile__ ("mov %%cr0,%0" : "=r" (cr0) : );
|
||||
|
||||
@@ -246,7 +266,7 @@ void vmx_do_launch(struct vcpu *v)
|
||||
page = (struct pfn_info *) alloc_domheap_page(NULL);
|
||||
pfn = (unsigned long) (page - frame_table);
|
||||
|
||||
vmx_setup_platform(v, regs);
|
||||
vmx_setup_platform(v);
|
||||
|
||||
vmx_set_host_env(v);
|
||||
|
||||
@@ -267,8 +287,7 @@ void vmx_do_launch(struct vcpu *v)
|
||||
/*
|
||||
* Initially set the same environement as host.
|
||||
*/
|
||||
static inline int
|
||||
construct_init_vmcs_guest(struct cpu_user_regs *regs)
|
||||
static inline int construct_init_vmcs_guest(cpu_user_regs_t *regs)
|
||||
{
|
||||
int error = 0;
|
||||
union vmcs_arbytes arbytes;
|
||||
@@ -374,34 +393,33 @@ construct_init_vmcs_guest(struct cpu_user_regs *regs)
|
||||
return error;
|
||||
}
|
||||
|
||||
static inline int construct_vmcs_host(struct host_execution_env *host_env)
|
||||
static inline int construct_vmcs_host()
|
||||
{
|
||||
int error = 0;
|
||||
#ifdef __x86_64__
|
||||
unsigned long fs_base;
|
||||
unsigned long gs_base;
|
||||
#endif
|
||||
unsigned long crn;
|
||||
|
||||
/* Host Selectors */
|
||||
host_env->ds_selector = __HYPERVISOR_DS;
|
||||
error |= __vmwrite(HOST_ES_SELECTOR, host_env->ds_selector);
|
||||
error |= __vmwrite(HOST_SS_SELECTOR, host_env->ds_selector);
|
||||
error |= __vmwrite(HOST_DS_SELECTOR, host_env->ds_selector);
|
||||
error |= __vmwrite(HOST_ES_SELECTOR, __HYPERVISOR_DS);
|
||||
error |= __vmwrite(HOST_SS_SELECTOR, __HYPERVISOR_DS);
|
||||
error |= __vmwrite(HOST_DS_SELECTOR, __HYPERVISOR_DS);
|
||||
#if defined (__i386__)
|
||||
error |= __vmwrite(HOST_FS_SELECTOR, host_env->ds_selector);
|
||||
error |= __vmwrite(HOST_GS_SELECTOR, host_env->ds_selector);
|
||||
error |= __vmwrite(HOST_FS_BASE, host_env->ds_base);
|
||||
error |= __vmwrite(HOST_GS_BASE, host_env->ds_base);
|
||||
error |= __vmwrite(HOST_FS_SELECTOR, __HYPERVISOR_DS);
|
||||
error |= __vmwrite(HOST_GS_SELECTOR, __HYPERVISOR_DS);
|
||||
error |= __vmwrite(HOST_FS_BASE, 0);
|
||||
error |= __vmwrite(HOST_GS_BASE, 0);
|
||||
|
||||
#else
|
||||
rdmsrl(MSR_FS_BASE, host_env->fs_base);
|
||||
rdmsrl(MSR_GS_BASE, host_env->gs_base);
|
||||
error |= __vmwrite(HOST_FS_BASE, host_env->fs_base);
|
||||
error |= __vmwrite(HOST_GS_BASE, host_env->gs_base);
|
||||
rdmsrl(MSR_FS_BASE, fs_base);
|
||||
rdmsrl(MSR_GS_BASE, gs_base);
|
||||
error |= __vmwrite(HOST_FS_BASE, fs_base);
|
||||
error |= __vmwrite(HOST_GS_BASE, gs_base);
|
||||
|
||||
#endif
|
||||
host_env->cs_selector = __HYPERVISOR_CS;
|
||||
error |= __vmwrite(HOST_CS_SELECTOR, host_env->cs_selector);
|
||||
|
||||
host_env->ds_base = 0;
|
||||
host_env->cs_base = 0;
|
||||
error |= __vmwrite(HOST_CS_SELECTOR, __HYPERVISOR_CS);
|
||||
|
||||
__asm__ __volatile__ ("mov %%cr0,%0" : "=r" (crn) : );
|
||||
error |= __vmwrite(HOST_CR0, crn); /* same CR0 */
|
||||
@@ -423,55 +441,58 @@ static inline int construct_vmcs_host(struct host_execution_env *host_env)
|
||||
|
||||
/*
|
||||
* Need to extend to support full virtualization.
|
||||
* The variable use_host_env indicates if the new VMCS needs to use
|
||||
* the same setups as the host has (xenolinux).
|
||||
*/
|
||||
|
||||
int construct_vmcs(struct arch_vmx_struct *arch_vmx,
|
||||
struct cpu_user_regs *regs,
|
||||
struct vcpu_guest_context *ctxt,
|
||||
int use_host_env)
|
||||
static int construct_vmcs(struct arch_vmx_struct *arch_vmx,
|
||||
cpu_user_regs_t *regs)
|
||||
{
|
||||
int error;
|
||||
long rc;
|
||||
u64 vmcs_phys_ptr;
|
||||
|
||||
struct host_execution_env host_env;
|
||||
|
||||
if (use_host_env != VMCS_USE_HOST_ENV)
|
||||
return -EINVAL;
|
||||
|
||||
memset(&host_env, 0, sizeof(struct host_execution_env));
|
||||
|
||||
memset(arch_vmx, 0, sizeof(struct arch_vmx_struct));
|
||||
/*
|
||||
* Create a new VMCS
|
||||
*/
|
||||
if (!(arch_vmx->vmcs = alloc_vmcs())) {
|
||||
printk("Failed to create a new VMCS\n");
|
||||
rc = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
vmcs_phys_ptr = (u64) virt_to_phys(arch_vmx->vmcs);
|
||||
|
||||
if ((error = __vmpclear (vmcs_phys_ptr))) {
|
||||
if ((error = __vmpclear(vmcs_phys_ptr))) {
|
||||
printk("construct_vmcs: VMCLEAR failed\n");
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
if ((error = load_vmcs(arch_vmx, vmcs_phys_ptr))) {
|
||||
printk("construct_vmcs: load_vmcs failed: VMCS = %lx\n",
|
||||
(unsigned long) vmcs_phys_ptr);
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
if ((error = construct_vmcs_controls(arch_vmx))) {
|
||||
printk("construct_vmcs: construct_vmcs_controls failed\n");
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
/* host selectors */
|
||||
if ((error = construct_vmcs_host(&host_env))) {
|
||||
if ((error = construct_vmcs_host())) {
|
||||
printk("construct_vmcs: construct_vmcs_host failed\n");
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
/* guest selectors */
|
||||
if ((error = construct_init_vmcs_guest(regs))) {
|
||||
printk("construct_vmcs: construct_vmcs_guest failed\n");
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if ((error |= __vmwrite(EXCEPTION_BITMAP,
|
||||
MONITOR_DEFAULT_EXCEPTION_BITMAP))) {
|
||||
printk("construct_vmcs: setting Exception bitmap failed\n");
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (regs->eflags & EF_TF)
|
||||
@@ -480,6 +501,27 @@ int construct_vmcs(struct arch_vmx_struct *arch_vmx,
|
||||
__vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
destroy_vmcs(arch_vmx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void destroy_vmcs(struct arch_vmx_struct *arch_vmx)
|
||||
{
|
||||
if(arch_vmx->vmcs != NULL)
|
||||
free_vmcs(arch_vmx->vmcs);
|
||||
if(arch_vmx->io_bitmap_a != 0) {
|
||||
free_xenheap_pages(
|
||||
arch_vmx->io_bitmap_a, get_order_from_bytes(0x1000));
|
||||
arch_vmx->io_bitmap_a = 0;
|
||||
}
|
||||
if(arch_vmx->io_bitmap_b != 0) {
|
||||
free_xenheap_pages(
|
||||
arch_vmx->io_bitmap_b, get_order_from_bytes(0x1000));
|
||||
arch_vmx->io_bitmap_b = 0;
|
||||
}
|
||||
arch_vmx->vmcs = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -506,26 +548,6 @@ int modify_vmcs(struct arch_vmx_struct *arch_vmx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
|
||||
{
|
||||
int error;
|
||||
|
||||
if ((error = __vmptrld(phys_ptr))) {
|
||||
clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
|
||||
return error;
|
||||
}
|
||||
set_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int store_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
|
||||
{
|
||||
/* take the current VMCS */
|
||||
__vmptrst(phys_ptr);
|
||||
clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vm_launch_fail(unsigned long eflags)
|
||||
{
|
||||
unsigned long error;
|
||||
@@ -553,9 +575,19 @@ void arch_vmx_do_resume(struct vcpu *v)
|
||||
|
||||
void arch_vmx_do_launch(struct vcpu *v)
|
||||
{
|
||||
u64 vmcs_phys_ptr = (u64) virt_to_phys(v->arch.arch_vmx.vmcs);
|
||||
int error;
|
||||
cpu_user_regs_t *regs = ¤t->arch.guest_context.user_regs;
|
||||
|
||||
load_vmcs(&v->arch.arch_vmx, vmcs_phys_ptr);
|
||||
error = construct_vmcs(&v->arch.arch_vmx, regs);
|
||||
if ( error < 0 )
|
||||
{
|
||||
if (v->vcpu_id == 0) {
|
||||
printk("Failed to construct a new VMCS for BSP.\n");
|
||||
} else {
|
||||
printk("Failed to construct a new VMCS for AP %d\n", v->vcpu_id);
|
||||
}
|
||||
domain_crash_synchronous();
|
||||
}
|
||||
vmx_do_launch(v);
|
||||
reset_stack_and_jump(vmx_asm_do_launch);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ extern void arch_vmx_do_launch(struct vcpu *);
|
||||
extern void arch_vmx_do_resume(struct vcpu *);
|
||||
extern void arch_vmx_do_relaunch(struct vcpu *);
|
||||
|
||||
extern int vmcs_size;
|
||||
extern unsigned int cpu_rev;
|
||||
|
||||
/*
|
||||
@@ -449,7 +448,7 @@ static inline void vmx_stts(void)
|
||||
__vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_NM);
|
||||
}
|
||||
|
||||
/* Works only for ed == current */
|
||||
/* Works only for vcpu == current */
|
||||
static inline int vmx_paging_enabled(struct vcpu *v)
|
||||
{
|
||||
unsigned long cr0;
|
||||
|
||||
@@ -53,6 +53,8 @@ struct vmcs_struct {
|
||||
unsigned char data [0]; /* vmcs size is read from MSR */
|
||||
};
|
||||
|
||||
extern int vmcs_size;
|
||||
|
||||
enum {
|
||||
VMX_INDEX_MSR_LSTAR = 0,
|
||||
VMX_INDEX_MSR_STAR,
|
||||
@@ -94,18 +96,11 @@ struct arch_vmx_struct {
|
||||
#define ARCH_VMX_VMCS_RESUME 2 /* Needs VMCS resume */
|
||||
#define ARCH_VMX_IO_WAIT 3 /* Waiting for I/O completion */
|
||||
|
||||
void vmx_do_launch(struct vcpu *);
|
||||
void vmx_do_resume(struct vcpu *);
|
||||
void vmx_set_host_env(struct vcpu *);
|
||||
|
||||
void vmx_do_resume(struct vcpu *);
|
||||
struct vmcs_struct *alloc_vmcs(void);
|
||||
void free_vmcs(struct vmcs_struct *);
|
||||
int load_vmcs(struct arch_vmx_struct *, u64);
|
||||
int store_vmcs(struct arch_vmx_struct *, u64);
|
||||
int construct_vmcs(struct arch_vmx_struct *, struct cpu_user_regs *,
|
||||
struct vcpu_guest_context *, int);
|
||||
int modify_vmcs(struct arch_vmx_struct *arch_vmx,
|
||||
struct cpu_user_regs *regs);
|
||||
void destroy_vmcs(struct arch_vmx_struct *arch_vmx);
|
||||
|
||||
#define VMCS_USE_HOST_ENV 1
|
||||
#define VMCS_USE_SEPARATE_ENV 0
|
||||
|
||||