--- /dev/null
+# HG changeset patch
+# User Keir Fraser <keir.fraser@citrix.com>
+# Date 1247484934 -3600
+# Node ID c0cb307d927f7c9cd64a726c3e2124c4c1d7c970
+# Parent 09dbdf12c33decf5a3ae7cf6f5fa7babc34683e9
+Mapping grant references into HVM guests, take 2
+
+After some discussion, here's a second version of the patch I posted a
+couple of weeks back to map grant references into HVM guests. As
+before, this is done by modifying the P2M map, but this time there's
+no new hypercall to do it. Instead, the existing GNTTABOP_map is
+overloaded to perform a P2M mapping if called from a shadow mode
+translate guest. This matches the IA64 API.
+
+Signed-off-by: Steven Smith <steven.smith@citrix.com>
+Acked-by: Tim Deegan <tim.deegan@citrix.com>
+CC: Bhaskar Jayaraman <Bhaskar.Jayaraman@lsi.com>
+
+diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
+index ad5ec35..a8c6d1a 100644
+--- a/xen/arch/x86/hvm/emulate.c
++++ b/xen/arch/x86/hvm/emulate.c
+@@ -408,20 +408,23 @@ static int __hvmemul_read(
+ rc = ((access_type == hvm_access_insn_fetch) ?
+ hvm_fetch_from_guest_virt(p_data, addr, bytes, pfec) :
+ hvm_copy_from_guest_virt(p_data, addr, bytes, pfec));
+- if ( rc == HVMCOPY_bad_gva_to_gfn )
+- return X86EMUL_EXCEPTION;
+
+- if ( rc == HVMCOPY_bad_gfn_to_mfn )
++ switch ( rc )
+ {
++ case HVMCOPY_bad_gva_to_gfn:
++ return X86EMUL_EXCEPTION;
++ case HVMCOPY_unhandleable:
++ return X86EMUL_UNHANDLEABLE;
++ case HVMCOPY_bad_gfn_to_mfn:
+ if ( access_type == hvm_access_insn_fetch )
+ return X86EMUL_UNHANDLEABLE;
+-
+ rc = hvmemul_linear_to_phys(
+ addr, &gpa, bytes, &reps, pfec, hvmemul_ctxt);
+ if ( rc != X86EMUL_OKAY )
+ return rc;
+-
+ return hvmemul_do_mmio(gpa, &reps, bytes, 0, IOREQ_READ, 0, p_data);
++ default:
++ break;
+ }
+
+ return X86EMUL_OKAY;
+@@ -496,18 +499,22 @@ static int hvmemul_write(
+ pfec |= PFEC_user_mode;
+
+ rc = hvm_copy_to_guest_virt(addr, p_data, bytes, pfec);
+- if ( rc == HVMCOPY_bad_gva_to_gfn )
+- return X86EMUL_EXCEPTION;
+
+- if ( rc == HVMCOPY_bad_gfn_to_mfn )
++ switch ( rc )
+ {
++ case HVMCOPY_bad_gva_to_gfn:
++ return X86EMUL_EXCEPTION;
++ case HVMCOPY_unhandleable:
++ return X86EMUL_UNHANDLEABLE;
++ case HVMCOPY_bad_gfn_to_mfn:
+ rc = hvmemul_linear_to_phys(
+ addr, &gpa, bytes, &reps, pfec, hvmemul_ctxt);
+ if ( rc != X86EMUL_OKAY )
+ return rc;
+-
+ return hvmemul_do_mmio(gpa, &reps, bytes, 0,
+ IOREQ_WRITE, 0, p_data);
++ default:
++ break;
+ }
+
+ return X86EMUL_OKAY;
+@@ -636,12 +643,12 @@ static int hvmemul_rep_movs(
+ return rc;
+
+ (void)gfn_to_mfn_current(sgpa >> PAGE_SHIFT, &p2mt);
+- if ( !p2m_is_ram(p2mt) )
++ if ( !p2m_is_ram(p2mt) && !p2m_is_grant(p2mt) )
+ return hvmemul_do_mmio(
+ sgpa, reps, bytes_per_rep, dgpa, IOREQ_READ, df, NULL);
+
+ (void)gfn_to_mfn_current(dgpa >> PAGE_SHIFT, &p2mt);
+- if ( !p2m_is_ram(p2mt) )
++ if ( !p2m_is_ram(p2mt) && !p2m_is_grant(p2mt) )
+ return hvmemul_do_mmio(
+ dgpa, reps, bytes_per_rep, sgpa, IOREQ_WRITE, df, NULL);
+
+diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
+index 42652ca..bd1faba 100644
+--- a/xen/arch/x86/hvm/hvm.c
++++ b/xen/arch/x86/hvm/hvm.c
+@@ -1536,6 +1536,8 @@ static enum hvm_copy_result __hvm_copy(
+
+ mfn = mfn_x(gfn_to_mfn_current(gfn, &p2mt));
+
++ if ( p2m_is_grant(p2mt) )
++ return HVMCOPY_unhandleable;
+ if ( !p2m_is_ram(p2mt) )
+ return HVMCOPY_bad_gfn_to_mfn;
+ ASSERT(mfn_valid(mfn));
+@@ -1929,7 +1931,8 @@ enum hvm_intblk hvm_interrupt_blocked(struct vcpu *v, struct hvm_intack intack)
+ static long hvm_grant_table_op(
+ unsigned int cmd, XEN_GUEST_HANDLE(void) uop, unsigned int count)
+ {
+- if ( (cmd != GNTTABOP_query_size) && (cmd != GNTTABOP_setup_table) )
++ if ( (cmd != GNTTABOP_query_size) && (cmd != GNTTABOP_setup_table) &&
++ (cmd != GNTTABOP_map_grant_ref) && (cmd != GNTTABOP_unmap_grant_ref) )
+ return -ENOSYS; /* all other commands need auditing */
+ return do_grant_table_op(cmd, uop, count);
+ }
+@@ -2736,17 +2739,36 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
+
+ if ( a.hvmmem_type >= ARRAY_SIZE(memtype) )
+ goto param_fail4;
+-
+- rc = 0;
+-
++
+ for ( pfn = a.first_pfn; pfn < a.first_pfn + a.nr; pfn++ )
+ {
+ p2m_type_t t;
++ p2m_type_t nt;
+ mfn_t mfn;
+ mfn = gfn_to_mfn(d, pfn, &t);
+- p2m_change_type(d, pfn, t, memtype[a.hvmmem_type]);
++ if ( p2m_is_grant(t) )
++ {
++ gdprintk(XENLOG_WARNING,
++ "type for pfn 0x%lx changed to grant while "
++ "we were working?\n", pfn);
++ goto param_fail4;
++ }
++ else
++ {
++ nt = p2m_change_type(d, pfn, t, memtype[a.hvmmem_type]);
++ if ( nt != t )
++ {
++ gdprintk(XENLOG_WARNING,
++ "type of pfn 0x%lx changed from %d to %d while "
++ "we were trying to change it to %d\n",
++ pfn, t, nt, memtype[a.hvmmem_type]);
++ goto param_fail4;
++ }
++ }
+ }
+-
++
++ rc = 0;
++
+ param_fail4:
+ rcu_unlock_domain(d);
+ break;
+diff --git a/xen/arch/x86/hvm/stdvga.c b/xen/arch/x86/hvm/stdvga.c
+index dd060fb..3e796a5 100644
+--- a/xen/arch/x86/hvm/stdvga.c
++++ b/xen/arch/x86/hvm/stdvga.c
+@@ -478,8 +478,8 @@ static int mmio_move(struct hvm_hw_stdvga *s, ioreq_t *p)
+ for ( i = 0; i < p->count; i++ )
+ {
+ tmp = stdvga_mem_read(addr, p->size);
+- if ( hvm_copy_to_guest_phys(data, &tmp, p->size) ==
+- HVMCOPY_bad_gfn_to_mfn )
++ if ( hvm_copy_to_guest_phys(data, &tmp, p->size) !=
++ HVMCOPY_okay )
+ {
+ (void)gfn_to_mfn_current(data >> PAGE_SHIFT, &p2mt);
+ /*
+@@ -500,8 +500,8 @@ static int mmio_move(struct hvm_hw_stdvga *s, ioreq_t *p)
+ uint32_t addr = p->addr, data = p->data, tmp;
+ for ( i = 0; i < p->count; i++ )
+ {
+- if ( hvm_copy_from_guest_phys(&tmp, data, p->size) ==
+- HVMCOPY_bad_gfn_to_mfn )
++ if ( hvm_copy_from_guest_phys(&tmp, data, p->size) !=
++ HVMCOPY_okay )
+ {
+ (void)gfn_to_mfn_current(data >> PAGE_SHIFT, &p2mt);
+ if ( (p2mt != p2m_mmio_dm) || (data < VGA_MEM_BASE) ||
+diff --git a/xen/arch/x86/hvm/svm/emulate.c b/xen/arch/x86/hvm/svm/emulate.c
+index 28b723f..b92ac06 100644
+--- a/xen/arch/x86/hvm/svm/emulate.c
++++ b/xen/arch/x86/hvm/svm/emulate.c
+@@ -121,11 +121,10 @@ static int fetch(struct vcpu *v, u8 *buf, unsigned long addr, int len)
+ switch ( hvm_fetch_from_guest_virt(buf, addr, len, pfec) )
+ {
+ case HVMCOPY_okay:
+- return 1;
++ break;
+ case HVMCOPY_bad_gva_to_gfn:
+ /* OK just to give up; we'll have injected #PF already */
+ return 0;
+- case HVMCOPY_bad_gfn_to_mfn:
+ default:
+ /* Not OK: fetches from non-RAM pages are not supportable. */
+ gdprintk(XENLOG_WARNING, "Bad instruction fetch at %#lx (%#lx)\n",
+@@ -133,6 +132,7 @@ static int fetch(struct vcpu *v, u8 *buf, unsigned long addr, int len)
+ hvm_inject_exception(TRAP_gp_fault, 0, 0);
+ return 0;
+ }
++ return 1;
+ }
+
+ int __get_instruction_length_from_list(struct vcpu *v,
+diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
+index 2b8428c..b12cf30 100644
+--- a/xen/arch/x86/hvm/svm/svm.c
++++ b/xen/arch/x86/hvm/svm/svm.c
+@@ -928,8 +928,27 @@ static void svm_do_nested_pgfault(paddr_t gpa, struct cpu_user_regs *regs)
+ }
+
+ /* Log-dirty: mark the page dirty and let the guest write it again */
+- paging_mark_dirty(current->domain, mfn_x(mfn));
+- p2m_change_type(current->domain, gfn, p2m_ram_logdirty, p2m_ram_rw);
++ if ( p2mt == p2m_ram_logdirty )
++ {
++ paging_mark_dirty(current->domain, mfn_x(mfn));
++ p2m_change_type(current->domain, gfn, p2m_ram_logdirty, p2m_ram_rw);
++ return;
++ }
++
++ /* Okay, this shouldn't happen. Maybe the guest was writing to a
++ read-only grant mapping? */
++ if ( p2mt == p2m_grant_map_ro )
++ {
++ /* Naughty... */
++ gdprintk(XENLOG_WARNING,
++ "trying to write to read-only grant mapping\n");
++ hvm_inject_exception(TRAP_gp_fault, 0, 0);
++ return;
++ }
++
++ /* Something bad has happened; either Xen or the hardware have
++ screwed up. */
++ gdprintk(XENLOG_WARNING, "unexpected SVM nested page fault\n");
+ }
+
+ static void svm_fpu_dirty_intercept(void)
+diff --git a/xen/arch/x86/hvm/viridian.c b/xen/arch/x86/hvm/viridian.c
+index ca4f224..37d2615 100644
+--- a/xen/arch/x86/hvm/viridian.c
++++ b/xen/arch/x86/hvm/viridian.c
+@@ -213,7 +213,7 @@ int wrmsr_viridian_regs(uint32_t idx, uint32_t eax, uint32_t edx)
+ {
+ uint32_t word = 0;
+ paddr_t page_start = val & ~1ul;
+- hvm_copy_to_guest_phys(page_start, &word, sizeof(word));
++ (void)hvm_copy_to_guest_phys(page_start, &word, sizeof(word));
+ }
+ break;
+
+diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
+index 0d6d5ee..cc0f9ee 100644
+--- a/xen/arch/x86/mm.c
++++ b/xen/arch/x86/mm.c
+@@ -2655,10 +2655,16 @@ int do_mmuext_op(
+ break;
+ }
+
+- okay = 1;
+ gmfn = op.arg1.mfn;
+ mfn = gmfn_to_mfn(FOREIGNDOM, gmfn);
++ if ( mfn == INVALID_MFN )
++ {
++ MEM_LOG("Bad gmfn_to_mfn");
++ rc = -EFAULT;
++ break;
++ }
+ page = mfn_to_page(mfn);
++ okay = 1;
+
+ switch ( op.cmd )
+ {
+@@ -3437,11 +3443,37 @@ static int destroy_grant_va_mapping(
+ return replace_grant_va_mapping(addr, frame, l1e_empty(), v);
+ }
+
++static int create_grant_p2m_mapping(uint64_t addr, unsigned long frame,
++ unsigned int flags,
++ unsigned int cache_flags)
++{
++ p2m_type_t p2mt;
++ int rc;
++
++ if ( cache_flags || (flags & ~GNTMAP_readonly) != GNTMAP_host_map )
++ return GNTST_general_error;
++
++ if ( flags & GNTMAP_readonly )
++ p2mt = p2m_grant_map_ro;
++ else
++ p2mt = p2m_grant_map_rw;
++ rc = guest_physmap_add_entry(current->domain, addr >> PAGE_SHIFT,
++ frame, 0, p2mt);
++ if ( rc )
++ return GNTST_general_error;
++ else
++ return GNTST_okay;
++}
++
+ int create_grant_host_mapping(uint64_t addr, unsigned long frame,
+ unsigned int flags, unsigned int cache_flags)
+ {
+- l1_pgentry_t pte = l1e_from_pfn(frame, GRANT_PTE_FLAGS);
++ l1_pgentry_t pte;
+
++ if ( paging_mode_external(current->domain) )
++ return create_grant_p2m_mapping(addr, frame, flags, cache_flags);
++
++ pte = l1e_from_pfn(frame, GRANT_PTE_FLAGS);
+ if ( (flags & GNTMAP_application_map) )
+ l1e_add_flags(pte,_PAGE_USER);
+ if ( !(flags & GNTMAP_readonly) )
+@@ -3458,6 +3490,29 @@ int create_grant_host_mapping(uint64_t addr, unsigned long frame,
+ return create_grant_va_mapping(addr, pte, current);
+ }
+
++static int replace_grant_p2m_mapping(
++ uint64_t addr, unsigned long frame, uint64_t new_addr, unsigned int flags)
++{
++ unsigned long gfn = (unsigned long)(addr >> PAGE_SHIFT);
++ p2m_type_t type;
++ mfn_t old_mfn;
++
++ if ( new_addr != 0 || (flags & GNTMAP_contains_pte) )
++ return GNTST_general_error;
++
++ old_mfn = gfn_to_mfn_current(gfn, &type);
++ if ( !p2m_is_grant(type) || mfn_x(old_mfn) != frame )
++ {
++ gdprintk(XENLOG_WARNING,
++ "replace_grant_p2m_mapping: old mapping invalid (type %d, mfn %lx, frame %lx)\n",
++ type, mfn_x(old_mfn), frame);
++ return GNTST_general_error;
++ }
++ guest_physmap_remove_page(current->domain, gfn, frame, 0);
++
++ return GNTST_okay;
++}
++
+ int replace_grant_host_mapping(
+ uint64_t addr, unsigned long frame, uint64_t new_addr, unsigned int flags)
+ {
+@@ -3467,6 +3522,9 @@ int replace_grant_host_mapping(
+ struct page_info *l1pg;
+ int rc;
+
++ if ( paging_mode_external(current->domain) )
++ return replace_grant_p2m_mapping(addr, frame, new_addr, flags);
++
+ if ( flags & GNTMAP_contains_pte )
+ {
+ if ( !new_addr )
+diff --git a/xen/arch/x86/mm/hap/p2m-ept.c b/xen/arch/x86/mm/hap/p2m-ept.c
+index 4017248..8ffc0a5 100644
+--- a/xen/arch/x86/mm/hap/p2m-ept.c
++++ b/xen/arch/x86/mm/hap/p2m-ept.c
+@@ -40,10 +40,12 @@ static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type)
+ return;
+ case p2m_ram_rw:
+ case p2m_mmio_direct:
++ case p2m_grant_map_rw:
+ entry->r = entry->w = entry->x = 1;
+ return;
+ case p2m_ram_logdirty:
+ case p2m_ram_ro:
++ case p2m_grant_map_ro:
+ entry->r = entry->x = 1;
+ entry->w = 0;
+ return;
+diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
+index 296eb44..cc0bd11 100644
+--- a/xen/arch/x86/mm/p2m.c
++++ b/xen/arch/x86/mm/p2m.c
+@@ -102,17 +102,27 @@
+
+ static unsigned long p2m_type_to_flags(p2m_type_t t)
+ {
+- unsigned long flags = (t & 0x7UL) << 9;
++ unsigned long flags;
++#ifdef __x86_64__
++ flags = (unsigned long)(t & 0x3fff) << 9;
++#else
++ flags = (t & 0x7UL) << 9;
++#endif
++#ifndef HAVE_GRANT_MAP_P2M
++ BUG_ON(p2m_is_grant(t));
++#endif
+ switch(t)
+ {
+ case p2m_invalid:
+ default:
+ return flags;
+ case p2m_ram_rw:
++ case p2m_grant_map_rw:
+ return flags | P2M_BASE_FLAGS | _PAGE_RW;
+ case p2m_ram_logdirty:
+ return flags | P2M_BASE_FLAGS;
+ case p2m_ram_ro:
++ case p2m_grant_map_ro:
+ return flags | P2M_BASE_FLAGS;
+ case p2m_mmio_dm:
+ return flags;
+@@ -1321,7 +1331,7 @@ pod_retry_l1:
+ unmap_domain_page(l1e);
+
+ ASSERT(mfn_valid(mfn) || !p2m_is_ram(*t));
+- return (p2m_is_valid(*t)) ? mfn : _mfn(INVALID_MFN);
++ return (p2m_is_valid(*t) || p2m_is_grant(*t)) ? mfn : _mfn(INVALID_MFN);
+ }
+
+ /* Read the current domain's p2m table (through the linear mapping). */
+@@ -1438,7 +1448,7 @@ static mfn_t p2m_gfn_to_mfn_current(unsigned long gfn, p2m_type_t *t,
+ }
+ }
+
+- if ( p2m_is_valid(p2mt) )
++ if ( p2m_is_valid(p2mt) || p2m_is_grant(p2mt) )
+ mfn = _mfn(l1e_get_pfn(l1e));
+ else
+ /* XXX see above */
+@@ -1790,17 +1800,22 @@ static void audit_p2m(struct domain *d)
+
+ for ( i1 = 0; i1 < L1_PAGETABLE_ENTRIES; i1++, gfn++ )
+ {
++ p2m_type_t type;
++
++ type = p2m_flags_to_type(l1e_get_flags(l1e[i1]));
+ if ( !(l1e_get_flags(l1e[i1]) & _PAGE_PRESENT) )
+ {
+- if ( p2m_flags_to_type(l1e_get_flags(l1e[i1]))
+- == p2m_populate_on_demand )
++ if ( type == p2m_populate_on_demand )
+ entry_count++;
+ continue;
+ }
+ mfn = l1e_get_pfn(l1e[i1]);
+ ASSERT(mfn_valid(_mfn(mfn)));
+ m2pfn = get_gpfn_from_mfn(mfn);
+- if ( m2pfn != gfn )
++ if ( m2pfn != gfn &&
++ type != p2m_mmio_direct &&
++ !p2m_is_grant(type) )
++
+ {
+ pmbad++;
+ printk("mismatch: gfn %#lx -> mfn %#lx"
+@@ -1853,6 +1868,8 @@ p2m_remove_page(struct domain *d, unsigned long gfn, unsigned long mfn,
+ unsigned int page_order)
+ {
+ unsigned long i;
++ mfn_t mfn_return;
++ p2m_type_t t;
+
+ if ( !paging_mode_translate(d) )
+ {
+@@ -1864,9 +1881,14 @@ p2m_remove_page(struct domain *d, unsigned long gfn, unsigned long mfn,
+
+ P2M_DEBUG("removing gfn=%#lx mfn=%#lx\n", gfn, mfn);
+
+- set_p2m_entry(d, gfn, _mfn(INVALID_MFN), page_order, p2m_invalid);
+ for ( i = 0; i < (1UL << page_order); i++ )
+- set_gpfn_from_mfn(mfn+i, INVALID_M2P_ENTRY);
++ {
++ mfn_return = p2m_gfn_to_mfn(d, gfn + i, &t, p2m_query);
++ if ( !p2m_is_grant(t) )
++ set_gpfn_from_mfn(mfn+i, INVALID_M2P_ENTRY);
++ ASSERT( !p2m_is_valid(t) || mfn + i == mfn_x(mfn_return) );
++ }
++ set_p2m_entry(d, gfn, _mfn(INVALID_MFN), page_order, p2m_invalid);
+ }
+
+ void
+@@ -2002,7 +2024,14 @@ guest_physmap_add_entry(struct domain *d, unsigned long gfn,
+ for ( i = 0; i < (1UL << page_order); i++ )
+ {
+ omfn = gfn_to_mfn_query(d, gfn + i, &ot);
+- if ( p2m_is_ram(ot) )
++ if ( p2m_is_grant(ot) )
++ {
++ /* Really shouldn't be unmapping grant maps this way */
++ domain_crash(d);
++ p2m_unlock(d->arch.p2m);
++ return -EINVAL;
++ }
++ else if ( p2m_is_ram(ot) )
+ {
+ ASSERT(mfn_valid(omfn));
+ set_gpfn_from_mfn(mfn_x(omfn), INVALID_M2P_ENTRY);
+@@ -2017,6 +2046,8 @@ guest_physmap_add_entry(struct domain *d, unsigned long gfn,
+ /* Then, look for m->p mappings for this range and deal with them */
+ for ( i = 0; i < (1UL << page_order); i++ )
+ {
++ if ( page_get_owner(mfn_to_page(_mfn(mfn + i))) != d )
++ continue;
+ ogfn = mfn_to_gfn(d, _mfn(mfn+i));
+ if (
+ #ifdef __x86_64__
+@@ -2032,6 +2063,9 @@ guest_physmap_add_entry(struct domain *d, unsigned long gfn,
+ P2M_DEBUG("aliased! mfn=%#lx, old gfn=%#lx, new gfn=%#lx\n",
+ mfn + i, ogfn, gfn + i);
+ omfn = gfn_to_mfn_query(d, ogfn, &ot);
++ /* If we get here, we know the local domain owns the page,
++ so it can't have been grant mapped in. */
++ BUG_ON( p2m_is_grant(ot) );
+ if ( p2m_is_ram(ot) )
+ {
+ ASSERT(mfn_valid(omfn));
+@@ -2048,8 +2082,11 @@ guest_physmap_add_entry(struct domain *d, unsigned long gfn,
+ {
+ if ( !set_p2m_entry(d, gfn, _mfn(mfn), page_order, t) )
+ rc = -EINVAL;
+- for ( i = 0; i < (1UL << page_order); i++ )
+- set_gpfn_from_mfn(mfn+i, gfn+i);
++ if ( !p2m_is_grant(t) )
++ {
++ for ( i = 0; i < (1UL << page_order); i++ )
++ set_gpfn_from_mfn(mfn+i, gfn+i);
++ }
+ }
+ else
+ {
+@@ -2089,6 +2126,8 @@ void p2m_change_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt)
+ int i4;
+ #endif /* CONFIG_PAGING_LEVELS == 4 */
+
++ BUG_ON(p2m_is_grant(ot) || p2m_is_grant(nt));
++
+ if ( !paging_mode_translate(d) )
+ return;
+
+@@ -2184,6 +2223,8 @@ p2m_type_t p2m_change_type(struct domain *d, unsigned long gfn,
+ p2m_type_t pt;
+ mfn_t mfn;
+
++ BUG_ON(p2m_is_grant(ot) || p2m_is_grant(nt));
++
+ p2m_lock(d->arch.p2m);
+
+ mfn = gfn_to_mfn(d, gfn, &pt);
+@@ -2206,7 +2247,12 @@ set_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn)
+ return 0;
+
+ omfn = gfn_to_mfn_query(d, gfn, &ot);
+- if ( p2m_is_ram(ot) )
++ if ( p2m_is_grant(ot) )
++ {
++ domain_crash(d);
++ return 0;
++ }
++ else if ( p2m_is_ram(ot) )
+ {
+ ASSERT(mfn_valid(omfn));
+ set_gpfn_from_mfn(mfn_x(omfn), INVALID_M2P_ENTRY);
+diff --git a/xen/arch/x86/mm/paging.c b/xen/arch/x86/mm/paging.c
+index 38f1202..8a80ad8 100644
+--- a/xen/arch/x86/mm/paging.c
++++ b/xen/arch/x86/mm/paging.c
+@@ -272,7 +272,8 @@ void paging_mark_dirty(struct domain *d, unsigned long guest_mfn)
+
+ gmfn = _mfn(guest_mfn);
+
+- if ( !paging_mode_log_dirty(d) || !mfn_valid(gmfn) )
++ if ( !paging_mode_log_dirty(d) || !mfn_valid(gmfn) ||
++ page_get_owner(mfn_to_page(gmfn)) != d )
+ return;
+
+ log_dirty_lock(d);
+diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c
+index ca4cb13..cee2b7c 100644
+--- a/xen/arch/x86/mm/shadow/common.c
++++ b/xen/arch/x86/mm/shadow/common.c
+@@ -172,10 +172,12 @@ hvm_read(enum x86_segment seg,
+ return X86EMUL_OKAY;
+ case HVMCOPY_bad_gva_to_gfn:
+ return X86EMUL_EXCEPTION;
+- default:
+- break;
++ case HVMCOPY_bad_gfn_to_mfn:
++ case HVMCOPY_unhandleable:
++ return X86EMUL_UNHANDLEABLE;
+ }
+
++ BUG();
+ return X86EMUL_UNHANDLEABLE;
+ }
+
+@@ -3431,7 +3433,7 @@ shadow_write_p2m_entry(struct vcpu *v, unsigned long gfn,
+ {
+ mfn_t mfn = _mfn(l1e_get_pfn(*p));
+ p2m_type_t p2mt = p2m_flags_to_type(l1e_get_flags(*p));
+- if ( p2m_is_valid(p2mt) && mfn_valid(mfn) )
++ if ( (p2m_is_valid(p2mt) || p2m_is_grant(p2mt)) && mfn_valid(mfn) )
+ {
+ sh_remove_all_shadows_and_parents(v, mfn);
+ if ( sh_remove_all_mappings(v, mfn) )
+diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c
+index b8cd752..b97ed37 100644
+--- a/xen/arch/x86/mm/shadow/multi.c
++++ b/xen/arch/x86/mm/shadow/multi.c
+@@ -483,7 +483,7 @@ _sh_propagate(struct vcpu *v,
+ ASSERT(GUEST_PAGING_LEVELS > 3 || level != 3);
+
+ /* Check there's something for the shadows to map to */
+- if ( !p2m_is_valid(p2mt) )
++ if ( !p2m_is_valid(p2mt) && !p2m_is_grant(p2mt) )
+ {
+ *sp = shadow_l1e_empty();
+ goto done;
+@@ -629,7 +629,7 @@ _sh_propagate(struct vcpu *v,
+ }
+
+ /* Read-only memory */
+- if ( p2mt == p2m_ram_ro )
++ if ( p2m_is_readonly(p2mt) )
+ sflags &= ~_PAGE_RW;
+
+ // protect guest page tables
+@@ -806,8 +806,10 @@ perms_strictly_increased(u32 old_flags, u32 new_flags)
+ return ((of | (of ^ nf)) == nf);
+ }
+
++/* type is only used to distinguish grant map pages from ordinary RAM
++ * i.e. non-p2m_is_grant() pages are treated as p2m_ram_rw. */
+ static int inline
+-shadow_get_page_from_l1e(shadow_l1e_t sl1e, struct domain *d)
++shadow_get_page_from_l1e(shadow_l1e_t sl1e, struct domain *d, p2m_type_t type)
+ {
+ int res;
+ mfn_t mfn;
+@@ -837,6 +839,20 @@ shadow_get_page_from_l1e(shadow_l1e_t sl1e, struct domain *d)
+ res ? "success" : "failed");
+ }
+
++ /* Okay, it might still be a grant mapping PTE. Try it. */
++ if ( unlikely(!res) &&
++ (type == p2m_grant_map_rw ||
++ (type == p2m_grant_map_ro &&
++ !(shadow_l1e_get_flags(sl1e) & _PAGE_RW))) )
++ {
++ /* It's a grant mapping. The grant table implementation will
++ already have checked that we're supposed to have access, so
++ we can just grab a reference directly. */
++ mfn = shadow_l1e_get_mfn(sl1e);
++ if ( mfn_valid(mfn) )
++ res = get_page_from_l1e(sl1e, d, page_get_owner(mfn_to_page(mfn)));
++ }
++
+ if ( unlikely(!res) )
+ {
+ perfc_incr(shadow_get_page_fail);
+@@ -1130,6 +1146,7 @@ static inline void shadow_vram_put_l1e(shadow_l1e_t old_sl1e,
+ static int shadow_set_l1e(struct vcpu *v,
+ shadow_l1e_t *sl1e,
+ shadow_l1e_t new_sl1e,
++ p2m_type_t new_type,
+ mfn_t sl1mfn)
+ {
+ int flags = 0;
+@@ -1157,7 +1174,7 @@ static int shadow_set_l1e(struct vcpu *v,
+ /* About to install a new reference */
+ if ( shadow_mode_refcounts(d) ) {
+ TRACE_SHADOW_PATH_FLAG(TRCE_SFLAG_SHADOW_L1_GET_REF);
+- if ( shadow_get_page_from_l1e(new_sl1e, d) == 0 )
++ if ( shadow_get_page_from_l1e(new_sl1e, d, new_type) == 0 )
+ {
+ /* Doesn't look like a pagetable. */
+ flags |= SHADOW_SET_ERROR;
+@@ -2374,7 +2391,7 @@ static int validate_gl1e(struct vcpu *v, void *new_ge, mfn_t sl1mfn, void *se)
+ gmfn = gfn_to_mfn_query(v->domain, gfn, &p2mt);
+
+ l1e_propagate_from_guest(v, new_gl1e, gmfn, &new_sl1e, ft_prefetch, p2mt);
+- result |= shadow_set_l1e(v, sl1p, new_sl1e, sl1mfn);
++ result |= shadow_set_l1e(v, sl1p, new_sl1e, p2mt, sl1mfn);
+
+ #if (SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC)
+ gl1mfn = _mfn(mfn_to_page(sl1mfn)->v.sh.back);
+@@ -2433,8 +2450,8 @@ void sh_resync_l1(struct vcpu *v, mfn_t gl1mfn, mfn_t snpmfn)
+ gfn = guest_l1e_get_gfn(gl1e);
+ gmfn = gfn_to_mfn_query(v->domain, gfn, &p2mt);
+ l1e_propagate_from_guest(v, gl1e, gmfn, &nsl1e, ft_prefetch, p2mt);
+- rc |= shadow_set_l1e(v, sl1p, nsl1e, sl1mfn);
+-
++ rc |= shadow_set_l1e(v, sl1p, nsl1e, p2mt, sl1mfn);
++
+ *snpl1p = gl1e;
+ }
+ });
+@@ -2751,7 +2768,7 @@ static void sh_prefetch(struct vcpu *v, walk_t *gw,
+
+ /* Propagate the entry. */
+ l1e_propagate_from_guest(v, gl1e, gmfn, &sl1e, ft_prefetch, p2mt);
+- (void) shadow_set_l1e(v, ptr_sl1e + i, sl1e, sl1mfn);
++ (void) shadow_set_l1e(v, ptr_sl1e + i, sl1e, p2mt, sl1mfn);
+
+ #if (SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC)
+ if ( snpl1p != NULL )
+@@ -3106,7 +3123,8 @@ static int sh_page_fault(struct vcpu *v,
+ gmfn = gfn_to_mfn_guest(d, gfn, &p2mt);
+
+ if ( shadow_mode_refcounts(d) &&
+- (!p2m_is_valid(p2mt) || (!p2m_is_mmio(p2mt) && !mfn_valid(gmfn))) )
++ ((!p2m_is_valid(p2mt) && !p2m_is_grant(p2mt)) ||
++ (!p2m_is_mmio(p2mt) && !mfn_valid(gmfn))) )
+ {
+ perfc_incr(shadow_fault_bail_bad_gfn);
+ SHADOW_PRINTK("BAD gfn=%"SH_PRI_gfn" gmfn=%"PRI_mfn"\n",
+@@ -3204,7 +3222,7 @@ static int sh_page_fault(struct vcpu *v,
+
+ /* Calculate the shadow entry and write it */
+ l1e_propagate_from_guest(v, gw.l1e, gmfn, &sl1e, ft, p2mt);
+- r = shadow_set_l1e(v, ptr_sl1e, sl1e, sl1mfn);
++ r = shadow_set_l1e(v, ptr_sl1e, sl1e, p2mt, sl1mfn);
+
+ #if (SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC)
+ if ( mfn_valid(gw.l1mfn)
+@@ -3257,7 +3275,7 @@ static int sh_page_fault(struct vcpu *v,
+ }
+
+ /* Ignore attempts to write to read-only memory. */
+- if ( (p2mt == p2m_ram_ro) && (ft == ft_demand_write) )
++ if ( p2m_is_readonly(p2mt) && (ft == ft_demand_write) )
+ {
+ static unsigned long lastpage;
+ if ( xchg(&lastpage, va & PAGE_MASK) != (va & PAGE_MASK) )
+@@ -3600,7 +3618,8 @@ sh_invlpg(struct vcpu *v, unsigned long va)
+ shadow_l1e_t *sl1;
+ sl1 = sh_linear_l1_table(v) + shadow_l1_linear_offset(va);
+ /* Remove the shadow entry that maps this VA */
+- (void) shadow_set_l1e(v, sl1, shadow_l1e_empty(), sl1mfn);
++ (void) shadow_set_l1e(v, sl1, shadow_l1e_empty(),
++ p2m_invalid, sl1mfn);
+ }
+ shadow_unlock(v->domain);
+ /* Need the invlpg, to pick up the disappeareance of the sl1e */
+@@ -4315,7 +4334,7 @@ int sh_rm_write_access_from_sl1p(struct vcpu *v, mfn_t gmfn,
+
+ /* Found it! Need to remove its write permissions. */
+ sl1e = shadow_l1e_remove_flags(sl1e, _PAGE_RW);
+- r = shadow_set_l1e(v, sl1p, sl1e, smfn);
++ r = shadow_set_l1e(v, sl1p, sl1e, p2m_ram_rw, smfn);
+ ASSERT( !(r & SHADOW_SET_ERROR) );
+
+ sh_unmap_domain_page(sl1p);
+@@ -4369,8 +4388,12 @@ static int sh_guess_wrmap(struct vcpu *v, unsigned long vaddr, mfn_t gmfn)
+ /* Found it! Need to remove its write permissions. */
+ sl1mfn = shadow_l2e_get_mfn(*sl2p);
+ sl1e = shadow_l1e_remove_flags(sl1e, _PAGE_RW);
+- r = shadow_set_l1e(v, sl1p, sl1e, sl1mfn);
+- ASSERT( !(r & SHADOW_SET_ERROR) );
++ r = shadow_set_l1e(v, sl1p, sl1e, p2m_ram_rw, sl1mfn);
++ if ( r & SHADOW_SET_ERROR ) {
++ /* Can only currently happen if we found a grant-mapped
++ * page. Just make the guess fail. */
++ return 0;
++ }
+ TRACE_SHADOW_PATH_FLAG(TRCE_SFLAG_WRMAP_GUESS_FOUND);
+ return 1;
+ }
+@@ -4395,7 +4418,7 @@ int sh_rm_write_access_from_l1(struct vcpu *v, mfn_t sl1mfn,
+ && (mfn_x(shadow_l1e_get_mfn(*sl1e)) == mfn_x(readonly_mfn)) )
+ {
+ shadow_l1e_t ro_sl1e = shadow_l1e_remove_flags(*sl1e, _PAGE_RW);
+- (void) shadow_set_l1e(v, sl1e, ro_sl1e, sl1mfn);
++ (void) shadow_set_l1e(v, sl1e, ro_sl1e, p2m_ram_rw, sl1mfn);
+ #if SHADOW_OPTIMIZATIONS & SHOPT_WRITABLE_HEURISTIC
+ /* Remember the last shadow that we shot a writeable mapping in */
+ v->arch.paging.shadow.last_writeable_pte_smfn = mfn_x(base_sl1mfn);
+@@ -4423,7 +4446,8 @@ int sh_rm_mappings_from_l1(struct vcpu *v, mfn_t sl1mfn, mfn_t target_mfn)
+ if ( (flags & _PAGE_PRESENT)
+ && (mfn_x(shadow_l1e_get_mfn(*sl1e)) == mfn_x(target_mfn)) )
+ {
+- (void) shadow_set_l1e(v, sl1e, shadow_l1e_empty(), sl1mfn);
++ (void) shadow_set_l1e(v, sl1e, shadow_l1e_empty(),
++ p2m_invalid, sl1mfn);
+ if ( (mfn_to_page(target_mfn)->count_info & PGC_count_mask) == 0 )
+ /* This breaks us cleanly out of the FOREACH macro */
+ done = 1;
+@@ -4441,17 +4465,21 @@ void sh_clear_shadow_entry(struct vcpu *v, void *ep, mfn_t smfn)
+ switch ( mfn_to_page(smfn)->u.sh.type )
+ {
+ case SH_type_l1_shadow:
+- (void) shadow_set_l1e(v, ep, shadow_l1e_empty(), smfn); break;
++ (void) shadow_set_l1e(v, ep, shadow_l1e_empty(), p2m_invalid, smfn);
++ break;
+ case SH_type_l2_shadow:
+ #if GUEST_PAGING_LEVELS >= 3
+ case SH_type_l2h_shadow:
+ #endif
+- (void) shadow_set_l2e(v, ep, shadow_l2e_empty(), smfn); break;
++ (void) shadow_set_l2e(v, ep, shadow_l2e_empty(), smfn);
++ break;
+ #if GUEST_PAGING_LEVELS >= 4
+ case SH_type_l3_shadow:
+- (void) shadow_set_l3e(v, ep, shadow_l3e_empty(), smfn); break;
++ (void) shadow_set_l3e(v, ep, shadow_l3e_empty(), smfn);
++ break;
+ case SH_type_l4_shadow:
+- (void) shadow_set_l4e(v, ep, shadow_l4e_empty(), smfn); break;
++ (void) shadow_set_l4e(v, ep, shadow_l4e_empty(), smfn);
++ break;
+ #endif
+ default: BUG(); /* Called with the wrong kind of shadow. */
+ }
+@@ -4559,7 +4587,7 @@ static mfn_t emulate_gva_to_mfn(struct vcpu *v,
+ else
+ mfn = gfn_to_mfn(v->domain, _gfn(gfn), &p2mt);
+
+- if ( p2mt == p2m_ram_ro )
++ if ( p2m_is_readonly(p2mt) )
+ return _mfn(READONLY_GFN);
+ if ( !p2m_is_ram(p2mt) )
+ return _mfn(BAD_GFN_TO_MFN);
+@@ -4963,7 +4991,7 @@ int sh_audit_l1_table(struct vcpu *v, mfn_t sl1mfn, mfn_t x)
+ gfn = guest_l1e_get_gfn(*gl1e);
+ mfn = shadow_l1e_get_mfn(*sl1e);
+ gmfn = gfn_to_mfn_query(v->domain, gfn, &p2mt);
+- if ( mfn_x(gmfn) != mfn_x(mfn) )
++ if ( !p2m_is_grant(p2mt) && mfn_x(gmfn) != mfn_x(mfn) )
+ AUDIT_FAIL(1, "bad translation: gfn %" SH_PRI_gfn
+ " --> %" PRI_mfn " != mfn %" PRI_mfn,
+ gfn_x(gfn), mfn_x(gmfn), mfn_x(mfn));
+diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
+index 5306354..7e3052c 100644
+--- a/xen/common/grant_table.c
++++ b/xen/common/grant_table.c
+@@ -226,6 +226,15 @@ __gnttab_map_grant_ref(
+ return;
+ }
+
++ if ( unlikely(paging_mode_external(ld) &&
++ (op->flags & (GNTMAP_device_map|GNTMAP_application_map|
++ GNTMAP_contains_pte))) )
++ {
++ gdprintk(XENLOG_INFO, "No device mapping in HVM domain.\n");
++ op->status = GNTST_general_error;
++ return;
++ }
++
+ if ( unlikely((rd = rcu_lock_domain_by_id(op->dom)) == NULL) )
+ {
+ gdprintk(XENLOG_INFO, "Could not find domain %d\n", op->dom);
+@@ -343,6 +352,13 @@ __gnttab_map_grant_ref(
+ if ( mfn_valid(frame) )
+ put_page(mfn_to_page(frame));
+
++ if ( paging_mode_external(ld) )
++ {
++ gdprintk(XENLOG_WARNING, "HVM guests can't grant map iomem\n");
++ rc = GNTST_general_error;
++ goto undo_out;
++ }
++
+ if ( !iomem_access_permitted(rd, frame, frame) )
+ {
+ gdprintk(XENLOG_WARNING,
+@@ -395,7 +411,12 @@ __gnttab_map_grant_ref(
+ !(old_pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) &&
+ (act_pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) )
+ {
+- if ( iommu_map_page(ld, mfn_to_gmfn(ld, frame), frame) )
++ /* Shouldn't happen, because you can't use iommu in a HVM
++ * domain. */
++ BUG_ON(paging_mode_translate(ld));
++ /* We're not translated, so we know that gmfns and mfns are
++ the same things, so the IOMMU entry is always 1-to-1. */
++ if ( iommu_map_page(ld, frame, frame) )
+ {
+ rc = GNTST_general_error;
+ goto undo_out;
+@@ -573,7 +594,8 @@ __gnttab_unmap_common(
+ (old_pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) &&
+ !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) )
+ {
+- if ( iommu_unmap_page(ld, mfn_to_gmfn(ld, op->frame)) )
++ BUG_ON(paging_mode_translate(ld));
++ if ( iommu_unmap_page(ld, op->frame) )
+ {
+ rc = GNTST_general_error;
+ goto unmap_out;
+@@ -1717,7 +1739,7 @@ gnttab_release_mappings(
+ {
+ BUG_ON(!(act->pin & GNTPIN_hstr_mask));
+ act->pin -= GNTPIN_hstr_inc;
+- if ( gnttab_release_host_mappings &&
++ if ( gnttab_release_host_mappings(d) &&
+ !is_iomem_page(act->frame) )
+ put_page(mfn_to_page(act->frame));
+ }
+@@ -1736,7 +1758,7 @@ gnttab_release_mappings(
+ {
+ BUG_ON(!(act->pin & GNTPIN_hstw_mask));
+ act->pin -= GNTPIN_hstw_inc;
+- if ( gnttab_release_host_mappings &&
++ if ( gnttab_release_host_mappings(d) &&
+ !is_iomem_page(act->frame) )
+ {
+ if ( gnttab_host_mapping_get_page_type(map, d, rd) )
+diff --git a/xen/include/asm-ia64/grant_table.h b/xen/include/asm-ia64/grant_table.h
+index 903a930..58aa635 100644
+--- a/xen/include/asm-ia64/grant_table.h
++++ b/xen/include/asm-ia64/grant_table.h
+@@ -68,7 +68,7 @@ static inline void gnttab_clear_flag(unsigned long nr, uint16_t *addr)
+ #define gnttab_host_mapping_get_page_type(op, ld, rd) \
+ (!((op)->flags & GNTMAP_readonly))
+
+-#define gnttab_release_host_mappings 1
++#define gnttab_release_host_mappings(domain) 1
+
+ static inline int replace_grant_supported(void)
+ {
+diff --git a/xen/include/asm-x86/grant_table.h b/xen/include/asm-x86/grant_table.h
+index 3a7fb2a..4c72d7c 100644
+--- a/xen/include/asm-x86/grant_table.h
++++ b/xen/include/asm-x86/grant_table.h
+@@ -44,7 +44,7 @@ static inline void gnttab_clear_flag(unsigned long nr, uint16_t *addr)
+ (((ld) == (rd)) || !paging_mode_external(rd)))
+
+ /* Done implicitly when page tables are destroyed. */
+-#define gnttab_release_host_mappings 0
++#define gnttab_release_host_mappings(domain) ( paging_mode_external(domain) )
+
+ static inline int replace_grant_supported(void)
+ {
+diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h
+index 70e38bf..8f3c110 100644
+--- a/xen/include/asm-x86/hvm/domain.h
++++ b/xen/include/asm-x86/hvm/domain.h
+@@ -31,6 +31,7 @@
+ #include <asm/hvm/viridian.h>
+ #include <asm/hvm/vmx/vmcs.h>
+ #include <asm/hvm/svm/vmcb.h>
++#include <public/grant_table.h>
+ #include <public/hvm/params.h>
+ #include <public/hvm/save.h>
+
+diff --git a/xen/include/asm-x86/hvm/support.h b/xen/include/asm-x86/hvm/support.h
+index 9e3ef99..e533f1b 100644
+--- a/xen/include/asm-x86/hvm/support.h
++++ b/xen/include/asm-x86/hvm/support.h
+@@ -71,7 +71,8 @@ void hvm_enable(struct hvm_function_table *);
+ enum hvm_copy_result {
+ HVMCOPY_okay = 0,
+ HVMCOPY_bad_gva_to_gfn,
+- HVMCOPY_bad_gfn_to_mfn
++ HVMCOPY_bad_gfn_to_mfn,
++ HVMCOPY_unhandleable
+ };
+
+ /*
+diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h
+index 303191e..963fe20 100644
+--- a/xen/include/asm-x86/p2m.h
++++ b/xen/include/asm-x86/p2m.h
+@@ -45,6 +45,10 @@
+ */
+ #define phys_to_machine_mapping ((l1_pgentry_t *)RO_MPT_VIRT_START)
+
++#ifdef __x86_64__
++#define HAVE_GRANT_MAP_P2M
++#endif
++
+ /*
+ * The upper levels of the p2m pagetable always contain full rights; all
+ * variation in the access control bits is made in the level-1 PTEs.
+@@ -65,6 +69,12 @@ typedef enum {
+ p2m_mmio_dm = 4, /* Reads and write go to the device model */
+ p2m_mmio_direct = 5, /* Read/write mapping of genuine MMIO area */
+ p2m_populate_on_demand = 6, /* Place-holder for empty memory */
++
++ /* Note that these can only be used if HAVE_GRANT_MAP_P2M is
++ defined. They get defined anyway so as to avoid lots of
++ #ifdef's everywhere else. */
++ p2m_grant_map_rw = 7, /* Read/write grant mapping */
++ p2m_grant_map_ro = 8, /* Read-only grant mapping */
+ } p2m_type_t;
+
+ typedef enum {
+@@ -81,13 +91,19 @@ typedef enum {
+ | p2m_to_mask(p2m_ram_logdirty) \
+ | p2m_to_mask(p2m_ram_ro))
+
++/* Grant mapping types, which map to a real machine frame in another
++ * VM */
++#define P2M_GRANT_TYPES (p2m_to_mask(p2m_grant_map_rw) \
++ | p2m_to_mask(p2m_grant_map_ro) )
++
+ /* MMIO types, which don't have to map to anything in the frametable */
+ #define P2M_MMIO_TYPES (p2m_to_mask(p2m_mmio_dm) \
+ | p2m_to_mask(p2m_mmio_direct))
+
+ /* Read-only types, which must have the _PAGE_RW bit clear in their PTEs */
+ #define P2M_RO_TYPES (p2m_to_mask(p2m_ram_logdirty) \
+- | p2m_to_mask(p2m_ram_ro))
++ | p2m_to_mask(p2m_ram_ro) \
++ | p2m_to_mask(p2m_grant_map_ro) )
+
+ #define P2M_MAGIC_TYPES (p2m_to_mask(p2m_populate_on_demand))
+
+@@ -96,6 +112,10 @@ typedef enum {
+ #define p2m_is_mmio(_t) (p2m_to_mask(_t) & P2M_MMIO_TYPES)
+ #define p2m_is_readonly(_t) (p2m_to_mask(_t) & P2M_RO_TYPES)
+ #define p2m_is_magic(_t) (p2m_to_mask(_t) & P2M_MAGIC_TYPES)
++#define p2m_is_grant(_t) (p2m_to_mask(_t) & P2M_GRANT_TYPES)
++/* Grant types are *not* considered valid, because they can be
++ unmapped at any time and, unless you happen to be the shadow or p2m
++ implementations, there's no way of synchronising against that. */
+ #define p2m_is_valid(_t) (p2m_to_mask(_t) & (P2M_RAM_TYPES | P2M_MMIO_TYPES))
+
+ /* Populate-on-demand */
+@@ -161,8 +181,12 @@ struct p2m_domain {
+ /* Extract the type from the PTE flags that store it */
+ static inline p2m_type_t p2m_flags_to_type(unsigned long flags)
+ {
+- /* Type is stored in the "available" bits, 9, 10 and 11 */
++ /* Type is stored in the "available" bits */
++#ifdef __x86_64__
++ return (flags >> 9) & 0x3fff;
++#else
+ return (flags >> 9) & 0x7;
++#endif
+ }
+
+ /* Read the current domain's p2m table. Do not populate PoD pages. */
+@@ -226,17 +250,6 @@ static inline unsigned long mfn_to_gfn(struct domain *d, mfn_t mfn)
+ return mfn_x(mfn);
+ }
+
+-/* Translate the frame number held in an l1e from guest to machine */
+-static inline l1_pgentry_t
+-gl1e_to_ml1e(struct domain *d, l1_pgentry_t l1e)
+-{
+- if ( unlikely(paging_mode_translate(d)) )
+- l1e = l1e_from_pfn(gmfn_to_mfn(d, l1e_get_pfn(l1e)),
+- l1e_get_flags(l1e));
+- return l1e;
+-}
+-
+-
+ /* Init the datastructures for later use by the p2m code */
+ int p2m_init(struct domain *d);
+