|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v3 2/3] xen: implement guest_physmap_(un)pin_range
On Thu, 8 Aug 2013, Ian Campbell wrote:
> > +int guest_physmap_pin_range(struct domain *d,
> > + xen_pfn_t gpfn,
> > + unsigned int order)
> > +{
> > + lpae_t *first = NULL, *second = NULL, *third = NULL, pte;
> > + paddr_t addr = gpfn << PAGE_SHIFT;
> > + struct p2m_domain *p2m = &d->arch.p2m;
> > + int rc = -EFAULT, i;
> > + unsigned long cur_first_offset = ~0, cur_second_offset = ~0;
> > +
> > + spin_lock(&p2m->lock);
> > +
> > + first = __map_domain_page(p2m->first_level);
> > +
> > + if ( !first ||
> > + !first[first_table_offset(addr)].p2m.valid ||
> > + !first[first_table_offset(addr)].p2m.table )
> > + goto err;
> > +
> > + for ( i = 0; i < (1UL << order); i++ )
> > + {
> > + if ( cur_first_offset != first_table_offset(addr) )
> > + {
> > + if (second) unmap_domain_page(second);
> > + second =
> > map_domain_page(first[first_table_offset(addr)].p2m.base);
> > + cur_first_offset = first_table_offset(addr);
> > + }
> > + if ( !second ||
> > + !second[second_table_offset(addr)].p2m.valid ||
> > + !second[second_table_offset(addr)].p2m.table )
> > + goto err;
> > +
> > + if ( cur_second_offset != second_table_offset(addr) )
> > + {
> > + if (third) unmap_domain_page(third);
> > + third =
> > map_domain_page(second[second_table_offset(addr)].p2m.base);
> > + cur_second_offset = second_table_offset(addr);
> > + }
> > + if ( !third ||
> > + !third[third_table_offset(addr)].p2m.valid ||
> > + third[third_table_offset(addr)].p2m.avail & P2M_DMA_PIN )
>
> At this point rc == -EFAULT, which doesn't seem right when failing the
> P2M_DMA_PIN check.
I'll go with -EINVAL. Do you have any better suggestions otherwise?
> > + goto err;
> > +
> > + pte = third[third_table_offset(addr)];
> > + pte.p2m.avail |= P2M_DMA_PIN;
> > + write_pte(&third[third_table_offset(addr)], pte);
> > +
> > + addr += PAGE_SIZE;
> > + }
> > +
> > + rc = 0;
> > +
> > +err:
>
> Leaks final mapping of third I think?
>
> You add two p2m walkers in this patch, and we have at least one already.
> Perhaps it is time for a generic function which calls a callback on the
> leaf ptes?
OK, good idea.
> > + if ( second ) unmap_domain_page(second);
> > + if ( first ) unmap_domain_page(first);
> > +
> > + spin_unlock(&p2m->lock);
> > +
> > + return rc;
> > +}
> > +
> > +int guest_physmap_unpin_range(struct domain *d,
> > + xen_pfn_t gpfn,
> > + unsigned int order)
> > +{
> > + lpae_t *first = NULL, *second = NULL, *third = NULL, pte;
> > + paddr_t addr = gpfn << PAGE_SHIFT;
> > + struct p2m_domain *p2m = &d->arch.p2m;
> > + int rc = -EFAULT, i;
> > + unsigned long cur_first_offset = ~0, cur_second_offset = ~0;
> > [...]
>
> Same generic comments as the pin version.
>
> > + rc = 0;
> > +
> > +err:
> > + if ( second ) unmap_domain_page(second);
> > + if ( first ) unmap_domain_page(first);
> > +
> > + spin_unlock(&p2m->lock);
> > +
> > + return rc;
> > +}
> > +
> > int guest_physmap_mark_populate_on_demand(struct domain *d,
> > unsigned long gfn,
> > unsigned int order)
> > @@ -184,6 +307,14 @@ static int create_p2m_entries(struct domain *d,
> > cur_second_offset = second_table_offset(addr);
> > }
> >
> > + if ( third[third_table_offset(addr)].p2m.avail & P2M_DMA_PIN )
> > + {
> > + rc = -EINVAL;
> > + printk("%s: cannot change p2m mapping for paddr=%"PRIpaddr
> > + " domid=%d, the page is pinned\n", __func__, addr,
> > d->domain_id);
>
> Not sure if a guest can trigger this, if yes then gdprintk.
>
> Do we always clear this bit when we clear the present bit? If not then
> we could end up with entries which are pinned and not-present. We should
> probably avoid that one way or another!
I went through the code: yes we do, because we always reset the entire
pte entry rather than only the valid bit.
> > + goto out;
> > + }
> > +
> > flush = third[third_table_offset(addr)].p2m.valid;
> >
> > /* Allocate a new RAM page and attach */
> > diff --git a/xen/include/asm-arm/mm.h b/xen/include/asm-arm/mm.h
> > index 5e7c5a3..8db8816 100644
> > --- a/xen/include/asm-arm/mm.h
> > +++ b/xen/include/asm-arm/mm.h
> > @@ -319,6 +319,10 @@ void free_init_memory(void);
> >
> > int guest_physmap_mark_populate_on_demand(struct domain *d, unsigned long
> > gfn,
> > unsigned int order);
> > +int guest_physmap_pin_range(struct domain *d, xen_pfn_t gpfn,
> > + unsigned int order);
> > +int guest_physmap_unpin_range(struct domain *d, xen_pfn_t gpfn,
> > + unsigned int order);
> >
> > extern void put_page_type(struct page_info *page);
> > static inline void put_page_and_type(struct page_info *page)
> > diff --git a/xen/include/asm-arm/page.h b/xen/include/asm-arm/page.h
> > index 41e9eff..12087d0 100644
> > --- a/xen/include/asm-arm/page.h
> > +++ b/xen/include/asm-arm/page.h
> > @@ -153,11 +153,15 @@ typedef struct {
> > unsigned long hint:1; /* In a block of 16 contiguous entries */
> > unsigned long sbz2:1;
> > unsigned long xn:1; /* eXecute-Never */
> > - unsigned long avail:4; /* Ignored by hardware */
> > + unsigned long avail:4; /* Ignored by hardware, see below */
> >
> > unsigned long sbz1:5;
> > } __attribute__((__packed__)) lpae_p2m_t;
> >
> > +/* Xen "avail" bits allocation in third level entries */
> > +#define P2M_DMA_PIN (1<<0) /* The page has been "pinned": the
> > hypervisor
> > + promises not to change the p2m mapping.
> > */
>
> I guess we are going to want to keep type info here eventually, this
> leaves 3 bits for that.
>
> For reference x86 has the following p2m types :
> p2m_ram_rw = 0, /* Normal read/write guest RAM */
> p2m_invalid = 1, /* Nothing mapped here */
> p2m_ram_logdirty = 2, /* Temporarily read-only for log-dirty */
> p2m_ram_ro = 3, /* Read-only; writes are silently dropped */
> p2m_mmio_dm = 4, /* Reads and write go to the device model */
> p2m_mmio_direct = 5, /* Read/write mapping of genuine MMIO area */
> p2m_populate_on_demand = 6, /* Place-holder for empty memory */
>
> /* Although these are defined in all builds, they can only
> * be used in 64-bit builds */
> p2m_grant_map_rw = 7, /* Read/write grant mapping */
> p2m_grant_map_ro = 8, /* Read-only grant mapping */
> p2m_ram_paging_out = 9, /* Memory that is being paged out */
> p2m_ram_paged = 10, /* Memory that has been paged out */
> p2m_ram_paging_in = 11, /* Memory that is being paged in */
> p2m_ram_shared = 12, /* Shared or sharable memory */
> p2m_ram_broken = 13, /* Broken page, access cause domain crash */
>
> We can get away with not having some of these for now, but not
> necessarily in the long term I think. 4 available bits is really too
> few :-(
>
> I'm unsure if pinning is orthogonal to type. I think it probably is? Or
> can we say that only normal ram can be pinned? Actually that may make
> sense since many of the other types are either implicitly pinned already
> (grant map, mmio etc) or pinning makes no sense (broken) or pinning
> would have to change the type anyway (pin shared -> unshare -> ram_rw
> +pinned, likewise for the paging types).
>
> So the pinable types are p2m_ram_rw, p2m_ram_ro, p2m_ram_logdirty? We
> could perhaps declare that ro and logdirty are implicitly pinned too?
> For log dirty it's pretty obvious, not so sure about ro -- doing DMA
> even just from r/o memory seems a bit dodgy to allow.
I agree. I think that only p2m_ram_rw should be pin-able.
I can add that to the comment.
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |