Add vbox -- VirtualBox time sync driver

Sets time forward to match the host time.

Started automatically if the corresponding device is present.
This commit is contained in:
David van Moolenbroek 2011-11-23 18:15:43 +01:00
parent b4d9ac91ba
commit 0aa01a2dce
8 changed files with 269 additions and 4 deletions

View file

@ -68,6 +68,7 @@ drivers/rtl8139/rtl8139
drivers/rtl8169/rtl8169
drivers/ti1225/ti1225
drivers/tty/tty
drivers/vbox/vbox
);
# 8< ----------- no user configurable parameters below this line ----------- >8

View file

@ -13,7 +13,7 @@ SUBDIR= at_wini bios_wini floppy log tty pci .WAIT ramdisk .WAIT memory
# memory driver must be last for ramdisk image
SUBDIR+= ahci amddev atl2 at_wini audio bios_wini dec21140A dp8390 dpeth \
e1000 filter floppy fxp hello lance log orinoco pci printer \
random readclock rtl8139 rtl8169 ti1225 tty acpi \
random readclock rtl8139 rtl8169 ti1225 tty vbox acpi \
.WAIT ramdisk .WAIT memory
.endif

View file

@ -47,6 +47,7 @@ struct pci_vendor pci_vendor_table[]=
{ 0x1969, "Atheros Communications" },
{ 0x5333, "S3" },
{ 0x8086, "Intel" },
{ 0x80ee, "Oracle" },
{ 0x9004, "Adaptec" },
{ 0x9005, "Adaptec" },
{ 0x0000, NULL }
@ -170,6 +171,7 @@ struct pci_device pci_device_table[]=
{ 0x8086, 0x7190, "Intel 82443BX" },
{ 0x8086, 0x7191, "Intel 82443BX (AGP bridge)" },
{ 0x8086, 0x7192, "Intel 82443BX (Host-to-PCI bridge)" },
{ 0x80ee, 0xcafe, "Oracle VirtualBox backdoor device" },
{ 0x9004, 0x8178, "Adaptec AHA-2940U/2940UW Ultra/Ultra-Wide SCSI Ctrlr" },
{ 0x9005, 0x0080, "Adaptec AIC-7892A Ultra160/m PCI SCSI Controller" },
{ 0x0000, 0x0000, NULL }

12
drivers/vbox/Makefile Normal file
View file

@ -0,0 +1,12 @@
# Makefile for the VirtualBox backdoor driver (VBOX)
PROG= vbox
SRCS= vbox.c
DPADD+= ${LIBSYS}
LDADD+= -lsys
MAN=
BINDIR?= /usr/sbin
.include <minix.service.mk>

189
drivers/vbox/vbox.c Normal file
View file

@ -0,0 +1,189 @@
/* 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;
}

44
drivers/vbox/vbox.h Normal file
View file

@ -0,0 +1,44 @@
#ifndef _VBOX_H
#define _VBOX_H
#define VBOX_PCI_VID 0x80ee
#define VBOX_PCI_DID 0xcafe
struct VMMDevRequestHeader {
u32_t size;
u32_t version;
u32_t type;
i32_t rc;
u32_t reserved[2];
};
struct VBoxGuestInfo {
u32_t add_version;
u32_t os_type;
};
struct VMMDevReportGuestInfo {
struct VMMDevRequestHeader header;
struct VBoxGuestInfo guest_info;
};
struct VMMDevReqHostTime {
struct VMMDevRequestHeader header;
u64_t time;
};
#define VMMDEV_MAKEWORD(m,n) (((m) << 16) | (n))
#define VMMDEV_BACKDOOR_VERSION VMMDEV_MAKEWORD(1, 1)
#define VMMDEV_GUEST_VERSION VMMDEV_MAKEWORD(1, 4)
#define VMMDEV_GUEST_OS_OTHER 0x90000 /* this is L4 - close enough */
#define VMMDEV_REQ_REPORTGUESTINFO 50
#define VMMDEV_REQ_HOSTTIME 10
#define VMMDEV_ERR_OK 0
#define VMMDEV_ERR_PERM (-10)
#define VMMDEV_BUF_SIZE 4096 /* just one page */
#endif /* _VBOX_H */

View file

@ -524,6 +524,19 @@ service devman
uid 0;
};
service vbox
{
system
UMAP # 14
DEVIO # 21
;
pci device 80ee/cafe;
ipc
SYSTEM
PM
RS
VM
pci
;
uid 0;
};

View file

@ -141,6 +141,10 @@ start)
fi
up -n printer -dev /dev/lp -period 10HZ
up -n ipc
# start VirtualBox time sync driver if the device is there
if grep '^[^ ]* [^ ]* 80EE:CAFE ' /proc/pci >/dev/null; then
up -n vbox -period 10HZ
fi
echo .
# Network initialization.