# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1184000663 -3600
# Node ID 1d1ccf6b861405805f46b5f17b973a05e138c871
# Parent aa640601575fb4b509befd9f032f0f3d577a46fc
hvm: Clean ups and fix MSR access functions.
Signed-off-by: Xin Li <xin.b.li@xxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
xen/arch/x86/hvm/svm/svm.c | 37 +++++-----
xen/arch/x86/hvm/vmx/vmx.c | 158 ++++++++++++++++++++++++++-------------------
2 files changed, 113 insertions(+), 82 deletions(-)
diff -r aa640601575f -r 1d1ccf6b8614 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c Mon Jul 09 14:51:44 2007 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c Mon Jul 09 18:04:23 2007 +0100
@@ -53,6 +53,8 @@
#define set_segment_register(name, value) \
asm volatile ( "movw %%ax ,%%" STR(name) "" : : "a" (value) )
+enum handler_return { HNDL_done, HNDL_unhandled, HNDL_exception_raised };
+
int inst_copy_from_guest(unsigned char *buf, unsigned long guest_eip,
int inst_len);
asmlinkage void do_IRQ(struct cpu_user_regs *);
@@ -173,7 +175,7 @@ static void svm_store_cpu_guest_regs(
}
}
-static int long_mode_do_msr_write(struct cpu_user_regs *regs)
+static enum handler_return long_mode_do_msr_write(struct cpu_user_regs *regs)
{
u64 msr_content = (u32)regs->eax | ((u64)regs->edx << 32);
u32 ecx = regs->ecx;
@@ -237,14 +239,14 @@ static int long_mode_do_msr_write(struct
break;
default:
- return 0;
- }
-
- return 1;
+ return HNDL_unhandled;
+ }
+
+ return HNDL_done;
gp_fault:
svm_inject_exception(v, TRAP_gp_fault, 1, 0);
- return 0;
+ return HNDL_exception_raised;
}
@@ -1716,8 +1718,8 @@ static int svm_set_cr0(unsigned long val
if ( old_base_mfn )
put_page(mfn_to_page(old_base_mfn));
- HVM_DBG_LOG(DBG_LEVEL_VMMU, "New arch.guest_table = %lx",
- (unsigned long) (mfn << PAGE_SHIFT));
+ HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx, mfn = %lx",
+ v->arch.hvm_vmx.cpu_cr3, mfn);
}
}
else if ( !(value & X86_CR0_PG) && (old_value & X86_CR0_PG) )
@@ -1744,8 +1746,7 @@ static int svm_set_cr0(unsigned long val
if ( (value ^ old_value) & X86_CR0_PG )
{
paging_update_paging_modes(v);
- /* signal paging update to ASID handler */
- svm_asid_g_update_paging (v);
+ svm_asid_g_update_paging(v);
}
return 1;
@@ -1894,8 +1895,8 @@ static int mov_to_cr(int gpreg, int cr,
{
if ( svm_pgbit_test(v) )
{
+#if CONFIG_PAGING_LEVELS >= 3
/* The guest is a 32-bit PAE guest. */
-#if CONFIG_PAGING_LEVELS >= 3
unsigned long mfn, old_base_mfn;
mfn = get_mfn_from_gpfn(v->arch.hvm_svm.cpu_cr3 >> PAGE_SHIFT);
if ( !mfn_valid(mfn) ||
@@ -1905,7 +1906,6 @@ static int mov_to_cr(int gpreg, int cr,
/*
* Now arch.guest_table points to machine physical.
*/
-
old_base_mfn = pagetable_get_pfn(v->arch.guest_table);
v->arch.guest_table = pagetable_from_pfn(mfn);
if ( old_base_mfn )
@@ -1913,9 +1913,6 @@ static int mov_to_cr(int gpreg, int cr,
paging_update_paging_modes(v);
/* signal paging update to ASID handler */
svm_asid_g_update_paging (v);
-
- HVM_DBG_LOG(DBG_LEVEL_VMMU, "New arch.guest_table = %lx",
- (unsigned long) (mfn << PAGE_SHIFT));
HVM_DBG_LOG(DBG_LEVEL_VMMU,
"Update CR3 value = %lx, mfn = %lx",
@@ -2201,8 +2198,16 @@ static void svm_do_msr_access(
break;
default:
- if ( !long_mode_do_msr_write(regs) )
+ switch ( long_mode_do_msr_write(regs) )
+ {
+ case HNDL_unhandled:
wrmsr_hypervisor_regs(ecx, regs->eax, regs->edx);
+ break;
+ case HNDL_exception_raised:
+ return;
+ case HNDL_done:
+ break;
+ }
break;
}
diff -r aa640601575f -r 1d1ccf6b8614 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c Mon Jul 09 14:51:44 2007 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c Mon Jul 09 18:04:23 2007 +0100
@@ -51,6 +51,8 @@
#include <public/hvm/save.h>
#include <asm/hvm/trace.h>
+enum handler_return { HNDL_done, HNDL_unhandled, HNDL_exception_raised };
+
char *vmx_msr_bitmap;
static void vmx_ctxt_switch_from(struct vcpu *v);
@@ -178,14 +180,15 @@ static void vmx_save_host_msrs(void)
set_bit(VMX_INDEX_MSR_ ## address, &host_msr_state->flags); \
break
-static int long_mode_do_msr_read(struct cpu_user_regs *regs)
+static enum handler_return long_mode_do_msr_read(struct cpu_user_regs *regs)
{
u64 msr_content = 0;
u32 ecx = regs->ecx;
struct vcpu *v = current;
struct vmx_msr_state *guest_msr_state = &v->arch.hvm_vmx.msr_state;
- switch ( ecx ) {
+ switch ( ecx )
+ {
case MSR_EFER:
msr_content = v->arch.hvm_vmx.efer;
break;
@@ -204,7 +207,7 @@ static int long_mode_do_msr_read(struct
if ( !(vmx_long_mode_enabled(v)) )
{
vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
- return 0;
+ return HNDL_exception_raised;
}
break;
@@ -225,7 +228,7 @@ static int long_mode_do_msr_read(struct
break;
default:
- return 0;
+ return HNDL_unhandled;
}
HVM_DBG_LOG(DBG_LEVEL_0, "msr 0x%x content 0x%"PRIx64, ecx, msr_content);
@@ -233,10 +236,10 @@ static int long_mode_do_msr_read(struct
regs->eax = (u32)(msr_content >> 0);
regs->edx = (u32)(msr_content >> 32);
- return 1;
-}
-
-static int long_mode_do_msr_write(struct cpu_user_regs *regs)
+ return HNDL_done;
+}
+
+static enum handler_return long_mode_do_msr_write(struct cpu_user_regs *regs)
{
u64 msr_content = (u32)regs->eax | ((u64)regs->edx << 32);
u32 ecx = regs->ecx;
@@ -326,16 +329,16 @@ static int long_mode_do_msr_write(struct
WRITE_MSR(SYSCALL_MASK);
default:
- return 0;
- }
-
- return 1;
+ return HNDL_unhandled;
+ }
+
+ return HNDL_done;
uncanonical_address:
HVM_DBG_LOG(DBG_LEVEL_0, "Not cano address of msr write %x", ecx);
gp_fault:
vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
- return 0;
+ return HNDL_exception_raised;
}
/*
@@ -434,7 +437,7 @@ static void vmx_restore_guest_msrs(struc
}
}
-static int long_mode_do_msr_read(struct cpu_user_regs *regs)
+static enum handler_return long_mode_do_msr_read(struct cpu_user_regs *regs)
{
u64 msr_content = 0;
struct vcpu *v = current;
@@ -445,16 +448,16 @@ static int long_mode_do_msr_read(struct
break;
default:
- return 0;
+ return HNDL_unhandled;
}
regs->eax = msr_content >> 0;
regs->edx = msr_content >> 32;
- return 1;
-}
-
-static int long_mode_do_msr_write(struct cpu_user_regs *regs)
+ return HNDL_done;
+}
+
+static enum handler_return long_mode_do_msr_write(struct cpu_user_regs *regs)
{
u64 msr_content = regs->eax | ((u64)regs->edx << 32);
struct vcpu *v = current;
@@ -469,7 +472,7 @@ static int long_mode_do_msr_write(struct
gdprintk(XENLOG_WARNING, "Trying to set reserved bit in "
"EFER: %"PRIx64"\n", msr_content);
vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
- return 0;
+ return HNDL_exception_raised;
}
if ( (msr_content ^ v->arch.hvm_vmx.efer) & EFER_NX )
@@ -479,10 +482,10 @@ static int long_mode_do_msr_write(struct
break;
default:
- return 0;
- }
-
- return 1;
+ return HNDL_unhandled;
+ }
+
+ return HNDL_done;
}
#endif /* __i386__ */
@@ -683,9 +686,9 @@ int vmx_vmcs_restore(struct vcpu *v, str
if ( old_base_mfn )
put_page(mfn_to_page(old_base_mfn));
+ skip_cr3:
v->arch.hvm_vmx.cpu_cr3 = c->cr3;
- skip_cr3:
if ( vmx_long_mode_enabled(v) )
vmx_enable_long_mode(v);
@@ -1663,10 +1666,10 @@ static int vmx_str_pio_check_descriptor(
}
-static void vmx_str_pio_check_limit(u32 limit, unsigned int size,
- u32 ar_bytes, unsigned long addr,
- unsigned long base, int df,
- unsigned long *count)
+static int vmx_str_pio_check_limit(u32 limit, unsigned int size,
+ u32 ar_bytes, unsigned long addr,
+ unsigned long base, int df,
+ unsigned long *count)
{
unsigned long ea = addr - base;
@@ -1675,10 +1678,7 @@ static void vmx_str_pio_check_limit(u32
if ( (u32)(ea + size - 1) < (u32)ea ||
(ar_bytes & 0xc) != 0x4 ? ea + size - 1 > limit
: ea <= limit )
- {
- vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
- return;
- }
+ return 0;
/* Check the limit for repeated instructions, as above we checked
only the first instance. Truncate the count if a limit violation
@@ -1719,22 +1719,23 @@ static void vmx_str_pio_check_limit(u32
}
ASSERT(*count);
}
+
+ return 1;
}
#ifdef __x86_64__
-static void vmx_str_pio_lm_check_limit(struct cpu_user_regs *regs,
- unsigned int size,
- unsigned long addr,
- unsigned long *count)
+static int vmx_str_pio_lm_check_limit(struct cpu_user_regs *regs,
+ unsigned int size,
+ unsigned long addr,
+ unsigned long *count)
{
if ( !is_canonical_address(addr) ||
!is_canonical_address(addr + size - 1) )
- {
- vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
- return;
- }
+ return 0;
+
if ( *count > (1UL << 48) / size )
*count = (1UL << 48) / size;
+
if ( !(regs->eflags & EF_DF) )
{
if ( addr + *count * size - 1 < addr ||
@@ -1747,7 +1748,10 @@ static void vmx_str_pio_lm_check_limit(s
!is_canonical_address(addr + (*count - 1) * size) )
*count = (addr & ~((1UL << 48) - 1)) / size + 1;
}
+
ASSERT(*count);
+
+ return 1;
}
#endif
@@ -1875,18 +1879,21 @@ static void vmx_do_str_pio(unsigned long
if ( !long_mode )
{
/* Segment must be readable for outs and writeable for ins. */
- if ( dir == IOREQ_WRITE ? (ar_bytes & 0xa) == 0x8
- : (ar_bytes & 0xa) != 0x2 ) {
+ if ( ((dir == IOREQ_WRITE)
+ ? ((ar_bytes & 0xa) == 0x8)
+ : ((ar_bytes & 0xa) != 0x2)) ||
+ !vmx_str_pio_check_limit(limit, size, ar_bytes,
+ addr, base, df, &count) )
+ {
vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
return;
}
-
- vmx_str_pio_check_limit(limit, size, ar_bytes, addr, base, df, &count);
}
#ifdef __x86_64__
- else
- {
- vmx_str_pio_lm_check_limit(regs, size, addr, &count);
+ else if ( !vmx_str_pio_lm_check_limit(regs, size, addr, &count) )
+ {
+ vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
+ return;
}
#endif
@@ -2133,12 +2140,20 @@ static int vmx_assist(struct vcpu *v, in
struct hvm_hw_vpic *vpic = v->domain->arch.hvm_domain.vpic;
u32 magic, cp;
- /* make sure vmxassist exists (this is not an error) */
if ( hvm_copy_from_guest_phys(&magic, VMXASSIST_MAGIC_OFFSET,
sizeof(magic)) )
+ {
+ gdprintk(XENLOG_ERR, "No vmxassist: can't execute real mode code\n");
+ domain_crash(v->domain);
return 0;
+ }
+
if ( magic != VMXASSIST_MAGIC )
+ {
+ gdprintk(XENLOG_ERR, "vmxassist magic number not match\n");
+ domain_crash(v->domain);
return 0;
+ }
switch ( mode ) {
/*
@@ -2280,28 +2295,26 @@ static int vmx_set_cr0(unsigned long val
if ( old_base_mfn )
put_page(mfn_to_page(old_base_mfn));
- paging_update_paging_modes(v);
-
- HVM_DBG_LOG(DBG_LEVEL_VMMU, "New arch.guest_table = %lx",
- (unsigned long) (mfn << PAGE_SHIFT));
-
HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx, mfn = %lx",
v->arch.hvm_vmx.cpu_cr3, mfn);
+
+ paging_update_paging_modes(v);
}
/* Trying to disable paging. */
if ( ((value & (X86_CR0_PE | X86_CR0_PG)) != (X86_CR0_PE | X86_CR0_PG)) &&
paging_enabled )
{
+ /* When CR0.PG is cleared, LMA is cleared immediately. */
+ if ( vmx_long_mode_enabled(v) )
+ vmx_disable_long_mode(v);
+
if ( v->arch.hvm_vmx.cpu_cr3 )
{
put_page(mfn_to_page(get_mfn_from_gpfn(
v->arch.hvm_vmx.cpu_cr3 >> PAGE_SHIFT)));
v->arch.guest_table = pagetable_null();
}
-
- if ( vmx_long_mode_enabled(v) )
- vmx_disable_long_mode(v);
}
/*
@@ -2461,8 +2474,8 @@ static int mov_to_cr(int gp, int cr, str
{
if ( vmx_pgbit_test(v) )
{
+#if CONFIG_PAGING_LEVELS >= 3
/* The guest is a 32-bit PAE guest. */
-#if CONFIG_PAGING_LEVELS >= 3
unsigned long mfn, old_base_mfn;
mfn = get_mfn_from_gpfn(v->arch.hvm_vmx.cpu_cr3 >> PAGE_SHIFT);
if ( !mfn_valid(mfn) ||
@@ -2476,9 +2489,6 @@ static int mov_to_cr(int gp, int cr, str
v->arch.guest_table = pagetable_from_pfn(mfn);
if ( old_base_mfn )
put_page(mfn_to_page(old_base_mfn));
-
- HVM_DBG_LOG(DBG_LEVEL_VMMU, "New arch.guest_table = %lx",
- (unsigned long) (mfn << PAGE_SHIFT));
HVM_DBG_LOG(DBG_LEVEL_VMMU,
"Update CR3 value = %lx, mfn = %lx",
@@ -2645,8 +2655,15 @@ static int vmx_do_msr_read(struct cpu_us
case MSR_IA32_VMX_BASIC...MSR_IA32_VMX_PROCBASED_CTLS2:
goto gp_fault;
default:
- if ( long_mode_do_msr_read(regs) )
- goto done;
+ switch ( long_mode_do_msr_read(regs) )
+ {
+ case HNDL_unhandled:
+ break;
+ case HNDL_exception_raised:
+ return 0;
+ case HNDL_done:
+ goto done;
+ }
if ( rdmsr_hypervisor_regs(ecx, &eax, &edx) ||
rdmsr_safe(ecx, eax, edx) == 0 )
@@ -2771,8 +2788,16 @@ static int vmx_do_msr_write(struct cpu_u
case MSR_IA32_VMX_BASIC...MSR_IA32_VMX_PROCBASED_CTLS2:
goto gp_fault;
default:
- if ( !long_mode_do_msr_write(regs) )
- wrmsr_hypervisor_regs(ecx, regs->eax, regs->edx);
+ switch ( long_mode_do_msr_write(regs) )
+ {
+ case HNDL_unhandled:
+ wrmsr_hypervisor_regs(ecx, regs->eax, regs->edx);
+ break;
+ case HNDL_exception_raised:
+ return 0;
+ case HNDL_done:
+ break;
+ }
break;
}
@@ -2812,7 +2837,8 @@ static void vmx_do_extint(struct cpu_use
vector &= INTR_INFO_VECTOR_MASK;
HVMTRACE_1D(INTR, current, vector);
- switch(vector) {
+ switch ( vector )
+ {
case LOCAL_TIMER_VECTOR:
smp_apic_timer_interrupt(regs);
break;
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|