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