Hi Julien,
On 09/12/2016 02:08 PM, Julien Grall wrote: > Hi Sergej, > > On 16/08/16 23:17, Sergej Proskurin wrote: >> The HVMOP_altp2m_set_mem_access allows to set gfn permissions of >> (currently one page at a time) of a specific altp2m view. In case the >> view does not hold the requested gfn entry, it will be first copied from >> the host's p2m table and then modified as requested. >> >> Signed-off-by: Sergej Proskurin <prosku...@sec.in.tum.de> >> --- >> Cc: Stefano Stabellini <sstabell...@kernel.org> >> Cc: Julien Grall <julien.gr...@arm.com> >> --- >> v2: Prevent the page reference count from being falsely updated on >> altp2m modification. Therefore, we add a check determining whether >> the target p2m is a hostp2m before p2m_put_l3_page is called. >> >> v3: Cosmetic fixes. >> >> Added the functionality to set/get the default_access also in/from >> the requested altp2m view. >> >> Read-locked hp2m in "altp2m_set_mem_access". >> >> Moved the functions "p2m_is_(hostp2m|altp2m)" out of this commit. >> >> Moved the funtion "modify_altp2m_entry" out of this commit. >> >> Moved the function "p2m_lookup_attr" out of this commit. >> >> Moved guards for "p2m_put_l3_page" out of this commit. >> --- >> xen/arch/arm/altp2m.c | 53 ++++++++++++++++++++++++++++ >> xen/arch/arm/hvm.c | 7 +++- >> xen/arch/arm/p2m.c | 82 >> ++++++++++++++++++++++++++++++++------------ >> xen/include/asm-arm/altp2m.h | 12 +++++++ >> 4 files changed, 131 insertions(+), 23 deletions(-) >> >> diff --git a/xen/arch/arm/altp2m.c b/xen/arch/arm/altp2m.c >> index ba345b9..03b8ce5 100644 >> --- a/xen/arch/arm/altp2m.c >> +++ b/xen/arch/arm/altp2m.c >> @@ -80,6 +80,59 @@ int altp2m_switch_domain_altp2m_by_id(struct >> domain *d, unsigned int idx) >> return rc; >> } >> >> +int altp2m_set_mem_access(struct domain *d, >> + struct p2m_domain *hp2m, >> + struct p2m_domain *ap2m, >> + p2m_access_t a, >> + gfn_t gfn) >> +{ >> + p2m_type_t p2mt; >> + p2m_access_t old_a; >> + mfn_t mfn; >> + unsigned int page_order; >> + int rc; >> + >> + altp2m_lock(d); > > Why do you have this lock? This will serialize all the mem access > modification even if the ap2m is different. > > I am also surprised that you only lock the altp2m in > modify_altp2m_entry. IHMO, the change in the same a2pm should be > serialized. > You are correct, the implementation in the upcoming patch write-locks the altp2m view and hence also removes the need for the locking the altp2m_lock. Thank you. >> + p2m_read_lock(hp2m); >> + >> + /* Check if entry is part of the altp2m view. */ >> + mfn = p2m_lookup_attr(ap2m, gfn, &p2mt, NULL, &page_order); >> + >> + /* Check host p2m if no valid entry in ap2m. */ >> + if ( mfn_eq(mfn, INVALID_MFN) ) >> + { >> + /* Check if entry is part of the host p2m view. */ >> + mfn = p2m_lookup_attr(hp2m, gfn, &p2mt, &old_a, &page_order); > > As mentioned in patch #27, p2m_lookup_attr will take a read reference > on the hp2m lock. However you already did it above. > > Anyway, I really think that p2m_lookup_attr should not exist and ever > caller be replaced by a direct call to p2m_get_entry. > Sounds good. I thought you did not want have the functions p2m_(set|get)_entry exported, which is the reason for the wrappers. I have already removed these wrappers in the upcoming patch. Thank you. > >> + if ( mfn_eq(mfn, INVALID_MFN) || >> + ((p2mt != p2m_ram_rw) && (p2mt != p2m_ram_ro)) ) > > Please use p2m_is_ram rather than open-coding the check on p2mt. > > However, I don't understand why access restriction on altp2m is > limited to RAM whilst the hostp2m allows restriction on any type of page. > I agree: It makes sense to allow setting memory permissions without such restrictions. It it seems to be a remnant of the old implementation, in which invalid mfn's were not guaranteed to be marked as INVALID_MFN. Anyway, I will remove this check. Thank you. >> + { >> + rc = -ESRCH; >> + goto out; >> + } >> + >> + /* If this is a superpage, copy that first. */ >> + if ( page_order != THIRD_ORDER ) >> + { >> + rc = modify_altp2m_entry(ap2m, gfn, mfn, p2mt, old_a, >> page_order); >> + if ( rc < 0 ) >> + { >> + rc = -ESRCH; >> + goto out; >> + } >> + } >> + } >> + >> + /* Set mem access attributes - currently supporting only one >> (4K) page. */ >> + page_order = THIRD_ORDER; > > This looks pointless, please use THIRD_ORDER directly as argument. > >> + rc = modify_altp2m_entry(ap2m, gfn, mfn, p2mt, a, page_order); >> + >> +out: >> + p2m_read_unlock(hp2m); >> + altp2m_unlock(d); >> + >> + return rc; >> +} >> + >> static void altp2m_vcpu_reset(struct vcpu *v) >> { >> struct altp2mvcpu *av = &altp2m_vcpu(v); >> diff --git a/xen/arch/arm/hvm.c b/xen/arch/arm/hvm.c >> index 9ac3422..df78893 100644 >> --- a/xen/arch/arm/hvm.c >> +++ b/xen/arch/arm/hvm.c >> @@ -136,7 +136,12 @@ static int >> do_altp2m_op(XEN_GUEST_HANDLE_PARAM(void) arg) >> break; >> >> case HVMOP_altp2m_set_mem_access: >> - rc = -EOPNOTSUPP; >> + if ( a.u.set_mem_access.pad ) >> + rc = -EINVAL; >> + else >> + rc = p2m_set_mem_access(d, _gfn(a.u.set_mem_access.gfn), >> 1, 0, 0, >> + a.u.set_mem_access.hvmmem_access, >> + a.u.set_mem_access.view); >> break; >> >> case HVMOP_altp2m_change_gfn: >> diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c >> index df2b85b..8dee02187 100644 >> --- a/xen/arch/arm/p2m.c >> +++ b/xen/arch/arm/p2m.c >> @@ -1913,7 +1913,7 @@ long p2m_set_mem_access(struct domain *d, gfn_t >> gfn, uint32_t nr, >> uint32_t start, uint32_t mask, >> xenmem_access_t access, >> unsigned int altp2m_idx) >> { >> - struct p2m_domain *p2m = p2m_get_hostp2m(d); >> + struct p2m_domain *hp2m = p2m_get_hostp2m(d), *ap2m = NULL; >> p2m_access_t a; >> unsigned int order; >> long rc = 0; >> @@ -1933,13 +1933,26 @@ long p2m_set_mem_access(struct domain *d, >> gfn_t gfn, uint32_t nr, >> #undef ACCESS >> }; >> >> + /* altp2m view 0 is treated as the hostp2m */ >> + if ( altp2m_idx ) >> + { >> + if ( altp2m_idx >= MAX_ALTP2M || >> + d->arch.altp2m_p2m[altp2m_idx] == NULL ) >> + return -EINVAL; >> + >> + ap2m = d->arch.altp2m_p2m[altp2m_idx]; >> + } >> + >> switch ( access ) >> { >> case 0 ... ARRAY_SIZE(memaccess) - 1: >> a = memaccess[access]; >> break; >> case XENMEM_access_default: >> - a = p2m->default_access; >> + if ( ap2m ) >> + a = ap2m->default_access; >> + else >> + a = hp2m->default_access; > > On the previous version, I requested to have this change documented in > the code [1]. I don't see it here. > You have requested to explain, why the default_access is set on the hostp2m and not the altp2m. With this patch, we changed this behavior and allow to set the default_access of both the hostp2m and altp2m. Not sure what kind of explanation you expect at this point. >> break; >> default: >> return -EINVAL; >> @@ -1949,39 +1962,66 @@ long p2m_set_mem_access(struct domain *d, >> gfn_t gfn, uint32_t nr, >> * Flip mem_access_enabled to true when a permission is set, as >> to prevent >> * allocating or inserting super-pages. >> */ >> - p2m->mem_access_enabled = true; >> + if ( ap2m ) >> + ap2m->mem_access_enabled = true; >> + else >> + hp2m->mem_access_enabled = true; >> >> /* If request to set default access. */ >> if ( gfn_eq(gfn, INVALID_GFN) ) >> { >> - p2m->default_access = a; >> + if ( ap2m ) >> + ap2m->default_access = a; >> + else >> + hp2m->default_access = a; >> + >> return 0; >> } >> >> - p2m_write_lock(p2m); >> - >> for ( gfn = gfn_add(gfn, start); nr > start; gfn = gfn_add(gfn, >> 1UL << order) ) >> { >> - p2m_type_t t; >> - mfn_t mfn = p2m_get_entry(p2m, gfn, &t, NULL, &order); >> - >> - /* Skip hole */ >> - if ( mfn_eq(mfn, INVALID_MFN) ) >> + if ( ap2m ) >> { >> + order = THIRD_ORDER; >> + >> /* >> - * the order corresponds to the order of the mapping in the >> - * page table. so we need to align the gfn before >> - * incrementing. >> + * ARM altp2m currently supports only setting of memory >> access rights >> + * of only one (4K) page at a time. > > This looks like a TODO to me. So please add either : "XXX:" or "TODO:" > in front. > Done. >> */ >> - gfn = _gfn(gfn_x(gfn) & ~((1UL << order) - 1)); >> - continue; >> + rc = altp2m_set_mem_access(d, hp2m, ap2m, a, gfn); >> + if ( rc && rc != -ESRCH ) >> + break; >> } >> else >> { >> - order = 0; >> - rc = __p2m_set_entry(p2m, gfn, 0, mfn, t, a); >> - if ( rc ) >> - break; >> + p2m_type_t t; >> + mfn_t mfn; >> + >> + p2m_write_lock(hp2m); >> + >> + mfn = p2m_get_entry(hp2m, gfn, &t, NULL, &order); >> + >> + /* Skip hole */ >> + if ( mfn_eq(mfn, INVALID_MFN) ) >> + { >> + /* >> + * the order corresponds to the order of the mapping >> in the >> + * page table. so we need to align the gfn before >> + * incrementing. >> + */ >> + gfn = _gfn(gfn_x(gfn) & ~((1UL << order) - 1)); >> + continue; > > I just noticed that my series is buggy. The "continue" should be > dropped. I will do it in the next version. > Ok. >> + } >> + else >> + { >> + order = 0; >> + >> + rc = __p2m_set_entry(hp2m, gfn, 0, mfn, t, a); >> + if ( rc ) >> + break; >> + } >> + >> + p2m_write_unlock(hp2m); > > By moving the lock within the loop, you will impose a TLB flush per-4K > which is currently not the case. > True. Since I needed to lock the hp2m explicitly inside of altp2m_set_mem_access, I could not move the lock outside of the loop. Now, this restriction has changed. > Looking at the function, I think the implementation the support of > altp2m could really be simplified. The main difference is if the entry > is not present in the altp2m then you lookup the host p2m. > I will try to simplify the function. >> } >> >> start += (1UL << order); >> @@ -1993,8 +2033,6 @@ long p2m_set_mem_access(struct domain *d, gfn_t >> gfn, uint32_t nr, >> } >> } >> >> - p2m_write_unlock(p2m); >> - >> if ( rc < 0 ) >> return rc; >> else if ( rc > 0 ) >> diff --git a/xen/include/asm-arm/altp2m.h b/xen/include/asm-arm/altp2m.h >> index c2e44ab..3e4c36d 100644 >> --- a/xen/include/asm-arm/altp2m.h >> +++ b/xen/include/asm-arm/altp2m.h >> @@ -71,4 +71,16 @@ void altp2m_flush(struct domain *d); >> int altp2m_destroy_by_id(struct domain *d, >> unsigned int idx); >> >> +/* >> + * Set memory access attributes of the gfn in the altp2m view. If >> the altp2m >> + * view does not contain the particular entry, copy it first from >> the hostp2m. >> + * >> + * Currently supports memory attribute adoptions of only one (4K) page. >> + */ >> +int altp2m_set_mem_access(struct domain *d, >> + struct p2m_domain *hp2m, >> + struct p2m_domain *ap2m, >> + p2m_access_t a, >> + gfn_t gfn); >> + >> #endif /* __ASM_ARM_ALTP2M_H */ >> > > Regards, > > [1] > https://lists.xenproject.org/archives/html/xen-devel/2016-08/msg01007.html > > Regards, > Cheers, ~Sergej
_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel