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 *
segmf_data_zalloc(struct seg * seg)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
segmf_create(struct seg * seg,void * args)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
segmf_dup(struct seg * seg,struct seg * newseg)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
segmf_unmap(struct seg * seg,caddr_t addr,size_t len)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
segmf_free(struct seg * seg)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
segmf_faultpage(struct hat * hat,struct seg * seg,caddr_t addr,enum fault_type type,uint_t prot)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
seg_rw_to_prot(enum seg_rw rw)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
segmf_softunlock(struct hat * hat,struct seg * seg,caddr_t addr,size_t len)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
segmf_fault_range(struct hat * hat,struct seg * seg,caddr_t addr,size_t len,enum fault_type type,enum seg_rw rw)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
segmf_fault(struct hat * hat,struct seg * seg,caddr_t addr,size_t len,enum fault_type type,enum seg_rw rw)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
segmf_faulta(struct seg * seg,caddr_t addr)370 segmf_faulta(struct seg *seg, caddr_t addr)
371 {
372 return (0);
373 }
374
375 /*ARGSUSED*/
376 static int
segmf_setprot(struct seg * seg,caddr_t addr,size_t len,uint_t prot)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
segmf_checkprot(struct seg * seg,caddr_t addr,size_t len,uint_t prot)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
segmf_kluster(struct seg * seg,caddr_t addr,ssize_t delta)391 segmf_kluster(struct seg *seg, caddr_t addr, ssize_t delta)
392 {
393 return (-1);
394 }
395
396 /*ARGSUSED*/
397 static int
segmf_sync(struct seg * seg,caddr_t addr,size_t len,int attr,uint_t flags)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
segmf_incore(struct seg * seg,caddr_t addr,size_t len,char * vec)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
segmf_lockop(struct seg * seg,caddr_t addr,size_t len,int attr,int op,ulong_t * lockmap,size_t pos)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
segmf_getprot(struct seg * seg,caddr_t addr,size_t len,uint_t * protv)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
segmf_getoffset(struct seg * seg,caddr_t addr)443 segmf_getoffset(struct seg *seg, caddr_t addr)
444 {
445 return (addr - seg->s_base);
446 }
447
448 /*ARGSUSED*/
449 static int
segmf_gettype(struct seg * seg,caddr_t addr)450 segmf_gettype(struct seg *seg, caddr_t addr)
451 {
452 return (MAP_SHARED);
453 }
454
455 /*ARGSUSED1*/
456 static int
segmf_getvp(struct seg * seg,caddr_t addr,struct vnode ** vpp)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
segmf_advise(struct seg * seg,caddr_t addr,size_t len,uint_t behav)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
segmf_dump(struct seg * seg)474 segmf_dump(struct seg *seg)
475 {}
476
477 /*ARGSUSED*/
478 static int
segmf_pagelock(struct seg * seg,caddr_t addr,size_t len,struct page *** ppp,enum lock_type type,enum seg_rw rw)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
segmf_setpagesize(struct seg * seg,caddr_t addr,size_t len,uint_t szc)487 segmf_setpagesize(struct seg *seg, caddr_t addr, size_t len, uint_t szc)
488 {
489 return (ENOTSUP);
490 }
491
492 static int
segmf_getmemid(struct seg * seg,caddr_t addr,memid_t * memid)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 *
segmf_getpolicy(struct seg * seg,caddr_t addr)504 segmf_getpolicy(struct seg *seg, caddr_t addr)
505 {
506 return (NULL);
507 }
508
509 /*ARGSUSED*/
510 static int
segmf_capable(struct seg * seg,segcapability_t capability)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
segmf_add_mfns(struct seg * seg,caddr_t addr,mfn_t mfn,pgcnt_t pgcnt,domid_t domid)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
segmf_add_grefs(struct seg * seg,caddr_t addr,uint_t flags,grant_ref_t * grefs,uint_t cnt,domid_t domid)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
segmf_release_grefs(struct seg * seg,caddr_t addr,uint_t cnt)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
segmf_add_gref_pte(struct seg * seg,caddr_t addr,uint64_t pte_ma)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
segmf_fault_gref_range(struct seg * seg,caddr_t addr,size_t cnt)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