/* 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; }
/* * 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; }
/* * Get access type for a gfn. * If gfn == INVALID_GFN, gets the default access type. */ static int _p2m_get_mem_access(struct p2m_domain *p2m, gfn_t gfn, xenmem_access_t *access) { p2m_type_t t; p2m_access_t a; mfn_t mfn; static const xenmem_access_t memaccess[] = { #define ACCESS(ac) [p2m_access_##ac] = XENMEM_access_##ac ACCESS(n), ACCESS(r), ACCESS(w), ACCESS(rw), ACCESS(x), ACCESS(rx), ACCESS(wx), ACCESS(rwx), ACCESS(rx2rw), ACCESS(n2rwx), #undef ACCESS }; /* If request to get default access. */ if ( gfn_eq(gfn, INVALID_GFN) ) { *access = memaccess[p2m->default_access]; return 0; } gfn_lock(p2m, gfn, 0); mfn = p2m->get_entry(p2m, gfn_x(gfn), &t, &a, 0, NULL, NULL); gfn_unlock(p2m, gfn, 0); if ( mfn_eq(mfn, INVALID_MFN) ) return -ESRCH; if ( (unsigned int)a >= ARRAY_SIZE(memaccess) ) return -ERANGE; *access = memaccess[a]; return 0; }
/* * Set access type for a region of pfns. * 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); p2m_access_t a; unsigned int order; long rc = 0; static const p2m_access_t memaccess[] = { #define ACCESS(ac) [XENMEM_access_##ac] = p2m_access_##ac ACCESS(n), ACCESS(r), ACCESS(w), ACCESS(rw), ACCESS(x), ACCESS(rx), ACCESS(wx), ACCESS(rwx), ACCESS(rx2rw), ACCESS(n2rwx), #undef ACCESS }; switch ( access ) { case 0 ... ARRAY_SIZE(memaccess) - 1: a = memaccess[access]; break; case XENMEM_access_default: a = p2m->default_access; break; default: return -EINVAL; } /* * Flip mem_access_enabled to true when a permission is set, as to prevent * allocating or inserting super-pages. */ p2m->mem_access_enabled = true; /* If request to set default access. */ if ( gfn_eq(gfn, INVALID_GFN) ) { p2m->default_access = a; return 0; } p2m_write_lock(p2m); for ( gfn = gfn_add(gfn, start); nr > start; gfn = gfn_next_boundary(gfn, order) ) { p2m_type_t t; mfn_t mfn = p2m_get_entry(p2m, gfn, &t, NULL, &order); if ( !mfn_eq(mfn, INVALID_MFN) ) { order = 0; rc = p2m_set_entry(p2m, gfn, 1, mfn, t, a); if ( rc ) break; } start += gfn_x(gfn_next_boundary(gfn, order)) - gfn_x(gfn); /* Check for continuation if it is not the last iteration */ if ( nr > start && !(start & mask) && hypercall_preempt_check() ) { rc = start; break; } } p2m_write_unlock(p2m); return rc; }
static int __p2m_get_mem_access(struct domain *d, gfn_t gfn, xenmem_access_t *access) { struct p2m_domain *p2m = p2m_get_hostp2m(d); void *i; unsigned int index; static const xenmem_access_t memaccess[] = { #define ACCESS(ac) [p2m_access_##ac] = XENMEM_access_##ac ACCESS(n), ACCESS(r), ACCESS(w), ACCESS(rw), ACCESS(x), ACCESS(rx), ACCESS(wx), ACCESS(rwx), ACCESS(rx2rw), ACCESS(n2rwx), #undef ACCESS }; ASSERT(p2m_is_locked(p2m)); /* If no setting was ever set, just return rwx. */ if ( !p2m->mem_access_enabled ) { *access = XENMEM_access_rwx; return 0; } /* If request to get default access. */ if ( gfn_eq(gfn, INVALID_GFN) ) { *access = memaccess[p2m->default_access]; return 0; } i = radix_tree_lookup(&p2m->mem_access_settings, gfn_x(gfn)); if ( !i ) { /* * No setting was found in the Radix tree. Check if the * entry exists in the page-tables. */ mfn_t mfn = p2m_get_entry(p2m, gfn, NULL, NULL, NULL); if ( mfn_eq(mfn, INVALID_MFN) ) return -ESRCH; /* If entry exists then its rwx. */ *access = XENMEM_access_rwx; } else { /* Setting was found in the Radix tree. */ index = radix_tree_ptr_to_int(i); if ( index >= ARRAY_SIZE(memaccess) ) return -ERANGE; *access = memaccess[index]; } return 0; }