Nested Virtualization: hap-on-hap
PATCH 14/14 Nested Virtualization: hap-on-hap
Signature · 6 lines
---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
# HG changeset patch
# User cegger
# Date 1281006359 -7200
Implement Nested-on-Nested.
This allows the guest to run nested guest with hap enabled.
xen/arch/x86/hvm/hvm.c +72 -7
@@ -1042,12 +1042,56 @@ int hvm_inject_exception(unsigned int trreturn 0 ; } -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) + &&nestedhvm_paging_mode_hap (v) ) + { +enum nestedhvm_vmexits nsret; +struct nestedhvm *hvm = &VCPU_NESTEDHVM (v); + +/* 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. */ + hvm->nh_forcevmexit.exitcode =NESTEDHVM_INTERCEPT_NPF ; + hvm->nh_forcevmexit.exitinfo1 = regs->error_code; + hvm->nh_forcevmexit.exitinfo2 = gpa; + hvm->nh_hostflags.fields.forcevmexit =1 ; + nsret =nestedhvm_vcpu_vmexit (v, regs,NESTEDHVM_INTERCEPT_NPF ); + hvm->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);
@@ -1128,6 +1172,15 @@ int hvm_set_efer(uint64_t value)return X86EMUL_EXCEPTION ; } +if (nestedhvm_enabled (v->domain) && + ((value &EFER_SVME ) ==0 ) && + ((value ^ v->arch.hvm_vcpu.guest_efer) &EFER_SVME ) ) + { +/* Cleared EFER.SVME: Flush all nestedp2m tables */ +p2m_flush_nestedp2m (v->domain); +nestedhvm_vcpu_reset (v); + } + value |= v->arch.hvm_vcpu.guest_efer &EFER_LMA ; v->arch.hvm_vcpu.guest_efer = value;hvm_update_guest_efer (v);
@@ -1278,8 +1331,12 @@ int hvm_set_cr0(unsigned long value) v->arch.hvm_vcpu.guest_cr[0 ] = value;hvm_update_guest_cr (v,0 ); -if ( (value ^ old_value) &X86_CR0_PG ) -paging_update_paging_modes (v); +if ( (value ^ old_value) &X86_CR0_PG ) { +if ( !nestedhvm_vmentry_emulate (v) &&nestedhvm_vcpu_in_guestmode (v) ) +paging_update_nestedmode (v); +else +paging_update_paging_modes (v); + }return X86EMUL_OKAY ;
@@ -1346,8 +1403,12 @@ int hvm_set_cr4(unsigned long value)hvm_update_guest_cr (v,4 );/* Modifying CR4.{PSE,PAE,PGE} invalidates all TLB entries, inc. Global. */ -if ( (old_cr ^ value) & (X86_CR4_PSE |X86_CR4_PGE |X86_CR4_PAE ) ) -paging_update_paging_modes (v); +if ( (old_cr ^ value) & (X86_CR4_PSE |X86_CR4_PGE |X86_CR4_PAE ) ) { +if ( !nestedhvm_vmentry_emulate (v) &&nestedhvm_vcpu_in_guestmode (v) ) +paging_update_nestedmode (v); +else +paging_update_paging_modes (v); + }return X86EMUL_OKAY ;
@@ -1831,11 +1892,15 @@ static enum hvm_copy_result __hvm_copy( void *buf, paddr_t addr, int size, unsigned int flags, uint32_t pfec) { struct vcpu *curr = current; -struct p2m_domain *p2m =p2m_get_hostp2m (curr->domain); +struct p2m_domain *p2m;unsigned long gfn, mfn;p2m_type_t p2mt;char *p;int count, todo = size; +unsigned long cr3 = curr->arch.hvm_vcpu.guest_cr[3 ]; +const struct paging_mode *mode =paging_get_mode (curr); + + p2m =p2m_get_p2m (curr);while ( todo >0 ) {
@@ -1843,7 +1908,7 @@ static enum hvm_copy_result __hvm_copy(if ( flags & HVMCOPY_virt ) { - gfn =paging_gva_to_gfn (curr, addr, &pfec); + gfn =paging_p2m_ga_to_gfn (curr, p2m, mode, cr3, addr, &pfec);if ( gfn ==INVALID_GFN ) {if ( pfec == PFEC_page_paged )
xen/arch/x86/hvm/nestedhvm.c +1 -0
@@ -487,6 +487,7 @@ nestedhvm_vcpu_vmexit(struct vcpu *v, stenum hvm_copy_result hvm_rc; hvm->nh_hostflags.fields.vmentry =1 ; +paging_update_nestedmode (v);if (nestedhvm_vcpu_in_guestmode (v)) { ret =nestedhvm_vmexit (v, regs, exitcode);switch (ret) {
xen/arch/x86/hvm/svm/svm.c +16 -7
@@ -1580,6 +1580,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);
@@ -1966,14 +1970,16 @@ struct hvm_function_table * __init startreturn &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) { +int ret;unsigned long gfn = gpa >>PAGE_SHIFT ;mfn_t mfn;p2m_type_t p2mt; -struct p2m_domain *p2m; - - p2m =p2m_get_hostp2m (current->domain); +struct p2m_domain *p2m =NULL ; + + ret =hvm_hap_nested_page_fault (gpa, regs);if ( tb_init_done ) {
@@ -1984,6 +1990,7 @@ static void svm_do_nested_pgfault(paddr_uint32_t p2mt; } _d; + p2m =p2m_get_p2m (v); _d.gpa = gpa; _d.qualification =0 ; _d.mfn =mfn_x (gfn_to_mfn_query (p2m, gfn, &_d.p2mt));
@@ -1991,14 +1998,16 @@ 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 ( ret )return ; +if ( p2m ==NULL ) + p2m =p2m_get_p2m (v);/* 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 )
@@ -2924,7 +2933,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
@@ -2120,7 +2120,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/guest_walk.c +23 -3
@@ -29,6 +29,9 @@#define _hap_gva_to_gfn (levels) hap_gva_to_gfn_##levels##_levels#define hap_gva_to_gfn (levels) _hap_gva_to_gfn(levels) +#define _hap_p2m_ga_to_gfn (levels) hap_p2m_ga_to_gfn_##levels##_levels +#define hap_p2m_ga_to_gfn (levels) _hap_p2m_ga_to_gfn(levels) +#if GUEST_PAGING_LEVELS <=CONFIG_PAGING_LEVELS #include <asm/guest_pt.h>
@@ -38,15 +41,23 @@ unsigned long hap_gva_to_gfn(GUEST_PAGIN struct vcpu *v, unsigned long gva, uint32_t *pfec) { unsigned long cr3; +struct p2m_domain *p2m =p2m_get_hostp2m (v->domain); + + cr3 = v->arch.hvm_vcpu.guest_cr[3 ]; +return hap_p2m_ga_to_gfn (GUEST_PAGING_LEVELS )(v, p2m, cr3, gva, pfec); +} + +unsigned long hap_p2m_ga_to_gfn (GUEST_PAGING_LEVELS )( +struct vcpu *v,struct p2m_domain *p2m,unsigned long cr3, +paddr_t ga,uint32_t *pfec) +{uint32_t missing;mfn_t top_mfn;void *top_map;p2m_type_t p2mt;walk_t gw; -struct p2m_domain *p2m =p2m_get_hostp2m (v->domain);/* Get the top-level table's MFN */ - cr3 = v->arch.hvm_vcpu.guest_cr[3 ]; top_mfn =gfn_to_mfn_unshare (p2m, cr3 >>PAGE_SHIFT , &p2mt,0 );if (p2m_is_paging (p2mt) ) {
@@ -72,7 +83,7 @@ unsigned long hap_gva_to_gfn(GUEST_PAGIN#if GUEST_PAGING_LEVELS ==3 top_map += (cr3 & ~(PAGE_MASK |31 ));#endif - missing =guest_walk_tables (v, p2m, gva, &gw, pfec[0 ], top_mfn, top_map); + missing =guest_walk_tables (v, p2m, ga, &gw, pfec[0 ], top_mfn, top_map);unmap_domain_page (top_map);/* Interpret the answer */
@@ -119,6 +130,15 @@ unsigned long hap_gva_to_gfn(GUEST_PAGIN return INVALID_GFN; } +unsigned long hap_p2m_ga_to_gfn (GUEST_PAGING_LEVELS )( +struct vcpu *v,struct p2m_domain *p2m,unsigned long cr3, +paddr_t ga,uint32_t *pfec) +{ +gdprintk (XENLOG_ERR , +"Guest paging level is greater than host paging level!\n" ); +domain_crash (v->domain); +return INVALID_GFN ; +}#endif
xen/arch/x86/mm/hap/hap.c +72 -6
161 lines not on this page · raw message
xen/arch/x86/mm/hap/nested_hap.c new file +421 -0
421 lines not on this page · raw message
xen/arch/x86/mm/hap/private.h +10 -0
@@ -30,4 +30,14 @@ unsigned long hap_gva_to_gfn_3_levels(stunsigned long hap_gva_to_gfn_4_levels (struct vcpu *v,unsigned long gva,uint32_t *pfec); +unsigned long hap_p2m_ga_to_gfn_2_levels (struct vcpu *v, +struct p2m_domain *p2m,unsigned long cr3, +paddr_t ga,uint32_t *pfec); +unsigned long hap_p2m_ga_to_gfn_3_levels (struct vcpu *v, +struct p2m_domain *p2m,unsigned long cr3, +paddr_t ga,uint32_t *pfec); +unsigned long hap_p2m_ga_to_gfn_4_levels (struct vcpu *v, +struct p2m_domain *p2m,unsigned long cr3, +paddr_t ga,uint32_t *pfec); +#endif /* __HAP_PRIVATE_H__ */
xen/arch/x86/mm/p2m.c +207 -4
283 lines not on this page · raw message
xen/arch/x86/mm/paging.c +37 -5
64 lines not on this page · raw message
xen/include/asm-x86/domain.h +7 -0
@@ -207,6 +207,8 @@ struct paging_domain {struct paging_vcpu {/* Pointers to mode-specific entry points. */ const struct paging_mode *mode; +/* Nested Virtualization: paging mode of nested guest */ +const struct paging_mode *nestedmode;/* HVM guest: last emulate was to a pagetable */ unsigned int last_write_was_pt:1 ;/* HVM guest: last write emulation succeeds */
@@ -222,6 +224,7 @@ struct paging_vcpu {#define MAX_CPUID_INPUT 40typedef xen_domctl_cpuid_t cpuid_input_t ; +#define MAX_NESTEDP2M 10struct p2m_domain ;struct time_scale {int shift;
@@ -255,6 +258,10 @@ struct arch_domainstruct paging_domain paging;struct p2m_domain *p2m; +/* nestedhvm: translate l2 guest physical to host physical */ +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
@@ -371,7 +371,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 +29 -0
@@ -173,6 +173,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;
@@ -229,8 +230,26 @@ 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); + +#define p2m_is_nestedp2m (p2m) ((p2m) != p2m_get_hostp2m((p2m->domain))) +#define p2m_get_pagetable (p2m) ((p2m)->phys_table) +/* Flushes specified p2m table */ +void p2m_flush (struct vcpu *v,struct p2m_domain *p2m); +/* Flushes all nested p2m tables */ +void p2m_flush_nestedp2m (struct domain *d); +/* * The P2M lock. This protects all updates to the p2m table. * Updates are expected to be safe against concurrent reads,
@@ -372,6 +391,9 @@ static inline unsigned long mfn_to_gfn(s/* Init the datastructures for later use by the p2m code */ int p2m_init (struct domain *d); +/* PTE flags for various types of p2m entry */ +unsigned long p2m_type_to_flags (p2m_type_t t); +/* Allocate a new p2m table for a domain. * * The alloc_page and free_page functions will be used to get memory to
@@ -382,6 +404,13 @@ int p2m_alloc_table(struct p2m_domain *pstruct page_info * (*alloc_page)(struct p2m_domain *p2m), void (*free_page)(struct p2m_domain *p2m, struct page_info *pg)); +/* Find the next level's P2M entry, checking for out-of-range gfn's... +* Returns NULL on error. +*/ +l1_pgentry_t * +p2m_find_entry (void *table,unsigned long *gfn_remainder, +unsigned long gfn,uint32_t shift,uint32_t max); +/* Return all the p2m resources to Xen. */ void p2m_teardown (struct p2m_domain *p2m);void p2m_final_teardown (struct domain *d);
xen/include/asm-x86/paging.h +42 -12
127 lines not on this page · raw message
_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
Hi,
This looks a lot nicer than the last version I reviewed. I'm still concerned about TLB and p2m flushes, though.
- I can't see how writes to the 'host' p2m table cause the 'shadow' p2m tables to be flushed. I might just have missed it.
- The p2m_flush operations don't look safe against other vpcus. Mostly they're called with v==current, which looks OK, but what if two vcpus are running on the same p2m? Also when p2m_get_nestedp2m() flushes the domain's LRU p2m, there's no shootdown if that p2m is in use on another pcpu. That could happen if the VM has more vcpus than MAX_NESTEDP2M. (Actually, that case is probably pretty broken generally.)
Cheers,
Tim.
Signature · 3 lines
Tim Deegan <[email protected]> Principal Software Engineer, XenServer Engineering Citrix Systems UK Ltd. (Company #02937203, SL9 0BG)
Quoted 7 lines · On Monday 09 August 2010 15:18:22 Tim Deegan wrote:
Hi,
This looks a lot nicer than the last version I reviewed. I'm still concerned about TLB and p2m flushes, though.
- I can't see how writes to the 'host' p2m table cause the 'shadow' p2m tables to be flushed. I might just have missed it.
The 'shadow' p2m is flushed when
- the l1 guest runs an instruction like INVLPGA (e.g. Windows 7 does so)
- the l1 guest sets up a VMCB where
* the tlb_control is set
* the asid changed
* the nested cr3 changed (and there is no free nestedp2m slot)
Quoted 7 lines
- The
p2m_flushoperations don't look safe against other vpcus. Mostly they're called with v==current, which looks OK, but what if two vcpus are running on the same p2m? Also whenp2m_get_nestedp2m()flushes the domain's LRU p2m, there's no shootdown if that p2m is in use on another pcpu. That could happen if the VM has more vcpus thanMAX_NESTEDP2M. (Actually, that case is probably pretty broken generally.)
Yes, this is indeed an issue that needs to be fixed. How do I do a TLB shootdown across physical cpus which schedule
vcpus bound to the l1 guest ?
The physical cpu must leave the l1/l2 guest on the tlb shootdown. An optimization is to limit the tlb shootdown to those physical cpus where "their" vcpus are in guestmode if this is possible to implement.
Christoph
Signature · 6 lines
---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
Quoted 10 lines · Christoph Egger
Quoted 2 lines · On Monday 09 August 2010 15:18:22 Tim Deegan wrote:
- I can't see how writes to the 'host' p2m table cause the 'shadow' p2m tables to be flushed. I might just have missed it.
The 'shadow' p2m is flushed when
- the l1 guest runs an instruction like INVLPGA (e.g. Windows 7 does so)
- the l1 guest sets up a VMCB where
* thetlb_controlis set
* the asid changed
* the nested cr3 changed (and there is no free nestedp2m slot)
OK, so the case I'm worried about is: if the L1's p2m is changed (by ballooning, or the mem-event code, or by a page being marked as broken) then the shadow p2ms need to be updated or discarded because they might contain mappings made before the change.
The equivalent problem exists in the normal shadow pagetables, which is why the p2m code has to use a callback (shadow_write_p2m_entry()) to write its entries. The shadow code writes the entry and removes all offending shadow PTEs at the same time. You'll need something equivalent here for safety.
BTW, it won't be enough to just declare that these are unsupported combinations - if a nested-mode guest can give up a page of memory that its l2 guest still has mappings of then it breaks the basic memory safety of Xen.
Quoted 11 lines
Quoted 7 lines
- The
p2m_flushoperations don't look safe against other vpcus. Mostly they're called with v==current, which looks OK, but what if two vcpus are running on the same p2m? Also whenp2m_get_nestedp2m()flushes the domain's LRU p2m, there's no shootdown if that p2m is in use on another pcpu. That could happen if the VM has more vcpus thanMAX_NESTEDP2M. (Actually, that case is probably pretty broken generally.)Yes, this is indeed an issue that needs to be fixed. How do I do a TLB shootdown across physical cpus which schedule vcpus bound to the l1 guest ?
You can call on_selected_cpus() with the vcpu's v->vcpu_dirty_cpumask (remembering to take smp_processor_id() out of the mask first). If all you need is a TLB shootdown you can call flush_tlb_mask(). That will cause a VMEXIT on the target CPUs so if you make it so that they can't VMENTER again with the old p2m settings that might be all you need.
Quoted 3 lines
The physical cpu must leave the l1/l2 guest on the tlb shootdown. An optimization is to limit the tlb shootdown to those physical cpus where "their" vcpus are in guestmode if this is possible to implement.
You'd have to add another cpumask to express that, but that's doable.
Cheers,
Tim.
Signature · 3 lines
Tim Deegan <[email protected]> Principal Software Engineer, XenServer Engineering Citrix Systems UK Ltd. (Company #02937203, SL9 0BG)
Quoted 23 lines · On Thursday 19 August 2010 18:33:16 Tim Deegan wrote:
Quoted 10 lines · Christoph Egger
Quoted 2 lines · On Monday 09 August 2010 15:18:22 Tim Deegan wrote:
- I can't see how writes to the 'host' p2m table cause the 'shadow' p2m tables to be flushed. I might just have missed it.
The 'shadow' p2m is flushed when
- the l1 guest runs an instruction like INVLPGA (e.g. Windows 7 does so)
- the l1 guest sets up a VMCB where
* thetlb_controlis set
* the asid changed
* the nested cr3 changed (and there is no free nestedp2m slot)OK, so the case I'm worried about is: if the L1's p2m is changed (by ballooning, or the mem-event code, or by a page being marked as broken) then the shadow p2ms need to be updated or discarded because they might contain mappings made before the change.
The equivalent problem exists in the normal shadow pagetables, which is why the p2m code has to use a callback (
shadow_write_p2m_entry()) to write its entries. The shadow code writes the entry and removes all offending shadow PTEs at the same time. You'll need something equivalent here for safety.
Quoted 4 lines
BTW, it won't be enough to just declare that these are unsupported combinations - if a nested-mode guest can give up a page of memory that its l2 guest still has mappings of then it breaks the basic memory safety of Xen.
I see.
Quoted 19 lines
Quoted 11 lines
Quoted 7 lines
- The
p2m_flushoperations don't look safe against other vpcus. Mostly they're called with v==current, which looks OK, but what if two vcpus are running on the same p2m? Also whenp2m_get_nestedp2m()flushes the domain's LRU p2m, there's no shootdown if that p2m is in use on another pcpu. That could happen if the VM has more vcpus thanMAX_NESTEDP2M. (Actually, that case is probably pretty broken generally.)Yes, this is indeed an issue that needs to be fixed. How do I do a TLB shootdown across physical cpus which schedule vcpus bound to the l1 guest ?
You can call
on_selected_cpus()with the vcpu'sv->vcpu_dirty_cpumask(remembering to takesmp_processor_id()out of the mask first). If all you need is a TLB shootdown you can callflush_tlb_mask(). That will cause a VMEXIT on the target CPUs so if you make it so that they can't VMENTER again with the old p2m settings that might be all you need.
Quoted 5 lines
Quoted 3 lines
The physical cpu must leave the l1/l2 guest on the tlb shootdown. An optimization is to limit the tlb shootdown to those physical cpus where "their" vcpus are in guestmode if this is possible to implement.
You'd have to add another cpumask to express that, but that's doable.
Thanks. I implemented the tlb shootdown per p2m and do it on those physical cpus whose vcpus are in guestmode.
I have implemented and fixed all feedback I got so far, except for the "flush nestedp2m on hostp2m write" we talked above. It is on my todo list.
I will send the fourth patch series for feedback, the "flush nestedp2m on hostp2m write" will be part of the over next patch series.
Christoph
Signature · 6 lines
---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