From: Christoph Egger <Christoph.Egger@amd.com>
To: "xen-devel@lists.xensource.com" <xen-devel@lists.xensource.com>
Subject: [PATCH 10/12] Nested Virtualization: interrupts (svm specific)
Date: Mon, 20 Dec 2010 17:11:35 +0100 [thread overview]
Message-ID: <201012201711.37080.Christoph.Egger@amd.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 264 bytes --]
--
---to satisfy European Law for business letters:
Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach b. Muenchen
Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd
Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen
Registergericht Muenchen, HRB Nr. 43632
[-- Attachment #2: xen_nh10_svm_interrupt.diff --]
[-- Type: text/x-diff, Size: 11997 bytes --]
# HG changeset patch
# User cegger
# Date 1292839443 -3600
Implement SVM specific interrupt handling
Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
diff -r ca44f5981d17 -r 9d27b197ca34 xen/arch/x86/hvm/svm/intr.c
--- a/xen/arch/x86/hvm/svm/intr.c
+++ b/xen/arch/x86/hvm/svm/intr.c
@@ -33,6 +33,7 @@
#include <asm/hvm/vlapic.h>
#include <asm/hvm/svm/svm.h>
#include <asm/hvm/svm/intr.h>
+#include <asm/hvm/nestedhvm.h> /* for nestedhvm_vcpu_in_guestmode */
#include <xen/event.h>
#include <xen/kernel.h>
#include <public/hvm/ioreq.h>
@@ -74,15 +75,30 @@ static void svm_inject_extint(struct vcp
ASSERT(vmcb->eventinj.fields.v == 0);
vmcb->eventinj = event;
}
-
+
static void enable_intr_window(struct vcpu *v, struct hvm_intack intack)
{
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- u32 general1_intercepts = vmcb_get_general1_intercepts(vmcb);
+ uint32_t general1_intercepts = vmcb_get_general1_intercepts(vmcb);
vintr_t intr;
ASSERT(intack.source != hvm_intsrc_none);
+ if ( nestedhvm_enabled(v->domain) ) {
+ struct nestedvcpu *nv = &vcpu_nestedhvm(v);
+ if ( nv->nv_vmentry_pending ) {
+ struct vmcb_struct *gvmcb = nv->nv_vmcx;
+
+ /* check if l1 guest injects interrupt into l2 guest via vintr.
+ * return here or l2 guest looses interrupts, otherwise.
+ */
+ ASSERT(gvmcb != NULL);
+ intr = vmcb_get_vintr(gvmcb);
+ if ( intr.fields.irq )
+ return;
+ }
+ }
+
HVMTRACE_3D(INTR_WINDOW, intack.vector, intack.source,
vmcb->eventinj.fields.v?vmcb->eventinj.fields.vector:-1);
@@ -121,6 +137,7 @@ asmlinkage void svm_intr_assist(void)
struct vcpu *v = current;
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
struct hvm_intack intack;
+ enum hvm_intblk intblk;
/* Crank the handle on interrupt state. */
pt_update_irq(v);
@@ -130,6 +147,39 @@ asmlinkage void svm_intr_assist(void)
if ( likely(intack.source == hvm_intsrc_none) )
return;
+ intblk = hvm_interrupt_blocked(v, intack);
+ if ( intblk == hvm_intblk_svm_gif ) {
+ ASSERT(nestedhvm_enabled(v->domain));
+ return;
+ }
+
+ /* Interrupts for the nested guest are already
+ * in the vmcb.
+ */
+ if ( nestedhvm_enabled(v->domain) && nestedhvm_vcpu_in_guestmode(v) )
+ {
+ int rc;
+
+ /* l2 guest was running when an interrupt for
+ * the l1 guest occured.
+ */
+ rc = nestedsvm_vcpu_interrupt(v, intack);
+ switch (rc) {
+ case NSVM_INTR_NOTINTERCEPTED:
+ /* Inject interrupt into 2nd level guest directly. */
+ break;
+ case NSVM_INTR_NOTHANDLED:
+ case NSVM_INTR_FORCEVMEXIT:
+ return;
+ case NSVM_INTR_MASKED:
+ /* Guest already enabled an interrupt window. */
+ return;
+ default:
+ panic("%s: nestedsvm_vcpu_interrupt can't handle value 0x%x\n",
+ __func__, rc);
+ }
+ }
+
/*
* Pending IRQs must be delayed if:
* 1. An event is already pending. This is despite the fact that SVM
@@ -144,8 +194,7 @@ asmlinkage void svm_intr_assist(void)
* have cleared the interrupt out of the IRR.
* 2. The IRQ is masked.
*/
- if ( unlikely(vmcb->eventinj.fields.v) ||
- hvm_interrupt_blocked(v, intack) )
+ if ( unlikely(vmcb->eventinj.fields.v) || intblk )
{
enable_intr_window(v, intack);
return;
diff -r ca44f5981d17 -r 9d27b197ca34 xen/arch/x86/hvm/svm/nestedsvm.c
--- a/xen/arch/x86/hvm/svm/nestedsvm.c
+++ b/xen/arch/x86/hvm/svm/nestedsvm.c
@@ -25,6 +25,22 @@
#include <asm/hvm/svm/nestedsvm.h>
#include <asm/hvm/svm/svmdebug.h>
#include <asm/paging.h> /* paging_mode_hap */
+#include <asm/event.h> /* for local_event_delivery_(en|dis)able */
+
+static void
+nestedsvm_vcpu_clgi(struct vcpu *v)
+{
+ /* clear gif flag */
+ vcpu_nestedsvm(v).ns_gif = 0;
+ local_event_delivery_disable(); /* mask events for PV drivers */
+}
+
+static void
+nestedsvm_vcpu_stgi(struct vcpu *v)
+{
+ vcpu_nestedsvm(v).ns_gif = 1;
+ local_event_delivery_enable(); /* unmask events for PV drivers */
+}
static int
nestedsvm_vmcb_isvalid(struct vcpu *v, uint64_t vmcxaddr)
@@ -144,6 +160,7 @@ int nsvm_vcpu_reset(struct vcpu *v)
svm->ns_iomap = NULL;
}
+ nestedsvm_vcpu_stgi(v);
return 0;
}
@@ -572,6 +589,8 @@ nsvm_vcpu_vmentry(struct vcpu *v, struct
return ret;
}
+ nestedsvm_vcpu_stgi(v);
+
return 0;
}
@@ -617,6 +636,7 @@ nsvm_vcpu_vmexit_inject(struct vcpu *v,
struct nestedsvm *svm = &vcpu_nestedsvm(v);
struct vmcb_struct *ns_vmcb;
+ ASSERT(svm->ns_gif == 0);
ns_vmcb = nv->nv_vmcx;
if (nv->nv_vmexit_pending) {
@@ -1000,6 +1020,32 @@ nsvm_vmcb_hap_enabled(struct vcpu *v)
return vcpu_nestedsvm(v).ns_hap_enabled;
}
+enum hvm_intblk nsvm_intr_blocked(struct vcpu *v)
+{
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+ struct nestedvcpu *nv = &vcpu_nestedhvm(v);
+
+ ASSERT(nestedhvm_enabled(v->domain));
+
+ if ( !nestedsvm_gif_isset(v) )
+ return hvm_intblk_svm_gif;
+
+ if ( nestedhvm_vcpu_in_guestmode(v) ) {
+ if ( svm->ns_hostflags.fields.vintrmask )
+ if ( !svm->ns_hostflags.fields.rflagsif )
+ return hvm_intblk_rflags_ie;
+ }
+
+ if ( nv->nv_vmexit_pending ) {
+ /* hvm_inject_exception() must have run before.
+ * exceptions have higher priority than interrupts.
+ */
+ return hvm_intblk_rflags_ie;
+ }
+
+ return hvm_intblk_none;
+}
+
/* MSR handling */
int nsvm_rdmsr(struct vcpu *v, unsigned int msr, uint64_t *msr_content)
{
@@ -1055,6 +1101,7 @@ nestedsvm_vmexit_defer(struct vcpu *v,
{
struct nestedsvm *svm = &vcpu_nestedsvm(v);
+ nestedsvm_vcpu_clgi(v);
svm->ns_vmexit.exitcode = exitcode;
svm->ns_vmexit.exitinfo1 = exitinfo1;
svm->ns_vmexit.exitinfo2 = exitinfo2;
@@ -1236,4 +1283,98 @@ asmlinkage void nsvm_vcpu_switch(struct
}
}
+/* Interrupts, Virtual GIF */
+int
+nestedsvm_vcpu_interrupt(struct vcpu *v, const struct hvm_intack intack)
+{
+ int ret;
+ enum hvm_intblk intr;
+ uint64_t exitcode = VMEXIT_INTR;
+ uint64_t exitinfo2 = 0;
+ ASSERT(nestedhvm_vcpu_in_guestmode(v));
+ intr = nhvm_interrupt_blocked(v);
+ if ( intr != hvm_intblk_none )
+ return NSVM_INTR_MASKED;
+
+ switch (intack.source) {
+ case hvm_intsrc_pic:
+ case hvm_intsrc_lapic:
+ exitcode = VMEXIT_INTR;
+ exitinfo2 = intack.vector;
+ break;
+ case hvm_intsrc_nmi:
+ exitcode = VMEXIT_NMI;
+ exitinfo2 = intack.vector;
+ break;
+ case hvm_intsrc_mce:
+ exitcode = VMEXIT_EXCEPTION_MC;
+ exitinfo2 = intack.vector;
+ break;
+ case hvm_intsrc_none:
+ return NSVM_INTR_NOTHANDLED;
+ default:
+ BUG();
+ }
+
+ ret = nsvm_vmcb_guest_intercepts_exitcode(v,
+ guest_cpu_user_regs(), exitcode);
+ if (ret) {
+ nestedsvm_vmexit_defer(v, exitcode, intack.source, exitinfo2);
+ return NSVM_INTR_FORCEVMEXIT;
+ }
+
+ return NSVM_INTR_NOTINTERCEPTED;
+}
+
+bool_t
+nestedsvm_gif_isset(struct vcpu *v)
+{
+ struct nestedsvm *svm = &vcpu_nestedsvm(v);
+
+ return (!!svm->ns_gif);
+}
+
+void svm_vmexit_do_stgi(struct cpu_user_regs *regs, struct vcpu *v)
+{
+ unsigned int inst_len;
+
+ if ( !nestedhvm_enabled(v->domain) ) {
+ hvm_inject_exception(TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE, 0);
+ return;
+ }
+
+ if ( (inst_len = __get_instruction_length(v, INSTR_STGI)) == 0 )
+ return;
+
+ nestedsvm_vcpu_stgi(v);
+
+ __update_guest_eip(regs, inst_len);
+}
+
+void svm_vmexit_do_clgi(struct cpu_user_regs *regs, struct vcpu *v)
+{
+ struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+ unsigned int inst_len;
+ uint32_t general1_intercepts = vmcb_get_general1_intercepts(vmcb);
+ vintr_t intr;
+
+ if ( !nestedhvm_enabled(v->domain) ) {
+ hvm_inject_exception(TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE, 0);
+ return;
+ }
+
+ if ( (inst_len = __get_instruction_length(v, INSTR_CLGI)) == 0 )
+ return;
+
+ nestedsvm_vcpu_clgi(v);
+
+ /* After a CLGI no interrupts should come */
+ intr = vmcb_get_vintr(vmcb);
+ intr.fields.irq = 0;
+ general1_intercepts &= ~GENERAL1_INTERCEPT_VINTR;
+ vmcb_set_vintr(vmcb, intr);
+ vmcb_set_general1_intercepts(vmcb, general1_intercepts);
+
+ __update_guest_eip(regs, inst_len);
+}
diff -r ca44f5981d17 -r 9d27b197ca34 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -78,8 +78,7 @@ static DEFINE_PER_CPU_READ_MOSTLY(void *
static bool_t amd_erratum383_found __read_mostly;
-static void inline __update_guest_eip(
- struct cpu_user_regs *regs, unsigned int inst_len)
+void __update_guest_eip(struct cpu_user_regs *regs, unsigned int inst_len)
{
struct vcpu *curr = current;
@@ -1589,6 +1588,7 @@ static struct hvm_function_table __read_
.nhvm_vcpu_asid = nsvm_vcpu_asid,
.nhvm_vmcx_guest_intercepts_trap = nsvm_vmcb_guest_intercepts_trap,
.nhvm_vmcx_hap_enabled = nsvm_vmcb_hap_enabled,
+ .nhvm_intr_blocked = nsvm_intr_blocked,
};
asmlinkage void svm_vmexit_handler(struct cpu_user_regs *regs)
@@ -1900,7 +1900,11 @@ asmlinkage void svm_vmexit_handler(struc
svm_vmexit_do_vmsave(vmcb, regs, v, regs->eax);
break;
case VMEXIT_STGI:
+ svm_vmexit_do_stgi(regs, v);
+ break;
case VMEXIT_CLGI:
+ svm_vmexit_do_clgi(regs, v);
+ break;
case VMEXIT_SKINIT:
hvm_inject_exception(TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE, 0);
break;
diff -r ca44f5981d17 -r 9d27b197ca34 xen/include/asm-x86/hvm/svm/nestedsvm.h
--- a/xen/include/asm-x86/hvm/svm/nestedsvm.h
+++ b/xen/include/asm-x86/hvm/svm/nestedsvm.h
@@ -23,7 +23,12 @@
#include <asm/hvm/hvm.h>
#include <asm/hvm/svm/vmcb.h>
+/* SVM specific intblk types, cannot be an enum because gcc 4.5 complains */
+/* GIF cleared */
+#define hvm_intblk_svm_gif hvm_intblk_arch
+
struct nestedsvm {
+ bool_t ns_gif;
uint64_t ns_msr_hsavepa; /* MSR HSAVE_PA value */
/* Cached real intercepts of the nested guest */
@@ -108,11 +113,23 @@ int nsvm_vmcb_guest_intercepts_exitcode(
struct cpu_user_regs *regs, uint64_t exitcode);
int nsvm_vmcb_guest_intercepts_trap(struct vcpu *v, unsigned int trapnr);
bool_t nsvm_vmcb_hap_enabled(struct vcpu *v);
+enum hvm_intblk nsvm_intr_blocked(struct vcpu *v);
/* MSRs */
int nsvm_rdmsr(struct vcpu *v, unsigned int msr, uint64_t *msr_content);
int nsvm_wrmsr(struct vcpu *v, unsigned int msr, uint64_t msr_content);
+/* Interrupts, vGIF */
+void svm_vmexit_do_clgi(struct cpu_user_regs *regs, struct vcpu *v);
+void svm_vmexit_do_stgi(struct cpu_user_regs *regs, struct vcpu *v);
+bool_t nestedsvm_gif_isset(struct vcpu *v);
+
+#define NSVM_INTR_NOTHANDLED 3
+#define NSVM_INTR_NOTINTERCEPTED 2
+#define NSVM_INTR_FORCEVMEXIT 1
+#define NSVM_INTR_MASKED 0
+int nestedsvm_vcpu_interrupt(struct vcpu *v, const struct hvm_intack intack);
+
#endif /* ASM_X86_HVM_SVM_NESTEDSVM_H__ */
/*
diff -r ca44f5981d17 -r 9d27b197ca34 xen/include/asm-x86/hvm/svm/svm.h
--- a/xen/include/asm-x86/hvm/svm/svm.h
+++ b/xen/include/asm-x86/hvm/svm/svm.h
@@ -61,6 +61,7 @@ static inline void svm_vmsave(void *vmcb
}
unsigned long *svm_msrbit(unsigned long *msr_bitmap, uint32_t msr);
+void __update_guest_eip(struct cpu_user_regs *regs, unsigned int inst_len);
extern u32 svm_feature_flags;
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
next reply other threads:[~2010-12-20 16:11 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-12-20 16:11 Christoph Egger [this message]
-- strict thread matches above, loose matches on Subject: below --
2011-03-09 14:26 [PATCH 10/12] Nested Virtualization: interrupts (svm specific) Christoph Egger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201012201711.37080.Christoph.Egger@amd.com \
--to=christoph.egger@amd.com \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.