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
);
93 if ((r
= sys_irqsetpolicy(irq
, 0 /* IRQ_REENABLE */, &hook_id
)) != OK
)
94 panic("unable to register IRQ: %d", r
);
96 if ((r
= sys_irqenable(&hook_id
)) != OK
)
97 panic("unable to enable IRQ: %d", r
);
99 if ((vir_ptr
= alloc_contig(VMMDEV_BUF_SIZE
, 0, &phys_ptr
)) == NULL
)
100 panic("unable to allocate memory");
102 req
= (struct VMMDevReportGuestInfo
*) vir_ptr
;
103 req
->add_version
= VMMDEV_GUEST_VERSION
;
104 req
->os_type
= VMMDEV_GUEST_OS_OTHER
;
106 if ((r
= vbox_request(&req
->header
, phys_ptr
,
107 VMMDEV_REQ_REPORTGUESTINFO
, sizeof(*req
))) !=
109 panic("backdoor device not functioning");
111 ticks
= sys_hz() * interval
;
113 sys_setalarm(ticks
, 0);
118 /*===========================================================================*
120 *===========================================================================*/
121 static void vbox_intr(void)
123 /* Process an interrupt. */
124 struct VMMDevEvents
*req
;
127 req
= (struct VMMDevEvents
*) vir_ptr
;
130 /* If we cannot retrieve the events mask, we cannot do anything with
131 * this or any future interrupt either, so return without reenabling
134 if ((r
= vbox_request(&req
->header
, phys_ptr
,
135 VMMDEV_REQ_ACKNOWLEDGEEVENTS
, sizeof(*req
))) !=
137 printf("VBOX: unable to retrieve event mask (%d)\n", r
);
142 if (req
->events
& VMMDEV_EVENT_HGCM
)
145 if ((r
= sys_irqenable(&hook_id
)) != OK
)
146 panic("unable to reenable IRQ: %d", r
);
149 /*===========================================================================*
151 *===========================================================================*/
152 static void vbox_update_time(void)
154 /* Update the current time if it has drifted too far. */
155 struct VMMDevReqHostTime
*req
;
158 req
= (struct VMMDevReqHostTime
*) vir_ptr
;
160 if (vbox_request(&req
->header
, phys_ptr
, VMMDEV_REQ_HOSTTIME
,
161 sizeof(*req
)) == VMMDEV_ERR_OK
) {
162 time(&otime
); /* old time */
164 ntime
= div64u(req
->time
, 1000); /* new time */
166 /* Make time go forward, if the difference exceeds the drift
167 * threshold. Never make time go backward.
169 if ((int) (ntime
- otime
) >= drift
)
173 sys_setalarm(ticks
, 0);
176 /*===========================================================================*
178 *===========================================================================*/
179 static void vbox_signal(int signo
)
181 /* Process a signal. If it is a SIGTERM, terminate immediately. */
183 if (signo
!= SIGTERM
) return;
188 /*===========================================================================*
189 * sef_local_startup *
190 *===========================================================================*/
191 static void sef_local_startup(void)
193 /* Perform local SEF initialization. */
195 sef_setcb_init_fresh(vbox_init
);
196 sef_setcb_init_restart(vbox_init
);
198 sef_setcb_signal_handler(vbox_signal
);
203 /*===========================================================================*
205 *===========================================================================*/
206 int main(int argc
, char **argv
)
208 /* The main message loop. */
212 env_setargs(argc
, argv
);
216 if ((r
= driver_receive(ANY
, &m
, &ipc_status
)) != OK
)
217 panic("driver_receive failed: %d", r
);
219 if (is_ipc_notify(ipc_status
)) {
220 switch (m
.m_source
) {
232 printf("VBOX: received notify from %d\n",
239 hgcm_message(&m
, ipc_status
);