# HG changeset patch
# User Jimi Xenidis <jimix@xxxxxxxxxxxxxx>
# Node ID 1d50658481071d73564b4d722e3d3199104c481a
# Parent f4f153f9960314768307e34700be96139b5faa71
[POWERPC][XEN] Safety with foreign get_page() calls and RMA
The following patch deals with get_page() possibly failing for H_ENTER
on a foreign page and returning the correct error. We also tag and
checke that a put_page() for RMA pages will panic (for now) if the
domain is _not_ dying.
Signed-off-by: Jimi Xenidis <jimix@xxxxxxxxxxxxxx>
---
xen/arch/powerpc/mm.c | 20 ++++++++++++--
xen/arch/powerpc/papr/xlate.c | 58 +++++++++++++++++++++++++-----------------
xen/include/asm-powerpc/mm.h | 8 +++++
3 files changed, 59 insertions(+), 27 deletions(-)
diff -r f4f153f99603 -r 1d5065848107 xen/arch/powerpc/mm.c
--- a/xen/arch/powerpc/mm.c Thu Sep 14 01:36:39 2006 -0400
+++ b/xen/arch/powerpc/mm.c Thu Sep 14 01:41:13 2006 -0400
@@ -287,6 +287,7 @@ int allocate_rma(struct domain *d, unsig
struct vcpu *v;
ulong rma_base;
ulong rma_sz;
+ int i;
if (d->arch.rma_page)
return -EINVAL;
@@ -301,11 +302,17 @@ int allocate_rma(struct domain *d, unsig
rma_base = page_to_maddr(d->arch.rma_page);
rma_sz = rma_size(d->arch.rma_order);
+
BUG_ON(rma_base & (rma_sz - 1)); /* check alignment */
- /* XXX shouldn't be needed */
- printk("clearing RMA: 0x%lx[0x%lx]\n", rma_base, rma_sz);
- memset((void *)rma_base, 0, rma_sz);
+ printk("allocated RMA for Dom[%d]: 0x%lx[0x%lx]\n",
+ d->domain_id, rma_base, rma_sz);
+
+ for (i = 0; i < (1 << d->arch.rma_order); i++ ) {
+ /* Add in any extra CPUs that need flushing because of this page. */
+ d->arch.rma_page[i].count_info |= PGC_page_RMA;
+ clear_page((void *)page_to_maddr(&d->arch.rma_page[i]));
+ }
d->shared_info = (shared_info_t *)
(rma_addr(&d->arch, RMA_SHARED_INFO) + rma_base);
@@ -318,6 +325,13 @@ int allocate_rma(struct domain *d, unsig
return 0;
}
+void free_rma_check(struct page_info *page)
+{
+ if (test_bit(_PGC_page_RMA, &page->count_info) &&
+ !test_bit(_DOMF_dying, &page_get_owner(page)->domain_flags))
+ panic("Attempt to free an RMA page: 0x%lx\n", page_to_mfn(page));
+}
+
ulong pfn2mfn(struct domain *d, ulong pfn, int *type)
{
diff -r f4f153f99603 -r 1d5065848107 xen/arch/powerpc/papr/xlate.c
--- a/xen/arch/powerpc/papr/xlate.c Thu Sep 14 01:36:39 2006 -0400
+++ b/xen/arch/powerpc/papr/xlate.c Thu Sep 14 01:41:13 2006 -0400
@@ -123,6 +123,9 @@ static void h_enter(struct cpu_user_regs
struct vcpu *v = get_current();
struct domain *d = v->domain;
int mtype;
+ struct page_info *pg = NULL;
+ struct domain *f = NULL;
+
htab = &d->arch.htab;
if (ptex > (1UL << htab->log_num_ptes)) {
@@ -203,15 +206,39 @@ static void h_enter(struct cpu_user_regs
pte.bits.ts = 0x0;
pte.bits.res2 = 0x0;
+ if (mtype == PFN_TYPE_FOREIGN) {
+ pg = mfn_to_page(mfn);
+ f = page_get_owner(pg);
+
+ BUG_ON(f == d);
+
+ if (unlikely(!get_domain(f))) {
+ regs->gprs[3] = H_Rescinded;
+ return;
+ }
+ if (unlikely(!get_page(pg, f))) {
+ put_domain(f);
+ regs->gprs[3] = H_Rescinded;
+ return;
+ }
+ }
+
if ( !(flags & H_EXACT) ) {
/* PTEG (not specific PTE); clear 3 lowest bits */
ptex &= ~0x7UL;
limit = 7;
}
- /* data manipulations should be done prior to the pte insertion. */
+ /* data manipulations should be done prior to the pte insertion. */
if ( flags & H_ZERO_PAGE ) {
- memset((void *)(mfn << PAGE_SHIFT), 0, 1UL << pgshift);
+ ulong pg = mfn << PAGE_SHIFT;
+ ulong pgs = 1UL << pgshift;
+
+ while (pgs > 0) {
+ clear_page((void *)pg);
+ pg += PAGE_SIZE;
+ --pgs;
+ }
}
if ( flags & H_ICACHE_INVALIDATE ) {
@@ -252,27 +279,6 @@ static void h_enter(struct cpu_user_regs
regs->gprs[3] = H_Success;
regs->gprs[4] = idx;
-
- switch (mtype) {
- case PFN_TYPE_IO:
- break;
- case PFN_TYPE_FOREIGN:
- {
- struct page_info *pg = mfn_to_page(mfn);
- struct domain *f = page_get_owner(pg);
-
- BUG_ON(f == d);
- get_domain(f);
- get_page(pg, f);
- }
- break;
- case PFN_TYPE_RMA:
- case PFN_TYPE_LOGICAL:
- break;
- default:
- BUG();
- }
-
return;
}
}
@@ -281,6 +287,12 @@ static void h_enter(struct cpu_user_regs
/* If the PTEG is full then no additional values are returned. */
printk("%s: PTEG FULL\n", __func__);
#endif
+
+ if (pg != NULL)
+ put_page(pg);
+
+ if (f != NULL)
+ put_domain(f);
regs->gprs[3] = H_PTEG_Full;
}
diff -r f4f153f99603 -r 1d5065848107 xen/include/asm-powerpc/mm.h
--- a/xen/include/asm-powerpc/mm.h Thu Sep 14 01:36:39 2006 -0400
+++ b/xen/include/asm-powerpc/mm.h Thu Sep 14 01:41:13 2006 -0400
@@ -122,8 +122,11 @@ struct page_extents {
/* Set when is using a page as a page table */
#define _PGC_page_table 29
#define PGC_page_table (1U<<_PGC_page_table)
+/* Set when using page for RMA */
+#define _PGC_page_RMA 28
+#define PGC_page_RMA (1U<<_PGC_page_RMA)
/* 29-bit count of references to this frame. */
-#define PGC_count_mask ((1U<<29)-1)
+#define PGC_count_mask ((1U<<28)-1)
#define IS_XEN_HEAP_FRAME(_pfn) (page_to_maddr(_pfn) < xenheap_phys_end)
@@ -142,6 +145,7 @@ extern unsigned long max_page;
extern unsigned long max_page;
extern unsigned long total_pages;
void init_frametable(void);
+void free_rma_check(struct page_info *page);
static inline void put_page(struct page_info *page)
{
@@ -154,6 +158,8 @@ static inline void put_page(struct page_
while ( unlikely((y = cmpxchg(&page->count_info, x, nx)) != x) );
if ( unlikely((nx & PGC_count_mask) == 0) ) {
+ /* RMA pages can only be released while the domain is dying */
+ free_rma_check(page);
free_domheap_page(page);
}
}
_______________________________________________
Xen-ppc-devel mailing list
Xen-ppc-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-ppc-devel
|