aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/hvm/svm/svm.c
diff options
context:
space:
mode:
Diffstat (limited to 'xen/arch/x86/hvm/svm/svm.c')
-rw-r--r--xen/arch/x86/hvm/svm/svm.c39
1 files changed, 37 insertions, 2 deletions
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 998611220e..9ee9ee5bf8 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -456,6 +456,28 @@ void svm_init_ap_context(struct vcpu_guest_context *ctxt,
ctxt->flags = VGCF_HVM_GUEST;
}
+static void svm_init_hypercall_page(struct domain *d, void *hypercall_page)
+{
+ char *p;
+ int i;
+
+ memset(hypercall_page, 0, PAGE_SIZE);
+
+ for ( i = 0; i < (PAGE_SIZE / 32); i++ )
+ {
+ p = (char *)(hypercall_page + (i * 32));
+ *(u8 *)(p + 0) = 0xb8; /* mov imm32, %eax */
+ *(u32 *)(p + 1) = i;
+ *(u8 *)(p + 5) = 0x0f; /* vmmcall */
+ *(u8 *)(p + 6) = 0x01;
+ *(u8 *)(p + 7) = 0xd9;
+ *(u8 *)(p + 8) = 0xc3; /* ret */
+ }
+
+ /* Don't support HYPERVISOR_iret at the moment */
+ *(u16 *)(hypercall_page + (__HYPERVISOR_iret * 32)) = 0x0b0f; /* ud2 */
+}
+
int start_svm(void)
{
u32 eax, ecx, edx;
@@ -504,6 +526,8 @@ int start_svm(void)
hvm_funcs.get_guest_ctrl_reg = svm_get_ctrl_reg;
hvm_funcs.init_ap_context = svm_init_ap_context;
+ hvm_funcs.init_hypercall_page = svm_init_hypercall_page;
+
hvm_enabled = 1;
return 1;
@@ -1980,11 +2004,13 @@ static int svm_cr_access(struct vcpu *v, unsigned int cr, unsigned int type,
return result;
}
-static inline void svm_do_msr_access(struct vcpu *v, struct cpu_user_regs *regs)
+static inline void svm_do_msr_access(
+ struct vcpu *v, struct cpu_user_regs *regs)
{
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
int inst_len;
u64 msr_content=0;
+ u32 eax, edx;
ASSERT(vmcb);
@@ -2018,6 +2044,14 @@ static inline void svm_do_msr_access(struct vcpu *v, struct cpu_user_regs *regs)
default:
if (long_mode_do_msr_read(regs))
goto done;
+
+ if ( rdmsr_hypervisor_regs(regs->ecx, &eax, &edx) )
+ {
+ regs->eax = eax;
+ regs->edx = edx;
+ goto done;
+ }
+
rdmsr_safe(regs->ecx, regs->eax, regs->edx);
break;
}
@@ -2047,7 +2081,8 @@ static inline void svm_do_msr_access(struct vcpu *v, struct cpu_user_regs *regs)
vlapic_msr_set(VLAPIC(v), msr_content);
break;
default:
- long_mode_do_msr_write(regs);
+ if ( !long_mode_do_msr_write(regs) )
+ wrmsr_hypervisor_regs(regs->ecx, regs->eax, regs->edx);
break;
}
}