Changeset 4988 in vbox for trunk/src/VBox/HostDrivers/Support
- Timestamp:
- Sep 24, 2007 3:47:01 AM (17 years ago)
- Location:
- trunk/src/VBox/HostDrivers/Support/freebsd
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/freebsd/SUPDrv-freebsd.c
r4800 r4988 41 41 #include <sys/errno.h> 42 42 #include <sys/kernel.h> 43 #include <sys/fcntl.h> 43 44 #include <sys/conf.h> 44 45 #include <sys/uio.h> … … 52 53 #include <iprt/assert.h> 53 54 #include <iprt/log.h> 55 #include <iprt/alloc.h> 56 #include <iprt/err.h> 54 57 55 58 … … 60 63 static int VBoxDrvFreeBSDLoad(void); 61 64 static int VBoxDrvFreeBSDUnload(void); 65 static void VBoxDrvFreeBSDClone(void *pvArg, struct ucred *pCred, char *pachName, int cchName, struct cdev **ppDev); 66 62 67 static d_fdopen_t VBoxDrvFreeBSDOpen; 63 68 static d_close_t VBoxDrvFreeBSDClose; 64 69 static d_ioctl_t VBoxDrvFreeBSDIOCtl; 65 static int VBoxDrvFreeBsdErr2Native(int rc);70 static int VBoxDrvFreeBSDIOCtlSlow(PSUPDRVSESSION pSession, u_long ulCmd, caddr_t pvData, struct thread *pTd); 66 71 67 72 … … 72 77 * Module info structure used by the kernel. 73 78 */ 74 static moduledata_t g_VBoxDrvFreeBSDModule =79 static moduledata_t g_VBoxDrvFreeBSDModule = 75 80 { 76 81 "vboxdrv", … … 80 85 81 86 /** Declare the module as a pseudo device. */ 82 DECLARE_MODULE(vboxdrv, g_VBoxDrvFreeBSDModule, SI_SUB_PSEUDO, SI_ORDER_ANY);87 DECLARE_MODULE(vboxdrv, g_VBoxDrvFreeBSDModule, SI_SUB_PSEUDO, SI_ORDER_ANY); 83 88 84 89 /** … … 88 93 { 89 94 .d_version = D_VERSION, 90 .d_flags = D_ TRACKCLOSE,95 .d_flags = D_PSEUDO | D_TRACKCLOSE, 91 96 .d_fdopen = VBoxDrvFreeBSDOpen, 92 97 .d_close = VBoxDrvFreeBSDClose, … … 95 100 }; 96 101 97 /** The make_dev result. */ 98 static struct cdev *g_pVBoxDrvFreeBSDChrDev; 102 /** List of cloned device. Managed by the kernel. */ 103 static struct clonedevs *g_pVBoxDrvFreeBSDClones; 104 /** The dev_clone event handler tag. */ 105 static eventhandler_tag g_VBoxDrvFreeBSDEHTag; 99 106 100 107 /** The device extention. */ 101 static SUPDRVDEVEXT g_DevExt; 102 103 /** Spinlock protecting g_apSessionHashTab. */ 104 static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK; 105 /** Hash table */ 106 static PSUPDRVSESSION g_apSessionHashTab[19]; 107 /** Calculates the index into g_apSessionHashTab.*/ 108 #define SESSION_HASH(sfn) ((sfn) % RT_ELEMENTS(g_apSessionHashTab)) 108 static SUPDRVDEVEXT g_VBoxDrvFreeBSDDevExt; 109 109 110 110 … … 141 141 if (RT_SUCCESS(rc)) 142 142 return 0; 143 return VBoxDrvFreeBsdErr2Native(rc);143 return RTErrConvertToErrno(rc); 144 144 } 145 145 … … 158 158 * Initialize the device extension. 159 159 */ 160 rc = supdrvInitDevExt(&g_ DevExt);160 rc = supdrvInitDevExt(&g_VBoxDrvFreeBSDDevExt); 161 161 if (RT_SUCCESS(rc)) 162 162 { 163 163 /* 164 * Initialize the session hash table.164 * Configure device cloning. 165 165 */ 166 rc = RTSpinlockCreate(&g_Spinlock); 167 if (RT_SUCCESS(rc)) 166 clone_setup(&g_pVBoxDrvFreeBSDClones); 167 g_VBoxDrvFreeBSDEHTag = EVENTHANDLER_REGISTER(dev_clone, VBoxDrvFreeBSDClone, 0, 1000); 168 if (g_VBoxDrvFreeBSDEHTag) 168 169 { 169 /* 170 * Create our device node. 171 */ 172 /** @todo find a way to fix this 0666 permission issue. Perhaps by defining some vboxusers group with a fixed gid? */ 173 g_pVBoxDrvFreeBSDChrDev = make_dev(&g_VBoxDrvFreeBSDChrDevSW, 174 0, 175 UID_ROOT, 176 GID_WHEEL, 177 0666, 178 "vboxdrv"); 179 if (g_pVBoxDrvFreeBSDChrDev) 180 { 181 dprintf(("VBoxDrvFreeBSDLoad: returns successfully\n")); 182 return VINF_SUCCESS; 183 } 184 185 printf("vboxdrv: make_dev failed\n"); 186 rc = SUPDRV_ERR_ALREADY_LOADED; 187 RTSpinlockDestroy(g_Spinlock); 188 g_Spinlock = NIL_RTSPINLOCK; 170 dprintf(("VBoxDrvFreeBSDLoad: returns successfully\n")); 171 return VINF_SUCCESS; 189 172 } 190 else 191 printf("vboxdrv: RTSpinlockCreate failed, rc=%d\n", rc); 192 supdrvDeleteDevExt(&g_DevExt); 173 174 printf("vboxdrv: EVENTHANDLER_REGISTER(dev_clone,,,) failed\n"); 175 clone_cleanup(&g_pVBoxDrvFreeBSDClones); 176 rc = SUPDRV_ERR_ALREADY_LOADED; 177 supdrvDeleteDevExt(&g_VBoxDrvFreeBSDDevExt); 193 178 } 194 179 else … … 203 188 static int VBoxDrvFreeBSDUnload(void) 204 189 { 205 int rc;206 190 dprintf(("VBoxDrvFreeBSDUnload:\n")); 207 191 … … 211 195 * Reserve what we did in VBoxDrvFreeBSDInit. 212 196 */ 213 if (g_pVBoxDrvFreeBSDChrDev) 214 { 215 destroy_dev(g_pVBoxDrvFreeBSDChrDev); 216 g_pVBoxDrvFreeBSDChrDev = NULL; 217 } 218 219 supdrvDeleteDevExt(&g_DevExt); 220 221 rc = RTSpinlockDestroy(g_Spinlock); 222 AssertRC(rc); 223 g_Spinlock = NIL_RTSPINLOCK; 197 clone_cleanup(&g_pVBoxDrvFreeBSDClones); 198 199 supdrvDeleteDevExt(&g_VBoxDrvFreeBSDDevExt); 224 200 225 201 RTR0Term(); 226 202 227 memset(&g_ DevExt, 0, sizeof(g_DevExt));203 memset(&g_VBoxDrvFreeBSDDevExt, 0, sizeof(g_VBoxDrvFreeBSDDevExt)); 228 204 229 205 dprintf(("VBoxDrvFreeBSDUnload: returns\n")); … … 232 208 233 209 234 static int VBoxDrvFreeBSDOpen(struct cdev *dev, int oflags, struct thread *td, int fdidx) 235 { 236 dprintf(("VBoxDrvFreeBSDOpen:\n")); 237 return EOPNOTSUPP; 238 } 239 240 241 static int VBoxDrvFreeBSDClose(struct cdev *dev, int fflag, int devtype, struct thread *td) 242 { 243 dprintf(("VBoxDrvFreeBSDClose:\n")); 244 return EBADF; 245 } 246 247 248 static int VBoxDrvFreeBSDIOCtl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 249 { 250 dprintf(("VBoxDrvFreeBSDIOCtl:\n")); 251 return EINVAL; 252 } 253 254 255 /** 256 * Converts an supdrv error code to a FreeBSD error code. 257 * 258 * @returns corresponding FreeBSD error code. 259 * @param rc supdrv error code (SUPDRV_ERR_* defines). 260 */ 261 static int VBoxDrvFreeBsdErr2Native(int rc) 262 { 263 switch (rc) 264 { 265 case 0: return 0; 266 case SUPDRV_ERR_GENERAL_FAILURE: return EACCES; 267 case SUPDRV_ERR_INVALID_PARAM: return EINVAL; 268 case SUPDRV_ERR_INVALID_MAGIC: return EILSEQ; 269 case SUPDRV_ERR_INVALID_HANDLE: return ENXIO; 270 case SUPDRV_ERR_INVALID_POINTER: return EFAULT; 271 case SUPDRV_ERR_LOCK_FAILED: return ENOLCK; 272 case SUPDRV_ERR_ALREADY_LOADED: return EEXIST; 273 case SUPDRV_ERR_PERMISSION_DENIED: return EPERM; 274 case SUPDRV_ERR_VERSION_MISMATCH: return ENOSYS; 275 } 276 277 return EPERM; 278 } 210 /** 211 * DEVFS event handler. 212 */ 213 static void VBoxDrvFreeBSDClone(void *pvArg, struct ucred *pCred, char *pszName, int cchName, struct cdev **ppDev) 214 { 215 int iUnit; 216 int rc; 217 218 dprintf(("VBoxDrvFreeBSDClone: pszName=%s ppDev=%p\n", pszName, ppDev)); 219 220 /* 221 * One device node per user, si_drv1 points to the session. 222 * /dev/vboxdrv<N> where N = {0...255}. 223 */ 224 if (!ppDev) 225 return; 226 if (dev_stdclone(pszName, NULL, "vboxdrv", &iUnit) != 1) 227 return; 228 if (iUnit >= 256 || iUnit < 0) 229 { 230 dprintf(("VBoxDrvFreeBSDClone: iUnit=%d >= 256 - rejected\n", iUnit)); 231 return; 232 } 233 234 dprintf(("VBoxDrvFreeBSDClone: pszName=%s iUnit=%d\n", pszName, iUnit)); 235 236 rc = clone_create(&g_pVBoxDrvFreeBSDClones, &g_VBoxDrvFreeBSDChrDevSW, &iUnit, ppDev, 0); 237 dprintf(("VBoxDrvFreeBSDClone: clone_create -> %d; iUnit=%d\n", rc, iUnit)); 238 if (rc) 239 { 240 *ppDev = make_dev(&g_VBoxDrvFreeBSDChrDevSW, 241 unit2minor(iUnit), 242 UID_ROOT, 243 GID_WHEEL, 244 0666, 245 "vboxdrv%d", iUnit); 246 if (*ppDev) 247 { 248 dev_ref(*ppDev); 249 (*ppDev)->si_flags |= SI_CHEAPCLONE; 250 dprintf(("VBoxDrvFreeBSDClone: Created *ppDev=%p iUnit=%d si_drv1=%p si_drv2=%p\n", 251 *ppDev, iUnit, (*ppDev)->si_drv1, (*ppDev)->si_drv2)); 252 (*ppDev)->si_drv1 = (*ppDev)->si_drv2 = NULL; 253 } 254 else 255 OSDBGPRINT(("VBoxDrvFreeBSDClone: make_dev iUnit=%d failed\n", iUnit)); 256 } 257 else 258 dprintf(("VBoxDrvFreeBSDClone: Existing *ppDev=%p iUnit=%d si_drv1=%p si_drv2=%p\n", 259 *ppDev, iUnit, (*ppDev)->si_drv1, (*ppDev)->si_drv2)); 260 } 261 262 263 264 /** 265 * 266 * @returns 0 on success, errno on failure. 267 * EBUSY if the device is used by someone else. 268 * @param pDev The device node. 269 * @param fOpen The open flags. 270 * @param pTd The thread. 271 * @param pFd The file descriptor. FreeBSD 7.0 and later. 272 * @param iFd The file descriptor index(?). Pre FreeBSD 7.0. 273 */ 274 #if FreeBSD >= 700 /* figure when and how to check properly */ 275 static int VBoxDrvFreeBSDOpen(struct cdev *pDev, int fOpen, struct thread *pTd, struct file *pFd) 276 #else 277 static int VBoxDrvFreeBSDOpen(struct cdev *pDev, int fOpen, struct thread *pTd, int iFd) 278 #endif 279 { 280 PSUPDRVSESSION pSession; 281 int rc; 282 283 dprintf(("VBoxDrvFreeBSDOpen: fOpen=%#x iUnit=%d\n", fOpen, minor2unit(minor(pDev)))); 284 285 /* 286 * Let's be a bit picky about the flags... 287 */ 288 if (fOpen != (FREAD|FWRITE /*=O_RDWR*/)) 289 { 290 dprintf(("VBoxDrvFreeBSDOpen: fOpen=%#x expected %#x\n", fOpen, O_RDWR)); 291 return EINVAL; 292 } 293 294 /* 295 * Try grab it (we don't grab the giant, remember). 296 */ 297 if (!ASMAtomicCmpXchgPtr(&pDev->si_drv1, (void *)0x42, NULL)) 298 return EBUSY; 299 300 /* 301 * Create a new session. 302 */ 303 rc = supdrvCreateSession(&g_VBoxDrvFreeBSDDevExt, &pSession); 304 if (RT_SUCCESS(rc)) 305 { 306 pSession->Uid = 0; 307 pSession->Gid = 0; 308 pSession->Process = RTProcSelf(); 309 pSession->R0Process = RTR0ProcHandleSelf(); 310 if (ASMAtomicCmpXchgPtr(&pDev->si_drv1, pSession, (void *)0x42)) 311 return 0; 312 313 OSDBGPRINT(("VBoxDrvFreeBSDOpen: si_drv1=%p, expected 0x42!\n", pDev->si_drv1)); 314 supdrvCloseSession(&g_VBoxDrvFreeBSDDevExt, pSession); 315 } 316 317 return RTErrConvertToErrno(rc); 318 } 319 320 321 /** 322 * Close a file device previously opened by VBoxDrvFreeBSDOpen 323 * 324 * @returns 0 on success. 325 * @param pDev The device. 326 * @param fFile The file descriptor flags. 327 * @param DevType The device type (CHR. 328 * @param pTd The calling thread. 329 */ 330 static int VBoxDrvFreeBSDClose(struct cdev *pDev, int fFile, int DevType, struct thread *pTd) 331 { 332 PSUPDRVSESSION pSession = (PSUPDRVSESSION)pDev->si_drv1; 333 dprintf(("VBoxDrvFreeBSDClose: fFile=%#x iUnit=%d pSession=%p\n", fFile, minor2unit(minor(pDev)), pSession)); 334 335 /* 336 * Close the session if it's still hanging on to the device... 337 */ 338 if (VALID_PTR(pSession)) 339 { 340 supdrvCloseSession(&g_VBoxDrvFreeBSDDevExt, pSession); 341 if (!ASMAtomicCmpXchgPtr(&pDev->si_drv1, NULL, pSession)) 342 OSDBGPRINT(("VBoxDrvFreeBSDClose: si_drv1=%p expected %p!\n", pDev->si_drv1, pSession)); 343 } 344 else 345 OSDBGPRINT(("VBoxDrvFreeBSDClose: si_drv1=%p!\n", pSession)); 346 return 0; 347 } 348 349 350 /** 351 * I/O control request. 352 * 353 * @returns depends... 354 * @param pDev The device. 355 * @param ulCmd The command. 356 * @param pvData Pointer to the data. 357 * @param fFile The file descriptor flags. 358 * @param pTd The calling thread. 359 */ 360 static int VBoxDrvFreeBSDIOCtl(struct cdev *pDev, u_long ulCmd, caddr_t pvData, int fFile, struct thread *pTd) 361 { 362 /* 363 * Validate the input. 364 */ 365 PSUPDRVSESSION pSession = (PSUPDRVSESSION)pDev->si_drv1; 366 if (RT_UNLIKELY(!VALID_PTR(pSession))) 367 return EINVAL; 368 369 /* 370 * Deal with the fast ioctl path first. 371 */ 372 if ( ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN 373 || ulCmd == SUP_IOCTL_FAST_DO_HWACC_RUN 374 || ulCmd == SUP_IOCTL_FAST_DO_NOP) 375 return supdrvIOCtlFast(ulCmd, &g_VBoxDrvFreeBSDDevExt, pSession); 376 377 return VBoxDrvFreeBSDIOCtlSlow(pSession, ulCmd, pvData, pTd); 378 } 379 380 381 /** 382 * Deal with the 'slow' I/O control requests. 383 * 384 * @returns 0 on success, appropriate errno on failure. 385 * @param pSession The session. 386 * @param ulCmd The command. 387 * @param pvData The request data. 388 * @param pTd The calling thread. 389 */ 390 static int VBoxDrvFreeBSDIOCtlSlow(PSUPDRVSESSION pSession, u_long ulCmd, caddr_t pvData, struct thread *pTd) 391 { 392 PSUPREQHDR pHdr; 393 uint32_t cbReq = IOCPARM_LEN(ulCmd); 394 void *pvUser = NULL; 395 396 /* 397 * Buffered request? 398 */ 399 if ((IOC_DIRMASK & ulCmd) == IOC_INOUT) 400 { 401 pHdr = (PSUPREQHDR)pvData; 402 if (RT_UNLIKELY(cbReq < sizeof(*pHdr))) 403 { 404 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: cbReq=%#x < %#x; ulCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), ulCmd)); 405 return EINVAL; 406 } 407 if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC)) 408 { 409 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: bad magic fFlags=%#x; ulCmd=%#lx\n", pHdr->fFlags, ulCmd)); 410 return EINVAL; 411 } 412 if (RT_UNLIKELY( RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq 413 || pHdr->cbIn < sizeof(*pHdr) 414 || pHdr->cbOut < sizeof(*pHdr))) 415 { 416 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: max(%#x,%#x) != %#x; ulCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, ulCmd)); 417 return EINVAL; 418 } 419 } 420 /* 421 * Big unbuffered request? 422 */ 423 else if ((IOC_DIRMASK & ulCmd) == IOC_VOID && !cbReq) 424 { 425 /* 426 * Read the header, validate it and figure out how much that needs to be buffered. 427 */ 428 SUPREQHDR Hdr; 429 pvUser = *(void **)pvData; 430 int rc = copyin(pvUser, &Hdr, sizeof(Hdr)); 431 if (RT_UNLIKELY(rc)) 432 { 433 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyin(%p,Hdr,) -> %#x; ulCmd=%#lx\n", pvUser, rc, ulCmd)); 434 return rc; 435 } 436 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC)) 437 { 438 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: bad magic fFlags=%#x; ulCmd=%#lx\n", Hdr.fFlags, ulCmd)); 439 return EINVAL; 440 } 441 cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut); 442 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr) 443 || Hdr.cbOut < sizeof(Hdr) 444 || cbReq > _1M*16)) 445 { 446 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: max(%#x,%#x); ulCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, ulCmd)); 447 return EINVAL; 448 } 449 450 /* 451 * Allocate buffer and copy in the data. 452 */ 453 pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq); 454 if (RT_UNLIKELY(!pHdr)) 455 { 456 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: failed to allocate buffer of %d bytes; ulCmd=%#lx\n", cbReq, ulCmd)); 457 return ENOMEM; 458 } 459 rc = copyin(pvUser, pHdr, Hdr.cbIn); 460 if (RT_UNLIKELY(rc)) 461 { 462 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyin(%p,%p,%#x) -> %#x; ulCmd=%#lx\n", 463 pvUser, pHdr, Hdr.cbIn, rc, ulCmd)); 464 RTMemTmpFree(pHdr); 465 return rc; 466 } 467 } 468 else 469 { 470 dprintf(("VBoxDrvFreeBSDIOCtlSlow: huh? cbReq=%#x ulCmd=%#lx\n", cbReq, ulCmd)); 471 return EINVAL; 472 } 473 474 /* 475 * Process the IOCtl. 476 */ 477 int rc = supdrvIOCtl(ulCmd, &g_VBoxDrvFreeBSDDevExt, pSession, pHdr); 478 if (RT_LIKELY(!rc)) 479 { 480 /* 481 * If unbuffered, copy back the result before returning. 482 */ 483 if (pvUser) 484 { 485 uint32_t cbOut = pHdr->cbOut; 486 if (cbOut > cbReq) 487 { 488 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, ulCmd)); 489 cbOut = cbReq; 490 } 491 rc = copyout(pHdr, pvUser, cbOut); 492 if (RT_UNLIKELY(rc)) 493 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyout(%p,%p,%#x) -> %d; uCmd=%#lx!\n", pHdr, pvUser, cbOut, rc, ulCmd)); 494 495 /* cleanup */ 496 RTMemTmpFree(pHdr); 497 } 498 dprintf(("VBoxDrvFreeBSDIOCtlSlow: returns %d / %d ulCmd=%lx\n", 0, pHdr->rc, ulCmd)); 499 } 500 else 501 { 502 /* 503 * The request failed, just clean up. 504 */ 505 if (pvUser) 506 RTMemTmpFree(pHdr); 507 508 dprintf(("VBoxDrvFreeBSDIOCtlSlow: ulCmd=%lx pData=%p failed, rc=%d\n", ulCmd, pvData, rc)); 509 rc = EINVAL; 510 } 511 512 return rc; 513 } 514 279 515 280 516 -
trunk/src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp
r4925 r4988 43 43 * Defined Constants And Macros * 44 44 *******************************************************************************/ 45 /** BSD Device name. */45 /** FreeBSD base device name. */ 46 46 #define DEVICE_NAME "/dev/vboxdrv" 47 47 … … 65 65 * Try open the BSD device. 66 66 */ 67 g_hDevice = open(DEVICE_NAME, O_RDWR, 0); 67 char szDevice[sizeof(DEVICE_NAME) + 16]; 68 for (unsigned iUnit = 0; iUnit < 1024; iUnit++) 69 { 70 errno = 0; 71 RTStrPrintf(szDevice, sizeof(szDevice), DEVICE_NAME "%d", iUnit); 72 g_hDevice = open(szDevice, O_RDWR, 0); 73 if (g_hDevice >= 0 || errno != EBUSY) 74 break; 75 } 68 76 if (g_hDevice < 0) 69 77 { … … 77 85 default: rc = VERR_VM_DRIVER_OPEN_ERROR; break; 78 86 } 79 LogRel(("Failed to open \"%s\", errno=%d, rc=%Vrc\n", DEVICE_NAME, errno, rc));80 return RTErrConvertFromErrno(rc);87 LogRel(("Failed to open \"%s\", errno=%d, rc=%Vrc\n", szDevice, errno, rc)); 88 return rc; 81 89 } 82 90
Note:
See TracChangeset
for help on using the changeset viewer.