minix/drivers/vbox/vbox.c
David van Moolenbroek 0aa01a2dce Add vbox -- VirtualBox time sync driver
Sets time forward to match the host time.

Started automatically if the corresponding device is present.
2011-11-23 18:15:43 +01:00

189 lines
4.6 KiB
C

/* VirtualBox driver - only does regular time sync - by D.C. van Moolenbroek */
#include <minix/drivers.h>
#include <minix/driver.h>
#include <minix/optset.h>
#include <machine/pci.h>
#include <sys/time.h>
#include "vbox.h"
#define DEFAULT_INTERVAL 1 /* check host time every second */
#define DEFAULT_DRIFT 2 /* update time if delta is >= 2 secs */
PRIVATE void *vir_ptr;
PRIVATE phys_bytes phys_ptr;
PRIVATE port_t port;
PRIVATE u32_t ticks;
PRIVATE int interval;
PRIVATE int drift;
PRIVATE struct optset optset_table[] = {
{ "interval", OPT_INT, &interval, 10 },
{ "drift", OPT_INT, &drift, 10 },
{ NULL, 0, NULL, 0 }
};
/*===========================================================================*
* vbox_request *
*===========================================================================*/
PRIVATE int vbox_request(int req_nr, size_t size)
{
/* Perform a VirtualBox backdoor request. */
struct VMMDevRequestHeader *hdr;
int r;
hdr = (struct VMMDevRequestHeader *) vir_ptr;
hdr->size = size;
hdr->version = VMMDEV_BACKDOOR_VERSION;
hdr->type = req_nr;
hdr->rc = VMMDEV_ERR_PERM;
if ((r = sys_outl(port, phys_ptr)) != OK)
panic("device I/O failed: %d", r);
return hdr->rc;
}
/*===========================================================================*
* vbox_init *
*===========================================================================*/
PRIVATE int vbox_init(int UNUSED(type), sef_init_info_t *UNUSED(info))
{
/* Initialize the device. */
int devind;
u16_t vid, did;
struct VMMDevReportGuestInfo *req;
int r;
interval = DEFAULT_INTERVAL;
drift = DEFAULT_DRIFT;
if (env_argc > 1)
optset_parse(optset_table, env_argv[1]);
pci_init();
r = pci_first_dev(&devind, &vid, &did);
for (;;) {
if (r != 1)
panic("backdoor device not found");
if (vid == VBOX_PCI_VID && did == VBOX_PCI_DID)
break;
r = pci_next_dev(&devind, &vid, &did);
}
port = pci_attr_r16(devind, PCI_BAR) & 0xfffc;
pci_reserve(devind);
if ((vir_ptr = alloc_contig(VMMDEV_BUF_SIZE, 0, &phys_ptr)) == NULL)
panic("unable to allocate memory");
req = (struct VMMDevReportGuestInfo *) vir_ptr;
req->guest_info.add_version = VMMDEV_GUEST_VERSION;
req->guest_info.os_type = VMMDEV_GUEST_OS_OTHER;
if ((r = vbox_request(VMMDEV_REQ_REPORTGUESTINFO, sizeof(*req))) !=
VMMDEV_ERR_OK)
panic("backdoor device not functioning");
ticks = sys_hz() * interval;
sys_setalarm(ticks, 0);
return OK;
}
/*===========================================================================*
* vbox_update_time *
*===========================================================================*/
PRIVATE void vbox_update_time(void)
{
/* Update the current time if it has drifted too far. */
struct VMMDevReqHostTime *req;
time_t otime, ntime;
req = (struct VMMDevReqHostTime *) vir_ptr;
if (vbox_request(VMMDEV_REQ_HOSTTIME, sizeof(*req)) == VMMDEV_ERR_OK) {
time(&otime); /* old time */
ntime = div64u(req->time, 1000); /* new time */
/* Make time go forward, if the difference exceeds the drift
* threshold. Never make time go backward.
*/
if ((int) (ntime - otime) >= drift)
stime(&ntime);
}
sys_setalarm(ticks, 0);
}
/*===========================================================================*
* vbox_signal *
*===========================================================================*/
PRIVATE void vbox_signal(int signo)
{
/* Process a signal. If it is a SIGTERM, terminate immediately. */
if (signo != SIGTERM) return;
exit(0);
}
/*===========================================================================*
* sef_local_startup *
*===========================================================================*/
PRIVATE void sef_local_startup(void)
{
/* Perform local SEF initialization. */
sef_setcb_init_fresh(vbox_init);
sef_setcb_init_restart(vbox_init);
sef_setcb_signal_handler(vbox_signal);
sef_startup();
}
/*===========================================================================*
* main *
*===========================================================================*/
PUBLIC int main(int argc, char **argv)
{
/* The main message loop. */
message m;
int r, ipc_status;
env_setargs(argc, argv);
sef_local_startup();
while (TRUE) {
if ((r = driver_receive(ANY, &m, &ipc_status)) != OK)
panic("driver_receive failed: %d", r);
if (is_ipc_notify(ipc_status)) {
switch (m.m_source) {
case CLOCK:
vbox_update_time();
break;
default:
printf("VBOX: received notify from %d\n",
m.m_source);
}
continue;
}
printf("VBOX: received message %d from %d\n",
m.m_type, m.m_source);
}
return 0;
}