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

[Xen-changelog] [xen-unstable] [IA64] split domain.c into mm.c and domain.c



# HG changeset patch
# User awilliam@xxxxxxxxxxx
# Node ID f3be4eb8dac9df26d7bdeddbc89edf894d9bcb49
# Parent  34455164dd33c48adb8af1b183db4a6ccabda765
[IA64] split domain.c into mm.c and domain.c

domain.c has grown too much. split it into two files.

Signed-off-by: Isaku Yamahata <yamahata@xxxxxxxxxxxxx>
---
 xen/arch/ia64/xen/Makefile    |    1 
 xen/arch/ia64/xen/domain.c    | 1019 -----------------------------------------
 xen/arch/ia64/xen/mm.c        | 1036 ++++++++++++++++++++++++++++++++++++++++++
 xen/include/asm-ia64/domain.h |   16 
 xen/include/asm-ia64/mm.h     |   29 -
 5 files changed, 1065 insertions(+), 1036 deletions(-)

diff -r 34455164dd33 -r f3be4eb8dac9 xen/arch/ia64/xen/Makefile
--- a/xen/arch/ia64/xen/Makefile        Sat Jun 03 13:21:14 2006 -0600
+++ b/xen/arch/ia64/xen/Makefile        Sat Jun 03 13:21:38 2006 -0600
@@ -9,6 +9,7 @@ obj-y += idle0_task.o
 obj-y += idle0_task.o
 obj-y += irq.o
 obj-y += ivt.o
+obj-y += mm.o
 obj-y += mm_init.o
 obj-y += pcdp.o
 obj-y += privop.o
diff -r 34455164dd33 -r f3be4eb8dac9 xen/arch/ia64/xen/domain.c
--- a/xen/arch/ia64/xen/domain.c        Sat Jun 03 13:21:14 2006 -0600
+++ b/xen/arch/ia64/xen/domain.c        Sat Jun 03 13:21:38 2006 -0600
@@ -8,6 +8,10 @@
  *     Kun Tian (Kevin Tian) <kevin.tian@xxxxxxxxx>
  *
  * 05/04/29 Kun Tian (Kevin Tian) <kevin.tian@xxxxxxxxx> Add VTI domain support
+ *
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *                    dom0 vp model support
  */
 
 #include <xen/config.h>
@@ -77,44 +81,6 @@ static void init_switch_stack(struct vcp
 static void init_switch_stack(struct vcpu *v);
 void build_physmap_table(struct domain *d);
 
-static void try_to_clear_PGC_allocate(struct domain* d,
-                                      struct page_info* page);
-
-#ifdef CONFIG_XEN_IA64_DOM0_VP
-static struct domain *dom_xen, *dom_io;
-
-// followings are stolen from arch_init_memory() @ xen/arch/x86/mm.c
-void
-alloc_dom_xen_and_dom_io(void)
-{
-    /*
-     * Initialise our DOMID_XEN domain.
-     * Any Xen-heap pages that we will allow to be mapped will have
-     * their domain field set to dom_xen.
-     */
-    dom_xen = alloc_domain();
-    BUG_ON(dom_xen == NULL);
-    spin_lock_init(&dom_xen->page_alloc_lock);
-    INIT_LIST_HEAD(&dom_xen->page_list);
-    INIT_LIST_HEAD(&dom_xen->xenpage_list);
-    atomic_set(&dom_xen->refcnt, 1);
-    dom_xen->domain_id = DOMID_XEN;
-
-    /*
-     * Initialise our DOMID_IO domain.
-     * This domain owns I/O pages that are within the range of the page_info
-     * array. Mappings occur at the priv of the caller.
-     */
-    dom_io = alloc_domain();
-    BUG_ON(dom_io == NULL);
-    spin_lock_init(&dom_io->page_alloc_lock);
-    INIT_LIST_HEAD(&dom_io->page_list);
-    INIT_LIST_HEAD(&dom_io->xenpage_list);
-    atomic_set(&dom_io->refcnt, 1);
-    dom_io->domain_id = DOMID_IO;
-}
-#endif
-
 /* this belongs in include/asm, but there doesn't seem to be a suitable place 
*/
 void arch_domain_destroy(struct domain *d)
 {
@@ -414,106 +380,6 @@ static void relinquish_memory(struct dom
     }
 
     spin_unlock_recursive(&d->page_alloc_lock);
-}
-
-static void
-relinquish_pte(struct domain* d, pte_t* pte)
-{
-    unsigned long mfn = pte_pfn(*pte);
-    struct page_info* page;
-
-    // vmx domain use bit[58:56] to distinguish io region from memory.
-    // see vmx_build_physmap_table() in vmx_init.c
-    if (((mfn << PAGE_SHIFT) & GPFN_IO_MASK) != GPFN_MEM)
-        return;
-
-    // domain might map IO space or acpi table pages. check it.
-    if (!mfn_valid(mfn))
-        return;
-    page = mfn_to_page(mfn);
-    // struct page_info corresponding to mfn may exist or not depending
-    // on CONFIG_VIRTUAL_FRAME_TABLE.
-    // This check is too easy.
-    // The right way is to check whether this page is of io area or acpi pages
-    if (page_get_owner(page) == NULL) {
-        BUG_ON(page->count_info != 0);
-        return;
-    }
-
-#ifdef CONFIG_XEN_IA64_DOM0_VP
-    if (page_get_owner(page) == d) {
-        BUG_ON(get_gpfn_from_mfn(mfn) == INVALID_M2P_ENTRY);
-        set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY);
-    }
-#endif
-    try_to_clear_PGC_allocate(d, page);
-    put_page(page);
-}
-
-static void
-relinquish_pmd(struct domain* d, pmd_t* pmd, unsigned long offset)
-{
-    unsigned long i;
-    pte_t* pte = pte_offset_map(pmd, offset);
-
-    for (i = 0; i < PTRS_PER_PTE; i++, pte++) {
-        if (!pte_present(*pte))
-            continue;
-        
-        relinquish_pte(d, pte);
-    }
-    pte_free_kernel(pte_offset_map(pmd, offset));
-}
-
-static void
-relinquish_pud(struct domain* d, pud_t *pud, unsigned long offset)
-{
-    unsigned long i;
-    pmd_t *pmd = pmd_offset(pud, offset);
-    
-    for (i = 0; i < PTRS_PER_PMD; i++, pmd++) {
-        if (!pmd_present(*pmd))
-            continue;
-        
-        relinquish_pmd(d, pmd, offset + (i << PMD_SHIFT));
-    }
-    pmd_free(pmd_offset(pud, offset));
-}
-
-static void
-relinquish_pgd(struct domain* d, pgd_t *pgd, unsigned long offset)
-{
-    unsigned long i;
-    pud_t *pud = pud_offset(pgd, offset);
-
-    for (i = 0; i < PTRS_PER_PUD; i++, pud++) {
-        if (!pud_present(*pud))
-            continue;
-
-        relinquish_pud(d, pud, offset + (i << PUD_SHIFT));
-    }
-    pud_free(pud_offset(pgd, offset));
-}
-
-static void
-relinquish_mm(struct domain* d)
-{
-    struct mm_struct* mm = &d->arch.mm;
-    unsigned long i;
-    pgd_t* pgd;
-
-    if (mm->pgd == NULL)
-        return;
-
-    pgd = pgd_offset(mm, 0);
-    for (i = 0; i < PTRS_PER_PGD; i++, pgd++) {
-        if (!pgd_present(*pgd))
-            continue;
-
-        relinquish_pgd(d, pgd, i << PGDIR_SHIFT);
-    }
-    pgd_free(mm->pgd);
-    mm->pgd = NULL;
 }
 
 void domain_relinquish_resources(struct domain *d)
@@ -600,451 +466,6 @@ void new_thread(struct vcpu *v,
        }
 }
 
-// stolen from share_xen_page_with_guest() in xen/arch/x86/mm.c
-void
-share_xen_page_with_guest(struct page_info *page,
-                          struct domain *d, int readonly)
-{
-    if ( page_get_owner(page) == d )
-        return;
-
-#if 1
-    if (readonly) {
-        printk("%s:%d readonly is not supported yet\n", __func__, __LINE__);
-    }
-#endif
-
-    // alloc_xenheap_pages() doesn't initialize page owner.
-    //BUG_ON(page_get_owner(page) != NULL);
-#if 0
-    if (get_gpfn_from_mfn(page_to_mfn(page)) != INVALID_M2P_ENTRY) {
-        printk("%s:%d page 0x%p mfn 0x%lx gpfn 0x%lx\n", __func__, __LINE__,
-               page, page_to_mfn(page), get_gpfn_from_mfn(page_to_mfn(page)));
-    }
-#endif
-    // grant_table_destroy() release these pages.
-    // but it doesn't clear m2p entry. So there might remain stale entry.
-    // We clear such a stale entry here.
-    set_gpfn_from_mfn(page_to_mfn(page), INVALID_M2P_ENTRY);
-
-    spin_lock(&d->page_alloc_lock);
-
-#ifndef __ia64__
-    /* The incremented type count pins as writable or read-only. */
-    page->u.inuse.type_info  = (readonly ? PGT_none : PGT_writable_page);
-    page->u.inuse.type_info |= PGT_validated | 1;
-#endif
-
-    page_set_owner(page, d);
-    wmb(); /* install valid domain ptr before updating refcnt. */
-    ASSERT(page->count_info == 0);
-    page->count_info |= PGC_allocated | 1;
-
-    if ( unlikely(d->xenheap_pages++ == 0) )
-        get_knownalive_domain(d);
-    list_add_tail(&page->list, &d->xenpage_list);
-
-    spin_unlock(&d->page_alloc_lock);
-}
-
-void
-share_xen_page_with_privileged_guests(struct page_info *page, int readonly)
-{
-    share_xen_page_with_guest(page, dom_xen, readonly);
-}
-
-//XXX !xxx_present() should be used instread of !xxx_none()?
-static pte_t*
-lookup_alloc_domain_pte(struct domain* d, unsigned long mpaddr)
-{
-    struct mm_struct *mm = &d->arch.mm;
-    pgd_t *pgd;
-    pud_t *pud;
-    pmd_t *pmd;
-
-    BUG_ON(mm->pgd == NULL);
-    pgd = pgd_offset(mm, mpaddr);
-    if (pgd_none(*pgd)) {
-        pgd_populate(mm, pgd, pud_alloc_one(mm,mpaddr));
-    }
-
-    pud = pud_offset(pgd, mpaddr);
-    if (pud_none(*pud)) {
-        pud_populate(mm, pud, pmd_alloc_one(mm,mpaddr));
-    }
-
-    pmd = pmd_offset(pud, mpaddr);
-    if (pmd_none(*pmd)) {
-        pmd_populate_kernel(mm, pmd, pte_alloc_one_kernel(mm, mpaddr));
-    }
-
-    return pte_offset_map(pmd, mpaddr);
-}
-
-//XXX xxx_none() should be used instread of !xxx_present()?
-static pte_t*
-lookup_noalloc_domain_pte(struct domain* d, unsigned long mpaddr)
-{
-    struct mm_struct *mm = &d->arch.mm;
-    pgd_t *pgd;
-    pud_t *pud;
-    pmd_t *pmd;
-
-    BUG_ON(mm->pgd == NULL);
-    pgd = pgd_offset(mm, mpaddr);
-    if (!pgd_present(*pgd))
-        goto not_present;
-
-    pud = pud_offset(pgd, mpaddr);
-    if (!pud_present(*pud))
-        goto not_present;
-
-    pmd = pmd_offset(pud, mpaddr);
-    if (!pmd_present(*pmd))
-        goto not_present;
-
-    return pte_offset_map(pmd, mpaddr);
-
-not_present:
-    return NULL;
-}
-
-#ifdef CONFIG_XEN_IA64_DOM0_VP
-static pte_t*
-lookup_noalloc_domain_pte_none(struct domain* d, unsigned long mpaddr)
-{
-    struct mm_struct *mm = &d->arch.mm;
-    pgd_t *pgd;
-    pud_t *pud;
-    pmd_t *pmd;
-
-    BUG_ON(mm->pgd == NULL);
-    pgd = pgd_offset(mm, mpaddr);
-    if (pgd_none(*pgd))
-        goto not_present;
-
-    pud = pud_offset(pgd, mpaddr);
-    if (pud_none(*pud))
-        goto not_present;
-
-    pmd = pmd_offset(pud, mpaddr);
-    if (pmd_none(*pmd))
-        goto not_present;
-
-    return pte_offset_map(pmd, mpaddr);
-
-not_present:
-    return NULL;
-}
-#endif
-
-/* Allocate a new page for domain and map it to the specified metaphysical 
-   address.  */
-struct page_info *
-__assign_new_domain_page(struct domain *d, unsigned long mpaddr, pte_t* pte)
-{
-    struct page_info *p = NULL;
-    unsigned long maddr;
-    int ret;
-
-    BUG_ON(!pte_none(*pte));
-
-#ifdef CONFIG_DOMAIN0_CONTIGUOUS
-    if (d == dom0) {
-#if 0
-        if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
-            /* FIXME: is it true ?
-               dom0 memory is not contiguous!  */
-            panic("assign_new_domain_page: bad domain0 "
-                  "mpaddr=%lx, start=%lx, end=%lx!\n",
-                  mpaddr, dom0_start, dom0_start+dom0_size);
-        }
-#endif
-        p = mfn_to_page((mpaddr >> PAGE_SHIFT));
-        return p;
-    }
-#endif
-
-    p = alloc_domheap_page(d);
-    if (unlikely(!p)) {
-        printf("assign_new_domain_page: Can't alloc!!!! Aaaargh!\n");
-        return(p);
-    }
-
-    // zero out pages for security reasons
-    clear_page(page_to_virt(p));
-    maddr = page_to_maddr (p);
-    if (unlikely(maddr > __get_cpu_var(vhpt_paddr)
-                 && maddr < __get_cpu_var(vhpt_pend))) {
-        /* FIXME: how can this happen ?
-           vhpt is allocated by alloc_domheap_page.  */
-        printf("assign_new_domain_page: reassigned vhpt page %lx!!\n",
-               maddr);
-    }
-
-    ret = get_page(p, d);
-    BUG_ON(ret == 0);
-    set_pte(pte, pfn_pte(maddr >> PAGE_SHIFT,
-                         __pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX)));
-
-    mb ();
-    //XXX CONFIG_XEN_IA64_DOM0_VP
-    //    TODO racy
-    set_gpfn_from_mfn(page_to_mfn(p), mpaddr >> PAGE_SHIFT);
-    return p;
-}
-
-struct page_info *
-assign_new_domain_page(struct domain *d, unsigned long mpaddr)
-{
-#ifdef CONFIG_DOMAIN0_CONTIGUOUS
-    pte_t dummy_pte = __pte(0);
-    return __assign_new_domain_page(d, mpaddr, &dummy_pte);
-#else
-    struct page_info *p = NULL;
-    pte_t *pte;
-
-    pte = lookup_alloc_domain_pte(d, mpaddr);
-    if (pte_none(*pte)) {
-        p = __assign_new_domain_page(d, mpaddr, pte);
-    } else {
-        DPRINTK("%s: d 0x%p mpaddr %lx already mapped!\n",
-                __func__, d, mpaddr);
-    }
-
-    return p;
-#endif
-}
-
-void
-assign_new_domain0_page(struct domain *d, unsigned long mpaddr)
-{
-#ifndef CONFIG_DOMAIN0_CONTIGUOUS
-    pte_t *pte;
-
-    BUG_ON(d != dom0);
-    pte = lookup_alloc_domain_pte(d, mpaddr);
-    if (pte_none(*pte)) {
-        struct page_info *p = __assign_new_domain_page(d, mpaddr, pte);
-        if (p == NULL) {
-            panic("%s: can't allocate page for dom0", __func__);
-        }
-    }
-#endif
-}
-
-/* map a physical address to the specified metaphysical addr */
-// flags: currently only ASSIGN_readonly
-void
-__assign_domain_page(struct domain *d,
-                     unsigned long mpaddr, unsigned long physaddr,
-                     unsigned long flags)
-{
-    pte_t *pte;
-    unsigned long arflags = (flags & ASSIGN_readonly)? _PAGE_AR_R: 
_PAGE_AR_RWX;
-
-    pte = lookup_alloc_domain_pte(d, mpaddr);
-    if (pte_none(*pte)) {
-        set_pte(pte, pfn_pte(physaddr >> PAGE_SHIFT,
-                             __pgprot(__DIRTY_BITS | _PAGE_PL_2 | arflags)));
-        mb ();
-    } else
-        printk("%s: mpaddr %lx already mapped!\n", __func__, mpaddr);
-}
-
-/* get_page() and map a physical address to the specified metaphysical addr */
-void
-assign_domain_page(struct domain *d,
-                   unsigned long mpaddr, unsigned long physaddr)
-{
-    struct page_info* page = mfn_to_page(physaddr >> PAGE_SHIFT);
-    int ret;
-
-    BUG_ON((physaddr & GPFN_IO_MASK) != GPFN_MEM);
-    ret = get_page(page, d);
-    BUG_ON(ret == 0);
-    __assign_domain_page(d, mpaddr, physaddr, ASSIGN_writable);
-
-    //XXX CONFIG_XEN_IA64_DOM0_VP
-    //    TODO racy
-    set_gpfn_from_mfn(physaddr >> PAGE_SHIFT, mpaddr >> PAGE_SHIFT);
-}
-
-#ifdef CONFIG_XEN_IA64_DOM0_VP
-static void
-assign_domain_same_page(struct domain *d,
-                        unsigned long mpaddr, unsigned long size,
-                        unsigned long flags)
-{
-    //XXX optimization
-    unsigned long end = mpaddr + size;
-    for (; mpaddr < end; mpaddr += PAGE_SIZE) {
-        __assign_domain_page(d, mpaddr, mpaddr, flags);
-    }
-}
-
-static int
-efi_mmio(unsigned long physaddr, unsigned long size)
-{
-    void *efi_map_start, *efi_map_end;
-    u64 efi_desc_size;
-    void* p;
-
-    efi_map_start = __va(ia64_boot_param->efi_memmap);
-    efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
-    efi_desc_size = ia64_boot_param->efi_memdesc_size;
-
-    for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
-        efi_memory_desc_t* md = (efi_memory_desc_t *)p;
-        unsigned long start = md->phys_addr;
-        unsigned long end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
-        
-        if (start <= physaddr && physaddr < end) {
-            if ((physaddr + size) > end) {
-                DPRINTK("%s:%d physaddr 0x%lx size = 0x%lx\n",
-                        __func__, __LINE__, physaddr, size);
-                return 0;
-            }
-
-            // for io space
-            if (md->type == EFI_MEMORY_MAPPED_IO ||
-                md->type == EFI_MEMORY_MAPPED_IO_PORT_SPACE) {
-                return 1;
-            }
-
-            // for runtime
-            // see efi_enter_virtual_mode(void)
-            // in linux/arch/ia64/kernel/efi.c
-            if ((md->attribute & EFI_MEMORY_RUNTIME) &&
-                !(md->attribute & EFI_MEMORY_WB)) {
-                return 1;
-            }
-
-            DPRINTK("%s:%d physaddr 0x%lx size = 0x%lx\n",
-                    __func__, __LINE__, physaddr, size);
-            return 0;
-        }
-
-        if (physaddr < start) {
-            break;
-        }
-    }
-
-    return 1;
-}
-
-unsigned long
-assign_domain_mmio_page(struct domain *d,
-                        unsigned long mpaddr, unsigned long size)
-{
-    if (size == 0) {
-        DPRINTK("%s: domain %p mpaddr 0x%lx size = 0x%lx\n",
-                __func__, d, mpaddr, size);
-    }
-    if (!efi_mmio(mpaddr, size)) {
-        DPRINTK("%s:%d domain %p mpaddr 0x%lx size = 0x%lx\n",
-                __func__, __LINE__, d, mpaddr, size);
-        return -EINVAL;
-    }
-    assign_domain_same_page(d, mpaddr, size, ASSIGN_writable);
-    return mpaddr;
-}
-
-unsigned long
-assign_domain_mach_page(struct domain *d,
-                        unsigned long mpaddr, unsigned long size,
-                        unsigned long flags)
-{
-    assign_domain_same_page(d, mpaddr, size, flags);
-    return mpaddr;
-}
-
-//XXX selege hammer.
-//    flush finer range.
-void
-domain_page_flush(struct domain* d, unsigned long mpaddr,
-                  unsigned long old_mfn, unsigned long new_mfn)
-{
-    domain_flush_vtlb_all();
-}
-#endif
-
-//XXX heavily depends on the struct page_info layout.
-//
-// if (page_get_owner(page) == d &&
-//     test_and_clear_bit(_PGC_allocated, &page->count_info)) {
-//     put_page(page);
-// }
-static void
-try_to_clear_PGC_allocate(struct domain* d, struct page_info* page)
-{
-    u32 _d, _nd;
-    u64 x, nx, y;
-
-    _d = pickle_domptr(d);
-    y = *((u64*)&page->count_info);
-    do {
-        x = y;
-        _nd = x >> 32;
-        nx = x - 1;
-        __clear_bit(_PGC_allocated, &nx);
-
-        if (unlikely(!(x & PGC_allocated)) || unlikely(_nd != _d)) {
-            struct domain* nd = unpickle_domptr(_nd);
-            if (nd == NULL) {
-                DPRINTK("gnttab_transfer: Bad page %p: ed=%p(%u) 0x%x, "
-                        "sd=%p 0x%x,"
-                        " caf=%016lx, taf=%" PRtype_info "\n",
-                        (void *) page_to_mfn(page),
-                        d, d->domain_id, _d,
-                        nd, _nd,
-                        x,
-                        page->u.inuse.type_info);
-            }
-            break;
-        }
-
-        BUG_ON((nx & PGC_count_mask) < 1);
-        y = cmpxchg((u64*)&page->count_info, x, nx);
-    } while (unlikely(y != x));
-}
-
-#ifdef CONFIG_XEN_IA64_DOM0_VP
-static void
-zap_domain_page_one(struct domain *d, unsigned long mpaddr, int do_put_page)
-{
-    struct mm_struct *mm = &d->arch.mm;
-    pte_t *pte;
-    pte_t old_pte;
-    unsigned long mfn;
-    struct page_info *page;
-
-    pte = lookup_noalloc_domain_pte_none(d, mpaddr);
-    if (pte == NULL)
-        return;
-    if (pte_none(*pte))
-        return;
-
-    // update pte
-    old_pte = ptep_get_and_clear(mm, mpaddr, pte);
-    mfn = pte_pfn(old_pte);
-    page = mfn_to_page(mfn);
-    BUG_ON((page->count_info & PGC_count_mask) == 0);
-
-    if (page_get_owner(page) == d) {
-        BUG_ON(get_gpfn_from_mfn(mfn) != (mpaddr >> PAGE_SHIFT));
-        set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY);
-    }
-
-    domain_page_flush(d, mpaddr, mfn, INVALID_MFN);
-
-    if (do_put_page) {
-        try_to_clear_PGC_allocate(d, page);
-        put_page(page);
-    }
-}
-#endif
-
 void build_physmap_table(struct domain *d)
 {
        struct list_head *list_ent = d->page_list.next;
@@ -1061,438 +482,6 @@ void build_physmap_table(struct domain *
        }
        d->arch.physmap_built = 1;
 }
-
-void mpafoo(unsigned long mpaddr)
-{
-       extern unsigned long privop_trace;
-       if (mpaddr == 0x3800)
-               privop_trace = 1;
-}
-
-#ifdef CONFIG_XEN_IA64_DOM0_VP
-unsigned long
-____lookup_domain_mpa(struct domain *d, unsigned long mpaddr)
-{
-    pte_t *pte;
-
-    pte = lookup_noalloc_domain_pte(d, mpaddr);
-    if (pte == NULL)
-        goto not_present;
-
-    if (pte_present(*pte))
-        return (pte->pte & _PFN_MASK);
-    else if (VMX_DOMAIN(d->vcpu[0]))
-        return GPFN_INV_MASK;
-
-not_present:
-    return INVALID_MFN;
-}
-
-unsigned long
-__lookup_domain_mpa(struct domain *d, unsigned long mpaddr)
-{
-    unsigned long machine = ____lookup_domain_mpa(d, mpaddr);
-    if (machine != INVALID_MFN)
-        return machine;
-
-    printk("%s: d 0x%p id %d current 0x%p id %d\n",
-           __func__, d, d->domain_id, current, current->vcpu_id);
-    printk("%s: bad mpa 0x%lx (max_pages 0x%lx)\n",
-           __func__, mpaddr, (unsigned long)d->max_pages << PAGE_SHIFT);
-    return INVALID_MFN;
-}
-#endif
-
-unsigned long lookup_domain_mpa(struct domain *d, unsigned long mpaddr)
-{
-       pte_t *pte;
-
-#ifdef CONFIG_DOMAIN0_CONTIGUOUS
-       if (d == dom0) {
-               pte_t pteval;
-               if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
-                       //printk("lookup_domain_mpa: bad dom0 mpaddr 
0x%lx!\n",mpaddr);
-                       //printk("lookup_domain_mpa: 
start=0x%lx,end=0x%lx!\n",dom0_start,dom0_start+dom0_size);
-                       mpafoo(mpaddr);
-               }
-               pteval = pfn_pte(mpaddr >> PAGE_SHIFT,
-                       __pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX));
-               return pte_val(pteval);
-       }
-#endif
-       pte = lookup_noalloc_domain_pte(d, mpaddr);
-       if (pte != NULL) {
-               if (pte_present(*pte)) {
-//printk("lookup_domain_page: found mapping for %lx, 
pte=%lx\n",mpaddr,pte_val(*pte));
-                       return pte_val(*pte);
-               } else if (VMX_DOMAIN(d->vcpu[0]))
-                       return GPFN_INV_MASK;
-       }
-
-       printk("%s: d 0x%p id %d current 0x%p id %d\n",
-              __func__, d, d->domain_id, current, current->vcpu_id);
-       if ((mpaddr >> PAGE_SHIFT) < d->max_pages)
-               printk("%s: non-allocated mpa 0x%lx (< 0x%lx)\n", __func__,
-                      mpaddr, (unsigned long)d->max_pages << PAGE_SHIFT);
-       else
-               printk("%s: bad mpa 0x%lx (=> 0x%lx)\n", __func__,
-                      mpaddr, (unsigned long)d->max_pages << PAGE_SHIFT);
-       mpafoo(mpaddr);
-
-       //XXX This is a work around until the emulation memory access to a 
region
-       //    where memory or device are attached is implemented.
-       return pte_val(pfn_pte(0, __pgprot(__DIRTY_BITS | _PAGE_PL_2 | 
_PAGE_AR_RWX)));
-}
-
-#ifdef CONFIG_XEN_IA64_DOM0_VP
-//XXX SMP
-unsigned long
-dom0vp_zap_physmap(struct domain *d, unsigned long gpfn,
-                   unsigned int extent_order)
-{
-    unsigned long ret = 0;
-    if (extent_order != 0) {
-        //XXX
-        ret = -ENOSYS;
-        goto out;
-    }
-
-    zap_domain_page_one(d, gpfn << PAGE_SHIFT, 1);
-
-out:
-    return ret;
-}
-
-// caller must get_page(mfn_to_page(mfn)) before
-// caller must call set_gpfn_from_mfn().
-// flags: currently only ASSIGN_readonly
-static void
-assign_domain_page_replace(struct domain *d, unsigned long mpaddr,
-                           unsigned long mfn, unsigned long flags)
-{
-    struct mm_struct *mm = &d->arch.mm;
-    pte_t* pte;
-    pte_t old_pte;
-    pte_t npte;
-    unsigned long arflags = (flags & ASSIGN_readonly)? _PAGE_AR_R: 
_PAGE_AR_RWX;
-
-    pte = lookup_alloc_domain_pte(d, mpaddr);
-
-    // update pte
-    npte = pfn_pte(mfn, __pgprot(__DIRTY_BITS | _PAGE_PL_2 | arflags));
-    old_pte = ptep_xchg(mm, mpaddr, pte, npte);
-    if (pte_mem(old_pte)) {
-        unsigned long old_mfn;
-        struct page_info* old_page;
-
-        // XXX should previous underlying page be removed?
-        //  or should error be returned because it is a due to a domain?
-        old_mfn = pte_pfn(old_pte);//XXX
-        old_page = mfn_to_page(old_mfn);
-
-        if (page_get_owner(old_page) == d) {
-            BUG_ON(get_gpfn_from_mfn(old_mfn) != (mpaddr >> PAGE_SHIFT));
-            set_gpfn_from_mfn(old_mfn, INVALID_M2P_ENTRY);
-        }
-
-        domain_page_flush(d, mpaddr, old_mfn, mfn);
-
-        try_to_clear_PGC_allocate(d, old_page);
-        put_page(old_page);
-    } else {
-        BUG_ON(!mfn_valid(mfn));
-        BUG_ON(page_get_owner(mfn_to_page(mfn)) == d &&
-               get_gpfn_from_mfn(mfn) != INVALID_M2P_ENTRY);
-    }
-}
-
-unsigned long
-dom0vp_add_physmap(struct domain* d, unsigned long gpfn, unsigned long mfn,
-                   unsigned long flags, domid_t domid)
-{
-    int error = 0;
-    struct domain* rd;
-
-    rd = find_domain_by_id(domid);
-    if (unlikely(rd == NULL)) {
-        switch (domid) {
-        case DOMID_XEN:
-            rd = dom_xen;
-            break;
-        case DOMID_IO:
-            rd = dom_io;
-            break;
-        default:
-            DPRINTK("d 0x%p domid %d "
-                    "pgfn 0x%lx mfn 0x%lx flags 0x%lx domid %d\n",
-                    d, d->domain_id, gpfn, mfn, flags, domid);
-            error = -ESRCH;
-            goto out0;
-        }
-        BUG_ON(rd == NULL);
-        get_knownalive_domain(rd);
-    }
-
-    if (unlikely(rd == d)) {
-        error = -EINVAL;
-        goto out1;
-    }
-    if (unlikely(get_page(mfn_to_page(mfn), rd) == 0)) {
-        error = -EINVAL;
-        goto out1;
-    }
-
-    assign_domain_page_replace(d, gpfn << PAGE_SHIFT, mfn, flags);
-    //don't update p2m table because this page belongs to rd, not d.
-out1:
-    put_domain(rd);
-out0:
-    return error;
-}
-
-// grant table host mapping
-// mpaddr: host_addr: pseudo physical address
-// mfn: frame: machine page frame
-// flags: GNTMAP_readonly | GNTMAP_application_map | GNTMAP_contains_pte
-int
-create_grant_host_mapping(unsigned long gpaddr,
-                         unsigned long mfn, unsigned int flags)
-{
-    struct domain* d = current->domain;
-    struct page_info* page;
-    int ret;
-
-    if (flags & (GNTMAP_device_map | 
-                 GNTMAP_application_map | GNTMAP_contains_pte)) {
-        DPRINTK("%s: flags 0x%x\n", __func__, flags);
-        return GNTST_general_error;
-    }
-
-    page = mfn_to_page(mfn);
-    ret = get_page(page, page_get_owner(page));
-    BUG_ON(ret == 0);
-
-    assign_domain_page_replace(d, gpaddr, mfn, (flags & GNTMAP_readonly)?
-                                              ASSIGN_readonly: 
ASSIGN_writable);
-    return GNTST_okay;
-}
-
-// grant table host unmapping
-int
-destroy_grant_host_mapping(unsigned long gpaddr,
-                          unsigned long mfn, unsigned int flags)
-{
-    struct domain* d = current->domain;
-    pte_t* pte;
-    pte_t old_pte;
-    unsigned long old_mfn = INVALID_MFN;
-    struct page_info* old_page;
-
-    if (flags & (GNTMAP_application_map | GNTMAP_contains_pte)) {
-        DPRINTK("%s: flags 0x%x\n", __func__, flags);
-        return GNTST_general_error;
-    }
-
-    pte = lookup_noalloc_domain_pte(d, gpaddr);
-    if (pte == NULL || !pte_present(*pte) || pte_pfn(*pte) != mfn)
-        return GNTST_general_error;
-
-    // update pte
-    old_pte = ptep_get_and_clear(&d->arch.mm, gpaddr, pte);
-    if (pte_present(old_pte)) {
-        old_mfn = pte_pfn(old_pte);
-    } else {
-        return GNTST_general_error;
-    }
-    domain_page_flush(d, gpaddr, old_mfn, INVALID_MFN);
-
-    old_page = mfn_to_page(old_mfn);
-    BUG_ON(page_get_owner(old_page) == d);//try_to_clear_PGC_allocate(d, page) 
is not needed.
-    put_page(old_page);
-
-    return GNTST_okay;
-}
-
-//XXX needs refcount patch
-//XXX heavily depends on the struct page layout.
-//XXX SMP
-int
-steal_page_for_grant_transfer(struct domain *d, struct page_info *page)
-{
-#if 0 /* if big endian */
-# error "implement big endian version of steal_page_for_grant_transfer()"
-#endif
-    u32 _d, _nd;
-    u64 x, nx, y;
-    unsigned long mpaddr = get_gpfn_from_mfn(page_to_mfn(page)) << PAGE_SHIFT;
-    struct page_info *new;
-
-    zap_domain_page_one(d, mpaddr, 0);
-    put_page(page);
-
-    spin_lock(&d->page_alloc_lock);
-
-    /*
-     * The tricky bit: atomically release ownership while there is just one
-     * benign reference to the page (PGC_allocated). If that reference
-     * disappears then the deallocation routine will safely spin.
-     */
-    _d  = pickle_domptr(d);
-    y = *((u64*)&page->count_info);
-    do {
-        x = y;
-        nx = x & 0xffffffff;
-        // page->count_info: untouched
-        // page->u.inused._domain = 0;
-        _nd = x >> 32;
-
-        if (unlikely((x & (PGC_count_mask | PGC_allocated)) !=
-                     (1 | PGC_allocated)) ||
-            unlikely(_nd != _d)) {
-            struct domain* nd = unpickle_domptr(_nd);
-            if (nd == NULL) {
-                DPRINTK("gnttab_transfer: Bad page %p: ed=%p(%u) 0x%x, "
-                        "sd=%p 0x%x,"
-                        " caf=%016lx, taf=%" PRtype_info "\n",
-                        (void *) page_to_mfn(page),
-                        d, d->domain_id, _d,
-                        nd, _nd,
-                        x,
-                        page->u.inuse.type_info);
-            } else {
-                DPRINTK("gnttab_transfer: Bad page %p: ed=%p(%u) 0x%x, "
-                        "sd=%p(%u) 0x%x,"
-                        " caf=%016lx, taf=%" PRtype_info "\n",
-                        (void *) page_to_mfn(page),
-                        d, d->domain_id, _d,
-                        nd, nd->domain_id, _nd,
-                        x,
-                        page->u.inuse.type_info);
-            }
-            spin_unlock(&d->page_alloc_lock);
-            return -1;
-        }
-
-        y = cmpxchg((u64*)&page->count_info, x, nx);
-    } while (unlikely(y != x));
-
-    /*
-     * Unlink from 'd'. At least one reference remains (now anonymous), so
-     * noone else is spinning to try to delete this page from 'd'.
-     */
-    d->tot_pages--;
-    list_del(&page->list);
-
-    spin_unlock(&d->page_alloc_lock);
-
-#if 1
-    //XXX Until net_rx_action() fix
-    // assign new page for this mpaddr
-    new = assign_new_domain_page(d, mpaddr);
-    BUG_ON(new == NULL);//XXX
-#endif
-
-    return 0;
-}
-
-void
-guest_physmap_add_page(struct domain *d, unsigned long gpfn,
-                       unsigned long mfn)
-{
-    int ret;
-
-    ret = get_page(mfn_to_page(mfn), d);
-    BUG_ON(ret == 0);
-    assign_domain_page_replace(d, gpfn << PAGE_SHIFT, mfn, ASSIGN_writable);
-    set_gpfn_from_mfn(mfn, gpfn);//XXX SMP
-
-    //BUG_ON(mfn != ((lookup_domain_mpa(d, gpfn << PAGE_SHIFT) & _PFN_MASK) >> 
PAGE_SHIFT));
-}
-
-void
-guest_physmap_remove_page(struct domain *d, unsigned long gpfn,
-                          unsigned long mfn)
-{
-    BUG_ON(mfn == 0);//XXX
-    zap_domain_page_one(d, gpfn << PAGE_SHIFT, 1);
-}
-#endif
-
-/* Flush cache of domain d.  */
-void domain_cache_flush (struct domain *d, int sync_only)
-{
-       struct mm_struct *mm = &d->arch.mm;
-       pgd_t *pgd = mm->pgd;
-       unsigned long maddr;
-       int i,j,k, l;
-       int nbr_page = 0;
-       void (*flush_func)(unsigned long start, unsigned long end);
-       extern void flush_dcache_range (unsigned long, unsigned long);
-
-       if (sync_only)
-               flush_func = &flush_icache_range;
-       else
-               flush_func = &flush_dcache_range;
-
-#ifdef CONFIG_DOMAIN0_CONTIGUOUS
-       if (d == dom0) {
-               /* This is not fully correct (because of hole), but it should
-                  be enough for now.  */
-               (*flush_func)(__va_ul (dom0_start),
-                             __va_ul (dom0_start + dom0_size));
-               return;
-       }
-#endif
-       for (i = 0; i < PTRS_PER_PGD; pgd++, i++) {
-               pud_t *pud;
-               if (!pgd_present(*pgd))
-                       continue;
-               pud = pud_offset(pgd, 0);
-               for (j = 0; j < PTRS_PER_PUD; pud++, j++) {
-                       pmd_t *pmd;
-                       if (!pud_present(*pud))
-                               continue;
-                       pmd = pmd_offset(pud, 0);
-                       for (k = 0; k < PTRS_PER_PMD; pmd++, k++) {
-                               pte_t *pte;
-                               if (!pmd_present(*pmd))
-                                       continue;
-                               pte = pte_offset_map(pmd, 0);
-                               for (l = 0; l < PTRS_PER_PTE; pte++, l++) {
-                                       if (!pte_present(*pte))
-                                               continue;
-                                       /* Convert PTE to maddr.  */
-                                       maddr = __va_ul (pte_val(*pte)
-                                                        & _PAGE_PPN_MASK);
-                                       (*flush_func)(maddr, maddr+ PAGE_SIZE);
-                                       nbr_page++;
-                               }
-                       }
-               }
-       }
-       //printf ("domain_cache_flush: %d %d pages\n", d->domain_id, nbr_page);
-}
-
-// FIXME: ONLY USE FOR DOMAIN PAGE_SIZE == PAGE_SIZE
-#if 1
-unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr)
-{
-       unsigned long pte = lookup_domain_mpa(d,mpaddr);
-       unsigned long imva;
-
-       pte &= _PAGE_PPN_MASK;
-       imva = (unsigned long) __va(pte);
-       imva |= mpaddr & ~PAGE_MASK;
-       return(imva);
-}
-#else
-unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr)
-{
-    unsigned long imva = __gpa_to_mpa(d, mpaddr);
-
-    return __va(imva);
-}
-#endif
 
 // remove following line if not privifying in memory
 //#define HAVE_PRIVIFY_MEMORY
diff -r 34455164dd33 -r f3be4eb8dac9 xen/include/asm-ia64/domain.h
--- a/xen/include/asm-ia64/domain.h     Sat Jun 03 13:21:14 2006 -0600
+++ b/xen/include/asm-ia64/domain.h     Sat Jun 03 13:21:38 2006 -0600
@@ -118,22 +118,6 @@ struct arch_vcpu {
     struct arch_vmx_struct arch_vmx; /* Virtual Machine Extensions */
 };
 
-struct page_info * assign_new_domain_page(struct domain *d, unsigned long 
mpaddr);
-void assign_new_domain0_page(struct domain *d, unsigned long mpaddr);
-void __assign_domain_page(struct domain *d, unsigned long mpaddr, unsigned 
long physaddr, unsigned long flags);
-void assign_domain_page(struct domain *d, unsigned long mpaddr, unsigned long 
physaddr);
-void assign_domain_io_page(struct domain *d, unsigned long mpaddr, unsigned 
long flags);
-#ifdef CONFIG_XEN_IA64_DOM0_VP
-void alloc_dom_xen_and_dom_io(void);
-unsigned long assign_domain_mmio_page(struct domain *d, unsigned long mpaddr, 
unsigned long size);
-unsigned long assign_domain_mach_page(struct domain *d, unsigned long mpaddr, 
unsigned long size, unsigned long flags);
-unsigned long do_dom0vp_op(unsigned long cmd, unsigned long arg0, unsigned 
long arg1, unsigned long arg2, unsigned long arg3);
-unsigned long dom0vp_zap_physmap(struct domain *d, unsigned long gpfn, 
unsigned int extent_order);
-unsigned long dom0vp_add_physmap(struct domain* d, unsigned long gpfn, 
unsigned long mfn, unsigned long flags, domid_t domid);
-#else
-#define alloc_dom_xen_and_dom_io()      do { } while (0)
-#endif
-
 #include <asm/uaccess.h> /* for KERNEL_DS */
 #include <asm/pgtable.h>
 
diff -r 34455164dd33 -r f3be4eb8dac9 xen/include/asm-ia64/mm.h
--- a/xen/include/asm-ia64/mm.h Sat Jun 03 13:21:14 2006 -0600
+++ b/xen/include/asm-ia64/mm.h Sat Jun 03 13:21:38 2006 -0600
@@ -1,3 +1,8 @@
+/*
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *                    dom0 vp model support
+ */
 #ifndef __ASM_IA64_MM_H__
 #define __ASM_IA64_MM_H__
 
@@ -416,14 +421,28 @@ extern unsigned long totalram_pages;
 extern unsigned long totalram_pages;
 extern int nr_swap_pages;
 
+extern void alloc_dom_xen_and_dom_io(void);
+extern void relinquish_mm(struct domain* d);
+extern struct page_info * assign_new_domain_page(struct domain *d, unsigned 
long mpaddr);
+extern void assign_new_domain0_page(struct domain *d, unsigned long mpaddr);
+extern void __assign_domain_page(struct domain *d, unsigned long mpaddr, 
unsigned long physaddr, unsigned long flags);
+extern void assign_domain_page(struct domain *d, unsigned long mpaddr, 
unsigned long physaddr);
+extern void assign_domain_io_page(struct domain *d, unsigned long mpaddr, 
unsigned long flags);
+extern unsigned long lookup_domain_mpa(struct domain *d, unsigned long mpaddr);
+
+#ifdef CONFIG_XEN_IA64_DOM0_VP
+extern unsigned long assign_domain_mmio_page(struct domain *d, unsigned long 
mpaddr, unsigned long size);
+extern unsigned long assign_domain_mach_page(struct domain *d, unsigned long 
mpaddr, unsigned long size, unsigned long flags);
+extern unsigned long __lookup_domain_mpa(struct domain *d, unsigned long 
mpaddr);
+extern unsigned long ____lookup_domain_mpa(struct domain *d, unsigned long 
mpaddr);
+extern unsigned long do_dom0vp_op(unsigned long cmd, unsigned long arg0, 
unsigned long arg1, unsigned long arg2, unsigned long arg3);
+extern unsigned long dom0vp_zap_physmap(struct domain *d, unsigned long gpfn, 
unsigned int extent_order);
+extern unsigned long dom0vp_add_physmap(struct domain* d, unsigned long gpfn, 
unsigned long mfn, unsigned long flags, domid_t domid);
+#endif
+
 extern unsigned long *mpt_table;
 extern unsigned long gmfn_to_mfn_foreign(struct domain *d, unsigned long gpfn);
 extern u64 translate_domain_pte(u64 pteval, u64 address, u64 itir__, u64* 
logps);
-extern unsigned long lookup_domain_mpa(struct domain *d, unsigned long mpaddr);
-#ifdef CONFIG_XEN_IA64_DOM0_VP
-extern unsigned long __lookup_domain_mpa(struct domain *d, unsigned long 
mpaddr);
-extern unsigned long ____lookup_domain_mpa(struct domain *d, unsigned long 
mpaddr);
-#endif
 #define machine_to_phys_mapping        mpt_table
 
 #define INVALID_M2P_ENTRY        (~0UL)
