VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/freebsd/SUPDrv-freebsd.c@ 39522

最後變更 在這個檔案從39522是 39522,由 vboxsync 提交於 13 年 前

Support/FreeBSD: errno and IPRT error code mixup

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 15.1 KB
 
1/* $Id: SUPDrv-freebsd.c 39522 2011-12-05 10:19:31Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - FreeBSD specifics.
4 */
5
6/*
7 * Copyright (c) 2007 knut st. osmundsen <[email protected]>
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#define LOG_GROUP LOG_GROUP_SUP_DRV
35/* Deal with conflicts first. */
36#include <sys/param.h>
37#undef PVM
38#include <sys/types.h>
39#include <sys/module.h>
40#include <sys/systm.h>
41#include <sys/errno.h>
42#include <sys/kernel.h>
43#include <sys/fcntl.h>
44#include <sys/conf.h>
45#include <sys/uio.h>
46
47#include "../SUPDrvInternal.h"
48#include <VBox/version.h>
49#include <iprt/initterm.h>
50#include <iprt/string.h>
51#include <iprt/spinlock.h>
52#include <iprt/process.h>
53#include <iprt/assert.h>
54#include <iprt/uuid.h>
55#include <VBox/log.h>
56#include <iprt/alloc.h>
57#include <iprt/err.h>
58#include <iprt/asm.h>
59
60#ifdef VBOX_WITH_HARDENING
61# define VBOXDRV_PERM 0600
62#else
63# define VBOXDRV_PERM 0666
64#endif
65
66/*******************************************************************************
67* Internal Functions *
68*******************************************************************************/
69static int VBoxDrvFreeBSDModuleEvent(struct module *pMod, int enmEventType, void *pvArg);
70static int VBoxDrvFreeBSDLoad(void);
71static int VBoxDrvFreeBSDUnload(void);
72
73static d_open_t VBoxDrvFreeBSDOpen;
74static void VBoxDrvFreeBSDDtr(void *pData);
75static d_ioctl_t VBoxDrvFreeBSDIOCtl;
76static int VBoxDrvFreeBSDIOCtlSlow(PSUPDRVSESSION pSession, u_long ulCmd, caddr_t pvData, struct thread *pTd);
77
78
79/*******************************************************************************
80* Global Variables *
81*******************************************************************************/
82/**
83 * Module info structure used by the kernel.
84 */
85static moduledata_t g_VBoxDrvFreeBSDModule =
86{
87 "vboxdrv",
88 VBoxDrvFreeBSDModuleEvent,
89 NULL
90};
91
92/** Declare the module as a pseudo device. */
93DECLARE_MODULE(vboxdrv, g_VBoxDrvFreeBSDModule, SI_SUB_PSEUDO, SI_ORDER_ANY);
94MODULE_VERSION(vboxdrv, 1);
95
96/**
97 * The /dev/vboxdrv character device entry points.
98 */
99static struct cdevsw g_VBoxDrvFreeBSDChrDevSW =
100{
101 .d_version = D_VERSION,
102 .d_open = VBoxDrvFreeBSDOpen,
103 .d_ioctl = VBoxDrvFreeBSDIOCtl,
104 .d_name = "vboxdrv"
105};
106
107/** The /dev/vboxdrv character device. */
108static struct cdev *g_pVBoxDrvFreeBSDChrDev;
109/** Reference counter. */
110static volatile uint32_t g_cUsers;
111
112/** The device extention. */
113static SUPDRVDEVEXT g_VBoxDrvFreeBSDDevExt;
114
115/**
116 * Module event handler.
117 *
118 * @param pMod The module structure.
119 * @param enmEventType The event type (modeventtype_t).
120 * @param pvArg Module argument. NULL.
121 *
122 * @return 0 on success, errno.h status code on failure.
123 */
124static int VBoxDrvFreeBSDModuleEvent(struct module *pMod, int enmEventType, void *pvArg)
125{
126 int rc;
127 switch (enmEventType)
128 {
129 case MOD_LOAD:
130 rc = VBoxDrvFreeBSDLoad();
131 break;
132
133 case MOD_UNLOAD:
134 mtx_unlock(&Giant);
135 rc = VBoxDrvFreeBSDUnload();
136 mtx_lock(&Giant);
137 break;
138
139 case MOD_SHUTDOWN:
140 case MOD_QUIESCE:
141 default:
142 return EOPNOTSUPP;
143 }
144
145 if (RT_SUCCESS(rc))
146 return 0;
147 return RTErrConvertToErrno(rc);
148}
149
150
151static int VBoxDrvFreeBSDLoad(void)
152{
153 g_cUsers = 0;
154
155 /*
156 * Initialize the runtime.
157 */
158 int rc = RTR0Init(0);
159 if (RT_SUCCESS(rc))
160 {
161 Log(("VBoxDrvFreeBSDLoad:\n"));
162
163 /*
164 * Initialize the device extension.
165 */
166 rc = supdrvInitDevExt(&g_VBoxDrvFreeBSDDevExt, sizeof(SUPDRVSESSION));
167 if (RT_SUCCESS(rc))
168 {
169 /*
170 * Configure character device. Add symbolic link for compatibility.
171 */
172 g_pVBoxDrvFreeBSDChrDev = make_dev(&g_VBoxDrvFreeBSDChrDevSW, 0, UID_ROOT, GID_WHEEL, VBOXDRV_PERM, "vboxdrv");
173 return VINF_SUCCESS;
174 }
175 else
176 printf("vboxdrv: supdrvInitDevExt failed, rc=%d\n", rc);
177 RTR0Term();
178 }
179 else
180 printf("vboxdrv: RTR0Init failed, rc=%d\n", rc);
181 return rc;
182}
183
184static int VBoxDrvFreeBSDUnload(void)
185{
186 Log(("VBoxDrvFreeBSDUnload:\n"));
187
188 if (g_cUsers > 0)
189 return VERR_RESOURCE_BUSY;
190
191 /*
192 * Reserve what we did in VBoxDrvFreeBSDInit.
193 */
194 destroy_dev(g_pVBoxDrvFreeBSDChrDev);
195
196 supdrvDeleteDevExt(&g_VBoxDrvFreeBSDDevExt);
197
198 RTR0Term();
199
200 memset(&g_VBoxDrvFreeBSDDevExt, 0, sizeof(g_VBoxDrvFreeBSDDevExt));
201
202 Log(("VBoxDrvFreeBSDUnload: returns\n"));
203 return VINF_SUCCESS;
204}
205
206
207/**
208 *
209 * @returns 0 on success, errno on failure.
210 * EBUSY if the device is used by someone else.
211 * @param pDev The device node.
212 * @param fOpen The open flags.
213 * @param pTd The thread.
214 * @param pFd The file descriptor. FreeBSD 7.0 and later.
215 * @param iFd The file descriptor index(?). Pre FreeBSD 7.0.
216 */
217static int VBoxDrvFreeBSDOpen(struct cdev *pDev, int fOpen, int iDevtype, struct thread *pTd)
218{
219 PSUPDRVSESSION pSession;
220 int rc;
221
222 /*
223 * Let's be a bit picky about the flags...
224 */
225 if (fOpen != (FREAD|FWRITE /*=O_RDWR*/))
226 {
227 Log(("VBoxDrvFreeBSDOpen: fOpen=%#x expected %#x\n", fOpen, O_RDWR));
228 return EINVAL;
229 }
230
231 /*
232 * Create a new session.
233 */
234 rc = supdrvCreateSession(&g_VBoxDrvFreeBSDDevExt, true /* fUser */, &pSession);
235 if (RT_SUCCESS(rc))
236 {
237 /** @todo get (r)uid and (r)gid.
238 pSession->Uid = stuff;
239 pSession->Gid = stuff; */
240 devfs_set_cdevpriv(pSession, VBoxDrvFreeBSDDtr);
241 Log(("VBoxDrvFreeBSDOpen: pSession=%p\n", pSession));
242 ASMAtomicIncU32(&g_cUsers);
243 return 0;
244 }
245
246 return RTErrConvertToErrno(rc);
247}
248
249
250/**
251 * Close a file device previously opened by VBoxDrvFreeBSDOpen
252 *
253 * @returns 0 on success.
254 * @param pDev The device.
255 * @param fFile The file descriptor flags.
256 * @param DevType The device type (CHR.
257 * @param pTd The calling thread.
258 */
259static void VBoxDrvFreeBSDDtr(void *pData)
260{
261 PSUPDRVSESSION pSession = pData;
262 Log(("VBoxDrvFreeBSDDtr: pSession=%p\n", pSession));
263
264 /*
265 * Close the session.
266 */
267 supdrvCloseSession(&g_VBoxDrvFreeBSDDevExt, pSession);
268 ASMAtomicDecU32(&g_cUsers);
269}
270
271
272/**
273 * I/O control request.
274 *
275 * @returns depends...
276 * @param pDev The device.
277 * @param ulCmd The command.
278 * @param pvData Pointer to the data.
279 * @param fFile The file descriptor flags.
280 * @param pTd The calling thread.
281 */
282static int VBoxDrvFreeBSDIOCtl(struct cdev *pDev, u_long ulCmd, caddr_t pvData, int fFile, struct thread *pTd)
283{
284 PSUPDRVSESSION pSession;
285 devfs_get_cdevpriv((void **)&pSession);
286
287 /*
288 * Deal with the fast ioctl path first.
289 */
290 if ( ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN
291 || ulCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
292 || ulCmd == SUP_IOCTL_FAST_DO_NOP)
293 return supdrvIOCtlFast(ulCmd, *(uint32_t *)pvData, &g_VBoxDrvFreeBSDDevExt, pSession);
294
295 return VBoxDrvFreeBSDIOCtlSlow(pSession, ulCmd, pvData, pTd);
296}
297
298
299/**
300 * Deal with the 'slow' I/O control requests.
301 *
302 * @returns 0 on success, appropriate errno on failure.
303 * @param pSession The session.
304 * @param ulCmd The command.
305 * @param pvData The request data.
306 * @param pTd The calling thread.
307 */
308static int VBoxDrvFreeBSDIOCtlSlow(PSUPDRVSESSION pSession, u_long ulCmd, caddr_t pvData, struct thread *pTd)
309{
310 PSUPREQHDR pHdr;
311 uint32_t cbReq = IOCPARM_LEN(ulCmd);
312 void *pvUser = NULL;
313
314 /*
315 * Buffered request?
316 */
317 if ((IOC_DIRMASK & ulCmd) == IOC_INOUT)
318 {
319 pHdr = (PSUPREQHDR)pvData;
320 if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
321 {
322 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: cbReq=%#x < %#x; ulCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), ulCmd));
323 return EINVAL;
324 }
325 if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
326 {
327 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: bad magic fFlags=%#x; ulCmd=%#lx\n", pHdr->fFlags, ulCmd));
328 return EINVAL;
329 }
330 if (RT_UNLIKELY( RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
331 || pHdr->cbIn < sizeof(*pHdr)
332 || pHdr->cbOut < sizeof(*pHdr)))
333 {
334 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: max(%#x,%#x) != %#x; ulCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, ulCmd));
335 return EINVAL;
336 }
337 }
338 /*
339 * Big unbuffered request?
340 */
341 else if ((IOC_DIRMASK & ulCmd) == IOC_VOID && !cbReq)
342 {
343 /*
344 * Read the header, validate it and figure out how much that needs to be buffered.
345 */
346 SUPREQHDR Hdr;
347 pvUser = *(void **)pvData;
348 int rc = copyin(pvUser, &Hdr, sizeof(Hdr));
349 if (RT_UNLIKELY(rc))
350 {
351 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyin(%p,Hdr,) -> %#x; ulCmd=%#lx\n", pvUser, rc, ulCmd));
352 return rc;
353 }
354 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
355 {
356 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: bad magic fFlags=%#x; ulCmd=%#lx\n", Hdr.fFlags, ulCmd));
357 return EINVAL;
358 }
359 cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
360 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
361 || Hdr.cbOut < sizeof(Hdr)
362 || cbReq > _1M*16))
363 {
364 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: max(%#x,%#x); ulCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, ulCmd));
365 return EINVAL;
366 }
367
368 /*
369 * Allocate buffer and copy in the data.
370 */
371 pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq);
372 if (RT_UNLIKELY(!pHdr))
373 {
374 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: failed to allocate buffer of %d bytes; ulCmd=%#lx\n", cbReq, ulCmd));
375 return ENOMEM;
376 }
377 rc = copyin(pvUser, pHdr, Hdr.cbIn);
378 if (RT_UNLIKELY(rc))
379 {
380 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyin(%p,%p,%#x) -> %#x; ulCmd=%#lx\n",
381 pvUser, pHdr, Hdr.cbIn, rc, ulCmd));
382 RTMemTmpFree(pHdr);
383 return rc;
384 }
385 }
386 else
387 {
388 Log(("VBoxDrvFreeBSDIOCtlSlow: huh? cbReq=%#x ulCmd=%#lx\n", cbReq, ulCmd));
389 return EINVAL;
390 }
391
392 /*
393 * Process the IOCtl.
394 */
395 int rc = supdrvIOCtl(ulCmd, &g_VBoxDrvFreeBSDDevExt, pSession, pHdr);
396 if (RT_LIKELY(!rc))
397 {
398 /*
399 * If unbuffered, copy back the result before returning.
400 */
401 if (pvUser)
402 {
403 uint32_t cbOut = pHdr->cbOut;
404 if (cbOut > cbReq)
405 {
406 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, ulCmd));
407 cbOut = cbReq;
408 }
409 rc = copyout(pHdr, pvUser, cbOut);
410 if (RT_UNLIKELY(rc))
411 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyout(%p,%p,%#x) -> %d; uCmd=%#lx!\n", pHdr, pvUser, cbOut, rc, ulCmd));
412
413 Log(("VBoxDrvFreeBSDIOCtlSlow: returns %d / %d ulCmd=%lx\n", 0, pHdr->rc, ulCmd));
414
415 /* cleanup */
416 RTMemTmpFree(pHdr);
417 }
418 }
419 else
420 {
421 /*
422 * The request failed, just clean up.
423 */
424 if (pvUser)
425 RTMemTmpFree(pHdr);
426
427 Log(("VBoxDrvFreeBSDIOCtlSlow: ulCmd=%lx pData=%p failed, rc=%d\n", ulCmd, pvData, rc));
428 rc = EINVAL;
429 }
430
431 return rc;
432}
433
434
435/**
436 * The SUPDRV IDC entry point.
437 *
438 * @returns VBox status code, see supdrvIDC.
439 * @param iReq The request code.
440 * @param pReq The request.
441 */
442int VBOXCALL SUPDrvFreeBSDIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
443{
444 PSUPDRVSESSION pSession;
445
446 /*
447 * Some quick validations.
448 */
449 if (RT_UNLIKELY(!VALID_PTR(pReq)))
450 return VERR_INVALID_POINTER;
451
452 pSession = pReq->pSession;
453 if (pSession)
454 {
455 if (RT_UNLIKELY(!VALID_PTR(pReq->pSession)))
456 return VERR_INVALID_PARAMETER;
457 if (RT_UNLIKELY(pSession->pDevExt != &g_VBoxDrvFreeBSDDevExt))
458 return VERR_INVALID_PARAMETER;
459 }
460 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
461 return VERR_INVALID_PARAMETER;
462
463 /*
464 * Do the job.
465 */
466 return supdrvIDC(uReq, &g_VBoxDrvFreeBSDDevExt, pSession, pReq);
467}
468
469
470void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
471{
472 NOREF(pObj);
473 NOREF(pSession);
474}
475
476
477bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
478{
479 NOREF(pObj);
480 NOREF(pSession);
481 NOREF(pszObjName);
482 NOREF(prc);
483 return false;
484}
485
486
487bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
488{
489 return false;
490}
491
492
493int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
494{
495 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
496 return VERR_NOT_SUPPORTED;
497}
498
499
500int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
501{
502 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
503 return VERR_NOT_SUPPORTED;
504}
505
506
507int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
508{
509 NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits); NOREF(pReq);
510 return VERR_NOT_SUPPORTED;
511}
512
513
514void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
515{
516 NOREF(pDevExt); NOREF(pImage);
517}
518
519
520SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
521{
522 va_list va;
523 char szMsg[256];
524 int cch;
525
526 va_start(va, pszFormat);
527 cch = RTStrPrintfV(szMsg, sizeof(szMsg), pszFormat, va);
528 va_end(va);
529
530 printf("%s", szMsg);
531
532 return cch;
533}
534
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette