xref: /illumos-gate/usr/src/uts/i86xpv/vm/seg_mf.c (revision bbe876c07ed632b8f85e195d41e7948382064a95)
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 	seg_inherit_notsup
785 };
786