[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 03/11] nEPT: Implement guest ept's walker
At 01:57 +0800 on 11 Dec (1355191035), xiantao.zhang@xxxxxxxxx wrote: > From: Zhang Xiantao <xiantao.zhang@xxxxxxxxx> > > Implment guest EPT PT walker, some logic is based on shadow's > ia32e PT walker. During the PT walking, if the target pages are > not in memory, use RETRY mechanism and get a chance to let the > target page back. > > Signed-off-by: Zhang Xiantao <xiantao.zhang@xxxxxxxxx> The design looks pretty good. A few comments below on code details -- I think the only big one is that the ept walker shouldn't force eptes into 'normal' pte types just so it can reuse the walk_t struct. > @@ -88,10 +88,11 @@ static uint32_t set_ad_bits(void *guest_p, void *walk_p, > int set_dirty) > > /* If the map is non-NULL, we leave this function having > * acquired an extra ref on mfn_to_page(*mfn) */ > -static inline void *map_domain_gfn(struct p2m_domain *p2m, > +void *map_domain_gfn(struct p2m_domain *p2m, > gfn_t gfn, > mfn_t *mfn, > p2m_type_t *p2mt, > + p2m_query_t *q, I think this should just be a plain p2m_query_t and not a pointer to one; the code below only dereferences the pointer to read it. That will save you having a variable just to hold 'P2M_ALLOC | P2M_UNSHARE' in a few places below. > --- /dev/null > +++ b/xen/arch/x86/mm/hap/nested_ept.c > +/* For EPT's walker reserved bits and EMT check */ > +#define EPT_MUST_RSV_BITS (((1ull << PADDR_BITS) -1) & \ > + ~((1ull << paddr_bits) - 1)) > + > + > +#define EPT_EMT_WB 6 > +#define EPT_EMT_UC 0 These two definitions should be in vmx.h along with the other architectural constants for EPTEs. > + > +#define NEPT_VPID_CAP_BITS 0 > + > +#define NEPT_1G_ENTRY_FLAG (1 << 11) > +#define NEPT_2M_ENTRY_FLAG (1 << 10) > +#define NEPT_4K_ENTRY_FLAG (1 << 9) > + > +/* Always expose 1G and 2M capability to guest, > + so don't need additional check */ > +bool_t nept_sp_entry(uint64_t entry) > +{ > + return !!(entry & EPTE_SUPER_PAGE_MASK); > +} > + > +static bool_t nept_rsv_bits_check(uint64_t entry, uint32_t level) > +{ > + uint64_t rsv_bits = EPT_MUST_RSV_BITS; > + > + switch ( level ){ > + case 1: > + break; > + case 2 ... 3: > + if (nept_sp_entry(entry)) > + rsv_bits |= ((1ull << (9 * (level -1 ))) -1) << PAGE_SHIFT; > + else > + rsv_bits |= 0xfull << 3; Please use EPTE_EMT_MASK rather than open-coding it. > + break; > + case 4: > + rsv_bits |= 0xf8; Again, please use EPTE_EMT_MASK | EPTE_IGMT_MASK | EPTE_SUPER_PAGE_MASK. > + break; > + default: > + printk("Unsupported EPT paging level: %d\n", level); > + } > + if ( ((entry & rsv_bits) ^ rsv_bits) == rsv_bits ) > + return 0; This XOR is useful in the normal walker because we care about _which_ bits are wrong. Here, you can just return !(entry & rsv_bits) for the same result. > + return 1; > +} > + > +/* EMT checking*/ > +static bool_t nept_emt_bits_check(uint64_t entry, uint32_t level) > +{ > + ept_entry_t e; > + e.epte = entry; > + if ( e.sp || level == 1 ) { > + if ( e.emt == 2 || e.emt == 3 || e.emt == 7 ) > + return 1; Please define more of the EPT_EMT_* constants for these values and use them. > + } > + return 0; > +} > + > +static bool_t nept_rwx_bits_check(uint64_t entry) { > + /*write only or write/execute only*/ > + uint8_t rwx_bits = entry & 0x7; > + > + if ( rwx_bits == 2 || rwx_bits == 6) > + return 1; > + if ( rwx_bits == 4 && !(NEPT_VPID_CAP_BITS & > + VMX_EPT_EXEC_ONLY_SUPPORTED)) Please pass the entry as an ept_entry_t and check the named r, w and x fields rather than using magic numbers. > + return 1; > + return 0; > +} > + > +/* nept's misconfiguration check */ > +static bool_t nept_misconfiguration_check(uint64_t entry, uint32_t level) > +{ > + return (nept_rsv_bits_check(entry, level) || > + nept_emt_bits_check(entry, level) || > + nept_rwx_bits_check(entry)); > +} > + > +static bool_t nept_present_check(uint64_t entry) > +{ > + if (entry & 0x7) Again, please pass an ept_entry_t and check the r/w/x fields. > + return 1; > + return 0; > +} > + > +uint64_t nept_get_ept_vpid_cap(void) > +{ > + /*TODO: exposed ept and vpid features*/ This TODO comment doesn't get removed later in the series. Is returning 0 here always OK? > + return NEPT_VPID_CAP_BITS; > +} > + > +static uint32_t > +nept_walk_tables(struct vcpu *v, unsigned long l2ga, walk_t *gw) > +{ > + p2m_type_t p2mt; > + uint32_t rc = 0, ret = 0, gflags; > + struct domain *d = v->domain; > + struct p2m_domain *p2m = d->arch.p2m; > + gfn_t base_gfn = _gfn(nhvm_vcpu_p2m_base(v) >> PAGE_SHIFT); > + p2m_query_t qt = P2M_ALLOC; > + > + guest_l1e_t *l1p = NULL; > + guest_l2e_t *l2p = NULL; > + guest_l3e_t *l3p = NULL; > + guest_l4e_t *l4p = NULL; These aren't realy guest_l*es, so I think you should use ept_entry_t * to point to them. While you're at it, why not define an equivalent ept_walk_t struct that uses the ept-specific types instead of putting EPT entries in a normal walk_t? Also, unlike the normal guest walker, you don't need to hold these maps open for writing A/D bits, so you could just use a single pointer and unmap as you go. > + sp = nept_sp_entry(gw->l3e.l3); > + /* Super 1G entry */ > + if ( sp ) > + { > + /* Generate a fake l1 table entry so callers don't all > + * have to understand superpages. */ You only have one caller for this function, and it does understand superpages -- it explicitly check for them. So I think you can avoid this part altogether (likewise for 2M superpages) and just DTRT in the caller. Cheers, Tim. > + gfn_t start = guest_l3e_get_gfn(gw->l3e); > + > + /* Increment the pfn by the right number of 4k pages. */ > + start = _gfn((gfn_x(start) & ~GUEST_L3_GFN_MASK) + > + ((l2ga >> PAGE_SHIFT) & GUEST_L3_GFN_MASK)); > + gflags = (gw->l3e.l3 & 0x7f) | NEPT_1G_ENTRY_FLAG; > + gw->l1e = guest_l1e_from_gfn(start, gflags); > + gw->l2mfn = gw->l1mfn = _mfn(INVALID_MFN); > + goto done; > + } > + _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |