xref: /titanic_44/usr/src/uts/common/vm/seg_umap.c (revision cc401b3700f84e16c3a03f62783088a993d21466)
1*cc401b37SPatrick Mooney /*
2*cc401b37SPatrick Mooney  * This file and its contents are supplied under the terms of the
3*cc401b37SPatrick Mooney  * Common Development and Distribution License ("CDDL"), version 1.0.
4*cc401b37SPatrick Mooney  * You may only use this file in accordance with the terms of version
5*cc401b37SPatrick Mooney  * 1.0 of the CDDL.
6*cc401b37SPatrick Mooney  *
7*cc401b37SPatrick Mooney  * A full copy of the text of the CDDL should have accompanied this
8*cc401b37SPatrick Mooney  * source.  A copy of the CDDL is also available via the Internet at
9*cc401b37SPatrick Mooney  * http://www.illumos.org/license/CDDL.
10*cc401b37SPatrick Mooney  */
11*cc401b37SPatrick Mooney 
12*cc401b37SPatrick Mooney /*
13*cc401b37SPatrick Mooney  * Copyright 2016 Joyent, Inc.
14*cc401b37SPatrick Mooney  */
15*cc401b37SPatrick Mooney 
16*cc401b37SPatrick Mooney /*
17*cc401b37SPatrick Mooney  * VM - Kernel-to-user mapping segment
18*cc401b37SPatrick Mooney  *
19*cc401b37SPatrick Mooney  * The umap segment driver was primarily designed to facilitate the comm page:
20*cc401b37SPatrick Mooney  * a portion of kernel memory shared with userspace so that certain (namely
21*cc401b37SPatrick Mooney  * clock-related) actions could operate without making an expensive trip into
22*cc401b37SPatrick Mooney  * the kernel.
23*cc401b37SPatrick Mooney  *
24*cc401b37SPatrick Mooney  * Since the initial requirements for the comm page are slim, advanced features
25*cc401b37SPatrick Mooney  * of the segment driver such as per-page protection have been left
26*cc401b37SPatrick Mooney  * unimplemented at this time.
27*cc401b37SPatrick Mooney  */
28*cc401b37SPatrick Mooney 
29*cc401b37SPatrick Mooney 
30*cc401b37SPatrick Mooney #include <sys/types.h>
31*cc401b37SPatrick Mooney #include <sys/param.h>
32*cc401b37SPatrick Mooney #include <sys/errno.h>
33*cc401b37SPatrick Mooney #include <sys/cred.h>
34*cc401b37SPatrick Mooney #include <sys/kmem.h>
35*cc401b37SPatrick Mooney #include <sys/lgrp.h>
36*cc401b37SPatrick Mooney #include <sys/mman.h>
37*cc401b37SPatrick Mooney 
38*cc401b37SPatrick Mooney #include <vm/hat.h>
39*cc401b37SPatrick Mooney #include <vm/as.h>
40*cc401b37SPatrick Mooney #include <vm/seg.h>
41*cc401b37SPatrick Mooney #include <vm/seg_kmem.h>
42*cc401b37SPatrick Mooney #include <vm/seg_umap.h>
43*cc401b37SPatrick Mooney 
44*cc401b37SPatrick Mooney 
45*cc401b37SPatrick Mooney static boolean_t segumap_verify_safe(caddr_t, size_t);
46*cc401b37SPatrick Mooney static int segumap_dup(struct seg *, struct seg *);
47*cc401b37SPatrick Mooney static int segumap_unmap(struct seg *, caddr_t, size_t);
48*cc401b37SPatrick Mooney static void segumap_free(struct seg *);
49*cc401b37SPatrick Mooney static faultcode_t segumap_fault(struct hat *, struct seg *, caddr_t, size_t,
50*cc401b37SPatrick Mooney     enum fault_type, enum seg_rw);
51*cc401b37SPatrick Mooney static faultcode_t segumap_faulta(struct seg *, caddr_t);
52*cc401b37SPatrick Mooney static int segumap_setprot(struct seg *, caddr_t, size_t, uint_t);
53*cc401b37SPatrick Mooney static int segumap_checkprot(struct seg *, caddr_t, size_t, uint_t);
54*cc401b37SPatrick Mooney static int segumap_sync(struct seg *, caddr_t, size_t, int, uint_t);
55*cc401b37SPatrick Mooney static size_t segumap_incore(struct seg *, caddr_t, size_t, char *);
56*cc401b37SPatrick Mooney static int segumap_lockop(struct seg *, caddr_t, size_t, int, int, ulong_t *,
57*cc401b37SPatrick Mooney     size_t);
58*cc401b37SPatrick Mooney static int segumap_getprot(struct seg *, caddr_t, size_t, uint_t *);
59*cc401b37SPatrick Mooney static u_offset_t segumap_getoffset(struct seg *, caddr_t);
60*cc401b37SPatrick Mooney static int segumap_gettype(struct seg *, caddr_t);
61*cc401b37SPatrick Mooney static int segumap_getvp(struct seg *, caddr_t, struct vnode **);
62*cc401b37SPatrick Mooney static int segumap_advise(struct seg *, caddr_t, size_t, uint_t);
63*cc401b37SPatrick Mooney static void segumap_dump(struct seg *);
64*cc401b37SPatrick Mooney static int segumap_pagelock(struct seg *, caddr_t, size_t, struct page ***,
65*cc401b37SPatrick Mooney     enum lock_type, enum seg_rw);
66*cc401b37SPatrick Mooney static int segumap_setpagesize(struct seg *, caddr_t, size_t, uint_t);
67*cc401b37SPatrick Mooney static int segumap_getmemid(struct seg *, caddr_t, memid_t *);
68*cc401b37SPatrick Mooney static int segumap_capable(struct seg *, segcapability_t);
69*cc401b37SPatrick Mooney 
70*cc401b37SPatrick Mooney static struct seg_ops segumap_ops = {
71*cc401b37SPatrick Mooney 	segumap_dup,
72*cc401b37SPatrick Mooney 	segumap_unmap,
73*cc401b37SPatrick Mooney 	segumap_free,
74*cc401b37SPatrick Mooney 	segumap_fault,
75*cc401b37SPatrick Mooney 	segumap_faulta,
76*cc401b37SPatrick Mooney 	segumap_setprot,
77*cc401b37SPatrick Mooney 	segumap_checkprot,
78*cc401b37SPatrick Mooney 	NULL,			/* kluster: disabled */
79*cc401b37SPatrick Mooney 	NULL,			/* swapout: disabled */
80*cc401b37SPatrick Mooney 	segumap_sync,
81*cc401b37SPatrick Mooney 	segumap_incore,
82*cc401b37SPatrick Mooney 	segumap_lockop,
83*cc401b37SPatrick Mooney 	segumap_getprot,
84*cc401b37SPatrick Mooney 	segumap_getoffset,
85*cc401b37SPatrick Mooney 	segumap_gettype,
86*cc401b37SPatrick Mooney 	segumap_getvp,
87*cc401b37SPatrick Mooney 	segumap_advise,
88*cc401b37SPatrick Mooney 	segumap_dump,
89*cc401b37SPatrick Mooney 	segumap_pagelock,
90*cc401b37SPatrick Mooney 	segumap_setpagesize,
91*cc401b37SPatrick Mooney 	segumap_getmemid,
92*cc401b37SPatrick Mooney 	NULL,			/* getpolicy: disabled */
93*cc401b37SPatrick Mooney 	segumap_capable,
94*cc401b37SPatrick Mooney 	seg_inherit_notsup
95*cc401b37SPatrick Mooney };
96*cc401b37SPatrick Mooney 
97*cc401b37SPatrick Mooney 
98*cc401b37SPatrick Mooney /*
99*cc401b37SPatrick Mooney  * Create a kernel/user-mapped segment.
100*cc401b37SPatrick Mooney  */
101*cc401b37SPatrick Mooney int
segumap_create(struct seg * seg,void * argsp)102*cc401b37SPatrick Mooney segumap_create(struct seg *seg, void *argsp)
103*cc401b37SPatrick Mooney {
104*cc401b37SPatrick Mooney 	segumap_crargs_t *a = (struct segumap_crargs *)argsp;
105*cc401b37SPatrick Mooney 	segumap_data_t *data;
106*cc401b37SPatrick Mooney 
107*cc401b37SPatrick Mooney 	ASSERT((uintptr_t)a->kaddr > _userlimit);
108*cc401b37SPatrick Mooney 
109*cc401b37SPatrick Mooney 	/*
110*cc401b37SPatrick Mooney 	 * Check several aspects of the mapping request to ensure validity:
111*cc401b37SPatrick Mooney 	 * - kernel pages must reside entirely in kernel space
112*cc401b37SPatrick Mooney 	 * - target protection must be user-accessible
113*cc401b37SPatrick Mooney 	 * - kernel address must be page-aligned
114*cc401b37SPatrick Mooney 	 * - kernel address must reside inside a "safe" segment
115*cc401b37SPatrick Mooney 	 */
116*cc401b37SPatrick Mooney 	if ((uintptr_t)a->kaddr <= _userlimit ||
117*cc401b37SPatrick Mooney 	    ((uintptr_t)a->kaddr + seg->s_size) < (uintptr_t)a->kaddr ||
118*cc401b37SPatrick Mooney 	    (a->prot & PROT_USER) == 0 ||
119*cc401b37SPatrick Mooney 	    ((uintptr_t)a->kaddr & PAGEOFFSET) != 0 ||
120*cc401b37SPatrick Mooney 	    !segumap_verify_safe(a->kaddr, seg->s_size)) {
121*cc401b37SPatrick Mooney 		return (EINVAL);
122*cc401b37SPatrick Mooney 	}
123*cc401b37SPatrick Mooney 
124*cc401b37SPatrick Mooney 	data = kmem_zalloc(sizeof (*data), KM_SLEEP);
125*cc401b37SPatrick Mooney 	rw_init(&data->sud_lock, NULL, RW_DEFAULT, NULL);
126*cc401b37SPatrick Mooney 	data->sud_kaddr = a->kaddr;
127*cc401b37SPatrick Mooney 	data->sud_prot = a->prot;
128*cc401b37SPatrick Mooney 
129*cc401b37SPatrick Mooney 	seg->s_ops = &segumap_ops;
130*cc401b37SPatrick Mooney 	seg->s_data = data;
131*cc401b37SPatrick Mooney 	return (0);
132*cc401b37SPatrick Mooney }
133*cc401b37SPatrick Mooney 
134*cc401b37SPatrick Mooney static boolean_t
segumap_verify_safe(caddr_t kaddr,size_t len)135*cc401b37SPatrick Mooney segumap_verify_safe(caddr_t kaddr, size_t len)
136*cc401b37SPatrick Mooney {
137*cc401b37SPatrick Mooney 	struct seg *seg;
138*cc401b37SPatrick Mooney 
139*cc401b37SPatrick Mooney 	/*
140*cc401b37SPatrick Mooney 	 * Presently, only pages which are backed by segkmem are allowed to be
141*cc401b37SPatrick Mooney 	 * shared with userspace.  This prevents nasty paging behavior with
142*cc401b37SPatrick Mooney 	 * other drivers such as seg_kp.  Furthermore, the backing kernel
143*cc401b37SPatrick Mooney 	 * segment must completely contain the region to be mapped.
144*cc401b37SPatrick Mooney 	 *
145*cc401b37SPatrick Mooney 	 * Failing these checks is fatal for now since such mappings are done
146*cc401b37SPatrick Mooney 	 * in a very limited context from the kernel.
147*cc401b37SPatrick Mooney 	 */
148*cc401b37SPatrick Mooney 	AS_LOCK_ENTER(&kas, RW_READER);
149*cc401b37SPatrick Mooney 	seg = as_segat(&kas, kaddr);
150*cc401b37SPatrick Mooney 	VERIFY(seg != NULL);
151*cc401b37SPatrick Mooney 	VERIFY(seg->s_base + seg->s_size >= kaddr + len);
152*cc401b37SPatrick Mooney 	VERIFY(seg->s_ops == &segkmem_ops);
153*cc401b37SPatrick Mooney 	AS_LOCK_EXIT(&kas);
154*cc401b37SPatrick Mooney 
155*cc401b37SPatrick Mooney 	return (B_TRUE);
156*cc401b37SPatrick Mooney }
157*cc401b37SPatrick Mooney 
158*cc401b37SPatrick Mooney static int
segumap_dup(struct seg * seg,struct seg * newseg)159*cc401b37SPatrick Mooney segumap_dup(struct seg *seg, struct seg *newseg)
160*cc401b37SPatrick Mooney {
161*cc401b37SPatrick Mooney 	segumap_data_t *sud = (segumap_data_t *)seg->s_data;
162*cc401b37SPatrick Mooney 	segumap_data_t *newsud;
163*cc401b37SPatrick Mooney 
164*cc401b37SPatrick Mooney 	ASSERT(seg->s_as && AS_WRITE_HELD(seg->s_as));
165*cc401b37SPatrick Mooney 
166*cc401b37SPatrick Mooney 	newsud = kmem_zalloc(sizeof (segumap_data_t), KM_SLEEP);
167*cc401b37SPatrick Mooney 	rw_init(&newsud->sud_lock, NULL, RW_DEFAULT, NULL);
168*cc401b37SPatrick Mooney 	newsud->sud_kaddr = sud->sud_kaddr;
169*cc401b37SPatrick Mooney 	newsud->sud_prot = sud->sud_prot;
170*cc401b37SPatrick Mooney 
171*cc401b37SPatrick Mooney 	newseg->s_ops = seg->s_ops;
172*cc401b37SPatrick Mooney 	newseg->s_data = newsud;
173*cc401b37SPatrick Mooney 	return (0);
174*cc401b37SPatrick Mooney }
175*cc401b37SPatrick Mooney 
176*cc401b37SPatrick Mooney static int
segumap_unmap(struct seg * seg,caddr_t addr,size_t len)177*cc401b37SPatrick Mooney segumap_unmap(struct seg *seg, caddr_t addr, size_t len)
178*cc401b37SPatrick Mooney {
179*cc401b37SPatrick Mooney 	segumap_data_t *sud = (segumap_data_t *)seg->s_data;
180*cc401b37SPatrick Mooney 
181*cc401b37SPatrick Mooney 	ASSERT(seg->s_as && AS_WRITE_HELD(seg->s_as));
182*cc401b37SPatrick Mooney 
183*cc401b37SPatrick Mooney 	/* Only allow unmap of entire segment */
184*cc401b37SPatrick Mooney 	if (addr != seg->s_base || len != seg->s_size) {
185*cc401b37SPatrick Mooney 		return (EINVAL);
186*cc401b37SPatrick Mooney 	}
187*cc401b37SPatrick Mooney 	if (sud->sud_softlockcnt != 0) {
188*cc401b37SPatrick Mooney 		return (EAGAIN);
189*cc401b37SPatrick Mooney 	}
190*cc401b37SPatrick Mooney 
191*cc401b37SPatrick Mooney 	/*
192*cc401b37SPatrick Mooney 	 * Unconditionally unload the entire segment range.
193*cc401b37SPatrick Mooney 	 */
194*cc401b37SPatrick Mooney 	hat_unload(seg->s_as->a_hat, addr, len, HAT_UNLOAD_UNMAP);
195*cc401b37SPatrick Mooney 
196*cc401b37SPatrick Mooney 	seg_free(seg);
197*cc401b37SPatrick Mooney 	return (0);
198*cc401b37SPatrick Mooney }
199*cc401b37SPatrick Mooney 
200*cc401b37SPatrick Mooney static void
segumap_free(struct seg * seg)201*cc401b37SPatrick Mooney segumap_free(struct seg *seg)
202*cc401b37SPatrick Mooney {
203*cc401b37SPatrick Mooney 	segumap_data_t *data = (segumap_data_t *)seg->s_data;
204*cc401b37SPatrick Mooney 
205*cc401b37SPatrick Mooney 	ASSERT(data != NULL);
206*cc401b37SPatrick Mooney 
207*cc401b37SPatrick Mooney 	rw_destroy(&data->sud_lock);
208*cc401b37SPatrick Mooney 	VERIFY(data->sud_softlockcnt == 0);
209*cc401b37SPatrick Mooney 	kmem_free(data, sizeof (*data));
210*cc401b37SPatrick Mooney 	seg->s_data = NULL;
211*cc401b37SPatrick Mooney }
212*cc401b37SPatrick Mooney 
213*cc401b37SPatrick Mooney /* ARGSUSED */
214*cc401b37SPatrick Mooney static faultcode_t
segumap_fault(struct hat * hat,struct seg * seg,caddr_t addr,size_t len,enum fault_type type,enum seg_rw tw)215*cc401b37SPatrick Mooney segumap_fault(struct hat *hat, struct seg *seg, caddr_t addr, size_t len,
216*cc401b37SPatrick Mooney     enum fault_type type, enum seg_rw tw)
217*cc401b37SPatrick Mooney {
218*cc401b37SPatrick Mooney 	segumap_data_t *sud = (segumap_data_t *)seg->s_data;
219*cc401b37SPatrick Mooney 
220*cc401b37SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
221*cc401b37SPatrick Mooney 
222*cc401b37SPatrick Mooney 	if (type == F_PROT) {
223*cc401b37SPatrick Mooney 		/*
224*cc401b37SPatrick Mooney 		 * Since protection on the segment is fixed, there is nothing
225*cc401b37SPatrick Mooney 		 * to do but report an error for protection faults.
226*cc401b37SPatrick Mooney 		 */
227*cc401b37SPatrick Mooney 		return (FC_PROT);
228*cc401b37SPatrick Mooney 	} else if (type == F_SOFTUNLOCK) {
229*cc401b37SPatrick Mooney 		size_t plen = btop(len);
230*cc401b37SPatrick Mooney 
231*cc401b37SPatrick Mooney 		rw_enter(&sud->sud_lock, RW_WRITER);
232*cc401b37SPatrick Mooney 		VERIFY(sud->sud_softlockcnt >= plen);
233*cc401b37SPatrick Mooney 		sud->sud_softlockcnt -= plen;
234*cc401b37SPatrick Mooney 		rw_exit(&sud->sud_lock);
235*cc401b37SPatrick Mooney 		return (0);
236*cc401b37SPatrick Mooney 	}
237*cc401b37SPatrick Mooney 
238*cc401b37SPatrick Mooney 	ASSERT(type == F_INVAL || type == F_SOFTLOCK);
239*cc401b37SPatrick Mooney 	rw_enter(&sud->sud_lock, RW_WRITER);
240*cc401b37SPatrick Mooney 
241*cc401b37SPatrick Mooney 	if (type == F_INVAL ||
242*cc401b37SPatrick Mooney 	    (type == F_SOFTLOCK && sud->sud_softlockcnt == 0)) {
243*cc401b37SPatrick Mooney 		/*
244*cc401b37SPatrick Mooney 		 * Load the (entire) segment into the HAT.
245*cc401b37SPatrick Mooney 		 *
246*cc401b37SPatrick Mooney 		 * It's possible that threads racing into as_fault will cause
247*cc401b37SPatrick Mooney 		 * seg_umap to load the same range multiple times in quick
248*cc401b37SPatrick Mooney 		 * succession.  Redundant hat_devload operations are safe.
249*cc401b37SPatrick Mooney 		 */
250*cc401b37SPatrick Mooney 		for (uintptr_t i = 0; i < seg->s_size; i += PAGESIZE) {
251*cc401b37SPatrick Mooney 			pfn_t pfn;
252*cc401b37SPatrick Mooney 
253*cc401b37SPatrick Mooney 			pfn = hat_getpfnum(kas.a_hat, sud->sud_kaddr + i);
254*cc401b37SPatrick Mooney 			VERIFY(pfn != PFN_INVALID);
255*cc401b37SPatrick Mooney 			hat_devload(seg->s_as->a_hat, seg->s_base + i,
256*cc401b37SPatrick Mooney 			    PAGESIZE, pfn, sud->sud_prot, HAT_LOAD);
257*cc401b37SPatrick Mooney 		}
258*cc401b37SPatrick Mooney 	}
259*cc401b37SPatrick Mooney 	if (type == F_SOFTLOCK) {
260*cc401b37SPatrick Mooney 		size_t nval = sud->sud_softlockcnt + btop(len);
261*cc401b37SPatrick Mooney 
262*cc401b37SPatrick Mooney 		if (sud->sud_softlockcnt >= nval) {
263*cc401b37SPatrick Mooney 			rw_exit(&sud->sud_lock);
264*cc401b37SPatrick Mooney 			return (FC_MAKE_ERR(EOVERFLOW));
265*cc401b37SPatrick Mooney 		}
266*cc401b37SPatrick Mooney 		sud->sud_softlockcnt = nval;
267*cc401b37SPatrick Mooney 	}
268*cc401b37SPatrick Mooney 
269*cc401b37SPatrick Mooney 	rw_exit(&sud->sud_lock);
270*cc401b37SPatrick Mooney 	return (0);
271*cc401b37SPatrick Mooney }
272*cc401b37SPatrick Mooney 
273*cc401b37SPatrick Mooney /* ARGSUSED */
274*cc401b37SPatrick Mooney static faultcode_t
segumap_faulta(struct seg * seg,caddr_t addr)275*cc401b37SPatrick Mooney segumap_faulta(struct seg *seg, caddr_t addr)
276*cc401b37SPatrick Mooney {
277*cc401b37SPatrick Mooney 	/* Do nothing since asynch pagefault should not load translation. */
278*cc401b37SPatrick Mooney 	return (0);
279*cc401b37SPatrick Mooney }
280*cc401b37SPatrick Mooney 
281*cc401b37SPatrick Mooney /* ARGSUSED */
282*cc401b37SPatrick Mooney static int
segumap_setprot(struct seg * seg,caddr_t addr,size_t len,uint_t prot)283*cc401b37SPatrick Mooney segumap_setprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
284*cc401b37SPatrick Mooney {
285*cc401b37SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
286*cc401b37SPatrick Mooney 
287*cc401b37SPatrick Mooney 	/*
288*cc401b37SPatrick Mooney 	 * The seg_umap driver does not yet allow protection to be changed.
289*cc401b37SPatrick Mooney 	 */
290*cc401b37SPatrick Mooney 	return (EACCES);
291*cc401b37SPatrick Mooney }
292*cc401b37SPatrick Mooney 
293*cc401b37SPatrick Mooney /* ARGSUSED */
294*cc401b37SPatrick Mooney static int
segumap_checkprot(struct seg * seg,caddr_t addr,size_t len,uint_t prot)295*cc401b37SPatrick Mooney segumap_checkprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
296*cc401b37SPatrick Mooney {
297*cc401b37SPatrick Mooney 	segumap_data_t *sud = (segumap_data_t *)seg->s_data;
298*cc401b37SPatrick Mooney 	int error = 0;
299*cc401b37SPatrick Mooney 
300*cc401b37SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
301*cc401b37SPatrick Mooney 
302*cc401b37SPatrick Mooney 	rw_enter(&sud->sud_lock, RW_READER);
303*cc401b37SPatrick Mooney 	if ((sud->sud_prot & prot) != prot) {
304*cc401b37SPatrick Mooney 		error = EACCES;
305*cc401b37SPatrick Mooney 	}
306*cc401b37SPatrick Mooney 	rw_exit(&sud->sud_lock);
307*cc401b37SPatrick Mooney 	return (error);
308*cc401b37SPatrick Mooney }
309*cc401b37SPatrick Mooney 
310*cc401b37SPatrick Mooney /* ARGSUSED */
311*cc401b37SPatrick Mooney static int
segumap_sync(struct seg * seg,caddr_t addr,size_t len,int attr,uint_t flags)312*cc401b37SPatrick Mooney segumap_sync(struct seg *seg, caddr_t addr, size_t len, int attr, uint_t flags)
313*cc401b37SPatrick Mooney {
314*cc401b37SPatrick Mooney 	/* Always succeed since there are no backing store to sync */
315*cc401b37SPatrick Mooney 	return (0);
316*cc401b37SPatrick Mooney }
317*cc401b37SPatrick Mooney 
318*cc401b37SPatrick Mooney /* ARGSUSED */
319*cc401b37SPatrick Mooney static size_t
segumap_incore(struct seg * seg,caddr_t addr,size_t len,char * vec)320*cc401b37SPatrick Mooney segumap_incore(struct seg *seg, caddr_t addr, size_t len, char *vec)
321*cc401b37SPatrick Mooney {
322*cc401b37SPatrick Mooney 	size_t sz = 0;
323*cc401b37SPatrick Mooney 
324*cc401b37SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
325*cc401b37SPatrick Mooney 
326*cc401b37SPatrick Mooney 	len = (len + PAGEOFFSET) & PAGEMASK;
327*cc401b37SPatrick Mooney 	while (len > 0) {
328*cc401b37SPatrick Mooney 		*vec = 1;
329*cc401b37SPatrick Mooney 		sz += PAGESIZE;
330*cc401b37SPatrick Mooney 		vec++;
331*cc401b37SPatrick Mooney 		len -= PAGESIZE;
332*cc401b37SPatrick Mooney 	}
333*cc401b37SPatrick Mooney 	return (sz);
334*cc401b37SPatrick Mooney }
335*cc401b37SPatrick Mooney 
336*cc401b37SPatrick Mooney /* ARGSUSED */
337*cc401b37SPatrick Mooney static int
segumap_lockop(struct seg * seg,caddr_t addr,size_t len,int attr,int op,ulong_t * lockmap,size_t pos)338*cc401b37SPatrick Mooney segumap_lockop(struct seg *seg, caddr_t addr, size_t len, int attr, int op,
339*cc401b37SPatrick Mooney     ulong_t *lockmap, size_t pos)
340*cc401b37SPatrick Mooney {
341*cc401b37SPatrick Mooney 	/* Report success since kernel pages are always in memory. */
342*cc401b37SPatrick Mooney 	return (0);
343*cc401b37SPatrick Mooney }
344*cc401b37SPatrick Mooney 
345*cc401b37SPatrick Mooney static int
segumap_getprot(struct seg * seg,caddr_t addr,size_t len,uint_t * protv)346*cc401b37SPatrick Mooney segumap_getprot(struct seg *seg, caddr_t addr, size_t len, uint_t *protv)
347*cc401b37SPatrick Mooney {
348*cc401b37SPatrick Mooney 	segumap_data_t *sud = (segumap_data_t *)seg->s_data;
349*cc401b37SPatrick Mooney 	size_t pgno;
350*cc401b37SPatrick Mooney 	uint_t prot;
351*cc401b37SPatrick Mooney 
352*cc401b37SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
353*cc401b37SPatrick Mooney 
354*cc401b37SPatrick Mooney 	rw_enter(&sud->sud_lock, RW_READER);
355*cc401b37SPatrick Mooney 	prot = sud->sud_prot;
356*cc401b37SPatrick Mooney 	rw_exit(&sud->sud_lock);
357*cc401b37SPatrick Mooney 
358*cc401b37SPatrick Mooney 	/*
359*cc401b37SPatrick Mooney 	 * Reporting protection is simple since it is not tracked per-page.
360*cc401b37SPatrick Mooney 	 */
361*cc401b37SPatrick Mooney 	pgno = seg_page(seg, addr + len) - seg_page(seg, addr) + 1;
362*cc401b37SPatrick Mooney 	while (pgno > 0) {
363*cc401b37SPatrick Mooney 		protv[--pgno] = prot;
364*cc401b37SPatrick Mooney 	}
365*cc401b37SPatrick Mooney 	return (0);
366*cc401b37SPatrick Mooney }
367*cc401b37SPatrick Mooney 
368*cc401b37SPatrick Mooney /* ARGSUSED */
369*cc401b37SPatrick Mooney static u_offset_t
segumap_getoffset(struct seg * seg,caddr_t addr)370*cc401b37SPatrick Mooney segumap_getoffset(struct seg *seg, caddr_t addr)
371*cc401b37SPatrick Mooney {
372*cc401b37SPatrick Mooney 	/*
373*cc401b37SPatrick Mooney 	 * To avoid leaking information about the layout of the kernel address
374*cc401b37SPatrick Mooney 	 * space, always report '0' as the offset.
375*cc401b37SPatrick Mooney 	 */
376*cc401b37SPatrick Mooney 	return (0);
377*cc401b37SPatrick Mooney }
378*cc401b37SPatrick Mooney 
379*cc401b37SPatrick Mooney /* ARGSUSED */
380*cc401b37SPatrick Mooney static int
segumap_gettype(struct seg * seg,caddr_t addr)381*cc401b37SPatrick Mooney segumap_gettype(struct seg *seg, caddr_t addr)
382*cc401b37SPatrick Mooney {
383*cc401b37SPatrick Mooney 	/*
384*cc401b37SPatrick Mooney 	 * Since already-existing kernel pages are being mapped into userspace,
385*cc401b37SPatrick Mooney 	 * always report the segment type as shared.
386*cc401b37SPatrick Mooney 	 */
387*cc401b37SPatrick Mooney 	return (MAP_SHARED);
388*cc401b37SPatrick Mooney }
389*cc401b37SPatrick Mooney 
390*cc401b37SPatrick Mooney /* ARGSUSED */
391*cc401b37SPatrick Mooney static int
segumap_getvp(struct seg * seg,caddr_t addr,struct vnode ** vpp)392*cc401b37SPatrick Mooney segumap_getvp(struct seg *seg, caddr_t addr, struct vnode **vpp)
393*cc401b37SPatrick Mooney {
394*cc401b37SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
395*cc401b37SPatrick Mooney 
396*cc401b37SPatrick Mooney 	*vpp = NULL;
397*cc401b37SPatrick Mooney 	return (0);
398*cc401b37SPatrick Mooney }
399*cc401b37SPatrick Mooney 
400*cc401b37SPatrick Mooney /* ARGSUSED */
401*cc401b37SPatrick Mooney static int
segumap_advise(struct seg * seg,caddr_t addr,size_t len,uint_t behav)402*cc401b37SPatrick Mooney segumap_advise(struct seg *seg, caddr_t addr, size_t len, uint_t behav)
403*cc401b37SPatrick Mooney {
404*cc401b37SPatrick Mooney 	if (behav == MADV_PURGE) {
405*cc401b37SPatrick Mooney 		/* Purge does not make sense for this mapping */
406*cc401b37SPatrick Mooney 		return (EINVAL);
407*cc401b37SPatrick Mooney 	}
408*cc401b37SPatrick Mooney 	/* Indicate success for everything else. */
409*cc401b37SPatrick Mooney 	return (0);
410*cc401b37SPatrick Mooney }
411*cc401b37SPatrick Mooney 
412*cc401b37SPatrick Mooney /* ARGSUSED */
413*cc401b37SPatrick Mooney static void
segumap_dump(struct seg * seg)414*cc401b37SPatrick Mooney segumap_dump(struct seg *seg)
415*cc401b37SPatrick Mooney {
416*cc401b37SPatrick Mooney 	/*
417*cc401b37SPatrick Mooney 	 * Since this is a mapping to share kernel data with userspace, nothing
418*cc401b37SPatrick Mooney 	 * additional should be dumped.
419*cc401b37SPatrick Mooney 	 */
420*cc401b37SPatrick Mooney }
421*cc401b37SPatrick Mooney 
422*cc401b37SPatrick Mooney /* ARGSUSED */
423*cc401b37SPatrick Mooney static int
segumap_pagelock(struct seg * seg,caddr_t addr,size_t len,struct page *** ppp,enum lock_type type,enum seg_rw rw)424*cc401b37SPatrick Mooney segumap_pagelock(struct seg *seg, caddr_t addr, size_t len, struct page ***ppp,
425*cc401b37SPatrick Mooney     enum lock_type type, enum seg_rw rw)
426*cc401b37SPatrick Mooney {
427*cc401b37SPatrick Mooney 	return (ENOTSUP);
428*cc401b37SPatrick Mooney }
429*cc401b37SPatrick Mooney 
430*cc401b37SPatrick Mooney /* ARGSUSED */
431*cc401b37SPatrick Mooney static int
segumap_setpagesize(struct seg * seg,caddr_t addr,size_t len,uint_t szc)432*cc401b37SPatrick Mooney segumap_setpagesize(struct seg *seg, caddr_t addr, size_t len, uint_t szc)
433*cc401b37SPatrick Mooney {
434*cc401b37SPatrick Mooney 	return (ENOTSUP);
435*cc401b37SPatrick Mooney }
436*cc401b37SPatrick Mooney 
437*cc401b37SPatrick Mooney static int
segumap_getmemid(struct seg * seg,caddr_t addr,memid_t * memidp)438*cc401b37SPatrick Mooney segumap_getmemid(struct seg *seg, caddr_t addr, memid_t *memidp)
439*cc401b37SPatrick Mooney {
440*cc401b37SPatrick Mooney 	segumap_data_t *sud = (segumap_data_t *)seg->s_data;
441*cc401b37SPatrick Mooney 
442*cc401b37SPatrick Mooney 	memidp->val[0] = (uintptr_t)sud->sud_kaddr;
443*cc401b37SPatrick Mooney 	memidp->val[1] = (uintptr_t)(addr - seg->s_base);
444*cc401b37SPatrick Mooney 	return (0);
445*cc401b37SPatrick Mooney }
446*cc401b37SPatrick Mooney 
447*cc401b37SPatrick Mooney /* ARGSUSED */
448*cc401b37SPatrick Mooney static int
segumap_capable(struct seg * seg,segcapability_t capability)449*cc401b37SPatrick Mooney segumap_capable(struct seg *seg, segcapability_t capability)
450*cc401b37SPatrick Mooney {
451*cc401b37SPatrick Mooney 	/* no special capablities */
452*cc401b37SPatrick Mooney 	return (0);
453*cc401b37SPatrick Mooney }
454