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 void vbox_update_time(void)
61 /* Update the current time if it has drifted too far. */
62 struct VMMDevReqHostTime
*req
;
65 req
= (struct VMMDevReqHostTime
*) vir_ptr
;
67 if (vbox_request(&req
->header
, phys_ptr
, VMMDEV_REQ_HOSTTIME
,
68 sizeof(*req
)) == VMMDEV_ERR_OK
) {
69 time(&otime
); /* old time */
71 ntime
= req
->time
/ 1000; /* new time */
73 /* Make time go forward, if the difference exceeds the drift
74 * threshold. Never make time go backward.
76 if ((ntime
- otime
) >= drift
)
80 sys_setalarm(ticks
, 0);
83 /*===========================================================================*
85 *===========================================================================*/
86 static int vbox_init(int UNUSED(type
), sef_init_info_t
*UNUSED(info
))
88 /* Initialize the device. */
91 struct VMMDevReportGuestInfo
*req
;
94 interval
= DEFAULT_INTERVAL
;
95 drift
= DEFAULT_DRIFT
;
98 optset_parse(optset_table
, env_argv
[1]);
102 r
= pci_first_dev(&devind
, &vid
, &did
);
106 panic("backdoor device not found");
108 if (vid
== VMMDEV_PCI_VID
&& did
== VMMDEV_PCI_DID
)
111 r
= pci_next_dev(&devind
, &vid
, &did
);
116 port
= pci_attr_r32(devind
, PCI_BAR
) & PCI_BAR_IO_MASK
;
118 irq
= pci_attr_r8(devind
, PCI_ILR
);
121 if ((r
= sys_irqsetpolicy(irq
, 0 /* IRQ_REENABLE */, &hook_id
)) != OK
)
122 panic("unable to register IRQ: %d", r
);
124 if ((r
= sys_irqenable(&hook_id
)) != OK
)
125 panic("unable to enable IRQ: %d", r
);
127 if ((vir_ptr
= alloc_contig(VMMDEV_BUF_SIZE
, 0, &phys_ptr
)) == NULL
)
128 panic("unable to allocate memory");
130 req
= (struct VMMDevReportGuestInfo
*) vir_ptr
;
131 req
->add_version
= VMMDEV_GUEST_VERSION
;
132 req
->os_type
= VMMDEV_GUEST_OS_OTHER
;
134 if ((r
= vbox_request(&req
->header
, phys_ptr
,
135 VMMDEV_REQ_REPORTGUESTINFO
, sizeof(*req
))) !=
137 panic("backdoor device not functioning");
139 ticks
= sys_hz() * interval
;
142 * Do the first time update immediately. If the time changes
143 * significantly, there may otherwise be interference with rc scripts.
150 /*===========================================================================*
152 *===========================================================================*/
153 static void vbox_intr(void)
155 /* Process an interrupt. */
156 struct VMMDevEvents
*req
;
159 req
= (struct VMMDevEvents
*) vir_ptr
;
162 /* If we cannot retrieve the events mask, we cannot do anything with
163 * this or any future interrupt either, so return without reenabling
166 if ((r
= vbox_request(&req
->header
, phys_ptr
,
167 VMMDEV_REQ_ACKNOWLEDGEEVENTS
, sizeof(*req
))) !=
169 printf("VBOX: unable to retrieve event mask (%d)\n", r
);
174 if (req
->events
& VMMDEV_EVENT_HGCM
)
177 if ((r
= sys_irqenable(&hook_id
)) != OK
)
178 panic("unable to reenable IRQ: %d", r
);
181 /*===========================================================================*
183 *===========================================================================*/
184 static void vbox_signal(int signo
)
186 /* Process a signal. If it is a SIGTERM, terminate immediately. */
188 if (signo
!= SIGTERM
) return;
193 /*===========================================================================*
194 * sef_local_startup *
195 *===========================================================================*/
196 static void sef_local_startup(void)
198 /* Perform local SEF initialization. */
200 sef_setcb_init_fresh(vbox_init
);
201 sef_setcb_init_restart(vbox_init
);
203 sef_setcb_signal_handler(vbox_signal
);
208 /*===========================================================================*
210 *===========================================================================*/
211 int main(int argc
, char **argv
)
213 /* The main message loop. */
217 env_setargs(argc
, argv
);
221 if ((r
= driver_receive(ANY
, &m
, &ipc_status
)) != OK
)
222 panic("driver_receive failed: %d", r
);
224 if (is_ipc_notify(ipc_status
)) {
225 switch (m
.m_source
) {
237 printf("VBOX: received notify from %d\n",
244 hgcm_message(&m
, ipc_status
);