diff -r 34455164dd33 -r f3be4eb8dac9 xen/arch/ia64/xen/mm.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/ia64/xen/mm.c    Sat Jun 03 13:21:38 2006 -0600
@@ -0,0 +1,1036 @@
+/*
+ *  Copyright (C) 2005 Intel Co
+ *     Kun Tian (Kevin Tian) <kevin.tian@xxxxxxxxx>
+ *
+ * 05/04/29 Kun Tian (Kevin Tian) <kevin.tian@xxxxxxxxx> Add VTI domain support
+ *
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *                    dom0 vp model support
+ */
+
+#include <xen/config.h>
+#include <asm/xentypes.h>
+#include <asm/mm.h>
+#include <asm/pgalloc.h>
+#include <asm/vhpt.h>
+#include <linux/efi.h>
+
+#ifndef CONFIG_XEN_IA64_DOM0_VP
+#define CONFIG_DOMAIN0_CONTIGUOUS
+#else
+static void domain_page_flush(struct domain* d, unsigned long mpaddr,
+                              unsigned long old_mfn, unsigned long new_mfn);
+#endif
+
+static struct domain *dom_xen, *dom_io;
+
+// followings are stolen from arch_init_memory() @ xen/arch/x86/mm.c
+void
+alloc_dom_xen_and_dom_io(void)
+{
+    /*
+     * Initialise our DOMID_XEN domain.
+     * Any Xen-heap pages that we will allow to be mapped will have
+     * their domain field set to dom_xen.
+     */
+    dom_xen = alloc_domain();
+    BUG_ON(dom_xen == NULL);
+    spin_lock_init(&dom_xen->page_alloc_lock);
+    INIT_LIST_HEAD(&dom_xen->page_list);
+    INIT_LIST_HEAD(&dom_xen->xenpage_list);
+    atomic_set(&dom_xen->refcnt, 1);
+    dom_xen->domain_id = DOMID_XEN;
+
+    /*
+     * Initialise our DOMID_IO domain.
+     * This domain owns I/O pages that are within the range of the page_info
+     * array. Mappings occur at the priv of the caller.
+     */
+    dom_io = alloc_domain();
+    BUG_ON(dom_io == NULL);
+    spin_lock_init(&dom_io->page_alloc_lock);
+    INIT_LIST_HEAD(&dom_io->page_list);
+    INIT_LIST_HEAD(&dom_io->xenpage_list);
+    atomic_set(&dom_io->refcnt, 1);
+    dom_io->domain_id = DOMID_IO;
+}
+
+// heavily depends on the struct page_info layout.
+// if (page_get_owner(page) == d &&
+//     test_and_clear_bit(_PGC_allocated, &page->count_info)) {
+//     put_page(page);
+// }
+static void
+try_to_clear_PGC_allocate(struct domain* d, struct page_info* page)
+{
+    u32 _d, _nd;
+    u64 x, nx, y;
+
+    _d = pickle_domptr(d);
+    y = *((u64*)&page->count_info);
+    do {
+        x = y;
+        _nd = x >> 32;
+        nx = x - 1;
+        __clear_bit(_PGC_allocated, &nx);
+
+        if (unlikely(!(x & PGC_allocated)) || unlikely(_nd != _d)) {
+            struct domain* nd = unpickle_domptr(_nd);
+            if (nd == NULL) {
+                DPRINTK("gnttab_transfer: Bad page %p: ed=%p(%u) 0x%x, "
+                        "sd=%p 0x%x,"
+                        " caf=%016lx, taf=%" PRtype_info "\n",
+                        (void *) page_to_mfn(page),
+                        d, d->domain_id, _d,
+                        nd, _nd,
+                        x,
+                        page->u.inuse.type_info);
+            }
+            break;
+        }
+
+        BUG_ON((nx & PGC_count_mask) < 1);
+        y = cmpxchg((u64*)&page->count_info, x, nx);
+    } while (unlikely(y != x));
+}
+
+static void
+relinquish_pte(struct domain* d, pte_t* pte)
+{
+    unsigned long mfn = pte_pfn(*pte);
+    struct page_info* page;
+
+    // vmx domain use bit[58:56] to distinguish io region from memory.
+    // see vmx_build_physmap_table() in vmx_init.c
+    if (((mfn << PAGE_SHIFT) & GPFN_IO_MASK) != GPFN_MEM)
+        return;
+
+    // domain might map IO space or acpi table pages. check it.
+    if (!mfn_valid(mfn))
+        return;
+    page = mfn_to_page(mfn);
+    // struct page_info corresponding to mfn may exist or not depending
+    // on CONFIG_VIRTUAL_FRAME_TABLE.
+    // This check is too easy.
+    // The right way is to check whether this page is of io area or acpi pages
+    if (page_get_owner(page) == NULL) {
+        BUG_ON(page->count_info != 0);
+        return;
+    }
+
+#ifdef CONFIG_XEN_IA64_DOM0_VP
+    if (page_get_owner(page) == d) {
+        BUG_ON(get_gpfn_from_mfn(mfn) == INVALID_M2P_ENTRY);
+        set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY);
+    }
+#endif
+    try_to_clear_PGC_allocate(d, page);
+    put_page(page);
+}
+
+static void
+relinquish_pmd(struct domain* d, pmd_t* pmd, unsigned long offset)
+{
+    unsigned long i;
+    pte_t* pte = pte_offset_map(pmd, offset);
+
+    for (i = 0; i < PTRS_PER_PTE; i++, pte++) {
+        if (!pte_present(*pte))
+            continue;
+
+        relinquish_pte(d, pte);
+    }
+    pte_free_kernel(pte_offset_map(pmd, offset));
+}
+
+static void
+relinquish_pud(struct domain* d, pud_t *pud, unsigned long offset)
+{
+    unsigned long i;
+    pmd_t *pmd = pmd_offset(pud, offset);
+
+    for (i = 0; i < PTRS_PER_PMD; i++, pmd++) {
+        if (!pmd_present(*pmd))
+            continue;
+
+        relinquish_pmd(d, pmd, offset + (i << PMD_SHIFT));
+    }
+    pmd_free(pmd_offset(pud, offset));
+}
+
+static void
+relinquish_pgd(struct domain* d, pgd_t *pgd, unsigned long offset)
+{
+    unsigned long i;
+    pud_t *pud = pud_offset(pgd, offset);
+
+    for (i = 0; i < PTRS_PER_PUD; i++, pud++) {
+        if (!pud_present(*pud))
+            continue;
+
+        relinquish_pud(d, pud, offset + (i << PUD_SHIFT));
+    }
+    pud_free(pud_offset(pgd, offset));
+}
+
+void
+relinquish_mm(struct domain* d)
+{
+    struct mm_struct* mm = &d->arch.mm;
+    unsigned long i;
+    pgd_t* pgd;
+
+    if (mm->pgd == NULL)
+        return;
+
+    pgd = pgd_offset(mm, 0);
+    for (i = 0; i < PTRS_PER_PGD; i++, pgd++) {
+        if (!pgd_present(*pgd))
+            continue;
+
+        relinquish_pgd(d, pgd, i << PGDIR_SHIFT);
+    }
+    pgd_free(mm->pgd);
+    mm->pgd = NULL;
+}
+
+// stolen from share_xen_page_with_guest() in xen/arch/x86/mm.c
+void
+share_xen_page_with_guest(struct page_info *page,
+                          struct domain *d, int readonly)
+{
+    if ( page_get_owner(page) == d )
+        return;
+
+#if 1
+    if (readonly) {
+        printk("%s:%d readonly is not supported yet\n", __func__, __LINE__);
+    }
+#endif
+
+    // alloc_xenheap_pages() doesn't initialize page owner.
+    //BUG_ON(page_get_owner(page) != NULL);
+#if 0
+    if (get_gpfn_from_mfn(page_to_mfn(page)) != INVALID_M2P_ENTRY) {
+        printk("%s:%d page 0x%p mfn 0x%lx gpfn 0x%lx\n", __func__, __LINE__,
+               page, page_to_mfn(page), get_gpfn_from_mfn(page_to_mfn(page)));
+    }
+#endif
+    // grant_table_destroy() release these pages.
+    // but it doesn't clear m2p entry. So there might remain stale entry.
+    // We clear such a stale entry here.
+    set_gpfn_from_mfn(page_to_mfn(page), INVALID_M2P_ENTRY);
+
+    spin_lock(&d->page_alloc_lock);
+
+#ifndef __ia64__
+    /* The incremented type count pins as writable or read-only. */
+    page->u.inuse.type_info  = (readonly ? PGT_none : PGT_writable_page);
+    page->u.inuse.type_info |= PGT_validated | 1;
+#endif
+
+    page_set_owner(page, d);
+    wmb(); /* install valid domain ptr before updating refcnt. */
+    ASSERT(page->count_info == 0);
+    page->count_info |= PGC_allocated | 1;
+
+    if ( unlikely(d->xenheap_pages++ == 0) )
+        get_knownalive_domain(d);
+    list_add_tail(&page->list, &d->xenpage_list);
+
+    spin_unlock(&d->page_alloc_lock);
+}
+
+void
+share_xen_page_with_privileged_guests(struct page_info *page, int readonly)
+{
+    share_xen_page_with_guest(page, dom_xen, readonly);
+}
+
+//XXX !xxx_present() should be used instread of !xxx_none()?
+static pte_t*
+lookup_alloc_domain_pte(struct domain* d, unsigned long mpaddr)
+{
+    struct mm_struct *mm = &d->arch.mm;
+    pgd_t *pgd;
+    pud_t *pud;
+    pmd_t *pmd;
+
+    BUG_ON(mm->pgd == NULL);
+    pgd = pgd_offset(mm, mpaddr);
+    if (pgd_none(*pgd)) {
+        pgd_populate(mm, pgd, pud_alloc_one(mm,mpaddr));
+    }
+
+    pud = pud_offset(pgd, mpaddr);
+    if (pud_none(*pud)) {
+        pud_populate(mm, pud, pmd_alloc_one(mm,mpaddr));
+    }
+
+    pmd = pmd_offset(pud, mpaddr);
+    if (pmd_none(*pmd)) {
+        pmd_populate_kernel(mm, pmd, pte_alloc_one_kernel(mm, mpaddr));
+    }
+
+    return pte_offset_map(pmd, mpaddr);
+}
+
+//XXX xxx_none() should be used instread of !xxx_present()?
+static pte_t*
+lookup_noalloc_domain_pte(struct domain* d, unsigned long mpaddr)
+{
+    struct mm_struct *mm = &d->arch.mm;
+    pgd_t *pgd;
+    pud_t *pud;
+    pmd_t *pmd;
+
+    BUG_ON(mm->pgd == NULL);
+    pgd = pgd_offset(mm, mpaddr);
+    if (!pgd_present(*pgd))
+        goto not_present;
+
+    pud = pud_offset(pgd, mpaddr);
+    if (!pud_present(*pud))
+        goto not_present;
+
+    pmd = pmd_offset(pud, mpaddr);
+    if (!pmd_present(*pmd))
+        goto not_present;
+
+    return pte_offset_map(pmd, mpaddr);
+
+not_present:
+    return NULL;
+}
+
+#ifdef CONFIG_XEN_IA64_DOM0_VP
+static pte_t*
+lookup_noalloc_domain_pte_none(struct domain* d, unsigned long mpaddr)
+{
+    struct mm_struct *mm = &d->arch.mm;
+    pgd_t *pgd;
+    pud_t *pud;
+    pmd_t *pmd;
+
+    BUG_ON(mm->pgd == NULL);
+    pgd = pgd_offset(mm, mpaddr);
+    if (pgd_none(*pgd))
+        goto not_present;
+
+    pud = pud_offset(pgd, mpaddr);
+    if (pud_none(*pud))
+        goto not_present;
+
+    pmd = pmd_offset(pud, mpaddr);
+    if (pmd_none(*pmd))
+        goto not_present;
+
+    return pte_offset_map(pmd, mpaddr);
+
+not_present:
+    return NULL;
+}
+
+unsigned long
+____lookup_domain_mpa(struct domain *d, unsigned long mpaddr)
+{
+    pte_t *pte;
+
+    pte = lookup_noalloc_domain_pte(d, mpaddr);
+    if (pte == NULL)
+        goto not_present;
+
+    if (pte_present(*pte))
+        return (pte->pte & _PFN_MASK);
+    else if (VMX_DOMAIN(d->vcpu[0]))
+        return GPFN_INV_MASK;
+
+not_present:
+    return INVALID_MFN;
+}
+
+unsigned long
+__lookup_domain_mpa(struct domain *d, unsigned long mpaddr)
+{
+    unsigned long machine = ____lookup_domain_mpa(d, mpaddr);
+    if (machine != INVALID_MFN)
+        return machine;
+
+    printk("%s: d 0x%p id %d current 0x%p id %d\n",
+           __func__, d, d->domain_id, current, current->vcpu_id);
+    printk("%s: bad mpa 0x%lx (max_pages 0x%lx)\n",
+           __func__, mpaddr, (unsigned long)d->max_pages << PAGE_SHIFT);
+    return INVALID_MFN;
+}
+#endif
+
+void mpafoo(unsigned long mpaddr)
+{
+    extern unsigned long privop_trace;
+    if (mpaddr == 0x3800)
+        privop_trace = 1;
+}
+
+unsigned long lookup_domain_mpa(struct domain *d, unsigned long mpaddr)
+{
+    pte_t *pte;
+
+#ifdef CONFIG_DOMAIN0_CONTIGUOUS
+    if (d == dom0) {
+        pte_t pteval;
+        if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
+            //printk("lookup_domain_mpa: bad dom0 mpaddr 0x%lx!\n",mpaddr);
+            //printk("lookup_domain_mpa: 
start=0x%lx,end=0x%lx!\n",dom0_start,dom0_start+dom0_size);
+            mpafoo(mpaddr);
+        }
+        pteval = pfn_pte(mpaddr >> PAGE_SHIFT,
+            __pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX));
+        return pte_val(pteval);
+    }
+#endif
+    pte = lookup_noalloc_domain_pte(d, mpaddr);
+    if (pte != NULL) {
+        if (pte_present(*pte)) {
+//printk("lookup_domain_page: found mapping for %lx, 
pte=%lx\n",mpaddr,pte_val(*pte));
+            return pte_val(*pte);
+        } else if (VMX_DOMAIN(d->vcpu[0]))
+            return GPFN_INV_MASK;
+    }
+
+    printk("%s: d 0x%p id %d current 0x%p id %d\n",
+           __func__, d, d->domain_id, current, current->vcpu_id);
+    if ((mpaddr >> PAGE_SHIFT) < d->max_pages)
+        printk("%s: non-allocated mpa 0x%lx (< 0x%lx)\n", __func__,
+               mpaddr, (unsigned long)d->max_pages << PAGE_SHIFT);
+    else
+        printk("%s: bad mpa 0x%lx (=> 0x%lx)\n", __func__,
+               mpaddr, (unsigned long)d->max_pages << PAGE_SHIFT);
+    mpafoo(mpaddr);
+
+    //XXX This is a work around until the emulation memory access to a region
+    //    where memory or device are attached is implemented.
+    return pte_val(pfn_pte(0, __pgprot(__DIRTY_BITS | _PAGE_PL_2 | 
_PAGE_AR_RWX)));
+}
+
+// FIXME: ONLY USE FOR DOMAIN PAGE_SIZE == PAGE_SIZE
+#if 1
+unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr)
+{
+    unsigned long pte = lookup_domain_mpa(d,mpaddr);
+    unsigned long imva;
+
+    pte &= _PAGE_PPN_MASK;
+    imva = (unsigned long) __va(pte);
+    imva |= mpaddr & ~PAGE_MASK;
+    return(imva);
+}
+#else
+unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr)
+{
+    unsigned long imva = __gpa_to_mpa(d, mpaddr);
+
+    return __va(imva);
+}
+#endif
+
+/* Allocate a new page for domain and map it to the specified metaphysical
+   address.  */
+struct page_info *
+__assign_new_domain_page(struct domain *d, unsigned long mpaddr, pte_t* pte)
+{
+    struct page_info *p = NULL;
+    unsigned long maddr;
+    int ret;
+
+    BUG_ON(!pte_none(*pte));
+
+#ifdef CONFIG_DOMAIN0_CONTIGUOUS
+    if (d == dom0) {
+#if 0
+        if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
+            /* FIXME: is it true ?
+               dom0 memory is not contiguous!  */
+            panic("assign_new_domain_page: bad domain0 "
+                  "mpaddr=%lx, start=%lx, end=%lx!\n",
+                  mpaddr, dom0_start, dom0_start+dom0_size);
+        }
+#endif
+        p = mfn_to_page((mpaddr >> PAGE_SHIFT));
+        return p;
+    }
+#endif
+
+    p = alloc_domheap_page(d);
+    if (unlikely(!p)) {
+        printf("assign_new_domain_page: Can't alloc!!!! Aaaargh!\n");
+        return(p);
+    }
+
+    // zero out pages for security reasons
+    clear_page(page_to_virt(p));
+    maddr = page_to_maddr (p);
+    if (unlikely(maddr > __get_cpu_var(vhpt_paddr)
+                 && maddr < __get_cpu_var(vhpt_pend))) {
+        /* FIXME: how can this happen ?
+           vhpt is allocated by alloc_domheap_page.  */
+        printf("assign_new_domain_page: reassigned vhpt page %lx!!\n",
+               maddr);
+    }
+
+    ret = get_page(p, d);
+    BUG_ON(ret == 0);
+    set_pte(pte, pfn_pte(maddr >> PAGE_SHIFT,
+                         __pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX)));
+
+    mb ();
+    //XXX CONFIG_XEN_IA64_DOM0_VP
+    //    TODO racy
+    set_gpfn_from_mfn(page_to_mfn(p), mpaddr >> PAGE_SHIFT);
+    return p;
+}
+
+struct page_info *
+assign_new_domain_page(struct domain *d, unsigned long mpaddr)
+{
+#ifdef CONFIG_DOMAIN0_CONTIGUOUS
+    pte_t dummy_pte = __pte(0);
+    return __assign_new_domain_page(d, mpaddr, &dummy_pte);
+#else
+    struct page_info *p = NULL;
+    pte_t *pte;
+
+    pte = lookup_alloc_domain_pte(d, mpaddr);
+    if (pte_none(*pte)) {
+        p = __assign_new_domain_page(d, mpaddr, pte);
+    } else {
+        DPRINTK("%s: d 0x%p mpaddr %lx already mapped!\n",
+                __func__, d, mpaddr);
+    }
+
+    return p;
+#endif
+}
+
+void
+assign_new_domain0_page(struct domain *d, unsigned long mpaddr)
+{
+#ifndef CONFIG_DOMAIN0_CONTIGUOUS
+    pte_t *pte;
+
+    BUG_ON(d != dom0);
+    pte = lookup_alloc_domain_pte(d, mpaddr);
+    if (pte_none(*pte)) {
+        struct page_info *p = __assign_new_domain_page(d, mpaddr, pte);
+        if (p == NULL) {
+            panic("%s: can't allocate page for dom0", __func__);
+        }
+    }
+#endif
+}
+
+/* map a physical address to the specified metaphysical addr */
+// flags: currently only ASSIGN_readonly
+void
+__assign_domain_page(struct domain *d,
+                     unsigned long mpaddr, unsigned long physaddr,
+                     unsigned long flags)
+{
+    pte_t *pte;
+    unsigned long arflags = (flags & ASSIGN_readonly)? _PAGE_AR_R: 
_PAGE_AR_RWX;
+
+    pte = lookup_alloc_domain_pte(d, mpaddr);
+    if (pte_none(*pte)) {
+        set_pte(pte, pfn_pte(physaddr >> PAGE_SHIFT,
+                             __pgprot(__DIRTY_BITS | _PAGE_PL_2 | arflags)));
+        mb ();
+    } else
+        printk("%s: mpaddr %lx already mapped!\n", __func__, mpaddr);
+}
+
+/* get_page() and map a physical address to the specified metaphysical addr */
+void
+assign_domain_page(struct domain *d,
+                   unsigned long mpaddr, unsigned long physaddr)
+{
+    struct page_info* page = mfn_to_page(physaddr >> PAGE_SHIFT);
+    int ret;
+
+    BUG_ON((physaddr & GPFN_IO_MASK) != GPFN_MEM);
+    ret = get_page(page, d);
+    BUG_ON(ret == 0);
+    __assign_domain_page(d, mpaddr, physaddr, ASSIGN_writable);
+
+    //XXX CONFIG_XEN_IA64_DOM0_VP
+    //    TODO racy
+    set_gpfn_from_mfn(physaddr >> PAGE_SHIFT, mpaddr >> PAGE_SHIFT);
+}
+
+#ifdef CONFIG_XEN_IA64_DOM0_VP
+static void
+assign_domain_same_page(struct domain *d,
+                        unsigned long mpaddr, unsigned long size,
+                        unsigned long flags)
+{
+    //XXX optimization
+    unsigned long end = mpaddr + size;
+    for (; mpaddr < end; mpaddr += PAGE_SIZE) {
+        __assign_domain_page(d, mpaddr, mpaddr, flags);
+    }
+}
+
+static int
+efi_mmio(unsigned long physaddr, unsigned long size)
+{
+    void *efi_map_start, *efi_map_end;
+    u64 efi_desc_size;
+    void* p;
+
+    efi_map_start = __va(ia64_boot_param->efi_memmap);
+    efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
+    efi_desc_size = ia64_boot_param->efi_memdesc_size;
+
+    for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
+        efi_memory_desc_t* md = (efi_memory_desc_t *)p;
+        unsigned long start = md->phys_addr;
+        unsigned long end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
+
+        if (start <= physaddr && physaddr < end) {
+            if ((physaddr + size) > end) {
+                DPRINTK("%s:%d physaddr 0x%lx size = 0x%lx\n",
+                        __func__, __LINE__, physaddr, size);
+                return 0;
+            }
+
+            // for io space
+            if (md->type == EFI_MEMORY_MAPPED_IO ||
+                md->type == EFI_MEMORY_MAPPED_IO_PORT_SPACE) {
+                return 1;
+            }
+
+            // for runtime
+            // see efi_enter_virtual_mode(void)
+            // in linux/arch/ia64/kernel/efi.c
+            if ((md->attribute & EFI_MEMORY_RUNTIME) &&
+                !(md->attribute & EFI_MEMORY_WB)) {
+                return 1;
+            }
+
+            DPRINTK("%s:%d physaddr 0x%lx size = 0x%lx\n",
+                    __func__, __LINE__, physaddr, size);
+            return 0;
+        }
+
+        if (physaddr < start) {
+            break;
+        }
+    }
+
+    return 1;
+}
+
+unsigned long
+assign_domain_mmio_page(struct domain *d,
+                        unsigned long mpaddr, unsigned long size)
+{
+    if (size == 0) {
+        DPRINTK("%s: domain %p mpaddr 0x%lx size = 0x%lx\n",
+                __func__, d, mpaddr, size);
+    }
+    if (!efi_mmio(mpaddr, size)) {
+        DPRINTK("%s:%d domain %p mpaddr 0x%lx size = 0x%lx\n",
+                __func__, __LINE__, d, mpaddr, size);
+        return -EINVAL;
+    }
+    assign_domain_same_page(d, mpaddr, size, ASSIGN_writable);
+    return mpaddr;
+}
+
+unsigned long
+assign_domain_mach_page(struct domain *d,
+                        unsigned long mpaddr, unsigned long size,
+                        unsigned long flags)
+{
+    assign_domain_same_page(d, mpaddr, size, flags);
+    return mpaddr;
+}
+
+// caller must get_page(mfn_to_page(mfn)) before
+// caller must call set_gpfn_from_mfn().
+// flags: currently only ASSIGN_readonly
+static void
+assign_domain_page_replace(struct domain *d, unsigned long mpaddr,
+                           unsigned long mfn, unsigned long flags)
+{
+    struct mm_struct *mm = &d->arch.mm;
+    pte_t* pte;
+    pte_t old_pte;
+    pte_t npte;
+    unsigned long arflags = (flags & ASSIGN_readonly)? _PAGE_AR_R: 
_PAGE_AR_RWX;
+
+    pte = lookup_alloc_domain_pte(d, mpaddr);
+
+    // update pte
+    npte = pfn_pte(mfn, __pgprot(__DIRTY_BITS | _PAGE_PL_2 | arflags));
+    old_pte = ptep_xchg(mm, mpaddr, pte, npte);
+    if (pte_mem(old_pte)) {
+        unsigned long old_mfn;
+        struct page_info* old_page;
+
+        // XXX should previous underlying page be removed?
+        //  or should error be returned because it is a due to a domain?
+        old_mfn = pte_pfn(old_pte);//XXX
+        old_page = mfn_to_page(old_mfn);
+
+        if (page_get_owner(old_page) == d) {
+            BUG_ON(get_gpfn_from_mfn(old_mfn) != (mpaddr >> PAGE_SHIFT));
+            set_gpfn_from_mfn(old_mfn, INVALID_M2P_ENTRY);
+        }
+
+        domain_page_flush(d, mpaddr, old_mfn, mfn);
+
+        try_to_clear_PGC_allocate(d, old_page);
+        put_page(old_page);
+    } else {
+        BUG_ON(!mfn_valid(mfn));
+        BUG_ON(page_get_owner(mfn_to_page(mfn)) == d &&
+               get_gpfn_from_mfn(mfn) != INVALID_M2P_ENTRY);
+    }
+}
+
+static void
+zap_domain_page_one(struct domain *d, unsigned long mpaddr, int do_put_page)
+{
+    struct mm_struct *mm = &d->arch.mm;
+    pte_t *pte;
+    pte_t old_pte;
+    unsigned long mfn;
+    struct page_info *page;
+
+    pte = lookup_noalloc_domain_pte_none(d, mpaddr);
+    if (pte == NULL)
+        return;
+    if (pte_none(*pte))
+        return;
+
+    // update pte
+    old_pte = ptep_get_and_clear(mm, mpaddr, pte);
+    mfn = pte_pfn(old_pte);
+    page = mfn_to_page(mfn);
+    BUG_ON((page->count_info & PGC_count_mask) == 0);
+
+    if (page_get_owner(page) == d) {
+        BUG_ON(get_gpfn_from_mfn(mfn) != (mpaddr >> PAGE_SHIFT));
+        set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY);
+    }
+
+    domain_page_flush(d, mpaddr, mfn, INVALID_MFN);
+
+    if (do_put_page) {
+        try_to_clear_PGC_allocate(d, page);
+        put_page(page);
+    }
+}
+
+//XXX SMP
+unsigned long
+dom0vp_zap_physmap(struct domain *d, unsigned long gpfn,
+                   unsigned int extent_order)
+{
+    unsigned long ret = 0;
+    if (extent_order != 0) {
+        //XXX
+        ret = -ENOSYS;
+        goto out;
+    }
+
+    zap_domain_page_one(d, gpfn << PAGE_SHIFT, 1);
+
+out:
+    return ret;
+}
+
+unsigned long
+dom0vp_add_physmap(struct domain* d, unsigned long gpfn, unsigned long mfn,
+                   unsigned long flags, domid_t domid)
+{
+    int error = 0;
+    struct domain* rd;
+
+    rd = find_domain_by_id(domid);
+    if (unlikely(rd == NULL)) {
+        switch (domid) {
+        case DOMID_XEN:
+            rd = dom_xen;
+            break;
+        case DOMID_IO:
+            rd = dom_io;
+            break;
+        default:
+            DPRINTK("d 0x%p domid %d "
+                    "pgfn 0x%lx mfn 0x%lx flags 0x%lx domid %d\n",
+                    d, d->domain_id, gpfn, mfn, flags, domid);
+            error = -ESRCH;
+            goto out0;
+        }
+        BUG_ON(rd == NULL);
+        get_knownalive_domain(rd);
+    }
+
+    if (unlikely(rd == d)) {
+        error = -EINVAL;
+        goto out1;
+    }
+    if (unlikely(get_page(mfn_to_page(mfn), rd) == 0)) {
+        error = -EINVAL;
+        goto out1;
+    }
+
+    assign_domain_page_replace(d, gpfn << PAGE_SHIFT, mfn, flags);
+    //don't update p2m table because this page belongs to rd, not d.
+out1:
+    put_domain(rd);
+out0:
+    return error;
+}
+
+// grant table host mapping
+// mpaddr: host_addr: pseudo physical address
+// mfn: frame: machine page frame
+// flags: GNTMAP_readonly | GNTMAP_application_map | GNTMAP_contains_pte
+int
+create_grant_host_mapping(unsigned long gpaddr,
+              unsigned long mfn, unsigned int flags)
+{
+    struct domain* d = current->domain;
+    struct page_info* page;
+    int ret;
+
+    if (flags & (GNTMAP_device_map |
+                 GNTMAP_application_map | GNTMAP_contains_pte)) {
+        DPRINTK("%s: flags 0x%x\n", __func__, flags);
+        return GNTST_general_error;
+    }
+
+    page = mfn_to_page(mfn);
+    ret = get_page(page, page_get_owner(page));
+    BUG_ON(ret == 0);
+
+    assign_domain_page_replace(d, gpaddr, mfn, (flags & GNTMAP_readonly)?
+                                              ASSIGN_readonly: 
ASSIGN_writable);
+    return GNTST_okay;
+}
+
+// grant table host unmapping
+int
+destroy_grant_host_mapping(unsigned long gpaddr,
+               unsigned long mfn, unsigned int flags)
+{
+    struct domain* d = current->domain;
+    pte_t* pte;
+    pte_t old_pte;
+    unsigned long old_mfn = INVALID_MFN;
+    struct page_info* old_page;
+
+    if (flags & (GNTMAP_application_map | GNTMAP_contains_pte)) {
+        DPRINTK("%s: flags 0x%x\n", __func__, flags);
+        return GNTST_general_error;
+    }
+
+    pte = lookup_noalloc_domain_pte(d, gpaddr);
+    if (pte == NULL || !pte_present(*pte) || pte_pfn(*pte) != mfn)
+        return GNTST_general_error;
+
+    // update pte
+    old_pte = ptep_get_and_clear(&d->arch.mm, gpaddr, pte);
+    if (pte_present(old_pte)) {
+        old_mfn = pte_pfn(old_pte);
+    } else {
+        return GNTST_general_error;
+    }
+    domain_page_flush(d, gpaddr, old_mfn, INVALID_MFN);
+
+    old_page = mfn_to_page(old_mfn);
+    BUG_ON(page_get_owner(old_page) == d);//try_to_clear_PGC_allocate(d, page) 
is not needed.
+    put_page(old_page);
+
+    return GNTST_okay;
+}
+
+// heavily depends on the struct page layout.
+//XXX SMP
+int
+steal_page_for_grant_transfer(struct domain *d, struct page_info *page)
+{
+#if 0 /* if big endian */
+# error "implement big endian version of steal_page_for_grant_transfer()"
+#endif
+    u32 _d, _nd;
+    u64 x, nx, y;
+    unsigned long mpaddr = get_gpfn_from_mfn(page_to_mfn(page)) << PAGE_SHIFT;
+    struct page_info *new;
+
+    zap_domain_page_one(d, mpaddr, 0);
+    put_page(page);
+
+    spin_lock(&d->page_alloc_lock);
+
+    /*
+     * The tricky bit: atomically release ownership while there is just one
+     * benign reference to the page (PGC_allocated). If that reference
+     * disappears then the deallocation routine will safely spin.
+     */
+    _d  = pickle_domptr(d);
+    y = *((u64*)&page->count_info);
+    do {
+        x = y;
+        nx = x & 0xffffffff;
+        // page->count_info: untouched
+        // page->u.inused._domain = 0;
+        _nd = x >> 32;
+
+        if (unlikely((x & (PGC_count_mask | PGC_allocated)) !=
+                     (1 | PGC_allocated)) ||
+            unlikely(_nd != _d)) {
+            struct domain* nd = unpickle_domptr(_nd);
+            if (nd == NULL) {
+                DPRINTK("gnttab_transfer: Bad page %p: ed=%p(%u) 0x%x, "
+                        "sd=%p 0x%x,"
+                        " caf=%016lx, taf=%" PRtype_info "\n",
+                        (void *) page_to_mfn(page),
+                        d, d->domain_id, _d,
+                        nd, _nd,
+                        x,
+                        page->u.inuse.type_info);
+            } else {
+                DPRINTK("gnttab_transfer: Bad page %p: ed=%p(%u) 0x%x, "
+                        "sd=%p(%u) 0x%x,"
+                        " caf=%016lx, taf=%" PRtype_info "\n",
+                        (void *) page_to_mfn(page),
+                        d, d->domain_id, _d,
+                        nd, nd->domain_id, _nd,
+                        x,
+                        page->u.inuse.type_info);
+            }
+            spin_unlock(&d->page_alloc_lock);
+            return -1;
+        }
+
+        y = cmpxchg((u64*)&page->count_info, x, nx);
+    } while (unlikely(y != x));
+
+    /*
+     * Unlink from 'd'. At least one reference remains (now anonymous), so
+     * noone else is spinning to try to delete this page from 'd'.
+     */
+    d->tot_pages--;
+    list_del(&page->list);
+
+    spin_unlock(&d->page_alloc_lock);
+
+#if 1
+    //XXX Until net_rx_action() fix
+    // assign new page for this mpaddr
+    new = assign_new_domain_page(d, mpaddr);
+    BUG_ON(new == NULL);//XXX
+#endif
+
+    return 0;
+}
+
+void
+guest_physmap_add_page(struct domain *d, unsigned long gpfn,
+                       unsigned long mfn)
+{
+    int ret;
+
+    ret = get_page(mfn_to_page(mfn), d);
+    BUG_ON(ret == 0);
+    assign_domain_page_replace(d, gpfn << PAGE_SHIFT, mfn, ASSIGN_writable);
+    set_gpfn_from_mfn(mfn, gpfn);//XXX SMP
+
+    //BUG_ON(mfn != ((lookup_domain_mpa(d, gpfn << PAGE_SHIFT) & _PFN_MASK) >> 
PAGE_SHIFT));
+}
+
+void
+guest_physmap_remove_page(struct domain *d, unsigned long gpfn,
+                          unsigned long mfn)
+{
+    BUG_ON(mfn == 0);//XXX
+    zap_domain_page_one(d, gpfn << PAGE_SHIFT, 1);
+}
+
+//XXX sledgehammer.
+//    flush finer range.
+void
+domain_page_flush(struct domain* d, unsigned long mpaddr,
+                  unsigned long old_mfn, unsigned long new_mfn)
+{
+    domain_flush_vtlb_all();
+}
+#endif
+
+/* Flush cache of domain d.  */
+void domain_cache_flush (struct domain *d, int sync_only)
+{
+    struct mm_struct *mm = &d->arch.mm;
+    pgd_t *pgd = mm->pgd;
+    unsigned long maddr;
+    int i,j,k, l;
+    int nbr_page = 0;
+    void (*flush_func)(unsigned long start, unsigned long end);
+    extern void flush_dcache_range (unsigned long, unsigned long);
+
+    if (sync_only)
+        flush_func = &flush_icache_range;
+    else
+        flush_func = &flush_dcache_range;
+
+#ifdef CONFIG_DOMAIN0_CONTIGUOUS
+    if (d == dom0) {
+        /* This is not fully correct (because of hole), but it should
+           be enough for now.  */
+        (*flush_func)(__va_ul (dom0_start),
+                  __va_ul (dom0_start + dom0_size));
+        return;
+    }
+#endif
+    for (i = 0; i < PTRS_PER_PGD; pgd++, i++) {
+        pud_t *pud;
+        if (!pgd_present(*pgd))
+            continue;
+        pud = pud_offset(pgd, 0);
+        for (j = 0; j < PTRS_PER_PUD; pud++, j++) {
+            pmd_t *pmd;
+            if (!pud_present(*pud))
+                continue;
+            pmd = pmd_offset(pud, 0);
+            for (k = 0; k < PTRS_PER_PMD; pmd++, k++) {
+                pte_t *pte;
+                if (!pmd_present(*pmd))
+                    continue;
+                pte = pte_offset_map(pmd, 0);
+                for (l = 0; l < PTRS_PER_PTE; pte++, l++) {
+                    if (!pte_present(*pte))
+                        continue;
+                    /* Convert PTE to maddr.  */
+                    maddr = __va_ul (pte_val(*pte)
+                             & _PAGE_PPN_MASK);
+                    (*flush_func)(maddr, maddr+ PAGE_SIZE);
+                    nbr_page++;
+                }
+            }
+        }
+    }
+    //printf ("domain_cache_flush: %d %d pages\n", d->domain_id, nbr_page);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */

_______________________________________________
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®.