memory: use sys_safememset() for /dev/zero
[minix.git] / drivers / vbox / vbox.c
blob4053515d00881d52955b57fbd4ef707df1d2eb11
1 /* VirtualBox driver - by D.C. van Moolenbroek */
2 /*
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.
6 */
7 #include <minix/drivers.h>
8 #include <minix/driver.h>
9 #include <minix/optset.h>
10 #include <machine/pci.h>
11 #include <sys/time.h>
13 #include "vmmdev.h"
14 #include "proto.h"
16 #define DEFAULT_INTERVAL 1 /* check host time every second */
17 #define DEFAULT_DRIFT 2 /* update time if delta is >= 2 secs */
19 static void *vir_ptr;
20 static phys_bytes phys_ptr;
21 static port_t port;
22 static u32_t ticks;
23 static int interval;
24 static int drift;
26 static unsigned int irq;
27 static int hook_id;
29 static struct optset optset_table[] = {
30 { "interval", OPT_INT, &interval, 10 },
31 { "drift", OPT_INT, &drift, 10 },
32 { NULL, 0, NULL, 0 }
35 /*===========================================================================*
36 * vbox_request *
37 *===========================================================================*/
38 int vbox_request(struct VMMDevRequestHeader *header, phys_bytes addr,
39 int type, size_t size)
41 /* Perform a VirtualBox backdoor request. */
42 int r;
44 header->size = size;
45 header->version = VMMDEV_BACKDOOR_VERSION;
46 header->type = type;
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 /*===========================================================================*
56 * vbox_init *
57 *===========================================================================*/
58 static int vbox_init(int UNUSED(type), sef_init_info_t *UNUSED(info))
60 /* Initialize the device. */
61 int devind;
62 u16_t vid, did;
63 struct VMMDevReportGuestInfo *req;
64 int r;
66 interval = DEFAULT_INTERVAL;
67 drift = DEFAULT_DRIFT;
69 if (env_argc > 1)
70 optset_parse(optset_table, env_argv[1]);
72 pci_init();
74 r = pci_first_dev(&devind, &vid, &did);
76 for (;;) {
77 if (r != 1)
78 panic("backdoor device not found");
80 if (vid == VMMDEV_PCI_VID && did == VMMDEV_PCI_DID)
81 break;
83 r = pci_next_dev(&devind, &vid, &did);
86 pci_reserve(devind);
88 port = pci_attr_r32(devind, PCI_BAR) & PCI_BAR_IO_MASK;
90 irq = pci_attr_r8(devind, PCI_ILR);
92 if ((r = sys_irqsetpolicy(irq, 0 /* IRQ_REENABLE */, &hook_id)) != OK)
93 panic("unable to register IRQ: %d", r);
95 if ((r = sys_irqenable(&hook_id)) != OK)
96 panic("unable to enable IRQ: %d", r);
98 if ((vir_ptr = alloc_contig(VMMDEV_BUF_SIZE, 0, &phys_ptr)) == NULL)
99 panic("unable to allocate memory");
101 req = (struct VMMDevReportGuestInfo *) vir_ptr;
102 req->add_version = VMMDEV_GUEST_VERSION;
103 req->os_type = VMMDEV_GUEST_OS_OTHER;
105 if ((r = vbox_request(&req->header, phys_ptr,
106 VMMDEV_REQ_REPORTGUESTINFO, sizeof(*req))) !=
107 VMMDEV_ERR_OK)
108 panic("backdoor device not functioning");
110 ticks = sys_hz() * interval;
112 sys_setalarm(ticks, 0);
114 return OK;
117 /*===========================================================================*
118 * vbox_intr *
119 *===========================================================================*/
120 static void vbox_intr(void)
122 /* Process an interrupt. */
123 struct VMMDevEvents *req;
124 int r;
126 req = (struct VMMDevEvents *) vir_ptr;
127 req->events = 0;
129 /* If we cannot retrieve the events mask, we cannot do anything with
130 * this or any future interrupt either, so return without reenabling
131 * interrupts.
133 if ((r = vbox_request(&req->header, phys_ptr,
134 VMMDEV_REQ_ACKNOWLEDGEEVENTS, sizeof(*req))) !=
135 VMMDEV_ERR_OK) {
136 printf("VBOX: unable to retrieve event mask (%d)\n", r);
138 return;
141 if (req->events & VMMDEV_EVENT_HGCM)
142 hgcm_intr();
144 if ((r = sys_irqenable(&hook_id)) != OK)
145 panic("unable to reenable IRQ: %d", r);
148 /*===========================================================================*
149 * vbox_update_time *
150 *===========================================================================*/
151 static void vbox_update_time(void)
153 /* Update the current time if it has drifted too far. */
154 struct VMMDevReqHostTime *req;
155 time_t otime, ntime;
157 req = (struct VMMDevReqHostTime *) vir_ptr;
159 if (vbox_request(&req->header, phys_ptr, VMMDEV_REQ_HOSTTIME,
160 sizeof(*req)) == VMMDEV_ERR_OK) {
161 time(&otime); /* old time */
163 ntime = div64u(req->time, 1000); /* new time */
165 /* Make time go forward, if the difference exceeds the drift
166 * threshold. Never make time go backward.
168 if ((int) (ntime - otime) >= drift)
169 stime(&ntime);
172 sys_setalarm(ticks, 0);
175 /*===========================================================================*
176 * vbox_signal *
177 *===========================================================================*/
178 static void vbox_signal(int signo)
180 /* Process a signal. If it is a SIGTERM, terminate immediately. */
182 if (signo != SIGTERM) return;
184 exit(0);
187 /*===========================================================================*
188 * sef_local_startup *
189 *===========================================================================*/
190 static void sef_local_startup(void)
192 /* Perform local SEF initialization. */
194 sef_setcb_init_fresh(vbox_init);
195 sef_setcb_init_restart(vbox_init);
197 sef_setcb_signal_handler(vbox_signal);
199 sef_startup();
202 /*===========================================================================*
203 * main *
204 *===========================================================================*/
205 int main(int argc, char **argv)
207 /* The main message loop. */
208 message m;
209 int r, ipc_status;
211 env_setargs(argc, argv);
212 sef_local_startup();
214 while (TRUE) {
215 if ((r = driver_receive(ANY, &m, &ipc_status)) != OK)
216 panic("driver_receive failed: %d", r);
218 if (is_ipc_notify(ipc_status)) {
219 switch (m.m_source) {
220 case HARDWARE:
221 vbox_intr();
223 break;
225 case CLOCK:
226 vbox_update_time();
228 break;
230 default:
231 printf("VBOX: received notify from %d\n",
232 m.m_source);
235 continue;
238 hgcm_message(&m, ipc_status);
241 return 0;