1 /* VirtualBox driver - by D.C. van Moolenbroek */
3 * This driver currently performs two tasks:
4 * - synchronizing to the host system time;
5 * - providing an interface for HGCM communication with the host system.
7 #include <minix/sysutil.h>
8 #include <minix/drivers.h>
9 #include <minix/driver.h>
10 #include <minix/optset.h>
11 #include <machine/pci.h>
17 #define DEFAULT_INTERVAL 1 /* check host time every second */
18 #define DEFAULT_DRIFT 2 /* update time if delta is >= 2 secs */
21 static phys_bytes phys_ptr
;
27 static unsigned int irq
;
30 static struct optset optset_table
[] = {
31 { "interval", OPT_INT
, &interval
, 10 },
32 { "drift", OPT_INT
, &drift
, 10 },
36 /*===========================================================================*
38 *===========================================================================*/
39 int vbox_request(struct VMMDevRequestHeader
*header
, phys_bytes addr
,
40 int type
, size_t size
)
42 /* Perform a VirtualBox backdoor request. */
46 header
->version
= VMMDEV_BACKDOOR_VERSION
;
48 header
->result
= VMMDEV_ERR_GENERIC
;
50 if ((r
= sys_outl(port
, addr
)) != OK
)
51 panic("device I/O failed: %d", r
);
53 return header
->result
;
56 /*===========================================================================*
58 *===========================================================================*/
59 static int vbox_init(int UNUSED(type
), sef_init_info_t
*UNUSED(info
))
61 /* Initialize the device. */
64 struct VMMDevReportGuestInfo
*req
;
67 interval
= DEFAULT_INTERVAL
;
68 drift
= DEFAULT_DRIFT
;
71 optset_parse(optset_table
, env_argv
[1]);
75 r
= pci_first_dev(&devind
, &vid
, &did
);
79 panic("backdoor device not found");
81 if (vid
== VMMDEV_PCI_VID
&& did
== VMMDEV_PCI_DID
)
84 r
= pci_next_dev(&devind
, &vid
, &did
);
89 port
= pci_attr_r32(devind
, PCI_BAR
) & PCI_BAR_IO_MASK
;
91 irq
= pci_attr_r8(devind
, PCI_ILR
);
94 if ((r
= sys_irqsetpolicy(irq
, 0 /* IRQ_REENABLE */, &hook_id
)) != OK
)
95 panic("unable to register IRQ: %d", r
);
97 if ((r
= sys_irqenable(&hook_id
)) != OK
)
98 panic("unable to enable IRQ: %d", r
);
100 if ((vir_ptr
= alloc_contig(VMMDEV_BUF_SIZE
, 0, &phys_ptr
)) == NULL
)
101 panic("unable to allocate memory");
103 req
= (struct VMMDevReportGuestInfo
*) vir_ptr
;
104 req
->add_version
= VMMDEV_GUEST_VERSION
;
105 req
->os_type
= VMMDEV_GUEST_OS_OTHER
;
107 if ((r
= vbox_request(&req
->header
, phys_ptr
,
108 VMMDEV_REQ_REPORTGUESTINFO
, sizeof(*req
))) !=
110 panic("backdoor device not functioning");
112 ticks
= sys_hz() * interval
;
114 sys_setalarm(ticks
, 0);
119 /*===========================================================================*
121 *===========================================================================*/
122 static void vbox_intr(void)
124 /* Process an interrupt. */
125 struct VMMDevEvents
*req
;
128 req
= (struct VMMDevEvents
*) vir_ptr
;
131 /* If we cannot retrieve the events mask, we cannot do anything with
132 * this or any future interrupt either, so return without reenabling
135 if ((r
= vbox_request(&req
->header
, phys_ptr
,
136 VMMDEV_REQ_ACKNOWLEDGEEVENTS
, sizeof(*req
))) !=
138 printf("VBOX: unable to retrieve event mask (%d)\n", r
);
143 if (req
->events
& VMMDEV_EVENT_HGCM
)
146 if ((r
= sys_irqenable(&hook_id
)) != OK
)
147 panic("unable to reenable IRQ: %d", r
);
150 /*===========================================================================*
152 *===========================================================================*/
153 static void vbox_update_time(void)
155 /* Update the current time if it has drifted too far. */
156 struct VMMDevReqHostTime
*req
;
159 req
= (struct VMMDevReqHostTime
*) vir_ptr
;
161 if (vbox_request(&req
->header
, phys_ptr
, VMMDEV_REQ_HOSTTIME
,
162 sizeof(*req
)) == VMMDEV_ERR_OK
) {
163 time(&otime
); /* old time */
165 ntime
= req
->time
/ 1000; /* new time */
167 /* Make time go forward, if the difference exceeds the drift
168 * threshold. Never make time go backward.
170 if ((ntime
- otime
) >= drift
)
174 sys_setalarm(ticks
, 0);
177 /*===========================================================================*
179 *===========================================================================*/
180 static void vbox_signal(int signo
)
182 /* Process a signal. If it is a SIGTERM, terminate immediately. */
184 if (signo
!= SIGTERM
) return;
189 /*===========================================================================*
190 * sef_local_startup *
191 *===========================================================================*/
192 static void sef_local_startup(void)
194 /* Perform local SEF initialization. */
196 sef_setcb_init_fresh(vbox_init
);
197 sef_setcb_init_restart(vbox_init
);
199 sef_setcb_signal_handler(vbox_signal
);
204 /*===========================================================================*
206 *===========================================================================*/
207 int main(int argc
, char **argv
)
209 /* The main message loop. */
213 env_setargs(argc
, argv
);
217 if ((r
= driver_receive(ANY
, &m
, &ipc_status
)) != OK
)
218 panic("driver_receive failed: %d", r
);
220 if (is_ipc_notify(ipc_status
)) {
221 switch (m
.m_source
) {
233 printf("VBOX: received notify from %d\n",
240 hgcm_message(&m
, ipc_status
);