Home | History | Annotate | Download | only in vm
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * Machine frame segment driver.  This segment driver allows dom0 processes to
     29  * map pages of other domains or Xen (e.g. during save/restore).  ioctl()s on
     30  * the privcmd driver provide the MFN values backing each mapping, and we map
     31  * them into the process's address space at this time.  Demand-faulting is not
     32  * supported by this driver due to the requirements upon some of the ioctl()s.
     33  */
     34 
     35 
     36 #include <sys/types.h>
     37 #include <sys/systm.h>
     38 #include <sys/vmsystm.h>
     39 #include <sys/mman.h>
     40 #include <sys/errno.h>
     41 #include <sys/kmem.h>
     42 #include <sys/cmn_err.h>
     43 #include <sys/vnode.h>
     44 #include <sys/conf.h>
     45 #include <sys/debug.h>
     46 #include <sys/lgrp.h>
     47 #include <sys/hypervisor.h>
     48 
     49 #include <vm/page.h>
     50 #include <vm/hat.h>
     51 #include <vm/as.h>
     52 #include <vm/seg.h>
     53 
     54 #include <vm/hat_pte.h>
     55 #include <vm/hat_i86.h>
     56 #include <vm/seg_mf.h>
     57 
     58 #include <sys/fs/snode.h>
     59 
     60 #define	VTOCVP(vp)	(VTOS(vp)->s_commonvp)
     61 
     62 typedef struct segmf_mfn_s {
     63 	mfn_t		m_mfn;
     64 } segmf_mfn_t;
     65 
     66 /* g_flags */
     67 #define	SEGMF_GFLAGS_WR		0x1
     68 #define	SEGMF_GFLAGS_MAPPED	0x2
     69 typedef struct segmf_gref_s {
     70 	uint64_t	g_ptep;
     71 	grant_ref_t	g_gref;
     72 	uint32_t	g_flags;
     73 	grant_handle_t	g_handle;
     74 } segmf_gref_t;
     75 
     76 typedef union segmf_mu_u {
     77 	segmf_mfn_t	m;
     78 	segmf_gref_t	g;
     79 } segmf_mu_t;
     80 
     81 typedef enum {
     82 	SEGMF_MAP_EMPTY = 0,
     83 	SEGMF_MAP_MFN,
     84 	SEGMF_MAP_GREF
     85 } segmf_map_type_t;
     86 
     87 typedef struct segmf_map_s {
     88 	segmf_map_type_t	t_type;
     89 	segmf_mu_t		u;
     90 } segmf_map_t;
     91 
     92 struct segmf_data {
     93 	kmutex_t	lock;
     94 	struct vnode	*vp;
     95 	uchar_t		prot;
     96 	uchar_t		maxprot;
     97 	size_t		softlockcnt;
     98 	domid_t		domid;
     99 	segmf_map_t	*map;
    100 };
    101 
    102 static struct seg_ops segmf_ops;
    103 
    104 static int segmf_fault_gref_range(struct seg *seg, caddr_t addr, size_t len);
    105 
    106 static struct segmf_data *
    107 segmf_data_zalloc(struct seg *seg)
    108 {
    109 	struct segmf_data *data = kmem_zalloc(sizeof (*data), KM_SLEEP);
    110 
    111 	mutex_init(&data->lock, "segmf.lock", MUTEX_DEFAULT, NULL);
    112 	seg->s_ops = &segmf_ops;
    113 	seg->s_data = data;
    114 	return (data);
    115 }
    116 
    117 int
    118 segmf_create(struct seg *seg, void *args)
    119 {
    120 	struct segmf_crargs *a = args;
    121 	struct segmf_data *data;
    122 	struct as *as = seg->s_as;
    123 	pgcnt_t i, npages = seg_pages(seg);
    124 	int error;
    125 
    126 	hat_map(as->a_hat, seg->s_base, seg->s_size, HAT_MAP);
    127 
    128 	data = segmf_data_zalloc(seg);
    129 	data->vp = specfind(a->dev, VCHR);
    130 	data->prot = a->prot;
    131 	data->maxprot = a->maxprot;
    132 
    133 	data->map = kmem_alloc(npages * sizeof (segmf_map_t), KM_SLEEP);
    134 	for (i = 0; i < npages; i++) {
    135 		data->map[i].t_type = SEGMF_MAP_EMPTY;
    136 	}
    137 
    138 	error = VOP_ADDMAP(VTOCVP(data->vp), 0, as, seg->s_base, seg->s_size,
    139 	    data->prot, data->maxprot, MAP_SHARED, CRED(), NULL);
    140 
    141 	if (error != 0)
    142 		hat_unload(as->a_hat,
    143 		    seg->s_base, seg->s_size, HAT_UNLOAD_UNMAP);
    144 	return (error);
    145 }
    146 
    147 /*
    148  * Duplicate a seg and return new segment in newseg.
    149  */
    150 static int
    151 segmf_dup(struct seg *seg, struct seg *newseg)
    152 {
    153 	struct segmf_data *data = seg->s_data;
    154 	struct segmf_data *ndata;
    155 	pgcnt_t npages = seg_pages(newseg);
    156 	size_t sz;
    157 
    158 	ndata = segmf_data_zalloc(newseg);
    159 
    160 	VN_HOLD(data->vp);
    161 	ndata->vp = data->vp;
    162 	ndata->prot = data->prot;
    163 	ndata->maxprot = data->maxprot;
    164 	ndata->domid = data->domid;
    165 
    166 	sz = npages * sizeof (segmf_map_t);
    167 	ndata->map = kmem_alloc(sz, KM_SLEEP);
    168 	bcopy(data->map, ndata->map, sz);
    169 
    170 	return (VOP_ADDMAP(VTOCVP(ndata->vp), 0, newseg->s_as,
    171 	    newseg->s_base, newseg->s_size, ndata->prot, ndata->maxprot,
    172 	    MAP_SHARED, CRED(), NULL));
    173 }
    174 
    175 /*
    176  * We only support unmapping the whole segment, and we automatically unlock
    177  * what we previously soft-locked.
    178  */
    179 static int
    180 segmf_unmap(struct seg *seg, caddr_t addr, size_t len)
    181 {
    182 	struct segmf_data *data = seg->s_data;
    183 	offset_t off;
    184 
    185 	if (addr < seg->s_base || addr + len > seg->s_base + seg->s_size ||
    186 	    (len & PAGEOFFSET) || ((uintptr_t)addr & PAGEOFFSET))
    187 		panic("segmf_unmap");
    188 
    189 	if (addr != seg->s_base || len != seg->s_size)
    190 		return (ENOTSUP);
    191 
    192 	hat_unload(seg->s_as->a_hat, addr, len,
    193 	    HAT_UNLOAD_UNMAP | HAT_UNLOAD_UNLOCK);
    194 
    195 	off = (offset_t)seg_page(seg, addr);
    196 
    197 	ASSERT(data->vp != NULL);
    198 
    199 	(void) VOP_DELMAP(VTOCVP(data->vp), off, seg->s_as, addr, len,
    200 	    data->prot, data->maxprot, MAP_SHARED, CRED(), NULL);
    201 
    202 	seg_free(seg);
    203 	return (0);
    204 }
    205 
    206 static void
    207 segmf_free(struct seg *seg)
    208 {
    209 	struct segmf_data *data = seg->s_data;
    210 	pgcnt_t npages = seg_pages(seg);
    211 
    212 	kmem_free(data->map, npages * sizeof (segmf_map_t));
    213 	VN_RELE(data->vp);
    214 	mutex_destroy(&data->lock);
    215 	kmem_free(data, sizeof (*data));
    216 }
    217 
    218 static int segmf_faultpage_debug = 0;
    219 /*ARGSUSED*/
    220 static int
    221 segmf_faultpage(struct hat *hat, struct seg *seg, caddr_t addr,
    222     enum fault_type type, uint_t prot)
    223 {
    224 	struct segmf_data *data = seg->s_data;
    225 	uint_t hat_flags = HAT_LOAD_NOCONSIST;
    226 	mfn_t mfn;
    227 	x86pte_t pte;
    228 	segmf_map_t *map;
    229 	uint_t idx;
    230 
    231 
    232 	idx = seg_page(seg, addr);
    233 	map = &data->map[idx];
    234 	ASSERT(map->t_type == SEGMF_MAP_MFN);
    235 
    236 	mfn = map->u.m.m_mfn;
    237 
    238 	if (type == F_SOFTLOCK) {
    239 		mutex_enter(&freemem_lock);
    240 		data->softlockcnt++;
    241 		mutex_exit(&freemem_lock);
    242 		hat_flags |= HAT_LOAD_LOCK;
    243 	} else
    244 		hat_flags |= HAT_LOAD;
    245 
    246 	if (segmf_faultpage_debug > 0) {
    247 		uprintf("segmf_faultpage: addr %p domid %x mfn %lx prot %x\n",
    248 		    (void *)addr, data->domid, mfn, prot);
    249 		segmf_faultpage_debug--;
    250 	}
    251 
    252 	/*
    253 	 * Ask the HAT to load a throwaway mapping to page zero, then
    254 	 * overwrite it with our foreign domain mapping. It gets removed
    255 	 * later via hat_unload()
    256 	 */
    257 	hat_devload(hat, addr, MMU_PAGESIZE, (pfn_t)0,
    258 	    PROT_READ | HAT_UNORDERED_OK, hat_flags);
    259 
    260 	pte = mmu_ptob((x86pte_t)mfn) | PT_VALID | PT_USER | PT_FOREIGN;
    261 	if (prot & PROT_WRITE)
    262 		pte |= PT_WRITABLE;
    263 
    264 	if (HYPERVISOR_update_va_mapping_otherdomain((uintptr_t)addr, pte,
    265 	    UVMF_INVLPG | UVMF_ALL, data->domid) != 0) {
    266 		hat_flags = HAT_UNLOAD_UNMAP;
    267 
    268 		if (type == F_SOFTLOCK) {
    269 			hat_flags |= HAT_UNLOAD_UNLOCK;
    270 			mutex_enter(&freemem_lock);
    271 			data->softlockcnt--;
    272 			mutex_exit(&freemem_lock);
    273 		}
    274 
    275 		hat_unload(hat, addr, MMU_PAGESIZE, hat_flags);
    276 		return (FC_MAKE_ERR(EFAULT));
    277 	}
    278 
    279 	return (0);
    280 }
    281 
    282 static int
    283 seg_rw_to_prot(enum seg_rw rw)
    284 {
    285 	switch (rw) {
    286 	case S_READ:
    287 		return (PROT_READ);
    288 	case S_WRITE:
    289 		return (PROT_WRITE);
    290 	case S_EXEC:
    291 		return (PROT_EXEC);
    292 	case S_OTHER:
    293 	default:
    294 		break;
    295 	}
    296 	return (PROT_READ | PROT_WRITE | PROT_EXEC);
    297 }
    298 
    299 static void
    300 segmf_softunlock(struct hat *hat, struct seg *seg, caddr_t addr, size_t len)
    301 {
    302 	struct segmf_data *data = seg->s_data;
    303 
    304 	hat_unlock(hat, addr, len);
    305 
    306 	mutex_enter(&freemem_lock);
    307 	ASSERT(data->softlockcnt >= btopr(len));
    308 	data->softlockcnt -= btopr(len);
    309 	mutex_exit(&freemem_lock);
    310 
    311 	if (data->softlockcnt == 0) {
    312 		struct as *as = seg->s_as;
    313 
    314 		if (AS_ISUNMAPWAIT(as)) {
    315 			mutex_enter(&as->a_contents);
    316 			if (AS_ISUNMAPWAIT(as)) {
    317 				AS_CLRUNMAPWAIT(as);
    318 				cv_broadcast(&as->a_cv);
    319 			}
    320 			mutex_exit(&as->a_contents);
    321 		}
    322 	}
    323 }
    324 
    325 static int
    326 segmf_fault_range(struct hat *hat, struct seg *seg, caddr_t addr, size_t len,
    327     enum fault_type type, enum seg_rw rw)
    328 {
    329 	struct segmf_data *data = seg->s_data;
    330 	int error = 0;
    331 	caddr_t a;
    332 
    333 	if ((data->prot & seg_rw_to_prot(rw)) == 0)
    334 		return (FC_PROT);
    335 
    336 	/* loop over the address range handling each fault */
    337 
    338 	for (a = addr; a < addr + len; a += PAGESIZE) {
    339 		error = segmf_faultpage(hat, seg, a, type, data->prot);
    340 		if (error != 0)
    341 			break;
    342 	}
    343 
    344 	if (error != 0 && type == F_SOFTLOCK) {
    345 		size_t done = (size_t)(a - addr);
    346 
    347 		/*
    348 		 * Undo what's been done so far.
    349 		 */
    350 		if (done > 0)
    351 			segmf_softunlock(hat, seg, addr, done);
    352 	}
    353 
    354 	return (error);
    355 }
    356 
    357 /*
    358  * We never demand-fault for seg_mf.
    359  */
    360 /*ARGSUSED*/
    361 static int
    362 segmf_fault(struct hat *hat, struct seg *seg, caddr_t addr, size_t len,
    363     enum fault_type type, enum seg_rw rw)
    364 {
    365 	return (FC_MAKE_ERR(EFAULT));
    366 }
    367 
    368 /*ARGSUSED*/
    369 static int
    370 segmf_faulta(struct seg *seg, caddr_t addr)
    371 {
    372 	return (0);
    373 }
    374 
    375 /*ARGSUSED*/
    376 static int
    377 segmf_setprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
    378 {
    379 	return (EINVAL);
    380 }
    381 
    382 /*ARGSUSED*/
    383 static int
    384 segmf_checkprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
    385 {
    386 	return (EINVAL);
    387 }
    388 
    389 /*ARGSUSED*/
    390 static int
    391 segmf_kluster(struct seg *seg, caddr_t addr, ssize_t delta)
    392 {
    393 	return (-1);
    394 }
    395 
    396 /*ARGSUSED*/
    397 static int
    398 segmf_sync(struct seg *seg, caddr_t addr, size_t len, int attr, uint_t flags)
    399 {
    400 	return (0);
    401 }
    402 
    403 /*
    404  * XXPV	Hmm.  Should we say that mf mapping are "in core?"
    405  */
    406 
    407 /*ARGSUSED*/
    408 static size_t
    409 segmf_incore(struct seg *seg, caddr_t addr, size_t len, char *vec)
    410 {
    411 	size_t v;
    412 
    413 	for (v = 0, len = (len + PAGEOFFSET) & PAGEMASK; len;
    414 	    len -= PAGESIZE, v += PAGESIZE)
    415 		*vec++ = 1;
    416 	return (v);
    417 }
    418 
    419 /*ARGSUSED*/
    420 static int
    421 segmf_lockop(struct seg *seg, caddr_t addr,
    422     size_t len, int attr, int op, ulong_t *lockmap, size_t pos)
    423 {
    424 	return (0);
    425 }
    426 
    427 static int
    428 segmf_getprot(struct seg *seg, caddr_t addr, size_t len, uint_t *protv)
    429 {
    430 	struct segmf_data *data = seg->s_data;
    431 	pgcnt_t pgno = seg_page(seg, addr + len) - seg_page(seg, addr) + 1;
    432 
    433 	if (pgno != 0) {
    434 		do
    435 			protv[--pgno] = data->prot;
    436 		while (pgno != 0)
    437 			;
    438 	}
    439 	return (0);
    440 }
    441 
    442 static u_offset_t
    443 segmf_getoffset(struct seg *seg, caddr_t addr)
    444 {
    445 	return (addr - seg->s_base);
    446 }
    447 
    448 /*ARGSUSED*/
    449 static int
    450 segmf_gettype(struct seg *seg, caddr_t addr)
    451 {
    452 	return (MAP_SHARED);
    453 }
    454 
    455 /*ARGSUSED1*/
    456 static int
    457 segmf_getvp(struct seg *seg, caddr_t addr, struct vnode **vpp)
    458 {
    459 	struct segmf_data *data = seg->s_data;
    460 
    461 	*vpp = VTOCVP(data->vp);
    462 	return (0);
    463 }
    464 
    465 /*ARGSUSED*/
    466 static int
    467 segmf_advise(struct seg *seg, caddr_t addr, size_t len, uint_t behav)
    468 {
    469 	return (0);
    470 }
    471 
    472 /*ARGSUSED*/
    473 static void
    474 segmf_dump(struct seg *seg)
    475 {}
    476 
    477 /*ARGSUSED*/
    478 static int
    479 segmf_pagelock(struct seg *seg, caddr_t addr, size_t len,
    480     struct page ***ppp, enum lock_type type, enum seg_rw rw)
    481 {
    482 	return (ENOTSUP);
    483 }
    484 
    485 /*ARGSUSED*/
    486 static int
    487 segmf_setpagesize(struct seg *seg, caddr_t addr, size_t len, uint_t szc)
    488 {
    489 	return (ENOTSUP);
    490 }
    491 
    492 static int
    493 segmf_getmemid(struct seg *seg, caddr_t addr, memid_t *memid)
    494 {
    495 	struct segmf_data *data = seg->s_data;
    496 
    497 	memid->val[0] = (uintptr_t)VTOCVP(data->vp);
    498 	memid->val[1] = (uintptr_t)seg_page(seg, addr);
    499 	return (0);
    500 }
    501 
    502 /*ARGSUSED*/
    503 static lgrp_mem_policy_info_t *
    504 segmf_getpolicy(struct seg *seg, caddr_t addr)
    505 {
    506 	return (NULL);
    507 }
    508 
    509 /*ARGSUSED*/
    510 static int
    511 segmf_capable(struct seg *seg, segcapability_t capability)
    512 {
    513 	return (0);
    514 }
    515 
    516 /*
    517  * Add a set of contiguous foreign MFNs to the segment. soft-locking them.  The
    518  * pre-faulting is necessary due to live migration; in particular we must
    519  * return an error in response to IOCTL_PRIVCMD_MMAPBATCH rather than faulting
    520  * later on a bad MFN.  Whilst this isn't necessary for the other MMAP
    521  * ioctl()s, we lock them too, as they should be transitory.
    522  */
    523 int
    524 segmf_add_mfns(struct seg *seg, caddr_t addr, mfn_t mfn,
    525     pgcnt_t pgcnt, domid_t domid)
    526 {
    527 	struct segmf_data *data = seg->s_data;
    528 	pgcnt_t base;
    529 	faultcode_t fc;
    530 	pgcnt_t i;
    531 	int error = 0;
    532 
    533 	if (seg->s_ops != &segmf_ops)
    534 		return (EINVAL);
    535 
    536 	/*
    537 	 * Don't mess with dom0.
    538 	 *
    539 	 * Only allow the domid to be set once for the segment.
    540 	 * After that attempts to add mappings to this segment for
    541 	 * other domains explicitly fails.
    542 	 */
    543 
    544 	if (domid == 0 || domid == DOMID_SELF)
    545 		return (EACCES);
    546 
    547 	mutex_enter(&data->lock);
    548 
    549 	if (data->domid == 0)
    550 		data->domid = domid;
    551 
    552 	if (data->domid != domid) {
    553 		error = EINVAL;
    554 		goto out;
    555 	}
    556 
    557 	base = seg_page(seg, addr);
    558 
    559 	for (i = 0; i < pgcnt; i++) {
    560 		data->map[base + i].t_type = SEGMF_MAP_MFN;
    561 		data->map[base + i].u.m.m_mfn = mfn++;
    562 	}
    563 
    564 	fc = segmf_fault_range(seg->s_as->a_hat, seg, addr,
    565 	    pgcnt * MMU_PAGESIZE, F_SOFTLOCK, S_OTHER);
    566 
    567 	if (fc != 0) {
    568 		error = fc_decode(fc);
    569 		for (i = 0; i < pgcnt; i++) {
    570 			data->map[base + i].t_type = SEGMF_MAP_EMPTY;
    571 		}
    572 	}
    573 
    574 out:
    575 	mutex_exit(&data->lock);
    576 	return (error);
    577 }
    578 
    579 int
    580 segmf_add_grefs(struct seg *seg, caddr_t addr, uint_t flags,
    581     grant_ref_t *grefs, uint_t cnt, domid_t domid)
    582 {
    583 	struct segmf_data *data;
    584 	segmf_map_t *map;
    585 	faultcode_t fc;
    586 	uint_t idx;
    587 	uint_t i;
    588 	int e;
    589 
    590 	if (seg->s_ops != &segmf_ops)
    591 		return (EINVAL);
    592 
    593 	/*
    594 	 * Don't mess with dom0.
    595 	 *
    596 	 * Only allow the domid to be set once for the segment.
    597 	 * After that attempts to add mappings to this segment for
    598 	 * other domains explicitly fails.
    599 	 */
    600 
    601 	if (domid == 0 || domid == DOMID_SELF)
    602 		return (EACCES);
    603 
    604 	data = seg->s_data;
    605 	idx = seg_page(seg, addr);
    606 	map = &data->map[idx];
    607 	e = 0;
    608 
    609 	mutex_enter(&data->lock);
    610 
    611 	if (data->domid == 0)
    612 		data->domid = domid;
    613 
    614 	if (data->domid != domid) {
    615 		e = EINVAL;
    616 		goto out;
    617 	}
    618 
    619 	/* store away the grefs passed in then fault in the pages */
    620 	for (i = 0; i < cnt; i++) {
    621 		map[i].t_type = SEGMF_MAP_GREF;
    622 		map[i].u.g.g_gref = grefs[i];
    623 		map[i].u.g.g_handle = 0;
    624 		map[i].u.g.g_flags = 0;
    625 		if (flags & SEGMF_GREF_WR) {
    626 			map[i].u.g.g_flags |= SEGMF_GFLAGS_WR;
    627 		}
    628 	}
    629 	fc = segmf_fault_gref_range(seg, addr, cnt);
    630 	if (fc != 0) {
    631 		e = fc_decode(fc);
    632 		for (i = 0; i < cnt; i++) {
    633 			data->map[i].t_type = SEGMF_MAP_EMPTY;
    634 		}
    635 	}
    636 
    637 out:
    638 	mutex_exit(&data->lock);
    639 	return (e);
    640 }
    641 
    642 int
    643 segmf_release_grefs(struct seg *seg, caddr_t addr, uint_t cnt)
    644 {
    645 	gnttab_unmap_grant_ref_t mapop[SEGMF_MAX_GREFS];
    646 	struct segmf_data *data;
    647 	segmf_map_t *map;
    648 	uint_t idx;
    649 	long e;
    650 	int i;
    651 	int n;
    652 
    653 
    654 	if (cnt > SEGMF_MAX_GREFS) {
    655 		return (-1);
    656 	}
    657 
    658 	idx = seg_page(seg, addr);
    659 	data = seg->s_data;
    660 	map = &data->map[idx];
    661 
    662 	bzero(mapop, sizeof (gnttab_unmap_grant_ref_t) * cnt);
    663 
    664 	/*
    665 	 * for each entry which isn't empty and is currently mapped,
    666 	 * set it up for an unmap then mark them empty.
    667 	 */
    668 	n = 0;
    669 	for (i = 0; i < cnt; i++) {
    670 		ASSERT(map[i].t_type != SEGMF_MAP_MFN);
    671 		if ((map[i].t_type == SEGMF_MAP_GREF) &&
    672 		    (map[i].u.g.g_flags & SEGMF_GFLAGS_MAPPED)) {
    673 			mapop[n].handle = map[i].u.g.g_handle;
    674 			mapop[n].host_addr = map[i].u.g.g_ptep;
    675 			mapop[n].dev_bus_addr = 0;
    676 			n++;
    677 		}
    678 		map[i].t_type = SEGMF_MAP_EMPTY;
    679 	}
    680 
    681 	/* if there's nothing to unmap, just return */
    682 	if (n == 0) {
    683 		return (0);
    684 	}
    685 
    686 	e = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &mapop, n);
    687 	if (e != 0) {
    688 		return (-1);
    689 	}
    690 
    691 	return (0);
    692 }
    693 
    694 
    695 void
    696 segmf_add_gref_pte(struct seg *seg, caddr_t addr, uint64_t pte_ma)
    697 {
    698 	struct segmf_data *data;
    699 	uint_t idx;
    700 
    701 	idx = seg_page(seg, addr);
    702 	data = seg->s_data;
    703 
    704 	data->map[idx].u.g.g_ptep = pte_ma;
    705 }
    706 
    707 
    708 static int
    709 segmf_fault_gref_range(struct seg *seg, caddr_t addr, size_t cnt)
    710 {
    711 	gnttab_map_grant_ref_t mapop[SEGMF_MAX_GREFS];
    712 	struct segmf_data *data;
    713 	segmf_map_t *map;
    714 	uint_t idx;
    715 	int e;
    716 	int i;
    717 
    718 
    719 	if (cnt > SEGMF_MAX_GREFS) {
    720 		return (-1);
    721 	}
    722 
    723 	data = seg->s_data;
    724 	idx = seg_page(seg, addr);
    725 	map = &data->map[idx];
    726 
    727 	bzero(mapop, sizeof (gnttab_map_grant_ref_t) * cnt);
    728 
    729 	ASSERT(map->t_type == SEGMF_MAP_GREF);
    730 
    731 	/*
    732 	 * map in each page passed in into the user apps AS. We do this by
    733 	 * passing the MA of the actual pte of the mapping to the hypervisor.
    734 	 */
    735 	for (i = 0; i < cnt; i++) {
    736 		mapop[i].host_addr = map[i].u.g.g_ptep;
    737 		mapop[i].dom = data->domid;
    738 		mapop[i].ref = map[i].u.g.g_gref;
    739 		mapop[i].flags = GNTMAP_host_map | GNTMAP_application_map |
    740 		    GNTMAP_contains_pte;
    741 		if (!(map[i].u.g.g_flags & SEGMF_GFLAGS_WR)) {
    742 			mapop[i].flags |= GNTMAP_readonly;
    743 		}
    744 	}
    745 	e = xen_map_gref(GNTTABOP_map_grant_ref, mapop, cnt, B_TRUE);
    746 	if ((e != 0) || (mapop[0].status != GNTST_okay)) {
    747 		return (FC_MAKE_ERR(EFAULT));
    748 	}
    749 
    750 	/* save handle for segmf_release_grefs() and mark it as mapped */
    751 	for (i = 0; i < cnt; i++) {
    752 		ASSERT(mapop[i].status == GNTST_okay);
    753 		map[i].u.g.g_handle = mapop[i].handle;
    754 		map[i].u.g.g_flags |= SEGMF_GFLAGS_MAPPED;
    755 	}
    756 
    757 	return (0);
    758 }
    759 
    760 static struct seg_ops segmf_ops = {
    761 	segmf_dup,
    762 	segmf_unmap,
    763 	segmf_free,
    764 	segmf_fault,
    765 	segmf_faulta,
    766 	segmf_setprot,
    767 	segmf_checkprot,
    768 	(int (*)())segmf_kluster,
    769 	(size_t (*)(struct seg *))NULL,	/* swapout */
    770 	segmf_sync,
    771 	segmf_incore,
    772 	segmf_lockop,
    773 	segmf_getprot,
    774 	segmf_getoffset,
    775 	segmf_gettype,
    776 	segmf_getvp,
    777 	segmf_advise,
    778 	segmf_dump,
    779 	segmf_pagelock,
    780 	segmf_setpagesize,
    781 	segmf_getmemid,
    782 	segmf_getpolicy,
    783 	segmf_capable
    784 };
    785