WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

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

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [IA64] Foreign p2m: xen side
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Tue, 11 Sep 2007 15:30:38 -0700
Delivery-date: Tue, 11 Sep 2007 15:33:24 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] [IA64] Foreign p2m: xen side, Xen patchbot-unstable <=