Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/i86xpv/io/privcmd.c
+++ new/usr/src/uts/i86xpv/io/privcmd.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 #include <sys/xpv_user.h>
28 28
29 29 #include <sys/types.h>
30 30 #include <sys/file.h>
31 31 #include <sys/errno.h>
32 32 #include <sys/open.h>
33 33 #include <sys/cred.h>
34 34 #include <sys/conf.h>
35 35 #include <sys/stat.h>
36 36 #include <sys/modctl.h>
37 37 #include <sys/ddi.h>
38 38 #include <sys/sunddi.h>
39 39 #include <sys/vmsystm.h>
40 40 #include <sys/sdt.h>
41 41 #include <sys/hypervisor.h>
42 42 #include <sys/xen_errno.h>
43 43 #include <sys/policy.h>
44 44
45 45 #include <vm/hat_i86.h>
46 46 #include <vm/hat_pte.h>
47 47 #include <vm/seg_mf.h>
48 48
49 49 #include <xen/sys/privcmd.h>
50 50 #include <sys/privcmd_impl.h>
51 51
52 52 static dev_info_t *privcmd_devi;
53 53
54 54 /*ARGSUSED*/
55 55 static int
56 56 privcmd_getinfo(dev_info_t *devi, ddi_info_cmd_t cmd, void *arg, void **result)
57 57 {
58 58 switch (cmd) {
59 59 case DDI_INFO_DEVT2DEVINFO:
60 60 case DDI_INFO_DEVT2INSTANCE:
61 61 break;
62 62 default:
63 63 return (DDI_FAILURE);
64 64 }
65 65
66 66 switch (getminor((dev_t)arg)) {
67 67 case PRIVCMD_MINOR:
68 68 break;
69 69 default:
70 70 return (DDI_FAILURE);
71 71 }
72 72
73 73 if (cmd == DDI_INFO_DEVT2INSTANCE)
74 74 *result = 0;
75 75 else
76 76 *result = privcmd_devi;
77 77 return (DDI_SUCCESS);
78 78 }
79 79
80 80 static int
81 81 privcmd_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
82 82 {
83 83 if (cmd != DDI_ATTACH)
84 84 return (DDI_FAILURE);
85 85
86 86 if (ddi_create_minor_node(devi, PRIVCMD_NODE,
87 87 S_IFCHR, PRIVCMD_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS)
88 88 return (DDI_FAILURE);
89 89
90 90 privcmd_devi = devi;
91 91 ddi_report_dev(devi);
92 92 return (DDI_SUCCESS);
93 93 }
94 94
95 95 static int
96 96 privcmd_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
97 97 {
98 98 if (cmd != DDI_DETACH)
99 99 return (DDI_FAILURE);
100 100 ddi_remove_minor_node(devi, NULL);
101 101 privcmd_devi = NULL;
102 102 return (DDI_SUCCESS);
103 103 }
104 104
105 105 /*ARGSUSED1*/
106 106 static int
107 107 privcmd_open(dev_t *dev, int flag, int otyp, cred_t *cr)
108 108 {
109 109 return (getminor(*dev) == PRIVCMD_MINOR ? 0 : ENXIO);
110 110 }
111 111
112 112 /*
113 113 * Map a contiguous set of machine frames in a foreign domain.
114 114 * Used in the following way:
115 115 *
116 116 * privcmd_mmap_t p;
117 117 * privcmd_mmap_entry_t e;
118 118 *
119 119 * addr = mmap(NULL, size, prot, MAP_SHARED, fd, 0);
120 120 * p.num = number of privcmd_mmap_entry_t's
121 121 * p.dom = domid;
122 122 * p.entry = &e;
123 123 * e.va = addr;
124 124 * e.mfn = mfn;
125 125 * e.npages = btopr(size);
126 126 * ioctl(fd, IOCTL_PRIVCMD_MMAP, &p);
127 127 */
128 128 /*ARGSUSED2*/
129 129 int
130 130 do_privcmd_mmap(void *uarg, int mode, cred_t *cr)
131 131 {
132 132 privcmd_mmap_t __mmapcmd, *mmc = &__mmapcmd;
133 133 privcmd_mmap_entry_t *umme;
134 134 struct as *as = curproc->p_as;
135 135 struct seg *seg;
136 136 int i, error = 0;
137 137
138 138 if (ddi_copyin(uarg, mmc, sizeof (*mmc), mode))
139 139 return (EFAULT);
140 140
141 141 DTRACE_XPV3(mmap__start, domid_t, mmc->dom, int, mmc->num,
142 142 privcmd_mmap_entry_t *, mmc->entry);
143 143
144 144 if (mmc->dom == DOMID_SELF) {
145 145 error = ENOTSUP; /* Too paranoid? */
146 146 goto done;
147 147 }
148 148
149 149 for (umme = mmc->entry, i = 0; i < mmc->num; i++, umme++) {
150 150 privcmd_mmap_entry_t __mmapent, *mme = &__mmapent;
151 151 caddr_t addr;
152 152
153 153 if (ddi_copyin(umme, mme, sizeof (*mme), mode)) {
154 154 error = EFAULT;
155 155 break;
156 156 }
157 157
158 158 DTRACE_XPV3(mmap__entry, ulong_t, mme->va, ulong_t, mme->mfn,
159 159 ulong_t, mme->npages);
160 160
161 161 if (mme->mfn == MFN_INVALID) {
162 162 error = EINVAL;
163 163 break;
164 164 }
165 165
166 166 addr = (caddr_t)mme->va;
167 167
168 168 /*
169 169 * Find the segment we want to mess with, then add
170 170 * the mfn range to the segment.
171 171 */
172 172 AS_LOCK_ENTER(as, RW_READER);
173 173 if ((seg = as_findseg(as, addr, 0)) == NULL ||
174 174 addr + mmu_ptob(mme->npages) > seg->s_base + seg->s_size)
175 175 error = EINVAL;
176 176 else
177 177 error = segmf_add_mfns(seg, addr,
178 178 mme->mfn, mme->npages, mmc->dom);
179 179 AS_LOCK_EXIT(as);
180 180
181 181 if (error != 0)
182 182 break;
183 183 }
184 184
185 185 done:
186 186 DTRACE_XPV1(mmap__end, int, error);
187 187
188 188 return (error);
189 189 }
190 190
191 191 /*
192 192 * Set up the address range to map to an array of mfns in
193 193 * a foreign domain. Used in the following way:
194 194 *
195 195 * privcmd_mmap_batch_t p;
196 196 *
197 197 * addr = mmap(NULL, size, prot, MAP_SHARED, fd, 0);
198 198 * p.num = number of pages
199 199 * p.dom = domid
200 200 * p.addr = addr;
201 201 * p.arr = array of mfns, indexed 0 .. p.num - 1
202 202 * ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &p);
203 203 */
204 204 /*ARGSUSED2*/
205 205 static int
206 206 do_privcmd_mmapbatch(void *uarg, int mode, cred_t *cr)
207 207 {
208 208 privcmd_mmapbatch_t __mmapbatch, *mmb = &__mmapbatch;
209 209 struct as *as = curproc->p_as;
210 210 struct seg *seg;
211 211 int i, error = 0;
212 212 caddr_t addr;
213 213 ulong_t *ulp;
214 214
215 215 if (ddi_copyin(uarg, mmb, sizeof (*mmb), mode))
216 216 return (EFAULT);
217 217
218 218 DTRACE_XPV3(mmapbatch__start, domid_t, mmb->dom, int, mmb->num,
219 219 caddr_t, mmb->addr);
220 220
221 221 addr = (caddr_t)mmb->addr;
222 222 AS_LOCK_ENTER(as, RW_READER);
223 223 if ((seg = as_findseg(as, addr, 0)) == NULL ||
224 224 addr + ptob(mmb->num) > seg->s_base + seg->s_size) {
225 225 error = EINVAL;
226 226 goto done;
227 227 }
228 228
229 229 for (i = 0, ulp = mmb->arr;
230 230 i < mmb->num; i++, addr += PAGESIZE, ulp++) {
231 231 mfn_t mfn;
232 232
233 233 if (fulword(ulp, &mfn) != 0) {
234 234 error = EFAULT;
235 235 break;
236 236 }
237 237
238 238 if (mfn == MFN_INVALID) {
239 239 /*
240 240 * This mfn is invalid and should not be added to
241 241 * segmf, as we'd only cause an immediate EFAULT when
242 242 * we tried to fault it in.
243 243 */
244 244 mfn |= XEN_DOMCTL_PFINFO_XTAB;
245 245 continue;
246 246 }
247 247
248 248 if (segmf_add_mfns(seg, addr, mfn, 1, mmb->dom) == 0)
249 249 continue;
250 250
251 251 /*
252 252 * Tell the process that this MFN could not be mapped, so it
253 253 * won't later try to access it.
254 254 */
255 255 mfn |= XEN_DOMCTL_PFINFO_XTAB;
256 256 if (sulword(ulp, mfn) != 0) {
257 257 error = EFAULT;
258 258 break;
259 259 }
260 260 }
261 261
262 262 done:
263 263 AS_LOCK_EXIT(as);
264 264
265 265 DTRACE_XPV3(mmapbatch__end, int, error, struct seg *, seg, caddr_t,
266 266 mmb->addr);
267 267
268 268 return (error);
269 269 }
270 270
271 271 /*ARGSUSED*/
272 272 static int
273 273 privcmd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval)
274 274 {
275 275 if (secpolicy_xvm_control(cr))
276 276 return (EPERM);
277 277
278 278 /*
279 279 * Everything is a -native- data type.
280 280 */
281 281 if ((mode & FMODELS) != FNATIVE)
282 282 return (EOVERFLOW);
283 283
284 284 switch (cmd) {
285 285 case IOCTL_PRIVCMD_HYPERCALL:
286 286 return (do_privcmd_hypercall((void *)arg, mode, cr, rval));
287 287 case IOCTL_PRIVCMD_MMAP:
288 288 if (DOMAIN_IS_PRIVILEGED(xen_info))
289 289 return (do_privcmd_mmap((void *)arg, mode, cr));
290 290 break;
291 291 case IOCTL_PRIVCMD_MMAPBATCH:
292 292 if (DOMAIN_IS_PRIVILEGED(xen_info))
293 293 return (do_privcmd_mmapbatch((void *)arg, mode, cr));
294 294 break;
295 295 default:
296 296 break;
297 297 }
298 298 return (EINVAL);
299 299 }
300 300
301 301 /*
302 302 * The real magic happens in the segmf segment driver.
303 303 */
304 304 /*ARGSUSED8*/
305 305 static int
306 306 privcmd_segmap(dev_t dev, off_t off, struct as *as, caddr_t *addrp,
307 307 off_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr)
308 308 {
309 309 struct segmf_crargs a;
310 310 int error;
311 311
312 312 if (secpolicy_xvm_control(cr))
313 313 return (EPERM);
314 314
315 315 as_rangelock(as);
316 316 if ((flags & MAP_FIXED) == 0) {
317 317 map_addr(addrp, len, (offset_t)off, 0, flags);
318 318 if (*addrp == NULL) {
319 319 error = ENOMEM;
320 320 goto rangeunlock;
321 321 }
322 322 } else {
323 323 /*
324 324 * User specified address
325 325 */
326 326 (void) as_unmap(as, *addrp, len);
327 327 }
328 328
329 329 /*
330 330 * The mapping *must* be MAP_SHARED at offset 0.
331 331 *
332 332 * (Foreign pages are treated like device memory; the
333 333 * ioctl interface allows the backing objects to be
334 334 * arbitrarily redefined to point at any machine frame.)
335 335 */
336 336 if ((flags & MAP_TYPE) != MAP_SHARED || off != 0) {
337 337 error = EINVAL;
338 338 goto rangeunlock;
339 339 }
340 340
341 341 a.dev = dev;
342 342 a.prot = (uchar_t)prot;
343 343 a.maxprot = (uchar_t)maxprot;
344 344 error = as_map(as, *addrp, len, segmf_create, &a);
345 345
346 346 rangeunlock:
347 347 as_rangeunlock(as);
348 348 return (error);
349 349 }
350 350
351 351 static struct cb_ops privcmd_cb_ops = {
352 352 privcmd_open,
353 353 nulldev, /* close */
354 354 nodev, /* strategy */
355 355 nodev, /* print */
356 356 nodev, /* dump */
357 357 nodev, /* read */
358 358 nodev, /* write */
359 359 privcmd_ioctl,
360 360 nodev, /* devmap */
361 361 nodev, /* mmap */
362 362 privcmd_segmap,
363 363 nochpoll, /* poll */
364 364 ddi_prop_op,
365 365 NULL,
366 366 D_64BIT | D_NEW | D_MP
367 367 };
368 368
369 369 static struct dev_ops privcmd_dv_ops = {
370 370 DEVO_REV,
371 371 0,
372 372 privcmd_getinfo,
373 373 nulldev, /* identify */
374 374 nulldev, /* probe */
375 375 privcmd_attach,
376 376 privcmd_detach,
377 377 nodev, /* reset */
378 378 &privcmd_cb_ops,
379 379 0, /* struct bus_ops */
380 380 NULL, /* power */
381 381 ddi_quiesce_not_needed, /* quiesce */
↓ open down ↓ |
381 lines elided |
↑ open up ↑ |
382 382 };
383 383
384 384 static struct modldrv modldrv = {
385 385 &mod_driverops,
386 386 "privcmd driver",
387 387 &privcmd_dv_ops
388 388 };
389 389
390 390 static struct modlinkage modl = {
391 391 MODREV_1,
392 - &modldrv
392 + { &modldrv, NULL }
393 393 };
394 394
395 395 int
396 396 _init(void)
397 397 {
398 398 return (mod_install(&modl));
399 399 }
400 400
401 401 int
402 402 _fini(void)
403 403 {
404 404 return (mod_remove(&modl));
405 405 }
406 406
407 407 int
408 408 _info(struct modinfo *modinfo)
409 409 {
410 410 return (mod_info(&modl, modinfo));
411 411 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX