From 0aa01a2dced5060d10cb4b0528bda3a1fb53ad71 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Wed, 23 Nov 2011 18:15:43 +0100 Subject: [PATCH] Add vbox -- VirtualBox time sync driver Sets time forward to match the host time. Started automatically if the corresponding device is present. --- commands/profile/sprofalyze.pl | 1 + drivers/Makefile | 2 +- drivers/pci/pci_table.c | 2 + drivers/vbox/Makefile | 12 +++ drivers/vbox/vbox.c | 189 +++++++++++++++++++++++++++++++++ drivers/vbox/vbox.h | 44 ++++++++ etc/system.conf | 19 +++- etc/usr/rc | 4 + 8 files changed, 269 insertions(+), 4 deletions(-) create mode 100644 drivers/vbox/Makefile create mode 100644 drivers/vbox/vbox.c create mode 100644 drivers/vbox/vbox.h diff --git a/commands/profile/sprofalyze.pl b/commands/profile/sprofalyze.pl index d631c2bff..1632d894e 100755 --- a/commands/profile/sprofalyze.pl +++ b/commands/profile/sprofalyze.pl @@ -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 diff --git a/drivers/Makefile b/drivers/Makefile index 8183e9105..ad932c7b5 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -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 diff --git a/drivers/pci/pci_table.c b/drivers/pci/pci_table.c index 966686393..06cbbb0e2 100644 --- a/drivers/pci/pci_table.c +++ b/drivers/pci/pci_table.c @@ -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 } diff --git a/drivers/vbox/Makefile b/drivers/vbox/Makefile new file mode 100644 index 000000000..abf3e773f --- /dev/null +++ b/drivers/vbox/Makefile @@ -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 diff --git a/drivers/vbox/vbox.c b/drivers/vbox/vbox.c new file mode 100644 index 000000000..24c8351a0 --- /dev/null +++ b/drivers/vbox/vbox.c @@ -0,0 +1,189 @@ +/* VirtualBox driver - only does regular time sync - by D.C. van Moolenbroek */ +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/vbox/vbox.h b/drivers/vbox/vbox.h new file mode 100644 index 000000000..4e4367354 --- /dev/null +++ b/drivers/vbox/vbox.h @@ -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 */ diff --git a/etc/system.conf b/etc/system.conf index 5e147631b..ead66bbdf 100644 --- a/etc/system.conf +++ b/etc/system.conf @@ -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; +}; diff --git a/etc/usr/rc b/etc/usr/rc index a985e2287..69fe0c529 100644 --- a/etc/usr/rc +++ b/etc/usr/rc @@ -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. -- 2.44.0