|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v1 3/5] x86/nestedsvm: update vmexit without pending or deferred flag
From: Chunjie Zhu <chunjie.zhu@xxxxxxxxxx>
Signed-off-by: Chunjie Zhu <chunjie.zhu@xxxxxxxxxx>
---
xen/arch/x86/hvm/svm/intr.c | 4 +-
xen/arch/x86/hvm/svm/nestedhvm.h | 5 +-
xen/arch/x86/hvm/svm/nestedsvm.c | 168 ++++++++---------------
xen/arch/x86/hvm/svm/svm.c | 10 +-
xen/arch/x86/include/asm/hvm/svm-types.h | 7 -
5 files changed, 72 insertions(+), 122 deletions(-)
diff --git a/xen/arch/x86/hvm/svm/intr.c b/xen/arch/x86/hvm/svm/intr.c
index 7f6cafb6db78..f9b59a0d6a46 100644
--- a/xen/arch/x86/hvm/svm/intr.c
+++ b/xen/arch/x86/hvm/svm/intr.c
@@ -55,7 +55,7 @@ static void svm_inject_nmi(struct vcpu *v)
vmcb, general1_intercepts | GENERAL1_INTERCEPT_IRET);
}
-static void svm_inject_intr(struct vcpu *v, int vector)
+void svm_inject_intr(struct vcpu *v, int vector)
{
struct vmcb_struct *vmcb = v->arch.hvm.svm.vmcb;
intinfo_t event;
@@ -69,7 +69,7 @@ static void svm_inject_intr(struct vcpu *v, int vector)
vmcb->event_inj = event;
}
-static void svm_enable_intr_window(struct vcpu *v, struct hvm_intack intack)
+void svm_enable_intr_window(struct vcpu *v, struct hvm_intack intack)
{
struct vmcb_struct *vmcb = v->arch.hvm.svm.vmcb;
uint32_t general1_intercepts = vmcb_get_general1_intercepts(vmcb);
diff --git a/xen/arch/x86/hvm/svm/nestedhvm.h b/xen/arch/x86/hvm/svm/nestedhvm.h
index e22ef259c171..5876a948f39a 100644
--- a/xen/arch/x86/hvm/svm/nestedhvm.h
+++ b/xen/arch/x86/hvm/svm/nestedhvm.h
@@ -27,7 +27,8 @@
(!!((v)->arch.hvm.guest_efer & EFER_SVME))
int nestedsvm_vmcb_map(struct vcpu *v, uint64_t vmcbaddr);
-void nestedsvm_vmexit_defer(struct vcpu *v,
+enum nestedhvm_vmexits
+nestedsvm_vcpu_vmexit(struct vcpu *v, struct cpu_user_regs *regs,
uint64_t exitcode, uint64_t exitinfo1, uint64_t exitinfo2);
enum nestedhvm_vmexits
nestedsvm_vmexit_n2n1(struct vcpu *v, struct cpu_user_regs *regs);
@@ -65,6 +66,8 @@ int cf_check nsvm_hap_walk_L1_p2m(
#define NSVM_INTR_MASKED 0
int nestedsvm_vcpu_interrupt(struct vcpu *v, const struct hvm_intack intack);
+void svm_enable_intr_window(struct vcpu *v, struct hvm_intack intack);
+void svm_inject_intr(struct vcpu *v, int vector);
#endif /* __X86_HVM_SVM_NESTEDHVM_PRIV_H__ */
diff --git a/xen/arch/x86/hvm/svm/nestedsvm.c b/xen/arch/x86/hvm/svm/nestedsvm.c
index edb3f444756d..9e5e804a5b00 100644
--- a/xen/arch/x86/hvm/svm/nestedsvm.c
+++ b/xen/arch/x86/hvm/svm/nestedsvm.c
@@ -152,8 +152,6 @@ int cf_check nsvm_vcpu_reset(struct vcpu *v)
svm->ns_vmcb_hostcr3 = 0;
svm->ns_asid = 0;
svm->ns_hostflags.bytes = 0;
- svm->ns_vmexit.exitinfo1 = 0;
- svm->ns_vmexit.exitinfo2 = 0;
svm->ns_iomap = NULL;
@@ -712,14 +710,10 @@ nsvm_vcpu_vmrun(struct vcpu *v, struct cpu_user_regs
*regs)
int ret;
unsigned int inst_len;
struct nestedvcpu *nv = &vcpu_nestedhvm(v);
- struct nestedsvm *svm = &vcpu_nestedsvm(v);
inst_len = svm_get_insn_len(v, INSTR_VMRUN);
if ( inst_len == 0 )
- {
- svm->ns_vmexit.exitcode = VMEXIT_SHUTDOWN;
return -1;
- }
nv->nv_vmswitch_in_progress = 1;
ASSERT(nv->nv_vvmcx != NULL);
@@ -738,15 +732,10 @@ nsvm_vcpu_vmrun(struct vcpu *v, struct cpu_user_regs
*regs)
break;
case NSVM_ERROR_VVMCB:
gdprintk(XENLOG_ERR, "inject VMEXIT(INVALID)\n");
- svm->ns_vmexit.exitcode = VMEXIT_INVALID;
return -1;
case NSVM_ERROR_VMENTRY:
default:
- gdprintk(XENLOG_ERR,
- "nsvm_vcpu_vmentry failed, injecting #UD\n");
- hvm_inject_hw_exception(X86_EXC_UD, X86_EVENT_NO_EC);
- /* Must happen after hvm_inject_hw_exception or it doesn't work right.
*/
- nv->nv_vmswitch_in_progress = 0;
+ gdprintk(XENLOG_ERR, "nsvm_vcpu_vmentry failed\n");
return 1;
}
@@ -760,47 +749,55 @@ nsvm_vcpu_vmrun(struct vcpu *v, struct cpu_user_regs
*regs)
static int
nsvm_vcpu_vmexit_inject(struct vcpu *v, struct cpu_user_regs *regs,
- uint64_t exitcode)
+ uint64_t exitcode, uint64_t exitinfo1, uint64_t exitinfo2)
{
struct nestedvcpu *nv = &vcpu_nestedhvm(v);
- struct nestedsvm *svm = &vcpu_nestedsvm(v);
struct vmcb_struct *ns_vmcb;
struct vmcb_struct *vmcb = v->arch.hvm.svm.vmcb;
- if ( vmcb->_vintr.fields.vgif_enable )
+ ASSERT(vmcb->_vintr.fields.vgif_enable);
vmcb->_vintr.fields.vgif = 0;
- else
- svm->ns_gif = 0;
ns_vmcb = nv->nv_vvmcx;
- if ( nv->nv_vmexit_pending )
+ switch ( exitcode )
+ {
+ case VMEXIT_INTR:
{
- switch ( exitcode )
+ struct hvm_intack intack = {
+ .source = exitinfo1,
+ .vector = exitinfo2
+ };
+
+ /* See the comment in svm_intr_assist() for why this is necessary */
+ if ( unlikely(vmcb->event_inj.v) ||
+ hvm_interrupt_blocked(v, intack) )
{
- case VMEXIT_INTR:
- if ( unlikely(ns_vmcb->event_inj.v) && nv->nv_vmentry_pending &&
- hvm_event_needs_reinjection(ns_vmcb->event_inj.type,
- ns_vmcb->event_inj.vector) )
- ns_vmcb->exit_int_info = ns_vmcb->event_inj;
- break;
- case VMEXIT_EXCEPTION_PF:
- ns_vmcb->_cr2 = ns_vmcb->ei.exc.cr2;
- fallthrough;
- case VMEXIT_NPF:
- ns_vmcb->exitinfo2 = svm->ns_vmexit.exitinfo2;
- fallthrough;
- case VMEXIT_EXCEPTION_NP:
- case VMEXIT_EXCEPTION_SS:
- case VMEXIT_EXCEPTION_GP:
- case VMEXIT_EXCEPTION_15:
- case VMEXIT_EXCEPTION_MF:
- case VMEXIT_EXCEPTION_AC:
- ns_vmcb->exitinfo1 = svm->ns_vmexit.exitinfo1;
- break;
- default:
+ svm_enable_intr_window(v, intack);
break;
}
+
+ svm_inject_intr(v, intack.vector);
+ pt_intr_post(v, intack);
+ break;
+ }
+
+ case VMEXIT_EXCEPTION_PF:
+ ns_vmcb->_cr2 = exitinfo2;
+ fallthrough;
+ case VMEXIT_NPF:
+ ns_vmcb->exitinfo2 = exitinfo2;
+ fallthrough;
+ case VMEXIT_EXCEPTION_NP:
+ case VMEXIT_EXCEPTION_SS:
+ case VMEXIT_EXCEPTION_GP:
+ case VMEXIT_EXCEPTION_15:
+ case VMEXIT_EXCEPTION_MF:
+ case VMEXIT_EXCEPTION_AC:
+ ns_vmcb->exitinfo1 = exitinfo1;
+ break;
+ default:
+ break;
}
ns_vmcb->exitcode = exitcode;
@@ -811,10 +808,16 @@ nsvm_vcpu_vmexit_inject(struct vcpu *v, struct
cpu_user_regs *regs,
int cf_check nsvm_vcpu_vmexit_event(
struct vcpu *v, const struct x86_event *event)
{
+ enum nestedhvm_vmexits ret;
+
ASSERT(vcpu_nestedhvm(v).nv_vvmcx != NULL);
- nestedsvm_vmexit_defer(v, VMEXIT_EXCEPTION_DE + event->vector,
- event->error_code, event->data);
+ ret = nestedsvm_vcpu_vmexit(v, guest_cpu_user_regs(),
+ VMEXIT_EXCEPTION_DE + event->vector,
+ event->error_code, event->data);
+ if ( ret == NESTEDHVM_VMEXIT_FATALERROR )
+ domain_crash(v->domain);
+
return NESTEDHVM_VMEXIT_DONE;
}
@@ -1219,7 +1222,7 @@ enum hvm_intblk cf_check nsvm_intr_blocked(struct vcpu *v)
if ( v->io.req.state != STATE_IOREQ_NONE )
return hvm_intblk_shadow;
- if ( !nv->nv_vmexit_pending && n2vmcb->exit_int_info.v )
+ if ( n2vmcb->exit_int_info.v )
{
/* Give the l2 guest a chance to finish the delivery of
* the last injected interrupt or exception before we
@@ -1228,42 +1231,15 @@ enum hvm_intblk cf_check nsvm_intr_blocked(struct vcpu
*v)
return hvm_intblk_shadow;
}
}
-
- if ( nv->nv_vmexit_pending )
- /* hvm_inject_hw_exception() must have run before.
- * exceptions have higher priority than interrupts.
- */
- return hvm_intblk_rflags_ie;
-
return hvm_intblk_none;
}
-/* VMEXIT emulation */
-void
-nestedsvm_vmexit_defer(struct vcpu *v,
- uint64_t exitcode, uint64_t exitinfo1, uint64_t exitinfo2)
-{
- struct nestedsvm *svm = &vcpu_nestedsvm(v);
- struct vmcb_struct *vmcb = v->arch.hvm.svm.vmcb;
-
- if ( vmcb->_vintr.fields.vgif_enable )
- vmcb->_vintr.fields.vgif = 0;
- else
- svm->ns_gif = 0;
-
- svm->ns_vmexit.exitcode = exitcode;
- svm->ns_vmexit.exitinfo1 = exitinfo1;
- svm->ns_vmexit.exitinfo2 = exitinfo2;
- vcpu_nestedhvm(v).nv_vmexit_pending = 1;
-}
-
enum nestedhvm_vmexits
nestedsvm_check_intercepts(struct vcpu *v, struct cpu_user_regs *regs,
uint64_t exitcode)
{
bool is_intercepted;
- ASSERT(vcpu_nestedhvm(v).nv_vmexit_pending == 0);
is_intercepted = nsvm_vmcb_guest_intercepts_exitcode(v, regs, exitcode);
/*
@@ -1352,11 +1328,12 @@ nestedsvm_vmexit_n2n1(struct vcpu *v, struct
cpu_user_regs *regs)
/* The exitcode is in native SVM/VMX format. The forced exitcode
* is in generic format.
*/
-static enum nestedhvm_vmexits
+enum nestedhvm_vmexits
nestedsvm_vcpu_vmexit(struct vcpu *v, struct cpu_user_regs *regs,
- uint64_t exitcode)
+ uint64_t exitcode, uint64_t exitinfo1, uint64_t exitinfo2)
{
int rc;
+ enum nestedhvm_vmexits ret = NESTEDHVM_VMEXIT_DONE;
struct nestedvcpu *nv = &vcpu_nestedhvm(v);
nv->nv_vmswitch_in_progress = 1;
@@ -1368,14 +1345,12 @@ nestedsvm_vcpu_vmexit(struct vcpu *v, struct
cpu_user_regs *regs,
*/
if ( nestedhvm_vcpu_in_guestmode(v) )
{
- enum nestedhvm_vmexits ret;
-
ret = nestedsvm_vmexit_n2n1(v, regs);
switch ( ret )
{
case NESTEDHVM_VMEXIT_FATALERROR:
gdprintk(XENLOG_ERR, "VMEXIT: fatal error\n");
- return ret;
+ goto out;
case NESTEDHVM_VMEXIT_HOST:
BUG();
@@ -1395,46 +1370,18 @@ nestedsvm_vcpu_vmexit(struct vcpu *v, struct
cpu_user_regs *regs,
/* Prepare for running the l1 guest. Make the actual
* modifications to the virtual VMCB/VMCS.
*/
- rc = nsvm_vcpu_vmexit_inject(v, regs, exitcode);
+ rc = nsvm_vcpu_vmexit_inject(v, regs, exitcode, exitinfo1, exitinfo2);
/* If l1 guest uses shadow paging, update the paging mode. */
if ( !nestedhvm_paging_mode_hap(v) )
paging_update_paging_modes(v);
- nv->nv_vmswitch_in_progress = 0;
-
if ( rc )
- return NESTEDHVM_VMEXIT_FATALERROR;
-
- return NESTEDHVM_VMEXIT_DONE;
-}
-
-/* VCPU switch */
-void asmlinkage nsvm_vcpu_switch(void)
-{
- struct cpu_user_regs *regs = guest_cpu_user_regs();
- struct vcpu *v = current;
- struct nestedvcpu *nv;
- struct nestedsvm *svm;
-
- if ( !nestedhvm_enabled(v->domain) )
- return;
-
- nv = &vcpu_nestedhvm(v);
- svm = &vcpu_nestedsvm(v);
- ASSERT(v->arch.hvm.svm.vmcb != NULL);
- ASSERT(nv->nv_n1vmcx != NULL);
- ASSERT(nv->nv_n2vmcx != NULL);
- ASSERT(nv->nv_n1vmcx_pa != INVALID_PADDR);
- ASSERT(nv->nv_n2vmcx_pa != INVALID_PADDR);
+ ret = NESTEDHVM_VMEXIT_FATALERROR;
- if ( nv->nv_vmexit_pending )
- {
- vmexit:
- nestedsvm_vcpu_vmexit(v, regs, svm->ns_vmexit.exitcode);
- nv->nv_vmexit_pending = 0;
- return;
- }
+out:
+ nv->nv_vmswitch_in_progress = 0;
+ return ret;
}
/* Interrupts, Virtual GIF */
@@ -1477,7 +1424,10 @@ nestedsvm_vcpu_interrupt(struct vcpu *v, const struct
hvm_intack intack)
guest_cpu_user_regs(), exitcode);
if ( ret )
{
- nestedsvm_vmexit_defer(v, exitcode, intack.source, exitinfo2);
+ ret = nestedsvm_vcpu_vmexit(v, guest_cpu_user_regs(), exitcode,
+ intack.source, exitinfo2);
+ if ( ret == NESTEDHVM_VMEXIT_FATALERROR )
+ domain_crash(v->domain);
return NSVM_INTR_FORCEVMEXIT;
}
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index fc447d24d67e..a8d258aa3980 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -1619,7 +1619,9 @@ static void svm_do_nested_pgfault(struct vcpu *v,
case -1:
ASSERT(nestedhvm_enabled(v->domain) && nestedhvm_vcpu_in_guestmode(v));
/* inject #VMEXIT(NPF) into guest. */
- nestedsvm_vmexit_defer(v, VMEXIT_NPF, pfec, gpa);
+ if ( nestedsvm_vcpu_vmexit(v, regs, VMEXIT_NPF, pfec, gpa) ==
+ NESTEDHVM_VMEXIT_FATALERROR )
+ domain_crash(v->domain);
return;
}
@@ -2595,8 +2597,10 @@ void asmlinkage svm_vmexit_handler(void)
switch ( nsret )
{
case NESTEDHVM_VMEXIT_DONE:
- /* defer VMEXIT injection */
- nestedsvm_vmexit_defer(v, exit_reason, exitinfo1, exitinfo2);
+ nsret = nestedsvm_vcpu_vmexit(v, regs, exit_reason,
+ exitinfo1, exitinfo2);
+ if ( nsret == NESTEDHVM_VMEXIT_FATALERROR )
+ domain_crash(v->domain);
goto out;
case NESTEDHVM_VMEXIT_FATALERROR:
gdprintk(XENLOG_ERR, "unexpected nestedsvm_vmexit() error\n");
diff --git a/xen/arch/x86/include/asm/hvm/svm-types.h
b/xen/arch/x86/include/asm/hvm/svm-types.h
index beab9a3af203..256bf5b91402 100644
--- a/xen/arch/x86/include/asm/hvm/svm-types.h
+++ b/xen/arch/x86/include/asm/hvm/svm-types.h
@@ -69,13 +69,6 @@ struct nestedsvm {
bool ns_gif;
bool ns_hap_enabled;
- /* Only meaningful when vmexit_pending flag is set */
- struct {
- uint64_t exitcode; /* native exitcode to inject into l1 guest */
- uint64_t exitinfo1; /* additional information to the exitcode */
- uint64_t exitinfo2; /* additional information to the exitcode */
- } ns_vmexit;
-
union {
uint32_t bytes;
struct {
--
2.34.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |