[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [IA64] Foreign p2m: xen side



# HG changeset patch
# User Alex Williamson <alex.williamson@xxxxxx>
# Date 1189109618 21600
# Node ID d956779d8d47875ccd74bb9d28b175a2a7f36a4d
# Parent  c5f735271e2202aa7f86ac2da4588074bf3ae3ba
[IA64] Foreign p2m: xen side

Signed-off-by: Isaku Yamahata <yamahata@xxxxxxxxxxxxx>
---
 xen/arch/ia64/xen/dom0_ops.c   |    9 
 xen/arch/ia64/xen/domain.c     |    1 
 xen/arch/ia64/xen/mm.c         |  605 +++++++++++++++++++++++++++++++++++++----
 xen/include/asm-ia64/domain.h  |   13 
 xen/include/asm-ia64/mm.h      |    8 
 xen/include/public/arch-ia64.h |    7 
 6 files changed, 584 insertions(+), 59 deletions(-)

diff -r c5f735271e22 -r d956779d8d47 xen/arch/ia64/xen/dom0_ops.c
--- a/xen/arch/ia64/xen/dom0_ops.c      Thu Sep 06 13:48:43 2007 -0600
+++ b/xen/arch/ia64/xen/dom0_ops.c      Thu Sep 06 14:13:38 2007 -0600
@@ -415,6 +415,15 @@ do_dom0vp_op(unsigned long cmd,
     case IA64_DOM0VP_add_io_space:
         ret = dom0vp_add_io_space(d, arg0, arg1, arg2);
         break;
+    case IA64_DOM0VP_expose_foreign_p2m: {
+        XEN_GUEST_HANDLE(char) hnd;
+        set_xen_guest_handle(hnd, (char*)arg2);
+        ret = dom0vp_expose_foreign_p2m(d, arg0, (domid_t)arg1, hnd, arg3);
+        break;
+    }
+    case IA64_DOM0VP_unexpose_foreign_p2m:
+        ret = dom0vp_unexpose_foreign_p2m(d, arg0, arg1);
+        break;
     default:
         ret = -1;
                printk("unknown dom0_vp_op 0x%lx\n", cmd);
diff -r c5f735271e22 -r d956779d8d47 xen/arch/ia64/xen/domain.c
--- a/xen/arch/ia64/xen/domain.c        Thu Sep 06 13:48:43 2007 -0600
+++ b/xen/arch/ia64/xen/domain.c        Thu Sep 06 14:13:38 2007 -0600
@@ -540,6 +540,7 @@ int arch_domain_create(struct domain *d)
        if (is_idle_domain(d))
            return 0;
 
+       foreign_p2m_init(d);
 #ifdef CONFIG_XEN_IA64_PERVCPU_VHPT
        d->arch.has_pervcpu_vhpt = opt_pervcpu_vhpt;
        dprintk(XENLOG_INFO, "%s:%d domain %d pervcpu_vhpt %d\n",
diff -r c5f735271e22 -r d956779d8d47 xen/arch/ia64/xen/mm.c
--- a/xen/arch/ia64/xen/mm.c    Thu Sep 06 13:48:43 2007 -0600
+++ b/xen/arch/ia64/xen/mm.c    Thu Sep 06 14:13:38 2007 -0600
@@ -175,8 +175,10 @@
 #include <asm/p2m_entry.h>
 #include <asm/tlb_track.h>
 #include <linux/efi.h>
+#include <linux/sort.h>
 #include <xen/guest_access.h>
 #include <asm/page.h>
+#include <asm/dom_fw_common.h>
 #include <public/memory.h>
 #include <asm/event.h>
 
@@ -354,6 +356,8 @@ mm_teardown(struct domain* d)
         if (mm_teardown_pgd(d, pgd, cur_offset))
             return -EAGAIN;
     }
+
+    foreign_p2m_destroy(d);
     return 0;
 }
 
@@ -1528,6 +1532,12 @@ dom0vp_add_physmap_with_gmfn(struct doma
 }
 
 #ifdef CONFIG_XEN_IA64_EXPOSE_P2M
+#define P2M_PFN_ROUNDUP(x)      (((x) + PTRS_PER_PTE - 1) & \
+                                 ~(PTRS_PER_PTE - 1))
+#define P2M_PFN_ROUNDDOWN(x)    ((x) & ~(PTRS_PER_PTE - 1))
+#define P2M_NUM_PFN(x)          (((x) + PTRS_PER_PTE - 1) / PTRS_PER_PTE)
+#define MD_END(md)              ((md)->phys_addr + \
+                                 ((md)->num_pages << EFI_PAGE_SHIFT))
 static struct page_info* p2m_pte_zero_page = NULL;
 
 /* This must called before dom0 p2m table allocation */
@@ -1550,6 +1560,43 @@ expose_p2m_init(void)
     p2m_pte_zero_page = virt_to_page(pte);
 }
 
+// allocate pgd, pmd of dest_dom if necessary
+static int
+allocate_pgd_pmd(struct domain* dest_dom, unsigned long dest_gpfn,
+                 struct domain* src_dom,
+                 unsigned long src_gpfn, unsigned long num_src_gpfn)
+{
+    unsigned long i = 0;
+
+    BUG_ON((src_gpfn % PTRS_PER_PTE) != 0);
+    BUG_ON((num_src_gpfn % PTRS_PER_PTE) != 0);
+
+    while (i < num_src_gpfn) {
+        volatile pte_t* src_pte;
+        volatile pte_t* dest_pte;
+
+        src_pte = lookup_noalloc_domain_pte(src_dom,
+                                            (src_gpfn + i) << PAGE_SHIFT);
+        if (src_pte == NULL) {
+            i++;
+            continue;
+        }
+        
+        dest_pte = lookup_alloc_domain_pte(dest_dom,
+                                           (dest_gpfn << PAGE_SHIFT) +
+                                           i * sizeof(pte_t));
+        if (dest_pte == NULL) {
+            gdprintk(XENLOG_INFO, "%s failed to allocate pte page\n",
+                     __func__);
+            return -ENOMEM;
+        }
+
+        // skip to next pte page
+        i = P2M_PFN_ROUNDDOWN(i + PTRS_PER_PTE);
+    }
+    return 0;
+}
+
 static int
 expose_p2m_page(struct domain* d, unsigned long mpaddr, struct page_info* page)
 {
@@ -1557,6 +1604,94 @@ expose_p2m_page(struct domain* d, unsign
     BUG_ON(ret != 1);
     return __assign_domain_page(d, mpaddr, page_to_maddr(page),
                                 ASSIGN_readonly);
+}
+
+// expose pte page
+static int
+expose_p2m_range(struct domain* dest_dom, unsigned long dest_gpfn,
+                 struct domain* src_dom,
+                 unsigned long src_gpfn, unsigned long num_src_gpfn)
+{
+    unsigned long i = 0;
+
+    BUG_ON((src_gpfn % PTRS_PER_PTE) != 0);
+    BUG_ON((num_src_gpfn % PTRS_PER_PTE) != 0);
+
+    while (i < num_src_gpfn) {
+        volatile pte_t* pte;
+
+        pte = lookup_noalloc_domain_pte(src_dom, (src_gpfn + i) << PAGE_SHIFT);
+        if (pte == NULL) {
+            i++;
+            continue;
+        }
+
+        if (expose_p2m_page(dest_dom,
+                            (dest_gpfn << PAGE_SHIFT) + i * sizeof(pte_t),
+                            virt_to_page(pte)) < 0) {
+            gdprintk(XENLOG_INFO, "%s failed to assign page\n", __func__);
+            return -EAGAIN;
+        }
+
+        // skip to next pte page
+        i = P2M_PFN_ROUNDDOWN(i + PTRS_PER_PTE);
+    }
+    return 0;
+}
+
+// expose p2m_pte_zero_page 
+static int
+expose_zero_page(struct domain* dest_dom, unsigned long dest_gpfn,
+                 unsigned long num_src_gpfn)
+{
+    unsigned long i;
+    
+    for (i = 0; i < P2M_NUM_PFN(num_src_gpfn); i++) {
+        volatile pte_t* pte;
+        pte = lookup_noalloc_domain_pte(dest_dom,
+                                        (dest_gpfn + i) << PAGE_SHIFT);
+        if (pte == NULL || pte_present(*pte))
+            continue;
+
+        if (expose_p2m_page(dest_dom, (dest_gpfn + i) << PAGE_SHIFT,
+                            p2m_pte_zero_page) < 0) {
+            gdprintk(XENLOG_INFO, "%s failed to assign zero-pte page\n",
+                     __func__);
+            return -EAGAIN;
+        }
+    }
+    return 0;
+}
+
+static int
+expose_p2m(struct domain* dest_dom, unsigned long dest_gpfn,
+           struct domain* src_dom,
+           unsigned long src_gpfn, unsigned long num_src_gpfn)
+{
+    if (allocate_pgd_pmd(dest_dom, dest_gpfn,
+                         src_dom, src_gpfn, num_src_gpfn))
+        return -ENOMEM;
+
+    if (expose_p2m_range(dest_dom, dest_gpfn,
+                         src_dom, src_gpfn, num_src_gpfn))
+        return -EAGAIN;
+
+    if (expose_zero_page(dest_dom, dest_gpfn, num_src_gpfn))
+        return -EAGAIN;
+    
+    return 0;
+}
+
+static void
+unexpose_p2m(struct domain* dest_dom,
+             unsigned long dest_gpfn, unsigned long num_dest_gpfn)
+{
+    unsigned long i;
+
+    for (i = 0; i < num_dest_gpfn; i++) {
+        zap_domain_page_one(dest_dom, (dest_gpfn + i) << PAGE_SHIFT,
+                            0, INVALID_MFN);
+    }
 }
 
 // It is possible to optimize loop, But this isn't performance critical.
@@ -1566,10 +1701,8 @@ dom0vp_expose_p2m(struct domain* d,
                   unsigned long assign_start_gpfn,
                   unsigned long expose_size, unsigned long granule_pfn)
 {
+    unsigned long ret;
     unsigned long expose_num_pfn = expose_size >> PAGE_SHIFT;
-    unsigned long i;
-    volatile pte_t* conv_pte;
-    volatile pte_t* assign_pte;
 
     if ((expose_size % PAGE_SIZE) != 0 ||
         (granule_pfn % PTRS_PER_PTE) != 0 ||
@@ -1590,65 +1723,419 @@ dom0vp_expose_p2m(struct domain* d,
                 __func__, granule_pfn, PTRS_PER_PTE);
         return -ENOSYS;
     }
-
-    // allocate pgd, pmd.
-    i = conv_start_gpfn;
-    while (i < expose_num_pfn) {
-        conv_pte = lookup_noalloc_domain_pte(d, (conv_start_gpfn + i) <<
-                                             PAGE_SHIFT);
-        if (conv_pte == NULL) {
-            i++;
+    ret = expose_p2m(d, assign_start_gpfn,
+                     d, conv_start_gpfn, expose_num_pfn);
+    return ret;
+}
+
+static int
+memmap_info_copy_from_guest(struct xen_ia64_memmap_info* memmap_info,
+                            char** memmap_p,
+                            XEN_GUEST_HANDLE(char) buffer)
+{
+    char *memmap;
+    char *p;
+    char *memmap_end;
+    efi_memory_desc_t *md;
+    unsigned long start;
+    unsigned long end;
+    efi_memory_desc_t *prev_md;
+
+    if (copy_from_guest((char*)memmap_info, buffer, sizeof(*memmap_info)))
+        return -EFAULT;
+    if (memmap_info->efi_memdesc_size < sizeof(efi_memory_desc_t) ||
+        memmap_info->efi_memmap_size < memmap_info->efi_memdesc_size ||
+        (memmap_info->efi_memmap_size % memmap_info->efi_memdesc_size) != 0)
+        return -EINVAL;
+    
+    memmap = _xmalloc(memmap_info->efi_memmap_size,
+                      __alignof__(efi_memory_desc_t));
+    if (memmap == NULL)
+        return -ENOMEM;
+    if (copy_from_guest_offset(memmap, buffer, sizeof(*memmap_info),
+                               memmap_info->efi_memmap_size)) {
+        xfree(memmap);
+        return -EFAULT;
+    }
+
+    /* intergirty check & simplify */
+    sort(memmap, memmap_info->efi_memmap_size / memmap_info->efi_memdesc_size,
+         memmap_info->efi_memdesc_size, efi_mdt_cmp, NULL);
+
+    /* alignement & overlap check */
+    prev_md = NULL;
+    p = memmap;
+    memmap_end = memmap + memmap_info->efi_memmap_size;
+    for (p = memmap; p < memmap_end; p += memmap_info->efi_memmap_size) {
+        md = (efi_memory_desc_t*)p;
+        start = md->phys_addr;
+        
+        if (start & ((1UL << EFI_PAGE_SHIFT) - 1) || md->num_pages == 0) {
+            xfree(memmap);
+            return -EINVAL;
+        }
+
+        if (prev_md != NULL) {
+            unsigned long prev_end = MD_END(prev_md);
+            if (prev_end > start) {
+                xfree(memmap);
+                return -EINVAL;
+            }
+        }
+
+        prev_md = (efi_memory_desc_t *)p;
+    }
+
+    /* coalease */
+    prev_md = NULL;
+    p = memmap;
+    while (p < memmap_end) {
+        md = (efi_memory_desc_t*)p;
+        start = md->phys_addr;
+        end = MD_END(md);
+
+        start = P2M_PFN_ROUNDDOWN(start >> PAGE_SHIFT) << PAGE_SHIFT;
+        end = P2M_PFN_ROUNDUP(end >> PAGE_SHIFT) << PAGE_SHIFT;
+        md->phys_addr = start;
+        md->num_pages = (end - start) >> EFI_PAGE_SHIFT;
+
+        if (prev_md != NULL) {
+            unsigned long prev_end = MD_END(prev_md);
+            if (prev_end >= start) {
+                size_t left;
+                end = max(prev_end, end);
+                prev_md->num_pages = (end - prev_md->phys_addr) >> 
EFI_PAGE_SHIFT;
+
+                left = memmap_end - p;
+                if (left > memmap_info->efi_memdesc_size) {
+                    left -= memmap_info->efi_memdesc_size;
+                    memmove(p, p + memmap_info->efi_memdesc_size, left);
+                }
+
+                memmap_info->efi_memmap_size -= memmap_info->efi_memdesc_size;
+                memmap_end -= memmap_info->efi_memdesc_size;
+                continue;
+            }
+        }
+
+        prev_md = md;
+        p += memmap_info->efi_memdesc_size;
+    }
+
+    if (copy_to_guest(buffer, (char*)memmap_info, sizeof(*memmap_info)) ||
+        copy_to_guest_offset(buffer, sizeof(*memmap_info),
+                             (char*)memmap, memmap_info->efi_memmap_size)) {
+        xfree(memmap);
+        return -EFAULT;
+    }
+    
+    *memmap_p = memmap;
+    return 0;
+}
+
+static int
+foreign_p2m_allocate_pte(struct domain* d,
+                         const struct xen_ia64_memmap_info* memmap_info,
+                         const void* memmap)
+{
+    const void* memmap_end = memmap + memmap_info->efi_memmap_size;
+    const void* p;
+
+    for (p = memmap; p < memmap_end; p += memmap_info->efi_memdesc_size) {
+        const efi_memory_desc_t* md = p;
+        unsigned long start = md->phys_addr;
+        unsigned long end = MD_END(md);
+        unsigned long gpaddr;
+
+        for (gpaddr = start; gpaddr < end; gpaddr += PAGE_SIZE) {
+            if (lookup_alloc_domain_pte(d, gpaddr) == NULL) {
+                return -ENOMEM;
+            }
+        }
+    }
+
+    return 0;
+}
+
+struct foreign_p2m_region {
+    unsigned long       gpfn;
+    unsigned long       num_gpfn;
+};
+
+struct foreign_p2m_entry {
+    struct list_head            list;
+    int                         busy;
+
+    /* src domain  */
+    struct domain*              src_dom;
+
+    /* region into which foreign p2m table is mapped */
+    unsigned long               gpfn;
+    unsigned long               num_gpfn;
+    unsigned int                num_region;
+    struct foreign_p2m_region   region[0];
+};
+
+/* caller must increment the reference count of src_dom */
+static int
+foreign_p2m_alloc(struct foreign_p2m* foreign_p2m,
+                  unsigned long dest_gpfn, struct domain* src_dom,
+                  struct xen_ia64_memmap_info* memmap_info, void* memmap,
+                  struct foreign_p2m_entry** entryp)
+{
+    void* memmap_end = memmap + memmap_info->efi_memmap_size;
+    efi_memory_desc_t* md;
+    unsigned long dest_gpfn_end;
+    unsigned long src_gpfn;
+    unsigned long src_gpfn_end;
+
+    unsigned int num_region;
+    struct foreign_p2m_entry* entry;
+    struct foreign_p2m_entry* prev;
+    struct foreign_p2m_entry* pos;
+
+    num_region = (memmap_end - memmap) / memmap_info->efi_memdesc_size;
+
+    md = memmap;
+    src_gpfn = P2M_PFN_ROUNDDOWN(md->phys_addr >> PAGE_SHIFT);
+
+    md = memmap + (num_region - 1) * memmap_info->efi_memdesc_size;
+    src_gpfn_end = MD_END(md) >> PAGE_SHIFT;
+    if (src_gpfn_end >
+        P2M_PFN_ROUNDUP(src_dom->arch.convmem_end >> PAGE_SHIFT))
+        return -EINVAL;
+
+    src_gpfn_end = P2M_PFN_ROUNDUP(src_gpfn_end);
+    dest_gpfn_end = dest_gpfn + P2M_NUM_PFN(src_gpfn_end - src_gpfn);
+    entry = _xmalloc(sizeof(*entry) + num_region * sizeof(entry->region[0]),
+                     __alignof__(*entry));
+    if (entry == NULL)
+        return -ENOMEM;
+
+    entry->busy = 1;
+    entry->gpfn = dest_gpfn;
+    entry->num_gpfn = dest_gpfn_end - dest_gpfn;
+    entry->src_dom = src_dom;
+    entry->num_region = 0;
+    memset(entry->region, 0, sizeof(entry->region[0]) * num_region);
+    prev = NULL;
+
+    spin_lock(&foreign_p2m->lock);
+    if (list_empty(&foreign_p2m->head))
+        prev = (struct foreign_p2m_entry*)&foreign_p2m->head;
+
+    list_for_each_entry(pos, &foreign_p2m->head, list) {
+        if (pos->gpfn + pos->num_gpfn < dest_gpfn) {
+            prev = pos;
             continue;
         }
+
+        if (dest_gpfn_end < pos->gpfn) {
+            if (prev != NULL && prev->gpfn + prev->num_gpfn > dest_gpfn)
+                prev = NULL;/* overlap */
+            break;
+        }
+
+        /* overlap */
+        prev = NULL;
+        break;
+    }
+    if (prev != NULL) {
+            list_add(&entry->list, &prev->list);
+            spin_unlock(&foreign_p2m->lock);
+            *entryp = entry;
+            return 0;
+    }
+    spin_unlock(&foreign_p2m->lock);
+    xfree(entry);
+    return -EBUSY;
+}
+
+static void
+foreign_p2m_unexpose(struct domain* dest_dom, struct foreign_p2m_entry* entry)
+{
+    unsigned int i;
+
+    BUG_ON(!entry->busy);
+    for (i = 0; i < entry->num_region; i++)
+        unexpose_p2m(dest_dom,
+                     entry->region[i].gpfn, entry->region[i].num_gpfn);
+}
+
+static void
+foreign_p2m_unbusy(struct foreign_p2m* foreign_p2m,
+                   struct foreign_p2m_entry* entry)
+{
+    spin_lock(&foreign_p2m->lock);
+    BUG_ON(!entry->busy);
+    entry->busy = 0;
+    spin_unlock(&foreign_p2m->lock);
+}
+
+static void
+foreign_p2m_free(struct foreign_p2m* foreign_p2m, 
+                 struct foreign_p2m_entry* entry)
+{
+    spin_lock(&foreign_p2m->lock);
+    BUG_ON(!entry->busy);
+    list_del(&entry->list);
+    spin_unlock(&foreign_p2m->lock);
+
+    put_domain(entry->src_dom);
+    xfree(entry);
+}
+
+void
+foreign_p2m_init(struct domain* d)
+{
+    struct foreign_p2m* foreign_p2m = &d->arch.foreign_p2m;
+    INIT_LIST_HEAD(&foreign_p2m->head);
+    spin_lock_init(&foreign_p2m->lock);
+}
+
+void
+foreign_p2m_destroy(struct domain* d)
+{
+    struct foreign_p2m* foreign_p2m = &d->arch.foreign_p2m;
+    struct foreign_p2m_entry* entry;
+    struct foreign_p2m_entry* n;
+
+    spin_lock(&foreign_p2m->lock);
+    list_for_each_entry_safe(entry, n, &foreign_p2m->head, list) {
+        /* mm_teardown() cleared p2m table already */
+        /* foreign_p2m_unexpose(d, entry);*/
+        list_del(&entry->list);
+        put_domain(entry->src_dom);
+        xfree(entry);
+    }
+    spin_unlock(&foreign_p2m->lock);
+}
+
+unsigned long
+dom0vp_expose_foreign_p2m(struct domain* dest_dom,
+                          unsigned long dest_gpfn,
+                          domid_t domid,
+                          XEN_GUEST_HANDLE(char) buffer,
+                          unsigned long flags)
+{
+    unsigned long ret = 0;
+    struct domain* src_dom;
+    struct xen_ia64_memmap_info memmap_info;
+    char* memmap;
+    void* memmap_end;
+    void* p;
+
+    struct foreign_p2m_entry* entry;
+
+    ret = memmap_info_copy_from_guest(&memmap_info, &memmap, buffer);
+    if (ret != 0)
+        return ret;
+
+    dest_dom = rcu_lock_domain(dest_dom);
+    if (dest_dom == NULL) {
+        ret = -EINVAL;
+        goto out;
+    }
+#if 1
+    // Self foreign domain p2m exposure isn't allowed.
+    // Otherwise the domain can't be destroyed because
+    // no one decrements the domain reference count.
+    if (domid == dest_dom->domain_id) {
+        ret = -EINVAL;
+        goto out;
+    }
+#endif    
+
+    src_dom = get_domain_by_id(domid);
+    if (src_dom == NULL) {
+        ret = -EINVAL;
+        goto out_unlock;
+    }
+
+    if (flags & IA64_DOM0VP_EFP_ALLOC_PTE) {
+        ret = foreign_p2m_allocate_pte(src_dom, &memmap_info, memmap);
+        if (ret != 0)
+            goto out_unlock;
+    }
+
+    ret = foreign_p2m_alloc(&dest_dom->arch.foreign_p2m, dest_gpfn,
+                            src_dom, &memmap_info, memmap, &entry);
+    if (ret != 0)
+        goto out_unlock;
+
+    memmap_end = memmap + memmap_info.efi_memmap_size;
+    for (p = memmap; p < memmap_end; p += memmap_info.efi_memdesc_size) {
+        efi_memory_desc_t* md = p;
+        unsigned long src_gpfn =
+            P2M_PFN_ROUNDDOWN(md->phys_addr >> PAGE_SHIFT);
+        unsigned long src_gpfn_end =
+            P2M_PFN_ROUNDUP(MD_END(md) >> PAGE_SHIFT);
+        unsigned long num_src_gpfn = src_gpfn_end - src_gpfn;
         
-        assign_pte = lookup_alloc_domain_pte(d, (assign_start_gpfn <<
-                                             PAGE_SHIFT) + i * sizeof(pte_t));
-        if (assign_pte == NULL) {
-            gdprintk(XENLOG_INFO, "%s failed to allocate pte page\n", 
__func__);
-            return -ENOMEM;
-        }
-
-        // skip to next pte page
-        i += PTRS_PER_PTE;
-        i &= ~(PTRS_PER_PTE - 1);
-    }
-
-    // expose pte page
-    i = 0;
-    while (i < expose_num_pfn) {
-        conv_pte = lookup_noalloc_domain_pte(d, (conv_start_gpfn + i) <<
-                                             PAGE_SHIFT);
-        if (conv_pte == NULL) {
-            i++;
-            continue;
-        }
-
-        if (expose_p2m_page(d, (assign_start_gpfn << PAGE_SHIFT) +
-                            i * sizeof(pte_t), virt_to_page(conv_pte)) < 0) {
-            gdprintk(XENLOG_INFO, "%s failed to assign page\n", __func__);
-            return -EAGAIN;
-        }
-
-        // skip to next pte page
-        i += PTRS_PER_PTE;
-        i &= ~(PTRS_PER_PTE - 1);
-    }
-
-    // expose p2m_pte_zero_page 
-    for (i = 0; i < (expose_num_pfn + PTRS_PER_PTE - 1) / PTRS_PER_PTE; i++) {
-        assign_pte = lookup_noalloc_domain_pte(d, (assign_start_gpfn + i) <<
-                                               PAGE_SHIFT);
-        if (assign_pte == NULL || pte_present(*assign_pte))
-            continue;
-
-        if (expose_p2m_page(d, (assign_start_gpfn + i) << PAGE_SHIFT,
-                            p2m_pte_zero_page) < 0) {
-            gdprintk(XENLOG_INFO, "%s failed to assign zero-pte page\n", 
__func__);
-            return -EAGAIN;
-        }
-    }
-    
-    return 0;
+        ret = expose_p2m(dest_dom, dest_gpfn + src_gpfn / PTRS_PER_PTE,
+                         src_dom, src_gpfn, num_src_gpfn);
+        if (ret != 0)
+            break;
+
+        entry->region[entry->num_region].gpfn =
+            dest_gpfn + src_gpfn / PTRS_PER_PTE;
+        entry->region[entry->num_region].num_gpfn = P2M_NUM_PFN(num_src_gpfn);
+        entry->num_region++;
+    }
+
+    if (ret == 0) {
+        foreign_p2m_unbusy(&dest_dom->arch.foreign_p2m, entry);
+    } else {
+        foreign_p2m_unexpose(dest_dom, entry);
+        foreign_p2m_free(&dest_dom->arch.foreign_p2m, entry);
+    }
+
+ out_unlock:
+    rcu_unlock_domain(dest_dom);
+ out:
+    xfree(memmap);
+    return ret;
+}
+
+unsigned long
+dom0vp_unexpose_foreign_p2m(struct domain* dest_dom,
+                            unsigned long dest_gpfn,
+                            domid_t domid)
+{
+    int ret = -ENOENT;
+    struct foreign_p2m* foreign_p2m = &dest_dom->arch.foreign_p2m;
+    struct foreign_p2m_entry* entry;
+
+    dest_dom = rcu_lock_domain(dest_dom);
+    if (dest_dom == NULL)
+        return ret;
+    spin_lock(&foreign_p2m->lock);
+    list_for_each_entry(entry, &foreign_p2m->head, list) {
+        if (entry->gpfn < dest_gpfn)
+              continue;
+        if (dest_gpfn < entry->gpfn)
+            break;
+
+        if (domid == entry->src_dom->domain_id)
+            ret = 0;
+        else
+            ret = -EINVAL;
+        break;
+    }
+    if (ret == 0) {
+        if (entry->busy == 0)
+            entry->busy = 1;
+        else
+            ret = -EBUSY;
+    }
+    spin_unlock(&foreign_p2m->lock);
+
+    if (ret == 0) {
+        foreign_p2m_unexpose(dest_dom, entry);
+        foreign_p2m_free(&dest_dom->arch.foreign_p2m, entry);
+    }
+    rcu_unlock_domain(dest_dom);
+    return ret;
 }
 #endif
 
diff -r c5f735271e22 -r d956779d8d47 xen/include/asm-ia64/domain.h
--- a/xen/include/asm-ia64/domain.h     Thu Sep 06 13:48:43 2007 -0600
+++ b/xen/include/asm-ia64/domain.h     Thu Sep 06 14:13:38 2007 -0600
@@ -45,6 +45,16 @@ struct mm_struct {
 struct mm_struct {
        volatile pgd_t * pgd;
     // atomic_t mm_users;                      /* How many users with user 
space? */
+};
+
+struct foreign_p2m {
+    spinlock_t          lock;
+    /*
+     * sorted list with entry->gpfn.
+     * It is expected that only small number of foreign domain p2m
+     * mapping happens at the same time.
+     */
+    struct list_head    head;
 };
 
 struct last_vcpu {
@@ -164,6 +174,9 @@ struct arch_domain {
     /* Number of faults.  */
     atomic64_t shadow_fault_count;
 
+    /* for foreign domain p2m table mapping */
+    struct foreign_p2m foreign_p2m;
+
     struct last_vcpu last_vcpu[NR_CPUS];
 
     struct opt_feature opt_feature;
diff -r c5f735271e22 -r d956779d8d47 xen/include/asm-ia64/mm.h
--- a/xen/include/asm-ia64/mm.h Thu Sep 06 13:48:43 2007 -0600
+++ b/xen/include/asm-ia64/mm.h Thu Sep 06 14:13:38 2007 -0600
@@ -440,9 +440,17 @@ extern unsigned long dom0vp_add_physmap_
 #ifdef CONFIG_XEN_IA64_EXPOSE_P2M
 extern void expose_p2m_init(void);
 extern unsigned long dom0vp_expose_p2m(struct domain* d, unsigned long 
conv_start_gpfn, unsigned long assign_start_gpfn, unsigned long expose_size, 
unsigned long granule_pfn);
+extern void foreign_p2m_init(struct domain* d);
+extern void foreign_p2m_destroy(struct domain* d);
+extern unsigned long dom0vp_expose_foreign_p2m(struct domain* dest_dom, 
unsigned long dest_gpfn, domid_t domid, XEN_GUEST_HANDLE(char) buffer, unsigned 
long flags);
+extern unsigned long dom0vp_unexpose_foreign_p2m(struct domain* dest_dom, 
unsigned long dest_gpfn, domid_t domid);
 #else
 #define expose_p2m_init()       do { } while (0)
 #define dom0vp_expose_p2m(d, conv_start_gpfn, assign_start_gpfn, expose_size, 
granule_pfn)     (-ENOSYS)
+#define foreign_p2m_init(d)    do { } while (0)
+#define foreign_p2m_destroy(d) do { } while (0)
+#define dom0vp_expose_foreign_p2m(dest_dom, dest_gpfn, domid, buffer, flags)   
(-ENOSYS)
+#define dom0vp_unexpose_foreign_p2m(dest_dom, dest_gpfn, domid)        
(-ENOSYS)
 #endif
 
 extern volatile unsigned long *mpt_table;
diff -r c5f735271e22 -r d956779d8d47 xen/include/public/arch-ia64.h
--- a/xen/include/public/arch-ia64.h    Thu Sep 06 13:48:43 2007 -0600
+++ b/xen/include/public/arch-ia64.h    Thu Sep 06 14:13:38 2007 -0600
@@ -469,6 +469,13 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_conte
 /* Add an I/O port space range */
 #define IA64_DOM0VP_add_io_space        11
 
+/* expose the foreign domain's p2m table into privileged domain */
+#define IA64_DOM0VP_expose_foreign_p2m  12
+#define         IA64_DOM0VP_EFP_ALLOC_PTE       0x1 /* allocate p2m table */
+
+/* unexpose the foreign domain's p2m table into privileged domain */
+#define IA64_DOM0VP_unexpose_foreign_p2m        13
+
 // flags for page assignement to pseudo physical address space
 #define _ASSIGN_readonly                0
 #define ASSIGN_readonly                 (1UL << _ASSIGN_readonly)

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.