|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [V10 PATCH 23/23] PVH xen: introduce vmexit handler for PVH
On Mon, Aug 12, 2013 at 5:00 PM, George Dunlap <dunlapg@xxxxxxxxx> wrote:
> Overall I have the same comment here as I had for the VMCS patch: the
> code looks 98% identical. Substantial differences seem to be:
> - emulation of privileged ops
> - cpuid
> - cr4 handling
>
> It seems like it would be much better to share the codepath and just
> put "is_pvh_domain()" in the places where it needs to be different.
So below is a patch which, I think, should be functionally mostly
equivalent to the patch you have -- but a *lot* shorter, and also
*very* clear about how PVH is different than normal HVM. I think this
is definitely the better approach.
-George
PVH xen: introduce vmexit handler for PVH
This version has unified PVH and HVM vmexit handlers.
A couple of notes:
- No check for cr3 accesses; that's a HAP/shadow issue, not a PVH one
- debug trap and ept violation cause guest crash now, as with HVM
- Don't know what to do if a hcall returns invalidate
- Don't know what to do on task switch
- Removed single_step=0 on MTF; may not be correct.
Signed-off-by: Mukesh Rathor <mukesh.rathor@xxxxxxxxxx>
Signed-off-by: George Dunlap <george.dunlap@xxxxxxxxxxxxx>
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index c742d7b..e9f9ef6 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -1776,7 +1776,17 @@ int hvm_set_cr0(unsigned long value)
(value & (X86_CR0_PE | X86_CR0_PG)) == X86_CR0_PG )
goto gpf;
- if ( (value & X86_CR0_PG) && !(old_value & X86_CR0_PG) )
+
+
+ /* A pvh is not expected to change to real mode. */
+ if ( is_pvh_vcpu(v)
+ && (value & (X86_CR0_PE | X86_CR0_PG)) != (X86_CR0_PG | X86_CR0_PE) )
+ {
+ printk(XENLOG_G_WARNING
+ "PVH attempting to turn off PE/PG. CR0:%lx\n", new_cr0);
+ goto gpf
+ }
+ else if ( (value & X86_CR0_PG) && !(old_value & X86_CR0_PG) )
{
if ( v->arch.hvm_vcpu.guest_efer & EFER_LME )
{
@@ -1953,6 +1963,11 @@ int hvm_set_cr4(unsigned long value)
* Modifying CR4.{PSE,PAE,PGE,SMEP}, or clearing CR4.PCIDE
* invalidate all TLB entries.
*/
+ /*
+ * PVH: I assume this is suitable -- it subsumes the conditions
+ * from the custom PVH handler:
+ * (old_val ^ new) & (X86_CR4_PSE | X86_CR4_PGE | X86_CR4_PAE)
+ */
if ( ((old_cr ^ value) &
(X86_CR4_PSE | X86_CR4_PGE | X86_CR4_PAE | X86_CR4_SMEP)) ||
(!(value & X86_CR4_PCIDE) && (old_cr & X86_CR4_PCIDE)) )
diff --git a/xen/arch/x86/hvm/vmx/pvh.c b/xen/arch/x86/hvm/vmx/pvh.c
index 8e61d23..a5a8ee1 100644
--- a/xen/arch/x86/hvm/vmx/pvh.c
+++ b/xen/arch/x86/hvm/vmx/pvh.c
@@ -20,10 +20,6 @@
#include <asm/hvm/nestedhvm.h>
#include <asm/xstate.h>
-/* Implemented in the next patch */
-void vmx_pvh_vmexit_handler(struct cpu_user_regs *regs)
-{
-}
/*
* Set vmcs fields in support of vcpu_op -> VCPUOP_initialise hcall. Called
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index bbfa130..37ec385 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -1244,6 +1244,12 @@ static void vmx_update_guest_cr(struct vcpu *v,
unsigned int cr)
*/
v->arch.hvm_vcpu.hw_cr[4] &= ~X86_CR4_SMEP;
}
+ if ( is_pvh_vcpu(v) )
+ {
+ /* What is this for? */
+ v->arch.hvm_vcpu.hw_cr[4] |= X86_CR4_VMXE | X86_CR4_MCE;
+ }
+
__vmwrite(GUEST_CR4, v->arch.hvm_vcpu.hw_cr[4]);
__vmwrite(CR4_READ_SHADOW, v->arch.hvm_vcpu.guest_cr[4]);
break;
@@ -2242,7 +2248,8 @@ static void ept_handle_violation(unsigned long
qualification, paddr_t gpa)
__trace_var(TRC_HVM_NPF, 0, sizeof(_d), &_d);
}
- ret = hvm_hap_nested_page_fault(gpa,
+ ret = is_pvh_domain(d) ? 0 :
+ hvm_hap_nested_page_fault(gpa,
qualification & EPT_GLA_VALID ? 1 : 0,
qualification & EPT_GLA_VALID
? __vmread(GUEST_LINEAR_ADDRESS) : ~0ull,
@@ -2490,12 +2497,6 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
if ( unlikely(exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) )
return vmx_failed_vmentry(exit_reason, regs);
- if ( is_pvh_vcpu(v) )
- {
- vmx_pvh_vmexit_handler(regs);
- return;
- }
-
if ( v->arch.hvm_vmx.vmx_realmode )
{
/* Put RFLAGS back the way the guest wants it */
@@ -2654,8 +2655,16 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
/* Already handled above. */
break;
case TRAP_invalid_op:
- HVMTRACE_1D(TRAP, vector);
- vmx_vmexit_ud_intercept(regs);
+ if ( is_pvh_domain(d) )
+ {
+ if ( guest_kernel_mode(current, regs) ||
!emulate_forced_invalid_op(regs) )
+ hvm_inject_hw_exception(TRAP_invalid_op,
HVM_DELIVER_NO_ERROR_CODE);
+ }
+ else
+ {
+ HVMTRACE_1D(TRAP, vector);
+ vmx_vmexit_ud_intercept(regs);
+ }
break;
default:
HVMTRACE_1D(TRAP, vector);
@@ -2685,6 +2694,8 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
};
int32_t ecode = -1, source;
+ /* PVH FIXME: What to do? */
+
exit_qualification = __vmread(EXIT_QUALIFICATION);
source = (exit_qualification >> 30) & 3;
/* Vectored event should fill in interrupt information. */
@@ -2704,8 +2715,8 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
break;
}
case EXIT_REASON_CPUID:
+ is_pvh_domain(d) ? pv_cpuid(regs) : vmx_do_cpuid(regs);
vmx_update_guest_eip(); /* Safe: CPUID */
- vmx_do_cpuid(regs);
break;
case EXIT_REASON_HLT:
vmx_update_guest_eip(); /* Safe: HLT */
@@ -2731,6 +2742,7 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
if ( rc != HVM_HCALL_preempted )
{
vmx_update_guest_eip(); /* Safe: VMCALL */
+ /* PVH FIXME: What to do? */
if ( rc == HVM_HCALL_invalidate )
send_invalidate_req();
}
@@ -2750,7 +2762,28 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
case EXIT_REASON_MSR_READ:
{
uint64_t msr_content;
- if ( hvm_msr_read_intercept(regs->ecx, &msr_content) == X86EMUL_OKAY )
+ if ( is_pvh_vcpu(v) )
+ {
+ u64 msr_content = 0;
+
+ switch ( regs->ecx )
+ {
+ case MSR_IA32_MISC_ENABLE:
+ rdmsrl(MSR_IA32_MISC_ENABLE, msr_content);
+ msr_content |= MSR_IA32_MISC_ENABLE_BTS_UNAVAIL |
+ MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL;
+ break;
+
+ default:
+ /* PVH fixme: see hvm_msr_read_intercept(). */
+ rdmsrl(regs->ecx, msr_content);
+ break;
+ }
+ regs->eax = (uint32_t)msr_content;
+ regs->edx = (uint32_t)(msr_content >> 32);
+ vmx_update_guest_eip(); /* Safe: RDMSR */
+ }
+ else if ( hvm_msr_read_intercept(regs->ecx, &msr_content) ==
X86EMUL_OKAY )
{
regs->eax = (uint32_t)msr_content;
regs->edx = (uint32_t)(msr_content >> 32);
@@ -2853,21 +2886,42 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
}
case EXIT_REASON_IO_INSTRUCTION:
- exit_qualification = __vmread(EXIT_QUALIFICATION);
- if ( exit_qualification & 0x10 )
+ if ( is_pvh_vcpu(v) )
{
- /* INS, OUTS */
- if ( !handle_mmio() )
- hvm_inject_hw_exception(TRAP_gp_fault, 0);
+ /*
+ * Note: A PVH guest sets IOPL natively by setting bits in
+ * the eflags, and not via hypercalls used by a PV.
+ */
+ struct segment_register seg;
+ int requested = (regs->rflags & X86_EFLAGS_IOPL) >> 12;
+ int curr_lvl = (regs->rflags & X86_EFLAGS_VM) ? 3 : 0;
+
+ if ( curr_lvl == 0 )
+ {
+ hvm_get_segment_register(current, x86_seg_ss, &seg);
+ curr_lvl = seg.attr.fields.dpl;
+ }
+ if ( requested < curr_lvl || !emulate_privileged_op(regs) )
+ hvm_inject_hw_exception(TRAP_gp_fault, regs->error_code);
}
else
{
- /* IN, OUT */
- uint16_t port = (exit_qualification >> 16) & 0xFFFF;
- int bytes = (exit_qualification & 0x07) + 1;
- int dir = (exit_qualification & 0x08) ? IOREQ_READ : IOREQ_WRITE;
- if ( handle_pio(port, bytes, dir) )
- vmx_update_guest_eip(); /* Safe: IN, OUT */
+ exit_qualification = __vmread(EXIT_QUALIFICATION);
+ if ( exit_qualification & 0x10 )
+ {
+ /* INS, OUTS */
+ if ( !handle_mmio() )
+ hvm_inject_hw_exception(TRAP_gp_fault, 0);
+ }
+ else
+ {
+ /* IN, OUT */
+ uint16_t port = (exit_qualification >> 16) & 0xFFFF;
+ int bytes = (exit_qualification & 0x07) + 1;
+ int dir = (exit_qualification & 0x08) ? IOREQ_READ :
IOREQ_WRITE;
+ if ( handle_pio(port, bytes, dir) )
+ vmx_update_guest_eip(); /* Safe: IN, OUT */
+ }
}
break;
@@ -2890,6 +2944,7 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
case EXIT_REASON_MONITOR_TRAP_FLAG:
v->arch.hvm_vmx.exec_control &= ~CPU_BASED_MONITOR_TRAP_FLAG;
vmx_update_cpu_exec_control(v);
+ /* PVH code set hvm_vcpu.single_step = 0 -- is that necessary? */
if ( v->arch.hvm_vcpu.single_step ) {
hvm_memory_event_single_step(regs->eip);
if ( v->domain->debugger_attached )
Attachment:
pvh-vmexit-unified.diff _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |