static int __init modify_identity_mmio(struct domain *d, unsigned long pfn, unsigned long nr_pages, const bool map) { int rc; for ( ; ; ) { rc = (map ? map_mmio_regions : unmap_mmio_regions) (d, _gfn(pfn), nr_pages, _mfn(pfn)); if ( rc == 0 ) break; if ( rc < 0 ) { printk(XENLOG_WARNING "Failed to identity %smap [%#lx,%#lx) for d%d: %d\n", map ? "" : "un", pfn, pfn + nr_pages, d->domain_id, rc); break; } nr_pages -= rc; pfn += rc; process_pending_softirqs(); } return rc; }
/* Returns: mfn for the given (hvm guest) vaddr */ static mfn_t dbg_hvm_va2mfn(dbgva_t vaddr, struct domain *dp, int toaddr, gfn_t *gfn) { mfn_t mfn; uint32_t pfec = PFEC_page_present; p2m_type_t gfntype; DBGP2("vaddr:%lx domid:%d\n", vaddr, dp->domain_id); *gfn = _gfn(paging_gva_to_gfn(dp->vcpu[0], vaddr, &pfec)); if ( gfn_eq(*gfn, INVALID_GFN) ) { DBGP2("kdb:bad gfn from gva_to_gfn\n"); return INVALID_MFN; } mfn = get_gfn(dp, gfn_x(*gfn), &gfntype); if ( p2m_is_readonly(gfntype) && toaddr ) { DBGP2("kdb:p2m_is_readonly: gfntype:%x\n", gfntype); mfn = INVALID_MFN; } else DBGP2("X: vaddr:%lx domid:%d mfn:%#"PRI_mfn"\n", vaddr, dp->domain_id, mfn_x(mfn)); if ( mfn_eq(mfn, INVALID_MFN) ) { put_gfn(dp, gfn_x(*gfn)); *gfn = INVALID_GFN; } return mfn; }
/* Assign the low 1MB to Dom0. */ static void __init pvh_steal_low_ram(struct domain *d, unsigned long start, unsigned long nr_pages) { unsigned long mfn; ASSERT(start + nr_pages <= PFN_DOWN(MB(1))); for ( mfn = start; mfn < start + nr_pages; mfn++ ) { struct page_info *pg = mfn_to_page(mfn); int rc; rc = unshare_xen_page_with_guest(pg, dom_io); if ( rc ) { printk("Unable to unshare Xen mfn %#lx: %d\n", mfn, rc); continue; } share_xen_page_with_guest(pg, d, XENSHARE_writable); rc = guest_physmap_add_entry(d, _gfn(mfn), _mfn(mfn), 0, p2m_ram_rw); if ( rc ) printk("Unable to add mfn %#lx to p2m: %d\n", mfn, rc); } }
bool p2m_mem_access_emulate_check(struct vcpu *v, const vm_event_response_t *rsp) { xenmem_access_t access; bool violation = 1; const struct vm_event_mem_access *data = &rsp->u.mem_access; struct domain *d = v->domain; struct p2m_domain *p2m = NULL; if ( altp2m_active(d) ) p2m = p2m_get_altp2m(v); if ( !p2m ) p2m = p2m_get_hostp2m(d); if ( _p2m_get_mem_access(p2m, _gfn(data->gfn), &access) == 0 ) { switch ( access ) { case XENMEM_access_n: case XENMEM_access_n2rwx: default: violation = data->flags & MEM_ACCESS_RWX; break; case XENMEM_access_r: violation = data->flags & MEM_ACCESS_WX; break; case XENMEM_access_w: violation = data->flags & MEM_ACCESS_RX; break; case XENMEM_access_x: violation = data->flags & MEM_ACCESS_RW; break; case XENMEM_access_rx: case XENMEM_access_rx2rw: violation = data->flags & MEM_ACCESS_W; break; case XENMEM_access_wx: violation = data->flags & MEM_ACCESS_R; break; case XENMEM_access_rw: violation = data->flags & MEM_ACCESS_X; break; case XENMEM_access_rwx: violation = 0; break; } } return violation; }
static int __init pvh_setup_vmx_realmode_helpers(struct domain *d) { p2m_type_t p2mt; uint32_t rc, *ident_pt; mfn_t mfn; paddr_t gaddr; struct vcpu *v = d->vcpu[0]; /* * Steal some space from the last RAM region below 4GB and use it to * store the real-mode TSS. It needs to be aligned to 128 so that the * TSS structure (which accounts for the first 104b) doesn't cross * a page boundary. */ if ( !pvh_steal_ram(d, HVM_VM86_TSS_SIZE, 128, GB(4), &gaddr) ) { if ( hvm_copy_to_guest_phys(gaddr, NULL, HVM_VM86_TSS_SIZE, v) != HVMCOPY_okay ) printk("Unable to zero VM86 TSS area\n"); d->arch.hvm_domain.params[HVM_PARAM_VM86_TSS_SIZED] = VM86_TSS_UPDATED | ((uint64_t)HVM_VM86_TSS_SIZE << 32) | gaddr; if ( pvh_add_mem_range(d, gaddr, gaddr + HVM_VM86_TSS_SIZE, E820_RESERVED) ) printk("Unable to set VM86 TSS as reserved in the memory map\n"); } else printk("Unable to allocate VM86 TSS area\n"); /* Steal some more RAM for the identity page tables. */ if ( pvh_steal_ram(d, PAGE_SIZE, PAGE_SIZE, GB(4), &gaddr) ) { printk("Unable to find memory to stash the identity page tables\n"); return -ENOMEM; } /* * Identity-map page table is required for running with CR0.PG=0 * when using Intel EPT. Create a 32-bit non-PAE page directory of * superpages. */ ident_pt = map_domain_gfn(p2m_get_hostp2m(d), _gfn(PFN_DOWN(gaddr)), &mfn, &p2mt, 0, &rc); if ( ident_pt == NULL ) { printk("Unable to map identity page tables\n"); return -ENOMEM; } write_32bit_pse_identmap(ident_pt); unmap_domain_page(ident_pt); put_page(mfn_to_page(mfn_x(mfn))); d->arch.hvm_domain.params[HVM_PARAM_IDENT_PT] = gaddr; if ( pvh_add_mem_range(d, gaddr, gaddr + PAGE_SIZE, E820_RESERVED) ) printk("Unable to set identity page tables as reserved in the memory map\n"); return 0; }
/* * Set access type for a region of gfns. * If gfn == INVALID_GFN, sets the default access type. */ long p2m_set_mem_access(struct domain *d, gfn_t gfn, uint32_t nr, uint32_t start, uint32_t mask, xenmem_access_t access, unsigned int altp2m_idx) { struct p2m_domain *p2m = p2m_get_hostp2m(d), *ap2m = NULL; p2m_access_t a; unsigned long gfn_l; long rc = 0; /* altp2m view 0 is treated as the hostp2m */ if ( altp2m_idx ) { if ( altp2m_idx >= MAX_ALTP2M || d->arch.altp2m_eptp[altp2m_idx] == mfn_x(INVALID_MFN) ) return -EINVAL; ap2m = d->arch.altp2m_p2m[altp2m_idx]; } if ( !xenmem_access_to_p2m_access(p2m, access, &a) ) return -EINVAL; /* If request to set default access. */ if ( gfn_eq(gfn, INVALID_GFN) ) { p2m->default_access = a; return 0; } p2m_lock(p2m); if ( ap2m ) p2m_lock(ap2m); for ( gfn_l = gfn_x(gfn) + start; nr > start; ++gfn_l ) { rc = set_mem_access(d, p2m, ap2m, a, _gfn(gfn_l)); if ( rc ) break; /* Check for continuation if it's not the last iteration. */ if ( nr > ++start && !(start & mask) && hypercall_preempt_check() ) { rc = start; break; } } if ( ap2m ) p2m_unlock(ap2m); p2m_unlock(p2m); return rc; }
/* Populate a HVM memory range using the biggest possible order. */ static int __init pvh_populate_memory_range(struct domain *d, unsigned long start, unsigned long nr_pages) { unsigned int order, i = 0; struct page_info *page; int rc; #define MAP_MAX_ITER 64 order = MAX_ORDER; while ( nr_pages != 0 ) { unsigned int range_order = get_order_from_pages(nr_pages + 1); order = min(range_order ? range_order - 1 : 0, order); page = alloc_domheap_pages(d, order, dom0_memflags); if ( page == NULL ) { if ( order == 0 && dom0_memflags ) { /* Try again without any dom0_memflags. */ dom0_memflags = 0; order = MAX_ORDER; continue; } if ( order == 0 ) { printk("Unable to allocate memory with order 0!\n"); return -ENOMEM; } order--; continue; } rc = guest_physmap_add_page(d, _gfn(start), _mfn(page_to_mfn(page)), order); if ( rc != 0 ) { printk("Failed to populate memory: [%#lx,%lx): %d\n", start, start + (1UL << order), rc); return -ENOMEM; } start += 1UL << order; nr_pages -= 1UL << order; if ( (++i % MAP_MAX_ITER) == 0 ) process_pending_softirqs(); } return 0; #undef MAP_MAX_ITER }
int guest_remove_page(struct domain *d, unsigned long gmfn) { struct page_info *page; #ifdef CONFIG_X86 p2m_type_t p2mt; #endif mfn_t mfn; #ifdef CONFIG_X86 mfn = get_gfn_query(d, gmfn, &p2mt); if ( unlikely(p2m_is_paging(p2mt)) ) { guest_physmap_remove_page(d, _gfn(gmfn), mfn, 0); put_gfn(d, gmfn); /* If the page hasn't yet been paged out, there is an * actual page that needs to be released. */ if ( p2mt == p2m_ram_paging_out ) { ASSERT(mfn_valid(mfn_x(mfn))); page = mfn_to_page(mfn_x(mfn)); if ( test_and_clear_bit(_PGC_allocated, &page->count_info) ) put_page(page); } p2m_mem_paging_drop_page(d, gmfn, p2mt); return 1; } if ( p2mt == p2m_mmio_direct ) { clear_mmio_p2m_entry(d, gmfn, mfn, 0); put_gfn(d, gmfn); return 1; } #else mfn = gfn_to_mfn(d, _gfn(gmfn)); #endif if ( unlikely(!mfn_valid(mfn_x(mfn))) ) { put_gfn(d, gmfn); gdprintk(XENLOG_INFO, "Domain %u page number %lx invalid\n", d->domain_id, gmfn); return 0; } #ifdef CONFIG_X86 if ( p2m_is_shared(p2mt) ) { /* Unshare the page, bail out on error. We unshare because * we might be the only one using this shared page, and we * need to trigger proper cleanup. Once done, this is * like any other page. */ if ( mem_sharing_unshare_page(d, gmfn, 0) ) { put_gfn(d, gmfn); (void)mem_sharing_notify_enomem(d, gmfn, 0); return 0; } /* Maybe the mfn changed */ mfn = get_gfn_query_unlocked(d, gmfn, &p2mt); ASSERT(!p2m_is_shared(p2mt)); } #endif /* CONFIG_X86 */ page = mfn_to_page(mfn_x(mfn)); if ( unlikely(!get_page(page, d)) ) { put_gfn(d, gmfn); gdprintk(XENLOG_INFO, "Bad page free for domain %u\n", d->domain_id); return 0; } if ( test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) ) put_page_and_type(page); /* * With the lack of an IOMMU on some platforms, domains with DMA-capable * device must retrieve the same pfn when the hypercall populate_physmap * is called. * * For this purpose (and to match populate_physmap() behavior), the page * is kept allocated. */ if ( !is_domain_direct_mapped(d) && test_and_clear_bit(_PGC_allocated, &page->count_info) ) put_page(page); guest_physmap_remove_page(d, _gfn(gmfn), mfn, 0); put_page(page); put_gfn(d, gmfn); return 1; }
static void populate_physmap(struct memop_args *a) { struct page_info *page; unsigned int i, j; xen_pfn_t gpfn, mfn; struct domain *d = a->domain; if ( !guest_handle_subrange_okay(a->extent_list, a->nr_done, a->nr_extents-1) ) return; if ( a->extent_order > (a->memflags & MEMF_populate_on_demand ? MAX_ORDER : max_order(current->domain)) ) return; for ( i = a->nr_done; i < a->nr_extents; i++ ) { if ( i != a->nr_done && hypercall_preempt_check() ) { a->preempted = 1; goto out; } if ( unlikely(__copy_from_guest_offset(&gpfn, a->extent_list, i, 1)) ) goto out; if ( a->memflags & MEMF_populate_on_demand ) { if ( guest_physmap_mark_populate_on_demand(d, gpfn, a->extent_order) < 0 ) goto out; } else { if ( is_domain_direct_mapped(d) ) { mfn = gpfn; for ( j = 0; j < (1U << a->extent_order); j++, mfn++ ) { if ( !mfn_valid(mfn) ) { gdprintk(XENLOG_INFO, "Invalid mfn %#"PRI_xen_pfn"\n", mfn); goto out; } page = mfn_to_page(mfn); if ( !get_page(page, d) ) { gdprintk(XENLOG_INFO, "mfn %#"PRI_xen_pfn" doesn't belong to d%d\n", mfn, d->domain_id); goto out; } put_page(page); } mfn = gpfn; page = mfn_to_page(mfn); } else { page = alloc_domheap_pages(d, a->extent_order, a->memflags); if ( unlikely(!page) ) { if ( !tmem_enabled() || a->extent_order ) gdprintk(XENLOG_INFO, "Could not allocate order=%u extent: id=%d memflags=%#x (%u of %u)\n", a->extent_order, d->domain_id, a->memflags, i, a->nr_extents); goto out; } mfn = page_to_mfn(page); } guest_physmap_add_page(d, _gfn(gpfn), _mfn(mfn), a->extent_order); if ( !paging_mode_translate(d) ) { for ( j = 0; j < (1U << a->extent_order); j++ ) set_gpfn_from_mfn(mfn + j, gpfn + j); /* Inform the domain of the new page's machine address. */ if ( unlikely(__copy_to_guest_offset(a->extent_list, i, &mfn, 1)) ) goto out; } } } out: a->nr_done = i; }
/* * If mem_access is in use it might have been the reason why get_page_from_gva * failed to fetch the page, as it uses the MMU for the permission checking. * Only in these cases we do a software-based type check and fetch the page if * we indeed found a conflicting mem_access setting. */ struct page_info* p2m_mem_access_check_and_get_page(vaddr_t gva, unsigned long flag, const struct vcpu *v) { long rc; paddr_t ipa; gfn_t gfn; mfn_t mfn; xenmem_access_t xma; p2m_type_t t; struct page_info *page = NULL; struct p2m_domain *p2m = &v->domain->arch.p2m; rc = gva_to_ipa(gva, &ipa, flag); if ( rc < 0 ) goto err; gfn = _gfn(paddr_to_pfn(ipa)); /* * We do this first as this is faster in the default case when no * permission is set on the page. */ rc = __p2m_get_mem_access(v->domain, gfn, &xma); if ( rc < 0 ) goto err; /* Let's check if mem_access limited the access. */ switch ( xma ) { default: case XENMEM_access_rwx: case XENMEM_access_rw: /* * If mem_access contains no rw perm restrictions at all then the original * fault was correct. */ goto err; case XENMEM_access_n2rwx: case XENMEM_access_n: case XENMEM_access_x: /* * If no r/w is permitted by mem_access, this was a fault caused by mem_access. */ break; case XENMEM_access_wx: case XENMEM_access_w: /* * If this was a read then it was because of mem_access, but if it was * a write then the original get_page_from_gva fault was correct. */ if ( flag == GV2M_READ ) break; else goto err; case XENMEM_access_rx2rw: case XENMEM_access_rx: case XENMEM_access_r: /* * If this was a write then it was because of mem_access, but if it was * a read then the original get_page_from_gva fault was correct. */ if ( flag == GV2M_WRITE ) break; else goto err; } /* * We had a mem_access permission limiting the access, but the page type * could also be limiting, so we need to check that as well. */ mfn = p2m_get_entry(p2m, gfn, &t, NULL, NULL); if ( mfn_eq(mfn, INVALID_MFN) ) goto err; if ( !mfn_valid(mfn) ) goto err; /* * Base type doesn't allow r/w */ if ( t != p2m_ram_rw ) goto err; page = mfn_to_page(mfn_x(mfn)); if ( unlikely(!get_page(page, v->domain)) ) page = NULL; err: return page; }
bool_t p2m_mem_access_check(paddr_t gpa, vaddr_t gla, const struct npfec npfec) { int rc; bool_t violation; xenmem_access_t xma; vm_event_request_t *req; struct vcpu *v = current; struct p2m_domain *p2m = p2m_get_hostp2m(v->domain); /* Mem_access is not in use. */ if ( !p2m->mem_access_enabled ) return true; rc = p2m_get_mem_access(v->domain, _gfn(paddr_to_pfn(gpa)), &xma); if ( rc ) return true; /* Now check for mem_access violation. */ switch ( xma ) { case XENMEM_access_rwx: violation = false; break; case XENMEM_access_rw: violation = npfec.insn_fetch; break; case XENMEM_access_wx: violation = npfec.read_access; break; case XENMEM_access_rx: case XENMEM_access_rx2rw: violation = npfec.write_access; break; case XENMEM_access_x: violation = npfec.read_access || npfec.write_access; break; case XENMEM_access_w: violation = npfec.read_access || npfec.insn_fetch; break; case XENMEM_access_r: violation = npfec.write_access || npfec.insn_fetch; break; default: case XENMEM_access_n: case XENMEM_access_n2rwx: violation = true; break; } if ( !violation ) return true; /* First, handle rx2rw and n2rwx conversion automatically. */ if ( npfec.write_access && xma == XENMEM_access_rx2rw ) { rc = p2m_set_mem_access(v->domain, _gfn(paddr_to_pfn(gpa)), 1, 0, ~0, XENMEM_access_rw, 0); return false; } else if ( xma == XENMEM_access_n2rwx ) { rc = p2m_set_mem_access(v->domain, _gfn(paddr_to_pfn(gpa)), 1, 0, ~0, XENMEM_access_rwx, 0); } /* Otherwise, check if there is a vm_event monitor subscriber */ if ( !vm_event_check_ring(&v->domain->vm_event->monitor) ) { /* No listener */ if ( p2m->access_required ) { gdprintk(XENLOG_INFO, "Memory access permissions failure, " "no vm_event listener VCPU %d, dom %d\n", v->vcpu_id, v->domain->domain_id); domain_crash(v->domain); } else { /* n2rwx was already handled */ if ( xma != XENMEM_access_n2rwx ) { /* A listener is not required, so clear the access * restrictions. */ rc = p2m_set_mem_access(v->domain, _gfn(paddr_to_pfn(gpa)), 1, 0, ~0, XENMEM_access_rwx, 0); } } /* No need to reinject */ return false; } req = xzalloc(vm_event_request_t); if ( req ) { req->reason = VM_EVENT_REASON_MEM_ACCESS; /* Send request to mem access subscriber */ req->u.mem_access.gfn = gpa >> PAGE_SHIFT; req->u.mem_access.offset = gpa & ((1 << PAGE_SHIFT) - 1); if ( npfec.gla_valid ) { req->u.mem_access.flags |= MEM_ACCESS_GLA_VALID; req->u.mem_access.gla = gla; if ( npfec.kind == npfec_kind_with_gla ) req->u.mem_access.flags |= MEM_ACCESS_FAULT_WITH_GLA; else if ( npfec.kind == npfec_kind_in_gpt ) req->u.mem_access.flags |= MEM_ACCESS_FAULT_IN_GPT; } req->u.mem_access.flags |= npfec.read_access ? MEM_ACCESS_R : 0; req->u.mem_access.flags |= npfec.write_access ? MEM_ACCESS_W : 0; req->u.mem_access.flags |= npfec.insn_fetch ? MEM_ACCESS_X : 0; if ( monitor_traps(v, (xma != XENMEM_access_n2rwx), req) < 0 ) domain_crash(v->domain); xfree(req); } return false; }