Nested Virtualization: hap-on-hap
PATCH 18/18 Nested Virtualization: hap-on-hap
Signature · 6 lines
---to satisfy European Law for business letters: Advanced Micro Devices GmbH Karl-Hammerschmidt-Str. 34, 85609 Dornach b. Muenchen Geschaeftsfuehrer: Andrew Bowd, Thomas M. McCoy, Giuliano Meroni Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
# HG changeset patch
# User cegger
# Date 1271330316 -7200
Implemented Nested-on-Nested.
This allows the guest to run nested guest with hap.
xen/arch/x86/hvm/hvm.c +40 -1
@@ -955,12 +955,51 @@ void hvm_triple_fault(void)domain_shutdown (v->domain, SHUTDOWN_reboot); } -bool_t hvm_hap_nested_page_fault (unsigned long gfn) +bool_t hvm_hap_nested_page_fault (paddr_t gpa,struct cpu_user_regs *regs) {p2m_type_t p2mt;mfn_t mfn;struct vcpu *v = current;struct p2m_domain *p2m =p2m_get_hostp2m (v->domain); +unsigned long gfn = gpa >>PAGE_SHIFT ; +int rv; + +/* On Nested Virtualization, walk the guest page table. +* If this succeeds, all is fine. +* If this fails, inject a nested page fault into the guest. +*/ +if (nestedhvm_enabled (v->domain) &&nestedhvm_vcpu_in_guestmode (v) ) + { +enum nestedhvm_vmexits nsret; + +/* nested guest gpa == guest gva */ + rv =nestedhvm_hap_nested_page_fault (v, gpa); +switch (rv) { +case NESTEDHVM_PAGEFAULT_DONE : +return 1 ; +case NESTEDHVM_PAGEFAULT_ERROR : +return 0 ; +case NESTEDHVM_PAGEFAULT_INJECT : +break ; + } + +/* inject #VMEXIT(NPF) into guest. */ +VCPU_NESTEDHVM (v).nh_forcevmexit_exitcode =VMEXIT_NPF ; +VCPU_NESTEDHVM (v).nh_hostflags.fields.forcevmexit =1 ; + nsret =nestedhvm_vcpu_vmexit (v, regs,VMEXIT_NPF ); +VCPU_NESTEDHVM (v).nh_hostflags.fields.forcevmexit =0 ; +switch (nsret) { +case NESTEDHVM_VMEXIT_DONE : +case NESTEDHVM_VMEXIT_ERROR :/* L1 guest will crash L2 guest */ +return 1 ; +case NESTEDHVM_VMEXIT_HOST : +case NESTEDHVM_VMEXIT_CONTINUE : +case NESTEDHVM_VMEXIT_FATALERROR : +default : +gdprintk (XENLOG_ERR ,"unexpected nestedhvm error %i\n" , nsret); +return 0 ; + } + } mfn =gfn_to_mfn_guest (p2m, gfn, &p2mt);
xen/arch/x86/hvm/svm/svm.c +16 -5
@@ -892,6 +892,12 @@ static int nsvm_vcpu_features(struct vcp *edx =0 ; +/* We require the host to use nested paging as +* nested-on-shadow is not supported. +*/ +if ( cpu_has_svm_npt &&paging_mode_hap (v->domain) ) + *edx |= (1U <<SVM_FEATURE_NPT ); +if ( cpu_has_svm_lbrv ) *edx |= (1U <<SVM_FEATURE_LBRV );#if 0 /* not yet implemented */
@@ -1222,6 +1228,10 @@ static int nsvm_vmcb_prepare4vmrun(struc/* Nested paging mode */ if (nestedhvm_paging_mode_hap (v)) {/* host nested paging + guest nested paging. */ + host_vmcb->np_enable =1 ; + + host_vmcb->h_cr3 = +pagetable_get_paddr (p2m_get_pagetable (p2m_get_nestedp2m (v, ns_vmcb->h_cr3)));/* hvm_set_cr3() below sets v->arch.hvm_vcpu.guest_cr[3] for us. */ rc =hvm_set_cr3 (ns_vmcb->cr3);
@@ -1531,14 +1541,15 @@ void start_svm(struct cpuinfo_x86 *c)hvm_enable (&svm_function_table); } -static void svm_do_nested_pgfault (paddr_t gpa) +static void svm_do_nested_pgfault (struct vcpu *v, +struct cpu_user_regs *regs,paddr_t gpa) {unsigned long gfn = gpa >>PAGE_SHIFT ;mfn_t mfn;p2m_type_t p2mt;struct p2m_domain *p2m; - p2m =p2m_get_hostp2m (current->domain); + p2m =p2m_get_p2m (v,VCPU_NESTEDHVM (v).nh_vmcb_hcr3);if ( tb_init_done ) {
@@ -1556,14 +1567,14 @@ static void svm_do_nested_pgfault(paddr___trace_var (TRC_HVM_NPF ,0 ,sizeof (_d), (unsigned char *)&_d); } -if (hvm_hap_nested_page_fault (gfn) ) +if (hvm_hap_nested_page_fault (gpa, regs) )return ;/* Everything else is an error. */ mfn =gfn_to_mfn_guest (p2m, gfn, &p2mt);gdprintk (XENLOG_ERR ,"SVM violation gpa %#" PRIpaddr", mfn %#lx, type %i\n" , gpa,mfn_x (mfn), p2mt); -domain_crash (current->domain); +domain_crash (v->domain); }static void svm_fpu_dirty_intercept (void )
@@ -2354,7 +2365,7 @@ asmlinkage void svm_vmexit_handler(struccase VMEXIT_NPF :perfc_incra (svmexits,VMEXIT_NPF_PERFC ); regs->error_code = vmcb->exitinfo1; -svm_do_nested_pgfault (vmcb->exitinfo2); +svm_do_nested_pgfault (v, regs, vmcb->exitinfo2);break ;case VMEXIT_IRET :
xen/arch/x86/hvm/vmx/vmx.c +1 -1
@@ -2145,7 +2145,7 @@ static void ept_handle_violation(unsigne }if ( (qualification &EPT_GLA_VALID ) && -hvm_hap_nested_page_fault (gfn) ) +hvm_hap_nested_page_fault (gpa,guest_cpu_user_regs ()) )return ;/* Everything else is an error. */
xen/arch/x86/mm/hap/Makefile +1 -0
@@ -3,6 +3,7 @@ obj-y += guest_walk_2level.o obj-y += guest_walk_3level.o obj-y += guest_walk_4level.o obj-y += p2m-ept.o +obj-y += nested_hap.o guest_levels = $(subst level,,$(filter %level,$(subst ., ,$(subst _, ,$(1))))) guest_walk_defns = -DGUEST_PAGING_LEVELS=$(call guest_levels,$(1))
xen/arch/x86/mm/hap/nested_hap.c new file +469 -0
469 lines not on this page · raw message
xen/arch/x86/mm/p2m.c +151 -0
192 lines not on this page · raw message
xen/include/asm-x86/domain.h +5 -0
@@ -213,6 +213,7 @@ struct paging_vcpu {#define MAX_CPUID_INPUT 40typedef xen_domctl_cpuid_t cpuid_input_t ; +#define MAX_NESTEDP2M 10struct p2m_domain ;/* Define for GUEST MCA handling */
@@ -272,6 +273,10 @@ struct arch_domainstruct paging_domain paging;struct p2m_domain *p2m; +/* NestedSVM: phys_table + guest phys_table */ +struct p2m_domain *nested_p2m[MAX_NESTEDP2M ]; +spinlock_t nested_p2m_lock; +/* NB. protected by d->event_lock and by irq_desc[irq].lock */ int *irq_pirq;int *pirq_irq;
xen/include/asm-x86/hvm/hvm.h +1 -1
@@ -358,7 +358,7 @@ static inline void hvm_set_info_guest(stint hvm_debug_op (struct vcpu *v,int32_t op); -bool_t hvm_hap_nested_page_fault (unsigned long gfn); +bool_t hvm_hap_nested_page_fault (paddr_t gpa,struct cpu_user_regs *regs);#define hvm_msr_tsc_aux (v) ({ \ struct domain *__d = (v)->domain; \
xen/include/asm-x86/p2m.h +12 -0
@@ -171,6 +171,7 @@ struct p2m_domain {pagetable_t phys_table;struct domain *domain;/* back pointer to domain */ +uint64_t cr3;/* to identify this p2m for re-use */ /* Pages used to construct the p2m */ struct page_list_head pages;
@@ -223,6 +224,17 @@ struct p2m_domain {/* get host p2m table */ #define p2m_get_hostp2m (d) ((d)->arch.p2m) +/* Get p2m table (re)usable for specified cr3. +* Automatically destroys and re-initializes a p2m if none found. +* If cr3 == 0 then v->arch.hvm_vcpu.guest_cr[3] is used. +*/ +struct p2m_domain *p2m_get_nestedp2m (struct vcpu *v,uint64_t cr3); + +/* If vcpu is in host mode then behaviour matches p2m_get_hostp2m(). +* If vcpu is in guest mode then behaviour matches p2m_get_nestedp2m(). +*/ +struct p2m_domain *p2m_get_p2m (struct vcpu *v,uint64_t cr3); +#define p2m_get_pagetable (p2m) ((p2m)->phys_table)/*
xen/include/asm-x86/paging.h +17 -0
@@ -109,6 +109,10 @@ struct paging_mode {int (*invlpg )(struct vcpu *v,unsigned long va);unsigned long (*gva_to_gfn )(struct vcpu *v,unsigned long va,uint32_t *pfec); +unsigned long (*p2m_gva_to_gfn )(struct vcpu *v, +struct p2m_domain *p2m, +unsigned long cr3, +paddr_t gva,uint32_t *pfec);void (*update_cr3 )(struct vcpu *v,int do_locking);void (*update_paging_modes )(struct vcpu *v); void (*write_p2m_entry )(struct vcpu *v, unsigned long gfn,
@@ -257,6 +261,19 @@ static inline unsigned long paging_gva_treturn v->arch.paging.mode->gva_to_gfn (v, va, pfec); } +/* With nested virtualization gva == nested gpa, hence we use paddr_t +* to not overflow. */ +static inline unsigned long paging_p2m_gva_to_gfn (struct vcpu *v, +struct p2m_domain *p2m, +unsigned long cr3, +paddr_t gva, +uint32_t *pfec) +{ +if (is_hvm_domain (v->domain) &&paging_mode_hap (v->domain) ) +return v->arch.paging.mode->p2m_gva_to_gfn (v, p2m, cr3, gva, pfec); +return INVALID_GFN ; +} +/* Update all the things that are derived from the guest's CR3. * Called when the guest changes CR3; the caller can then use v->arch.cr3 * as the value to load into the host CR3 to schedule this vcpu */
_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
A message that is not in the archive (sent off-list or not yet received): [email protected]
Hi,
I'll start by saying that the overall design seems like a good one:
keeping a selection of shadow p2m tables around that follow guest_p2m(host_p2m(l2gpa)), and updating them on demand. I think it's good to start with a simple system like this one, though we might find that nested Xen performs poorly because of its tendency to discard ASIDs on every vcpu context switch.
On the down side, the terminology is quite confusing. There are a few places where it's not clear what kind of cr3 value is meant, and I couldn't understand this patch at all until I saw this comment:
Quoted 2 lines
+/* With nested virtualization gva == nested gpa, hence we use
paddr_t
+ * to not overflow. */
This is not right - the nested GPA is not a virtual address. It's yet another fictional physical address. Can you please find some better name for it? At the moment you have functions called p2m_gva_to_gfn that don't take a GVA and don't return a GFN.
Anyway, backing away from the detail of the code, I have some more general design questions:
- How does memory management work in general for the nested p2ms?
- What happens if we run out of memory?
- What's the performance difference between shadow-on-HAP and HAP-on-HAP?
- What's the difference if the nested hypervisor runs more than MAX_NESTEDP2M VMs?
- How was the figure for MAX_NESTEDP2M arrived at?
- What happens when the host changes the p2m table of the L1 guest? Don't we need some sort of global flush of all the nested p2ms to maintain isolation? Or is it implicitly handled by existing TLB shootdowns?
- You seem to have duplicated a lot of the existing p2m-building code (type_to_flags, write_p2m_entry, next_level, &c). Why is that? I thought the whole point of patches 4, 6 and 17 was so that the nested p2ms could be handled with the same mechanism as normal p2ms?
Cheers,
Tim.
Signature · 3 lines
Tim Deegan <[email protected]> Principal Software Engineer, XenServer Engineering Citrix Systems UK Ltd. (Company #02937203, SL9 0BG)
Quoted 1 line
On the down side, the terminology is quite confusing...
/me votes for meta-virtual to indicate a VM running in a nest. And meta-physical address to refer to a guest physical address in a meta-virtual VM.
Quoted 67 lines
-----Original Message-----
From: Tim Deegan [mailto:[email protected]]
Sent: Friday, April 16, 2010 10:10 AM
To: Christoph Egger
Cc: [email protected]
Subject: Re: [Xen-devel] [PATCH 18/18] Nested Virtualization: hap-on- hapHi,
I'll start by saying that the overall design seems like a good one:
keeping a selection of shadow p2m tables around that follow guest_p2m(host_p2m(l2gpa)), and updating them on demand. I think it's good to start with a simple system like this one, though we might find that nested Xen performs poorly because of its tendency to discard ASIDs
on every vcpu context switch.On the down side, the terminology is quite confusing. There are a few places where it's not clear what kind of cr3 value is meant, and I couldn't understand this patch at all until I saw this comment:
Quoted 1 line
+/* With nested virtualization gva == nested gpa, hence we use
paddr_tQuoted 1 line
+ * to not overflow. */
This is not right - the nested GPA is not a virtual address. It's yet another fictional physical address. Can you please find some better name for it? At the moment you have functions called
p2m_gva_to_gfnthat don't take a GVA and don't return a GFN.Anyway, backing away from the detail of the code, I have some more general design questions:
- How does memory management work in general for the nested p2ms?
- What happens if we run out of memory?- What's the performance difference between shadow-on-HAP and HAP-on- HAP?
- What's the difference if the nested hypervisor runs more thanMAX_NESTEDP2MVMs?
- How was the figure forMAX_NESTEDP2Marrived at?- What happens when the host changes the p2m table of the L1 guest? Don't we need some sort of global flush of all the nested p2ms to maintain isolation? Or is it implicitly handled by existing TLB shootdowns?
- You seem to have duplicated a lot of the existing p2m-building code (
type_to_flags,write_p2m_entry,next_level, &c). Why is that? I thought the whole point of patches 4, 6 and 17 was so that the nested p2ms could be handled with the same mechanism as normal p2ms?Cheers,
Tim.
--
Tim Deegan <[email protected]>
Principal Software Engineer, XenServer Engineering Citrix Systems UK Ltd. (Company #02937203, SL9 0BG)_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel