VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest-netbsd.c@ 63455

Last change on this file since 63455 was 63455, checked in by vboxsync, 8 years ago

VBoxGuest-netbsd.c: fix indentation and brace placement.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.7 KB
Line 
1/* $Id: VBoxGuest-netbsd.c 63455 2016-08-15 00:54:45Z vboxsync $ */
2/** @file
3 * VirtualBox Guest Additions Driver for NetBSD.
4 */
5
6/*
7 * Copyright (C) 2007-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/** @todo r=bird: This must merge with SUPDrv-netbsd.c before long. The two
19 * source files should only differ on prefixes and the extra bits wrt to the
20 * pci device. I.e. it should be diffable so that fixes to one can easily be
21 * applied to the other. */
22
23
24/*********************************************************************************************************************************
25* Header Files *
26*********************************************************************************************************************************/
27#include <sys/param.h>
28#include <sys/systm.h>
29#include <sys/select.h>
30#include <sys/conf.h>
31#include <sys/kernel.h>
32#include <sys/kmem.h>
33#include <sys/module.h>
34#include <sys/device.h>
35#include <sys/bus.h>
36#include <sys/poll.h>
37#include <sys/proc.h>
38#include <sys/stat.h>
39#include <sys/selinfo.h>
40#include <sys/queue.h>
41#include <sys/lock.h>
42#include <sys/types.h>
43#include <sys/conf.h>
44#include <sys/malloc.h>
45#include <sys/uio.h>
46#include <sys/file.h>
47#include <sys/filedesc.h>
48#include <sys/vfs_syscalls.h>
49#include <dev/pci/pcivar.h>
50#include <dev/pci/pcireg.h>
51#include <dev/pci/pcidevs.h>
52
53#ifdef PVM
54# undef PVM
55#endif
56#include "VBoxGuestInternal.h"
57#include <VBox/log.h>
58#include <iprt/assert.h>
59#include <iprt/initterm.h>
60#include <iprt/process.h>
61#include <iprt/mem.h>
62#include <iprt/asm.h>
63
64
65/*********************************************************************************************************************************
66* Defined Constants And Macros *
67*********************************************************************************************************************************/
68/** The module name. */
69#define DEVICE_NAME "vboxguest"
70
71
72/*********************************************************************************************************************************
73* Structures and Typedefs *
74*********************************************************************************************************************************/
75typedef struct VBoxGuestDeviceState
76{
77 device_t sc_dev;
78 pci_chipset_tag_t pc;
79 bus_space_tag_t io_tag;
80 bus_space_handle_t io_handle;
81 bus_addr_t uIOPortBase;
82 bus_size_t io_regsize;
83 bus_space_tag_t iVMMDevMemResId;
84 bus_space_handle_t VMMDevMemHandle;
85
86 /** Size of the memory area. */
87 bus_size_t VMMDevMemSize;
88 /** Mapping of the register space */
89 bus_addr_t pMMIOBase;
90
91 /** IRQ resource handle. */
92 pci_intr_handle_t ih;
93 /** Pointer to the IRQ handler. */
94 void *pfnIrqHandler;
95
96 /** Controller features, limits and status. */
97 u_int vboxguest_state;
98} vboxguest_softc;
99
100
101struct vboxguest_session
102{
103 vboxguest_softc *sc;
104 PVBOXGUESTSESSION session;
105};
106
107#define VBOXGUEST_STATE_INITOK 1 << 0
108
109/*********************************************************************************************************************************
110* Internal Functions *
111*********************************************************************************************************************************/
112/*
113 * Character device file handlers.
114 */
115static int VBoxGuestNetBSDOpen(dev_t device, int flags, int fmt, struct lwp *process);
116static int VBoxGuestNetBSDClose(struct file *fp);
117static int VBoxGuestNetBSDIOCtl(struct file *fp, u_long cmd, void *addr);
118static int VBoxGuestNetBSDPoll(struct file *fp, int events);
119static void VBoxGuestNetBSDAttach(device_t, device_t, void*);
120static int VBoxGuestNetBSDDetach(device_t pDevice, int flags);
121
122/*
123 * IRQ related functions.
124 */
125static void VBoxGuestNetBSDRemoveIRQ(vboxguest_softc *sc);
126static int VBoxGuestNetBSDAddIRQ(vboxguest_softc *pvState, struct pci_attach_args *pa);
127static int VBoxGuestNetBSDISR(void *pvState);
128
129
130/*********************************************************************************************************************************
131* Global Variables *
132*********************************************************************************************************************************/
133/*
134 * The /dev/vboxguest character device entry points.
135 */
136static struct cdevsw g_VBoxGuestNetBSDChrDevSW =
137{
138 VBoxGuestNetBSDOpen,
139 noclose,
140 noread,
141 nowrite,
142 noioctl,
143 nostop,
144 notty,
145 nopoll,
146 nommap,
147 nokqfilter,
148};
149
150static const struct fileops vboxguest_fileops = {
151 .fo_read = fbadop_read,
152 .fo_write = fbadop_write,
153 .fo_ioctl = VBoxGuestNetBSDIOCtl,
154 .fo_fcntl = fnullop_fcntl,
155 .fo_poll = VBoxGuestNetBSDPoll,
156 .fo_stat = fbadop_stat,
157 .fo_close = VBoxGuestNetBSDClose,
158 .fo_kqfilter = fnullop_kqfilter,
159 .fo_restart = fnullop_restart
160};
161
162/** Device extention & session data association structure. */
163static VBOXGUESTDEVEXT g_DevExt;
164/** Reference counter */
165static volatile uint32_t cUsers;
166/** selinfo structure used for polling. */
167static struct selinfo g_SelInfo;
168
169CFDRIVER_DECL(vboxguest, DV_DULL, NULL);
170extern struct cfdriver vboxguest_cd;
171
172/**
173 * File open handler
174 *
175 */
176static int VBoxGuestNetBSDOpen(dev_t device, int flags, int fmt, struct lwp *process)
177{
178 int rc;
179 vboxguest_softc *vboxguest;
180 struct vboxguest_session *session;
181 file_t *fp;
182 int fd, error;
183
184 LogFlow((DEVICE_NAME ": %s\n", __func__));
185
186 if ((vboxguest = device_lookup_private(&vboxguest_cd, minor(device))) == NULL)
187 {
188 printf("device_lookup_private failed\n");
189 return (ENXIO);
190 }
191
192 if ((vboxguest->vboxguest_state & VBOXGUEST_STATE_INITOK) == 0)
193 {
194 aprint_error_dev(vboxguest->sc_dev, "device not configured\n");
195 return (ENXIO);
196 }
197
198 session = kmem_alloc(sizeof(*session), KM_SLEEP);
199 if (session == NULL)
200 {
201 return (ENOMEM);
202 }
203
204 session->sc = vboxguest;
205
206 if ((error = fd_allocfile(&fp, &fd)) != 0)
207 {
208 kmem_free(session, sizeof(*session));
209 return error;
210 }
211
212 /*
213 * Create a new session.
214 */
215 rc = VGDrvCommonCreateUserSession(&g_DevExt, &session->session);
216 if (! RT_SUCCESS(rc))
217 {
218 aprint_error_dev(vboxguest->sc_dev, "VBox session creation failed\n");
219 closef(fp); /* ??? */
220 kmem_free(session, sizeof(*session));
221 return RTErrConvertToErrno(rc);
222 }
223 ASMAtomicIncU32(&cUsers);
224 return fd_clone(fp, fd, flags, &vboxguest_fileops, session);
225
226}
227
228/**
229 * File close handler
230 *
231 */
232static int VBoxGuestNetBSDClose(struct file *fp)
233{
234 struct vboxguest_session *session = fp->f_data;
235 vboxguest_softc *vboxguest = session->sc;
236
237 LogFlow((DEVICE_NAME ": %s\n", __func__));
238
239 VGDrvCommonCloseSession(&g_DevExt, session->session);
240 ASMAtomicDecU32(&cUsers);
241
242 kmem_free(session, sizeof(*session));
243
244 return 0;
245}
246
247/**
248 * IOCTL handler
249 *
250 */
251static int VBoxGuestNetBSDIOCtl(struct file *fp, u_long command, void *data)
252{
253 struct vboxguest_session *session = fp->f_data;
254 vboxguest_softc *vboxguest = session->sc;
255
256 int rc = 0;
257
258 LogFlow((DEVICE_NAME ": %s: command=%#lx data=%p\n",
259 __func__, command, data));
260
261 /*
262 * Validate the request wrapper.
263 */
264 if (IOCPARM_LEN(command) != sizeof(VBGLBIGREQ))
265 {
266 Log((DEVICE_NAME ": %s: bad request %#lx size=%lu expected=%zu\n",
267 __func__, command, IOCPARM_LEN(command), sizeof(VBGLBIGREQ)));
268 return ENOTTY;
269 }
270
271 PVBGLBIGREQ ReqWrap = (PVBGLBIGREQ)data;
272 if (ReqWrap->u32Magic != VBGLBIGREQ_MAGIC)
273 {
274 Log((DEVICE_NAME ": %s: bad magic %#" PRIx32 "; pArg=%p Cmd=%#lx\n",
275 __func__, ReqWrap->u32Magic, data, command));
276 return EINVAL;
277 }
278 if (RT_UNLIKELY( ReqWrap->cbData == 0
279 || ReqWrap->cbData > _1M*16))
280 {
281 Log((DEVICE_NAME ": %s: bad size %" PRIu32 "; pArg=%p Cmd=%#lx\n",
282 __func__, ReqWrap->cbData, data, command));
283 return EINVAL;
284 }
285
286 /*
287 * Read the request.
288 */
289 void *pvBuf = RTMemTmpAlloc(ReqWrap->cbData);
290 if (RT_UNLIKELY(!pvBuf))
291 {
292 Log((DEVICE_NAME ": %s: RTMemTmpAlloc failed to alloc %" PRIu32 " bytes.\n",
293 __func__, ReqWrap->cbData));
294 return ENOMEM;
295 }
296
297 rc = copyin((void *)(uintptr_t)ReqWrap->pvDataR3, pvBuf, ReqWrap->cbData);
298 if (RT_UNLIKELY(rc))
299 {
300 RTMemTmpFree(pvBuf);
301 Log((DEVICE_NAME ": %s: copyin failed; pvBuf=%p pArg=%p Cmd=%#lx. rc=%d\n",
302 __func__, pvBuf, data, command, rc));
303 aprint_error_dev(vboxguest->sc_dev, "copyin failed\n");
304 return EFAULT;
305 }
306 if (RT_UNLIKELY( ReqWrap->cbData != 0
307 && !VALID_PTR(pvBuf)))
308 {
309 RTMemTmpFree(pvBuf);
310 Log((DEVICE_NAME ": %s: invalid pvBuf=%p\n",
311 __func__, pvBuf));
312 return EINVAL;
313 }
314
315 /*
316 * Process the IOCtl.
317 */
318 size_t cbDataReturned;
319 rc = VGDrvCommonIoCtl(command, &g_DevExt, session->session, pvBuf, ReqWrap->cbData, &cbDataReturned);
320 if (RT_SUCCESS(rc))
321 {
322 rc = 0;
323 if (RT_UNLIKELY(cbDataReturned > ReqWrap->cbData))
324 {
325 Log((DEVICE_NAME ": %s: too much output data %zu expected %" PRIu32 "\n",
326 __func__, cbDataReturned, ReqWrap->cbData));
327 cbDataReturned = ReqWrap->cbData;
328 }
329 if (cbDataReturned > 0)
330 {
331 rc = copyout(pvBuf, (void *)(uintptr_t)ReqWrap->pvDataR3, cbDataReturned);
332 if (RT_UNLIKELY(rc))
333 {
334 Log((DEVICE_NAME ": %s: copyout failed; pvBuf=%p pArg=%p. rc=%d\n",
335 __func__, pvBuf, data, rc));
336 }
337 }
338 } else {
339 Log((DEVICE_NAME ": %s: VGDrvCommonIoCtl failed. rc=%d\n",
340 __func__, rc));
341 rc = -rc;
342 }
343 RTMemTmpFree(pvBuf);
344 return rc;
345}
346
347static int VBoxGuestNetBSDPoll(struct file *fp, int events)
348{
349 struct vboxguest_session *session = fp->f_data;
350 vboxguest_softc *vboxguest = session->sc;
351
352 int rc = 0;
353 int events_processed;
354
355 uint32_t u32CurSeq;
356
357 LogFlow((DEVICE_NAME ": %s\n", __func__));
358
359 u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
360 if (session->session->u32MousePosChangedSeq != u32CurSeq)
361 {
362 events_processed = events & (POLLIN | POLLRDNORM);
363 session->session->u32MousePosChangedSeq = u32CurSeq;
364 }
365 else
366 {
367 events_processed = 0;
368
369 selrecord(curlwp, &g_SelInfo);
370 }
371
372 return events_processed;
373}
374
375static int VBoxGuestNetBSDDetach(device_t self, int flags)
376{
377 vboxguest_softc *vboxguest;
378 vboxguest = device_private(self);
379
380 LogFlow((DEVICE_NAME ": %s\n", __func__));
381
382 if (cUsers > 0)
383 return EBUSY;
384
385 if ((vboxguest->vboxguest_state & VBOXGUEST_STATE_INITOK) == 0)
386 return 0;
387
388 /*
389 * Reverse what we did in VBoxGuestNetBSDAttach.
390 */
391
392 VBoxGuestNetBSDRemoveIRQ(vboxguest);
393
394 VGDrvCommonDeleteDevExt(&g_DevExt);
395
396 bus_space_unmap(vboxguest->iVMMDevMemResId, vboxguest->VMMDevMemHandle, vboxguest->VMMDevMemSize);
397 bus_space_unmap(vboxguest->io_tag, vboxguest->io_handle, vboxguest->io_regsize);
398
399 RTR0Term();
400
401 return 0;
402}
403
404/**
405 * Interrupt service routine.
406 *
407 * @returns Whether the interrupt was from VMMDev.
408 * @param pvState Opaque pointer to the device state.
409 */
410static int VBoxGuestNetBSDISR(void *pvState)
411{
412 LogFlow((DEVICE_NAME ": %s: pvState=%p\n", __func__, pvState));
413
414 bool fOurIRQ = VGDrvCommonISR(&g_DevExt);
415
416 return fOurIRQ ? 0 : 1;
417}
418
419void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
420{
421 LogFlow((DEVICE_NAME ": %s\n", __func__));
422
423 /*
424 * Wake up poll waiters.
425 */
426 selnotify(&g_SelInfo, 0, 0);
427}
428
429/**
430 * Sets IRQ for VMMDev.
431 *
432 * @returns NetBSD error code.
433 * @param vboxguest Pointer to the state info structure.
434 * @param pa Pointer to the PCI attach arguments.
435 */
436static int VBoxGuestNetBSDAddIRQ(vboxguest_softc *vboxguest, struct pci_attach_args *pa)
437{
438 int iResId = 0;
439 int rc = 0;
440 const char *intrstr;
441#if __NetBSD_Prereq__(6, 99, 39)
442 char intstrbuf[100];
443#endif
444
445 LogFlow((DEVICE_NAME ": %s\n", __func__));
446
447 if (pci_intr_map(pa, &vboxguest->ih))
448 {
449 aprint_error_dev(vboxguest->sc_dev, "couldn't map interrupt.\n");
450 return VERR_DEV_IO_ERROR;
451 }
452
453 intrstr = pci_intr_string(vboxguest->pc, vboxguest->ih
454#if __NetBSD_Prereq__(6, 99, 39)
455 , intstrbuf, sizeof(intstrbuf)
456#endif
457 );
458 aprint_normal_dev(vboxguest->sc_dev, "interrupting at %s\n", intrstr);
459
460 vboxguest->pfnIrqHandler = pci_intr_establish(vboxguest->pc, vboxguest->ih, IPL_BIO, VBoxGuestNetBSDISR, vboxguest);
461 if (vboxguest->pfnIrqHandler == NULL)
462 {
463 aprint_error_dev(vboxguest->sc_dev, "couldn't establish interrupt\n");
464 return VERR_DEV_IO_ERROR;
465 }
466
467 return VINF_SUCCESS;
468}
469
470/**
471 * Removes IRQ for VMMDev.
472 *
473 * @param vboxguest Opaque pointer to the state info structure.
474 */
475static void VBoxGuestNetBSDRemoveIRQ(vboxguest_softc *vboxguest)
476{
477 LogFlow((DEVICE_NAME ": %s\n", __func__));
478
479 if (vboxguest->pfnIrqHandler)
480 {
481 pci_intr_disestablish(vboxguest->pc, vboxguest->pfnIrqHandler);
482 }
483}
484
485static void VBoxGuestNetBSDAttach(device_t parent, device_t self, void *aux)
486{
487 int rc = VINF_SUCCESS;
488 int iResId = 0;
489 vboxguest_softc *vboxguest;
490 struct pci_attach_args *pa = aux;
491 bus_space_tag_t iot, memt;
492 bus_space_handle_t ioh, memh;
493 bus_dma_segment_t seg;
494 int ioh_valid, memh_valid;
495
496 cUsers = 0;
497
498 aprint_normal(": VirtualBox Guest\n");
499
500 vboxguest = device_private(self);
501 vboxguest->sc_dev = self;
502
503 /*
504 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
505 */
506 rc = RTR0Init(0);
507 if (RT_FAILURE(rc))
508 {
509 LogFunc(("RTR0Init failed.\n"));
510 aprint_error_dev(vboxguest->sc_dev, "RTR0Init failed\n");
511 return;
512 }
513
514 vboxguest->pc = pa->pa_pc;
515
516 /*
517 * Allocate I/O port resource.
518 */
519 ioh_valid = (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0, &vboxguest->io_tag, &vboxguest->io_handle, &vboxguest->uIOPortBase, &vboxguest->io_regsize) == 0);
520
521 if (ioh_valid)
522 {
523
524 /*
525 * Map the MMIO region.
526 */
527 memh_valid = (pci_mapreg_map(pa, PCI_MAPREG_START+4, PCI_MAPREG_TYPE_MEM, BUS_SPACE_MAP_LINEAR, &vboxguest->iVMMDevMemResId, &vboxguest->VMMDevMemHandle, &vboxguest->pMMIOBase, &vboxguest->VMMDevMemSize) == 0);
528 if (memh_valid)
529 {
530 /*
531 * Call the common device extension initializer.
532 */
533 rc = VGDrvCommonInitDevExt(&g_DevExt, vboxguest->uIOPortBase,
534 bus_space_vaddr(vboxguest->iVMMDevMemResId,
535 vboxguest->VMMDevMemHandle),
536 vboxguest->VMMDevMemSize,
537#if ARCH_BITS == 64
538 VBOXOSTYPE_NetBSD_x64,
539#else
540 VBOXOSTYPE_NetBSD,
541#endif
542 VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
543 if (RT_SUCCESS(rc))
544 {
545 /*
546 * Add IRQ of VMMDev.
547 */
548 rc = VBoxGuestNetBSDAddIRQ(vboxguest, pa);
549 if (RT_SUCCESS(rc))
550 {
551 vboxguest->vboxguest_state |= VBOXGUEST_STATE_INITOK;
552 return;
553 }
554 VGDrvCommonDeleteDevExt(&g_DevExt);
555 }
556 else
557 {
558 aprint_error_dev(vboxguest->sc_dev, "init failed\n");
559 }
560 bus_space_unmap(vboxguest->iVMMDevMemResId, vboxguest->VMMDevMemHandle, vboxguest->VMMDevMemSize);
561 }
562 else
563 {
564 aprint_error_dev(vboxguest->sc_dev, "MMIO mapping failed\n");
565 }
566 bus_space_unmap(vboxguest->io_tag, vboxguest->io_handle, vboxguest->io_regsize);
567 }
568 else
569 {
570 aprint_error_dev(vboxguest->sc_dev, "IO mapping failed\n");
571 }
572
573 RTR0Term();
574 return;
575}
576
577static int
578VBoxGuestNetBSDMatch(device_t parent, cfdata_t match, void *aux)
579{
580 const struct pci_attach_args *pa = aux;
581
582 if ( PCI_VENDOR(pa->pa_id) == VMMDEV_VENDORID
583 && PCI_PRODUCT(pa->pa_id) == VMMDEV_DEVICEID)
584 {
585 return 1;
586 }
587
588 return 0;
589}
590
591/* Common code that depend on g_DevExt. */
592#include "VBoxGuestIDC-unix.c.h"
593
594CFATTACH_DECL_NEW(vboxguest, sizeof(vboxguest_softc),
595 VBoxGuestNetBSDMatch, VBoxGuestNetBSDAttach, VBoxGuestNetBSDDetach, NULL);
596
597MODULE(MODULE_CLASS_DRIVER, vboxguest, "pci");
598
599static int loc[2] = {-1, -1};
600
601static const struct cfparent pspec = {
602 "pci", "pci", DVUNIT_ANY
603};
604
605static struct cfdata vboxguest_cfdata[] = {
606 {
607 .cf_name = "vboxguest",
608 .cf_atname = "vboxguest",
609 .cf_unit = 0, /* Only unit 0 is ever used */
610 .cf_fstate = FSTATE_STAR,
611 .cf_loc = loc,
612 .cf_flags = 0,
613 .cf_pspec = &pspec,
614 },
615 { NULL, NULL, 0, 0, NULL, 0, NULL }
616};
617
618static int
619vboxguest_modcmd(modcmd_t cmd, void *opaque)
620{
621 devmajor_t bmajor, cmajor;
622 int error;
623 register_t retval;
624
625 LogFlow((DEVICE_NAME ": %s\n", __func__));
626
627 bmajor = cmajor = NODEVMAJOR;
628 switch (cmd)
629 {
630 case MODULE_CMD_INIT:
631 error = config_cfdriver_attach(&vboxguest_cd);
632 if (error)
633 {
634 printf("config_cfdriver_attach failed: %d", error);
635 break;
636 }
637 error = config_cfattach_attach(vboxguest_cd.cd_name, &vboxguest_ca);
638 if (error)
639 {
640 config_cfdriver_detach(&vboxguest_cd);
641 printf("%s: unable to register cfattach\n", vboxguest_cd.cd_name);
642 break;
643 }
644 error = config_cfdata_attach(vboxguest_cfdata, 1);
645 if (error)
646 {
647 printf("%s: unable to attach cfdata\n", vboxguest_cd.cd_name);
648 config_cfattach_detach(vboxguest_cd.cd_name, &vboxguest_ca);
649 config_cfdriver_detach(&vboxguest_cd);
650 break;
651 }
652
653 error = devsw_attach("vboxguest", NULL, &bmajor, &g_VBoxGuestNetBSDChrDevSW, &cmajor);
654
655 if (error == EEXIST)
656 error = 0; /* maybe built-in ... improve eventually */
657
658 if (error)
659 break;
660
661 error = do_sys_mknod(curlwp, "/dev/vboxguest", 0666|S_IFCHR, makedev(cmajor, 0), &retval, UIO_SYSSPACE);
662 if (error == EEXIST)
663 error = 0;
664 break;
665
666 case MODULE_CMD_FINI:
667 error = config_cfdata_detach(vboxguest_cfdata);
668 if (error)
669 break;
670 error = config_cfattach_detach(vboxguest_cd.cd_name, &vboxguest_ca);
671 if (error)
672 break;
673 config_cfdriver_detach(&vboxguest_cd);
674 error = devsw_detach(NULL, &g_VBoxGuestNetBSDChrDevSW);
675 break;
676
677 default:
678 return ENOTTY;
679 }
680 return error;
681}
Note: See TracBrowser for help on using the repository browser.

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