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/drivers.h>
8 #include <minix/driver.h>
9 #include <minix/optset.h>
10 #include <machine/pci.h>
16 #define DEFAULT_INTERVAL 1 /* check host time every second */
17 #define DEFAULT_DRIFT 2 /* update time if delta is >= 2 secs */
20 static phys_bytes phys_ptr
;
26 static unsigned int irq
;
29 static struct optset optset_table
[] = {
30 { "interval", OPT_INT
, &interval
, 10 },
31 { "drift", OPT_INT
, &drift
, 10 },
35 /*===========================================================================*
37 *===========================================================================*/
38 int vbox_request(struct VMMDevRequestHeader
*header
, phys_bytes addr
,
39 int type
, size_t size
)
41 /* Perform a VirtualBox backdoor request. */
45 header
->version
= VMMDEV_BACKDOOR_VERSION
;
47 header
->result
= VMMDEV_ERR_GENERIC
;
49 if ((r
= sys_outl(port
, addr
)) != OK
)
50 panic("device I/O failed: %d", r
);
52 return header
->result
;
55 /*===========================================================================*
57 *===========================================================================*/
58 static int vbox_init(int UNUSED(type
), sef_init_info_t
*UNUSED(info
))
60 /* Initialize the device. */
63 struct VMMDevReportGuestInfo
*req
;
66 interval
= DEFAULT_INTERVAL
;
67 drift
= DEFAULT_DRIFT
;
70 optset_parse(optset_table
, env_argv
[1]);
74 r
= pci_first_dev(&devind
, &vid
, &did
);
78 panic("backdoor device not found");
80 if (vid
== VMMDEV_PCI_VID
&& did
== VMMDEV_PCI_DID
)
83 r
= pci_next_dev(&devind
, &vid
, &did
);
88 port
= pci_attr_r32(devind
, PCI_BAR
) & PCI_BAR_IO_MASK
;
90 irq
= pci_attr_r8(devind
, PCI_ILR
);
92 if ((r
= sys_irqsetpolicy(irq
, 0 /* IRQ_REENABLE */, &hook_id
)) != OK
)
93 panic("unable to register IRQ: %d", r
);
95 if ((r
= sys_irqenable(&hook_id
)) != OK
)
96 panic("unable to enable IRQ: %d", r
);
98 if ((vir_ptr
= alloc_contig(VMMDEV_BUF_SIZE
, 0, &phys_ptr
)) == NULL
)
99 panic("unable to allocate memory");
101 req
= (struct VMMDevReportGuestInfo
*) vir_ptr
;
102 req
->add_version
= VMMDEV_GUEST_VERSION
;
103 req
->os_type
= VMMDEV_GUEST_OS_OTHER
;
105 if ((r
= vbox_request(&req
->header
, phys_ptr
,
106 VMMDEV_REQ_REPORTGUESTINFO
, sizeof(*req
))) !=
108 panic("backdoor device not functioning");
110 ticks
= sys_hz() * interval
;
112 sys_setalarm(ticks
, 0);
117 /*===========================================================================*
119 *===========================================================================*/
120 static void vbox_intr(void)
122 /* Process an interrupt. */
123 struct VMMDevEvents
*req
;
126 req
= (struct VMMDevEvents
*) vir_ptr
;
129 /* If we cannot retrieve the events mask, we cannot do anything with
130 * this or any future interrupt either, so return without reenabling
133 if ((r
= vbox_request(&req
->header
, phys_ptr
,
134 VMMDEV_REQ_ACKNOWLEDGEEVENTS
, sizeof(*req
))) !=
136 printf("VBOX: unable to retrieve event mask (%d)\n", r
);
141 if (req
->events
& VMMDEV_EVENT_HGCM
)
144 if ((r
= sys_irqenable(&hook_id
)) != OK
)
145 panic("unable to reenable IRQ: %d", r
);
148 /*===========================================================================*
150 *===========================================================================*/
151 static void vbox_update_time(void)
153 /* Update the current time if it has drifted too far. */
154 struct VMMDevReqHostTime
*req
;
157 req
= (struct VMMDevReqHostTime
*) vir_ptr
;
159 if (vbox_request(&req
->header
, phys_ptr
, VMMDEV_REQ_HOSTTIME
,
160 sizeof(*req
)) == VMMDEV_ERR_OK
) {
161 time(&otime
); /* old time */
163 ntime
= div64u(req
->time
, 1000); /* new time */
165 /* Make time go forward, if the difference exceeds the drift
166 * threshold. Never make time go backward.
168 if ((int) (ntime
- otime
) >= drift
)
172 sys_setalarm(ticks
, 0);
175 /*===========================================================================*
177 *===========================================================================*/
178 static void vbox_signal(int signo
)
180 /* Process a signal. If it is a SIGTERM, terminate immediately. */
182 if (signo
!= SIGTERM
) return;
187 /*===========================================================================*
188 * sef_local_startup *
189 *===========================================================================*/
190 static void sef_local_startup(void)
192 /* Perform local SEF initialization. */
194 sef_setcb_init_fresh(vbox_init
);
195 sef_setcb_init_restart(vbox_init
);
197 sef_setcb_signal_handler(vbox_signal
);
202 /*===========================================================================*
204 *===========================================================================*/
205 int main(int argc
, char **argv
)
207 /* The main message loop. */
211 env_setargs(argc
, argv
);
215 if ((r
= driver_receive(ANY
, &m
, &ipc_status
)) != OK
)
216 panic("driver_receive failed: %d", r
);
218 if (is_ipc_notify(ipc_status
)) {
219 switch (m
.m_source
) {
231 printf("VBOX: received notify from %d\n",
238 hgcm_message(&m
, ipc_status
);